@cleocode/contracts 2026.6.13 → 2026.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/__tests__/operation-def.test.js +4 -1
  2. package/dist/__tests__/operation-def.test.js.map +1 -1
  3. package/dist/__tests__/provider-def.test.d.ts +12 -0
  4. package/dist/__tests__/provider-def.test.d.ts.map +1 -0
  5. package/dist/__tests__/provider-def.test.js +84 -0
  6. package/dist/__tests__/provider-def.test.js.map +1 -0
  7. package/dist/__tests__/service-provider.test.d.ts +17 -0
  8. package/dist/__tests__/service-provider.test.d.ts.map +1 -0
  9. package/dist/__tests__/service-provider.test.js +108 -0
  10. package/dist/__tests__/service-provider.test.js.map +1 -0
  11. package/dist/boundary.d.ts +52 -0
  12. package/dist/boundary.d.ts.map +1 -1
  13. package/dist/boundary.js +23 -0
  14. package/dist/boundary.js.map +1 -1
  15. package/dist/branch-lock.d.ts +4 -0
  16. package/dist/branch-lock.d.ts.map +1 -1
  17. package/dist/branch-lock.js.map +1 -1
  18. package/dist/conduit.d.ts +171 -0
  19. package/dist/conduit.d.ts.map +1 -1
  20. package/dist/config/index.d.ts +23 -0
  21. package/dist/config/index.d.ts.map +1 -0
  22. package/dist/config/index.js +22 -0
  23. package/dist/config/index.js.map +1 -0
  24. package/dist/config.d.ts +109 -1
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts +21 -0
  27. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts.map +1 -0
  28. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js +84 -0
  29. package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js.map +1 -0
  30. package/dist/dispatch/identity.d.ts +1 -1
  31. package/dist/dispatch/identity.d.ts.map +1 -1
  32. package/dist/dispatch/identity.js +20 -0
  33. package/dist/dispatch/identity.js.map +1 -1
  34. package/dist/dispatch/operation-def.d.ts +20 -0
  35. package/dist/dispatch/operation-def.d.ts.map +1 -1
  36. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  37. package/dist/dispatch/operations-registry.js +1030 -46
  38. package/dist/dispatch/operations-registry.js.map +1 -1
  39. package/dist/index.d.ts +17 -8
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +15 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/lease-ipc/__tests__/freeze.test.js +92 -0
  44. package/dist/lease-ipc/__tests__/freeze.test.js.map +1 -1
  45. package/dist/lease-ipc/index.d.ts +2 -2
  46. package/dist/lease-ipc/index.d.ts.map +1 -1
  47. package/dist/lease-ipc/index.js +1 -1
  48. package/dist/lease-ipc/index.js.map +1 -1
  49. package/dist/lease-ipc/messages.d.ts +167 -3
  50. package/dist/lease-ipc/messages.d.ts.map +1 -1
  51. package/dist/lease-ipc/messages.js +93 -0
  52. package/dist/lease-ipc/messages.js.map +1 -1
  53. package/dist/llm/catalog-schema.d.ts +242 -0
  54. package/dist/llm/catalog-schema.d.ts.map +1 -0
  55. package/dist/llm/catalog-schema.js +153 -0
  56. package/dist/llm/catalog-schema.js.map +1 -0
  57. package/dist/llm/catalog-schema.json +139 -0
  58. package/dist/llm/index.d.ts +15 -0
  59. package/dist/llm/index.d.ts.map +1 -0
  60. package/dist/llm/index.js +14 -0
  61. package/dist/llm/index.js.map +1 -0
  62. package/dist/llm/oauth.d.ts +16 -2
  63. package/dist/llm/oauth.d.ts.map +1 -1
  64. package/dist/llm/onboarding.d.ts +126 -0
  65. package/dist/llm/onboarding.d.ts.map +1 -0
  66. package/dist/llm/onboarding.js +34 -0
  67. package/dist/llm/onboarding.js.map +1 -0
  68. package/dist/llm/provider-def.d.ts +254 -0
  69. package/dist/llm/provider-def.d.ts.map +1 -0
  70. package/dist/llm/provider-def.js +93 -0
  71. package/dist/llm/provider-def.js.map +1 -0
  72. package/dist/llm/system-resolver.d.ts +42 -0
  73. package/dist/llm/system-resolver.d.ts.map +1 -1
  74. package/dist/operations/admin.d.ts +124 -1
  75. package/dist/operations/admin.d.ts.map +1 -1
  76. package/dist/operations/entities.d.ts +110 -0
  77. package/dist/operations/entities.d.ts.map +1 -0
  78. package/dist/operations/entities.js +695 -0
  79. package/dist/operations/entities.js.map +1 -0
  80. package/dist/operations/llm.d.ts +16 -1
  81. package/dist/operations/llm.d.ts.map +1 -1
  82. package/dist/operations/output-contracts-data.d.ts.map +1 -1
  83. package/dist/operations/output-contracts-data.js +230 -0
  84. package/dist/operations/output-contracts-data.js.map +1 -1
  85. package/dist/operations/service.d.ts +68 -0
  86. package/dist/operations/service.d.ts.map +1 -0
  87. package/dist/operations/service.js +336 -0
  88. package/dist/operations/service.js.map +1 -0
  89. package/dist/operations/tasks.d.ts +109 -0
  90. package/dist/operations/tasks.d.ts.map +1 -1
  91. package/dist/operations/tasks.js.map +1 -1
  92. package/dist/operations/worktree.d.ts +11 -1
  93. package/dist/operations/worktree.d.ts.map +1 -1
  94. package/dist/playbook.d.ts +56 -0
  95. package/dist/playbook.d.ts.map +1 -1
  96. package/dist/release/plan.d.ts +5 -5
  97. package/dist/spawn.d.ts +70 -0
  98. package/dist/spawn.d.ts.map +1 -1
  99. package/dist/spawn.js +1 -0
  100. package/dist/spawn.js.map +1 -1
  101. package/dist/vault/service-provider.d.ts +343 -0
  102. package/dist/vault/service-provider.d.ts.map +1 -0
  103. package/dist/vault/service-provider.js +857 -0
  104. package/dist/vault/service-provider.js.map +1 -0
  105. package/dist/workgraph.d.ts +12 -12
  106. package/package.json +10 -2
  107. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  108. package/src/__tests__/operation-def.test.ts +6 -1
  109. package/src/__tests__/provider-def.test.ts +93 -0
  110. package/src/__tests__/service-provider.test.ts +129 -0
  111. package/src/boundary.ts +69 -0
  112. package/src/branch-lock.ts +4 -0
  113. package/src/conduit.ts +200 -0
  114. package/src/config/index.ts +35 -0
  115. package/src/config.ts +116 -1
  116. package/src/dispatch/__tests__/tasks-gateway-crud-ops.test.ts +99 -0
  117. package/src/dispatch/identity.ts +20 -0
  118. package/src/dispatch/operation-def.ts +21 -0
  119. package/src/dispatch/operations-registry.ts +1062 -36
  120. package/src/index.ts +147 -2
  121. package/src/lease-ipc/__tests__/freeze.test.ts +96 -0
  122. package/src/lease-ipc/index.ts +12 -0
  123. package/src/lease-ipc/messages.ts +117 -0
  124. package/src/llm/catalog-schema.json +139 -0
  125. package/src/llm/catalog-schema.ts +184 -0
  126. package/src/llm/index.ts +29 -0
  127. package/src/llm/oauth.ts +16 -2
  128. package/src/llm/onboarding.ts +131 -0
  129. package/src/llm/provider-def.ts +291 -0
  130. package/src/llm/system-resolver.ts +45 -0
  131. package/src/operations/admin.ts +144 -0
  132. package/src/operations/entities.ts +758 -0
  133. package/src/operations/llm.ts +16 -0
  134. package/src/operations/output-contracts-data.ts +264 -0
  135. package/src/operations/service.ts +360 -0
  136. package/src/operations/tasks.ts +119 -0
  137. package/src/operations/worktree.ts +11 -0
  138. package/src/playbook.ts +56 -0
  139. package/src/spawn.ts +79 -0
  140. package/src/vault/service-provider.ts +1137 -0
