ai-project-manage-cli 8.1.6 → 8.1.8

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.
@@ -14,6 +14,10 @@ var requestConfig = {
14
14
  path: "/cli/me"
15
15
  }
16
16
  ),
17
+ webideAgentConfig: defineEndpoint({
18
+ method: "GET",
19
+ path: "/cli/webide/agent-config"
20
+ }),
17
21
  webideAppendMessageContent: defineEndpoint({
18
22
  method: "PUT",
19
23
  path: "/cli/webide/messages/content"
@@ -72,6 +76,14 @@ var requestConfig = {
72
76
  method: "PUT",
73
77
  path: "/cli/webide/plan"
74
78
  }),
79
+ webideUpsertChecklist: defineEndpoint({
80
+ method: "PUT",
81
+ path: "/cli/webide/checklist"
82
+ }),
83
+ webideGetChecklist: defineEndpoint({
84
+ method: "GET",
85
+ path: "/cli/webide/checklist"
86
+ }),
75
87
  webideReplaceTestCases: defineEndpoint({
76
88
  method: "PUT",
77
89
  path: "/cli/webide/test-cases"
@@ -317,11 +329,8 @@ function requireRemoteWorkdir(workdir) {
317
329
  }
318
330
 
319
331
  // src/utils/workspace.ts
320
- import { copyFileSync, existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
321
- import { dirname, join as join2, resolve as resolve2 } from "path";
322
- import { fileURLToPath } from "url";
323
- var __dirname = dirname(fileURLToPath(import.meta.url));
324
- var CLI_TEMPLATE_DIR = resolve2(__dirname, "../template");
332
+ import { existsSync, mkdirSync as mkdirSync2, readdirSync, statSync } from "fs";
333
+ import { join as join2, resolve as resolve2 } from "path";
325
334
  function workspaceApmDir(cwd = resolveWorkdirPath()) {
326
335
  return resolve2(resolve2(cwd), ".apm");
327
336
  }
@@ -372,90 +381,6 @@ async function ensureWorkspaceApmDirForInit(cwd = resolveWorkdirPath()) {
372
381
  }
373
382
  mkdirSync2(fsDir, { recursive: true });
374
383
  }
375
- var WEBIDE_AGENTS_TEMPLATE_NAME = "AGENTS.webide.md";
376
- function shouldSkipTemplateEntry(name) {
377
- return name === ".DS_Store" || name === "Thumbs.db";
378
- }
379
- function isWebIdeRuleFileName(name) {
380
- return name.startsWith("webide");
381
- }
382
- function copyTemplateEntry(src, dest) {
383
- const fsSrc = toFsPath(src);
384
- const fsDest = toFsPath(dest);
385
- const st = statSync(fsSrc);
386
- if (st.isDirectory()) {
387
- mkdirSync2(fsDest, { recursive: true });
388
- for (const name of readdirSync(fsSrc)) {
389
- if (shouldSkipTemplateEntry(name)) continue;
390
- copyTemplateEntry(join2(src, name), join2(dest, name));
391
- }
392
- return;
393
- }
394
- if (!st.isFile()) return;
395
- mkdirSync2(toFsPath(dirname(dest)), { recursive: true });
396
- copyFileSync(fsSrc, fsDest);
397
- }
398
- function listWebIdeRuleFileNames(rulesDir) {
399
- const fsRulesDir = toFsPath(rulesDir);
400
- if (!existsSync(fsRulesDir) || !statSync(fsRulesDir).isDirectory()) {
401
- return [];
402
- }
403
- return readdirSync(fsRulesDir).filter((name) => {
404
- if (shouldSkipTemplateEntry(name) || !isWebIdeRuleFileName(name)) {
405
- return false;
406
- }
407
- return statSync(toFsPath(join2(rulesDir, name))).isFile();
408
- });
409
- }
410
- function assertWebIdeTemplateCopiedToApm(apmDir, workdir) {
411
- const required = ["AGENTS.md", "rules"];
412
- for (const item of required) {
413
- const path3 = join2(apmDir, item);
414
- if (!existsSync(toFsPath(path3))) {
415
- throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11: ${path3}`);
416
- }
417
- }
418
- const rulesDir = join2(apmDir, "rules");
419
- const ruleNames = listWebIdeRuleFileNames(rulesDir);
420
- if (ruleNames.length === 0) {
421
- throw new Error(`[apm] WebIDE \u521D\u59CB\u5316\u4E0D\u5B8C\u6574\uFF0C\u7F3A\u5C11 webide \u89C4\u5219: ${rulesDir}`);
422
- }
423
- const leakedRules = join2(workdir, "rules");
424
- const apmRules = join2(apmDir, "rules");
425
- if (existsSync(toFsPath(leakedRules)) && !existsSync(toFsPath(join2(apmRules, "webide_reply.md")))) {
426
- throw new Error(
427
- `[apm] \u6A21\u677F\u88AB\u590D\u5236\u5230\u9519\u8BEF\u4F4D\u7F6E: ${leakedRules}\uFF08\u5E94\u5728 ${apmRules}\uFF09`
428
- );
429
- }
430
- }
431
- async function copyWebIdeTemplateFiles(targetDir, workdir = resolveWorkdirPath()) {
432
- const resolvedTarget = resolve2(targetDir);
433
- const templateDir = resolve2(CLI_TEMPLATE_DIR);
434
- const fsTemplateDir = toFsPath(templateDir);
435
- if (!existsSync(fsTemplateDir) || !statSync(fsTemplateDir).isDirectory()) {
436
- throw new Error(`[apm] \u672A\u627E\u5230 CLI \u6A21\u677F\u76EE\u5F55: ${templateDir}`);
437
- }
438
- const agentsSrc = join2(templateDir, WEBIDE_AGENTS_TEMPLATE_NAME);
439
- if (!existsSync(toFsPath(agentsSrc))) {
440
- throw new Error(`[apm] \u672A\u627E\u5230 WebIDE \u6307\u5357: ${agentsSrc}`);
441
- }
442
- const rulesSrc = join2(templateDir, "rules");
443
- const ruleNames = listWebIdeRuleFileNames(rulesSrc);
444
- if (ruleNames.length === 0) {
445
- throw new Error(`[apm] CLI \u6A21\u677F\u4E2D\u6CA1\u6709 webide \u89C4\u5219: ${rulesSrc}`);
446
- }
447
- mkdirSync2(toFsPath(resolvedTarget), { recursive: true });
448
- copyFileSync(
449
- toFsPath(agentsSrc),
450
- toFsPath(join2(resolvedTarget, "AGENTS.md"))
451
- );
452
- const rulesDest = join2(resolvedTarget, "rules");
453
- mkdirSync2(toFsPath(rulesDest), { recursive: true });
454
- for (const name of ruleNames) {
455
- copyTemplateEntry(join2(rulesSrc, name), join2(rulesDest, name));
456
- }
457
- assertWebIdeTemplateCopiedToApm(resolvedTarget, resolve2(workdir));
458
- }
459
384
 
460
385
  // src/utils/git.ts
461
386
  import { execFile as execFile2 } from "child_process";
@@ -656,7 +581,7 @@ import {
656
581
  statSync as statSync2,
657
582
  writeFileSync as writeFileSync2
658
583
  } from "fs";
659
- import { basename, dirname as dirname2, join as join3, relative, resolve as resolve3 } from "path";
584
+ import { basename, dirname, join as join3, relative, resolve as resolve3 } from "path";
660
585
  var WORKSPACE_REPOS_MANIFEST = "workspace-repos.json";
661
586
  var WORKSPACE_REPOS_VERSION = 1;
662
587
  var SKIP_DIR_NAMES = /* @__PURE__ */ new Set([".apm", "node_modules"]);
@@ -1499,7 +1424,7 @@ function createMergeWebIdePullRequestsTool(options) {
1499
1424
  const { webideMergePullRequests } = options;
1500
1425
  return {
1501
1426
  MergeWebIdePullRequests: {
1502
- description: "Merge all open pull requests for this WebIDE task. Call once with confirmedConflictFree=true. No baseline sync or review is required before calling.",
1427
+ description: "Merge all open pull requests for this WebIDE task. During accept, call UpsertWebIdeChecklist first with the full acceptance checklist, then call this once with confirmedConflictFree=true. No baseline sync is required before merging.",
1503
1428
  inputSchema: {
1504
1429
  type: "object",
1505
1430
  properties: {
@@ -1586,6 +1511,63 @@ function createUpsertWebIdePlanTool(options) {
1586
1511
  }
1587
1512
  };
1588
1513
  }
1514
+ function createUpsertWebIdeChecklistTool(options) {
1515
+ const { webideUpsertChecklist } = options;
1516
+ return {
1517
+ UpsertWebIdeChecklist: {
1518
+ description: "Persist or replace the acceptance checklist markdown for this WebIDE task. Call with the full checklist (what changed, which repos/files, how to verify) before merging PRs. Use during accept so humans can review later.",
1519
+ inputSchema: {
1520
+ type: "object",
1521
+ properties: {
1522
+ content: {
1523
+ type: "string",
1524
+ description: "Full acceptance checklist in Markdown (Chinese): summary of code changes, scope by repo, key files, verification notes"
1525
+ }
1526
+ },
1527
+ required: ["content"]
1528
+ },
1529
+ execute: async (args) => {
1530
+ const content = asString(args.content);
1531
+ if (!content) {
1532
+ throw new Error("UpsertWebIdeChecklist \u7F3A\u5C11 content");
1533
+ }
1534
+ await webideUpsertChecklist({ content });
1535
+ return JSON.stringify({ ok: true, chars: content.length }, null, 2);
1536
+ }
1537
+ }
1538
+ };
1539
+ }
1540
+ function createGetWebIdeChecklistTool(options) {
1541
+ const { boundTaskId, webideGetChecklist } = options;
1542
+ return {
1543
+ GetWebIdeChecklist: {
1544
+ description: "Fetch the acceptance checklist markdown for a WebIDE task by taskId. Returns content=null if none has been written yet. Use when you need to read or revise an existing checklist.",
1545
+ inputSchema: {
1546
+ type: "object",
1547
+ properties: {
1548
+ taskId: {
1549
+ type: "string",
1550
+ description: "WebIDE task id whose checklist to load"
1551
+ }
1552
+ },
1553
+ required: ["taskId"]
1554
+ },
1555
+ execute: async (args) => {
1556
+ const taskId = asString(args.taskId);
1557
+ if (!taskId) {
1558
+ throw new Error("GetWebIdeChecklist \u7F3A\u5C11 taskId");
1559
+ }
1560
+ if (taskId !== boundTaskId) {
1561
+ throw new Error(
1562
+ `GetWebIdeChecklist \u7684 taskId \u987B\u4E3A\u5F53\u524D\u4EFB\u52A1 ${boundTaskId}`
1563
+ );
1564
+ }
1565
+ const result = await webideGetChecklist({ taskId });
1566
+ return JSON.stringify(result, null, 2);
1567
+ }
1568
+ }
1569
+ };
1570
+ }
1589
1571
 
1590
1572
  // src/commands/connect/tools/webide-test-case-tools.ts
1591
1573
  function asString2(value) {
@@ -1618,7 +1600,7 @@ function createUpsertWebIdeTestCasesTool(options) {
1618
1600
  const { webideReplaceTestCases } = options;
1619
1601
  return {
1620
1602
  UpsertWebIdeTestCases: {
1621
- description: "Persist generated automated test cases for this WebIDE task (full replace) and mark the workflow TEST_READY. Call once with the complete case list after reviewing the task and code changes.",
1603
+ description: "Persist generated automated test cases for this WebIDE task (full replace). Call once with the complete case list after reviewing the task and code changes. Does not change workflow phase.",
1622
1604
  inputSchema: {
1623
1605
  type: "object",
1624
1606
  properties: {
@@ -2364,6 +2346,23 @@ function createCursorCustomTools(cfg2, options) {
2364
2346
  })
2365
2347
  );
2366
2348
  }
2349
+ if (wantsTool("UpsertWebIdeChecklist", options, enablePlan)) {
2350
+ Object.assign(
2351
+ tools,
2352
+ createUpsertWebIdeChecklistTool({
2353
+ webideUpsertChecklist: (args) => cli.webideUpsertChecklist({ taskId, ...args })
2354
+ })
2355
+ );
2356
+ }
2357
+ if (wantsTool("GetWebIdeChecklist", options, enablePlan)) {
2358
+ Object.assign(
2359
+ tools,
2360
+ createGetWebIdeChecklistTool({
2361
+ boundTaskId: taskId,
2362
+ webideGetChecklist: (args) => cli.webideGetChecklist(args)
2363
+ })
2364
+ );
2365
+ }
2367
2366
  if (wantsTool("UpsertWebIdeTestCases", options, enablePlan)) {
2368
2367
  Object.assign(
2369
2368
  tools,
@@ -3138,14 +3137,75 @@ function createThrottledWebIdeMessageLogSync(cfg2, ctx, onError, options) {
3138
3137
  };
3139
3138
  }
3140
3139
 
3141
- // src/commands/init.ts
3142
- async function initializeWorkspace(workdir) {
3143
- await ensureWorkspaceApmDirForInit(workdir);
3140
+ // src/commands/sync-webide-agent.ts
3141
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3142
+ import { join as join4 } from "path";
3143
+ var REVISION_FILE = ".webide-agent.json";
3144
+ var RULE_KEY = /^webide_[a-z0-9_]+$/;
3145
+ function withTrailingNewline(text) {
3146
+ return text.endsWith("\n") ? text : `${text}
3147
+ `;
3148
+ }
3149
+ function readRevision(apmDir) {
3150
+ const path3 = toFsPath(join4(apmDir, REVISION_FILE));
3151
+ if (!existsSync5(path3)) return null;
3152
+ try {
3153
+ const parsed = JSON.parse(readFileSync4(path3, "utf8"));
3154
+ if (parsed?.version === 1 && parsed.revision?.trim()) {
3155
+ return parsed.revision.trim();
3156
+ }
3157
+ } catch {
3158
+ return null;
3159
+ }
3160
+ return null;
3161
+ }
3162
+ function writeRevision(apmDir, revision) {
3163
+ writeFileSync3(
3164
+ toFsPath(join4(apmDir, REVISION_FILE)),
3165
+ `${JSON.stringify({ version: 1, revision }, null, 2)}
3166
+ `,
3167
+ "utf8"
3168
+ );
3169
+ }
3170
+ async function syncWebIdeAgentFiles(workdir, cfg2) {
3171
+ const api = createApmApiClient(cfg2);
3172
+ const bundle = await api.cli.webideAgentConfig();
3173
+ const revision = bundle.revision?.trim();
3174
+ if (!revision) {
3175
+ throw new Error("[apm] \u5E73\u53F0\u672A\u8FD4\u56DE WebIDE \u89C4\u5219\u7248\u672C");
3176
+ }
3144
3177
  const apmDir = workspaceApmDir(workdir);
3145
- await copyWebIdeTemplateFiles(apmDir, workdir);
3146
- console.log(`[apm] \u5DF2\u6309 WebIDE \u521D\u59CB\u5316\u5DE5\u4F5C\u533A\uFF1A${apmDir}`);
3147
- return { didInit: true };
3178
+ mkdirSync4(toFsPath(apmDir), { recursive: true });
3179
+ if (readRevision(apmDir) === revision) {
3180
+ return { revision, wrote: false, ruleCount: bundle.rules?.length ?? 0 };
3181
+ }
3182
+ const rulesDir = join4(apmDir, "rules");
3183
+ mkdirSync4(toFsPath(rulesDir), { recursive: true });
3184
+ writeFileSync3(
3185
+ toFsPath(join4(apmDir, "AGENTS.md")),
3186
+ withTrailingNewline(bundle.guide ?? ""),
3187
+ "utf8"
3188
+ );
3189
+ for (const rule of bundle.rules ?? []) {
3190
+ const key = rule.key?.trim() ?? "";
3191
+ if (!RULE_KEY.test(key)) {
3192
+ throw new Error(`[apm] \u975E\u6CD5\u89C4\u5219\u540D: ${key || "(\u7A7A)"}`);
3193
+ }
3194
+ writeFileSync3(
3195
+ toFsPath(join4(rulesDir, `${key}.md`)),
3196
+ withTrailingNewline(rule.body ?? ""),
3197
+ "utf8"
3198
+ );
3199
+ }
3200
+ writeRevision(apmDir, revision);
3201
+ return {
3202
+ revision,
3203
+ wrote: true,
3204
+ ruleCount: bundle.rules?.length ?? 0
3205
+ };
3148
3206
  }
3207
+
3208
+ // src/commands/init.ts
3149
3209
  async function ensureWorkspaceInitialized(workdir) {
3150
3210
  if (isWorkspaceApmInitialized(workdir)) {
3151
3211
  return { didInit: false };
@@ -3153,19 +3213,21 @@ async function ensureWorkspaceInitialized(workdir) {
3153
3213
  console.log(
3154
3214
  `[apm] \u5DE5\u4F5C\u76EE\u5F55 ${workdir} \u672A\u68C0\u6D4B\u5230\u5DF2\u521D\u59CB\u5316\u7684 .apm\uFF0C\u6B63\u5728\u6309 WebIDE \u81EA\u52A8\u521D\u59CB\u5316\u2026`
3155
3215
  );
3156
- return initializeWorkspace(workdir);
3216
+ await ensureWorkspaceApmDirForInit(workdir);
3217
+ console.log(`[apm] \u5DF2\u521B\u5EFA\u5DE5\u4F5C\u533A\u76EE\u5F55\uFF1A${workspaceApmDir(workdir)}`);
3218
+ return { didInit: true };
3157
3219
  }
3158
3220
 
3159
3221
  // src/utils/project-documents.ts
3160
3222
  import {
3161
- existsSync as existsSync5,
3223
+ existsSync as existsSync6,
3162
3224
  readdirSync as readdirSync3,
3163
- readFileSync as readFileSync4,
3225
+ readFileSync as readFileSync5,
3164
3226
  rmSync,
3165
- writeFileSync as writeFileSync3
3227
+ writeFileSync as writeFileSync4
3166
3228
  } from "fs";
3167
3229
  import { createHash as createHash2 } from "crypto";
3168
- import { dirname as dirname3, join as join4, relative as relative4, sep } from "path";
3230
+ import { dirname as dirname2, join as join5, relative as relative4, sep } from "path";
3169
3231
  var MANIFEST_FILE = "manifest.json";
3170
3232
  function normalizeProjectIdForPath(projectId) {
3171
3233
  const id = projectId.trim();
@@ -3179,11 +3241,11 @@ function normalizeProjectIdForPath(projectId) {
3179
3241
  }
3180
3242
  function projectDocumentsDir(apmRoot, projectId) {
3181
3243
  const id = normalizeProjectIdForPath(projectId);
3182
- return join4(apmRoot ?? workspaceApmDir(), "project", id);
3244
+ return join5(apmRoot ?? workspaceApmDir(), "project", id);
3183
3245
  }
3184
3246
  function projectDocumentLocalPath(apmRoot, projectId, documentPath) {
3185
3247
  const normalized = normalizeLocalDocumentPath(documentPath);
3186
- return join4(
3248
+ return join5(
3187
3249
  projectDocumentsDir(apmRoot, projectId),
3188
3250
  ...normalized.split("/")
3189
3251
  );
@@ -3203,16 +3265,16 @@ function hashLocalFileContent(content) {
3203
3265
  return createHash2("sha256").update(content, "utf8").digest("hex");
3204
3266
  }
3205
3267
  function readLocalManifest(apmRoot, projectId) {
3206
- const manifestPath3 = join4(
3268
+ const manifestPath2 = join5(
3207
3269
  projectDocumentsDir(apmRoot, projectId),
3208
3270
  MANIFEST_FILE
3209
3271
  );
3210
- if (!existsSync5(manifestPath3)) {
3272
+ if (!existsSync6(manifestPath2)) {
3211
3273
  return null;
3212
3274
  }
3213
3275
  try {
3214
3276
  return JSON.parse(
3215
- readFileSync4(manifestPath3, "utf8")
3277
+ readFileSync5(manifestPath2, "utf8")
3216
3278
  );
3217
3279
  } catch {
3218
3280
  return null;
@@ -3220,13 +3282,13 @@ function readLocalManifest(apmRoot, projectId) {
3220
3282
  }
3221
3283
  function listLocalDocumentPaths(apmRoot, projectId) {
3222
3284
  const root = projectDocumentsDir(apmRoot, projectId);
3223
- if (!existsSync5(root)) {
3285
+ if (!existsSync6(root)) {
3224
3286
  return [];
3225
3287
  }
3226
3288
  const paths = [];
3227
3289
  const walk = (dir) => {
3228
3290
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
3229
- const abs = join4(dir, entry.name);
3291
+ const abs = join5(dir, entry.name);
3230
3292
  if (entry.isDirectory()) {
3231
3293
  walk(abs);
3232
3294
  continue;
@@ -3345,8 +3407,8 @@ ${diagnostic ?? ""}`);
3345
3407
  const absPath = toFsPath(
3346
3408
  projectDocumentLocalPath(targetApmDir, projectId, doc.path)
3347
3409
  );
3348
- await ensureDirExists(dirname3(absPath));
3349
- writeFileSync3(absPath, doc.content, "utf8");
3410
+ await ensureDirExists(dirname2(absPath));
3411
+ writeFileSync4(absPath, doc.content, "utf8");
3350
3412
  downloaded += 1;
3351
3413
  }
3352
3414
  }
@@ -3355,13 +3417,13 @@ ${diagnostic ?? ""}`);
3355
3417
  const absPath = toFsPath(
3356
3418
  projectDocumentLocalPath(targetApmDir, projectId, path3)
3357
3419
  );
3358
- if (existsSync5(absPath)) {
3420
+ if (existsSync6(absPath)) {
3359
3421
  rmSync(absPath, { force: true });
3360
3422
  deleted += 1;
3361
3423
  }
3362
3424
  }
3363
- writeFileSync3(
3364
- toFsPath(join4(docsDir, MANIFEST_FILE)),
3425
+ writeFileSync4(
3426
+ toFsPath(join5(docsDir, MANIFEST_FILE)),
3365
3427
  `${JSON.stringify(remoteManifest, null, 2)}
3366
3428
  `,
3367
3429
  "utf8"
@@ -3404,7 +3466,7 @@ async function syncProjectDocumentsPush(cfg2, workdirPath, apmRoot, options) {
3404
3466
  const absPath = toFsPath(
3405
3467
  projectDocumentLocalPath(targetApmDir, projectId, path3)
3406
3468
  );
3407
- const content = readFileSync4(absPath, "utf8");
3469
+ const content = readFileSync5(absPath, "utf8");
3408
3470
  const contentHash = hashLocalFileContent(content);
3409
3471
  if (remoteHashByPath.get(path3) === contentHash) {
3410
3472
  continue;
@@ -3424,71 +3486,6 @@ async function syncProjectDocumentsPush(cfg2, workdirPath, apmRoot, options) {
3424
3486
  return synced;
3425
3487
  }
3426
3488
 
3427
- // src/version.ts
3428
- import { readFileSync as readFileSync5 } from "fs";
3429
- import { dirname as dirname4, join as join5 } from "path";
3430
- import { fileURLToPath as fileURLToPath2 } from "url";
3431
- function readCliVersion() {
3432
- try {
3433
- const dir = dirname4(fileURLToPath2(import.meta.url));
3434
- const pkgPath = join5(dir, "..", "package.json");
3435
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
3436
- return pkg.version ?? "0.0.0";
3437
- } catch {
3438
- return "0.0.0";
3439
- }
3440
- }
3441
-
3442
- // src/commands/connect/cli-version-sync.ts
3443
- import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
3444
- import { join as join6 } from "path";
3445
- var CLI_VERSION_FILE = ".cli-version.json";
3446
- function manifestPath2(apmDir) {
3447
- return join6(apmDir, CLI_VERSION_FILE);
3448
- }
3449
- function loadManifest(apmDir) {
3450
- const path3 = toFsPath(manifestPath2(apmDir));
3451
- if (!existsSync6(path3)) {
3452
- return null;
3453
- }
3454
- try {
3455
- const parsed = JSON.parse(
3456
- readFileSync6(path3, "utf8")
3457
- );
3458
- if (parsed?.version === 1 && typeof parsed.cliVersion === "string" && parsed.cliVersion.trim()) {
3459
- return parsed;
3460
- }
3461
- } catch {
3462
- }
3463
- return null;
3464
- }
3465
- function saveManifest(apmDir, cliVersion) {
3466
- const manifest = { version: 1, cliVersion };
3467
- writeFileSync4(
3468
- toFsPath(manifestPath2(apmDir)),
3469
- `${JSON.stringify(manifest, null, 2)}
3470
- `,
3471
- "utf8"
3472
- );
3473
- }
3474
- var syncedInSession = /* @__PURE__ */ new Map();
3475
- function shouldSyncSkillsForCliVersion(workdir, currentVersion) {
3476
- const cached = syncedInSession.get(workdir);
3477
- if (cached === currentVersion) {
3478
- return false;
3479
- }
3480
- const stored = loadManifest(workspaceApmDir(workdir));
3481
- if (stored?.cliVersion === currentVersion) {
3482
- syncedInSession.set(workdir, currentVersion);
3483
- return false;
3484
- }
3485
- return true;
3486
- }
3487
- function markSkillsSyncedForCliVersion(workdir, cliVersion) {
3488
- saveManifest(workspaceApmDir(workdir), cliVersion);
3489
- syncedInSession.set(workdir, cliVersion);
3490
- }
3491
-
3492
3489
  // src/commands/connect/upload-package-artifact.ts
3493
3490
  import fs2 from "node:fs";
3494
3491
  import path2 from "node:path";
@@ -3608,26 +3605,12 @@ async function handleWebIdePackage(cfg2, msg2, signal) {
3608
3605
  },
3609
3606
  (didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
3610
3607
  );
3611
- const cliVersion = readCliVersion();
3612
- if (shouldSyncSkillsForCliVersion(workdir, cliVersion)) {
3613
- if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3614
- await runPrepStep(
3615
- "\u540C\u6B65 WebIDE \u89C4\u5219",
3616
- async () => {
3617
- await copyWebIdeTemplateFiles(workspaceApmDir(workdir), workdir);
3618
- markSkillsSyncedForCliVersion(workdir, cliVersion);
3619
- return cliVersion;
3620
- },
3621
- (version) => `\u5DF2\u540C\u6B65\u81F3 CLI ${version}`
3622
- );
3623
- } else {
3624
- eventSession.addCliStep(
3625
- "\u540C\u6B65 WebIDE \u89C4\u5219",
3626
- `\u7248\u672C\u4E00\u81F4\uFF08${cliVersion}\uFF09\uFF0C\u8DF3\u8FC7`,
3627
- "skip"
3628
- );
3629
- await syncPrepLog();
3630
- }
3608
+ if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3609
+ await runPrepStep(
3610
+ "\u540C\u6B65 WebIDE \u89C4\u5219",
3611
+ async () => syncWebIdeAgentFiles(workdir, cfg2),
3612
+ (result) => result.wrote ? `\u5DF2\u5199\u5165 ${result.ruleCount} \u6761\u89C4\u5219` : "\u89C4\u5219\u672A\u53D8\u5316\uFF0C\u8DF3\u8FC7"
3613
+ );
3631
3614
  await runPrepStep(
3632
3615
  "\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355",
3633
3616
  async () => {
@@ -3856,6 +3839,7 @@ async function handleStartProject(cfg2, msg2, signal) {
3856
3839
  try {
3857
3840
  if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
3858
3841
  await ensureWorkspaceInitialized(workdir);
3842
+ await syncWebIdeAgentFiles(workdir, cfg2);
3859
3843
  const api = createApmApiClient(cfg2);
3860
3844
  const outcome = await runCursorAgent(
3861
3845
  cfg2,
@@ -3967,8 +3951,8 @@ async function handleStartProject(cfg2, msg2, signal) {
3967
3951
  }
3968
3952
 
3969
3953
  // src/commands/connect/webide-agent-registry.ts
3970
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
3971
- import { dirname as dirname5, resolve as resolve6 } from "node:path";
3954
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "node:fs";
3955
+ import { dirname as dirname3, resolve as resolve6 } from "node:path";
3972
3956
  function registryPath(workdir, taskId, fileName = "cursor-agent.json") {
3973
3957
  return resolve6(workdir, ".apm", "webide", taskId, fileName);
3974
3958
  }
@@ -3978,7 +3962,7 @@ function readRegistry(path3) {
3978
3962
  return {};
3979
3963
  }
3980
3964
  try {
3981
- const parsed = JSON.parse(readFileSync7(path3, "utf8"));
3965
+ const parsed = JSON.parse(readFileSync6(path3, "utf8"));
3982
3966
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3983
3967
  const raw = parsed;
3984
3968
  const state = {};
@@ -4007,7 +3991,7 @@ function readRegistry(path3) {
4007
3991
  return {};
4008
3992
  }
4009
3993
  function writeRegistry(path3, registry) {
4010
- mkdirSync4(dirname5(path3), { recursive: true });
3994
+ mkdirSync5(dirname3(path3), { recursive: true });
4011
3995
  writeFileSync5(path3, `${JSON.stringify(registry, null, 2)}
4012
3996
  `, "utf8");
4013
3997
  }
@@ -4145,100 +4129,6 @@ async function cleanWebIdeWorkspaceCache(taskId, workdir, cfg2) {
4145
4129
  }
4146
4130
  }
4147
4131
 
4148
- // src/commands/connect/webide-run-action.ts
4149
- function startActionForInbound(action) {
4150
- switch (action) {
4151
- case "request-assessment":
4152
- return "start-assessment";
4153
- case "request-design":
4154
- case "request-revise-design":
4155
- return "start-design";
4156
- case "request-write-plan":
4157
- case "request-revise-plan":
4158
- return "start-write-plan";
4159
- case "request-develop":
4160
- case "skip-plan":
4161
- return "start-develop";
4162
- case "request-start-project":
4163
- return "start-project";
4164
- case "request-execute-sql":
4165
- return "start-execute-sql";
4166
- case "request-bugfix":
4167
- return "start-bugfix";
4168
- case "request-organize-code":
4169
- case "request-patch":
4170
- return "start-organize-code";
4171
- case "request-accept":
4172
- return "start-accept";
4173
- default:
4174
- return null;
4175
- }
4176
- }
4177
- function completeActionForInbound(action) {
4178
- switch (action) {
4179
- case "request-assessment":
4180
- case "confirm-assumptions":
4181
- return "complete-assessment";
4182
- case "request-design":
4183
- case "request-revise-design":
4184
- return "complete-design";
4185
- case "request-write-plan":
4186
- case "request-revise-plan":
4187
- return "complete-write-plan";
4188
- case "request-develop":
4189
- case "skip-plan":
4190
- return "complete-develop";
4191
- case "request-start-project":
4192
- return "complete-project";
4193
- case "request-execute-sql":
4194
- return "complete-execute-sql";
4195
- case "request-bugfix":
4196
- return "complete-bugfix";
4197
- case "request-organize-code":
4198
- case "request-patch":
4199
- return "complete-organize-code";
4200
- case "request-accept":
4201
- return "complete-accept";
4202
- default:
4203
- return null;
4204
- }
4205
- }
4206
- async function webIdeRunAction(cfg2, taskId, action, params) {
4207
- const api = createApmApiClient(cfg2);
4208
- await api.cli.webideRunAction({ taskId, action, params });
4209
- console.log(`[apm] webide runAction ok action=${action} taskId=${taskId}`);
4210
- }
4211
- async function webIdeSyncTransitionPrepEvents(cfg2, taskId, startAction, prepEvents) {
4212
- try {
4213
- const api = createApmApiClient(cfg2);
4214
- await api.cli.webideUpdateTransitionPrepEvents({
4215
- taskId,
4216
- startAction,
4217
- prepEvents
4218
- });
4219
- } catch (err) {
4220
- console.warn(
4221
- `[apm] sync transition prepEvents failed taskId=${taskId}:`,
4222
- err instanceof Error ? err.message : err
4223
- );
4224
- }
4225
- }
4226
- async function webIdeDiscardTransitionPrepDraft(cfg2, taskId, startAction) {
4227
- try {
4228
- const api = createApmApiClient(cfg2);
4229
- await api.cli.webideUpdateTransitionPrepEvents({
4230
- taskId,
4231
- startAction,
4232
- discardDraft: true
4233
- });
4234
- } catch (err) {
4235
- console.warn(
4236
- `[apm] discard transition prep draft failed taskId=${taskId}:`,
4237
- err instanceof Error ? err.message : err
4238
- );
4239
- }
4240
- }
4241
-
4242
4132
  // src/commands/connect/webide-ask-question.ts
4243
4133
  function asString5(value) {
4244
4134
  return typeof value === "string" ? value.trim() : "";
@@ -4298,9 +4188,8 @@ async function fetchAssumptionAnswersAndContinueAssessment(options) {
4298
4188
  resolution: row.resolution
4299
4189
  });
4300
4190
  }
4301
- await webIdeRunAction(cfg2, taskId, "continue-assessment");
4302
4191
  console.log(
4303
- `[apm] \u5047\u8BBE\u7ED3\u679C\u5DF2\u62C9\u53D6\u5E76\u7EE7\u7EED\u8BC4\u4F30 taskId=${taskId} count=${answers.length}`
4192
+ `[apm] \u5047\u8BBE\u7ED3\u679C\u5DF2\u62C9\u53D6 taskId=${taskId} count=${answers.length}`
4304
4193
  );
4305
4194
  return JSON.stringify({ title, answers }, null, 2);
4306
4195
  }
@@ -4554,8 +4443,8 @@ async function ensureWebIdePullRequests(cfg2, taskId, workdir) {
4554
4443
  }
4555
4444
 
4556
4445
  // src/commands/sync-webide-attachments.ts
4557
- import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
4558
- import { join as join7 } from "path";
4446
+ import { existsSync as existsSync9, readFileSync as readFileSync7, writeFileSync as writeFileSync6 } from "fs";
4447
+ import { join as join6 } from "path";
4559
4448
  var MANIFEST_FILE2 = ".sync-manifest.json";
4560
4449
  async function downloadAttachment(cfg2, attachmentId) {
4561
4450
  const base = cfg2.baseUrl.trim().replace(/\/+$/, "");
@@ -4570,14 +4459,14 @@ async function downloadAttachment(cfg2, attachmentId) {
4570
4459
  }
4571
4460
  return Buffer.from(await res.arrayBuffer());
4572
4461
  }
4573
- function loadManifest2(dir) {
4574
- const path3 = join7(dir, MANIFEST_FILE2);
4462
+ function loadManifest(dir) {
4463
+ const path3 = join6(dir, MANIFEST_FILE2);
4575
4464
  if (!existsSync9(path3)) {
4576
4465
  return { version: 1, attachments: {} };
4577
4466
  }
4578
4467
  try {
4579
4468
  const parsed = JSON.parse(
4580
- readFileSync8(path3, "utf8")
4469
+ readFileSync7(path3, "utf8")
4581
4470
  );
4582
4471
  if (parsed?.version === 1 && parsed.attachments && typeof parsed.attachments === "object") {
4583
4472
  return parsed;
@@ -4586,9 +4475,9 @@ function loadManifest2(dir) {
4586
4475
  }
4587
4476
  return { version: 1, attachments: {} };
4588
4477
  }
4589
- function saveManifest2(dir, manifest) {
4478
+ function saveManifest(dir, manifest) {
4590
4479
  writeFileSync6(
4591
- join7(dir, MANIFEST_FILE2),
4480
+ join6(dir, MANIFEST_FILE2),
4592
4481
  `${JSON.stringify(manifest, null, 2)}
4593
4482
  `,
4594
4483
  "utf8"
@@ -4603,14 +4492,14 @@ function isAttachmentUpToDate(entry, item, dest) {
4603
4492
  async function syncAttachmentsToDirectory(cfg2, attachments, dir, logLabel) {
4604
4493
  await ensureDirExists(dir);
4605
4494
  if (attachments.length === 0) {
4606
- saveManifest2(dir, { version: 1, attachments: {} });
4495
+ saveManifest(dir, { version: 1, attachments: {} });
4607
4496
  return [];
4608
4497
  }
4609
- const manifest = loadManifest2(dir);
4498
+ const manifest = loadManifest(dir);
4610
4499
  const nextManifest = { version: 1, attachments: {} };
4611
4500
  const names = [];
4612
4501
  for (const item of attachments) {
4613
- const dest = join7(dir, item.name);
4502
+ const dest = join6(dir, item.name);
4614
4503
  const entry = manifest.attachments[item.id];
4615
4504
  const createdAt = item.createdAt ?? "";
4616
4505
  names.push(item.name);
@@ -4627,7 +4516,7 @@ async function syncAttachmentsToDirectory(cfg2, attachments, dir, logLabel) {
4627
4516
  };
4628
4517
  console.log(`[apm] \u5DF2\u4E0B\u8F7D\u9644\u4EF6: ${logLabel}/${item.name}`);
4629
4518
  }
4630
- saveManifest2(dir, nextManifest);
4519
+ saveManifest(dir, nextManifest);
4631
4520
  return names;
4632
4521
  }
4633
4522
  async function syncWebIdeAttachments(cfg2, taskId, workdir, attachments) {
@@ -4642,19 +4531,19 @@ async function syncWebIdeAttachments(cfg2, taskId, workdir, attachments) {
4642
4531
 
4643
4532
  // src/commands/sync-webide-design.ts
4644
4533
  import { createHash as createHash3 } from "crypto";
4645
- import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
4646
- import { join as join8 } from "path";
4534
+ import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
4535
+ import { join as join7 } from "path";
4647
4536
  var MANIFEST_FILE3 = ".sync-manifest.json";
4648
4537
  function hashBuffer(buf) {
4649
4538
  return createHash3("sha256").update(buf).digest("hex");
4650
4539
  }
4651
- function loadManifest3(dir) {
4652
- const path3 = join8(dir, MANIFEST_FILE3);
4540
+ function loadManifest2(dir) {
4541
+ const path3 = join7(dir, MANIFEST_FILE3);
4653
4542
  if (!existsSync10(path3)) {
4654
4543
  return { version: 1, files: {} };
4655
4544
  }
4656
4545
  try {
4657
- const parsed = JSON.parse(readFileSync9(path3, "utf8"));
4546
+ const parsed = JSON.parse(readFileSync8(path3, "utf8"));
4658
4547
  if (parsed?.version === 1 && parsed.files && typeof parsed.files === "object") {
4659
4548
  return parsed;
4660
4549
  }
@@ -4662,9 +4551,9 @@ function loadManifest3(dir) {
4662
4551
  }
4663
4552
  return { version: 1, files: {} };
4664
4553
  }
4665
- function saveManifest3(dir, manifest) {
4554
+ function saveManifest2(dir, manifest) {
4666
4555
  writeFileSync7(
4667
- join8(dir, MANIFEST_FILE3),
4556
+ join7(dir, MANIFEST_FILE3),
4668
4557
  `${JSON.stringify(manifest, null, 2)}
4669
4558
  `,
4670
4559
  "utf8"
@@ -4687,12 +4576,12 @@ async function downloadDesignFile(cfg2, taskId, name) {
4687
4576
  async function syncWebIdeDesign(cfg2, taskId, workdir, artifacts) {
4688
4577
  const dir = webideDesignDir(taskId, workdir);
4689
4578
  await ensureDirExists(dir);
4690
- const manifest = loadManifest3(dir);
4579
+ const manifest = loadManifest2(dir);
4691
4580
  const synced = [];
4692
4581
  for (const art of artifacts) {
4693
4582
  const name = art.name?.trim();
4694
4583
  if (!name || !name.toLowerCase().endsWith(".html")) continue;
4695
- const localPath = join8(dir, name);
4584
+ const localPath = join7(dir, name);
4696
4585
  const entry = manifest.files[name];
4697
4586
  if (entry?.contentHash === art.contentHash && existsSync10(localPath)) {
4698
4587
  continue;
@@ -4702,7 +4591,7 @@ async function syncWebIdeDesign(cfg2, taskId, workdir, artifacts) {
4702
4591
  manifest.files[name] = { contentHash: hashBuffer(buf) };
4703
4592
  synced.push(name);
4704
4593
  }
4705
- saveManifest3(dir, manifest);
4594
+ saveManifest2(dir, manifest);
4706
4595
  return synced;
4707
4596
  }
4708
4597
  function listLocalDesignHtmlFiles(taskId, workdir) {
@@ -4711,8 +4600,8 @@ function listLocalDesignHtmlFiles(taskId, workdir) {
4711
4600
  const out = [];
4712
4601
  for (const name of readdirSync4(dir)) {
4713
4602
  if (!name.toLowerCase().endsWith(".html")) continue;
4714
- const absPath = join8(dir, name);
4715
- const buf = readFileSync9(absPath);
4603
+ const absPath = join7(dir, name);
4604
+ const buf = readFileSync8(absPath);
4716
4605
  if (buf.length === 0) continue;
4717
4606
  out.push({ name, absPath, contentHash: hashBuffer(buf) });
4718
4607
  }
@@ -4790,6 +4679,102 @@ function parseWebIdePromptPayload(content) {
4790
4679
  return null;
4791
4680
  }
4792
4681
 
4682
+ // src/commands/connect/webide-run-action.ts
4683
+ function startActionForInbound(action) {
4684
+ switch (action) {
4685
+ case "request-assessment":
4686
+ return "start-assessment";
4687
+ case "request-design":
4688
+ case "request-revise-design":
4689
+ return "start-design";
4690
+ case "request-write-plan":
4691
+ case "request-revise-plan":
4692
+ return "start-write-plan";
4693
+ case "request-develop":
4694
+ case "skip-plan":
4695
+ return "start-develop";
4696
+ case "request-start-project":
4697
+ return "start-project";
4698
+ case "request-execute-sql":
4699
+ return "start-execute-sql";
4700
+ case "request-bugfix":
4701
+ return "start-bugfix";
4702
+ case "request-organize-code":
4703
+ case "request-patch":
4704
+ return "start-organize-code";
4705
+ case "request-accept":
4706
+ return "start-accept";
4707
+ case "confirm-assumptions":
4708
+ return "continue-assessment";
4709
+ default:
4710
+ return null;
4711
+ }
4712
+ }
4713
+ function completeActionForInbound(action) {
4714
+ switch (action) {
4715
+ case "request-assessment":
4716
+ case "confirm-assumptions":
4717
+ return "complete-assessment";
4718
+ case "request-design":
4719
+ case "request-revise-design":
4720
+ return "complete-design";
4721
+ case "request-write-plan":
4722
+ case "request-revise-plan":
4723
+ return "complete-write-plan";
4724
+ case "request-develop":
4725
+ case "skip-plan":
4726
+ return "complete-develop";
4727
+ case "request-start-project":
4728
+ return "complete-project";
4729
+ case "request-execute-sql":
4730
+ return "complete-execute-sql";
4731
+ case "request-bugfix":
4732
+ return "complete-bugfix";
4733
+ case "request-organize-code":
4734
+ case "request-patch":
4735
+ return "complete-organize-code";
4736
+ case "request-accept":
4737
+ return "complete-accept";
4738
+ default:
4739
+ return null;
4740
+ }
4741
+ }
4742
+ async function webIdeRunAction(cfg2, taskId, action, params) {
4743
+ const api = createApmApiClient(cfg2);
4744
+ await api.cli.webideRunAction({ taskId, action, params });
4745
+ console.log(`[apm] webide runAction ok action=${action} taskId=${taskId}`);
4746
+ }
4747
+ async function webIdeSyncTransitionPrepEvents(cfg2, taskId, startAction, prepEvents) {
4748
+ try {
4749
+ const api = createApmApiClient(cfg2);
4750
+ await api.cli.webideUpdateTransitionPrepEvents({
4751
+ taskId,
4752
+ startAction,
4753
+ prepEvents
4754
+ });
4755
+ } catch (err) {
4756
+ console.warn(
4757
+ `[apm] sync transition prepEvents failed taskId=${taskId}:`,
4758
+ err instanceof Error ? err.message : err
4759
+ );
4760
+ }
4761
+ }
4762
+ async function webIdeDiscardTransitionPrepDraft(cfg2, taskId, startAction) {
4763
+ try {
4764
+ const api = createApmApiClient(cfg2);
4765
+ await api.cli.webideUpdateTransitionPrepEvents({
4766
+ taskId,
4767
+ startAction,
4768
+ discardDraft: true
4769
+ });
4770
+ } catch (err) {
4771
+ console.warn(
4772
+ `[apm] discard transition prep draft failed taskId=${taskId}:`,
4773
+ err instanceof Error ? err.message : err
4774
+ );
4775
+ }
4776
+ }
4777
+
4793
4778
  // src/commands/connect/core/worker/handlers/webide-message.ts
4794
4779
  var WEBIDE_CODE_CHANGE_ACTIONS = /* @__PURE__ */ new Set([
4795
4780
  "skip-plan",
@@ -4899,26 +4884,12 @@ async function handleWebIdeInboundMessage(cfg2, msg2, signal) {
4899
4884
  },
4900
4885
  (didInit) => didInit ? "\u5DF2\u521D\u59CB\u5316\u5DE5\u4F5C\u533A" : "\u5DE5\u4F5C\u533A\u5DF2\u5C31\u7EEA"
4901
4886
  );
4902
- const cliVersion = readCliVersion();
4903
- if (shouldSyncSkillsForCliVersion(workdir, cliVersion)) {
4904
- if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
4905
- await runPrepStep(
4906
- "\u540C\u6B65 WebIDE \u89C4\u5219",
4907
- async () => {
4908
- await copyWebIdeTemplateFiles(workspaceApmDir(workdir), workdir);
4909
- markSkillsSyncedForCliVersion(workdir, cliVersion);
4910
- return cliVersion;
4911
- },
4912
- (version) => `\u5DF2\u540C\u6B65\u81F3 CLI ${version}`
4913
- );
4914
- } else {
4915
- eventSession.addCliStep(
4916
- "\u540C\u6B65 WebIDE \u89C4\u5219",
4917
- `\u7248\u672C\u4E00\u81F4\uFF08${cliVersion}\uFF09\uFF0C\u8DF3\u8FC7`,
4918
- "skip"
4919
- );
4920
- await syncPrepLog();
4921
- }
4887
+ if (signal.aborted) throw new Error("\u4EFB\u52A1\u5DF2\u53D6\u6D88");
4888
+ await runPrepStep(
4889
+ "\u540C\u6B65 WebIDE \u89C4\u5219",
4890
+ async () => syncWebIdeAgentFiles(workdir, cfg2),
4891
+ (result) => result.wrote ? `\u5DF2\u5199\u5165 ${result.ruleCount} \u6761\u89C4\u5219` : "\u89C4\u5219\u672A\u53D8\u5316\uFF0C\u8DF3\u8FC7"
4892
+ );
4922
4893
  await runPrepStep(
4923
4894
  "\u5DE5\u4F5C\u533A\u4ED3\u5E93\u6E05\u5355",
4924
4895
  async () => {