agent-handoff 0.1.0 → 0.2.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.0] - 2026-03-02
6
+
7
+ ### Added
8
+ - `agent-handoff validate` 命令 - 校验产物结构完整性
9
+ - `agent-handoff advance` 命令 - 推进 workspace 状态
10
+ - `agent-handoff config` 命令 - 查看和管理配置
11
+ - `--copy` 选项 - 自动复制 prompt 到剪贴板(跨平台支持)
12
+ - `--skip-event` 选项 - 跳过事件日志写入
13
+ - 产物校验模块 - 检查 output.md 必要区块
14
+ - 剪贴板模块 - 跨平台剪贴板操作
15
+ - 事件写入模块 - events.jsonl 追加式日志
16
+ - 配置文件支持 - `.agenthandoffrc` / `.agenthandoffrc.yaml` / `package.json#agenthandoff`
17
+
18
+ ### Changed
19
+ - `next` 命令支持 `--no-event` 选项跳过事件写入
20
+ - 改进 prompt 输出格式
21
+
22
+ ### Dependencies
23
+ - 新增 `clipboardy` 依赖(跨平台剪贴板)
24
+
25
+ ## [0.1.1] - 2026-03-02
26
+
27
+ ### Changed
28
+ - 更新 repository URL 为正确的 GitHub 地址
29
+ - 更新 author 信息
30
+ - 统一文档中的文件路径为相对路径
31
+
5
32
  ## [0.1.0] - 2026-03-01
6
33
 
7
34
  ### Added
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command4 } from "commander";
4
+ import { createRequire } from "module";
5
+ import { Command as Command7 } from "commander";
5
6
 
6
7
  // src/cli/commands/init.ts
7
8
  import { Command } from "commander";
