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
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createInterface } from "node:readline/promises";
|
|
4
|
+
import { addCapability, auditTemplateProjections, buildStatus, doctorUserSkill, installUserSkill, normalizeLocale, refreshTemplateProjections, rebuildGovernanceIndexes, validateSourcePackageBoundary, writeInitFiles, } from "../lib/harness-core.mjs";
|
|
5
|
+
import { createArgReaders } from "../lib/command-registry.mjs";
|
|
6
|
+
import { runDashboardCommand, runDevDashboardCommand } from "./dashboard-command.mjs";
|
|
7
|
+
import { runMigrationCommand } from "./migration-command.mjs";
|
|
8
|
+
import { runModuleCommand } from "./module-command.mjs";
|
|
9
|
+
import { runPresetCommand } from "./preset-command.mjs";
|
|
10
|
+
import { runTaskCommand } from "./task-command.mjs";
|
|
11
|
+
const jsonFlag = flag("--json", "Print JSON output");
|
|
12
|
+
const dryRunFlag = flag("--dry-run", "Plan changes without writing files");
|
|
13
|
+
const localeFlag = option("--locale", "Override output locale");
|
|
14
|
+
const applyFlag = flag("--apply", "Apply the planned change");
|
|
15
|
+
const projectFlag = flag("--project", "Use project preset scope");
|
|
16
|
+
export const commandRegistry = [
|
|
17
|
+
{
|
|
18
|
+
name: "check",
|
|
19
|
+
description: "Validate harness structure and configuration",
|
|
20
|
+
usage: "harness check [--profile source-package|private-harness|target-project] [target]",
|
|
21
|
+
flags: [option("--profile", "Check profile", "target-project"), flag("--strict", "Enable strict validation")],
|
|
22
|
+
handler: runCheck,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: "status",
|
|
26
|
+
description: "Print harness status",
|
|
27
|
+
usage: "harness status [--json] [--strict] [target]",
|
|
28
|
+
flags: [jsonFlag, flag("--strict", "Enable strict validation")],
|
|
29
|
+
handler: runStatus,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "dev",
|
|
33
|
+
description: "Serve the dashboard workbench",
|
|
34
|
+
usage: "harness dev [--no-open] [--out-dir folder] [--host 127.0.0.1] [--port n] [target]",
|
|
35
|
+
flags: [flag("--no-open", "Do not open the browser"), option("--out-dir", "Dashboard output folder"), option("--host", "Workbench host"), option("--port", "Workbench port")],
|
|
36
|
+
handler: legacyDashboardHandler(runDevDashboardCommand),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "dashboard",
|
|
40
|
+
description: "Write or serve a dashboard",
|
|
41
|
+
usage: "harness dashboard [--out file.html] [--out-dir folder] [--workbench] [--host 127.0.0.1] [--port n] [target]",
|
|
42
|
+
flags: [option("--out", "Single-file dashboard output"), option("--out-dir", "Dashboard folder output"), flag("--workbench", "Serve editable workbench"), option("--host", "Workbench host"), option("--port", "Workbench port")],
|
|
43
|
+
handler: legacyDashboardHandler(runDashboardCommand),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "init",
|
|
47
|
+
description: "Initialize harness files",
|
|
48
|
+
usage: "harness init [--dry-run] [--locale zh-CN|en-US] [--capabilities core,dashboard] [--add-npm-scripts] [target]",
|
|
49
|
+
flags: [dryRunFlag, localeFlag, option("--capabilities", "Comma-separated capabilities"), flag("--add-npm-scripts", "Add package scripts")],
|
|
50
|
+
handler: runInit,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "add-capability",
|
|
54
|
+
description: "Add a harness capability",
|
|
55
|
+
usage: "harness add-capability <name> [--dry-run] [--locale zh-CN|en-US] [target]",
|
|
56
|
+
positionals: ["name"],
|
|
57
|
+
flags: [dryRunFlag, localeFlag],
|
|
58
|
+
handler: runAddCapability,
|
|
59
|
+
},
|
|
60
|
+
...migrationCommands(),
|
|
61
|
+
{
|
|
62
|
+
name: "governance",
|
|
63
|
+
description: "Run governance subcommands",
|
|
64
|
+
usage: "harness governance rebuild [--dry-run] [--archive] [--apply] [target]",
|
|
65
|
+
flags: [dryRunFlag, flag("--archive", "Archive generated governance outputs"), applyFlag],
|
|
66
|
+
handler: runGovernanceUnknown,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "governance rebuild",
|
|
70
|
+
description: "Rebuild governance indexes",
|
|
71
|
+
usage: "harness governance rebuild [--dry-run] [--archive] [--apply] [target]",
|
|
72
|
+
flags: [dryRunFlag, flag("--archive", "Archive generated governance outputs"), applyFlag],
|
|
73
|
+
handler: runGovernanceRebuild,
|
|
74
|
+
},
|
|
75
|
+
...presetCommands(),
|
|
76
|
+
{
|
|
77
|
+
name: "templates",
|
|
78
|
+
description: "Audit template projections",
|
|
79
|
+
usage: "harness templates audit [--json] [target]",
|
|
80
|
+
flags: [jsonFlag],
|
|
81
|
+
handler: legacyTemplatesHandler("audit"),
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "templates audit",
|
|
85
|
+
description: "Audit template projections",
|
|
86
|
+
usage: "harness templates audit [--json] [target]",
|
|
87
|
+
flags: [jsonFlag],
|
|
88
|
+
handler: legacyTemplatesHandler("audit"),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "templates refresh",
|
|
92
|
+
description: "Refresh template projections",
|
|
93
|
+
usage: "harness templates refresh [--apply] [--json] [target]",
|
|
94
|
+
flags: [applyFlag, jsonFlag],
|
|
95
|
+
handler: legacyTemplatesHandler("refresh"),
|
|
96
|
+
},
|
|
97
|
+
...moduleCommands(),
|
|
98
|
+
...taskCommands(),
|
|
99
|
+
{
|
|
100
|
+
name: "install-user",
|
|
101
|
+
description: "Install user-level skill files",
|
|
102
|
+
usage: "harness install-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir] [--dry-run] [--force] [--skip-presets] [--yes]",
|
|
103
|
+
hasTarget: false,
|
|
104
|
+
flags: [option("--agent", "Target agent"), option("--home", "User home override"), dryRunFlag, flag("--force", "Overwrite existing files"), flag("--skip-presets", "Skip preset seeding"), { name: "--yes", alias: "-y", type: "boolean", description: "Confirm writes without prompting", default: false }],
|
|
105
|
+
handler: runInstallUser,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: "doctor-user",
|
|
109
|
+
description: "Diagnose user-level skill files",
|
|
110
|
+
usage: "harness doctor-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir]",
|
|
111
|
+
hasTarget: false,
|
|
112
|
+
flags: [option("--agent", "Target agent"), option("--home", "User home override")],
|
|
113
|
+
handler: runDoctorUser,
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
function migrationCommands() {
|
|
117
|
+
return [
|
|
118
|
+
{
|
|
119
|
+
name: "migrate-plan",
|
|
120
|
+
description: "Build a migration plan",
|
|
121
|
+
usage: "harness migrate-plan [--json] [--limit n] [target]",
|
|
122
|
+
flags: [jsonFlag, option("--limit", "Maximum task actions")],
|
|
123
|
+
handler: legacyMigrationHandler("migrate-plan"),
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "migrate-structure",
|
|
127
|
+
description: "Plan or apply v2 structure migration",
|
|
128
|
+
usage: "harness migrate-structure [--plan|--apply] [--force] [--json] [target]",
|
|
129
|
+
flags: [flag("--plan", "Print migration plan"), applyFlag, flag("--force", "Force migration"), jsonFlag],
|
|
130
|
+
handler: legacyMigrationHandler("migrate-structure"),
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "migrate-task-audit-index",
|
|
134
|
+
description: "Plan or apply task audit index migration",
|
|
135
|
+
usage: "harness migrate-task-audit-index [--plan] [--apply] [--json] [target]",
|
|
136
|
+
flags: [flag("--plan", "Print migration plan"), applyFlag, jsonFlag],
|
|
137
|
+
handler: legacyMigrationHandler("migrate-task-audit-index"),
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: "migrate-run",
|
|
141
|
+
description: "Run migration workflow",
|
|
142
|
+
usage: "harness migrate-run [--locale zh-CN|en-US] [--assume-locale] [--allow-dirty] [--plan-only] [--out-dir folder] [--session-dir folder] [target]",
|
|
143
|
+
flags: [localeFlag, flag("--assume-locale", "Use detected locale without prompting"), flag("--allow-dirty", "Allow dirty worktree"), flag("--plan-only", "Plan without applying"), option("--out-dir", "Output folder"), option("--session-dir", "Session folder")],
|
|
144
|
+
handler: legacyMigrationHandler("migrate-run"),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "migrate-verify",
|
|
148
|
+
description: "Verify a migration session",
|
|
149
|
+
usage: "harness migrate-verify [--json] [--full-cutover] <session.json>",
|
|
150
|
+
hasTarget: false,
|
|
151
|
+
positionals: ["session.json"],
|
|
152
|
+
flags: [jsonFlag, flag("--full-cutover", "Require full cutover eligibility")],
|
|
153
|
+
handler: legacyMigrationHandler("migrate-verify"),
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
}
|
|
157
|
+
function presetCommands() {
|
|
158
|
+
return [
|
|
159
|
+
{ name: "preset", description: "List presets", usage: "harness preset list [--json] [target]", flags: [jsonFlag], handler: legacyPresetHandler() },
|
|
160
|
+
{ name: "preset list", description: "List presets", usage: "harness preset list [--json] [target]", flags: [jsonFlag], handler: legacyPresetHandler("list") },
|
|
161
|
+
{ name: "preset inspect", description: "Inspect a preset", usage: "harness preset inspect <id> [--json] [target]", positionals: ["id"], flags: [jsonFlag], handler: legacyPresetHandler("inspect") },
|
|
162
|
+
{ name: "preset check", description: "Check a preset", usage: "harness preset check <id> [--json] [target]", positionals: ["id"], flags: [jsonFlag], handler: legacyPresetHandler("check") },
|
|
163
|
+
{
|
|
164
|
+
name: "preset install",
|
|
165
|
+
description: "Install a preset package",
|
|
166
|
+
usage: "harness preset install <folder|zip|builtin-id> [--project] [--force] [--allow-scripts] [--json] [target]",
|
|
167
|
+
positionals: ["folder|zip|builtin-id"],
|
|
168
|
+
flags: [projectFlag, flag("--force", "Overwrite existing preset"), flag("--allow-scripts", "Allow trusted preset scripts"), jsonFlag],
|
|
169
|
+
handler: legacyPresetHandler("install"),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "preset seed",
|
|
173
|
+
description: "Seed bundled presets",
|
|
174
|
+
usage: "harness preset seed [--project] [--force] [--dry-run] [--json] [target]",
|
|
175
|
+
flags: [projectFlag, flag("--force", "Overwrite existing presets"), dryRunFlag, jsonFlag],
|
|
176
|
+
handler: legacyPresetHandler("seed"),
|
|
177
|
+
},
|
|
178
|
+
{ name: "preset audit", description: "Audit bundled preset drift", usage: "harness preset audit [--project] [--json] [target]", flags: [projectFlag, jsonFlag], handler: legacyPresetHandler("audit") },
|
|
179
|
+
{ name: "preset uninstall", description: "Uninstall a preset", usage: "harness preset uninstall <id> [--project] [--json] [target]", positionals: ["id"], flags: [projectFlag, jsonFlag], handler: legacyPresetHandler("uninstall") },
|
|
180
|
+
{
|
|
181
|
+
name: "preset run",
|
|
182
|
+
description: "Run a preset entrypoint",
|
|
183
|
+
usage: "harness preset run <id> <plan|scaffold|check> --task <task-id> [--use-current-preset --reason text] [--json] [target]",
|
|
184
|
+
positionals: ["id", "plan|scaffold|check"],
|
|
185
|
+
flags: [option("--task", "Task id"), flag("--use-current-preset", "Use preset recorded on task"), option("--reason", "Reason for preset override"), jsonFlag],
|
|
186
|
+
handler: legacyPresetHandler("run"),
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: "preset action",
|
|
190
|
+
description: "Run a preset action",
|
|
191
|
+
usage: "harness preset action <id> <action> --task <task-id> [--allow-scripts] [--use-current-preset --reason text] [--json] [action flags...] [target]",
|
|
192
|
+
positionals: ["id", "action"],
|
|
193
|
+
flags: [option("--task", "Task id"), flag("--allow-scripts", "Allow trusted preset scripts"), flag("--use-current-preset", "Use preset recorded on task"), option("--reason", "Reason for preset override"), jsonFlag],
|
|
194
|
+
handler: legacyPresetHandler("action"),
|
|
195
|
+
},
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
function moduleCommands() {
|
|
199
|
+
return [
|
|
200
|
+
{ name: "module", description: "List modules", usage: "harness module list [--json] [target]", flags: [jsonFlag], handler: legacyModuleHandler() },
|
|
201
|
+
{ name: "module list", description: "List modules", usage: "harness module list [--json] [target]", flags: [jsonFlag], handler: legacyModuleHandler("list") },
|
|
202
|
+
{ name: "module inspect", description: "Inspect a module", usage: "harness module inspect <key> [target]", positionals: ["key"], handler: legacyModuleHandler("inspect") },
|
|
203
|
+
{
|
|
204
|
+
name: "module register",
|
|
205
|
+
description: "Register a module",
|
|
206
|
+
usage: "harness module register <key> --title title --prefix PREFIX --scope path [--status state] [--branch branch] [--owner owner] [--current-step step] [--shared path] [--depends-on key] [--locale zh-CN|en-US] [--dry-run] [target]",
|
|
207
|
+
positionals: ["key"],
|
|
208
|
+
flags: [option("--title", "Module title"), option("--prefix", "Module prefix"), repeated("--scope", "Owned path"), option("--status", "Module status"), option("--branch", "Module branch"), option("--owner", "Module owner"), option("--current-step", "Current step"), repeated("--shared", "Shared path"), repeated("--depends-on", "Dependency module key"), localeFlag, dryRunFlag],
|
|
209
|
+
handler: legacyModuleHandler("register"),
|
|
210
|
+
},
|
|
211
|
+
{ name: "module scaffold", description: "Scaffold module docs", usage: "harness module scaffold <key|--all> [--locale zh-CN|en-US] [--dry-run] [target]", positionals: ["key|--all"], flags: [flag("--all", "Scaffold all modules"), localeFlag, dryRunFlag], handler: legacyModuleHandler("scaffold") },
|
|
212
|
+
{ name: "module unregister", description: "Unregister a module", usage: "harness module unregister <key> [--dry-run] [target]", positionals: ["key"], flags: [dryRunFlag], handler: legacyModuleHandler("unregister") },
|
|
213
|
+
];
|
|
214
|
+
}
|
|
215
|
+
function taskCommands() {
|
|
216
|
+
const lifecycleFlags = [option("--message", "Lifecycle message")];
|
|
217
|
+
return [
|
|
218
|
+
{
|
|
219
|
+
name: "new-task",
|
|
220
|
+
description: "Create a task package",
|
|
221
|
+
usage: "harness new-task [task-id] [--module key] [--register-module --module-title title --module-prefix PREFIX --module-scope path] [--budget simple|standard|complex] [--preset id] [--from-session session.json] [--long-running] [--title title] [--locale zh-CN|en-US] [--dry-run] [target]",
|
|
222
|
+
flags: [option("--module", "Module key"), flag("--register-module", "Register missing module"), option("--module-title", "New module title"), option("--module-prefix", "New module prefix"), repeated("--module-scope", "New module scope"), option("--budget", "Task budget"), option("--preset", "Task preset"), option("--from-session", "Session JSON path"), flag("--long-running", "Create long-running task contract"), option("--title", "Task title"), localeFlag, dryRunFlag],
|
|
223
|
+
handler: legacyTaskHandler("new-task"),
|
|
224
|
+
},
|
|
225
|
+
{ name: "task-start", description: "Mark task started", usage: "harness task-start <task-id> [--message text] [target]", positionals: ["task-id"], flags: lifecycleFlags, handler: legacyTaskHandler("task-start") },
|
|
226
|
+
{ name: "task-phase", description: "Update a task phase", usage: "harness task-phase <task-id> <phase-id> [--state done] [--completion 100] [--evidence present] [target]", positionals: ["task-id", "phase-id"], flags: [option("--state", "Phase state"), option("--completion", "Completion percentage"), option("--evidence", "Evidence status")], handler: legacyTaskHandler("task-phase") },
|
|
227
|
+
{ name: "task-log", description: "Append task progress log", usage: "harness task-log <task-id> --message text [--evidence type:PATH:summary] [target]", positionals: ["task-id"], flags: [option("--message", "Progress message"), option("--evidence", "Evidence reference")], handler: legacyTaskHandler("task-log") },
|
|
228
|
+
{ name: "task-block", description: "Mark task blocked", usage: "harness task-block <task-id> [--message text] [target]", positionals: ["task-id"], flags: lifecycleFlags, handler: legacyTaskHandler("task-block") },
|
|
229
|
+
{ name: "task-review", description: "Move task to review", usage: "harness task-review <task-id> [--message text] [target]", positionals: ["task-id"], flags: lifecycleFlags, handler: legacyTaskHandler("task-review") },
|
|
230
|
+
{ name: "task-complete", description: "Complete a task", usage: "harness task-complete <task-id> [--message text] [target]", positionals: ["task-id"], flags: lifecycleFlags, handler: legacyTaskHandler("task-complete") },
|
|
231
|
+
{ name: "lesson-promote", description: "Promote a lesson candidate", usage: "harness lesson-promote <task-id> <candidate-id> [--dry-run|--apply] [target]", positionals: ["task-id", "candidate-id"], flags: [dryRunFlag, applyFlag], handler: legacyTaskHandler("lesson-promote") },
|
|
232
|
+
{ name: "lesson-sediment", description: "Create a lesson sedimentation task", usage: "harness lesson-sediment <task-id> <candidate-id> [--dry-run] [--title title] [target]", positionals: ["task-id", "candidate-id"], flags: [dryRunFlag, option("--title", "Lesson title")], handler: legacyTaskHandler("lesson-sediment") },
|
|
233
|
+
{ name: "task-list", description: "List tasks", usage: "harness task-list [--json] [--state state] [--module key] [--queue queue] [--preset id] [--review status] [--lesson status] [--missing-materials] [--include-archived] [--search text] [target]", flags: [jsonFlag, option("--state", "Filter state"), option("--module", "Filter module"), option("--queue", "Filter queue"), option("--preset", "Filter preset"), option("--review", "Filter review status"), option("--lesson", "Filter lesson status"), flag("--missing-materials", "Only tasks missing materials"), flag("--include-archived", "Include archived tasks"), option("--search", "Search text")], handler: legacyTaskHandler("task-list") },
|
|
234
|
+
{ name: "task-index", description: "Build task index", usage: "harness task-index [--json] [target]", flags: [jsonFlag], handler: legacyTaskHandler("task-index") },
|
|
235
|
+
{ name: "task-supersede", description: "Supersede a task", usage: "harness task-supersede <old-task-id> --by <new-task-id> [--reason text] [--deleted-by name-or-email] [--confirm task-id] [--allow-open-findings] [target]", positionals: ["old-task-id"], flags: [option("--by", "Replacement task id"), option("--reason", "Supersede reason"), option("--deleted-by", "Actor"), option("--confirm", "Confirmation task id"), flag("--allow-open-findings", "Allow open findings")], handler: legacyTaskHandler("task-supersede") },
|
|
236
|
+
{ name: "task-delete", description: "Delete a task", usage: "harness task-delete <task-id> [--soft|--hard] [--confirm canonical-id] [--deleted-by name-or-email] [--reason text] [target]", positionals: ["task-id"], flags: [flag("--soft", "Soft delete"), flag("--hard", "Hard delete"), option("--confirm", "Confirmation id"), option("--deleted-by", "Actor"), option("--reason", "Delete reason")], handler: legacyTaskHandler("task-delete") },
|
|
237
|
+
{ name: "task-archive", description: "Archive a task", usage: "harness task-archive <task-id> --archived-by name-or-email [--reason text] [--archive-field key=value] [target]", positionals: ["task-id"], flags: [option("--archived-by", "Actor"), option("--reason", "Archive reason"), repeated("--archive-field", "Archive metadata field")], handler: legacyTaskHandler("task-archive") },
|
|
238
|
+
{ name: "task-reopen", description: "Reopen a task", usage: "harness task-reopen <task-id> [--reason text] [target]", positionals: ["task-id"], flags: [option("--reason", "Reopen reason")], handler: legacyTaskHandler("task-reopen") },
|
|
239
|
+
{ name: "module-step", description: "Update a module step", usage: "harness module-step <module-key> <step-id> [--state done|in-progress|blocked] [target]", positionals: ["module-key", "step-id"], flags: [option("--state", "Step state")], handler: legacyTaskHandler("module-step") },
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
function runCheck(ctx) {
|
|
243
|
+
const profile = ctx.takeOption("--profile", "target-project");
|
|
244
|
+
const strict = ctx.takeFlag("--strict");
|
|
245
|
+
const target = ctx.targetArg();
|
|
246
|
+
const failures = [];
|
|
247
|
+
const warnings = [];
|
|
248
|
+
if (profile === "source-package") {
|
|
249
|
+
for (const required of ["package.json", "dist/harness.mjs", "dist/check-harness.mjs", "templates/planning/task_plan.md"]) {
|
|
250
|
+
if (!fs.existsSync(path.resolve(target, required)))
|
|
251
|
+
failures.push(`missing source package file: ${required}`);
|
|
252
|
+
}
|
|
253
|
+
const boundary = validateSourcePackageBoundary(target);
|
|
254
|
+
failures.push(...boundary.failures);
|
|
255
|
+
warnings.push(...boundary.warnings);
|
|
256
|
+
}
|
|
257
|
+
const status = buildStatus(target, { skipLegacyCheck: profile === "source-package", strictLegacy: strict, strict, allowLegacyTarget: profile === "source-package" });
|
|
258
|
+
failures.push(...status.checkState.details.failures);
|
|
259
|
+
warnings.push(...status.checkState.details.warnings);
|
|
260
|
+
if (!["source-package", "private-harness", "target-project"].includes(profile))
|
|
261
|
+
failures.push(`unknown profile: ${profile}`);
|
|
262
|
+
if (failures.length === 0)
|
|
263
|
+
console.log(`Harness check passed (${profile}): ${path.resolve(target)}`);
|
|
264
|
+
exitWithReport({ failures: [...new Set(failures)], warnings: [...new Set(warnings)] });
|
|
265
|
+
}
|
|
266
|
+
function runStatus(ctx) {
|
|
267
|
+
const json = ctx.takeFlag("--json");
|
|
268
|
+
const strict = ctx.takeFlag("--strict");
|
|
269
|
+
const status = buildStatus(ctx.targetArg(), { strictLegacy: strict, strict });
|
|
270
|
+
if (json) {
|
|
271
|
+
console.log(JSON.stringify(status, null, 2));
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
console.log(`${status.project.name}: ${status.checkState.status} (${status.checkState.failures} failures, ${status.checkState.warnings} warnings)`);
|
|
275
|
+
console.log(`mode: ${status.mode}`);
|
|
276
|
+
console.log(`capabilities: ${status.capabilities.map((capability) => `${capability.name}:${capability.state}`).join(", ")}`);
|
|
277
|
+
console.log(`tasks: ${status.tasks.length}`);
|
|
278
|
+
}
|
|
279
|
+
process.exitCode = status.checkState.status === "fail" ? 1 : 0;
|
|
280
|
+
}
|
|
281
|
+
async function runInit(ctx) {
|
|
282
|
+
const dryRun = ctx.takeFlag("--dry-run");
|
|
283
|
+
const addNpmScripts = ctx.takeFlag("--add-npm-scripts");
|
|
284
|
+
const locale = await resolveInitLocale(ctx.takeOption("--locale", ""));
|
|
285
|
+
const capabilities = ctx.takeOption("--capabilities", "core").split(",").map((item) => item.trim()).filter(Boolean);
|
|
286
|
+
try {
|
|
287
|
+
const result = writeInitFiles(ctx.targetArg(), capabilities, { dryRun, locale, addNpmScripts });
|
|
288
|
+
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));
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
console.error(errorMessage(error));
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function runAddCapability(ctx) {
|
|
296
|
+
const args = [...ctx.raw];
|
|
297
|
+
const readers = createArgReaders(args);
|
|
298
|
+
const dryRun = readers.takeFlag("--dry-run");
|
|
299
|
+
const locale = normalizeLocale(readers.takeOption("--locale", ""));
|
|
300
|
+
const capability = args.shift();
|
|
301
|
+
if (!capability) {
|
|
302
|
+
console.error("Missing capability name");
|
|
303
|
+
process.exit(2);
|
|
304
|
+
}
|
|
305
|
+
try {
|
|
306
|
+
const result = addCapability(readers.targetArg(), capability, { dryRun, locale });
|
|
307
|
+
console.log(JSON.stringify({ dryRun, registry: result.registry, changes: result.changes, report: result.report }, null, 2));
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
console.error(errorMessage(error));
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function runGovernanceUnknown(ctx) {
|
|
315
|
+
const subcommand = ctx.raw[0] || "";
|
|
316
|
+
console.error(`Unknown governance subcommand: ${subcommand || "(missing)"}`);
|
|
317
|
+
process.exit(2);
|
|
318
|
+
}
|
|
319
|
+
function runGovernanceRebuild(ctx) {
|
|
320
|
+
const dryRun = ctx.takeFlag("--dry-run");
|
|
321
|
+
const archive = ctx.takeFlag("--archive");
|
|
322
|
+
const apply = ctx.takeFlag("--apply");
|
|
323
|
+
try {
|
|
324
|
+
console.log(JSON.stringify(rebuildGovernanceIndexes(ctx.targetArg(), { dryRun, archive, apply }), null, 2));
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
console.error(errorMessage(error));
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function legacyTemplatesHandler(subcommand) {
|
|
332
|
+
return (ctx) => {
|
|
333
|
+
const args = ctx.definition.name === "templates" ? [...ctx.raw] : [subcommand, ...ctx.raw];
|
|
334
|
+
const readers = createArgReaders(args);
|
|
335
|
+
const actualSubcommand = args.shift() || "audit";
|
|
336
|
+
const json = readers.takeFlag("--json");
|
|
337
|
+
const apply = readers.takeFlag("--apply");
|
|
338
|
+
try {
|
|
339
|
+
if (actualSubcommand === "audit") {
|
|
340
|
+
const result = auditTemplateProjections(readers.targetArg());
|
|
341
|
+
if (json)
|
|
342
|
+
console.log(JSON.stringify(result, null, 2));
|
|
343
|
+
else
|
|
344
|
+
console.log(`Template projection audit: ${result.summary.refreshable} refreshable, ${result.summary.reportOnly} report-only`);
|
|
345
|
+
}
|
|
346
|
+
else if (actualSubcommand === "refresh") {
|
|
347
|
+
const result = refreshTemplateProjections(readers.targetArg(), { apply });
|
|
348
|
+
if (json)
|
|
349
|
+
console.log(JSON.stringify(result, null, 2));
|
|
350
|
+
else
|
|
351
|
+
console.log(`Template projection refresh ${result.dryRun ? "dry-run" : "applied"}: ${result.changes.length} changes`);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
throw new Error(`Unknown templates subcommand: ${actualSubcommand}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
console.error(errorMessage(error));
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function legacyMigrationHandler(command) {
|
|
364
|
+
return (ctx) => {
|
|
365
|
+
const args = [...ctx.raw];
|
|
366
|
+
runMigrationCommand(command, { args, ...createArgReaders(args) });
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
function legacyPresetHandler(subcommand) {
|
|
370
|
+
return (ctx) => {
|
|
371
|
+
const args = subcommand ? [subcommand, ...ctx.raw] : [...ctx.raw];
|
|
372
|
+
runPresetCommand({ args, ...createArgReaders(args) });
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function legacyModuleHandler(subcommand) {
|
|
376
|
+
return (ctx) => {
|
|
377
|
+
const args = subcommand ? [subcommand, ...ctx.raw] : [...ctx.raw];
|
|
378
|
+
runModuleCommand({ args, ...createArgReaders(args) });
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
function legacyTaskHandler(command) {
|
|
382
|
+
return (ctx) => {
|
|
383
|
+
const args = [...ctx.raw];
|
|
384
|
+
runTaskCommand(command, { args, ...createArgReaders(args) });
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
function legacyDashboardHandler(handler) {
|
|
388
|
+
return (ctx) => {
|
|
389
|
+
const args = [...ctx.raw];
|
|
390
|
+
return handler(createArgReaders(args));
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
async function runInstallUser(ctx) {
|
|
394
|
+
const dryRun = ctx.takeFlag("--dry-run");
|
|
395
|
+
const force = ctx.takeFlag("--force");
|
|
396
|
+
const yes = ctx.takeFlag("--yes") || ctx.takeFlag("-y");
|
|
397
|
+
const skipPresets = ctx.takeFlag("--skip-presets");
|
|
398
|
+
ctx.takeFlag("--global");
|
|
399
|
+
const agent = ctx.takeOption("--agent", "codex");
|
|
400
|
+
const home = ctx.takeOption("--home", "");
|
|
401
|
+
if (!(await confirmUserInstall({ yes, dryRun, agent }))) {
|
|
402
|
+
console.error("Refusing to write user skill files without confirmation. Re-run with --yes or --dry-run.");
|
|
403
|
+
process.exit(2);
|
|
404
|
+
}
|
|
405
|
+
try {
|
|
406
|
+
console.log(JSON.stringify(installUserSkill({ agent, home, dryRun, force, seedPresets: !skipPresets }), null, 2));
|
|
407
|
+
}
|
|
408
|
+
catch (error) {
|
|
409
|
+
console.error(errorMessage(error));
|
|
410
|
+
process.exit(1);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function runDoctorUser(ctx) {
|
|
414
|
+
const agent = ctx.takeOption("--agent", "codex");
|
|
415
|
+
const home = ctx.takeOption("--home", "");
|
|
416
|
+
try {
|
|
417
|
+
const report = doctorUserSkill({ agent, home });
|
|
418
|
+
console.log(JSON.stringify(report, null, 2));
|
|
419
|
+
process.exit(report.status === "pass" ? 0 : 1);
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
console.error(errorMessage(error));
|
|
423
|
+
process.exit(1);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async function resolveInitLocale(requestedLocale) {
|
|
427
|
+
if (requestedLocale)
|
|
428
|
+
return normalizeLocale(requestedLocale);
|
|
429
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
430
|
+
return "en-US";
|
|
431
|
+
const prompt = [
|
|
432
|
+
"Select harness language / 选择初始化语言:",
|
|
433
|
+
" 1. 中文 (zh-CN)",
|
|
434
|
+
" 2. English (en-US)",
|
|
435
|
+
"Language [1/2, default 2]: ",
|
|
436
|
+
].join("\n");
|
|
437
|
+
const reader = createInterface({ input: process.stdin, output: process.stdout });
|
|
438
|
+
try {
|
|
439
|
+
const answer = (await reader.question(prompt)).trim().toLowerCase();
|
|
440
|
+
if (["1", "zh", "zh-cn", "cn", "中文"].includes(answer))
|
|
441
|
+
return "zh-CN";
|
|
442
|
+
if (["2", "en", "en-us", "english", "英文", ""].includes(answer))
|
|
443
|
+
return "en-US";
|
|
444
|
+
console.error(`Unknown language selection: ${answer}. Falling back to en-US.`);
|
|
445
|
+
return "en-US";
|
|
446
|
+
}
|
|
447
|
+
finally {
|
|
448
|
+
reader.close();
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
async function confirmUserInstall({ yes = false, dryRun = false, agent = "codex" } = {}) {
|
|
452
|
+
if (yes || dryRun)
|
|
453
|
+
return true;
|
|
454
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
455
|
+
return false;
|
|
456
|
+
const reader = createInterface({ input: process.stdin, output: process.stdout });
|
|
457
|
+
try {
|
|
458
|
+
const answer = (await reader.question(`Install Coding Agent Harness into user skill directory for ${agent}? [y/N] `)).trim().toLowerCase();
|
|
459
|
+
return ["y", "yes"].includes(answer);
|
|
460
|
+
}
|
|
461
|
+
finally {
|
|
462
|
+
reader.close();
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
function exitWithReport(report) {
|
|
466
|
+
for (const warning of report.warnings || [])
|
|
467
|
+
console.log(`Warning: ${warning}`);
|
|
468
|
+
for (const failure of report.failures || [])
|
|
469
|
+
console.error(`Failure: ${failure}`);
|
|
470
|
+
process.exit((report.failures || []).length > 0 ? 1 : 0);
|
|
471
|
+
}
|
|
472
|
+
function flag(name, description, fallback = false) {
|
|
473
|
+
return { name, type: "boolean", description, default: fallback };
|
|
474
|
+
}
|
|
475
|
+
function option(name, description, fallback = "") {
|
|
476
|
+
return { name, type: "string", description, default: fallback };
|
|
477
|
+
}
|
|
478
|
+
function repeated(name, description) {
|
|
479
|
+
return { name, type: "string[]", description, default: [] };
|
|
480
|
+
}
|
|
481
|
+
function errorMessage(error) {
|
|
482
|
+
return error instanceof Error ? error.message : String(error);
|
|
483
|
+
}
|