coding-agent-harness 1.0.7 → 1.1.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 +33 -0
- package/CONTRIBUTING.md +9 -5
- package/README.md +12 -2
- package/README.zh-CN.md +10 -2
- package/SKILL.md +14 -3
- package/dist/build-dist.mjs +32 -6
- package/dist/check-dist-observation.mjs +73 -28
- package/dist/check-harness.mjs +0 -1
- package/dist/check-import-graph.mjs +44 -27
- package/dist/check-lite-forbidden-surfaces.mjs +121 -0
- package/dist/check-no-ts-nocheck.mjs +88 -0
- package/dist/check-runtime-emit.mjs +10 -3
- package/dist/check-type-boundaries.mjs +67 -8
- package/dist/commands/dashboard-command.mjs +52 -14
- package/dist/commands/migration-command.mjs +18 -8
- package/dist/commands/module-command.mjs +142 -0
- package/dist/commands/preset-command.mjs +65 -4
- package/dist/commands/registry.mjs +483 -0
- package/dist/commands/task-command.mjs +111 -53
- package/dist/harness.mjs +6 -303
- package/dist/lib/capability-registry.mjs +229 -53
- package/dist/lib/check-module-parallel.mjs +1 -6
- package/dist/lib/check-profiles.mjs +39 -46
- package/dist/lib/check-task-contracts.mjs +6 -4
- package/dist/lib/command-registry.mjs +248 -0
- package/dist/lib/core-shared.mjs +78 -3
- package/dist/lib/dashboard-data.mjs +203 -22
- package/dist/lib/dashboard-workbench.mjs +245 -21
- package/dist/lib/dashboard-writer.mjs +4 -1
- package/dist/lib/git-status-summary.mjs +0 -1
- package/dist/lib/governance-index-generator.mjs +7 -5
- package/dist/lib/governance-sync.mjs +46 -121
- package/dist/lib/governance-table-boundary.mjs +1 -14
- package/dist/lib/harness-core.mjs +5 -1
- package/dist/lib/harness-paths.mjs +115 -1
- package/dist/lib/impact-classifier.mjs +420 -0
- package/dist/lib/lesson-maintenance.mjs +1 -2
- package/dist/lib/markdown-utils.mjs +50 -1
- package/dist/lib/migration-planner.mjs +31 -16
- package/dist/lib/migration-support.mjs +5 -4
- package/dist/lib/module-registry.mjs +296 -0
- package/dist/lib/preset-audit-contracts.mjs +24 -1
- package/dist/lib/preset-engine.mjs +68 -29
- package/dist/lib/preset-registry.mjs +374 -72
- package/dist/lib/preset-runner.mjs +560 -0
- package/dist/lib/review-confirm-git-gate.mjs +73 -19
- package/dist/lib/status-builder.mjs +23 -8
- package/dist/lib/structure-migration.mjs +6 -4
- package/dist/lib/subagent-authorization-audit.mjs +8 -2
- package/dist/lib/task-archive-eligibility.mjs +65 -0
- package/dist/lib/task-audit-metadata.mjs +25 -11
- package/dist/lib/task-audit-migration.mjs +21 -14
- package/dist/lib/task-discovery-contract.mjs +32 -0
- package/dist/lib/task-index.mjs +4 -2
- package/dist/lib/task-lesson-candidates.mjs +1 -2
- package/dist/lib/task-lesson-sedimentation.mjs +310 -9
- package/dist/lib/task-lifecycle/create-task-helpers.mjs +6 -3
- package/dist/lib/task-lifecycle/phase-sync.mjs +0 -1
- package/dist/lib/task-lifecycle/preset-interop.mjs +16 -0
- package/dist/lib/task-lifecycle/review-confirm.mjs +34 -2
- package/dist/lib/task-lifecycle/review-gates.mjs +12 -5
- package/dist/lib/task-lifecycle/review-submission.mjs +1 -2
- package/dist/lib/task-lifecycle/scaffold-provenance.mjs +0 -1
- package/dist/lib/task-lifecycle/template-files.mjs +2 -5
- package/dist/lib/task-lifecycle.mjs +117 -159
- package/dist/lib/task-metadata.mjs +10 -5
- package/dist/lib/task-preset-contract-drift.mjs +45 -0
- package/dist/lib/task-repository.mjs +192 -0
- package/dist/lib/task-review-model.mjs +38 -17
- package/dist/lib/task-scanner.mjs +75 -23
- package/dist/lib/task-template-materials.mjs +131 -0
- package/dist/lib/task-tombstone-commands.mjs +187 -18
- package/dist/lib/types/check-profiles.js +1 -0
- package/dist/lib/types/impact.js +1 -0
- package/dist/lib/types/preset.js +1 -0
- package/dist/lib/types/task-lifecycle.js +1 -0
- package/dist/lib/types/task-scanner.js +1 -0
- package/dist/postinstall.mjs +2 -2
- package/dist/run-built-tests.mjs +10 -3
- package/docs-release/README.md +2 -1
- package/docs-release/architecture/document-contract-kernel/README.md +150 -0
- package/docs-release/architecture/document-contract-kernel/products/full-skill-overlay.md +29 -0
- package/docs-release/architecture/document-contract-kernel/products/lite-forbidden-surfaces.txt +26 -0
- package/docs-release/architecture/document-contract-kernel/products/lite-skill-overlay.md +37 -0
- package/docs-release/architecture/overview.md +2 -2
- package/docs-release/architecture/overview.zh-CN.md +2 -2
- package/docs-release/architecture/system-explainer/01-system-overview.md +11 -7
- package/docs-release/architecture/system-explainer/02-module-dependency.md +4 -4
- package/docs-release/architecture/system-explainer/03-task-lifecycle.md +17 -12
- package/docs-release/architecture/system-explainer/05-data-flow.md +6 -6
- package/docs-release/architecture/system-explainer/06-preset-and-migration.md +2 -2
- package/docs-release/architecture/system-explainer/README.md +1 -1
- package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +12 -8
- package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +5 -5
- package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +19 -11
- package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +5 -5
- package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +2 -2
- package/docs-release/architecture/system-explainer/en-US/README.md +1 -1
- package/docs-release/guides/agent-installation.en-US.md +4 -6
- package/docs-release/guides/agent-installation.md +11 -8
- package/docs-release/guides/contributing.md +10 -3
- package/docs-release/guides/contributing.zh-CN.md +10 -3
- package/docs-release/guides/legacy-migration-agent-prompt.md +1 -1
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +1 -1
- package/docs-release/guides/migration-playbook.en-US.md +9 -6
- package/docs-release/guides/migration-playbook.md +9 -6
- package/docs-release/guides/preset-development.md +68 -2
- package/docs-release/guides/task-state-machine.en-US.md +8 -8
- package/docs-release/guides/task-state-machine.md +7 -7
- package/docs-release/guides/typescript-runtime-migration-closeout.md +17 -13
- package/package.json +19 -11
- package/postinstall.mjs +37 -0
- package/presets/legacy-migration/preset.yaml +5 -5
- package/presets/legacy-migration/templates/execution_strategy.append.md +1 -1
- package/presets/lesson-sedimentation/preset.yaml +3 -3
- package/presets/module/preset.yaml +2 -2
- package/presets/module/templates/execution_strategy.append.md +1 -1
- package/presets/module/templates/task_plan.append.md +3 -3
- package/presets/release-closeout/checks/check-release-package.mjs +29 -0
- package/presets/release-closeout/preset.yaml +100 -0
- package/presets/release-closeout/scripts/generate-release-package.mjs +572 -0
- package/presets/release-closeout/templates/execution_strategy.append.md +7 -0
- package/presets/release-closeout/templates/findings.seed.md +5 -0
- package/presets/release-closeout/templates/review.seed.md +3 -0
- package/presets/release-closeout/templates/task_plan.append.md +24 -0
- package/presets/standard-task/preset.yaml +2 -2
- package/references/agents-md-pattern.md +23 -17
- package/references/lessons-governance.md +2 -2
- package/references/module-parallel-standard.md +3 -6
- package/references/pull-request-standard.md +2 -2
- package/references/ssot-governance.md +2 -2
- package/references/taskr-gap-analysis.md +3 -3
- package/run-dist.mjs +34 -0
- package/skills/preset-creator/SKILL.md +40 -8
- package/skills/preset-creator/references/complex-task-skeleton/brief.md +32 -8
- package/skills/preset-creator/references/preset-package-skeleton.md +15 -5
- package/skills/preset-creator/references/structure-aware-paths.md +112 -0
- package/templates/AGENTS.md.template +28 -26
- package/templates/architecture/README.md +2 -2
- package/templates/architecture/service-catalog.md +2 -2
- package/templates/architecture/services/service-template.md +1 -1
- package/templates/dashboard/assets/app-src/00-state.js +5 -1
- package/templates/dashboard/assets/app-src/10-router.js +7 -0
- package/templates/dashboard/assets/app-src/20-overview.js +8 -8
- package/templates/dashboard/assets/app-src/30-tasks.js +132 -40
- package/templates/dashboard/assets/app-src/32-task-swimlane.js +314 -0
- package/templates/dashboard/assets/app-src/35-task-detail.js +35 -5
- package/templates/dashboard/assets/app-src/40-modules.js +257 -41
- package/templates/dashboard/assets/app-src/45-review.js +127 -1
- package/templates/dashboard/assets/app-src/90-bindings.js +185 -2
- package/templates/dashboard/assets/app.css +928 -53
- package/templates/dashboard/assets/app.css.manifest.json +2 -0
- package/templates/dashboard/assets/app.js +1071 -98
- package/templates/dashboard/assets/app.manifest.json +1 -0
- package/templates/dashboard/assets/css-src/00-foundation.css +12 -6
- package/templates/dashboard/assets/css-src/10-panels-flow.css +2 -2
- package/templates/dashboard/assets/css-src/30-task-index.css +21 -13
- package/templates/dashboard/assets/css-src/31-archive.css +94 -0
- package/templates/dashboard/assets/css-src/32-task-swimlane.css +487 -0
- package/templates/dashboard/assets/css-src/35-review-workspace.css +78 -0
- package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +191 -14
- package/templates/dashboard/assets/css-src/50-responsive-overrides.css +23 -0
- package/templates/dashboard/assets/i18n.js +166 -2
- package/templates/development/README.md +9 -9
- package/templates/development/cross-repo-debugging.md +3 -3
- package/templates/development/external-context/service-template.md +1 -1
- package/templates/development/external-source-packs/README.md +2 -2
- package/templates/integrations/README.md +4 -4
- package/templates/integrations/api-contract.md +1 -1
- package/templates/integrations/event-contract.md +1 -1
- package/templates/integrations/third-party/vendor-template.md +1 -1
- package/templates/integrations/webhook-contract.md +1 -1
- package/templates/ledger/Harness-Ledger.md +1 -1
- package/templates/modules/module_brief.md +50 -0
- package/templates/modules/module_plan.md +49 -0
- package/templates/modules/registry_view.md +9 -0
- package/templates/modules/session_prompt_pack.md +55 -0
- package/templates/planning/brief.md +32 -8
- package/templates/planning/module_brief.md +28 -3
- package/templates/planning/module_plan.md +26 -11
- package/templates/planning/module_session_prompt.md +11 -2
- package/templates/planning/optional/slices/_slice-template/brief.md +28 -0
- package/templates/planning/review.md +1 -1
- package/templates/planning/visual_map.md +1 -1
- package/templates/reference/docs-library-standard.md +7 -7
- package/templates/reference/execution-workflow-standard.md +13 -0
- package/templates/reference/external-source-intake-standard.md +10 -10
- package/templates/reference/pull-request-standard.md +2 -2
- package/templates/reference/repo-governance-standard.md +1 -1
- package/templates/reference/review-routing-standard.md +4 -0
- package/templates/ssot/Module-Registry.md +4 -38
- package/templates/walkthrough/walkthrough-template.md +1 -1
- package/templates-zh-CN/AGENTS.md.template +27 -25
- package/templates-zh-CN/CLAUDE.md.template +1 -1
- package/templates-zh-CN/architecture/README.md +2 -2
- package/templates-zh-CN/architecture/service-catalog.md +2 -2
- package/templates-zh-CN/architecture/services/service-template.md +1 -1
- package/templates-zh-CN/development/README.md +9 -9
- package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
- package/templates-zh-CN/development/external-context/service-template.md +1 -1
- package/templates-zh-CN/development/external-source-packs/README.md +2 -2
- package/templates-zh-CN/integrations/README.md +4 -4
- package/templates-zh-CN/integrations/api-contract.md +1 -1
- package/templates-zh-CN/integrations/event-contract.md +1 -1
- package/templates-zh-CN/integrations/third-party/vendor-template.md +1 -1
- package/templates-zh-CN/integrations/webhook-contract.md +1 -1
- package/templates-zh-CN/ledger/Harness-Ledger.md +1 -1
- package/templates-zh-CN/lessons/lesson-arch-process-change.md +1 -1
- package/templates-zh-CN/lessons/lesson-new-doc.md +3 -3
- package/templates-zh-CN/lessons/lesson-ref-change.md +4 -4
- package/templates-zh-CN/modules/module_brief.md +47 -0
- package/templates-zh-CN/modules/module_plan.md +48 -0
- package/templates-zh-CN/modules/registry_view.md +9 -0
- package/templates-zh-CN/modules/session_prompt_pack.md +50 -0
- package/templates-zh-CN/planning/INDEX.md +1 -0
- package/templates-zh-CN/planning/brief.md +26 -7
- package/templates-zh-CN/planning/module_brief.md +24 -2
- package/templates-zh-CN/planning/module_plan.md +35 -29
- package/templates-zh-CN/planning/module_session_prompt.md +15 -11
- package/templates-zh-CN/planning/optional/slices/_slice-template/brief.md +28 -11
- package/templates-zh-CN/planning/review.md +1 -1
- package/templates-zh-CN/reference/adversarial-review-standard.md +1 -1
- package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
- package/templates-zh-CN/reference/docs-library-standard.md +27 -27
- package/templates-zh-CN/reference/execution-workflow-standard.md +12 -2
- package/templates-zh-CN/reference/external-source-intake-standard.md +10 -10
- package/templates-zh-CN/reference/harness-ledger-standard.md +3 -3
- package/templates-zh-CN/reference/pull-request-standard.md +1 -1
- package/templates-zh-CN/reference/regression-ssot-governance.md +2 -2
- package/templates-zh-CN/reference/repo-governance-standard.md +1 -1
- package/templates-zh-CN/reference/review-routing-standard.md +3 -0
- package/templates-zh-CN/reference/walkthrough-standard.md +2 -2
- package/templates-zh-CN/reference/worktree-standard.md +1 -1
- package/templates-zh-CN/regression/Cadence-Ledger.md +2 -2
- package/templates-zh-CN/ssot/Delivery-SSoT.md +2 -2
- package/templates-zh-CN/ssot/Module-Registry.md +5 -44
- package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
- package/templates-zh-CN/walkthrough/walkthrough-template.md +4 -4
|
@@ -1,21 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
import { createTask, readPresetPackage, buildTaskIndex, createLessonSedimentationTask, archiveTask, deleteTask, listLifecycleTasks, promoteLessonCandidate, reopenTask, supersedeTask, updateModuleStep, updateTaskPhase, updateTaskLifecycle, } from "../lib/harness-core.mjs";
|
|
2
|
+
import { takeRepeatedOptionsFromArgs } from "../lib/command-registry.mjs";
|
|
3
3
|
export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg }) {
|
|
4
4
|
if (command === "new-task") {
|
|
5
5
|
const dryRun = takeFlag("--dry-run");
|
|
6
6
|
const locale = takeOption("--locale", "");
|
|
7
7
|
const title = takeOption("--title", "");
|
|
8
8
|
const moduleKey = takeOption("--module", "");
|
|
9
|
+
const registerModule = takeFlag("--register-module");
|
|
10
|
+
const moduleRegistration = {
|
|
11
|
+
title: takeOption("--module-title", ""),
|
|
12
|
+
prefix: takeOption("--module-prefix", ""),
|
|
13
|
+
status: takeOption("--module-status", "planned"),
|
|
14
|
+
branch: takeOption("--module-branch", ""),
|
|
15
|
+
owner: takeOption("--module-owner", "coordinator"),
|
|
16
|
+
currentStep: takeOption("--module-current-step", ""),
|
|
17
|
+
locale,
|
|
18
|
+
scope: takeRepeatedOptionsFromArgs(args, "--module-scope"),
|
|
19
|
+
shared: takeRepeatedOptionsFromArgs(args, "--module-shared"),
|
|
20
|
+
dependsOn: takeRepeatedOptionsFromArgs(args, "--module-depends-on"),
|
|
21
|
+
};
|
|
9
22
|
const budget = takeOption("--budget", "standard");
|
|
10
23
|
const preset = takeOption("--preset", "");
|
|
11
24
|
const fromSession = takeOption("--from-session", "");
|
|
12
25
|
const longRunning = takeFlag("--long-running");
|
|
13
26
|
try {
|
|
14
27
|
const parsed = parseNewTaskArgs(args, { preset, fromSession });
|
|
15
|
-
|
|
28
|
+
const createOptions = { title, locale, dryRun, moduleKey, budget, longRunning, preset, fromSession, presetArgs: parsed.presetArgs, automaticTaskId: parsed.automaticTaskId, registerModule, moduleRegistration };
|
|
29
|
+
console.log(JSON.stringify(invokeCreateTask(parsed.target, parsed.taskId, createOptions), null, 2));
|
|
16
30
|
}
|
|
17
31
|
catch (error) {
|
|
18
|
-
console.error(error
|
|
32
|
+
console.error(errorMessage(error));
|
|
19
33
|
process.exit(1);
|
|
20
34
|
}
|
|
21
35
|
return;
|
|
@@ -34,7 +48,7 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
34
48
|
console.log(JSON.stringify(updateTaskPhase(targetArg(), taskId, phaseId, { state, completion, evidenceStatus }), null, 2));
|
|
35
49
|
}
|
|
36
50
|
catch (error) {
|
|
37
|
-
console.error(error
|
|
51
|
+
console.error(errorMessage(error));
|
|
38
52
|
process.exit(1);
|
|
39
53
|
}
|
|
40
54
|
return;
|
|
@@ -47,37 +61,19 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
47
61
|
console.error("Missing task id");
|
|
48
62
|
process.exit(2);
|
|
49
63
|
}
|
|
50
|
-
const
|
|
64
|
+
const lifecycleByCommand = {
|
|
51
65
|
"task-start": { event: "task-start", state: "in_progress" },
|
|
52
66
|
"task-log": { event: "task-log", state: "" },
|
|
53
67
|
"task-block": { event: "task-block", state: "blocked" },
|
|
54
68
|
"task-review": { event: "task-review", state: "review" },
|
|
55
69
|
"task-complete": { event: "task-complete", state: "done" },
|
|
56
|
-
}
|
|
70
|
+
};
|
|
71
|
+
const lifecycle = lifecycleByCommand[command];
|
|
57
72
|
try {
|
|
58
73
|
console.log(JSON.stringify(updateTaskLifecycle(targetArg(), taskId, { ...lifecycle, message, evidence }), null, 2));
|
|
59
74
|
}
|
|
60
75
|
catch (error) {
|
|
61
|
-
console.error(error
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (command === "review-confirm") {
|
|
67
|
-
const reviewer = takeOption("--reviewer", "Human Reviewer");
|
|
68
|
-
const message = takeOption("--message", "");
|
|
69
|
-
const evidence = takeOption("--evidence", "");
|
|
70
|
-
const confirmText = takeOption("--confirm", "");
|
|
71
|
-
const taskId = args.shift();
|
|
72
|
-
if (!taskId) {
|
|
73
|
-
console.error("Missing task id");
|
|
74
|
-
process.exit(2);
|
|
75
|
-
}
|
|
76
|
-
try {
|
|
77
|
-
console.log(JSON.stringify(confirmTaskReview(targetArg(), taskId, { reviewer, message, evidence, confirmText }), null, 2));
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
console.error(formatTaskCommandError(error));
|
|
76
|
+
console.error(errorMessage(error));
|
|
81
77
|
process.exit(1);
|
|
82
78
|
}
|
|
83
79
|
return;
|
|
@@ -95,7 +91,7 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
95
91
|
console.log(JSON.stringify(promoteLessonCandidate(targetArg(), taskId, candidateId, { dryRun, apply }), null, 2));
|
|
96
92
|
}
|
|
97
93
|
catch (error) {
|
|
98
|
-
console.error(error
|
|
94
|
+
console.error(errorMessage(error));
|
|
99
95
|
process.exit(1);
|
|
100
96
|
}
|
|
101
97
|
return;
|
|
@@ -113,7 +109,7 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
113
109
|
console.log(JSON.stringify(createLessonSedimentationTask(targetArg(), taskId, candidateId, { dryRun, title }), null, 2));
|
|
114
110
|
}
|
|
115
111
|
catch (error) {
|
|
116
|
-
console.error(error
|
|
112
|
+
console.error(errorMessage(error));
|
|
117
113
|
process.exit(1);
|
|
118
114
|
}
|
|
119
115
|
return;
|
|
@@ -128,7 +124,8 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
128
124
|
const lesson = takeOption("--lesson", "");
|
|
129
125
|
const search = takeOption("--search", "");
|
|
130
126
|
const missingMaterials = takeFlag("--missing-materials");
|
|
131
|
-
const
|
|
127
|
+
const includeArchived = takeFlag("--include-archived");
|
|
128
|
+
const result = listLifecycleTasks(targetArg(), { state, moduleKey, queue, preset, review, lesson, search, missingMaterials, includeArchived });
|
|
132
129
|
if (json) {
|
|
133
130
|
console.log(JSON.stringify(result, null, 2));
|
|
134
131
|
}
|
|
@@ -151,40 +148,49 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
151
148
|
if (command === "task-supersede") {
|
|
152
149
|
const by = takeOption("--by", "");
|
|
153
150
|
const reason = takeOption("--reason", "");
|
|
151
|
+
const deletedBy = takeOption("--deleted-by", "");
|
|
152
|
+
const confirm = takeOption("--confirm", "");
|
|
153
|
+
const allowOpenFindings = takeFlag("--allow-open-findings");
|
|
154
154
|
const taskId = args.shift();
|
|
155
155
|
if (!taskId) {
|
|
156
156
|
console.error("Missing task id");
|
|
157
157
|
process.exit(2);
|
|
158
158
|
}
|
|
159
159
|
try {
|
|
160
|
-
console.log(JSON.stringify(supersedeTask(targetArg(), taskId, { by, reason }), null, 2));
|
|
160
|
+
console.log(JSON.stringify(supersedeTask(targetArg(), taskId, { by, reason, deletedBy, confirm, allowOpenFindings }), null, 2));
|
|
161
161
|
}
|
|
162
162
|
catch (error) {
|
|
163
|
-
console.error(error
|
|
163
|
+
console.error(errorMessage(error));
|
|
164
164
|
process.exit(1);
|
|
165
165
|
}
|
|
166
166
|
return;
|
|
167
167
|
}
|
|
168
168
|
if (["task-delete", "task-archive", "task-reopen"].includes(command)) {
|
|
169
169
|
const soft = takeFlag("--soft");
|
|
170
|
+
const hard = takeFlag("--hard");
|
|
170
171
|
const reason = takeOption("--reason", "");
|
|
172
|
+
const deletedBy = command === "task-delete" ? takeOption("--deleted-by", "") : "";
|
|
173
|
+
const confirm = command === "task-delete" ? takeOption("--confirm", "") : "";
|
|
174
|
+
const allowOpenFindings = command === "task-delete" ? takeFlag("--allow-open-findings") : false;
|
|
175
|
+
const archivedBy = command === "task-archive" ? takeOption("--archived-by", "") : "";
|
|
176
|
+
const archiveFields = command === "task-archive" ? takeRepeatedKeyValueOptions(args, "--archive-field") : {};
|
|
171
177
|
const taskId = args.shift();
|
|
172
178
|
if (!taskId) {
|
|
173
179
|
console.error("Missing task id");
|
|
174
180
|
process.exit(2);
|
|
175
181
|
}
|
|
176
182
|
try {
|
|
177
|
-
if (command === "task-delete" &&
|
|
178
|
-
throw new Error("task-delete only
|
|
183
|
+
if (command === "task-delete" && soft && hard)
|
|
184
|
+
throw new Error("task-delete accepts only one of --soft or --hard");
|
|
179
185
|
const result = command === "task-delete"
|
|
180
|
-
?
|
|
186
|
+
? deleteTask(targetArg(), taskId, { hard, reason, deletedBy, confirm, allowOpenFindings })
|
|
181
187
|
: command === "task-archive"
|
|
182
|
-
? archiveTask(targetArg(), taskId, { reason })
|
|
188
|
+
? archiveTask(targetArg(), taskId, { reason, archivedBy, archiveFields })
|
|
183
189
|
: reopenTask(targetArg(), taskId, { reason });
|
|
184
190
|
console.log(JSON.stringify(result, null, 2));
|
|
185
191
|
}
|
|
186
192
|
catch (error) {
|
|
187
|
-
console.error(error
|
|
193
|
+
console.error(errorMessage(error));
|
|
188
194
|
process.exit(1);
|
|
189
195
|
}
|
|
190
196
|
return;
|
|
@@ -201,14 +207,15 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
201
207
|
console.log(JSON.stringify(updateModuleStep(targetArg(), moduleKey, stepId, { state }), null, 2));
|
|
202
208
|
}
|
|
203
209
|
catch (error) {
|
|
204
|
-
console.error(error
|
|
210
|
+
console.error(errorMessage(error));
|
|
205
211
|
process.exit(1);
|
|
206
212
|
}
|
|
207
213
|
return;
|
|
208
214
|
}
|
|
209
215
|
throw new Error(`Unsupported task command: ${command}`);
|
|
210
216
|
}
|
|
211
|
-
function parseNewTaskArgs(args, { preset = "" } = {}) {
|
|
217
|
+
function parseNewTaskArgs(args, { preset = "", fromSession = "" } = {}) {
|
|
218
|
+
void fromSession;
|
|
212
219
|
const values = [...args];
|
|
213
220
|
const presetPackage = preset ? readPresetPackageForNewTask(preset, values) : null;
|
|
214
221
|
const parsed = splitPresetArgsAndPositionals(values, presetPackage);
|
|
@@ -220,6 +227,9 @@ function parseNewTaskArgs(args, { preset = "" } = {}) {
|
|
|
220
227
|
presetArgs: parsed.presetArgs,
|
|
221
228
|
};
|
|
222
229
|
}
|
|
230
|
+
function invokeCreateTask(target, taskId, options) {
|
|
231
|
+
return Reflect.apply(createTask, undefined, [target, taskId, options]);
|
|
232
|
+
}
|
|
223
233
|
function readPresetPackageForNewTask(preset, values) {
|
|
224
234
|
const candidates = presetDiscoveryTargetCandidates(values);
|
|
225
235
|
let fallbackPackage = null;
|
|
@@ -300,25 +310,73 @@ function resolveNewTaskPositionals(positionals) {
|
|
|
300
310
|
throw new Error(`Too many positional arguments for new-task: ${positionals.join(", ")}`);
|
|
301
311
|
}
|
|
302
312
|
function formatTaskCommandError(error) {
|
|
303
|
-
const
|
|
304
|
-
|
|
313
|
+
const recovery = readArrayProperty(error, "recovery");
|
|
314
|
+
const details = readRecordProperty(error, "details");
|
|
315
|
+
const lines = [errorMessage(error)];
|
|
316
|
+
if (recovery.length > 0) {
|
|
305
317
|
lines.push("", "Recovery:");
|
|
306
|
-
for (const item of
|
|
307
|
-
lines.push(`- ${item}`);
|
|
318
|
+
for (const item of recovery)
|
|
319
|
+
lines.push(`- ${String(item)}`);
|
|
308
320
|
}
|
|
309
|
-
|
|
321
|
+
const entries = readArrayProperty(details, "entries");
|
|
322
|
+
if (entries.length) {
|
|
310
323
|
lines.push("", "Blocking Git status:");
|
|
311
|
-
for (const entry of
|
|
312
|
-
|
|
324
|
+
for (const entry of entries) {
|
|
325
|
+
const raw = readProperty(entry, "raw");
|
|
326
|
+
const entryPath = readProperty(entry, "path");
|
|
327
|
+
lines.push(`- ${String(raw || entryPath || "")}`);
|
|
328
|
+
}
|
|
313
329
|
}
|
|
314
|
-
|
|
330
|
+
const disallowed = readArrayProperty(details, "disallowed");
|
|
331
|
+
if (disallowed.length) {
|
|
315
332
|
lines.push("", "Disallowed paths:");
|
|
316
|
-
for (const item of
|
|
317
|
-
lines.push(`- ${item}`);
|
|
333
|
+
for (const item of disallowed)
|
|
334
|
+
lines.push(`- ${String(item)}`);
|
|
318
335
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (
|
|
322
|
-
lines.push("",
|
|
336
|
+
const stderr = readProperty(details, "stderr");
|
|
337
|
+
const stdout = readProperty(details, "stdout");
|
|
338
|
+
if (stderr)
|
|
339
|
+
lines.push("", String(stderr));
|
|
340
|
+
if (stdout)
|
|
341
|
+
lines.push("", String(stdout));
|
|
323
342
|
return lines.join("\n");
|
|
324
343
|
}
|
|
344
|
+
function takeRepeatedKeyValueOptions(args, flag) {
|
|
345
|
+
const fields = {};
|
|
346
|
+
for (let index = 0; index < args.length;) {
|
|
347
|
+
if (args[index] !== flag) {
|
|
348
|
+
index += 1;
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
const raw = args[index + 1] || "";
|
|
352
|
+
args.splice(index, 2);
|
|
353
|
+
const separator = raw.indexOf("=");
|
|
354
|
+
if (separator <= 0)
|
|
355
|
+
throw new Error(`${flag} requires key=value`);
|
|
356
|
+
const key = raw.slice(0, separator).trim();
|
|
357
|
+
const value = raw.slice(separator + 1).trim();
|
|
358
|
+
if (!key || /[\r\n|]/.test(key))
|
|
359
|
+
throw new Error(`${flag} has invalid field key: ${key || "<empty>"}`);
|
|
360
|
+
if (Object.prototype.hasOwnProperty.call(fields, key))
|
|
361
|
+
throw new Error(`${flag} duplicate field key: ${key}`);
|
|
362
|
+
fields[key] = value;
|
|
363
|
+
}
|
|
364
|
+
return fields;
|
|
365
|
+
}
|
|
366
|
+
function readArrayProperty(value, key) {
|
|
367
|
+
const property = readProperty(value, key);
|
|
368
|
+
return Array.isArray(property) ? property : [];
|
|
369
|
+
}
|
|
370
|
+
function readRecordProperty(value, key) {
|
|
371
|
+
const property = readProperty(value, key);
|
|
372
|
+
return isRecord(property) ? property : null;
|
|
373
|
+
}
|
|
374
|
+
function readProperty(value, key) {
|
|
375
|
+
return isRecord(value) ? value[key] : undefined;
|
|
376
|
+
}
|
|
377
|
+
function isRecord(value) {
|
|
378
|
+
return typeof value === "object" && value !== null;
|
|
379
|
+
}
|
|
380
|
+
function errorMessage(error) {
|
|
381
|
+
return error instanceof Error ? error.message : String(error);
|
|
382
|
+
}
|
package/dist/harness.mjs
CHANGED
|
@@ -1,304 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import { runDashboardCommand } from "./commands/dashboard-command.mjs";
|
|
9
|
-
import { runMigrationCommand } from "./commands/migration-command.mjs";
|
|
10
|
-
import { runPresetCommand } from "./commands/preset-command.mjs";
|
|
11
|
-
import { runTaskCommand } from "./commands/task-command.mjs";
|
|
12
|
-
const args = process.argv.slice(2);
|
|
13
|
-
const command = args.shift() || "help";
|
|
14
|
-
function takeFlag(name, fallback = false) {
|
|
15
|
-
const index = args.indexOf(name);
|
|
16
|
-
if (index < 0)
|
|
17
|
-
return fallback;
|
|
18
|
-
args.splice(index, 1);
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
function takeOption(name, fallback = "") {
|
|
22
|
-
const index = args.indexOf(name);
|
|
23
|
-
if (index < 0)
|
|
24
|
-
return fallback;
|
|
25
|
-
const value = args[index + 1] || fallback;
|
|
26
|
-
args.splice(index, 2);
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
async function resolveInitLocale(requestedLocale) {
|
|
30
|
-
if (requestedLocale)
|
|
31
|
-
return normalizeLocale(requestedLocale);
|
|
32
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
33
|
-
return "en-US";
|
|
34
|
-
const prompt = [
|
|
35
|
-
"Select harness language / 选择初始化语言:",
|
|
36
|
-
" 1. 中文 (zh-CN)",
|
|
37
|
-
" 2. English (en-US)",
|
|
38
|
-
"Language [1/2, default 2]: ",
|
|
39
|
-
].join("\n");
|
|
40
|
-
const reader = createInterface({ input: process.stdin, output: process.stdout });
|
|
41
|
-
try {
|
|
42
|
-
const answer = (await reader.question(prompt)).trim().toLowerCase();
|
|
43
|
-
if (["1", "zh", "zh-cn", "cn", "中文"].includes(answer))
|
|
44
|
-
return "zh-CN";
|
|
45
|
-
if (["2", "en", "en-us", "english", "英文", ""].includes(answer))
|
|
46
|
-
return "en-US";
|
|
47
|
-
console.error(`Unknown language selection: ${answer}. Falling back to en-US.`);
|
|
48
|
-
return "en-US";
|
|
49
|
-
}
|
|
50
|
-
finally {
|
|
51
|
-
reader.close();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
async function confirmUserInstall({ yes = false, dryRun = false, agent = "codex" } = {}) {
|
|
55
|
-
if (yes || dryRun)
|
|
56
|
-
return true;
|
|
57
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
58
|
-
return false;
|
|
59
|
-
const reader = createInterface({ input: process.stdin, output: process.stdout });
|
|
60
|
-
try {
|
|
61
|
-
const answer = (await reader.question(`Install Coding Agent Harness into user skill directory for ${agent}? [y/N] `)).trim().toLowerCase();
|
|
62
|
-
return ["y", "yes"].includes(answer);
|
|
63
|
-
}
|
|
64
|
-
finally {
|
|
65
|
-
reader.close();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function targetArg() {
|
|
69
|
-
return args[args.length - 1] && !args[args.length - 1].startsWith("-") ? args[args.length - 1] : ".";
|
|
70
|
-
}
|
|
71
|
-
function printHelp() {
|
|
72
|
-
console.log(`Coding Agent Harness
|
|
73
|
-
|
|
74
|
-
Usage:
|
|
75
|
-
harness check [--profile source-package|private-harness|target-project] [target]
|
|
76
|
-
harness status [--json] [--strict] [target]
|
|
77
|
-
harness dev [--no-open] [--out-dir folder] [--host 127.0.0.1] [--port n] [target]
|
|
78
|
-
harness dashboard [--out file.html] [--out-dir folder] [--workbench] [--host 127.0.0.1] [--port n] [target]
|
|
79
|
-
harness init [--dry-run] [--locale zh-CN|en-US] [--capabilities core,dashboard] [--add-npm-scripts] [target]
|
|
80
|
-
harness add-capability <name> [--dry-run] [--locale zh-CN|en-US] [target]
|
|
81
|
-
harness migrate-plan [--json] [--limit n] [target]
|
|
82
|
-
harness migrate-structure [--plan|--apply] [--force] [--json] [target]
|
|
83
|
-
harness migrate-task-audit-index [--plan] [--apply] [--json] [target]
|
|
84
|
-
harness migrate-run [--locale zh-CN|en-US] [--assume-locale] [--allow-dirty] [--plan-only] [--out-dir folder] [--session-dir folder] [target]
|
|
85
|
-
harness migrate-verify [--json] [--full-cutover] <session.json>
|
|
86
|
-
harness governance rebuild [--dry-run] [--archive] [--apply] [target]
|
|
87
|
-
harness preset list [--json] [target]
|
|
88
|
-
harness preset inspect <id> [--json] [target]
|
|
89
|
-
harness preset check <id> [--json] [target]
|
|
90
|
-
harness preset install <folder|zip|builtin-id> [--project] [--force] [--json] [target]
|
|
91
|
-
harness preset seed [--project] [--force] [--dry-run] [--json] [target]
|
|
92
|
-
harness preset uninstall <id> [--project] [--json] [target]
|
|
93
|
-
harness new-task [task-id] [--module key] [--budget simple|standard|complex] [--preset id] [--from-session session.json] [--long-running] [--title title] [--locale zh-CN|en-US] [--dry-run] [target]
|
|
94
|
-
harness task-start <task-id> [--message text] [target]
|
|
95
|
-
harness task-phase <task-id> <phase-id> [--state done] [--completion 100] [--evidence present] [target]
|
|
96
|
-
harness task-log <task-id> --message text [--evidence type:PATH:summary] [target]
|
|
97
|
-
harness task-block <task-id> [--message text] [target]
|
|
98
|
-
harness task-review <task-id> [--message text] [target]
|
|
99
|
-
harness review-confirm <task-id> --confirm task-id [--reviewer name] [--message text] [target]
|
|
100
|
-
harness lesson-promote <task-id> <candidate-id> [--dry-run|--apply] [target]
|
|
101
|
-
harness lesson-sediment <task-id> <candidate-id> [--dry-run] [--title title] [target]
|
|
102
|
-
harness task-complete <task-id> [--message text] [target]
|
|
103
|
-
harness task-list [--json] [--state state] [--module key] [--queue queue] [--preset id] [--review status] [--lesson status] [--missing-materials] [--search text] [target]
|
|
104
|
-
harness task-index [--json] [target]
|
|
105
|
-
harness task-supersede <old-task-id> --by <new-task-id> [--reason text] [target]
|
|
106
|
-
harness task-delete <task-id> --soft [--reason text] [target]
|
|
107
|
-
harness task-archive <task-id> [--reason text] [target]
|
|
108
|
-
harness task-reopen <task-id> [--reason text] [target]
|
|
109
|
-
harness module-step <module-key> <step-id> [--state done|in-progress|blocked] [target]
|
|
110
|
-
harness install-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir] [--dry-run] [--force] [--skip-presets] [--yes]
|
|
111
|
-
harness doctor-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir]
|
|
112
|
-
|
|
113
|
-
If init runs in an interactive terminal and --locale is omitted, it asks for a
|
|
114
|
-
language. Non-interactive init defaults to en-US.
|
|
115
|
-
|
|
116
|
-
Preset discovery:
|
|
117
|
-
Project presets live in <target>/.coding-agent-harness/presets/<preset-id>/.
|
|
118
|
-
User presets live in ~/.coding-agent-harness/presets/<preset-id>/.
|
|
119
|
-
Harness discovers project presets first when a target is supplied, then user
|
|
120
|
-
presets, then bundled package presets under presets/<preset-id>/.
|
|
121
|
-
"harness init" seeds bundled presets into the target project. "harness
|
|
122
|
-
install-user" and npm postinstall seed bundled presets into the user root.
|
|
123
|
-
Use "harness preset seed" to repair or re-run preset seeding.
|
|
124
|
-
Use "harness preset install" with a local preset folder, .zip archive, or
|
|
125
|
-
bundled preset id. Preset archives must contain preset.yaml at the archive
|
|
126
|
-
root or inside one top-level folder.
|
|
127
|
-
Use "harness preset list --json" to see available presets, their source,
|
|
128
|
-
purpose, compatible budgets, and manifest path. Use "harness preset inspect
|
|
129
|
-
<id> --json" for the full preset manifest summary.
|
|
130
|
-
`);
|
|
131
|
-
}
|
|
132
|
-
function exitWithReport(report) {
|
|
133
|
-
for (const warning of report.warnings || [])
|
|
134
|
-
console.log(`Warning: ${warning}`);
|
|
135
|
-
for (const failure of report.failures || [])
|
|
136
|
-
console.error(`Failure: ${failure}`);
|
|
137
|
-
process.exit((report.failures || []).length > 0 ? 1 : 0);
|
|
138
|
-
}
|
|
139
|
-
if (command === "help" || command === "--help" || command === "-h") {
|
|
140
|
-
printHelp();
|
|
141
|
-
}
|
|
142
|
-
else if (args[0] === "help" || args.includes("--help") || args.includes("-h")) {
|
|
143
|
-
printHelp();
|
|
144
|
-
}
|
|
145
|
-
else if (command === "check") {
|
|
146
|
-
const profile = takeOption("--profile", "target-project");
|
|
147
|
-
const strict = takeFlag("--strict");
|
|
148
|
-
const target = targetArg();
|
|
149
|
-
const failures = [];
|
|
150
|
-
const warnings = [];
|
|
151
|
-
if (profile === "source-package") {
|
|
152
|
-
for (const required of ["package.json", "dist/harness.mjs", "dist/check-harness.mjs", "templates/planning/task_plan.md"]) {
|
|
153
|
-
if (!fs.existsSync(path.resolve(target, required)))
|
|
154
|
-
failures.push(`missing source package file: ${required}`);
|
|
155
|
-
}
|
|
156
|
-
const boundary = validateSourcePackageBoundary(target);
|
|
157
|
-
failures.push(...boundary.failures);
|
|
158
|
-
warnings.push(...boundary.warnings);
|
|
159
|
-
}
|
|
160
|
-
const status = buildStatus(target, { skipLegacyCheck: profile === "source-package", strictLegacy: strict, strict, allowLegacyTarget: profile === "source-package" });
|
|
161
|
-
failures.push(...status.checkState.details.failures);
|
|
162
|
-
warnings.push(...status.checkState.details.warnings);
|
|
163
|
-
if (!["source-package", "private-harness", "target-project"].includes(profile))
|
|
164
|
-
failures.push(`unknown profile: ${profile}`);
|
|
165
|
-
if (failures.length === 0)
|
|
166
|
-
console.log(`Harness check passed (${profile}): ${path.resolve(target)}`);
|
|
167
|
-
exitWithReport({ failures: [...new Set(failures)], warnings: [...new Set(warnings)] });
|
|
168
|
-
}
|
|
169
|
-
else if (command === "status") {
|
|
170
|
-
const json = takeFlag("--json");
|
|
171
|
-
const strict = takeFlag("--strict");
|
|
172
|
-
const status = buildStatus(targetArg(), { strictLegacy: strict, strict });
|
|
173
|
-
if (json) {
|
|
174
|
-
console.log(JSON.stringify(status, null, 2));
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
console.log(`${status.project.name}: ${status.checkState.status} (${status.checkState.failures} failures, ${status.checkState.warnings} warnings)`);
|
|
178
|
-
console.log(`mode: ${status.mode}`);
|
|
179
|
-
console.log(`capabilities: ${status.capabilities.map((capability) => `${capability.name}:${capability.state}`).join(", ")}`);
|
|
180
|
-
console.log(`tasks: ${status.tasks.length}`);
|
|
181
|
-
}
|
|
182
|
-
process.exitCode = status.checkState.status === "fail" ? 1 : 0;
|
|
183
|
-
}
|
|
184
|
-
else if (command === "dev") {
|
|
185
|
-
const open = !takeFlag("--no-open");
|
|
186
|
-
const outDir = takeOption("--out-dir", "");
|
|
187
|
-
const host = takeOption("--host", "127.0.0.1");
|
|
188
|
-
const port = takeOption("--port", "0");
|
|
189
|
-
const localeOverride = takeOption("--locale", "");
|
|
190
|
-
const target = targetArg();
|
|
191
|
-
const usesDefaultOutDir = !outDir;
|
|
192
|
-
const dashboardOutDir = outDir || defaultDevOutDir(target);
|
|
193
|
-
const opts = { ...(localeOverride ? { localeOverride } : {}), recoverGeneratedDashboard: usesDefaultOutDir };
|
|
194
|
-
try {
|
|
195
|
-
await serveDashboardWorkbench(dashboardOutDir, target, { ...opts, host, port, autoRefresh: true, open, label: "harness dev" });
|
|
196
|
-
}
|
|
197
|
-
catch (error) {
|
|
198
|
-
console.error(error.message);
|
|
199
|
-
process.exit(1);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
else if (command === "dashboard") {
|
|
203
|
-
await runDashboardCommand({ takeFlag, takeOption, targetArg });
|
|
204
|
-
}
|
|
205
|
-
else if (command === "init") {
|
|
206
|
-
const dryRun = takeFlag("--dry-run");
|
|
207
|
-
const addNpmScripts = takeFlag("--add-npm-scripts");
|
|
208
|
-
const locale = await resolveInitLocale(takeOption("--locale", ""));
|
|
209
|
-
const capabilities = takeOption("--capabilities", "core").split(",").map((item) => item.trim()).filter(Boolean);
|
|
210
|
-
try {
|
|
211
|
-
const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale, addNpmScripts });
|
|
212
|
-
console.log(JSON.stringify({ dryRun, locale: result.locale, capabilities: result.capabilities, changes: result.changes, presetSeed: result.presetSeed, nextCommands: result.nextCommands, report: result.report }, null, 2));
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
console.error(error.message);
|
|
216
|
-
process.exit(1);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
else if (command === "add-capability") {
|
|
220
|
-
const dryRun = takeFlag("--dry-run");
|
|
221
|
-
const locale = normalizeLocale(takeOption("--locale", ""));
|
|
222
|
-
const capability = args.shift();
|
|
223
|
-
if (!capability) {
|
|
224
|
-
console.error("Missing capability name");
|
|
225
|
-
process.exit(2);
|
|
226
|
-
}
|
|
227
|
-
try {
|
|
228
|
-
const result = addCapability(targetArg(), capability, { dryRun, locale });
|
|
229
|
-
console.log(JSON.stringify({ dryRun, registry: result.registry, changes: result.changes, report: result.report }, null, 2));
|
|
230
|
-
}
|
|
231
|
-
catch (error) {
|
|
232
|
-
console.error(error.message);
|
|
233
|
-
process.exit(1);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
else if (["migrate-plan", "migrate-structure", "migrate-run", "migrate-verify", "migrate-task-audit-index"].includes(command)) {
|
|
237
|
-
runMigrationCommand(command, { args, takeFlag, takeOption, targetArg });
|
|
238
|
-
}
|
|
239
|
-
else if (command === "governance") {
|
|
240
|
-
const subcommand = args.shift() || "";
|
|
241
|
-
if (subcommand !== "rebuild") {
|
|
242
|
-
console.error(`Unknown governance subcommand: ${subcommand || "(missing)"}`);
|
|
243
|
-
process.exit(2);
|
|
244
|
-
}
|
|
245
|
-
const dryRun = takeFlag("--dry-run");
|
|
246
|
-
const archive = takeFlag("--archive");
|
|
247
|
-
const apply = takeFlag("--apply");
|
|
248
|
-
try {
|
|
249
|
-
console.log(JSON.stringify(rebuildGovernanceIndexes(targetArg(), { dryRun, archive, apply }), null, 2));
|
|
250
|
-
}
|
|
251
|
-
catch (error) {
|
|
252
|
-
console.error(error.message);
|
|
253
|
-
process.exit(1);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
else if (command === "preset") {
|
|
257
|
-
runPresetCommand({ args, takeFlag, targetArg });
|
|
258
|
-
}
|
|
259
|
-
else if (["new-task", "task-phase", "task-start", "task-log", "task-block", "task-review", "task-complete", "review-confirm", "lesson-promote", "lesson-sediment", "task-list", "task-index", "task-supersede", "task-delete", "task-archive", "task-reopen", "module-step"].includes(command)) {
|
|
260
|
-
runTaskCommand(command, { args, takeFlag, takeOption, targetArg });
|
|
261
|
-
}
|
|
262
|
-
else if (command === "install-user") {
|
|
263
|
-
const dryRun = takeFlag("--dry-run");
|
|
264
|
-
const force = takeFlag("--force");
|
|
265
|
-
const yes = takeFlag("--yes") || takeFlag("-y");
|
|
266
|
-
const skipPresets = takeFlag("--skip-presets");
|
|
267
|
-
takeFlag("--global");
|
|
268
|
-
const agent = takeOption("--agent", "codex");
|
|
269
|
-
const home = takeOption("--home", "");
|
|
270
|
-
if (!(await confirmUserInstall({ yes, dryRun, agent }))) {
|
|
271
|
-
console.error("Refusing to write user skill files without confirmation. Re-run with --yes or --dry-run.");
|
|
272
|
-
process.exit(2);
|
|
273
|
-
}
|
|
274
|
-
try {
|
|
275
|
-
console.log(JSON.stringify(installUserSkill({ agent, home, dryRun, force, seedPresets: !skipPresets }), null, 2));
|
|
276
|
-
}
|
|
277
|
-
catch (error) {
|
|
278
|
-
console.error(error.message);
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
else if (command === "doctor-user") {
|
|
283
|
-
const agent = takeOption("--agent", "codex");
|
|
284
|
-
const home = takeOption("--home", "");
|
|
285
|
-
try {
|
|
286
|
-
const report = doctorUserSkill({ agent, home });
|
|
287
|
-
console.log(JSON.stringify(report, null, 2));
|
|
288
|
-
process.exit(report.status === "pass" ? 0 : 1);
|
|
289
|
-
}
|
|
290
|
-
catch (error) {
|
|
291
|
-
console.error(error.message);
|
|
292
|
-
process.exit(1);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
printHelp();
|
|
297
|
-
process.exit(2);
|
|
298
|
-
}
|
|
299
|
-
function defaultDevOutDir(targetInput) {
|
|
300
|
-
const target = path.resolve(targetInput || ".");
|
|
301
|
-
const name = path.basename(target) || "project";
|
|
302
|
-
const hash = Buffer.from(target).toString("hex").slice(0, 16);
|
|
303
|
-
return path.join(os.tmpdir(), "coding-agent-harness-dev", `${name}-${hash}`);
|
|
304
|
-
}
|
|
2
|
+
import { commandRegistry } from "./commands/registry.mjs";
|
|
3
|
+
import { dispatchCommand } from "./lib/command-registry.mjs";
|
|
4
|
+
await Promise.resolve(dispatchCommand(commandRegistry, process.argv.slice(2))).catch((error) => {
|
|
5
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
6
|
+
process.exit(1);
|
|
7
|
+
});
|