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.
- package/dist/index.js +254 -42
- 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
|
-
|
|
476
|
+
updateTaskDeploymentStatus: defineEndpoint({
|
|
477
477
|
method: "PUT",
|
|
478
|
-
path: "/cli/
|
|
478
|
+
path: "/cli/task-deployments/status"
|
|
479
479
|
}),
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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/
|
|
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
|
-
|
|
1748
|
-
const
|
|
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
|
|
1765
|
-
|
|
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 ${
|
|
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 ${
|
|
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",
|
|
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 (
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
2814
|
-
const syncRemoteLog = createThrottledCursorMessageLogSync(
|
|
2994
|
+
const syncRemoteLog = options?.skipRemoteLogSync ? noopRemoteLogSync : createThrottledCursorMessageLogSync(
|
|
2815
2995
|
cfg,
|
|
2816
|
-
|
|
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
|
-
|
|
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}
|
|
4545
|
-
|
|
4546
|
-
|
|
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.
|
|
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": {
|