@@ -1078,6 +1078,113 @@ export interface TasksReorderDispatchResult {
1078
1078
  totalSiblings: number;
1079
1079
  }
1080
1080
 
1081
+ // ---------------------------------------------------------------------------
1082
+ // tasks.reorder-rank / tasks.bulk-move / tasks.assignee
1083
+ // (T11786 · epic T11556 · E1-GATEWAY-CRUD — bulk task mutate ops Studio's
1084
+ // interactive Kanban binds to)
1085
+ // ---------------------------------------------------------------------------
1086
+
1087
+ /**
1088
+ * Params for `tasks.reorder-rank` — explicit within-column positional ordering.
1089
+ *
1090
+ * Unlike `tasks.reorder` (which moves ONE task to a 1-based index and recomputes
1091
+ * every sibling), this op takes the FULL desired ordering of a sibling/column
1092
+ * scope as a task-ID array and writes each task's `position` to its index in the
1093
+ * array. This is the Kanban "drag a card and the whole column re-ranks" shape:
1094
+ * the client sends the new column order, the op persists it in one pass.
1095
+ *
1096
+ * @task T11786
1097
+ */
1098
+ export interface TasksReorderRankParams {
1099
+ /**
1100
+ * Ordered task IDs describing the desired top-to-bottom column order. Each
1101
+ * task's `position` is set to its (1-based) index in this array. All IDs
1102
+ * SHOULD share a sibling scope (same `parentId`); IDs not found are reported
1103
+ * in {@link TasksReorderRankResult.skipped} rather than failing the batch.
1104
+ */
1105
+ orderedIds: string[];
1106
+ }
1107
+ /**
1108
+ * Result of `tasks.reorder-rank` — within-column rank confirmation.
1109
+ *
1110
+ * @task T11786
1111
+ */
1112
+ export interface TasksReorderRankResult {
1113
+ /** Task IDs whose `position` was written, in the new top-to-bottom order. */
1114
+ ranked: string[];
1115
+ /** Task IDs from the request that did not resolve to a task (no-op for these). */
1116
+ skipped: string[];
1117
+ /** Number of tasks re-ranked (= `ranked.length`). */
1118
+ count: number;
1119
+ }
1120
+
1121
+ /**
1122
+ * Params for `tasks.bulk-move` — atomic status/stage transition for N tasks.
1123
+ *
1124
+ * Moves a set of tasks to a new `status` (and optionally `pipelineStage`) inside
1125
+ * a SINGLE DB transaction — the Kanban "select N cards, drop them in a new
1126
+ * column" shape. Either `status` or `pipelineStage` (or both) MUST be supplied;
1127
+ * an empty target is rejected. All-or-nothing: any failure rolls back every move.
1128
+ *
1129
+ * @task T11786
1130
+ */
1131
+ export interface TasksBulkMoveParams {
1132
+ /** Task IDs to move. Non-empty. */
1133
+ taskIds: string[];
1134
+ /** Target lifecycle status applied to every task. */
1135
+ status?: string;
1136
+ /** Target pipeline stage applied to every task (forward-only validation). */
1137
+ pipelineStage?: string;
1138
+ }
1139
+ /**
1140
+ * Result of `tasks.bulk-move` — atomic multi-move confirmation.
1141
+ *
1142
+ * @task T11786
1143
+ */
1144
+ export interface TasksBulkMoveResult {
1145
+ /** Task IDs successfully moved (all-or-nothing — empty only when count is 0). */
1146
+ moved: string[];
1147
+ /** The status applied, when supplied. */
1148
+ status?: string;
1149
+ /** The pipeline stage applied, when supplied. */
1150
+ pipelineStage?: string;
1151
+ /** Number of tasks moved (= `moved.length`). */
1152
+ count: number;
1153
+ }
1154
+
1155
+ /**
1156
+ * Params for `tasks.assignee` — set/clear a task's first-class assignee.
1157
+ *
1158
+ * A first-class human/owner assignee surface, DISTINCT from the agent
1159
+ * claim/unclaim lock (`tasks.claim` does a conditional atomic claim with
1160
+ * agent-lock semantics; `tasks.assignee` is a direct unconditional set/clear an
1161
+ * operator or Studio board uses). Pass `assignee: null` (or omit it) to clear.
1162
+ *
1163
+ * @task T11786
1164
+ */
1165
+ export interface TasksAssigneeParams {
1166
+ /** Task ID whose assignee is being set or cleared. */
1167
+ taskId: string;
1168
+ /**
1169
+ * The assignee to set. `null` / empty / omitted CLEARS the assignee. A
1170
+ * non-empty string assigns the task to that owner.
1171
+ */
1172
+ assignee?: string | null;
1173
+ }
1174
+ /**
1175
+ * Result of `tasks.assignee` — assignee set/clear confirmation.
1176
+ *
1177
+ * @task T11786
1178
+ */
1179
+ export interface TasksAssigneeResult {
1180
+ /** The task ID whose assignee changed. */
1181
+ taskId: string;
1182
+ /** The new assignee value (null when cleared). */
1183
+ assignee: string | null;
1184
+ /** True when an assignee was set; false when it was cleared. */
1185
+ assigned: boolean;
1186
+ }
1187
+
1081
1188
  // tasks.relates.add — relatedId is canonical; targetId kept for backward compat (T5149)
