ai-project-manage-cli 3.0.16 → 3.0.18

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
@@ -158,8 +158,8 @@ import { fileURLToPath } from "url";
158
158
  var __dirname = dirname(fileURLToPath(import.meta.url));
159
159
  var CLI_TEMPLATE_DIR = resolve(__dirname, "../template");
160
160
  var WORKSPACE_APM_DIR = resolve(process.cwd(), ".apm");
161
- function requirementWorkitemsDir(requirementId) {
162
- return join2(WORKSPACE_APM_DIR, "workitems", requirementId);
161
+ function requirementWorkitemsDir(requirementId, workspaceDir = WORKSPACE_APM_DIR) {
162
+ return join2(workspaceDir, "workitems", requirementId);
163
163
  }
164
164
  async function ensureLoggedConfig() {
165
165
  const cfg = await ensureApmConfig();
@@ -227,7 +227,6 @@ async function runComment(requirementId, file, model) {
227
227
  }
228
228
 
229
229
  // src/commands/connect.ts
230
- import { execSync } from "child_process";
231
230
  import { randomUUID } from "crypto";
232
231
  import WebSocket from "ws";
233
232
  import { Agent } from "@cursor/sdk";
@@ -329,6 +328,228 @@ var EventSession = class {
329
328
  }
330
329
  };
331
330
 
331
+ // src/commands/upload-artifact.ts
332
+ import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
333
+ import { join as join3, relative, sep } from "path";
334
+ var EXCLUDED_RELATIVE_PATHS = /* @__PURE__ */ new Set([
335
+ "defect.xml",
336
+ "prd.md",
337
+ "requirement-status.yaml",
338
+ "reviews.xml",
339
+ "testcase.xml"
340
+ ]);
341
+ function toPosixRelative(root, absoluteFile) {
342
+ return relative(root, absoluteFile).split(sep).join("/");
343
+ }
344
+ function artifactTagFromRelPath(relPosix) {
345
+ const parts = relPosix.split("/");
346
+ const fileName = parts[parts.length - 1] ?? relPosix;
347
+ if (parts.length > 1) {
348
+ return parts[0] ?? fileName;
349
+ }
350
+ const dot = fileName.lastIndexOf(".");
351
+ return dot > 0 ? fileName.slice(0, dot) : fileName;
352
+ }
353
+ function* walkMarkdownFiles(dir) {
354
+ const names = readdirSync2(dir);
355
+ for (const name of names) {
356
+ if (name.startsWith(".")) continue;
357
+ const full = join3(dir, name);
358
+ const st = statSync2(full);
359
+ if (st.isDirectory()) {
360
+ yield* walkMarkdownFiles(full);
361
+ continue;
362
+ }
363
+ if (!st.isFile()) continue;
364
+ if (!name.toLowerCase().endsWith(".md")) continue;
365
+ yield full;
366
+ }
367
+ }
368
+ async function deleteAllArtifactsForRequirement(api, requirementId) {
369
+ const pageSize = 100;
370
+ let page = 1;
371
+ const rows = [];
372
+ while (true) {
373
+ const batch = await api.requirementArtifact.list({
374
+ requirementId,
375
+ page,
376
+ pageSize
377
+ });
378
+ rows.push(...batch.items);
379
+ if (batch.total === 0 || rows.length >= batch.total) break;
380
+ page += 1;
381
+ }
382
+ for (const row of rows) {
383
+ await api.requirementArtifact.delete({ artifactId: row.id });
384
+ }
385
+ return rows.length;
386
+ }
387
+ async function runUploadArtifact(requirementId, workspaceDir) {
388
+ const cfg = await ensureLoggedConfig();
389
+ const api = createApmApiClient(cfg);
390
+ const root = requirementWorkitemsDir(requirementId, workspaceDir);
391
+ if (!existsSync2(root)) {
392
+ console.error(
393
+ `[apm] \u76EE\u5F55\u4E0D\u5B58\u5728: ${root}
394
+ \u8BF7\u5148\u6267\u884C: apm pull ${requirementId}`
395
+ );
396
+ process.exit(1);
397
+ }
398
+ const deleted = await deleteAllArtifactsForRequirement(api, requirementId);
399
+ console.log(`[apm] \u5DF2\u6E05\u7A7A\u9700\u6C42\u4EA7\u7269\u6587\u6863 ${deleted} \u6761`);
400
+ const paths = [...walkMarkdownFiles(root)];
401
+ let created = 0;
402
+ let skipped = 0;
403
+ for (const abs of paths) {
404
+ const relPosix = toPosixRelative(root, abs);
405
+ if (EXCLUDED_RELATIVE_PATHS.has(relPosix)) {
406
+ skipped += 1;
407
+ console.log(`[apm] \u8DF3\u8FC7\uFF08\u6392\u9664\u5217\u8868\uFF09: ${relPosix}`);
408
+ continue;
409
+ }
410
+ const content = readFileSync3(abs, "utf8");
411
+ const tag = artifactTagFromRelPath(relPosix);
412
+ await api.requirementArtifact.create({
413
+ requirementId,
414
+ tag,
415
+ fileName: relPosix,
416
+ content
417
+ });
418
+ created += 1;
419
+ console.log(`[apm] \u5DF2\u4E0A\u4F20\u4EA7\u7269: ${relPosix} (tag=${tag})`);
420
+ }
421
+ console.log(
422
+ `[apm] \u5B8C\u6210\uFF1A\u5220\u9664 ${deleted}\uFF0C\u65B0\u5EFA ${created}\uFF0C\u8DF3\u8FC7\uFF08\u6392\u9664\uFF09 ${skipped}\uFF0C\u5171\u626B\u63CF ${paths.length} \u4E2A Markdown \u6587\u4EF6`
423
+ );
424
+ }
425
+
426
+ // src/commands/pull.ts
427
+ import { writeFileSync as writeFileSync2 } from "fs";
428
+ import { join as join4 } from "path";
429
+ import { stringify as yamlStringify } from "yaml";
430
+ function valueToXmlContent(value) {
431
+ if (value === null || value === void 0) return "";
432
+ if (typeof value === "string") return xmlEscape(value);
433
+ if (typeof value === "number" || typeof value === "boolean") {
434
+ return xmlEscape(String(value));
435
+ }
436
+ return `<![CDATA[${JSON.stringify(value)}]]>`;
437
+ }
438
+ function recordToXmlLines(record, indent) {
439
+ const lines = [];
440
+ for (const [rawKey, val] of Object.entries(record)) {
441
+ const key = /^[a-zA-Z_][\w.-]*$/.test(rawKey) ? rawKey : "field";
442
+ lines.push(`${indent}<${key}>${valueToXmlContent(val)}</${key}>`);
443
+ }
444
+ return lines;
445
+ }
446
+ function unknownArrayToXml(rootName, itemName, items) {
447
+ const lines = [`<${rootName}>`];
448
+ items.forEach((item, index) => {
449
+ if (item !== null && typeof item === "object" && !Array.isArray(item)) {
450
+ lines.push(` <${itemName} index="${index}">`);
451
+ lines.push(...recordToXmlLines(item, " "));
452
+ lines.push(` </${itemName}>`);
453
+ } else {
454
+ lines.push(
455
+ ` <${itemName} index="${index}">${valueToXmlContent(
456
+ item
457
+ )}</${itemName}>`
458
+ );
459
+ }
460
+ });
461
+ lines.push(`</${rootName}>`, "");
462
+ return lines.join("\n");
463
+ }
464
+ function tasksForStatusYaml(tasks) {
465
+ return tasks.map((t) => ({
466
+ id: t.id,
467
+ title: t.title,
468
+ status: t.status,
469
+ executor: t.executorType
470
+ }));
471
+ }
472
+ function escapeForCdata(text) {
473
+ return text.replace(/\]\]>/g, "]]]]><![CDATA[>");
474
+ }
475
+ function defectsToXml(defects) {
476
+ const sorted = [...defects].sort(
477
+ (a, b) => new Date(a.createdAt ?? 0).getTime() - new Date(b.createdAt ?? 0).getTime()
478
+ );
479
+ const lines = ["<defects>"];
480
+ for (const d of sorted) {
481
+ lines.push(` <defect id="${xmlEscape(d.id)}">`);
482
+ lines.push(` <status>${xmlEscape(d.status)}</status>`);
483
+ lines.push(
484
+ ` <current><![CDATA[${escapeForCdata(
485
+ d.currentState ?? ""
486
+ )}]]></current>`
487
+ );
488
+ lines.push(
489
+ ` <expected><![CDATA[${escapeForCdata(
490
+ d.expectedEffect ?? ""
491
+ )}]]></expected>`
492
+ );
493
+ lines.push(` </defect>`);
494
+ }
495
+ lines.push("</defects>", "");
496
+ return lines.join("\n");
497
+ }
498
+ async function runPull(requirementId, workspaceDir) {
499
+ const cfg = await ensureLoggedConfig();
500
+ const api = createApmApiClient(cfg);
501
+ const data = await api.cliRequirements.pull({ requirementId });
502
+ const WORKITEMS_DIR = requirementWorkitemsDir(requirementId, workspaceDir);
503
+ await ensureDirExists(WORKITEMS_DIR);
504
+ const req2 = data.requirement;
505
+ const statusYaml = yamlStringify(
506
+ {
507
+ id: req2.id,
508
+ status: req2.status,
509
+ title: req2.title,
510
+ env: req2.envName || "",
511
+ tasks: tasksForStatusYaml(data.tasks ?? [])
512
+ },
513
+ { lineWidth: 0 }
514
+ );
515
+ writeFileSync2(
516
+ join4(WORKITEMS_DIR, "requirement-status.yaml"),
517
+ statusYaml.endsWith("\n") ? statusYaml : `${statusYaml}
518
+ `,
519
+ "utf8"
520
+ );
521
+ writeFileSync2(join4(WORKITEMS_DIR, "prd.md"), req2.content || "", "utf8");
522
+ const reviews = data.reviews ?? [];
523
+ const reviewsXml = [
524
+ "<reviews>",
525
+ ...reviews.map((r) => {
526
+ return [
527
+ ` <review id="${xmlEscape(r.id)}">`,
528
+ ` <model>${xmlEscape(r.model ?? "")}</model>`,
529
+ ` <content>`,
530
+ `${xmlEscape(r.content ?? "")}`,
531
+ ` </content>`,
532
+ ` <reply>`,
533
+ `${xmlEscape(r.reply ?? "")}`,
534
+ ` </reply>`,
535
+ " </review>"
536
+ ].join("\n");
537
+ }),
538
+ "</reviews>",
539
+ ""
540
+ ].join("\n");
541
+ writeFileSync2(join4(WORKITEMS_DIR, "reviews.xml"), reviewsXml, "utf8");
542
+ const defectsXml = defectsToXml(data.defects ?? []);
543
+ writeFileSync2(join4(WORKITEMS_DIR, "defect.xml"), defectsXml, "utf8");
544
+ const testCasesXml = unknownArrayToXml(
545
+ "testcases",
546
+ "case",
547
+ data.testCases ?? []
548
+ );
549
+ writeFileSync2(join4(WORKITEMS_DIR, "testcase.xml"), testCasesXml, "utf8");
550
+ return WORKITEMS_DIR;
551
+ }
552
+
332
553
  // src/commands/connect.ts