@@ -295,7 +296,7 @@ var statusCommand = new Command2("status").description("\u663E\u793A workspace \
295
296
 
296
297
  // src/cli/commands/next.ts
297
298
  import { Command as Command3 } from "commander";
298
- import path4 from "path";
299
+ import path5 from "path";
299
300
 
300
301
  // src/core/prompt-generator.ts
301
302
  function generatePrompt(context) {
@@ -344,9 +345,68 @@ AgentHandoff Step Prompt`;
344
345
  return prompt;
345
346
  }
346
347
 
348
+ // src/core/clipboard.ts
349
+ import clipboard from "clipboardy";
350
+ var clipboardSupported = null;
351
+ function isClipboardSupported() {
352
+ if (clipboardSupported !== null) {
353
+ return clipboardSupported;
354
+ }
355
+ try {
356
+ clipboardSupported = true;
357
+ return true;
358
+ } catch {
359
+ clipboardSupported = false;
360
+ return false;
361
+ }
362
+ }
363
+ async function copyToClipboard(text) {
364
+ try {
365
+ await clipboard.write(text);
366
+ return { success: true };
367
+ } catch (error) {
368
+ const errorMessage = error instanceof Error ? error.message : String(error);
369
+ return {
370
+ success: false,
371
+ error: errorMessage
372
+ };
373
+ }
374
+ }
375
+
376
+ // src/core/events-writer.ts
377
+ import fs4 from "fs/promises";
378
+ import path4 from "path";
379
+ async function writeEvent(options) {
380
+ const { workspacePath, step, type, summary, workItemId, links } = options;
381
+ const event = {
382
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
383
+ step,
384
+ type,
385
+ summary,
386
+ ...workItemId && { workItemId },
387
+ ...links && links.length > 0 && { links }
388
+ };
389
+ try {
390
+ const eventsPath = path4.join(workspacePath, "events.jsonl");
391
+ const line = JSON.stringify(event) + "\n";
392
+ await fs4.appendFile(eventsPath, line, "utf-8");
393
+ return {
394
+ success: true,
395
+ event
396
+ };
397
+ } catch (error) {
398
+ const errorMessage = error instanceof Error ? error.message : String(error);
399
+ return {
400
+ success: false,
401
+ event,
402
+ error: errorMessage
403
+ };
404
+ }
405
+ }
406
+
347
407
  // src/cli/commands/next.ts
348
- var nextCommand = new Command3("next").description("\u8F93\u51FA\u4E0B\u4E00\u6B65\u6267\u884C\u6307\u4EE4\u548C prompt").argument("[workspace]", "workspace \u8DEF\u5F84", ".").option("-c, --copy", "\u590D\u5236 prompt \u5230\u526A\u8D34\u677F\uFF08v0.2\uFF09").action(async (workspace, options) => {
349
- const workspacePath = path4.resolve(workspace);
408
+ var nextCommand = new Command3("next").description("\u8F93\u51FA\u4E0B\u4E00\u6B65\u6267\u884C\u6307\u4EE4\u548C prompt").argument("[workspace]", "workspace \u8DEF\u5F84", ".").option("-c, --copy", "\u590D\u5236 prompt \u5230\u526A\u8D34\u677F").option("--no-event", "\u4E0D\u5199\u5165\u4E8B\u4EF6\u65E5\u5FD7").action(async (workspace, options) => {
409
+ const workspacePath = path5.resolve(workspace);
350
410
  try {
351
411
  const info = await loadWorkspace(workspacePath);
352
412
  if (!info.exists) {
@@ -397,22 +457,603 @@ var nextCommand = new Command3("next").description("\u8F93\u51FA\u4E0B\u4E00\u6B
397
457
  console.log(prompt);
398
458
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
399
459
  console.log("");
400
- console.log("\u63D0\u793A\uFF1A\u5C06\u4E0A\u8FF0 Prompt \u590D\u5236\u5230 TRAE \u65B0 Task \u4E2D\u6267\u884C");
460
+ if (options.event) {
461
+ await writeEvent({
462
+ workspacePath,
463
+ step: { index: index + 1, id: step.id },
464
+ type: "step.started",
465
+ summary: `\u5F00\u59CB\u6267\u884C\u6B65\u9AA4: ${step.id}`,
466
+ workItemId: step.workItemId,
467
+ links: [step.input]
468
+ });
469
+ }
401
470
  if (options.copy) {
471
+ if (!isClipboardSupported()) {
472
+ console.log("\u26A0\uFE0F \u526A\u8D34\u677F\u529F\u80FD\u5728\u5F53\u524D\u73AF\u5883\u4E0D\u53EF\u7528");
473
+ console.log("\u8BF7\u624B\u52A8\u590D\u5236\u4E0A\u9762\u7684 Prompt");
474
+ } else {
475
+ const result = await copyToClipboard(prompt);
476
+ if (result.success) {
477
+ console.log("\u2705 Prompt \u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
478
+ } else {
479
+ console.log(`\u274C \u590D\u5236\u5931\u8D25: ${result.error}`);
480
+ console.log("\u8BF7\u624B\u52A8\u590D\u5236\u4E0A\u9762\u7684 Prompt");
481
+ }
482
+ }
483
+ } else {
484
+ console.log("\u63D0\u793A\uFF1A\u5C06\u4E0A\u8FF0 Prompt \u590D\u5236\u5230 TRAE \u65B0 Task \u4E2D\u6267\u884C");
485
+ console.log(" \u4F7F\u7528 --copy \u9009\u9879\u53EF\u81EA\u52A8\u590D\u5236\u5230\u526A\u8D34\u677F");
486
+ }
487
+ } catch (error) {
488
+ console.error(`Error: ${error}`);
489
+ process.exit(1);
490
+ }
491
+ });
492
+
493
+ // src/cli/commands/validate.ts
494
+ import { Command as Command4 } from "commander";
495
+ import path7 from "path";
496
+
497
+ // src/core/artifact-validator.ts
498
+ import fs5 from "fs/promises";
499
+ import path6 from "path";
500
+ var REQUIRED_SECTIONS = [
501
+ "\u4EA7\u7269\u66F4\u65B0",
502
+ "\u5173\u952E\u51B3\u7B56",
503
+ "\u98CE\u9669\u4E0E\u5F85\u786E\u8BA4",
504
+ "\u4E0B\u4E00\u6B65\u4EA4\u63A5"
505
+ ];
506
+ var MIN_CONTENT_LENGTH = 10;
507
+ function validateArtifact(content) {
508
+ const errors = [];
509
+ const warnings = [];
510
+ for (const section of REQUIRED_SECTIONS) {
511
+ const sectionResult = findSection(content, section);
512
+ if (!sectionResult.found) {
513
+ errors.push({
514
+ type: "missing_section",
515
+ section,
516
+ message: `\u7F3A\u5C11\u5FC5\u8981\u533A\u5757: ${section}`
517
+ });
518
+ } else if (!sectionResult.hasContent) {
519
+ errors.push({
520
+ type: "empty_section",
521
+ section,
522
+ message: `\u533A\u5757\u5185\u5BB9\u4E3A\u7A7A: ${section}`
523
+ });
524
+ } else if (sectionResult.contentLength < MIN_CONTENT_LENGTH) {
525
+ warnings.push({
526
+ type: "short_content",
527
+ section,
528
+ message: `\u533A\u5757\u5185\u5BB9\u8FC7\u77ED (${sectionResult.contentLength} \u5B57\u7B26): ${section}`
529
+ });
530
+ }
531
+ }
532
+ return {
533
+ valid: errors.length === 0,
534
+ errors,
535
+ warnings
536
+ };
537
+ }
538
+ function findSection(content, sectionName) {
539
+ const patterns = [
540
+ new RegExp(`^##\\s+${escapeRegex(sectionName)}[^\\n]*$`, "m"),
541
+ new RegExp(`^###\\s+${escapeRegex(sectionName)}[^\\n]*$`, "m")
542
+ ];
543
+ let matchIndex = -1;
544
+ let matchLength = 0;
545
+ for (const pattern of patterns) {
546
+ const match = content.match(pattern);
547
+ if (match && match.index !== void 0) {
548
+ matchIndex = match.index;
549
+ matchLength = match[0].length;
550
+ break;
551
+ }
552
+ }
553
+ if (matchIndex === -1) {
554
+ return { found: false, hasContent: false, contentLength: 0 };
555
+ }
556
+ const contentStart = matchIndex + matchLength;
557
+ const remainingContent = content.slice(contentStart);
558
+ const nextSectionMatch = remainingContent.match(/^#{1,3}\s+/m);
559
+ const sectionContent = nextSectionMatch ? remainingContent.slice(0, nextSectionMatch.index) : remainingContent;
560
+ const trimmedContent = sectionContent.trim();
561
+ return {
562
+ found: true,
563
+ hasContent: trimmedContent.length > 0,
564
+ contentLength: trimmedContent.length
565
+ };
566
+ }
567
+ function escapeRegex(str) {
568
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
569
+ }
570
+ async function validateArtifactFile(filePath) {
571
+ try {
572
+ const content = await fs5.readFile(filePath, "utf-8");
573
+ return validateArtifact(content);
574
+ } catch (error) {
575
+ return {
576
+ valid: false,
577
+ errors: [
578
+ {
579
+ type: "invalid_format",
580
+ section: "",
581
+ message: `\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6: ${filePath}`
582
+ }
583
+ ],
584
+ warnings: []
585
+ };
586
+ }
587
+ }
588
+ async function validateWorkspaceArtifacts(workspacePath) {
589
+ const workspace = await loadWorkspace(workspacePath);
590
+ const stepResults = /* @__PURE__ */ new Map();
591
+ let validSteps = 0;
592
+ let errorCount = 0;
593
+ let warningCount = 0;
594
+ if (!workspace.workflow) {
595
+ return {
596
+ valid: false,
597
+ stepResults,
598
+ totalSteps: 0,
599
+ validSteps: 0,
600
+ errorCount: 1,
601
+ warningCount: 0
602
+ };
603
+ }
604
+ for (const step of workspace.workflow.steps) {
605
+ const outputPath = path6.join(workspace.path, step.output);
606
+ const result = await validateArtifactFile(outputPath);
607
+ stepResults.set(step.id, result);
608
+ if (result.valid) {
609
+ validSteps++;
610
+ }
611
+ errorCount += result.errors.length;
612
+ warningCount += result.warnings.length;
613
+ }
614
+ return {
615
+ valid: errorCount === 0,
616
+ stepResults,
617
+ totalSteps: workspace.workflow.steps.length,
618
+ validSteps,
619
+ errorCount,
620
+ warningCount
621
+ };
622
+ }
623
+
624
+ // src/cli/commands/validate.ts
625
+ var validateCommand = new Command4("validate").description("\u6821\u9A8C workspace \u4EA7\u7269\u7ED3\u6784").argument("[workspace]", "workspace \u8DEF\u5F84", ".").option("--strict", "\u4E25\u683C\u6A21\u5F0F\uFF08\u5C06\u8B66\u544A\u89C6\u4E3A\u9519\u8BEF\uFF09").option("-j, --json", "JSON \u683C\u5F0F\u8F93\u51FA").action(async (workspace, options) => {
626
+ const workspacePath = path7.resolve(workspace);
627
+ try {
628
+ const info = await loadWorkspace(workspacePath);
629
+ if (!info.exists) {
630
+ console.error(`Error: workspace not found: ${workspacePath}`);
631
+ process.exit(1);
632
+ }
633
+ if (!info.hasWorkflow) {
634
+ console.error(`Error: workflow.yaml not found in ${workspacePath}`);
635
+ process.exit(1);
636
+ }
637
+ if (!info.workflow) {
638
+ console.error(`Error: failed to parse workflow.yaml`);
639
+ process.exit(1);
640
+ }
641
+ const result = await validateWorkspaceArtifacts(workspacePath);
642
+ if (options.json) {
643
+ const jsonOutput = {
644
+ valid: options.strict ? result.valid && result.warningCount === 0 : result.valid,
645
+ workspace: workspacePath,
646
+ totalSteps: result.totalSteps,
647
+ validSteps: result.validSteps,
648
+ errorCount: result.errorCount,
649
+ warningCount: result.warningCount,
650
+ steps: Array.from(result.stepResults.entries()).map(([stepId, stepResult]) => ({
651
+ stepId,
652
+ valid: options.strict ? stepResult.valid && stepResult.warnings.length === 0 : stepResult.valid,
653
+ errors: stepResult.errors,
654
+ warnings: stepResult.warnings
655
+ }))
656
+ };
657
+ console.log(JSON.stringify(jsonOutput, null, 2));
658
+ } else {
659
+ console.log(`Workspace: ${info.workflow.name}`);
660
+ console.log("");
661
+ for (const step of info.workflow.steps) {
662
+ const stepResult = result.stepResults.get(step.id);
663
+ if (!stepResult) continue;
664
+ const icon = stepResult.valid ? "\u2705" : "\u274C";
665
+ console.log(`${icon} ${step.output} - ${stepResult.valid ? "Valid" : "Invalid"}`);
666
+ if (!stepResult.valid) {
667
+ for (const error of stepResult.errors) {
668
+ console.log(` - ${error.message}`);
669
+ }
670
+ }
671
+ if (stepResult.warnings.length > 0) {
672
+ for (const warning of stepResult.warnings) {
673
+ console.log(` \u26A0\uFE0F ${warning.message}`);
674
+ }
675
+ }
676
+ }
677
+ console.log("");
678
+ const hasErrors = result.errorCount > 0;
679
+ const hasWarnings = result.warningCount > 0;
680
+ const strictFail = options.strict && hasWarnings;
681
+ if (!hasErrors && !strictFail) {
682
+ console.log("All artifacts validated successfully.");
683
+ if (hasWarnings) {
684
+ console.log(`\u26A0\uFE0F ${result.warningCount} warning(s) found.`);
685
+ }
686
+ } else {
687
+ const totalErrors = result.errorCount + (strictFail ? result.warningCount : 0);
688
+ console.log(`Validation failed with ${totalErrors} error(s).`);
689
+ }
690
+ if (hasErrors || strictFail) {
691
+ process.exit(1);
692
+ }
693
+ }
694
+ } catch (error) {
695
+ console.error(`Error: ${error}`);
696
+ process.exit(1);
697
+ }
698
+ });
699
+
700
+ // src/cli/commands/advance.ts
701
+ import { Command as Command5 } from "commander";
702
+ import path8 from "path";
703
+ import fs6 from "fs/promises";
704
+ var advanceCommand = new Command5("advance").description("\u63A8\u8FDB workspace \u72B6\u6001").argument("[workspace]", "workspace \u8DEF\u5F84", ".").option("-e, --event <type>", "\u4E8B\u4EF6\u7C7B\u578B", "step.done").option("-s, --summary <text>", "\u4E8B\u4EF6\u6458\u8981").option("--no-state", "\u4E0D\u66F4\u65B0 state.json").option("--skip-event", "\u4E0D\u5199\u5165\u4E8B\u4EF6\u65E5\u5FD7").action(
705
+ async (workspace, options) => {
706
+ const workspacePath = path8.resolve(workspace);
707
+ try {
708
+ const info = await loadWorkspace(workspacePath);
709
+ if (!info.exists) {
710
+ console.error(`Error: workspace not found: ${workspacePath}`);
711
+ process.exit(1);
712
+ }
713
+ if (!info.hasWorkflow) {
714
+ console.error(`Error: workflow.yaml not found in ${workspacePath}`);
715
+ process.exit(1);
716
+ }
717
+ if (!info.workflow) {
718
+ console.error(`Error: failed to parse workflow.yaml`);
719
+ process.exit(1);
720
+ }
721
+ const stateResult = computeState(info.workflow, info.stepOutputs);
722
+ console.log(`Workspace: ${info.workflow.name}`);
723
+ if (stateResult.status === "done") {
724
+ console.log("Status: done");
725
+ console.log("");
726
+ console.log("\u26A0\uFE0F Workflow already completed. No steps to advance.");
727
+ return;
728
+ }
729
+ const currentStep = getCurrentStep(info.workflow, info.stepOutputs);
730
+ if (!currentStep) {
731
+ console.log("Status: done");
732
+ console.log("");
733
+ console.log("\u26A0\uFE0F Workflow already completed. No steps to advance.");
734
+ return;
735
+ }
736
+ const { step, index } = currentStep;
737
+ console.log(`Current step: ${step.id} (index: ${index})`);
402
738
  console.log("");
403
- console.log("\u6CE8\u610F\uFF1A\u526A\u8D34\u677F\u529F\u80FD\u5C06\u5728 v0.2 \u7248\u672C\u5B9E\u73B0");
739
+ const eventType = options.event;
740
+ const eventSummary = options.summary || getDefaultSummary(eventType, step.id);
741
+ if (!options.skipEvent) {
742
+ const result = await writeEvent({
743
+ workspacePath,
744
+ step: { index: index + 1, id: step.id },
745
+ type: eventType,
746
+ summary: eventSummary,
747
+ workItemId: step.workItemId,
748
+ links: [step.output]
749
+ });
750
+ if (result.success) {
751
+ console.log(`\u2705 Event written: ${eventType}`);
752
+ console.log(` Summary: ${eventSummary}`);
753
+ if (step.workItemId) {
754
+ console.log(` Work Item: ${step.workItemId}`);
755
+ }
756
+ if (step.output) {
757
+ console.log(` Links: ${step.output}`);
758
+ }
759
+ } else {
760
+ console.log(`\u274C Failed to write event: ${result.error}`);
761
+ }
762
+ }
763
+ if (options.state) {
764
+ const statePath = path8.join(workspacePath, "state.json");
765
+ const newIndex = index + 1;
766
+ const isDone = newIndex >= info.workflow.steps.length;
767
+ const newState = {
768
+ currentIndex: newIndex,
769
+ status: isDone ? "done" : "running",
770
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
771
+ };
772
+ await fs6.writeFile(statePath, JSON.stringify(newState, null, 2));
773
+ console.log("");
774
+ console.log(`\u2705 State updated: ${statePath}`);
775
+ console.log(` Current index: ${newState.currentIndex}`);
776
+ console.log(` Status: ${newState.status}`);
777
+ if (isDone) {
778
+ console.log("");
779
+ console.log("\u{1F389} Workflow completed!");
780
+ } else {
781
+ const nextStep = info.workflow.steps[newIndex];
782
+ console.log(` Next step: ${nextStep.id}`);
783
+ }
784
+ }
785
+ } catch (error) {
786
+ console.error(`Error: ${error}`);
787
+ process.exit(1);
788
+ }
789
+ }
790
+ );
791
+ function getDefaultSummary(eventType, stepId) {
792
+ const summaries = {
793
+ "step.started": `\u5F00\u59CB\u6267\u884C\u6B65\u9AA4: ${stepId}`,
794
+ "step.done": `\u6B65\u9AA4\u5B8C\u6210: ${stepId}`,
795
+ "artifact.updated": "\u4EA7\u7269\u5DF2\u66F4\u65B0",
796
+ "workflow.updated": "\u5DE5\u4F5C\u6D41\u5DF2\u66F4\u65B0",
797
+ "verify.passed": "\u9A8C\u8BC1\u901A\u8FC7",
798
+ "verify.failed": "\u9A8C\u8BC1\u5931\u8D25",
799
+ "accept.passed": "\u9A8C\u6536\u901A\u8FC7",
800
+ "accept.failed": "\u9A8C\u6536\u5931\u8D25",
801
+ "issue.raised": "\u53D1\u73B0\u95EE\u9898",
802
+ "handoff.sent": "\u5DF2\u4EA4\u63A5\u7ED9\u4E0B\u4E00\u6B65"
803
+ };
804
+ return summaries[eventType] || `\u4E8B\u4EF6: ${eventType}`;
805
+ }
806
+
807
+ // src/cli/commands/config.ts
808
+ import { Command as Command6 } from "commander";
809
+ import os2 from "os";
810
+
811
+ // src/core/config.ts
812
+ import fs7 from "fs/promises";
813
+ import path9 from "path";
814
+ import os from "os";
815
+ var DEFAULT_CONFIG = {
816
+ events: {
817
+ enabled: true,
818
+ logStepStarted: true,
819
+ logStepDone: true
820
+ },
821
+ clipboard: {
822
+ autoCopy: false
823
+ },
824
+ prompt: {
825
+ language: "zh"
826
+ },
827
+ validation: {
828
+ strict: false,
829
+ warnOnShortContent: true
830
+ }
831
+ };
832
+ var CONFIG_FILES = [
833
+ ".agenthandoffrc",
834
+ ".agenthandoffrc.json",
835
+ ".agenthandoffrc.yaml",
836
+ ".agenthandoffrc.yml"
837
+ ];
838
+ var configCache = /* @__PURE__ */ new Map();
839
+ async function findConfigFile(startPath) {
840
+ let currentPath = path9.resolve(startPath);
841
+ const homePath = os.homedir();
842
+ while (true) {
843
+ for (const configFile of CONFIG_FILES) {
844
+ const filePath = path9.join(currentPath, configFile);
845
+ try {
846
+ await fs7.access(filePath);
847
+ return filePath;
848
+ } catch {
849
+ }
850
+ }
851
+ const packageJsonPath = path9.join(currentPath, "package.json");
852
+ try {
853
+ const content = await fs7.readFile(packageJsonPath, "utf-8");
854
+ const pkg = JSON.parse(content);
855
+ if (pkg.agenthandoff) {
856
+ return packageJsonPath;
857
+ }
858
+ } catch {
859
+ }
860
+ if (currentPath === homePath || currentPath === path9.dirname(currentPath)) {
861
+ break;
862
+ }
863
+ currentPath = path9.dirname(currentPath);
864
+ }
865
+ return null;
866
+ }
867
+ async function loadConfigFile(filePath) {
868
+ try {
869
+ const content = await fs7.readFile(filePath, "utf-8");
870
+ const ext = path9.extname(filePath);
871
+ if (ext === ".yaml" || ext === ".yml") {
872
+ return parseYaml(content);
873
+ }
874
+ if (filePath.endsWith("package.json")) {
875
+ const pkg = JSON.parse(content);
876
+ return pkg.agenthandoff || {};
877
+ }
878
+ return JSON.parse(content);
879
+ } catch {
880
+ return {};
881
+ }
882
+ }
883
+ function parseYaml(content) {
884
+ const result = {};
885
+ const lines = content.split("\n");
886
+ let currentObj = result;
887
+ const stack = [];
888
+ for (const line of lines) {
889
+ if (!line.trim() || line.trim().startsWith("#")) {
890
+ continue;
891
+ }
892
+ const indent = line.search(/\S/);
893
+ const trimmed = line.trim();
894
+ if (trimmed.includes(":")) {
895
+ const colonIndex = trimmed.indexOf(":");
896
+ const key = trimmed.slice(0, colonIndex).trim();
897
+ const value = trimmed.slice(colonIndex + 1).trim();
898
+ if (value === "") {
899
+ if (stack.length > 0) {
900
+ const expectedIndent = stack.length * 2;
901
+ if (indent < expectedIndent) {
902
+ while (stack.length > 0 && indent < stack.length * 2) {
903
+ stack.pop();
904
+ }
905
+ if (stack.length > 0) {
906
+ currentObj = stack[stack.length - 1].obj;
907
+ } else {
908
+ currentObj = result;
909
+ }
910
+ }
911
+ }
912
+ const newObj = {};
913
+ currentObj[key] = newObj;
914
+ stack.push({ obj: currentObj });
915
+ currentObj = newObj;
916
+ } else {
917
+ let parsedValue = value;
918
+ if (value === "true") parsedValue = true;
919
+ else if (value === "false") parsedValue = false;
920
+ else if (value === "null") parsedValue = null;
921
+ else if (/^\d+$/.test(value)) parsedValue = parseInt(value, 10);
922
+ else if (/^\d+\.\d+$/.test(value)) parsedValue = parseFloat(value);
923
+ else if (value.startsWith('"') && value.endsWith('"')) {
924
+ parsedValue = value.slice(1, -1);
925
+ } else if (value.startsWith("'") && value.endsWith("'")) {
926
+ parsedValue = value.slice(1, -1);
927
+ }
928
+ currentObj[key] = parsedValue;
929
+ }
930
+ }
931
+ }
932
+ return result;
933
+ }
934
+ function mergeConfig(base, override) {
935
+ const result = JSON.parse(JSON.stringify(base));
936
+ for (const key of Object.keys(override)) {
937
+ const overrideValue = override[key];
938
+ if (overrideValue === void 0) continue;
939
+ if (typeof overrideValue === "object" && overrideValue !== null && !Array.isArray(overrideValue)) {
940
+ const baseValue = result[key];
941
+ if (typeof baseValue === "object" && baseValue !== null && !Array.isArray(baseValue)) {
942
+ result[key] = mergeConfig(
943
+ baseValue,
944
+ overrideValue
945
+ );
946
+ } else {
947
+ result[key] = overrideValue;
948
+ }
949
+ } else {
950
+ result[key] = overrideValue;
951
+ }
952
+ }
953
+ return result;
954
+ }
955
+ async function loadConfig(workspacePath) {
956
+ const startPath = workspacePath ? path9.resolve(workspacePath) : process.cwd();
957
+ const cacheKey = startPath;
958
+ if (configCache.has(cacheKey)) {
959
+ return configCache.get(cacheKey);
960
+ }
961
+ let config = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
962
+ const globalConfigPath = path9.join(os.homedir(), ".agenthandoffrc");
963
+ try {
964
+ await fs7.access(globalConfigPath);
965
+ const globalConfig = await loadConfigFile(globalConfigPath);
966
+ config = mergeConfig(config, globalConfig);
967
+ } catch {
968
+ }
969
+ const localConfigFile = await findConfigFile(startPath);
970
+ if (localConfigFile) {
971
+ const localConfig = await loadConfigFile(localConfigFile);
972
+ config = mergeConfig(config, localConfig);
973
+ }
974
+ configCache.set(cacheKey, config);
975
+ return config;
976
+ }
977
+ async function initConfigFile(targetPath, global = false) {
978
+ const configPath = global ? path9.join(os.homedir(), ".agenthandoffrc") : path9.join(targetPath, ".agenthandoffrc");
979
+ const content = JSON.stringify(DEFAULT_CONFIG, null, 2);
980
+ await fs7.writeFile(configPath, content, "utf-8");
981
+ return configPath;
982
+ }
983
+
984
+ // src/cli/commands/config.ts
985
+ var configCommand = new Command6("config").description("\u67E5\u770B\u6216\u7BA1\u7406\u914D\u7F6E").argument("[action]", "\u64CD\u4F5C: show, init", "show").option("-g, --global", "\u64CD\u4F5C\u5168\u5C40\u914D\u7F6E").option("--verbose", "\u663E\u793A\u8BE6\u7EC6\u4FE1\u606F").action(async (action, options) => {
986
+ try {
987
+ if (action === "show") {
988
+ await showConfig(options);
989
+ } else if (action === "init") {
990
+ await initConfig(options);
991
+ } else if (action === "list") {
992
+ await listConfig(options);
993
+ } else {
994
+ console.error(`Unknown action: ${action}`);
995
+ console.log("Available actions: show, init, list");
996
+ process.exit(1);
404
997
  }
405
998
  } catch (error) {
406
999
  console.error(`Error: ${error}`);
407
1000
  process.exit(1);
408
1001
  }
409
1002
  });
1003
+ async function showConfig(options) {
1004
+ const targetPath = options.global ? os2.homedir() : process.cwd();
1005
+ const config = await loadConfig(targetPath);
1006
+ if (options.verbose) {
1007
+ const configFile = await findConfigFile(targetPath);
1008
+ if (configFile) {
1009
+ console.log(`Config file: ${configFile}`);
1010
+ console.log("");
1011
+ } else {
1012
+ console.log("No config file found, using defaults");
1013
+ console.log("");
1014
+ }
1015
+ }
1016
+ console.log(JSON.stringify(config, null, 2));
1017
+ }
1018
+ async function initConfig(options) {
1019
+ const targetPath = options.global ? os2.homedir() : process.cwd();
1020
+ const configPath = await initConfigFile(targetPath, options.global);
1021
+ console.log(`\u2705 Created config file: ${configPath}`);
1022
+ console.log("");
1023
+ console.log("Default configuration:");
1024
+ console.log(JSON.stringify(DEFAULT_CONFIG, null, 2));
1025
+ }
1026
+ async function listConfig(options) {
1027
+ console.log("Configuration options:");
1028
+ console.log("");
1029
+ console.log(" defaultWorkspace - \u9ED8\u8BA4 workspace \u8DEF\u5F84");
1030
+ console.log(" events.enabled - \u662F\u5426\u542F\u7528\u4E8B\u4EF6\u65E5\u5FD7 (default: true)");
1031
+ console.log(" events.logStepStarted - \u662F\u5426\u8BB0\u5F55 step.started (default: true)");
1032
+ console.log(" events.logStepDone - \u662F\u5426\u8BB0\u5F55 step.done (default: true)");
1033
+ console.log(" clipboard.autoCopy - \u662F\u5426\u81EA\u52A8\u590D\u5236 prompt (default: false)");
1034
+ console.log(" prompt.templatePath - \u81EA\u5B9A\u4E49 prompt \u6A21\u677F\u8DEF\u5F84");
1035
+ console.log(" prompt.language - prompt \u8BED\u8A00 (default: zh)");
1036
+ console.log(" validation.strict - \u4E25\u683C\u6821\u9A8C\u6A21\u5F0F (default: false)");
1037
+ console.log(" validation.warnOnShortContent - \u5185\u5BB9\u8FC7\u77ED\u65F6\u8B66\u544A (default: true)");
1038
+ console.log("");
1039
+ console.log("Config file locations (in order of priority):");
1040
+ console.log(" .agenthandoffrc");
1041
+ console.log(" .agenthandoffrc.json");
1042
+ console.log(" .agenthandoffrc.yaml");
1043
+ console.log(" package.json#agenthandoff");
1044
+ console.log(` ~/.agenthandoffrc (global)`);
1045
+ }
410
1046
 
411
1047
  // src/index.ts
412
- var program = new Command4();
413
- program.name("agent-handoff").description("\u8F7B\u91CF\u7EA7\u591A Agent \u534F\u4F5C\u63A5\u529B\u5DE5\u5177").version("0.1.0");
1048
+ var require2 = createRequire(import.meta.url);
1049
+ var { version } = require2("../package.json");
1050
+ var program = new Command7();
1051
+ program.name("agent-handoff").description("\u8F7B\u91CF\u7EA7\u591A Agent \u534F\u4F5C\u63A5\u529B\u5DE5\u5177").version(version);
414
1052
  program.addCommand(initCommand);
415
1053
  program.addCommand(statusCommand);
416
1054
  program.addCommand(nextCommand);
1055
+ program.addCommand(validateCommand);
1056
+ program.addCommand(advanceCommand);
1057
+ program.addCommand(configCommand);
417
1058
  program.parse();
418
1059
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cli/commands/init.ts","../src/cli/commands/status.ts","../src/core/workspace.ts","../src/core/workflow-parser.ts","../src/core/state-machine.ts","../src/cli/commands/next.ts","../src/core/prompt-generator.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { initCommand } from './cli/commands/init.js';\nimport { statusCommand } from './cli/commands/status.js';\nimport { nextCommand } from './cli/commands/next.js';\n\nconst program = new Command();\n\nprogram\n .name('agent-handoff')\n .description('轻量级多 Agent 协作接力工具')\n .version('0.1.0');\n\nprogram.addCommand(initCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(nextCommand);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport fs from 'fs/promises';\nimport path from 'path';\n\nexport const initCommand = new Command('init')\n .description('创建新的 workspace')\n .argument('<name>', 'workspace 名称')\n .option('-p, --path <path>', '父目录路径', process.cwd())\n .action(async (name: string, options: { path: string }) => {\n const workspacePath = path.resolve(options.path, name);\n\n try {\n await fs.access(workspacePath);\n console.error(`Error: workspace \"${name}\" already exists at ${workspacePath}`);\n process.exit(1);\n } catch {\n // 目录不存在,继续创建\n }\n\n try {\n await fs.mkdir(workspacePath, { recursive: true });\n await fs.mkdir(path.join(workspacePath, 'steps'), { recursive: true });\n\n const workflowTemplate = `name: ${name}\nsteps:\n - id: clarify\n executor: trae\n input: brief.md\n output: steps/01-clarify/output.md\n acceptance:\n - 澄清需求范围与非目标\n - 产出结构化需求文档\n`;\n\n const stateTemplate = JSON.stringify({\n currentIndex: 0,\n status: 'running',\n updatedAt: new Date().toISOString(),\n }, null, 2);\n\n const briefTemplate = `# brief:需求描述\n\n## 背景\n(请描述项目背景)\n\n## 目标\n(请描述本轮目标)\n\n## 非目标\n(请描述本轮不做的事情)\n\n## 验收标准\n(请描述验收标准)\n`;\n\n await fs.writeFile(path.join(workspacePath, 'workflow.yaml'), workflowTemplate);\n await fs.writeFile(path.join(workspacePath, 'state.json'), stateTemplate);\n await fs.writeFile(path.join(workspacePath, 'brief.md'), briefTemplate);\n\n console.log(`✅ Created workspace \"${name}\" at ${workspacePath}`);\n console.log(`\nNext steps:\n 1. Edit brief.md to describe your requirements\n 2. Run \"agent-handoff status ${name}\" to check workspace status\n 3. Run \"agent-handoff next ${name}\" to get the first step prompt\n`);\n } catch (error) {\n console.error(`Error creating workspace: ${error}`);\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState } from '../../core/state-machine.js';\n\nexport const statusCommand = new Command('status')\n .description('显示 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (options.json) {\n const jsonOutput = {\n name: info.workflow.name,\n path: workspacePath,\n status: stateResult.status,\n currentIndex: stateResult.currentIndex,\n totalSteps: info.workflow.steps.length,\n completedSteps: stateResult.completedSteps.length,\n steps: info.workflow.steps.map((step, index) => ({\n index,\n id: step.id,\n executor: step.executor,\n workItemId: step.workItemId,\n completed: info.stepOutputs.get(step.id) ?? false,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log(`Status: ${stateResult.status}`);\n console.log('');\n console.log('Steps:');\n\n info.workflow.steps.forEach((step, index) => {\n const completed = info.stepOutputs.get(step.id) ?? false;\n const statusIcon = completed ? '✅' : '⬜';\n const stepNum = String(index + 1).padStart(2, '0');\n let line = ` ${statusIcon} ${stepNum}-${step.id} (${step.executor})`;\n if (step.workItemId) {\n line += ` [${step.workItemId}]`;\n }\n console.log(line);\n });\n\n console.log('');\n if (stateResult.status === 'done') {\n console.log('Current: completed');\n } else {\n const currentStep = info.workflow.steps[stateResult.currentIndex];\n console.log(`Current: step ${stateResult.currentIndex + 1} (${currentStep?.id})`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Workflow } from './models/workflow.js';\nimport { State } from './models/state.js';\nimport { parseWorkflow } from './workflow-parser.js';\n\nexport interface WorkspaceInfo {\n path: string;\n exists: boolean;\n hasWorkflow: boolean;\n hasState: boolean;\n workflow?: Workflow;\n state?: State;\n stepOutputs: Map<string, boolean>;\n}\n\nexport async function loadWorkspace(workspacePath: string): Promise<WorkspaceInfo> {\n const absolutePath = path.resolve(workspacePath);\n const workflowPath = path.join(absolutePath, 'workflow.yaml');\n const statePath = path.join(absolutePath, 'state.json');\n\n let exists = false;\n let hasWorkflow = false;\n let hasState = false;\n let workflow: Workflow | undefined;\n let state: State | undefined;\n let stepOutputs = new Map<string, boolean>();\n\n try {\n await fs.access(absolutePath);\n exists = true;\n } catch {\n return {\n path: absolutePath,\n exists: false,\n hasWorkflow: false,\n hasState: false,\n stepOutputs,\n };\n }\n\n try {\n await fs.access(workflowPath);\n hasWorkflow = true;\n workflow = await parseWorkflow(workflowPath);\n } catch {\n hasWorkflow = false;\n }\n\n try {\n const stateContent = await fs.readFile(statePath, 'utf-8');\n hasState = true;\n state = JSON.parse(stateContent) as State;\n } catch {\n hasState = false;\n }\n\n if (workflow) {\n stepOutputs = await detectStepOutputs(absolutePath, workflow);\n }\n\n return {\n path: absolutePath,\n exists,\n hasWorkflow,\n hasState,\n workflow,\n state,\n stepOutputs,\n };\n}\n\nexport async function detectStepOutputs(\n workspacePath: string,\n workflow: Workflow\n): Promise<Map<string, boolean>> {\n const outputs = new Map<string, boolean>();\n\n for (const step of workflow.steps) {\n const outputPath = path.join(workspacePath, step.output);\n try {\n const content = await fs.readFile(outputPath, 'utf-8');\n outputs.set(step.id, content.trim().length > 0);\n } catch {\n outputs.set(step.id, false);\n }\n }\n\n return outputs;\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function fileNotEmpty(filePath: string): Promise<boolean> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return content.trim().length > 0;\n } catch {\n return false;\n }\n}\n","import fs from 'fs/promises';\nimport YAML from 'yaml';\nimport { Workflow, Step, Executor } from './models/workflow';\n\nexport async function parseWorkflow(filePath: string): Promise<Workflow> {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsed = YAML.parse(content);\n \n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid workflow.yaml: ${filePath}`);\n }\n \n if (!parsed.name || typeof parsed.name !== 'string') {\n throw new Error('workflow.yaml missing required field: name');\n }\n \n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) {\n throw new Error('workflow.yaml missing required field: steps (non-empty array)');\n }\n \n const steps: Step[] = parsed.steps.map((step: Record<string, unknown>, index: number) => {\n if (!step.id || typeof step.id !== 'string') {\n throw new Error(`Step ${index} missing required field: id`);\n }\n if (!step.executor || typeof step.executor !== 'string') {\n throw new Error(`Step ${index} missing required field: executor`);\n }\n if (!step.input || typeof step.input !== 'string') {\n throw new Error(`Step ${index} missing required field: input`);\n }\n if (!step.output || typeof step.output !== 'string') {\n throw new Error(`Step ${index} missing required field: output`);\n }\n \n return {\n id: step.id,\n executor: step.executor as Executor,\n input: step.input,\n output: step.output,\n workItemId: step.workItemId as string | undefined,\n acceptance: step.acceptance as string[] | undefined,\n };\n });\n \n return {\n name: parsed.name,\n steps,\n };\n}\n\nexport function validateWorkflow(workflow: Workflow): string[] {\n const errors: string[] = [];\n \n if (!workflow.name || workflow.name.trim() === '') {\n errors.push('workflow.name is required');\n }\n \n if (!workflow.steps || workflow.steps.length === 0) {\n errors.push('workflow.steps is required and must be non-empty');\n return errors;\n }\n \n workflow.steps.forEach((step, index) => {\n if (!step.id || step.id.trim() === '') {\n errors.push(`steps[${index}].id is required`);\n }\n if (!step.executor) {\n errors.push(`steps[${index}].executor is required`);\n }\n if (!step.input || step.input.trim() === '') {\n errors.push(`steps[${index}].input is required`);\n }\n if (!step.output || step.output.trim() === '') {\n errors.push(`steps[${index}].output is required`);\n }\n if (!step.output.startsWith('steps/')) {\n errors.push(`steps[${index}].output should start with 'steps/'`);\n }\n });\n \n return errors;\n}\n","import { Workflow } from './models/workflow';\nimport { State, WorkflowStatus } from './models/state';\n\nexport interface StateMachineResult {\n currentIndex: number;\n status: WorkflowStatus;\n nextStepIndex: number | null;\n completedSteps: number[];\n pendingSteps: number[];\n}\n\nexport function computeState(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): StateMachineResult {\n if (!workflow.steps || workflow.steps.length === 0) {\n return {\n currentIndex: 0,\n status: 'done',\n nextStepIndex: null,\n completedSteps: [],\n pendingSteps: [],\n };\n }\n\n const completedSteps: number[] = [];\n const pendingSteps: number[] = [];\n let currentIndex = 0;\n let status: WorkflowStatus = 'running';\n\n for (let i = 0; i < workflow.steps.length; i++) {\n const step = workflow.steps[i];\n const outputExists = stepOutputs.get(step.id) ?? false;\n\n if (outputExists) {\n completedSteps.push(i);\n } else {\n pendingSteps.push(i);\n }\n }\n\n const firstPendingIndex = pendingSteps[0];\n\n if (firstPendingIndex === undefined) {\n currentIndex = workflow.steps.length;\n status = 'done';\n } else {\n currentIndex = firstPendingIndex;\n status = 'running';\n }\n\n return {\n currentIndex,\n status,\n nextStepIndex: status === 'done' ? null : currentIndex,\n completedSteps,\n pendingSteps,\n };\n}\n\nexport function advanceState(\n state: State,\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): State {\n const result = computeState(workflow, stepOutputs);\n\n return {\n ...state,\n currentIndex: result.currentIndex,\n status: result.status,\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function isWorkflowComplete(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): boolean {\n if (!workflow.steps || workflow.steps.length === 0) {\n return true;\n }\n\n return workflow.steps.every((step) => stepOutputs.get(step.id) === true);\n}\n\nexport function getCurrentStep(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): { index: number; step: typeof workflow.steps[0] } | null {\n const result = computeState(workflow, stepOutputs);\n\n if (result.status === 'done' || result.nextStepIndex === null) {\n return null;\n }\n\n return {\n index: result.nextStepIndex,\n step: workflow.steps[result.nextStepIndex],\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { generatePrompt } from '../../core/prompt-generator.js';\n\nexport const nextCommand = new Command('next')\n .description('输出下一步执行指令和 prompt')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-c, --copy', '复制 prompt 到剪贴板(v0.2)')\n .action(async (workspace: string, options: { copy: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (stateResult.status === 'done') {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Step: ${step.id}`);\n console.log(`Executor: ${step.executor}`);\n if (step.workItemId) {\n console.log(`Work Item: ${step.workItemId}`);\n }\n console.log('');\n console.log('Input:');\n console.log(` - ${step.input}`);\n console.log('');\n console.log('Output:');\n console.log(` - ${step.output}`);\n console.log('');\n console.log('Prompt:');\n console.log('────────────────────────────────────────');\n\n const prompt = generatePrompt({\n workflow: info.workflow,\n step,\n stepIndex: index,\n workspacePath: info.path,\n });\n\n console.log(prompt);\n console.log('────────────────────────────────────────');\n console.log('');\n console.log('提示:将上述 Prompt 复制到 TRAE 新 Task 中执行');\n\n if (options.copy) {\n console.log('');\n console.log('注意:剪贴板功能将在 v0.2 版本实现');\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import { Workflow, Step } from './models/workflow.js';\n\nexport interface PromptContext {\n workflow: Workflow;\n step: Step;\n stepIndex: number;\n workspacePath: string;\n}\n\nexport function generatePrompt(context: PromptContext): string {\n const { workflow, step, stepIndex } = context;\n const totalSteps = workflow.steps.length;\n const stepNum = stepIndex + 1;\n\n let prompt = `# 任务:${step.id}\n\n## 上下文\n- Workflow: ${workflow.name}\n- Step: ${stepNum} / ${totalSteps}\n- Executor: ${step.executor}`;\n\n if (step.workItemId) {\n prompt += `\\n- Work Item: ${step.workItemId}`;\n }\n\n prompt += `\n\n## 输入产物\n请阅读以下输入产物:\n- ${step.input}\n\n## 输出产物\n请将结果写入:\n- ${step.output}`;\n\n if (step.acceptance && step.acceptance.length > 0) {\n prompt += `\n\n## 验收标准`;\n for (const criteria of step.acceptance) {\n prompt += `\\n- ${criteria}`;\n }\n }\n\n prompt += `\n\n## 输出要求\n完成后请在 output.md 中包含以下区块:\n- 产物更新\n- 关键决策\n- 风险与待确认\n- 下一步交接\n\n---\nAgentHandoff Step Prompt`;\n\n return prompt;\n}\n"],"mappings":"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","names":["Command","Command","path","fs","path","fs","path","fs","Command","path","Command","path","Command","path","Command"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cli/commands/init.ts","../src/cli/commands/status.ts","../src/core/workspace.ts","../src/core/workflow-parser.ts","../src/core/state-machine.ts","../src/cli/commands/next.ts","../src/core/prompt-generator.ts","../src/core/clipboard.ts","../src/core/events-writer.ts","../src/cli/commands/validate.ts","../src/core/artifact-validator.ts","../src/cli/commands/advance.ts","../src/cli/commands/config.ts","../src/core/config.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { createRequire } from 'module';\nimport { Command } from 'commander';\nimport { initCommand } from './cli/commands/init.js';\nimport { statusCommand } from './cli/commands/status.js';\nimport { nextCommand } from './cli/commands/next.js';\nimport { validateCommand } from './cli/commands/validate.js';\nimport { advanceCommand } from './cli/commands/advance.js';\nimport { configCommand } from './cli/commands/config.js';\n\nconst require = createRequire(import.meta.url);\nconst { version } = require('../package.json');\n\nconst program = new Command();\n\nprogram\n .name('agent-handoff')\n .description('轻量级多 Agent 协作接力工具')\n .version(version);\n\nprogram.addCommand(initCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(nextCommand);\nprogram.addCommand(validateCommand);\nprogram.addCommand(advanceCommand);\nprogram.addCommand(configCommand);\n\nprogram.parse();\n","import { Command } from 'commander';\nimport fs from 'fs/promises';\nimport path from 'path';\n\nexport const initCommand = new Command('init')\n .description('创建新的 workspace')\n .argument('<name>', 'workspace 名称')\n .option('-p, --path <path>', '父目录路径', process.cwd())\n .action(async (name: string, options: { path: string }) => {\n const workspacePath = path.resolve(options.path, name);\n\n try {\n await fs.access(workspacePath);\n console.error(`Error: workspace \"${name}\" already exists at ${workspacePath}`);\n process.exit(1);\n } catch {\n // 目录不存在,继续创建\n }\n\n try {\n await fs.mkdir(workspacePath, { recursive: true });\n await fs.mkdir(path.join(workspacePath, 'steps'), { recursive: true });\n\n const workflowTemplate = `name: ${name}\nsteps:\n - id: clarify\n executor: trae\n input: brief.md\n output: steps/01-clarify/output.md\n acceptance:\n - 澄清需求范围与非目标\n - 产出结构化需求文档\n`;\n\n const stateTemplate = JSON.stringify({\n currentIndex: 0,\n status: 'running',\n updatedAt: new Date().toISOString(),\n }, null, 2);\n\n const briefTemplate = `# brief:需求描述\n\n## 背景\n(请描述项目背景)\n\n## 目标\n(请描述本轮目标)\n\n## 非目标\n(请描述本轮不做的事情)\n\n## 验收标准\n(请描述验收标准)\n`;\n\n await fs.writeFile(path.join(workspacePath, 'workflow.yaml'), workflowTemplate);\n await fs.writeFile(path.join(workspacePath, 'state.json'), stateTemplate);\n await fs.writeFile(path.join(workspacePath, 'brief.md'), briefTemplate);\n\n console.log(`✅ Created workspace \"${name}\" at ${workspacePath}`);\n console.log(`\nNext steps:\n 1. Edit brief.md to describe your requirements\n 2. Run \"agent-handoff status ${name}\" to check workspace status\n 3. Run \"agent-handoff next ${name}\" to get the first step prompt\n`);\n } catch (error) {\n console.error(`Error creating workspace: ${error}`);\n process.exit(1);\n }\n });\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState } from '../../core/state-machine.js';\n\nexport const statusCommand = new Command('status')\n .description('显示 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (options.json) {\n const jsonOutput = {\n name: info.workflow.name,\n path: workspacePath,\n status: stateResult.status,\n currentIndex: stateResult.currentIndex,\n totalSteps: info.workflow.steps.length,\n completedSteps: stateResult.completedSteps.length,\n steps: info.workflow.steps.map((step, index) => ({\n index,\n id: step.id,\n executor: step.executor,\n workItemId: step.workItemId,\n completed: info.stepOutputs.get(step.id) ?? false,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log(`Status: ${stateResult.status}`);\n console.log('');\n console.log('Steps:');\n\n info.workflow.steps.forEach((step, index) => {\n const completed = info.stepOutputs.get(step.id) ?? false;\n const statusIcon = completed ? '✅' : '⬜';\n const stepNum = String(index + 1).padStart(2, '0');\n let line = ` ${statusIcon} ${stepNum}-${step.id} (${step.executor})`;\n if (step.workItemId) {\n line += ` [${step.workItemId}]`;\n }\n console.log(line);\n });\n\n console.log('');\n if (stateResult.status === 'done') {\n console.log('Current: completed');\n } else {\n const currentStep = info.workflow.steps[stateResult.currentIndex];\n console.log(`Current: step ${stateResult.currentIndex + 1} (${currentStep?.id})`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Workflow } from './models/workflow.js';\nimport { State } from './models/state.js';\nimport { parseWorkflow } from './workflow-parser.js';\n\nexport interface WorkspaceInfo {\n path: string;\n exists: boolean;\n hasWorkflow: boolean;\n hasState: boolean;\n workflow?: Workflow;\n state?: State;\n stepOutputs: Map<string, boolean>;\n}\n\nexport async function loadWorkspace(workspacePath: string): Promise<WorkspaceInfo> {\n const absolutePath = path.resolve(workspacePath);\n const workflowPath = path.join(absolutePath, 'workflow.yaml');\n const statePath = path.join(absolutePath, 'state.json');\n\n let exists = false;\n let hasWorkflow = false;\n let hasState = false;\n let workflow: Workflow | undefined;\n let state: State | undefined;\n let stepOutputs = new Map<string, boolean>();\n\n try {\n await fs.access(absolutePath);\n exists = true;\n } catch {\n return {\n path: absolutePath,\n exists: false,\n hasWorkflow: false,\n hasState: false,\n stepOutputs,\n };\n }\n\n try {\n await fs.access(workflowPath);\n hasWorkflow = true;\n workflow = await parseWorkflow(workflowPath);\n } catch {\n hasWorkflow = false;\n }\n\n try {\n const stateContent = await fs.readFile(statePath, 'utf-8');\n hasState = true;\n state = JSON.parse(stateContent) as State;\n } catch {\n hasState = false;\n }\n\n if (workflow) {\n stepOutputs = await detectStepOutputs(absolutePath, workflow);\n }\n\n return {\n path: absolutePath,\n exists,\n hasWorkflow,\n hasState,\n workflow,\n state,\n stepOutputs,\n };\n}\n\nexport async function detectStepOutputs(\n workspacePath: string,\n workflow: Workflow\n): Promise<Map<string, boolean>> {\n const outputs = new Map<string, boolean>();\n\n for (const step of workflow.steps) {\n const outputPath = path.join(workspacePath, step.output);\n try {\n const content = await fs.readFile(outputPath, 'utf-8');\n outputs.set(step.id, content.trim().length > 0);\n } catch {\n outputs.set(step.id, false);\n }\n }\n\n return outputs;\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function fileNotEmpty(filePath: string): Promise<boolean> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return content.trim().length > 0;\n } catch {\n return false;\n }\n}\n","import fs from 'fs/promises';\nimport YAML from 'yaml';\nimport { Workflow, Step, Executor } from './models/workflow';\n\nexport async function parseWorkflow(filePath: string): Promise<Workflow> {\n const content = await fs.readFile(filePath, 'utf-8');\n const parsed = YAML.parse(content);\n \n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid workflow.yaml: ${filePath}`);\n }\n \n if (!parsed.name || typeof parsed.name !== 'string') {\n throw new Error('workflow.yaml missing required field: name');\n }\n \n if (!Array.isArray(parsed.steps) || parsed.steps.length === 0) {\n throw new Error('workflow.yaml missing required field: steps (non-empty array)');\n }\n \n const steps: Step[] = parsed.steps.map((step: Record<string, unknown>, index: number) => {\n if (!step.id || typeof step.id !== 'string') {\n throw new Error(`Step ${index} missing required field: id`);\n }\n if (!step.executor || typeof step.executor !== 'string') {\n throw new Error(`Step ${index} missing required field: executor`);\n }\n if (!step.input || typeof step.input !== 'string') {\n throw new Error(`Step ${index} missing required field: input`);\n }\n if (!step.output || typeof step.output !== 'string') {\n throw new Error(`Step ${index} missing required field: output`);\n }\n \n return {\n id: step.id,\n executor: step.executor as Executor,\n input: step.input,\n output: step.output,\n workItemId: step.workItemId as string | undefined,\n acceptance: step.acceptance as string[] | undefined,\n };\n });\n \n return {\n name: parsed.name,\n steps,\n };\n}\n\nexport function validateWorkflow(workflow: Workflow): string[] {\n const errors: string[] = [];\n \n if (!workflow.name || workflow.name.trim() === '') {\n errors.push('workflow.name is required');\n }\n \n if (!workflow.steps || workflow.steps.length === 0) {\n errors.push('workflow.steps is required and must be non-empty');\n return errors;\n }\n \n workflow.steps.forEach((step, index) => {\n if (!step.id || step.id.trim() === '') {\n errors.push(`steps[${index}].id is required`);\n }\n if (!step.executor) {\n errors.push(`steps[${index}].executor is required`);\n }\n if (!step.input || step.input.trim() === '') {\n errors.push(`steps[${index}].input is required`);\n }\n if (!step.output || step.output.trim() === '') {\n errors.push(`steps[${index}].output is required`);\n }\n if (!step.output.startsWith('steps/')) {\n errors.push(`steps[${index}].output should start with 'steps/'`);\n }\n });\n \n return errors;\n}\n","import { Workflow } from './models/workflow';\nimport { State, WorkflowStatus } from './models/state';\n\nexport interface StateMachineResult {\n currentIndex: number;\n status: WorkflowStatus;\n nextStepIndex: number | null;\n completedSteps: number[];\n pendingSteps: number[];\n}\n\nexport function computeState(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): StateMachineResult {\n if (!workflow.steps || workflow.steps.length === 0) {\n return {\n currentIndex: 0,\n status: 'done',\n nextStepIndex: null,\n completedSteps: [],\n pendingSteps: [],\n };\n }\n\n const completedSteps: number[] = [];\n const pendingSteps: number[] = [];\n let currentIndex = 0;\n let status: WorkflowStatus = 'running';\n\n for (let i = 0; i < workflow.steps.length; i++) {\n const step = workflow.steps[i];\n const outputExists = stepOutputs.get(step.id) ?? false;\n\n if (outputExists) {\n completedSteps.push(i);\n } else {\n pendingSteps.push(i);\n }\n }\n\n const firstPendingIndex = pendingSteps[0];\n\n if (firstPendingIndex === undefined) {\n currentIndex = workflow.steps.length;\n status = 'done';\n } else {\n currentIndex = firstPendingIndex;\n status = 'running';\n }\n\n return {\n currentIndex,\n status,\n nextStepIndex: status === 'done' ? null : currentIndex,\n completedSteps,\n pendingSteps,\n };\n}\n\nexport function advanceState(\n state: State,\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): State {\n const result = computeState(workflow, stepOutputs);\n\n return {\n ...state,\n currentIndex: result.currentIndex,\n status: result.status,\n updatedAt: new Date().toISOString(),\n };\n}\n\nexport function isWorkflowComplete(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): boolean {\n if (!workflow.steps || workflow.steps.length === 0) {\n return true;\n }\n\n return workflow.steps.every((step) => stepOutputs.get(step.id) === true);\n}\n\nexport function getCurrentStep(\n workflow: Workflow,\n stepOutputs: Map<string, boolean>\n): { index: number; step: typeof workflow.steps[0] } | null {\n const result = computeState(workflow, stepOutputs);\n\n if (result.status === 'done' || result.nextStepIndex === null) {\n return null;\n }\n\n return {\n index: result.nextStepIndex,\n step: workflow.steps[result.nextStepIndex],\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { generatePrompt } from '../../core/prompt-generator.js';\nimport { copyToClipboard, isClipboardSupported } from '../../core/clipboard.js';\nimport { writeEvent } from '../../core/events-writer.js';\n\nexport const nextCommand = new Command('next')\n .description('输出下一步执行指令和 prompt')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-c, --copy', '复制 prompt 到剪贴板')\n .option('--no-event', '不写入事件日志')\n .action(async (workspace: string, options: { copy: boolean; event: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n if (stateResult.status === 'done') {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log(`Workflow \"${info.workflow.name}\" 已完成所有步骤。`);\n console.log('无下一步操作。');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Step: ${step.id}`);\n console.log(`Executor: ${step.executor}`);\n if (step.workItemId) {\n console.log(`Work Item: ${step.workItemId}`);\n }\n console.log('');\n console.log('Input:');\n console.log(` - ${step.input}`);\n console.log('');\n console.log('Output:');\n console.log(` - ${step.output}`);\n console.log('');\n console.log('Prompt:');\n console.log('────────────────────────────────────────');\n\n const prompt = generatePrompt({\n workflow: info.workflow,\n step,\n stepIndex: index,\n workspacePath: info.path,\n });\n\n console.log(prompt);\n console.log('────────────────────────────────────────');\n console.log('');\n\n if (options.event) {\n await writeEvent({\n workspacePath,\n step: { index: index + 1, id: step.id },\n type: 'step.started',\n summary: `开始执行步骤: ${step.id}`,\n workItemId: step.workItemId,\n links: [step.input],\n });\n }\n\n if (options.copy) {\n if (!isClipboardSupported()) {\n console.log('⚠️ 剪贴板功能在当前环境不可用');\n console.log('请手动复制上面的 Prompt');\n } else {\n const result = await copyToClipboard(prompt);\n if (result.success) {\n console.log('✅ Prompt 已复制到剪贴板');\n } else {\n console.log(`❌ 复制失败: ${result.error}`);\n console.log('请手动复制上面的 Prompt');\n }\n }\n } else {\n console.log('提示:将上述 Prompt 复制到 TRAE 新 Task 中执行');\n console.log(' 使用 --copy 选项可自动复制到剪贴板');\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import { Workflow, Step } from './models/workflow.js';\n\nexport interface PromptContext {\n workflow: Workflow;\n step: Step;\n stepIndex: number;\n workspacePath: string;\n}\n\nexport function generatePrompt(context: PromptContext): string {\n const { workflow, step, stepIndex } = context;\n const totalSteps = workflow.steps.length;\n const stepNum = stepIndex + 1;\n\n let prompt = `# 任务:${step.id}\n\n## 上下文\n- Workflow: ${workflow.name}\n- Step: ${stepNum} / ${totalSteps}\n- Executor: ${step.executor}`;\n\n if (step.workItemId) {\n prompt += `\\n- Work Item: ${step.workItemId}`;\n }\n\n prompt += `\n\n## 输入产物\n请阅读以下输入产物:\n- ${step.input}\n\n## 输出产物\n请将结果写入:\n- ${step.output}`;\n\n if (step.acceptance && step.acceptance.length > 0) {\n prompt += `\n\n## 验收标准`;\n for (const criteria of step.acceptance) {\n prompt += `\\n- ${criteria}`;\n }\n }\n\n prompt += `\n\n## 输出要求\n完成后请在 output.md 中包含以下区块:\n- 产物更新\n- 关键决策\n- 风险与待确认\n- 下一步交接\n\n---\nAgentHandoff Step Prompt`;\n\n return prompt;\n}\n","import clipboard from 'clipboardy';\n\nexport interface ClipboardResult {\n success: boolean;\n error?: string;\n}\n\nlet clipboardSupported: boolean | null = null;\n\nexport function isClipboardSupported(): boolean {\n if (clipboardSupported !== null) {\n return clipboardSupported;\n }\n\n try {\n clipboardSupported = true;\n return true;\n } catch {\n clipboardSupported = false;\n return false;\n }\n}\n\nexport async function copyToClipboard(text: string): Promise<ClipboardResult> {\n try {\n await clipboard.write(text);\n return { success: true };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n error: errorMessage,\n };\n }\n}\n\nexport async function readFromClipboard(): Promise<string> {\n try {\n return await clipboard.read();\n } catch {\n return '';\n }\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { Event, EventType, EventStep } from './models/event.js';\n\nexport interface WriteEventOptions {\n workspacePath: string;\n step: EventStep;\n type: EventType;\n summary: string;\n workItemId?: string;\n links?: string[];\n}\n\nexport interface EventsWriterResult {\n success: boolean;\n event: Event;\n error?: string;\n}\n\nexport async function writeEvent(options: WriteEventOptions): Promise<EventsWriterResult> {\n const { workspacePath, step, type, summary, workItemId, links } = options;\n\n const event: Event = {\n ts: new Date().toISOString(),\n step,\n type,\n summary,\n ...(workItemId && { workItemId }),\n ...(links && links.length > 0 && { links }),\n };\n\n try {\n const eventsPath = path.join(workspacePath, 'events.jsonl');\n const line = JSON.stringify(event) + '\\n';\n await fs.appendFile(eventsPath, line, 'utf-8');\n\n return {\n success: true,\n event,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n event,\n error: errorMessage,\n };\n }\n}\n\nexport async function readEvents(workspacePath: string): Promise<Event[]> {\n const eventsPath = path.join(workspacePath, 'events.jsonl');\n\n try {\n const content = await fs.readFile(eventsPath, 'utf-8');\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const events: Event[] = [];\n for (const line of lines) {\n try {\n const event = JSON.parse(line) as Event;\n events.push(event);\n } catch {\n // Skip invalid lines\n }\n }\n\n return events;\n } catch {\n return [];\n }\n}\n\nexport async function getLatestEvent(workspacePath: string): Promise<Event | null> {\n const events = await readEvents(workspacePath);\n if (events.length === 0) {\n return null;\n }\n return events[events.length - 1];\n}\n\nexport async function getEventsByStep(workspacePath: string, stepId: string): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.step.id === stepId);\n}\n\nexport async function getEventsByType(workspacePath: string, type: EventType): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.type === type);\n}\n\nexport async function getEventsByWorkItem(\n workspacePath: string,\n workItemId: string\n): Promise<Event[]> {\n const events = await readEvents(workspacePath);\n return events.filter((event) => event.workItemId === workItemId);\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { validateWorkspaceArtifacts } from '../../core/artifact-validator.js';\n\nexport const validateCommand = new Command('validate')\n .description('校验 workspace 产物结构')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('--strict', '严格模式(将警告视为错误)')\n .option('-j, --json', 'JSON 格式输出')\n .action(async (workspace: string, options: { strict: boolean; json: boolean }) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const result = await validateWorkspaceArtifacts(workspacePath);\n\n if (options.json) {\n const jsonOutput = {\n valid: options.strict ? result.valid && result.warningCount === 0 : result.valid,\n workspace: workspacePath,\n totalSteps: result.totalSteps,\n validSteps: result.validSteps,\n errorCount: result.errorCount,\n warningCount: result.warningCount,\n steps: Array.from(result.stepResults.entries()).map(([stepId, stepResult]) => ({\n stepId,\n valid: options.strict ? stepResult.valid && stepResult.warnings.length === 0 : stepResult.valid,\n errors: stepResult.errors,\n warnings: stepResult.warnings,\n })),\n };\n console.log(JSON.stringify(jsonOutput, null, 2));\n } else {\n console.log(`Workspace: ${info.workflow.name}`);\n console.log('');\n\n for (const step of info.workflow.steps) {\n const stepResult = result.stepResults.get(step.id);\n if (!stepResult) continue;\n\n const icon = stepResult.valid ? '✅' : '❌';\n console.log(`${icon} ${step.output} - ${stepResult.valid ? 'Valid' : 'Invalid'}`);\n\n if (!stepResult.valid) {\n for (const error of stepResult.errors) {\n console.log(` - ${error.message}`);\n }\n }\n\n if (stepResult.warnings.length > 0) {\n for (const warning of stepResult.warnings) {\n console.log(` ⚠️ ${warning.message}`);\n }\n }\n }\n\n console.log('');\n\n const hasErrors = result.errorCount > 0;\n const hasWarnings = result.warningCount > 0;\n const strictFail = options.strict && hasWarnings;\n\n if (!hasErrors && !strictFail) {\n console.log('All artifacts validated successfully.');\n if (hasWarnings) {\n console.log(`⚠️ ${result.warningCount} warning(s) found.`);\n }\n } else {\n const totalErrors = result.errorCount + (strictFail ? result.warningCount : 0);\n console.log(`Validation failed with ${totalErrors} error(s).`);\n }\n\n if (hasErrors || strictFail) {\n process.exit(1);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n","import fs from 'fs/promises';\nimport path from 'path';\nimport { loadWorkspace } from './workspace.js';\n\nexport interface ValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationWarning[];\n}\n\nexport interface ValidationError {\n type: 'missing_section' | 'empty_section' | 'invalid_format';\n section: string;\n message: string;\n}\n\nexport interface ValidationWarning {\n type: 'short_content' | 'missing_detail';\n section: string;\n message: string;\n}\n\nexport const REQUIRED_SECTIONS = [\n '产物更新',\n '关键决策',\n '风险与待确认',\n '下一步交接',\n] as const;\n\nexport type RequiredSection = (typeof REQUIRED_SECTIONS)[number];\n\nexport interface WorkspaceValidationResult {\n valid: boolean;\n stepResults: Map<string, ValidationResult>;\n totalSteps: number;\n validSteps: number;\n errorCount: number;\n warningCount: number;\n}\n\nconst MIN_CONTENT_LENGTH = 10;\n\nexport function validateArtifact(content: string): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n for (const section of REQUIRED_SECTIONS) {\n const sectionResult = findSection(content, section);\n\n if (!sectionResult.found) {\n errors.push({\n type: 'missing_section',\n section,\n message: `缺少必要区块: ${section}`,\n });\n } else if (!sectionResult.hasContent) {\n errors.push({\n type: 'empty_section',\n section,\n message: `区块内容为空: ${section}`,\n });\n } else if (sectionResult.contentLength < MIN_CONTENT_LENGTH) {\n warnings.push({\n type: 'short_content',\n section,\n message: `区块内容过短 (${sectionResult.contentLength} 字符): ${section}`,\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\ninterface SectionResult {\n found: boolean;\n hasContent: boolean;\n contentLength: number;\n}\n\nfunction findSection(content: string, sectionName: string): SectionResult {\n const patterns = [\n new RegExp(`^##\\\\s+${escapeRegex(sectionName)}[^\\\\n]*$`, 'm'),\n new RegExp(`^###\\\\s+${escapeRegex(sectionName)}[^\\\\n]*$`, 'm'),\n ];\n\n let matchIndex = -1;\n let matchLength = 0;\n\n for (const pattern of patterns) {\n const match = content.match(pattern);\n if (match && match.index !== undefined) {\n matchIndex = match.index;\n matchLength = match[0].length;\n break;\n }\n }\n\n if (matchIndex === -1) {\n return { found: false, hasContent: false, contentLength: 0 };\n }\n\n const contentStart = matchIndex + matchLength;\n const remainingContent = content.slice(contentStart);\n\n const nextSectionMatch = remainingContent.match(/^#{1,3}\\s+/m);\n const sectionContent = nextSectionMatch\n ? remainingContent.slice(0, nextSectionMatch.index)\n : remainingContent;\n\n const trimmedContent = sectionContent.trim();\n\n return {\n found: true,\n hasContent: trimmedContent.length > 0,\n contentLength: trimmedContent.length,\n };\n}\n\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport async function validateArtifactFile(\n filePath: string\n): Promise<ValidationResult> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n return validateArtifact(content);\n } catch (error) {\n return {\n valid: false,\n errors: [\n {\n type: 'invalid_format',\n section: '',\n message: `无法读取文件: ${filePath}`,\n },\n ],\n warnings: [],\n };\n }\n}\n\nexport async function validateWorkspaceArtifacts(\n workspacePath: string\n): Promise<WorkspaceValidationResult> {\n const workspace = await loadWorkspace(workspacePath);\n const stepResults = new Map<string, ValidationResult>();\n let validSteps = 0;\n let errorCount = 0;\n let warningCount = 0;\n\n if (!workspace.workflow) {\n return {\n valid: false,\n stepResults,\n totalSteps: 0,\n validSteps: 0,\n errorCount: 1,\n warningCount: 0,\n };\n }\n\n for (const step of workspace.workflow.steps) {\n const outputPath = path.join(workspace.path, step.output);\n const result = await validateArtifactFile(outputPath);\n stepResults.set(step.id, result);\n\n if (result.valid) {\n validSteps++;\n }\n errorCount += result.errors.length;\n warningCount += result.warnings.length;\n }\n\n return {\n valid: errorCount === 0,\n stepResults,\n totalSteps: workspace.workflow.steps.length,\n validSteps,\n errorCount,\n warningCount,\n };\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport fs from 'fs/promises';\nimport { loadWorkspace } from '../../core/workspace.js';\nimport { computeState, getCurrentStep } from '../../core/state-machine.js';\nimport { writeEvent } from '../../core/events-writer.js';\nimport { EventType } from '../../core/models/event.js';\n\nexport const advanceCommand = new Command('advance')\n .description('推进 workspace 状态')\n .argument('[workspace]', 'workspace 路径', '.')\n .option('-e, --event <type>', '事件类型', 'step.done')\n .option('-s, --summary <text>', '事件摘要')\n .option('--no-state', '不更新 state.json')\n .option('--skip-event', '不写入事件日志')\n .action(\n async (\n workspace: string,\n options: { event: string; summary?: string; state: boolean; skipEvent: boolean }\n ) => {\n const workspacePath = path.resolve(workspace);\n\n try {\n const info = await loadWorkspace(workspacePath);\n\n if (!info.exists) {\n console.error(`Error: workspace not found: ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.hasWorkflow) {\n console.error(`Error: workflow.yaml not found in ${workspacePath}`);\n process.exit(1);\n }\n\n if (!info.workflow) {\n console.error(`Error: failed to parse workflow.yaml`);\n process.exit(1);\n }\n\n const stateResult = computeState(info.workflow, info.stepOutputs);\n\n console.log(`Workspace: ${info.workflow.name}`);\n\n if (stateResult.status === 'done') {\n console.log('Status: done');\n console.log('');\n console.log('⚠️ Workflow already completed. No steps to advance.');\n return;\n }\n\n const currentStep = getCurrentStep(info.workflow, info.stepOutputs);\n\n if (!currentStep) {\n console.log('Status: done');\n console.log('');\n console.log('⚠️ Workflow already completed. No steps to advance.');\n return;\n }\n\n const { step, index } = currentStep;\n\n console.log(`Current step: ${step.id} (index: ${index})`);\n console.log('');\n\n const eventType = options.event as EventType;\n const eventSummary = options.summary || getDefaultSummary(eventType, step.id);\n\n if (!options.skipEvent) {\n const result = await writeEvent({\n workspacePath,\n step: { index: index + 1, id: step.id },\n type: eventType,\n summary: eventSummary,\n workItemId: step.workItemId,\n links: [step.output],\n });\n\n if (result.success) {\n console.log(`✅ Event written: ${eventType}`);\n console.log(` Summary: ${eventSummary}`);\n if (step.workItemId) {\n console.log(` Work Item: ${step.workItemId}`);\n }\n if (step.output) {\n console.log(` Links: ${step.output}`);\n }\n } else {\n console.log(`❌ Failed to write event: ${result.error}`);\n }\n }\n\n if (options.state) {\n const statePath = path.join(workspacePath, 'state.json');\n const newIndex = index + 1;\n const isDone = newIndex >= info.workflow.steps.length;\n\n const newState = {\n currentIndex: newIndex,\n status: isDone ? 'done' : 'running',\n updatedAt: new Date().toISOString(),\n };\n\n await fs.writeFile(statePath, JSON.stringify(newState, null, 2));\n console.log('');\n console.log(`✅ State updated: ${statePath}`);\n console.log(` Current index: ${newState.currentIndex}`);\n console.log(` Status: ${newState.status}`);\n\n if (isDone) {\n console.log('');\n console.log('🎉 Workflow completed!');\n } else {\n const nextStep = info.workflow.steps[newIndex];\n console.log(` Next step: ${nextStep.id}`);\n }\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n }\n );\n\nfunction getDefaultSummary(eventType: EventType, stepId: string): string {\n const summaries: Record<EventType, string> = {\n 'step.started': `开始执行步骤: ${stepId}`,\n 'step.done': `步骤完成: ${stepId}`,\n 'artifact.updated': '产物已更新',\n 'workflow.updated': '工作流已更新',\n 'verify.passed': '验证通过',\n 'verify.failed': '验证失败',\n 'accept.passed': '验收通过',\n 'accept.failed': '验收失败',\n 'issue.raised': '发现问题',\n 'handoff.sent': '已交接给下一步',\n };\n return summaries[eventType] || `事件: ${eventType}`;\n}\n","import { Command } from 'commander';\nimport path from 'path';\nimport os from 'os';\nimport {\n loadConfig,\n findConfigFile,\n initConfigFile,\n DEFAULT_CONFIG,\n} from '../../core/config.js';\n\nexport const configCommand = new Command('config')\n .description('查看或管理配置')\n .argument('[action]', '操作: show, init', 'show')\n .option('-g, --global', '操作全局配置')\n .option('--verbose', '显示详细信息')\n .action(async (action: string, options: { global: boolean; verbose: boolean }) => {\n try {\n if (action === 'show') {\n await showConfig(options);\n } else if (action === 'init') {\n await initConfig(options);\n } else if (action === 'list') {\n await listConfig(options);\n } else {\n console.error(`Unknown action: ${action}`);\n console.log('Available actions: show, init, list');\n process.exit(1);\n }\n } catch (error) {\n console.error(`Error: ${error}`);\n process.exit(1);\n }\n });\n\nasync function showConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n const targetPath = options.global ? os.homedir() : process.cwd();\n const config = await loadConfig(targetPath);\n\n if (options.verbose) {\n const configFile = await findConfigFile(targetPath);\n if (configFile) {\n console.log(`Config file: ${configFile}`);\n console.log('');\n } else {\n console.log('No config file found, using defaults');\n console.log('');\n }\n }\n\n console.log(JSON.stringify(config, null, 2));\n}\n\nasync function initConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n const targetPath = options.global ? os.homedir() : process.cwd();\n const configPath = await initConfigFile(targetPath, options.global);\n\n console.log(`✅ Created config file: ${configPath}`);\n console.log('');\n console.log('Default configuration:');\n console.log(JSON.stringify(DEFAULT_CONFIG, null, 2));\n}\n\nasync function listConfig(options: { global: boolean; verbose: boolean }): Promise<void> {\n console.log('Configuration options:');\n console.log('');\n console.log(' defaultWorkspace - 默认 workspace 路径');\n console.log(' events.enabled - 是否启用事件日志 (default: true)');\n console.log(' events.logStepStarted - 是否记录 step.started (default: true)');\n console.log(' events.logStepDone - 是否记录 step.done (default: true)');\n console.log(' clipboard.autoCopy - 是否自动复制 prompt (default: false)');\n console.log(' prompt.templatePath - 自定义 prompt 模板路径');\n console.log(' prompt.language - prompt 语言 (default: zh)');\n console.log(' validation.strict - 严格校验模式 (default: false)');\n console.log(' validation.warnOnShortContent - 内容过短时警告 (default: true)');\n console.log('');\n console.log('Config file locations (in order of priority):');\n console.log(' .agenthandoffrc');\n console.log(' .agenthandoffrc.json');\n console.log(' .agenthandoffrc.yaml');\n console.log(' package.json#agenthandoff');\n console.log(` ~/.agenthandoffrc (global)`);\n}\n","import fs from 'fs/promises';\nimport path from 'path';\nimport os from 'os';\n\nexport interface AgentHandoffConfig {\n defaultWorkspace?: string;\n events?: {\n enabled: boolean;\n logStepStarted: boolean;\n logStepDone: boolean;\n };\n clipboard?: {\n autoCopy: boolean;\n };\n prompt?: {\n templatePath?: string;\n language: 'zh' | 'en';\n };\n validation?: {\n strict: boolean;\n warnOnShortContent: boolean;\n };\n}\n\nexport const DEFAULT_CONFIG: AgentHandoffConfig = {\n events: {\n enabled: true,\n logStepStarted: true,\n logStepDone: true,\n },\n clipboard: {\n autoCopy: false,\n },\n prompt: {\n language: 'zh',\n },\n validation: {\n strict: false,\n warnOnShortContent: true,\n },\n};\n\nconst CONFIG_FILES = [\n '.agenthandoffrc',\n '.agenthandoffrc.json',\n '.agenthandoffrc.yaml',\n '.agenthandoffrc.yml',\n];\n\nconst configCache = new Map<string, AgentHandoffConfig>();\n\nexport async function findConfigFile(startPath: string): Promise<string | null> {\n let currentPath = path.resolve(startPath);\n const homePath = os.homedir();\n\n while (true) {\n for (const configFile of CONFIG_FILES) {\n const filePath = path.join(currentPath, configFile);\n try {\n await fs.access(filePath);\n return filePath;\n } catch {\n // File doesn't exist, continue\n }\n }\n\n const packageJsonPath = path.join(currentPath, 'package.json');\n try {\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n const pkg = JSON.parse(content);\n if (pkg.agenthandoff) {\n return packageJsonPath;\n }\n } catch {\n // File doesn't exist or invalid, continue\n }\n\n if (currentPath === homePath || currentPath === path.dirname(currentPath)) {\n break;\n }\n currentPath = path.dirname(currentPath);\n }\n\n return null;\n}\n\nexport async function loadConfigFile(filePath: string): Promise<Partial<AgentHandoffConfig>> {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const ext = path.extname(filePath);\n\n if (ext === '.yaml' || ext === '.yml') {\n return parseYaml(content);\n }\n\n if (filePath.endsWith('package.json')) {\n const pkg = JSON.parse(content);\n return pkg.agenthandoff || {};\n }\n\n return JSON.parse(content);\n } catch {\n return {};\n }\n}\n\nfunction parseYaml(content: string): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const lines = content.split('\\n');\n let currentObj: Record<string, unknown> = result;\n const stack: Array<{ obj: Record<string, unknown> }> = [];\n\n for (const line of lines) {\n if (!line.trim() || line.trim().startsWith('#')) {\n continue;\n }\n\n const indent = line.search(/\\S/);\n const trimmed = line.trim();\n\n if (trimmed.includes(':')) {\n const colonIndex = trimmed.indexOf(':');\n const key = trimmed.slice(0, colonIndex).trim();\n const value = trimmed.slice(colonIndex + 1).trim();\n\n if (value === '') {\n if (stack.length > 0) {\n const expectedIndent = stack.length * 2;\n if (indent < expectedIndent) {\n while (stack.length > 0 && indent < stack.length * 2) {\n stack.pop();\n }\n if (stack.length > 0) {\n currentObj = stack[stack.length - 1].obj as Record<string, unknown>;\n } else {\n currentObj = result;\n }\n }\n }\n\n const newObj: Record<string, unknown> = {};\n currentObj[key] = newObj;\n stack.push({ obj: currentObj });\n currentObj = newObj;\n } else {\n let parsedValue: unknown = value;\n if (value === 'true') parsedValue = true;\n else if (value === 'false') parsedValue = false;\n else if (value === 'null') parsedValue = null;\n else if (/^\\d+$/.test(value)) parsedValue = parseInt(value, 10);\n else if (/^\\d+\\.\\d+$/.test(value)) parsedValue = parseFloat(value);\n else if (value.startsWith('\"') && value.endsWith('\"')) {\n parsedValue = value.slice(1, -1);\n } else if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n parsedValue = value.slice(1, -1);\n }\n\n currentObj[key] = parsedValue;\n }\n }\n }\n\n return result;\n}\n\nexport function mergeConfig(\n base: AgentHandoffConfig,\n override: Partial<AgentHandoffConfig>\n): AgentHandoffConfig {\n const result: AgentHandoffConfig = JSON.parse(JSON.stringify(base));\n\n for (const key of Object.keys(override) as Array<keyof AgentHandoffConfig>) {\n const overrideValue = override[key];\n if (overrideValue === undefined) continue;\n\n if (\n typeof overrideValue === 'object' &&\n overrideValue !== null &&\n !Array.isArray(overrideValue)\n ) {\n const baseValue = result[key];\n if (\n typeof baseValue === 'object' &&\n baseValue !== null &&\n !Array.isArray(baseValue)\n ) {\n // Deep merge for nested objects\n (result as Record<string, unknown>)[key] = mergeConfig(\n baseValue as AgentHandoffConfig,\n overrideValue as Partial<AgentHandoffConfig>\n );\n } else {\n (result as Record<string, unknown>)[key] = overrideValue;\n }\n } else {\n (result as Record<string, unknown>)[key] = overrideValue;\n }\n }\n\n return result;\n}\n\nexport async function loadConfig(workspacePath?: string): Promise<AgentHandoffConfig> {\n const startPath = workspacePath ? path.resolve(workspacePath) : process.cwd();\n const cacheKey = startPath;\n\n if (configCache.has(cacheKey)) {\n return configCache.get(cacheKey)!;\n }\n\n let config = JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as AgentHandoffConfig;\n\n const globalConfigPath = path.join(os.homedir(), '.agenthandoffrc');\n try {\n await fs.access(globalConfigPath);\n const globalConfig = await loadConfigFile(globalConfigPath);\n config = mergeConfig(config, globalConfig);\n } catch {\n // Global config doesn't exist\n }\n\n const localConfigFile = await findConfigFile(startPath);\n if (localConfigFile) {\n const localConfig = await loadConfigFile(localConfigFile);\n config = mergeConfig(config, localConfig);\n }\n\n configCache.set(cacheKey, config);\n return config;\n}\n\nexport function clearConfigCache(): void {\n configCache.clear();\n}\n\nexport async function initConfigFile(targetPath: string, global = false): Promise<string> {\n const configPath = global\n ? path.join(os.homedir(), '.agenthandoffrc')\n : path.join(targetPath, '.agenthandoffrc');\n\n const content = JSON.stringify(DEFAULT_CONFIG, null, 2);\n await fs.writeFile(configPath, content, 'utf-8');\n\n return configPath;\n}\n"],"mappings":"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","names":["Command","Command","path","fs","path","fs","path","fs","Command","path","Command","path","fs","path","Command","path","Command","path","fs","path","fs","path","Command","path","Command","path","fs","Command","path","fs","Command","os","fs","path","path","fs","Command","os","require","Command"]}
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "agent-handoff",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "轻量级多 Agent 协作接力工具",
5
5
  "type": "module",
6
- "author": "",
6
+ "author": "helinjiang",
7
7
  "license": "MIT",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "https://github.com/your-org/agent-handoff.git"
10
+ "url": "https://github.com/helinjiang/agent-handoff.git"
11
11
  },
12
12
  "keywords": [
13
13
  "agent",
@@ -33,6 +33,7 @@
33
33
  "typecheck": "tsc --noEmit"
34
34
  },
35
35
  "dependencies": {
36
+ "clipboardy": "^5.3.1",
36
37
  "commander": "^12.0.0",
37
38
  "yaml": "^2.4.0"
38
39
  },