ai-project-manage-cli 6.0.64 → 6.0.65

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.
Files changed (2) hide show
  1. package/dist/index.js +149 -403
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -473,33 +473,19 @@ var requestConfig = {
473
473
  method: "DELETE",
474
474
  path: "/cli/repository-project-documents"
475
475
  }),
476
- updateCoordinatorDeploymentStatus: defineEndpoint({
476
+ updateTaskDeploymentStatus: defineEndpoint({
477
477
  method: "PUT",
478
- path: "/cli/coordinator-deployments/status"
478
+ path: "/cli/task-deployments/status"
479
479
  }),
480
- syncCoordinatorDeploymentLog: defineEndpoint({
481
- method: "PUT",
482
- path: "/cli/coordinator-deployments/log"
483
- }),
484
- completeCoordinatorDeployment: defineEndpoint({
485
- method: "PUT",
486
- path: "/cli/coordinator-deployments/complete"
487
- }),
488
- updateCoordinatorDispatchStatus: defineEndpoint({
489
- method: "PUT",
490
- path: "/cli/coordinator-dispatches/status"
491
- }),
492
- appendCoordinatorDispatchResponse: defineEndpoint({
493
- method: "PUT",
494
- path: "/cli/coordinator-dispatches/append-response"
495
- }),
496
- completeCoordinatorDispatch: defineEndpoint({
480
+ syncTaskDeploymentLog: defineEndpoint(
481
+ {
482
+ method: "PUT",
483
+ path: "/cli/task-deployments/log"
484
+ }
485
+ ),
486
+ completeTaskDeployment: defineEndpoint({
497
487
  method: "PUT",
498
- path: "/cli/coordinator-dispatches/complete"
499
- }),
500
- createCoordinatorDispatchQuestions: defineEndpoint({
501
- method: "POST",
502
- path: "/cli/coordinator-dispatches/questions"
488
+ path: "/cli/task-deployments/complete"
503
489
  })
504
490
  }
505
491
  };
@@ -1760,8 +1746,12 @@ function registryBaseUrl() {
1760
1746
  const fromEnv = process.env.npm_config_registry?.trim() || process.env.NPM_CONFIG_REGISTRY?.trim();
1761
1747
  return (fromEnv || "https://registry.npmjs.org").replace(/\/+$/, "");
1762
1748
  }
1763
- async function fetchLatestPublishedVersion() {
1764
- const url = `${registryBaseUrl()}/${CLI_PACKAGE_NAME}/latest`;
1749
+ function parseMajorVersion(version) {
1750
+ const m = /^(\d+)/.exec(version.trim());
1751
+ return m ? Number(m[1]) : 0;
1752
+ }
1753
+ async function fetchPublishedVersion(spec) {
1754
+ const url = `${registryBaseUrl()}/${CLI_PACKAGE_NAME}/${spec}`;
1765
1755
  try {
1766
1756
  const res = await fetch(url);
1767
1757
  if (!res.ok) return null;
@@ -1771,28 +1761,73 @@ async function fetchLatestPublishedVersion() {
1771
1761
  return null;
1772
1762
  }
1773
1763
  }
1764
+ async function fetchLatestPublishedVersion() {
1765
+ return fetchPublishedVersion("latest");
1766
+ }
1767
+ async function fetchLatestPublishedVersionInMajor(major) {
1768
+ return fetchPublishedVersion(String(major));
1769
+ }
1770
+ function resolveUpdateTarget(input) {
1771
+ const { current, allowMajorUpgrade, latestInMajor, globalLatest } = input;
1772
+ const currentMajor = parseMajorVersion(current);
1773
+ if (allowMajorUpgrade) {
1774
+ if (globalLatest && globalLatest === current) {
1775
+ return { action: "skip" };
1776
+ }
1777
+ return {
1778
+ action: "install",
1779
+ installSpec: `${CLI_PACKAGE_NAME}@latest`,
1780
+ targetLabel: globalLatest ?? "latest",
1781
+ expectedVersion: globalLatest,
1782
+ majorUpgradeAvailable: null
1783
+ };
1784
+ }
1785
+ if (latestInMajor && latestInMajor === current) {
1786
+ return { action: "skip" };
1787
+ }
1788
+ const majorUpgradeAvailable = globalLatest && parseMajorVersion(globalLatest) > currentMajor ? globalLatest : null;
1789
+ return {
1790
+ action: "install",
1791
+ installSpec: `${CLI_PACKAGE_NAME}@${currentMajor}`,
1792
+ targetLabel: latestInMajor ?? String(currentMajor),
1793
+ expectedVersion: latestInMajor,
1794
+ majorUpgradeAvailable
1795
+ };
1796
+ }
1774
1797
  function npmAvailable() {
1775
1798
  const r = runNpm(["--version"], { encoding: "utf8" });
1776
1799
  return !r.error && r.status === 0;
1777
1800
  }
1778
- async function runUpdate() {
1801
+ async function runUpdate(options = {}) {
1779
1802
  const current = readCliVersion();
1780
- const latest = await fetchLatestPublishedVersion();
1781
- if (latest && current === latest) {
1803
+ const currentMajor = parseMajorVersion(current);
1804
+ const globalLatest = await fetchLatestPublishedVersion();
1805
+ const latestInMajor = options.allowMajorUpgrade ? null : await fetchLatestPublishedVersionInMajor(currentMajor);
1806
+ const resolved = resolveUpdateTarget({
1807
+ current,
1808
+ allowMajorUpgrade: options.allowMajorUpgrade,
1809
+ latestInMajor,
1810
+ globalLatest
1811
+ });
1812
+ if (resolved.action === "skip") {
1782
1813
  console.log(`[apm] \u5DF2\u662F\u6700\u65B0\u7248\u672C ${current}`);
1783
1814
  return { didUpdate: false };
1784
1815
  }
1816
+ if (resolved.majorUpgradeAvailable) {
1817
+ console.log(
1818
+ `[apm] registry \u6700\u65B0\u4E3A ${resolved.majorUpgradeAvailable}\uFF08\u5927\u7248\u672C\u5347\u7EA7\uFF09\uFF0C\u672C\u6B21\u4EC5\u66F4\u65B0\u5230 ${currentMajor}.x\uFF1B\u4F7F\u7528 apm update --major \u53EF\u8DE8\u5927\u7248\u672C\u5347\u7EA7`
1819
+ );
1820
+ }
1785
1821
  if (!npmAvailable()) {
1786
1822
  console.error(
1787
- `[apm] \u672A\u627E\u5230 npm\u3002\u8BF7\u5B89\u88C5 Node.js \u540E\u6267\u884C\uFF1Anpm install -g ${CLI_PACKAGE_NAME}@latest`
1823
+ `[apm] \u672A\u627E\u5230 npm\u3002\u8BF7\u5B89\u88C5 Node.js \u540E\u6267\u884C\uFF1Anpm install -g ${resolved.installSpec}`
1788
1824
  );
1789
1825
  process.exit(1);
1790
1826
  }
1791
- const targetLabel = latest ?? "latest";
1792
1827
  console.error(
1793
- `[apm] \u5F53\u524D\u7248\u672C ${current}\uFF0C\u6B63\u5728\u5B89\u88C5 ${CLI_PACKAGE_NAME}@${targetLabel} \u2026`
1828
+ `[apm] \u5F53\u524D\u7248\u672C ${current}\uFF0C\u6B63\u5728\u5B89\u88C5 ${resolved.installSpec} \u2026` + (resolved.targetLabel !== current ? `\uFF08\u76EE\u6807 ${resolved.targetLabel}\uFF09` : "")
1794
1829
  );
1795
- const install = runNpm(["install", "-g", `${CLI_PACKAGE_NAME}@latest`], {
1830
+ const install = runNpm(["install", "-g", resolved.installSpec], {
1796
1831
  stdio: "inherit"
1797
1832
  });
1798
1833
  if (install.error) {
@@ -1803,7 +1838,7 @@ async function runUpdate() {
1803
1838
  process.exit(install.status ?? 1);
1804
1839
  }
1805
1840
  const after = readCliVersion();
1806
- if (latest && after === latest) {
1841
+ if (resolved.expectedVersion && after === resolved.expectedVersion) {
1807
1842
  console.log(`[apm] \u5DF2\u66F4\u65B0\u5230 ${after}`);
1808
1843
  } else {
1809
1844
  console.log(
@@ -2168,113 +2203,13 @@ function validateDeployPush(o) {
2168
2203
  }
2169
2204
  };
2170
2205
  }
2171
- function validateCoordinatorDispatchMode(mode) {
2172
- return mode === "plan" || mode === "agent";
2173
- }
2174
- function validateCoordinatorDispatchPush(o) {
2175
- if (o.type !== "coordinator_dispatch") {
2176
- return { ok: false, reason: "\u671F\u671B coordinator_dispatch" };
2177
- }
2178
- if (!nonEmptyString(o.dispatchId)) {
2179
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 dispatchId" };
2180
- }
2181
- if (!nonEmptyString(o.dispatchSessionId)) {
2182
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 dispatchSessionId" };
2183
- }
2184
- if (!validateCoordinatorDispatchMode(o.mode)) {
2185
- return { ok: false, reason: "coordinator_dispatch.mode \u65E0\u6548" };
2186
- }
2187
- if (!nonEmptyString(o.content)) {
2188
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 content" };
2189
- }
2190
- if (!nonEmptyString(o.model)) {
2191
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 model" };
2192
- }
2193
- if (!nonEmptyString(o.apiKey)) {
2194
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 apiKey" };
2195
- }
2196
- if (!nonEmptyString(o.workdir)) {
2197
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 workdir" };
2198
- }
2199
- if (!nonEmptyString(o.user)) {
2200
- return { ok: false, reason: "coordinator_dispatch \u7F3A\u5C11 user" };
2201
- }
2202
- const data = {
2203
- type: "coordinator_dispatch",
2204
- dispatchId: o.dispatchId.trim(),
2205
- dispatchSessionId: o.dispatchSessionId.trim(),
2206
- mode: o.mode,
2207
- content: o.content,
2208
- model: o.model.trim(),
2209
- apiKey: o.apiKey.trim(),
2210
- workdir: o.workdir.trim(),
2211
- user: o.user.trim()
2212
- };
2213
- if (nonEmptyString(o.resumeAgentId)) {
2214
- data.resumeAgentId = o.resumeAgentId.trim();
2215
- }
2216
- return { ok: true, data };
2217
- }
2218
- function validateCoordinatorDispatchResumePush(o) {
2219
- if (o.type !== "coordinator_dispatch_resume") {
2220
- return { ok: false, reason: "\u671F\u671B coordinator_dispatch_resume" };
2221
- }
2222
- if (!nonEmptyString(o.dispatchId)) {
2223
- return { ok: false, reason: "coordinator_dispatch_resume \u7F3A\u5C11 dispatchId" };
2224
- }
2225
- if (!nonEmptyString(o.dispatchSessionId)) {
2226
- return {
2227
- ok: false,
2228
- reason: "coordinator_dispatch_resume \u7F3A\u5C11 dispatchSessionId"
2229
- };
2230
- }
2231
- if (!validateCoordinatorDispatchMode(o.mode)) {
2232
- return { ok: false, reason: "coordinator_dispatch_resume.mode \u65E0\u6548" };
2233
- }
2234
- if (!nonEmptyString(o.content)) {
2235
- return { ok: false, reason: "coordinator_dispatch_resume \u7F3A\u5C11 content" };
2236
- }
2237
- if (!nonEmptyString(o.resumeAgentId)) {
2238
- return {
2239
- ok: false,
2240
- reason: "coordinator_dispatch_resume \u7F3A\u5C11 resumeAgentId"
2241
- };
2242
- }
2243
- if (!nonEmptyString(o.model)) {
2244
- return { ok: false, reason: "coordinator_dispatch_resume \u7F3A\u5C11 model" };
2245
- }
2246
- if (!nonEmptyString(o.apiKey)) {
2247
- return { ok: false, reason: "coordinator_dispatch_resume \u7F3A\u5C11 apiKey" };
2248
- }
2249
- if (!nonEmptyString(o.workdir)) {
2250
- return { ok: false, reason: "coordinator_dispatch_resume \u7F3A\u5C11 workdir" };
2251
- }
2252
- if (!nonEmptyString(o.user)) {
2253
- return { ok: false, reason: "coordinator_dispatch_resume \u7F3A\u5C11 user" };
2254
- }
2255
- return {
2256
- ok: true,
2257
- data: {
2258
- type: "coordinator_dispatch_resume",
2259
- dispatchId: o.dispatchId.trim(),
2260
- dispatchSessionId: o.dispatchSessionId.trim(),
2261
- mode: o.mode,
2262
- content: o.content,
2263
- resumeAgentId: o.resumeAgentId.trim(),
2264
- model: o.model.trim(),
2265
- apiKey: o.apiKey.trim(),
2266
- workdir: o.workdir.trim(),
2267
- user: o.user.trim()
2268
- }
2269
- };
2270
- }
2271
2206
  function validateAgentWsMessage(value, kind) {
2272
2207
  if (typeof value !== "object" || value === null) {
2273
2208
  return { ok: false, reason: "\u6D88\u606F\u4F53\u4E0D\u662F JSON \u5BF9\u8C61" };
2274
2209
  }
2275
2210
  const o = value;
2276
2211
  const type = o.type;
2277
- if (type !== "heartbeat" && type !== "message" && type !== "cancel" && type !== "deploy" && type !== "coordinator_dispatch" && type !== "coordinator_dispatch_resume") {
2212
+ if (type !== "heartbeat" && type !== "message" && type !== "cancel" && type !== "deploy") {
2278
2213
  return { ok: false, reason: `\u672A\u77E5 type: ${String(type)}` };
2279
2214
  }
2280
2215
  if (kind === "heartbeat" || type === "heartbeat") {
@@ -2286,12 +2221,6 @@ function validateAgentWsMessage(value, kind) {
2286
2221
  if (type === "deploy") {
2287
2222
  return validateDeployPush(o);
2288
2223
  }
2289
- if (type === "coordinator_dispatch") {
2290
- return validateCoordinatorDispatchPush(o);
2291
- }
2292
- if (type === "coordinator_dispatch_resume") {
2293
- return validateCoordinatorDispatchResumePush(o);
2294
- }
2295
2224
  return validateMessagePush(o);
2296
2225
  }
2297
2226
 
@@ -2378,7 +2307,7 @@ function createDeployLogSyncer(api, deploymentRunId) {
2378
2307
  if (!latestLog || latestLog === lastSyncedLog) {
2379
2308
  return;
2380
2309
  }
2381
- await api.cli.syncCoordinatorDeploymentLog({
2310
+ await api.cli.syncTaskDeploymentLog({
2382
2311
  id: deploymentRunId,
2383
2312
  log: latestLog
2384
2313
  });
@@ -2409,7 +2338,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2409
2338
  const api = createApmApiClient(cfg);
2410
2339
  const deploymentRunId = msg.deploymentRunId;
2411
2340
  if (signal.aborted) return;
2412
- await api.cli.updateCoordinatorDeploymentStatus({
2341
+ await api.cli.updateTaskDeploymentStatus({
2413
2342
  id: deploymentRunId,
2414
2343
  status: "DEPLOYING"
2415
2344
  });
@@ -2418,7 +2347,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2418
2347
  if (!command) {
2419
2348
  const error = missingDeployCommandMessage(msg.environment);
2420
2349
  console.error(`[apm] ${error}`);
2421
- await api.cli.completeCoordinatorDeployment({
2350
+ await api.cli.completeTaskDeployment({
2422
2351
  id: deploymentRunId,
2423
2352
  status: "FAILED",
2424
2353
  log: error,
@@ -2440,7 +2369,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2440
2369
  latestLog = log;
2441
2370
  logSyncer.updateLog(log);
2442
2371
  await logSyncer.flush();
2443
- await api.cli.completeCoordinatorDeployment({
2372
+ await api.cli.completeTaskDeployment({
2444
2373
  id: deploymentRunId,
2445
2374
  status: "SUCCESS",
2446
2375
  log
@@ -2451,7 +2380,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2451
2380
  const log = error && typeof error === "object" && "log" in error ? String(error.log ?? latestLog) : latestLog;
2452
2381
  logSyncer.updateLog(log);
2453
2382
  await logSyncer.flush();
2454
- await api.cli.completeCoordinatorDeployment({
2383
+ await api.cli.completeTaskDeployment({
2455
2384
  id: deploymentRunId,
2456
2385
  status: "FAILED",
2457
2386
  log,
@@ -2463,6 +2392,69 @@ async function handleInboundDeploy(cfg, msg, signal) {
2463
2392
  }
2464
2393
  }
2465
2394
 
2395
+ // src/commands/connect/abort-signal-debug.ts
2396
+ import {
2397
+ getEventListeners,
2398
+ getMaxListeners,
2399
+ setMaxListeners
2400
+ } from "node:events";
2401
+ function isAbortSignalDebugEnabled() {
2402
+ const v = process.env.APM_DEBUG_ABORT_SIGNAL?.trim().toLowerCase();
2403
+ return v === "1" || v === "true" || v === "yes";
2404
+ }
2405
+ function formatAbortSignalStats(signal, label) {
2406
+ if (!signal) {
2407
+ return `[apm:abort-debug] ${label}: (no signal)`;
2408
+ }
2409
+ const listeners = getEventListeners(signal, "abort");
2410
+ const max = getMaxListeners(signal);
2411
+ return `[apm:abort-debug] ${label}: abortListeners=${listeners.length} maxListeners=${max} aborted=${signal.aborted}`;
2412
+ }
2413
+ function logAbortSignalStats(signal, label) {
2414
+ if (!isAbortSignalDebugEnabled()) return;
2415
+ console.log(formatAbortSignalStats(signal, label));
2416
+ }
2417
+ var installed = false;
2418
+ function installAbortSignalDebug() {
2419
+ if (!isAbortSignalDebugEnabled() || installed) return;
2420
+ installed = true;
2421
+ const maxFromEnv = Number.parseInt(
2422
+ process.env.APM_ABORT_SIGNAL_MAX_LISTENERS ?? "",
2423
+ 10
2424
+ );
2425
+ if (Number.isFinite(maxFromEnv) && maxFromEnv > 0) {
2426
+ setMaxListeners(maxFromEnv);
2427
+ console.log(
2428
+ `[apm:abort-debug] setMaxListeners(${maxFromEnv}) via APM_ABORT_SIGNAL_MAX_LISTENERS`
2429
+ );
2430
+ }
2431
+ process.on("warning", (warning) => {
2432
+ if (warning.name !== "MaxListenersExceededWarning") return;
2433
+ console.warn(`[apm:abort-debug] ${warning.name}: ${warning.message}`);
2434
+ if (warning.stack) {
2435
+ console.warn(warning.stack);
2436
+ }
2437
+ });
2438
+ const proto = AbortSignal.prototype;
2439
+ const original = proto.addEventListener;
2440
+ proto.addEventListener = function(type, listener, options) {
2441
+ if (type === "abort") {
2442
+ const sig = this;
2443
+ const before = getEventListeners(sig, "abort").length;
2444
+ const max = getMaxListeners(sig);
2445
+ const stack = new Error("[apm:abort-debug] addEventListener stack").stack?.split("\n").slice(2, 8).join("\n") ?? "";
2446
+ console.log(
2447
+ `[apm:abort-debug] addEventListener("abort") before=${before} max=${max}
2448
+ ${stack}`
2449
+ );
2450
+ }
2451
+ return original.call(this, type, listener, options);
2452
+ };
2453
+ console.log(
2454
+ "[apm:abort-debug] \u5DF2\u542F\u7528 AbortSignal \u8C03\u8BD5\uFF08APM_DEBUG_ABORT_SIGNAL\uFF09"
2455
+ );
2456
+ }
2457
+
2466
2458
  // src/commands/connect/cursor-agent.ts
2467
2459
  import {
2468
2460
  Agent,
@@ -2792,97 +2784,6 @@ async function syncCursorMessageLog(cfg, ctx, events) {
2792
2784
  });
2793
2785
  }
2794
2786
 
2795
- // src/commands/connect/abort-signal-debug.ts
2796
- import {
2797
- getEventListeners,
2798
- getMaxListeners,
2799
- setMaxListeners
2800
- } from "node:events";
2801
- function isAbortSignalDebugEnabled() {
2802
- const v = process.env.APM_DEBUG_ABORT_SIGNAL?.trim().toLowerCase();
2803
- return v === "1" || v === "true" || v === "yes";
2804
- }
2805
- function formatAbortSignalStats(signal, label) {
2806
- if (!signal) {
2807
- return `[apm:abort-debug] ${label}: (no signal)`;
2808
- }
2809
- const listeners = getEventListeners(signal, "abort");
2810
- const max = getMaxListeners(signal);
2811
- return `[apm:abort-debug] ${label}: abortListeners=${listeners.length} maxListeners=${max} aborted=${signal.aborted}`;
2812
- }
2813
- function logAbortSignalStats(signal, label) {
2814
- if (!isAbortSignalDebugEnabled()) return;
2815
- console.log(formatAbortSignalStats(signal, label));
2816
- }
2817
- var installed = false;
2818
- function installAbortSignalDebug() {
2819
- if (!isAbortSignalDebugEnabled() || installed) return;
2820
- installed = true;
2821
- const maxFromEnv = Number.parseInt(
2822
- process.env.APM_ABORT_SIGNAL_MAX_LISTENERS ?? "",
2823
- 10
2824
- );
2825
- if (Number.isFinite(maxFromEnv) && maxFromEnv > 0) {
2826
- setMaxListeners(maxFromEnv);
2827
- console.log(
2828
- `[apm:abort-debug] setMaxListeners(${maxFromEnv}) via APM_ABORT_SIGNAL_MAX_LISTENERS`
2829
- );
2830
- }
2831
- process.on("warning", (warning) => {
2832
- if (warning.name !== "MaxListenersExceededWarning") return;
2833
- console.warn(`[apm:abort-debug] ${warning.name}: ${warning.message}`);
2834
- if (warning.stack) {
2835
- console.warn(warning.stack);
2836
- }
2837
- });
2838
- const proto = AbortSignal.prototype;
2839
- const original = proto.addEventListener;
2840
- proto.addEventListener = function(type, listener, options) {
2841
- if (type === "abort") {
2842
- const sig = this;
2843
- const before = getEventListeners(sig, "abort").length;
2844
- const max = getMaxListeners(sig);
2845
- const stack = new Error("[apm:abort-debug] addEventListener stack").stack?.split("\n").slice(2, 8).join("\n") ?? "";
2846
- console.log(
2847
- `[apm:abort-debug] addEventListener("abort") before=${before} max=${max}
2848
- ${stack}`
2849
- );
2850
- }
2851
- return original.call(this, type, listener, options);
2852
- };
2853
- console.log(
2854
- "[apm:abort-debug] \u5DF2\u542F\u7528 AbortSignal \u8C03\u8BD5\uFF08APM_DEBUG_ABORT_SIGNAL\uFF09"
2855
- );
2856
- }
2857
-
2858
- // src/commands/connect/append-dispatch-response-tool.ts
2859
- function createAppendDispatchResponseTools(cfg, dispatchId) {
2860
- return {
2861
- append_dispatch_response: {
2862
- description: "Append content to the coordinator member dispatch response for the coordinator Agent to read.",
2863
- inputSchema: {
2864
- type: "object",
2865
- properties: {
2866
- content: { type: "string", description: "Response text to append" }
2867
- },
2868
- required: ["content"]
2869
- },
2870
- execute: async (args) => {
2871
- const content = String(args.content ?? "").trim();
2872
- if (!content) {
2873
- return "content \u4E0D\u80FD\u4E3A\u7A7A";
2874
- }
2875
- const api = createApmApiClient(cfg);
2876
- await api.cli.appendCoordinatorDispatchResponse({
2877
- id: dispatchId,
2878
- content
2879
- });
2880
- return `\u5DF2\u8FFD\u52A0\u6D3E\u53D1\u54CD\u5E94\uFF08${content.length} \u5B57\u7B26\uFF09`;
2881
- }
2882
- }
2883
- };
2884
- }
2885
-
2886
2787
  // src/commands/connect/append-message-tool.ts
2887
2788
  function createAppendMessageCustomTools(cfg, messageId) {
2888
2789
  return {
@@ -2923,8 +2824,7 @@ function createAppendMessageCustomTools(cfg, messageId) {
2923
2824
  }
2924
2825
 
2925
2826
  // src/commands/connect/ask-question-tool.ts
2926
- import { randomUUID } from "crypto";
2927
- function createAskQuestionTool(options) {
2827
+ function createAskQuestionMockTool(options) {
2928
2828
  return {
2929
2829
  description: "Collect structured multiple-choice answers from the user. Use when blocked on a decision that is genuinely the user's to make.",
2930
2830
  inputSchema: {
@@ -2962,61 +2862,6 @@ function createAskQuestionTool(options) {
2962
2862
  },
2963
2863
  required: ["questions"]
2964
2864
  },
2965
- execute: async (args) => {
2966
- const record = args;
2967
- const questions = record.questions;
2968
- if (!Array.isArray(questions) || questions.length === 0) {
2969
- return "questions \u4E0D\u80FD\u4E3A\u7A7A";
2970
- }
2971
- const api = createApmApiClient(options.cfg);
2972
- await api.cli.createCoordinatorDispatchQuestions({
2973
- dispatchId: options.dispatchId,
2974
- batchId: randomUUID(),
2975
- title: typeof record.title === "string" ? record.title : void 0,
2976
- questions
2977
- });
2978
- options.onSubmitted?.();
2979
- return "\u5DF2\u5411\u7528\u6237\u63D0\u4EA4\u95EE\u9898\uFF0C\u8BF7\u7ED3\u675F\u672C\u8F6E run\uFF0C\u7B49\u5F85\u7528\u6237\u5728\u534F\u8C03\u4F1A\u8BDD\u9875\u56DE\u7B54\u540E\u7EE7\u7EED\u3002";
2980
- }
2981
- };
2982
- }
2983
-
2984
- // src/commands/connect/ask-question-tool.mock.ts
2985
- function createAskQuestionMockTool(options) {
2986
- return {
2987
- description: "Collect structured multiple-choice answers from the user. Use when blocked on a decision that is genuinely the user's to make.",
2988
- inputSchema: {
2989
- type: "object",
2990
- properties: {
2991
- title: { type: "string" },
2992
- questions: {
2993
- type: "array",
2994
- minItems: 1,
2995
- items: {
2996
- type: "object",
2997
- properties: {
2998
- id: { type: "string" },
2999
- prompt: { type: "string" },
3000
- allow_multiple: { type: "boolean" },
3001
- options: {
3002
- type: "array",
3003
- minItems: 2,
3004
- items: {
3005
- type: "object",
3006
- properties: {
3007
- id: { type: "string" },
3008
- label: { type: "string" }
3009
- },
3010
- required: ["id", "label"]
3011
- }
3012
- }
3013
- },
3014
- required: ["id", "prompt", "options"]
3015
- }
3016
- }
3017
- },
3018
- required: ["questions"]
3019
- },
3020
2865
  execute: async (args) => {
3021
2866
  const payload = JSON.stringify(args, null, 2);
3022
2867
  console.log(`[apm] AskQuestion mock \u8C03\u7528:
@@ -3041,16 +2886,6 @@ function createCursorCustomTools(cfg, messageId, options) {
3041
2886
  })
3042
2887
  };
3043
2888
  }
3044
- function createCursorDispatchCustomTools(cfg, options) {
3045
- return {
3046
- ...createAppendDispatchResponseTools(cfg, options.dispatchId),
3047
- AskQuestion: createAskQuestionTool({
3048
- cfg,
3049
- dispatchId: options.dispatchId,
3050
- onSubmitted: options.onAskQuestionSubmitted
3051
- })
3052
- };
3053
- }
3054
2889
  function withPlanModeToolHint(prompt, mode) {
3055
2890
  if (mode !== "plan") {
3056
2891
  return prompt;
@@ -3137,7 +2972,7 @@ async function runCursorAgent(cfg, ctx, options) {
3137
2972
  throw new Error("\u7F3A\u5C11 apiKey\uFF0C\u65E0\u6CD5\u8C03\u7528 Cursor SDK");
3138
2973
  }
3139
2974
  const workdir = resolveWorkdirPath(ctx.workdir);
3140
- const customTools = options?.customTools ?? createCursorCustomTools(cfg, ctx.messageId, {
2975
+ const customTools = createCursorCustomTools(cfg, ctx.messageId, {
3141
2976
  onAskQuestion: options?.onAskQuestion
3142
2977
  });
3143
2978
  const prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
@@ -3265,79 +3100,6 @@ async function runCursorAgent(cfg, ctx, options) {
3265
3100
  }
3266
3101
  }
3267
3102
 
3268
- // src/commands/connect/coordinator-dispatch-handler.ts
3269
- async function handleInboundCoordinatorDispatch(cfg, msg, signal) {
3270
- const workdir = requireRemoteWorkdir(msg.workdir);
3271
- assertApmGitignoredInRepo(workdir);
3272
- await ensureWorkspaceInitialized(workdir);
3273
- const api = createApmApiClient(cfg);
3274
- let askQuestionSubmitted = false;
3275
- try {
3276
- await api.cli.updateCoordinatorDispatchStatus({
3277
- id: msg.dispatchId,
3278
- status: "DISPATCHING"
3279
- });
3280
- const result = await runCursorAgent(
3281
- cfg,
3282
- {
3283
- messageId: msg.dispatchId,
3284
- sessionId: msg.dispatchSessionId,
3285
- prompt: msg.content,
3286
- model: msg.model,
3287
- apiKey: msg.apiKey,
3288
- workdir: msg.workdir,
3289
- user: msg.user,
3290
- mode: msg.mode,
3291
- resumeAgentId: msg.type === "coordinator_dispatch_resume" ? msg.resumeAgentId : msg.resumeAgentId
3292
- },
3293
- {
3294
- signal,
3295
- forceSend: true,
3296
- skipRemoteLogSync: true,
3297
- customTools: createCursorDispatchCustomTools(cfg, {
3298
- dispatchId: msg.dispatchId,
3299
- onAskQuestionSubmitted: () => {
3300
- askQuestionSubmitted = true;
3301
- }
3302
- })
3303
- }
3304
- );
3305
- if (askQuestionSubmitted) {
3306
- if (result.agentId) {
3307
- await api.cli.completeCoordinatorDispatch({
3308
- id: msg.dispatchId,
3309
- agentId: result.agentId
3310
- });
3311
- }
3312
- console.log(
3313
- `[apm] \u534F\u8C03\u6D3E\u53D1 ${msg.dispatchId} \u5DF2\u63D0\u4EA4 AskQuestion\uFF0C\u7B49\u5F85\u7528\u6237\u7B54\u9898`
3314
- );
3315
- return;
3316
- }
3317
- await api.cli.completeCoordinatorDispatch({
3318
- id: msg.dispatchId,
3319
- agentId: result.agentId,
3320
- createPlan: result.createPlan,
3321
- artifacts: result.artifactDocuments.map((doc) => ({
3322
- name: doc.path.split("/").pop() ?? doc.path,
3323
- content: doc.content
3324
- })),
3325
- status: "SUCCESS"
3326
- });
3327
- console.log(`[apm] \u534F\u8C03\u6D3E\u53D1\u5B8C\u6210 dispatchId=${msg.dispatchId}`);
3328
- } catch (error) {
3329
- const message = error instanceof Error ? error.message : String(error);
3330
- console.error(`[apm] \u534F\u8C03\u6D3E\u53D1\u5931\u8D25 dispatchId=${msg.dispatchId}:`, message);
3331
- if (!askQuestionSubmitted) {
3332
- await api.cli.completeCoordinatorDispatch({
3333
- id: msg.dispatchId,
3334
- status: "FAILED",
3335
- error: message
3336
- });
3337
- }
3338
- }
3339
- }
3340
-
3341
3103
  // src/commands/connect/cli-version-sync.ts
3342
3104
  import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync11 } from "fs";
3343
3105
  import { join as join14 } from "path";
@@ -3713,27 +3475,6 @@ async function runConnect(options) {
3713
3475
  });
3714
3476
  return;
3715
3477
  }
3716
- if (validated.data.type === "coordinator_dispatch" || validated.data.type === "coordinator_dispatch_resume") {
3717
- const msg2 = validated.data;
3718
- const perDispatchController = new AbortController();
3719
- const signal2 = AbortSignal.any([
3720
- shutdownAbort.signal,
3721
- perDispatchController.signal
3722
- ]);
3723
- const task2 = (async () => {
3724
- await runSlots.acquire();
3725
- try {
3726
- await handleInboundCoordinatorDispatch(cfg, msg2, signal2);
3727
- } finally {
3728
- runSlots.release();
3729
- }
3730
- })();
3731
- activeTasks.add(task2);
3732
- void task2.finally(() => {
3733
- activeTasks.delete(task2);
3734
- });
3735
- return;
3736
- }
3737
3478
  if (validated.data.type !== "message") {
3738
3479
  return;
3739
3480
  }
@@ -5007,9 +4748,14 @@ function buildProgram() {
5007
4748
  await runInit(opts.name);
5008
4749
  });
5009
4750
  program.command("update").description(
5010
- `\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5 ${CLI_PACKAGE_NAME}@latest\uFF0C\u5C06 apm \u66F4\u65B0\u5230 registry \u6700\u65B0\u7248`
5011
- ).action(async () => {
5012
- await runUpdate();
4751
+ `\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5 ${CLI_PACKAGE_NAME}\uFF0C\u9ED8\u8BA4\u66F4\u65B0\u5230\u5F53\u524D\u5927\u7248\u672C\uFF08${parseMajorVersion(
4752
+ readCliVersion()
4753
+ )}.x\uFF09\u6700\u65B0\u7248`
4754
+ ).option(
4755
+ "--major",
4756
+ "\u5141\u8BB8\u8DE8\u5927\u7248\u672C\u66F4\u65B0\u5230 registry \u5168\u5C40 latest\uFF08\u9ED8\u8BA4\u4EC5\u8DDF\u968F\u5F53\u524D\u5927\u7248\u672C\uFF09"
4757
+ ).action(async (opts) => {
4758
+ await runUpdate({ allowMajorUpgrade: opts.major === true });
5013
4759
  });
5014
4760
  program.command("update-skills").description(
5015
4761
  "\u540C\u6B65 .apm/ \u4E0B\u7684\u89C4\u5219\u4E0E\u6280\u80FD\uFF1A\u57FA\u7840\u5185\u5BB9\u6765\u81EA CLI \u6A21\u677F\uFF0C\u8865\u5145\u6280\u80FD\u6765\u81EA\u5E73\u53F0"
@@ -5047,7 +4793,7 @@ function buildProgram() {
5047
4793
  await runUpdateMessageStatus(opts);
5048
4794
  });
5049
4795
  program.command("connect").description(
5050
- "\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09\uFF0C\u7EF4\u6301\u5FC3\u8DF3\u5E76\u5904\u7406\u4E0B\u884C message\uFF08TYPING \u2192 Cursor \u2192 SUCCESS/FAILED\uFF09\uFF1B\u542F\u52A8\u524D\u81EA\u52A8 apm update \u5230\u6700\u65B0\u7248"
4796
+ "\u8FDE\u63A5\u5E73\u53F0 WebSocket\uFF08/ws/agent\uFF09\uFF0C\u7EF4\u6301\u5FC3\u8DF3\u5E76\u5904\u7406\u4E0B\u884C message\uFF08TYPING \u2192 Cursor \u2192 SUCCESS/FAILED\uFF09\uFF1B\u542F\u52A8\u524D\u81EA\u52A8 apm update \u5230\u5F53\u524D\u5927\u7248\u672C\u6700\u65B0\u7248"
5051
4797
  ).option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").action(async (opts) => {
5052
4798
  await runConnect(opts);
5053
4799
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.64",
3
+ "version": "6.0.65",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,