assistant-ui 0.0.120 → 0.0.122
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +1 -2
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/cloud.d.ts +25 -0
- package/dist/commands/cloud.d.ts.map +1 -0
- package/dist/commands/cloud.js +194 -0
- package/dist/commands/cloud.js.map +1 -0
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +10 -2
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/info.js +2 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +95 -23
- package/dist/commands/mcp.js.map +1 -1
- package/dist/lib/agent-skill.d.ts +2 -2
- package/dist/lib/agent-skill.d.ts.map +1 -1
- package/dist/lib/agent-skill.js +10 -28
- package/dist/lib/agent-skill.js.map +1 -1
- package/dist/lib/cloud-abort.d.ts +2 -0
- package/dist/lib/cloud-abort.d.ts.map +1 -0
- package/dist/lib/cloud-abort.js +13 -0
- package/dist/lib/cloud-abort.js.map +1 -0
- package/dist/lib/cloud-auth.d.ts +28 -0
- package/dist/lib/cloud-auth.d.ts.map +1 -0
- package/dist/lib/cloud-auth.js +169 -0
- package/dist/lib/cloud-auth.js.map +1 -0
- package/dist/lib/cloud-config.d.ts +21 -0
- package/dist/lib/cloud-config.d.ts.map +1 -0
- package/dist/lib/cloud-config.js +76 -0
- package/dist/lib/cloud-config.js.map +1 -0
- package/dist/lib/cloud-provision.d.ts +20 -0
- package/dist/lib/cloud-provision.d.ts.map +1 -0
- package/dist/lib/cloud-provision.js +55 -0
- package/dist/lib/cloud-provision.js.map +1 -0
- package/dist/lib/cloud-setup-login.d.ts +9 -0
- package/dist/lib/cloud-setup-login.d.ts.map +1 -0
- package/dist/lib/cloud-setup-login.js +137 -0
- package/dist/lib/cloud-setup-login.js.map +1 -0
- package/dist/lib/cloud-url.d.ts +2 -0
- package/dist/lib/cloud-url.d.ts.map +1 -0
- package/dist/lib/cloud-url.js +14 -0
- package/dist/lib/cloud-url.js.map +1 -0
- package/dist/lib/create-project.d.ts +0 -9
- package/dist/lib/create-project.d.ts.map +1 -1
- package/dist/lib/create-project.js +15 -46
- package/dist/lib/create-project.js.map +1 -1
- package/dist/lib/transform.d.ts +0 -4
- package/dist/lib/transform.d.ts.map +1 -1
- package/dist/lib/transform.js +8 -17
- package/dist/lib/transform.js.map +1 -1
- package/dist/lib/utils/download.d.ts +5 -0
- package/dist/lib/utils/download.d.ts.map +1 -0
- package/dist/lib/utils/download.js +41 -0
- package/dist/lib/utils/download.js.map +1 -0
- package/dist/lib/utils/file-scanner.d.ts +0 -1
- package/dist/lib/utils/file-scanner.d.ts.map +1 -1
- package/dist/lib/utils/file-scanner.js +1 -16
- package/dist/lib/utils/file-scanner.js.map +1 -1
- package/dist/lib/utils/package-manager.d.ts +7 -0
- package/dist/lib/utils/package-manager.d.ts.map +1 -1
- package/dist/lib/utils/package-manager.js +15 -1
- package/dist/lib/utils/package-manager.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +2 -1
- package/dist/program.js.map +1 -1
- package/package.json +12 -8
- package/src/commands/add.ts +2 -1
- package/src/commands/cloud.test.ts +238 -0
- package/src/commands/cloud.ts +455 -0
- package/src/commands/create.ts +13 -3
- package/src/commands/init.ts +5 -2
- package/src/commands/mcp.ts +223 -56
- package/src/lib/agent-skill.ts +18 -44
- package/src/lib/cloud-abort.ts +12 -0
- package/src/lib/cloud-auth.test.ts +500 -0
- package/src/lib/cloud-auth.ts +273 -0
- package/src/lib/cloud-config.test.ts +82 -0
- package/src/lib/cloud-config.ts +138 -0
- package/src/lib/cloud-provision.test.ts +132 -0
- package/src/lib/cloud-provision.ts +93 -0
- package/src/lib/cloud-setup-login.test.ts +361 -0
- package/src/lib/cloud-setup-login.ts +240 -0
- package/src/lib/cloud-url.ts +19 -0
- package/src/lib/create-project.test.ts +0 -17
- package/src/lib/create-project.ts +33 -98
- package/src/lib/transform-files.test.ts +1 -3
- package/src/lib/transform.ts +6 -20
- package/src/lib/utils/download.ts +57 -0
- package/src/lib/utils/file-scanner.ts +0 -26
- package/src/lib/utils/package-manager.ts +26 -0
- package/src/lib/utils/registry.test.ts +0 -6
- package/src/program.ts +2 -0
- package/templates/cloud-harness/.assistant-ui/template.json +3 -0
- package/templates/cloud-harness/.env.example +1 -0
- package/templates/cloud-harness/.gitignore +42 -0
- package/templates/cloud-harness/README.md +28 -0
- package/templates/cloud-harness/app/api/chat/route.ts +14 -0
- package/templates/cloud-harness/app/api/credential/route.ts +14 -0
- package/templates/cloud-harness/app/assistant.tsx +83 -0
- package/templates/cloud-harness/app/favicon.ico +0 -0
- package/templates/cloud-harness/app/globals.css +139 -0
- package/templates/cloud-harness/app/layout.tsx +37 -0
- package/templates/cloud-harness/app/page.tsx +5 -0
- package/templates/cloud-harness/components/assistant-ui/elements/attachment.aui.tsx +279 -0
- package/templates/cloud-harness/components/assistant-ui/elements/collapsible-root.tsx +19 -0
- package/templates/cloud-harness/components/assistant-ui/elements/markdown-text.tsx +238 -0
- package/templates/cloud-harness/components/assistant-ui/elements/thread.aui.tsx +521 -0
- package/templates/cloud-harness/components/assistant-ui/elements/tool-fallback.aui.tsx +1321 -0
- package/templates/cloud-harness/components/assistant-ui/elements/tooltip-icon-button.tsx +49 -0
- package/templates/cloud-harness/components/ui/avatar.tsx +109 -0
- package/templates/cloud-harness/components/ui/button.tsx +58 -0
- package/templates/cloud-harness/components/ui/collapsible.tsx +21 -0
- package/templates/cloud-harness/components/ui/dialog.tsx +159 -0
- package/templates/cloud-harness/components/ui/textarea.tsx +18 -0
- package/templates/cloud-harness/components/ui/tooltip.tsx +69 -0
- package/templates/cloud-harness/components.json +24 -0
- package/templates/cloud-harness/hooks/use-attachment-src.ts +46 -0
- package/templates/cloud-harness/hooks/use-copy-to-clipboard.ts +54 -0
- package/templates/cloud-harness/lib/utils.ts +1 -0
- package/templates/cloud-harness/next.config.ts +6 -0
- package/templates/cloud-harness/package.json +51 -0
- package/templates/cloud-harness/postcss.config.mjs +5 -0
- package/templates/cloud-harness/tsconfig.json +33 -0
- package/templates/cloud-harness/vendor/README.md +13 -0
- package/templates/cloud-harness/vendor/assistant-ui-react-harness-sdk-0.0.2.tgz +0 -0
- package/templates/cloud-harness/vendor/harness-sdk-0.3.1.tgz +0 -0
- package/templates/cloud-harness/vendor/provenance.json +38 -0
- package/templates/cloud-harness/vendor/statewire-0.19.3.tgz +0 -0
- /package/{LICENSE → templates/cloud-harness/vendor/LICENSE} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { downloadTemplate } from "giget";
|
|
2
|
+
//#region src/lib/utils/download.ts
|
|
3
|
+
const DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
4
|
+
function resolveGitHubAuthToken() {
|
|
5
|
+
return (process.env.GIGET_AUTH ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN)?.trim() || void 0;
|
|
6
|
+
}
|
|
7
|
+
async function withStagedDownload(source, options, timeoutMessage, cleanup, consumeDownload) {
|
|
8
|
+
const origDebug = process.env.DEBUG;
|
|
9
|
+
delete process.env.DEBUG;
|
|
10
|
+
let download;
|
|
11
|
+
let settled = false;
|
|
12
|
+
try {
|
|
13
|
+
const authToken = resolveGitHubAuthToken();
|
|
14
|
+
download = downloadTemplate(source, {
|
|
15
|
+
...options,
|
|
16
|
+
...authToken ? { auth: authToken } : {}
|
|
17
|
+
}).finally(() => {
|
|
18
|
+
settled = true;
|
|
19
|
+
});
|
|
20
|
+
let timer;
|
|
21
|
+
const timeout = new Promise((_, reject) => {
|
|
22
|
+
timer = setTimeout(() => reject(new Error(timeoutMessage)), DOWNLOAD_TIMEOUT_MS);
|
|
23
|
+
});
|
|
24
|
+
try {
|
|
25
|
+
return await consumeDownload(Promise.race([download, timeout]));
|
|
26
|
+
} finally {
|
|
27
|
+
clearTimeout(timer);
|
|
28
|
+
}
|
|
29
|
+
} finally {
|
|
30
|
+
try {
|
|
31
|
+
if (!download || settled) await cleanup();
|
|
32
|
+
else download.then(cleanup, cleanup);
|
|
33
|
+
} finally {
|
|
34
|
+
if (origDebug !== void 0) process.env.DEBUG = origDebug;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { DOWNLOAD_TIMEOUT_MS, resolveGitHubAuthToken, withStagedDownload };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download.js","names":[],"sources":["../../../src/lib/utils/download.ts"],"sourcesContent":["import { downloadTemplate } from \"giget\";\n\nexport const DOWNLOAD_TIMEOUT_MS = 30_000;\n\nexport function resolveGitHubAuthToken(): string | undefined {\n const token =\n process.env.GIGET_AUTH ?? process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;\n const trimmed = token?.trim();\n return trimmed || undefined;\n}\n\nexport async function withStagedDownload<T>(\n source: string,\n options: NonNullable<Parameters<typeof downloadTemplate>[1]>,\n timeoutMessage: string,\n cleanup: () => void | Promise<void>,\n consumeDownload: (download: Promise<unknown>) => Promise<T>,\n): Promise<T> {\n // giget logs to console.debug whenever DEBUG is set, which the `debug`\n // package does at module load for an unrelated namespace.\n const origDebug = process.env.DEBUG;\n delete process.env.DEBUG;\n let download: Promise<unknown> | undefined;\n let settled = false;\n try {\n const authToken = resolveGitHubAuthToken();\n download = downloadTemplate(source, {\n ...options,\n ...(authToken ? { auth: authToken } : {}),\n }).finally(() => {\n settled = true;\n });\n\n let timer: ReturnType<typeof setTimeout>;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(timeoutMessage)),\n DOWNLOAD_TIMEOUT_MS,\n );\n });\n try {\n return await consumeDownload(Promise.race([download, timeout]));\n } finally {\n clearTimeout(timer!);\n }\n } finally {\n try {\n if (!download || settled) {\n await cleanup();\n } else {\n void download.then(cleanup, cleanup);\n }\n } finally {\n if (origDebug !== undefined) process.env.DEBUG = origDebug;\n }\n }\n}\n"],"mappings":";;AAEA,MAAa,sBAAsB;AAEnC,SAAgB,yBAA6C;CAI3D,QAFE,QAAQ,IAAI,cAAc,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,SAAA,EAC7C,KAAK,KACV,KAAA;AACpB;AAEA,eAAsB,mBACpB,QACA,SACA,gBACA,SACA,iBACY;CAGZ,MAAM,YAAY,QAAQ,IAAI;CAC9B,OAAO,QAAQ,IAAI;CACnB,IAAI;CACJ,IAAI,UAAU;CACd,IAAI;EACF,MAAM,YAAY,uBAAuB;EACzC,WAAW,iBAAiB,QAAQ;GAClC,GAAG;GACH,GAAI,YAAY,EAAE,MAAM,UAAU,IAAI,CAAC;EACzC,CAAC,CAAC,CAAC,cAAc;GACf,UAAU;EACZ,CAAC;EAED,IAAI;EACJ,MAAM,UAAU,IAAI,SAAgB,GAAG,WAAW;GAChD,QAAQ,iBACA,OAAO,IAAI,MAAM,cAAc,CAAC,GACtC,mBACF;EACF,CAAC;EACD,IAAI;GACF,OAAO,MAAM,gBAAgB,QAAQ,KAAK,CAAC,UAAU,OAAO,CAAC,CAAC;EAChE,UAAU;GACR,aAAa,KAAM;EACrB;CACF,UAAU;EACR,IAAI;GACF,IAAI,CAAC,YAAY,SACf,MAAM,QAAQ;QAEd,SAAc,KAAK,SAAS,OAAO;EAEvC,UAAU;GACR,IAAI,cAAc,KAAA,GAAW,QAAQ,IAAI,QAAQ;EACnD;CACF;AACF"}
|
|
@@ -12,5 +12,4 @@ export declare function readProjectFiles(pattern: string, options: {
|
|
|
12
12
|
content: string;
|
|
13
13
|
}>;
|
|
14
14
|
export declare function scanForImport(importPattern: string | string[], options?: ScanOptions): boolean;
|
|
15
|
-
export declare function getFilesContaining(searchString: string, options?: ScanOptions): string[];
|
|
16
15
|
//# sourceMappingURL=file-scanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-scanner.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/file-scanner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAiB,gBAAgB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1C,SAAS,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAYhE;AAED,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,EAChC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAoBT
|
|
1
|
+
{"version":3,"file":"file-scanner.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/file-scanner.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAiB,gBAAgB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1C,SAAS,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAYhE;AAED,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,EAChC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAoBT"}
|
|
@@ -32,22 +32,7 @@ function scanForImport(importPattern, options = {}) {
|
|
|
32
32
|
})) if (patterns.some((p) => content.includes(p))) return true;
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
|
-
function getFilesContaining(searchString, options = {}) {
|
|
36
|
-
const cwd = options.cwd || process.cwd();
|
|
37
|
-
const pattern = options.pattern || "**/*.{js,jsx,ts,tsx}";
|
|
38
|
-
const ignore = options.ignore || [
|
|
39
|
-
"**/node_modules/**",
|
|
40
|
-
"**/dist/**",
|
|
41
|
-
"**/build/**"
|
|
42
|
-
];
|
|
43
|
-
const result = [];
|
|
44
|
-
for (const { fullPath, content } of readProjectFiles(pattern, {
|
|
45
|
-
cwd,
|
|
46
|
-
ignore
|
|
47
|
-
})) if (content.includes(searchString)) result.push(fullPath);
|
|
48
|
-
return result;
|
|
49
|
-
}
|
|
50
35
|
//#endregion
|
|
51
|
-
export {
|
|
36
|
+
export { readProjectFiles, scanForImport };
|
|
52
37
|
|
|
53
38
|
//# sourceMappingURL=file-scanner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-scanner.js","names":["globSync","path","fs"],"sources":["../../../src/lib/utils/file-scanner.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { sync as globSync } from \"glob\";\n\nexport interface ScanOptions {\n cwd?: string;\n pattern?: string;\n ignore?: string[];\n}\n\nexport function* readProjectFiles(\n pattern: string,\n options: { cwd: string; ignore?: string[] },\n): Generator<{ file: string; fullPath: string; content: string }> {\n const files = globSync(pattern, options);\n\n for (const file of files) {\n const fullPath = path.join(options.cwd, file);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n yield { file, fullPath, content };\n } catch {\n continue;\n }\n }\n}\n\nexport function scanForImport(\n importPattern: string | string[],\n options: ScanOptions = {},\n): boolean {\n const cwd = options.cwd || process.cwd();\n const pattern = options.pattern || \"**/*.{js,jsx,ts,tsx}\";\n const ignore = options.ignore || [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n ];\n\n const patterns = Array.isArray(importPattern)\n ? importPattern\n : [importPattern];\n\n for (const { content } of readProjectFiles(pattern, { cwd, ignore })) {\n if (patterns.some((p) => content.includes(p))) {\n return true;\n }\n }\n\n return false;\n}\n
|
|
1
|
+
{"version":3,"file":"file-scanner.js","names":["globSync","path","fs"],"sources":["../../../src/lib/utils/file-scanner.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { sync as globSync } from \"glob\";\n\nexport interface ScanOptions {\n cwd?: string;\n pattern?: string;\n ignore?: string[];\n}\n\nexport function* readProjectFiles(\n pattern: string,\n options: { cwd: string; ignore?: string[] },\n): Generator<{ file: string; fullPath: string; content: string }> {\n const files = globSync(pattern, options);\n\n for (const file of files) {\n const fullPath = path.join(options.cwd, file);\n try {\n const content = fs.readFileSync(fullPath, \"utf8\");\n yield { file, fullPath, content };\n } catch {\n continue;\n }\n }\n}\n\nexport function scanForImport(\n importPattern: string | string[],\n options: ScanOptions = {},\n): boolean {\n const cwd = options.cwd || process.cwd();\n const pattern = options.pattern || \"**/*.{js,jsx,ts,tsx}\";\n const ignore = options.ignore || [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/build/**\",\n ];\n\n const patterns = Array.isArray(importPattern)\n ? importPattern\n : [importPattern];\n\n for (const { content } of readProjectFiles(pattern, { cwd, ignore })) {\n if (patterns.some((p) => content.includes(p))) {\n return true;\n }\n }\n\n return false;\n}\n"],"mappings":";;;;AAUA,UAAiB,iBACf,SACA,SACgE;CAChE,MAAM,QAAQA,KAAS,SAAS,OAAO;CAEvC,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAWC,OAAK,KAAK,QAAQ,KAAK,IAAI;EAC5C,IAAI;GAEF,MAAM;IAAE;IAAM;IAAU,SADRC,KAAG,aAAa,UAAU,MACZ;GAAE;EAClC,QAAQ;GACN;EACF;CACF;AACF;AAEA,SAAgB,cACd,eACA,UAAuB,CAAC,GACf;CACT,MAAM,MAAM,QAAQ,OAAO,QAAQ,IAAI;CACvC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,QAAQ,UAAU;EAC/B;EACA;EACA;CACF;CAEA,MAAM,WAAW,MAAM,QAAQ,aAAa,IACxC,gBACA,CAAC,aAAa;CAElB,KAAK,MAAM,EAAE,aAAa,iBAAiB,SAAS;EAAE;EAAK;CAAO,CAAC,GACjE,IAAI,SAAS,MAAM,MAAM,QAAQ,SAAS,CAAC,CAAC,GAC1C,OAAO;CAIX,OAAO;AACT"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export type PackageManagerName = "npm" | "pnpm" | "yarn" | "bun";
|
|
2
|
+
export declare function dlxCommand(pm: PackageManagerName): [string, string[]];
|
|
3
|
+
export declare function resolvePackageManager(opts: {
|
|
4
|
+
useNpm?: boolean;
|
|
5
|
+
usePnpm?: boolean;
|
|
6
|
+
useYarn?: boolean;
|
|
7
|
+
useBun?: boolean;
|
|
8
|
+
}): PackageManagerName | undefined;
|
|
2
9
|
export declare function askQuestion(query: string): Promise<string>;
|
|
3
10
|
export declare function isPackageInstalled(pkg: string, cwd?: string): boolean;
|
|
4
11
|
export interface InstallCommand {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/package-manager.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAEjE,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC1D;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAgBT;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,EAC9B,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,CAAC,CAazB;AAYD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,kBAAkB,GAClC,OAAO,CAAC,kBAAkB,CAAC,CAS7B;AAED,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|
|
1
|
+
{"version":3,"file":"package-manager.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/package-manager.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAEjE,wBAAgB,UAAU,CAAC,EAAE,EAAE,kBAAkB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAWrE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,kBAAkB,GAAG,SAAS,CAMjC;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC1D;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAgBT;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,EAC9B,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,cAAc,CAAC,CAazB;AAYD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,kBAAkB,GAClC,OAAO,CAAC,kBAAkB,CAAC,CAS7B;AAED,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAUlB"}
|
|
@@ -5,6 +5,20 @@ import * as path$1 from "node:path";
|
|
|
5
5
|
import { detect } from "detect-package-manager";
|
|
6
6
|
import * as readline from "node:readline";
|
|
7
7
|
//#region src/lib/utils/package-manager.ts
|
|
8
|
+
function dlxCommand(pm) {
|
|
9
|
+
switch (pm) {
|
|
10
|
+
case "pnpm": return ["pnpm", ["dlx"]];
|
|
11
|
+
case "yarn": return ["yarn", ["dlx"]];
|
|
12
|
+
case "bun": return ["bunx", []];
|
|
13
|
+
case "npm": return ["npx", ["--yes"]];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function resolvePackageManager(opts) {
|
|
17
|
+
if (opts.useNpm) return "npm";
|
|
18
|
+
if (opts.usePnpm) return "pnpm";
|
|
19
|
+
if (opts.useYarn) return "yarn";
|
|
20
|
+
if (opts.useBun) return "bun";
|
|
21
|
+
}
|
|
8
22
|
function askQuestion(query) {
|
|
9
23
|
return new Promise((resolve) => {
|
|
10
24
|
if (process.stdin.readableEnded) {
|
|
@@ -93,6 +107,6 @@ async function installPackage(packageName, cwd) {
|
|
|
93
107
|
}
|
|
94
108
|
}
|
|
95
109
|
//#endregion
|
|
96
|
-
export { askQuestion, getInstallCommand, installPackage, isPackageInstalled, resolvePackageManagerForCwd };
|
|
110
|
+
export { askQuestion, dlxCommand, getInstallCommand, installPackage, isPackageInstalled, resolvePackageManager, resolvePackageManagerForCwd };
|
|
97
111
|
|
|
98
112
|
//# sourceMappingURL=package-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-manager.js","names":["path","fs"],"sources":["../../../src/lib/utils/package-manager.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { detect } from \"detect-package-manager\";\nimport * as readline from \"node:readline\";\nimport { logger } from \"./logger\";\nimport { runSpawn, SpawnSignalError } from \"../run-spawn\";\n\nexport type PackageManagerName = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport function askQuestion(query: string): Promise<string> {\n return new Promise((resolve) => {\n // A stream only reaches EOF once, so a run that already consumed stdin gets\n // no further `end` and an interface built over it would wait on a `close`\n // that cannot arrive. An upgrade asks up to three questions.\n if (process.stdin.readableEnded) {\n resolve(\"\");\n return;\n }\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n // stdin at EOF (a piped or CI run) emits `close` without a `line`, so the\n // question callback alone would leave this pending forever and the process\n // would exit 0 with the remaining work silently skipped. An empty answer is\n // what pressing Enter sends, so EOF lands on the prompt's own default.\n // A final answer with no trailing newline arrives as `line` instead of\n // through the callback, and has to win over that default.\n // Ctrl-C in raw mode is delivered as this event rather than as a signal,\n // and without a listener readline answers it by closing — which the EOF\n // default would then read as approval. A cancelled prompt declines.\n let cancelled = false;\n rl.on(\"SIGINT\", () => {\n cancelled = true;\n rl.close();\n });\n rl.on(\"line\", resolve);\n rl.on(\"close\", () => resolve(cancelled ? \"n\" : \"\"));\n rl.question(query, (answer) => {\n resolve(answer);\n rl.close();\n });\n });\n}\n\nexport function isPackageInstalled(\n pkg: string,\n cwd: string = process.cwd(),\n): boolean {\n try {\n const pkgJsonPath = path.join(cwd, \"package.json\");\n if (fs.existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf8\"));\n const deps = pkgJson.dependencies || {};\n const devDeps = pkgJson.devDependencies || {};\n if (deps[pkg] || devDeps[pkg]) {\n return true;\n }\n }\n } catch {\n // Fall back to node_modules check below.\n }\n const modulePath = path.join(cwd, \"node_modules\", ...pkg.split(\"/\"));\n return fs.existsSync(modulePath);\n}\n\nexport interface InstallCommand {\n command: string;\n args: string[];\n}\n\nexport async function getInstallCommand(\n packageName: string | string[],\n cwd?: string,\n): Promise<InstallCommand> {\n const pm = await detect({ cwd });\n const packages = Array.isArray(packageName) ? packageName : [packageName];\n switch (pm) {\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", ...packages] };\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", ...packages] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", ...packages] };\n default:\n return { command: \"npm\", args: [\"install\", ...packages] };\n }\n}\n\nfunction detectFromUserAgent(): PackageManagerName | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua) return undefined;\n if (ua.startsWith(\"bun/\")) return \"bun\";\n if (ua.startsWith(\"pnpm/\")) return \"pnpm\";\n if (ua.startsWith(\"yarn/\")) return \"yarn\";\n if (ua.startsWith(\"npm/\")) return \"npm\";\n return undefined;\n}\n\nexport async function resolvePackageManagerForCwd(\n cwd: string,\n packageManager?: PackageManagerName,\n): Promise<PackageManagerName> {\n if (packageManager) return packageManager;\n const fromAgent = detectFromUserAgent();\n if (fromAgent) return fromAgent;\n try {\n return await detect({ cwd });\n } catch {\n return \"npm\";\n }\n}\n\nexport async function installPackage(\n packageName: string,\n cwd?: string,\n): Promise<boolean> {\n try {\n const { command, args } = await getInstallCommand(packageName, cwd);\n await runSpawn(command, args, cwd);\n return true;\n } catch (e) {\n if (e instanceof SpawnSignalError) throw e;\n logger.error(`Installation failed: ${String(e)}`);\n return false;\n }\n}\n"],"mappings":";;;;;;;AASA,SAAgB,YAAY,OAAgC;CAC1D,OAAO,IAAI,SAAS,YAAY;EAI9B,IAAI,QAAQ,MAAM,eAAe;GAC/B,QAAQ,EAAE;GACV;EACF;EACA,MAAM,KAAK,SAAS,gBAAgB;GAClC,OAAO,QAAQ;GACf,QAAQ,QAAQ;EAClB,CAAC;EAUD,IAAI,YAAY;EAChB,GAAG,GAAG,gBAAgB;GACpB,YAAY;GACZ,GAAG,MAAM;EACX,CAAC;EACD,GAAG,GAAG,QAAQ,OAAO;EACrB,GAAG,GAAG,eAAe,QAAQ,YAAY,MAAM,EAAE,CAAC;EAClD,GAAG,SAAS,QAAQ,WAAW;GAC7B,QAAQ,MAAM;GACd,GAAG,MAAM;EACX,CAAC;CACH,CAAC;AACH;AAEA,SAAgB,mBACd,KACA,MAAc,QAAQ,IAAI,GACjB;CACT,IAAI;EACF,MAAM,cAAcA,OAAK,KAAK,KAAK,cAAc;EACjD,IAAIC,KAAG,WAAW,WAAW,GAAG;GAC9B,MAAM,UAAU,KAAK,MAAMA,KAAG,aAAa,aAAa,MAAM,CAAC;GAC/D,MAAM,OAAO,QAAQ,gBAAgB,CAAC;GACtC,MAAM,UAAU,QAAQ,mBAAmB,CAAC;GAC5C,IAAI,KAAK,QAAQ,QAAQ,MACvB,OAAO;EAEX;CACF,QAAQ,CAER;CACA,MAAM,aAAaD,OAAK,KAAK,KAAK,gBAAgB,GAAG,IAAI,MAAM,GAAG,CAAC;CACnE,OAAOC,KAAG,WAAW,UAAU;AACjC;AAOA,eAAsB,kBACpB,aACA,KACyB;CACzB,MAAM,KAAK,MAAM,OAAO,EAAE,IAAI,CAAC;CAC/B,MAAM,WAAW,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW;CACxE,QAAQ,IAAR;EACE,KAAK,QACH,OAAO;GAAE,SAAS;GAAQ,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACvD,KAAK,QACH,OAAO;GAAE,SAAS;GAAQ,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACvD,KAAK,OACH,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC,OAAO,GAAG,QAAQ;EAAE;EACtD,SACE,OAAO;GAAE,SAAS;GAAO,MAAM,CAAC,WAAW,GAAG,QAAQ;EAAE;CAC5D;AACF;AAEA,SAAS,sBAAsD;CAC7D,MAAM,KAAK,QAAQ,IAAI;CACvB,IAAI,CAAC,IAAI,OAAO,KAAA;CAChB,IAAI,GAAG,WAAW,MAAM,GAAG,OAAO;CAClC,IAAI,GAAG,WAAW,OAAO,GAAG,OAAO;CACnC,IAAI,GAAG,WAAW,OAAO,GAAG,OAAO;CACnC,IAAI,GAAG,WAAW,MAAM,GAAG,OAAO;AAEpC;AAEA,eAAsB,4BACpB,KACA,gBAC6B;CAC7B,IAAI,gBAAgB,OAAO;CAC3B,MAAM,YAAY,oBAAoB;CACtC,IAAI,WAAW,OAAO;CACtB,IAAI;EACF,OAAO,MAAM,OAAO,EAAE,IAAI,CAAC;CAC7B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAsB,eACpB,aACA,KACkB;CAClB,IAAI;EACF,MAAM,EAAE,SAAS,SAAS,MAAM,kBAAkB,aAAa,GAAG;EAClE,MAAM,SAAS,SAAS,MAAM,GAAG;EACjC,OAAO;CACT,SAAS,GAAG;EACV,IAAI,aAAa,kBAAkB,MAAM;EACzC,OAAO,MAAM,wBAAwB,OAAO,CAAC,GAAG;EAChD,OAAO;CACT;AACF"}
|
|
1
|
+
{"version":3,"file":"package-manager.js","names":["path","fs"],"sources":["../../../src/lib/utils/package-manager.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { detect } from \"detect-package-manager\";\nimport * as readline from \"node:readline\";\nimport { logger } from \"./logger\";\nimport { runSpawn, SpawnSignalError } from \"../run-spawn\";\n\nexport type PackageManagerName = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport function dlxCommand(pm: PackageManagerName): [string, string[]] {\n switch (pm) {\n case \"pnpm\":\n return [\"pnpm\", [\"dlx\"]];\n case \"yarn\":\n return [\"yarn\", [\"dlx\"]];\n case \"bun\":\n return [\"bunx\", []];\n case \"npm\":\n return [\"npx\", [\"--yes\"]];\n }\n}\n\nexport function resolvePackageManager(opts: {\n useNpm?: boolean;\n usePnpm?: boolean;\n useYarn?: boolean;\n useBun?: boolean;\n}): PackageManagerName | undefined {\n if (opts.useNpm) return \"npm\";\n if (opts.usePnpm) return \"pnpm\";\n if (opts.useYarn) return \"yarn\";\n if (opts.useBun) return \"bun\";\n return undefined;\n}\n\nexport function askQuestion(query: string): Promise<string> {\n return new Promise((resolve) => {\n // A stream only reaches EOF once, so a run that already consumed stdin gets\n // no further `end` and an interface built over it would wait on a `close`\n // that cannot arrive. An upgrade asks up to three questions.\n if (process.stdin.readableEnded) {\n resolve(\"\");\n return;\n }\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n // stdin at EOF (a piped or CI run) emits `close` without a `line`, so the\n // question callback alone would leave this pending forever and the process\n // would exit 0 with the remaining work silently skipped. An empty answer is\n // what pressing Enter sends, so EOF lands on the prompt's own default.\n // A final answer with no trailing newline arrives as `line` instead of\n // through the callback, and has to win over that default.\n // Ctrl-C in raw mode is delivered as this event rather than as a signal,\n // and without a listener readline answers it by closing — which the EOF\n // default would then read as approval. A cancelled prompt declines.\n let cancelled = false;\n rl.on(\"SIGINT\", () => {\n cancelled = true;\n rl.close();\n });\n rl.on(\"line\", resolve);\n rl.on(\"close\", () => resolve(cancelled ? \"n\" : \"\"));\n rl.question(query, (answer) => {\n resolve(answer);\n rl.close();\n });\n });\n}\n\nexport function isPackageInstalled(\n pkg: string,\n cwd: string = process.cwd(),\n): boolean {\n try {\n const pkgJsonPath = path.join(cwd, \"package.json\");\n if (fs.existsSync(pkgJsonPath)) {\n const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, \"utf8\"));\n const deps = pkgJson.dependencies || {};\n const devDeps = pkgJson.devDependencies || {};\n if (deps[pkg] || devDeps[pkg]) {\n return true;\n }\n }\n } catch {\n // Fall back to node_modules check below.\n }\n const modulePath = path.join(cwd, \"node_modules\", ...pkg.split(\"/\"));\n return fs.existsSync(modulePath);\n}\n\nexport interface InstallCommand {\n command: string;\n args: string[];\n}\n\nexport async function getInstallCommand(\n packageName: string | string[],\n cwd?: string,\n): Promise<InstallCommand> {\n const pm = await detect({ cwd });\n const packages = Array.isArray(packageName) ? packageName : [packageName];\n switch (pm) {\n case \"yarn\":\n return { command: \"yarn\", args: [\"add\", ...packages] };\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"add\", ...packages] };\n case \"bun\":\n return { command: \"bun\", args: [\"add\", ...packages] };\n default:\n return { command: \"npm\", args: [\"install\", ...packages] };\n }\n}\n\nfunction detectFromUserAgent(): PackageManagerName | undefined {\n const ua = process.env.npm_config_user_agent;\n if (!ua) return undefined;\n if (ua.startsWith(\"bun/\")) return \"bun\";\n if (ua.startsWith(\"pnpm/\")) return \"pnpm\";\n if (ua.startsWith(\"yarn/\")) return \"yarn\";\n if (ua.startsWith(\"npm/\")) return \"npm\";\n return undefined;\n}\n\nexport async function resolvePackageManagerForCwd(\n cwd: string,\n packageManager?: PackageManagerName,\n): Promise<PackageManagerName> {\n if (packageManager) return packageManager;\n const fromAgent = detectFromUserAgent();\n if (fromAgent) return fromAgent;\n try {\n return await detect({ cwd });\n } catch {\n return \"npm\";\n }\n}\n\nexport async function installPackage(\n packageName: string,\n cwd?: string,\n): Promise<boolean> {\n try {\n const { command, args } = await getInstallCommand(packageName, cwd);\n await runSpawn(command, args, cwd);\n return true;\n } catch (e) {\n if (e instanceof SpawnSignalError) throw e;\n logger.error(`Installation failed: ${String(e)}`);\n return false;\n }\n}\n"],"mappings":"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"}
|
package/dist/program.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,YAAY,YAe3B"}
|
package/dist/program.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { add } from "./commands/add.js";
|
|
2
2
|
import { agent } from "./commands/agent.js";
|
|
3
3
|
import { create } from "./commands/create.js";
|
|
4
|
+
import { cloud } from "./commands/cloud.js";
|
|
4
5
|
import { doctor } from "./commands/doctor.js";
|
|
5
6
|
import { info } from "./commands/info.js";
|
|
6
7
|
import { init } from "./commands/init.js";
|
|
@@ -10,7 +11,7 @@ import { codemodCommand, upgradeCommand } from "./commands/upgrade.js";
|
|
|
10
11
|
import { Command } from "commander";
|
|
11
12
|
//#region src/program.ts
|
|
12
13
|
function buildProgram() {
|
|
13
|
-
return new Command().name("assistant-ui").description("add components and dependencies to your project").addCommand(add).addCommand(create).addCommand(init).addCommand(mcp).addCommand(codemodCommand).addCommand(upgradeCommand).addCommand(update).addCommand(agent).addCommand(info).addCommand(doctor);
|
|
14
|
+
return new Command().name("assistant-ui").description("add components and dependencies to your project").addCommand(add).addCommand(create).addCommand(init).addCommand(mcp).addCommand(codemodCommand).addCommand(upgradeCommand).addCommand(update).addCommand(agent).addCommand(cloud).addCommand(info).addCommand(doctor);
|
|
14
15
|
}
|
|
15
16
|
//#endregion
|
|
16
17
|
export { buildProgram };
|
package/dist/program.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.js","names":[],"sources":["../src/program.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { create } from \"./commands/create\";\nimport { add } from \"./commands/add\";\nimport { codemodCommand, upgradeCommand } from \"./commands/upgrade\";\nimport { init } from \"./commands/init\";\nimport { update } from \"./commands/update\";\nimport { mcp } from \"./commands/mcp\";\nimport { agent } from \"./commands/agent\";\nimport { info } from \"./commands/info\";\nimport { doctor } from \"./commands/doctor\";\n\nexport function buildProgram() {\n return new Command()\n .name(\"assistant-ui\")\n .description(\"add components and dependencies to your project\")\n .addCommand(add)\n .addCommand(create)\n .addCommand(init)\n .addCommand(mcp)\n .addCommand(codemodCommand)\n .addCommand(upgradeCommand)\n .addCommand(update)\n .addCommand(agent)\n .addCommand(info)\n .addCommand(doctor);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"program.js","names":[],"sources":["../src/program.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { create } from \"./commands/create\";\nimport { add } from \"./commands/add\";\nimport { codemodCommand, upgradeCommand } from \"./commands/upgrade\";\nimport { init } from \"./commands/init\";\nimport { update } from \"./commands/update\";\nimport { mcp } from \"./commands/mcp\";\nimport { agent } from \"./commands/agent\";\nimport { info } from \"./commands/info\";\nimport { doctor } from \"./commands/doctor\";\nimport { cloud } from \"./commands/cloud\";\n\nexport function buildProgram() {\n return new Command()\n .name(\"assistant-ui\")\n .description(\"add components and dependencies to your project\")\n .addCommand(add)\n .addCommand(create)\n .addCommand(init)\n .addCommand(mcp)\n .addCommand(codemodCommand)\n .addCommand(upgradeCommand)\n .addCommand(update)\n .addCommand(agent)\n .addCommand(cloud)\n .addCommand(info)\n .addCommand(doctor);\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,eAAe;CAC7B,OAAO,IAAI,QAAQ,CAAC,CACjB,KAAK,cAAc,CAAC,CACpB,YAAY,iDAAiD,CAAC,CAC9D,WAAW,GAAG,CAAC,CACf,WAAW,MAAM,CAAC,CAClB,WAAW,IAAI,CAAC,CAChB,WAAW,GAAG,CAAC,CACf,WAAW,cAAc,CAAC,CAC1B,WAAW,cAAc,CAAC,CAC1B,WAAW,MAAM,CAAC,CAClB,WAAW,KAAK,CAAC,CACjB,WAAW,KAAK,CAAC,CACjB,WAAW,IAAI,CAAC,CAChB,WAAW,MAAM;AACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "assistant-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.122",
|
|
4
4
|
"description": "CLI for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -21,12 +21,14 @@
|
|
|
21
21
|
"bin",
|
|
22
22
|
"dist",
|
|
23
23
|
"src",
|
|
24
|
-
"README.md"
|
|
24
|
+
"README.md",
|
|
25
|
+
"templates/cloud-harness"
|
|
25
26
|
],
|
|
26
27
|
"sideEffects": false,
|
|
27
28
|
"dependencies": {
|
|
28
29
|
"@assistant-ui/agent-launcher": "^0.1.17",
|
|
29
30
|
"@clack/prompts": "^1.8.1",
|
|
31
|
+
"aui-auth": "^0.0.11",
|
|
30
32
|
"chalk": "^6.0.1",
|
|
31
33
|
"cli-progress": "^3.12.0",
|
|
32
34
|
"commander": "^15.0.0",
|
|
@@ -37,7 +39,9 @@
|
|
|
37
39
|
"glob": "^13.0.6",
|
|
38
40
|
"jscodeshift": "^17.4.0",
|
|
39
41
|
"jsonc-parser": "^3.3.1",
|
|
40
|
-
"
|
|
42
|
+
"react": "^19.3.0",
|
|
43
|
+
"semver": "^7.8.5",
|
|
44
|
+
"statewire": "^0.19.4"
|
|
41
45
|
},
|
|
42
46
|
"devDependencies": {
|
|
43
47
|
"@assistant-ui/x-buildutils": "0.0.30",
|
|
@@ -45,7 +49,7 @@
|
|
|
45
49
|
"@types/cross-spawn": "^6.0.6",
|
|
46
50
|
"@types/debug": "^4.1.13",
|
|
47
51
|
"@types/jscodeshift": "^17.3.0",
|
|
48
|
-
"@types/node": "^26.6.
|
|
52
|
+
"@types/node": "^26.6.4",
|
|
49
53
|
"@types/semver": "^7.8.0",
|
|
50
54
|
"@vitest/coverage-v8": "^5.0.3",
|
|
51
55
|
"vitest": "^5.0.3"
|
|
@@ -64,10 +68,10 @@
|
|
|
64
68
|
"url": "https://github.com/assistant-ui/assistant-ui/issues"
|
|
65
69
|
},
|
|
66
70
|
"scripts": {
|
|
67
|
-
"build": "aui-build",
|
|
68
|
-
"test": "vitest run",
|
|
71
|
+
"build": "aui-build && node scripts/copy-cloud-harness-template.mjs",
|
|
72
|
+
"test": "vitest run && node --test scripts/copy-cloud-harness-template.test.mjs",
|
|
73
|
+
"test:coverage": "vitest run --coverage --coverage.reporter=text --coverage.reporter=html --coverage.reporter=json-summary && node --test scripts/copy-cloud-harness-template.test.mjs",
|
|
69
74
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json",
|
|
70
|
-
"test:watch": "vitest"
|
|
71
|
-
"test:coverage": "vitest run --coverage"
|
|
75
|
+
"test:watch": "vitest"
|
|
72
76
|
}
|
|
73
77
|
}
|
package/src/commands/add.ts
CHANGED
|
@@ -6,9 +6,10 @@ import {
|
|
|
6
6
|
getComponentsJsonStyle,
|
|
7
7
|
resolveRegistryItemUrl,
|
|
8
8
|
} from "../lib/utils/registry";
|
|
9
|
-
import { dlxCommand, resolvePackageManager } from "../lib/create-project";
|
|
10
9
|
import { runSpawn, SpawnExitError, SpawnSignalError } from "../lib/run-spawn";
|
|
11
10
|
import {
|
|
11
|
+
dlxCommand,
|
|
12
|
+
resolvePackageManager,
|
|
12
13
|
type PackageManagerName,
|
|
13
14
|
resolvePackageManagerForCwd,
|
|
14
15
|
} from "../lib/utils/package-manager";
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { setupCloud, cloud } from "./cloud";
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
fetchOrganizations,
|
|
9
|
+
fetchProjects,
|
|
10
|
+
createProject,
|
|
11
|
+
cloudAccessToken,
|
|
12
|
+
provisionCloudHarness,
|
|
13
|
+
scaffold,
|
|
14
|
+
select,
|
|
15
|
+
password,
|
|
16
|
+
} = vi.hoisted(() => ({
|
|
17
|
+
fetchOrganizations: vi.fn(),
|
|
18
|
+
fetchProjects: vi.fn(),
|
|
19
|
+
createProject: vi.fn(),
|
|
20
|
+
cloudAccessToken: vi.fn(),
|
|
21
|
+
provisionCloudHarness: vi.fn(),
|
|
22
|
+
scaffold: vi.fn(),
|
|
23
|
+
select: vi.fn(),
|
|
24
|
+
password: vi.fn(),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
vi.mock("aui-auth/accounts", async (importOriginal) => ({
|
|
28
|
+
...(await importOriginal<typeof import("aui-auth/accounts")>()),
|
|
29
|
+
fetchOrganizations,
|
|
30
|
+
fetchProjects,
|
|
31
|
+
createProject,
|
|
32
|
+
}));
|
|
33
|
+
vi.mock("../lib/cloud-auth", async (importOriginal) => ({
|
|
34
|
+
...(await importOriginal<typeof import("../lib/cloud-auth")>()),
|
|
35
|
+
cloudAccessToken,
|
|
36
|
+
}));
|
|
37
|
+
vi.mock("../lib/cloud-provision", async (importOriginal) => ({
|
|
38
|
+
...(await importOriginal<typeof import("../lib/cloud-provision")>()),
|
|
39
|
+
provisionCloudHarness,
|
|
40
|
+
}));
|
|
41
|
+
vi.mock("./create", async (importOriginal) => ({
|
|
42
|
+
...(await importOriginal<typeof import("./create")>()),
|
|
43
|
+
create: { parseAsync: scaffold },
|
|
44
|
+
}));
|
|
45
|
+
vi.mock("@clack/prompts", async (importOriginal) => ({
|
|
46
|
+
...(await importOriginal<typeof import("@clack/prompts")>()),
|
|
47
|
+
select,
|
|
48
|
+
password,
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
const directories: string[] = [];
|
|
52
|
+
afterEach(async () => {
|
|
53
|
+
await Promise.all(
|
|
54
|
+
directories
|
|
55
|
+
.splice(0)
|
|
56
|
+
.map((directory) => rm(directory, { recursive: true, force: true })),
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const fixture = async () => {
|
|
61
|
+
const directory = await mkdtemp(
|
|
62
|
+
path.join(os.tmpdir(), "assistant-ui-cloud-command-"),
|
|
63
|
+
);
|
|
64
|
+
directories.push(directory);
|
|
65
|
+
cloudAccessToken.mockResolvedValue("oauth-access");
|
|
66
|
+
fetchOrganizations.mockResolvedValue([
|
|
67
|
+
{ id: "org-1", slug: "team", name: "Team" },
|
|
68
|
+
]);
|
|
69
|
+
fetchProjects.mockResolvedValue([
|
|
70
|
+
{ id: "project-1", slug: "chat", name: "Team chat" },
|
|
71
|
+
]);
|
|
72
|
+
provisionCloudHarness.mockResolvedValue({
|
|
73
|
+
project_id: "project-1",
|
|
74
|
+
workspace_id: "shared-workspace",
|
|
75
|
+
harness_id: "harness-1",
|
|
76
|
+
harness_origin: "https://harness.example.com",
|
|
77
|
+
api_origin: "https://project.example.com",
|
|
78
|
+
api_key: "cloud-server-key",
|
|
79
|
+
});
|
|
80
|
+
scaffold.mockResolvedValue(undefined);
|
|
81
|
+
return directory;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const options = {
|
|
85
|
+
backendUrl: "http://localhost:3000/api/chat",
|
|
86
|
+
apiUrl: "https://cloud.example.com",
|
|
87
|
+
yes: true,
|
|
88
|
+
skipInstall: true,
|
|
89
|
+
accessCode: "hackathon-code",
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
describe("cloud setup", () => {
|
|
93
|
+
it("selects an existing project and scaffolds a shared harness with server-only credentials", async () => {
|
|
94
|
+
const directory = await fixture();
|
|
95
|
+
await setupCloud(directory, { ...options, org: "team", project: "chat" });
|
|
96
|
+
expect(createProject).not.toHaveBeenCalled();
|
|
97
|
+
expect(scaffold).toHaveBeenCalledWith(
|
|
98
|
+
expect.arrayContaining([
|
|
99
|
+
"cloud-harness",
|
|
100
|
+
"--skip-install",
|
|
101
|
+
"--no-skills",
|
|
102
|
+
]),
|
|
103
|
+
{ from: "user" },
|
|
104
|
+
);
|
|
105
|
+
expect(provisionCloudHarness).toHaveBeenCalledWith(
|
|
106
|
+
options.apiUrl,
|
|
107
|
+
"oauth-access",
|
|
108
|
+
expect.objectContaining({
|
|
109
|
+
org_id: "org-1",
|
|
110
|
+
project_id: "project-1",
|
|
111
|
+
access_code: "hackathon-code",
|
|
112
|
+
backend_urls: [],
|
|
113
|
+
allow_localhost: true,
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
const env = await readFile(path.join(directory, ".env.local"), "utf8");
|
|
117
|
+
expect(env).toContain('ASSISTANT_API_KEY="cloud-server-key"');
|
|
118
|
+
expect(env).not.toContain("NEXT_PUBLIC_ASSISTANT_API_KEY");
|
|
119
|
+
expect(
|
|
120
|
+
await readFile(
|
|
121
|
+
path.join(directory, ".assistant-ui", "cloud.json"),
|
|
122
|
+
"utf8",
|
|
123
|
+
),
|
|
124
|
+
).not.toContain("cloud-server-key");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("does not provision again or overwrite customizations when setup is repeated", async () => {
|
|
128
|
+
const directory = await fixture();
|
|
129
|
+
await setupCloud(directory, options);
|
|
130
|
+
const envFile = path.join(directory, ".env.local");
|
|
131
|
+
const custom = `${(await readFile(envFile, "utf8")).replace(/^ASSISTANT_API_KEY=/m, "export ASSISTANT_API_KEY=")}OPENAI_API_KEY=custom-key\nCUSTOM_SETTING=keep-me\n`;
|
|
132
|
+
await writeFile(envFile, custom);
|
|
133
|
+
const before = provisionCloudHarness.mock.calls.length;
|
|
134
|
+
await setupCloud(directory, options);
|
|
135
|
+
expect(provisionCloudHarness.mock.calls.length).toBe(before);
|
|
136
|
+
expect(await readFile(envFile, "utf8")).toBe(custom);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("requires an explicit project when noninteractive users have several choices", async () => {
|
|
140
|
+
const directory = await fixture();
|
|
141
|
+
fetchProjects.mockResolvedValue([
|
|
142
|
+
{ id: "one", slug: "one", name: "One" },
|
|
143
|
+
{ id: "two", slug: "two", name: "Two" },
|
|
144
|
+
]);
|
|
145
|
+
await expect(setupCloud(directory, options)).rejects.toThrow("--project");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("reuses an organization created by an interrupted setup", async () => {
|
|
149
|
+
const directory = await fixture();
|
|
150
|
+
const before = fetchProjects.mock.calls.length;
|
|
151
|
+
await setupCloud(directory, {
|
|
152
|
+
...options,
|
|
153
|
+
newOrg: "team",
|
|
154
|
+
project: "chat",
|
|
155
|
+
});
|
|
156
|
+
expect(fetchProjects.mock.calls.slice(before)).toEqual([
|
|
157
|
+
[expect.anything(), "oauth-access", { id: "org-1" }],
|
|
158
|
+
]);
|
|
159
|
+
expect(fetchProjects).toHaveBeenCalledWith(
|
|
160
|
+
expect.anything(),
|
|
161
|
+
"oauth-access",
|
|
162
|
+
{
|
|
163
|
+
id: "org-1",
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
expect(provisionCloudHarness).toHaveBeenCalledWith(
|
|
167
|
+
options.apiUrl,
|
|
168
|
+
"oauth-access",
|
|
169
|
+
expect.objectContaining({ org_id: "org-1" }),
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("rejects a changed backend before silently reusing configured resources", async () => {
|
|
174
|
+
const directory = await fixture();
|
|
175
|
+
await setupCloud(directory, options);
|
|
176
|
+
const before = provisionCloudHarness.mock.calls.length;
|
|
177
|
+
await expect(
|
|
178
|
+
setupCloud(directory, {
|
|
179
|
+
...options,
|
|
180
|
+
backendUrl: "https://app.example.com/api/chat",
|
|
181
|
+
}),
|
|
182
|
+
).rejects.toThrow("backend allowlist in the Cloud dashboard");
|
|
183
|
+
expect(provisionCloudHarness.mock.calls.length).toBe(before);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("rejects conflicting selection flags before logging in", async () => {
|
|
187
|
+
const directory = await fixture();
|
|
188
|
+
const before = cloudAccessToken.mock.calls.length;
|
|
189
|
+
await expect(
|
|
190
|
+
setupCloud(directory, { ...options, org: "team", newOrg: "other" }),
|
|
191
|
+
).rejects.toThrow("Choose --org or --new-org");
|
|
192
|
+
expect(cloudAccessToken.mock.calls.length).toBe(before);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("rejects URL credentials and invalid organization slugs before logging in", async () => {
|
|
196
|
+
const directory = await fixture();
|
|
197
|
+
const before = cloudAccessToken.mock.calls.length;
|
|
198
|
+
await expect(
|
|
199
|
+
setupCloud(directory, {
|
|
200
|
+
...options,
|
|
201
|
+
backendUrl: "https://user:secret@app.example.com/api/chat",
|
|
202
|
+
}),
|
|
203
|
+
).rejects.toThrow("credentials");
|
|
204
|
+
await expect(
|
|
205
|
+
setupCloud(directory, { ...options, newOrg: "Bad Org!" }),
|
|
206
|
+
).rejects.toThrow("Organization slugs");
|
|
207
|
+
expect(cloudAccessToken.mock.calls.length).toBe(before);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("stops before provisioning when organization selection is cancelled", async () => {
|
|
211
|
+
const directory = await fixture();
|
|
212
|
+
fetchOrganizations.mockResolvedValue([
|
|
213
|
+
{ id: "one", slug: "one", name: "One" },
|
|
214
|
+
{ id: "two", slug: "two", name: "Two" },
|
|
215
|
+
]);
|
|
216
|
+
const prompts =
|
|
217
|
+
await vi.importActual<typeof import("@clack/prompts")>("@clack/prompts");
|
|
218
|
+
const cancelled = await prompts.select({
|
|
219
|
+
message: "Cancel test",
|
|
220
|
+
options: [{ value: "one", label: "One" }],
|
|
221
|
+
signal: AbortSignal.abort(),
|
|
222
|
+
});
|
|
223
|
+
select.mockResolvedValue(cancelled);
|
|
224
|
+
const before = provisionCloudHarness.mock.calls.length;
|
|
225
|
+
await expect(
|
|
226
|
+
setupCloud(directory, { ...options, yes: false }),
|
|
227
|
+
).rejects.toThrow();
|
|
228
|
+
expect(provisionCloudHarness.mock.calls.length).toBe(before);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("exposes login, logout, and setup as cloud commands", () => {
|
|
232
|
+
expect(cloud.commands.map((command) => command.name())).toEqual([
|
|
233
|
+
"login",
|
|
234
|
+
"logout",
|
|
235
|
+
"setup",
|
|
236
|
+
]);
|
|
237
|
+
});
|
|
238
|
+
});
|