@cleocode/contracts 2026.10.8 → 2026.10.9-rc.ci.676
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/branch-lock.d.ts +5 -2
- package/dist/branch-lock.d.ts.map +1 -1
- package/dist/branch-lock.js.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +7 -1
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/index.d.ts +2 -2
- 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 +10 -1
- package/dist/invariants/sync-write-invariants.js.map +1 -1
- package/dist/nexus-cloud.d.ts +19 -1
- package/dist/nexus-cloud.d.ts.map +1 -1
- package/dist/nexus-cloud.js +4 -0
- package/dist/nexus-cloud.js.map +1 -1
- package/dist/nexus-vault.d.ts +155 -1
- package/dist/nexus-vault.d.ts.map +1 -1
- package/dist/operations/nexus.d.ts +4 -0
- package/dist/operations/nexus.d.ts.map +1 -1
- package/dist/operations/nexus.js.map +1 -1
- package/dist/operations/orchestrate.d.ts +7 -0
- package/dist/operations/orchestrate.d.ts.map +1 -1
- package/dist/operations/validate.d.ts +5 -0
- package/dist/operations/validate.d.ts.map +1 -1
- package/dist/operations/worktree.d.ts +61 -0
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/project-context.d.ts +9 -0
- package/dist/project-context.d.ts.map +1 -1
- package/dist/project-hook-delivery.d.ts +137 -0
- package/dist/project-hook-delivery.d.ts.map +1 -0
- package/dist/project-hook-delivery.js +21 -0
- package/dist/project-hook-delivery.js.map +1 -0
- package/dist/project-hooks.d.ts +276 -0
- package/dist/project-hooks.d.ts.map +1 -0
- package/dist/project-hooks.js +113 -0
- package/dist/project-hooks.js.map +1 -0
- package/dist/release/channel.d.ts +1 -1
- package/dist/release/channel.d.ts.map +1 -1
- package/dist/release/hook-pilot.d.ts +179 -0
- package/dist/release/hook-pilot.d.ts.map +1 -0
- package/dist/release/hook-pilot.js +112 -0
- package/dist/release/hook-pilot.js.map +1 -0
- package/dist/release/plan.d.ts +12 -1
- package/dist/release/plan.d.ts.map +1 -1
- package/dist/release/plan.js +25 -2
- package/dist/release/plan.js.map +1 -1
- package/dist/release/plan.test.js +14 -3
- package/dist/release/plan.test.js.map +1 -1
- package/dist/row-identity.d.ts +7 -0
- package/dist/row-identity.d.ts.map +1 -1
- package/dist/task.d.ts +7 -0
- package/dist/task.d.ts.map +1 -1
- package/dist/tools/atomic.d.ts +6 -0
- package/dist/tools/atomic.d.ts.map +1 -1
- package/dist/tools/atomic.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/branch-lock.ts +5 -2
- package/src/dispatch/operations-registry.ts +7 -1
- package/src/index.ts +7 -0
- package/src/invariants/sync-write-invariants.ts +10 -1
- package/src/nexus-cloud.ts +13 -1
- package/src/nexus-vault.ts +138 -1
- package/src/operations/nexus.ts +4 -0
- package/src/operations/orchestrate.ts +7 -0
- package/src/operations/validate.ts +5 -0
- package/src/operations/worktree.ts +59 -0
- package/src/project-context.ts +9 -0
- package/src/project-hook-delivery.ts +144 -0
- package/src/project-hooks.ts +256 -0
- package/src/release/channel.ts +1 -1
- package/src/release/hook-pilot.ts +163 -0
- package/src/release/plan.test.ts +15 -3
- package/src/release/plan.ts +81 -56
- package/src/row-identity.ts +7 -0
- package/src/task.ts +7 -0
- package/src/tools/atomic.ts +8 -0
package/src/branch-lock.ts
CHANGED
|
@@ -193,8 +193,11 @@ export interface GitShimEnv {
|
|
|
193
193
|
CLEO_ALLOW_BRANCH_OPS?: '1';
|
|
194
194
|
/** Worktree root path — informational for shim error messages. */
|
|
195
195
|
CLEO_WORKTREE_ROOT?: string;
|
|
196
|
-
/**
|
|
197
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Branch protection mode. `unavailable`: strict was intended but the git
|
|
198
|
+
* shim could not be installed, so nothing enforces it (T13522).
|
|
199
|
+
*/
|
|
200
|
+
CLEO_BRANCH_PROTECTION?: 'strict' | 'permissive' | 'off' | 'unavailable';
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
/**
|
|
@@ -9428,7 +9428,7 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
9428
9428
|
name: 'channel',
|
|
9429
9429
|
type: 'string',
|
|
9430
9430
|
required: false,
|
|
9431
|
-
description: 'Release channel: latest | beta | alpha | rc',
|
|
9431
|
+
description: 'Release channel: latest | beta | alpha | rc | canary',
|
|
9432
9432
|
},
|
|
9433
9433
|
{
|
|
9434
9434
|
name: 'hotfix',
|
|
@@ -9436,6 +9436,12 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
9436
9436
|
required: false,
|
|
9437
9437
|
description: 'Mark plan as release_kind=hotfix',
|
|
9438
9438
|
},
|
|
9439
|
+
{
|
|
9440
|
+
name: 'hooksV1Promotion',
|
|
9441
|
+
type: 'boolean',
|
|
9442
|
+
required: false,
|
|
9443
|
+
description: 'Require the unified-hooks pilot for this stable promotion',
|
|
9444
|
+
},
|
|
9439
9445
|
{
|
|
9440
9446
|
name: 'dryRun',
|
|
9441
9447
|
type: 'boolean',
|
package/src/index.ts
CHANGED
|
@@ -2032,6 +2032,7 @@ export type {
|
|
|
2032
2032
|
WorktreeHookResult,
|
|
2033
2033
|
WorktreeIncludePattern,
|
|
2034
2034
|
WorktreeInfo,
|
|
2035
|
+
WorktreeInstallOutcome,
|
|
2035
2036
|
WorktreeLifecycleAction,
|
|
2036
2037
|
WorktreeLifecycleAuditEntry,
|
|
2037
2038
|
WorktreeListEntry,
|
|
@@ -3163,6 +3164,12 @@ export {
|
|
|
3163
3164
|
type CloudConflict,
|
|
3164
3165
|
type CloudConflictResolveResult,
|
|
3165
3166
|
type CloudConflictsResult,
|
|
3167
|
+
type CloudDeviceOverviewResult,
|
|
3168
|
+
type CloudDeviceOverviewRow,
|
|
3169
|
+
type CloudJournalActivityDevice,
|
|
3170
|
+
type CloudJournalActivityItem,
|
|
3171
|
+
type CloudJournalActivityResult,
|
|
3172
|
+
type CloudJournalTableOps,
|
|
3166
3173
|
type CloudLeaseReleaseResult,
|
|
3167
3174
|
type CloudPushResult,
|
|
3168
3175
|
type CloudRestoreResult,
|
|
@@ -490,7 +490,16 @@ export const SYNC_WRITE_INVARIANTS: readonly SyncWriteInvariant[] = Object.freez
|
|
|
490
490
|
{
|
|
491
491
|
id: 'identity.local-minting',
|
|
492
492
|
class: 'identity-layer',
|
|
493
|
-
|
|
493
|
+
// T13405: the counter-key re-mint after a uid collision renames these too.
|
|
494
|
+
tables: [
|
|
495
|
+
'tasks_tasks',
|
|
496
|
+
'tasks_sessions',
|
|
497
|
+
'brain_decisions',
|
|
498
|
+
'brain_sticky_notes',
|
|
499
|
+
'brain_sticky_tags',
|
|
500
|
+
'brain_page_nodes',
|
|
501
|
+
'brain_page_edges',
|
|
502
|
+
],
|
|
494
503
|
sites: [],
|
|
495
504
|
inventory: ['V12', 'B07', 'B12'],
|
|
496
505
|
reason:
|
package/src/nexus-cloud.ts
CHANGED
|
@@ -145,6 +145,10 @@ export const nexusCloudReplicaSchema = z.object({
|
|
|
145
145
|
lastSyncAt: isoTime.nullable(),
|
|
146
146
|
presence: nexusCloudPresenceSchema.nullable(),
|
|
147
147
|
presenceAt: isoTime.nullable(),
|
|
148
|
+
/** When the replica was retired (cleo-nexus T123), else null. Absent from servers older than retirement. */
|
|
149
|
+
retiredAt: isoTime.nullable().optional(),
|
|
150
|
+
/** The retired replica's named successor, else null (not retired, or retired with none). */
|
|
151
|
+
successor: z.string().nullable().optional(),
|
|
148
152
|
});
|
|
149
153
|
|
|
150
154
|
/** `DeviceCounts` (§4.1): distinct devices holding a replica. */
|
|
@@ -631,7 +635,11 @@ export interface CloudStatusSeenTxns {
|
|
|
631
635
|
export interface CloudStatusSyncStream {
|
|
632
636
|
/** Which store. */
|
|
633
637
|
readonly scope: 'project' | 'global';
|
|
634
|
-
/**
|
|
638
|
+
/**
|
|
639
|
+
* Its stream (`project:<id>`, `home:<userId>`) when known locally: from the
|
|
640
|
+
* project link, else from the store's own genesis cut or pull position
|
|
641
|
+
* (T13370); `null` before either exists.
|
|
642
|
+
*/
|
|
635
643
|
readonly stream: string | null;
|
|
636
644
|
/** The store file. */
|
|
637
645
|
readonly dbPath: string;
|
|
@@ -645,6 +653,10 @@ export interface CloudStatusSyncStream {
|
|
|
645
653
|
readonly oldestUnsealedAtMs: number | null;
|
|
646
654
|
/** The highest sealed local sequence (`_sync_txn.local_seq`), or `null` before the first seal. */
|
|
647
655
|
readonly lastSealedSeq: number | null;
|
|
656
|
+
/** The local sequence of this stream's genesis cut, or `null` before the store cut or joined it (T13370). */
|
|
657
|
+
readonly genesisCut: number | null;
|
|
658
|
+
/** The cut's genesis checkpoint is not yet confirmed stored; no segment is sent until it is (T13370). */
|
|
659
|
+
readonly genesisPending: boolean;
|
|
648
660
|
/** Captures the sealer could not read and holds aside (`_sync_quarantine`), per table. */
|
|
649
661
|
readonly quarantined: Readonly<Record<string, number>>;
|
|
650
662
|
/** Tables marked suspect until a repair re-emits them. */
|
package/src/nexus-vault.ts
CHANGED
|
@@ -220,9 +220,31 @@ export interface CloudSyncPushEnableResult {
|
|
|
220
220
|
* `enabled`: the cut was recorded and its genesis checkpoint stored; `resumed`: a cut recorded
|
|
221
221
|
* by an earlier run whose checkpoint push failed was pushed now; `already`: push was already on;
|
|
222
222
|
* `joined`: this store holds the stream's journal checkpoint another device cut, and now pushes its
|
|
223
|
-
* own writes and pulls the stream's after it, with no genesis of its own (T13312).
|
|
223
|
+
* own writes and pulls the stream's after it, with no genesis of its own (T13312). A store that
|
|
224
|
+
* never synced with the stream joins too, keeping its own rows (see `merged`, T13466).
|
|
224
225
|
*/
|
|
225
226
|
status: 'enabled' | 'resumed' | 'already' | 'joined';
|
|
227
|
+
/**
|
|
228
|
+
* A merge join (T13466): stream rows adopted here, this store's own rows emitted as its first
|
|
229
|
+
* transactions, and stream rows not placed (an unresolved reference). `overwritten` lists fields of
|
|
230
|
+
* this store's own rows whose older value took the stream's newer one (T13503); `safetyBackup` is
|
|
231
|
+
* the bundle of the store as it was before the merge. Null when the reconcile is still due
|
|
232
|
+
* (`cleo cloud sync` finishes it); absent on any other status.
|
|
233
|
+
*/
|
|
234
|
+
merged?: {
|
|
235
|
+
adopted: number;
|
|
236
|
+
emitted: number;
|
|
237
|
+
unresolved: number;
|
|
238
|
+
overwritten: Array<{ table: string; uid: string; column: string }>;
|
|
239
|
+
/**
|
|
240
|
+
* Fields of the stream's rows that took this store's newer value on every replica (T13507);
|
|
241
|
+
* column `*` is a whole row this store's newer edit restored over a stream delete (T13508).
|
|
242
|
+
*/
|
|
243
|
+
replaced: Array<{ table: string; uid: string; column: string }>;
|
|
244
|
+
/** This store's own rows a newer stream delete removed; the safety bundle holds them (T13508). */
|
|
245
|
+
deleted: Array<{ table: string; uid: string }>;
|
|
246
|
+
safetyBackup: string;
|
|
247
|
+
} | null;
|
|
226
248
|
/** The genesis cut: the highest capture seq the checkpoint carries. */
|
|
227
249
|
cut: number;
|
|
228
250
|
/** Transactions sealed before the cut, folded into the checkpoint, and rows given genesis row meta. */
|
|
@@ -427,6 +449,121 @@ export interface CloudActivityResult {
|
|
|
427
449
|
warnings: CloudWarning[];
|
|
428
450
|
}
|
|
429
451
|
|
|
452
|
+
/** Per-table op counts of one journal transaction, by op kind. */
|
|
453
|
+
export interface CloudJournalTableOps {
|
|
454
|
+
I: number;
|
|
455
|
+
U: number;
|
|
456
|
+
D: number;
|
|
457
|
+
K: number;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* One transaction another device (or this one, echoed back) wrote, as this
|
|
462
|
+
* store's journal received it (`cleo cloud activity --journal`, T13369).
|
|
463
|
+
*/
|
|
464
|
+
export interface CloudJournalActivityItem {
|
|
465
|
+
/** The transaction id, `${replicaId}:${localSeq}`. */
|
|
466
|
+
txn: string;
|
|
467
|
+
stream: string;
|
|
468
|
+
/** The segment's stream sequence number and the transaction's index in it. */
|
|
469
|
+
seq: number;
|
|
470
|
+
txnIdx: number;
|
|
471
|
+
/** The replica (store) that wrote it. */
|
|
472
|
+
replicaId: string;
|
|
473
|
+
/** The Nexus device that signed its segment. */
|
|
474
|
+
deviceId: string;
|
|
475
|
+
/** The device's name from the account's device list; `null` offline or when unknown. */
|
|
476
|
+
deviceName: string | null;
|
|
477
|
+
/** Written by a replica this machine bound. */
|
|
478
|
+
thisDevice: boolean;
|
|
479
|
+
/** The transaction's HLC. */
|
|
480
|
+
hlc: string;
|
|
481
|
+
/** When it was written: the HLC's physical time, ISO-8601. */
|
|
482
|
+
at: string;
|
|
483
|
+
/** When this store staged it, and applied it (`null` until applied). */
|
|
484
|
+
stagedAt: string;
|
|
485
|
+
appliedAt: string | null;
|
|
486
|
+
/** Inbox status: `applied`, `void`, `conflict`, `staged`, `pending`, `held-skew`, `refused-schema`. */
|
|
487
|
+
status: string;
|
|
488
|
+
/** Why it is void, held or refused, when it is. */
|
|
489
|
+
reason: string | null;
|
|
490
|
+
/**
|
|
491
|
+
* Applied as inherited history (§1.5, T13278/T13366): its replica was
|
|
492
|
+
* retired by a server-confirmed retire at a lower stream position, so the
|
|
493
|
+
* merge recorded no conflict for it. Always `false` for an unconfirmed
|
|
494
|
+
* retire or a transaction that was not applied.
|
|
495
|
+
*/
|
|
496
|
+
history: boolean;
|
|
497
|
+
/** `write`, `repair`, `retire`, … and how the writes reached the store. */
|
|
498
|
+
kind: string;
|
|
499
|
+
via: string;
|
|
500
|
+
/** The command, agent and session that wrote it, when recorded. */
|
|
501
|
+
actor: { agent?: string; session?: string; op?: string } | null;
|
|
502
|
+
/** The project the transaction is for (`null` for a global-scope txn). */
|
|
503
|
+
project: string | null;
|
|
504
|
+
/** Total ops, and op counts per table. */
|
|
505
|
+
ops: number;
|
|
506
|
+
tables: Record<string, CloudJournalTableOps>;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/** One device's share of the journal activity matching the filters. */
|
|
510
|
+
export interface CloudJournalActivityDevice {
|
|
511
|
+
deviceId: string;
|
|
512
|
+
deviceName: string | null;
|
|
513
|
+
thisDevice: boolean;
|
|
514
|
+
/** Matching transactions, and the newest one's write time (ISO-8601). */
|
|
515
|
+
txns: number;
|
|
516
|
+
lastAt: string;
|
|
517
|
+
/** The device's last presence report from the account's device list; `null` offline or when unknown. */
|
|
518
|
+
lastSeenAt: string | null;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/** `cleo cloud activity --journal`: what each device changed and when, from the local journal. */
|
|
522
|
+
export interface CloudJournalActivityResult {
|
|
523
|
+
scope: CloudVaultScope;
|
|
524
|
+
/** Newest first. */
|
|
525
|
+
items: CloudJournalActivityItem[];
|
|
526
|
+
/** Per device, over every matching transaction (not just this page). */
|
|
527
|
+
devices: CloudJournalActivityDevice[];
|
|
528
|
+
/** Pass as `--before` for the next older page; `null` at the end. */
|
|
529
|
+
nextBefore: string | null;
|
|
530
|
+
warnings: CloudWarning[];
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* One device in `cleo cloud activity --devices` (T13482): its presence, its
|
|
535
|
+
* newest journal change this store received, and its newest server event.
|
|
536
|
+
*/
|
|
537
|
+
export interface CloudDeviceOverviewRow {
|
|
538
|
+
deviceId: string;
|
|
539
|
+
/** From the account's device list; `null` offline or when unknown. */
|
|
540
|
+
deviceName: string | null;
|
|
541
|
+
thisDevice: boolean;
|
|
542
|
+
/** `active`, `signed-out` or `revoked`; `null` when not in the device list. */
|
|
543
|
+
state: string | null;
|
|
544
|
+
/** Presence reported within the freshness window; `null` offline or when unknown. */
|
|
545
|
+
online: boolean | null;
|
|
546
|
+
lastSeenAt: string | null;
|
|
547
|
+
/** Its journal transactions in this store, and the newest one; `null` when none. */
|
|
548
|
+
journal: {
|
|
549
|
+
txns: number;
|
|
550
|
+
lastAt: string;
|
|
551
|
+
/** Command (or txn kind), inbox status and tables of the newest transaction on the page read. */
|
|
552
|
+
last: { op: string; status: string; tables: string[] } | null;
|
|
553
|
+
} | null;
|
|
554
|
+
/** Its newest server event (snapshot, lease, enrolment …); `null` offline or when none. */
|
|
555
|
+
server: { at: string; action: string; target: string | null } | null;
|
|
556
|
+
/** The newest of its journal change, server event and presence. */
|
|
557
|
+
lastActivityAt: string | null;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/** `cleo cloud activity --devices`: one row per device, newest activity first (T13482). */
|
|
561
|
+
export interface CloudDeviceOverviewResult {
|
|
562
|
+
scope: CloudVaultScope;
|
|
563
|
+
devices: CloudDeviceOverviewRow[];
|
|
564
|
+
warnings: CloudWarning[];
|
|
565
|
+
}
|
|
566
|
+
|
|
430
567
|
/** One conflict an apply recorded (`cleo cloud conflicts`, T12344 PR-6). */
|
|
431
568
|
export interface CloudConflict {
|
|
432
569
|
id: number;
|
package/src/operations/nexus.ts
CHANGED
|
@@ -854,6 +854,8 @@ export interface NexusImpactParams {
|
|
|
854
854
|
why?: boolean;
|
|
855
855
|
/** Maximum reverse traversal depth (default 3, capped at 5). */
|
|
856
856
|
depth?: number;
|
|
857
|
+
/** `--no-refresh` (T13523): answer from the index as it stands. */
|
|
858
|
+
noRefresh?: boolean;
|
|
857
859
|
}
|
|
858
860
|
/** Affected symbol in impact result. */
|
|
859
861
|
export interface NexusImpactAffectedNode {
|
|
@@ -1203,6 +1205,8 @@ export interface NexusContextParams {
|
|
|
1203
1205
|
limit?: number;
|
|
1204
1206
|
/** When true, fetch source code content. */
|
|
1205
1207
|
content?: boolean;
|
|
1208
|
+
/** `--no-refresh` (T13523): answer from the index as it stands. */
|
|
1209
|
+
noRefresh?: boolean;
|
|
1206
1210
|
}
|
|
1207
1211
|
/** A single caller or callee relationship from `nexus.context`. */
|
|
1208
1212
|
export interface NexusContextRelation {
|
|
@@ -630,6 +630,13 @@ export interface OrchestrateSpawnResult {
|
|
|
630
630
|
* @task T963
|
|
631
631
|
*/
|
|
632
632
|
sessionId: string | null;
|
|
633
|
+
/**
|
|
634
|
+
* The worktree's dependency install outcome (`skipped` under `--no-install`,
|
|
635
|
+
* `deferred` when the heavy-work budget was busy, with the command the
|
|
636
|
+
* worker runs instead), or `null` without a worktree.
|
|
637
|
+
* @task T13524
|
|
638
|
+
*/
|
|
639
|
+
install?: import('./worktree.js').WorktreeInstallOutcome | null;
|
|
633
640
|
/**
|
|
634
641
|
* Legacy mirror of the prompt/protocolType/tier bundle for readers that
|
|
635
642
|
* still consume `spawnContext.*`.
|
|
@@ -228,6 +228,11 @@ export interface ValidateGateParams {
|
|
|
228
228
|
* none; a gate without a fresh cached pass refuses with `E_GATE_NOT_CACHED`.
|
|
229
229
|
*/
|
|
230
230
|
noRun?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* `--run-typed` (T13521): execute uncached typed gates during this write.
|
|
233
|
+
* Without it a write reads cached passes only (owner decision).
|
|
234
|
+
*/
|
|
235
|
+
runTyped?: boolean;
|
|
231
236
|
/**
|
|
232
237
|
* `cleo verify --run --req A,B` (T13486): run and cache only the typed gates
|
|
233
238
|
* with these REQ-IDs (comma-separated); the others are not run.
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
18
|
// Hooks framework
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
|
+
import type { HookExecutor, HookOutcome } from '../project-hooks.js';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* A declarative lifecycle hook definition for worktree events.
|
|
@@ -28,6 +29,8 @@
|
|
|
28
29
|
* @task T1161
|
|
29
30
|
*/
|
|
30
31
|
export interface WorktreeHook {
|
|
32
|
+
/** Shared hook identity when legacy wiring duplicates a tracked project definition. */
|
|
33
|
+
projectHookId?: string;
|
|
31
34
|
/** Shell command to run in the worktree dir (`/bin/sh -c` on POSIX, cmd.exe on Windows). */
|
|
32
35
|
command: string;
|
|
33
36
|
/**
|
|
@@ -239,6 +242,8 @@ export interface CreateWorktreeOptions {
|
|
|
239
242
|
reason?: 'subagent' | 'experiment' | 'parallel-wave';
|
|
240
243
|
/** Declarative hooks to run after creation. */
|
|
241
244
|
hooks?: WorktreeHook[];
|
|
245
|
+
/** Optional shared project executor injected by CLEO; never imports core into worktree. */
|
|
246
|
+
projectHookExecutor?: HookExecutor;
|
|
242
247
|
/**
|
|
243
248
|
* When true, read `.cleo/worktree-include` from the project root and apply
|
|
244
249
|
* any declared include patterns to the new worktree.
|
|
@@ -317,6 +322,50 @@ export interface CreateWorktreeOptions {
|
|
|
317
322
|
* @task T12506
|
|
318
323
|
*/
|
|
319
324
|
lockTtlMs?: number;
|
|
325
|
+
/**
|
|
326
|
+
* The git shim the caller installed for this worktree (T13522). Only when
|
|
327
|
+
* `installed` is the shim dir prepended to PATH and
|
|
328
|
+
* `CLEO_BRANCH_PROTECTION=strict` advertised; otherwise the env says
|
|
329
|
+
* `unavailable`, so nothing claims a fence that is not there.
|
|
330
|
+
*
|
|
331
|
+
* @task T13522
|
|
332
|
+
*/
|
|
333
|
+
gitShim?: { readonly dir: string; readonly installed: boolean };
|
|
334
|
+
/**
|
|
335
|
+
* Provision without installing dependencies (`--no-install`, T13524). The
|
|
336
|
+
* result's `install` says so, with the command the worker runs instead.
|
|
337
|
+
*
|
|
338
|
+
* @task T13524
|
|
339
|
+
*/
|
|
340
|
+
skipInstall?: boolean;
|
|
341
|
+
/**
|
|
342
|
+
* Admission for the dependency install (T13524): called before `pnpm install`
|
|
343
|
+
* runs; resolves to a release function once admitted, or `null` when the
|
|
344
|
+
* machine budget is busy, in which case the install is deferred to the
|
|
345
|
+
* worker rather than run outside the heavy-work queue. Absent: install
|
|
346
|
+
* unadmitted (legacy callers).
|
|
347
|
+
*
|
|
348
|
+
* @task T13524
|
|
349
|
+
*/
|
|
350
|
+
admitInstall?: () => Promise<(() => Promise<void>) | null>;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* What happened to a worktree's dependency install (T13524).
|
|
355
|
+
*
|
|
356
|
+
* @task T13524
|
|
357
|
+
*/
|
|
358
|
+
export interface WorktreeInstallOutcome {
|
|
359
|
+
/**
|
|
360
|
+
* `installed`/`failed`: it ran. `skipped`: `--no-install`. `deferred`: the
|
|
361
|
+
* machine budget was busy, so the worker installs. `not-needed`: no
|
|
362
|
+
* lockfile, already installed, or a re-attached worktree.
|
|
363
|
+
*/
|
|
364
|
+
status: 'installed' | 'failed' | 'skipped' | 'deferred' | 'not-needed';
|
|
365
|
+
/** Why, for anything but `installed`. */
|
|
366
|
+
reason?: string;
|
|
367
|
+
/** The command the worker runs when the install did not happen here. */
|
|
368
|
+
command?: string;
|
|
320
369
|
}
|
|
321
370
|
|
|
322
371
|
/**
|
|
@@ -365,6 +414,8 @@ export interface CreateWorktreeResult {
|
|
|
365
414
|
preamble: string;
|
|
366
415
|
/** Results of any post-create hooks that were executed. */
|
|
367
416
|
hookResults: WorktreeHookResult[];
|
|
417
|
+
/** Results from activated project definitions for post-create. */
|
|
418
|
+
projectHookResults?: HookOutcome[];
|
|
368
419
|
/** Include patterns that were applied (empty if none). */
|
|
369
420
|
appliedPatterns: WorktreeIncludePattern[];
|
|
370
421
|
/**
|
|
@@ -378,7 +429,15 @@ export interface CreateWorktreeResult {
|
|
|
378
429
|
failedPaths: string[];
|
|
379
430
|
/** Results of post-start hooks. */
|
|
380
431
|
hookResults: WorktreeHookResult[];
|
|
432
|
+
/** Results from activated project definitions for post-start. */
|
|
433
|
+
projectHookResults?: HookOutcome[];
|
|
381
434
|
};
|
|
435
|
+
/**
|
|
436
|
+
* The dependency install outcome (T13524).
|
|
437
|
+
*
|
|
438
|
+
* @task T13524
|
|
439
|
+
*/
|
|
440
|
+
install?: WorktreeInstallOutcome;
|
|
382
441
|
}
|
|
383
442
|
|
|
384
443
|
// ---------------------------------------------------------------------------
|
package/src/project-context.ts
CHANGED
|
@@ -97,6 +97,15 @@ export interface ProjectEvidenceContext {
|
|
|
97
97
|
* CLEO's own installed hook files are always excluded (T13135, gh#1805).
|
|
98
98
|
*/
|
|
99
99
|
scopeExcludes?: string[];
|
|
100
|
+
/**
|
|
101
|
+
* Globs of TRACKED files a harness rewrites while a run executes (a goal
|
|
102
|
+
* runtime's `run.json`, its ledger), left out of the evidence tree hash so
|
|
103
|
+
* the run cannot stale its own receipt; they stay tracked for history
|
|
104
|
+
* (T13554). Read from the default branch only. A glob that matches the
|
|
105
|
+
* project context, a `goal.yaml`, an oracle or a typed gate's input is
|
|
106
|
+
* refused (E_EVIDENCE_RUNTIME_PATH_PROTECTED). Default: none.
|
|
107
|
+
*/
|
|
108
|
+
runtimePaths?: string[];
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
/**
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/** Provider delivery contracts; runtime installers live in adapters and CAAMP. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { HookJsonValue } from './heavy-command-hook.js';
|
|
4
|
+
import type { HookInvocation } from './project-hooks.js';
|
|
5
|
+
|
|
6
|
+
/** Parsed JSON object used by surgical managed writers. */
|
|
7
|
+
export type HookConfigObject = { readonly [key: string]: HookJsonValue };
|
|
8
|
+
/** One surgical edit; undefined removes exactly the addressed node. */
|
|
9
|
+
export interface HookConfigEdit {
|
|
10
|
+
/** JSON property/index path. */
|
|
11
|
+
path: (string | number)[];
|
|
12
|
+
/** Replacement value, or undefined for removal. */
|
|
13
|
+
value?: HookJsonValue;
|
|
14
|
+
/** Append/insert an array element without replacing its siblings. */
|
|
15
|
+
insert?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Receipt authorizing management of one exact config entry. */
|
|
18
|
+
export const ProjectHookDeliveryReceiptSchema = z
|
|
19
|
+
.object({
|
|
20
|
+
schemaVersion: z.literal(1),
|
|
21
|
+
provider: z.string().min(1).max(128),
|
|
22
|
+
configPath: z.string().min(1).max(4096),
|
|
23
|
+
entries: z
|
|
24
|
+
.array(
|
|
25
|
+
z
|
|
26
|
+
.object({
|
|
27
|
+
event: z.string().min(1).max(128),
|
|
28
|
+
hash: z.string().regex(/^[a-f0-9]{64}$/),
|
|
29
|
+
command: z.string().min(1).max(8192),
|
|
30
|
+
})
|
|
31
|
+
.strict(),
|
|
32
|
+
)
|
|
33
|
+
.max(128),
|
|
34
|
+
recordedAt: z.iso.datetime(),
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
/** Machine-local source and entry ownership receipt. */
|
|
38
|
+
export type ProjectHookDeliveryReceipt = z.infer<typeof ProjectHookDeliveryReceiptSchema>;
|
|
39
|
+
/** Entry-level provenance without printing commands that may contain secrets. */
|
|
40
|
+
export interface ProjectHookEntryInspection {
|
|
41
|
+
/** Native provider event. */
|
|
42
|
+
event: string;
|
|
43
|
+
/** Index in the provider event's entry array. */
|
|
44
|
+
index: number;
|
|
45
|
+
/** Receipt proves project delivery ownership; other ownership remains unknown. */
|
|
46
|
+
owner: 'project' | 'unknown';
|
|
47
|
+
/** Generated entry is attributable only through its retained local receipt. */
|
|
48
|
+
provenance: 'cleo-receipt' | 'unknown';
|
|
49
|
+
/** Entry digest permits review without retaining its command text. */
|
|
50
|
+
hash: string;
|
|
51
|
+
/** Tracked source, only for receipt-owned project checks. */
|
|
52
|
+
source?: '.cleo/hooks.json';
|
|
53
|
+
}
|
|
54
|
+
/** Inspect/install result; a config file never proves native trust or live support. */
|
|
55
|
+
export interface ProjectHookDeliveryResult {
|
|
56
|
+
/** Harness identifier. */
|
|
57
|
+
provider: string;
|
|
58
|
+
/** Observed local binary version, when discoverable. */
|
|
59
|
+
version?: string;
|
|
60
|
+
/** Safe resolved project-local destination, absent when unsupported. */
|
|
61
|
+
configPath?: string;
|
|
62
|
+
/** Delivery state. */
|
|
63
|
+
state: 'planned' | 'current' | 'installed' | 'conflict' | 'unsupported' | 'disabled' | 'missing';
|
|
64
|
+
/** Independent capability evidence. */
|
|
65
|
+
capability: 'verified' | 'documented' | 'unverified';
|
|
66
|
+
/** Native project/definition trust is never granted by CLEO. */
|
|
67
|
+
nativeTrust: 'unverified';
|
|
68
|
+
/** Receipt-backed provenance; legacy config provenance remains unknown. */
|
|
69
|
+
provenance: 'cleo-receipt' | 'unknown';
|
|
70
|
+
/** Sanitized actionable findings. */
|
|
71
|
+
diagnostics: string[];
|
|
72
|
+
/** Reviewed team-config integration aid when automatic local delivery is ineligible. */
|
|
73
|
+
integrationSnippet?: string;
|
|
74
|
+
/** Per-entry attribution, deliberately excluding raw config command strings. */
|
|
75
|
+
entries?: ProjectHookEntryInspection[];
|
|
76
|
+
}
|
|
77
|
+
/** SDK-owned utilities injected into provider delivery without a runtime SDK dependency. */
|
|
78
|
+
export interface ProjectHookDeliveryServices {
|
|
79
|
+
/**
|
|
80
|
+
* Read bounded regular files through the canonical filesystem primitive.
|
|
81
|
+
* @remarks
|
|
82
|
+
* The caller supplies the SDK implementation, preserving special-file and racing-growth checks.
|
|
83
|
+
* @param path - Resolved file path selected by the delivery adapter.
|
|
84
|
+
* @param maxBytes - Maximum UTF-8 input size in bytes.
|
|
85
|
+
* @returns The file's text after its descriptor and allocation limit have been checked.
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const readConfiguration = (services: ProjectHookDeliveryServices) =>
|
|
89
|
+
* services.readTextFile('/repo/.codex/hooks.json', 262144);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
readTextFile(path: string, maxBytes: number): Promise<string>;
|
|
93
|
+
/**
|
|
94
|
+
* Git discovery environment with ambient repository overrides removed.
|
|
95
|
+
* @defaultValue No implicit default; the caller supplies the snapshot.
|
|
96
|
+
*/
|
|
97
|
+
gitEnvironment: Readonly<Record<string, string | undefined>>;
|
|
98
|
+
}
|
|
99
|
+
/** Explicit cold-path provider sync inputs. */
|
|
100
|
+
export interface ProjectHookDeliveryOptions {
|
|
101
|
+
/** Canonical SDK utilities supplied by the caller through the contracts port. */
|
|
102
|
+
services: ProjectHookDeliveryServices;
|
|
103
|
+
/** Checkout root validated by the core context resolver. */
|
|
104
|
+
projectRoot: string;
|
|
105
|
+
/** Per-checkout Git-private receipt directory. */
|
|
106
|
+
stateDir: string;
|
|
107
|
+
/** Canonical agent events selected from the manifest. */
|
|
108
|
+
events: string[];
|
|
109
|
+
/** Activation was inspected fresh. */
|
|
110
|
+
enabled: boolean;
|
|
111
|
+
/** No files (including lock files) may be written in dry-run mode. */
|
|
112
|
+
dryRun: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Explicit provider selection; otherwise detect project-local configuration.
|
|
115
|
+
* @defaultValue Providers detected from local configuration and installed harness binaries.
|
|
116
|
+
*/
|
|
117
|
+
providers?: string[];
|
|
118
|
+
/**
|
|
119
|
+
* Remove only receipt-owned, unmodified additions instead of synchronizing.
|
|
120
|
+
* @defaultValue false
|
|
121
|
+
*/
|
|
122
|
+
rollback?: boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Provider-normalized request awaiting checkout resolution by core. */
|
|
126
|
+
export interface ProjectHookNativeRequest {
|
|
127
|
+
/** Actual triggering directory, independent of harness-specific environment variables. */
|
|
128
|
+
cwd: string;
|
|
129
|
+
/** Provider wire protocol. */
|
|
130
|
+
provider: string;
|
|
131
|
+
/** Optional native event name from the provider input. */
|
|
132
|
+
nativeEvent?: string;
|
|
133
|
+
/** Shared input fields before Git resolves projectRoot and gitCommonDir. */
|
|
134
|
+
input: Omit<HookInvocation, 'projectRoot' | 'gitCommonDir'>;
|
|
135
|
+
}
|
|
136
|
+
/** Native stdout/stderr and adapter exit code; never an approval rewrite. */
|
|
137
|
+
export interface ProjectHookNativeResult {
|
|
138
|
+
/** Provider-format advisory output. */
|
|
139
|
+
stdout: string;
|
|
140
|
+
/** Safe current-invocation diagnostics. */
|
|
141
|
+
stderr: string;
|
|
142
|
+
/** Git verdict failure or zero for advisory/infra failure. */
|
|
143
|
+
exitCode: number;
|
|
144
|
+
}
|