ai-project-manage-cli 7.1.7 → 7.1.9

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 CHANGED
@@ -6469,6 +6469,22 @@ var EventSession = class {
6469
6469
  this.dirtyIndices.delete(index);
6470
6470
  }
6471
6471
  }
6472
+ /**
6473
+ * 仅清除仍与上传快照一致的 dirty index。
6474
+ * 异步同步期间若事件内容又变了,保留 dirty,由下一轮 drain 继续覆盖写入。
6475
+ */
6476
+ clearDirtyIfUnchanged(synced) {
6477
+ for (const { index, data } of synced) {
6478
+ const event = this.events[index];
6479
+ if (!event) {
6480
+ this.dirtyIndices.delete(index);
6481
+ continue;
6482
+ }
6483
+ if (JSON.stringify(event) === data) {
6484
+ this.dirtyIndices.delete(index);
6485
+ }
6486
+ }
6487
+ }
6472
6488
  getEventCount() {
6473
6489
  return this.events.length;
6474
6490
  }
@@ -6621,7 +6637,7 @@ function createThrottledCursorMessageLogSync(cfg, ctx, onError) {
6621
6637
  lastRunAt = Date.now();
6622
6638
  try {
6623
6639
  await syncCursorMessageLog(cfg, ctx, events);
6624
- session.clearDirty(events.map((event) => event.index));
6640
+ session.clearDirtyIfUnchanged(events);
6625
6641
  } catch (err) {
6626
6642
  onError(err);
6627
6643
  }
@@ -7023,7 +7039,11 @@ async function obtainAgent(ctx) {
7023
7039
  cwd: ctx.cwd,
7024
7040
  store: createWorkspaceLocalAgentStore(ctx.workdir),
7025
7041
  ...ctx.customTools ? { customTools: ctx.customTools } : {},
7026
- ...ctx.enableSandbox ? { sandboxOptions: { enabled: true } } : {}
7042
+ ...ctx.enableSandbox ? {
7043
+ sandboxOptions: { enabled: true },
7044
+ // 只加载项目级设置,避免 ~/.cursor/mcp.json 里需 OAuth/审批的 MCP 在无头沙箱被拒
7045
+ settingSources: ["project"]
7046
+ } : {}
7027
7047
  },
7028
7048
  ...ctx.mode ? { mode: ctx.mode } : {}
7029
7049
  // mcpServers: createPlaywrightMcpServers(),
@@ -7084,9 +7104,7 @@ async function runCursorAgent(cfg, ctx, options) {
7084
7104
  });
7085
7105
  const enableSandbox = Boolean(options?.enableSandbox);
7086
7106
  let prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
7087
- if (enableSandbox) {
7088
- prompt = withWorkspaceBoundaryHint(prompt);
7089
- }
7107
+ prompt = withWorkspaceBoundaryHint(prompt);
7090
7108
  console.log(
7091
7109
  `[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId} sessionId=${ctx.sessionId} cwd=${workdir} sandbox=${enableSandbox}`
7092
7110
  );
@@ -1113,6 +1113,22 @@ var EventSession = class {
1113
1113
  this.dirtyIndices.delete(index);
1114
1114
  }
1115
1115
  }
1116
+ /**
1117
+ * 仅清除仍与上传快照一致的 dirty index。
1118
+ * 异步同步期间若事件内容又变了,保留 dirty,由下一轮 drain 继续覆盖写入。
1119
+ */
1120
+ clearDirtyIfUnchanged(synced) {
1121
+ for (const { index, data } of synced) {
1122
+ const event = this.events[index];
1123
+ if (!event) {
1124
+ this.dirtyIndices.delete(index);
1125
+ continue;
1126
+ }
1127
+ if (JSON.stringify(event) === data) {
1128
+ this.dirtyIndices.delete(index);
1129
+ }
1130
+ }
1131
+ }
1116
1132
  getEventCount() {
1117
1133
  return this.events.length;
1118
1134
  }