333
554
  function runConnect(opts) {
334
555
  void (async () => {
@@ -373,10 +594,7 @@ function runConnect(opts) {
373
594
  }
374
595
  const payload = msg.payload;
375
596
  try {
376
- execSync(`apm pull ${payload.requirementId}`, {
377
- cwd: payload.cwd,
378
- encoding: "utf8"
379
- });
597
+ await runPull(payload.requirementId, payload.cwd);
380
598
  } catch (pullErr) {
381
599
  console.error("[apm] apm pull \u5931\u8D25:", pullErr);
382
600
  throw pullErr;
@@ -454,6 +672,12 @@ function runConnect(opts) {
454
672
  });
455
673
  console.log("[Done]");
456
674
  session.writeToFile(payload.cwd, payload.requirementId, run.agentId);
675
+ try {
676
+ await runUploadArtifact(payload.requirementId, payload.cwd);
677
+ } catch (pullErr) {
678
+ console.error("[apm] apm upload-artifact \u5931\u8D25:", pullErr);
679
+ throw pullErr;
680
+ }
457
681
  } catch {
458
682
  console.error("[apm] \u65E0\u6CD5\u89E3\u6790 WebSocket \u6D88\u606F:", text);
459
683
  }
@@ -469,17 +693,17 @@ function runConnect(opts) {
469
693
  }
470
694
 
471
695
  // src/commands/init.ts
472
- import { join as join3 } from "path";
473
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
696
+ import { join as join5 } from "path";
697
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
474
698
  async function runInit(name) {
475
699
  await ensureWorkspaceApmDirForInit();
476
700
  await copyTemplateFiles(WORKSPACE_APM_DIR);
477
701
  if (name) {
478
- const apmConfigPath = join3(WORKSPACE_APM_DIR, "apm.config.json");
479
- const config = readFileSync3(apmConfigPath, "utf8");
702
+ const apmConfigPath = join5(WORKSPACE_APM_DIR, "apm.config.json");
703
+ const config = readFileSync4(apmConfigPath, "utf8");
480
704
  const configJson = JSON.parse(config);
481
705
  configJson.name = name;
482
- writeFileSync2(apmConfigPath, JSON.stringify(configJson, null, 2), "utf8");
706
+ writeFileSync3(apmConfigPath, JSON.stringify(configJson, null, 2), "utf8");
483
707
  }
484
708
  }
485
709
 
@@ -666,134 +890,13 @@ async function runBranch(requirementId, options = {}) {
666
890
  return branch;
667
891
  }
668
892
 
669
- // src/commands/pull.ts
670
- import { writeFileSync as writeFileSync3 } from "fs";
671
- import { join as join4 } from "path";
672
- import { stringify as yamlStringify } from "yaml";
673
- function valueToXmlContent(value) {
674
- if (value === null || value === void 0) return "";
675
- if (typeof value === "string") return xmlEscape(value);
676
- if (typeof value === "number" || typeof value === "boolean") {
677
- return xmlEscape(String(value));
678
- }
679
- return `<![CDATA[${JSON.stringify(value)}]]>`;
680
- }
681
- function recordToXmlLines(record, indent) {
682
- const lines = [];
683
- for (const [rawKey, val] of Object.entries(record)) {
684
- const key = /^[a-zA-Z_][\w.-]*$/.test(rawKey) ? rawKey : "field";
685
- lines.push(`${indent}<${key}>${valueToXmlContent(val)}</${key}>`);
686
- }
687
- return lines;
688
- }
689
- function unknownArrayToXml(rootName, itemName, items) {
690
- const lines = [`<${rootName}>`];
691
- items.forEach((item, index) => {
692
- if (item !== null && typeof item === "object" && !Array.isArray(item)) {
693
- lines.push(` <${itemName} index="${index}">`);
694
- lines.push(...recordToXmlLines(item, " "));
695
- lines.push(` </${itemName}>`);
696
- } else {
697
- lines.push(
698
- ` <${itemName} index="${index}">${valueToXmlContent(
699
- item
700
- )}</${itemName}>`
701
- );
702
- }
703
- });
704
- lines.push(`</${rootName}>`, "");
705
- return lines.join("\n");
706
- }
707
- function tasksForStatusYaml(tasks) {
708
- return tasks.map((t) => ({
709
- id: t.id,
710
- title: t.title,
711
- status: t.status,
712
- executor: t.executorType
713
- }));
714
- }
715
- function escapeForCdata(text) {
716
- return text.replace(/\]\]>/g, "]]]]><![CDATA[>");
717
- }
718
- function defectsToXml(defects) {
719
- const sorted = [...defects].sort(
720
- (a, b) => new Date(a.createdAt ?? 0).getTime() - new Date(b.createdAt ?? 0).getTime()
721
- );
722
- const lines = ["<defects>"];
723
- for (const d of sorted) {
724
- lines.push(` <defect id="${xmlEscape(d.id)}">`);
725
- lines.push(` <status>${xmlEscape(d.status)}</status>`);
726
- lines.push(` <current><![CDATA[${escapeForCdata(d.currentState ?? "")}]]></current>`);
727
- lines.push(
728
- ` <expected><![CDATA[${escapeForCdata(d.expectedEffect ?? "")}]]></expected>`
729
- );
730
- lines.push(` </defect>`);
731
- }
732
- lines.push("</defects>", "");
733
- return lines.join("\n");
734
- }
735
- async function runPull(requirementId) {
736
- const cfg = await ensureLoggedConfig();
737
- const api = createApmApiClient(cfg);
738
- const data = await api.cliRequirements.pull({ requirementId });
739
- const WORKITEMS_DIR = requirementWorkitemsDir(requirementId);
740
- await ensureDirExists(WORKITEMS_DIR);
741
- const req2 = data.requirement;
742
- const statusYaml = yamlStringify(
743
- {
744
- id: req2.id,
745
- status: req2.status,
746
- title: req2.title,
747
- env: req2.envName || "",
748
- tasks: tasksForStatusYaml(data.tasks ?? [])
749
- },
750
- { lineWidth: 0 }
751
- );
752
- writeFileSync3(
753
- join4(WORKITEMS_DIR, "requirement-status.yaml"),
754
- statusYaml.endsWith("\n") ? statusYaml : `${statusYaml}
755
- `,
756
- "utf8"
757
- );
758
- writeFileSync3(join4(WORKITEMS_DIR, "prd.md"), req2.content || "", "utf8");
759
- const reviews = data.reviews ?? [];
760
- const reviewsXml = [
761
- "<reviews>",
762
- ...reviews.map((r) => {
763
- return [
764
- ` <review id="${xmlEscape(r.id)}">`,
765
- ` <model>${xmlEscape(r.model ?? "")}</model>`,
766
- ` <content>`,
767
- `${xmlEscape(r.content ?? "")}`,
768
- ` </content>`,
769
- ` <reply>`,
770
- `${xmlEscape(r.reply ?? "")}`,
771
- ` </reply>`,
772
- " </review>"
773
- ].join("\n");
774
- }),
775
- "</reviews>",
776
- ""
777
- ].join("\n");
778
- writeFileSync3(join4(WORKITEMS_DIR, "reviews.xml"), reviewsXml, "utf8");
779
- const defectsXml = defectsToXml(data.defects ?? []);
780
- writeFileSync3(join4(WORKITEMS_DIR, "defect.xml"), defectsXml, "utf8");
781
- const testCasesXml = unknownArrayToXml(
782
- "testcases",
783
- "case",
784
- data.testCases ?? []
785
- );
786
- writeFileSync3(join4(WORKITEMS_DIR, "testcase.xml"), testCasesXml, "utf8");
787
- return WORKITEMS_DIR;
788
- }
789
-
790
893
  // src/commands/refine.ts
