@hassangameryt/freeflow 0.8.0 → 0.9.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.
Files changed (290) hide show
  1. package/.agents/plugins/marketplace.json +2 -2
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +2 -2
  4. package/.codex-plugin/plugin.json +3 -3
  5. package/.cursor-plugin/plugin.json +1 -1
  6. package/README.md +96 -149
  7. package/capabilities/cognitive-routing/SKILL.md +21 -129
  8. package/capabilities/cognitive-routing/references/coordinator.md +163 -0
  9. package/capabilities/cognitive-routing/references/worker.md +38 -0
  10. package/capabilities/compaction/SKILL.md +3 -3
  11. package/capabilities/compaction/references/summary-format.md +26 -15
  12. package/capabilities/messaging/SKILL.md +49 -0
  13. package/capabilities/task-memory/SKILL.md +87 -0
  14. package/command-surface.json +6 -54
  15. package/gemini-extension.json +1 -1
  16. package/hooks/claude/hooks.json +13 -3
  17. package/hooks/codex/hooks.json +2 -1
  18. package/hooks/shared/runtime-context.mjs +69 -77
  19. package/package.json +25 -8
  20. package/pi-extension/dist/ask-user/ask.js +108 -0
  21. package/pi-extension/dist/ask-user/form.js +250 -0
  22. package/pi-extension/dist/ask-user/questions.js +66 -0
  23. package/pi-extension/dist/ask-user/tool.js +124 -0
  24. package/pi-extension/dist/cognitive-routing/assembler.js +35 -11
  25. package/pi-extension/dist/cognitive-routing/bootstrap.js +90 -0
  26. package/pi-extension/dist/cognitive-routing/config.js +3 -4
  27. package/pi-extension/dist/cognitive-routing/event-store.js +4 -1
  28. package/pi-extension/dist/cognitive-routing/gate.js +20 -5
  29. package/pi-extension/dist/cognitive-routing/handlers.js +15 -13
  30. package/pi-extension/dist/cognitive-routing/model-control.js +17 -8
  31. package/pi-extension/dist/cognitive-routing/projection.js +23 -6
  32. package/pi-extension/dist/cognitive-routing/provenance.js +3 -1
  33. package/pi-extension/dist/cognitive-routing/render.js +15 -15
  34. package/pi-extension/dist/cognitive-routing/runtime.js +4 -2
  35. package/pi-extension/dist/cognitive-routing/schemas.js +4 -4
  36. package/pi-extension/dist/cognitive-routing/session.js +3 -1
  37. package/pi-extension/dist/cognitive-routing/sources.js +29 -4
  38. package/pi-extension/dist/cognitive-routing/state.js +18 -8
  39. package/pi-extension/dist/cognitive-routing/status.js +4 -3
  40. package/pi-extension/dist/cognitive-routing/tools.js +29 -15
  41. package/pi-extension/dist/cognitive-routing/types.js +10 -1
  42. package/pi-extension/dist/compaction/carry.js +36 -22
  43. package/pi-extension/dist/compaction/config.js +4 -2
  44. package/pi-extension/dist/compaction/controller.js +52 -29
  45. package/pi-extension/dist/compaction/harness.js +19 -3
  46. package/pi-extension/dist/compaction/results.js +14 -13
  47. package/pi-extension/dist/compaction/tool.js +6 -6
  48. package/pi-extension/dist/host/catalog.js +20 -35
  49. package/pi-extension/dist/host/config-validation.js +233 -0
  50. package/pi-extension/dist/host/config.js +78 -91
  51. package/pi-extension/dist/host/inbound.js +142 -0
  52. package/pi-extension/dist/host/projection-tags.js +1 -1
  53. package/pi-extension/dist/host/prompts.js +24 -13
  54. package/pi-extension/dist/host/read-only-session.js +6 -1
  55. package/pi-extension/dist/host/request-history.js +7 -3
  56. package/pi-extension/dist/host/rows.js +25 -0
  57. package/pi-extension/dist/host/runtime-state.js +17 -2
  58. package/pi-extension/dist/host/section-keeper.js +85 -0
  59. package/pi-extension/dist/host/settings/freeflow-command.js +846 -93
  60. package/pi-extension/dist/host/settings/settings-view.js +27 -8
  61. package/pi-extension/dist/host/status.js +19 -5
  62. package/pi-extension/dist/index.js +638 -72
  63. package/pi-extension/dist/messaging/config.js +27 -0
  64. package/pi-extension/dist/messaging/messaging.js +398 -0
  65. package/pi-extension/dist/messaging/registry.js +57 -0
  66. package/pi-extension/dist/messaging/render.js +90 -0
  67. package/pi-extension/dist/messaging/tools.js +109 -0
  68. package/pi-extension/dist/messaging/transport.js +101 -0
  69. package/pi-extension/dist/provider-support/cache/keepalive.js +16 -4
  70. package/pi-extension/dist/task-memory/config.js +49 -0
  71. package/pi-extension/dist/task-memory/registry.js +119 -0
  72. package/pi-extension/dist/task-memory/render.js +107 -0
  73. package/pi-extension/dist/task-memory/runtime.js +994 -0
  74. package/pi-extension/dist/task-memory/tool.js +233 -0
  75. package/pi-extension/dist/tool-execution/apply-patch/tool.js +1 -1
  76. package/pi-extension/dist/tool-execution/background.js +220 -28
  77. package/pi-extension/dist/tool-execution/config.js +14 -3
  78. package/pi-extension/dist/tool-execution/file-tracking.js +24 -4
  79. package/pi-extension/dist/tool-execution/guidance-notices.js +124 -0
  80. package/pi-extension/dist/tool-execution/skill-reads.js +143 -0
  81. package/pi-extension/dist/tool-execution/tools.js +2 -2
  82. package/runtime/prompts/cognitive-routing.md +4 -4
  83. package/runtime/prompts/core.md +24 -14
  84. package/runtime/prompts/interaction-contract.md +7 -4
  85. package/runtime/prompts/tool-execution.md +3 -16
  86. package/runtime/prompts/working-method.md +16 -99
  87. package/skills/deliver-work/SKILL.md +76 -0
  88. package/skills/deliver-work/references/branch-closeout.md +134 -0
  89. package/skills/deliver-work/references/commit.md +83 -0
  90. package/skills/deliver-work/references/launch.md +94 -0
  91. package/skills/deliver-work/references/release.md +85 -0
  92. package/skills/deliver-work/scripts/commit-state.mjs +139 -0
  93. package/skills/deliver-work/scripts/delivery-state.mjs +107 -0
  94. package/skills/deliver-work/scripts/lib/git-state.mjs +178 -0
  95. package/skills/deliver-work/scripts/push-route.mjs +122 -0
  96. package/skills/deliver-work/scripts/release-preflight.mjs +177 -0
  97. package/skills/discuss-work/SKILL.md +148 -0
  98. package/skills/{discuss → discuss-work}/references/discussion-continuity.md +10 -27
  99. package/skills/discuss-work/references/learning-action.md +36 -0
  100. package/skills/discuss-work/scripts/choices.mjs +101 -0
  101. package/skills/discuss-work/scripts/lib/choices.mjs +159 -0
  102. package/skills/evaluate-behavior/SKILL.md +107 -0
  103. package/skills/evaluate-behavior/references/authoring.md +381 -0
  104. package/skills/evaluate-behavior/references/coding-tasks.md +145 -0
  105. package/skills/evaluate-behavior/references/conversations-pipelines-judges.md +177 -0
  106. package/skills/evaluate-behavior/references/design-and-measurement.md +273 -0
  107. package/skills/evaluate-behavior/references/running-and-evidence.md +245 -0
  108. package/skills/evaluate-behavior/scripts/claude-guard.mjs +76 -0
  109. package/skills/evaluate-behavior/scripts/guard-rules.mjs +309 -0
  110. package/skills/evaluate-behavior/scripts/lib/agreement.mjs +90 -0
  111. package/skills/evaluate-behavior/scripts/lib/arms.mjs +55 -0
  112. package/skills/evaluate-behavior/scripts/lib/budget.mjs +87 -0
  113. package/skills/evaluate-behavior/scripts/lib/build-source.mjs +287 -0
  114. package/skills/evaluate-behavior/scripts/lib/clear.mjs +74 -0
  115. package/skills/evaluate-behavior/scripts/lib/container.mjs +395 -0
  116. package/skills/evaluate-behavior/scripts/lib/decision.mjs +418 -0
  117. package/skills/evaluate-behavior/scripts/lib/definitions.mjs +1072 -0
  118. package/skills/evaluate-behavior/scripts/lib/freeflow.mjs +103 -0
  119. package/skills/evaluate-behavior/scripts/lib/grade-command.mjs +591 -0
  120. package/skills/evaluate-behavior/scripts/lib/grade-comparison.mjs +90 -0
  121. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-interaction.mjs +19 -18
  122. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-support.mjs +32 -5
  123. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/grade-workspace.mjs +28 -12
  124. package/skills/evaluate-behavior/scripts/lib/grade.mjs +101 -0
  125. package/skills/evaluate-behavior/scripts/lib/hooks.mjs +98 -0
  126. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/confinement.mjs +196 -0
  127. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/constraints.mjs +111 -0
  128. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/index.mjs +48 -0
  129. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/isolation.mjs +74 -0
  130. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/launch.mjs +123 -0
  131. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/model-call.mjs +73 -0
  132. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/recorder.mjs +178 -0
  133. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/session.mjs +494 -0
  134. package/skills/evaluate-behavior/scripts/lib/hosts/claude-code/skills.mjs +81 -0
  135. package/skills/evaluate-behavior/scripts/lib/hosts/index.mjs +31 -0
  136. package/skills/evaluate-behavior/scripts/lib/hosts/names.mjs +3 -0
  137. package/skills/evaluate-behavior/scripts/lib/hosts/pi/confinement.mjs +173 -0
  138. package/skills/evaluate-behavior/scripts/lib/hosts/pi/host.mjs +148 -0
  139. package/skills/evaluate-behavior/scripts/lib/hosts/pi/index.mjs +70 -0
  140. package/skills/evaluate-behavior/scripts/lib/hosts/pi/isolation.mjs +81 -0
  141. package/skills/evaluate-behavior/scripts/lib/hosts/pi/model-call.mjs +79 -0
  142. package/skills/evaluate-behavior/scripts/lib/hosts/pi/process.mjs +241 -0
  143. package/skills/{evaluate-skill/scripts/lib → evaluate-behavior/scripts/lib/hosts/pi}/rpc.mjs +144 -26
  144. package/skills/evaluate-behavior/scripts/lib/identity.mjs +82 -0
  145. package/skills/evaluate-behavior/scripts/lib/judge.mjs +688 -0
  146. package/skills/evaluate-behavior/scripts/lib/metrics.mjs +332 -0
  147. package/skills/evaluate-behavior/scripts/lib/model-call.mjs +17 -0
  148. package/skills/evaluate-behavior/scripts/lib/participants.mjs +616 -0
  149. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/process.mjs +22 -0
  150. package/skills/evaluate-behavior/scripts/lib/queue.mjs +54 -0
  151. package/skills/evaluate-behavior/scripts/lib/reference.mjs +343 -0
  152. package/skills/evaluate-behavior/scripts/lib/reuse.mjs +277 -0
  153. package/skills/evaluate-behavior/scripts/lib/review.mjs +933 -0
  154. package/skills/evaluate-behavior/scripts/lib/runner.mjs +732 -0
  155. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/sandbox.mjs +119 -14
  156. package/skills/evaluate-behavior/scripts/lib/scan-shell.mjs +457 -0
  157. package/skills/evaluate-behavior/scripts/lib/scan.mjs +479 -0
  158. package/skills/evaluate-behavior/scripts/lib/seal.mjs +91 -0
  159. package/skills/evaluate-behavior/scripts/lib/shell.mjs +560 -0
  160. package/skills/evaluate-behavior/scripts/lib/source-override.mjs +64 -0
  161. package/skills/evaluate-behavior/scripts/lib/subject-file.mjs +88 -0
  162. package/skills/{evaluate-skill/scripts/lib/pi.mjs → evaluate-behavior/scripts/lib/subject.mjs} +235 -265
  163. package/skills/evaluate-behavior/scripts/lib/task-copy.mjs +124 -0
  164. package/skills/evaluate-behavior/scripts/lib/trials.mjs +524 -0
  165. package/skills/evaluate-behavior/scripts/lib/validity.mjs +68 -0
  166. package/skills/evaluate-behavior/scripts/lib/view-html.mjs +454 -0
  167. package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/view.mjs +159 -18
  168. package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-command-tool.mjs +21 -6
  169. package/skills/evaluate-behavior/scripts/pi-container-route.mjs +23 -0
  170. package/skills/evaluate-behavior/scripts/pi-guard.mjs +77 -0
  171. package/skills/evaluate-behavior/scripts/pi-login-refresh.mjs +31 -0
  172. package/skills/evaluate-behavior/scripts/skill-eval.mjs +586 -0
  173. package/skills/execute-work/SKILL.md +96 -104
  174. package/skills/execute-work/references/code-practices.md +27 -51
  175. package/skills/execute-work/references/design.md +271 -0
  176. package/skills/execute-work/references/diagnose.md +117 -0
  177. package/skills/execute-work/references/migration.md +108 -0
  178. package/skills/execute-work/references/simplify.md +65 -0
  179. package/skills/execute-work/scripts/self-review.mjs +422 -0
  180. package/skills/execute-work/scripts/touch-map.mjs +290 -0
  181. package/skills/review-work/SKILL.md +89 -65
  182. package/skills/review-work/references/adjudication.md +94 -0
  183. package/skills/review-work/references/artifact.md +198 -0
  184. package/skills/review-work/references/evals-and-judges.md +66 -0
  185. package/skills/review-work/references/work.md +177 -0
  186. package/skills/review-work/scripts/check-brief.mjs +128 -0
  187. package/skills/review-work/scripts/review-packet.mjs +233 -0
  188. package/skills/setup-freeflow/SKILL.md +68 -17
  189. package/skills/track-work/SKILL.md +52 -20
  190. package/skills/track-work/references/handoff.md +190 -0
  191. package/skills/track-work/references/projects.md +51 -0
  192. package/skills/track-work/references/working-record-format.md +36 -18
  193. package/skills/track-work/scripts/lib/document.mjs +17 -13
  194. package/skills/track-work/scripts/lib/format.mjs +2 -0
  195. package/skills/track-work/scripts/lib/recover.mjs +254 -0
  196. package/skills/track-work/scripts/lib/registry.mjs +656 -0
  197. package/skills/track-work/scripts/lib/search.mjs +40 -0
  198. package/skills/track-work/scripts/lib/store.mjs +46 -15
  199. package/skills/track-work/scripts/lib/views.mjs +50 -1
  200. package/skills/track-work/scripts/working-record.mjs +232 -13
  201. package/skills/verify-work/SKILL.md +45 -37
  202. package/skills/verify-work/references/feature-map.md +120 -0
  203. package/skills/verify-work/references/runtime-evidence.md +203 -0
  204. package/skills/verify-work/references/test-design.md +25 -6
  205. package/skills/verify-work/scripts/test-changes.mjs +246 -0
  206. package/skills/write-docs/SKILL.md +113 -25
  207. package/skills/write-docs/references/documentation-shapes.md +68 -3
  208. package/skills/write-docs/references/spec-and-plan-shapes.md +308 -0
  209. package/skills/write-docs/scripts/artifact-check.mjs +148 -0
  210. package/skills/write-docs/scripts/docs-check.mjs +96 -6
  211. package/skills/write-docs/scripts/plan-lint.mjs +123 -0
  212. package/skills/write-skill/SKILL.md +92 -52
  213. package/skills/write-skill/references/activation-and-wording.md +143 -0
  214. package/skills/write-skill/references/placement-and-dependencies.md +154 -0
  215. package/skills/write-skill/scripts/lib/compare.mjs +701 -0
  216. package/skills/write-skill/scripts/lib/skill-author.mjs +197 -3
  217. package/skills/write-skill/scripts/skill-author.mjs +51 -8
  218. package/capabilities/cognitive-routing/references/both-mode.md +0 -36
  219. package/capabilities/cognitive-routing/references/executor-mode.md +0 -48
  220. package/capabilities/cognitive-routing/references/helper-mode.md +0 -47
  221. package/plugin.json +0 -33
  222. package/skills/action-selection/SKILL.md +0 -92
  223. package/skills/action-selection/references/trajectory-stalls.md +0 -73
  224. package/skills/bypass/SKILL.md +0 -153
  225. package/skills/commit-work/SKILL.md +0 -93
  226. package/skills/commit-work/references/git-state-edges.md +0 -94
  227. package/skills/commit-work/references/simple-push.md +0 -94
  228. package/skills/commit-work/references/staging-decisions.md +0 -106
  229. package/skills/decision-gate/SKILL.md +0 -87
  230. package/skills/design-for-depth/SKILL.md +0 -108
  231. package/skills/design-for-depth/references/design-pressure-signals.md +0 -84
  232. package/skills/design-for-depth/references/implementation-decisions.md +0 -76
  233. package/skills/design-for-depth/references/interface-design-loop.md +0 -105
  234. package/skills/design-for-depth/references/module-and-dependency-design.md +0 -117
  235. package/skills/design-for-depth/references/state-and-failure-boundaries.md +0 -125
  236. package/skills/diagnose-failure/SKILL.md +0 -140
  237. package/skills/diagnose-failure/references/diagnostic-loop-catalog.md +0 -50
  238. package/skills/diagnose-failure/references/flaky-and-performance-diagnosis.md +0 -51
  239. package/skills/discuss/SKILL.md +0 -140
  240. package/skills/evaluate-skill/SKILL.md +0 -188
  241. package/skills/evaluate-skill/references/evaluation-definition-schema.md +0 -415
  242. package/skills/evaluate-skill/references/evaluation-design.md +0 -112
  243. package/skills/evaluate-skill/references/execution-and-evidence.md +0 -111
  244. package/skills/evaluate-skill/references/review-and-revision.md +0 -94
  245. package/skills/evaluate-skill/scripts/lib/definitions.mjs +0 -448
  246. package/skills/evaluate-skill/scripts/lib/grade-comparison.mjs +0 -60
  247. package/skills/evaluate-skill/scripts/lib/grade.mjs +0 -64
  248. package/skills/evaluate-skill/scripts/lib/review.mjs +0 -196
  249. package/skills/evaluate-skill/scripts/lib/runner.mjs +0 -405
  250. package/skills/evaluate-skill/scripts/lib/trials.mjs +0 -103
  251. package/skills/evaluate-skill/scripts/pi-guard.mjs +0 -181
  252. package/skills/evaluate-skill/scripts/skill-eval.mjs +0 -182
  253. package/skills/execute-work/references/execute-work-edges.md +0 -78
  254. package/skills/finish-branch/SKILL.md +0 -117
  255. package/skills/finish-branch/references/integration-options.md +0 -80
  256. package/skills/handoff/SKILL.md +0 -82
  257. package/skills/handoff/references/handoff-templates.md +0 -150
  258. package/skills/launch-work/SKILL.md +0 -116
  259. package/skills/launch-work/references/launch-readiness.md +0 -85
  260. package/skills/migration-work/SKILL.md +0 -115
  261. package/skills/migration-work/references/migration-lifecycle.md +0 -82
  262. package/skills/release-work/SKILL.md +0 -118
  263. package/skills/release-work/references/release-evidence.md +0 -78
  264. package/skills/review-artifact/SKILL.md +0 -143
  265. package/skills/review-artifact/references/adjudicate-artifact-review.md +0 -101
  266. package/skills/review-artifact/references/independent-artifact-reviewer-contract.md +0 -159
  267. package/skills/review-work/references/adjudicate-work-review.md +0 -97
  268. package/skills/review-work/references/independent-work-reviewer-contract.md +0 -139
  269. package/skills/review-work/references/security-risk-lens.md +0 -67
  270. package/skills/setup-freeflow/references/activation-contract.md +0 -103
  271. package/skills/setup-freeflow/references/host-setup.md +0 -67
  272. package/skills/simplify-code/SKILL.md +0 -85
  273. package/skills/simplify-code/references/simplification-patterns.md +0 -70
  274. package/skills/verify-work/references/browser-runtime-evidence.md +0 -51
  275. package/skills/verify-work/references/integration-evidence.md +0 -49
  276. package/skills/verify-work/references/performance-evidence.md +0 -59
  277. package/skills/workflow/SKILL.md +0 -171
  278. package/skills/workflow/references/domain-skill-composition.md +0 -45
  279. package/skills/write-plan/SKILL.md +0 -92
  280. package/skills/write-plan/references/plan-shapes.md +0 -156
  281. package/skills/write-skill/references/activation-boundaries.md +0 -106
  282. package/skills/write-skill/references/agent-first-instructions.md +0 -133
  283. package/skills/write-skill/references/progressive-disclosure.md +0 -129
  284. package/skills/write-skill/references/skill-dependency-graphs.md +0 -192
  285. package/skills/write-spec/SKILL.md +0 -85
  286. package/skills/write-spec/references/artifact-standards.md +0 -86
  287. package/skills/write-spec/references/decision-records.md +0 -80
  288. package/skills/write-spec/references/spec-shapes.md +0 -143
  289. /package/skills/{evaluate-skill → evaluate-behavior}/scripts/lib/evidence.mjs +0 -0
  290. /package/skills/{evaluate-skill → evaluate-behavior}/scripts/pi-observer.mjs +0 -0
