@open-agent-toolkit/cli 0.2.65 → 0.2.67

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 (238) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +33 -2
  3. package/assets/docs/cli-utilities/index.md +3 -0
  4. package/assets/docs/cli-utilities/project-log.md +63 -4
  5. package/assets/docs/cli-utilities/remote-project-management.md +191 -0
  6. package/assets/docs/contributing/code.md +8 -4
  7. package/assets/docs/contributing/skills.md +29 -17
  8. package/assets/docs/docs-tooling/commands.md +3 -1
  9. package/assets/docs/provider-sync/manifest-and-drift.md +2 -18
  10. package/assets/docs/reference/cli-reference.md +12 -1
  11. package/assets/docs/reference/file-locations.md +22 -0
  12. package/assets/docs/reference/oat-directory-structure.md +30 -17
  13. package/assets/docs/reference/troubleshooting.md +44 -0
  14. package/assets/docs/workflows/projects/lifecycle.md +17 -0
  15. package/assets/docs/workflows/projects/picking-up-projects.md +18 -0
  16. package/assets/docs/workflows/skills/index.md +33 -0
  17. package/assets/docs/workflows/skills/repo-improve.md +7 -3
  18. package/assets/public-package-versions.json +4 -4
  19. package/assets/skills/create-agnostic-skill/SKILL.md +19 -37
  20. package/assets/skills/create-agnostic-skill/references/docs/skills-guide.md +58 -15
  21. package/assets/skills/create-agnostic-skill/references/skill-template.md +17 -15
  22. package/assets/skills/oat-agent-instructions-apply/SKILL.md +1 -1
  23. package/assets/skills/oat-agent-instructions-apply/references/instruction-file-templates/glob-scoped-rule.md +1 -4
  24. package/assets/skills/oat-doctor/SKILL.md +3 -6
  25. package/assets/skills/oat-pjm-remote/SKILL.md +101 -0
  26. package/assets/skills/oat-pjm-remote/references/external-action-protocol.md +43 -0
  27. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
  28. package/assets/skills/oat-project-complete/SKILL.md +158 -30
  29. package/assets/skills/oat-project-complete/scripts/finalize-synced-archive.mjs +26 -7
  30. package/assets/skills/oat-project-complete/scripts/validate-durable-archive-receipt.mjs +183 -0
  31. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
  32. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
  33. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -1
  34. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
  35. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
  36. package/assets/skills/oat-project-retro/SKILL.md +1 -1
  37. package/assets/skills/oat-project-retro/references/apply-procedure.md +11 -0
  38. package/assets/skills/oat-project-review-provide/SKILL.md +4 -4
  39. package/assets/skills/oat-project-summary/SKILL.md +24 -2
  40. package/assets/skills/oat-repo-improve/SKILL.md +9 -2
  41. package/assets/skills/oat-repo-improve/references/plan-template.md +4 -6
  42. package/assets/skills/oat-repo-knowledge-index/SKILL.md +11 -9
  43. package/assets/skills/oat-wave-execute/SKILL.md +20 -6
  44. package/assets/skills/oat-wave-program/SKILL.md +9 -4
  45. package/dist/commands/backlog/new.d.ts +1 -0
  46. package/dist/commands/backlog/new.d.ts.map +1 -1
  47. package/dist/commands/backlog/new.js +3 -1
  48. package/dist/commands/config/index.d.ts +3 -1
  49. package/dist/commands/config/index.d.ts.map +1 -1
  50. package/dist/commands/config/index.js +362 -36
  51. package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
  52. package/dist/commands/docs/index-generate/index.js +68 -12
  53. package/dist/commands/docs/init/index.d.ts +11 -0
  54. package/dist/commands/docs/init/index.d.ts.map +1 -1
  55. package/dist/commands/docs/init/index.js +19 -1
  56. package/dist/commands/gate/index.d.ts.map +1 -1
  57. package/dist/commands/gate/index.js +10 -2
  58. package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
  59. package/dist/commands/instructions/instructions.utils.js +42 -9
  60. package/dist/commands/internal/validate-skill-version-bumps.d.ts.map +1 -1
  61. package/dist/commands/internal/validate-skill-version-bumps.js +5 -5
  62. package/dist/commands/pjm/doctor.d.ts +2 -0
  63. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  64. package/dist/commands/pjm/doctor.js +71 -1
  65. package/dist/commands/pjm/index.d.ts +2 -0
  66. package/dist/commands/pjm/index.d.ts.map +1 -1
  67. package/dist/commands/pjm/index.js +3 -0
  68. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts +60 -0
  69. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts.map +1 -0
  70. package/dist/commands/pjm/remote/__integration__/lifecycle-harness.js +151 -0
  71. package/dist/commands/pjm/remote/association.d.ts +27 -0
  72. package/dist/commands/pjm/remote/association.d.ts.map +1 -0
  73. package/dist/commands/pjm/remote/association.js +68 -0
  74. package/dist/commands/pjm/remote/authority.d.ts +210 -0
  75. package/dist/commands/pjm/remote/authority.d.ts.map +1 -0
  76. package/dist/commands/pjm/remote/authority.js +341 -0
  77. package/dist/commands/pjm/remote/batch.d.ts +15 -0
  78. package/dist/commands/pjm/remote/batch.d.ts.map +1 -0
  79. package/dist/commands/pjm/remote/batch.js +126 -0
  80. package/dist/commands/pjm/remote/closeout.d.ts +69 -0
  81. package/dist/commands/pjm/remote/closeout.d.ts.map +1 -0
  82. package/dist/commands/pjm/remote/closeout.js +208 -0
  83. package/dist/commands/pjm/remote/create-binding.d.ts +62 -0
  84. package/dist/commands/pjm/remote/create-binding.d.ts.map +1 -0
  85. package/dist/commands/pjm/remote/create-binding.js +126 -0
  86. package/dist/commands/pjm/remote/credential-safety.d.ts +7 -0
  87. package/dist/commands/pjm/remote/credential-safety.d.ts.map +1 -0
  88. package/dist/commands/pjm/remote/credential-safety.js +21 -0
  89. package/dist/commands/pjm/remote/discussion.d.ts +49 -0
  90. package/dist/commands/pjm/remote/discussion.d.ts.map +1 -0
  91. package/dist/commands/pjm/remote/discussion.js +124 -0
  92. package/dist/commands/pjm/remote/doctor.d.ts +22 -0
  93. package/dist/commands/pjm/remote/doctor.d.ts.map +1 -0
  94. package/dist/commands/pjm/remote/doctor.js +380 -0
  95. package/dist/commands/pjm/remote/external-action.d.ts +208 -0
  96. package/dist/commands/pjm/remote/external-action.d.ts.map +1 -0
  97. package/dist/commands/pjm/remote/external-action.js +367 -0
  98. package/dist/commands/pjm/remote/host-execution.d.ts +28 -0
  99. package/dist/commands/pjm/remote/host-execution.d.ts.map +1 -0
  100. package/dist/commands/pjm/remote/host-execution.js +63 -0
  101. package/dist/commands/pjm/remote/index.d.ts +41 -0
  102. package/dist/commands/pjm/remote/index.d.ts.map +1 -0
  103. package/dist/commands/pjm/remote/index.js +280 -0
  104. package/dist/commands/pjm/remote/jira-adf.d.ts +35 -0
  105. package/dist/commands/pjm/remote/jira-adf.d.ts.map +1 -0
  106. package/dist/commands/pjm/remote/jira-adf.js +169 -0
  107. package/dist/commands/pjm/remote/lifecycle.d.ts +163 -0
  108. package/dist/commands/pjm/remote/lifecycle.d.ts.map +1 -0
  109. package/dist/commands/pjm/remote/lifecycle.js +224 -0
  110. package/dist/commands/pjm/remote/local-projection.d.ts +30 -0
  111. package/dist/commands/pjm/remote/local-projection.d.ts.map +1 -0
  112. package/dist/commands/pjm/remote/local-projection.js +95 -0
  113. package/dist/commands/pjm/remote/managed-markdown.d.ts +30 -0
  114. package/dist/commands/pjm/remote/managed-markdown.d.ts.map +1 -0
  115. package/dist/commands/pjm/remote/managed-markdown.js +128 -0
  116. package/dist/commands/pjm/remote/migrate.d.ts +14 -0
  117. package/dist/commands/pjm/remote/migrate.d.ts.map +1 -0
  118. package/dist/commands/pjm/remote/migrate.js +32 -0
  119. package/dist/commands/pjm/remote/operation-state.d.ts +15 -0
  120. package/dist/commands/pjm/remote/operation-state.d.ts.map +1 -0
  121. package/dist/commands/pjm/remote/operation-state.js +143 -0
  122. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts +25 -0
  123. package/dist/commands/pjm/remote/outbound-projection-safety.d.ts.map +1 -0
  124. package/dist/commands/pjm/remote/outbound-projection-safety.js +99 -0
  125. package/dist/commands/pjm/remote/output.d.ts +60 -0
  126. package/dist/commands/pjm/remote/output.d.ts.map +1 -0
  127. package/dist/commands/pjm/remote/output.js +48 -0
  128. package/dist/commands/pjm/remote/preview.d.ts +88 -0
  129. package/dist/commands/pjm/remote/preview.d.ts.map +1 -0
  130. package/dist/commands/pjm/remote/preview.js +154 -0
  131. package/dist/commands/pjm/remote/provider-conformance.d.ts +13 -0
  132. package/dist/commands/pjm/remote/provider-conformance.d.ts.map +1 -0
  133. package/dist/commands/pjm/remote/provider-conformance.js +37 -0
  134. package/dist/commands/pjm/remote/provider.d.ts +57 -0
  135. package/dist/commands/pjm/remote/provider.d.ts.map +1 -0
  136. package/dist/commands/pjm/remote/provider.js +28 -0
  137. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts +46 -0
  138. package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts.map +1 -0
  139. package/dist/commands/pjm/remote/providers/github-publication-safety.js +126 -0
  140. package/dist/commands/pjm/remote/providers/github.d.ts +207 -0
  141. package/dist/commands/pjm/remote/providers/github.d.ts.map +1 -0
  142. package/dist/commands/pjm/remote/providers/github.js +1456 -0
  143. package/dist/commands/pjm/remote/providers/jira.d.ts +245 -0
  144. package/dist/commands/pjm/remote/providers/jira.d.ts.map +1 -0
  145. package/dist/commands/pjm/remote/providers/jira.js +1650 -0
  146. package/dist/commands/pjm/remote/providers/linear.d.ts +182 -0
  147. package/dist/commands/pjm/remote/providers/linear.d.ts.map +1 -0
  148. package/dist/commands/pjm/remote/providers/linear.js +1289 -0
  149. package/dist/commands/pjm/remote/purpose-policy.d.ts +29 -0
  150. package/dist/commands/pjm/remote/purpose-policy.d.ts.map +1 -0
  151. package/dist/commands/pjm/remote/purpose-policy.js +118 -0
  152. package/dist/commands/pjm/remote/reconcile.d.ts +42 -0
  153. package/dist/commands/pjm/remote/reconcile.d.ts.map +1 -0
  154. package/dist/commands/pjm/remote/reconcile.js +101 -0
  155. package/dist/commands/pjm/remote/resolution.d.ts +122 -0
  156. package/dist/commands/pjm/remote/resolution.d.ts.map +1 -0
  157. package/dist/commands/pjm/remote/resolution.js +243 -0
  158. package/dist/commands/pjm/remote/schema.d.ts +9309 -0
  159. package/dist/commands/pjm/remote/schema.d.ts.map +1 -0
  160. package/dist/commands/pjm/remote/schema.js +1503 -0
  161. package/dist/commands/pjm/remote/service.d.ts +20 -0
  162. package/dist/commands/pjm/remote/service.d.ts.map +1 -0
  163. package/dist/commands/pjm/remote/service.js +5121 -0
  164. package/dist/commands/pjm/remote/shared-storage.d.ts +36 -0
  165. package/dist/commands/pjm/remote/shared-storage.d.ts.map +1 -0
  166. package/dist/commands/pjm/remote/shared-storage.js +110 -0
  167. package/dist/commands/pjm/remote/snapshot.d.ts +32 -0
  168. package/dist/commands/pjm/remote/snapshot.d.ts.map +1 -0
  169. package/dist/commands/pjm/remote/snapshot.js +140 -0
  170. package/dist/commands/pjm/remote/storage-locator.d.ts +29 -0
  171. package/dist/commands/pjm/remote/storage-locator.d.ts.map +1 -0
  172. package/dist/commands/pjm/remote/storage-locator.js +62 -0
  173. package/dist/commands/pjm/remote/store.d.ts +85 -0
  174. package/dist/commands/pjm/remote/store.d.ts.map +1 -0
  175. package/dist/commands/pjm/remote/store.js +553 -0
  176. package/dist/commands/pjm/remote/verification.d.ts +40 -0
  177. package/dist/commands/pjm/remote/verification.d.ts.map +1 -0
  178. package/dist/commands/pjm/remote/verification.js +100 -0
  179. package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
  180. package/dist/commands/project/dispatch-ceiling/index.js +32 -18
  181. package/dist/commands/project/log/append.d.ts +48 -0
  182. package/dist/commands/project/log/append.d.ts.map +1 -1
  183. package/dist/commands/project/log/append.js +207 -30
  184. package/dist/commands/project/log/check.d.ts +87 -1
  185. package/dist/commands/project/log/check.d.ts.map +1 -1
  186. package/dist/commands/project/log/check.js +139 -5
  187. package/dist/commands/project/log/grammar.d.ts +165 -0
  188. package/dist/commands/project/log/grammar.d.ts.map +1 -1
  189. package/dist/commands/project/log/grammar.js +219 -1
  190. package/dist/commands/project/log/rollup.d.ts +16 -1
  191. package/dist/commands/project/log/rollup.d.ts.map +1 -1
  192. package/dist/commands/project/log/rollup.js +22 -2
  193. package/dist/commands/project/log/synthesize.d.ts +16 -0
  194. package/dist/commands/project/log/synthesize.d.ts.map +1 -1
  195. package/dist/commands/project/log/synthesize.js +85 -9
  196. package/dist/commands/status/index.d.ts.map +1 -1
  197. package/dist/commands/status/index.js +24 -2
  198. package/dist/commands/sync/apply.d.ts.map +1 -1
  199. package/dist/commands/sync/apply.js +6 -4
  200. package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
  201. package/dist/commands/tools/shared/pack-manifest.js +1 -0
  202. package/dist/config/dispatch-matrix.d.ts.map +1 -1
  203. package/dist/config/dispatch-matrix.js +13 -5
  204. package/dist/config/oat-config.d.ts +41 -0
  205. package/dist/config/oat-config.d.ts.map +1 -1
  206. package/dist/config/oat-config.js +247 -9
  207. package/dist/config/own-keys.d.ts +22 -0
  208. package/dist/config/own-keys.d.ts.map +1 -0
  209. package/dist/config/own-keys.js +32 -0
  210. package/dist/config/resolve.d.ts +11 -0
  211. package/dist/config/resolve.d.ts.map +1 -1
  212. package/dist/config/resolve.js +35 -11
  213. package/dist/config/sync-config.d.ts.map +1 -1
  214. package/dist/config/sync-config.js +16 -0
  215. package/dist/drift/detector.d.ts.map +1 -1
  216. package/dist/drift/detector.js +52 -1
  217. package/dist/drift/skill-view-diagnostic.d.ts.map +1 -1
  218. package/dist/drift/skill-view-diagnostic.js +2 -23
  219. package/dist/engine/compute-plan.d.ts.map +1 -1
  220. package/dist/engine/compute-plan.js +22 -72
  221. package/dist/engine/managed-copy-hash.d.ts +69 -0
  222. package/dist/engine/managed-copy-hash.d.ts.map +1 -0
  223. package/dist/engine/managed-copy-hash.js +175 -0
  224. package/dist/fs/assets.d.ts +11 -0
  225. package/dist/fs/assets.d.ts.map +1 -1
  226. package/dist/fs/assets.js +1 -1
  227. package/dist/manifest/hash.d.ts +110 -0
  228. package/dist/manifest/hash.d.ts.map +1 -1
  229. package/dist/manifest/hash.js +111 -13
  230. package/dist/providers/ceiling/registry.d.ts.map +1 -1
  231. package/dist/providers/ceiling/registry.js +6 -1
  232. package/dist/providers/identity/dispatch-report.d.ts.map +1 -1
  233. package/dist/providers/identity/dispatch-report.js +4 -1
  234. package/dist/release/public-package-contract.d.ts.map +1 -1
  235. package/dist/release/public-package-contract.js +21 -0
  236. package/dist/validation/skills.d.ts.map +1 -1
  237. package/dist/validation/skills.js +305 -40
  238. package/package.json +2 -2
