@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.
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/cli-utilities/configuration.md +33 -2
- package/assets/docs/cli-utilities/index.md +3 -0
- package/assets/docs/cli-utilities/project-log.md +63 -4
- package/assets/docs/cli-utilities/remote-project-management.md +191 -0
- package/assets/docs/contributing/code.md +8 -4
- package/assets/docs/contributing/skills.md +29 -17
- package/assets/docs/docs-tooling/commands.md +3 -1
- package/assets/docs/provider-sync/manifest-and-drift.md +2 -18
- package/assets/docs/reference/cli-reference.md +12 -1
- package/assets/docs/reference/file-locations.md +22 -0
- package/assets/docs/reference/oat-directory-structure.md +30 -17
- package/assets/docs/reference/troubleshooting.md +44 -0
- package/assets/docs/workflows/projects/lifecycle.md +17 -0
- package/assets/docs/workflows/projects/picking-up-projects.md +18 -0
- package/assets/docs/workflows/skills/index.md +33 -0
- package/assets/docs/workflows/skills/repo-improve.md +7 -3
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/create-agnostic-skill/SKILL.md +19 -37
- package/assets/skills/create-agnostic-skill/references/docs/skills-guide.md +58 -15
- package/assets/skills/create-agnostic-skill/references/skill-template.md +17 -15
- package/assets/skills/oat-agent-instructions-apply/SKILL.md +1 -1
- package/assets/skills/oat-agent-instructions-apply/references/instruction-file-templates/glob-scoped-rule.md +1 -4
- package/assets/skills/oat-doctor/SKILL.md +3 -6
- package/assets/skills/oat-pjm-remote/SKILL.md +101 -0
- package/assets/skills/oat-pjm-remote/references/external-action-protocol.md +43 -0
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
- package/assets/skills/oat-project-complete/SKILL.md +158 -30
- package/assets/skills/oat-project-complete/scripts/finalize-synced-archive.mjs +26 -7
- package/assets/skills/oat-project-complete/scripts/validate-durable-archive-receipt.mjs +183 -0
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-retro/SKILL.md +1 -1
- package/assets/skills/oat-project-retro/references/apply-procedure.md +11 -0
- package/assets/skills/oat-project-review-provide/SKILL.md +4 -4
- package/assets/skills/oat-project-summary/SKILL.md +24 -2
- package/assets/skills/oat-repo-improve/SKILL.md +9 -2
- package/assets/skills/oat-repo-improve/references/plan-template.md +4 -6
- package/assets/skills/oat-repo-knowledge-index/SKILL.md +11 -9
- package/assets/skills/oat-wave-execute/SKILL.md +20 -6
- package/assets/skills/oat-wave-program/SKILL.md +9 -4
- package/dist/commands/backlog/new.d.ts +1 -0
- package/dist/commands/backlog/new.d.ts.map +1 -1
- package/dist/commands/backlog/new.js +3 -1
- package/dist/commands/config/index.d.ts +3 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +362 -36
- package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
- package/dist/commands/docs/index-generate/index.js +68 -12
- package/dist/commands/docs/init/index.d.ts +11 -0
- package/dist/commands/docs/init/index.d.ts.map +1 -1
- package/dist/commands/docs/init/index.js +19 -1
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +10 -2
- package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.js +42 -9
- package/dist/commands/internal/validate-skill-version-bumps.d.ts.map +1 -1
- package/dist/commands/internal/validate-skill-version-bumps.js +5 -5
- package/dist/commands/pjm/doctor.d.ts +2 -0
- package/dist/commands/pjm/doctor.d.ts.map +1 -1
- package/dist/commands/pjm/doctor.js +71 -1
- package/dist/commands/pjm/index.d.ts +2 -0
- package/dist/commands/pjm/index.d.ts.map +1 -1
- package/dist/commands/pjm/index.js +3 -0
- package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts +60 -0
- package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts.map +1 -0
- package/dist/commands/pjm/remote/__integration__/lifecycle-harness.js +151 -0
- package/dist/commands/pjm/remote/association.d.ts +27 -0
- package/dist/commands/pjm/remote/association.d.ts.map +1 -0
- package/dist/commands/pjm/remote/association.js +68 -0
- package/dist/commands/pjm/remote/authority.d.ts +210 -0
- package/dist/commands/pjm/remote/authority.d.ts.map +1 -0
- package/dist/commands/pjm/remote/authority.js +341 -0
- package/dist/commands/pjm/remote/batch.d.ts +15 -0
- package/dist/commands/pjm/remote/batch.d.ts.map +1 -0
- package/dist/commands/pjm/remote/batch.js +126 -0
- package/dist/commands/pjm/remote/closeout.d.ts +69 -0
- package/dist/commands/pjm/remote/closeout.d.ts.map +1 -0
- package/dist/commands/pjm/remote/closeout.js +208 -0
- package/dist/commands/pjm/remote/create-binding.d.ts +62 -0
- package/dist/commands/pjm/remote/create-binding.d.ts.map +1 -0
- package/dist/commands/pjm/remote/create-binding.js +126 -0
- package/dist/commands/pjm/remote/credential-safety.d.ts +7 -0
- package/dist/commands/pjm/remote/credential-safety.d.ts.map +1 -0
- package/dist/commands/pjm/remote/credential-safety.js +21 -0
- package/dist/commands/pjm/remote/discussion.d.ts +49 -0
- package/dist/commands/pjm/remote/discussion.d.ts.map +1 -0
- package/dist/commands/pjm/remote/discussion.js +124 -0
- package/dist/commands/pjm/remote/doctor.d.ts +22 -0
- package/dist/commands/pjm/remote/doctor.d.ts.map +1 -0
- package/dist/commands/pjm/remote/doctor.js +380 -0
- package/dist/commands/pjm/remote/external-action.d.ts +208 -0
- package/dist/commands/pjm/remote/external-action.d.ts.map +1 -0
- package/dist/commands/pjm/remote/external-action.js +367 -0
- package/dist/commands/pjm/remote/host-execution.d.ts +28 -0
- package/dist/commands/pjm/remote/host-execution.d.ts.map +1 -0
- package/dist/commands/pjm/remote/host-execution.js +63 -0
- package/dist/commands/pjm/remote/index.d.ts +41 -0
- package/dist/commands/pjm/remote/index.d.ts.map +1 -0
- package/dist/commands/pjm/remote/index.js +280 -0
- package/dist/commands/pjm/remote/jira-adf.d.ts +35 -0
- package/dist/commands/pjm/remote/jira-adf.d.ts.map +1 -0
- package/dist/commands/pjm/remote/jira-adf.js +169 -0
- package/dist/commands/pjm/remote/lifecycle.d.ts +163 -0
- package/dist/commands/pjm/remote/lifecycle.d.ts.map +1 -0
- package/dist/commands/pjm/remote/lifecycle.js +224 -0
- package/dist/commands/pjm/remote/local-projection.d.ts +30 -0
- package/dist/commands/pjm/remote/local-projection.d.ts.map +1 -0
- package/dist/commands/pjm/remote/local-projection.js +95 -0
- package/dist/commands/pjm/remote/managed-markdown.d.ts +30 -0
- package/dist/commands/pjm/remote/managed-markdown.d.ts.map +1 -0
- package/dist/commands/pjm/remote/managed-markdown.js +128 -0
- package/dist/commands/pjm/remote/migrate.d.ts +14 -0
- package/dist/commands/pjm/remote/migrate.d.ts.map +1 -0
- package/dist/commands/pjm/remote/migrate.js +32 -0
- package/dist/commands/pjm/remote/operation-state.d.ts +15 -0
- package/dist/commands/pjm/remote/operation-state.d.ts.map +1 -0
- package/dist/commands/pjm/remote/operation-state.js +143 -0
- package/dist/commands/pjm/remote/outbound-projection-safety.d.ts +25 -0
- package/dist/commands/pjm/remote/outbound-projection-safety.d.ts.map +1 -0
- package/dist/commands/pjm/remote/outbound-projection-safety.js +99 -0
- package/dist/commands/pjm/remote/output.d.ts +60 -0
- package/dist/commands/pjm/remote/output.d.ts.map +1 -0
- package/dist/commands/pjm/remote/output.js +48 -0
- package/dist/commands/pjm/remote/preview.d.ts +88 -0
- package/dist/commands/pjm/remote/preview.d.ts.map +1 -0
- package/dist/commands/pjm/remote/preview.js +154 -0
- package/dist/commands/pjm/remote/provider-conformance.d.ts +13 -0
- package/dist/commands/pjm/remote/provider-conformance.d.ts.map +1 -0
- package/dist/commands/pjm/remote/provider-conformance.js +37 -0
- package/dist/commands/pjm/remote/provider.d.ts +57 -0
- package/dist/commands/pjm/remote/provider.d.ts.map +1 -0
- package/dist/commands/pjm/remote/provider.js +28 -0
- package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts +46 -0
- package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/github-publication-safety.js +126 -0
- package/dist/commands/pjm/remote/providers/github.d.ts +207 -0
- package/dist/commands/pjm/remote/providers/github.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/github.js +1456 -0
- package/dist/commands/pjm/remote/providers/jira.d.ts +245 -0
- package/dist/commands/pjm/remote/providers/jira.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/jira.js +1650 -0
- package/dist/commands/pjm/remote/providers/linear.d.ts +182 -0
- package/dist/commands/pjm/remote/providers/linear.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/linear.js +1289 -0
- package/dist/commands/pjm/remote/purpose-policy.d.ts +29 -0
- package/dist/commands/pjm/remote/purpose-policy.d.ts.map +1 -0
- package/dist/commands/pjm/remote/purpose-policy.js +118 -0
- package/dist/commands/pjm/remote/reconcile.d.ts +42 -0
- package/dist/commands/pjm/remote/reconcile.d.ts.map +1 -0
- package/dist/commands/pjm/remote/reconcile.js +101 -0
- package/dist/commands/pjm/remote/resolution.d.ts +122 -0
- package/dist/commands/pjm/remote/resolution.d.ts.map +1 -0
- package/dist/commands/pjm/remote/resolution.js +243 -0
- package/dist/commands/pjm/remote/schema.d.ts +9309 -0
- package/dist/commands/pjm/remote/schema.d.ts.map +1 -0
- package/dist/commands/pjm/remote/schema.js +1503 -0
- package/dist/commands/pjm/remote/service.d.ts +20 -0
- package/dist/commands/pjm/remote/service.d.ts.map +1 -0
- package/dist/commands/pjm/remote/service.js +5121 -0
- package/dist/commands/pjm/remote/shared-storage.d.ts +36 -0
- package/dist/commands/pjm/remote/shared-storage.d.ts.map +1 -0
- package/dist/commands/pjm/remote/shared-storage.js +110 -0
- package/dist/commands/pjm/remote/snapshot.d.ts +32 -0
- package/dist/commands/pjm/remote/snapshot.d.ts.map +1 -0
- package/dist/commands/pjm/remote/snapshot.js +140 -0
- package/dist/commands/pjm/remote/storage-locator.d.ts +29 -0
- package/dist/commands/pjm/remote/storage-locator.d.ts.map +1 -0
- package/dist/commands/pjm/remote/storage-locator.js +62 -0
- package/dist/commands/pjm/remote/store.d.ts +85 -0
- package/dist/commands/pjm/remote/store.d.ts.map +1 -0
- package/dist/commands/pjm/remote/store.js +553 -0
- package/dist/commands/pjm/remote/verification.d.ts +40 -0
- package/dist/commands/pjm/remote/verification.d.ts.map +1 -0
- package/dist/commands/pjm/remote/verification.js +100 -0
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +32 -18
- package/dist/commands/project/log/append.d.ts +48 -0
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +207 -30
- package/dist/commands/project/log/check.d.ts +87 -1
- package/dist/commands/project/log/check.d.ts.map +1 -1
- package/dist/commands/project/log/check.js +139 -5
- package/dist/commands/project/log/grammar.d.ts +165 -0
- package/dist/commands/project/log/grammar.d.ts.map +1 -1
- package/dist/commands/project/log/grammar.js +219 -1
- package/dist/commands/project/log/rollup.d.ts +16 -1
- package/dist/commands/project/log/rollup.d.ts.map +1 -1
- package/dist/commands/project/log/rollup.js +22 -2
- package/dist/commands/project/log/synthesize.d.ts +16 -0
- package/dist/commands/project/log/synthesize.d.ts.map +1 -1
- package/dist/commands/project/log/synthesize.js +85 -9
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +24 -2
- package/dist/commands/sync/apply.d.ts.map +1 -1
- package/dist/commands/sync/apply.js +6 -4
- package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.js +1 -0
- package/dist/config/dispatch-matrix.d.ts.map +1 -1
- package/dist/config/dispatch-matrix.js +13 -5
- package/dist/config/oat-config.d.ts +41 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +247 -9
- package/dist/config/own-keys.d.ts +22 -0
- package/dist/config/own-keys.d.ts.map +1 -0
- package/dist/config/own-keys.js +32 -0
- package/dist/config/resolve.d.ts +11 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +35 -11
- package/dist/config/sync-config.d.ts.map +1 -1
- package/dist/config/sync-config.js +16 -0
- package/dist/drift/detector.d.ts.map +1 -1
- package/dist/drift/detector.js +52 -1
- package/dist/drift/skill-view-diagnostic.d.ts.map +1 -1
- package/dist/drift/skill-view-diagnostic.js +2 -23
- package/dist/engine/compute-plan.d.ts.map +1 -1
- package/dist/engine/compute-plan.js +22 -72
- package/dist/engine/managed-copy-hash.d.ts +69 -0
- package/dist/engine/managed-copy-hash.d.ts.map +1 -0
- package/dist/engine/managed-copy-hash.js +175 -0
- package/dist/fs/assets.d.ts +11 -0
- package/dist/fs/assets.d.ts.map +1 -1
- package/dist/fs/assets.js +1 -1
- package/dist/manifest/hash.d.ts +110 -0
- package/dist/manifest/hash.d.ts.map +1 -1
- package/dist/manifest/hash.js +111 -13
- package/dist/providers/ceiling/registry.d.ts.map +1 -1
- package/dist/providers/ceiling/registry.js +6 -1
- package/dist/providers/identity/dispatch-report.d.ts.map +1 -1
- package/dist/providers/identity/dispatch-report.js +4 -1
- package/dist/release/public-package-contract.d.ts.map +1 -1
- package/dist/release/public-package-contract.js +21 -0
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +305 -40
- 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(
|
|
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
|
-
|
|
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;
|
|
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
|
|
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;
|
|
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 {
|
|
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
|
|
48
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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
|
-
|
|
76
|
-
|
|
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.
|
|
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,
|
|
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.
|
|
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,
|
|
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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-matrix.d.ts","sourceRoot":"","sources":["../../src/config/dispatch-matrix.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,UAAU,GACV,MAAM,GACN,UAAU,CAAC;AAEf,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG,2BAA2B,CAAC;AAC9E,MAAM,MAAM,qBAAqB,GAAG,0BAA0B,EAAE,CAAC;AAEjE,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,qBAAqB,CAAC;CAC9B;AAED,MAAM,MAAM,yBAAyB,GACjC,0BAA0B,GAC1B,6BAA6B,CAAC;AAElC,MAAM,WAAW,+BAA+B;IAC9C,UAAU,EAAE,yBAAyB,EAAE,CAAC;CACzC;AAED,MAAM,MAAM,gCAAgC,GAAG,MAAM,GAAG,qBAAqB,CAAC;AAC9E,MAAM,MAAM,0BAA0B,GAClC,+BAA+B,GAC/B,gCAAgC,CAAC;AACrC,MAAM,MAAM,6BAA6B,GACrC,MAAM,GACN,OAAO,CAAC,MAAM,CAAC,0BAA0B,EAAE,0BAA0B,CAAC,CAAC,CAAC;AAE5E,MAAM,MAAM,oCAAoC,GAC5C,oBAAoB,GACpB,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,oCAAoC,CAAC;IAC3C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;IACzD,MAAM,EAAE,gCAAgC,EAAE,CAAC;CAC5C;AAED,MAAM,MAAM,oBAAoB,GAC5B,cAAc,GACd,aAAa,GACb,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,0BAA0B,GAAG,IAAI,CAAC;IACxC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,eAAO,MAAM,2BAA2B,EAAE,SAAS,0BAA0B,EAChC,CAAC;AAyM9C,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IACP,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,gBAAgB,GAAG,eAAe,CAAC;CACvD,GACA,wBAAwB,
|
|
1
|
+
{"version":3,"file":"dispatch-matrix.d.ts","sourceRoot":"","sources":["../../src/config/dispatch-matrix.ts"],"names":[],"mappings":"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"}
|