coding-agent-harness 1.0.8 → 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 +10 -0
- package/CONTRIBUTING.md +8 -4
- package/README.md +12 -2
- package/README.zh-CN.md +10 -2
- package/SKILL.md +14 -3
- package/dist/build-dist.mjs +19 -6
- package/dist/check-dist-observation.mjs +57 -29
- 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 +7 -7
- package/dist/check-runtime-emit.mjs +10 -3
- package/dist/check-type-boundaries.mjs +51 -9
- 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 +51 -12
- package/dist/commands/registry.mjs +483 -0
- package/dist/commands/task-command.mjs +109 -52
- package/dist/harness.mjs +6 -304
- 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 +4 -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 +67 -29
- package/dist/lib/preset-registry.mjs +361 -71
- package/dist/lib/preset-runner.mjs +292 -26
- 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 +3 -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 +116 -160
- 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 +36 -17
- package/dist/lib/task-scanner.mjs +74 -23
- package/dist/lib/task-template-materials.mjs +131 -0
- package/dist/lib/task-tombstone-commands.mjs +186 -29
- 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 +1 -0
- 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 +16 -12
- 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 +6 -1
- package/presets/release-closeout/preset.yaml +9 -9
- package/presets/release-closeout/scripts/generate-release-package.mjs +387 -25
- package/presets/release-closeout/templates/task_plan.append.md +5 -5
- 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/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/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/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;
|
|
@@ -152,40 +148,49 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
152
148
|
if (command === "task-supersede") {
|
|
153
149
|
const by = takeOption("--by", "");
|
|
154
150
|
const reason = takeOption("--reason", "");
|
|
151
|
+
const deletedBy = takeOption("--deleted-by", "");
|
|
152
|
+
const confirm = takeOption("--confirm", "");
|
|
153
|
+
const allowOpenFindings = takeFlag("--allow-open-findings");
|
|
155
154
|
const taskId = args.shift();
|
|
156
155
|
if (!taskId) {
|
|
157
156
|
console.error("Missing task id");
|
|
158
157
|
process.exit(2);
|
|
159
158
|
}
|
|
160
159
|
try {
|
|
161
|
-
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));
|
|
162
161
|
}
|
|
163
162
|
catch (error) {
|
|
164
|
-
console.error(error
|
|
163
|
+
console.error(errorMessage(error));
|
|
165
164
|
process.exit(1);
|
|
166
165
|
}
|
|
167
166
|
return;
|
|
168
167
|
}
|
|
169
168
|
if (["task-delete", "task-archive", "task-reopen"].includes(command)) {
|
|
170
169
|
const soft = takeFlag("--soft");
|
|
170
|
+
const hard = takeFlag("--hard");
|
|
171
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") : {};
|
|
172
177
|
const taskId = args.shift();
|
|
173
178
|
if (!taskId) {
|
|
174
179
|
console.error("Missing task id");
|
|
175
180
|
process.exit(2);
|
|
176
181
|
}
|
|
177
182
|
try {
|
|
178
|
-
if (command === "task-delete" &&
|
|
179
|
-
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");
|
|
180
185
|
const result = command === "task-delete"
|
|
181
|
-
?
|
|
186
|
+
? deleteTask(targetArg(), taskId, { hard, reason, deletedBy, confirm, allowOpenFindings })
|
|
182
187
|
: command === "task-archive"
|
|
183
|
-
? archiveTask(targetArg(), taskId, { reason })
|
|
188
|
+
? archiveTask(targetArg(), taskId, { reason, archivedBy, archiveFields })
|
|
184
189
|
: reopenTask(targetArg(), taskId, { reason });
|
|
185
190
|
console.log(JSON.stringify(result, null, 2));
|
|
186
191
|
}
|
|
187
192
|
catch (error) {
|
|
188
|
-
console.error(error
|
|
193
|
+
console.error(errorMessage(error));
|
|
189
194
|
process.exit(1);
|
|
190
195
|
}
|
|
191
196
|
return;
|
|
@@ -202,14 +207,15 @@ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg
|
|
|
202
207
|
console.log(JSON.stringify(updateModuleStep(targetArg(), moduleKey, stepId, { state }), null, 2));
|
|
203
208
|
}
|
|
204
209
|
catch (error) {
|
|
205
|
-
console.error(error
|
|
210
|
+
console.error(errorMessage(error));
|
|
206
211
|
process.exit(1);
|
|
207
212
|
}
|
|
208
213
|
return;
|
|
209
214
|
}
|
|
210
215
|
throw new Error(`Unsupported task command: ${command}`);
|
|
211
216
|
}
|
|
212
|
-
function parseNewTaskArgs(args, { preset = "" } = {}) {
|
|
217
|
+
function parseNewTaskArgs(args, { preset = "", fromSession = "" } = {}) {
|
|
218
|
+
void fromSession;
|
|
213
219
|
const values = [...args];
|
|
214
220
|
const presetPackage = preset ? readPresetPackageForNewTask(preset, values) : null;
|
|
215
221
|
const parsed = splitPresetArgsAndPositionals(values, presetPackage);
|
|
@@ -221,6 +227,9 @@ function parseNewTaskArgs(args, { preset = "" } = {}) {
|
|
|
221
227
|
presetArgs: parsed.presetArgs,
|
|
222
228
|
};
|
|
223
229
|
}
|
|
230
|
+
function invokeCreateTask(target, taskId, options) {
|
|
231
|
+
return Reflect.apply(createTask, undefined, [target, taskId, options]);
|
|
232
|
+
}
|
|
224
233
|
function readPresetPackageForNewTask(preset, values) {
|
|
225
234
|
const candidates = presetDiscoveryTargetCandidates(values);
|
|
226
235
|
let fallbackPackage = null;
|
|
@@ -301,25 +310,73 @@ function resolveNewTaskPositionals(positionals) {
|
|
|
301
310
|
throw new Error(`Too many positional arguments for new-task: ${positionals.join(", ")}`);
|
|
302
311
|
}
|
|
303
312
|
function formatTaskCommandError(error) {
|
|
304
|
-
const
|
|
305
|
-
|
|
313
|
+
const recovery = readArrayProperty(error, "recovery");
|
|
314
|
+
const details = readRecordProperty(error, "details");
|
|
315
|
+
const lines = [errorMessage(error)];
|
|
316
|
+
if (recovery.length > 0) {
|
|
306
317
|
lines.push("", "Recovery:");
|
|
307
|
-
for (const item of
|
|
308
|
-
lines.push(`- ${item}`);
|
|
318
|
+
for (const item of recovery)
|
|
319
|
+
lines.push(`- ${String(item)}`);
|
|
309
320
|
}
|
|
310
|
-
|
|
321
|
+
const entries = readArrayProperty(details, "entries");
|
|
322
|
+
if (entries.length) {
|
|
311
323
|
lines.push("", "Blocking Git status:");
|
|
312
|
-
for (const entry of
|
|
313
|
-
|
|
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
|
+
}
|
|
314
329
|
}
|
|
315
|
-
|
|
330
|
+
const disallowed = readArrayProperty(details, "disallowed");
|
|
331
|
+
if (disallowed.length) {
|
|
316
332
|
lines.push("", "Disallowed paths:");
|
|
317
|
-
for (const item of
|
|
318
|
-
lines.push(`- ${item}`);
|
|
333
|
+
for (const item of disallowed)
|
|
334
|
+
lines.push(`- ${String(item)}`);
|
|
319
335
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (
|
|
323
|
-
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));
|
|
324
342
|
return lines.join("\n");
|
|
325
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,305 +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 preset run <id> <plan|scaffold|check> --task <task-id> [--json] [target]
|
|
94
|
-
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]
|
|
95
|
-
harness task-start <task-id> [--message text] [target]
|
|
96
|
-
harness task-phase <task-id> <phase-id> [--state done] [--completion 100] [--evidence present] [target]
|
|
97
|
-
harness task-log <task-id> --message text [--evidence type:PATH:summary] [target]
|
|
98
|
-
harness task-block <task-id> [--message text] [target]
|
|
99
|
-
harness task-review <task-id> [--message text] [target]
|
|
100
|
-
harness review-confirm <task-id> --confirm task-id [--reviewer name] [--message text] [target]
|
|
101
|
-
harness lesson-promote <task-id> <candidate-id> [--dry-run|--apply] [target]
|
|
102
|
-
harness lesson-sediment <task-id> <candidate-id> [--dry-run] [--title title] [target]
|
|
103
|
-
harness task-complete <task-id> [--message text] [target]
|
|
104
|
-
harness task-list [--json] [--state state] [--module key] [--queue queue] [--preset id] [--review status] [--lesson status] [--missing-materials] [--include-archived] [--search text] [target]
|
|
105
|
-
harness task-index [--json] [target]
|
|
106
|
-
harness task-supersede <old-task-id> --by <new-task-id> [--reason text] [target]
|
|
107
|
-
harness task-delete <task-id> --soft [--reason text] [target]
|
|
108
|
-
harness task-archive <task-id> [--reason text] [target]
|
|
109
|
-
harness task-reopen <task-id> [--reason text] [target]
|
|
110
|
-
harness module-step <module-key> <step-id> [--state done|in-progress|blocked] [target]
|
|
111
|
-
harness install-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir] [--dry-run] [--force] [--skip-presets] [--yes]
|
|
112
|
-
harness doctor-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir]
|
|
113
|
-
|
|
114
|
-
If init runs in an interactive terminal and --locale is omitted, it asks for a
|
|
115
|
-
language. Non-interactive init defaults to en-US.
|
|
116
|
-
|
|
117
|
-
Preset discovery:
|
|
118
|
-
Project presets live in <target>/.coding-agent-harness/presets/<preset-id>/.
|
|
119
|
-
User presets live in ~/.coding-agent-harness/presets/<preset-id>/.
|
|
120
|
-
Harness discovers project presets first when a target is supplied, then user
|
|
121
|
-
presets, then bundled package presets under presets/<preset-id>/.
|
|
122
|
-
"harness init" seeds bundled presets into the target project. "harness
|
|
123
|
-
install-user" and npm postinstall seed bundled presets into the user root.
|
|
124
|
-
Use "harness preset seed" to repair or re-run preset seeding.
|
|
125
|
-
Use "harness preset install" with a local preset folder, .zip archive, or
|
|
126
|
-
bundled preset id. Preset archives must contain preset.yaml at the archive
|
|
127
|
-
root or inside one top-level folder.
|
|
128
|
-
Use "harness preset list --json" to see available presets, their source,
|
|
129
|
-
purpose, compatible budgets, and manifest path. Use "harness preset inspect
|
|
130
|
-
<id> --json" for the full preset manifest summary.
|
|
131
|
-
`);
|
|
132
|
-
}
|
|
133
|
-
function exitWithReport(report) {
|
|
134
|
-
for (const warning of report.warnings || [])
|
|
135
|
-
console.log(`Warning: ${warning}`);
|
|
136
|
-
for (const failure of report.failures || [])
|
|
137
|
-
console.error(`Failure: ${failure}`);
|
|
138
|
-
process.exit((report.failures || []).length > 0 ? 1 : 0);
|
|
139
|
-
}
|
|
140
|
-
if (command === "help" || command === "--help" || command === "-h") {
|
|
141
|
-
printHelp();
|
|
142
|
-
}
|
|
143
|
-
else if (args[0] === "help" || args.includes("--help") || args.includes("-h")) {
|
|
144
|
-
printHelp();
|
|
145
|
-
}
|
|
146
|
-
else if (command === "check") {
|
|
147
|
-
const profile = takeOption("--profile", "target-project");
|
|
148
|
-
const strict = takeFlag("--strict");
|
|
149
|
-
const target = targetArg();
|
|
150
|
-
const failures = [];
|
|
151
|
-
const warnings = [];
|
|
152
|
-
if (profile === "source-package") {
|
|
153
|
-
for (const required of ["package.json", "dist/harness.mjs", "dist/check-harness.mjs", "templates/planning/task_plan.md"]) {
|
|
154
|
-
if (!fs.existsSync(path.resolve(target, required)))
|
|
155
|
-
failures.push(`missing source package file: ${required}`);
|
|
156
|
-
}
|
|
157
|
-
const boundary = validateSourcePackageBoundary(target);
|
|
158
|
-
failures.push(...boundary.failures);
|
|
159
|
-
warnings.push(...boundary.warnings);
|
|
160
|
-
}
|
|
161
|
-
const status = buildStatus(target, { skipLegacyCheck: profile === "source-package", strictLegacy: strict, strict, allowLegacyTarget: profile === "source-package" });
|
|
162
|
-
failures.push(...status.checkState.details.failures);
|
|
163
|
-
warnings.push(...status.checkState.details.warnings);
|
|
164
|
-
if (!["source-package", "private-harness", "target-project"].includes(profile))
|
|
165
|
-
failures.push(`unknown profile: ${profile}`);
|
|
166
|
-
if (failures.length === 0)
|
|
167
|
-
console.log(`Harness check passed (${profile}): ${path.resolve(target)}`);
|
|
168
|
-
exitWithReport({ failures: [...new Set(failures)], warnings: [...new Set(warnings)] });
|
|
169
|
-
}
|
|
170
|
-
else if (command === "status") {
|
|
171
|
-
const json = takeFlag("--json");
|
|
172
|
-
const strict = takeFlag("--strict");
|
|
173
|
-
const status = buildStatus(targetArg(), { strictLegacy: strict, strict });
|
|
174
|
-
if (json) {
|
|
175
|
-
console.log(JSON.stringify(status, null, 2));
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
console.log(`${status.project.name}: ${status.checkState.status} (${status.checkState.failures} failures, ${status.checkState.warnings} warnings)`);
|
|
179
|
-
console.log(`mode: ${status.mode}`);
|
|
180
|
-
console.log(`capabilities: ${status.capabilities.map((capability) => `${capability.name}:${capability.state}`).join(", ")}`);
|
|
181
|
-
console.log(`tasks: ${status.tasks.length}`);
|
|
182
|
-
}
|
|
183
|
-
process.exitCode = status.checkState.status === "fail" ? 1 : 0;
|
|
184
|
-
}
|
|
185
|
-
else if (command === "dev") {
|
|
186
|
-
const open = !takeFlag("--no-open");
|
|
187
|
-
const outDir = takeOption("--out-dir", "");
|
|
188
|
-
const host = takeOption("--host", "127.0.0.1");
|
|
189
|
-
const port = takeOption("--port", "0");
|
|
190
|
-
const localeOverride = takeOption("--locale", "");
|
|
191
|
-
const target = targetArg();
|
|
192
|
-
const usesDefaultOutDir = !outDir;
|
|
193
|
-
const dashboardOutDir = outDir || defaultDevOutDir(target);
|
|
194
|
-
const opts = { ...(localeOverride ? { localeOverride } : {}), recoverGeneratedDashboard: usesDefaultOutDir };
|
|
195
|
-
try {
|
|
196
|
-
await serveDashboardWorkbench(dashboardOutDir, target, { ...opts, host, port, autoRefresh: true, open, label: "harness dev" });
|
|
197
|
-
}
|
|
198
|
-
catch (error) {
|
|
199
|
-
console.error(error.message);
|
|
200
|
-
process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
else if (command === "dashboard") {
|
|
204
|
-
await runDashboardCommand({ takeFlag, takeOption, targetArg });
|
|
205
|
-
}
|
|
206
|
-
else if (command === "init") {
|
|
207
|
-
const dryRun = takeFlag("--dry-run");
|
|
208
|
-
const addNpmScripts = takeFlag("--add-npm-scripts");
|
|
209
|
-
const locale = await resolveInitLocale(takeOption("--locale", ""));
|
|
210
|
-
const capabilities = takeOption("--capabilities", "core").split(",").map((item) => item.trim()).filter(Boolean);
|
|
211
|
-
try {
|
|
212
|
-
const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale, addNpmScripts });
|
|
213
|
-
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));
|
|
214
|
-
}
|
|
215
|
-
catch (error) {
|
|
216
|
-
console.error(error.message);
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
else if (command === "add-capability") {
|
|
221
|
-
const dryRun = takeFlag("--dry-run");
|
|
222
|
-
const locale = normalizeLocale(takeOption("--locale", ""));
|
|
223
|
-
const capability = args.shift();
|
|
224
|
-
if (!capability) {
|
|
225
|
-
console.error("Missing capability name");
|
|
226
|
-
process.exit(2);
|
|
227
|
-
}
|
|
228
|
-
try {
|
|
229
|
-
const result = addCapability(targetArg(), capability, { dryRun, locale });
|
|
230
|
-
console.log(JSON.stringify({ dryRun, registry: result.registry, changes: result.changes, report: result.report }, null, 2));
|
|
231
|
-
}
|
|
232
|
-
catch (error) {
|
|
233
|
-
console.error(error.message);
|
|
234
|
-
process.exit(1);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
else if (["migrate-plan", "migrate-structure", "migrate-run", "migrate-verify", "migrate-task-audit-index"].includes(command)) {
|
|
238
|
-
runMigrationCommand(command, { args, takeFlag, takeOption, targetArg });
|
|
239
|
-
}
|
|
240
|
-
else if (command === "governance") {
|
|
241
|
-
const subcommand = args.shift() || "";
|
|
242
|
-
if (subcommand !== "rebuild") {
|
|
243
|
-
console.error(`Unknown governance subcommand: ${subcommand || "(missing)"}`);
|
|
244
|
-
process.exit(2);
|
|
245
|
-
}
|
|
246
|
-
const dryRun = takeFlag("--dry-run");
|
|
247
|
-
const archive = takeFlag("--archive");
|
|
248
|
-
const apply = takeFlag("--apply");
|
|
249
|
-
try {
|
|
250
|
-
console.log(JSON.stringify(rebuildGovernanceIndexes(targetArg(), { dryRun, archive, apply }), null, 2));
|
|
251
|
-
}
|
|
252
|
-
catch (error) {
|
|
253
|
-
console.error(error.message);
|
|
254
|
-
process.exit(1);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
else if (command === "preset") {
|
|
258
|
-
runPresetCommand({ args, takeFlag, targetArg });
|
|
259
|
-
}
|
|
260
|
-
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)) {
|
|
261
|
-
runTaskCommand(command, { args, takeFlag, takeOption, targetArg });
|
|
262
|
-
}
|
|
263
|
-
else if (command === "install-user") {
|
|
264
|
-
const dryRun = takeFlag("--dry-run");
|
|
265
|
-
const force = takeFlag("--force");
|
|
266
|
-
const yes = takeFlag("--yes") || takeFlag("-y");
|
|
267
|
-
const skipPresets = takeFlag("--skip-presets");
|
|
268
|
-
takeFlag("--global");
|
|
269
|
-
const agent = takeOption("--agent", "codex");
|
|
270
|
-
const home = takeOption("--home", "");
|
|
271
|
-
if (!(await confirmUserInstall({ yes, dryRun, agent }))) {
|
|
272
|
-
console.error("Refusing to write user skill files without confirmation. Re-run with --yes or --dry-run.");
|
|
273
|
-
process.exit(2);
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
console.log(JSON.stringify(installUserSkill({ agent, home, dryRun, force, seedPresets: !skipPresets }), null, 2));
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
console.error(error.message);
|
|
280
|
-
process.exit(1);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
else if (command === "doctor-user") {
|
|
284
|
-
const agent = takeOption("--agent", "codex");
|
|
285
|
-
const home = takeOption("--home", "");
|
|
286
|
-
try {
|
|
287
|
-
const report = doctorUserSkill({ agent, home });
|
|
288
|
-
console.log(JSON.stringify(report, null, 2));
|
|
289
|
-
process.exit(report.status === "pass" ? 0 : 1);
|
|
290
|
-
}
|
|
291
|
-
catch (error) {
|
|
292
|
-
console.error(error.message);
|
|
293
|
-
process.exit(1);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
printHelp();
|
|
298
|
-
process.exit(2);
|
|
299
|
-
}
|
|
300
|
-
function defaultDevOutDir(targetInput) {
|
|
301
|
-
const target = path.resolve(targetInput || ".");
|
|
302
|
-
const name = path.basename(target) || "project";
|
|
303
|
-
const hash = Buffer.from(target).toString("hex").slice(0, 16);
|
|
304
|
-
return path.join(os.tmpdir(), "coding-agent-harness-dev", `${name}-${hash}`);
|
|
305
|
-
}
|
|
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
|
+
});
|