coding-agent-harness 1.0.2 → 1.0.5
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 +32 -0
- package/CONTRIBUTING.md +98 -0
- package/LICENSE +661 -21
- package/LICENSE-EXCEPTION.md +37 -0
- package/README.md +244 -87
- package/README.zh-CN.md +77 -35
- package/SKILL.md +32 -24
- package/docs-release/README.md +9 -5
- package/docs-release/architecture/overview.md +17 -5
- package/docs-release/architecture/overview.zh-CN.md +9 -5
- package/docs-release/architecture/system-explainer/01-system-overview.md +217 -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 +239 -0
- package/docs-release/architecture/system-explainer/05-data-flow.md +276 -0
- package/docs-release/architecture/system-explainer/06-preset-and-migration.md +303 -0
- package/docs-release/architecture/system-explainer/README.md +67 -0
- package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +226 -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 +250 -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 +323 -0
- package/docs-release/architecture/system-explainer/en-US/README.md +70 -0
- package/docs-release/assets/dashboard-overview.png +0 -0
- package/docs-release/guides/agent-installation.en-US.md +39 -15
- package/docs-release/guides/agent-installation.md +43 -16
- package/docs-release/guides/contributing.md +100 -0
- package/docs-release/guides/contributing.zh-CN.md +99 -0
- package/docs-release/guides/document-audience-and-surfaces.en-US.md +3 -2
- package/docs-release/guides/document-audience-and-surfaces.md +3 -2
- package/docs-release/guides/full-legacy-migration-subagent-strategy.md +2 -2
- package/docs-release/guides/full-legacy-migration-subagent-strategy.zh-CN.md +2 -2
- package/docs-release/guides/legacy-migration-agent-prompt.md +0 -11
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +0 -11
- package/docs-release/guides/migration-playbook.en-US.md +14 -15
- package/docs-release/guides/migration-playbook.md +14 -15
- package/docs-release/guides/parent-control-repository-pattern.en-US.md +7 -5
- package/docs-release/guides/parent-control-repository-pattern.md +7 -5
- package/docs-release/guides/preset-development.md +238 -0
- package/docs-release/guides/repository-operating-models.en-US.md +5 -4
- package/docs-release/guides/repository-operating-models.md +5 -4
- package/docs-release/guides/task-state-machine.en-US.md +224 -0
- package/docs-release/guides/task-state-machine.md +231 -0
- package/docs-release/intl/en-US.md +1 -1
- package/docs-release/intl/zh-CN.md +1 -1
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/INDEX.md +60 -0
- package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/findings.md +7 -0
- package/package.json +10 -4
- package/presets/legacy-migration/checks/preset-check.mjs +3 -0
- package/presets/legacy-migration/preset.yaml +134 -0
- package/presets/legacy-migration/scripts/plan-work-queue.mjs +4 -0
- package/presets/legacy-migration/scripts/scaffold-task-contracts.mjs +4 -0
- package/presets/legacy-migration/templates/execution_strategy.append.md +18 -0
- package/presets/legacy-migration/templates/findings.seed.md +17 -0
- package/presets/legacy-migration/templates/review.seed.md +12 -0
- package/presets/legacy-migration/templates/task_plan.append.md +9 -0
- package/presets/legacy-migration/templates/visual_map.append.md +12 -0
- package/presets/legacy-migration/workbench/dashboard-panels.yaml +2 -0
- package/presets/legacy-migration/workbench/migration-queue.schema.json +23 -0
- package/presets/lesson-sedimentation/preset.yaml +23 -0
- package/presets/lesson-sedimentation/templates/prompt.md +23 -0
- package/presets/module/preset.yaml +25 -0
- package/presets/module/templates/execution_strategy.append.md +8 -0
- package/presets/module/templates/task_plan.append.md +17 -0
- package/presets/standard-task/preset.yaml +31 -0
- package/presets/standard-task/templates/task_plan.append.md +7 -0
- package/references/adversarial-review-standard.md +2 -2
- package/references/agents-md-pattern.md +2 -2
- package/references/delivery-operating-model-standard.md +3 -3
- package/references/docs-directory-standard.md +6 -7
- package/references/harness-ledger.md +53 -96
- package/references/lessons-governance.md +88 -93
- package/references/module-parallel-standard.md +14 -14
- package/references/planning-loop.md +12 -6
- package/references/pull-request-standard.md +118 -0
- package/references/repo-governance-standard.md +11 -2
- package/references/review-routing-standard.md +7 -1
- package/references/ssot-governance.md +67 -59
- package/references/taskr-gap-analysis.md +600 -0
- package/references/walkthrough-closeout.md +7 -7
- package/scripts/check-harness.mjs +40 -301
- package/scripts/commands/dashboard-command.mjs +67 -0
- package/scripts/commands/migration-command.mjs +126 -0
- package/scripts/commands/preset-command.mjs +73 -0
- package/scripts/commands/task-command.mjs +328 -0
- package/scripts/harness.mjs +59 -260
- package/scripts/lib/capability-registry.mjs +82 -28
- package/scripts/lib/check-module-parallel.mjs +230 -0
- package/scripts/lib/check-profiles.mjs +90 -228
- package/scripts/lib/check-task-contracts.mjs +55 -0
- package/scripts/lib/core-shared.mjs +65 -2
- package/scripts/lib/dashboard-data.mjs +155 -24
- package/scripts/lib/dashboard-workbench.mjs +131 -12
- package/scripts/lib/dashboard-writer.mjs +20 -4
- package/scripts/lib/git-status-summary.mjs +46 -0
- package/scripts/lib/governance-index-generator.mjs +174 -0
- package/scripts/lib/governance-sync.mjs +611 -0
- package/scripts/lib/governance-table-boundary.mjs +175 -0
- package/scripts/lib/harness-core.mjs +6 -0
- package/scripts/lib/lesson-maintenance.mjs +36 -29
- package/scripts/lib/markdown-utils.mjs +33 -0
- package/scripts/lib/migration-planner.mjs +4 -6
- package/scripts/lib/migration-support.mjs +1 -1
- package/scripts/lib/phase-kind.mjs +50 -0
- package/scripts/lib/preset-audit-contracts.mjs +37 -0
- package/scripts/lib/preset-engine.mjs +494 -0
- package/scripts/lib/preset-registry.mjs +776 -0
- package/scripts/lib/preset-resource-contracts.mjs +83 -0
- package/scripts/lib/review-confirm-git-gate.mjs +248 -0
- package/scripts/lib/status-builder.mjs +88 -0
- package/scripts/lib/status-dashboard-renderer.mjs +105 -0
- package/scripts/lib/subagent-authorization-audit.mjs +196 -0
- package/scripts/lib/task-audit-metadata.mjs +385 -0
- package/scripts/lib/task-audit-migration.mjs +350 -0
- package/scripts/lib/task-completion-consistency.mjs +26 -0
- package/scripts/lib/task-index.mjs +93 -0
- package/scripts/lib/task-lesson-candidates.mjs +242 -0
- package/scripts/lib/task-lesson-sedimentation.mjs +326 -0
- package/scripts/lib/task-lifecycle/create-task-helpers.mjs +67 -0
- package/scripts/lib/task-lifecycle/phase-sync.mjs +88 -0
- package/scripts/lib/task-lifecycle/review-confirm.mjs +112 -0
- package/scripts/lib/task-lifecycle/review-gates.mjs +73 -0
- package/scripts/lib/task-lifecycle/review-submission.mjs +63 -0
- package/scripts/lib/task-lifecycle/scaffold-provenance.mjs +49 -0
- package/scripts/lib/task-lifecycle/template-files.mjs +53 -0
- package/scripts/lib/task-lifecycle/text-utils.mjs +24 -0
- package/scripts/lib/task-lifecycle.mjs +338 -477
- package/scripts/lib/task-metadata.mjs +118 -0
- package/scripts/lib/task-review-model.mjs +455 -0
- package/scripts/lib/task-scanner.mjs +193 -372
- package/scripts/lib/task-tombstone-commands.mjs +140 -0
- package/scripts/postinstall.mjs +14 -0
- package/skills/preset-creator/SKILL.md +179 -0
- package/skills/preset-creator/references/complex-task-skeleton/README.md +31 -0
- package/skills/preset-creator/references/complex-task-skeleton/artifacts/INDEX.md +12 -0
- package/skills/preset-creator/references/complex-task-skeleton/brief.md +43 -0
- package/skills/preset-creator/references/complex-task-skeleton/execution_strategy.md +71 -0
- package/skills/preset-creator/references/complex-task-skeleton/findings.md +24 -0
- package/skills/preset-creator/references/complex-task-skeleton/lesson_candidates.md +70 -0
- package/skills/preset-creator/references/complex-task-skeleton/long-running-task-contract.md +76 -0
- package/skills/preset-creator/references/complex-task-skeleton/progress.md +33 -0
- package/skills/preset-creator/references/complex-task-skeleton/references/INDEX.md +13 -0
- package/skills/preset-creator/references/complex-task-skeleton/review.md +107 -0
- package/skills/preset-creator/references/complex-task-skeleton/task_plan.md +111 -0
- package/skills/preset-creator/references/complex-task-skeleton/visual_map.md +50 -0
- package/skills/preset-creator/references/preset-package-skeleton.md +296 -0
- package/templates/AGENTS.md.template +24 -18
- package/templates/dashboard/assets/app-src/00-state.js +13 -0
- package/templates/dashboard/assets/app-src/10-router.js +5 -1
- package/templates/dashboard/assets/app-src/20-overview.js +18 -8
- package/templates/dashboard/assets/app-src/30-tasks.js +92 -246
- package/templates/dashboard/assets/app-src/35-task-detail.js +286 -0
- package/templates/dashboard/assets/app-src/45-review.js +241 -22
- package/templates/dashboard/assets/app-src/50-migration.js +24 -10
- 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 +302 -29
- package/templates/dashboard/assets/app.css +1501 -376
- package/templates/dashboard/assets/app.css.manifest.json +10 -0
- package/templates/dashboard/assets/app.js +1240 -101
- package/templates/dashboard/assets/app.manifest.json +2 -0
- package/templates/dashboard/assets/css-src/00-foundation.css +346 -0
- package/templates/dashboard/assets/css-src/10-panels-flow.css +236 -0
- package/templates/dashboard/assets/css-src/20-briefs-controls.css +398 -0
- package/templates/dashboard/assets/css-src/30-task-index.css +739 -0
- package/templates/dashboard/assets/css-src/35-review-workspace.css +507 -0
- package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +489 -0
- package/templates/dashboard/assets/css-src/45-presets.css +516 -0
- package/templates/dashboard/assets/css-src/50-responsive-overrides.css +551 -0
- package/templates/dashboard/assets/i18n.js +263 -23
- package/templates/ledger/Harness-Ledger.md +13 -25
- package/templates/lessons/lesson-arch-process-change.md +1 -1
- package/templates/lessons/lesson-new-doc.md +1 -1
- package/templates/lessons/lesson-ref-change.md +1 -1
- package/templates/planning/INDEX.md +87 -0
- package/templates/planning/brief.md +1 -1
- package/templates/planning/execution_strategy.md +31 -0
- package/templates/planning/lesson_candidates.md +18 -6
- package/templates/planning/module_session_prompt.md +1 -0
- package/templates/planning/optional/artifacts/INDEX.md +3 -3
- package/templates/planning/optional/references/INDEX.md +3 -3
- package/templates/planning/review.md +41 -0
- package/templates/planning/task_plan.md +5 -21
- package/templates/planning/visual_map.md +13 -9
- package/templates/planning/visual_map.simple.md +52 -0
- package/templates/reference/execution-workflow-standard.md +31 -3
- package/templates/reference/pull-request-standard.md +80 -0
- package/templates/reference/repo-governance-standard.md +7 -6
- package/templates/reference/review-routing-standard.md +6 -0
- package/templates/reference/walkthrough-standard.md +2 -1
- package/templates/verifier/verifier-output.md +1 -1
- package/templates-zh-CN/AGENTS.md.template +25 -19
- package/templates-zh-CN/ledger/Harness-Ledger.md +17 -40
- package/templates-zh-CN/planning/INDEX.md +87 -0
- package/templates-zh-CN/planning/brief.md +1 -1
- package/templates-zh-CN/planning/execution_strategy.md +30 -0
- package/templates-zh-CN/planning/lesson_candidates.md +18 -6
- package/templates-zh-CN/planning/module_session_prompt.md +1 -0
- package/templates-zh-CN/planning/review.md +41 -1
- package/templates-zh-CN/planning/task_plan.md +4 -44
- 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/reference/adversarial-review-standard.md +1 -1
- package/templates-zh-CN/reference/docs-library-standard.md +1 -1
- package/templates-zh-CN/reference/execution-workflow-standard.md +33 -7
- package/templates-zh-CN/reference/harness-ledger-standard.md +2 -2
- package/templates-zh-CN/reference/pull-request-standard.md +106 -0
- package/templates-zh-CN/reference/repo-governance-standard.md +4 -3
- package/templates-zh-CN/reference/review-routing-standard.md +8 -1
- package/templates-zh-CN/reference/walkthrough-standard.md +3 -2
- package/templates-zh-CN/walkthrough/Closeout-SSoT.md +1 -1
- package/docs-release/assets/dashboard-overview-en.png +0 -0
- package/scripts/smoke-dashboard.mjs +0 -92
- package/scripts/test-harness.mjs +0 -1395
- package/templates/ssot/Feature-SSoT.md +0 -43
- package/templates/ssot/Lessons-SSoT.md +0 -44
- package/templates-zh-CN/ssot/Feature-SSoT.md +0 -49
- package/templates-zh-CN/ssot/Lessons-SSoT.md +0 -49
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
lessonCandidatesFile,
|
|
5
|
+
readFileSafe,
|
|
6
|
+
toPosix,
|
|
7
|
+
visualMapFile,
|
|
8
|
+
} from "./core-shared.mjs";
|
|
9
|
+
import {
|
|
10
|
+
listTaskPlanPaths,
|
|
11
|
+
parseTaskBudget,
|
|
12
|
+
parseTaskContractInfo,
|
|
13
|
+
} from "./task-scanner.mjs";
|
|
14
|
+
import { parseTaskAuditMetadata } from "./task-audit-metadata.mjs";
|
|
15
|
+
|
|
16
|
+
export function validatePlanContracts(target, { strict = true, taskPlanPaths } = {}) {
|
|
17
|
+
const failures = [];
|
|
18
|
+
const warnings = [];
|
|
19
|
+
const report = (message) => {
|
|
20
|
+
if (strict) failures.push(message);
|
|
21
|
+
else warnings.push(`adoption-needed: ${message}`);
|
|
22
|
+
};
|
|
23
|
+
for (const taskPlanPath of taskPlanPaths || listTaskPlanPaths(target)) {
|
|
24
|
+
const taskDir = path.dirname(taskPlanPath);
|
|
25
|
+
const relativeDir = toPosix(path.relative(target.projectRoot, taskDir));
|
|
26
|
+
const taskPlanContent = readFileSafe(taskPlanPath);
|
|
27
|
+
const indexContent = readFileSafe(path.join(taskDir, "INDEX.md"));
|
|
28
|
+
const budget = parseTaskBudget(taskPlanContent);
|
|
29
|
+
const taskContract = parseTaskContractInfo(taskPlanContent);
|
|
30
|
+
const taskAudit = parseTaskAuditMetadata(indexContent, { required: strict && taskContract.generated });
|
|
31
|
+
if (!taskContract.generated) {
|
|
32
|
+
warnings.push(`adoption-needed: ${relativeDir} missing Task Contract: harness-task/v1 marker`);
|
|
33
|
+
}
|
|
34
|
+
for (const issue of taskAudit.issues) {
|
|
35
|
+
if (taskContract.generated || taskAudit.present) failures.push(`${relativeDir}/INDEX.md ${issue.message}`);
|
|
36
|
+
else report(`${relativeDir}/INDEX.md ${issue.message}`);
|
|
37
|
+
}
|
|
38
|
+
const indexRequired = /^Task Package Index\s*[::]\s*(required|yes|true|必需|必须|required)\s*$/im.test(taskPlanContent);
|
|
39
|
+
for (const fileName of requiredTaskFilesForBudget(budget, { indexRequired })) {
|
|
40
|
+
if (!fs.existsSync(path.join(taskDir, fileName))) {
|
|
41
|
+
if (taskContract.generated) failures.push(`${relativeDir} missing ${fileName}`);
|
|
42
|
+
else report(`${relativeDir} missing ${fileName}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { failures, warnings };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function requiredTaskFilesForBudget(budget, { indexRequired = false } = {}) {
|
|
50
|
+
const simpleFiles = [...(indexRequired ? ["INDEX.md"] : []), "brief.md", "task_plan.md", visualMapFile, "progress.md"];
|
|
51
|
+
if (budget === "simple") return simpleFiles;
|
|
52
|
+
const standardFiles = [...simpleFiles, "execution_strategy.md", "findings.md", lessonCandidatesFile, "review.md"];
|
|
53
|
+
if (budget === "complex") return [...standardFiles, "references/INDEX.md", "artifacts/INDEX.md"];
|
|
54
|
+
return standardFiles;
|
|
55
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
|
|
@@ -10,6 +11,11 @@ export const legacyVisualRoadmapFile = "visual_roadmap.md";
|
|
|
10
11
|
export const lessonCandidatesFile = "lesson_candidates.md";
|
|
11
12
|
export const longRunningTaskContractFile = "long-running-task-contract.md";
|
|
12
13
|
export const taskContractMarker = "Task Contract: harness-task/v1";
|
|
14
|
+
export const builtinPresetRoot = path.join(repoRoot, "presets");
|
|
15
|
+
export function userPresetRootForHome(home = "") {
|
|
16
|
+
return path.join(path.resolve(home || os.homedir()), ".coding-agent-harness/presets");
|
|
17
|
+
}
|
|
18
|
+
export const userPresetRoot = userPresetRootForHome();
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
export const supportedLocales = new Set(["zh-CN", "en-US"]);
|
|
@@ -40,6 +46,10 @@ export function normalizeTarget(input = ".") {
|
|
|
40
46
|
};
|
|
41
47
|
}
|
|
42
48
|
|
|
49
|
+
export function projectPresetRoot(targetInput = ".") {
|
|
50
|
+
return path.join(normalizeTarget(targetInput).projectRoot, ".coding-agent-harness/presets");
|
|
51
|
+
}
|
|
52
|
+
|
|
43
53
|
export function toPosix(value) {
|
|
44
54
|
return value.split(path.sep).join("/");
|
|
45
55
|
}
|
|
@@ -60,6 +70,15 @@ export function readFileSafe(filePath) {
|
|
|
60
70
|
}
|
|
61
71
|
}
|
|
62
72
|
|
|
73
|
+
export function readJsonSafe(filePath, fallback = null, { onError } = {}) {
|
|
74
|
+
try {
|
|
75
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
if (typeof onError === "function") onError(error);
|
|
78
|
+
return fallback;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
63
82
|
export function readBundledTemplate(source) {
|
|
64
83
|
const sourcePath = path.join(repoRoot, source);
|
|
65
84
|
if (!fs.existsSync(sourcePath)) throw new Error(`Bundled template missing: ${source}`);
|
|
@@ -68,15 +87,17 @@ export function readBundledTemplate(source) {
|
|
|
68
87
|
return content;
|
|
69
88
|
}
|
|
70
89
|
|
|
71
|
-
export function walkFiles(root) {
|
|
90
|
+
export function walkFiles(root, options = {}) {
|
|
72
91
|
const results = [];
|
|
73
92
|
if (!fs.existsSync(root)) return results;
|
|
93
|
+
const dirFilter = typeof options.dirFilter === "function" ? options.dirFilter : () => true;
|
|
74
94
|
function walk(dir) {
|
|
75
95
|
for (const entry of fs.readdirSync(dir)) {
|
|
76
96
|
const full = path.join(dir, entry);
|
|
77
97
|
const stat = fs.statSync(full);
|
|
78
98
|
if (stat.isDirectory()) {
|
|
79
99
|
if ([".git", "node_modules", "tmp"].includes(entry)) continue;
|
|
100
|
+
if (!dirFilter(entry, full)) continue;
|
|
80
101
|
walk(full);
|
|
81
102
|
} else {
|
|
82
103
|
results.push(full);
|
|
@@ -170,14 +191,56 @@ export function normalizeTaskId(value) {
|
|
|
170
191
|
return slug(value || "task");
|
|
171
192
|
}
|
|
172
193
|
|
|
173
|
-
export function renderTaskTemplate(content, { taskId, title, locale, budget = "standard" }) {
|
|
194
|
+
export function renderTaskTemplate(content, { taskId, title, locale, budget = "standard", moduleKey = "", preset = "none", presetVersion = "", evidenceBundle = "", longRunning = false, scaffoldProvenance = {}, taskAudit = {} }) {
|
|
174
195
|
const date = todayDate();
|
|
196
|
+
const provenance = {
|
|
197
|
+
createdBy: scaffoldProvenance.createdBy || "harness new-task",
|
|
198
|
+
command: scaffoldProvenance.command || "harness new-task [task-id] <target>",
|
|
199
|
+
createdAt: scaffoldProvenance.createdAt || date,
|
|
200
|
+
budget: scaffoldProvenance.budget || budget,
|
|
201
|
+
templateSource: scaffoldProvenance.templateSource || "templates/planning/brief.md",
|
|
202
|
+
exceptionReason: scaffoldProvenance.exceptionReason || "n/a",
|
|
203
|
+
};
|
|
175
204
|
return String(content)
|
|
176
205
|
.replaceAll("{{TASK_ID}}", taskId)
|
|
177
206
|
.replaceAll("{{TASK_TITLE}}", title)
|
|
178
207
|
.replaceAll("{{DATE}}", date)
|
|
179
208
|
.replaceAll("{{LOCALE}}", normalizeLocale(locale))
|
|
180
209
|
.replaceAll("{{TASK_BUDGET}}", budget)
|
|
210
|
+
.replaceAll("{{TASK_MODULE}}", moduleKey || "n/a")
|
|
211
|
+
.replaceAll("{{TASK_PRESET}}", preset || "none")
|
|
212
|
+
.replaceAll("{{TASK_PRESET_VERSION}}", presetVersion || "n/a")
|
|
213
|
+
.replaceAll("{{TASK_EVIDENCE_BUNDLE}}", evidenceBundle || "n/a")
|
|
214
|
+
.replaceAll("{{TASK_LONG_RUNNING}}", longRunning ? "yes" : "no")
|
|
215
|
+
.replaceAll("{{SCAFFOLD_CREATED_BY}}", provenance.createdBy)
|
|
216
|
+
.replaceAll("{{SCAFFOLD_COMMAND}}", provenance.command)
|
|
217
|
+
.replaceAll("{{SCAFFOLD_CREATED_AT}}", provenance.createdAt)
|
|
218
|
+
.replaceAll("{{SCAFFOLD_BUDGET}}", provenance.budget)
|
|
219
|
+
.replaceAll("{{SCAFFOLD_TEMPLATE_SOURCE}}", provenance.templateSource)
|
|
220
|
+
.replaceAll("{{SCAFFOLD_EXCEPTION_REASON}}", provenance.exceptionReason)
|
|
221
|
+
.replaceAll("{{TASK_AUDIT_CREATED_BY}}", taskAudit["Created By"] || provenance.createdBy)
|
|
222
|
+
.replaceAll("{{TASK_AUDIT_CREATED_AT}}", taskAudit["Created At"] || provenance.createdAt)
|
|
223
|
+
.replaceAll("{{TASK_AUDIT_COMMAND_SHAPE}}", taskAudit["Command Shape"] || provenance.command)
|
|
224
|
+
.replaceAll("{{TASK_AUDIT_BUDGET}}", taskAudit.Budget || provenance.budget)
|
|
225
|
+
.replaceAll("{{TASK_AUDIT_TEMPLATE_SOURCE}}", taskAudit["Template Source"] || provenance.templateSource)
|
|
226
|
+
.replaceAll("{{TASK_AUDIT_TASK_CREATOR}}", taskAudit["Task Creator"] || "n/a")
|
|
227
|
+
.replaceAll("{{TASK_AUDIT_TASK_CREATOR_SOURCE}}", taskAudit["Task Creator Source"] || "git-unavailable")
|
|
228
|
+
.replaceAll("{{TASK_AUDIT_HUMAN_REVIEW_STATUS}}", taskAudit["Human Review Status"] || "not-confirmed")
|
|
229
|
+
.replaceAll("{{TASK_AUDIT_CONFIRMATION_ID}}", taskAudit["Confirmation ID"] || "n/a")
|
|
230
|
+
.replaceAll("{{TASK_AUDIT_CONFIRMED_AT}}", taskAudit["Confirmed At"] || "n/a")
|
|
231
|
+
.replaceAll("{{TASK_AUDIT_REVIEWER}}", taskAudit.Reviewer || "n/a")
|
|
232
|
+
.replaceAll("{{TASK_AUDIT_REVIEWER_EMAIL}}", taskAudit["Reviewer Email"] || "n/a")
|
|
233
|
+
.replaceAll("{{TASK_AUDIT_CONFIRM_TEXT}}", taskAudit["Confirm Text"] || "n/a")
|
|
234
|
+
.replaceAll("{{TASK_AUDIT_EVIDENCE_CHECKED}}", taskAudit["Evidence Checked"] || "n/a")
|
|
235
|
+
.replaceAll("{{TASK_AUDIT_REVIEW_COMMIT_SHA}}", taskAudit["Review Commit SHA"] || "n/a")
|
|
236
|
+
.replaceAll("{{TASK_AUDIT_AUDIT_SOURCE}}", taskAudit["Audit Source"] || "native-index")
|
|
237
|
+
.replaceAll("{{TASK_AUDIT_AUDIT_STATUS}}", taskAudit["Audit Status"] || "created")
|
|
238
|
+
.replaceAll("{{TASK_AUDIT_EXCEPTION_REASON}}", taskAudit["Exception Reason"] || provenance.exceptionReason)
|
|
239
|
+
.replaceAll("{{TASK_AUDIT_MESSAGE}}", taskAudit.Message || "n/a")
|
|
240
|
+
.replaceAll("{{TASK_AUDIT_MIGRATION_STATUS}}", taskAudit["Migration Status"] || "native")
|
|
241
|
+
.replaceAll("{{TASK_AUDIT_MIGRATED_FROM}}", taskAudit["Migrated From"] || "n/a")
|
|
242
|
+
.replaceAll("{{TASK_AUDIT_LEGACY_EXTRA_FIELDS}}", taskAudit["Legacy Extra Fields"] || "{}")
|
|
243
|
+
.replaceAll("{{TASK_AUDIT_MIGRATION_NOTES}}", taskAudit["Migration Notes"] || "n/a")
|
|
181
244
|
.replaceAll("[simple / standard / complex]", budget)
|
|
182
245
|
.replaceAll("[simple / standard / long-running / module-parallel]", budget)
|
|
183
246
|
.replaceAll("[simple / complex]", budget)
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
3
4
|
import {
|
|
5
|
+
legacyChecker,
|
|
4
6
|
repoRoot,
|
|
7
|
+
builtinPresetRoot,
|
|
5
8
|
normalizeTarget,
|
|
9
|
+
projectPresetRoot,
|
|
6
10
|
readFileSafe,
|
|
7
11
|
sanitizeText,
|
|
8
12
|
sanitizeDeep,
|
|
@@ -15,24 +19,29 @@ import {
|
|
|
15
19
|
legacyVisualRoadmapFile,
|
|
16
20
|
lessonCandidatesFile,
|
|
17
21
|
longRunningTaskContractFile,
|
|
22
|
+
userPresetRoot,
|
|
18
23
|
} from "./core-shared.mjs";
|
|
19
24
|
import {
|
|
20
25
|
parseAllMarkdownTables,
|
|
21
26
|
getCell,
|
|
22
27
|
splitDependencies,
|
|
23
28
|
} from "./markdown-utils.mjs";
|
|
24
|
-
import { readCapabilityRegistry } from "./capability-registry.mjs";
|
|
25
|
-
import {
|
|
29
|
+
import { readCapabilityRegistry, validateCapabilities } from "./capability-registry.mjs";
|
|
30
|
+
import { buildStatusData } from "./status-builder.mjs";
|
|
26
31
|
import {
|
|
27
32
|
listTaskPlanPaths,
|
|
28
33
|
parseTaskState,
|
|
29
34
|
isActiveTaskState,
|
|
30
35
|
} from "./task-scanner.mjs";
|
|
31
36
|
import { writeDashboardDirectory, writeDashboardFile } from "./dashboard-writer.mjs";
|
|
37
|
+
import { listPresetPackageLayers } from "./preset-registry.mjs";
|
|
38
|
+
import { validateGovernanceTableBoundaries } from "./governance-table-boundary.mjs";
|
|
39
|
+
import { summarizeGitState } from "./git-status-summary.mjs";
|
|
32
40
|
|
|
33
|
-
export function collectMarkdownDocuments(target) {
|
|
34
|
-
const docs = collectDashboardDocumentPaths(target);
|
|
35
|
-
return docs.map((
|
|
41
|
+
export function collectMarkdownDocuments(target, options = {}) {
|
|
42
|
+
const docs = collectDashboardDocumentPaths(target, options);
|
|
43
|
+
return docs.map((entry, index) => {
|
|
44
|
+
const file = typeof entry === "string" ? entry : entry.file;
|
|
36
45
|
const content = sanitizeText(readFileSafe(file));
|
|
37
46
|
const source = prefixedPath(target, file);
|
|
38
47
|
return {
|
|
@@ -41,12 +50,14 @@ export function collectMarkdownDocuments(target) {
|
|
|
41
50
|
title: titleFromMarkdown(content, path.basename(file)),
|
|
42
51
|
type: documentKind(source),
|
|
43
52
|
content,
|
|
53
|
+
...(entry.partial ? { partial: true, partialReason: entry.partialReason || "partial", taskId: entry.taskId || "" } : {}),
|
|
44
54
|
};
|
|
45
55
|
});
|
|
46
56
|
}
|
|
47
57
|
|
|
48
|
-
function collectDashboardDocumentPaths(target) {
|
|
58
|
+
function collectDashboardDocumentPaths(target, options = {}) {
|
|
49
59
|
const selected = new Set();
|
|
60
|
+
const partial = new Map();
|
|
50
61
|
const addDocsPath = (relativePath) => {
|
|
51
62
|
const file = path.join(target.docsRoot, relativePath);
|
|
52
63
|
if (fs.existsSync(file)) selected.add(file);
|
|
@@ -56,7 +67,6 @@ function collectDashboardDocumentPaths(target) {
|
|
|
56
67
|
"09-PLANNING/Module-Registry.md",
|
|
57
68
|
"05-TEST-QA/Regression-SSoT.md",
|
|
58
69
|
"05-TEST-QA/Cadence-Ledger.md",
|
|
59
|
-
"01-GOVERNANCE/Lessons-SSoT.md",
|
|
60
70
|
"10-WALKTHROUGH/Closeout-SSoT.md",
|
|
61
71
|
]) {
|
|
62
72
|
addDocsPath(relativePath);
|
|
@@ -67,21 +77,38 @@ function collectDashboardDocumentPaths(target) {
|
|
|
67
77
|
if (path.basename(file).startsWith("_")) continue;
|
|
68
78
|
selected.add(file);
|
|
69
79
|
}
|
|
70
|
-
|
|
80
|
+
const tasksByPlanPath = new Map((options.tasks || []).map((task) => [
|
|
81
|
+
path.join(target.projectRoot, String(task.taskPlanPath || "").replace(/^TARGET:/, "")),
|
|
82
|
+
task,
|
|
83
|
+
]));
|
|
84
|
+
for (const taskPlanPath of options.taskPlanPaths || listTaskPlanPaths(target)) {
|
|
71
85
|
const taskDir = path.dirname(taskPlanPath);
|
|
72
86
|
const progress = readFileSafe(path.join(taskDir, "progress.md"));
|
|
73
87
|
const state = parseTaskState(progress);
|
|
74
88
|
const active = isActiveTaskState(state);
|
|
75
|
-
const
|
|
76
|
-
|
|
89
|
+
const task = tasksByPlanPath.get(taskPlanPath);
|
|
90
|
+
const historicalClosed = !active && task?.closeoutStatus === "closed";
|
|
91
|
+
const documentNames = historicalClosed
|
|
92
|
+
? ["brief.md"]
|
|
77
93
|
: ["brief.md", "task_plan.md", "execution_strategy.md", visualMapFile, legacyVisualRoadmapFile, lessonCandidatesFile, longRunningTaskContractFile, "progress.md", "review.md", "findings.md"];
|
|
78
94
|
for (const fileName of documentNames) {
|
|
79
95
|
const file = path.join(taskDir, fileName);
|
|
80
|
-
if (fs.existsSync(file))
|
|
96
|
+
if (fs.existsSync(file)) {
|
|
97
|
+
selected.add(file);
|
|
98
|
+
if (historicalClosed) {
|
|
99
|
+
partial.set(file, {
|
|
100
|
+
partial: true,
|
|
101
|
+
partialReason: "historical-closed",
|
|
102
|
+
taskId: task?.id || path.basename(taskDir),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
81
106
|
}
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
107
|
+
if (!historicalClosed) {
|
|
108
|
+
for (const indexFile of ["references/INDEX.md", "artifacts/INDEX.md"]) {
|
|
109
|
+
const file = path.join(taskDir, indexFile);
|
|
110
|
+
if (fs.existsSync(file)) selected.add(file);
|
|
111
|
+
}
|
|
85
112
|
}
|
|
86
113
|
}
|
|
87
114
|
for (const file of walkFiles(path.join(target.docsRoot, "09-PLANNING/MODULES"))) {
|
|
@@ -95,7 +122,8 @@ function collectDashboardDocumentPaths(target) {
|
|
|
95
122
|
.filter((file) => !file.includes(`${path.sep}_archive${path.sep}`))
|
|
96
123
|
.filter((file) => !file.includes(`${path.sep}_task-template${path.sep}`))
|
|
97
124
|
.filter((file) => !file.includes(`${path.sep}_optional-structures${path.sep}`))
|
|
98
|
-
.sort()
|
|
125
|
+
.sort()
|
|
126
|
+
.map((file) => ({ file, ...(partial.get(file) || {}) }));
|
|
99
127
|
}
|
|
100
128
|
|
|
101
129
|
function documentKind(source) {
|
|
@@ -104,7 +132,7 @@ function documentKind(source) {
|
|
|
104
132
|
if (lower.includes("module-registry.md")) return "module-registry";
|
|
105
133
|
if (lower.includes("regression-ssot.md")) return "regression-ssot";
|
|
106
134
|
if (lower.includes("cadence-ledger.md")) return "cadence-ledger";
|
|
107
|
-
if (
|
|
135
|
+
if (/\/01-governance\/lessons\/[^/]+\.md$/i.test(lower)) return "lesson-detail";
|
|
108
136
|
if (lower.endsWith("/progress.md")) return "task-progress";
|
|
109
137
|
if (lower.endsWith("/brief.md")) return "task-brief";
|
|
110
138
|
if (lower.endsWith("/review.md")) return "task-review";
|
|
@@ -146,7 +174,17 @@ export function collectGraph(status, tables = { tables: [] }) {
|
|
|
146
174
|
addNode({ id: `task:${task.id}`, type: "task", label: task.title, state: task.state, completion: task.completion });
|
|
147
175
|
for (const phase of task.phases || []) {
|
|
148
176
|
const phaseId = `phase:${task.id}:${phase.id}`;
|
|
149
|
-
addNode({
|
|
177
|
+
addNode({
|
|
178
|
+
id: phaseId,
|
|
179
|
+
type: "phase",
|
|
180
|
+
label: phase.id,
|
|
181
|
+
state: phase.state,
|
|
182
|
+
completion: phase.completion,
|
|
183
|
+
kind: phase.kind,
|
|
184
|
+
actor: phase.actor,
|
|
185
|
+
exitCommand: phase.exitCommand,
|
|
186
|
+
taskId: task.id,
|
|
187
|
+
});
|
|
150
188
|
addEdge({ from: `task:${task.id}`, to: phaseId, type: "contains" });
|
|
151
189
|
for (const dependency of phase.dependsOn || []) {
|
|
152
190
|
addEdge({ from: `phase:${task.id}:${dependency}`, to: phaseId, type: "depends_on" });
|
|
@@ -200,6 +238,7 @@ export function collectGraph(status, tables = { tables: [] }) {
|
|
|
200
238
|
}
|
|
201
239
|
|
|
202
240
|
export function categorizeWarning(message) {
|
|
241
|
+
if (/governance-table-entropy/i.test(message)) return "Governance Table Boundary";
|
|
203
242
|
if (/missing execution_strategy\.md|missing visual_(?:map|roadmap)\.md|Visual (?:Map|Roadmap)/i.test(message)) return "Plan Contract Missing";
|
|
204
243
|
if (/legacy-compat|adoption-needed|legacy check/i.test(message)) return "Adoption Advice";
|
|
205
244
|
if (/Evidence|evidence/i.test(message)) return "Missing Evidence";
|
|
@@ -213,6 +252,7 @@ function warningType(message) {
|
|
|
213
252
|
if (/missing visual_map\.md|Visual Map/i.test(message)) return "missing-visual-map";
|
|
214
253
|
if (/missing visual_roadmap\.md|Visual Roadmap/i.test(message)) return "missing-visual-roadmap";
|
|
215
254
|
if (/Reviewer Identity|Confidence Challenge|Final Confidence Basis|Evidence Checked/i.test(message)) return "review-schema-gap";
|
|
255
|
+
if (/governance-table-entropy/i.test(message)) return "governance-table-entropy";
|
|
216
256
|
if (/Evidence|evidence/i.test(message)) return "missing-evidence";
|
|
217
257
|
if (/missing required file/i.test(message)) return "legacy-reference-gap";
|
|
218
258
|
if (/legacy-compat|legacy check|adoption-needed/i.test(message)) return "capability-adoption";
|
|
@@ -231,6 +271,7 @@ function warningScope(message) {
|
|
|
231
271
|
|
|
232
272
|
function warningPhase(type, scope) {
|
|
233
273
|
if (type === "capability-adoption") return "baseline";
|
|
274
|
+
if (type === "governance-table-entropy") return "global-table-boundary";
|
|
234
275
|
if (type === "missing-brief" || type === "missing-execution-strategy" || type === "missing-visual-map" || type === "missing-visual-roadmap") return "active-task-contracts";
|
|
235
276
|
if (scope === "module") return "module-classification";
|
|
236
277
|
if (type === "review-schema-gap" || type === "missing-evidence") return "review-evidence";
|
|
@@ -240,6 +281,7 @@ function warningPhase(type, scope) {
|
|
|
240
281
|
|
|
241
282
|
function warningFixability(type, scope) {
|
|
242
283
|
if (["missing-brief", "missing-execution-strategy", "missing-visual-map", "missing-visual-roadmap"].includes(type)) return "guided";
|
|
284
|
+
if (type === "governance-table-entropy") return "manual";
|
|
243
285
|
if (type === "legacy-reference-gap" || scope === "reference") return "template";
|
|
244
286
|
if (type === "capability-adoption") return "decision";
|
|
245
287
|
if (type === "review-schema-gap" || type === "missing-evidence") return "human-evidence";
|
|
@@ -248,6 +290,7 @@ function warningFixability(type, scope) {
|
|
|
248
290
|
|
|
249
291
|
function warningPriority(type, scope, message) {
|
|
250
292
|
if (/fail|invalid|blocked/i.test(message) || type === "schema-drift") return "P1";
|
|
293
|
+
if (type === "governance-table-entropy") return /legacy-report-only/i.test(message) ? "P3" : "P2";
|
|
251
294
|
if (["missing-brief", "missing-execution-strategy", "missing-visual-map", "missing-visual-roadmap"].includes(type) && scope === "task") return "P2";
|
|
252
295
|
if (type === "review-schema-gap" || type === "missing-evidence") return "P2";
|
|
253
296
|
if (type === "capability-adoption") return "P3";
|
|
@@ -284,19 +327,24 @@ function summarizeWarnings(warnings) {
|
|
|
284
327
|
}
|
|
285
328
|
|
|
286
329
|
export function collectAdoption(status) {
|
|
287
|
-
const
|
|
330
|
+
const dashboardMessages = [
|
|
331
|
+
...(status.checkState.details.warnings || []),
|
|
332
|
+
...(status.checkState.details.failures || []).filter((message) => /governance-table-entropy/i.test(message)),
|
|
333
|
+
];
|
|
334
|
+
const warnings = dashboardMessages.flatMap((message) => splitWarningMessage(message)).map((message, index) => {
|
|
288
335
|
const type = warningType(message);
|
|
289
336
|
const scope = warningScope(message);
|
|
290
337
|
const affectedPaths = warningAffectedPaths(message);
|
|
338
|
+
const stableSuffix = type === "governance-table-entropy" ? `-${stableWarningIdPart(governanceWarningRowKey(message))}` : "";
|
|
291
339
|
return {
|
|
292
|
-
id: `AD-${String(index + 1).padStart(3, "0")}`,
|
|
340
|
+
id: `AD-${String(index + 1).padStart(3, "0")}${stableSuffix}`,
|
|
293
341
|
category: categorizeWarning(message),
|
|
294
342
|
type,
|
|
295
343
|
scope,
|
|
296
344
|
priority: warningPriority(type, scope, message),
|
|
297
345
|
phase: warningPhase(type, scope),
|
|
298
346
|
fixability: warningFixability(type, scope),
|
|
299
|
-
status: "open",
|
|
347
|
+
status: /legacy-report-only/i.test(message) ? "legacy-report-only" : "open",
|
|
300
348
|
confidence: warningConfidence(message),
|
|
301
349
|
severity: status.mode === "legacy-compat" ? "advice" : "warning",
|
|
302
350
|
title: warningTitle(message),
|
|
@@ -330,6 +378,18 @@ export function collectAdoption(status) {
|
|
|
330
378
|
};
|
|
331
379
|
}
|
|
332
380
|
|
|
381
|
+
function governanceWarningRowKey(message) {
|
|
382
|
+
const match = String(message || "").match(/\brow\s+([^:]+)/i);
|
|
383
|
+
return match ? match[1].trim() : "global-table";
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function stableWarningIdPart(value) {
|
|
387
|
+
return String(value || "global-table")
|
|
388
|
+
.replace(/[^A-Za-z0-9_-]+/g, "-")
|
|
389
|
+
.replace(/^-+|-+$/g, "")
|
|
390
|
+
.slice(0, 80) || "global-table";
|
|
391
|
+
}
|
|
392
|
+
|
|
333
393
|
export function splitWarningMessage(message) {
|
|
334
394
|
return String(message || "")
|
|
335
395
|
.split(/\n-\s+/)
|
|
@@ -338,6 +398,7 @@ export function splitWarningMessage(message) {
|
|
|
338
398
|
}
|
|
339
399
|
|
|
340
400
|
function warningTitle(message) {
|
|
401
|
+
if (/governance-table-entropy/i.test(message)) return "Global table boundary";
|
|
341
402
|
if (/missing execution_strategy\.md/i.test(message)) return "Missing execution strategy";
|
|
342
403
|
if (/missing visual_map\.md|Visual Map/i.test(message)) return "Missing visual map";
|
|
343
404
|
if (/missing visual_roadmap\.md|Visual Roadmap/i.test(message)) return "Missing legacy visual roadmap";
|
|
@@ -354,6 +415,7 @@ function warningAffected(message) {
|
|
|
354
415
|
}
|
|
355
416
|
|
|
356
417
|
function warningAction(message) {
|
|
418
|
+
if (/governance-table-entropy/i.test(message)) return "Move local detail to module/task docs; keep the global row to summary, state, route, and audit result.";
|
|
357
419
|
if (/execution_strategy\.md/i.test(message)) return "Add standalone execution strategy file.";
|
|
358
420
|
if (/visual_map\.md|Visual Map/i.test(message)) return "Add standalone visual map file.";
|
|
359
421
|
if (/visual_roadmap\.md|Visual Roadmap/i.test(message)) return "Rewrite legacy visual_roadmap.md into canonical visual_map.md.";
|
|
@@ -363,13 +425,82 @@ function warningAction(message) {
|
|
|
363
425
|
}
|
|
364
426
|
|
|
365
427
|
export function buildDashboardBundle(targetInput, options = {}) {
|
|
366
|
-
const status = buildStatus(targetInput, options);
|
|
367
428
|
const target = normalizeTarget(targetInput);
|
|
368
|
-
const
|
|
429
|
+
const taskPlanPaths = listTaskPlanPaths(target);
|
|
430
|
+
const capabilityState = validateCapabilities(target);
|
|
431
|
+
const gitState = summarizeGitState(target);
|
|
432
|
+
const declaredCapabilities = new Set(capabilityState.registry.capabilities.map((capability) => capability.name));
|
|
433
|
+
const shouldRunLegacy = !options.skipLegacyCheck && (capabilityState.registry.mode === "legacy-compat" || declaredCapabilities.has("safe-adoption"));
|
|
434
|
+
const legacy = shouldRunLegacy ? runDashboardLegacyCheck(target) : { status: "skipped", code: 0, stdout: "", stderr: "" };
|
|
435
|
+
const legacyWarnings = legacy.status === "fail" ? [`adoption-needed: legacy check failed: ${(legacy.stderr || legacy.stdout).trim()}`] : [];
|
|
436
|
+
const governanceBoundaries = validateGovernanceTableBoundaries(target);
|
|
437
|
+
const status = buildStatusData(target, {
|
|
438
|
+
...options,
|
|
439
|
+
capabilityState,
|
|
440
|
+
gitState,
|
|
441
|
+
taskPlanPaths,
|
|
442
|
+
legacy,
|
|
443
|
+
failures: [...capabilityState.failures, ...governanceBoundaries.failures],
|
|
444
|
+
warnings: [...capabilityState.warnings, ...legacyWarnings, ...governanceBoundaries.warnings, ...gitState.warnings],
|
|
445
|
+
});
|
|
446
|
+
const documents = { documents: collectMarkdownDocuments(target, { taskPlanPaths, tasks: status.tasks }) };
|
|
369
447
|
const tables = collectTables(documents.documents);
|
|
370
448
|
const graph = collectGraph(status, tables);
|
|
371
449
|
const adoption = collectAdoption(status);
|
|
372
|
-
|
|
450
|
+
const presetCatalog = collectPresetCatalog(targetInput, target, options);
|
|
451
|
+
return sanitizeDeep({ status, tables, documents, graph, adoption, presetCatalog });
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function runDashboardLegacyCheck(target) {
|
|
455
|
+
const checkTarget = target.docsOnly ? target.projectRoot : target.input;
|
|
456
|
+
const result = spawnSync(process.execPath, [legacyChecker, checkTarget], {
|
|
457
|
+
cwd: repoRoot,
|
|
458
|
+
encoding: "utf8",
|
|
459
|
+
});
|
|
460
|
+
return {
|
|
461
|
+
status: result.status === 0 ? "pass" : "fail",
|
|
462
|
+
code: result.status ?? 1,
|
|
463
|
+
stdout: result.stdout || "",
|
|
464
|
+
stderr: result.stderr || "",
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export function collectPresetCatalog(targetInput, target = normalizeTarget(targetInput), options = {}) {
|
|
469
|
+
const home = options.home || "";
|
|
470
|
+
const presets = listPresetPackageLayers({ targetInput: target.projectRoot, home }).map((preset) => ({
|
|
471
|
+
key: `${preset.source}:${preset.id}`,
|
|
472
|
+
id: preset.id,
|
|
473
|
+
version: preset.version,
|
|
474
|
+
source: preset.source,
|
|
475
|
+
effective: preset.effective === true,
|
|
476
|
+
purpose: preset.purpose,
|
|
477
|
+
compatibleBudgets: preset.compatibleBudgets,
|
|
478
|
+
manifestPath: preset.manifestRelativePath,
|
|
479
|
+
manifestSha256: preset.manifestSha256,
|
|
480
|
+
taskKind: preset.task?.kind || "",
|
|
481
|
+
inputCount: Object.keys(preset.inputs || {}).length,
|
|
482
|
+
referenceCount: Object.keys(preset.resources?.references || {}).length,
|
|
483
|
+
artifactCount: Object.keys(preset.resources?.artifacts || {}).length,
|
|
484
|
+
writeScopeCount: Object.keys(preset.writeScopes || {}).length,
|
|
485
|
+
evidenceFileCount: Object.keys(preset.evidence?.files || {}).length,
|
|
486
|
+
requiredReadCount: Array.isArray(preset.context?.requiredReads) ? preset.context.requiredReads.length : 0,
|
|
487
|
+
checkStatus: "unknown",
|
|
488
|
+
}));
|
|
489
|
+
const countSource = (source) => presets.filter((preset) => preset.source === source).length;
|
|
490
|
+
return {
|
|
491
|
+
summary: {
|
|
492
|
+
total: presets.length,
|
|
493
|
+
project: countSource("project"),
|
|
494
|
+
user: countSource("user"),
|
|
495
|
+
builtin: countSource("builtin"),
|
|
496
|
+
},
|
|
497
|
+
roots: [
|
|
498
|
+
{ source: "project", path: projectPresetRoot(target.projectRoot) },
|
|
499
|
+
{ source: "user", path: home ? path.join(path.resolve(home), ".coding-agent-harness/presets") : userPresetRoot },
|
|
500
|
+
{ source: "builtin", path: builtinPresetRoot },
|
|
501
|
+
],
|
|
502
|
+
presets,
|
|
503
|
+
};
|
|
373
504
|
}
|
|
374
505
|
|
|
375
506
|
export function writeDashboardFolder(outDir, targetInput, options = {}) {
|
|
@@ -377,7 +508,7 @@ export function writeDashboardFolder(outDir, targetInput, options = {}) {
|
|
|
377
508
|
const registry = readCapabilityRegistry(target);
|
|
378
509
|
const locale = options.localeOverride || registry.locale;
|
|
379
510
|
const bundle = buildDashboardBundle(targetInput, options);
|
|
380
|
-
return writeDashboardDirectory(outDir, bundle, { repoRoot, projectRoot: target.projectRoot, docsRoot: target.docsRoot, locale, workbenchRuntime: options.workbenchRuntime === true });
|
|
511
|
+
return writeDashboardDirectory(outDir, bundle, { repoRoot, projectRoot: target.projectRoot, docsRoot: target.docsRoot, locale, workbenchRuntime: options.workbenchRuntime === true, recoverGeneratedDashboard: options.recoverGeneratedDashboard === true });
|
|
381
512
|
}
|
|
382
513
|
|
|
383
514
|
export function writeDashboardSingleFile(outFile, targetInput, options = {}) {
|