@di-code/coding-agent 0.1.0 → 0.1.2
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 +224 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/resources/index.d.ts +3 -0
- package/dist/core/resources/index.d.ts.map +1 -0
- package/dist/core/resources/index.js +2 -0
- package/dist/core/resources/index.js.map +1 -0
- package/dist/core/resources/loader.d.ts +8 -0
- package/dist/core/resources/loader.d.ts.map +1 -0
- package/dist/core/resources/loader.js +174 -0
- package/dist/core/resources/loader.js.map +1 -0
- package/dist/core/resources/skills.d.ts +10 -0
- package/dist/core/resources/skills.d.ts.map +1 -0
- package/dist/core/resources/skills.js +167 -0
- package/dist/core/resources/skills.js.map +1 -0
- package/dist/core/resources/types.d.ts +41 -0
- package/dist/core/resources/types.d.ts.map +1 -0
- package/dist/core/resources/types.js +2 -0
- package/dist/core/resources/types.js.map +1 -0
- package/dist/core/session.d.ts +7 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/core/session.js +23 -3
- package/dist/core/session.js.map +1 -1
- package/dist/core/skill-command.d.ts +3 -0
- package/dist/core/skill-command.d.ts.map +1 -0
- package/dist/core/skill-command.js +34 -0
- package/dist/core/skill-command.js.map +1 -0
- package/dist/core/system-prompt.d.ts +6 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +57 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/extensions/runtime.d.ts +7 -4
- package/dist/extensions/runtime.d.ts.map +1 -1
- package/dist/extensions/runtime.js +45 -10
- package/dist/extensions/runtime.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +85 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive-components.d.ts.map +1 -1
- package/dist/modes/interactive-components.js +4 -0
- package/dist/modes/interactive-components.js.map +1 -1
- package/dist/modes/interactive-state.js +1 -1
- package/dist/modes/interactive-state.js.map +1 -1
- package/dist/modes/interactive.d.ts +4 -0
- package/dist/modes/interactive.d.ts.map +1 -1
- package/dist/modes/interactive.js +26 -5
- package/dist/modes/interactive.js.map +1 -1
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/loader.d.ts +18 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +92 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manager.d.ts +23 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +152 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/manifest.d.ts +7 -0
- package/dist/plugins/manifest.d.ts.map +1 -0
- package/dist/plugins/manifest.js +116 -0
- package/dist/plugins/manifest.js.map +1 -0
- package/dist/plugins/types.d.ts +41 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/provider-onboarding.d.ts.map +1 -1
- package/dist/provider-onboarding.js +13 -1
- package/dist/provider-onboarding.js.map +1 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +37 -15
- package/dist/startup.js.map +1 -1
- package/package.json +24 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/plugins/loader.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { createJiti } from \"jiti\";\nimport { type ExtensionHost, loadExtensions } from \"../extensions/runtime.ts\";\nimport type { ProjectTrustManager } from \"../extensions/trust.ts\";\nimport type { ExtensionFactory } from \"../extensions/types.ts\";\nimport { PluginManager } from \"./manager.ts\";\nimport { readPackagePluginManifest, readPluginManifest, resolvePluginEntry } from \"./manifest.ts\";\nimport type { DiscoveredPlugin, PluginDiagnostic } from \"./types.ts\";\n\nexport interface PluginLoadOptions {\n\treadonly cwd: string;\n\treadonly agentDir?: string;\n\treadonly projectTrusted?: boolean;\n\treadonly trustManager?: ProjectTrustManager;\n\treadonly mode?: \"interactive\" | \"print\" | \"json\";\n\treadonly explicitPaths?: readonly string[];\n}\n\nexport interface PluginLoadResult {\n\treadonly host: ExtensionHost;\n\treadonly loaded: readonly DiscoveredPlugin[];\n\treadonly diagnostics: readonly PluginDiagnostic[];\n}\n\nasync function isPluginPackage(root: string): Promise<boolean> {\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(await readFile(join(root, \"package.json\"), \"utf8\"));\n\t\treturn typeof parsed === \"object\" && parsed !== null && \"diCode\" in parsed;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function discoverPluginRoots(cwd: string, agentDir: string, trusted: boolean): Promise<string[]> {\n\tconst roots = [...(trusted ? [join(cwd, \".di-code\", \"plugins\")] : []), join(agentDir, \"plugins\", \"installed\")];\n\tconst result: string[] = [];\n\tfor (const root of roots) {\n\t\tif (!existsSync(root)) continue;\n\t\tfor (const entry of await readdir(root, { withFileTypes: true })) {\n\t\t\tif (!entry.isDirectory()) continue;\n\t\t\tconst pluginRoot = join(root, entry.name);\n\t\t\tif (existsSync(join(pluginRoot, \"plugin.json\")) || (await isPluginPackage(pluginRoot)))\n\t\t\t\tresult.push(resolve(pluginRoot));\n\t\t}\n\t}\n\treturn result.sort((a, b) => a.localeCompare(b));\n}\n\nexport async function loadPlugins(options: PluginLoadOptions): Promise<PluginLoadResult> {\n\tconst cwd = resolve(options.cwd);\n\tconst agentDir = resolve(options.agentDir ?? join(cwd, \".di-code\"));\n\tconst trusted =\n\t\toptions.projectTrusted ?? (options.trustManager ? (await options.trustManager.get(cwd)) === true : false);\n\tconst extensionResult = await loadExtensions({\n\t\tcwd,\n\t\tprojectTrusted: trusted,\n\t\ttrustManager: options.trustManager,\n\t\tmode: options.mode,\n\t\tpaths: options.explicitPaths,\n\t});\n\tconst diagnostics: PluginDiagnostic[] = extensionResult.diagnostics.map((diagnostic) => ({\n\t\tsourcePath: diagnostic.path,\n\t\tstage: diagnostic.stage,\n\t\tseverity: \"error\",\n\t\tmessage: diagnostic.message,\n\t}));\n\tconst enabledGlobal = new Set(\n\t\t(await new PluginManager({ agentDir }).list()).filter((plugin) => plugin.enabled).map((plugin) => plugin.id),\n\t);\n\tconst pluginRoots = await discoverPluginRoots(cwd, agentDir, trusted);\n\tconst loaded: DiscoveredPlugin[] = [];\n\tconst jiti = createJiti(import.meta.url, { moduleCache: false });\n\tfor (const root of pluginRoots) {\n\t\tconst manifestPath = join(root, \"plugin.json\");\n\t\tlet manifest: Awaited<ReturnType<typeof readPluginManifest>>;\n\t\ttry {\n\t\t\tmanifest = await readPluginManifest(manifestPath).catch(async () => readPackagePluginManifest(root));\n\t\t} catch (cause) {\n\t\t\tdiagnostics.push({\n\t\t\t\tsourcePath: manifestPath,\n\t\t\t\tstage: \"manifest\",\n\t\t\t\tseverity: \"error\",\n\t\t\t\tmessage: cause instanceof Error ? cause.message : String(cause),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst projectLocal = root.startsWith(resolve(cwd, \".di-code\", \"plugins\"));\n\t\tif (!projectLocal && !enabledGlobal.has(manifest.id)) continue;\n\t\ttry {\n\t\t\tconst entry = await resolvePluginEntry(root, manifest.entry);\n\t\t\tconst module = await jiti.import<{ default?: unknown }>(entry);\n\t\t\tif (typeof module.default !== \"function\") throw new Error(\"plugin entry must export a default factory function\");\n\t\t\tawait extensionResult.host.registerExtension(entry, module.default as ExtensionFactory, manifest.id);\n\t\t\tloaded.push({ manifest, root, sourcePath: manifestPath, projectLocal });\n\t\t} catch (cause) {\n\t\t\tdiagnostics.push({\n\t\t\t\tpluginId: manifest.id,\n\t\t\t\tsourcePath: manifestPath,\n\t\t\t\tstage: \"import\",\n\t\t\t\tseverity: \"error\",\n\t\t\t\tmessage: cause instanceof Error ? cause.message : String(cause),\n\t\t\t});\n\t\t}\n\t}\n\treturn { host: extensionResult.host, loaded, diagnostics };\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ManagedPlugin } from "./types.ts";
|
|
2
|
+
export interface PluginManagerOptions {
|
|
3
|
+
readonly agentDir: string;
|
|
4
|
+
readonly now?: () => Date;
|
|
5
|
+
}
|
|
6
|
+
export declare class PluginManager {
|
|
7
|
+
private readonly registryPath;
|
|
8
|
+
private readonly installRoot;
|
|
9
|
+
private readonly now;
|
|
10
|
+
constructor(options: PluginManagerOptions);
|
|
11
|
+
list(): Promise<readonly ManagedPlugin[]>;
|
|
12
|
+
enable(id: string): Promise<ManagedPlugin>;
|
|
13
|
+
disable(id: string): Promise<ManagedPlugin>;
|
|
14
|
+
remove(id: string): Promise<void>;
|
|
15
|
+
installLocal(sourcePath: string): Promise<ManagedPlugin>;
|
|
16
|
+
install(source: string): Promise<ManagedPlugin>;
|
|
17
|
+
update(id: string): Promise<ManagedPlugin>;
|
|
18
|
+
private installCopied;
|
|
19
|
+
private setEnabled;
|
|
20
|
+
private readRegistry;
|
|
21
|
+
private writeRegistry;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/plugins/manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,YAAY,CAAC;AAEhE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAgBD,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;gBACrB,OAAO,EAAE,oBAAoB;IAKnC,IAAI,IAAI,OAAO,CAAC,SAAS,aAAa,EAAE,CAAC;IAGzC,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAG1C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAG3C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAuBxD,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAwB/C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;YAMlC,aAAa;YAuBb,UAAU;YASV,YAAY;YAQZ,aAAa;CAM3B"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { cp, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { readPackagePluginManifest, readPluginManifest } from "./manifest.js";
|
|
5
|
+
function emptyRegistry() {
|
|
6
|
+
return { version: 1, plugins: {} };
|
|
7
|
+
}
|
|
8
|
+
function isRegistry(value) {
|
|
9
|
+
if (typeof value !== "object" || value === null)
|
|
10
|
+
return false;
|
|
11
|
+
const candidate = value;
|
|
12
|
+
return candidate.version === 1 && typeof candidate.plugins === "object" && candidate.plugins !== null;
|
|
13
|
+
}
|
|
14
|
+
function assertManagedPath(target, root) {
|
|
15
|
+
const child = relative(resolve(root), resolve(target));
|
|
16
|
+
if (!child || child.startsWith("..") || isAbsolute(child))
|
|
17
|
+
throw new Error("plugin path is outside the managed install directory");
|
|
18
|
+
}
|
|
19
|
+
export class PluginManager {
|
|
20
|
+
registryPath;
|
|
21
|
+
installRoot;
|
|
22
|
+
now;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.registryPath = resolve(options.agentDir, "plugins", "registry.json");
|
|
25
|
+
this.installRoot = resolve(options.agentDir, "plugins", "installed");
|
|
26
|
+
this.now = options.now ?? (() => new Date());
|
|
27
|
+
}
|
|
28
|
+
async list() {
|
|
29
|
+
return Object.values((await this.readRegistry()).plugins).sort((a, b) => a.id.localeCompare(b.id));
|
|
30
|
+
}
|
|
31
|
+
async enable(id) {
|
|
32
|
+
return this.setEnabled(id, true);
|
|
33
|
+
}
|
|
34
|
+
async disable(id) {
|
|
35
|
+
return this.setEnabled(id, false);
|
|
36
|
+
}
|
|
37
|
+
async remove(id) {
|
|
38
|
+
const registry = await this.readRegistry();
|
|
39
|
+
const plugin = registry.plugins[id];
|
|
40
|
+
if (!plugin)
|
|
41
|
+
throw new Error(`Unknown plugin: ${id}`);
|
|
42
|
+
assertManagedPath(plugin.installedPath, this.installRoot);
|
|
43
|
+
await rm(plugin.installedPath, { recursive: true, force: true });
|
|
44
|
+
delete registry.plugins[id];
|
|
45
|
+
await this.writeRegistry(registry);
|
|
46
|
+
}
|
|
47
|
+
async installLocal(sourcePath) {
|
|
48
|
+
const source = resolve(sourcePath);
|
|
49
|
+
const manifest = await readPluginManifest(join(source, "plugin.json")).catch(() => readPackagePluginManifest(source));
|
|
50
|
+
const destination = resolve(this.installRoot, manifest.id);
|
|
51
|
+
assertManagedPath(destination, this.installRoot);
|
|
52
|
+
await mkdir(this.installRoot, { recursive: true });
|
|
53
|
+
await rm(destination, { recursive: true, force: true });
|
|
54
|
+
await cp(source, destination, { recursive: true, force: false, errorOnExist: false });
|
|
55
|
+
const plugin = {
|
|
56
|
+
id: manifest.id,
|
|
57
|
+
source,
|
|
58
|
+
installedPath: destination,
|
|
59
|
+
enabled: true,
|
|
60
|
+
installedAt: this.now().toISOString(),
|
|
61
|
+
manifest,
|
|
62
|
+
};
|
|
63
|
+
const registry = await this.readRegistry();
|
|
64
|
+
registry.plugins[plugin.id] = plugin;
|
|
65
|
+
await this.writeRegistry(registry);
|
|
66
|
+
return plugin;
|
|
67
|
+
}
|
|
68
|
+
async install(source) {
|
|
69
|
+
if (!source.startsWith("npm:") && !source.startsWith("git:"))
|
|
70
|
+
return this.installLocal(source);
|
|
71
|
+
const staging = resolve(this.installRoot, `.staging-${process.pid}-${Date.now()}`);
|
|
72
|
+
await mkdir(staging, { recursive: true });
|
|
73
|
+
try {
|
|
74
|
+
if (source.startsWith("npm:")) {
|
|
75
|
+
await runCommand("npm", ["install", "--ignore-scripts", "--prefix", staging, source.slice(4)], this.installRoot);
|
|
76
|
+
const modules = join(staging, "node_modules");
|
|
77
|
+
const packageName = source.slice(4).replace(/@[^@]+$/, "");
|
|
78
|
+
const sourceRoot = join(modules, packageName);
|
|
79
|
+
return await this.installCopied(sourceRoot, source, staging);
|
|
80
|
+
}
|
|
81
|
+
await rm(staging, { recursive: true, force: true });
|
|
82
|
+
await runCommand("git", ["clone", "--depth", "1", source.slice(4), staging], this.installRoot);
|
|
83
|
+
return await this.installCopied(staging, source, staging);
|
|
84
|
+
}
|
|
85
|
+
catch (cause) {
|
|
86
|
+
await rm(staging, { recursive: true, force: true });
|
|
87
|
+
throw cause;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async update(id) {
|
|
91
|
+
const plugin = (await this.readRegistry()).plugins[id];
|
|
92
|
+
if (!plugin)
|
|
93
|
+
throw new Error(`Unknown plugin: ${id}`);
|
|
94
|
+
const updated = await this.install(plugin.source);
|
|
95
|
+
return plugin.enabled ? updated : this.disable(updated.id);
|
|
96
|
+
}
|
|
97
|
+
async installCopied(sourceRoot, source, temporaryRoot) {
|
|
98
|
+
const manifest = await readPluginManifest(join(sourceRoot, "plugin.json")).catch(() => readPackagePluginManifest(sourceRoot));
|
|
99
|
+
const destination = resolve(this.installRoot, manifest.id);
|
|
100
|
+
assertManagedPath(destination, this.installRoot);
|
|
101
|
+
await mkdir(this.installRoot, { recursive: true });
|
|
102
|
+
await rm(destination, { recursive: true, force: true });
|
|
103
|
+
await cp(sourceRoot, destination, { recursive: true, force: false, errorOnExist: false });
|
|
104
|
+
if (resolve(temporaryRoot) !== resolve(sourceRoot))
|
|
105
|
+
await rm(temporaryRoot, { recursive: true, force: true });
|
|
106
|
+
const plugin = {
|
|
107
|
+
id: manifest.id,
|
|
108
|
+
source,
|
|
109
|
+
installedPath: destination,
|
|
110
|
+
enabled: true,
|
|
111
|
+
installedAt: this.now().toISOString(),
|
|
112
|
+
manifest,
|
|
113
|
+
};
|
|
114
|
+
const registry = await this.readRegistry();
|
|
115
|
+
registry.plugins[plugin.id] = plugin;
|
|
116
|
+
await this.writeRegistry(registry);
|
|
117
|
+
return plugin;
|
|
118
|
+
}
|
|
119
|
+
async setEnabled(id, enabled) {
|
|
120
|
+
const registry = await this.readRegistry();
|
|
121
|
+
const plugin = registry.plugins[id];
|
|
122
|
+
if (!plugin)
|
|
123
|
+
throw new Error(`Unknown plugin: ${id}`);
|
|
124
|
+
const next = { ...plugin, enabled };
|
|
125
|
+
registry.plugins[id] = next;
|
|
126
|
+
await this.writeRegistry(registry);
|
|
127
|
+
return next;
|
|
128
|
+
}
|
|
129
|
+
async readRegistry() {
|
|
130
|
+
try {
|
|
131
|
+
const value = JSON.parse(await readFile(this.registryPath, "utf8"));
|
|
132
|
+
return isRegistry(value) ? { version: 1, plugins: { ...value.plugins } } : emptyRegistry();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return emptyRegistry();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async writeRegistry(registry) {
|
|
139
|
+
await mkdir(dirname(this.registryPath), { recursive: true });
|
|
140
|
+
const temporary = `${this.registryPath}.tmp-${process.pid}`;
|
|
141
|
+
await writeFile(temporary, `${JSON.stringify(registry, null, 2)}\n`, "utf8");
|
|
142
|
+
await rename(temporary, this.registryPath);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function runCommand(command, args, cwd) {
|
|
146
|
+
await new Promise((resolveResult, reject) => {
|
|
147
|
+
const child = spawn(command, [...args], { cwd, stdio: "ignore" });
|
|
148
|
+
child.once("error", reject);
|
|
149
|
+
child.once("close", (code) => code === 0 ? resolveResult() : reject(new Error(`${command} plugin install failed`)));
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/plugins/manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn } from \"node:child_process\";\nimport { cp, mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { readPackagePluginManifest, readPluginManifest } from \"./manifest.ts\";\nimport type { ManagedPlugin, PluginRegistry } from \"./types.ts\";\n\nexport interface PluginManagerOptions {\n\treadonly agentDir: string;\n\treadonly now?: () => Date;\n}\n\nfunction emptyRegistry(): PluginRegistry {\n\treturn { version: 1, plugins: {} };\n}\nfunction isRegistry(value: unknown): value is PluginRegistry {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = value as { version?: unknown; plugins?: unknown };\n\treturn candidate.version === 1 && typeof candidate.plugins === \"object\" && candidate.plugins !== null;\n}\nfunction assertManagedPath(target: string, root: string): void {\n\tconst child = relative(resolve(root), resolve(target));\n\tif (!child || child.startsWith(\"..\") || isAbsolute(child))\n\t\tthrow new Error(\"plugin path is outside the managed install directory\");\n}\n\nexport class PluginManager {\n\tprivate readonly registryPath: string;\n\tprivate readonly installRoot: string;\n\tprivate readonly now: () => Date;\n\tconstructor(options: PluginManagerOptions) {\n\t\tthis.registryPath = resolve(options.agentDir, \"plugins\", \"registry.json\");\n\t\tthis.installRoot = resolve(options.agentDir, \"plugins\", \"installed\");\n\t\tthis.now = options.now ?? (() => new Date());\n\t}\n\tasync list(): Promise<readonly ManagedPlugin[]> {\n\t\treturn Object.values((await this.readRegistry()).plugins).sort((a, b) => a.id.localeCompare(b.id));\n\t}\n\tasync enable(id: string): Promise<ManagedPlugin> {\n\t\treturn this.setEnabled(id, true);\n\t}\n\tasync disable(id: string): Promise<ManagedPlugin> {\n\t\treturn this.setEnabled(id, false);\n\t}\n\tasync remove(id: string): Promise<void> {\n\t\tconst registry = await this.readRegistry();\n\t\tconst plugin = registry.plugins[id];\n\t\tif (!plugin) throw new Error(`Unknown plugin: ${id}`);\n\t\tassertManagedPath(plugin.installedPath, this.installRoot);\n\t\tawait rm(plugin.installedPath, { recursive: true, force: true });\n\t\tdelete registry.plugins[id];\n\t\tawait this.writeRegistry(registry);\n\t}\n\tasync installLocal(sourcePath: string): Promise<ManagedPlugin> {\n\t\tconst source = resolve(sourcePath);\n\t\tconst manifest = await readPluginManifest(join(source, \"plugin.json\")).catch(() =>\n\t\t\treadPackagePluginManifest(source),\n\t\t);\n\t\tconst destination = resolve(this.installRoot, manifest.id);\n\t\tassertManagedPath(destination, this.installRoot);\n\t\tawait mkdir(this.installRoot, { recursive: true });\n\t\tawait rm(destination, { recursive: true, force: true });\n\t\tawait cp(source, destination, { recursive: true, force: false, errorOnExist: false });\n\t\tconst plugin: ManagedPlugin = {\n\t\t\tid: manifest.id,\n\t\t\tsource,\n\t\t\tinstalledPath: destination,\n\t\t\tenabled: true,\n\t\t\tinstalledAt: this.now().toISOString(),\n\t\t\tmanifest,\n\t\t};\n\t\tconst registry = await this.readRegistry();\n\t\tregistry.plugins[plugin.id] = plugin;\n\t\tawait this.writeRegistry(registry);\n\t\treturn plugin;\n\t}\n\tasync install(source: string): Promise<ManagedPlugin> {\n\t\tif (!source.startsWith(\"npm:\") && !source.startsWith(\"git:\")) return this.installLocal(source);\n\t\tconst staging = resolve(this.installRoot, `.staging-${process.pid}-${Date.now()}`);\n\t\tawait mkdir(staging, { recursive: true });\n\t\ttry {\n\t\t\tif (source.startsWith(\"npm:\")) {\n\t\t\t\tawait runCommand(\n\t\t\t\t\t\"npm\",\n\t\t\t\t\t[\"install\", \"--ignore-scripts\", \"--prefix\", staging, source.slice(4)],\n\t\t\t\t\tthis.installRoot,\n\t\t\t\t);\n\t\t\t\tconst modules = join(staging, \"node_modules\");\n\t\t\t\tconst packageName = source.slice(4).replace(/@[^@]+$/, \"\");\n\t\t\t\tconst sourceRoot = join(modules, packageName);\n\t\t\t\treturn await this.installCopied(sourceRoot, source, staging);\n\t\t\t}\n\t\t\tawait rm(staging, { recursive: true, force: true });\n\t\t\tawait runCommand(\"git\", [\"clone\", \"--depth\", \"1\", source.slice(4), staging], this.installRoot);\n\t\t\treturn await this.installCopied(staging, source, staging);\n\t\t} catch (cause) {\n\t\t\tawait rm(staging, { recursive: true, force: true });\n\t\t\tthrow cause;\n\t\t}\n\t}\n\tasync update(id: string): Promise<ManagedPlugin> {\n\t\tconst plugin = (await this.readRegistry()).plugins[id];\n\t\tif (!plugin) throw new Error(`Unknown plugin: ${id}`);\n\t\tconst updated = await this.install(plugin.source);\n\t\treturn plugin.enabled ? updated : this.disable(updated.id);\n\t}\n\tprivate async installCopied(sourceRoot: string, source: string, temporaryRoot: string): Promise<ManagedPlugin> {\n\t\tconst manifest = await readPluginManifest(join(sourceRoot, \"plugin.json\")).catch(() =>\n\t\t\treadPackagePluginManifest(sourceRoot),\n\t\t);\n\t\tconst destination = resolve(this.installRoot, manifest.id);\n\t\tassertManagedPath(destination, this.installRoot);\n\t\tawait mkdir(this.installRoot, { recursive: true });\n\t\tawait rm(destination, { recursive: true, force: true });\n\t\tawait cp(sourceRoot, destination, { recursive: true, force: false, errorOnExist: false });\n\t\tif (resolve(temporaryRoot) !== resolve(sourceRoot)) await rm(temporaryRoot, { recursive: true, force: true });\n\t\tconst plugin: ManagedPlugin = {\n\t\t\tid: manifest.id,\n\t\t\tsource,\n\t\t\tinstalledPath: destination,\n\t\t\tenabled: true,\n\t\t\tinstalledAt: this.now().toISOString(),\n\t\t\tmanifest,\n\t\t};\n\t\tconst registry = await this.readRegistry();\n\t\tregistry.plugins[plugin.id] = plugin;\n\t\tawait this.writeRegistry(registry);\n\t\treturn plugin;\n\t}\n\tprivate async setEnabled(id: string, enabled: boolean): Promise<ManagedPlugin> {\n\t\tconst registry = await this.readRegistry();\n\t\tconst plugin = registry.plugins[id];\n\t\tif (!plugin) throw new Error(`Unknown plugin: ${id}`);\n\t\tconst next = { ...plugin, enabled };\n\t\tregistry.plugins[id] = next;\n\t\tawait this.writeRegistry(registry);\n\t\treturn next;\n\t}\n\tprivate async readRegistry(): Promise<PluginRegistry> {\n\t\ttry {\n\t\t\tconst value: unknown = JSON.parse(await readFile(this.registryPath, \"utf8\"));\n\t\t\treturn isRegistry(value) ? { version: 1, plugins: { ...value.plugins } } : emptyRegistry();\n\t\t} catch {\n\t\t\treturn emptyRegistry();\n\t\t}\n\t}\n\tprivate async writeRegistry(registry: PluginRegistry): Promise<void> {\n\t\tawait mkdir(dirname(this.registryPath), { recursive: true });\n\t\tconst temporary = `${this.registryPath}.tmp-${process.pid}`;\n\t\tawait writeFile(temporary, `${JSON.stringify(registry, null, 2)}\\n`, \"utf8\");\n\t\tawait rename(temporary, this.registryPath);\n\t}\n}\n\nasync function runCommand(command: string, args: readonly string[], cwd: string): Promise<void> {\n\tawait new Promise<void>((resolveResult, reject) => {\n\t\tconst child = spawn(command, [...args], { cwd, stdio: \"ignore\" });\n\t\tchild.once(\"error\", reject);\n\t\tchild.once(\"close\", (code) =>\n\t\t\tcode === 0 ? resolveResult() : reject(new Error(`${command} plugin install failed`)),\n\t\t);\n\t});\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PluginManifest } from "./types.ts";
|
|
2
|
+
export declare function parsePluginManifest(value: unknown): PluginManifest;
|
|
3
|
+
export declare function readPluginManifest(manifestPath: string): Promise<PluginManifest>;
|
|
4
|
+
export declare function readPackagePluginManifest(root: string): Promise<PluginManifest>;
|
|
5
|
+
export declare function resolvePluginEntry(root: string, entry: string): Promise<string>;
|
|
6
|
+
export declare function pluginRootFromManifest(manifestPath: string): string;
|
|
7
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/plugins/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,cAAc,EAA0B,MAAM,YAAY,CAAC;AA4C7F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAgBlE;AAED,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAQtF;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAqBrF;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBrF;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEnE"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
import { PLUGIN_API_VERSION } from "./types.js";
|
|
4
|
+
const PLUGIN_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
5
|
+
const COMMAND_NAME = /^[a-zA-Z0-9][a-zA-Z0-9-]*$/;
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function stringField(value, name) {
|
|
10
|
+
const field = value[name];
|
|
11
|
+
if (typeof field !== "string" || field.trim() === "")
|
|
12
|
+
throw new Error(`plugin manifest ${name} must be a non-empty string`);
|
|
13
|
+
return field;
|
|
14
|
+
}
|
|
15
|
+
function stringList(value, name) {
|
|
16
|
+
if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string" && entry.trim() !== ""))
|
|
17
|
+
throw new Error(`plugin manifest ${name} must be an array of non-empty strings`);
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function parsePermissions(value) {
|
|
21
|
+
if (!isRecord(value))
|
|
22
|
+
throw new Error("plugin manifest permissions must be an object");
|
|
23
|
+
const filesystem = value.filesystem;
|
|
24
|
+
if (filesystem !== "none" && filesystem !== "read-project")
|
|
25
|
+
throw new Error('plugin manifest permissions.filesystem must be "none" or "read-project"');
|
|
26
|
+
const network = stringList(value.network, "permissions.network");
|
|
27
|
+
if (!network.every((url) => {
|
|
28
|
+
try {
|
|
29
|
+
return new URL(url).protocol === "https:";
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}))
|
|
35
|
+
throw new Error("plugin manifest permissions.network only permits absolute HTTPS URLs");
|
|
36
|
+
const process = stringList(value.process, "permissions.process");
|
|
37
|
+
if (!process.every((command) => COMMAND_NAME.test(command)))
|
|
38
|
+
throw new Error("plugin manifest permissions.process only permits exact command names");
|
|
39
|
+
return { filesystem, network, process };
|
|
40
|
+
}
|
|
41
|
+
export function parsePluginManifest(value) {
|
|
42
|
+
if (!isRecord(value))
|
|
43
|
+
throw new Error("plugin manifest must be an object");
|
|
44
|
+
if (value.apiVersion !== PLUGIN_API_VERSION)
|
|
45
|
+
throw new Error(`plugin API version must be ${PLUGIN_API_VERSION}`);
|
|
46
|
+
const id = stringField(value, "id");
|
|
47
|
+
if (id.length > 64 || !PLUGIN_ID.test(id))
|
|
48
|
+
throw new Error("plugin manifest id must use lowercase letters, numbers, and single hyphens");
|
|
49
|
+
const entry = stringField(value, "entry");
|
|
50
|
+
if (isAbsolute(entry))
|
|
51
|
+
throw new Error("plugin manifest entry must be relative to the plugin root");
|
|
52
|
+
return {
|
|
53
|
+
apiVersion: PLUGIN_API_VERSION,
|
|
54
|
+
id,
|
|
55
|
+
name: stringField(value, "name"),
|
|
56
|
+
version: stringField(value, "version"),
|
|
57
|
+
entry,
|
|
58
|
+
permissions: parsePermissions(value.permissions),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export async function readPluginManifest(manifestPath) {
|
|
62
|
+
let parsed;
|
|
63
|
+
try {
|
|
64
|
+
parsed = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error("plugin manifest is not valid JSON");
|
|
68
|
+
}
|
|
69
|
+
return parsePluginManifest(parsed);
|
|
70
|
+
}
|
|
71
|
+
export async function readPackagePluginManifest(root) {
|
|
72
|
+
let packageJson;
|
|
73
|
+
try {
|
|
74
|
+
packageJson = JSON.parse(await readFile(resolve(root, "package.json"), "utf8"));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
throw new Error("plugin package.json is not valid JSON");
|
|
78
|
+
}
|
|
79
|
+
if (!isRecord(packageJson) || !isRecord(packageJson.diCode))
|
|
80
|
+
throw new Error("plugin package.json must include a diCode object");
|
|
81
|
+
const diCode = packageJson.diCode;
|
|
82
|
+
const entries = diCode.plugins;
|
|
83
|
+
if (!Array.isArray(entries) || entries.length !== 1 || typeof entries[0] !== "string")
|
|
84
|
+
throw new Error("plugin package diCode.plugins must contain exactly one entry");
|
|
85
|
+
return parsePluginManifest({
|
|
86
|
+
apiVersion: diCode.apiVersion,
|
|
87
|
+
id: typeof packageJson.name === "string" ? packageJson.name.replace(/^@[^/]+\//, "") : "package-plugin",
|
|
88
|
+
name: packageJson.name,
|
|
89
|
+
version: packageJson.version,
|
|
90
|
+
entry: entries[0],
|
|
91
|
+
permissions: diCode.permissions ?? { filesystem: "none", network: [], process: [] },
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export async function resolvePluginEntry(root, entry) {
|
|
95
|
+
const resolvedRoot = await realpath(root);
|
|
96
|
+
const candidate = resolve(resolvedRoot, entry);
|
|
97
|
+
const relativeCandidate = relative(resolvedRoot, candidate);
|
|
98
|
+
if (relativeCandidate.startsWith("..") || relativeCandidate === "")
|
|
99
|
+
throw new Error("plugin entry must stay inside the plugin root");
|
|
100
|
+
let resolvedEntry;
|
|
101
|
+
try {
|
|
102
|
+
resolvedEntry = await realpath(candidate);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new Error("plugin entry does not exist");
|
|
106
|
+
}
|
|
107
|
+
if (relative(resolvedRoot, resolvedEntry).startsWith(".."))
|
|
108
|
+
throw new Error("plugin entry symlink escapes the plugin root");
|
|
109
|
+
if (!(await lstat(resolvedEntry)).isFile())
|
|
110
|
+
throw new Error("plugin entry must be a file");
|
|
111
|
+
return resolvedEntry;
|
|
112
|
+
}
|
|
113
|
+
export function pluginRootFromManifest(manifestPath) {
|
|
114
|
+
return dirname(manifestPath);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/plugins/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstat, readFile, realpath } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport { PLUGIN_API_VERSION, type PluginManifest, type PluginPermissions } from \"./types.ts\";\n\nconst PLUGIN_ID = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst COMMAND_NAME = /^[a-zA-Z0-9][a-zA-Z0-9-]*$/;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(value: Record<string, unknown>, name: string): string {\n\tconst field = value[name];\n\tif (typeof field !== \"string\" || field.trim() === \"\")\n\t\tthrow new Error(`plugin manifest ${name} must be a non-empty string`);\n\treturn field;\n}\n\nfunction stringList(value: unknown, name: string): readonly string[] {\n\tif (!Array.isArray(value) || !value.every((entry) => typeof entry === \"string\" && entry.trim() !== \"\"))\n\t\tthrow new Error(`plugin manifest ${name} must be an array of non-empty strings`);\n\treturn value;\n}\n\nfunction parsePermissions(value: unknown): PluginPermissions {\n\tif (!isRecord(value)) throw new Error(\"plugin manifest permissions must be an object\");\n\tconst filesystem = value.filesystem;\n\tif (filesystem !== \"none\" && filesystem !== \"read-project\")\n\t\tthrow new Error('plugin manifest permissions.filesystem must be \"none\" or \"read-project\"');\n\tconst network = stringList(value.network, \"permissions.network\");\n\tif (\n\t\t!network.every((url) => {\n\t\t\ttry {\n\t\t\t\treturn new URL(url).protocol === \"https:\";\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t})\n\t)\n\t\tthrow new Error(\"plugin manifest permissions.network only permits absolute HTTPS URLs\");\n\tconst process = stringList(value.process, \"permissions.process\");\n\tif (!process.every((command) => COMMAND_NAME.test(command)))\n\t\tthrow new Error(\"plugin manifest permissions.process only permits exact command names\");\n\treturn { filesystem, network, process };\n}\n\nexport function parsePluginManifest(value: unknown): PluginManifest {\n\tif (!isRecord(value)) throw new Error(\"plugin manifest must be an object\");\n\tif (value.apiVersion !== PLUGIN_API_VERSION) throw new Error(`plugin API version must be ${PLUGIN_API_VERSION}`);\n\tconst id = stringField(value, \"id\");\n\tif (id.length > 64 || !PLUGIN_ID.test(id))\n\t\tthrow new Error(\"plugin manifest id must use lowercase letters, numbers, and single hyphens\");\n\tconst entry = stringField(value, \"entry\");\n\tif (isAbsolute(entry)) throw new Error(\"plugin manifest entry must be relative to the plugin root\");\n\treturn {\n\t\tapiVersion: PLUGIN_API_VERSION,\n\t\tid,\n\t\tname: stringField(value, \"name\"),\n\t\tversion: stringField(value, \"version\"),\n\t\tentry,\n\t\tpermissions: parsePermissions(value.permissions),\n\t};\n}\n\nexport async function readPluginManifest(manifestPath: string): Promise<PluginManifest> {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(await readFile(manifestPath, \"utf8\"));\n\t} catch {\n\t\tthrow new Error(\"plugin manifest is not valid JSON\");\n\t}\n\treturn parsePluginManifest(parsed);\n}\n\nexport async function readPackagePluginManifest(root: string): Promise<PluginManifest> {\n\tlet packageJson: unknown;\n\ttry {\n\t\tpackageJson = JSON.parse(await readFile(resolve(root, \"package.json\"), \"utf8\"));\n\t} catch {\n\t\tthrow new Error(\"plugin package.json is not valid JSON\");\n\t}\n\tif (!isRecord(packageJson) || !isRecord(packageJson.diCode))\n\t\tthrow new Error(\"plugin package.json must include a diCode object\");\n\tconst diCode = packageJson.diCode;\n\tconst entries = diCode.plugins;\n\tif (!Array.isArray(entries) || entries.length !== 1 || typeof entries[0] !== \"string\")\n\t\tthrow new Error(\"plugin package diCode.plugins must contain exactly one entry\");\n\treturn parsePluginManifest({\n\t\tapiVersion: diCode.apiVersion,\n\t\tid: typeof packageJson.name === \"string\" ? packageJson.name.replace(/^@[^/]+\\//, \"\") : \"package-plugin\",\n\t\tname: packageJson.name,\n\t\tversion: packageJson.version,\n\t\tentry: entries[0],\n\t\tpermissions: diCode.permissions ?? { filesystem: \"none\", network: [], process: [] },\n\t});\n}\n\nexport async function resolvePluginEntry(root: string, entry: string): Promise<string> {\n\tconst resolvedRoot = await realpath(root);\n\tconst candidate = resolve(resolvedRoot, entry);\n\tconst relativeCandidate = relative(resolvedRoot, candidate);\n\tif (relativeCandidate.startsWith(\"..\") || relativeCandidate === \"\")\n\t\tthrow new Error(\"plugin entry must stay inside the plugin root\");\n\tlet resolvedEntry: string;\n\ttry {\n\t\tresolvedEntry = await realpath(candidate);\n\t} catch {\n\t\tthrow new Error(\"plugin entry does not exist\");\n\t}\n\tif (relative(resolvedRoot, resolvedEntry).startsWith(\"..\"))\n\t\tthrow new Error(\"plugin entry symlink escapes the plugin root\");\n\tif (!(await lstat(resolvedEntry)).isFile()) throw new Error(\"plugin entry must be a file\");\n\treturn resolvedEntry;\n}\n\nexport function pluginRootFromManifest(manifestPath: string): string {\n\treturn dirname(manifestPath);\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const PLUGIN_API_VERSION = 1;
|
|
2
|
+
export type PluginDiagnosticStage = "discover" | "manifest" | "compatibility" | "trust" | "import" | "factory" | "register" | "handler" | "install";
|
|
3
|
+
export interface PluginDiagnostic {
|
|
4
|
+
readonly pluginId?: string;
|
|
5
|
+
readonly sourcePath: string;
|
|
6
|
+
readonly stage: PluginDiagnosticStage;
|
|
7
|
+
readonly severity: "warning" | "error";
|
|
8
|
+
readonly message: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PluginPermissions {
|
|
11
|
+
readonly filesystem: "none" | "read-project";
|
|
12
|
+
readonly network: readonly string[];
|
|
13
|
+
readonly process: readonly string[];
|
|
14
|
+
}
|
|
15
|
+
export interface PluginManifest {
|
|
16
|
+
readonly apiVersion: typeof PLUGIN_API_VERSION;
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly version: string;
|
|
20
|
+
readonly entry: string;
|
|
21
|
+
readonly permissions: PluginPermissions;
|
|
22
|
+
}
|
|
23
|
+
export interface DiscoveredPlugin {
|
|
24
|
+
readonly manifest: PluginManifest;
|
|
25
|
+
readonly root: string;
|
|
26
|
+
readonly sourcePath: string;
|
|
27
|
+
readonly projectLocal: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ManagedPlugin {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly source: string;
|
|
32
|
+
readonly installedPath: string;
|
|
33
|
+
readonly enabled: boolean;
|
|
34
|
+
readonly installedAt: string;
|
|
35
|
+
readonly manifest: PluginManifest;
|
|
36
|
+
}
|
|
37
|
+
export interface PluginRegistry {
|
|
38
|
+
readonly version: 1;
|
|
39
|
+
readonly plugins: Record<string, ManagedPlugin>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,MAAM,MAAM,qBAAqB,GAC9B,UAAU,GACV,UAAU,GACV,eAAe,GACf,OAAO,GACP,QAAQ,GACR,SAAS,GACT,UAAU,GACV,SAAS,GACT,SAAS,CAAC;AAEb,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,UAAU,EAAE,OAAO,kBAAkB,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,iBAAiB,CAAC;CACxC;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAChD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC","sourcesContent":["export const PLUGIN_API_VERSION = 1;\n\nexport type PluginDiagnosticStage =\n\t| \"discover\"\n\t| \"manifest\"\n\t| \"compatibility\"\n\t| \"trust\"\n\t| \"import\"\n\t| \"factory\"\n\t| \"register\"\n\t| \"handler\"\n\t| \"install\";\n\nexport interface PluginDiagnostic {\n\treadonly pluginId?: string;\n\treadonly sourcePath: string;\n\treadonly stage: PluginDiagnosticStage;\n\treadonly severity: \"warning\" | \"error\";\n\treadonly message: string;\n}\n\nexport interface PluginPermissions {\n\treadonly filesystem: \"none\" | \"read-project\";\n\treadonly network: readonly string[];\n\treadonly process: readonly string[];\n}\n\nexport interface PluginManifest {\n\treadonly apiVersion: typeof PLUGIN_API_VERSION;\n\treadonly id: string;\n\treadonly name: string;\n\treadonly version: string;\n\treadonly entry: string;\n\treadonly permissions: PluginPermissions;\n}\n\nexport interface DiscoveredPlugin {\n\treadonly manifest: PluginManifest;\n\treadonly root: string;\n\treadonly sourcePath: string;\n\treadonly projectLocal: boolean;\n}\n\nexport interface ManagedPlugin {\n\treadonly id: string;\n\treadonly source: string;\n\treadonly installedPath: string;\n\treadonly enabled: boolean;\n\treadonly installedAt: string;\n\treadonly manifest: PluginManifest;\n}\n\nexport interface PluginRegistry {\n\treadonly version: 1;\n\treadonly plugins: Record<string, ManagedPlugin>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-onboarding.d.ts","sourceRoot":"","sources":["../src/provider-onboarding.ts"],"names":[],"mappings":"AACA,OAAO,EAA+D,KAAK,QAAQ,EAAa,MAAM,cAAc,CAAC;AACrH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAyB,KAAK,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAErG,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAErE,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC5B;AAED,wBAAgB,6BAA6B,CAC5C,OAAO,EAAE,iBAAiB,EAC1B,qBAAqB,EAAE,OAAO,EAC9B,aAAa,EAAE,oBAAoB,GACjC,OAAO,CAOT;
|
|
1
|
+
{"version":3,"file":"provider-onboarding.d.ts","sourceRoot":"","sources":["../src/provider-onboarding.ts"],"names":[],"mappings":"AACA,OAAO,EAA+D,KAAK,QAAQ,EAAa,MAAM,cAAc,CAAC;AACrH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAyB,KAAK,oBAAoB,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAErG,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAErE,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,aAAa,EAAE,oBAAoB,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC5B;AAED,wBAAgB,6BAA6B,CAC5C,OAAO,EAAE,iBAAiB,EAC1B,qBAAqB,EAAE,OAAO,EAC9B,aAAa,EAAE,oBAAoB,GACjC,OAAO,CAOT;AA2FD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAmF7G"}
|
|
@@ -45,18 +45,30 @@ function providerChoices() {
|
|
|
45
45
|
{ value: "openai", providerId: "openai", label: "OpenAI", description: "OpenAI Responses API" },
|
|
46
46
|
{ value: "deepseek", providerId: "deepseek", label: "DeepSeek", description: "DeepSeek Responses API" },
|
|
47
47
|
{ value: "faux", providerId: "faux", label: "Faux (offline)", description: "Deterministic local provider" },
|
|
48
|
+
{ value: "zhipu", providerId: "zhipu", label: "Zhipu AI", description: "GLM Chat Completions API" },
|
|
48
49
|
];
|
|
49
50
|
}
|
|
50
51
|
function modelsFor(providerId) {
|
|
51
52
|
if (providerId === "faux")
|
|
52
53
|
return [createFauxProvider({ responses: [] }).model];
|
|
53
|
-
|
|
54
|
+
const models = MODELS.filter((model) => model.provider === providerId);
|
|
55
|
+
if (providerId === "openai") {
|
|
56
|
+
const preferred = models.find((model) => model.id === "gpt-4o");
|
|
57
|
+
return preferred ? [preferred, ...models.filter((model) => model !== preferred)] : models;
|
|
58
|
+
}
|
|
59
|
+
if (providerId === "zhipu") {
|
|
60
|
+
const preferred = models.find((model) => model.id === "glm-5.3");
|
|
61
|
+
return preferred ? [preferred, ...models.filter((model) => model !== preferred)] : models;
|
|
62
|
+
}
|
|
63
|
+
return models;
|
|
54
64
|
}
|
|
55
65
|
function apiKeyEnvironmentVariable(providerId) {
|
|
56
66
|
if (providerId === "openai")
|
|
57
67
|
return "OPENAI_API_KEY";
|
|
58
68
|
if (providerId === "deepseek")
|
|
59
69
|
return "DEEPSEEK_API_KEY";
|
|
70
|
+
if (providerId === "zhipu")
|
|
71
|
+
return "ZAI_API_KEY";
|
|
60
72
|
return undefined;
|
|
61
73
|
}
|
|
62
74
|
function modelChoices(models) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-onboarding.js","sourceRoot":"","sources":["../src/provider-onboarding.ts"],"names":[],"mappings":"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","sourcesContent":["import { createFauxProvider, MODELS, type Model } from \"@di-code/ai\";\nimport { Input, Key, KeybindingsManager, type SelectItem, SelectList, type Terminal, Text, TUI } from \"@di-code/tui\";\nimport type { CliCommand } from \"./cli.ts\";\nimport { resolveStartupRuntime, type StartupConfiguration, type StartupRuntime } from \"./startup.ts\";\n\nexport type StartupRunCommand = Extract<CliCommand, { kind: \"run\" }>;\n\nexport interface ProviderOnboardingOptions {\n\treadonly configuration: StartupConfiguration;\n\treadonly terminal: Terminal;\n}\n\nexport function shouldStartProviderOnboarding(\n\tcommand: StartupRunCommand,\n\tisInteractiveTerminal: boolean,\n\tconfiguration: StartupConfiguration,\n): boolean {\n\treturn (\n\t\tcommand.mode === \"interactive\" &&\n\t\tisInteractiveTerminal &&\n\t\tconfiguration.providers.length === 0 &&\n\t\t!configuration.environment.DI_CODE_PROVIDER?.trim()\n\t);\n}\n\ninterface OnboardingChoice extends SelectItem {\n\treadonly providerId: \"openai\" | \"deepseek\" | \"faux\";\n}\n\nclass OnboardingScreen {\n\tprivate readonly title = new Text(\"di-code provider setup\", 1, 1);\n\tprivate readonly prompt = new Text(\"\", 1, 0);\n\tprivate readonly error = new Text(\"\", 1, 0);\n\tprivate active: SelectList | Input | null = null;\n\n\tsetStep(prompt: string, active: SelectList | Input): void {\n\t\tthis.prompt.setText(prompt);\n\t\tthis.error.setText(\"\");\n\t\tthis.active = active;\n\t}\n\n\tsetError(message: string): void {\n\t\tthis.error.setText(message);\n\t}\n\n\tsetCancelled(): void {\n\t\tthis.prompt.setText(\"Provider setup cancelled.\");\n\t\tthis.error.setText(\"\");\n\t\tthis.active = null;\n\t}\n\n\trender(width: number): string[] {\n\t\treturn [\n\t\t\t...this.title.render(width),\n\t\t\t...this.prompt.render(width),\n\t\t\t...this.error.render(width),\n\t\t\t...(this.active?.render(width) ?? []),\n\t\t];\n\t}\n\n\tinvalidate(): void {\n\t\tthis.title.invalidate();\n\t\tthis.prompt.invalidate();\n\t\tthis.error.invalidate();\n\t\tthis.active?.invalidate();\n\t}\n}\n\nfunction providerChoices(): OnboardingChoice[] {\n\treturn [\n\t\t{ value: \"openai\", providerId: \"openai\", label: \"OpenAI\", description: \"OpenAI Responses API\" },\n\t\t{ value: \"deepseek\", providerId: \"deepseek\", label: \"DeepSeek\", description: \"DeepSeek Responses API\" },\n\t\t{ value: \"faux\", providerId: \"faux\", label: \"Faux (offline)\", description: \"Deterministic local provider\" },\n\t];\n}\n\nfunction modelsFor(providerId: OnboardingChoice[\"providerId\"]): readonly Model[] {\n\tif (providerId === \"faux\") return [createFauxProvider({ responses: [] }).model];\n\treturn MODELS.filter((model) => model.provider === providerId);\n}\n\nfunction apiKeyEnvironmentVariable(providerId: OnboardingChoice[\"providerId\"]): string | undefined {\n\tif (providerId === \"openai\") return \"OPENAI_API_KEY\";\n\tif (providerId === \"deepseek\") return \"DEEPSEEK_API_KEY\";\n\treturn undefined;\n}\n\nfunction modelChoices(models: readonly Model[]): SelectItem[] {\n\treturn models.map((model) => ({\n\t\tvalue: model.id,\n\t\tlabel: model.name,\n\t\tdescription: `${model.id}${model.reasoning ? \" - reasoning\" : \"\"}`,\n\t}));\n}\n\nfunction onboardingSelectList(items: readonly SelectItem[]): SelectList {\n\treturn new SelectList(items, {\n\t\tkeybindings: new KeybindingsManager({\n\t\t\t\"tui.select.cancel\": [Key.escape, Key.ctrl(\"c\"), Key.ctrl(\"d\")],\n\t\t}),\n\t});\n}\n\nexport function runProviderOnboarding(options: ProviderOnboardingOptions): Promise<StartupRuntime | undefined> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst tui = new TUI(options.terminal);\n\t\tconst screen = new OnboardingScreen();\n\t\tlet settled = false;\n\t\tlet selectedProvider: OnboardingChoice[\"providerId\"] | undefined;\n\n\t\tconst finish = (runtime: StartupRuntime | undefined): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tif (runtime === undefined) screen.setCancelled();\n\t\t\ttui.stop({ finalLines: runtime ? [\"Provider configured for this run.\"] : [\"Provider setup cancelled.\"] });\n\t\t\tresolve(runtime);\n\t\t};\n\n\t\tconst fail = (cause: unknown): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\ttui.stop({ finalLines: [\"Provider setup failed.\"] });\n\t\t\treject(cause);\n\t\t};\n\n\t\tconst finishSelection = (modelId: string, apiKey?: string): void => {\n\t\t\tif (!selectedProvider) return;\n\t\t\tconst keyVariable = apiKeyEnvironmentVariable(selectedProvider);\n\t\t\tconst environment = {\n\t\t\t\t...options.configuration.environment,\n\t\t\t\tDI_CODE_PROVIDER: selectedProvider,\n\t\t\t\tDI_CODE_MODEL: modelId,\n\t\t\t\t...(keyVariable && apiKey ? { [keyVariable]: apiKey } : {}),\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tfinish(resolveStartupRuntime(environment, options.configuration.providers));\n\t\t\t} catch (cause) {\n\t\t\t\tfail(cause);\n\t\t\t}\n\t\t};\n\n\t\tconst showKey = (modelId: string, keyVariable: string): void => {\n\t\t\tconst input = new Input({ mask: \"*\", cancelOnEndOfTransmission: true });\n\t\t\tinput.onSubmit = (value) => {\n\t\t\t\tconst key = value.trim();\n\t\t\t\tif (key.length === 0) {\n\t\t\t\t\tscreen.setError(\"API key cannot be empty. Press Escape to cancel.\");\n\t\t\t\t\ttui.requestRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfinishSelection(modelId, key);\n\t\t\t};\n\t\t\tinput.onEscape = () => finish(undefined);\n\t\t\tscreen.setStep(`Enter ${keyVariable} (input is hidden):`, input);\n\t\t\ttui.setFocus(input);\n\t\t\ttui.requestRender(true);\n\t\t};\n\n\t\tconst showModels = (choice: OnboardingChoice): void => {\n\t\t\tselectedProvider = choice.providerId;\n\t\t\tconst models = modelsFor(choice.providerId);\n\t\t\tconst modelList = onboardingSelectList(modelChoices(models));\n\t\t\tmodelList.onSelect = (item) => {\n\t\t\t\tconst keyVariable = apiKeyEnvironmentVariable(choice.providerId);\n\t\t\t\tconst existingKey = keyVariable ? options.configuration.environment[keyVariable]?.trim() : undefined;\n\t\t\t\tif (keyVariable && !existingKey) showKey(item.value, keyVariable);\n\t\t\t\telse finishSelection(item.value);\n\t\t\t};\n\t\t\tmodelList.onCancel = () => finish(undefined);\n\t\t\tscreen.setStep(`Select a ${choice.label} model:`, modelList);\n\t\t\ttui.setFocus(modelList);\n\t\t\ttui.requestRender(true);\n\t\t};\n\n\t\tconst providerList = onboardingSelectList(providerChoices());\n\t\tproviderList.onSelect = (item) => {\n\t\t\tconst choice = providerChoices().find((candidate) => candidate.value === item.value);\n\t\t\tif (choice) showModels(choice);\n\t\t};\n\t\tproviderList.onCancel = () => finish(undefined);\n\t\tscreen.setStep(\"Select a provider:\", providerList);\n\t\ttui.addChild(screen);\n\t\ttui.start();\n\t\ttui.setFocus(providerList);\n\t\ttui.requestRender(true);\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provider-onboarding.js","sourceRoot":"","sources":["../src/provider-onboarding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAc,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,kBAAkB,EAAmB,UAAU,EAAiB,IAAI,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAErH,OAAO,EAAE,qBAAqB,EAAkD,MAAM,cAAc,CAAC;AASrG,MAAM,UAAU,6BAA6B,CAC5C,OAA0B,EAC1B,qBAA8B,EAC9B,aAAmC;IAEnC,OAAO,CACN,OAAO,CAAC,IAAI,KAAK,aAAa;QAC9B,qBAAqB;QACrB,aAAa,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QACpC,CAAC,aAAa,CAAC,WAAW,CAAC,gBAAgB,EAAE,IAAI,EAAE,CACnD,CAAC;AACH,CAAC;AAMD,MAAM,gBAAgB;IACJ,KAAK,GAAG,IAAI,IAAI,CAAC,wBAAwB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACjD,MAAM,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5B,KAAK,GAAG,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACpC,MAAM,GAA8B,IAAI,CAAC;IAEjD,OAAO,CAAC,MAAc,EAAE,MAA0B;QACjD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,QAAQ,CAAC,OAAe;QACvB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,YAAY;QACX,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,KAAa;QACnB,OAAO;YACN,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;YAC3B,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAC5B,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;YAC3B,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;SACrC,CAAC;IACH,CAAC;IAED,UAAU;QACT,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAC3B,CAAC;CACD;AAED,SAAS,eAAe;IACvB,OAAO;QACN,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE;QAC/F,EAAE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,wBAAwB,EAAE;QACvG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,8BAA8B,EAAE;QAC3G,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,0BAA0B,EAAE;KACnG,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,UAA0C;IAC5D,IAAI,UAAU,KAAK,MAAM;QAAE,OAAO,CAAC,kBAAkB,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IACvE,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;QAChE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3F,CAAC;IACD,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC;QACjE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3F,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,yBAAyB,CAAC,UAA0C;IAC5E,IAAI,UAAU,KAAK,QAAQ;QAAE,OAAO,gBAAgB,CAAC;IACrD,IAAI,UAAU,KAAK,UAAU;QAAE,OAAO,kBAAkB,CAAC;IACzD,IAAI,UAAU,KAAK,OAAO;QAAE,OAAO,aAAa,CAAC;IACjD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,YAAY,CAAC,MAAwB;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC7B,KAAK,EAAE,KAAK,CAAC,EAAE;QACf,KAAK,EAAE,KAAK,CAAC,IAAI;QACjB,WAAW,EAAE,GAAG,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE;KAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAAC,KAA4B;IACzD,OAAO,IAAI,UAAU,CAAC,KAAK,EAAE;QAC5B,WAAW,EAAE,IAAI,kBAAkB,CAAC;YACnC,mBAAmB,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SAC/D,CAAC;KACF,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAkC;IACvE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACtC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,gBAA4D,CAAC;QAEjE,MAAM,MAAM,GAAG,CAAC,OAAmC,EAAQ,EAAE;YAC5D,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,OAAO,KAAK,SAAS;gBAAE,MAAM,CAAC,YAAY,EAAE,CAAC;YACjD,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,EAAE,CAAC,CAAC;YAC1G,OAAO,CAAC,OAAO,CAAC,CAAC;QAClB,CAAC,CAAC;QAEF,MAAM,IAAI,GAAG,CAAC,KAAc,EAAQ,EAAE;YACrC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,CAAC;QACf,CAAC,CAAC;QAEF,MAAM,eAAe,GAAG,CAAC,OAAe,EAAE,MAAe,EAAQ,EAAE;YAClE,IAAI,CAAC,gBAAgB;gBAAE,OAAO;YAC9B,MAAM,WAAW,GAAG,yBAAyB,CAAC,gBAAgB,CAAC,CAAC;YAChE,MAAM,WAAW,GAAG;gBACnB,GAAG,OAAO,CAAC,aAAa,CAAC,WAAW;gBACpC,gBAAgB,EAAE,gBAAgB;gBAClC,aAAa,EAAE,OAAO;gBACtB,GAAG,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC3D,CAAC;YACF,IAAI,CAAC;gBACJ,MAAM,CAAC,qBAAqB,CAAC,WAAW,EAAE,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;YAC7E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,CAAC;YACb,CAAC;QACF,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAQ,EAAE;YAC9D,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,yBAAyB,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,KAAK,CAAC,QAAQ,GAAG,CAAC,KAAK,EAAE,EAAE;gBAC1B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;gBACzB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACtB,MAAM,CAAC,QAAQ,CAAC,kDAAkD,CAAC,CAAC;oBACpE,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;oBACxB,OAAO;gBACR,CAAC;gBACD,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YAC/B,CAAC,CAAC;YACF,KAAK,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACzC,MAAM,CAAC,OAAO,CAAC,SAAS,WAAW,qBAAqB,EAAE,KAAK,CAAC,CAAC;YACjE,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YACpB,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,CAAC;QAEF,MAAM,UAAU,GAAG,CAAC,MAAwB,EAAQ,EAAE;YACrD,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC;YACrC,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,SAAS,GAAG,oBAAoB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7D,SAAS,CAAC,QAAQ,GAAG,CAAC,IAAI,EAAE,EAAE;gBAC7B,MAAM,WAAW,GAAG,yBAAyB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBACjE,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrG,IAAI,WAAW,IAAI,CAAC,WAAW;oBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;;oBAC7D,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC,CAAC;YACF,SAAS,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,CAAC,YAAY,MAAM,CAAC,KAAK,SAAS,EAAE,SAAS,CAAC,CAAC;YAC7D,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;YACxB,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,CAAC;QAEF,MAAM,YAAY,GAAG,oBAAoB,CAAC,eAAe,EAAE,CAAC,CAAC;QAC7D,YAAY,CAAC,QAAQ,GAAG,CAAC,IAAI,EAAE,EAAE;YAChC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC;YACrF,IAAI,MAAM;gBAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC,CAAC;QACF,YAAY,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,YAAY,CAAC,CAAC;QACnD,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACrB,GAAG,CAAC,KAAK,EAAE,CAAC;QACZ,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAC3B,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { createFauxProvider, MODELS, type Model } from \"@di-code/ai\";\nimport { Input, Key, KeybindingsManager, type SelectItem, SelectList, type Terminal, Text, TUI } from \"@di-code/tui\";\nimport type { CliCommand } from \"./cli.ts\";\nimport { resolveStartupRuntime, type StartupConfiguration, type StartupRuntime } from \"./startup.ts\";\n\nexport type StartupRunCommand = Extract<CliCommand, { kind: \"run\" }>;\n\nexport interface ProviderOnboardingOptions {\n\treadonly configuration: StartupConfiguration;\n\treadonly terminal: Terminal;\n}\n\nexport function shouldStartProviderOnboarding(\n\tcommand: StartupRunCommand,\n\tisInteractiveTerminal: boolean,\n\tconfiguration: StartupConfiguration,\n): boolean {\n\treturn (\n\t\tcommand.mode === \"interactive\" &&\n\t\tisInteractiveTerminal &&\n\t\tconfiguration.providers.length === 0 &&\n\t\t!configuration.environment.DI_CODE_PROVIDER?.trim()\n\t);\n}\n\ninterface OnboardingChoice extends SelectItem {\n\treadonly providerId: \"openai\" | \"deepseek\" | \"zhipu\" | \"faux\";\n}\n\nclass OnboardingScreen {\n\tprivate readonly title = new Text(\"di-code provider setup\", 1, 1);\n\tprivate readonly prompt = new Text(\"\", 1, 0);\n\tprivate readonly error = new Text(\"\", 1, 0);\n\tprivate active: SelectList | Input | null = null;\n\n\tsetStep(prompt: string, active: SelectList | Input): void {\n\t\tthis.prompt.setText(prompt);\n\t\tthis.error.setText(\"\");\n\t\tthis.active = active;\n\t}\n\n\tsetError(message: string): void {\n\t\tthis.error.setText(message);\n\t}\n\n\tsetCancelled(): void {\n\t\tthis.prompt.setText(\"Provider setup cancelled.\");\n\t\tthis.error.setText(\"\");\n\t\tthis.active = null;\n\t}\n\n\trender(width: number): string[] {\n\t\treturn [\n\t\t\t...this.title.render(width),\n\t\t\t...this.prompt.render(width),\n\t\t\t...this.error.render(width),\n\t\t\t...(this.active?.render(width) ?? []),\n\t\t];\n\t}\n\n\tinvalidate(): void {\n\t\tthis.title.invalidate();\n\t\tthis.prompt.invalidate();\n\t\tthis.error.invalidate();\n\t\tthis.active?.invalidate();\n\t}\n}\n\nfunction providerChoices(): OnboardingChoice[] {\n\treturn [\n\t\t{ value: \"openai\", providerId: \"openai\", label: \"OpenAI\", description: \"OpenAI Responses API\" },\n\t\t{ value: \"deepseek\", providerId: \"deepseek\", label: \"DeepSeek\", description: \"DeepSeek Responses API\" },\n\t\t{ value: \"faux\", providerId: \"faux\", label: \"Faux (offline)\", description: \"Deterministic local provider\" },\n\t\t{ value: \"zhipu\", providerId: \"zhipu\", label: \"Zhipu AI\", description: \"GLM Chat Completions API\" },\n\t];\n}\n\nfunction modelsFor(providerId: OnboardingChoice[\"providerId\"]): readonly Model[] {\n\tif (providerId === \"faux\") return [createFauxProvider({ responses: [] }).model];\n\tconst models = MODELS.filter((model) => model.provider === providerId);\n\tif (providerId === \"openai\") {\n\t\tconst preferred = models.find((model) => model.id === \"gpt-4o\");\n\t\treturn preferred ? [preferred, ...models.filter((model) => model !== preferred)] : models;\n\t}\n\tif (providerId === \"zhipu\") {\n\t\tconst preferred = models.find((model) => model.id === \"glm-5.3\");\n\t\treturn preferred ? [preferred, ...models.filter((model) => model !== preferred)] : models;\n\t}\n\treturn models;\n}\n\nfunction apiKeyEnvironmentVariable(providerId: OnboardingChoice[\"providerId\"]): string | undefined {\n\tif (providerId === \"openai\") return \"OPENAI_API_KEY\";\n\tif (providerId === \"deepseek\") return \"DEEPSEEK_API_KEY\";\n\tif (providerId === \"zhipu\") return \"ZAI_API_KEY\";\n\treturn undefined;\n}\n\nfunction modelChoices(models: readonly Model[]): SelectItem[] {\n\treturn models.map((model) => ({\n\t\tvalue: model.id,\n\t\tlabel: model.name,\n\t\tdescription: `${model.id}${model.reasoning ? \" - reasoning\" : \"\"}`,\n\t}));\n}\n\nfunction onboardingSelectList(items: readonly SelectItem[]): SelectList {\n\treturn new SelectList(items, {\n\t\tkeybindings: new KeybindingsManager({\n\t\t\t\"tui.select.cancel\": [Key.escape, Key.ctrl(\"c\"), Key.ctrl(\"d\")],\n\t\t}),\n\t});\n}\n\nexport function runProviderOnboarding(options: ProviderOnboardingOptions): Promise<StartupRuntime | undefined> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst tui = new TUI(options.terminal);\n\t\tconst screen = new OnboardingScreen();\n\t\tlet settled = false;\n\t\tlet selectedProvider: OnboardingChoice[\"providerId\"] | undefined;\n\n\t\tconst finish = (runtime: StartupRuntime | undefined): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tif (runtime === undefined) screen.setCancelled();\n\t\t\ttui.stop({ finalLines: runtime ? [\"Provider configured for this run.\"] : [\"Provider setup cancelled.\"] });\n\t\t\tresolve(runtime);\n\t\t};\n\n\t\tconst fail = (cause: unknown): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\ttui.stop({ finalLines: [\"Provider setup failed.\"] });\n\t\t\treject(cause);\n\t\t};\n\n\t\tconst finishSelection = (modelId: string, apiKey?: string): void => {\n\t\t\tif (!selectedProvider) return;\n\t\t\tconst keyVariable = apiKeyEnvironmentVariable(selectedProvider);\n\t\t\tconst environment = {\n\t\t\t\t...options.configuration.environment,\n\t\t\t\tDI_CODE_PROVIDER: selectedProvider,\n\t\t\t\tDI_CODE_MODEL: modelId,\n\t\t\t\t...(keyVariable && apiKey ? { [keyVariable]: apiKey } : {}),\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tfinish(resolveStartupRuntime(environment, options.configuration.providers));\n\t\t\t} catch (cause) {\n\t\t\t\tfail(cause);\n\t\t\t}\n\t\t};\n\n\t\tconst showKey = (modelId: string, keyVariable: string): void => {\n\t\t\tconst input = new Input({ mask: \"*\", cancelOnEndOfTransmission: true });\n\t\t\tinput.onSubmit = (value) => {\n\t\t\t\tconst key = value.trim();\n\t\t\t\tif (key.length === 0) {\n\t\t\t\t\tscreen.setError(\"API key cannot be empty. Press Escape to cancel.\");\n\t\t\t\t\ttui.requestRender(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfinishSelection(modelId, key);\n\t\t\t};\n\t\t\tinput.onEscape = () => finish(undefined);\n\t\t\tscreen.setStep(`Enter ${keyVariable} (input is hidden):`, input);\n\t\t\ttui.setFocus(input);\n\t\t\ttui.requestRender(true);\n\t\t};\n\n\t\tconst showModels = (choice: OnboardingChoice): void => {\n\t\t\tselectedProvider = choice.providerId;\n\t\t\tconst models = modelsFor(choice.providerId);\n\t\t\tconst modelList = onboardingSelectList(modelChoices(models));\n\t\t\tmodelList.onSelect = (item) => {\n\t\t\t\tconst keyVariable = apiKeyEnvironmentVariable(choice.providerId);\n\t\t\t\tconst existingKey = keyVariable ? options.configuration.environment[keyVariable]?.trim() : undefined;\n\t\t\t\tif (keyVariable && !existingKey) showKey(item.value, keyVariable);\n\t\t\t\telse finishSelection(item.value);\n\t\t\t};\n\t\t\tmodelList.onCancel = () => finish(undefined);\n\t\t\tscreen.setStep(`Select a ${choice.label} model:`, modelList);\n\t\t\ttui.setFocus(modelList);\n\t\t\ttui.requestRender(true);\n\t\t};\n\n\t\tconst providerList = onboardingSelectList(providerChoices());\n\t\tproviderList.onSelect = (item) => {\n\t\t\tconst choice = providerChoices().find((candidate) => candidate.value === item.value);\n\t\t\tif (choice) showModels(choice);\n\t\t};\n\t\tproviderList.onCancel = () => finish(undefined);\n\t\tscreen.setStep(\"Select a provider:\", providerList);\n\t\ttui.addChild(screen);\n\t\ttui.start();\n\t\ttui.setFocus(providerList);\n\t\ttui.requestRender(true);\n\t});\n}\n"]}
|
package/dist/startup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup.d.ts","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"startup.d.ts","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"AAEA,OAAO,EAMN,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,SAAS,4BAA4B,EAAE,CAAC;CAC5D;AAQD,KAAK,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAehE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAE7E;AAqND,wBAAgB,qBAAqB,CACpC,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,SAAS,4BAA4B,EAAE,GAChD,cAAc,CAgBhB;AAED,wBAAsB,wBAAwB,CAC7C,GAAG,EAAE,MAAM,EACX,WAAW,GAAE,WAAyB,GACpC,OAAO,CAAC,oBAAoB,CAAC,CAuB/B;AAED,wBAAsB,sBAAsB,CAC3C,GAAG,EAAE,MAAM,EACX,WAAW,GAAE,WAAyB,GACpC,OAAO,CAAC,WAAW,CAAC,CAEtB"}
|