@@ -0,0 +1,254 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, isAbsolute, join, relative } from "node:path";
5
+ import { parseDocument, sectionContentLines } from "./document.mjs";
6
+ import { renderResume } from "./views.mjs";
7
+
8
+ // Recovery in one call (Track Work, "Recover After Context Loss"): the resume view, then what each defining artifact
9
+ // and Recovery source points to and whether it can be read now, then where live Git state disagrees with the record.
10
+ // It reports; reading the sources and reconciling stays the agent's work.
11
+ //
12
+ // It also finds the evidence pointers in Material updates for `validate`: files and commits a later context will
13
+ // rely on. A pointer inside the repository that does not resolve is a problem; one outside it is reported, not checked.
14
+
15
+ const PATH_TOKEN = /^(~\/|\/|\.{1,2}\/)?[A-Za-z0-9_@.-]+(\/[A-Za-z0-9_@.()-]+)*\/?(#[^\s]*)?$/;
16
+ const COMMIT = /^[0-9a-f]{7,40}$/;
17
+ const URL = /^[a-z][a-z0-9+.-]*:\/\//i;
18
+
19
+ function git(root, args) {
20
+ try {
21
+ return execFileSync("git", args, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ // A path names a file with an extension, a directory with a trailing "/", or starts like one (./, ../, ~/, /). Slashed
28
+ // words such as "lost/weakened" or "17/9" are not paths.
29
+ const looksLikePath = (token) =>
30
+ PATH_TOKEN.test(token) &&
31
+ !COMMIT.test(token) &&
32
+ !token.includes("*") &&
33
+ (/^(~\/|\/|\.{1,2}\/)/.test(token) ||
34
+ /\/$/.test(token) ||
35
+ (/\.[A-Za-z][A-Za-z0-9]{0,7}(#.*)?$/.test(token) && (token.includes("/") || /^[^.]+\.[A-Za-z]/.test(token))));
36
+ const looksLikeCommit = (token) => COMMIT.test(token) && /\d/.test(token) && /[a-f]/.test(token);
37
+
38
+ // The pointers a line names: backticked tokens, Markdown link targets, a leading "pointer — ..." token, typed
39
+ // trail pointers (commit:<sha>, file:<path>), and bare commit hashes.
40
+ export function pointersIn(line) {
41
+ const found = [];
42
+ const add = (kind, value) => {
43
+ if (!found.some((each) => each.kind === kind && each.value === value)) found.push({ kind, value });
44
+ };
45
+ const text = line.replace(/^\s*[-*]\s+/, "");
46
+ for (const match of text.matchAll(/\]\(([^)\s]+)\)/g)) classify(match[1], add);
47
+ for (const match of text.matchAll(/`([^`\n]+)`/g)) classify(match[1].trim(), add);
48
+ const lead = /^(\S+)\s+[—–-]\s/.exec(text);
49
+ if (lead) classify(lead[1].replace(/[,;:]$/, ""), add);
50
+ const prose = text.replace(/`[^`\n]*`/g, " ").replace(/\]\([^)]*\)/g, " ");
51
+ for (const match of prose.matchAll(/\b(?:commit|file|path):([^\s,;)]+)/g))
52
+ classify(match[1], add, match[0].startsWith("commit:"));
53
+ for (const word of prose.split(/[\s,;()[\]"'“”]+/)) {
54
+ const token = word.replace(/[.:]+$/, "");
55
+ if (looksLikeCommit(token)) add("commit", token);
56
+ // A bare path in prose must name a file: a slashed word ending in "/" is usually a folder named in passing.
57
+ else if (token.includes("/") && !token.endsWith("/") && looksLikePath(token) && !URL.test(token))
58
+ add("path", token.replace(/#.*$/, ""));
59
+ }
60
+ return found;
61
+ }
62
+
63
+ function classify(raw, add, commitOnly = false) {
64
+ const token = raw.replace(/^(file|path|commit):/, "");
65
+ if (URL.test(token)) return add("url", token);
66
+ if (commitOnly || looksLikeCommit(token)) return add("commit", token);
67
+ const range = /^([0-9a-f]{7,40})\.\.\.?([0-9a-f]{7,40}|HEAD)$/.exec(token);
68
+ if (range) {
69
+ add("commit", range[1]);
70
+ if (range[2] !== "HEAD") add("commit", range[2]);
71
+ return;
72
+ }
73
+ if (looksLikePath(token)) add("path", token.replace(/#.*$/, ""));
74
+ }
75
+
76
+ // Where a path pointer resolves: the repository root, the task folder, or as given when absolute or home-relative.
77
+ export function resolvePointer(pointer, { root, taskDir }) {
78
+ if (pointer.startsWith("~/")) return { outside: true, path: join(homedir(), pointer.slice(2)) };
79
+ if (isAbsolute(pointer)) {
80
+ const inside = !relative(root, pointer).startsWith("..");
81
+ return { outside: !inside, path: pointer };
82
+ }
83
+ const candidates = [join(taskDir, pointer), join(root, pointer)];
84
+ const hit = candidates.find((candidate) => existsSync(candidate));
85
+ return { outside: false, path: hit ?? candidates[1] };
86
+ }
87
+
88
+ function describe(path) {
89
+ try {
90
+ const stat = statSync(path);
91
+ if (stat.isDirectory()) return `directory, ${readdirSync(path).length} entries`;
92
+ const text = readFileSync(path, "utf8");
93
+ return `${text.split("\n").length} lines, ${text.split(/\s+/).filter(Boolean).length} words`;
94
+ } catch {
95
+ return null;
96
+ }
97
+ }
98
+
99
+ function checkPointer(pointer, context) {
100
+ if (pointer.kind === "url") return { ...pointer, state: "not checked (URL)" };
101
+ if (pointer.kind === "commit") {
102
+ if (!context.isGit) return { ...pointer, state: "not checked (not a Git repository)" };
103
+ const full = git(context.root, ["rev-parse", "--verify", "--quiet", `${pointer.value}^{commit}`]);
104
+ return full
105
+ ? { ...pointer, state: "resolves", commit: full }
106
+ : { ...pointer, state: "missing", problem: `commit ${pointer.value} is not in this repository` };
107
+ }
108
+ const where = resolvePointer(pointer.value, context);
109
+ const size = describe(where.path);
110
+ if (size) return { ...pointer, state: "resolves", size, ...(where.outside ? { outside: true } : {}) };
111
+ if (where.outside) return { ...pointer, state: "not checked (outside the repository)", outside: true };
112
+ return { ...pointer, state: "missing", problem: `${pointer.value} does not exist` };
113
+ }
114
+
115
+ const bullets = (lines) => lines.filter((line) => /^\s*[-*]\s+\S/.test(line));
116
+
117
+ function sourceEntries(lines, context) {
118
+ return bullets(lines).map((line) => {
119
+ const text = line.trim().replace(/^[-*]\s+/, "");
120
+ const trigger = /\bread (?:only )?(?:when|if) ([^.;]+)/i.exec(text)?.[1]?.trim() ?? null;
121
+ return { text, trigger, pointers: pointersIn(line).map((pointer) => checkPointer(pointer, context)) };
122
+ });
123
+ }
124
+
125
+ function liveState(document, context) {
126
+ const { root } = context;
127
+ if (!context.isGit) return { git: false, mismatches: [], notes: ["not a Git repository: no live state to compare"] };
128
+ const branch = git(root, ["branch", "--show-current"]) || null;
129
+ const head = git(root, ["rev-parse", "--short=12", "HEAD"]);
130
+ const subject = head ? git(root, ["log", "-1", "--format=%s"]) : null;
131
+ const dirty = (git(root, ["status", "--porcelain"]) ?? "").split("\n").filter(Boolean).length;
132
+ const mismatches = [];
133
+ const notes = [];
134
+ const current = document.sections["Current Work"];
135
+ const sliceText = current ? document.lines.slice(current.start, current.end).join("\n") : "";
136
+ const contextText = sectionContentLines(document, "Current Context").join("\n");
137
+ const branches = (git(root, ["for-each-ref", "--format=%(refname:short)", "refs/heads"]) ?? "")
138
+ .split("\n")
139
+ .filter(Boolean);
140
+ const named = branches.filter((name) =>
141
+ new RegExp(`(^|[\\s\`(])${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([\\s\`),.;:]|$)`).test(
142
+ `${sliceText}\n${contextText}`,
143
+ ),
144
+ );
145
+ if (!branch) mismatches.push(`HEAD is detached at ${head}`);
146
+ else if (named.length && !named.includes(branch))
147
+ mismatches.push(`the record names branch ${named.join(", ")}; HEAD is on ${branch}`);
148
+ const commits = [...new Set(pointersIn(sliceText.replace(/\n/g, " ")).filter((each) => each.kind === "commit"))];
149
+ for (const { value } of commits) {
150
+ const full = git(root, ["rev-parse", "--verify", "--quiet", `${value}^{commit}`]);
151
+ if (!full) mismatches.push(`the Current Slice names commit ${value}, which this repository does not have`);
152
+ else if (head && git(root, ["merge-base", "--is-ancestor", full, "HEAD"]) === null)
153
+ mismatches.push(`the Current Slice names commit ${value}, which is not in HEAD's history`);
154
+ }
155
+ const updated = /^Last updated:\s*(\S+)/m.exec(document.lines.slice(0, 10).join("\n"))?.[1];
156
+ if (updated && head) {
157
+ const since = (git(root, ["log", "--oneline", `--since=${updated}`, "HEAD"]) ?? "").split("\n").filter(Boolean);
158
+ if (since.length)
159
+ notes.push(
160
+ `${since.length} commit(s) on HEAD since the record's Last updated (${updated}); it may not describe them`,
161
+ );
162
+ }
163
+ if (dirty) notes.push(`${dirty} uncommitted or untracked path(s)`);
164
+ return { git: true, branch, head, subject, dirty, namedBranches: named, mismatches, notes };
165
+ }
166
+
167
+ function contextFor(root, recordPath) {
168
+ return {
169
+ root,
170
+ taskDir: dirname(recordPath),
171
+ isGit: git(root, ["rev-parse", "--is-inside-work-tree"]) === "true",
172
+ };
173
+ }
174
+
175
+ function gitRoot(root) {
176
+ return git(root, ["rev-parse", "--show-toplevel"]) ?? root;
177
+ }
178
+
179
+ export function renderRecover(text, { root, recordPath }) {
180
+ const document = parseDocument(text);
181
+ const context = contextFor(gitRoot(root), recordPath);
182
+ const defines = document.context.headings.get("What defines this task");
183
+ const defining = sourceEntries(document.lines.slice(defines.start, defines.end), context);
184
+ const sources = document.current.recoverySources;
185
+ const recovery = sources ? sourceEntries(document.lines.slice(sources.start, sources.end), context) : [];
186
+ const live = liveState(document, context);
187
+ const pointerLine = (pointer) =>
188
+ `${pointer.value}: ${pointer.state}${pointer.size ? ` (${pointer.size})` : ""}${pointer.outside && pointer.size ? ", outside the repository" : ""}`;
189
+ const entryLines = (entries, withTrigger) =>
190
+ entries.length
191
+ ? entries.flatMap((entry) => [
192
+ `- ${entry.text}`,
193
+ ...(withTrigger ? [` - ${entry.trigger ? `read when ${entry.trigger}` : "read now"}`] : []),
194
+ ...(entry.pointers.length
195
+ ? entry.pointers.map((pointer) => ` - ${pointerLine(pointer)}`)
196
+ : [" - no pointer found: recover it from the text"]),
197
+ ])
198
+ : ["None."];
199
+ const lines = [
200
+ "## Recovery",
201
+ "",
202
+ "Read in this order: every defining artifact, then each Recovery source whose trigger applies, then the History entries the next action depends on (`view entry <ID>`).",
203
+ "",
204
+ "### Defining artifacts",
205
+ "",
206
+ ...entryLines(defining, false),
207
+ "",
208
+ "### Recovery sources",
209
+ "",
210
+ ...entryLines(recovery, true),
211
+ "",
212
+ "### Live state",
213
+ "",
214
+ ...(live.git
215
+ ? [
216
+ `- ${live.branch ? `branch ${live.branch}` : "detached HEAD"}, HEAD ${live.head ?? "none"}${live.subject ? ` (${live.subject})` : ""}`,
217
+ ]
218
+ : []),
219
+ ...live.notes.map((note) => `- ${note}`),
220
+ ...(live.mismatches.length
221
+ ? ["", "Mismatches: resolve each from sources before acting.", ...live.mismatches.map((each) => `- ${each}`)]
222
+ : ["- no mismatch found between the record and live Git state"]),
223
+ ];
224
+ const resume = renderResume(text);
225
+ return `${resume.trimEnd()}${document.newline}${document.newline}${lines.join(document.newline)}${document.newline}`;
226
+ }
227
+
228
+ // Evidence pointers in every Material updates list. An unresolved pointer inside the repository is a problem on an
229
+ // Evidence or Result line, which claims it exists, and a warning on any other line (an Extension may name a planned
230
+ // path); the caller decides whether problems fail. Pointers outside the repository are listed, not checked.
231
+ export function checkEvidencePointers(text, { root, recordPath }) {
232
+ const document = parseDocument(text);
233
+ const context = contextFor(gitRoot(root), recordPath);
234
+ const lines = document.lines;
235
+ const problems = [];
236
+ const warnings = [];
237
+ const outside = [];
238
+ let checked = 0;
239
+ for (let index = 0; index < lines.length; index += 1) {
240
+ if (!/^#####\s+Material updates\s*$/.test(lines[index])) continue;
241
+ for (let at = index + 1; at < lines.length && !/^#{1,5}\s/.test(lines[at]); at += 1) {
242
+ for (const pointer of pointersIn(lines[at])) {
243
+ if (pointer.kind === "url") continue;
244
+ const result = checkPointer(pointer, context);
245
+ const claims = /^\s*[-*]\s+(Evidence|Result)\b/.test(lines[at]);
246
+ if (result.problem) (claims ? problems : warnings).push(`line ${at + 1}: ${result.problem}`);
247
+ else if (result.outside || result.state.startsWith("not checked"))
248
+ outside.push(`line ${at + 1}: ${pointer.value}`);
249
+ if (!result.outside && !result.state.startsWith("not checked")) checked += 1;
250
+ }
251
+ }
252
+ }
253
+ return { checked, problems, warnings, outside };
254
+ }