@cleocode/contracts 2026.10.12 → 2026.10.13-rc.ci.682
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/dist/attachment.d.ts +5 -2
- package/dist/attachment.d.ts.map +1 -1
- package/dist/branch-lock.d.ts +3 -0
- package/dist/branch-lock.d.ts.map +1 -1
- package/dist/branch-lock.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/dispatch/__tests__/operation-envelope-snapshots.test.js +8 -0
- package/dist/dispatch/__tests__/operation-envelope-snapshots.test.js.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +84 -2
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/done-plan.d.ts +1 -1
- package/dist/done-plan.d.ts.map +1 -1
- package/dist/graph.d.ts +24 -4
- package/dist/graph.d.ts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/invariants/sync-write-invariants.d.ts.map +1 -1
- package/dist/invariants/sync-write-invariants.js +30 -4
- package/dist/invariants/sync-write-invariants.js.map +1 -1
- package/dist/lean.d.ts +34 -0
- package/dist/lean.d.ts.map +1 -0
- package/dist/lean.js +14 -0
- package/dist/lean.js.map +1 -0
- package/dist/lease-ipc/messages.d.ts +10 -10
- package/dist/ledger/index.d.ts +4 -4
- package/dist/operations/docs.d.ts +259 -6
- package/dist/operations/docs.d.ts.map +1 -1
- package/dist/operations/docs.js.map +1 -1
- package/dist/operations/worktree.d.ts +50 -0
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/project-hooks.d.ts +1 -1
- package/dist/resource-governor.d.ts +6 -0
- package/dist/resource-governor.d.ts.map +1 -1
- package/dist/resource-governor.js +6 -0
- package/dist/resource-governor.js.map +1 -1
- package/dist/templates/manifest.d.ts +1 -1
- package/dist/tools/atomic.d.ts +5 -2
- package/dist/tools/atomic.d.ts.map +1 -1
- package/dist/tools/atomic.js.map +1 -1
- package/dist/workgraph.d.ts +4 -4
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/attachment.ts +5 -2
- package/src/branch-lock.ts +4 -0
- package/src/config.ts +7 -0
- package/src/dispatch/__tests__/operation-envelope-snapshots.test.ts +8 -0
- package/src/dispatch/operations-registry.ts +89 -2
- package/src/done-plan.ts +1 -0
- package/src/graph.ts +25 -4
- package/src/index.ts +7 -0
- package/src/invariants/sync-write-invariants.ts +56 -29
- package/src/lean.ts +36 -0
- package/src/operations/docs.ts +266 -6
- package/src/operations/worktree.ts +49 -0
- package/src/resource-governor.ts +7 -0
- package/src/tools/atomic.ts +5 -2
package/src/operations/docs.ts
CHANGED
|
@@ -105,7 +105,7 @@ export type DocsType = BuiltinDocKind;
|
|
|
105
105
|
* for list/fetch wire responses).
|
|
106
106
|
*
|
|
107
107
|
* @see {@link import('../attachment.js').AttachmentMetadata} — the full domain
|
|
108
|
-
* registry row stored in
|
|
108
|
+
* registry row stored in the `attachments` table of the project `cleo.db`.
|
|
109
109
|
*/
|
|
110
110
|
export interface DocsAttachmentRow {
|
|
111
111
|
/** Attachment identifier (UUID-like string). */
|
|
@@ -172,13 +172,25 @@ export interface DocsAttachmentRow {
|
|
|
172
172
|
title?: string;
|
|
173
173
|
/** Backing blob name, e.g. `spec.md` (only populated by fetch/view envelopes, T13352). */
|
|
174
174
|
blobName?: string;
|
|
175
|
+
/**
|
|
176
|
+
* Conduit head version uid at fetch/view time (T13674) — the version the
|
|
177
|
+
* fetched body was projected from. Pass it back as `baseVersionUid` on
|
|
178
|
+
* `docs.update` so a stale base is detected and merged (or conflicted)
|
|
179
|
+
* instead of silently overwriting a concurrent writer's edit. Only
|
|
180
|
+
* populated for docs adopted into the conduit family; omitted otherwise.
|
|
181
|
+
*
|
|
182
|
+
* @task T13674
|
|
183
|
+
*/
|
|
184
|
+
headVersionUid?: string;
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
/**
|
|
178
188
|
* Supported attachment backend.
|
|
179
189
|
*
|
|
180
|
-
* - `legacy` — original file-based store (
|
|
181
|
-
*
|
|
190
|
+
* - `legacy` — original file-based byte store (`.cleo/attachments`); retired
|
|
191
|
+
* as a read/write surface in T13362, bytes migrate to the blob store
|
|
192
|
+
* (label retained for wire compatibility with older envelopes)
|
|
193
|
+
* - `llmstxt-v2` — llmtxt-backed manifest store (canonical byte store)
|
|
182
194
|
*/
|
|
183
195
|
export type AttachmentBackend = 'legacy' | 'llmstxt-v2';
|
|
184
196
|
|
|
@@ -346,6 +358,66 @@ export interface DocsFetchParams {
|
|
|
346
358
|
attachmentRef: string;
|
|
347
359
|
}
|
|
348
360
|
|
|
361
|
+
/**
|
|
362
|
+
* Advisory section-lease notice (T13356): the named section is leased by
|
|
363
|
+
* another session, so the caller's edit went through uncoordinated. Leases
|
|
364
|
+
* are advisory — this is the 409 equivalent as data, never a failure.
|
|
365
|
+
*/
|
|
366
|
+
export interface DocsSectionLeaseNotice {
|
|
367
|
+
/** The leased section the update edited. */
|
|
368
|
+
sectionId: string;
|
|
369
|
+
/** The current holder agent id. */
|
|
370
|
+
holder: string;
|
|
371
|
+
/** The current holder's session id. */
|
|
372
|
+
sessionId: string;
|
|
373
|
+
/** When the blocking lease expires without renew (ISO-8601). */
|
|
374
|
+
expiresAt: string;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* One recorded non-append concurrent section edit on the CRDT write path
|
|
379
|
+
* (T13595, surfaced T13604): the incoming edit landed as its own version
|
|
380
|
+
* row (append-only history preserves both) while the head kept the stored
|
|
381
|
+
* projection. Never invented text — a true merge is not expressible with
|
|
382
|
+
* the append-only llmtxt primitives.
|
|
383
|
+
*/
|
|
384
|
+
export interface DocsSectionConflict {
|
|
385
|
+
/** The section that could not be merged. */
|
|
386
|
+
sectionId: string;
|
|
387
|
+
/** Version row carrying the incoming (authored) edit — the loser. */
|
|
388
|
+
incomingVersionUid: string;
|
|
389
|
+
/** Projection version row the head kept — the winner. */
|
|
390
|
+
projectionVersionUid: string;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* The most recent recorded head conflict of a conduit doc (T13604), parsed
|
|
395
|
+
* from `conduit_doc_heads.last_conflict_json`.
|
|
396
|
+
*/
|
|
397
|
+
export interface DocsHeadConflictEntry {
|
|
398
|
+
/** The losing version's uid. */
|
|
399
|
+
versionUid: string;
|
|
400
|
+
/** The losing head's HLC. */
|
|
401
|
+
hlc: string;
|
|
402
|
+
/** ISO-8601 instant the conflict was recorded. */
|
|
403
|
+
recordedAt: string;
|
|
404
|
+
/** The winning head's version uid at recording time, when recorded. */
|
|
405
|
+
winnerVersionUid?: string;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Head-conflict summary surfaced on `docs.fetch` when a doc's conduit head
|
|
410
|
+
* carries recorded conflicts (T13604). The content returned is the winning
|
|
411
|
+
* (head) projection; the losing edits survive in the append-only version
|
|
412
|
+
* history.
|
|
413
|
+
*/
|
|
414
|
+
export interface DocsHeadConflictInfo {
|
|
415
|
+
/** Total recorded conflicts (`conduit_doc_heads.conflict_count`). */
|
|
416
|
+
conflictCount: number;
|
|
417
|
+
/** The most recently recorded conflict, when any. */
|
|
418
|
+
lastConflict?: DocsHeadConflictEntry;
|
|
419
|
+
}
|
|
420
|
+
|
|
349
421
|
/**
|
|
350
422
|
* Result of `docs.fetch`.
|
|
351
423
|
*/
|
|
@@ -371,6 +443,12 @@ export interface DocsFetchResult {
|
|
|
371
443
|
inlined: boolean;
|
|
372
444
|
/** Current attachment backend in use. */
|
|
373
445
|
attachmentBackend?: AttachmentBackend;
|
|
446
|
+
/**
|
|
447
|
+
* Present when the doc's conduit head carries recorded CRDT merge
|
|
448
|
+
* conflicts (T13604): the fetched content is the winning projection, and
|
|
449
|
+
* the losing edits survive in the append-only version history.
|
|
450
|
+
*/
|
|
451
|
+
headConflict?: DocsHeadConflictInfo;
|
|
374
452
|
/**
|
|
375
453
|
* `D####` brain ledger decisions linked to this ADR doc through
|
|
376
454
|
* `decision_adr_links` (T13359, spec `cleodocs-rearch-design` §4/§10,
|
|
@@ -742,6 +820,27 @@ export interface DocsUpdateParams {
|
|
|
742
820
|
allowExternal?: boolean;
|
|
743
821
|
/** Inline UTF-8 content (mutually exclusive with `file`). */
|
|
744
822
|
content?: string;
|
|
823
|
+
/**
|
|
824
|
+
* Expected base version — the conduit version uid the edit was authored
|
|
825
|
+
* against: the `metadata.headVersionUid` from the `docs.fetch` envelope the
|
|
826
|
+
* writer read (T13674). Stale-base detection: when the stored head has
|
|
827
|
+
* already moved past this base, every section is merged relative to the
|
|
828
|
+
* base — an append-shaped edit composes onto the stored state (both
|
|
829
|
+
* writers survive, `staleBaseMerged: true`) and a non-mergeable edit is
|
|
830
|
+
* recorded as a named section conflict (`sectionConflicts`); a concurrent
|
|
831
|
+
* writer's edit is never silently dropped. A declared base that does not
|
|
832
|
+
* resolve to this doc's version history is refused with
|
|
833
|
+
* `E_DOC_BASE_UNKNOWN` before any write. When omitted, the current head at
|
|
834
|
+
* invocation time is assumed — the single-writer semantics of the
|
|
835
|
+
* pre-T13674 path, safe only for callers that did not base their edit on
|
|
836
|
+
* an earlier fetch. Inline content and UTF-8 text `file` bodies both
|
|
837
|
+
* project through the section CRDT and honour the base (T13688); a
|
|
838
|
+
* declared base with a non-text `file` is refused with
|
|
839
|
+
* `E_DOC_BASE_UNSUPPORTED` before any write, never ignored.
|
|
840
|
+
*
|
|
841
|
+
* @task T13674
|
|
842
|
+
*/
|
|
843
|
+
baseVersionUid?: string;
|
|
745
844
|
/** Optional one-line summary describing the change (recorded in the audit log). */
|
|
746
845
|
message?: string;
|
|
747
846
|
/**
|
|
@@ -820,6 +919,41 @@ export interface DocsUpdateResult {
|
|
|
820
919
|
* `llmtxt` when the V2 mirror write succeeded; `legacy` otherwise.
|
|
821
920
|
*/
|
|
822
921
|
attachmentBackend?: AttachmentBackend;
|
|
922
|
+
/**
|
|
923
|
+
* Non-append concurrent section edits recorded during the CRDT projection
|
|
924
|
+
* (T13604): the incoming edit is NOT in the returned conduit head — it
|
|
925
|
+
* landed as its own version row while the head kept the stored projection.
|
|
926
|
+
* Absent when nothing conflicted. A `W_DOC_SECTION_CONFLICT` warning names
|
|
927
|
+
* the same sections.
|
|
928
|
+
*/
|
|
929
|
+
sectionConflicts?: DocsSectionConflict[];
|
|
930
|
+
/**
|
|
931
|
+
* Advisory section-lease notices from the CRDT write path (T13356): a
|
|
932
|
+
* section the update edited is leased by ANOTHER live session — the edit
|
|
933
|
+
* PROCEEDED anyway (leases are advisory: "409 is a social signal, not a
|
|
934
|
+
* hard lock", llmtxt T285). A `W_DOC_SECTION_LEASED` warning names the
|
|
935
|
+
* same sections and holders. Absent when no section was leased elsewhere.
|
|
936
|
+
*/
|
|
937
|
+
leaseNotices?: DocsSectionLeaseNotice[];
|
|
938
|
+
/**
|
|
939
|
+
* True when the update was authored against a superseded head and the
|
|
940
|
+
* section CRDT merged a concurrent writer's edit into the projection
|
|
941
|
+
* (T13674): the returned head text is the merge, not the submitted bytes.
|
|
942
|
+
* A `W_DOC_STALE_BASE` warning names the same situation and its remedy
|
|
943
|
+
* (re-fetch before the next edit). Absent when the declared base was the
|
|
944
|
+
* current head (or no base was declared).
|
|
945
|
+
*
|
|
946
|
+
* @task T13674
|
|
947
|
+
*/
|
|
948
|
+
staleBaseMerged?: boolean;
|
|
949
|
+
/**
|
|
950
|
+
* The conduit head version uid after the update (T13674) — pass it as the
|
|
951
|
+
* next update's `baseVersionUid` to chain edits without a re-fetch. Absent
|
|
952
|
+
* for docs outside the conduit family.
|
|
953
|
+
*
|
|
954
|
+
* @task T13674
|
|
955
|
+
*/
|
|
956
|
+
headVersionUid?: string;
|
|
823
957
|
}
|
|
824
958
|
|
|
825
959
|
// --------------------------------------------------------------------------
|
|
@@ -956,6 +1090,12 @@ export interface DocsDecisionLinkResult {
|
|
|
956
1090
|
export interface DocsDoctorParams {
|
|
957
1091
|
/** Execute repairs instead of producing a dry-run plan. Default false. */
|
|
958
1092
|
apply?: boolean;
|
|
1093
|
+
/**
|
|
1094
|
+
* Execute ONLY the legacy-blob-coverage backfill (T13653): mirror
|
|
1095
|
+
* hash-verified legacy bytes into the blob store so unmigrated docs
|
|
1096
|
+
* become readable again. Same backup gate as `apply`.
|
|
1097
|
+
*/
|
|
1098
|
+
repair?: boolean;
|
|
959
1099
|
/** Age threshold (days) for the `stale-drafts` diagnostic. Default 30. */
|
|
960
1100
|
olderThanDays?: number;
|
|
961
1101
|
}
|
|
@@ -973,6 +1113,7 @@ export interface DocsDoctorDiagnostic {
|
|
|
973
1113
|
| 'empty-provenance'
|
|
974
1114
|
| 'wikilinks-drift'
|
|
975
1115
|
| 'legacy-store-present'
|
|
1116
|
+
| 'legacy-blob-coverage'
|
|
976
1117
|
| 'stale-drafts';
|
|
977
1118
|
/** `error` should be fixed promptly; `info` is observational. */
|
|
978
1119
|
severity: 'info' | 'warn' | 'error';
|
|
@@ -1016,7 +1157,7 @@ export interface DocsDoctorResult {
|
|
|
1016
1157
|
olderThanDays: number;
|
|
1017
1158
|
/** Backup receipt that authorised this run (null on dry runs). */
|
|
1018
1159
|
backupReceiptPath: string | null;
|
|
1019
|
-
/** All
|
|
1160
|
+
/** All seven diagnostics, in declaration order. */
|
|
1020
1161
|
diagnostics: readonly DocsDoctorDiagnostic[];
|
|
1021
1162
|
/** Repair plan (dry run) or executed repairs (apply). */
|
|
1022
1163
|
repairs: readonly DocsDoctorRepairAction[];
|
|
@@ -1024,6 +1165,76 @@ export interface DocsDoctorResult {
|
|
|
1024
1165
|
summary: string;
|
|
1025
1166
|
}
|
|
1026
1167
|
|
|
1168
|
+
/**
|
|
1169
|
+
* Parameters for `docs.stats` — per-project adoption metrics (T13363).
|
|
1170
|
+
*
|
|
1171
|
+
* Read-only; no filtering yet. Emitted per project so the CleoDocs
|
|
1172
|
+
* re-architecture can be judged by behaviour (spec §7/§9).
|
|
1173
|
+
*
|
|
1174
|
+
* @task T13363 (Epic T13340 / Saga T13339)
|
|
1175
|
+
*/
|
|
1176
|
+
export interface DocsStatsParams {
|
|
1177
|
+
/** Reserved for future filtering; currently unused. */
|
|
1178
|
+
readonly _future?: never;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Add vs update doc activity, from the docs audit log
|
|
1183
|
+
* (`.cleo/audit/docs-audit.jsonl`).
|
|
1184
|
+
*
|
|
1185
|
+
* @task T13363
|
|
1186
|
+
*/
|
|
1187
|
+
export interface DocsAddUpdateMetrics {
|
|
1188
|
+
/** `docs.add` entries in the audit log. */
|
|
1189
|
+
readonly adds: number;
|
|
1190
|
+
/** `docs.update` entries in the audit log. */
|
|
1191
|
+
readonly updates: number;
|
|
1192
|
+
/** `adds / updates`; `null` when there are no updates (division undefined). */
|
|
1193
|
+
readonly ratio: number | null;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/**
|
|
1197
|
+
* Loose-markdown footprint: markdown files living outside the CleoDocs
|
|
1198
|
+
* store, the growth signal for the Council pilot (baseline ~751 axiom-app +
|
|
1199
|
+
* 1,265 admin-operations).
|
|
1200
|
+
*
|
|
1201
|
+
* Counted files are GIT-TRACKED `*.md` outside the store (`git ls-files`),
|
|
1202
|
+
* so the scan is gitignore-aware by construction; untracked loose files are
|
|
1203
|
+
* intentionally out of scope.
|
|
1204
|
+
*
|
|
1205
|
+
* @task T13363
|
|
1206
|
+
*/
|
|
1207
|
+
export interface LooseMarkdownMetrics {
|
|
1208
|
+
/** Number of git-tracked `*.md` files outside the store. */
|
|
1209
|
+
readonly count: number;
|
|
1210
|
+
/** Top-level directories contributing tracked loose markdown (`'(root)'`
|
|
1211
|
+
* for files at the project root). */
|
|
1212
|
+
readonly scannedDirs: readonly string[];
|
|
1213
|
+
/** Excluded directory names (dependency trees, VCS internals, the
|
|
1214
|
+
* CleoDocs store). */
|
|
1215
|
+
readonly excludedDirs: readonly string[];
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
/**
|
|
1219
|
+
* Result of `docs.stats` — per-project adoption metrics.
|
|
1220
|
+
*
|
|
1221
|
+
* @task T13363
|
|
1222
|
+
*/
|
|
1223
|
+
export interface DocsStatsResult {
|
|
1224
|
+
/** `docs.add` vs `docs.update` activity and their ratio. */
|
|
1225
|
+
readonly addUpdate: DocsAddUpdateMetrics;
|
|
1226
|
+
/** Loose-markdown count plus what was scanned/excluded. */
|
|
1227
|
+
readonly looseMarkdown: LooseMarkdownMetrics;
|
|
1228
|
+
/** Row count of the `docs_wikilinks` edge table (T11826). */
|
|
1229
|
+
readonly wikilinksEdges: number;
|
|
1230
|
+
/** Live `decision_adr_links` rows (status `linked`, T13359). */
|
|
1231
|
+
readonly decisionsLinked: number;
|
|
1232
|
+
/** ISO-8601 when the metrics were computed. */
|
|
1233
|
+
readonly generatedAt: string;
|
|
1234
|
+
/** One-line human summary. */
|
|
1235
|
+
readonly summary: string;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1027
1238
|
// ============================================================================
|
|
1028
1239
|
// Discriminated Union (DocsOps)
|
|
1029
1240
|
// ============================================================================
|
|
@@ -1049,7 +1260,54 @@ export type DocsOps =
|
|
|
1049
1260
|
| { op: 'docs.supersede'; params: DocsSupersedeParams; result: DocsSupersedeResult }
|
|
1050
1261
|
| { op: 'docs.link-decision'; params: DocsDecisionLinkParams; result: DocsDecisionLinkResult }
|
|
1051
1262
|
| { op: 'docs.unlink-decision'; params: DocsDecisionLinkParams; result: DocsDecisionLinkResult }
|
|
1052
|
-
| { op: 'docs.doctor'; params: DocsDoctorParams; result: DocsDoctorResult }
|
|
1263
|
+
| { op: 'docs.doctor'; params: DocsDoctorParams; result: DocsDoctorResult }
|
|
1264
|
+
| { op: 'docs.migrate'; params: DocsMigrateParams; result: DocsMigrateResult }
|
|
1265
|
+
| { op: 'docs.stats'; params: DocsStatsParams; result: DocsStatsResult };
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* Parameters for `docs.migrate` — the T13360 legacy docs migration (spec §5).
|
|
1269
|
+
* No params: the migration derives everything from the legacy store state.
|
|
1270
|
+
*
|
|
1271
|
+
* @task T13360 (Epic T13340 / Saga T13339)
|
|
1272
|
+
*/
|
|
1273
|
+
export interface DocsMigrateParams {
|
|
1274
|
+
/** Reserved for future options; currently unused. */
|
|
1275
|
+
readonly _future?: never;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* Result of `docs.migrate` — the honest legacy docs import (T13360). The
|
|
1280
|
+
* migration runs inside the T13448 safety harness; `backupId`/`transaction`
|
|
1281
|
+
* expose the harness receipt so operators can audit (or undo) the run.
|
|
1282
|
+
*
|
|
1283
|
+
* @task T13360
|
|
1284
|
+
*/
|
|
1285
|
+
export interface DocsMigrateResult {
|
|
1286
|
+
/** Harness outcome: completed, or halted/refused (with `failure`). */
|
|
1287
|
+
readonly status: 'completed' | 'halted' | 'refused';
|
|
1288
|
+
/** Docs whose bytes were content-captured into the re-keyed store. */
|
|
1289
|
+
readonly captured: number;
|
|
1290
|
+
/** Dangling-pointer docs recorded in the migration ledger (AC3). */
|
|
1291
|
+
readonly dangling: number;
|
|
1292
|
+
/** Docs already migrated by an earlier run (idempotency, AC4). */
|
|
1293
|
+
readonly skipped: number;
|
|
1294
|
+
/**
|
|
1295
|
+
* Legacy slugs that already exist natively in `conduit_attachments` — the
|
|
1296
|
+
* migration never clobbers a native doc; counted explicitly so the
|
|
1297
|
+
* operator can reconcile them (T13633).
|
|
1298
|
+
*/
|
|
1299
|
+
readonly nativeConflicts: number;
|
|
1300
|
+
/** History rows imported across all captured docs. */
|
|
1301
|
+
readonly versionsImported: number;
|
|
1302
|
+
/** First failure when halted/refused. */
|
|
1303
|
+
readonly failure: string | null;
|
|
1304
|
+
/** The harness pre-step backup id (null only when the backup itself failed). */
|
|
1305
|
+
readonly backupId: string | null;
|
|
1306
|
+
/** Harness transaction outcome for the step. */
|
|
1307
|
+
readonly transaction: 'committed' | 'rolled-back' | 'none';
|
|
1308
|
+
/** One-line human summary. */
|
|
1309
|
+
readonly summary: string;
|
|
1310
|
+
}
|
|
1053
1311
|
|
|
1054
1312
|
/**
|
|
1055
1313
|
* Enumeration of all docs domain operation names.
|
|
@@ -1069,4 +1327,6 @@ export type DocsOp =
|
|
|
1069
1327
|
| 'docs.supersede'
|
|
1070
1328
|
| 'docs.link-decision'
|
|
1071
1329
|
| 'docs.unlink-decision'
|
|
1072
|
-
| 'docs.doctor'
|
|
1330
|
+
| 'docs.doctor'
|
|
1331
|
+
| 'docs.migrate'
|
|
1332
|
+
| 'docs.stats';
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
// Hooks framework
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
20
|
import type { HookExecutor, HookOutcome } from '../project-hooks.js';
|
|
21
|
+
import type { EvidenceAtom } from '../task.js';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* A declarative lifecycle hook definition for worktree events.
|
|
@@ -489,6 +490,48 @@ export interface DestroyWorktreeOptions {
|
|
|
489
490
|
* @default 'manual'
|
|
490
491
|
*/
|
|
491
492
|
reason?: string;
|
|
493
|
+
/**
|
|
494
|
+
* The task's recorded evidence atoms. An evidence file inside the worktree
|
|
495
|
+
* with no byte-identical copy at the same path under the project root keeps
|
|
496
|
+
* the worktree (T13696).
|
|
497
|
+
*/
|
|
498
|
+
evidence?: readonly EvidenceAtom[];
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Why a worktree disposal was refused (T13696). Disposal deletes the whole
|
|
503
|
+
* directory, so it is skipped while anything outside it still needs a file in it.
|
|
504
|
+
*
|
|
505
|
+
* @task T13696
|
|
506
|
+
*/
|
|
507
|
+
export interface WorktreeDisposalBlockers {
|
|
508
|
+
/** Paths in other worktrees (or the main checkout) that resolve into this worktree, e.g. a symlinked `node_modules`. */
|
|
509
|
+
dependents: string[];
|
|
510
|
+
/** Evidence files inside the worktree that re-validation could not find anywhere else once it is gone. */
|
|
511
|
+
evidence: string[];
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Durable record that a disposal kept a worktree (T13700), stored beside the
|
|
516
|
+
* checkout at `<worktreePath>.keep.json`. Every disposal path re-checks it:
|
|
517
|
+
* the worktree stays while any blocker remains, and the marker is removed
|
|
518
|
+
* once the dependents are gone and every evidence file has a root copy.
|
|
519
|
+
*
|
|
520
|
+
* @task T13700
|
|
521
|
+
*/
|
|
522
|
+
export interface WorktreeKeepMarker {
|
|
523
|
+
/** Task that owned the worktree, when known. */
|
|
524
|
+
taskId: string | null;
|
|
525
|
+
/** The disposal that first kept it, e.g. `complete`, `cancel`, `orphaned-merged`. */
|
|
526
|
+
reason: string;
|
|
527
|
+
/** Main checkout evidence re-validation falls back to; `null` when unknown. */
|
|
528
|
+
projectRoot: string | null;
|
|
529
|
+
/** Links from other checkouts that resolved into the worktree at the last check. */
|
|
530
|
+
dependents: string[];
|
|
531
|
+
/** Evidence files that existed only inside the worktree at the last check, with the sha256 they were verified at. */
|
|
532
|
+
evidence: Array<{ path: string; sha256: string }>;
|
|
533
|
+
/** ISO-8601 time the worktree was first kept. */
|
|
534
|
+
keptAt: string;
|
|
492
535
|
}
|
|
493
536
|
|
|
494
537
|
/**
|
|
@@ -511,6 +554,8 @@ export interface DestroyWorktreeResult {
|
|
|
511
554
|
force?: boolean;
|
|
512
555
|
/** Results of pre-remove and post-destroy hooks. */
|
|
513
556
|
hookResults?: WorktreeHookResult[];
|
|
557
|
+
/** Set when the worktree was kept because something still needs its files (T13696). */
|
|
558
|
+
kept?: WorktreeDisposalBlockers;
|
|
514
559
|
}
|
|
515
560
|
|
|
516
561
|
// ---------------------------------------------------------------------------
|
|
@@ -730,6 +775,8 @@ export interface WorktreeInfo {
|
|
|
730
775
|
* @default 'cleo-spawn'
|
|
731
776
|
*/
|
|
732
777
|
source: WorktreeSource;
|
|
778
|
+
/** Present when a disposal kept this worktree: what still needed it (T13701). */
|
|
779
|
+
kept?: WorktreeKeepMarker;
|
|
733
780
|
}
|
|
734
781
|
|
|
735
782
|
/**
|
|
@@ -909,6 +956,8 @@ export interface PrunedWorktreeOutcome {
|
|
|
909
956
|
branchDeleted: boolean;
|
|
910
957
|
/** Error message when prune failed (set only on `pruned=false` + error path). */
|
|
911
958
|
error?: string;
|
|
959
|
+
/** Set (with `pruned=false`) when the worktree was kept because something still needs its files (T13700). */
|
|
960
|
+
kept?: WorktreeDisposalBlockers;
|
|
912
961
|
}
|
|
913
962
|
|
|
914
963
|
/**
|
package/src/resource-governor.ts
CHANGED
|
@@ -74,6 +74,13 @@ export const RESOURCE_DEFERRED_CODE = 'E_RESOURCE_DEFERRED' as const;
|
|
|
74
74
|
*/
|
|
75
75
|
export const RUN_COMMAND_FAILED_CODE = 'E_COMMAND_FAILED' as const;
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* `cleo run`: a SIGINT, SIGTERM or SIGHUP reached the runner while it waited
|
|
79
|
+
* in the queue; it left the queue and started nothing. It exits 128 + the
|
|
80
|
+
* signal number. @task T13681
|
|
81
|
+
*/
|
|
82
|
+
export const RUN_INTERRUPTED_CODE = 'E_RUN_INTERRUPTED' as const;
|
|
83
|
+
|
|
77
84
|
/**
|
|
78
85
|
* `cleo run` exit code for "not admitted, nothing started"
|
|
79
86
|
* (sysexits EX_TEMPFAIL). Note a child may itself exit 75; the envelope's
|
package/src/tools/atomic.ts
CHANGED
|
@@ -106,8 +106,11 @@ export type ReadFileText = (input: ReadFileInput) => Promise<ReadFileResult>;
|
|
|
106
106
|
export interface WriteFileInput {
|
|
107
107
|
/** Absolute path to write. */
|
|
108
108
|
readonly path: string;
|
|
109
|
-
/**
|
|
110
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Content to write — UTF-8 text or raw bytes. Bytes are written verbatim
|
|
111
|
+
* (binary-safe); text is encoded as UTF-8.
|
|
112
|
+
*/
|
|
113
|
+
readonly content: string | Uint8Array;
|
|
111
114
|
/** Create parent directories if missing. Defaults to `true`. */
|
|
112
115
|
readonly createDirs?: boolean;
|
|
113
116
|
}
|