ai-project-manage-cli 6.0.63 → 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 +254 -42
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -473,17 +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({
480
+ syncTaskDeploymentLog: defineEndpoint(
481
+ {
482
+ method: "PUT",
483
+ path: "/cli/task-deployments/log"
484
+ }
485
+ ),
486
+ completeTaskDeployment: defineEndpoint({
485
487
  method: "PUT",
486
- path: "/cli/coordinator-deployments/complete"
488
+ path: "/cli/task-deployments/complete"
487
489
  })
488
490
  }
489
491
  };
@@ -1744,8 +1746,12 @@ function registryBaseUrl() {
1744
1746
  const fromEnv = process.env.npm_config_registry?.trim() || process.env.NPM_CONFIG_REGISTRY?.trim();
1745
1747
  return (fromEnv || "https://registry.npmjs.org").replace(/\/+$/, "");
1746
1748
  }
1747
- async function fetchLatestPublishedVersion() {
1748
- 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}`;
1749
1755
  try {
1750
1756
  const res = await fetch(url);
1751
1757
  if (!res.ok) return null;
@@ -1755,28 +1761,73 @@ async function fetchLatestPublishedVersion() {
1755
1761
  return null;
1756
1762
  }
1757
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
+ }
1758
1797
  function npmAvailable() {
1759
1798
  const r = runNpm(["--version"], { encoding: "utf8" });
1760
1799
  return !r.error && r.status === 0;
1761
1800
  }
1762
- async function runUpdate() {
1801
+ async function runUpdate(options = {}) {
1763
1802
  const current = readCliVersion();
1764
- const latest = await fetchLatestPublishedVersion();
1765
- 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") {
1766
1813
  console.log(`[apm] \u5DF2\u662F\u6700\u65B0\u7248\u672C ${current}`);
1767
1814
  return { didUpdate: false };
1768
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
+ }
1769
1821
  if (!npmAvailable()) {
1770
1822
  console.error(
1771
- `[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}`
1772
1824
  );
1773
1825
  process.exit(1);
1774
1826
  }
1775
- const targetLabel = latest ?? "latest";
1776
1827
  console.error(
1777
- `[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` : "")
1778
1829
  );
1779
- const install = runNpm(["install", "-g", `${CLI_PACKAGE_NAME}@latest`], {
1830
+ const install = runNpm(["install", "-g", resolved.installSpec], {
1780
1831
  stdio: "inherit"
1781
1832
  });
1782
1833
  if (install.error) {
@@ -1787,7 +1838,7 @@ async function runUpdate() {
1787
1838
  process.exit(install.status ?? 1);
1788
1839
  }
1789
1840
  const after = readCliVersion();
1790
- if (latest && after === latest) {
1841
+ if (resolved.expectedVersion && after === resolved.expectedVersion) {
1791
1842
  console.log(`[apm] \u5DF2\u66F4\u65B0\u5230 ${after}`);
1792
1843
  } else {
1793
1844
  console.log(
@@ -2256,7 +2307,7 @@ function createDeployLogSyncer(api, deploymentRunId) {
2256
2307
  if (!latestLog || latestLog === lastSyncedLog) {
2257
2308
  return;
2258
2309
  }
2259
- await api.cli.syncCoordinatorDeploymentLog({
2310
+ await api.cli.syncTaskDeploymentLog({
2260
2311
  id: deploymentRunId,
2261
2312
  log: latestLog
2262
2313
  });
@@ -2287,7 +2338,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2287
2338
  const api = createApmApiClient(cfg);
2288
2339
  const deploymentRunId = msg.deploymentRunId;
2289
2340
  if (signal.aborted) return;
2290
- await api.cli.updateCoordinatorDeploymentStatus({
2341
+ await api.cli.updateTaskDeploymentStatus({
2291
2342
  id: deploymentRunId,
2292
2343
  status: "DEPLOYING"
2293
2344
  });
@@ -2296,7 +2347,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2296
2347
  if (!command) {
2297
2348
  const error = missingDeployCommandMessage(msg.environment);
2298
2349
  console.error(`[apm] ${error}`);
2299
- await api.cli.completeCoordinatorDeployment({
2350
+ await api.cli.completeTaskDeployment({
2300
2351
  id: deploymentRunId,
2301
2352
  status: "FAILED",
2302
2353
  log: error,
@@ -2318,7 +2369,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2318
2369
  latestLog = log;
2319
2370
  logSyncer.updateLog(log);
2320
2371
  await logSyncer.flush();
2321
- await api.cli.completeCoordinatorDeployment({
2372
+ await api.cli.completeTaskDeployment({
2322
2373
  id: deploymentRunId,
2323
2374
  status: "SUCCESS",
2324
2375
  log
@@ -2329,7 +2380,7 @@ async function handleInboundDeploy(cfg, msg, signal) {
2329
2380
  const log = error && typeof error === "object" && "log" in error ? String(error.log ?? latestLog) : latestLog;
2330
2381
  logSyncer.updateLog(log);
2331
2382
  await logSyncer.flush();
2332
- await api.cli.completeCoordinatorDeployment({
2383
+ await api.cli.completeTaskDeployment({
2333
2384
  id: deploymentRunId,
2334
2385
  status: "FAILED",
2335
2386
  log,
@@ -2411,6 +2462,27 @@ import {
2411
2462
  } from "@cursor/sdk";
2412
2463
  import { setMaxListeners as setMaxListeners2 } from "node:events";
2413
2464
 
2465
+ // src/plan-format.ts
2466
+ function formatPlanMarkdown(raw) {
2467
+ let text = raw.trim();
2468
+ if (!text) {
2469
+ return text;
2470
+ }
2471
+ if (text.startsWith("{") && text.endsWith("}")) {
2472
+ try {
2473
+ const parsed = JSON.parse(text);
2474
+ if (typeof parsed.plan === "string") {
2475
+ return formatPlanMarkdown(parsed.plan);
2476
+ }
2477
+ } catch {
2478
+ }
2479
+ }
2480
+ if (!text.includes("\n") && text.includes("\\n")) {
2481
+ text = text.replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
2482
+ }
2483
+ return text.replace(/\r\n/g, "\n").trimEnd() + "\n";
2484
+ }
2485
+
2414
2486
  // src/session-utils.ts
2415
2487
  var EventSession = class {
2416
2488
  events = [];
@@ -2536,6 +2608,23 @@ var EventSession = class {
2536
2608
  getAssistantText() {
2537
2609
  return this.events.filter((e) => e.type === "assistant").map((e) => String(e.content ?? "")).join("\n").trim();
2538
2610
  }
2611
+ /** plan 模式下 createPlan 工具 completed 时的 plan 字段(取最后一次) */
2612
+ getCreatePlanContent() {
2613
+ for (let i = this.events.length - 1; i >= 0; i--) {
2614
+ const event = this.events[i];
2615
+ if (event.type !== "tool_call") {
2616
+ continue;
2617
+ }
2618
+ if (event.name !== "createPlan" || event.status !== "completed") {
2619
+ continue;
2620
+ }
2621
+ const plan = event.args?.plan;
2622
+ if (typeof plan === "string" && plan.trim()) {
2623
+ return formatPlanMarkdown(plan);
2624
+ }
2625
+ }
2626
+ return void 0;
2627
+ }
2539
2628
  resolveLogContent() {
2540
2629
  return this.events.map((event) => formatLogEvent(event.type, event)).join("\n");
2541
2630
  }
@@ -2734,9 +2823,87 @@ function createAppendMessageCustomTools(cfg, messageId) {
2734
2823
  };
2735
2824
  }
2736
2825
 
2826
+ // src/commands/connect/ask-question-tool.ts
2827
+ function createAskQuestionMockTool(options) {
2828
+ return {
2829
+ description: "Collect structured multiple-choice answers from the user. Use when blocked on a decision that is genuinely the user's to make.",
2830
+ inputSchema: {
2831
+ type: "object",
2832
+ properties: {
2833
+ title: {
2834
+ type: "string",
2835
+ description: "Optional title for the questions form"
2836
+ },
2837
+ questions: {
2838
+ type: "array",
2839
+ minItems: 1,
2840
+ items: {
2841
+ type: "object",
2842
+ properties: {
2843
+ id: { type: "string" },
2844
+ prompt: { type: "string" },
2845
+ allow_multiple: { type: "boolean" },
2846
+ options: {
2847
+ type: "array",
2848
+ minItems: 2,
2849
+ items: {
2850
+ type: "object",
2851
+ properties: {
2852
+ id: { type: "string" },
2853
+ label: { type: "string" }
2854
+ },
2855
+ required: ["id", "label"]
2856
+ }
2857
+ }
2858
+ },
2859
+ required: ["id", "prompt", "options"]
2860
+ }
2861
+ }
2862
+ },
2863
+ required: ["questions"]
2864
+ },
2865
+ execute: async (args) => {
2866
+ const payload = JSON.stringify(args, null, 2);
2867
+ console.log(`[apm] AskQuestion mock \u8C03\u7528:
2868
+ ${payload}`);
2869
+ options?.onInvoke?.(args);
2870
+ return `[mock] AskQuestion \u5DF2\u8BB0\u5F55\uFF08\u672A\u521B\u5EFA\u4EFB\u52A1\u95EE\u9898\u3001\u672A\u7B49\u5F85\u7528\u6237\u56DE\u7B54\uFF09\u3002\u53C2\u6570:
2871
+ ${payload}`;
2872
+ }
2873
+ };
2874
+ }
2875
+
2876
+ // src/commands/connect/cursor-custom-tools.ts
2877
+ var PLAN_MODE_ASK_QUESTION_HINT = `[SDK \u73AF\u5883\u8BF4\u660E]
2878
+ AskQuestion \u5DF2\u901A\u8FC7 MCP \u670D\u52A1\u5668 custom-user-tools \u6CE8\u518C\uFF0C\u5DE5\u5177\u540D\u4E3A AskQuestion\u3002
2879
+ \u9700\u8981\u5411\u7528\u6237\u786E\u8BA4\u65F6\uFF0C\u8BF7\u8C03\u7528 AskQuestion\uFF08\u7ECF CallMcpTool / custom-user-tools\uFF09\uFF0C\u4E0D\u8981\u5047\u8BBE IDE \u5185\u7F6E AskQuestion \u4E0D\u53EF\u7528\u3002
2880
+ \u975E\u5FC5\u987B\u7684\u95EE\u9898\u53EF\u8DF3\u8FC7\uFF0C\u76F4\u63A5\u5B8C\u6210 createPlan\u3002`;
2881
+ function createCursorCustomTools(cfg, messageId, options) {
2882
+ return {
2883
+ ...createAppendMessageCustomTools(cfg, messageId),
2884
+ AskQuestion: createAskQuestionMockTool({
2885
+ onInvoke: options?.onAskQuestion
2886
+ })
2887
+ };
2888
+ }
2889
+ function withPlanModeToolHint(prompt, mode) {
2890
+ if (mode !== "plan") {
2891
+ return prompt;
2892
+ }
2893
+ return `${prompt.trim()}
2894
+
2895
+ ${PLAN_MODE_ASK_QUESTION_HINT}`;
2896
+ }
2897
+
2737
2898
  // src/commands/connect/cursor-agent.ts
2738
2899
  setMaxListeners2(50);
2739
2900
  installAbortSignalDebug();
2901
+ var noopRemoteLogSync = {
2902
+ schedule(_session) {
2903
+ },
2904
+ async flush(_session) {
2905
+ }
2906
+ };
2740
2907
  var logCtx = (ctx, agentId) => ({
2741
2908
  sessionId: ctx.sessionId,
2742
2909
  messageId: ctx.messageId,
@@ -2760,24 +2927,32 @@ async function obtainAgent(ctx) {
2760
2927
  apiKey: ctx.apiKey,
2761
2928
  model: { id: ctx.model || "default" },
2762
2929
  local: {
2763
- cwd: ctx.cwd
2764
- }
2930
+ cwd: ctx.cwd,
2931
+ ...ctx.customTools ? { customTools: ctx.customTools } : {}
2932
+ },
2933
+ ...ctx.mode ? { mode: ctx.mode } : {}
2765
2934
  // mcpServers: createPlaywrightMcpServers(),
2766
2935
  };
2767
- const savedAgentId = ctx.user ? loadSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user) : void 0;
2936
+ const explicitAgentId = ctx.resumeAgentId?.trim();
2937
+ const savedAgentId = explicitAgentId || (ctx.user ? loadSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user) : void 0);
2768
2938
  if (savedAgentId) {
2769
2939
  try {
2770
2940
  const agent2 = await Agent.resume(savedAgentId, agentOptions);
2771
2941
  console.log(
2772
- `[apm] \u590D\u7528\u4F1A\u8BDD Agent user=${ctx.user} agentId=${savedAgentId}`
2942
+ `[apm] \u590D\u7528 Agent user=${ctx.user} agentId=${savedAgentId}${explicitAgentId ? "\uFF08\u53C2\u6570\u6307\u5B9A\uFF09" : ""}`
2773
2943
  );
2944
+ if (ctx.user) {
2945
+ saveSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user, agent2.agentId);
2946
+ }
2774
2947
  return { agent: agent2, resumed: true };
2775
2948
  } catch (err) {
2776
2949
  console.warn(
2777
2950
  `[apm] \u590D\u7528 Agent \u5931\u8D25\uFF08agentId=${savedAgentId}\uFF09\uFF0C\u56DE\u9000\u4E3A\u65B0\u5EFA:`,
2778
2951
  err instanceof Error ? err.message : err
2779
2952
  );
2780
- clearSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user);
2953
+ if (!explicitAgentId && ctx.user) {
2954
+ clearSessionAgentId(ctx.workdir, ctx.sessionId, ctx.user);
2955
+ }
2781
2956
  }
2782
2957
  }
2783
2958
  const agent = await Agent.create(agentOptions);
@@ -2797,7 +2972,10 @@ async function runCursorAgent(cfg, ctx, options) {
2797
2972
  throw new Error("\u7F3A\u5C11 apiKey\uFF0C\u65E0\u6CD5\u8C03\u7528 Cursor SDK");
2798
2973
  }
2799
2974
  const workdir = resolveWorkdirPath(ctx.workdir);
2800
- const prompt = ctx.prompt;
2975
+ const customTools = createCursorCustomTools(cfg, ctx.messageId, {
2976
+ onAskQuestion: options?.onAskQuestion
2977
+ });
2978
+ const prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
2801
2979
  console.log(
2802
2980
  `[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId} sessionId=${ctx.sessionId} cwd=${workdir}`
2803
2981
  );
@@ -2807,13 +2985,15 @@ async function runCursorAgent(cfg, ctx, options) {
2807
2985
  cwd: workdir,
2808
2986
  workdir,
2809
2987
  sessionId: ctx.sessionId,
2810
- user: ctx.user
2988
+ user: ctx.user,
2989
+ mode: ctx.mode,
2990
+ resumeAgentId: ctx.resumeAgentId,
2991
+ customTools
2811
2992
  });
2812
2993
  const eventSession = new EventSession(prompt);
2813
- const remoteLogCtx = logCtx(ctx, agent.agentId);
2814
- const syncRemoteLog = createThrottledCursorMessageLogSync(
2994
+ const syncRemoteLog = options?.skipRemoteLogSync ? noopRemoteLogSync : createThrottledCursorMessageLogSync(
2815
2995
  cfg,
2816
- remoteLogCtx,
2996
+ logCtx(ctx, agent.agentId),
2817
2997
  (err) => {
2818
2998
  console.warn(
2819
2999
  "[apm] \u540C\u6B65 Cursor \u6D88\u606F\u65E5\u5FD7\u5931\u8D25:",
@@ -2830,9 +3010,11 @@ async function runCursorAgent(cfg, ctx, options) {
2830
3010
  logAbortSignalStats(signal, "runCursorAgent:after-addListener");
2831
3011
  try {
2832
3012
  const run = await agent.send(prompt, {
3013
+ ...ctx.mode ? { mode: ctx.mode } : {},
2833
3014
  // mcpServers: createPlaywrightMcpServers(),
2834
3015
  local: {
2835
- customTools: createAppendMessageCustomTools(cfg, ctx.messageId)
3016
+ ...options?.forceSend ? { force: true } : {},
3017
+ customTools
2836
3018
  }
2837
3019
  });
2838
3020
  activeRun = run;
@@ -2853,6 +3035,7 @@ async function runCursorAgent(cfg, ctx, options) {
2853
3035
  );
2854
3036
  }
2855
3037
  }
3038
+ options?.onStreamEvent?.(event);
2856
3039
  eventSession.addEvent(event);
2857
3040
  syncRemoteLog.schedule(eventSession);
2858
3041
  }
@@ -2873,6 +3056,32 @@ async function runCursorAgent(cfg, ctx, options) {
2873
3056
  throw new Error(`Cursor run \u5DF2\u53D6\u6D88: ${result.id}`);
2874
3057
  }
2875
3058
  console.log(`[apm] Cursor Agent \u5B8C\u6210 messageId=${ctx.messageId}`);
3059
+ const artifacts = await agent.listArtifacts().catch(() => []);
3060
+ const artifactDocuments = [];
3061
+ for (const artifact of artifacts) {
3062
+ try {
3063
+ const content = (await agent.downloadArtifact(artifact.path)).toString(
3064
+ "utf8"
3065
+ );
3066
+ artifactDocuments.push({ path: artifact.path, content });
3067
+ } catch (err) {
3068
+ console.warn(
3069
+ `[apm] \u8BFB\u53D6\u4EA7\u7269\u5931\u8D25 path=${artifact.path}:`,
3070
+ err instanceof Error ? err.message : err
3071
+ );
3072
+ }
3073
+ }
3074
+ return {
3075
+ runId: result.id,
3076
+ agentId: agent.agentId,
3077
+ status: result.status,
3078
+ result: result.result,
3079
+ durationMs: result.durationMs,
3080
+ assistantText: eventSession.getAssistantText(),
3081
+ createPlan: eventSession.getCreatePlanContent(),
3082
+ artifacts,
3083
+ artifactDocuments
3084
+ };
2876
3085
  } catch (err) {
2877
3086
  if (err instanceof CursorAgentError) {
2878
3087
  if (resumed) {
@@ -4403,14 +4612,12 @@ function buildClearRemoteDirExceptZipCommand(target) {
4403
4612
  const script = [
4404
4613
  `T=${quotedTarget}`,
4405
4614
  "S=$(mktemp -d)",
4406
- 'while IFS= read -r -d "" z; do',
4407
- 'r="${z#${T}/}"',
4615
+ 'while IFS= read -r -d "" z; do r="${z#${T}/}"',
4408
4616
  'mkdir -p "${S}/$(dirname "$r")"',
4409
4617
  'mv "$z" "${S}/${r}"',
4410
4618
  'done < <(find "$T" -mindepth 1 -type f -iname "*.zip" -print0)',
4411
4619
  'rm -rf "${T}"/*',
4412
- 'while IFS= read -r -d "" r; do',
4413
- 'r="${r#./}"',
4620
+ 'while IFS= read -r -d "" r; do r="${r#./}"',
4414
4621
  'mkdir -p "${T}/$(dirname "$r")"',
4415
4622
  'mv "${S}/${r}" "${T}/${r}"',
4416
4623
  'done < <(cd "$S" 2>/dev/null && find . -type f -print0)',
@@ -4541,9 +4748,14 @@ function buildProgram() {
4541
4748
  await runInit(opts.name);
4542
4749
  });
4543
4750
  program.command("update").description(
4544
- `\u901A\u8FC7 npm \u5168\u5C40\u5B89\u88C5 ${CLI_PACKAGE_NAME}@latest\uFF0C\u5C06 apm \u66F4\u65B0\u5230 registry \u6700\u65B0\u7248`
4545
- ).action(async () => {
4546
- 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 });
4547
4759
  });
4548
4760
  program.command("update-skills").description(
4549
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"
@@ -4581,7 +4793,7 @@ function buildProgram() {
4581
4793
  await runUpdateMessageStatus(opts);
4582
4794
  });
4583
4795
  program.command("connect").description(
4584
- "\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"
4585
4797
  ).option("--server <url>", "API \u6839\u5730\u5740\uFF0C\u8986\u76D6 config \u4E2D\u7684 baseUrl").action(async (opts) => {
4586
4798
  await runConnect(opts);
4587
4799
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "6.0.63",
3
+ "version": "6.0.65",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -15,6 +15,7 @@
15
15
  ],
16
16
  "scripts": {
17
17
  "build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --packages=external --outfile=dist/index.js && tsc --noEmit -p tsconfig.json",
18
+ "test:plan-cursor": "esbuild scripts/test-plan-cursor.ts --bundle --platform=node --format=esm --packages=external --outfile=dist/test-plan-cursor.mjs && node dist/test-plan-cursor.mjs",
18
19
  "prepublishOnly": "npm run build"
19
20
  },
20
21
  "devDependencies": {