coding-agent-harness 1.0.5 → 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/CONTRIBUTING.md +2 -2
- package/README.md +63 -3
- package/README.zh-CN.md +52 -3
- package/SKILL.md +43 -43
- 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 +2 -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 +44 -46
- 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 +12 -12
- package/docs-release/architecture/overview.zh-CN.md +12 -12
- package/docs-release/architecture/system-explainer/01-system-overview.md +15 -14
- package/docs-release/architecture/system-explainer/02-module-dependency.md +8 -8
- package/docs-release/architecture/system-explainer/03-task-lifecycle.md +3 -3
- package/docs-release/architecture/system-explainer/04-check-and-governance.md +9 -7
- package/docs-release/architecture/system-explainer/05-data-flow.md +5 -5
- package/docs-release/architecture/system-explainer/06-preset-and-migration.md +1 -4
- package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +15 -14
- package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +8 -8
- package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +3 -3
- package/docs-release/architecture/system-explainer/en-US/04-check-and-governance.md +10 -8
- 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 +1 -4
- package/docs-release/guides/agent-installation.en-US.md +14 -8
- package/docs-release/guides/agent-installation.md +14 -8
- 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 +2 -2
- 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 +5 -5
- package/docs-release/guides/task-state-machine.md +5 -5
- 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/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 +20 -12
- 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 +5 -5
- 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/task_plan.md +1 -1
- package/skills/preset-creator/references/preset-package-skeleton.md +5 -5
- package/templates/AGENTS.md.template +26 -26
- 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/20-overview.js +11 -5
- package/templates/dashboard/assets/app-src/40-modules.js +1 -1
- package/templates/dashboard/assets/app.js +12 -6
- package/templates/dashboard/assets/i18n.js +4 -2
- 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 +1 -0
- package/templates/planning/module_session_prompt.md +1 -1
- package/templates/planning/task_plan.md +1 -1
- package/templates/planning/walkthrough.md +47 -0
- package/templates/reference/docs-library-standard.md +8 -8
- 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 +26 -26
- 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/module_session_prompt.md +11 -11
- 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 +1 -1
- 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 -126
- package/scripts/commands/preset-command.mjs +0 -73
- package/scripts/commands/task-command.mjs +0 -328
- package/scripts/harness.mjs +0 -291
- package/scripts/lib/capability-registry.mjs +0 -587
- package/scripts/lib/check-module-parallel.mjs +0 -230
- package/scripts/lib/check-profiles.mjs +0 -372
- package/scripts/lib/check-task-contracts.mjs +0 -55
- package/scripts/lib/core-shared.mjs +0 -249
- package/scripts/lib/dashboard-data.mjs +0 -520
- package/scripts/lib/dashboard-workbench.mjs +0 -336
- package/scripts/lib/dashboard-writer.mjs +0 -202
- 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 -611
- package/scripts/lib/governance-table-boundary.mjs +0 -175
- package/scripts/lib/lesson-maintenance.mjs +0 -152
- package/scripts/lib/markdown-utils.mjs +0 -191
- package/scripts/lib/migration-planner.mjs +0 -476
- package/scripts/lib/migration-support.mjs +0 -312
- package/scripts/lib/phase-kind.mjs +0 -50
- package/scripts/lib/preset-audit-contracts.mjs +0 -37
- package/scripts/lib/preset-engine.mjs +0 -494
- package/scripts/lib/preset-registry.mjs +0 -776
- package/scripts/lib/preset-resource-contracts.mjs +0 -83
- package/scripts/lib/review-confirm-git-gate.mjs +0 -248
- package/scripts/lib/status-builder.mjs +0 -88
- package/scripts/lib/subagent-authorization-audit.mjs +0 -196
- package/scripts/lib/task-audit-metadata.mjs +0 -385
- package/scripts/lib/task-audit-migration.mjs +0 -350
- package/scripts/lib/task-completion-consistency.mjs +0 -26
- 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/create-task-helpers.mjs +0 -67
- package/scripts/lib/task-lifecycle/phase-sync.mjs +0 -88
- package/scripts/lib/task-lifecycle/review-confirm.mjs +0 -112
- package/scripts/lib/task-lifecycle/review-gates.mjs +0 -73
- package/scripts/lib/task-lifecycle/review-submission.mjs +0 -63
- package/scripts/lib/task-lifecycle/scaffold-provenance.mjs +0 -49
- package/scripts/lib/task-lifecycle/template-files.mjs +0 -53
- package/scripts/lib/task-lifecycle/text-utils.mjs +0 -24
- package/scripts/lib/task-lifecycle.mjs +0 -616
- package/scripts/lib/task-metadata.mjs +0 -118
- package/scripts/lib/task-review-model.mjs +0 -455
- package/scripts/lib/task-scanner.mjs +0 -503
- 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/INDEX.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,608 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Dashboard bundle aggregation stays behavior-first until dashboard domain types are modeled.
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { bundledCheckScript, repoRoot, builtinPresetRoot, normalizeTarget, projectPresetRoot, readFileSafe, sanitizeText, sanitizeDeep, slug, titleFromMarkdown, prefixedPath, toPosix, walkFiles, isArchivedHarnessPath, visualMapFile, legacyVisualRoadmapFile, lessonCandidatesFile, longRunningTaskContractFile, userPresetRoot, } from "./core-shared.mjs";
|
|
7
|
+
import { parseAllMarkdownTables, getCell, splitDependencies, } from "./markdown-utils.mjs";
|
|
8
|
+
import { readCapabilityRegistry, validateCapabilities } from "./capability-registry.mjs";
|
|
9
|
+
import { resolveHarnessPaths } from "./harness-paths.mjs";
|
|
10
|
+
import { legacyCompatMode, safeAdoptionCapability, } from "./harness-paths.mjs";
|
|
11
|
+
import { buildStatusData } from "./status-builder.mjs";
|
|
12
|
+
import { listTaskPlanPaths, parseTaskState, isActiveTaskState, } from "./task-scanner.mjs";
|
|
13
|
+
import { writeDashboardDirectory, writeDashboardFile } from "./dashboard-writer.mjs";
|
|
14
|
+
import { listPresetPackageLayers } from "./preset-registry.mjs";
|
|
15
|
+
import { validateGovernanceTableBoundaries } from "./governance-table-boundary.mjs";
|
|
16
|
+
import { summarizeGitState } from "./git-status-summary.mjs";
|
|
17
|
+
export function collectMarkdownDocuments(target, options = {}) {
|
|
18
|
+
const docs = collectDashboardDocumentPaths(target, options);
|
|
19
|
+
return docs.map((entry, index) => {
|
|
20
|
+
const file = typeof entry === "string" ? entry : entry.file;
|
|
21
|
+
const content = sanitizeText(readFileSafe(file));
|
|
22
|
+
const source = prefixedPath(target, file);
|
|
23
|
+
return {
|
|
24
|
+
id: `doc-${String(index + 1).padStart(4, "0")}-${slug(path.basename(file, ".md"))}`,
|
|
25
|
+
path: source,
|
|
26
|
+
title: titleFromMarkdown(content, path.basename(file)),
|
|
27
|
+
type: documentKind(source),
|
|
28
|
+
content,
|
|
29
|
+
...(entry.partial ? { partial: true, partialReason: entry.partialReason || "partial", taskId: entry.taskId || "" } : {}),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function collectDashboardDocumentPaths(target, options = {}) {
|
|
34
|
+
const harnessPaths = target.harness || resolveHarnessPaths(target);
|
|
35
|
+
const selected = new Set();
|
|
36
|
+
const partial = new Map();
|
|
37
|
+
const addAbsolutePath = (file) => {
|
|
38
|
+
if (file && fs.existsSync(file))
|
|
39
|
+
selected.add(file);
|
|
40
|
+
};
|
|
41
|
+
const addDocsPath = (relativePath) => {
|
|
42
|
+
const file = path.join(target.docsRoot, relativePath);
|
|
43
|
+
if (fs.existsSync(file))
|
|
44
|
+
selected.add(file);
|
|
45
|
+
};
|
|
46
|
+
if (harnessPaths.version === 2) {
|
|
47
|
+
addAbsolutePath(harnessPaths.ledgerPath);
|
|
48
|
+
addAbsolutePath(harnessPaths.closeoutIndexPath);
|
|
49
|
+
addAbsolutePath(path.join(harnessPaths.modulesRoot, "Module-Registry.md"));
|
|
50
|
+
addAbsolutePath(path.join(harnessPaths.regressionRoot, "Regression-SSoT.md"));
|
|
51
|
+
addAbsolutePath(path.join(harnessPaths.regressionRoot, "Cadence-Ledger.md"));
|
|
52
|
+
for (const generatedRoot of [harnessPaths.generatedRoot, path.join(harnessPaths.planningRoot, "generated")]) {
|
|
53
|
+
for (const file of walkFiles(generatedRoot)) {
|
|
54
|
+
if (file.endsWith(".md"))
|
|
55
|
+
selected.add(file);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (harnessPaths.version !== 2) {
|
|
60
|
+
for (const relativePath of [
|
|
61
|
+
"Harness-Ledger.md",
|
|
62
|
+
"09-PLANNING/Module-Registry.md",
|
|
63
|
+
"05-TEST-QA/Regression-SSoT.md",
|
|
64
|
+
"05-TEST-QA/Cadence-Ledger.md",
|
|
65
|
+
"10-WALKTHROUGH/Closeout-SSoT.md",
|
|
66
|
+
]) {
|
|
67
|
+
addDocsPath(relativePath);
|
|
68
|
+
}
|
|
69
|
+
for (const file of walkFiles(harnessPaths.legacy.walkthroughRoot)) {
|
|
70
|
+
if (!file.endsWith(".md"))
|
|
71
|
+
continue;
|
|
72
|
+
if (file.includes(`${path.sep}_archive${path.sep}`))
|
|
73
|
+
continue;
|
|
74
|
+
if (path.basename(file).startsWith("_"))
|
|
75
|
+
continue;
|
|
76
|
+
selected.add(file);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const tasksByPlanPath = new Map((options.tasks || []).map((task) => [
|
|
80
|
+
path.join(target.projectRoot, String(task.taskPlanPath || "").replace(/^TARGET:/, "")),
|
|
81
|
+
task,
|
|
82
|
+
]));
|
|
83
|
+
for (const taskPlanPath of options.taskPlanPaths || listTaskPlanPaths(target)) {
|
|
84
|
+
const taskDir = path.dirname(taskPlanPath);
|
|
85
|
+
const progress = readFileSafe(path.join(taskDir, "progress.md"));
|
|
86
|
+
const state = parseTaskState(progress);
|
|
87
|
+
const active = isActiveTaskState(state);
|
|
88
|
+
const task = tasksByPlanPath.get(taskPlanPath);
|
|
89
|
+
const historicalClosed = !active && task?.closeoutStatus === "closed";
|
|
90
|
+
const documentNames = historicalClosed
|
|
91
|
+
? ["brief.md", "walkthrough.md"]
|
|
92
|
+
: ["brief.md", "task_plan.md", "execution_strategy.md", visualMapFile, legacyVisualRoadmapFile, lessonCandidatesFile, longRunningTaskContractFile, "progress.md", "review.md", "findings.md", "walkthrough.md"];
|
|
93
|
+
for (const fileName of documentNames) {
|
|
94
|
+
const file = path.join(taskDir, fileName);
|
|
95
|
+
if (fs.existsSync(file)) {
|
|
96
|
+
selected.add(file);
|
|
97
|
+
if (historicalClosed) {
|
|
98
|
+
partial.set(file, {
|
|
99
|
+
partial: true,
|
|
100
|
+
partialReason: "historical-closed",
|
|
101
|
+
taskId: task?.id || path.basename(taskDir),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!historicalClosed) {
|
|
107
|
+
for (const indexFile of ["references/INDEX.md", "artifacts/INDEX.md"]) {
|
|
108
|
+
const file = path.join(taskDir, indexFile);
|
|
109
|
+
if (fs.existsSync(file))
|
|
110
|
+
selected.add(file);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const file of walkFiles(harnessPaths.modulesRoot)) {
|
|
115
|
+
if (file.endsWith("module_plan.md"))
|
|
116
|
+
selected.add(file);
|
|
117
|
+
if (file.endsWith(`${path.sep}brief.md`) && path.dirname(file) !== harnessPaths.modulesRoot)
|
|
118
|
+
selected.add(file);
|
|
119
|
+
}
|
|
120
|
+
const lessonsRoot = harnessPaths.version === 2
|
|
121
|
+
? path.join(harnessPaths.governanceRoot, "lessons")
|
|
122
|
+
: path.join(target.docsRoot, "01-GOVERNANCE/lessons");
|
|
123
|
+
for (const file of walkFiles(lessonsRoot)) {
|
|
124
|
+
if (file.endsWith(".md"))
|
|
125
|
+
selected.add(file);
|
|
126
|
+
}
|
|
127
|
+
return [...selected]
|
|
128
|
+
.filter((file) => !isArchivedHarnessPath(file))
|
|
129
|
+
.filter((file) => !file.includes(`${path.sep}_task-template${path.sep}`))
|
|
130
|
+
.filter((file) => !file.includes(`${path.sep}_optional-structures${path.sep}`))
|
|
131
|
+
.sort()
|
|
132
|
+
.map((file) => ({ file, ...(partial.get(file) || {}) }));
|
|
133
|
+
}
|
|
134
|
+
function documentKind(source) {
|
|
135
|
+
const lower = source.toLowerCase();
|
|
136
|
+
if (lower.includes("harness-ledger.md"))
|
|
137
|
+
return "harness-ledger";
|
|
138
|
+
if (lower.includes("module-registry.md"))
|
|
139
|
+
return "module-registry";
|
|
140
|
+
if (lower.includes("regression-ssot.md"))
|
|
141
|
+
return "regression-ssot";
|
|
142
|
+
if (lower.includes("cadence-ledger.md"))
|
|
143
|
+
return "cadence-ledger";
|
|
144
|
+
if (/\/(?:01-governance|governance)\/lessons\/[^/]+\.md$/i.test(lower))
|
|
145
|
+
return "lesson-detail";
|
|
146
|
+
if (lower.endsWith("/progress.md"))
|
|
147
|
+
return "task-progress";
|
|
148
|
+
if (lower.endsWith("/brief.md"))
|
|
149
|
+
return "task-brief";
|
|
150
|
+
if (lower.endsWith("/review.md"))
|
|
151
|
+
return "task-review";
|
|
152
|
+
if (lower.endsWith("/lesson_candidates.md"))
|
|
153
|
+
return "lesson-candidates";
|
|
154
|
+
if (lower.endsWith("/long-running-task-contract.md"))
|
|
155
|
+
return "long-running-contract";
|
|
156
|
+
if (lower.endsWith("/references/index.md"))
|
|
157
|
+
return "task-references";
|
|
158
|
+
if (lower.endsWith("/artifacts/index.md"))
|
|
159
|
+
return "task-artifacts";
|
|
160
|
+
if (lower.endsWith("/execution_strategy.md"))
|
|
161
|
+
return "execution-strategy";
|
|
162
|
+
if (lower.endsWith("/visual_map.md"))
|
|
163
|
+
return "visual-map";
|
|
164
|
+
if (lower.endsWith("/visual_roadmap.md"))
|
|
165
|
+
return "legacy-visual-roadmap";
|
|
166
|
+
if (lower.endsWith("/module_plan.md"))
|
|
167
|
+
return "module-plan";
|
|
168
|
+
return "markdown-table";
|
|
169
|
+
}
|
|
170
|
+
export function collectTables(documents) {
|
|
171
|
+
return {
|
|
172
|
+
tables: documents.flatMap((document) => parseAllMarkdownTables(document.content, document.path, documentKind(document.path))),
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
export function collectGraph(status, tables = { tables: [] }, target = null) {
|
|
176
|
+
const harnessPaths = target?.harness || null;
|
|
177
|
+
const nodes = [];
|
|
178
|
+
const edges = [];
|
|
179
|
+
const seenNodes = new Map();
|
|
180
|
+
const addNode = (node) => {
|
|
181
|
+
const existing = seenNodes.get(node.id);
|
|
182
|
+
if (existing) {
|
|
183
|
+
if (existing.type === "module" && node.type === "module" && node.state === "planned" && existing.state && existing.state !== "planned") {
|
|
184
|
+
const { state: _state, currentStep: _currentStep, ...rest } = node;
|
|
185
|
+
Object.assign(existing, rest);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
Object.assign(existing, node);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
seenNodes.set(node.id, node);
|
|
192
|
+
nodes.push(node);
|
|
193
|
+
};
|
|
194
|
+
const addEdge = (edge) => {
|
|
195
|
+
if (!edge.from || !edge.to || edge.from === edge.to)
|
|
196
|
+
return;
|
|
197
|
+
edges.push(edge);
|
|
198
|
+
};
|
|
199
|
+
for (const task of status.tasks) {
|
|
200
|
+
addNode({ id: `task:${task.id}`, type: "task", label: task.title, state: task.state, completion: task.completion });
|
|
201
|
+
for (const phase of task.phases || []) {
|
|
202
|
+
const phaseId = `phase:${task.id}:${phase.id}`;
|
|
203
|
+
addNode({
|
|
204
|
+
id: phaseId,
|
|
205
|
+
type: "phase",
|
|
206
|
+
label: phase.id,
|
|
207
|
+
state: phase.state,
|
|
208
|
+
completion: phase.completion,
|
|
209
|
+
kind: phase.kind,
|
|
210
|
+
actor: phase.actor,
|
|
211
|
+
exitCommand: phase.exitCommand,
|
|
212
|
+
taskId: task.id,
|
|
213
|
+
});
|
|
214
|
+
addEdge({ from: `task:${task.id}`, to: phaseId, type: "contains" });
|
|
215
|
+
for (const dependency of phase.dependsOn || []) {
|
|
216
|
+
addEdge({ from: `phase:${task.id}:${dependency}`, to: phaseId, type: "depends_on" });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
for (const handoff of task.handoffs || []) {
|
|
220
|
+
const handoffId = `handoff:${handoff.id}`;
|
|
221
|
+
addNode({ id: handoffId, type: "handoff", label: handoff.summary, state: handoff.state });
|
|
222
|
+
addEdge({ from: `task:${task.id}`, to: handoffId, type: "handoff" });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
for (const table of tables.tables || []) {
|
|
226
|
+
if (table.kind === "module-registry") {
|
|
227
|
+
for (const row of table.rows) {
|
|
228
|
+
const key = getCell(row.cells, ["Key", "Module", "模块 Key", "模块"]) || "";
|
|
229
|
+
if (!key)
|
|
230
|
+
continue;
|
|
231
|
+
const moduleId = `module:${key}`;
|
|
232
|
+
const status = getCell(row.cells, ["Status", "状态"], "unknown");
|
|
233
|
+
const currentStep = getCell(row.cells, ["Current Step", "当前步骤"], "");
|
|
234
|
+
addNode({
|
|
235
|
+
id: moduleId,
|
|
236
|
+
type: "module",
|
|
237
|
+
label: getCell(row.cells, ["Name", "Module", "模块名称", "模块"], key),
|
|
238
|
+
state: status,
|
|
239
|
+
currentStep,
|
|
240
|
+
...moduleDocumentPaths(target, key),
|
|
241
|
+
});
|
|
242
|
+
if (currentStep) {
|
|
243
|
+
const stepId = `step:${currentStep}`;
|
|
244
|
+
if (!seenNodes.has(stepId))
|
|
245
|
+
addNode({ id: stepId, type: "step", label: currentStep, state: status, module: key });
|
|
246
|
+
addEdge({ from: moduleId, to: stepId, type: "current_step" });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (table.kind === "module-plan") {
|
|
251
|
+
const moduleKey = moduleKeyFromPlanSource(table.source, target) || slug(table.source);
|
|
252
|
+
const moduleId = `module:${moduleKey}`;
|
|
253
|
+
addNode({ id: moduleId, type: "module", label: moduleKey, state: "planned", ...moduleDocumentPaths(target, moduleKey) });
|
|
254
|
+
for (const row of table.rows) {
|
|
255
|
+
const step = getCell(row.cells, ["Step ID", "步骤 ID"]);
|
|
256
|
+
if (!step)
|
|
257
|
+
continue;
|
|
258
|
+
const stepId = `step:${step}`;
|
|
259
|
+
addNode({ id: stepId, type: "step", label: `${step} ${getCell(row.cells, ["Name", "名称"]) || ""}`.trim(), state: getCell(row.cells, ["Status", "状态"], "unknown"), module: moduleKey });
|
|
260
|
+
addEdge({ from: moduleId, to: stepId, type: "contains" });
|
|
261
|
+
for (const dependency of splitDependencies(getCell(row.cells, ["Depends On", "依赖"]) || "")) {
|
|
262
|
+
addEdge({ from: `step:${dependency}`, to: stepId, type: "depends_on" });
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const edge of edges) {
|
|
268
|
+
if (edge.type === "depends_on" && !seenNodes.has(edge.from)) {
|
|
269
|
+
addNode({ id: edge.from, type: "external-dependency", label: edge.from.replace(/^(phase:[^:]+:|step:)/, ""), state: "external" });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return { nodes, edges: edges.filter((edge) => seenNodes.has(edge.from) && seenNodes.has(edge.to)) };
|
|
273
|
+
}
|
|
274
|
+
function moduleKeyFromPlanSource(source, target) {
|
|
275
|
+
if (!target?.projectRoot || !target?.harness?.modulesRoot) {
|
|
276
|
+
const moduleMatch = source.match(/(?:MODULES|modules)\/([^/]+)\/module_plan\.md$/);
|
|
277
|
+
return moduleMatch ? moduleMatch[1] : "";
|
|
278
|
+
}
|
|
279
|
+
const relativeSource = String(source || "").replace(/^TARGET:/, "");
|
|
280
|
+
const absoluteSource = path.join(target.projectRoot, relativeSource);
|
|
281
|
+
const relative = toPosix(path.relative(target.harness.modulesRoot, absoluteSource));
|
|
282
|
+
const match = relative.match(/^([^/]+)\/module_plan\.md$/);
|
|
283
|
+
if (match)
|
|
284
|
+
return match[1];
|
|
285
|
+
const legacyMatch = source.match(/(?:MODULES|modules)\/([^/]+)\/module_plan\.md$/);
|
|
286
|
+
return legacyMatch ? legacyMatch[1] : "";
|
|
287
|
+
}
|
|
288
|
+
function moduleDocumentPaths(target, moduleKey) {
|
|
289
|
+
if (!target?.harness?.modulesRoot || !moduleKey)
|
|
290
|
+
return {};
|
|
291
|
+
const brief = path.join(target.harness.modulesRoot, moduleKey, "brief.md");
|
|
292
|
+
const modulePlan = path.join(target.harness.modulesRoot, moduleKey, "module_plan.md");
|
|
293
|
+
return {
|
|
294
|
+
...(fs.existsSync(brief) ? { briefPath: prefixedPath(target, brief) } : {}),
|
|
295
|
+
...(fs.existsSync(modulePlan) ? { modulePlanPath: prefixedPath(target, modulePlan) } : {}),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
export function categorizeWarning(message) {
|
|
299
|
+
if (/governance-table-entropy/i.test(message))
|
|
300
|
+
return "Governance Table Boundary";
|
|
301
|
+
if (/missing execution_strategy\.md|missing visual_(?:map|roadmap)\.md|Visual (?:Map|Roadmap)/i.test(message))
|
|
302
|
+
return "Plan Contract Missing";
|
|
303
|
+
if (new RegExp(`${legacyCompatMode}|adoption-needed|legacy check`, "i").test(message))
|
|
304
|
+
return "Adoption Advice";
|
|
305
|
+
if (/Evidence|evidence/i.test(message))
|
|
306
|
+
return "Missing Evidence";
|
|
307
|
+
if (/schema|missing .*columns|invalid/i.test(message))
|
|
308
|
+
return "Schema Drift";
|
|
309
|
+
return "Review Finding";
|
|
310
|
+
}
|
|
311
|
+
function warningType(message) {
|
|
312
|
+
if (/missing brief\.md|briefSource|brief/i.test(message) && /missing|缺少/i.test(message))
|
|
313
|
+
return "missing-brief";
|
|
314
|
+
if (/missing execution_strategy\.md/i.test(message))
|
|
315
|
+
return "missing-execution-strategy";
|
|
316
|
+
if (/missing visual_map\.md|Visual Map/i.test(message))
|
|
317
|
+
return "missing-visual-map";
|
|
318
|
+
if (/missing visual_roadmap\.md|Visual Roadmap/i.test(message))
|
|
319
|
+
return "missing-visual-roadmap";
|
|
320
|
+
if (/Reviewer Identity|Confidence Challenge|Final Confidence Basis|Evidence Checked/i.test(message))
|
|
321
|
+
return "review-schema-gap";
|
|
322
|
+
if (/governance-table-entropy/i.test(message))
|
|
323
|
+
return "governance-table-entropy";
|
|
324
|
+
if (/Evidence|evidence/i.test(message))
|
|
325
|
+
return "missing-evidence";
|
|
326
|
+
if (/missing required file/i.test(message))
|
|
327
|
+
return "legacy-reference-gap";
|
|
328
|
+
if (new RegExp(`${legacyCompatMode}|legacy check|adoption-needed`, "i").test(message))
|
|
329
|
+
return "capability-adoption";
|
|
330
|
+
if (/schema|missing .*columns|invalid/i.test(message))
|
|
331
|
+
return "schema-drift";
|
|
332
|
+
return "review-finding";
|
|
333
|
+
}
|
|
334
|
+
function warningScope(message) {
|
|
335
|
+
if (/(?:docs\/09-PLANNING\/TASKS|coding-agent-harness\/planning\/tasks)\//i.test(message))
|
|
336
|
+
return "task";
|
|
337
|
+
if (/(?:docs\/09-PLANNING\/MODULES|coding-agent-harness\/planning\/modules)\//i.test(message))
|
|
338
|
+
return "module";
|
|
339
|
+
if (/review\.md|findings table/i.test(message))
|
|
340
|
+
return "review";
|
|
341
|
+
if (/docs\/11-REFERENCE\//i.test(message))
|
|
342
|
+
return "reference";
|
|
343
|
+
if (new RegExp(`\\.harness-capabilities\\.json|capability|${legacyCompatMode}`, "i").test(message))
|
|
344
|
+
return "capability";
|
|
345
|
+
return "project";
|
|
346
|
+
}
|
|
347
|
+
function warningPhase(type, scope) {
|
|
348
|
+
if (type === "capability-adoption")
|
|
349
|
+
return "baseline";
|
|
350
|
+
if (type === "governance-table-entropy")
|
|
351
|
+
return "global-table-boundary";
|
|
352
|
+
if (type === "missing-brief" || type === "missing-execution-strategy" || type === "missing-visual-map" || type === "missing-visual-roadmap")
|
|
353
|
+
return "active-task-contracts";
|
|
354
|
+
if (scope === "module")
|
|
355
|
+
return "module-classification";
|
|
356
|
+
if (type === "review-schema-gap" || type === "missing-evidence")
|
|
357
|
+
return "review-evidence";
|
|
358
|
+
if (type === "legacy-reference-gap" || type === "schema-drift")
|
|
359
|
+
return "strict-cutover";
|
|
360
|
+
return "triage";
|
|
361
|
+
}
|
|
362
|
+
function warningFixability(type, scope) {
|
|
363
|
+
if (["missing-brief", "missing-execution-strategy", "missing-visual-map", "missing-visual-roadmap"].includes(type))
|
|
364
|
+
return "guided";
|
|
365
|
+
if (type === "governance-table-entropy")
|
|
366
|
+
return "manual";
|
|
367
|
+
if (type === "legacy-reference-gap" || scope === "reference")
|
|
368
|
+
return "template";
|
|
369
|
+
if (type === "capability-adoption")
|
|
370
|
+
return "decision";
|
|
371
|
+
if (type === "review-schema-gap" || type === "missing-evidence")
|
|
372
|
+
return "human-evidence";
|
|
373
|
+
return "manual";
|
|
374
|
+
}
|
|
375
|
+
function warningPriority(type, scope, message) {
|
|
376
|
+
if (/fail|invalid|blocked/i.test(message) || type === "schema-drift")
|
|
377
|
+
return "P1";
|
|
378
|
+
if (type === "governance-table-entropy")
|
|
379
|
+
return /legacy-report-only/i.test(message) ? "P3" : "P2";
|
|
380
|
+
if (["missing-brief", "missing-execution-strategy", "missing-visual-map", "missing-visual-roadmap"].includes(type) && scope === "task")
|
|
381
|
+
return "P2";
|
|
382
|
+
if (type === "review-schema-gap" || type === "missing-evidence")
|
|
383
|
+
return "P2";
|
|
384
|
+
if (type === "capability-adoption")
|
|
385
|
+
return "P3";
|
|
386
|
+
return "P3";
|
|
387
|
+
}
|
|
388
|
+
function warningConfidence(message) {
|
|
389
|
+
if (/legacy|unknown|fallback/i.test(message))
|
|
390
|
+
return "medium";
|
|
391
|
+
return "high";
|
|
392
|
+
}
|
|
393
|
+
function warningAffectedPaths(message) {
|
|
394
|
+
const matches = String(message).match(/(?:docs|\.harness-private|coding-agent-harness)\/[^\s:]+|\.harness-capabilities\.json|AGENTS\.md|CLAUDE\.md/g) || [];
|
|
395
|
+
return [...new Set(matches.map((item) => item.replace(/[),.;]+$/, "")))];
|
|
396
|
+
}
|
|
397
|
+
function summarizeWarnings(warnings) {
|
|
398
|
+
const countBy = (field) => warnings.reduce((acc, warning) => {
|
|
399
|
+
const key = warning[field] || "unknown";
|
|
400
|
+
acc[key] = (acc[key] || 0) + 1;
|
|
401
|
+
return acc;
|
|
402
|
+
}, {});
|
|
403
|
+
return {
|
|
404
|
+
total: warnings.length,
|
|
405
|
+
byCategory: countBy("category"),
|
|
406
|
+
byType: countBy("type"),
|
|
407
|
+
byPriority: countBy("priority"),
|
|
408
|
+
byPhase: countBy("phase"),
|
|
409
|
+
byFixability: countBy("fixability"),
|
|
410
|
+
activeTaskWarnings: warnings.filter((warning) => warning.scope === "task" && warning.phase === "active-task-contracts").length,
|
|
411
|
+
strictCutoverWarnings: warnings.filter((warning) => warning.phase === "strict-cutover").length,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
export function collectAdoption(status) {
|
|
415
|
+
const dashboardMessages = [
|
|
416
|
+
...(status.checkState.details.warnings || []),
|
|
417
|
+
...(status.checkState.details.failures || []).filter((message) => /governance-table-entropy/i.test(message)),
|
|
418
|
+
];
|
|
419
|
+
const warnings = dashboardMessages.flatMap((message) => splitWarningMessage(message)).map((message, index) => {
|
|
420
|
+
const type = warningType(message);
|
|
421
|
+
const scope = warningScope(message);
|
|
422
|
+
const affectedPaths = warningAffectedPaths(message);
|
|
423
|
+
const stableSuffix = type === "governance-table-entropy" ? `-${stableWarningIdPart(governanceWarningRowKey(message))}` : "";
|
|
424
|
+
return {
|
|
425
|
+
id: `AD-${String(index + 1).padStart(3, "0")}${stableSuffix}`,
|
|
426
|
+
category: categorizeWarning(message),
|
|
427
|
+
type,
|
|
428
|
+
scope,
|
|
429
|
+
priority: warningPriority(type, scope, message),
|
|
430
|
+
phase: warningPhase(type, scope),
|
|
431
|
+
fixability: warningFixability(type, scope),
|
|
432
|
+
status: /legacy-report-only/i.test(message) ? "legacy-report-only" : "open",
|
|
433
|
+
confidence: warningConfidence(message),
|
|
434
|
+
severity: status.mode === legacyCompatMode ? "advice" : "warning",
|
|
435
|
+
title: warningTitle(message),
|
|
436
|
+
affected: affectedPaths[0] || warningAffected(message),
|
|
437
|
+
affectedPaths,
|
|
438
|
+
requiredAction: warningAction(message),
|
|
439
|
+
detail: sanitizeText(message),
|
|
440
|
+
};
|
|
441
|
+
});
|
|
442
|
+
return {
|
|
443
|
+
mode: status.mode,
|
|
444
|
+
project: status.project,
|
|
445
|
+
summary: {
|
|
446
|
+
blockers: status.checkState.failures,
|
|
447
|
+
advice: warnings.length,
|
|
448
|
+
...summarizeWarnings(warnings),
|
|
449
|
+
},
|
|
450
|
+
warnings,
|
|
451
|
+
manualSteps: {
|
|
452
|
+
zh: [
|
|
453
|
+
"先查看升级建议,决定当前项目要采用哪些 v1.0 能力合同。",
|
|
454
|
+
"为仍在活跃的任务手工补齐 execution_strategy.md 和 visual_map.md。",
|
|
455
|
+
"只有在项目明确声明 v1.0 capability 后,再把 strict check 当成阻塞门禁。",
|
|
456
|
+
],
|
|
457
|
+
en: [
|
|
458
|
+
"Review adoption advice and decide which v1.0 capability contracts should be adopted.",
|
|
459
|
+
"Manually add execution_strategy.md and visual_map.md for active tasks.",
|
|
460
|
+
"Treat strict check as blocking only after the project intentionally declares v1.0 capabilities.",
|
|
461
|
+
],
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function governanceWarningRowKey(message) {
|
|
466
|
+
const match = String(message || "").match(/\brow\s+([^:]+)/i);
|
|
467
|
+
return match ? match[1].trim() : "global-table";
|
|
468
|
+
}
|
|
469
|
+
function stableWarningIdPart(value) {
|
|
470
|
+
return String(value || "global-table")
|
|
471
|
+
.replace(/[^A-Za-z0-9_-]+/g, "-")
|
|
472
|
+
.replace(/^-+|-+$/g, "")
|
|
473
|
+
.slice(0, 80) || "global-table";
|
|
474
|
+
}
|
|
475
|
+
export function splitWarningMessage(message) {
|
|
476
|
+
return String(message || "")
|
|
477
|
+
.split(/\n-\s+/)
|
|
478
|
+
.map((item, index) => (index === 0 ? item : `- ${item}`))
|
|
479
|
+
.filter(Boolean);
|
|
480
|
+
}
|
|
481
|
+
function warningTitle(message) {
|
|
482
|
+
if (/governance-table-entropy/i.test(message))
|
|
483
|
+
return "Global table boundary";
|
|
484
|
+
if (/missing execution_strategy\.md/i.test(message))
|
|
485
|
+
return "Missing execution strategy";
|
|
486
|
+
if (/missing visual_map\.md|Visual Map/i.test(message))
|
|
487
|
+
return "Missing visual map";
|
|
488
|
+
if (/missing visual_roadmap\.md|Visual Roadmap/i.test(message))
|
|
489
|
+
return "Missing legacy visual roadmap";
|
|
490
|
+
if (new RegExp(legacyCompatMode, "i").test(message))
|
|
491
|
+
return "Legacy compatibility mode";
|
|
492
|
+
if (/legacy check failed/i.test(message))
|
|
493
|
+
return "Legacy checker finding";
|
|
494
|
+
if (/review\.md missing/i.test(message))
|
|
495
|
+
return "Review schema gap";
|
|
496
|
+
if (/findings table missing/i.test(message))
|
|
497
|
+
return "Review findings schema gap";
|
|
498
|
+
return String(message).split(":")[0].slice(0, 96);
|
|
499
|
+
}
|
|
500
|
+
function warningAffected(message) {
|
|
501
|
+
const target = String(message).match(/(?:docs|\.harness-private)\/[^\s:]+/);
|
|
502
|
+
return target ? target[0] : "project";
|
|
503
|
+
}
|
|
504
|
+
function warningAction(message) {
|
|
505
|
+
if (/governance-table-entropy/i.test(message))
|
|
506
|
+
return "Move local detail to module/task docs; keep the global row to summary, state, route, and audit result.";
|
|
507
|
+
if (/execution_strategy\.md/i.test(message))
|
|
508
|
+
return "Add standalone execution strategy file.";
|
|
509
|
+
if (/visual_map\.md|Visual Map/i.test(message))
|
|
510
|
+
return "Add standalone visual map file.";
|
|
511
|
+
if (/visual_roadmap\.md|Visual Roadmap/i.test(message))
|
|
512
|
+
return "Rewrite legacy visual_roadmap.md into canonical visual_map.md.";
|
|
513
|
+
if (/review\.md missing/i.test(message))
|
|
514
|
+
return "Update review.md to v1 review schema.";
|
|
515
|
+
if (/legacy/i.test(message))
|
|
516
|
+
return "Review manually; do not auto-migrate.";
|
|
517
|
+
return "Inspect source document and decide whether to adopt v1 contract.";
|
|
518
|
+
}
|
|
519
|
+
export function buildDashboardBundle(targetInput, options = {}) {
|
|
520
|
+
const target = normalizeTarget(targetInput);
|
|
521
|
+
const taskPlanPaths = listTaskPlanPaths(target);
|
|
522
|
+
const capabilityState = validateCapabilities(target);
|
|
523
|
+
const gitState = summarizeGitState(target);
|
|
524
|
+
const declaredCapabilities = new Set(capabilityState.registry.capabilities.map((capability) => capability.name));
|
|
525
|
+
const shouldRunLegacy = target.harness?.version !== 2 && !options.skipLegacyCheck && (capabilityState.registry.mode === legacyCompatMode || declaredCapabilities.has(safeAdoptionCapability));
|
|
526
|
+
const legacy = shouldRunLegacy ? runDashboardCompatibilityCheck(target) : { status: "skipped", code: 0, stdout: "", stderr: "" };
|
|
527
|
+
const legacyWarnings = legacy.status === "fail" ? [`adoption-needed: legacy check failed: ${(legacy.stderr || legacy.stdout).trim()}`] : [];
|
|
528
|
+
const governanceBoundaries = validateGovernanceTableBoundaries(target);
|
|
529
|
+
const status = buildStatusData(target, {
|
|
530
|
+
...options,
|
|
531
|
+
capabilityState,
|
|
532
|
+
gitState,
|
|
533
|
+
taskPlanPaths,
|
|
534
|
+
legacy,
|
|
535
|
+
failures: [...capabilityState.failures, ...governanceBoundaries.failures],
|
|
536
|
+
warnings: [...capabilityState.warnings, ...legacyWarnings, ...governanceBoundaries.warnings, ...gitState.warnings],
|
|
537
|
+
});
|
|
538
|
+
const documents = { documents: collectMarkdownDocuments(target, { taskPlanPaths, tasks: status.tasks }) };
|
|
539
|
+
const tables = collectTables(documents.documents);
|
|
540
|
+
const graph = collectGraph(status, tables, target);
|
|
541
|
+
const adoption = collectAdoption(status);
|
|
542
|
+
const presetCatalog = collectPresetCatalog(targetInput, target, options);
|
|
543
|
+
return sanitizeDeep({ status, tables, documents, graph, adoption, presetCatalog });
|
|
544
|
+
}
|
|
545
|
+
function runDashboardCompatibilityCheck(target) {
|
|
546
|
+
const checkTarget = target.docsOnly ? target.projectRoot : target.input;
|
|
547
|
+
const result = spawnSync(process.execPath, [bundledCheckScript, checkTarget], {
|
|
548
|
+
cwd: repoRoot,
|
|
549
|
+
encoding: "utf8",
|
|
550
|
+
});
|
|
551
|
+
return {
|
|
552
|
+
status: result.status === 0 ? "pass" : "fail",
|
|
553
|
+
code: result.status ?? 1,
|
|
554
|
+
stdout: result.stdout || "",
|
|
555
|
+
stderr: result.stderr || "",
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
export function collectPresetCatalog(targetInput, target = normalizeTarget(targetInput), options = {}) {
|
|
559
|
+
const home = options.home || "";
|
|
560
|
+
const presets = listPresetPackageLayers({ targetInput: target.projectRoot, home }).map((preset) => ({
|
|
561
|
+
key: `${preset.source}:${preset.id}`,
|
|
562
|
+
id: preset.id,
|
|
563
|
+
version: preset.version,
|
|
564
|
+
source: preset.source,
|
|
565
|
+
effective: preset.effective === true,
|
|
566
|
+
purpose: preset.purpose,
|
|
567
|
+
compatibleBudgets: preset.compatibleBudgets,
|
|
568
|
+
manifestPath: preset.manifestRelativePath,
|
|
569
|
+
manifestSha256: preset.manifestSha256,
|
|
570
|
+
taskKind: preset.task?.kind || "",
|
|
571
|
+
inputCount: Object.keys(preset.inputs || {}).length,
|
|
572
|
+
referenceCount: Object.keys(preset.resources?.references || {}).length,
|
|
573
|
+
artifactCount: Object.keys(preset.resources?.artifacts || {}).length,
|
|
574
|
+
writeScopeCount: Object.keys(preset.writeScopes || {}).length,
|
|
575
|
+
evidenceFileCount: Object.keys(preset.evidence?.files || {}).length,
|
|
576
|
+
requiredReadCount: Array.isArray(preset.context?.requiredReads) ? preset.context.requiredReads.length : 0,
|
|
577
|
+
checkStatus: "unknown",
|
|
578
|
+
}));
|
|
579
|
+
const countSource = (source) => presets.filter((preset) => preset.source === source).length;
|
|
580
|
+
return {
|
|
581
|
+
summary: {
|
|
582
|
+
total: presets.length,
|
|
583
|
+
project: countSource("project"),
|
|
584
|
+
user: countSource("user"),
|
|
585
|
+
builtin: countSource("builtin"),
|
|
586
|
+
},
|
|
587
|
+
roots: [
|
|
588
|
+
{ source: "project", path: projectPresetRoot(target.projectRoot) },
|
|
589
|
+
{ source: "user", path: home ? path.join(path.resolve(home), ".coding-agent-harness/presets") : userPresetRoot },
|
|
590
|
+
{ source: "builtin", path: builtinPresetRoot },
|
|
591
|
+
],
|
|
592
|
+
presets,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
export function writeDashboardFolder(outDir, targetInput, options = {}) {
|
|
596
|
+
const target = normalizeTarget(targetInput);
|
|
597
|
+
const registry = readCapabilityRegistry(target);
|
|
598
|
+
const locale = options.localeOverride || registry.locale;
|
|
599
|
+
const bundle = buildDashboardBundle(targetInput, options);
|
|
600
|
+
return writeDashboardDirectory(outDir, bundle, { repoRoot, projectRoot: target.projectRoot, docsRoot: target.docsRoot, locale, workbenchRuntime: options.workbenchRuntime === true, recoverGeneratedDashboard: options.recoverGeneratedDashboard === true });
|
|
601
|
+
}
|
|
602
|
+
export function writeDashboardSingleFile(outFile, targetInput, options = {}) {
|
|
603
|
+
const target = normalizeTarget(targetInput);
|
|
604
|
+
const registry = readCapabilityRegistry(target);
|
|
605
|
+
const locale = options.localeOverride || registry.locale;
|
|
606
|
+
const bundle = buildDashboardBundle(targetInput, options);
|
|
607
|
+
return writeDashboardFile(outFile, bundle, { repoRoot, projectRoot: target.projectRoot, docsRoot: target.docsRoot, locale });
|
|
608
|
+
}
|