aws-runtime-bridge 1.6.2 → 1.6.5
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.
|
@@ -47,5 +47,6 @@ export declare function buildToolStatusDetectionTargets(enabledTools: string[]):
|
|
|
47
47
|
* 汇总卸载后仍可执行的工具,用于避免把部分卸载误报为成功。
|
|
48
48
|
*/
|
|
49
49
|
export declare function buildUninstallFailureMessage(requestedTools: string[], toolStatus: Record<string, ToolInstallStatus>): string;
|
|
50
|
+
export declare function summarizeToolStatus(toolStatus: Record<string, ToolInstallStatus>): Record<string, Pick<ToolInstallStatus, "installed" | "version" | "executable" | "error">>;
|
|
50
51
|
export {};
|
|
51
52
|
//# sourceMappingURL=instance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/routes/instance.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAC/D,IAAI,CAEN;AAED,eAAO,MAAM,cAAc,4CAAW,CAAC;AAyBvC,wBAAgB,4BAA4B,CAAC,gBAAgB,EAAE,MAAM,GAAG;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QACJ,EAAE,EAAE,OAAO,CAAC;QACZ,aAAa,CAAC,EAAE,SAAS,CAAC;QAC1B,oBAAoB,EAAE,OAAO,CAAC;QAC9B,qBAAqB,EAAE,OAAO,CAAC;QAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAqCA;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iCAAiC;IACzC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,KAAK,EACZ,0BAA0B,EAAE,MAAM,GACjC,4BAA4B,CAiB9B;AAED;;;GAGG;AACH,wBAAgB,sCAAsC,CACpD,UAAU,EAAE,MAAM,EAAE,GACnB,iCAAiC,CAUnC;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQhF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,EAAE,EACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC5C,MAAM,CAaR"}
|
|
1
|
+
{"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/routes/instance.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAYrD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAC/D,IAAI,CAEN;AAED,eAAO,MAAM,cAAc,4CAAW,CAAC;AAyBvC,wBAAgB,4BAA4B,CAAC,gBAAgB,EAAE,MAAM,GAAG;IACtE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE;QACJ,EAAE,EAAE,OAAO,CAAC;QACZ,aAAa,CAAC,EAAE,SAAS,CAAC;QAC1B,oBAAoB,EAAE,OAAO,CAAC;QAC9B,qBAAqB,EAAE,OAAO,CAAC;QAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,CAqCA;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iCAAiC;IACzC,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,8BAA8B,CAAC;IACtC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,KAAK,EACZ,0BAA0B,EAAE,MAAM,GACjC,4BAA4B,CAiB9B;AAED;;;GAGG;AACH,wBAAgB,sCAAsC,CACpD,UAAU,EAAE,MAAM,EAAE,GACnB,iCAAiC,CAUnC;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQhF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,EAAE,EACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC5C,MAAM,CAaR;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAC5C,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,OAAO,CAAC,CAAC,CAY3F"}
|
package/dist/routes/instance.js
CHANGED
|
@@ -132,6 +132,17 @@ export function buildUninstallFailureMessage(requestedTools, toolStatus) {
|
|
|
132
132
|
})
|
|
133
133
|
.join("; ");
|
|
134
134
|
}
|
|
135
|
+
export function summarizeToolStatus(toolStatus) {
|
|
136
|
+
return Object.fromEntries(Object.entries(toolStatus || {}).map(([tool, status]) => [
|
|
137
|
+
tool,
|
|
138
|
+
{
|
|
139
|
+
installed: Boolean(status?.installed),
|
|
140
|
+
version: status?.version || null,
|
|
141
|
+
executable: status?.executable || null,
|
|
142
|
+
error: status?.error || null,
|
|
143
|
+
},
|
|
144
|
+
]));
|
|
145
|
+
}
|
|
135
146
|
instanceRouter.get("/healthz", (_req, res) => {
|
|
136
147
|
res.json({
|
|
137
148
|
ok: true,
|
|
@@ -180,6 +191,13 @@ instanceRouter.post("/init-instance", validateToken, async (req, res) => {
|
|
|
180
191
|
return;
|
|
181
192
|
}
|
|
182
193
|
try {
|
|
194
|
+
log.info("[init-instance] Request received", {
|
|
195
|
+
agentId: String(agentId),
|
|
196
|
+
workspacePath: String(workspacePath),
|
|
197
|
+
skillEnabled,
|
|
198
|
+
mcpEnabled,
|
|
199
|
+
ccSwitchEnabledTools,
|
|
200
|
+
});
|
|
183
201
|
const result = await initInstance(agentId, workspacePath, {
|
|
184
202
|
skillEnabled,
|
|
185
203
|
mcpEnabled,
|
|
@@ -188,10 +206,22 @@ instanceRouter.post("/init-instance", validateToken, async (req, res) => {
|
|
|
188
206
|
skillPackages,
|
|
189
207
|
mcpServers,
|
|
190
208
|
});
|
|
209
|
+
log.info("[init-instance] Initialization completed", {
|
|
210
|
+
agentId: String(agentId),
|
|
211
|
+
ok: result.ok,
|
|
212
|
+
logCount: result.logs?.length || 0,
|
|
213
|
+
enabledTools: result.enabledTools,
|
|
214
|
+
});
|
|
191
215
|
res.json(result);
|
|
192
216
|
}
|
|
193
217
|
catch (error) {
|
|
194
218
|
const err = error;
|
|
219
|
+
log.error("[init-instance] Initialization failed", {
|
|
220
|
+
agentId: String(agentId),
|
|
221
|
+
workspacePath: String(workspacePath),
|
|
222
|
+
error: err?.message || String(error),
|
|
223
|
+
stack: err?.stack || null,
|
|
224
|
+
});
|
|
195
225
|
res.status(400).json({
|
|
196
226
|
error: err?.message || "initialize instance failed",
|
|
197
227
|
});
|
|
@@ -204,11 +234,23 @@ instanceRouter.post("/cc-switch/state", validateToken, async (req, res) => {
|
|
|
204
234
|
return;
|
|
205
235
|
}
|
|
206
236
|
try {
|
|
237
|
+
log.info("[cc-switch/state] Request received", { agentId: String(agentId) });
|
|
207
238
|
const sdk = await loadCcSwitchSdk(agentId);
|
|
208
239
|
const imported = await discoverCcSwitchConfiguredItems(sdk);
|
|
209
240
|
const synced = await syncLegacyStateFromSdk(agentId, sdk);
|
|
210
241
|
const state = synced.state;
|
|
211
|
-
const
|
|
242
|
+
const detectionTargets = buildToolStatusDetectionTargets(state.enabledTools || []);
|
|
243
|
+
log.info("[cc-switch/state] Detecting SDK statuses", {
|
|
244
|
+
agentId: String(agentId),
|
|
245
|
+
detectionTargets,
|
|
246
|
+
});
|
|
247
|
+
const toolStatus = await detectToolStatuses(detectionTargets);
|
|
248
|
+
log.info("[cc-switch/state] SDK status detection completed", {
|
|
249
|
+
agentId: String(agentId),
|
|
250
|
+
toolStatus: summarizeToolStatus(toolStatus),
|
|
251
|
+
importedMcpCount: imported.mcpServers,
|
|
252
|
+
importedSkillCount: imported.skills,
|
|
253
|
+
});
|
|
212
254
|
res.json({
|
|
213
255
|
ok: true,
|
|
214
256
|
agentId: String(agentId),
|
|
@@ -221,6 +263,11 @@ instanceRouter.post("/cc-switch/state", validateToken, async (req, res) => {
|
|
|
221
263
|
}
|
|
222
264
|
catch (error) {
|
|
223
265
|
const err = error;
|
|
266
|
+
log.error("[cc-switch/state] Failed to load state", {
|
|
267
|
+
agentId: String(agentId),
|
|
268
|
+
error: err?.message || String(error),
|
|
269
|
+
stack: err?.stack || null,
|
|
270
|
+
});
|
|
224
271
|
res.status(400).json({ error: err?.message || "load state failed" });
|
|
225
272
|
}
|
|
226
273
|
});
|
|
@@ -237,9 +284,23 @@ instanceRouter.post("/cc-switch/install-tools", validateToken, async (req, res)
|
|
|
237
284
|
.toLowerCase())
|
|
238
285
|
.filter(Boolean)
|
|
239
286
|
: [];
|
|
287
|
+
log.info("[cc-switch/install-tools] Request received", {
|
|
288
|
+
agentId: String(agentId),
|
|
289
|
+
requestedTools,
|
|
290
|
+
});
|
|
240
291
|
const supportedInstallableTools = new Set(SUPPORTED_INSTALLABLE_TOOLS);
|
|
241
292
|
const installableTools = requestedTools.filter((tool) => supportedInstallableTools.has(tool));
|
|
293
|
+
log.info("[cc-switch/install-tools] Request normalized", {
|
|
294
|
+
agentId: String(agentId),
|
|
295
|
+
requestedTools,
|
|
296
|
+
installableTools,
|
|
297
|
+
supportedInstallableTools: SUPPORTED_INSTALLABLE_TOOLS,
|
|
298
|
+
});
|
|
242
299
|
if (installableTools.length === 0) {
|
|
300
|
+
log.warn("[cc-switch/install-tools] No supported installable tools requested", {
|
|
301
|
+
agentId: String(agentId),
|
|
302
|
+
requestedTools,
|
|
303
|
+
});
|
|
243
304
|
res
|
|
244
305
|
.status(400)
|
|
245
306
|
.json({
|
|
@@ -250,8 +311,22 @@ instanceRouter.post("/cc-switch/install-tools", validateToken, async (req, res)
|
|
|
250
311
|
try {
|
|
251
312
|
const state = await loadInstanceState(agentId);
|
|
252
313
|
const enabledTools = Array.from(new Set([...(state.enabledTools || []), ...installableTools]));
|
|
314
|
+
log.info("[cc-switch/install-tools] Starting installer", {
|
|
315
|
+
agentId: String(agentId),
|
|
316
|
+
installableTools,
|
|
317
|
+
previousEnabledTools: state.enabledTools || [],
|
|
318
|
+
nextEnabledTools: enabledTools,
|
|
319
|
+
});
|
|
253
320
|
const toolStatus = await ensureToolsInstalled(installableTools);
|
|
321
|
+
log.info("[cc-switch/install-tools] Installer completed", {
|
|
322
|
+
agentId: String(agentId),
|
|
323
|
+
toolStatus: summarizeToolStatus(toolStatus),
|
|
324
|
+
});
|
|
254
325
|
const refreshedToolStatus = await detectToolStatuses(enabledTools);
|
|
326
|
+
log.info("[cc-switch/install-tools] Refreshed enabled SDK statuses", {
|
|
327
|
+
agentId: String(agentId),
|
|
328
|
+
refreshedToolStatus: summarizeToolStatus(refreshedToolStatus),
|
|
329
|
+
});
|
|
255
330
|
const nextToolStatus = {
|
|
256
331
|
...refreshedToolStatus,
|
|
257
332
|
...toolStatus,
|
|
@@ -261,6 +336,20 @@ instanceRouter.post("/cc-switch/install-tools", validateToken, async (req, res)
|
|
|
261
336
|
enabledTools,
|
|
262
337
|
toolStatus: nextToolStatus,
|
|
263
338
|
});
|
|
339
|
+
const failedTools = Object.entries(nextToolStatus)
|
|
340
|
+
.filter(([, status]) => !status.installed)
|
|
341
|
+
.map(([tool, status]) => ({ tool, error: status.error || null }));
|
|
342
|
+
if (failedTools.length > 0) {
|
|
343
|
+
log.warn("[cc-switch/install-tools] Some SDKs remain unavailable", {
|
|
344
|
+
agentId: String(agentId),
|
|
345
|
+
failedTools,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
log.info("[cc-switch/install-tools] State saved", {
|
|
349
|
+
agentId: String(agentId),
|
|
350
|
+
enabledTools: savedState.enabledTools,
|
|
351
|
+
toolStatus: summarizeToolStatus(nextToolStatus),
|
|
352
|
+
});
|
|
264
353
|
res.json({
|
|
265
354
|
ok: true,
|
|
266
355
|
agentId: String(agentId),
|
|
@@ -270,6 +359,13 @@ instanceRouter.post("/cc-switch/install-tools", validateToken, async (req, res)
|
|
|
270
359
|
}
|
|
271
360
|
catch (error) {
|
|
272
361
|
const err = error;
|
|
362
|
+
log.error("[cc-switch/install-tools] Install route failed", {
|
|
363
|
+
agentId: String(agentId),
|
|
364
|
+
requestedTools,
|
|
365
|
+
installableTools,
|
|
366
|
+
error: err?.message || String(error),
|
|
367
|
+
stack: err?.stack || null,
|
|
368
|
+
});
|
|
273
369
|
res.status(400).json({ error: err?.message || "install tools failed" });
|
|
274
370
|
}
|
|
275
371
|
});
|
|
@@ -104,6 +104,40 @@ describe('instance route validation', () => {
|
|
|
104
104
|
},
|
|
105
105
|
})).toContain('opencode: uninstall completed but command is still available');
|
|
106
106
|
});
|
|
107
|
+
it('summarizes tool status for route diagnostics', async () => {
|
|
108
|
+
const { summarizeToolStatus } = await import('./instance.js');
|
|
109
|
+
expect(summarizeToolStatus({
|
|
110
|
+
opencode: {
|
|
111
|
+
tool: 'opencode',
|
|
112
|
+
installed: false,
|
|
113
|
+
executable: null,
|
|
114
|
+
version: null,
|
|
115
|
+
installing: false,
|
|
116
|
+
error: 'SDK package @opencode-ai/sdk is not installed in aws-runtime-bridge',
|
|
117
|
+
},
|
|
118
|
+
claude: {
|
|
119
|
+
tool: 'claude',
|
|
120
|
+
installed: true,
|
|
121
|
+
executable: '@anthropic-ai/claude-agent-sdk',
|
|
122
|
+
version: '0.2.87',
|
|
123
|
+
installing: false,
|
|
124
|
+
error: null,
|
|
125
|
+
},
|
|
126
|
+
})).toEqual({
|
|
127
|
+
opencode: {
|
|
128
|
+
installed: false,
|
|
129
|
+
executable: null,
|
|
130
|
+
version: null,
|
|
131
|
+
error: 'SDK package @opencode-ai/sdk is not installed in aws-runtime-bridge',
|
|
132
|
+
},
|
|
133
|
+
claude: {
|
|
134
|
+
installed: true,
|
|
135
|
+
executable: '@anthropic-ai/claude-agent-sdk',
|
|
136
|
+
version: '0.2.87',
|
|
137
|
+
error: null,
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
});
|
|
107
141
|
it('does not report uninstall failure when requested tools are no longer installed', async () => {
|
|
108
142
|
const { buildUninstallFailureMessage } = await import('./instance.js');
|
|
109
143
|
expect(buildUninstallFailureMessage(['claude'], {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-installer.d.ts","sourceRoot":"","sources":["../../src/services/tool-installer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-installer.d.ts","sourceRoot":"","sources":["../../src/services/tool-installer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAiHrD,eAAO,MAAM,2BAA2B,mBAEvC,CAAC;AAEF,eAAO,MAAM,6BAA6B,mBAIzC,CAAC;AAEF;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAK/D;AAoDD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAM5D;AAkOD;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAsC5B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAkB5C;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAqF5C;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAiD5C"}
|
|
@@ -4,7 +4,9 @@ import os from "node:os";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
|
+
import { createLogger } from "../utils/logger.js";
|
|
7
8
|
const execFileAsync = promisify(execFile);
|
|
9
|
+
const log = createLogger("tool-installer");
|
|
8
10
|
const bridgePackageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9
11
|
const isWindows = process.platform === "win32";
|
|
10
12
|
function quoteCommandArg(value) {
|
|
@@ -304,14 +306,30 @@ async function resolveSdkPackageCandidate(definition) {
|
|
|
304
306
|
};
|
|
305
307
|
}
|
|
306
308
|
}
|
|
309
|
+
function describeCommandFailure(error) {
|
|
310
|
+
if (!error || typeof error !== "object") {
|
|
311
|
+
return { message: String(error || "command failed") };
|
|
312
|
+
}
|
|
313
|
+
const failure = error;
|
|
314
|
+
return {
|
|
315
|
+
message: typeof failure.message === "string" ? failure.message : String(error),
|
|
316
|
+
code: failure.code ?? null,
|
|
317
|
+
signal: failure.signal ?? null,
|
|
318
|
+
stdout: typeof failure.stdout === "string" ? failure.stdout : "",
|
|
319
|
+
stderr: typeof failure.stderr === "string" ? failure.stderr : "",
|
|
320
|
+
};
|
|
321
|
+
}
|
|
307
322
|
async function runToolCommand(command) {
|
|
308
323
|
if (isWindows) {
|
|
309
|
-
await execFileAsync("cmd.exe", ["/d", "/s", "/c", command], {
|
|
324
|
+
const result = await execFileAsync("cmd.exe", ["/d", "/s", "/c", command], {
|
|
310
325
|
timeout: 10 * 60 * 1000,
|
|
311
326
|
});
|
|
312
|
-
return;
|
|
327
|
+
return { stdout: result.stdout || "", stderr: result.stderr || "" };
|
|
313
328
|
}
|
|
314
|
-
await execFileAsync("/bin/sh", ["-lc", command], {
|
|
329
|
+
const result = await execFileAsync("/bin/sh", ["-lc", command], {
|
|
330
|
+
timeout: 10 * 60 * 1000,
|
|
331
|
+
});
|
|
332
|
+
return { stdout: result.stdout || "", stderr: result.stderr || "" };
|
|
315
333
|
}
|
|
316
334
|
/**
|
|
317
335
|
* 检查单个工具的 CLI 可执行状态,供实例状态展示与初始化前判断使用。
|
|
@@ -322,6 +340,7 @@ export async function detectToolInstallStatus(tool) {
|
|
|
322
340
|
.toLowerCase();
|
|
323
341
|
const definition = TOOL_DEFINITIONS[normalizedTool];
|
|
324
342
|
if (!definition) {
|
|
343
|
+
log.warn("Unsupported tool status requested", { tool: normalizedTool });
|
|
325
344
|
return {
|
|
326
345
|
tool: normalizedTool,
|
|
327
346
|
installed: false,
|
|
@@ -370,25 +389,51 @@ export async function detectToolStatuses(tools) {
|
|
|
370
389
|
* 根据勾选工具自动安装缺失 CLI,安装后重新检测状态并返回。
|
|
371
390
|
*/
|
|
372
391
|
export async function ensureToolsInstalled(tools) {
|
|
392
|
+
log.info("Install request received", {
|
|
393
|
+
requestedTools: tools,
|
|
394
|
+
bridgePackageRoot,
|
|
395
|
+
platform: process.platform,
|
|
396
|
+
node: process.version,
|
|
397
|
+
});
|
|
373
398
|
const initialStatuses = await detectToolStatuses(tools);
|
|
399
|
+
log.info("Initial install status detected", { statuses: initialStatuses });
|
|
374
400
|
const nextStatuses = {
|
|
375
401
|
...initialStatuses,
|
|
376
402
|
};
|
|
377
403
|
for (const tool of Object.keys(initialStatuses)) {
|
|
378
404
|
const current = initialStatuses[tool];
|
|
379
405
|
if (current.installed) {
|
|
406
|
+
log.info("Skipping install because tool SDK is already available", {
|
|
407
|
+
tool,
|
|
408
|
+
version: current.version,
|
|
409
|
+
executable: current.executable,
|
|
410
|
+
});
|
|
380
411
|
continue;
|
|
381
412
|
}
|
|
382
413
|
const definition = TOOL_DEFINITIONS[tool];
|
|
383
414
|
if (!definition) {
|
|
415
|
+
log.warn("Skipping install because tool is unsupported", { tool, current });
|
|
384
416
|
continue;
|
|
385
417
|
}
|
|
386
418
|
let lastError = current.error;
|
|
387
419
|
for (const command of definition.installCommands) {
|
|
388
420
|
try {
|
|
389
|
-
|
|
421
|
+
log.info("Running install command", {
|
|
422
|
+
tool,
|
|
423
|
+
command,
|
|
424
|
+
sdkPackageName: definition.sdkPackageName || null,
|
|
425
|
+
packageName: definition.packageName,
|
|
426
|
+
});
|
|
427
|
+
const commandResult = await runToolCommand(command);
|
|
428
|
+
log.info("Install command completed", {
|
|
429
|
+
tool,
|
|
430
|
+
command,
|
|
431
|
+
stdout: commandResult.stdout,
|
|
432
|
+
stderr: commandResult.stderr,
|
|
433
|
+
});
|
|
390
434
|
const detected = await detectToolInstallStatus(tool);
|
|
391
435
|
nextStatuses[tool] = detected;
|
|
436
|
+
log.info("Post-install status detected", { tool, status: detected });
|
|
392
437
|
if (detected.installed) {
|
|
393
438
|
lastError = null;
|
|
394
439
|
break;
|
|
@@ -396,6 +441,11 @@ export async function ensureToolsInstalled(tools) {
|
|
|
396
441
|
lastError = detected.error;
|
|
397
442
|
}
|
|
398
443
|
catch (error) {
|
|
444
|
+
log.error("Install command failed", {
|
|
445
|
+
tool,
|
|
446
|
+
command,
|
|
447
|
+
failure: describeCommandFailure(error),
|
|
448
|
+
});
|
|
399
449
|
lastError =
|
|
400
450
|
error instanceof Error
|
|
401
451
|
? error.message
|
|
@@ -410,8 +460,14 @@ export async function ensureToolsInstalled(tools) {
|
|
|
410
460
|
installing: false,
|
|
411
461
|
error: lastError || "install failed",
|
|
412
462
|
};
|
|
463
|
+
log.warn("Tool SDK remains unavailable after install attempts", {
|
|
464
|
+
tool,
|
|
465
|
+
status: nextStatuses[tool],
|
|
466
|
+
attemptedCommands: definition.installCommands,
|
|
467
|
+
});
|
|
413
468
|
}
|
|
414
469
|
}
|
|
470
|
+
log.info("Install request completed", { statuses: nextStatuses });
|
|
415
471
|
return nextStatuses;
|
|
416
472
|
}
|
|
417
473
|
/**
|