coding-agent-harness 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/CONTRIBUTING.md +2 -2
  3. package/LICENSE +661 -21
  4. package/LICENSE-EXCEPTION.md +37 -0
  5. package/README.md +96 -4
  6. package/README.zh-CN.md +75 -4
  7. package/SKILL.md +52 -51
  8. package/dist/build-dist.mjs +189 -0
  9. package/dist/check-dist-observation.mjs +428 -0
  10. package/dist/check-harness.mjs +489 -0
  11. package/dist/check-import-graph.mjs +511 -0
  12. package/dist/check-runtime-emit.mjs +304 -0
  13. package/dist/check-type-boundaries.mjs +139 -0
  14. package/dist/commands/dashboard-command.mjs +80 -0
  15. package/dist/commands/migration-command.mjs +152 -0
  16. package/dist/commands/preset-command.mjs +91 -0
  17. package/dist/commands/task-command.mjs +324 -0
  18. package/dist/harness.mjs +304 -0
  19. package/dist/lib/capability-registry.mjs +643 -0
  20. package/dist/lib/check-module-parallel.mjs +227 -0
  21. package/dist/lib/check-profiles.mjs +414 -0
  22. package/dist/lib/check-task-contracts.mjs +54 -0
  23. package/dist/lib/core-shared.mjs +254 -0
  24. package/dist/lib/dashboard-data.mjs +608 -0
  25. package/dist/lib/dashboard-workbench.mjs +334 -0
  26. package/dist/lib/dashboard-writer.mjs +200 -0
  27. package/dist/lib/git-status-summary.mjs +45 -0
  28. package/dist/lib/governance-index-generator.mjs +236 -0
  29. package/dist/lib/governance-sync.mjs +617 -0
  30. package/dist/lib/governance-table-boundary.mjs +161 -0
  31. package/{scripts → dist}/lib/harness-core.mjs +3 -0
  32. package/dist/lib/harness-paths.mjs +338 -0
  33. package/dist/lib/lesson-maintenance.mjs +139 -0
  34. package/dist/lib/markdown-utils.mjs +193 -0
  35. package/dist/lib/migration-planner.mjs +439 -0
  36. package/dist/lib/migration-support.mjs +317 -0
  37. package/dist/lib/phase-kind.mjs +46 -0
  38. package/dist/lib/preset-audit-contracts.mjs +40 -0
  39. package/dist/lib/preset-engine.mjs +516 -0
  40. package/dist/lib/preset-registry.mjs +831 -0
  41. package/dist/lib/preset-resource-contracts.mjs +83 -0
  42. package/dist/lib/review-confirm-git-gate.mjs +244 -0
  43. package/dist/lib/status-builder.mjs +87 -0
  44. package/{scripts → dist}/lib/status-dashboard-renderer.mjs +48 -47
  45. package/dist/lib/structure-migration.mjs +404 -0
  46. package/dist/lib/subagent-authorization-audit.mjs +198 -0
  47. package/dist/lib/task-audit-metadata.mjs +376 -0
  48. package/dist/lib/task-audit-migration.mjs +355 -0
  49. package/dist/lib/task-completion-consistency.mjs +29 -0
  50. package/dist/lib/task-index.mjs +133 -0
  51. package/dist/lib/task-lesson-candidates.mjs +239 -0
  52. package/dist/lib/task-lesson-sedimentation.mjs +300 -0
  53. package/dist/lib/task-lifecycle/create-task-helpers.mjs +84 -0
  54. package/dist/lib/task-lifecycle/phase-sync.mjs +82 -0
  55. package/dist/lib/task-lifecycle/review-confirm.mjs +93 -0
  56. package/dist/lib/task-lifecycle/review-gates.mjs +62 -0
  57. package/dist/lib/task-lifecycle/review-submission.mjs +52 -0
  58. package/dist/lib/task-lifecycle/scaffold-provenance.mjs +54 -0
  59. package/dist/lib/task-lifecycle/template-files.mjs +52 -0
  60. package/dist/lib/task-lifecycle/text-utils.mjs +26 -0
  61. package/dist/lib/task-lifecycle.mjs +611 -0
  62. package/dist/lib/task-metadata.mjs +116 -0
  63. package/dist/lib/task-review-model.mjs +474 -0
  64. package/dist/lib/task-scanner.mjs +439 -0
  65. package/dist/lib/task-tombstone-commands.mjs +125 -0
  66. package/dist/postinstall.mjs +14 -0
  67. package/dist/run-built-tests.mjs +84 -0
  68. package/docs-release/README.md +1 -0
  69. package/docs-release/architecture/overview.md +13 -13
  70. package/docs-release/architecture/overview.zh-CN.md +13 -13
  71. package/docs-release/architecture/system-explainer/01-system-overview.md +218 -0
  72. package/docs-release/architecture/system-explainer/02-module-dependency.md +257 -0
  73. package/docs-release/architecture/system-explainer/03-task-lifecycle.md +304 -0
  74. package/docs-release/architecture/system-explainer/04-check-and-governance.md +241 -0
  75. package/docs-release/architecture/system-explainer/05-data-flow.md +276 -0
  76. package/docs-release/architecture/system-explainer/06-preset-and-migration.md +300 -0
  77. package/docs-release/architecture/system-explainer/README.md +67 -0
  78. package/docs-release/architecture/system-explainer/en-US/01-system-overview.md +227 -0
  79. package/docs-release/architecture/system-explainer/en-US/02-module-dependency.md +263 -0
  80. package/docs-release/architecture/system-explainer/en-US/03-task-lifecycle.md +319 -0
  81. package/docs-release/architecture/system-explainer/en-US/04-check-and-governance.md +252 -0
  82. package/docs-release/architecture/system-explainer/en-US/05-data-flow.md +290 -0
  83. package/docs-release/architecture/system-explainer/en-US/06-preset-and-migration.md +320 -0
  84. package/docs-release/architecture/system-explainer/en-US/README.md +70 -0
  85. package/docs-release/guides/agent-installation.en-US.md +22 -15
  86. package/docs-release/guides/agent-installation.md +23 -15
  87. package/docs-release/guides/contributing.md +3 -3
  88. package/docs-release/guides/contributing.zh-CN.md +3 -3
  89. package/docs-release/guides/document-audience-and-surfaces.en-US.md +10 -10
  90. package/docs-release/guides/document-audience-and-surfaces.md +10 -10
  91. package/docs-release/guides/legacy-migration-agent-prompt.md +25 -2
  92. package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +25 -2
  93. package/docs-release/guides/migration-playbook.en-US.md +63 -1
  94. package/docs-release/guides/migration-playbook.md +59 -1
  95. package/docs-release/guides/parent-control-repository-pattern.en-US.md +25 -25
  96. package/docs-release/guides/parent-control-repository-pattern.md +25 -25
  97. package/docs-release/guides/preset-development.md +28 -4
  98. package/docs-release/guides/repository-operating-models.en-US.md +21 -21
  99. package/docs-release/guides/repository-operating-models.md +21 -21
  100. package/docs-release/guides/task-state-machine.en-US.md +35 -18
  101. package/docs-release/guides/task-state-machine.md +35 -18
  102. package/docs-release/guides/typescript-runtime-migration-closeout.md +96 -0
  103. package/examples/minimal-project/AGENTS.md +2 -2
  104. package/examples/minimal-project/coding-agent-harness/harness.yaml +14 -0
  105. package/examples/minimal-project/coding-agent-harness/planning/tasks/demo-task/INDEX.md +60 -0
  106. package/examples/minimal-project/coding-agent-harness/planning/tasks/demo-task/progress.md +11 -0
  107. package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/review.md +1 -1
  108. package/package.json +22 -13
  109. package/presets/legacy-migration/preset.yaml +5 -5
  110. package/presets/legacy-migration/templates/execution_strategy.append.md +1 -1
  111. package/presets/lesson-sedimentation/preset.yaml +3 -3
  112. package/presets/module/preset.yaml +2 -2
  113. package/presets/module/templates/execution_strategy.append.md +1 -1
  114. package/presets/module/templates/task_plan.append.md +3 -3
  115. package/presets/standard-task/preset.yaml +2 -2
  116. package/references/adversarial-review-standard.md +2 -2
  117. package/references/agents-md-pattern.md +14 -14
  118. package/references/cadence-ledger.md +1 -1
  119. package/references/ci-cd-standard.md +1 -1
  120. package/references/delivery-operating-model-standard.md +4 -4
  121. package/references/docs-directory-standard.md +65 -159
  122. package/references/external-source-intake-standard.md +10 -10
  123. package/references/harness-ledger.md +6 -6
  124. package/references/legacy-12-phase-bootstrap.md +2 -2
  125. package/references/lessons-governance.md +15 -15
  126. package/references/long-running-task-standard.md +6 -6
  127. package/references/module-parallel-standard.md +34 -34
  128. package/references/planning-loop.md +6 -6
  129. package/references/project-onboarding-audit.md +4 -4
  130. package/references/regression-system.md +2 -2
  131. package/references/repo-governance-standard.md +4 -4
  132. package/references/review-routing-standard.md +1 -1
  133. package/references/ssot-governance.md +19 -19
  134. package/references/taskr-gap-analysis.md +5 -5
  135. package/references/walkthrough-closeout.md +14 -14
  136. package/references/worktree-parallel.md +3 -3
  137. package/skills/preset-creator/references/complex-task-skeleton/brief.md +11 -0
  138. package/skills/preset-creator/references/complex-task-skeleton/task_plan.md +1 -1
  139. package/skills/preset-creator/references/preset-package-skeleton.md +5 -5
  140. package/templates/AGENTS.md.template +31 -29
  141. package/templates/architecture/README.md +4 -4
  142. package/templates/architecture/service-catalog.md +2 -2
  143. package/templates/architecture/services/service-template.md +1 -1
  144. package/templates/dashboard/assets/app-src/00-state.js +12 -0
  145. package/templates/dashboard/assets/app-src/10-router.js +3 -0
  146. package/templates/dashboard/assets/app-src/20-overview.js +13 -3
  147. package/templates/dashboard/assets/app-src/35-task-detail.js +46 -6
  148. package/templates/dashboard/assets/app-src/40-modules.js +1 -1
  149. package/templates/dashboard/assets/app-src/55-presets.js +375 -0
  150. package/templates/dashboard/assets/app-src/60-shared.js +3 -1
  151. package/templates/dashboard/assets/app-src/90-bindings.js +131 -0
  152. package/templates/dashboard/assets/app.css +583 -0
  153. package/templates/dashboard/assets/app.css.manifest.json +1 -0
  154. package/templates/dashboard/assets/app.js +585 -11
  155. package/templates/dashboard/assets/app.manifest.json +1 -0
  156. package/templates/dashboard/assets/css-src/00-foundation.css +4 -0
  157. package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +62 -0
  158. package/templates/dashboard/assets/css-src/45-presets.css +516 -0
  159. package/templates/dashboard/assets/i18n.js +144 -4
  160. package/templates/development/README.md +10 -10
  161. package/templates/development/cross-repo-debugging.md +3 -3
  162. package/templates/development/external-context/service-template.md +2 -2
  163. package/templates/development/external-source-packs/README.md +4 -4
  164. package/templates/integrations/README.md +4 -4
  165. package/templates/integrations/api-contract.md +2 -2
  166. package/templates/integrations/event-contract.md +2 -2
  167. package/templates/integrations/third-party/vendor-template.md +2 -2
  168. package/templates/integrations/webhook-contract.md +2 -2
  169. package/templates/ledger/Harness-Ledger.md +1 -1
  170. package/templates/planning/INDEX.md +88 -0
  171. package/templates/planning/brief.md +1 -1
  172. package/templates/planning/module_session_prompt.md +2 -1
  173. package/templates/planning/review.md +0 -18
  174. package/templates/planning/task_plan.md +5 -44
  175. package/templates/planning/visual_map.md +13 -9
  176. package/templates/planning/visual_map.simple.md +52 -0
  177. package/templates/planning/walkthrough.md +47 -0
  178. package/templates/reference/docs-library-standard.md +8 -8
  179. package/templates/reference/execution-workflow-standard.md +29 -2
  180. package/templates/reference/external-source-intake-standard.md +15 -15
  181. package/templates/reference/repo-governance-standard.md +1 -1
  182. package/templates/ssot/Module-Registry.md +1 -1
  183. package/templates/walkthrough/walkthrough-template.md +2 -2
  184. package/templates-zh-CN/AGENTS.md.template +31 -29
  185. package/templates-zh-CN/CLAUDE.md.template +1 -1
  186. package/templates-zh-CN/architecture/README.md +4 -4
  187. package/templates-zh-CN/architecture/service-catalog.md +2 -2
  188. package/templates-zh-CN/architecture/services/service-template.md +1 -1
  189. package/templates-zh-CN/development/README.md +10 -10
  190. package/templates-zh-CN/development/cross-repo-debugging.md +3 -3
  191. package/templates-zh-CN/development/external-context/service-template.md +2 -2
  192. package/templates-zh-CN/development/external-source-packs/README.md +4 -4
  193. package/templates-zh-CN/integrations/README.md +4 -4
  194. package/templates-zh-CN/integrations/api-contract.md +2 -2
  195. package/templates-zh-CN/integrations/event-contract.md +2 -2
  196. package/templates-zh-CN/integrations/third-party/vendor-template.md +2 -2
  197. package/templates-zh-CN/integrations/webhook-contract.md +2 -2
  198. package/templates-zh-CN/ledger/Harness-Ledger.md +1 -1
  199. package/templates-zh-CN/lessons/lesson-arch-process-change.md +1 -1
  200. package/templates-zh-CN/lessons/lesson-new-doc.md +3 -3
  201. package/templates-zh-CN/lessons/lesson-ref-change.md +4 -4
  202. package/templates-zh-CN/planning/INDEX.md +87 -0
  203. package/templates-zh-CN/planning/brief.md +1 -1
  204. package/templates-zh-CN/planning/module_session_prompt.md +12 -11
  205. package/templates-zh-CN/planning/review.md +0 -18
  206. package/templates-zh-CN/planning/task_plan.md +3 -63
  207. package/templates-zh-CN/planning/visual_map.md +14 -7
  208. package/templates-zh-CN/planning/visual_map.simple.md +48 -0
  209. package/templates-zh-CN/planning/walkthrough.md +47 -0
  210. package/templates-zh-CN/reference/adversarial-review-standard.md +2 -2
  211. package/templates-zh-CN/reference/delivery-operating-model-standard.md +3 -3
  212. package/templates-zh-CN/reference/docs-library-standard.md +28 -28
  213. package/templates-zh-CN/reference/execution-workflow-standard.md +32 -7
  214. package/templates-zh-CN/reference/external-source-intake-standard.md +16 -16
  215. package/templates-zh-CN/reference/harness-ledger-standard.md +6 -6
  216. package/templates-zh-CN/reference/regression-ssot-governance.md +2 -2
  217. package/templates-zh-CN/reference/repo-governance-standard.md +1 -1
  218. package/templates-zh-CN/reference/review-routing-standard.md +1 -1
  219. package/templates-zh-CN/reference/walkthrough-standard.md +7 -7
  220. package/templates-zh-CN/reference/worktree-standard.md +1 -1
  221. package/templates-zh-CN/regression/Cadence-Ledger.md +2 -2
  222. package/templates-zh-CN/ssot/Delivery-SSoT.md +3 -3
  223. package/templates-zh-CN/ssot/Module-Registry.md +3 -3
  224. package/templates-zh-CN/ssot/Regression-SSoT.md +2 -2
  225. package/templates-zh-CN/walkthrough/walkthrough-template.md +5 -5
  226. package/tsconfig.dist.json +16 -0
  227. package/tsconfig.json +25 -0
  228. package/tsconfig.runtime.json +24 -0
  229. package/examples/minimal-project/.harness-capabilities.json +0 -8
  230. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/progress.md +0 -11
  231. package/scripts/check-harness.mjs +0 -508
  232. package/scripts/commands/dashboard-command.mjs +0 -67
  233. package/scripts/commands/migration-command.mjs +0 -96
  234. package/scripts/commands/preset-command.mjs +0 -73
  235. package/scripts/commands/task-command.mjs +0 -327
  236. package/scripts/harness.mjs +0 -287
  237. package/scripts/lib/capability-registry.mjs +0 -591
  238. package/scripts/lib/check-module-parallel.mjs +0 -237
  239. package/scripts/lib/check-profiles.mjs +0 -418
  240. package/scripts/lib/check-task-contracts.mjs +0 -47
  241. package/scripts/lib/core-shared.mjs +0 -196
  242. package/scripts/lib/dashboard-data.mjs +0 -412
  243. package/scripts/lib/dashboard-workbench.mjs +0 -257
  244. package/scripts/lib/dashboard-writer.mjs +0 -198
  245. package/scripts/lib/git-status-summary.mjs +0 -46
  246. package/scripts/lib/governance-index-generator.mjs +0 -174
  247. package/scripts/lib/governance-sync.mjs +0 -514
  248. package/scripts/lib/governance-table-boundary.mjs +0 -175
  249. package/scripts/lib/lesson-maintenance.mjs +0 -152
  250. package/scripts/lib/markdown-utils.mjs +0 -158
  251. package/scripts/lib/migration-planner.mjs +0 -478
  252. package/scripts/lib/migration-support.mjs +0 -312
  253. package/scripts/lib/preset-audit-contracts.mjs +0 -37
  254. package/scripts/lib/preset-engine.mjs +0 -497
  255. package/scripts/lib/preset-registry.mjs +0 -627
  256. package/scripts/lib/preset-resource-contracts.mjs +0 -83
  257. package/scripts/lib/review-confirm-git-gate.mjs +0 -248
  258. package/scripts/lib/subagent-authorization-audit.mjs +0 -196
  259. package/scripts/lib/task-completion-consistency.mjs +0 -16
  260. package/scripts/lib/task-index.mjs +0 -93
  261. package/scripts/lib/task-lesson-candidates.mjs +0 -242
  262. package/scripts/lib/task-lesson-sedimentation.mjs +0 -326
  263. package/scripts/lib/task-lifecycle/review-confirm.mjs +0 -101
  264. package/scripts/lib/task-lifecycle/review-gates.mjs +0 -70
  265. package/scripts/lib/task-lifecycle/text-utils.mjs +0 -24
  266. package/scripts/lib/task-lifecycle.mjs +0 -649
  267. package/scripts/lib/task-review-model.mjs +0 -469
  268. package/scripts/lib/task-scanner.mjs +0 -576
  269. package/scripts/lib/task-tombstone-commands.mjs +0 -140
  270. package/scripts/postinstall.mjs +0 -14
  271. package/templates/walkthrough/Closeout-SSoT.md +0 -43
  272. package/templates-zh-CN/walkthrough/Closeout-SSoT.md +0 -42
  273. /package/examples/minimal-project/{docs → coding-agent-harness/governance/generated}/Harness-Ledger.md +0 -0
  274. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/brief.md +0 -0
  275. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/execution_strategy.md +0 -0
  276. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/findings.md +0 -0
  277. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/lesson_candidates.md +0 -0
  278. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/task_plan.md +0 -0
  279. /package/examples/minimal-project/{docs/09-PLANNING/TASKS → coding-agent-harness/planning/tasks}/demo-task/visual_map.md +0 -0
