coding-agent-harness 1.0.4 → 1.0.6
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 +7 -0
- package/CONTRIBUTING.md +2 -2
- package/LICENSE +661 -21
- package/LICENSE-EXCEPTION.md +37 -0
- package/README.md +96 -4
- package/README.zh-CN.md +75 -4
- package/SKILL.md +52 -51
- package/dist/build-dist.mjs +189 -0
- package/dist/check-dist-observation.mjs +428 -0
- package/dist/check-harness.mjs +489 -0
- package/dist/check-import-graph.mjs +511 -0
- package/dist/check-runtime-emit.mjs +304 -0
- package/dist/check-type-boundaries.mjs +139 -0
- package/dist/commands/dashboard-command.mjs +80 -0
- package/dist/commands/migration-command.mjs +152 -0
- package/dist/commands/preset-command.mjs +91 -0
- package/dist/commands/task-command.mjs +324 -0
- package/dist/harness.mjs +304 -0
- package/dist/lib/capability-registry.mjs +643 -0
- package/dist/lib/check-module-parallel.mjs +227 -0
- package/dist/lib/check-profiles.mjs +414 -0
- package/dist/lib/check-task-contracts.mjs +54 -0
- package/dist/lib/core-shared.mjs +254 -0
- package/dist/lib/dashboard-data.mjs +608 -0
- package/dist/lib/dashboard-workbench.mjs +334 -0
- package/dist/lib/dashboard-writer.mjs +200 -0
- package/dist/lib/git-status-summary.mjs +45 -0
- package/dist/lib/governance-index-generator.mjs +236 -0
- package/dist/lib/governance-sync.mjs +617 -0
- package/dist/lib/governance-table-boundary.mjs +161 -0
- package/{scripts → dist}/lib/harness-core.mjs +3 -0
- package/dist/lib/harness-paths.mjs +338 -0
- package/dist/lib/lesson-maintenance.mjs +139 -0
- package/dist/lib/markdown-utils.mjs +193 -0
- package/dist/lib/migration-planner.mjs +439 -0
- package/dist/lib/migration-support.mjs +317 -0
- package/dist/lib/phase-kind.mjs +46 -0
- package/dist/lib/preset-audit-contracts.mjs +40 -0
- package/dist/lib/preset-engine.mjs +516 -0
- package/dist/lib/preset-registry.mjs +831 -0
- package/dist/lib/preset-resource-contracts.mjs +83 -0
- package/dist/lib/review-confirm-git-gate.mjs +244 -0
- package/dist/lib/status-builder.mjs +87 -0
- package/{scripts → dist}/lib/status-dashboard-renderer.mjs +48 -47
- package/dist/lib/structure-migration.mjs +404 -0
- package/dist/lib/subagent-authorization-audit.mjs +198 -0
- package/dist/lib/task-audit-metadata.mjs +376 -0
- package/dist/lib/task-audit-migration.mjs +355 -0
- package/dist/lib/task-completion-consistency.mjs +29 -0
- package/dist/lib/task-index.mjs +133 -0
- package/dist/lib/task-lesson-candidates.mjs +239 -0
- package/dist/lib/task-lesson-sedimentation.mjs +300 -0
- package/dist/lib/task-lifecycle/create-task-helpers.mjs +84 -0
- package/dist/lib/task-lifecycle/phase-sync.mjs +82 -0
- package/dist/lib/task-lifecycle/review-confirm.mjs +93 -0
- package/dist/lib/task-lifecycle/review-gates.mjs +62 -0
- package/dist/lib/task-lifecycle/review-submission.mjs +52 -0
- package/dist/lib/task-lifecycle/scaffold-provenance.mjs +54 -0
- package/dist/lib/task-lifecycle/template-files.mjs +52 -0
- package/dist/lib/task-lifecycle/text-utils.mjs +26 -0
- package/dist/lib/task-lifecycle.mjs +611 -0
- package/dist/lib/task-metadata.mjs +116 -0
- package/dist/lib/task-review-model.mjs +474 -0
- package/dist/lib/task-scanner.mjs +439 -0
- package/dist/lib/task-tombstone-commands.mjs +125 -0
- package/dist/postinstall.mjs +14 -0
- package/dist/run-built-tests.mjs +84 -0
- package/docs-release/README.md +1 -0
- package/docs-release/architecture/overview.md +13 -13
- package/docs-release/architecture/overview.zh-CN.md +13 -13
- package/docs-release/architecture/system-explainer/01-system-overview.md +218 -0
- package/docs-release/architecture/system-explainer/02-module-dependency.md +257 -0
- package/docs-release/architecture/system-explainer/03-task-lifecycle.md +304 -0
- package/docs-release/architecture/system-explainer/04-check-and-governance.md +241 -0
- package/docs-release/architecture/system-explainer/05-data-flow.md +276 -0
- package/docs-release/architecture/system-explainer/06-preset-and-migration.md +300 -0
- package/docs-release/architecture/system-explainer/README.md +67 -0
- package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +227 -0
- package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +263 -0
- package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +319 -0
- package/docs-release/architecture/system-explainer/en-US/04-check-and-governance.md +252 -0
- package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +290 -0
- package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +320 -0
- package/docs-release/architecture/system-explainer/en-US/README.md +70 -0
- package/docs-release/guides/agent-installation.en-US.md +22 -15
- package/docs-release/guides/agent-installation.md +23 -15
- package/docs-release/guides/contributing.md +3 -3
- package/docs-release/guides/contributing.zh-CN.md +3 -3
- package/docs-release/guides/document-audience-and-surfaces.en-US.md +10 -10
- package/docs-release/guides/document-audience-and-surfaces.md +10 -10
- package/docs-release/guides/legacy-migration-agent-prompt.md +25 -2
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +25 -2
- package/docs-release/guides/migration-playbook.en-US.md +63 -1
- package/docs-release/guides/migration-playbook.md +59 -1
- package/docs-release/guides/parent-control-repository-pattern.en-US.md +25 -25
- package/docs-release/guides/parent-control-repository-pattern.md +25 -25
- package/docs-release/guides/preset-development.md +28 -4
- package/docs-release/guides/repository-operating-models.en-US.md +21 -21
- package/docs-release/guides/repository-operating-models.md +21 -21
- package/docs-release/guides/task-state-machine.en-US.md +35 -18
- package/docs-release/guides/task-state-machine.md +35 -18
- package/docs-release/guides/typescript-runtime-migration-closeout.md +96 -0
- package/examples/minimal-project/AGENTS.md +2 -2
- package/examples/minimal-project/coding-agent-harness/harness.yaml +14 -0
- package/examples/minimal-project/coding-agent-harness/planning/tasks/demo-task/INDEX.md +60 -0
- package/examples/minimal-project/coding-agent-harness/planning/tasks/demo-task/progress.md +11 -0
- package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/review.md +1 -1
- package/package.json +22 -13
- 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/standard-task/preset.yaml +2 -2
- package/references/adversarial-review-standard.md +2 -2
- package/references/agents-md-pattern.md +14 -14
- package/references/cadence-ledger.md +1 -1
- package/references/ci-cd-standard.md +1 -1
- package/references/delivery-operating-model-standard.md +4 -4
- package/references/docs-directory-standard.md +65 -159
- package/references/external-source-intake-standard.md +10 -10
- package/references/harness-ledger.md +6 -6
- package/references/legacy-12-phase-bootstrap.md +2 -2
- package/references/lessons-governance.md +15 -15
- package/references/long-running-task-standard.md +6 -6
- package/references/module-parallel-standard.md +34 -34
- package/references/planning-loop.md +6 -6
- package/references/project-onboarding-audit.md +4 -4
- package/references/regression-system.md +2 -2
- package/references/repo-governance-standard.md +4 -4
- package/references/review-routing-standard.md +1 -1
- package/references/ssot-governance.md +19 -19
- package/references/taskr-gap-analysis.md +5 -5
- package/references/walkthrough-closeout.md +14 -14
- package/references/worktree-parallel.md +3 -3
- package/skills/preset-creator/references/complex-task-skeleton/brief.md +11 -0
- package/skills/preset-creator/references/complex-task-skeleton/task_plan.md +1 -1
- package/skills/preset-creator/references/preset-package-skeleton.md +5 -5
- package/templates/AGENTS.md.template +31 -29
- package/templates/architecture/README.md +4 -4
- 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 +12 -0
- package/templates/dashboard/assets/app-src/10-router.js +3 -0
- package/templates/dashboard/assets/app-src/20-overview.js +13 -3
- package/templates/dashboard/assets/app-src/35-task-detail.js +46 -6
- package/templates/dashboard/assets/app-src/40-modules.js +1 -1
- package/templates/dashboard/assets/app-src/55-presets.js +375 -0
- package/templates/dashboard/assets/app-src/60-shared.js +3 -1
- package/templates/dashboard/assets/app-src/90-bindings.js +131 -0
- package/templates/dashboard/assets/app.css +583 -0
- package/templates/dashboard/assets/app.css.manifest.json +1 -0
- package/templates/dashboard/assets/app.js +585 -11
- package/templates/dashboard/assets/app.manifest.json +1 -0
- package/templates/dashboard/assets/css-src/00-foundation.css +4 -0
- package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +62 -0
- package/templates/dashboard/assets/css-src/45-presets.css +516 -0
- package/templates/dashboard/assets/i18n.js +144 -4
- package/templates/development/README.md +10 -10
- package/templates/development/cross-repo-debugging.md +3 -3
- package/templates/development/external-context/service-template.md +2 -2
- package/templates/development/external-source-packs/README.md +4 -4
- package/templates/integrations/README.md +4 -4
- package/templates/integrations/api-contract.md +2 -2
- package/templates/integrations/event-contract.md +2 -2
- package/templates/integrations/third-party/vendor-template.md +2 -2
- package/templates/integrations/webhook-contract.md +2 -2
- package/templates/ledger/Harness-Ledger.md +1 -1
- package/templates/planning/INDEX.md +88 -0
- package/templates/planning/brief.md +1 -1
- package/templates/planning/module_session_prompt.md +2 -1
- package/templates/planning/review.md +0 -18
- package/templates/planning/task_plan.md +5 -44
- package/templates/planning/visual_map.md +13 -9
- package/templates/planning/visual_map.simple.md +52 -0
- package/templates/planning/walkthrough.md +47 -0
- package/templates/reference/docs-library-standard.md +8 -8
- package/templates/reference/execution-workflow-standard.md +29 -2
- package/templates/reference/external-source-intake-standard.md +15 -15
- package/templates/reference/repo-governance-standard.md +1 -1
- package/templates/ssot/Module-Registry.md +1 -1
- package/templates/walkthrough/walkthrough-template.md +2 -2
- package/templates-zh-CN/AGENTS.md.template +31 -29
- package/templates-zh-CN/CLAUDE.md.template +1 -1
- package/templates-zh-CN/architecture/README.md +4 -4
- 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 +10 -10
- package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
- package/templates-zh-CN/development/external-context/service-template.md +2 -2
- package/templates-zh-CN/development/external-source-packs/README.md +4 -4
- package/templates-zh-CN/integrations/README.md +4 -4
- package/templates-zh-CN/integrations/api-contract.md +2 -2
- package/templates-zh-CN/integrations/event-contract.md +2 -2
- package/templates-zh-CN/integrations/third-party/vendor-template.md +2 -2
- package/templates-zh-CN/integrations/webhook-contract.md +2 -2
- 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/planning/INDEX.md +87 -0
- package/templates-zh-CN/planning/brief.md +1 -1
- package/templates-zh-CN/planning/module_session_prompt.md +12 -11
- package/templates-zh-CN/planning/review.md +0 -18
- package/templates-zh-CN/planning/task_plan.md +3 -63
- package/templates-zh-CN/planning/visual_map.md +14 -7
- package/templates-zh-CN/planning/visual_map.simple.md +48 -0
- package/templates-zh-CN/planning/walkthrough.md +47 -0
- package/templates-zh-CN/reference/adversarial-review-standard.md +2 -2
- package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
- package/templates-zh-CN/reference/docs-library-standard.md +28 -28
- package/templates-zh-CN/reference/execution-workflow-standard.md +32 -7
- package/templates-zh-CN/reference/external-source-intake-standard.md +16 -16
- package/templates-zh-CN/reference/harness-ledger-standard.md +6 -6
- 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 +1 -1
- package/templates-zh-CN/reference/walkthrough-standard.md +7 -7
- 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 +3 -3
- package/templates-zh-CN/ssot/Module-Registry.md +3 -3
- package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
- package/templates-zh-CN/walkthrough/walkthrough-template.md +5 -5
- package/tsconfig.dist.json +16 -0
- package/tsconfig.json +25 -0
- package/tsconfig.runtime.json +24 -0
- package/examples/minimal-project/.harness-capabilities.json +0 -8
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/progress.md +0 -11
- package/scripts/check-harness.mjs +0 -508
- package/scripts/commands/dashboard-command.mjs +0 -67
- package/scripts/commands/migration-command.mjs +0 -96
- package/scripts/commands/preset-command.mjs +0 -73
- package/scripts/commands/task-command.mjs +0 -327
- package/scripts/harness.mjs +0 -287
- package/scripts/lib/capability-registry.mjs +0 -591
- package/scripts/lib/check-module-parallel.mjs +0 -237
- package/scripts/lib/check-profiles.mjs +0 -418
- package/scripts/lib/check-task-contracts.mjs +0 -47
- package/scripts/lib/core-shared.mjs +0 -196
- package/scripts/lib/dashboard-data.mjs +0 -412
- package/scripts/lib/dashboard-workbench.mjs +0 -257
- package/scripts/lib/dashboard-writer.mjs +0 -198
- package/scripts/lib/git-status-summary.mjs +0 -46
- package/scripts/lib/governance-index-generator.mjs +0 -174
- package/scripts/lib/governance-sync.mjs +0 -514
- package/scripts/lib/governance-table-boundary.mjs +0 -175
- package/scripts/lib/lesson-maintenance.mjs +0 -152
- package/scripts/lib/markdown-utils.mjs +0 -158
- package/scripts/lib/migration-planner.mjs +0 -478
- package/scripts/lib/migration-support.mjs +0 -312
- package/scripts/lib/preset-audit-contracts.mjs +0 -37
- package/scripts/lib/preset-engine.mjs +0 -497
- package/scripts/lib/preset-registry.mjs +0 -627
- package/scripts/lib/preset-resource-contracts.mjs +0 -83
- package/scripts/lib/review-confirm-git-gate.mjs +0 -248
- package/scripts/lib/subagent-authorization-audit.mjs +0 -196
- package/scripts/lib/task-completion-consistency.mjs +0 -16
- package/scripts/lib/task-index.mjs +0 -93
- package/scripts/lib/task-lesson-candidates.mjs +0 -242
- package/scripts/lib/task-lesson-sedimentation.mjs +0 -326
- package/scripts/lib/task-lifecycle/review-confirm.mjs +0 -101
- package/scripts/lib/task-lifecycle/review-gates.mjs +0 -70
- package/scripts/lib/task-lifecycle/text-utils.mjs +0 -24
- package/scripts/lib/task-lifecycle.mjs +0 -649
- package/scripts/lib/task-review-model.mjs +0 -469
- package/scripts/lib/task-scanner.mjs +0 -576
- package/scripts/lib/task-tombstone-commands.mjs +0 -140
- package/scripts/postinstall.mjs +0 -14
- package/templates/walkthrough/Closeout-SSoT.md +0 -43
- package/templates-zh-CN/walkthrough/Closeout-SSoT.md +0 -42
- /package/examples/minimal-project/{docs → coding-agent-harness/governance/generated}/Harness-Ledger.md +0 -0
- /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/brief.md +0 -0
- /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/execution_strategy.md +0 -0
- /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/findings.md +0 -0
- /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/lesson_candidates.md +0 -0
- /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/task_plan.md +0 -0
- /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/visual_map.md +0 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Migration support scans dynamic target state until migration session domain types are modeled.
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
import { normalizeTarget, normalizeLocale, readFileSafe, existsInDocs, walkFiles, toPosix, sanitizeText, slug, visualMapFile, } from "./core-shared.mjs";
|
|
8
|
+
import { readCapabilityRegistry, detectCapabilities } from "./capability-registry.mjs";
|
|
9
|
+
import { buildStatus } from "./check-profiles.mjs";
|
|
10
|
+
import { listTaskPlanPaths } from "./task-scanner.mjs";
|
|
11
|
+
export function migrationSampleFiles(target) {
|
|
12
|
+
const candidates = [
|
|
13
|
+
path.join(target.projectRoot, "AGENTS.md"),
|
|
14
|
+
path.join(target.projectRoot, "CLAUDE.md"),
|
|
15
|
+
path.join(target.docsRoot, "Harness-Ledger.md"),
|
|
16
|
+
path.join(target.docsRoot, "05-TEST-QA/Regression-SSoT.md"),
|
|
17
|
+
path.join(target.docsRoot, "09-PLANNING/Delivery-SSoT.md"),
|
|
18
|
+
];
|
|
19
|
+
const taskPlans = listTaskPlanPaths(target).slice(0, 20);
|
|
20
|
+
return [...candidates, ...taskPlans].filter((file) => fs.existsSync(file));
|
|
21
|
+
}
|
|
22
|
+
export function probeTargetLocale(target) {
|
|
23
|
+
const files = migrationSampleFiles(target);
|
|
24
|
+
let hanChars = 0;
|
|
25
|
+
let latinWords = 0;
|
|
26
|
+
const signals = [];
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const content = readFileSafe(file).slice(0, 20000);
|
|
29
|
+
const han = content.match(/\p{Script=Han}/gu)?.length || 0;
|
|
30
|
+
const latin = content.match(/\b[A-Za-z][A-Za-z-]{2,}\b/g)?.length || 0;
|
|
31
|
+
hanChars += han;
|
|
32
|
+
latinWords += latin;
|
|
33
|
+
if (han > 0 || latin > 0) {
|
|
34
|
+
signals.push({
|
|
35
|
+
path: `TARGET:${toPosix(path.relative(target.projectRoot, file))}`,
|
|
36
|
+
hanChars: han,
|
|
37
|
+
latinWords: latin,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const suggested = hanChars > 0 && hanChars >= latinWords * 0.4 ? "zh-CN" : "en-US";
|
|
42
|
+
const mixedLanguageDetected = hanChars >= 10 && latinWords >= 15;
|
|
43
|
+
const confidence = mixedLanguageDetected ? "requires-human-choice" : hanChars > 0 || latinWords > 0 ? "medium" : "low";
|
|
44
|
+
return { suggested, confidence, mixedLanguageDetected, signals: signals.slice(0, 12), totals: { hanChars, latinWords } };
|
|
45
|
+
}
|
|
46
|
+
export function inspectGitStatus(projectRoot) {
|
|
47
|
+
const probe = spawnSync("git", ["-C", projectRoot, "rev-parse", "--is-inside-work-tree"], { encoding: "utf8" });
|
|
48
|
+
if (probe.status !== 0)
|
|
49
|
+
return { inGit: false, branch: "", entries: [], staged: [], dirty: false };
|
|
50
|
+
const result = spawnSync("git", ["-C", projectRoot, "status", "--short", "--branch"], { encoding: "utf8" });
|
|
51
|
+
const lines = (result.stdout || "").split(/\r?\n/).filter(Boolean);
|
|
52
|
+
const entries = lines.filter((line) => !line.startsWith("## "));
|
|
53
|
+
const staged = entries.filter((line) => line.length >= 2 && line[0] !== " " && line[0] !== "?");
|
|
54
|
+
return {
|
|
55
|
+
inGit: true,
|
|
56
|
+
branch: lines.find((line) => line.startsWith("## ")) || "",
|
|
57
|
+
entries,
|
|
58
|
+
staged,
|
|
59
|
+
dirty: entries.length > 0,
|
|
60
|
+
error: result.status === 0 ? "" : result.stderr || result.stdout || `git status exited ${result.status}`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function ensureSessionDir(projectName, requestedDir = "") {
|
|
64
|
+
const base = requestedDir
|
|
65
|
+
? path.resolve(requestedDir)
|
|
66
|
+
: path.join(os.tmpdir(), `cah-migration-${slug(projectName)}-${new Date().toISOString().replace(/[:.]/g, "-")}`);
|
|
67
|
+
fs.mkdirSync(base, { recursive: true });
|
|
68
|
+
return base;
|
|
69
|
+
}
|
|
70
|
+
export function statusCheckSummary(status) {
|
|
71
|
+
return {
|
|
72
|
+
status: status.checkState.status,
|
|
73
|
+
failures: status.checkState.failures,
|
|
74
|
+
warnings: status.checkState.warnings,
|
|
75
|
+
legacyStatus: status.checkState.legacy?.status || "skipped",
|
|
76
|
+
failureDetails: status.checkState.details.failures,
|
|
77
|
+
warningDetails: status.checkState.details.warnings,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function strictDeferredFromStatus(strictStatus) {
|
|
81
|
+
const failures = strictStatus.checkState.details.failures;
|
|
82
|
+
if (strictStatus.checkState.status !== "fail")
|
|
83
|
+
return null;
|
|
84
|
+
return {
|
|
85
|
+
owner: "migration-owner",
|
|
86
|
+
trigger: "strict-cutover",
|
|
87
|
+
nextAction: "Classify each strict failure as active migration work or accepted historical residual, then rerun migrate-verify.",
|
|
88
|
+
reason: "Normal migration can be adopted while strict cutover remains deferred for historical contract gaps.",
|
|
89
|
+
failureCount: failures.length,
|
|
90
|
+
failures,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function writeMigrationReport(session) {
|
|
94
|
+
const lines = [
|
|
95
|
+
`# Coding Agent Harness Migration Report`,
|
|
96
|
+
"",
|
|
97
|
+
`- Target: ${session.target}`,
|
|
98
|
+
`- Result: ${session.result}`,
|
|
99
|
+
`- Locale: ${session.localeDecision.selected}`,
|
|
100
|
+
`- Locale confidence: ${session.localeDecision.probe.confidence}`,
|
|
101
|
+
`- Dashboard: ${session.dashboard?.indexPath || "not generated"}`,
|
|
102
|
+
`- Normal check: ${session.checks.normal.status} (${session.checks.normal.failures} failures, ${session.checks.normal.warnings} warnings)`,
|
|
103
|
+
`- Strict check: ${session.checks.strict.status} (${session.checks.strict.failures} failures, ${session.checks.strict.warnings} warnings)`,
|
|
104
|
+
"",
|
|
105
|
+
"## Capabilities",
|
|
106
|
+
"",
|
|
107
|
+
...session.capabilities.map((capability) => `- ${capability.name}: ${capability.state || "configured"}`),
|
|
108
|
+
"",
|
|
109
|
+
"## Warning Summary",
|
|
110
|
+
"",
|
|
111
|
+
`- Total: ${session.plan.summary.warnings}`,
|
|
112
|
+
`- Active task actions: ${session.plan.summary.taskActions}`,
|
|
113
|
+
`- Visual map actions: ${session.plan.summary.visualMapActions || 0}`,
|
|
114
|
+
`- Legacy visual-only tasks: ${session.plan.summary.legacyVisualOnly || 0}`,
|
|
115
|
+
`- Weak briefs: ${session.plan.summary.weakBrief || 0}`,
|
|
116
|
+
`- Unknown classifications: ${session.plan.summary.unknownClassification || 0}`,
|
|
117
|
+
`- Full cutover eligible: ${session.plan.summary.fullCutoverEligible === true ? "yes" : "no"}`,
|
|
118
|
+
`- Review schema gaps: ${session.plan.summary.reviewSchemaGaps}`,
|
|
119
|
+
`- Legacy residuals: ${session.plan.summary.legacyResiduals}`,
|
|
120
|
+
"",
|
|
121
|
+
"## Strict Deferred",
|
|
122
|
+
"",
|
|
123
|
+
];
|
|
124
|
+
if (session.strictDeferred) {
|
|
125
|
+
lines.push(`- Owner: ${session.strictDeferred.owner}`);
|
|
126
|
+
lines.push(`- Trigger: ${session.strictDeferred.trigger}`);
|
|
127
|
+
lines.push(`- Next action: ${session.strictDeferred.nextAction}`);
|
|
128
|
+
lines.push(`- Failure count: ${session.strictDeferred.failureCount}`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
lines.push("- none");
|
|
132
|
+
}
|
|
133
|
+
lines.push("", "## Next Commands", "");
|
|
134
|
+
for (const command of session.plan.nextCommands)
|
|
135
|
+
lines.push(`- \`${command}\``);
|
|
136
|
+
return `${lines.join("\n")}\n`;
|
|
137
|
+
}
|
|
138
|
+
export function validateFullCutoverSession(session, failures) {
|
|
139
|
+
if (session.result !== "complete")
|
|
140
|
+
failures.push(`full cutover requires result complete, got ${session.result || "(none)"}`);
|
|
141
|
+
if (session.strictDeferred)
|
|
142
|
+
failures.push("full cutover cannot have strictDeferred");
|
|
143
|
+
if (session.checks?.strict?.status !== "pass")
|
|
144
|
+
failures.push("full cutover requires recorded strict check pass");
|
|
145
|
+
if (session.plan?.mode !== "declared-capability")
|
|
146
|
+
failures.push(`full cutover requires migrate-plan mode declared-capability, got ${session.plan?.mode || "(none)"}`);
|
|
147
|
+
const summary = session.plan?.summary || {};
|
|
148
|
+
for (const [field, value] of [
|
|
149
|
+
["warnings", summary.warnings],
|
|
150
|
+
["visualMapActions", summary.visualMapActions],
|
|
151
|
+
["legacyVisualOnly", summary.legacyVisualOnly],
|
|
152
|
+
["unknownClassification", summary.unknownClassification],
|
|
153
|
+
["weakBrief", summary.weakBrief],
|
|
154
|
+
["missingCanonicalVisualMap", summary.missingCanonicalVisualMap],
|
|
155
|
+
["taskActions", summary.taskActions],
|
|
156
|
+
["reviewSchemaGaps", summary.reviewSchemaGaps],
|
|
157
|
+
["legacyReferenceGaps", summary.legacyReferenceGaps],
|
|
158
|
+
["legacyResiduals", summary.legacyResiduals],
|
|
159
|
+
]) {
|
|
160
|
+
if (Number(value || 0) !== 0)
|
|
161
|
+
failures.push(`full cutover requires ${field}=0, got ${value || 0}`);
|
|
162
|
+
}
|
|
163
|
+
if (summary.fullCutoverEligible !== true)
|
|
164
|
+
failures.push("full cutover requires summary.fullCutoverEligible=true");
|
|
165
|
+
if ((summary.recommendedCapabilities || []).length) {
|
|
166
|
+
failures.push(`full cutover has recommended capabilities: ${summary.recommendedCapabilities.join(", ")}`);
|
|
167
|
+
}
|
|
168
|
+
if (!session.target || !fs.existsSync(session.target))
|
|
169
|
+
return;
|
|
170
|
+
const status = buildStatus(session.target, { strict: true, strictLegacy: true, allowLegacyTarget: true });
|
|
171
|
+
if (status.checkState.status !== "pass")
|
|
172
|
+
failures.push(`full cutover current strict status is ${status.checkState.status}`);
|
|
173
|
+
for (const task of status.tasks) {
|
|
174
|
+
if (task.briefQuality?.status !== "pass")
|
|
175
|
+
failures.push(`${task.path} weak brief: ${(task.briefQuality?.issues || []).join(", ")}`);
|
|
176
|
+
if (task.migrationClassification === "unknown-needs-human")
|
|
177
|
+
failures.push(`${task.path} has unknown migration classification`);
|
|
178
|
+
if (task.visualMapStatus === "legacy-only")
|
|
179
|
+
failures.push(`${task.path} only has legacy visual_roadmap.md`);
|
|
180
|
+
if (["active", "reopened", "current-evidence", "historical-with-diagram"].includes(task.migrationClassification) && task.visualMapSource !== "canonical") {
|
|
181
|
+
failures.push(`${task.path} needs canonical visual_map.md for ${task.migrationClassification}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export function recommendedMigrationCapabilities(status, target, registry) {
|
|
186
|
+
const declared = new Set(registry.capabilities.map((capability) => capability.name));
|
|
187
|
+
const detected = new Set(detectCapabilities(target));
|
|
188
|
+
const recommendations = [];
|
|
189
|
+
if (!declared.has("safe-adoption")) {
|
|
190
|
+
recommendations.push({
|
|
191
|
+
name: "safe-adoption",
|
|
192
|
+
priority: "required",
|
|
193
|
+
reason: "The project has legacy harness artifacts or missing v1 registry; migration must preserve existing documents.",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
if (detected.has("long-running-task") && !declared.has("long-running-task")) {
|
|
197
|
+
recommendations.push({
|
|
198
|
+
name: "long-running-task",
|
|
199
|
+
priority: "candidate",
|
|
200
|
+
reason: "Long-running task artifacts exist; declare only if active work still uses continuous execution contracts.",
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const moduleRegistry = existsInDocs(target, "09-PLANNING/Module-Registry.md");
|
|
204
|
+
const modulePlans = walkFiles(path.join(target.docsRoot, "09-PLANNING/MODULES")).some((file) => file.endsWith("module_plan.md"));
|
|
205
|
+
if ((moduleRegistry || modulePlans) && !declared.has("module-parallel")) {
|
|
206
|
+
recommendations.push({
|
|
207
|
+
name: "module-parallel",
|
|
208
|
+
priority: "candidate",
|
|
209
|
+
reason: "Module planning artifacts already exist; verify owners, write scopes, and registry sync before declaring.",
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (status.checkState.details.warnings.some((warning) => /review/i.test(warning)) && !declared.has("adversarial-review")) {
|
|
213
|
+
recommendations.push({
|
|
214
|
+
name: "adversarial-review",
|
|
215
|
+
priority: "consider",
|
|
216
|
+
reason: "Review artifacts exist but may not use the v1 schema; declare when active release or architecture reviews are migrated.",
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return recommendations;
|
|
220
|
+
}
|
|
221
|
+
export function migrationPhases({ locale, recommendedCapabilities }) {
|
|
222
|
+
return [
|
|
223
|
+
{
|
|
224
|
+
id: "MP-01",
|
|
225
|
+
title: "Stabilize legacy state",
|
|
226
|
+
goal: "Record current harness state without rewriting historical documents.",
|
|
227
|
+
actions: ["Run safe-adoption dry-run", "Confirm locale", "Confirm current git status is understood"],
|
|
228
|
+
exitCriteria: [".harness-capabilities.json exists", "Existing AGENTS.md/CLAUDE.md/history are preserved"],
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: "MP-02",
|
|
232
|
+
title: "Choose capability cutover",
|
|
233
|
+
goal: "Declare only capabilities that match real project facts.",
|
|
234
|
+
actions: recommendedCapabilities.map((capability) => `Evaluate ${capability.name}: ${capability.reason}`),
|
|
235
|
+
exitCriteria: ["Capability registry has no accidental declarations", "Every optional capability has a project fact trigger"],
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
id: "MP-03",
|
|
239
|
+
title: "Classify tasks from SSoT before repairing contracts",
|
|
240
|
+
goal: "Use Harness Ledger, Closeout SSoT, Regression SSoT, task progress, walkthroughs, reviews, and git history to decide which tasks are actually current.",
|
|
241
|
+
actions: [
|
|
242
|
+
"Classify taskActions as current-active, closed-with-evidence, closed-with-residual, superseded, or unknown-history",
|
|
243
|
+
"Add brief.md, execution_strategy.md, visual_map.md only for current-active or reopened tasks",
|
|
244
|
+
"Route closed historical gaps as residuals instead of adding fake current templates",
|
|
245
|
+
],
|
|
246
|
+
exitCriteria: [
|
|
247
|
+
"Every repaired task cites SSoT/progress/walkthrough/review/git evidence",
|
|
248
|
+
"Closed historical tasks remain unchanged and have residual routing",
|
|
249
|
+
"Active task status is readable by status/dashboard",
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: "MP-04",
|
|
254
|
+
title: "Introduce modules if needed",
|
|
255
|
+
goal: "Move from single-line task history to module ownership only when the project has real independent domains.",
|
|
256
|
+
actions: ["Identify modules by product/domain, not file folders", "Create module registry after owner/write-scope decisions", "Route shared updates through coordinator"],
|
|
257
|
+
exitCriteria: ["Module owners and write scopes are explicit", "No worker owns shared global ledgers without coordinator sync"],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: "MP-05",
|
|
261
|
+
title: "Upgrade current reviews and references",
|
|
262
|
+
goal: "Bring only active review and reference gates to v1 schema.",
|
|
263
|
+
actions: ["Upgrade release-blocking reviews first", "Create missing reference files only for adopted capabilities", "Record accepted historical gaps as residuals"],
|
|
264
|
+
exitCriteria: ["Current release gates have v1 review evidence", "Legacy-only gaps are categorized as residuals"],
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
id: "MP-06",
|
|
268
|
+
title: "Strict cutover",
|
|
269
|
+
goal: "Turn strict checks into the blocking gate after migration scope is complete.",
|
|
270
|
+
actions: ["Run normal check until warnings are understood", "Run --strict after active work is migrated", "Keep residual owner/action/status for deferred history"],
|
|
271
|
+
exitCriteria: ["Strict check passes or every remaining failure has owner/action/status"],
|
|
272
|
+
},
|
|
273
|
+
].map((phase) => ({
|
|
274
|
+
...phase,
|
|
275
|
+
locale,
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
278
|
+
function splitWarningMessage(message) {
|
|
279
|
+
return String(message || "")
|
|
280
|
+
.split(/\n-\s+/)
|
|
281
|
+
.map((item, index) => (index === 0 ? item : `- ${item}`))
|
|
282
|
+
.filter(Boolean);
|
|
283
|
+
}
|
|
284
|
+
function warningTitle(message) {
|
|
285
|
+
if (/missing execution_strategy\.md/i.test(message))
|
|
286
|
+
return "Missing execution strategy";
|
|
287
|
+
if (/missing visual_map\.md|Visual Map/i.test(message))
|
|
288
|
+
return "Missing visual map";
|
|
289
|
+
if (/missing visual_roadmap\.md|Visual Roadmap/i.test(message))
|
|
290
|
+
return "Missing legacy visual roadmap";
|
|
291
|
+
if (/legacy-compat/i.test(message))
|
|
292
|
+
return "Legacy compatibility mode";
|
|
293
|
+
if (/legacy check failed/i.test(message))
|
|
294
|
+
return "Legacy checker finding";
|
|
295
|
+
if (/review\.md missing/i.test(message))
|
|
296
|
+
return "Review schema gap";
|
|
297
|
+
if (/findings table missing/i.test(message))
|
|
298
|
+
return "Review findings schema gap";
|
|
299
|
+
return String(message).split(":")[0].slice(0, 96);
|
|
300
|
+
}
|
|
301
|
+
function warningAffected(message) {
|
|
302
|
+
const target = String(message).match(/(?:docs|\.harness-private)\/[^\s:]+/);
|
|
303
|
+
return target ? target[0] : "project";
|
|
304
|
+
}
|
|
305
|
+
function warningAction(message) {
|
|
306
|
+
if (/execution_strategy\.md/i.test(message))
|
|
307
|
+
return "Add standalone execution strategy file.";
|
|
308
|
+
if (/visual_map\.md|Visual Map/i.test(message))
|
|
309
|
+
return "Add standalone visual map file.";
|
|
310
|
+
if (/visual_roadmap\.md|Visual Roadmap/i.test(message))
|
|
311
|
+
return "Rewrite legacy visual_roadmap.md into canonical visual_map.md.";
|
|
312
|
+
if (/review\.md missing/i.test(message))
|
|
313
|
+
return "Update review.md to v1 review schema.";
|
|
314
|
+
if (/legacy/i.test(message))
|
|
315
|
+
return "Review manually; do not auto-migrate.";
|
|
316
|
+
return "Inspect source document and decide whether to adopt v1 contract.";
|
|
317
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const allowedPhaseKinds = new Set(["init", "execution", "gate"]);
|
|
2
|
+
export const allowedPhaseActors = new Set(["agent", "human", "coordinator"]);
|
|
3
|
+
export function normalizePhaseKind(value) {
|
|
4
|
+
const normalized = String(value || "")
|
|
5
|
+
.replace(/`/g, "")
|
|
6
|
+
.trim()
|
|
7
|
+
.toLowerCase()
|
|
8
|
+
.replaceAll("_", "-");
|
|
9
|
+
if (!normalized)
|
|
10
|
+
return "execution";
|
|
11
|
+
if (normalized === "exec" || normalized === "implementation")
|
|
12
|
+
return "execution";
|
|
13
|
+
if (normalized === "prep" || normalized === "discussion")
|
|
14
|
+
return "init";
|
|
15
|
+
if (normalized === "review" || normalized === "closeout")
|
|
16
|
+
return "gate";
|
|
17
|
+
return normalized;
|
|
18
|
+
}
|
|
19
|
+
export function normalizePhaseActor(value) {
|
|
20
|
+
const normalized = String(value || "")
|
|
21
|
+
.replace(/`/g, "")
|
|
22
|
+
.trim()
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replaceAll("_", "-");
|
|
25
|
+
return normalized || "agent";
|
|
26
|
+
}
|
|
27
|
+
export function isExecutionPhase(phase) {
|
|
28
|
+
return normalizePhaseKind(phase?.kind) === "execution";
|
|
29
|
+
}
|
|
30
|
+
export function nonSkippedPhases(phases = []) {
|
|
31
|
+
return phases.filter((phase) => phase.state !== "skipped");
|
|
32
|
+
}
|
|
33
|
+
export function implementationPhases(phases = []) {
|
|
34
|
+
return nonSkippedPhases(phases).filter(isExecutionPhase);
|
|
35
|
+
}
|
|
36
|
+
export function phaseCompletionAverage(phases = []) {
|
|
37
|
+
const scored = implementationPhases(phases);
|
|
38
|
+
if (scored.length === 0)
|
|
39
|
+
return 0;
|
|
40
|
+
return Math.round(scored.reduce((sum, phase) => sum + phase.completion, 0) / scored.length);
|
|
41
|
+
}
|
|
42
|
+
export function phaseHasRecordedProgress(phase) {
|
|
43
|
+
return (phase.completion > 0 ||
|
|
44
|
+
["in_progress", "review", "blocked", "done"].includes(String(phase.state || "").toLowerCase()) ||
|
|
45
|
+
["partial", "present", "waived"].includes(String(phase.evidenceStatus || "").toLowerCase()));
|
|
46
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
// @ts-ignore core-shared remains a JS runtime dependency until its migration PR.
|
|
4
|
+
import { readFileSafe, toPosix } from "./core-shared.mjs";
|
|
5
|
+
export function validateTaskPresetAuditSnapshot(target, task, presetPackage) {
|
|
6
|
+
const failures = [];
|
|
7
|
+
if (!presetPackage?.audit?.manifestRequired)
|
|
8
|
+
return failures;
|
|
9
|
+
const bundle = String(task.evidenceBundle || "").replace(/^TARGET:/, "").replace(/^\/+/, "");
|
|
10
|
+
if (!bundle) {
|
|
11
|
+
failures.push(`${task.path} ${task.taskPreset} preset missing Evidence Bundle for manifest audit`);
|
|
12
|
+
return failures;
|
|
13
|
+
}
|
|
14
|
+
const auditPath = path.join(target.projectRoot, bundle, "preset-audit.json");
|
|
15
|
+
if (!fs.existsSync(auditPath)) {
|
|
16
|
+
failures.push(`${task.path} ${task.taskPreset} preset audit missing: TARGET:${toPosix(path.relative(target.projectRoot, auditPath))}`);
|
|
17
|
+
return failures;
|
|
18
|
+
}
|
|
19
|
+
let audit = null;
|
|
20
|
+
try {
|
|
21
|
+
audit = JSON.parse(readFileSafe(auditPath));
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
failures.push(`${task.path} ${task.taskPreset} preset audit invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
25
|
+
return failures;
|
|
26
|
+
}
|
|
27
|
+
if (audit.preset !== task.taskPreset) {
|
|
28
|
+
failures.push(`${task.path} ${task.taskPreset} preset audit id mismatch: ${audit.preset || "(missing)"}`);
|
|
29
|
+
}
|
|
30
|
+
if (String(audit.version || "") !== String(task.presetVersion || "")) {
|
|
31
|
+
failures.push(`${task.path} ${task.taskPreset} preset audit version mismatch: ${audit.version || "(missing)"}`);
|
|
32
|
+
}
|
|
33
|
+
if (!audit.manifestSha256) {
|
|
34
|
+
failures.push(`${task.path} ${task.taskPreset} preset audit missing manifestSha256`);
|
|
35
|
+
}
|
|
36
|
+
else if (audit.manifestSha256 !== presetPackage.manifestSha256) {
|
|
37
|
+
failures.push(`${task.path} ${task.taskPreset} preset manifest hash mismatch: task audit ${audit.manifestSha256}, current ${presetPackage.manifestSha256}`);
|
|
38
|
+
}
|
|
39
|
+
return failures;
|
|
40
|
+
}
|