@@ -15,17 +15,235 @@ export function isProjectLogSectionMarker(line) {
15
15
  export function isProjectLogEntryMarker(line) {
16
16
  return /^### .+$/.test(line);
17
17
  }
18
+ /**
19
+ * Every character JavaScript treats as a LineTerminator, and therefore every
20
+ * character a multiline `^` anchors after: LF, CR, U+2028 LINE SEPARATOR, and
21
+ * U+2029 PARAGRAPH SEPARATOR. VT, FF, and U+0085 NEL are deliberately absent —
22
+ * ECMAScript does not count them, so `^` does not match after them either.
23
+ *
24
+ * The set is exported rather than inlined because the append validator and this
25
+ * parser must enumerate exactly the same characters. A validator that split on
26
+ * fewer terminators than the parser anchored after is precisely how a body
27
+ * could smuggle a `## ` past validation and have it become a real section
28
+ * boundary, silently truncating the parsed entries region and voiding the
29
+ * completion seal.
30
+ */
31
+ export const PROJECT_LOG_LINE_TERMINATOR_RE = /[\n\r\u2028\u2029]/;
32
+ /**
33
+ * A *lone* line terminator: a carriage return not followed by a line feed, or a
34
+ * U+2028 / U+2029 separator.
35
+ *
36
+ * CRLF is deliberately excluded, and that carve-out is the whole point. Every
37
+ * reader in this module treats `\r\n` as exactly one boundary — `splitProjectLogLines`,
38
+ * the `/\r?\n/` scans, and `parseProjectLogEntries` — so a CRLF body has one
39
+ * reading and is accepted, as it was before this guard existed. A *lone* CR has
40
+ * two readings (a boundary to a multiline `^`, body text to everything here),
41
+ * and so do U+2028 and U+2029, so those stay refused.
42
+ *
43
+ * Written as one pattern rather than a strip-then-test so the rule is legible at
44
+ * the point of use: `\r(?!\n)` is "a carriage return that is not part of CRLF".
45
+ */
46
+ export const PROJECT_LOG_LONE_TERMINATOR_RE = /\r(?!\n)|[\u2028\u2029]/;
47
+ /**
48
+ * Canonicalizes accepted line endings to LF.
49
+ *
50
+ * The command parses leniently and writes strictly: CRLF is accepted from a
51
+ * caller — a `--body -` fed from a file, tool output, or a pasted buffer — and
52
+ * stored as LF, so a log this command writes never contains a terminator other
53
+ * than LF. That makes the file's single reading a property of its bytes rather
54
+ * than of every reader agreeing about them, which is the weaker guarantee this
55
+ * module kept failing to hold.
56
+ *
57
+ * It is not needed to satisfy `rollup`'s `^…$/m` ledger scan: a multiline `$`
58
+ * matches before a CR as readily as before an LF, so that scan reads a CRLF log
59
+ * correctly and always did. Storing LF is a narrowing of what future readers
60
+ * must cope with, not a repair of a present disagreement.
61
+ */
62
+ export function normalizeProjectLogLineEndings(value) {
63
+ return value.replaceAll('\r\n', '\n');
64
+ }
65
+ /**
66
+ * Splits on every LineTerminator, treating CRLF as one boundary.
67
+ *
68
+ * Validators use this rather than a `/\r?\n/` split so that a lone CR, a
69
+ * U+2028, or a U+2029 starts a new line for validation just as it would for a
70
+ * regular expression's multiline `^`.
71
+ */
72
+ export function splitProjectLogLines(content) {
73
+ return content.split(/\r\n|[\n\r\u2028\u2029]/);
74
+ }
75
+ /**
76
+ * The log's `## ` section boundaries, where a boundary is a `## ` that begins
77
+ * the content or directly follows a line feed.
78
+ *
79
+ * LF is the only boundary on purpose. The previous `/^## [^\r\n]+/gm` anchored
80
+ * after all four LineTerminators while the append validator only split on
81
+ * `/\r?\n/`, so a judgment body reading `carrier<CR>## Injected` passed
82
+ * validation and then became a real section boundary — truncating `## Entries`
83
+ * so `check` reported an already-written seal as `sealed: false` and appends
84
+ * kept succeeding onto a sealed log. Anchoring on LF alone keeps this parser
85
+ * and `parseProjectLogEntries`, which splits its section on `/\r?\n/`, reading
86
+ * the same file the same way, and it holds for a log written by hand as well as one
87
+ * the command wrote.
88
+ */
18
89
  export function findProjectLogSections(content) {
19
- const matches = [...content.matchAll(/^## [^\r\n]+/gm)];
90
+ const matches = [...content.matchAll(/(?<=^|\n)## [^\r\n]+/g)];
20
91
  return matches.map((match, index) => ({
21
92
  heading: match[0],
22
93
  start: match.index,
23
94
  end: matches[index + 1]?.index ?? content.length,
24
95
  }));
25
96
  }
97
+ /**
98
+ * The judgment-heading scan a `^…$/m` reader performs — the same pattern
99
+ * `rollup.ts` uses to key its ledger.
100
+ *
101
+ * Declared here so `containsAmbiguousProjectLogMarker` can ask the competing
102
+ * reader what *it* would see, rather than approximating it. `matchAll` builds a
103
+ * fresh regex per call, so the `g` flag's `lastIndex` is never shared.
104
+ */
105
+ /**
106
+ * The single-character form of "a terminator other than LF", for testing the
107
+ * one character that precedes a match. A lookahead-based rule cannot be used on
108
+ * a lone character; it does not need to be, because the character before a
109
+ * heading on a CRLF line is the LF, so CRLF never reaches this test.
110
+ */
111
+ const PRECEDING_NON_LINE_FEED_TERMINATOR_RE = /[\r\u2028\u2029]/;
112
+ const JUDGMENT_HEADING_SCAN_RE = /^### (\d{4}-\d{2}-\d{2}) \u00b7 (project|general) \u00b7 (bug|friction|worked-well|feedback) \u00b7 ([^\u00b7\r\n]+)$/gm;
113
+ /**
114
+ * Whether the log contains a heading that a `^…$/m` reader starts a line at but
115
+ * an LF-only reader does not — that is, whether the file has two readings.
116
+ *
117
+ * The two competing readers are enumerated rather than approximated: the
118
+ * pre-fix section scan `/^## [^\r\n]+/gm`, and `rollup.ts`'s ledger scan, which
119
+ * recognizes only the complete dated judgment grammar. A `### ` line that
120
+ * neither recognizes — `carrier<CR>### Notes` — is body text to every reader and
121
+ * is deliberately *not* flagged; refusing it would strand logs a previous
122
+ * release could legitimately have written.
123
+ *
124
+ * Mutators consult this and refuse rather than guess, because a file with two
125
+ * readings cannot answer "is this sealed?". Tightening the section parser to LF
126
+ * alone would otherwise silently *widen* such logs: a hand-written
127
+ * `preamble<U+2028>## Entries` used to parse, so its seal was found and a
128
+ * replayed seal was deduplicated, and under an LF-only reading the same file has
129
+ * no entries region, reports unsealed, and accepts a second seal. Refusing is
130
+ * the only resolution that is not weaker than the reading it replaces.
131
+ *
132
+ * CRLF is deliberately not caught, and the entries parser now earns that
133
+ * exemption rather than merely asserting it. The character immediately before a
134
+ * marker on a `\r\n`-terminated line is the LF, so a `## ` section boundary was
135
+ * always unambiguous; `### ` entries and the structural heading pattern were not,
136
+ * because their `$` cannot match before a trailing `\r`, so a CRLF log parsed to
137
+ * zero entries and an existing seal was invisible. `parseProjectLogEntries` now
138
+ * splits on `/\r?\n/`, which makes all three agree and makes "CRLF has exactly
139
+ * one reading" a fact about this module rather than a hope.
140
+ */
141
+ export function containsAmbiguousProjectLogMarker(content) {
142
+ if (/(?<=[\r\u2028\u2029])## [^\r\n]+/.test(content)) {
143
+ return true;
144
+ }
145
+ for (const match of content.matchAll(JUDGMENT_HEADING_SCAN_RE)) {
146
+ const preceding = content[match.index - 1];
147
+ if (preceding !== undefined &&
148
+ PRECEDING_NON_LINE_FEED_TERMINATOR_RE.test(preceding)) {
149
+ return true;
150
+ }
151
+ }
152
+ return false;
153
+ }
26
154
  export function composeJudgmentHeading(input) {
27
155
  return `### ${input.date} · ${input.scope} · ${input.type} · ${input.area}`;
28
156
  }
29
157
  export function composeStructuralHeading(input) {
30
158
  return `### ${input.date} · structural · ${input.producer} · ${input.ref}`;
31
159
  }
160
+ /**
161
+ * The producer and ref that together identify the completion seal — the last
162
+ * entry a project log may ever receive.
163
+ *
164
+ * Both fields are required. A `seal` ref from another producer is an ordinary
165
+ * structural entry, and an `oat-project-complete` entry with another ref is an
166
+ * ordinary lifecycle entry; treating either as a seal would let a foreign
167
+ * append freeze a log that was never completed.
168
+ */
169
+ export const PROJECT_LOG_SEAL_PRODUCER = 'oat-project-complete';
170
+ export const PROJECT_LOG_SEAL_REF = 'seal';
171
+ /**
172
+ * The prefix of the seal's idempotency token (`oat-seal:<project>`).
173
+ *
174
+ * The token is what makes a replayed seal recognize its own entry, so it is
175
+ * prefixed rather than bare: a project name alone could occur in ordinary prose
176
+ * and match an unrelated body.
177
+ */
178
+ export const PROJECT_LOG_SEAL_KEY_PREFIX = 'oat-seal:';
179
+ /**
180
+ * The single definition of "this entry is the completion seal", shared by the
181
+ * `check` probe and the `append` guard.
182
+ *
183
+ * Both callers route on this one predicate on purpose: two definitions of
184
+ * sealed is the regression that lets a log report itself unsealed to one
185
+ * command and sealed to the other.
186
+ */
187
+ export function isProjectLogSealEntry(entry) {
188
+ return (entry.producer === PROJECT_LOG_SEAL_PRODUCER &&
189
+ entry.ref === PROJECT_LOG_SEAL_REF);
190
+ }
191
+ /**
192
+ * Whether a composed or parsed entry *heading* is the completion seal's.
193
+ *
194
+ * The heading-level counterpart of `isProjectLogSealEntry`, and it delegates to
195
+ * it rather than restating the rule. One predicate serves both directions —
196
+ * "is this request the seal?" and "does this already-appended heading name a
197
+ * seal?" — so the two can never drift into disagreeing about what a seal
198
+ * heading is. It reads the producer and ref back out of the heading text rather
199
+ * than from a caller's flags, which is the same normalization
200
+ * `parseProjectLogEntries` applies.
201
+ */
202
+ export function isProjectLogSealHeading(heading) {
203
+ const parsed = STRUCTURAL_HEADING_RE.exec(heading);
204
+ return (parsed !== null &&
205
+ isProjectLogSealEntry({
206
+ producer: parsed[2].trim(),
207
+ ref: parsed[3].trim(),
208
+ }));
209
+ }
210
+ /**
211
+ * The raw line of `content` that is a completion-seal heading, or undefined.
212
+ *
213
+ * Deliberately independent of `parseProjectLogEntries`: it answers "is a seal
214
+ * physically in this file?" where the parser answers "can this file's structure
215
+ * be read to contain a seal?". The gap between those two questions is the state
216
+ * every mutator must refuse, and all of them ask it the same way.
217
+ *
218
+ * The offset is returned alongside the text because callers must locate the
219
+ * seal, not merely recognize it: prose inside `## Entries` can quote a seal
220
+ * heading verbatim, so a substring test would place a seal that really sits
221
+ * under a later section inside the entries region and blame the wrong cause.
222
+ */
223
+ export function findProjectLogSealHeadingLine(content) {
224
+ let cursor = 0;
225
+ for (const line of splitProjectLogLines(content)) {
226
+ if (isProjectLogSealHeading(line.trim())) {
227
+ return { line, index: content.indexOf(line, cursor) };
228
+ }
229
+ // Advance past this line and the terminator that ended it. The terminator's
230
+ // width varies (CRLF is two units), so it is measured rather than assumed.
231
+ const next = content.indexOf(line, cursor) + line.length;
232
+ cursor = next + (content.startsWith('\r\n', next) ? 2 : 1);
233
+ }
234
+ return undefined;
235
+ }
236
+ /**
237
+ * Whether a seal body carries the canonical stand-alone seal token.
238
+ *
239
+ * `idempotencyToken` records the whole whitespace-delimited word containing a
240
+ * key, so a key glued to the varying completion timestamp never matches its own
241
+ * earlier append. A seal written before this convention carries no token at
242
+ * all, which is exactly why the seal is also recognized structurally.
243
+ */
244
+ export function carriesProjectLogSealKey(body) {
245
+ return body
246
+ .split(/\s+/)
247
+ .some((word) => word.startsWith(PROJECT_LOG_SEAL_KEY_PREFIX) &&
248
+ word.length > PROJECT_LOG_SEAL_KEY_PREFIX.length);
249
+ }
@@ -14,12 +14,27 @@ export interface RollupProjectLogInput {
14
14
  summaryPath?: string;
15
15
  artifactTarget?: ProjectLogArtifactTarget;
16
16
  }
17
- export interface ProjectLogRollupResult {
17
+ /** The outcome of a roll-up that actually read the log. */
18
+ export interface ProjectLogRollupSuccess {
18
19
  status: 'ok' | 'failed';
19
20
  summarySection: 'written' | 'updated';
20
21
  ledgerOutcome: 'appended' | 'deduplicated' | 'skipped_permitted' | 'failed';
21
22
  entriesRolledUp: number;
22
23
  }
24
+ export type ProjectLogRollupResult = ProjectLogRollupSuccess
25
+ /**
26
+ * The log has two readings, so its entries cannot be rolled up honestly.
27
+ *
28
+ * A separate member rather than an extra field, because the success member's
29
+ * counts would otherwise have to be filled in with zeros — and reporting
30
+ * `entriesRolledUp: 0` for an unreadable log is exactly the conflation this
31
+ * refusal exists to remove: it was byte-identical to the output for an empty
32
+ * one.
33
+ */
34
+ | {
35
+ status: 'ambiguous';
36
+ ambiguity: string;
37
+ };
23
38
  export interface RollupProjectLogDependencies {
24
39
  resolveActiveProject: (repoRoot: string) => Promise<ActiveProjectResolution>;
25
40
  resolveEffectiveConfig: (repoRoot: string, userConfigDir: string, env?: NodeJS.ProcessEnv) => Promise<ResolvedConfig>;
@@ -1 +1 @@
1
- {"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/rollup.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,mCAAmC,EAAE,wBAGjD,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,wBAAwB,CAAC;CAC3C;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC;IACxB,cAAc,EAAE,SAAS,GAAG,SAAS,CAAC;IACtC,aAAa,EAAE,UAAU,GAAG,cAAc,GAAG,mBAAmB,GAAG,QAAQ,CAAC;IAC5E,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,KACpB,OAAO,CAAC,cAAc,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,mCAAoC,SAAQ,4BAA4B;IACvF,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAiFD,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,IAAI,CAChB,4BAA4B,EAC5B,wBAAwB,CACK,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAiBjC;AAoED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,EAC5B,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,sBAAsB,CAAC,CAyCjC;AAmDD,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,OAAO,CAAC,mCAAmC,CAAM,GAC3D,OAAO,CAoBT"}
1
+ {"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/rollup.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAA0B,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,mCAAmC,EAAE,wBAGjD,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,wBAAwB,CAAC;CAC3C;AAED,2DAA2D;AAC3D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC;IACxB,cAAc,EAAE,SAAS,GAAG,SAAS,CAAC;IACtC,aAAa,EAAE,UAAU,GAAG,cAAc,GAAG,mBAAmB,GAAG,QAAQ,CAAC;IAC5E,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,sBAAsB,GAC9B,uBAAuB;AACzB;;;;;;;;GAQG;GACD;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C,MAAM,WAAW,4BAA4B;IAC3C,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,KACpB,OAAO,CAAC,cAAc,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,mCAAoC,SAAQ,4BAA4B;IACvF,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACtD;AAiFD,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,IAAI,CAChB,4BAA4B,EAC5B,wBAAwB,CACK,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAiBjC;AAoED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,EAC5B,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,sBAAsB,CAAC,CAqDjC;AA4DD,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,OAAO,CAAC,mCAAmC,CAAM,GAC3D,OAAO,CAoBT"}
@@ -8,7 +8,7 @@ import { resolveEffectiveConfig } from '../../../config/resolve.js';
8
8
  import { dirExists, fileExists } from '../../../fs/io.js';
9
9
  import { resolveProjectRoot } from '../../../fs/paths.js';
10
10
  import { Command } from 'commander';
11
- import { parseProjectLogEntries, PROJECT_LOG_FILENAME, } from './check.js';
11
+ import { findProjectLogAmbiguity, parseProjectLogEntries, PROJECT_LOG_FILENAME, } from './check.js';
12
12
  const DEFAULT_LEDGER_PATH = '.oat/repo/reference/project-observations.md';
13
13
  const WORKFLOW_OBSERVATIONS_HEADING = '## Workflow Observations';
14
14
  export const DEFAULT_PROJECT_LOG_ARTIFACT_TARGET = {
@@ -145,7 +145,17 @@ export async function rollupProjectLog(input, overrides = {}) {
145
145
  if (!(await fileExists(summaryPath))) {
146
146
  throw new Error(`summary.md does not exist: ${summaryPath}. Author the project summary before roll-up.`);
147
147
  }
148
- const parsed = parseProjectLogEntries(await readFile(logPath, 'utf8'));
148
+ const content = await readFile(logPath, 'utf8');
149
+ // The same question `check`, both append paths and `synthesize` ask, asked
150
+ // before anything is written. `rollup` was the one surface without it: on a
151
+ // log the other four refused it rewrote `summary.md` and reported
152
+ // `status: "ok"` with `entriesRolledUp: 0`, indistinguishable from a clean
153
+ // empty log. It is a public command an operator can run directly.
154
+ const ambiguity = findProjectLogAmbiguity(content, logPath);
155
+ if (ambiguity !== undefined) {
156
+ return { status: 'ambiguous', ambiguity };
157
+ }
158
+ const parsed = parseProjectLogEntries(content);
149
159
  const summaryUpdate = writeSummarySection(await readFile(summaryPath, 'utf8'), artifactTarget.summaryHeading ?? WORKFLOW_OBSERVATIONS_HEADING, renderEntries(parsed.entries));
150
160
  await writeFile(summaryPath, summaryUpdate.content, 'utf8');
151
161
  const ledgerOutcome = await rollupLedger(input, parsed.entries, dependencies);
@@ -165,6 +175,16 @@ async function runRollupCommand(options, context, dependencies) {
165
175
  project: options.project,
166
176
  summaryPath: options.summaryPath,
167
177
  }, dependencies);
178
+ if (result.status === 'ambiguous') {
179
+ if (context.json) {
180
+ context.logger.json(result);
181
+ }
182
+ else {
183
+ context.logger.error(result.ambiguity);
184
+ }
185
+ process.exitCode = 1;
186
+ return;
187
+ }
168
188
  if (context.json) {
169
189
  context.logger.json(result);
170
190
  }
@@ -1,6 +1,7 @@
1
1
  import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
2
2
  import { type ActiveProjectResolution } from '../../../config/oat-config.js';
3
3
  import { Command } from 'commander';
4
+ import { type ProjectLogLockDependencies } from './append.js';
4
5
  export interface SynthesizeProjectLogInput {
5
6
  repoRoot: string;
6
7
  project?: string;
@@ -9,9 +10,24 @@ export interface SynthesizeProjectLogInput {
9
10
  export interface ProjectLogSynthesizeResult {
10
11
  status: 'synthesized';
11
12
  logPath: string;
13
+ /**
14
+ * Present and true when the accepted `--body` carried CRLF and was stored as
15
+ * LF, so the bytes on disk differ from the bytes the caller passed.
16
+ */
17
+ normalizedLineEndings?: true;
12
18
  }
13
19
  export interface SynthesizeProjectLogDependencies {
14
20
  resolveActiveProject: (repoRoot: string) => Promise<ActiveProjectResolution>;
21
+ /**
22
+ * The log's own read/write primitives, mirroring `appendProjectLog`.
23
+ * Injectable so a test can hold this writer inside its rewrite window while
24
+ * another enters, which is the only way to prove the serialization rather
25
+ * than assert it.
26
+ */
27
+ readLog: (path: string) => Promise<string>;
28
+ writeLog: (path: string, content: string) => Promise<void>;
29
+ /** Advisory-lock overrides for the synthesis window. */
30
+ lock: Partial<ProjectLogLockDependencies>;
15
31
  }
16
32
  export interface ProjectLogSynthesizeCommandDependencies extends SynthesizeProjectLogDependencies {
17
33
  buildCommandContext: (options: GlobalOptions) => CommandContext;
@@ -1 +1 @@
1
- {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/synthesize.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gCAAgC;IAC/C,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC9E;AAED,MAAM,WAAW,uCAAwC,SAAQ,gCAAgC;IAC/F,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AA+CD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,EAChC,SAAS,GAAE,OAAO,CAAC,gCAAgC,CAAM,GACxD,OAAO,CAAC,0BAA0B,CAAC,CAwDrC;AAqCD,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,uCAAuC,CAAM,GAC/D,OAAO,CAeT"}
1
+ {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/synthesize.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,0BAA0B,EAEhC,MAAM,UAAU,CAAC;AAkBlB,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,gCAAgC;IAC/C,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7E;;;;;OAKG;IACH,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,wDAAwD;IACxD,IAAI,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,uCAAwC,SAAQ,gCAAgC;IAC/F,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AAoDD,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,yBAAyB,EAChC,SAAS,GAAE,OAAO,CAAC,gCAAgC,CAAM,GACxD,OAAO,CAAC,0BAA0B,CAAC,CAkDrC;AA+HD,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,uCAAuC,CAAM,GAC/D,OAAO,CAeT"}
@@ -6,9 +6,16 @@ import { resolveActiveProject, } from '../../../config/oat-config.js';
6
6
  import { dirExists, fileExists } from '../../../fs/io.js';
7
7
  import { resolveProjectRoot } from '../../../fs/paths.js';
8
8
  import { Command } from 'commander';
9
- import { findCanonicalProjectLogSynthesisSection, PROJECT_LOG_FILENAME, SYNTHESIS_COMPLETE_HEADING, SYNTHESIS_PENDING_HEADING, } from './check.js';
9
+ import { ProjectLogSealedError, withProjectLogLock, } from './append.js';
10
+ import { findCanonicalProjectLogSynthesisSection, findProjectLogAmbiguity, findProjectLogSeal, unreachableProjectLogSealError, PROJECT_LOG_FILENAME, SYNTHESIS_COMPLETE_HEADING, SYNTHESIS_PENDING_HEADING, } from './check.js';
11
+ import { containsAmbiguousProjectLogMarker, findProjectLogSealHeadingLine, normalizeProjectLogLineEndings, PROJECT_LOG_LONE_TERMINATOR_RE, splitProjectLogLines, } from './grammar.js';
10
12
  const DEFAULT_SYNTHESIZE_DEPENDENCIES = {
11
13
  resolveActiveProject,
14
+ readLog: async (path) => readFile(path, 'utf8'),
15
+ writeLog: async (path, content) => {
16
+ await writeFile(path, content, 'utf8');
17
+ },
18
+ lock: {},
12
19
  };
13
20
  const DEFAULT_COMMAND_DEPENDENCIES = {
14
21
  ...DEFAULT_SYNTHESIZE_DEPENDENCIES,
@@ -44,13 +51,23 @@ export async function synthesizeProjectLog(input, overrides = {}) {
44
51
  ...DEFAULT_SYNTHESIZE_DEPENDENCIES,
45
52
  ...overrides,
46
53
  };
47
- const body = input.body?.trim();
48
- if (!body) {
54
+ const raw = input.body ?? '';
55
+ const supplied = raw.trim();
56
+ if (!supplied) {
49
57
  throw new Error('--body is required and must contain non-whitespace text.');
50
58
  }
51
- if (body
52
- .split(/\r?\n/)
53
- .some((line) => line === SYNTHESIS_PENDING_HEADING ||
59
+ // Same rule the judgment bodies follow: parse leniently, write strictly. CRLF
60
+ // is accepted and stored as LF; a lone CR and the U+2028 / U+2029 separators
61
+ // are refused, because those are the terminators this module's readers do not
62
+ // all agree about. Tested against `raw`, before trimming: trim treats all four
63
+ // as whitespace, so an edge-terminated body would otherwise slip past a rule
64
+ // whose message says it does not.
65
+ if (PROJECT_LOG_LONE_TERMINATOR_RE.test(raw)) {
66
+ throw new Error('--body must break lines with line feeds or CRLF; a lone carriage return and the U+2028 and U+2029 separators are not accepted.');
67
+ }
68
+ const normalized = supplied.includes('\r\n');
69
+ const body = normalizeProjectLogLineEndings(supplied);
70
+ if (splitProjectLogLines(body).some((line) => line === SYNTHESIS_PENDING_HEADING ||
54
71
  line === SYNTHESIS_COMPLETE_HEADING)) {
55
72
  throw new Error('--body must not recreate command-owned project-log synthesis markers.');
56
73
  }
@@ -59,7 +76,40 @@ export async function synthesizeProjectLog(input, overrides = {}) {
59
76
  if (!(await fileExists(logPath))) {
60
77
  throw new Error(`Project log does not exist: ${logPath}. Append an entry before synthesizing.`);
61
78
  }
62
- const content = await readFile(logPath, 'utf8');
79
+ // The read, the seal consultation, and the whole-file rewrite are one
80
+ // critical section under the log's own advisory lock — the same lock
81
+ // `appendProjectLog` takes, because this rewrite and a concurrent append race
82
+ // each other exactly as two appends do, and the loser's entry is simply gone.
83
+ return withProjectLogLock(logPath, dependencies.lock, 'required', async () => synthesizeLockedProjectLog(logPath, body, dependencies, normalized));
84
+ }
85
+ async function synthesizeLockedProjectLog(logPath, body, dependencies, normalized) {
86
+ const content = await dependencies.readLog(logPath);
87
+ // Refuse a log whose markers two readers resolve differently, before any
88
+ // routing decision reads them. `synthesize` replaces a whole section chosen by
89
+ // that reading, so a hidden second pending marker — `carrier<CR>## End-of-run
90
+ // synthesis (pending …)` — used to make the log ambiguous and be refused, and
91
+ // under an LF-only reading it becomes invisible and its content is consumed by
92
+ // the rewrite.
93
+ const ambiguity = findProjectLogAmbiguity(content, logPath);
94
+ if (ambiguity !== undefined) {
95
+ throw new Error(ambiguity);
96
+ }
97
+ // A sealed log is closed to this rewrite as much as to an append. The seal is
98
+ // the log's last entry by contract, so replacing the synthesis section after
99
+ // it would mutate a record the completion flow has already declared final.
100
+ // The refusal is the same typed error `append` raises, so both commands
101
+ // report `status: "sealed"` with a non-zero exit from one shape.
102
+ const seal = findProjectLogSeal(content);
103
+ if (seal !== null) {
104
+ throw new ProjectLogSealedError(logPath, seal, 'synthesis rewrite');
105
+ }
106
+ // The same refusal both append paths make, on the same file. A seal the
107
+ // parser cannot reach is still a seal, and rewriting a section of the log it
108
+ // closes is exactly the mutation it forbids.
109
+ const unreachableSeal = findProjectLogSealHeadingLine(content);
110
+ if (unreachableSeal !== undefined) {
111
+ throw unreachableProjectLogSealError(logPath, content, unreachableSeal);
112
+ }
63
113
  const synthesis = findCanonicalProjectLogSynthesisSection(content);
64
114
  if (synthesis.status === 'complete') {
65
115
  throw new Error('End-of-run synthesis is already written; append a correction judgment instead of replacing it.');
@@ -72,8 +122,17 @@ export async function synthesizeProjectLog(input, overrides = {}) {
72
122
  }
73
123
  const suffix = content.slice(synthesis.section.end);
74
124
  const nextContent = `${content.slice(0, synthesis.section.start)}${SYNTHESIS_COMPLETE_HEADING}\n\n${body}\n${suffix ? '\n' : ''}${suffix}`;
75
- await writeFile(logPath, nextContent, 'utf8');
76
- return { status: 'synthesized', logPath };
125
+ // Never write a log this command would refuse to read. The body reaches the
126
+ // file verbatim, so this is the backstop behind the body validation above.
127
+ if (containsAmbiguousProjectLogMarker(nextContent)) {
128
+ throw new Error('--body would leave a heading after a carriage return, U+2028, or U+2029, producing a log with two readings that no later command could safely mutate.');
129
+ }
130
+ await dependencies.writeLog(logPath, nextContent);
131
+ return {
132
+ status: 'synthesized',
133
+ logPath,
134
+ ...(normalized ? { normalizedLineEndings: true } : {}),
135
+ };
77
136
  }
78
137
  async function runSynthesizeCommand(options, context, dependencies) {
79
138
  try {
@@ -89,6 +148,23 @@ async function runSynthesizeCommand(options, context, dependencies) {
89
148
  process.exitCode = 0;
90
149
  }
91
150
  catch (error) {
151
+ // A sealed log is a terminal refusal, reported in the same shape `append`
152
+ // uses so a caller reading JSON can tell it from a malformed request.
153
+ if (error instanceof ProjectLogSealedError) {
154
+ if (context.json) {
155
+ context.logger.json({
156
+ status: 'sealed',
157
+ logPath: error.logPath,
158
+ heading: error.seal.heading,
159
+ message: error.message,
160
+ });
161
+ }
162
+ else {
163
+ context.logger.error(error.message);
164
+ }
165
+ process.exitCode = 1;
166
+ return;
167
+ }
92
168
  const message = error instanceof Error ? error.message : String(error);
93
169
  if (context.json) {
94
170
  context.logger.json({ status: 'error', message });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"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"}
@@ -761,6 +761,19 @@ async function runStatusCommand(context, dependencies, options = {}) {
761
761
  await dependencies.applyNativeSkillDisposition(scopeCollection.scopeRoot, strayCandidate, scopeCollection.manifest, disposition, scopeCollection.syncConfigPath);
762
762
  if (disposition === 'adopt') {
763
763
  adoptedCount += 1;
764
+ // A completed adopt persists, exactly as the ordinary-stray loop
765
+ // below and as `oat init` (`init/index.ts:1271`) and `oat sync`
766
+ // (`engine/execute-plan.ts:970-976`) already do after a completed
767
+ // run. Only `adopt` sets this: a `keep` writes the sync config
768
+ // through `appendKnownStray` and returns the manifest untouched
769
+ // (`native-skill-disposition.ts:92-94`), so it has nothing to
770
+ // save. Today this write adds no row and only restamps
771
+ // `oatVersion`, because adopting a natively read
772
+ // projection is manifest-neutral by contract
773
+ // (`adopt-stray.ts:140-142`); its executable owner is
774
+ // `adopt-stray.test.ts`'s "moves a native-read Cursor skill
775
+ // without recreating a provider view or manifest row".
776
+ manifestChanged = true;
764
777
  }
765
778
  else {
766
779
  context.logger.success(`Kept ${provider.displayName}-only [${scopeCollection.scope}]: ${formatPathForScope(scopeCollection.scope, strayCandidate.report.providerPath)}.`);
@@ -787,6 +800,9 @@ async function runStatusCommand(context, dependencies, options = {}) {
787
800
  scopeCollection.manifest =
788
801
  await dependencies.applyNativeSkillDisposition(scopeCollection.scopeRoot, strayCandidate, scopeCollection.manifest, disposition, scopeCollection.syncConfigPath, { replaceCanonical: true });
789
802
  adoptedCount += 1;
803
+ // Same rule on the confirmed `replaceCanonical` retry: this branch
804
+ // is only reachable for `disposition === 'adopt'`, and it completed.
805
+ manifestChanged = true;
790
806
  }
791
807
  }
792
808
  if (!migrationAborted && ordinaryStrays.length > 0) {
@@ -848,8 +864,14 @@ async function runStatusCommand(context, dependencies, options = {}) {
848
864
  }
849
865
  if (manifestChanged) {
850
866
  // Placed after the collection-migration block and immediately before
851
- // the only status-owned save. An aborted migration never reaches
852
- // here, so it never claims a restamp it did not perform.
867
+ // the only status-owned save. A migration that adopted nothing never
868
+ // reaches here, so it never claims a restamp it did not perform.
869
+ // Aborting *after* an adoption succeeded does reach here, and should:
870
+ // the adopt already moved the directory, so a migration did complete
871
+ // and the manifest is persisted and restamped for it. For a native
872
+ // adopt that write adds no row -- it is the `oatVersion` restamp
873
+ // alone (`adopt-stray.ts:140-142`). `migrationAborted` suppresses the
874
+ // remaining prompts, not the persistence of work already done.
853
875
  if (scopeCollection.versionRestamp && !context.json) {
854
876
  context.logger.warn(formatManifestVersionRestampWarning('status', scopeCollection.versionRestamp));
855
877
  }
@@ -1 +1 @@
1
- {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAiB3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;AAgVtB,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EAAE,EAC3B,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,IAAI,CAAC,CAoMf"}
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAiB3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;AAgVtB,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EAAE,EAC3B,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,IAAI,CAAC,CAsMf"}
@@ -339,18 +339,20 @@ export async function runSyncApply(context, scopePlans, dependencies) {
339
339
  // (`countPlannedOperations` admits only the mutating collection actions),
340
340
  // so a run can fail with `plannedOperations === 0`. That run is not
341
341
  // restamp-only and must never be described as needing no content changes.
342
+ // The trailing message below tests the failure arm first, so the branch
343
+ // order now enforces that outcome rather than leaving it to this conjunct.
342
344
  const restampOnly = summary.plannedOperations === 0 &&
343
345
  summary.failed === 0 &&
344
346
  versionSkew.length > 0;
345
347
  context.logger.info(formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies, restampOnly));
346
- if (summary.plannedOperations === 0) {
348
+ if (summary.failed > 0) {
349
+ context.logger.warn('\nSync completed with partial failures.');
350
+ }
351
+ else if (summary.plannedOperations === 0) {
347
352
  context.logger.info(restampOnly
348
353
  ? '\nManifest version refreshed; no content changes required.'
349
354
  : '\nNo changes required.');
350
355
  }
351
- else if (summary.failed > 0) {
352
- context.logger.warn('\nSync completed with partial failures.');
353
- }
354
356
  else {
355
357
  context.logger.success('\nSync applied successfully.');
356
358
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pack-manifest.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/pack-manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,EACd,QAAQ,EACT,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,GACf,CAAC;AAEF,eAAO,MAAM,UAAU,4GASiB,CAAC;AAEzC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,QAAQ,CAE3D;AAmID,eAAO,MAAM,aAAa,EAAE,SAAS,cAAc,EAyLlD,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAMhE;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,QAAQ,EACd,IAAI,CAAC,EAAE,aAAa,GACnB,SAAS,mBAAmB,EAAE,CAGhC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAC9C,MAAM,EAAE,CAQV;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAIlE;AAoJD,wBAAgB,oBAAoB,CAClC,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,IAAI,CAiEN"}
1
+ {"version":3,"file":"pack-manifest.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/pack-manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,EACd,QAAQ,EACT,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,GACf,CAAC;AAEF,eAAO,MAAM,UAAU,4GASiB,CAAC;AAEzC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,QAAQ,CAE3D;AAmID,eAAO,MAAM,aAAa,EAAE,SAAS,cAAc,EA0LlD,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,cAAc,CAMhE;AAED,wBAAgB,aAAa,CAC3B,IAAI,EAAE,QAAQ,EACd,IAAI,CAAC,EAAE,aAAa,GACnB,SAAS,mBAAmB,EAAE,CAGhC;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,GAC9C,MAAM,EAAE,CAQV;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAIlE;AAoJD,wBAAgB,oBAAoB,CAClC,QAAQ,GAAE,SAAS,cAAc,EAAkB,GAClD,IAAI,CAiEN"}
@@ -246,6 +246,7 @@ export const PACK_MANIFEST = [
246
246
  ...[
247
247
  'oat-pjm-add-backlog-item',
248
248
  'oat-pjm-decision',
249
+ 'oat-pjm-remote',
249
250
  'oat-pjm-update-repo-reference',
250
251
  'oat-pjm-review-backlog',
251
252
  ].map((name) => skill(name)),
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch-matrix.d.ts","sourceRoot":"","sources":["../../src/config/dispatch-matrix.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dispatch-matrix.d.ts","sourceRoot":"","sources":["../../src/config/dispatch-matrix.ts"],"names":[],"mappings":"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"}