@@ -1,152 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import {
4
- datePrefix,
5
- lessonCandidatesFile,
6
- normalizeTarget,
7
- readFileSafe,
8
- slug,
9
- toPosix,
10
- } from "./core-shared.mjs";
11
- import {
12
- collectTasks,
13
- parseLessonCandidateStatus,
14
- } from "./task-scanner.mjs";
15
- import {
16
- beginGovernanceSync,
17
- commitGovernanceSync,
18
- releaseGovernanceSync,
19
- } from "./governance-sync.mjs";
20
-
21
- export function promoteLessonCandidate(targetInput, taskId, candidateId, { dryRun = false, apply = false } = {}) {
22
- const target = normalizeTarget(targetInput);
23
- const normalizedRef = slug(taskId);
24
- const matchesBareSlug = (item) => {
25
- if (!datePrefix.test(normalizedRef)) {
26
- const shortBase = datePrefix.test(item.shortId) ? item.shortId.replace(datePrefix, "") : item.shortId;
27
- if (shortBase === normalizedRef) return true;
28
- }
29
- return false;
30
- };
31
- const candidates = collectTasks(target).filter((item) => item.id === taskId || item.shortId === taskId || item.id.endsWith(`/${taskId}`) || matchesBareSlug(item));
32
- if (candidates.length > 1) {
33
- const options = candidates.map((item) => `- ${item.id}`).join("\n");
34
- throw new Error(`Ambiguous task reference: ${taskId}\n${options}`);
35
- }
36
- const task = candidates[0];
37
- if (!task) throw new Error(`Task not found: ${taskId}`);
38
- if (!candidateId) throw new Error("Missing lesson candidate id");
39
- const taskDir = path.join(target.projectRoot, task.path.replace(/^TARGET:/, ""));
40
- const candidatePath = path.join(taskDir, lessonCandidatesFile);
41
- const candidateContent = readFileSafe(candidatePath);
42
- const parsed = parseLessonCandidateStatus(candidateContent);
43
- const row = parsed.rows.find((item) => item.id.toLowerCase() === candidateId.toLowerCase());
44
- if (!row) throw new Error(`Lesson candidate not found: ${candidateId}`);
45
- if (!["needs-promotion", "promoted"].includes(row.status)) {
46
- throw new Error(`Lesson candidate must be needs-promotion before promotion; current status is ${row.status}`);
47
- }
48
-
49
- const lessonId = lessonIdFromCandidate(row.id);
50
- const title = row.title || lessonId;
51
- const detailRelative = `docs/01-GOVERNANCE/lessons/${lessonId}-${slug(title)}.md`;
52
- const detailPath = path.join(target.projectRoot, detailRelative);
53
-
54
- const changes = [];
55
- if (!fs.existsSync(detailPath)) changes.push({ action: dryRun ? "would-create" : "create", path: `TARGET:${detailRelative}` });
56
- if (row.status !== "promoted" || parsed.status !== "promoted") changes.push({ action: dryRun ? "would-update" : "update", path: task.lessonCandidatePath || `TARGET:${toPosix(path.relative(target.projectRoot, candidatePath))}` });
57
-
58
- const effectiveDryRun = dryRun || !apply;
59
- if (effectiveDryRun) {
60
- return {
61
- dryRun: true,
62
- applyRequired: true,
63
- taskId: task.id,
64
- candidateId: row.id,
65
- lessonId,
66
- detailDoc: `TARGET:${detailRelative}`,
67
- changes: changes.map((change) => ({ ...change, action: change.action.replace(/^(create|append|update)$/, "would-$1") })),
68
- nextCommand: `harness lesson-promote ${task.shortId} ${row.id} --apply`,
69
- };
70
- }
71
-
72
- const governanceContext = beginGovernanceSync(target, { operation: `lesson-promote ${task.id} ${row.id}` });
73
- try {
74
- fs.mkdirSync(path.dirname(detailPath), { recursive: true });
75
- if (!fs.existsSync(detailPath)) fs.writeFileSync(detailPath, renderLessonDetail({ lessonId, candidate: row, task, detailRelative }));
76
- fs.writeFileSync(candidatePath, markCandidatePromoted(candidateContent, row.id, lessonId));
77
- const commit = commitGovernanceSync(
78
- governanceContext,
79
- [
80
- detailRelative,
81
- toPosix(path.relative(target.projectRoot, candidatePath)),
82
- ],
83
- { message: `chore(harness): promote lesson ${row.id}` },
84
- );
85
-
86
- return { dryRun: false, taskId: task.id, candidateId: row.id, lessonId, detailDoc: `TARGET:${detailRelative}`, changes, governance: { commit } };
87
- } finally {
88
- releaseGovernanceSync(governanceContext);
89
- }
90
- }
91
-
92
- function lessonIdFromCandidate(candidateId) {
93
- const match = String(candidateId || "").match(/^LC-(\d{4})(\d{2})(\d{2})-(\d+)$/i);
94
- if (!match) return `L-${slug(candidateId)}`;
95
- return `L-${match[1]}-${match[2]}-${match[3]}-${match[4].padStart(3, "0")}`;
96
- }
97
-
98
- function renderLessonDetail({ lessonId, candidate, task }) {
99
- return [
100
- `# ${lessonId} - ${candidate.title || "Lesson Candidate"}`,
101
- "",
102
- "## Source",
103
- "",
104
- `- Task: ${task.id}`,
105
- `- Candidate: ${candidate.id}`,
106
- `- Promotion target: ${candidate.promotionTarget || "not specified"}`,
107
- "",
108
- "## Summary",
109
- "",
110
- candidate.title || "Promoted lesson candidate.",
111
- "",
112
- "## Why It Matters",
113
- "",
114
- candidate.reviewDecision || "Human review marked this candidate for governance promotion.",
115
- "",
116
- "## Status",
117
- "",
118
- "- State: pending governance integration",
119
- "",
120
- ].join("\n");
121
- }
122
-
123
- function markCandidatePromoted(content, candidateId, lessonId) {
124
- const lines = String(content || "").split(/\r?\n/);
125
- const headerIndex = lines.findIndex((line) => /^\|\s*ID\s*\|/.test(line));
126
- if (headerIndex >= 0) {
127
- const header = splitSimpleRow(lines[headerIndex]);
128
- const statusIndex = header.findIndex((cell) => /^(Row Status|行状态|Status|状态)$/i.test(cell));
129
- const decisionIndex = header.findIndex((cell) => /^(Review Decision|审查决定)$/i.test(cell));
130
- for (let index = headerIndex + 2; index < lines.length && lines[index].trim().startsWith("|"); index += 1) {
131
- const cells = splitSimpleRow(lines[index]);
132
- if ((cells[0] || "").toLowerCase() !== candidateId.toLowerCase()) continue;
133
- if (statusIndex >= 0) cells[statusIndex] = "promoted";
134
- if (decisionIndex >= 0 && !cells[decisionIndex].includes(lessonId)) cells[decisionIndex] = `${cells[decisionIndex]} promoted:${lessonId}`.trim();
135
- lines[index] = `| ${cells.map(escapeCell).join(" | ")} |`;
136
- }
137
- }
138
- return `${lines.join("\n")
139
- .replace("| Task-level status | needs-promotion |", "| Task-level status | promoted |")
140
- .replace("| Promotion state | not-promoted |", "| Promotion state | promoted |")
141
- .replace("| Closeout token | pending |", `| Closeout token | checked-created:${lessonId} |`)
142
- .replace(/\| Closeout token \| queued-promotion:[^|]+ \|/, `| Closeout token | checked-created:${lessonId} |`)
143
- .trimEnd()}\n`;
144
- }
145
-
146
- function splitSimpleRow(line) {
147
- return String(line || "").replace(/^\s*\|/, "").replace(/\|\s*$/, "").split("|").map((cell) => cell.trim());
148
- }
149
-
150
- function escapeCell(value) {
151
- return String(value || "").replace(/\r?\n/g, " ").replaceAll("|", "\\|").trim();
152
- }
@@ -1,158 +0,0 @@
1
- import { sanitizeText, slug } from "./core-shared.mjs";
2
-
3
- export function markdownTableRows(content) {
4
- return content
5
- .split(/\r?\n/)
6
- .filter((line) => line.trim().startsWith("|"))
7
- .map(splitMarkdownRow);
8
- }
9
-
10
-
11
- export function parseAllMarkdownTables(content, source, kindPrefix) {
12
- const lines = content.split(/\r?\n/);
13
- const tables = [];
14
- let index = 0;
15
- let tableIndex = 1;
16
- while (index < lines.length) {
17
- if (!lines[index].trim().startsWith("|")) {
18
- index += 1;
19
- continue;
20
- }
21
- const start = index;
22
- const block = [];
23
- while (index < lines.length && lines[index].trim().startsWith("|")) {
24
- block.push(lines[index]);
25
- index += 1;
26
- }
27
- if (block.length < 2) continue;
28
- const rows = block.map(splitMarkdownRow);
29
- const separator = rows[1] || [];
30
- if (!separator.every((cell) => /^:?-{3,}:?$/.test(cell))) continue;
31
- const columns = rows[0];
32
- const dataRows = rows.slice(2).filter((row) => row.length === columns.length);
33
- tables.push({
34
- id: `${slug(kindPrefix)}-${String(tableIndex).padStart(2, "0")}`,
35
- kind: kindPrefix,
36
- source,
37
- line: start + 1,
38
- columns,
39
- rows: dataRows.map((row, rowIndex) => ({
40
- id: `${slug(kindPrefix)}-${String(tableIndex).padStart(2, "0")}-row-${String(rowIndex + 1).padStart(3, "0")}`,
41
- cells: Object.fromEntries(columns.map((column, columnIndex) => [column, sanitizeText(row[columnIndex] || "")])),
42
- })),
43
- });
44
- tableIndex += 1;
45
- }
46
- return tables;
47
- }
48
-
49
- export function splitMarkdownRow(line) {
50
- let text = String(line || "").trim();
51
- if (text.startsWith("|")) text = text.slice(1);
52
- if (text.endsWith("|") && !text.endsWith("\\|")) text = text.slice(0, -1);
53
- const cells = [];
54
- let current = "";
55
- let inCode = false;
56
- for (let index = 0; index < text.length; index += 1) {
57
- const char = text[index];
58
- if (char === "\\" && text[index + 1] === "|") {
59
- current += "|";
60
- index += 1;
61
- continue;
62
- }
63
- if (char === "`") inCode = !inCode;
64
- if (char === "|" && !inCode) {
65
- cells.push(current.trim());
66
- current = "";
67
- continue;
68
- }
69
- current += char;
70
- }
71
- cells.push(current.trim());
72
- return cells;
73
- }
74
-
75
- export function tableAfterHeading(content, headerPattern) {
76
- const rows = markdownTableRows(content);
77
- const headerIndex = rows.findIndex((cells) => cells.some((cell) => headerPattern.test(cell)));
78
- if (headerIndex < 0) return { header: [], rows: [] };
79
- const header = rows[headerIndex];
80
- const body = [];
81
- for (const row of rows.slice(headerIndex + 1)) {
82
- if (row.every((cell) => /^:?-{3,}:?$/.test(cell))) continue;
83
- if (row.length !== header.length) break;
84
- body.push(row);
85
- }
86
- return { header, rows: body };
87
- }
88
-
89
- export function getColumn(header, name) {
90
- return header.findIndex((cell) => cell.toLowerCase() === name.toLowerCase());
91
- }
92
-
93
- export function getColumnAny(header, names) {
94
- return header.findIndex((cell) => names.some((name) => cell.toLowerCase() === name.toLowerCase()));
95
- }
96
-
97
- export function contentHasAny(content, terms) {
98
- return terms.some((term) => (term instanceof RegExp ? term.test(content) : content.includes(term)));
99
- }
100
-
101
- export function getCell(cells, names, fallback = "") {
102
- for (const name of names) {
103
- if (cells[name] !== undefined) return cells[name];
104
- }
105
- return fallback;
106
- }
107
-
108
- export function splitList(value) {
109
- return String(value || "")
110
- .split(/[,+;]/)
111
- .map((item) => item.trim())
112
- .filter(Boolean)
113
- .filter((item) => item.toLowerCase() !== "none");
114
- }
115
-
116
- export function splitDependencies(value) {
117
- return String(value || "")
118
- .split(/\s*(?:,|;|\+|&|\/|\band\b|\bAND\b)\s*/)
119
- .map((item) => item.trim())
120
- .filter(Boolean)
121
- .filter((item) => !/^(none|n\/a|na|-|—|–|无)$/i.test(item))
122
- .filter((item) => !/^same\b/i.test(item));
123
- }
124
-
125
- export function firstColumn(header, names) {
126
- for (const name of names) {
127
- const index = getColumn(header, name);
128
- if (index >= 0) return index;
129
- }
130
- return -1;
131
- }
132
-
133
- export function updateMarkdownTableRow(content, headerPattern, updater) {
134
- const lines = content.split(/\r?\n/);
135
- for (let index = 0; index < lines.length; index += 1) {
136
- if (!lines[index].trim().startsWith("|")) continue;
137
- const header = splitMarkdownRow(lines[index]);
138
- if (!header.some((cell) => headerPattern.test(cell))) continue;
139
- let matched = false;
140
- let rowIndex = index + 2;
141
- while (rowIndex < lines.length && lines[rowIndex].trim().startsWith("|")) {
142
- const row = splitMarkdownRow(lines[rowIndex]);
143
- if (row.length === header.length && !row.every((cell) => /^:?-{3,}:?$/.test(cell))) {
144
- const next = updater(header, row);
145
- if (!next) {
146
- rowIndex += 1;
147
- continue;
148
- }
149
- matched = true;
150
- if (next.join("\u0000") !== row.join("\u0000")) matched = true;
151
- lines[rowIndex] = `| ${next.join(" | ")} |`;
152
- }
153
- rowIndex += 1;
154
- }
155
- return { content: lines.join("\n"), matched };
156
- }
157
- return { content, matched: false };
158
- }