coding-agent-harness 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/CONTRIBUTING.md +9 -5
- package/README.md +12 -2
- package/README.zh-CN.md +10 -2
- package/SKILL.md +14 -3
- package/dist/build-dist.mjs +32 -6
- package/dist/check-dist-observation.mjs +73 -28
- package/dist/check-harness.mjs +0 -1
- package/dist/check-import-graph.mjs +44 -27
- package/dist/check-lite-forbidden-surfaces.mjs +121 -0
- package/dist/check-no-ts-nocheck.mjs +88 -0
- package/dist/check-runtime-emit.mjs +10 -3
- package/dist/check-type-boundaries.mjs +67 -8
- package/dist/commands/dashboard-command.mjs +52 -14
- package/dist/commands/migration-command.mjs +18 -8
- package/dist/commands/module-command.mjs +142 -0
- package/dist/commands/preset-command.mjs +65 -4
- package/dist/commands/registry.mjs +483 -0
- package/dist/commands/task-command.mjs +111 -53
- package/dist/harness.mjs +6 -303
- package/dist/lib/capability-registry.mjs +229 -53
- package/dist/lib/check-module-parallel.mjs +1 -6
- package/dist/lib/check-profiles.mjs +39 -46
- package/dist/lib/check-task-contracts.mjs +6 -4
- package/dist/lib/command-registry.mjs +248 -0
- package/dist/lib/core-shared.mjs +78 -3
- package/dist/lib/dashboard-data.mjs +203 -22
- package/dist/lib/dashboard-workbench.mjs +245 -21
- package/dist/lib/dashboard-writer.mjs +4 -1
- package/dist/lib/git-status-summary.mjs +0 -1
- package/dist/lib/governance-index-generator.mjs +7 -5
- package/dist/lib/governance-sync.mjs +46 -121
- package/dist/lib/governance-table-boundary.mjs +1 -14
- package/dist/lib/harness-core.mjs +5 -1
- package/dist/lib/harness-paths.mjs +115 -1
- package/dist/lib/impact-classifier.mjs +420 -0
- package/dist/lib/lesson-maintenance.mjs +1 -2
- package/dist/lib/markdown-utils.mjs +50 -1
- package/dist/lib/migration-planner.mjs +31 -16
- package/dist/lib/migration-support.mjs +5 -4
- package/dist/lib/module-registry.mjs +296 -0
- package/dist/lib/preset-audit-contracts.mjs +24 -1
- package/dist/lib/preset-engine.mjs +68 -29
- package/dist/lib/preset-registry.mjs +374 -72
- package/dist/lib/preset-runner.mjs +560 -0
- package/dist/lib/review-confirm-git-gate.mjs +73 -19
- package/dist/lib/status-builder.mjs +23 -8
- package/dist/lib/structure-migration.mjs +6 -4
- package/dist/lib/subagent-authorization-audit.mjs +8 -2
- package/dist/lib/task-archive-eligibility.mjs +65 -0
- package/dist/lib/task-audit-metadata.mjs +25 -11
- package/dist/lib/task-audit-migration.mjs +21 -14
- package/dist/lib/task-discovery-contract.mjs +32 -0
- package/dist/lib/task-index.mjs +4 -2
- package/dist/lib/task-lesson-candidates.mjs +1 -2
- package/dist/lib/task-lesson-sedimentation.mjs +310 -9
- package/dist/lib/task-lifecycle/create-task-helpers.mjs +6 -3
- package/dist/lib/task-lifecycle/phase-sync.mjs +0 -1
- package/dist/lib/task-lifecycle/preset-interop.mjs +16 -0
- package/dist/lib/task-lifecycle/review-confirm.mjs +34 -2
- package/dist/lib/task-lifecycle/review-gates.mjs +12 -5
- package/dist/lib/task-lifecycle/review-submission.mjs +1 -2
- package/dist/lib/task-lifecycle/scaffold-provenance.mjs +0 -1
- package/dist/lib/task-lifecycle/template-files.mjs +2 -5
- package/dist/lib/task-lifecycle.mjs +117 -159
- package/dist/lib/task-metadata.mjs +10 -5
- package/dist/lib/task-preset-contract-drift.mjs +45 -0
- package/dist/lib/task-repository.mjs +192 -0
- package/dist/lib/task-review-model.mjs +38 -17
- package/dist/lib/task-scanner.mjs +75 -23
- package/dist/lib/task-template-materials.mjs +131 -0
- package/dist/lib/task-tombstone-commands.mjs +187 -18
- package/dist/lib/types/check-profiles.js +1 -0
- package/dist/lib/types/impact.js +1 -0
- package/dist/lib/types/preset.js +1 -0
- package/dist/lib/types/task-lifecycle.js +1 -0
- package/dist/lib/types/task-scanner.js +1 -0
- package/dist/postinstall.mjs +2 -2
- package/dist/run-built-tests.mjs +10 -3
- package/docs-release/README.md +2 -1
- package/docs-release/architecture/document-contract-kernel/README.md +150 -0
- package/docs-release/architecture/document-contract-kernel/products/full-skill-overlay.md +29 -0
- package/docs-release/architecture/document-contract-kernel/products/lite-forbidden-surfaces.txt +26 -0
- package/docs-release/architecture/document-contract-kernel/products/lite-skill-overlay.md +37 -0
- package/docs-release/architecture/overview.md +2 -2
- package/docs-release/architecture/overview.zh-CN.md +2 -2
- package/docs-release/architecture/system-explainer/01-system-overview.md +11 -7
- package/docs-release/architecture/system-explainer/02-module-dependency.md +4 -4
- package/docs-release/architecture/system-explainer/03-task-lifecycle.md +17 -12
- package/docs-release/architecture/system-explainer/05-data-flow.md +6 -6
- package/docs-release/architecture/system-explainer/06-preset-and-migration.md +2 -2
- package/docs-release/architecture/system-explainer/README.md +1 -1
- package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +12 -8
- package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +5 -5
- package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +19 -11
- package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +5 -5
- package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +2 -2
- package/docs-release/architecture/system-explainer/en-US/README.md +1 -1
- package/docs-release/guides/agent-installation.en-US.md +4 -6
- package/docs-release/guides/agent-installation.md +11 -8
- package/docs-release/guides/contributing.md +10 -3
- package/docs-release/guides/contributing.zh-CN.md +10 -3
- package/docs-release/guides/legacy-migration-agent-prompt.md +1 -1
- package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +1 -1
- package/docs-release/guides/migration-playbook.en-US.md +9 -6
- package/docs-release/guides/migration-playbook.md +9 -6
- package/docs-release/guides/preset-development.md +68 -2
- package/docs-release/guides/task-state-machine.en-US.md +8 -8
- package/docs-release/guides/task-state-machine.md +7 -7
- package/docs-release/guides/typescript-runtime-migration-closeout.md +17 -13
- package/package.json +19 -11
- package/postinstall.mjs +37 -0
- package/presets/legacy-migration/preset.yaml +5 -5
- package/presets/legacy-migration/templates/execution_strategy.append.md +1 -1
- package/presets/lesson-sedimentation/preset.yaml +3 -3
- package/presets/module/preset.yaml +2 -2
- package/presets/module/templates/execution_strategy.append.md +1 -1
- package/presets/module/templates/task_plan.append.md +3 -3
- package/presets/release-closeout/checks/check-release-package.mjs +29 -0
- package/presets/release-closeout/preset.yaml +100 -0
- package/presets/release-closeout/scripts/generate-release-package.mjs +572 -0
- package/presets/release-closeout/templates/execution_strategy.append.md +7 -0
- package/presets/release-closeout/templates/findings.seed.md +5 -0
- package/presets/release-closeout/templates/review.seed.md +3 -0
- package/presets/release-closeout/templates/task_plan.append.md +24 -0
- package/presets/standard-task/preset.yaml +2 -2
- package/references/agents-md-pattern.md +23 -17
- package/references/lessons-governance.md +2 -2
- package/references/module-parallel-standard.md +3 -6
- package/references/pull-request-standard.md +2 -2
- package/references/ssot-governance.md +2 -2
- package/references/taskr-gap-analysis.md +3 -3
- package/run-dist.mjs +34 -0
- package/skills/preset-creator/SKILL.md +40 -8
- package/skills/preset-creator/references/complex-task-skeleton/brief.md +32 -8
- package/skills/preset-creator/references/preset-package-skeleton.md +15 -5
- package/skills/preset-creator/references/structure-aware-paths.md +112 -0
- package/templates/AGENTS.md.template +28 -26
- package/templates/architecture/README.md +2 -2
- package/templates/architecture/service-catalog.md +2 -2
- package/templates/architecture/services/service-template.md +1 -1
- package/templates/dashboard/assets/app-src/00-state.js +5 -1
- package/templates/dashboard/assets/app-src/10-router.js +7 -0
- package/templates/dashboard/assets/app-src/20-overview.js +8 -8
- package/templates/dashboard/assets/app-src/30-tasks.js +132 -40
- package/templates/dashboard/assets/app-src/32-task-swimlane.js +314 -0
- package/templates/dashboard/assets/app-src/35-task-detail.js +35 -5
- package/templates/dashboard/assets/app-src/40-modules.js +257 -41
- package/templates/dashboard/assets/app-src/45-review.js +127 -1
- package/templates/dashboard/assets/app-src/90-bindings.js +185 -2
- package/templates/dashboard/assets/app.css +928 -53
- package/templates/dashboard/assets/app.css.manifest.json +2 -0
- package/templates/dashboard/assets/app.js +1071 -98
- package/templates/dashboard/assets/app.manifest.json +1 -0
- package/templates/dashboard/assets/css-src/00-foundation.css +12 -6
- package/templates/dashboard/assets/css-src/10-panels-flow.css +2 -2
- package/templates/dashboard/assets/css-src/30-task-index.css +21 -13
- package/templates/dashboard/assets/css-src/31-archive.css +94 -0
- package/templates/dashboard/assets/css-src/32-task-swimlane.css +487 -0
- package/templates/dashboard/assets/css-src/35-review-workspace.css +78 -0
- package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +191 -14
- package/templates/dashboard/assets/css-src/50-responsive-overrides.css +23 -0
- package/templates/dashboard/assets/i18n.js +166 -2
- package/templates/development/README.md +9 -9
- package/templates/development/cross-repo-debugging.md +3 -3
- package/templates/development/external-context/service-template.md +1 -1
- package/templates/development/external-source-packs/README.md +2 -2
- package/templates/integrations/README.md +4 -4
- package/templates/integrations/api-contract.md +1 -1
- package/templates/integrations/event-contract.md +1 -1
- package/templates/integrations/third-party/vendor-template.md +1 -1
- package/templates/integrations/webhook-contract.md +1 -1
- package/templates/ledger/Harness-Ledger.md +1 -1
- package/templates/modules/module_brief.md +50 -0
- package/templates/modules/module_plan.md +49 -0
- package/templates/modules/registry_view.md +9 -0
- package/templates/modules/session_prompt_pack.md +55 -0
- package/templates/planning/brief.md +32 -8
- package/templates/planning/module_brief.md +28 -3
- package/templates/planning/module_plan.md +26 -11
- package/templates/planning/module_session_prompt.md +11 -2
- package/templates/planning/optional/slices/_slice-template/brief.md +28 -0
- package/templates/planning/review.md +1 -1
- package/templates/planning/visual_map.md +1 -1
- package/templates/reference/docs-library-standard.md +7 -7
- package/templates/reference/execution-workflow-standard.md +13 -0
- package/templates/reference/external-source-intake-standard.md +10 -10
- package/templates/reference/pull-request-standard.md +2 -2
- package/templates/reference/repo-governance-standard.md +1 -1
- package/templates/reference/review-routing-standard.md +4 -0
- package/templates/ssot/Module-Registry.md +4 -38
- package/templates/walkthrough/walkthrough-template.md +1 -1
- package/templates-zh-CN/AGENTS.md.template +27 -25
- package/templates-zh-CN/CLAUDE.md.template +1 -1
- package/templates-zh-CN/architecture/README.md +2 -2
- package/templates-zh-CN/architecture/service-catalog.md +2 -2
- package/templates-zh-CN/architecture/services/service-template.md +1 -1
- package/templates-zh-CN/development/README.md +9 -9
- package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
- package/templates-zh-CN/development/external-context/service-template.md +1 -1
- package/templates-zh-CN/development/external-source-packs/README.md +2 -2
- package/templates-zh-CN/integrations/README.md +4 -4
- package/templates-zh-CN/integrations/api-contract.md +1 -1
- package/templates-zh-CN/integrations/event-contract.md +1 -1
- package/templates-zh-CN/integrations/third-party/vendor-template.md +1 -1
- package/templates-zh-CN/integrations/webhook-contract.md +1 -1
- package/templates-zh-CN/ledger/Harness-Ledger.md +1 -1
- package/templates-zh-CN/lessons/lesson-arch-process-change.md +1 -1
- package/templates-zh-CN/lessons/lesson-new-doc.md +3 -3
- package/templates-zh-CN/lessons/lesson-ref-change.md +4 -4
- package/templates-zh-CN/modules/module_brief.md +47 -0
- package/templates-zh-CN/modules/module_plan.md +48 -0
- package/templates-zh-CN/modules/registry_view.md +9 -0
- package/templates-zh-CN/modules/session_prompt_pack.md +50 -0
- package/templates-zh-CN/planning/INDEX.md +1 -0
- package/templates-zh-CN/planning/brief.md +26 -7
- package/templates-zh-CN/planning/module_brief.md +24 -2
- package/templates-zh-CN/planning/module_plan.md +35 -29
- package/templates-zh-CN/planning/module_session_prompt.md +15 -11
- package/templates-zh-CN/planning/optional/slices/_slice-template/brief.md +28 -11
- package/templates-zh-CN/planning/review.md +1 -1
- package/templates-zh-CN/reference/adversarial-review-standard.md +1 -1
- package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
- package/templates-zh-CN/reference/docs-library-standard.md +27 -27
- package/templates-zh-CN/reference/execution-workflow-standard.md +12 -2
- package/templates-zh-CN/reference/external-source-intake-standard.md +10 -10
- package/templates-zh-CN/reference/harness-ledger-standard.md +3 -3
- package/templates-zh-CN/reference/pull-request-standard.md +1 -1
- package/templates-zh-CN/reference/regression-ssot-governance.md +2 -2
- package/templates-zh-CN/reference/repo-governance-standard.md +1 -1
- package/templates-zh-CN/reference/review-routing-standard.md +3 -0
- package/templates-zh-CN/reference/walkthrough-standard.md +2 -2
- package/templates-zh-CN/reference/worktree-standard.md +1 -1
- package/templates-zh-CN/regression/Cadence-Ledger.md +2 -2
- package/templates-zh-CN/ssot/Delivery-SSoT.md +2 -2
- package/templates-zh-CN/ssot/Module-Registry.md +5 -44
- package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
- package/templates-zh-CN/walkthrough/walkthrough-template.md +4 -4
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
// Dashboard bundle aggregation stays behavior-first until dashboard domain types are modeled.
|
|
3
2
|
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
@@ -9,7 +8,7 @@ import { readCapabilityRegistry, validateCapabilities } from "./capability-regis
|
|
|
9
8
|
import { resolveHarnessPaths } from "./harness-paths.mjs";
|
|
10
9
|
import { legacyCompatMode, safeAdoptionCapability, } from "./harness-paths.mjs";
|
|
11
10
|
import { buildStatusData } from "./status-builder.mjs";
|
|
12
|
-
import {
|
|
11
|
+
import { parseTaskState, isActiveTaskState, createScannerTaskRepository, } from "./task-repository.mjs";
|
|
13
12
|
import { writeDashboardDirectory, writeDashboardFile } from "./dashboard-writer.mjs";
|
|
14
13
|
import { listPresetPackageLayers } from "./preset-registry.mjs";
|
|
15
14
|
import { validateGovernanceTableBoundaries } from "./governance-table-boundary.mjs";
|
|
@@ -17,7 +16,7 @@ import { summarizeGitState } from "./git-status-summary.mjs";
|
|
|
17
16
|
export function collectMarkdownDocuments(target, options = {}) {
|
|
18
17
|
const docs = collectDashboardDocumentPaths(target, options);
|
|
19
18
|
return docs.map((entry, index) => {
|
|
20
|
-
const file =
|
|
19
|
+
const file = entry.file;
|
|
21
20
|
const content = sanitizeText(readFileSafe(file));
|
|
22
21
|
const source = prefixedPath(target, file);
|
|
23
22
|
return {
|
|
@@ -76,17 +75,21 @@ function collectDashboardDocumentPaths(target, options = {}) {
|
|
|
76
75
|
selected.add(file);
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
|
-
const
|
|
80
|
-
|
|
78
|
+
const tasks = options.tasks || createScannerTaskRepository(target).list();
|
|
79
|
+
const tasksByPlanPath = new Map(tasks.map((task) => [
|
|
80
|
+
targetAbsolutePath(target, String(task.taskPlanPath || "")),
|
|
81
81
|
task,
|
|
82
82
|
]));
|
|
83
|
-
for (const
|
|
83
|
+
for (const listedTask of tasks) {
|
|
84
|
+
const taskPlanPath = targetAbsolutePath(target, String(listedTask.taskPlanPath || ""));
|
|
85
|
+
if (!taskPlanPath || !fs.existsSync(taskPlanPath))
|
|
86
|
+
continue;
|
|
84
87
|
const taskDir = path.dirname(taskPlanPath);
|
|
85
88
|
const progress = readFileSafe(path.join(taskDir, "progress.md"));
|
|
86
89
|
const state = parseTaskState(progress);
|
|
87
90
|
const active = isActiveTaskState(state);
|
|
88
|
-
const
|
|
89
|
-
const historicalClosed = !active &&
|
|
91
|
+
const taskRef = tasksByPlanPath.get(taskPlanPath);
|
|
92
|
+
const historicalClosed = !active && taskRef?.closeoutStatus === "closed";
|
|
90
93
|
const documentNames = historicalClosed
|
|
91
94
|
? ["brief.md", "walkthrough.md"]
|
|
92
95
|
: ["brief.md", "task_plan.md", "execution_strategy.md", visualMapFile, legacyVisualRoadmapFile, lessonCandidatesFile, longRunningTaskContractFile, "progress.md", "review.md", "findings.md", "walkthrough.md"];
|
|
@@ -98,7 +101,7 @@ function collectDashboardDocumentPaths(target, options = {}) {
|
|
|
98
101
|
partial.set(file, {
|
|
99
102
|
partial: true,
|
|
100
103
|
partialReason: "historical-closed",
|
|
101
|
-
taskId:
|
|
104
|
+
taskId: taskRef?.id || path.basename(taskDir),
|
|
102
105
|
});
|
|
103
106
|
}
|
|
104
107
|
}
|
|
@@ -198,7 +201,7 @@ export function collectGraph(status, tables = { tables: [] }, target = null) {
|
|
|
198
201
|
};
|
|
199
202
|
for (const task of status.tasks) {
|
|
200
203
|
addNode({ id: `task:${task.id}`, type: "task", label: task.title, state: task.state, completion: task.completion });
|
|
201
|
-
for (const phase of task
|
|
204
|
+
for (const phase of dashboardTaskPhases(task)) {
|
|
202
205
|
const phaseId = `phase:${task.id}:${phase.id}`;
|
|
203
206
|
addNode({
|
|
204
207
|
id: phaseId,
|
|
@@ -216,12 +219,34 @@ export function collectGraph(status, tables = { tables: [] }, target = null) {
|
|
|
216
219
|
addEdge({ from: `phase:${task.id}:${dependency}`, to: phaseId, type: "depends_on" });
|
|
217
220
|
}
|
|
218
221
|
}
|
|
219
|
-
for (const handoff of task
|
|
222
|
+
for (const handoff of dashboardTaskHandoffs(task)) {
|
|
220
223
|
const handoffId = `handoff:${handoff.id}`;
|
|
221
224
|
addNode({ id: handoffId, type: "handoff", label: handoff.summary, state: handoff.state });
|
|
222
225
|
addEdge({ from: `task:${task.id}`, to: handoffId, type: "handoff" });
|
|
223
226
|
}
|
|
224
227
|
}
|
|
228
|
+
for (const module of Array.isArray(status.modules) ? status.modules : []) {
|
|
229
|
+
const key = String(module.key || "");
|
|
230
|
+
if (!key)
|
|
231
|
+
continue;
|
|
232
|
+
const moduleId = `module:${key}`;
|
|
233
|
+
const currentStep = String(module.currentStep || "");
|
|
234
|
+
const state = module.status || "planned";
|
|
235
|
+
addNode({
|
|
236
|
+
id: moduleId,
|
|
237
|
+
type: "module",
|
|
238
|
+
label: String(module.title || key),
|
|
239
|
+
state,
|
|
240
|
+
currentStep,
|
|
241
|
+
...moduleDocumentPaths(target, key),
|
|
242
|
+
});
|
|
243
|
+
if (currentStep) {
|
|
244
|
+
const stepId = `step:${currentStep}`;
|
|
245
|
+
if (!seenNodes.has(stepId))
|
|
246
|
+
addNode({ id: stepId, type: "step", label: currentStep, state, module: key });
|
|
247
|
+
addEdge({ from: moduleId, to: stepId, type: "current_step" });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
225
250
|
for (const table of tables.tables || []) {
|
|
226
251
|
if (table.kind === "module-registry") {
|
|
227
252
|
for (const row of table.rows) {
|
|
@@ -234,7 +259,7 @@ export function collectGraph(status, tables = { tables: [] }, target = null) {
|
|
|
234
259
|
addNode({
|
|
235
260
|
id: moduleId,
|
|
236
261
|
type: "module",
|
|
237
|
-
label: getCell(row.cells, ["Name", "Module", "模块名称", "模块"], key),
|
|
262
|
+
label: getCell(row.cells, ["Title", "Name", "Module", "模块名称", "模块"], key),
|
|
238
263
|
state: status,
|
|
239
264
|
currentStep,
|
|
240
265
|
...moduleDocumentPaths(target, key),
|
|
@@ -271,6 +296,12 @@ export function collectGraph(status, tables = { tables: [] }, target = null) {
|
|
|
271
296
|
}
|
|
272
297
|
return { nodes, edges: edges.filter((edge) => seenNodes.has(edge.from) && seenNodes.has(edge.to)) };
|
|
273
298
|
}
|
|
299
|
+
function dashboardTaskPhases(task) {
|
|
300
|
+
return Array.isArray(task.phases) ? task.phases : [];
|
|
301
|
+
}
|
|
302
|
+
function dashboardTaskHandoffs(task) {
|
|
303
|
+
return Array.isArray(task.handoffs) ? task.handoffs : [];
|
|
304
|
+
}
|
|
274
305
|
function moduleKeyFromPlanSource(source, target) {
|
|
275
306
|
if (!target?.projectRoot || !target?.harness?.modulesRoot) {
|
|
276
307
|
const moduleMatch = source.match(/(?:MODULES|modules)\/([^/]+)\/module_plan\.md$/);
|
|
@@ -285,6 +316,14 @@ function moduleKeyFromPlanSource(source, target) {
|
|
|
285
316
|
const legacyMatch = source.match(/(?:MODULES|modules)\/([^/]+)\/module_plan\.md$/);
|
|
286
317
|
return legacyMatch ? legacyMatch[1] : "";
|
|
287
318
|
}
|
|
319
|
+
function targetAbsolutePath(target, targetPath) {
|
|
320
|
+
const withoutPrefix = String(targetPath || "").replace(/^TARGET:/, "");
|
|
321
|
+
if (!withoutPrefix)
|
|
322
|
+
return "";
|
|
323
|
+
if (path.isAbsolute(withoutPrefix))
|
|
324
|
+
return withoutPrefix;
|
|
325
|
+
return path.join(target.projectRoot, withoutPrefix.replace(/^\/+/, ""));
|
|
326
|
+
}
|
|
288
327
|
function moduleDocumentPaths(target, moduleKey) {
|
|
289
328
|
if (!target?.harness?.modulesRoot || !moduleKey)
|
|
290
329
|
return {};
|
|
@@ -295,6 +334,136 @@ function moduleDocumentPaths(target, moduleKey) {
|
|
|
295
334
|
...(fs.existsSync(modulePlan) ? { modulePlanPath: prefixedPath(target, modulePlan) } : {}),
|
|
296
335
|
};
|
|
297
336
|
}
|
|
337
|
+
function collectDashboardModules(status, target) {
|
|
338
|
+
const tasks = Array.isArray(status.tasks) ? status.tasks : [];
|
|
339
|
+
const registered = Array.isArray(status.modules)
|
|
340
|
+
? status.modules
|
|
341
|
+
: [];
|
|
342
|
+
const modules = new Map();
|
|
343
|
+
for (const module of registered) {
|
|
344
|
+
const key = String(module.key || "").trim();
|
|
345
|
+
if (!key)
|
|
346
|
+
continue;
|
|
347
|
+
modules.set(key, {
|
|
348
|
+
...module,
|
|
349
|
+
key,
|
|
350
|
+
title: String(module.title || key),
|
|
351
|
+
source: "registry",
|
|
352
|
+
...moduleDocumentPaths(target, key),
|
|
353
|
+
counts: emptyModuleCounts(),
|
|
354
|
+
tasks: [],
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
for (const task of tasks) {
|
|
358
|
+
if (isArchivedDashboardTask(task))
|
|
359
|
+
continue;
|
|
360
|
+
const key = dashboardTaskModuleKey(task);
|
|
361
|
+
if (key === "legacy-unclassified")
|
|
362
|
+
continue;
|
|
363
|
+
if (!modules.has(key)) {
|
|
364
|
+
modules.set(key, {
|
|
365
|
+
key,
|
|
366
|
+
title: key,
|
|
367
|
+
source: "inferred",
|
|
368
|
+
status: String(task.classificationSource || "inferred"),
|
|
369
|
+
...moduleDocumentPaths(target, key),
|
|
370
|
+
counts: emptyModuleCounts(),
|
|
371
|
+
tasks: [],
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
const module = modules.get(key);
|
|
375
|
+
if (!module)
|
|
376
|
+
continue;
|
|
377
|
+
accumulateModuleTask(module, task);
|
|
378
|
+
}
|
|
379
|
+
const unclassifiedTasks = tasks.filter((task) => !isArchivedDashboardTask(task) && dashboardTaskModuleKey(task) === "legacy-unclassified");
|
|
380
|
+
const moduleList = [...modules.values()].sort((left, right) => {
|
|
381
|
+
const leftStatus = String(left.status || "");
|
|
382
|
+
const rightStatus = String(right.status || "");
|
|
383
|
+
if (leftStatus === "in-progress" && rightStatus !== "in-progress")
|
|
384
|
+
return -1;
|
|
385
|
+
if (rightStatus === "in-progress" && leftStatus !== "in-progress")
|
|
386
|
+
return 1;
|
|
387
|
+
return left.key.localeCompare(right.key);
|
|
388
|
+
});
|
|
389
|
+
return {
|
|
390
|
+
modules: moduleList,
|
|
391
|
+
summary: {
|
|
392
|
+
total: moduleList.length,
|
|
393
|
+
registered: registered.length,
|
|
394
|
+
inferred: moduleList.filter((module) => module.source === "inferred").length,
|
|
395
|
+
active: moduleList.filter((module) => Number(module.counts.active || 0) > 0).length,
|
|
396
|
+
risk: moduleList.reduce((sum, module) => sum + Number(module.counts.risk || 0), 0),
|
|
397
|
+
unclassifiedTasks: unclassifiedTasks.length,
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function emptyModuleCounts() {
|
|
402
|
+
return {
|
|
403
|
+
total: 0,
|
|
404
|
+
active: 0,
|
|
405
|
+
in_progress: 0,
|
|
406
|
+
review: 0,
|
|
407
|
+
blocked: 0,
|
|
408
|
+
done: 0,
|
|
409
|
+
planned: 0,
|
|
410
|
+
not_started: 0,
|
|
411
|
+
unknown: 0,
|
|
412
|
+
risk: 0,
|
|
413
|
+
missingDocs: 0,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function accumulateModuleTask(module, task) {
|
|
417
|
+
const state = String(task.state || "unknown");
|
|
418
|
+
module.counts.total += 1;
|
|
419
|
+
module.counts[state] = (module.counts[state] || 0) + 1;
|
|
420
|
+
if (["in_progress", "review", "blocked", "planned", "not_started"].includes(state))
|
|
421
|
+
module.counts.active += 1;
|
|
422
|
+
if (dashboardTaskHasRisk(task))
|
|
423
|
+
module.counts.risk += 1;
|
|
424
|
+
if (dashboardTaskMissingDocs(task))
|
|
425
|
+
module.counts.missingDocs += 1;
|
|
426
|
+
if (module.tasks.length < 16) {
|
|
427
|
+
module.tasks.push({
|
|
428
|
+
id: task.id,
|
|
429
|
+
shortId: task.shortId,
|
|
430
|
+
title: task.title,
|
|
431
|
+
state,
|
|
432
|
+
completion: task.completion,
|
|
433
|
+
reviewStatus: task.reviewStatus,
|
|
434
|
+
closeoutStatus: task.closeoutStatus,
|
|
435
|
+
lifecycleState: task.lifecycleState,
|
|
436
|
+
taskQueues: task.taskQueues,
|
|
437
|
+
queueReasons: task.queueReasons,
|
|
438
|
+
visualMapStatus: task.visualMapStatus,
|
|
439
|
+
briefSource: task.briefSource,
|
|
440
|
+
path: task.path,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function dashboardTaskModuleKey(task) {
|
|
445
|
+
return String(task.module || task.inferredModule || "legacy-unclassified");
|
|
446
|
+
}
|
|
447
|
+
function isArchivedDashboardTask(task) {
|
|
448
|
+
const archiveState = String(task.archiveMetadata?.state || "").toLowerCase();
|
|
449
|
+
return task.deletionState === "archived" || archiveState === "archived";
|
|
450
|
+
}
|
|
451
|
+
function dashboardTaskHasRisk(task) {
|
|
452
|
+
if (task.state === "blocked")
|
|
453
|
+
return true;
|
|
454
|
+
if (String(task.reviewStatus || "").includes("blocked"))
|
|
455
|
+
return true;
|
|
456
|
+
if (Array.isArray(task.materialIssues) && task.materialIssues.length > 0)
|
|
457
|
+
return true;
|
|
458
|
+
if (Array.isArray(task.queueReasons) && task.queueReasons.length > 0)
|
|
459
|
+
return true;
|
|
460
|
+
if (String(task.visualMapStatus || "") === "missing")
|
|
461
|
+
return true;
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
function dashboardTaskMissingDocs(task) {
|
|
465
|
+
return task.briefSource !== "standalone" || String(task.visualMapStatus || "") === "missing";
|
|
466
|
+
}
|
|
298
467
|
export function categorizeWarning(message) {
|
|
299
468
|
if (/governance-table-entropy/i.test(message))
|
|
300
469
|
return "Governance Table Boundary";
|
|
@@ -395,11 +564,14 @@ function warningAffectedPaths(message) {
|
|
|
395
564
|
return [...new Set(matches.map((item) => item.replace(/[),.;]+$/, "")))];
|
|
396
565
|
}
|
|
397
566
|
function summarizeWarnings(warnings) {
|
|
398
|
-
const countBy = (field) =>
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
567
|
+
const countBy = (field) => {
|
|
568
|
+
const counts = {};
|
|
569
|
+
for (const warning of warnings) {
|
|
570
|
+
const key = String(warning[field] || "unknown");
|
|
571
|
+
counts[key] = (counts[key] ?? 0) + 1;
|
|
572
|
+
}
|
|
573
|
+
return counts;
|
|
574
|
+
};
|
|
403
575
|
return {
|
|
404
576
|
total: warnings.length,
|
|
405
577
|
byCategory: countBy("category"),
|
|
@@ -518,7 +690,7 @@ function warningAction(message) {
|
|
|
518
690
|
}
|
|
519
691
|
export function buildDashboardBundle(targetInput, options = {}) {
|
|
520
692
|
const target = normalizeTarget(targetInput);
|
|
521
|
-
const
|
|
693
|
+
const tasks = options.tasks || createScannerTaskRepository(target).list();
|
|
522
694
|
const capabilityState = validateCapabilities(target);
|
|
523
695
|
const gitState = summarizeGitState(target);
|
|
524
696
|
const declaredCapabilities = new Set(capabilityState.registry.capabilities.map((capability) => capability.name));
|
|
@@ -530,17 +702,18 @@ export function buildDashboardBundle(targetInput, options = {}) {
|
|
|
530
702
|
...options,
|
|
531
703
|
capabilityState,
|
|
532
704
|
gitState,
|
|
533
|
-
|
|
705
|
+
tasks,
|
|
534
706
|
legacy,
|
|
535
707
|
failures: [...capabilityState.failures, ...governanceBoundaries.failures],
|
|
536
708
|
warnings: [...capabilityState.warnings, ...legacyWarnings, ...governanceBoundaries.warnings, ...gitState.warnings],
|
|
537
709
|
});
|
|
538
|
-
const documents = { documents: collectMarkdownDocuments(target, {
|
|
710
|
+
const documents = { documents: collectMarkdownDocuments(target, { tasks: status.tasks }) };
|
|
539
711
|
const tables = collectTables(documents.documents);
|
|
540
712
|
const graph = collectGraph(status, tables, target);
|
|
713
|
+
const modules = collectDashboardModules(status, target);
|
|
541
714
|
const adoption = collectAdoption(status);
|
|
542
715
|
const presetCatalog = collectPresetCatalog(targetInput, target, options);
|
|
543
|
-
return sanitizeDeep({ status, tables, documents, graph, adoption, presetCatalog });
|
|
716
|
+
return sanitizeDeep({ status, tables, documents, graph, modules: modules.modules, moduleSummary: modules.summary, adoption, presetCatalog });
|
|
544
717
|
}
|
|
545
718
|
function runDashboardCompatibilityCheck(target) {
|
|
546
719
|
const checkTarget = target.docsOnly ? target.projectRoot : target.input;
|
|
@@ -597,7 +770,15 @@ export function writeDashboardFolder(outDir, targetInput, options = {}) {
|
|
|
597
770
|
const registry = readCapabilityRegistry(target);
|
|
598
771
|
const locale = options.localeOverride || registry.locale;
|
|
599
772
|
const bundle = buildDashboardBundle(targetInput, options);
|
|
600
|
-
return writeDashboardDirectory(outDir, bundle, {
|
|
773
|
+
return writeDashboardDirectory(outDir, bundle, {
|
|
774
|
+
repoRoot,
|
|
775
|
+
projectRoot: target.projectRoot,
|
|
776
|
+
docsRoot: target.docsRoot,
|
|
777
|
+
locale,
|
|
778
|
+
workbenchRuntime: options.workbenchRuntime === true,
|
|
779
|
+
recoverGeneratedDashboard: options.recoverGeneratedDashboard === true,
|
|
780
|
+
replaceExistingDashboardOutput: options.replaceExistingDashboardOutput === true,
|
|
781
|
+
});
|
|
601
782
|
}
|
|
602
783
|
export function writeDashboardSingleFile(outFile, targetInput, options = {}) {
|
|
603
784
|
const target = normalizeTarget(targetInput);
|