1082
1189
  export interface TasksRelatesAddParams {
1083
1190
  taskId: string;
@@ -1469,6 +1576,14 @@ export interface TasksCompleteQueryParams {
1469
1576
  * @saga T10538 (PM-Core V2 agent-trust)
1470
1577
  */
1471
1578
  cancelledChildWaiverReason?: string;
1579
+ /**
1580
+ * Reason for waiving the `E_CLEO_DEPENDENCY` gate when this task's own work
1581
+ * is done but its `depends` edges point at not-yet-terminal tasks (a stale or
1582
+ * over-specified dependency). Recorded to `.cleo/audit/depends-waiver.jsonl`.
1583
+ *
1584
+ * @task T11954 (DHQ-071)
1585
+ */
1586
+ waiveDependsReason?: string;
1472
1587
  }
1473
1588
  /**
1474
1589
  * Result of `tasks.complete` — completion confirmation with unblocked tasks.
@@ -2004,6 +2119,10 @@ export type TasksOps = {
2004
2119
  readonly restore: readonly [TasksRestoreParams, TasksRestoreResult];
2005
2120
  readonly reparent: readonly [TasksReparentQueryParams, TasksReparentDispatchResult];
2006
2121
  readonly reorder: readonly [TasksReorderQueryParams, TasksReorderDispatchResult];
2122
+ // T11786 (epic T11556) — bulk task mutate ops Studio's interactive Kanban binds to.
2123
+ readonly 'reorder-rank': readonly [TasksReorderRankParams, TasksReorderRankResult];
2124
+ readonly 'bulk-move': readonly [TasksBulkMoveParams, TasksBulkMoveResult];
2125
+ readonly assignee: readonly [TasksAssigneeParams, TasksAssigneeResult];
2007
2126
  readonly 'relates.add': readonly [TasksRelatesAddParams, TasksRelatesAddResult];
2008
2127
  readonly 'relates.add-batch': readonly [TasksRelatesAddBatchParams, TasksRelatesAddBatchResult];
2009
2128
  readonly 'relates.remove': readonly [TasksRelatesRemoveParams, TasksRelatesRemoveResult];
@@ -381,10 +381,20 @@ export interface PruneWorktreesResult {
381
381
  removed: number;
382
382
  /** Absolute paths that were removed. */
383
383
  removedPaths: string[];
384
+ /** Number of worktrees quarantined (dirty/unpushed — preserved, not deleted). */
385
+ quarantined: number;
386
+ /** Absolute paths of quarantined worktrees. */
387
+ quarantinedPaths: string[];
384
388
  /** Entries that failed to remove (with reasons). */
385
389
  errors: Array<{ path: string; reason: string }>;
386
390
  /** Whether `git worktree prune` was run. */
387
391
  gitPruneRan: boolean;
392
+ /**
393
+ * True when pruning was skipped entirely because the preserve set was empty
394
+ * or the task store was unreadable while worktrees exist (fail-closed guard,
395
+ * T11996). A structured audit warning is written to the lifecycle log.
396
+ */
397
+ skippedFailClosed?: boolean;
388
398
  }