@@ -1265,7 +1281,7 @@ function createThrottledCursorMessageLogSync(cfg, ctx, onError) {
1265
1281
  lastRunAt = Date.now();
1266
1282
  try {
1267
1283
  await syncCursorMessageLog(cfg, ctx, events);
1268
- session.clearDirty(events.map((event) => event.index));
1284
+ session.clearDirtyIfUnchanged(events);
1269
1285
  } catch (err) {
1270
1286
  onError(err);
1271
1287
  }
@@ -1743,7 +1759,11 @@ async function obtainAgent(ctx) {
1743
1759
  cwd: ctx.cwd,
1744
1760
  store: createWorkspaceLocalAgentStore(ctx.workdir),
1745
1761
  ...ctx.customTools ? { customTools: ctx.customTools } : {},
1746
- ...ctx.enableSandbox ? { sandboxOptions: { enabled: true } } : {}
1762
+ ...ctx.enableSandbox ? {
1763
+ sandboxOptions: { enabled: true },
1764
+ // 只加载项目级设置,避免 ~/.cursor/mcp.json 里需 OAuth/审批的 MCP 在无头沙箱被拒
1765
+ settingSources: ["project"]
1766
+ } : {}
1747
1767
  },
1748
1768
  ...ctx.mode ? { mode: ctx.mode } : {}
1749
1769
  // mcpServers: createPlaywrightMcpServers(),
@@ -1804,9 +1824,7 @@ async function runCursorAgent(cfg, ctx, options) {
1804
1824
  });
1805
1825
  const enableSandbox = Boolean(options?.enableSandbox);
1806
1826
  let prompt = withPlanModeToolHint(ctx.prompt, ctx.mode);
1807
- if (enableSandbox) {
1808
- prompt = withWorkspaceBoundaryHint(prompt);
1809
- }
1827
+ prompt = withWorkspaceBoundaryHint(prompt);
1810
1828
  console.log(
1811
1829
  `[apm] Cursor Agent \u5F00\u59CB messageId=${ctx.messageId} sessionId=${ctx.sessionId} cwd=${workdir} sandbox=${enableSandbox}`
1812
1830
  );
@@ -2200,7 +2218,7 @@ function createThrottledWebIdeMessageLogSync(cfg, ctx, onError) {
2200
2218
  await upsertLogHeader(cfg, ctx, {
2201
2219
  eventCount: session.getEventCount()
2202
2220
  });
2203
- session.clearDirty(events.map((e) => e.index));
2221
+ session.clearDirtyIfUnchanged(events);
2204
2222
  } catch (err) {
2205
2223
  onError(err);
2206
2224
  }
@@ -2581,66 +2599,9 @@ async function ensureWebIdeDraftPullRequests(cfg, taskId, workdir) {
2581
2599
  }
2582
2600
  }
2583
2601
 
2584
- // src/commands/connect/ensure-workspace-permissions.ts
2585
- import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "fs";
2586
- import { join as join8 } from "path";
2587
- var WEBIDE_MCP_ALLOWLIST = ["custom-user-tools:*"];
2588
- function parsePermissionsConfig(raw) {
2589
- try {
2590
- const parsed = JSON.parse(raw);
2591
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
2592
- return void 0;
2593
- }
2594
- return parsed;
2595
- } catch {
2596
- return void 0;
2597
- }
2598
- }
2599
- function mergeMcpAllowlist(existing) {
2600
- const merged = /* @__PURE__ */ new Set([
2601
- ...existing ?? [],
2602
- ...WEBIDE_MCP_ALLOWLIST
2603
- ]);
2604
- return [...merged];
2605
- }
2606
- function needsMcpAllowlistUpdate(existing) {
2607
- const current = existing ?? [];
2608
- return WEBIDE_MCP_ALLOWLIST.some((entry) => !current.includes(entry));
2609
- }
2610
- function ensureWorkspacePermissionsConfig(workdir) {
2611
- const cursorDir = toFsPath(join8(workdir, ".cursor"));
2612
- const permissionsPath = toFsPath(join8(cursorDir, "permissions.json"));
2613
- let config = {};
2614
- if (existsSync6(permissionsPath)) {
2615
- const raw = readFileSync8(permissionsPath, "utf8");
2616
- const parsed = parsePermissionsConfig(raw);
2617
- if (!parsed) {
2618
- console.warn(
2619
- `[apm] \u5DE5\u4F5C\u533A permissions.json \u65E0\u6CD5\u89E3\u6790\uFF0C\u8DF3\u8FC7\u5199\u5165\uFF1A${permissionsPath}`
2620
- );
2621
- return;
2622
- }
2623
- config = parsed;
2624
- }
2625
- if (!needsMcpAllowlistUpdate(config.mcpAllowlist)) {
2626
- return;
2627
- }
2628
- config.mcpAllowlist = mergeMcpAllowlist(config.mcpAllowlist);
2629
- mkdirSync7(cursorDir, { recursive: true });
2630
- writeFileSync9(
2631
- permissionsPath,
2632
- `${JSON.stringify(config, null, 2)}
2633
- `,
2634
- "utf8"
2635
- );
2636
- console.log(
2637
- `[apm] \u5DF2\u66F4\u65B0\u5DE5\u4F5C\u533A permissions \u914D\u7F6E\uFF08mcpAllowlist\uFF09\uFF1A${permissionsPath}`
2638
- );
2639
- }
2640
-
2641
2602
  // src/commands/connect/ensure-workspace-sandbox.ts
