@ai-agent-forge/agent-forge 0.88.8 → 0.88.10
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/CHANGELOG.md +13 -0
- package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
- package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
- package/bundled-plugins/alignment/agent-forge.json +1 -1
- package/bundled-plugins/alignment/plugin.json +1 -1
- package/bundled-plugins/browser-playwright/agent-forge.json +1 -1
- package/bundled-plugins/browser-playwright/plugin.json +1 -1
- package/bundled-plugins/coding-tools/agent-forge.json +1 -1
- package/bundled-plugins/coding-tools/plugin.json +1 -1
- package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
- package/bundled-plugins/compaction-policy/plugin.json +1 -1
- package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
- package/bundled-plugins/overflow-policy/plugin.json +1 -1
- package/bundled-plugins/provider-failover/agent-forge.json +1 -1
- package/bundled-plugins/provider-failover/plugin.json +1 -1
- package/bundled-plugins/retry-policy/agent-forge.json +1 -1
- package/bundled-plugins/retry-policy/plugin.json +1 -1
- package/dist/bundle/.build-manifest.json +11 -11
- package/dist/bundle/chunks/{chunk-ZS5JEI76.js → chunk-4BD6FSZA.js} +1 -1
- package/dist/bundle/chunks/{chunk-ISLHFRER.js → chunk-F73USSXE.js} +1 -1
- package/dist/bundle/chunks/{chunk-WJSKB3FC.js → chunk-HXGAAJQQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-L2SXIPI5.js → chunk-ZZCUNSGO.js} +4 -4
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{virtual-modules-2QGILFV7.js → virtual-modules-UQRUJLPM.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/client.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/cli.js +2 -1
- package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
- package/dist/plugins/ecosystem/catalog.d.ts +1 -1
- package/dist/plugins/ecosystem/catalog.d.ts.map +1 -1
- package/dist/plugins/ecosystem/catalog.js +10 -4
- package/dist/plugins/ecosystem/catalog.js.map +1 -1
- package/dist/plugins/ecosystem/node-disk-registry-source.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-disk-registry-source.js +12 -0
- package/dist/plugins/ecosystem/node-disk-registry-source.js.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +6 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js +11 -3
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +10 -0
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.js +66 -23
- package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/extensions/with-deps/plugin.json +1 -1
- package/package.json +1 -1
|
@@ -81,35 +81,45 @@ export async function runPluginBootstrapV1(input) {
|
|
|
81
81
|
}
|
|
82
82
|
const actions = [];
|
|
83
83
|
const diagnostics = [];
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
// Per-entry results slot by manifest index: parallel workers complete out of
|
|
85
|
+
// order, but actions/diagnostics and their callbacks keep a stable order —
|
|
86
|
+
// onAction stays live (fires the moment an entry settles) while the arrays
|
|
87
|
+
// the result carries always read in manifest order.
|
|
88
|
+
const slots = input.manifest.map(() => ({ actions: [], diagnostics: [] }));
|
|
89
|
+
const record = (index, action) => {
|
|
90
|
+
slots[index].actions.push(action);
|
|
86
91
|
input.onAction?.(action);
|
|
87
92
|
};
|
|
93
|
+
const addDiagnostic = (index, diagnostic) => {
|
|
94
|
+
slots[index].diagnostics.push(diagnostic);
|
|
95
|
+
};
|
|
88
96
|
if (input.onPendingInstalls !== undefined) {
|
|
89
|
-
|
|
97
|
+
// Upgrades count too (2026-10-08 启动走查): an active version outside the
|
|
98
|
+
// factory range goes through the same npm install window as a missing
|
|
99
|
+
// one — counting only missing entries left upgrade startups silent for
|
|
100
|
+
// the whole alignment (real replay: 9 plugins, 38s, zero feedback).
|
|
101
|
+
const pending = input.manifest.filter((entry) => {
|
|
102
|
+
const activeVersion = active.get(entry.pluginId);
|
|
103
|
+
return activeVersion === undefined || !satisfiesRangeV1(activeVersion, entry.range);
|
|
104
|
+
}).length;
|
|
90
105
|
if (pending > 0)
|
|
91
106
|
input.onPendingInstalls(pending);
|
|
92
107
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
diagnostics.push({
|
|
96
|
-
code: "cancelled",
|
|
97
|
-
message: "Plugin bootstrap was cancelled before all factory entries were processed",
|
|
98
|
-
});
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
108
|
+
const processEntry = async (index, entry) => {
|
|
109
|
+
const signal = input.deps.signal;
|
|
101
110
|
const activeVersion = active.get(entry.pluginId);
|
|
102
111
|
if (activeVersion !== undefined && satisfiesRangeV1(activeVersion, entry.range)) {
|
|
103
|
-
record(Object.freeze({ ...actionOf(entry, "skipped", "satisfies_range"), activeVersion }));
|
|
104
|
-
|
|
112
|
+
record(index, Object.freeze({ ...actionOf(entry, "skipped", "satisfies_range"), activeVersion }));
|
|
113
|
+
return;
|
|
105
114
|
}
|
|
115
|
+
input.onInstallStart?.({ npmName: entry.npmName, pluginId: entry.pluginId });
|
|
106
116
|
try {
|
|
107
117
|
const installed = await input.deps.installFromNpm({
|
|
108
118
|
npmName: entry.npmName,
|
|
109
119
|
...(entry.range === undefined ? {} : { range: entry.range }),
|
|
110
120
|
...(signal === undefined ? {} : { signal }),
|
|
111
121
|
});
|
|
112
|
-
record(Object.freeze({
|
|
122
|
+
record(index, Object.freeze({
|
|
113
123
|
...actionOf(entry, "installed", activeVersion === undefined ? "installed" : "range_aligned"),
|
|
114
124
|
installedVersion: installed.pluginVersion,
|
|
115
125
|
source: installed.source,
|
|
@@ -118,21 +128,54 @@ export async function runPluginBootstrapV1(input) {
|
|
|
118
128
|
catch (error) {
|
|
119
129
|
const errorCode = acquireErrorCode(error);
|
|
120
130
|
const aligning = activeVersion !== undefined;
|
|
121
|
-
record(Object.freeze({ ...actionOf(entry, "failed", aligning ? "align_failed" : "install_failed"), errorCode }));
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
131
|
+
record(index, Object.freeze({ ...actionOf(entry, "failed", aligning ? "align_failed" : "install_failed"), errorCode }));
|
|
132
|
+
addDiagnostic(index, aligning
|
|
133
|
+
? {
|
|
134
|
+
code: "install_failed",
|
|
135
|
+
pluginId: entry.pluginId,
|
|
136
|
+
message: `Bootstrap could not align ${entry.pluginId} (active ${activeVersion}) to the factory range ` +
|
|
127
137
|
`${entry.range ?? "latest"} from npm (${errorCode}: ${errorMessage(error)}). ` +
|
|
128
138
|
`Startup continues; the factory range stays unsatisfied, so the next startup retries automatically. ` +
|
|
129
|
-
`Run \`${pluginBootstrapInstallCommandV1(entry)}\` to align it now
|
|
130
|
-
|
|
139
|
+
`Run \`${pluginBootstrapInstallCommandV1(entry)}\` to align it now.`,
|
|
140
|
+
}
|
|
141
|
+
: {
|
|
142
|
+
code: "install_failed",
|
|
143
|
+
pluginId: entry.pluginId,
|
|
144
|
+
message: `Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +
|
|
131
145
|
`Startup continues without it; its capabilities stay unavailable until installed, ` +
|
|
132
146
|
`and the next startup retries automatically. ` +
|
|
133
147
|
`Run \`${pluginBootstrapInstallCommandV1(entry)}\` to install it manually.`,
|
|
134
|
-
|
|
148
|
+
});
|
|
135
149
|
}
|
|
150
|
+
};
|
|
151
|
+
// Bounded parallelism (2026-10-08 启动走查): serial npm alignment held a
|
|
152
|
+
// 0.88.7→0.88.8 upgrade startup hostage for ~38s (9 plugins × metadata +
|
|
153
|
+
// tarball, each silent). Four workers cut the wall time to roughly the
|
|
154
|
+
// slowest four installs while the npm acquisition host and the per-plugin
|
|
155
|
+
// activation chains stay per-key serialized underneath.
|
|
156
|
+
const WORKERS = 4;
|
|
157
|
+
let cursor = 0;
|
|
158
|
+
let cancelNoted = false;
|
|
159
|
+
const worker = async () => {
|
|
160
|
+
while (cursor < input.manifest.length) {
|
|
161
|
+
if (input.deps.signal?.aborted === true) {
|
|
162
|
+
if (!cancelNoted) {
|
|
163
|
+
cancelNoted = true;
|
|
164
|
+
diagnostics.push({
|
|
165
|
+
code: "cancelled",
|
|
166
|
+
message: "Plugin bootstrap was cancelled before all factory entries were processed",
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const index = cursor++;
|
|
172
|
+
await processEntry(index, input.manifest[index]);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
await Promise.all(Array.from({ length: Math.min(WORKERS, input.manifest.length) }, worker));
|
|
176
|
+
for (const slot of slots) {
|
|
177
|
+
actions.push(...slot.actions);
|
|
178
|
+
diagnostics.push(...slot.diagnostics);
|
|
136
179
|
}
|
|
137
180
|
const status = actions.some((action) => action.status === "failed")
|
|
138
181
|
? "failed"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-bootstrap.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Startup plugin bootstrap orchestrator (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7). Pure injectable decision loop\n * over the frozen factory manifest: every entry is compared against the\n * locally resolved active installations; missing plugins and factory entries\n * whose active version no longer satisfies the factory range are handed to\n * the npm install dependency — bootstrap never acquires through any other\n * source.\n *\n * Coverage rules (G5, with the 2026-10-04 install-and-use exception): a\n * satisfied range is skipped silently (zero acquisition calls, G3); a factory\n * entry whose range is unsatisfied is automatically realigned by installing\n * the factory range — factory plugins are version-locked to the running\n * framework, so an unsatisfied range is a broken compatibility state, not a\n * user preference to protect. User-installed third-party plugins are not in\n * the factory manifest and stay untouched. Failure semantics (G4): one\n * plugin's install failure is recorded and the loop continues; the run itself\n * never throws, and a failed entry self-heals on the next startup because it\n * stays unsatisfied. All effects live behind the injected dependencies, so\n * the loop is fully deterministic under mocks.\n */\n\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { selectNpmPackageVersionV1 } from \"./node-npm-registry-source.ts\";\nimport { PluginAcquisitionErrorV1 } from \"./plugin-acquisition.ts\";\n\nexport const PLUGIN_BOOTSTRAP_VERSION_V1 = 1 as const;\n\n/** Read-only local lookup of active installation versions (never networked). */\nexport type PluginBootstrapListActiveV1 = (input: {\n\treadonly signal?: AbortSignal;\n}) => Promise<ReadonlyMap<string, string>>;\n\n/** npm-only install action; resolves with the installed version and source label. */\nexport type PluginBootstrapInstallFromNpmV1 = (input: {\n\treadonly npmName: string;\n\treadonly range?: string;\n\treadonly signal?: AbortSignal;\n}) => Promise<{ readonly pluginVersion: string; readonly source: string }>;\n\nexport interface PluginBootstrapDepsV1 {\n\treadonly listActive: PluginBootstrapListActiveV1;\n\treadonly installFromNpm: PluginBootstrapInstallFromNpmV1;\n\t/** Deterministic clock for the observed duration; defaults to Date.now. */\n\treadonly now?: () => number;\n\t/** Cooperative cancellation; checked before each manifest entry. */\n\treadonly signal?: AbortSignal;\n}\n\nexport type PluginBootstrapActionStatusV1 = \"skipped\" | \"installed\" | \"failed\";\n\nexport type PluginBootstrapActionReasonV1 =\n\t| \"satisfies_range\"\n\t| \"installed\"\n\t| \"range_aligned\"\n\t| \"install_failed\"\n\t| \"align_failed\";\n\n/** One per-entry outcome; the version fields carry what each status observed. */\nexport interface PluginBootstrapActionV1 {\n\treadonly pluginId: string;\n\treadonly status: PluginBootstrapActionStatusV1;\n\treadonly reason: PluginBootstrapActionReasonV1;\n\treadonly npmName: string;\n\treadonly range?: string;\n\t/** Active version that decided a skipped outcome. */\n\treadonly activeVersion?: string;\n\t/** Version reported by the install action. */\n\treadonly installedVersion?: string;\n\t/** npm source label reported by the install action. */\n\treadonly source?: string;\n\t/** Acquisition or install failure code for failed actions. */\n\treadonly errorCode?: string;\n}\n\nexport type PluginBootstrapDiagnosticCodeV1 =\n\t| \"install_failed\"\n\t| \"list_active_failed\"\n\t| \"cancelled\"\n\t| \"bootstrap_failed\"\n\t| \"bootstrap_skipped_offline\";\n\nexport interface PluginBootstrapDiagnosticV1 {\n\treadonly code: PluginBootstrapDiagnosticCodeV1;\n\treadonly message: string;\n\treadonly pluginId?: string;\n}\n\nexport type PluginBootstrapStatusV1 = \"succeeded\" | \"failed\";\n\nexport interface PluginBootstrapResultV1 {\n\treadonly version: typeof PLUGIN_BOOTSTRAP_VERSION_V1;\n\t/** Aggregated outcome: failed (any failed entry) > succeeded. */\n\treadonly status: PluginBootstrapStatusV1;\n\treadonly actions: readonly PluginBootstrapActionV1[];\n\treadonly diagnostics: readonly PluginBootstrapDiagnosticV1[];\n\treadonly durationMs: number;\n}\n\n/**\n * A version satisfies a factory range under the same selection semantics npm\n * resolution uses: it is the version that would be picked if it were the only\n * candidate. Keeps local comparison and registry resolution consistent.\n */\nfunction satisfiesRangeV1(version: string, range: string | undefined): boolean {\n\treturn selectNpmPackageVersionV1([version], range) === version;\n}\n\n/** Executable repair command for diagnostics (G4 remediation hint). */\nexport function pluginBootstrapInstallCommandV1(entry: { readonly npmName: string; readonly range?: string }): string {\n\treturn `agent-forge plugin install ${entry.npmName}@${entry.range ?? \"latest\"}`;\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction acquireErrorCode(error: unknown): string {\n\treturn error instanceof PluginAcquisitionErrorV1 ? error.code : \"install_failed\";\n}\n\nfunction actionOf(\n\tentry: PluginBootstrapFactoryEntryV1,\n\tstatus: PluginBootstrapActionStatusV1,\n\treason: PluginBootstrapActionReasonV1,\n): PluginBootstrapActionV1 {\n\treturn Object.freeze({\n\t\tpluginId: entry.pluginId,\n\t\tstatus,\n\t\treason,\n\t\tnpmName: entry.npmName,\n\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t});\n}\n\n/**\n * Run the bootstrap decision loop. An empty manifest short-circuits before\n * any dependency is touched, so the factory-empty S1-c2 state performs zero\n * reads on real startups.\n */\nexport async function runPluginBootstrapV1(input: {\n\treadonly manifest: readonly PluginBootstrapFactoryEntryV1[];\n\treadonly deps: PluginBootstrapDepsV1;\n\t/**\n\t * Fired once after the local active-state read when at least one factory\n\t * entry has no active installation — the host's first-run progress line\n\t * hook (设计 §4.4 首装进度行, 2026-10-03): a fresh install is otherwise\n\t * silent for the whole network install window. Injected effect, the loop\n\t * itself stays free of console I/O.\n\t */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Fired after every per-entry action (设计 §4.4 逐插件进度, 2026-10-04):\n\t * the host renders one line per install/align/failure so the waiting user\n\t * sees live state; skipped entries stay silent at the host's discretion.\n\t * Injected effect, the loop itself stays free of console I/O.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}): Promise<PluginBootstrapResultV1> {\n\tconst now = input.deps.now ?? Date.now;\n\tconst startedAt = now();\n\tconst finish = (\n\t\tstatus: PluginBootstrapStatusV1,\n\t\tactions: readonly PluginBootstrapActionV1[],\n\t\tdiagnostics: readonly PluginBootstrapDiagnosticV1[],\n\t): PluginBootstrapResultV1 =>\n\t\tObject.freeze({\n\t\t\tversion: PLUGIN_BOOTSTRAP_VERSION_V1,\n\t\t\tstatus,\n\t\t\tactions: Object.freeze([...actions]),\n\t\t\tdiagnostics: Object.freeze([...diagnostics]),\n\t\t\tdurationMs: Math.max(0, now() - startedAt),\n\t\t});\n\tif (input.manifest.length === 0) return finish(\"succeeded\", [], []);\n\tconst signal = input.deps.signal;\n\tlet active: ReadonlyMap<string, string>;\n\ttry {\n\t\tactive = await input.deps.listActive({ ...(signal === undefined ? {} : { signal }) });\n\t} catch (error) {\n\t\treturn finish(\n\t\t\t\"failed\",\n\t\t\t[],\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcode: \"list_active_failed\",\n\t\t\t\t\tmessage: `Active plugin state could not be read; bootstrap installed nothing: ${errorMessage(error)}`,\n\t\t\t\t},\n\t\t\t],\n\t\t);\n\t}\n\tconst actions: PluginBootstrapActionV1[] = [];\n\tconst diagnostics: PluginBootstrapDiagnosticV1[] = [];\n\tconst record = (action: PluginBootstrapActionV1): void => {\n\t\tactions.push(action);\n\t\tinput.onAction?.(action);\n\t};\n\tif (input.onPendingInstalls !== undefined) {\n\t\tconst pending = input.manifest.filter((entry) => !active.has(entry.pluginId)).length;\n\t\tif (pending > 0) input.onPendingInstalls(pending);\n\t}\n\tfor (const entry of input.manifest) {\n\t\tif (signal?.aborted === true) {\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"cancelled\",\n\t\t\t\tmessage: \"Plugin bootstrap was cancelled before all factory entries were processed\",\n\t\t\t});\n\t\t\tbreak;\n\t\t}\n\t\tconst activeVersion = active.get(entry.pluginId);\n\t\tif (activeVersion !== undefined && satisfiesRangeV1(activeVersion, entry.range)) {\n\t\t\trecord(Object.freeze({ ...actionOf(entry, \"skipped\", \"satisfies_range\"), activeVersion }));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst installed = await input.deps.installFromNpm({\n\t\t\t\tnpmName: entry.npmName,\n\t\t\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t});\n\t\t\trecord(\n\t\t\t\tObject.freeze({\n\t\t\t\t\t...actionOf(entry, \"installed\", activeVersion === undefined ? \"installed\" : \"range_aligned\"),\n\t\t\t\t\tinstalledVersion: installed.pluginVersion,\n\t\t\t\t\tsource: installed.source,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst errorCode = acquireErrorCode(error);\n\t\t\tconst aligning = activeVersion !== undefined;\n\t\t\trecord(\n\t\t\t\tObject.freeze({ ...actionOf(entry, \"failed\", aligning ? \"align_failed\" : \"install_failed\"), errorCode }),\n\t\t\t);\n\t\t\tdiagnostics.push({\n\t\t\t\tcode: \"install_failed\",\n\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\tmessage: aligning\n\t\t\t\t\t? `Bootstrap could not align ${entry.pluginId} (active ${activeVersion}) to the factory range ` +\n\t\t\t\t\t\t`${entry.range ?? \"latest\"} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t\t`Startup continues; the factory range stays unsatisfied, so the next startup retries automatically. ` +\n\t\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to align it now.`\n\t\t\t\t\t: `Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t\t`Startup continues without it; its capabilities stay unavailable until installed, ` +\n\t\t\t\t\t\t`and the next startup retries automatically. ` +\n\t\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to install it manually.`,\n\t\t\t});\n\t\t}\n\t}\n\tconst status: PluginBootstrapStatusV1 = actions.some((action) => action.status === \"failed\")\n\t\t? \"failed\"\n\t\t: \"succeeded\";\n\treturn finish(status, actions, diagnostics);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"plugin-bootstrap.js","sourceRoot":"","sources":["../../../src/plugins/ecosystem/plugin-bootstrap.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Startup plugin bootstrap orchestrator (design\n * `插件独立分发与启动装配设计.md` §4.4, §0.7). Pure injectable decision loop\n * over the frozen factory manifest: every entry is compared against the\n * locally resolved active installations; missing plugins and factory entries\n * whose active version no longer satisfies the factory range are handed to\n * the npm install dependency — bootstrap never acquires through any other\n * source.\n *\n * Coverage rules (G5, with the 2026-10-04 install-and-use exception): a\n * satisfied range is skipped silently (zero acquisition calls, G3); a factory\n * entry whose range is unsatisfied is automatically realigned by installing\n * the factory range — factory plugins are version-locked to the running\n * framework, so an unsatisfied range is a broken compatibility state, not a\n * user preference to protect. User-installed third-party plugins are not in\n * the factory manifest and stay untouched. Failure semantics (G4): one\n * plugin's install failure is recorded and the loop continues; the run itself\n * never throws, and a failed entry self-heals on the next startup because it\n * stays unsatisfied. All effects live behind the injected dependencies, so\n * the loop is fully deterministic under mocks.\n */\n\nimport type { PluginBootstrapFactoryEntryV1 } from \"./bootstrap-factory-manifest.ts\";\nimport { selectNpmPackageVersionV1 } from \"./node-npm-registry-source.ts\";\nimport { PluginAcquisitionErrorV1 } from \"./plugin-acquisition.ts\";\n\nexport const PLUGIN_BOOTSTRAP_VERSION_V1 = 1 as const;\n\n/** Read-only local lookup of active installation versions (never networked). */\nexport type PluginBootstrapListActiveV1 = (input: {\n\treadonly signal?: AbortSignal;\n}) => Promise<ReadonlyMap<string, string>>;\n\n/** npm-only install action; resolves with the installed version and source label. */\nexport type PluginBootstrapInstallFromNpmV1 = (input: {\n\treadonly npmName: string;\n\treadonly range?: string;\n\treadonly signal?: AbortSignal;\n}) => Promise<{ readonly pluginVersion: string; readonly source: string }>;\n\nexport interface PluginBootstrapDepsV1 {\n\treadonly listActive: PluginBootstrapListActiveV1;\n\treadonly installFromNpm: PluginBootstrapInstallFromNpmV1;\n\t/** Deterministic clock for the observed duration; defaults to Date.now. */\n\treadonly now?: () => number;\n\t/** Cooperative cancellation; checked before each manifest entry. */\n\treadonly signal?: AbortSignal;\n}\n\nexport type PluginBootstrapActionStatusV1 = \"skipped\" | \"installed\" | \"failed\";\n\nexport type PluginBootstrapActionReasonV1 =\n\t| \"satisfies_range\"\n\t| \"installed\"\n\t| \"range_aligned\"\n\t| \"install_failed\"\n\t| \"align_failed\";\n\n/** One per-entry outcome; the version fields carry what each status observed. */\nexport interface PluginBootstrapActionV1 {\n\treadonly pluginId: string;\n\treadonly status: PluginBootstrapActionStatusV1;\n\treadonly reason: PluginBootstrapActionReasonV1;\n\treadonly npmName: string;\n\treadonly range?: string;\n\t/** Active version that decided a skipped outcome. */\n\treadonly activeVersion?: string;\n\t/** Version reported by the install action. */\n\treadonly installedVersion?: string;\n\t/** npm source label reported by the install action. */\n\treadonly source?: string;\n\t/** Acquisition or install failure code for failed actions. */\n\treadonly errorCode?: string;\n}\n\nexport type PluginBootstrapDiagnosticCodeV1 =\n\t| \"install_failed\"\n\t| \"list_active_failed\"\n\t| \"cancelled\"\n\t| \"bootstrap_failed\"\n\t| \"bootstrap_skipped_offline\";\n\nexport interface PluginBootstrapDiagnosticV1 {\n\treadonly code: PluginBootstrapDiagnosticCodeV1;\n\treadonly message: string;\n\treadonly pluginId?: string;\n}\n\nexport type PluginBootstrapStatusV1 = \"succeeded\" | \"failed\";\n\nexport interface PluginBootstrapResultV1 {\n\treadonly version: typeof PLUGIN_BOOTSTRAP_VERSION_V1;\n\t/** Aggregated outcome: failed (any failed entry) > succeeded. */\n\treadonly status: PluginBootstrapStatusV1;\n\treadonly actions: readonly PluginBootstrapActionV1[];\n\treadonly diagnostics: readonly PluginBootstrapDiagnosticV1[];\n\treadonly durationMs: number;\n}\n\n/**\n * A version satisfies a factory range under the same selection semantics npm\n * resolution uses: it is the version that would be picked if it were the only\n * candidate. Keeps local comparison and registry resolution consistent.\n */\nfunction satisfiesRangeV1(version: string, range: string | undefined): boolean {\n\treturn selectNpmPackageVersionV1([version], range) === version;\n}\n\n/** Executable repair command for diagnostics (G4 remediation hint). */\nexport function pluginBootstrapInstallCommandV1(entry: { readonly npmName: string; readonly range?: string }): string {\n\treturn `agent-forge plugin install ${entry.npmName}@${entry.range ?? \"latest\"}`;\n}\n\nfunction errorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction acquireErrorCode(error: unknown): string {\n\treturn error instanceof PluginAcquisitionErrorV1 ? error.code : \"install_failed\";\n}\n\nfunction actionOf(\n\tentry: PluginBootstrapFactoryEntryV1,\n\tstatus: PluginBootstrapActionStatusV1,\n\treason: PluginBootstrapActionReasonV1,\n): PluginBootstrapActionV1 {\n\treturn Object.freeze({\n\t\tpluginId: entry.pluginId,\n\t\tstatus,\n\t\treason,\n\t\tnpmName: entry.npmName,\n\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t});\n}\n\n/**\n * Run the bootstrap decision loop. An empty manifest short-circuits before\n * any dependency is touched, so the factory-empty S1-c2 state performs zero\n * reads on real startups.\n */\nexport async function runPluginBootstrapV1(input: {\n\treadonly manifest: readonly PluginBootstrapFactoryEntryV1[];\n\treadonly deps: PluginBootstrapDepsV1;\n\t/**\n\t * Fired once after the local active-state read when at least one factory\n\t * entry has no active installation — the host's first-run progress line\n\t * hook (设计 §4.4 首装进度行, 2026-10-03): a fresh install is otherwise\n\t * silent for the whole network install window. Injected effect, the loop\n\t * itself stays free of console I/O.\n\t */\n\treadonly onPendingInstalls?: (count: number) => void;\n\t/**\n\t * Fired when an install/align actually starts (2026-10-08 启动走查): npm\n\t * metadata + tarball take seconds per plugin, so the waiting user needs a\n\t * per-entry start line, not only the completion lines. Upgrade alignments\n\t * fire this too.\n\t */\n\treadonly onInstallStart?: (entry: { readonly npmName: string; readonly pluginId: string }) => void;\n\t/**\n\t * Fired after every per-entry action (设计 §4.4 逐插件进度, 2026-10-04):\n\t * the host renders one line per install/align/failure so the waiting user\n\t * sees live state; skipped entries stay silent at the host's discretion.\n\t * Injected effect, the loop itself stays free of console I/O.\n\t */\n\treadonly onAction?: (action: PluginBootstrapActionV1) => void;\n}): Promise<PluginBootstrapResultV1> {\n\tconst now = input.deps.now ?? Date.now;\n\tconst startedAt = now();\n\tconst finish = (\n\t\tstatus: PluginBootstrapStatusV1,\n\t\tactions: readonly PluginBootstrapActionV1[],\n\t\tdiagnostics: readonly PluginBootstrapDiagnosticV1[],\n\t): PluginBootstrapResultV1 =>\n\t\tObject.freeze({\n\t\t\tversion: PLUGIN_BOOTSTRAP_VERSION_V1,\n\t\t\tstatus,\n\t\t\tactions: Object.freeze([...actions]),\n\t\t\tdiagnostics: Object.freeze([...diagnostics]),\n\t\t\tdurationMs: Math.max(0, now() - startedAt),\n\t\t});\n\tif (input.manifest.length === 0) return finish(\"succeeded\", [], []);\n\tconst signal = input.deps.signal;\n\tlet active: ReadonlyMap<string, string>;\n\ttry {\n\t\tactive = await input.deps.listActive({ ...(signal === undefined ? {} : { signal }) });\n\t} catch (error) {\n\t\treturn finish(\n\t\t\t\"failed\",\n\t\t\t[],\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\tcode: \"list_active_failed\",\n\t\t\t\t\tmessage: `Active plugin state could not be read; bootstrap installed nothing: ${errorMessage(error)}`,\n\t\t\t\t},\n\t\t\t],\n\t\t);\n\t}\n\tconst actions: PluginBootstrapActionV1[] = [];\n\tconst diagnostics: PluginBootstrapDiagnosticV1[] = [];\n\t// Per-entry results slot by manifest index: parallel workers complete out of\n\t// order, but actions/diagnostics and their callbacks keep a stable order —\n\t// onAction stays live (fires the moment an entry settles) while the arrays\n\t// the result carries always read in manifest order.\n\tconst slots: Array<{ actions: PluginBootstrapActionV1[]; diagnostics: PluginBootstrapDiagnosticV1[] }> =\n\t\tinput.manifest.map(() => ({ actions: [], diagnostics: [] }));\n\tconst record = (index: number, action: PluginBootstrapActionV1): void => {\n\t\tslots[index]!.actions.push(action);\n\t\tinput.onAction?.(action);\n\t};\n\tconst addDiagnostic = (index: number, diagnostic: PluginBootstrapDiagnosticV1): void => {\n\t\tslots[index]!.diagnostics.push(diagnostic);\n\t};\n\tif (input.onPendingInstalls !== undefined) {\n\t\t// Upgrades count too (2026-10-08 启动走查): an active version outside the\n\t\t// factory range goes through the same npm install window as a missing\n\t\t// one — counting only missing entries left upgrade startups silent for\n\t\t// the whole alignment (real replay: 9 plugins, 38s, zero feedback).\n\t\tconst pending = input.manifest.filter((entry) => {\n\t\t\tconst activeVersion = active.get(entry.pluginId);\n\t\t\treturn activeVersion === undefined || !satisfiesRangeV1(activeVersion, entry.range);\n\t\t}).length;\n\t\tif (pending > 0) input.onPendingInstalls(pending);\n\t}\n\tconst processEntry = async (index: number, entry: PluginBootstrapFactoryEntryV1): Promise<void> => {\n\t\tconst signal = input.deps.signal;\n\t\tconst activeVersion = active.get(entry.pluginId);\n\t\tif (activeVersion !== undefined && satisfiesRangeV1(activeVersion, entry.range)) {\n\t\t\trecord(index, Object.freeze({ ...actionOf(entry, \"skipped\", \"satisfies_range\"), activeVersion }));\n\t\t\treturn;\n\t\t}\n\t\tinput.onInstallStart?.({ npmName: entry.npmName, pluginId: entry.pluginId });\n\t\ttry {\n\t\t\tconst installed = await input.deps.installFromNpm({\n\t\t\t\tnpmName: entry.npmName,\n\t\t\t\t...(entry.range === undefined ? {} : { range: entry.range }),\n\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t});\n\t\t\trecord(\n\t\t\t\tindex,\n\t\t\t\tObject.freeze({\n\t\t\t\t\t...actionOf(entry, \"installed\", activeVersion === undefined ? \"installed\" : \"range_aligned\"),\n\t\t\t\t\tinstalledVersion: installed.pluginVersion,\n\t\t\t\t\tsource: installed.source,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst errorCode = acquireErrorCode(error);\n\t\t\tconst aligning = activeVersion !== undefined;\n\t\t\trecord(\n\t\t\t\tindex,\n\t\t\t\tObject.freeze({ ...actionOf(entry, \"failed\", aligning ? \"align_failed\" : \"install_failed\"), errorCode }),\n\t\t\t);\n\t\t\taddDiagnostic(\n\t\t\t\tindex,\n\t\t\t\taligning\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcode: \"install_failed\",\n\t\t\t\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t`Bootstrap could not align ${entry.pluginId} (active ${activeVersion}) to the factory range ` +\n\t\t\t\t\t\t\t\t`${entry.range ?? \"latest\"} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t\t\t\t`Startup continues; the factory range stays unsatisfied, so the next startup retries automatically. ` +\n\t\t\t\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to align it now.`,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tcode: \"install_failed\",\n\t\t\t\t\t\t\tpluginId: entry.pluginId,\n\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t`Bootstrap could not install ${entry.pluginId} from npm (${errorCode}: ${errorMessage(error)}). ` +\n\t\t\t\t\t\t\t\t`Startup continues without it; its capabilities stay unavailable until installed, ` +\n\t\t\t\t\t\t\t\t`and the next startup retries automatically. ` +\n\t\t\t\t\t\t\t\t`Run \\`${pluginBootstrapInstallCommandV1(entry)}\\` to install it manually.`,\n\t\t\t\t\t\t},\n\t\t\t);\n\t\t}\n\t};\n\t// Bounded parallelism (2026-10-08 启动走查): serial npm alignment held a\n\t// 0.88.7→0.88.8 upgrade startup hostage for ~38s (9 plugins × metadata +\n\t// tarball, each silent). Four workers cut the wall time to roughly the\n\t// slowest four installs while the npm acquisition host and the per-plugin\n\t// activation chains stay per-key serialized underneath.\n\tconst WORKERS = 4;\n\tlet cursor = 0;\n\tlet cancelNoted = false;\n\tconst worker = async (): Promise<void> => {\n\t\twhile (cursor < input.manifest.length) {\n\t\t\tif (input.deps.signal?.aborted === true) {\n\t\t\t\tif (!cancelNoted) {\n\t\t\t\t\tcancelNoted = true;\n\t\t\t\t\tdiagnostics.push({\n\t\t\t\t\t\tcode: \"cancelled\",\n\t\t\t\t\t\tmessage: \"Plugin bootstrap was cancelled before all factory entries were processed\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst index = cursor++;\n\t\t\tawait processEntry(index, input.manifest[index]!);\n\t\t}\n\t};\n\tawait Promise.all(Array.from({ length: Math.min(WORKERS, input.manifest.length) }, worker));\n\tfor (const slot of slots) {\n\t\tactions.push(...slot.actions);\n\t\tdiagnostics.push(...slot.diagnostics);\n\t}\n\tconst status: PluginBootstrapStatusV1 = actions.some((action) => action.status === \"failed\")\n\t\t? \"failed\"\n\t\t: \"succeeded\";\n\treturn finish(status, actions, diagnostics);\n}\n"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-forge-extension-with-deps",
|
|
3
|
-
"version": "0.88.
|
|
3
|
+
"version": "0.88.10",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "agent-forge-extension-with-deps",
|
|
9
|
-
"version": "0.88.
|
|
9
|
+
"version": "0.88.10",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|