389
399
 
390
400
  // ---------------------------------------------------------------------------
@@ -576,6 +586,7 @@ export type WorktreeLifecycleAction =
576
586
  | 'adopt'
577
587
  | 'prune'
578
588
  | 'prune-skip'
589
+ | 'quarantine'
579
590
  | 'force-unlock'
580
591
  | 'complete'
581
592
  | 'complete-skip'
package/src/playbook.ts CHANGED
@@ -58,6 +58,62 @@ export interface PlaybookAgenticNode extends PlaybookNodeBase {
58
58
  * Enforced at spawn time by composeSpawnPayload (T1261 PSYCHE E4).
59
59
  */
60
60
  context_files?: string[];
61
+ /**
62
+ * Pin this stage's LLM to a named profile from `llm.profiles` (T11759 · M4).
63
+ *
64
+ * When present, the dispatcher resolves the stage's LLM through the E9
65
+ * chokepoint (`resolveLLMForSystem`) keyed by the cantbook node identity
66
+ * (`cantbook:<playbook>#<nodeId>`) with this profile name threaded as the
67
+ * pin — so the named profile's provider/model/credential win over the
68
+ * background role default. Additive: a node without `profile`/`model`/
69
+ * `provider` resolves exactly as before.
70
+ */
71
+ profile?: string;
72
+ /**
73
+ * Pin this stage's LLM to an explicit model id (T11759 · M4).
74
+ *
75
+ * A lower-precedence escape hatch than {@link profile}: when no `profile` is
76
+ * declared the dispatcher threads this model id as the resolution hint. The
77
+ * runtime never constructs a transport from it — it is a resolution hint
78
+ * consumed by the Pi runner / model-runner downstream (Gate-13).
79
+ */
80
+ model?: string;
81
+ /**
82
+ * Pin this stage's LLM to an explicit provider transport (T11759 · M4).
83
+ *
84
+ * Paired with {@link model} as the inline escape hatch when no {@link profile}
85
+ * is declared. A resolution hint only — never used to build a client here.
86
+ */
87
+ provider?: string;
88
+ /**
89
+ * Per-step skill allowlist enforced at spawn time (T1947 · M4 cantbook
90
+ * done-gate, Gap E/F).
91
+ *
92
+ * When present, the spawned agent's effective skill set is the INTERSECTION
93
+ * of the agent's resolved skills (the Tier-0/1/2 baseline) and this list — a
94
+ * skill not in both is dropped. The allowlist can only RESTRICT the baseline,
95
+ * never expand it: a skill named here that the agent does not already carry is
96
+ * NOT added. Additive: a node without `allowed_skills` spawns with its full
97
+ * baseline skill set, exactly as before.
98
+ *
99
+ * Enforced by `composeSpawnPayload` (it intersects `resolvedAgent.skills` with
100
+ * this list). An empty set after intersection is logged as a warning and the
101
+ * spawn proceeds with no skills.
102
+ */
103
+ allowed_skills?: string[];
104
+ /**
105
+ * Per-step tool allowlist enforced at spawn time (T1947 · M4 cantbook
106
+ * done-gate, Gap E/F).
107
+ *
108
+ * When present, the spawned agent's effective tool set is the INTERSECTION of
109
+ * the agent's resolved tool baseline and this list — a tool not in both is
110
+ * dropped. Like {@link allowed_skills}, this can only RESTRICT the baseline,
111
+ * never expand it. Additive: a node without `allowed_tools` is unaffected.
112
+ *
113
+ * Enforced by `composeSpawnPayload` AFTER the thin-agent guard, so a worker
114
+ * still cannot acquire a spawn-capable tool it was never granted.
115
+ */
116
+ allowed_tools?: string[];
61
117
  }