2642
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync10, existsSync as existsSync7 } from "fs";
2643
- import { join as join9 } from "path";
2603
+ import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync9, existsSync as existsSync6 } from "fs";
2604
+ import { join as join8 } from "path";
2644
2605
  var DEFAULT_SANDBOX_JSON = `{
2645
2606
  "type": "workspace_readwrite",
2646
2607
  "networkPolicy": {
@@ -2649,11 +2610,11 @@ var DEFAULT_SANDBOX_JSON = `{
2649
2610
  }
2650
2611
  `;
2651
2612
  function ensureWorkspaceSandboxConfig(workdir) {
2652
- const cursorDir = toFsPath(join9(workdir, ".cursor"));
2653
- const sandboxPath = toFsPath(join9(cursorDir, "sandbox.json"));
2654
- if (existsSync7(sandboxPath)) return;
2655
- mkdirSync8(cursorDir, { recursive: true });
2656
- writeFileSync10(sandboxPath, DEFAULT_SANDBOX_JSON, "utf8");
2613
+ const cursorDir = toFsPath(join8(workdir, ".cursor"));
2614
+ const sandboxPath = toFsPath(join8(cursorDir, "sandbox.json"));
2615
+ if (existsSync6(sandboxPath)) return;
2616
+ mkdirSync7(cursorDir, { recursive: true });
2617
+ writeFileSync9(sandboxPath, DEFAULT_SANDBOX_JSON, "utf8");
2657
2618
  console.log(`[apm] \u5DF2\u5199\u5165\u5DE5\u4F5C\u533A sandbox \u914D\u7F6E\uFF1A${sandboxPath}`);
2658
2619
  }
2659
2620
 
@@ -2686,7 +2647,6 @@ async function handleWebIdeInboundMessage(cfg, msg, signal) {
2686
2647
  assertApmGitignoredInRepo(workdir);
2687
2648
  }
2688
2649
  ensureWorkspaceSandboxConfig(workdir);
2689
- ensureWorkspacePermissionsConfig(workdir);
2690
2650
  resolveWorkspaceRepos(workdir);
2691
2651
  if (shouldRunBranch(branchCacheKey, workdir)) {
2692
2652
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
@@ -2727,6 +2687,7 @@ async function handleWebIdeInboundMessage(cfg, msg, signal) {
2727
2687
  signal
2728
2688
  }),
2729
2689
  enableWebIdePlanTools: true,
2690
+ // sandbox:工作区 FS 硬隔离;自定义工具由 CLI createCursorCustomTools 注册
2730
2691
  enableSandbox: true,
2731
2692
  taskId,
2732
2693
  createRemoteLogSync: (agentId) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "7.1.7",
3
+ "version": "7.1.9",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,