coding-agent-harness 1.0.8 → 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 +10 -0
- package/CONTRIBUTING.md +8 -4
- package/README.md +12 -2
- package/README.zh-CN.md +10 -2
- package/SKILL.md +14 -3
- package/dist/build-dist.mjs +19 -6
- package/dist/check-dist-observation.mjs +57 -29
- 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 +7 -7
- package/dist/check-runtime-emit.mjs +10 -3
- package/dist/check-type-boundaries.mjs +51 -9
- 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 +51 -12
- package/dist/commands/registry.mjs +483 -0
- package/dist/commands/task-command.mjs +109 -52
- package/dist/harness.mjs +6 -304
- 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 +4 -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 +67 -29
- package/dist/lib/preset-registry.mjs +361 -71
- package/dist/lib/preset-runner.mjs +292 -26
- 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 +3 -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 +116 -160
- 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 +36 -17
- package/dist/lib/task-scanner.mjs +74 -23
- package/dist/lib/task-template-materials.mjs +131 -0
- package/dist/lib/task-tombstone-commands.mjs +186 -29
- 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 +1 -0
- 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 +16 -12
- 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 +6 -1
- package/presets/release-closeout/preset.yaml +9 -9
- package/presets/release-closeout/scripts/generate-release-package.mjs +387 -25
- package/presets/release-closeout/templates/task_plan.append.md +5 -5
- 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/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/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/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
|
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { normalizeLocale, normalizeTarget, readJsonSafe, toPosix, } from "./core-shared.mjs";
|
|
@@ -92,7 +91,7 @@ export function applyStructureMigration(targetInput = ".", { force = false } = {
|
|
|
92
91
|
fs.writeFileSync(manifestPath, renderHarnessManifest({ locale: plan.capabilities.locale, capabilities: plan.capabilities.names }));
|
|
93
92
|
applied.push({ action: "write-manifest", destination: plan.manifest });
|
|
94
93
|
}
|
|
95
|
-
for (const action of plan.actions.filter(
|
|
94
|
+
for (const action of plan.actions.filter(isMoveAction)) {
|
|
96
95
|
const source = path.join(targetRoot, action.source);
|
|
97
96
|
const destination = path.join(targetRoot, action.destination);
|
|
98
97
|
if (!fs.existsSync(source))
|
|
@@ -150,7 +149,7 @@ function preflightStructureMigration(plan, { force = false } = {}) {
|
|
|
150
149
|
if (force)
|
|
151
150
|
return;
|
|
152
151
|
const conflicts = [];
|
|
153
|
-
for (const action of plan.actions.filter(
|
|
152
|
+
for (const action of plan.actions.filter(isMoveAction)) {
|
|
154
153
|
const source = path.join(plan.target, action.source);
|
|
155
154
|
const destination = path.join(plan.target, action.destination);
|
|
156
155
|
if (fs.existsSync(source) && fs.existsSync(destination))
|
|
@@ -161,6 +160,9 @@ function preflightStructureMigration(plan, { force = false } = {}) {
|
|
|
161
160
|
throw new Error(`Refusing to overwrite existing v2 destination(s): ${conflicts.join(", ")}`);
|
|
162
161
|
}
|
|
163
162
|
}
|
|
163
|
+
function isMoveAction(action) {
|
|
164
|
+
return action.action === "move" && typeof action.source === "string";
|
|
165
|
+
}
|
|
164
166
|
function moduleTaskNormalizationConflicts(targetRoot) {
|
|
165
167
|
const modulesRoot = path.join(targetRoot, legacyPath(legacyModuleRoot));
|
|
166
168
|
if (!fs.existsSync(modulesRoot))
|
|
@@ -207,7 +209,7 @@ function readLegacyCapabilities(projectRoot) {
|
|
|
207
209
|
if (raw) {
|
|
208
210
|
locale = normalizeLocale(raw.locale);
|
|
209
211
|
for (const entry of raw.capabilities || [])
|
|
210
|
-
names.add(typeof entry === "string" ? entry : entry.name);
|
|
212
|
+
names.add(typeof entry === "string" ? entry : entry.name || "");
|
|
211
213
|
}
|
|
212
214
|
return { locale, names: [...names].filter(Boolean) };
|
|
213
215
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { readFileSafe, toPosix, walkFiles, isArchivedHarnessPath, } from "./core-shared.mjs";
|
|
4
3
|
import { firstColumn, splitMarkdownRow, } from "./markdown-utils.mjs";
|
|
@@ -80,7 +79,14 @@ function subagentAuthorizationRows(content) {
|
|
|
80
79
|
.filter((line) => line.trim().startsWith("|"))
|
|
81
80
|
.map(splitMarkdownRow)
|
|
82
81
|
.filter((row) => row.length === header.length)
|
|
83
|
-
.map((row) =>
|
|
82
|
+
.map((row) => ({
|
|
83
|
+
role: row[indexes.role] || "",
|
|
84
|
+
status: row[indexes.status] || "",
|
|
85
|
+
authorizedBy: indexes.authorizedBy >= 0 ? row[indexes.authorizedBy] || "" : "",
|
|
86
|
+
authorizedAt: indexes.authorizedAt >= 0 ? row[indexes.authorizedAt] || "" : "",
|
|
87
|
+
scope: indexes.scope >= 0 ? row[indexes.scope] || "" : "",
|
|
88
|
+
worktreeBranch: indexes.worktreeBranch >= 0 ? row[indexes.worktreeBranch] || "" : "",
|
|
89
|
+
}));
|
|
84
90
|
}
|
|
85
91
|
return [];
|
|
86
92
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { isConcreteAuditField } from "./task-audit-metadata.mjs";
|
|
2
|
+
import { normalizeReviewBoolean } from "./task-review-model.mjs";
|
|
3
|
+
export function assessArchiveEligibility(task, { archivedBy = "", now = new Date().toISOString() } = {}) {
|
|
4
|
+
const reason = archiveBlockReason(task, { archivedBy });
|
|
5
|
+
if (reason)
|
|
6
|
+
return { eligible: false, reason, auditFields: {} };
|
|
7
|
+
const confirmation = (task.reviewConfirmation || {});
|
|
8
|
+
const actor = normalizeArchiveActor(archivedBy);
|
|
9
|
+
return {
|
|
10
|
+
eligible: true,
|
|
11
|
+
reason: "",
|
|
12
|
+
auditFields: {
|
|
13
|
+
"Archived By": actor,
|
|
14
|
+
"Archived At": now,
|
|
15
|
+
"Review Confirmed By": String(confirmation.reviewer || ""),
|
|
16
|
+
"Review Confirmed At": String(confirmation.confirmedAt || ""),
|
|
17
|
+
"Review Confirmation ID": String(confirmation.confirmationId || ""),
|
|
18
|
+
"Review Commit SHA": String(confirmation.commitSha || ""),
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function archiveBlockReason(task, { archivedBy = "" } = {}) {
|
|
23
|
+
if (task.deletionState === "superseded")
|
|
24
|
+
return "superseded tasks cannot be archived";
|
|
25
|
+
if (task.state === "blocked" || (task.taskQueues || []).includes("blocked")) {
|
|
26
|
+
return "blocked tasks cannot be archived without an explicit human waiver";
|
|
27
|
+
}
|
|
28
|
+
const blockingRisks = (task.risks || []).filter((risk) => normalizeReviewBoolean(risk.open) !== "no" && (normalizeReviewBoolean(risk.blocksRelease) === "yes" || ["P0", "P1", "P2"].includes(String(risk.severity))));
|
|
29
|
+
if (blockingRisks.length)
|
|
30
|
+
return "tasks with open blocking review findings cannot be archived without an explicit human waiver";
|
|
31
|
+
if (task.state !== "done")
|
|
32
|
+
return `state:${task.state || "unknown"}`;
|
|
33
|
+
if (task.budget !== "simple" && task.closeoutStatus !== "closed")
|
|
34
|
+
return "tasks must have closed closeout materials before archive";
|
|
35
|
+
if (task.materialsReady === false && task.reviewStatus !== "confirmed") {
|
|
36
|
+
return "tasks with incomplete closeout materials cannot be archived without an explicit human waiver";
|
|
37
|
+
}
|
|
38
|
+
const confirmation = (task.reviewConfirmation || {});
|
|
39
|
+
if (confirmation.confirmed !== true)
|
|
40
|
+
return "Human review confirmation is required before task archive";
|
|
41
|
+
const missingConfirmationFields = [];
|
|
42
|
+
if (!isConcreteAuditField(confirmation.confirmationId))
|
|
43
|
+
missingConfirmationFields.push("Confirmation ID");
|
|
44
|
+
if (!isConcreteAuditField(confirmation.confirmedAt))
|
|
45
|
+
missingConfirmationFields.push("Confirmed At");
|
|
46
|
+
if (!isConcreteAuditField(confirmation.reviewer))
|
|
47
|
+
missingConfirmationFields.push("Reviewer");
|
|
48
|
+
if (!isConcreteAuditField(confirmation.commitSha))
|
|
49
|
+
missingConfirmationFields.push("Review Commit SHA");
|
|
50
|
+
if (missingConfirmationFields.length) {
|
|
51
|
+
return `Human review confirmation is not traceable; missing ${missingConfirmationFields.join(", ")}`;
|
|
52
|
+
}
|
|
53
|
+
if (!normalizeArchiveActor(archivedBy)) {
|
|
54
|
+
return "task archive requires --archived-by <name-or-email> for accountability";
|
|
55
|
+
}
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
export function normalizeArchiveActor(value) {
|
|
59
|
+
const actor = String(value || "").replace(/\r?\n/g, " ").trim();
|
|
60
|
+
if (!actor)
|
|
61
|
+
return "";
|
|
62
|
+
if (/^(coordinator|agent|unknown|n\/a|na|none|pending|todo|tbd)$/i.test(actor))
|
|
63
|
+
return "";
|
|
64
|
+
return actor;
|
|
65
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
// Dynamic audit metadata parsing stays behavior-first until the metadata domain model PR.
|
|
3
2
|
import { spawnSync } from "node:child_process";
|
|
4
3
|
import path from "node:path";
|
|
@@ -178,22 +177,24 @@ export function taskAuditMaterialIssues(target, taskDir, audit) {
|
|
|
178
177
|
}));
|
|
179
178
|
}
|
|
180
179
|
export function scaffoldProvenanceSummaryFromTaskAudit(audit) {
|
|
181
|
-
const
|
|
180
|
+
const parsed = normalizeTaskAuditLike(audit);
|
|
181
|
+
const fields = parsed.fields;
|
|
182
182
|
return {
|
|
183
183
|
required: true,
|
|
184
|
-
present:
|
|
184
|
+
present: parsed.present,
|
|
185
185
|
createdBy: normalizeToken(fields.get("created by")),
|
|
186
186
|
command: fields.get("command shape") || "",
|
|
187
187
|
createdAt: fields.get("created at") || "",
|
|
188
188
|
budget: normalizeToken(fields.get("budget")),
|
|
189
189
|
templateSource: fields.get("template source") || "",
|
|
190
190
|
exceptionReason: fields.get("exception reason") || "",
|
|
191
|
-
issues:
|
|
191
|
+
issues: parsed.issues,
|
|
192
192
|
};
|
|
193
193
|
}
|
|
194
194
|
export function reviewConfirmationFromTaskAudit(audit, { taskKey = "" } = {}) {
|
|
195
|
-
const
|
|
196
|
-
|
|
195
|
+
const parsed = normalizeTaskAuditLike(audit);
|
|
196
|
+
const fields = parsed.fields;
|
|
197
|
+
if (!parsed.present)
|
|
197
198
|
return null;
|
|
198
199
|
const status = normalizeToken(fields.get("human review status"));
|
|
199
200
|
if (status !== "confirmed")
|
|
@@ -204,9 +205,8 @@ export function reviewConfirmationFromTaskAudit(audit, { taskKey = "" } = {}) {
|
|
|
204
205
|
const commitSha = fields.get("review commit sha") || "";
|
|
205
206
|
const auditStatus = fields.get("audit status") || "";
|
|
206
207
|
const auditSource = fields.get("audit source") || "";
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
const commitShaInvalid = Boolean(!migratedLegacy && isConcreteAuditField(commitSha) && !/^[0-9a-f]{7,40}$/i.test(commitSha));
|
|
208
|
+
const confirmTextMismatch = Boolean(taskKey && isConcreteAuditField(confirmText) && !taskKeysMatch(confirmText, taskKey));
|
|
209
|
+
const commitShaInvalid = Boolean(isConcreteAuditField(commitSha) && !/^[0-9a-f]{7,40}$/i.test(commitSha));
|
|
210
210
|
const auditStatusInvalid = Boolean(isConcreteAuditField(auditStatus) && auditStatus.trim().toLowerCase() !== "committed");
|
|
211
211
|
const invalidFields = [
|
|
212
212
|
...(confirmTextMismatch ? ["Confirm Text match"] : []),
|
|
@@ -231,7 +231,7 @@ export function reviewConfirmationFromTaskAudit(audit, { taskKey = "" } = {}) {
|
|
|
231
231
|
auditStatusInvalid,
|
|
232
232
|
auditSource,
|
|
233
233
|
migratedFrom: fields.get("migrated from") || "",
|
|
234
|
-
gitAudit:
|
|
234
|
+
gitAudit: null,
|
|
235
235
|
gitAuditInvalid: false,
|
|
236
236
|
};
|
|
237
237
|
}
|
|
@@ -250,7 +250,7 @@ export function extractLegacyBlock(content, pattern) {
|
|
|
250
250
|
}
|
|
251
251
|
export function fieldsFromMarkdownBlock(block) {
|
|
252
252
|
const fields = new Map();
|
|
253
|
-
const tableRows = markdownTableRows(block);
|
|
253
|
+
const tableRows = markdownTableRows(String(block || ""));
|
|
254
254
|
const header = tableRows[0] || [];
|
|
255
255
|
const fieldIndex = firstColumn(header, ["Field", "字段"]);
|
|
256
256
|
const valueIndex = firstColumn(header, ["Value", "值"]);
|
|
@@ -374,3 +374,17 @@ function isValidDateOnly(value) {
|
|
|
374
374
|
const date = new Date(`${raw}T00:00:00.000Z`);
|
|
375
375
|
return !Number.isNaN(date.getTime()) && date.toISOString().slice(0, 10) === raw;
|
|
376
376
|
}
|
|
377
|
+
function normalizeTaskAuditLike(audit) {
|
|
378
|
+
if (!audit || typeof audit !== "object") {
|
|
379
|
+
return { present: false, fields: new Map(), issues: [], summary: taskAuditSummary(new Map(), []) };
|
|
380
|
+
}
|
|
381
|
+
const record = audit;
|
|
382
|
+
const fields = record.fields instanceof Map ? record.fields : new Map();
|
|
383
|
+
const issues = Array.isArray(record.issues) ? record.issues : [];
|
|
384
|
+
return {
|
|
385
|
+
present: Boolean(record.present),
|
|
386
|
+
fields,
|
|
387
|
+
issues,
|
|
388
|
+
summary: record.summary || taskAuditSummary(fields, issues),
|
|
389
|
+
};
|
|
390
|
+
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { normalizeTarget, readFileSafe, toPosix } from "./core-shared.mjs";
|
|
5
4
|
import { listTaskPlanPaths, taskIdForDirectory } from "./task-scanner.mjs";
|
|
6
5
|
import { extractLegacyBlock, fieldsFromMarkdownBlock, humanReviewConfirmationHeadingPattern, isConcreteAuditField, legacyExtraFieldsJson, parseTaskAuditMetadata, replaceTaskAuditMetadata, scaffoldProvenanceHeadingPattern, stripLegacyAuditBlocks, taskAuditFieldOrder, } from "./task-audit-metadata.mjs";
|
|
7
6
|
import { firstColumn, markdownTableRows } from "./markdown-utils.mjs";
|
|
7
|
+
class TaskAuditMigrationError extends Error {
|
|
8
|
+
plan;
|
|
9
|
+
cause;
|
|
10
|
+
constructor(message, { plan, cause } = {}) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "TaskAuditMigrationError";
|
|
13
|
+
this.plan = plan;
|
|
14
|
+
this.cause = cause;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
8
17
|
const scaffoldFieldMap = new Map([
|
|
9
18
|
["created by", "Created By"],
|
|
10
19
|
["command", "Command Shape"],
|
|
@@ -77,9 +86,7 @@ export function applyTaskAuditIndexMigration(targetInput) {
|
|
|
77
86
|
const target = normalizeTarget(targetInput);
|
|
78
87
|
const plan = planTaskAuditIndexMigration(targetInput);
|
|
79
88
|
if (plan.failures.length) {
|
|
80
|
-
|
|
81
|
-
error.plan = plan;
|
|
82
|
-
throw error;
|
|
89
|
+
throw new TaskAuditMigrationError(`Task audit INDEX migration failed during plan: ${plan.failures.map((failure) => `${failure.taskId}: ${failure.failure}`).join("; ")}`, { plan });
|
|
83
90
|
}
|
|
84
91
|
const writes = [];
|
|
85
92
|
for (const action of plan.actions) {
|
|
@@ -114,10 +121,7 @@ export function applyTaskAuditIndexMigration(targetInput) {
|
|
|
114
121
|
fs.writeFileSync(write.briefPath, write.before.briefContent);
|
|
115
122
|
fs.writeFileSync(write.reviewPath, write.before.reviewContent);
|
|
116
123
|
}
|
|
117
|
-
|
|
118
|
-
error.cause = cause;
|
|
119
|
-
error.plan = plan;
|
|
120
|
-
throw error;
|
|
124
|
+
throw new TaskAuditMigrationError(`Task audit INDEX migration apply failed and was rolled back: ${errorMessage(cause)}`, { cause, plan });
|
|
121
125
|
}
|
|
122
126
|
return { ...plan, result: "applied" };
|
|
123
127
|
}
|
|
@@ -146,7 +150,7 @@ function parseLegacyAudit({ taskId, indexContent, scaffoldBlock, reviewBlock })
|
|
|
146
150
|
for (const [legacyKey, canonical] of scaffoldFieldMap) {
|
|
147
151
|
const value = scaffold.get(legacyKey);
|
|
148
152
|
if (isConcreteAuditField(value))
|
|
149
|
-
fields[canonical] = value;
|
|
153
|
+
fields[canonical] = value || "";
|
|
150
154
|
}
|
|
151
155
|
for (const field of requiredScaffold) {
|
|
152
156
|
if (!isConcreteAuditField(fields[field]))
|
|
@@ -169,7 +173,7 @@ function parseLegacyAudit({ taskId, indexContent, scaffoldBlock, reviewBlock })
|
|
|
169
173
|
for (const [legacyKey, canonical] of reviewFieldMap) {
|
|
170
174
|
const value = review.get(legacyKey);
|
|
171
175
|
if (isConcreteAuditField(value))
|
|
172
|
-
fields[canonical] = value;
|
|
176
|
+
fields[canonical] = value || "";
|
|
173
177
|
}
|
|
174
178
|
const legacyTaskKey = review.get("task key") || "";
|
|
175
179
|
if (isConcreteAuditField(legacyTaskKey) && legacyTaskKey !== taskId && !taskId.endsWith(`/${legacyTaskKey}`))
|
|
@@ -212,8 +216,8 @@ function parseLegacyAudit({ taskId, indexContent, scaffoldBlock, reviewBlock })
|
|
|
212
216
|
}
|
|
213
217
|
}
|
|
214
218
|
if (extraEntries.length) {
|
|
215
|
-
const mergedExtra = mergeLegacyExtraFields(fields["Legacy Extra Fields"], extraEntries);
|
|
216
|
-
if (mergedExtra.failure)
|
|
219
|
+
const mergedExtra = mergeLegacyExtraFields(fields["Legacy Extra Fields"] || "", extraEntries);
|
|
220
|
+
if (mergedExtra.failure !== undefined)
|
|
217
221
|
failures.push(mergedExtra.failure);
|
|
218
222
|
else
|
|
219
223
|
fields["Legacy Extra Fields"] = mergedExtra.json;
|
|
@@ -291,7 +295,7 @@ function normalizeExistingAuditFields(fields, taskId, extraEntries) {
|
|
|
291
295
|
}
|
|
292
296
|
function replacePreserving(fields, extraEntries, field, replacement) {
|
|
293
297
|
if (isConcreteAuditField(fields[field]))
|
|
294
|
-
extraEntries.push([`Original ${field}`, fields[field]]);
|
|
298
|
+
extraEntries.push([`Original ${field}`, fields[field] || ""]);
|
|
295
299
|
fields[field] = replacement;
|
|
296
300
|
}
|
|
297
301
|
function parseLegacyReviewFields(body) {
|
|
@@ -333,7 +337,7 @@ function concreteReviewConfirmationValues(fields) {
|
|
|
333
337
|
"commit sha",
|
|
334
338
|
"review commit sha",
|
|
335
339
|
];
|
|
336
|
-
return confirmationKeys.map((key) => fields.get(key)).filter(isConcreteAuditField);
|
|
340
|
+
return confirmationKeys.map((key) => fields.get(key)).filter((value) => isConcreteAuditField(value));
|
|
337
341
|
}
|
|
338
342
|
function titleField(value) {
|
|
339
343
|
return String(value || "")
|
|
@@ -353,3 +357,6 @@ function isValidDateOnly(value) {
|
|
|
353
357
|
const date = new Date(`${raw}T00:00:00.000Z`);
|
|
354
358
|
return !Number.isNaN(date.getTime()) && date.toISOString().slice(0, 10) === raw;
|
|
355
359
|
}
|
|
360
|
+
function errorMessage(error) {
|
|
361
|
+
return error instanceof Error ? error.message : String(error);
|
|
362
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { toPosix } from "./core-shared.mjs";
|
|
4
|
+
export function isExcludedTaskPlanPath(file, harnessPaths) {
|
|
5
|
+
const relative = toPosix(path.relative(harnessPaths.projectRoot, file));
|
|
6
|
+
const segments = relative.split("/").filter(Boolean);
|
|
7
|
+
if (segments.includes("_task-template") || segments.includes("_optional-structures"))
|
|
8
|
+
return true;
|
|
9
|
+
if (isTaskLocalOptionalStructure(file, harnessPaths.projectRoot, segments))
|
|
10
|
+
return true;
|
|
11
|
+
const generatedRoot = toPosix(path.relative(harnessPaths.projectRoot, harnessPaths.generatedRoot || ""));
|
|
12
|
+
if (generatedRoot && (relative === `${generatedRoot}/task_plan.md` || relative.startsWith(`${generatedRoot}/`)))
|
|
13
|
+
return true;
|
|
14
|
+
const governanceRoot = toPosix(path.relative(harnessPaths.projectRoot, harnessPaths.governanceRoot || ""));
|
|
15
|
+
return Boolean(governanceRoot && (relative.startsWith(`${governanceRoot}/releases/`) ||
|
|
16
|
+
relative.startsWith(`${governanceRoot}/archive/`) ||
|
|
17
|
+
relative.startsWith(`${governanceRoot}/generated/`)));
|
|
18
|
+
}
|
|
19
|
+
function isTaskLocalOptionalStructure(file, projectRoot, segments) {
|
|
20
|
+
const taskPlanFile = path.basename(file) === "task_plan.md";
|
|
21
|
+
if (!taskPlanFile)
|
|
22
|
+
return false;
|
|
23
|
+
for (const segmentName of ["artifacts", "references"]) {
|
|
24
|
+
const segmentIndex = segments.indexOf(segmentName);
|
|
25
|
+
if (segmentIndex < 1)
|
|
26
|
+
continue;
|
|
27
|
+
const ancestorDir = path.join(projectRoot, ...segments.slice(0, segmentIndex));
|
|
28
|
+
if (fs.existsSync(path.join(ancestorDir, "task_plan.md")))
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
package/dist/lib/task-index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import crypto from "node:crypto";
|
|
5
4
|
import { normalizeTarget, readFileSafe, toPosix, } from "./core-shared.mjs";
|
|
6
5
|
import { collectTasks } from "./task-scanner.mjs";
|
|
7
6
|
import { taskScannerVersion } from "./task-review-model.mjs";
|
|
7
|
+
const collectTasksForIndex = collectTasks;
|
|
8
8
|
export function buildTaskIndex(targetInput) {
|
|
9
9
|
const target = normalizeTarget(targetInput);
|
|
10
|
-
const tasks =
|
|
10
|
+
const tasks = collectTasksForIndex(target);
|
|
11
11
|
assertUniqueTaskKeys(tasks);
|
|
12
12
|
return {
|
|
13
13
|
schemaVersion: target.harness.version === 2 ? "task-index/v2" : "task-index/v1",
|
|
@@ -56,6 +56,7 @@ export function buildTaskIndex(targetInput) {
|
|
|
56
56
|
supersedes: task.supersedes || [],
|
|
57
57
|
supersededBy: task.supersededBy || "",
|
|
58
58
|
deletionState: task.deletionState || "active",
|
|
59
|
+
deleteReason: task.deleteReason || "",
|
|
59
60
|
archiveMetadata: task.archiveMetadata || {},
|
|
60
61
|
hiddenByDefault: task.hiddenByDefault === true,
|
|
61
62
|
repairPrompt: task.repairPrompt || "",
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import path from "node:path";
|
|
4
3
|
import { tableAfterHeading, firstColumn, } from "./markdown-utils.mjs";
|
|
@@ -85,7 +84,7 @@ export function parseLessonCandidateStatus(content) {
|
|
|
85
84
|
export function isLessonCandidateDecisionComplete(candidateStatus) {
|
|
86
85
|
if (!candidateStatus || candidateStatus.issues?.length)
|
|
87
86
|
return false;
|
|
88
|
-
return reviewCompleteLessonCandidateStatuses.has(candidateStatus.status);
|
|
87
|
+
return reviewCompleteLessonCandidateStatuses.has(String(candidateStatus.status || ""));
|
|
89
88
|
}
|
|
90
89
|
export function validateLessonCandidateDetailArtifacts(target, taskDir, candidateStatus) {
|
|
91
90
|
const issues = [];
|