62
118
 
63
119
  export interface PlaybookDeterministicNode extends PlaybookNodeBase {
package/src/spawn.ts CHANGED
@@ -4,8 +4,79 @@
4
4
  * @task T5240
5
5
  * @task T9214 — orchestrator-defer waiver field (W4 UX hardening)
6
6
  * @task T9215 — DelegateTaskEnvelope discriminated-union type (W1 wiring)
7
+ * @task T11998 — per-session suite containment (AgentSuiteOwnership)
7
8
  */
8
9
 
10
+ // =============================================================================
11
+ // Agent suite ownership handle (T11998 — suite containment)
12
+ // =============================================================================
13
+
14
+ /**
15
+ * Containment mode used when spawning an agent process tree.
16
+ *
17
+ * - `'systemd'` — the agent and its MCP children run inside a transient
18
+ * `systemd --user` scope unit. The scope is the kill handle.
19
+ * - `'pgid'` — the agent runs in its own POSIX process group. Negative-PID
20
+ * kill (`kill(-pgid, SIGTERM)`) reaps the whole group.
21
+ * - `'none'` — no containment (detached+unref legacy path). The janitor
22
+ * (T11995) is the only backstop.
23
+ */
24
+ export type AgentContainmentMode = 'systemd' | 'pgid' | 'none';
25
+
26
+ /**
27
+ * Ownership/cleanup handle recorded per spawned agent session.
28
+ *
29
+ * This record is stored alongside the {@link SpawnResult} so that
30
+ * `terminate()` and session-end flows can reap the entire process tree
31
+ * (including indirectly-spawned MCP grandchildren) via a single kill.
32
+ *
33
+ * ## Systemd path
34
+ * `systemctl --user stop <unitName>` stops the scope and all processes
35
+ * inside it. If the scope has already exited, use `reset-failed` to clear
36
+ * the failed-unit ledger; ESRCH / no-such-unit errors are no-ops.
37
+ *
38
+ * ## Pgid path
39
+ * `process.kill(-pgid, 'SIGTERM')` sends SIGTERM to every process in the
40
+ * group. After a grace period, `process.kill(-pgid, 'SIGKILL')` cleans
41
+ * up survivors. ESRCH is a no-op (group already gone).
42
+ *
43
+ * @task T11998
44
+ */
45
+ export interface AgentSuiteOwnership {
46
+ /**
47
+ * Containment mode in effect for this agent spawn.
48
+ *
49
+ * Determines which reap primitive to use on session end.
50
+ */
51
+ readonly mode: AgentContainmentMode;
52
+
53
+ /**
54
+ * Systemd transient scope unit name (e.g. `cleo-agent-session-T1234.scope`).
55
+ *
56
+ * Present only when `mode === 'systemd'`. Use as the argument to
57
+ * `systemctl --user stop <unitName>`.
58
+ */
59
+ readonly unitName?: string;
60
+
61
+ /**
62
+ * POSIX process-group ID of the spawned agent root process.
63
+ *
64
+ * Present only when `mode === 'pgid'`. Use as negative-PID with kill:
65
+ * `process.kill(-pgid, 'SIGTERM')`.
66
+ *
67
+ * When `mode === 'systemd'` the pgid is also populated as a fallback
68
+ * handle (e.g. if the scope unit is unavailable at reap time).
69
+ */
70
+ readonly pgid?: number;
71
+
72
+ /**
73
+ * PID of the direct child process spawned by cleo.
74
+ *
75
+ * Informational — prefer `unitName` or `pgid` for reaping.
76
+ */
77
+ readonly pid?: number;
78
+ }
79
+
9
80
  export interface AdapterSpawnProvider {
10
81
  canSpawn(): Promise<boolean>;
11
82
  spawn(context: SpawnContext): Promise<SpawnResult>;
@@ -48,6 +119,14 @@ export interface SpawnResult {
48
119
  endTime?: string;
49
120
  /** Error message when status is 'failed'. Contains details about what went wrong. */
50
121
  error?: string;
122
+ /**
123
+ * Suite containment ownership handle (T11998).
124
+ *
125
+ * Present when the spawn provider recorded containment info.
126
+ * Use this to reap the entire MCP suite tree on session end or terminate().
127
+ * Absent for legacy spawns that used detached+unref without containment.
128
+ */
129
+ ownership?: AgentSuiteOwnership;
51
130
  }
52
131
 
53
132
  // =============================================================================