coding-agent-harness 1.0.1 → 1.0.2
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 +19 -0
- package/README.en-US.md +14 -0
- package/README.md +111 -86
- package/README.zh-CN.md +270 -0
- package/SKILL.md +116 -189
- package/docs-release/README.md +72 -5
- package/docs-release/architecture/overview.md +286 -28
- package/docs-release/architecture/overview.zh-CN.md +288 -0
- package/docs-release/assets/dashboard-overview-en.png +0 -0
- package/docs-release/assets/harness-architecture.svg +163 -0
- package/docs-release/assets/harness-workflow.svg +64 -0
- package/docs-release/guides/agent-installation.en-US.md +214 -0
- package/docs-release/guides/agent-installation.md +123 -26
- package/docs-release/guides/document-audience-and-surfaces.en-US.md +112 -0
- package/docs-release/guides/document-audience-and-surfaces.md +112 -0
- package/docs-release/guides/full-legacy-migration-subagent-strategy.md +334 -0
- package/docs-release/guides/full-legacy-migration-subagent-strategy.zh-CN.md +334 -0
- package/docs-release/guides/legacy-migration-agent-prompt.md +384 -0
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +361 -0
- package/docs-release/guides/migration-playbook.en-US.md +325 -0
- package/docs-release/guides/migration-playbook.md +329 -0
- package/docs-release/guides/parent-control-repository-pattern.en-US.md +252 -0
- package/docs-release/guides/parent-control-repository-pattern.md +252 -0
- package/docs-release/guides/repository-operating-models.en-US.md +196 -0
- package/docs-release/guides/repository-operating-models.md +196 -0
- package/docs-release/intl/README.md +15 -0
- package/docs-release/intl/de-DE.md +18 -0
- package/docs-release/intl/en-US.md +18 -0
- package/docs-release/intl/es-ES.md +18 -0
- package/docs-release/intl/fr-FR.md +18 -0
- package/docs-release/intl/ja-JP.md +18 -0
- package/docs-release/intl/ko-KR.md +18 -0
- package/docs-release/intl/zh-CN.md +18 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/brief.md +13 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/lesson_candidates.md +24 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/progress.md +1 -1
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/task_plan.md +4 -2
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/{visual_roadmap.md → visual_map.md} +9 -1
- package/package.json +3 -1
- package/references/agents-md-pattern.md +3 -3
- package/references/docs-directory-standard.md +47 -3
- package/references/external-source-intake-standard.md +75 -0
- package/references/harness-ledger.md +5 -3
- package/references/legacy-12-phase-bootstrap.md +41 -0
- package/references/lessons-governance.md +23 -6
- package/references/planning-loop.md +41 -3
- package/references/project-onboarding-audit.md +10 -0
- package/references/repo-governance-standard.md +2 -0
- package/references/testing-standard.md +50 -0
- package/references/walkthrough-closeout.md +6 -5
- package/scripts/check-harness.mjs +76 -35
- package/scripts/harness.mjs +303 -12
- package/scripts/lib/capability-registry.mjs +533 -0
- package/scripts/lib/check-profiles.mjs +510 -0
- package/scripts/lib/core-shared.mjs +186 -0
- package/scripts/lib/dashboard-data.mjs +389 -0
- package/scripts/lib/dashboard-workbench.mjs +217 -0
- package/scripts/lib/dashboard-writer.mjs +93 -2
- package/scripts/lib/harness-core.mjs +10 -1318
- package/scripts/lib/lesson-maintenance.mjs +145 -0
- package/scripts/lib/markdown-utils.mjs +158 -0
- package/scripts/lib/migration-planner.mjs +478 -0
- package/scripts/lib/migration-support.mjs +312 -0
- package/scripts/lib/task-lifecycle.mjs +755 -0
- package/scripts/lib/task-scanner.mjs +682 -0
- package/scripts/smoke-dashboard.mjs +22 -0
- package/scripts/test-harness.mjs +926 -14
- package/templates/AGENTS.md.template +41 -30
- package/templates/architecture/Architecture-SSoT.md +21 -0
- package/templates/architecture/README.md +49 -0
- package/templates/architecture/critical-flows.md +22 -0
- package/templates/architecture/local-repo-context.md +20 -0
- package/templates/architecture/service-catalog.md +17 -0
- package/templates/architecture/services/service-template.md +31 -0
- package/templates/architecture/system-map.md +22 -0
- package/templates/dashboard/assets/app-src/00-state.js +41 -0
- package/templates/dashboard/assets/app-src/10-router.js +76 -0
- package/templates/dashboard/assets/app-src/20-overview.js +235 -0
- package/templates/dashboard/assets/app-src/30-tasks.js +563 -0
- package/templates/dashboard/assets/app-src/40-modules.js +58 -0
- package/templates/dashboard/assets/app-src/45-review.js +128 -0
- package/templates/dashboard/assets/app-src/50-migration.js +169 -0
- package/templates/dashboard/assets/app-src/60-shared.js +61 -0
- package/templates/dashboard/assets/app-src/90-bindings.js +382 -0
- package/templates/dashboard/assets/app.css +2575 -310
- package/templates/dashboard/assets/app.js +1498 -307
- package/templates/dashboard/assets/app.manifest.json +11 -0
- package/templates/dashboard/assets/i18n.js +429 -44
- package/templates/dashboard/assets/mermaid-renderer.js +58 -8
- package/templates/development/README.md +52 -0
- package/templates/development/codebase-map.md +11 -0
- package/templates/development/cross-repo-debugging.md +18 -0
- package/templates/development/external-context/service-template.md +33 -0
- package/templates/development/external-source-packs/README.md +24 -0
- package/templates/development/external-source-packs/digest-template.md +28 -0
- package/templates/development/local-setup.md +16 -0
- package/templates/development/stubs-and-mocks.md +11 -0
- package/templates/integrations/README.md +40 -0
- package/templates/integrations/api-contract.md +42 -0
- package/templates/integrations/event-contract.md +46 -0
- package/templates/integrations/third-party/vendor-template.md +42 -0
- package/templates/integrations/webhook-contract.md +41 -0
- package/templates/planning/brief.md +32 -0
- package/templates/planning/lesson_candidates.md +58 -0
- package/templates/planning/long-running-task-contract.md +7 -0
- package/templates/planning/module_brief.md +25 -0
- package/templates/planning/module_session_prompt.md +6 -0
- package/templates/planning/task_plan.md +7 -5
- package/templates/planning/{visual_roadmap.md → visual_map.md} +24 -2
- package/templates/reference/docs-library-standard.md +31 -0
- package/templates/reference/execution-workflow-standard.md +4 -2
- package/templates/reference/external-source-intake-standard.md +82 -0
- package/templates/reference/harness-ledger-standard.md +1 -0
- package/templates/reference/repo-governance-standard.md +6 -4
- package/templates/reference/walkthrough-standard.md +2 -1
- package/templates/walkthrough/walkthrough-template.md +2 -2
- package/templates-zh-CN/AGENTS.md.template +69 -70
- package/templates-zh-CN/architecture/Architecture-SSoT.md +21 -0
- package/templates-zh-CN/architecture/README.md +51 -0
- package/templates-zh-CN/architecture/critical-flows.md +24 -0
- package/templates-zh-CN/architecture/local-repo-context.md +20 -0
- package/templates-zh-CN/architecture/service-catalog.md +17 -0
- package/templates-zh-CN/architecture/services/service-template.md +31 -0
- package/templates-zh-CN/architecture/system-map.md +22 -0
- package/templates-zh-CN/development/README.md +54 -0
- package/templates-zh-CN/development/codebase-map.md +11 -0
- package/templates-zh-CN/development/cross-repo-debugging.md +18 -0
- package/templates-zh-CN/development/external-context/service-template.md +33 -0
- package/templates-zh-CN/development/external-source-packs/README.md +24 -0
- package/templates-zh-CN/development/external-source-packs/digest-template.md +28 -0
- package/templates-zh-CN/development/local-setup.md +16 -0
- package/templates-zh-CN/development/stubs-and-mocks.md +11 -0
- package/templates-zh-CN/integrations/README.md +42 -0
- package/templates-zh-CN/integrations/api-contract.md +42 -0
- package/templates-zh-CN/integrations/event-contract.md +46 -0
- package/templates-zh-CN/integrations/third-party/vendor-template.md +42 -0
- package/templates-zh-CN/integrations/webhook-contract.md +41 -0
- package/templates-zh-CN/planning/brief.md +32 -0
- package/templates-zh-CN/planning/lesson_candidates.md +58 -0
- package/templates-zh-CN/planning/long-running-task-contract.md +1 -1
- package/templates-zh-CN/planning/module_brief.md +25 -0
- package/templates-zh-CN/planning/module_plan.md +2 -2
- package/templates-zh-CN/planning/module_session_prompt.md +4 -3
- package/templates-zh-CN/planning/task_plan.md +10 -4
- package/templates-zh-CN/planning/{visual_roadmap.md → visual_map.md} +21 -2
- package/templates-zh-CN/reference/docs-library-standard.md +35 -0
- package/templates-zh-CN/reference/execution-workflow-standard.md +9 -2
- package/templates-zh-CN/reference/external-source-intake-standard.md +82 -0
- package/templates-zh-CN/reference/harness-ledger-standard.md +5 -2
- package/templates-zh-CN/reference/repo-governance-standard.md +2 -0
- package/templates-zh-CN/reference/walkthrough-standard.md +4 -4
- package/templates-zh-CN/walkthrough/Closeout-SSoT.md +2 -2
- package/templates-zh-CN/walkthrough/walkthrough-template.md +2 -2
- package/templates-zh-CN/dashboard/assets/app.css +0 -399
- package/templates-zh-CN/dashboard/assets/app.js +0 -435
- package/templates-zh-CN/dashboard/assets/i18n.js +0 -47
- package/templates-zh-CN/dashboard/assets/markdown-reader.js +0 -116
- package/templates-zh-CN/dashboard/assets/mermaid-renderer.js +0 -59
- package/templates-zh-CN/dashboard/index.html +0 -18
package/scripts/harness.mjs
CHANGED
|
@@ -1,16 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { createInterface } from "node:readline/promises";
|
|
6
7
|
import {
|
|
7
8
|
addCapability,
|
|
9
|
+
buildMigrationPlan,
|
|
8
10
|
buildStatus,
|
|
11
|
+
confirmTaskReview,
|
|
12
|
+
createTask,
|
|
9
13
|
doctorUserSkill,
|
|
10
14
|
installUserSkill,
|
|
11
|
-
|
|
15
|
+
listLifecycleTasks,
|
|
12
16
|
normalizeLocale,
|
|
17
|
+
promoteLessonCandidate,
|
|
18
|
+
runMigration,
|
|
19
|
+
serveDashboardWorkbench,
|
|
20
|
+
validateSourcePackageBoundary,
|
|
21
|
+
updateModuleStep,
|
|
22
|
+
updateTaskPhase,
|
|
23
|
+
updateTaskLifecycle,
|
|
24
|
+
verifyMigrationSession,
|
|
13
25
|
writeDashboardFolder,
|
|
26
|
+
writeDashboardSingleFile,
|
|
14
27
|
writeInitFiles,
|
|
15
28
|
} from "./lib/harness-core.mjs";
|
|
16
29
|
|
|
@@ -76,9 +89,24 @@ function printHelp() {
|
|
|
76
89
|
Usage:
|
|
77
90
|
harness check [--profile source-package|private-harness|target-project] [target]
|
|
78
91
|
harness status [--json] [--strict] [target]
|
|
79
|
-
harness
|
|
80
|
-
harness
|
|
92
|
+
harness dev [--no-open] [--out-dir folder] [--host 127.0.0.1] [--port n] [target]
|
|
93
|
+
harness dashboard [--out file.html] [--out-dir folder] [--workbench] [--host 127.0.0.1] [--port n] [target]
|
|
94
|
+
harness init [--dry-run] [--locale zh-CN|en-US] [--capabilities core,dashboard] [--add-npm-scripts] [target]
|
|
81
95
|
harness add-capability <name> [--dry-run] [--locale zh-CN|en-US] [target]
|
|
96
|
+
harness migrate-plan [--json] [--limit n] [target]
|
|
97
|
+
harness migrate-run [--locale zh-CN|en-US] [--assume-locale] [--allow-dirty] [--plan-only] [--out-dir folder] [--session-dir folder] [target]
|
|
98
|
+
harness migrate-verify [--json] [--full-cutover] <session.json>
|
|
99
|
+
harness new-task <task-id> [--module key] [--budget simple|standard|complex] [--preset legacy-migration] [--from-session session.json] [--long-running] [--title title] [--locale zh-CN|en-US] [--dry-run] [target]
|
|
100
|
+
harness task-start <task-id> [--message text] [target]
|
|
101
|
+
harness task-phase <task-id> <phase-id> [--state done] [--completion 100] [--evidence present] [target]
|
|
102
|
+
harness task-log <task-id> --message text [--evidence type:PATH:summary] [target]
|
|
103
|
+
harness task-block <task-id> [--message text] [target]
|
|
104
|
+
harness task-review <task-id> [--message text] [target]
|
|
105
|
+
harness review-confirm <task-id> --confirm task-id [--reviewer name] [--message text] [target]
|
|
106
|
+
harness lesson-promote <task-id> <candidate-id> [--dry-run] [target]
|
|
107
|
+
harness task-complete <task-id> [--message text] [target]
|
|
108
|
+
harness task-list [--json] [--state state] [--module key] [target]
|
|
109
|
+
harness module-step <module-key> <step-id> [--state done|in-progress|blocked] [target]
|
|
82
110
|
harness install-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir] [--dry-run] [--force] [--yes]
|
|
83
111
|
harness doctor-user [--agent codex|claude|gemini|openclaw|agents|all] [--home dir]
|
|
84
112
|
|
|
@@ -106,6 +134,9 @@ if (command === "help" || command === "--help" || command === "-h") {
|
|
|
106
134
|
for (const required of ["package.json", "scripts/harness.mjs", "scripts/check-harness.mjs", "templates/planning/task_plan.md"]) {
|
|
107
135
|
if (!fs.existsSync(path.resolve(target, required))) failures.push(`missing source package file: ${required}`);
|
|
108
136
|
}
|
|
137
|
+
const boundary = validateSourcePackageBoundary(target);
|
|
138
|
+
failures.push(...boundary.failures);
|
|
139
|
+
warnings.push(...boundary.warnings);
|
|
109
140
|
}
|
|
110
141
|
|
|
111
142
|
const status = buildStatus(target, { skipLegacyCheck: profile === "source-package", strictLegacy: strict, strict });
|
|
@@ -127,27 +158,88 @@ if (command === "help" || command === "--help" || command === "-h") {
|
|
|
127
158
|
console.log(`capabilities: ${status.capabilities.map((capability) => `${capability.name}:${capability.state}`).join(", ")}`);
|
|
128
159
|
console.log(`tasks: ${status.tasks.length}`);
|
|
129
160
|
}
|
|
130
|
-
process.
|
|
161
|
+
process.exitCode = status.checkState.status === "fail" ? 1 : 0;
|
|
162
|
+
} else if (command === "dev") {
|
|
163
|
+
const open = !takeFlag("--no-open");
|
|
164
|
+
const outDir = takeOption("--out-dir", "");
|
|
165
|
+
const host = takeOption("--host", "127.0.0.1");
|
|
166
|
+
const port = takeOption("--port", "0");
|
|
167
|
+
const localeOverride = takeOption("--locale", "");
|
|
168
|
+
const target = targetArg();
|
|
169
|
+
const dashboardOutDir = outDir || defaultDevOutDir(target);
|
|
170
|
+
const opts = localeOverride ? { localeOverride } : {};
|
|
171
|
+
try {
|
|
172
|
+
await serveDashboardWorkbench(dashboardOutDir, target, { ...opts, host, port, autoRefresh: true, open, label: "harness dev" });
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(error.message);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
131
177
|
} else if (command === "dashboard") {
|
|
178
|
+
const watch = takeFlag("--watch");
|
|
179
|
+
const workbench = takeFlag("--workbench");
|
|
132
180
|
const out = takeOption("--out", "harness-dashboard.html");
|
|
133
181
|
const outDir = takeOption("--out-dir", "");
|
|
182
|
+
const host = takeOption("--host", "127.0.0.1");
|
|
183
|
+
const port = takeOption("--port", "0");
|
|
184
|
+
const localeOverride = takeOption("--locale", "");
|
|
185
|
+
const opts = localeOverride ? { localeOverride } : {};
|
|
186
|
+
if (workbench) {
|
|
187
|
+
if (!outDir) {
|
|
188
|
+
console.error("dashboard --workbench requires --out-dir so regenerated data has a stable folder");
|
|
189
|
+
process.exit(2);
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
await serveDashboardWorkbench(outDir, targetArg(), { ...opts, host, port });
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error(error.message);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (watch) {
|
|
199
|
+
if (!outDir) {
|
|
200
|
+
console.error("dashboard --watch requires --out-dir so updates are written to a stable folder");
|
|
201
|
+
process.exit(2);
|
|
202
|
+
}
|
|
203
|
+
const target = targetArg();
|
|
204
|
+
const docsRoot = path.basename(path.resolve(target)) === "docs" ? path.resolve(target) : path.join(path.resolve(target), "docs");
|
|
205
|
+
const regenerate = () => {
|
|
206
|
+
try {
|
|
207
|
+
console.log(writeDashboardFolder(outDir, target, opts));
|
|
208
|
+
console.log(`dashboard regenerated: ${new Date().toISOString()}`);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.error(`dashboard regeneration failed: ${error.message}`);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
regenerate();
|
|
214
|
+
let timer = null;
|
|
215
|
+
const watcher = fs.watch(docsRoot, { recursive: true }, () => {
|
|
216
|
+
clearTimeout(timer);
|
|
217
|
+
timer = setTimeout(regenerate, 300);
|
|
218
|
+
});
|
|
219
|
+
const close = () => {
|
|
220
|
+
watcher.close();
|
|
221
|
+
clearTimeout(timer);
|
|
222
|
+
process.exit(0);
|
|
223
|
+
};
|
|
224
|
+
process.on("SIGINT", close);
|
|
225
|
+
process.on("SIGTERM", close);
|
|
226
|
+
console.log(`watching ${docsRoot}`);
|
|
227
|
+
await new Promise(() => {});
|
|
228
|
+
}
|
|
134
229
|
if (outDir) {
|
|
135
|
-
console.log(writeDashboardFolder(outDir, targetArg()));
|
|
230
|
+
console.log(writeDashboardFolder(outDir, targetArg(), opts));
|
|
136
231
|
} else {
|
|
137
|
-
|
|
138
|
-
const html = renderDashboard(status);
|
|
139
|
-
fs.mkdirSync(path.dirname(path.resolve(out)), { recursive: true });
|
|
140
|
-
fs.writeFileSync(path.resolve(out), html);
|
|
141
|
-
console.log(path.resolve(out));
|
|
232
|
+
console.log(writeDashboardSingleFile(out, targetArg(), opts));
|
|
142
233
|
}
|
|
143
234
|
process.exit(0);
|
|
144
235
|
} else if (command === "init") {
|
|
145
236
|
const dryRun = takeFlag("--dry-run");
|
|
237
|
+
const addNpmScripts = takeFlag("--add-npm-scripts");
|
|
146
238
|
const locale = await resolveInitLocale(takeOption("--locale", ""));
|
|
147
239
|
const capabilities = takeOption("--capabilities", "core").split(",").map((item) => item.trim()).filter(Boolean);
|
|
148
240
|
try {
|
|
149
|
-
const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale });
|
|
150
|
-
console.log(JSON.stringify({ dryRun, locale: result.locale, capabilities: result.capabilities, changes: result.changes, report: result.report }, null, 2));
|
|
241
|
+
const result = writeInitFiles(targetArg(), capabilities, { dryRun, locale, addNpmScripts });
|
|
242
|
+
console.log(JSON.stringify({ dryRun, locale: result.locale, capabilities: result.capabilities, changes: result.changes, nextCommands: result.nextCommands, report: result.report }, null, 2));
|
|
151
243
|
} catch (error) {
|
|
152
244
|
console.error(error.message);
|
|
153
245
|
process.exit(1);
|
|
@@ -167,6 +259,198 @@ if (command === "help" || command === "--help" || command === "-h") {
|
|
|
167
259
|
console.error(error.message);
|
|
168
260
|
process.exit(1);
|
|
169
261
|
}
|
|
262
|
+
} else if (command === "migrate-plan") {
|
|
263
|
+
const json = takeFlag("--json");
|
|
264
|
+
const limit = Number.parseInt(takeOption("--limit", "20"), 10) || 20;
|
|
265
|
+
try {
|
|
266
|
+
const plan = buildMigrationPlan(targetArg(), { limit });
|
|
267
|
+
if (json) {
|
|
268
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
269
|
+
} else {
|
|
270
|
+
console.log(`Migration Plan: ${plan.target}`);
|
|
271
|
+
console.log(`mode: ${plan.mode}`);
|
|
272
|
+
console.log(`warnings: ${plan.summary.warnings}`);
|
|
273
|
+
console.log(`task actions: ${plan.summary.taskActions}`);
|
|
274
|
+
console.log(`visual map actions: ${plan.summary.visualMapActions}`);
|
|
275
|
+
console.log(`legacy visual-only tasks: ${plan.summary.legacyVisualOnly}`);
|
|
276
|
+
console.log(`weak briefs: ${plan.summary.weakBrief}`);
|
|
277
|
+
console.log(`unknown classifications: ${plan.summary.unknownClassification}`);
|
|
278
|
+
console.log(`full cutover eligible: ${plan.summary.fullCutoverEligible ? "yes" : "no"}`);
|
|
279
|
+
console.log(`review actions: ${plan.summary.reviewSchemaGaps}`);
|
|
280
|
+
console.log(`legacy actions: ${plan.summary.legacyReferenceGaps}`);
|
|
281
|
+
console.log(`legacy residuals: ${plan.summary.legacyResiduals}`);
|
|
282
|
+
console.log(`recommended capabilities: ${plan.summary.recommendedCapabilities.join(", ") || "none"}`);
|
|
283
|
+
console.log("\nPhases:");
|
|
284
|
+
for (const phase of plan.phases) console.log(`- ${phase.id}: ${phase.title}`);
|
|
285
|
+
console.log("\nTop task actions:");
|
|
286
|
+
for (const action of plan.taskActions) console.log(`- ${action.taskId}: add ${action.files.join(", ")}`);
|
|
287
|
+
console.log("\nTop review actions:");
|
|
288
|
+
for (const action of plan.reviewActions) console.log(`- ${action.path}: add ${action.missing.join(", ")}`);
|
|
289
|
+
console.log("\nTop legacy residuals:");
|
|
290
|
+
for (const action of plan.legacyResiduals) console.log(`- ${action.taskId}: ${action.missing} (${action.reason})`);
|
|
291
|
+
console.log("\nNext commands:");
|
|
292
|
+
for (const next of plan.nextCommands) console.log(`- ${next}`);
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
console.error(error.message);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
} else if (command === "migrate-run") {
|
|
299
|
+
const locale = takeOption("--locale", "");
|
|
300
|
+
const assumeLocale = takeFlag("--assume-locale");
|
|
301
|
+
const allowDirty = takeFlag("--allow-dirty");
|
|
302
|
+
const planOnly = takeFlag("--plan-only");
|
|
303
|
+
const outDir = takeOption("--out-dir", "");
|
|
304
|
+
const sessionDir = takeOption("--session-dir", "");
|
|
305
|
+
try {
|
|
306
|
+
console.log(
|
|
307
|
+
JSON.stringify(
|
|
308
|
+
runMigration(targetArg(), {
|
|
309
|
+
locale,
|
|
310
|
+
assumeLocale,
|
|
311
|
+
allowDirty,
|
|
312
|
+
planOnly,
|
|
313
|
+
outDir,
|
|
314
|
+
sessionDir,
|
|
315
|
+
}),
|
|
316
|
+
null,
|
|
317
|
+
2,
|
|
318
|
+
),
|
|
319
|
+
);
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error(error.message);
|
|
322
|
+
process.exit(1);
|
|
323
|
+
}
|
|
324
|
+
} else if (command === "migrate-verify") {
|
|
325
|
+
const json = takeFlag("--json");
|
|
326
|
+
const fullCutover = takeFlag("--full-cutover");
|
|
327
|
+
const sessionPath = args.shift();
|
|
328
|
+
if (!sessionPath) {
|
|
329
|
+
console.error("Missing session.json path");
|
|
330
|
+
process.exit(2);
|
|
331
|
+
}
|
|
332
|
+
const result = verifyMigrationSession(sessionPath, { fullCutover });
|
|
333
|
+
if (json) {
|
|
334
|
+
console.log(JSON.stringify(result, null, 2));
|
|
335
|
+
} else {
|
|
336
|
+
for (const failure of result.failures) console.error(`Failure: ${failure}`);
|
|
337
|
+
for (const warning of result.warnings) console.log(`Warning: ${warning}`);
|
|
338
|
+
console.log(`Migration verify ${result.status}: ${result.sessionPath}`);
|
|
339
|
+
}
|
|
340
|
+
process.exit(result.status === "pass" ? 0 : 1);
|
|
341
|
+
} else if (command === "new-task") {
|
|
342
|
+
const dryRun = takeFlag("--dry-run");
|
|
343
|
+
const locale = takeOption("--locale", "");
|
|
344
|
+
const title = takeOption("--title", "");
|
|
345
|
+
const moduleKey = takeOption("--module", "");
|
|
346
|
+
const budget = takeOption("--budget", "standard");
|
|
347
|
+
const preset = takeOption("--preset", "");
|
|
348
|
+
const fromSession = takeOption("--from-session", "");
|
|
349
|
+
const longRunning = takeFlag("--long-running");
|
|
350
|
+
const taskId = args.shift() || (fromSession ? "harness-v1-migration" : "");
|
|
351
|
+
if (!taskId) {
|
|
352
|
+
console.error("Missing task id");
|
|
353
|
+
process.exit(2);
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
console.log(JSON.stringify(createTask(targetArg(), taskId, { title, locale, dryRun, moduleKey, budget, longRunning, preset, fromSession }), null, 2));
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error(error.message);
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
} else if (command === "task-phase") {
|
|
362
|
+
const state = takeOption("--state", "");
|
|
363
|
+
const completion = takeOption("--completion", "");
|
|
364
|
+
const evidenceStatus = takeOption("--evidence", "");
|
|
365
|
+
const taskId = args.shift();
|
|
366
|
+
const phaseId = args.shift();
|
|
367
|
+
if (!taskId || !phaseId) {
|
|
368
|
+
console.error("Missing task id or phase id");
|
|
369
|
+
process.exit(2);
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
console.log(JSON.stringify(updateTaskPhase(targetArg(), taskId, phaseId, { state, completion, evidenceStatus }), null, 2));
|
|
373
|
+
} catch (error) {
|
|
374
|
+
console.error(error.message);
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
} else if (["task-start", "task-log", "task-block", "task-review", "task-complete"].includes(command)) {
|
|
378
|
+
const message = takeOption("--message", "");
|
|
379
|
+
const evidence = takeOption("--evidence", "");
|
|
380
|
+
const taskId = args.shift();
|
|
381
|
+
if (!taskId) {
|
|
382
|
+
console.error("Missing task id");
|
|
383
|
+
process.exit(2);
|
|
384
|
+
}
|
|
385
|
+
const lifecycle = {
|
|
386
|
+
"task-start": { event: "task-start", state: "in_progress" },
|
|
387
|
+
"task-log": { event: "task-log", state: "" },
|
|
388
|
+
"task-block": { event: "task-block", state: "blocked" },
|
|
389
|
+
"task-review": { event: "task-review", state: "review" },
|
|
390
|
+
"task-complete": { event: "task-complete", state: "done" },
|
|
391
|
+
}[command];
|
|
392
|
+
try {
|
|
393
|
+
console.log(JSON.stringify(updateTaskLifecycle(targetArg(), taskId, { ...lifecycle, message, evidence }), null, 2));
|
|
394
|
+
} catch (error) {
|
|
395
|
+
console.error(error.message);
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
} else if (command === "review-confirm") {
|
|
399
|
+
const reviewer = takeOption("--reviewer", "Human Reviewer");
|
|
400
|
+
const message = takeOption("--message", "");
|
|
401
|
+
const evidence = takeOption("--evidence", "");
|
|
402
|
+
const confirmText = takeOption("--confirm", "");
|
|
403
|
+
const taskId = args.shift();
|
|
404
|
+
if (!taskId) {
|
|
405
|
+
console.error("Missing task id");
|
|
406
|
+
process.exit(2);
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
console.log(JSON.stringify(confirmTaskReview(targetArg(), taskId, { reviewer, message, evidence, confirmText }), null, 2));
|
|
410
|
+
} catch (error) {
|
|
411
|
+
console.error(error.message);
|
|
412
|
+
process.exit(1);
|
|
413
|
+
}
|
|
414
|
+
} else if (command === "lesson-promote") {
|
|
415
|
+
const dryRun = takeFlag("--dry-run");
|
|
416
|
+
const taskId = args.shift();
|
|
417
|
+
const candidateId = args.shift();
|
|
418
|
+
if (!taskId || !candidateId) {
|
|
419
|
+
console.error("Missing task id or candidate id");
|
|
420
|
+
process.exit(2);
|
|
421
|
+
}
|
|
422
|
+
try {
|
|
423
|
+
console.log(JSON.stringify(promoteLessonCandidate(targetArg(), taskId, candidateId, { dryRun }), null, 2));
|
|
424
|
+
} catch (error) {
|
|
425
|
+
console.error(error.message);
|
|
426
|
+
process.exit(1);
|
|
427
|
+
}
|
|
428
|
+
} else if (command === "task-list") {
|
|
429
|
+
const json = takeFlag("--json");
|
|
430
|
+
const state = takeOption("--state", "");
|
|
431
|
+
const moduleKey = takeOption("--module", "");
|
|
432
|
+
const result = listLifecycleTasks(targetArg(), { state, moduleKey });
|
|
433
|
+
if (json) {
|
|
434
|
+
console.log(JSON.stringify(result, null, 2));
|
|
435
|
+
} else {
|
|
436
|
+
for (const task of result.tasks) {
|
|
437
|
+
console.log(`${task.id}\t${task.state}\t${task.completion}%\t${task.title}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
} else if (command === "module-step") {
|
|
441
|
+
const state = takeOption("--state", "done");
|
|
442
|
+
const moduleKey = args.shift();
|
|
443
|
+
const stepId = args.shift();
|
|
444
|
+
if (!moduleKey || !stepId) {
|
|
445
|
+
console.error("Missing module key or step id");
|
|
446
|
+
process.exit(2);
|
|
447
|
+
}
|
|
448
|
+
try {
|
|
449
|
+
console.log(JSON.stringify(updateModuleStep(targetArg(), moduleKey, stepId, { state }), null, 2));
|
|
450
|
+
} catch (error) {
|
|
451
|
+
console.error(error.message);
|
|
452
|
+
process.exit(1);
|
|
453
|
+
}
|
|
170
454
|
} else if (command === "install-user") {
|
|
171
455
|
const dryRun = takeFlag("--dry-run");
|
|
172
456
|
const force = takeFlag("--force");
|
|
@@ -199,3 +483,10 @@ if (command === "help" || command === "--help" || command === "-h") {
|
|
|
199
483
|
printHelp();
|
|
200
484
|
process.exit(2);
|
|
201
485
|
}
|
|
486
|
+
|
|
487
|
+
function defaultDevOutDir(targetInput) {
|
|
488
|
+
const target = path.resolve(targetInput || ".");
|
|
489
|
+
const name = path.basename(target) || "project";
|
|
490
|
+
const hash = Buffer.from(target).toString("hex").slice(0, 16);
|
|
491
|
+
return path.join(os.tmpdir(), "coding-agent-harness-dev", `${name}-${hash}`);
|
|
492
|
+
}
|