Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
47baf27
feat: Added login method
kevinwang5658 Jul 16, 2025
78d5dd6
feat: Added connect integration with codify-dashboard
kevinwang5658 Jul 27, 2025
45cb8ca
feat: switched to hono server and added cors support
kevinwang5658 Jul 27, 2025
83bc13f
feat: switched to express
kevinwang5658 Jul 28, 2025
7cb3972
chore: refactored apply flow to use express
kevinwang5658 Jul 29, 2025
4c2759e
Added login helper and trying out parser abstraction
kevinwang5658 Sep 2, 2025
5630319
Added ability to load, apply and plan cloud files
kevinwang5658 Sep 3, 2025
38b2414
Moved login init to base command. Fixes
kevinwang5658 Sep 5, 2025
b73f126
Added new codify file resolution logic. WIP default document endpoint…
kevinwang5658 Sep 5, 2025
aa23381
Added path as an arg to apply and plan
kevinwang5658 Sep 5, 2025
487159f
Added path as an arg to validate
kevinwang5658 Sep 5, 2025
5976346
Fixed import logic to support cloud files
kevinwang5658 Sep 6, 2025
69f8ae1
Fixed login bugs.
kevinwang5658 Sep 12, 2025
f5eddbc
Fixed codify apply via connect to supply tmpFile path. Added helpful …
kevinwang5658 Sep 12, 2025
5289fd3
Switched to socketIO
kevinwang5658 Sep 15, 2025
7faf88f
Switched back to websockets instead of socket io
kevinwang5658 Sep 15, 2025
5984c56
Prevent multiple pty instances from being created
kevinwang5658 Sep 16, 2025
2cf0b95
Improved the command handler to support more variations
kevinwang5658 Sep 16, 2025
e031dfd
Fixed build bugs. Moved uuid to dependency. Fixed entry points that w…
kevinwang5658 Sep 16, 2025
ef61320
Improved session ending logic.
kevinwang5658 Sep 17, 2025
421e152
Added missing import flag
kevinwang5658 Sep 24, 2025
dae7277
Changed connect commands to use rootCommand that way it updates with …
kevinwang5658 Sep 24, 2025
add4147
Refactored how commands are handled. Allows for greater flexibility.
kevinwang5658 Sep 25, 2025
ddf8ba3
Added import handler
kevinwang5658 Sep 25, 2025
90b9578
Added concept of clientId. Added import writer
kevinwang5658 Sep 25, 2025
3643c4a
Re-worked login to get email, userId, claims directly from token. Swi…
kevinwang5658 Oct 1, 2025
ad81e8f
Removed extraneous logs. Added message for codify edit
kevinwang5658 Oct 1, 2025
441d624
Added install beta script. Fixed urls to point to dashboard.codifycli…
kevinwang5658 Oct 2, 2025
904ac3f
Fixed login behavior for connect and edit. Added log out command
kevinwang5658 Oct 2, 2025
aad8e5a
Add new refresh command
kevinwang5658 Oct 21, 2025
26ba958
Changed the parameterless import to mimic init (auto import everything)
kevinwang5658 Oct 21, 2025
a76a640
Added refresh method to connect and fixed bugs
kevinwang5658 Oct 21, 2025
b24f2a9
Fixed API calls to parse error messages as non-json
kevinwang5658 Oct 21, 2025
92bf7b3
Fixed bugs:
kevinwang5658 Oct 22, 2025
cbe9334
Added --updateExisting flag for import command. Made refresh orchestr…
kevinwang5658 Oct 22, 2025
f40e04c
Fixed file modification calculator handling of an empty file '[]'. Ad…
kevinwang5658 Oct 22, 2025
c186cd0
Fixed file modification calculator handling of an empty file '[]'. Ad…
kevinwang5658 Oct 22, 2025
2b5e4fa
fix: Fixed bugs with refresh and import
kevinwang5658 Oct 25, 2025
7604bf2
feat: Added support for Codify remote files
kevinwang5658 Oct 27, 2025
a681d7f
fix: Bug fix for files that don't currently exist. Import confirmatio…
kevinwang5658 Oct 27, 2025
821bef6
fix: Bug fix for MacOS oclif installer bug. It doesn't clear the ocli…
kevinwang5658 Nov 16, 2025
432614a
feat: Added auto complete, additional version flags, additional help …
kevinwang5658 Nov 17, 2025
028766a
fix: Added init command
kevinwang5658 Nov 20, 2025
989cad3
Added new finish event to unify sending the remote result back to the…
kevinwang5658 Nov 21, 2025
2ecee5e
Added the useful ability to kill the previous codify connect so you d…
kevinwang5658 Nov 21, 2025
f48c6ef
fix: Moved kill port to dependencies
kevinwang5658 Nov 22, 2025
5fb7d70
feat: Added connection start time and connection termination
kevinwang5658 Dec 3, 2025
46b3259
feat: Refactored the initialization process to return a resource defi…
kevinwang5658 Dec 13, 2025
6c96b0a
feat: Added sensitive parameter filtering to import and init. Added s…
kevinwang5658 Dec 13, 2025
5d9b8be
feat: Added improvements to import and init saving of results
kevinwang5658 Dec 13, 2025
780ad3e
feat: Improved init experience (always new project for init)
kevinwang5658 Dec 13, 2025
130402a
feat: Fixed build issues and improved help
kevinwang5658 Dec 13, 2025
950c4dd
fix: Fixed existing tests
kevinwang5658 Dec 14, 2025
a2280ee
feat: Added CLI logins without the browser
kevinwang5658 Dec 14, 2025
5584367
feat: Added test for connect + improvements and fixes
kevinwang5658 Dec 14, 2025
5d311dc
feat: Added test for connect commands (apply, plan, import, etc) + im…
kevinwang5658 Dec 14, 2025
4b37f78
feat: Added additional tests for edit, login and refresh
kevinwang5658 Dec 14, 2025
f2bf0e7
feat: Add readme and license
kevinwang5658 Dec 14, 2025
441ab31
feat: Upgrade to node 22
kevinwang5658 Dec 14, 2025
1871937
fix: Test and type fixes
kevinwang5658 Dec 14, 2025
acdeb77
fix: Temp disable socket-server tests
kevinwang5658 Dec 14, 2025
40eae06
fix: Enable one of the disabled tests
kevinwang5658 Dec 14, 2025
93339f3
kevin/fix-tests (#50)
kevinwang5658 Dec 15, 2025
9e4e7cc
Fix: Bug fixes for help, and init using dev-dependency. Added extra c…
kevinwang5658 Dec 19, 2025
1bc02e7
feat: Added new spawn code using node-pty. Root and stdin are both su…
kevinwang5658 Dec 23, 2025
aeb6219
feat: Removed the spinner powered by log messages (caused pointer iss…
kevinwang5658 Dec 23, 2025
26cfda2
feat: Added codify test command that can spawn a tart vm to test codi…
kevinwang5658 Jan 3, 2026
f91cffa
feat: Improved the display for test. Added linux support on a macOS h…
kevinwang5658 Jan 3, 2026
c56b4d7
feat: Added support for validating by OS and distro. Added improved i…
kevinwang5658 Jan 22, 2026
d31a9df
feat: Allow beta plugins to be auto-magically be added when codify ve…
kevinwang5658 Jan 25, 2026
b55db9b
feat: Reverted commenting out xz
kevinwang5658 Jan 25, 2026
50c2d76
feat: Added os filtering for codify init command
kevinwang5658 Jan 30, 2026
749265c
feat: Updated github urls and description
kevinwang5658 Feb 10, 2026
6ece30e
feat: Force arch to be arm64. Added linux to uplaod script.
kevinwang5658 Feb 15, 2026
4ff8152
fix: Fixed sudo, reporters, os filtering, and others (mainly linux re…
kevinwang5658 Feb 22, 2026
b69734e
fix: Connect commands not working on other shells
kevinwang5658 Feb 24, 2026
a68b0ec
fix: Fixed running sudo commands on linux and commands with quotes
kevinwang5658 Feb 24, 2026
bb604b1
chore: switch to public npm @codifycli/ink-form package
kevinwang5658 Feb 24, 2026
2c57de7
fix: Fixed environment variables not carried over to sudo. Fixed bash…
kevinwang5658 Feb 26, 2026
b4cc362
fix: Fixed warnings on linux install. Bumped oclif version.
kevinwang5658 Feb 27, 2026
05f94cb
feat: Updated ink. Switched to dots instead of half circles. Move sle…
kevinwang5658 Mar 3, 2026
2758c84
fix: Fixed weird memory problem with using spinner and status message…
kevinwang5658 Mar 3, 2026
1b085df
feat: Improved coloring for progress display
kevinwang5658 Mar 3, 2026
4508491
fix: Fixed tests
kevinwang5658 Mar 4, 2026
2b4b2d6
chore: commit package-lock.json
kevinwang5658 Mar 4, 2026
cfe7fa6
fix: Linux tests and build errors
kevinwang5658 Mar 4, 2026
920fb9f
feat: Allow CI builds to run on both macOS and linux
kevinwang5658 Mar 4, 2026
6ae774b
feat: Improved test command and added file syncing (#56)
kevinwang5658 Mar 6, 2026
03320ad
feat: Added test to list of remote commands
kevinwang5658 Mar 7, 2026
8decc0a
chore: Updated packages. Switched to @codifycli/schemas
kevinwang5658 Mar 7, 2026
9da6120
chore: Updated package-lock.json
kevinwang5658 Mar 7, 2026
6cadec4
feat: removed login requirement for connect command
kevinwang5658 Mar 7, 2026
fa69e91
fix: Remove github token code in github actions
kevinwang5658 Mar 8, 2026
54c6ef6
chore: Update to @codifycli/plugin-core and update version of @codify…
kevinwang5658 Mar 8, 2026
b3beab5
feat: Updated README
kevinwang5658 Mar 8, 2026
b7f97c9
chore: new package-lock.json
kevinwang5658 Mar 8, 2026
7c26073
feat: Add CLAUDE.md and updated the README.md
kevinwang5658 Mar 8, 2026
90b8e93
fix: Fix bugs with the test command
kevinwang5658 Mar 8, 2026
0a5eb91
chore: update version to 1.0.0
kevinwang5658 Mar 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: Added support for Codify remote files
  • Loading branch information
kevinwang5658 committed Oct 27, 2025
commit 7604bf29f1a3304cee8e006cd4d2544bee688311
13 changes: 7 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"ajv": "^8.12.0",
"ajv-formats": "^3.0.1",
"chalk": "^5.3.0",
"codify-schemas": "^1.0.76",
"codify-schemas": "^1.0.77",
"cors": "^2.8.5",
"debug": "^4.3.4",
"detect-indent": "^7.0.1",
Expand Down
91 changes: 91 additions & 0 deletions src/api/backend/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as fsSync from 'node:fs';
import * as fs from 'node:fs/promises';
import path from 'node:path';
import { Readable } from 'node:stream';
import { finished } from 'node:stream/promises';

import { PluginSearchQuery, PluginSearchResult } from './types.js';

const API_BASE_URL = 'https://api.codifycli.com'

export const ApiClient = {
async searchPlugins(query: PluginSearchQuery[]): Promise<PluginSearchResult> {
const body = JSON.stringify({ query });
const res = await fetch(
`${API_BASE_URL}/v1/plugins/versions/search`,
{ method: 'POST', body, headers: { 'Content-Type': 'application/json' } }
);

if (!res.ok) {
const message = await res.text();
throw new Error(message);
}

const json = await res.json();
return json.results as unknown as PluginSearchResult;
},

async downloadPlugin(filePath: string, url: string): Promise<void> {
const { body } = await fetch(url)

const dirname = path.dirname(filePath);
if (!await fs.stat(dirname).then((s) => s.isDirectory()).catch(() => false)) {
await fs.mkdir(dirname, { recursive: true });
}

const ws = fsSync.createWriteStream(filePath)
// Different type definitions here for readable stream (NodeJS vs DOM). Small hack to fix that
await finished(Readable.fromWeb(body as never).pipe(ws));
},

async getRemoteFileHash(filePath: string, credentials: string): Promise<string> {
const { documentId, fileId } = this.extractCodifyFileInfo(filePath);

const response = await fetch((`https://api.codifycli.com/v1/documents/${documentId}/file/${fileId}/hash`), {
method: 'GET',
headers: {
'Authorization': `Bearer ${credentials}`,
},
});

if (!response.ok) {
throw new Error(`Failed to get remote file hash for ${filePath}`);
}

const data = await response.json();
return data.hash;
},

async updateRemoteFile(filePath: string, content: Blob, credentials: string): Promise<string> {
const { documentId, fileId } = this.extractCodifyFileInfo(filePath);

const formData = new FormData();
formData.append('file', content);

const response = await fetch((`https://api.codifycli.com/v1/documents/${documentId}/file/${fileId}`), {
method: 'PUT',
headers: {
'Authorization': `Bearer ${credentials}`,
},
body: formData,
});

if (!response.ok) {
throw new Error(`Failed to save remote file ${filePath}`);
}
},

extractCodifyFileInfo(url: string) {
const regex = /codify:\/\/(.*):(.*)/

const [, group1, group2] = regex.exec(url) ?? [];
if (!group1 || !group2) {
throw new Error(`Invalid codify url ${url} for file`);
}

return {
documentId: group1,
fileId: group2,
}
},
};
File renamed without changes.
40 changes: 0 additions & 40 deletions src/api/index.ts

This file was deleted.

36 changes: 36 additions & 0 deletions src/common/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import createDebug from 'debug';

import { LoginHelper } from '../connect/login-helper.js';
import { Event, ctx } from '../events/context.js';
import { LoginOrchestrator } from '../orchestrators/login.js';
import { Reporter, ReporterFactory, ReporterType } from '../ui/reporters/reporter.js';
import { SudoUtils } from '../utils/sudo.js';
import { prettyPrintError } from './errors.js';
Expand Down Expand Up @@ -65,7 +66,42 @@ export abstract class BaseCommand extends Command {
ctx.pressKeyToContinueCompleted(pluginName)
})

ctx.on(Event.CODIFY_LOGIN_CREDENTIALS_REQUEST, async (pluginName: string) => {
if (pluginName !== 'default') {
throw new Error(`Only the default plugin can request Codify credentials. Instead received ${pluginName}`);
}

if (LoginHelper.get()?.isLoggedIn) {
const credentials = LoginHelper.get()?.credentials?.accessToken;
if (!credentials) {
throw new Error('Unable to retrieve Codify credentials for user...');
}

ctx.codifyLoginCompleted(pluginName, credentials);
} else {
ctx.log('User is not currently logged. Attempt to Login to Codify...');
await LoginOrchestrator.run();

if (LoginHelper.get()?.isLoggedIn) {
const credentials = LoginHelper.get()?.credentials?.accessToken;
if (!credentials) {
throw new Error('Unable to retrieve Codify credentials for user...');
}

ctx.codifyLoginCompleted(pluginName, credentials);
} else {
throw new Error('Unable to login...')
}
}
})

await LoginHelper.load();

// Catch any un-caught exceptions
process.on('uncaughtException', (error) => {
console.log('Caught exception')
this.catch(error);
})
}

protected async catch(err: Error): Promise<void> {
Expand Down
10 changes: 10 additions & 0 deletions src/events/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export enum Event {
SUDO_REQUEST_GRANTED = 'sudo_request_granted',
PRESS_KEY_TO_CONTINUE_REQUEST = 'press_key_to_continue_request',
PRESS_KEY_TO_CONTINUE_COMPLETED = 'press_key_to_continue_completed',
CODIFY_LOGIN_CREDENTIALS_REQUEST = 'codify_login_credentials_request',
CODIFY_LOGIN_CREDENTIALS_COMPLETED = 'codify_login_credentials_completed',
}

export enum ProcessName {
Expand Down Expand Up @@ -116,6 +118,14 @@ export const ctx = new class {
this.emitter.emit(Event.PRESS_KEY_TO_CONTINUE_COMPLETED, pluginName);
}

codifyLoginRequested(pluginName: string) {
this.emitter.emit(Event.CODIFY_LOGIN_CREDENTIALS_REQUEST, pluginName);
}

codifyLoginCompleted(pluginName: string, credentials: string) {
this.emitter.emit(Event.CODIFY_LOGIN_CREDENTIALS_COMPLETED, pluginName, credentials);
}

async subprocess<T>(name: string, run: () => Promise<T>): Promise<T> {
this.emitter.emit(Event.SUB_PROCESS_START, name);
const result = await run();
Expand Down
64 changes: 63 additions & 1 deletion src/orchestrators/import.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import chalk from 'chalk';
import fs from 'node:fs/promises';
import path from 'node:path';

import { ApiClient } from '../api/backend/index.js';
import { InitializationResult, PluginInitOrchestrator } from '../common/initialize-plugins.js';
import { LoginHelper } from '../connect/login-helper.js';
import { Project } from '../entities/project.js';
import { ResourceConfig } from '../entities/resource-config.js';
import { ResourceInfo } from '../entities/resource-info.js';
Expand All @@ -15,6 +19,7 @@ import { PromptType, Reporter } from '../ui/reporters/reporter.js';
import { FileUtils } from '../utils/file.js';
import { groupBy, sleep } from '../utils/index.js';
import { wildCardMatch } from '../utils/wild-card-match.js';
import { LoginOrchestrator } from './login.js';

export type ImportResult = { result: ResourceConfig[], errors: string[] }

Expand Down Expand Up @@ -161,8 +166,10 @@ export class ImportOrchestrator {
pluginManager: PluginManager,
args: ImportArgs,
): Promise<void> {
const multipleCodifyFiles = project.codifyFiles.length > 1;
// Special handling for remote-file resources. Offer to save them remotely if any changes are detected on import.
await ImportOrchestrator.handleCodifyRemoteFiles(reporter, importResult);

const multipleCodifyFiles = project.codifyFiles.length > 1;
const saveType = await ImportOrchestrator.getSaveType(reporter, project, args);

// Update an existing file
Expand Down Expand Up @@ -259,6 +266,61 @@ export class ImportOrchestrator {
await sleep(100);
}

// Special handling for codify cloud files. Import and refresh can automatically save file updates.
static async handleCodifyRemoteFiles(reporter: Reporter, importResult: ImportResult) {
try {
if (!importResult.result.some((r) => r.type === 'remote-file')) {
return;
}

if (!LoginHelper.get()?.isLoggedIn) {
await LoginOrchestrator.run();
}

const credentials = LoginHelper.get()!.credentials!.accessToken;

const filesToUpdate = [];
const remoteFiles = importResult.result.filter((r) => r.type === 'remote-file');
for (const file of remoteFiles) {
if (!file.parameters.remote || !file.parameters.hash) {
continue;
}

const hash = await ApiClient.getRemoteFileHash(file.parameters.remote as string, credentials);
if (hash !== file.parameters.hash) {
filesToUpdate.push(file);
}
}

if (filesToUpdate.length === 0) {
return;
}

const fileNames = filesToUpdate.map((f) => `'${f.parameters.path}'`).join(', ')
const shouldUpdate = await reporter.promptConfirmation(
`The following files have been updated: [${fileNames}].\nDo you want to upload the changes to Codify cloud? ${chalk.bold('(Warning this will override any existing data!)')}`,
);

if (!shouldUpdate) {
return;
}

for (const file of filesToUpdate) {
if (!file.parameters.path) {
console.warn(`Unable to find file path for file ${file.parameters.remote}`)
continue;
}

const content = await fs.readFile(file.parameters.path as string);
await ApiClient.updateRemoteFile(file.parameters.remote as string, new Blob([content]), credentials);
}

ctx.log('Successfully uploaded changes to Codify cloud');
} catch {
console.warn('Unable to process remote-files');
}
}

private static matchTypeIds(typeIds: string[], validTypeIds: string[]): string[] {
const result: string[] = [];
const unsupportedTypeIds: string[] = [];
Expand Down
4 changes: 4 additions & 0 deletions src/orchestrators/refresh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export class RefreshOrchestrator {

reporter.displayImportResult(importResult, false);


// Special handling for remote-file resources. Offer to save them remotely if any changes are detected on import.
await ImportOrchestrator.handleCodifyRemoteFiles(reporter, importResult);

const resourceInfoList = await pluginManager.getMultipleResourceInfo(
project.resourceConfigs.map((r) => r.type),
);
Expand Down
Loading
Loading