791
- import { readFileSync as readFileSync4 } from "fs";
792
- import { join as join5 } from "path";
894
+ import { readFileSync as readFileSync5 } from "fs";
895
+ import { join as join6 } from "path";
793
896
  async function runRefine(requirementId) {
794
897
  const cfg = await ensureLoggedConfig();
795
- const filePath = join5(WORKSPACE_APM_DIR, "workitems", requirementId, "prd.md");
796
- const content = readFileSync4(filePath, "utf8");
898
+ const filePath = join6(WORKSPACE_APM_DIR, "workitems", requirementId, "prd.md");
899
+ const content = readFileSync5(filePath, "utf8");
797
900
  const api = createApmApiClient(cfg);
798
901
  const data = await api.cliRequirements.refine({ requirementId, content });
799
902
  console.log(JSON.stringify(data, null, 2));
@@ -821,101 +924,6 @@ async function runUpdateStatus(requirementId, status) {
821
924
  console.log(JSON.stringify(data, null, 2));
822
925
  }
823
926
 
824
- // src/commands/upload-artifact.ts
825
- import { existsSync as existsSync2, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
826
- import { join as join6, relative, sep } from "path";
827
- var EXCLUDED_RELATIVE_PATHS = /* @__PURE__ */ new Set([
828
- "defect.xml",
829
- "prd.md",
830
- "requirement-status.yaml",
831
- "reviews.xml",
832
- "testcase.xml"
833
- ]);
834
- function toPosixRelative(root, absoluteFile) {
835
- return relative(root, absoluteFile).split(sep).join("/");
836
- }
837
- function artifactTagFromRelPath(relPosix) {
838
- const parts = relPosix.split("/");
839
- const fileName = parts[parts.length - 1] ?? relPosix;
840
- if (parts.length > 1) {
841
- return parts[0] ?? fileName;
842
- }
843
- const dot = fileName.lastIndexOf(".");
844
- return dot > 0 ? fileName.slice(0, dot) : fileName;
845
- }
846
- function* walkMarkdownFiles(dir) {
847
- const names = readdirSync2(dir);
848
- for (const name of names) {
849
- if (name.startsWith(".")) continue;
850
- const full = join6(dir, name);
851
- const st = statSync2(full);
852
- if (st.isDirectory()) {
853
- yield* walkMarkdownFiles(full);
854
- continue;
855
- }
856
- if (!st.isFile()) continue;
857
- if (!name.toLowerCase().endsWith(".md")) continue;
858
- yield full;
859
- }
860
- }
861
- async function deleteAllArtifactsForRequirement(api, requirementId) {
862
- const pageSize = 100;
863
- let page = 1;
864
- const rows = [];
865
- while (true) {
866
- const batch = await api.requirementArtifact.list({
867
- requirementId,
868
- page,
869
- pageSize
870
- });
871
- rows.push(...batch.items);
872
- if (batch.total === 0 || rows.length >= batch.total) break;
873
- page += 1;
874
- }
875
- for (const row of rows) {
876
- await api.requirementArtifact.delete({ artifactId: row.id });
877
- }
878
- return rows.length;
879
- }
880
- async function runUploadArtifact(requirementId) {
881
- const cfg = await ensureLoggedConfig();
882
- const api = createApmApiClient(cfg);
883
- const root = requirementWorkitemsDir(requirementId);
884
- if (!existsSync2(root)) {
885
- console.error(
886
- `[apm] \u76EE\u5F55\u4E0D\u5B58\u5728: ${root}
887
- \u8BF7\u5148\u6267\u884C: apm pull ${requirementId}`
888
- );
889
- process.exit(1);
890
- }
891
- const deleted = await deleteAllArtifactsForRequirement(api, requirementId);
892
- console.log(`[apm] \u5DF2\u6E05\u7A7A\u9700\u6C42\u4EA7\u7269\u6587\u6863 ${deleted} \u6761`);
893
- const paths = [...walkMarkdownFiles(root)];
894
- let created = 0;
895
- let skipped = 0;
896
- for (const abs of paths) {
897
- const relPosix = toPosixRelative(root, abs);
898
- if (EXCLUDED_RELATIVE_PATHS.has(relPosix)) {
899
- skipped += 1;
900
- console.log(`[apm] \u8DF3\u8FC7\uFF08\u6392\u9664\u5217\u8868\uFF09: ${relPosix}`);
901
- continue;
902
- }
903
- const content = readFileSync5(abs, "utf8");
904
- const tag = artifactTagFromRelPath(relPosix);
905
- await api.requirementArtifact.create({
906
- requirementId,
907
- tag,
908
- fileName: relPosix,
909
- content
910
- });
911
- created += 1;
912
- console.log(`[apm] \u5DF2\u4E0A\u4F20\u4EA7\u7269: ${relPosix} (tag=${tag})`);
913
- }
914
- console.log(
915
- `[apm] \u5B8C\u6210\uFF1A\u5220\u9664 ${deleted}\uFF0C\u65B0\u5EFA ${created}\uFF0C\u8DF3\u8FC7\uFF08\u6392\u9664\uFF09 ${skipped}\uFF0C\u5171\u626B\u63CF ${paths.length} \u4E2A Markdown \u6587\u4EF6`
916
- );
917
- }
918
-
919
927
  // src/commands/deploy/backend.ts
920
928
  import path5 from "node:path";
921
929
 
@@ -1332,7 +1340,7 @@ function assertDeployImageTag(tag) {
1332
1340
  import { platform } from "node:os";
1333
1341
 
1334
1342
  // src/commands/deploy/lib/backend-deploy/command-runner.ts
1335
- import { execSync as execSync2 } from "child_process";
1343
+ import { execSync } from "child_process";
1336
1344
 
1337
1345
  // src/commands/deploy/lib/backend-deploy/logger.ts
1338
1346
  var Logger = class {
@@ -1358,7 +1366,7 @@ var CommandRunner = class {
1358
1366
  static exec(command, cwd) {
1359
1367
  try {
1360
1368
  Logger.info(`\u6267\u884C\u547D\u4EE4: ${command}`);
1361
- const result = execSync2(command, {
1369
+ const result = execSync(command, {
1362
1370
  cwd,
1363
1371
  encoding: "utf8",
1364
1372
  stdio: "pipe"
@@ -1376,7 +1384,7 @@ var CommandRunner = class {
1376
1384
  static execWithOutput(command, cwd) {
1377
1385
  try {
1378
1386
  Logger.info(`\u6267\u884C\u547D\u4EE4: ${command}`);
1379
- execSync2(command, {
1387
+ execSync(command, {
1380
1388
  cwd,
1381
1389
  stdio: "inherit"
1382
1390
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-project-manage-cli",
3
- "version": "3.0.16",
3
+ "version": "3.0.18",
4
4
  "description": "命令行工具:后续用于调用平台后端 API 完成运维与自动化操作",
5
5
  "type": "module",
6
6
  "private": false,
@@ -59,8 +59,7 @@ instruction 子文件随该目录类推(如 `.apm/skills/apm-propose/propose-i
59
59
  ## 步骤 2:读取缺陷清单(defect.xml)
60
60
 
61
61
  1. 父 Agent 使用 **Read** 工具读取:`.apm/workitems/<requirementId>/defect.xml`(缺陷列表,格式以平台同步为准)。
62
- 2. 若首次 **Read** 失败(无此文件等):在仓库根目录执行 **`apm pull <requirementId>`**,再 **Read** 一次。
63
- 3. **分流(非失败)**:
62
+ 2. **分流(非失败)**:
64
63
  - **无文件、仍读不到、或文件无有效内容**(空文件、仅空白、无实质缺陷条目等;具体结构以同步格式为准):**不视为步骤失败**。表格步骤 2 填 **跳过(无 defect 内容 → 新功能)**,**直接进入步骤 3**。
65
64
  - **文件存在且有有效内容**:视为本轮为 **修复 Bug 流程**(与步骤 4 同属 Quick 形态,对照 **defect.xml + 必要时 prd.md**,目标是消除所列缺陷):
66
65
  - 父 Agent 已通过 **Read** 掌握 `defect.xml`;若启动子 Agent,在委派提示中写明 **`requirementId`**、工作项路径、`defect.xml` 路径,以及「逐项对照缺陷列表修复,改动范围最小化」。
@@ -78,7 +77,7 @@ instruction 子文件随该目录类推(如 `.apm/skills/apm-propose/propose-i
78
77
  **条件**:仅当步骤 2 **未**以「`defect.xml` **有内容**且 Quick 修 Bug **成功** → 短路至步骤 6」结束时执行(含:`defect.xml` 缺失、拉取后仍无、或**无有效内容**而走新功能流程)。
79
78
 
80
79
  1. **Read** 全文:`.apm/workitems/<requirementId>/prd.md`。
81
- 2. 若无法读取:在仓库根目录执行 **`apm pull <requirementId>`**(同步工作项),再 **Read** 一次;仍失败则**停止后续实现**,仅在表格中标记失败原因。
80
+ 2. 若失败则**停止后续实现**,仅在表格中标记失败原因。
82
81
  3. **不**为评估向用户发起追问;信息不足时倾向 **Spec**(保守)。
83
82
 
84
83
  ### Quick(较小)与 Spec(较大)判定参考
@@ -137,23 +136,7 @@ instruction 子文件随该目录类推(如 `.apm/skills/apm-propose/propose-i
137
136
 
138
137
  将命令结果、最终分支名、是否已 push、工作区是否干净写入表格。
139
138
 
140
- ---
141
-
142
- ## 步骤 7:同步产物
143
-
144
- 在**仓库/工作区根目录**(与步骤 1、6 一致)执行:
145
-
146
- ```bash
147
- apm upload-artifact <requirementId>
148
- ```
149
-
150
- 1. 该命令会**先清空**平台上该需求的产物文档,再将 `.apm/workitems/<requirementId>/` 下符合条件的 Markdown 重新上传(排除 `prd.md`、状态 YAML、reviews/defect/testcase 等 pull 系统文件;详见 CLI 行为)。
151
- 2. 若本地未放置需同步的 `.md` 产物,仍会清空平台侧产物;若有文档仅在仓库其它路径,须先复制或生成到工作项目录再执行。
152
- 3. 将命令是否成功、上传条数或错误摘要写入表格。
153
-
154
- ---
155
-
156
- ## 步骤 8:对用户回复(表格)
139
+ ## 步骤 7:对用户回复(表格)
157
140
 
158
141
  对用户回复 **必须包含一张 Markdown 表格**,汇总 **步骤 1~7**(步骤 8 为呈现表格本身,可不单独成行)。表头建议:
159
142
 
@@ -165,7 +148,6 @@ apm upload-artifact <requirementId>
165
148
  | 4 | Quick 开发(子 Agent) | 成功 / 失败 / **跳过** |
166
149
  | 5 | Spec:apm-propose → apm-apply-change(子 Agent) | 成功 / 失败 / **跳过**;可注明子步骤 |
167
150
  | 6 | commit & push;工作区干净 | 成功 / 失败(原因) |
168
- | 7 | `apm upload-artifact <requirementId>` | 成功 / 失败(原因) |
169
151
 
170
152
  **可选**:在表格外增加**简短**一句话摘要(例如当前分支名、阻塞点);若用户此前约定「仅表格」,则可仅输出表格。
171
153
 
@@ -173,7 +155,7 @@ apm upload-artifact <requirementId>
173
155
 
174
156
  ## Guardrails
175
157
 
176
- - **失败即终止**:在用户提供的 **`requirementId`** 等参数合法、命令与路径按本技能书写的前提下,任一步骤(含 `apm branch`、`apm pull`、`apm upload-artifact`、读文件、子 Agent、`git`)**一旦失败**:**停止后续所有步骤**,仅在表格中记录失败步骤与原因;**不要**为登录、依赖、网络、命令结果等做**多次**或「轮番」重试。
158
+ - **失败即终止**:在用户提供的 **`requirementId`** 等参数合法、命令与路径按本技能书写的前提下,任一步骤(含 `apm branch`、读文件、子 Agent、`git`)**一旦失败**:**停止后续所有步骤**,仅在表格中记录失败步骤与原因;**不要**为登录、依赖、网络、命令结果等做**多次**或「轮番」重试。
177
159
  - **例外(Agent 自身失误)**:若失败明显由执行 Agent **用错工作目录、读错/漏写路径** 等导致,**允许**纠正 `cwd` 或路径后**仅对该失败步骤再执行一次**;纠正后仍失败则**立即终止**,不再扩展尝试。
178
- - **不要**在无 `prd.md`(且 `apm pull` 后仍无)的情况下编造需求实现。
160
+ - **不要**在无 `prd.md`的情况下编造需求实现。
179
161
  - **子 Agent** 提示中须带 **`requirementId`** 与仓库根路径意识,避免改错工作树。