@cleocode/contracts 2026.6.14 → 2026.6.17
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 +4 -0
- package/dist/branch-lock.d.ts.map +1 -1
- package/dist/branch-lock.js.map +1 -1
- package/dist/config.d.ts +107 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +41 -0
- 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/operations/llm.d.ts +1 -1
- package/dist/operations/llm.d.ts.map +1 -1
- package/dist/operations/worktree.d.ts +11 -1
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/spawn.d.ts +70 -0
- package/dist/spawn.d.ts.map +1 -1
- package/dist/spawn.js +1 -0
- package/dist/spawn.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 +4 -0
- package/src/config.ts +114 -0
- package/src/dispatch/operations-registry.ts +45 -0
- package/src/index.ts +10 -1
- package/src/operations/llm.ts +1 -0
- package/src/operations/worktree.ts +11 -0
- package/src/spawn.ts +79 -0
package/src/branch-lock.ts
CHANGED
|
@@ -102,6 +102,10 @@ export interface WorktreeCleanupResult {
|
|
|
102
102
|
removed: number;
|
|
103
103
|
/** Paths that were removed. */
|
|
104
104
|
removedPaths: string[];
|
|
105
|
+
/** Number of worktrees quarantined (dirty/unpushed — preserved, not deleted). */
|
|
106
|
+
quarantined: number;
|
|
107
|
+
/** Paths that were quarantined. */
|
|
108
|
+
quarantinedPaths: string[];
|
|
105
109
|
/** Paths that failed to remove (with reasons). */
|
|
106
110
|
errors: Array<{ path: string; reason: string }>;
|
|
107
111
|
}
|
package/src/config.ts
CHANGED
|
@@ -751,6 +751,98 @@ export interface LeadRollupConfig {
|
|
|
751
751
|
mode?: LeadRollupMode;
|
|
752
752
|
}
|
|
753
753
|
|
|
754
|
+
/**
|
|
755
|
+
* Daemon lifecycle configuration.
|
|
756
|
+
*
|
|
757
|
+
* Controls whether the postinstall hook is allowed to auto-enable and start
|
|
758
|
+
* the cleo-daemon service. When `autoStart` is `false`, postinstall NEVER
|
|
759
|
+
* enables or starts the service — even on a fresh install. This flag persists
|
|
760
|
+
* across upgrades so the operator's intent survives `npm install -g`.
|
|
761
|
+
*
|
|
762
|
+
* Configure via `~/.local/share/cleo/config.json` (global config):
|
|
763
|
+
* ```json
|
|
764
|
+
* { "daemon": { "autoStart": false } }
|
|
765
|
+
* ```
|
|
766
|
+
* Or via env var override: `CLEO_DAEMON_DISABLE=1` (per-session, non-persistent).
|
|
767
|
+
*
|
|
768
|
+
* @task T11984
|
|
769
|
+
*/
|
|
770
|
+
export interface DaemonConfig {
|
|
771
|
+
/**
|
|
772
|
+
* Whether the postinstall hook may auto-enable and start the cleo-daemon.
|
|
773
|
+
*
|
|
774
|
+
* - `true` (default): first install enables+starts; upgrade respects the
|
|
775
|
+
* current systemd/launchd enabled state.
|
|
776
|
+
* - `false`: postinstall NEVER enables or starts the daemon. The unit file
|
|
777
|
+
* is still written so the operator can activate later via
|
|
778
|
+
* `cleo daemon enable`.
|
|
779
|
+
*
|
|
780
|
+
* @defaultValue true
|
|
781
|
+
*/
|
|
782
|
+
autoStart: boolean;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// ---------------------------------------------------------------------------
|
|
786
|
+
// Resources config (T11994 · PSI + MemAvailable sensing)
|
|
787
|
+
// ---------------------------------------------------------------------------
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* PSI pressure thresholds for the ResourceMonitor.
|
|
791
|
+
*
|
|
792
|
+
* Values are percentage points (0–100) for `avg10` exponential moving averages.
|
|
793
|
+
* Defaults sit far below systemd-oomd's Fedora kill line (80%/20s on
|
|
794
|
+
* user@1000.service).
|
|
795
|
+
*
|
|
796
|
+
* @task T11994
|
|
797
|
+
*/
|
|
798
|
+
export interface ResourcesPsiConfig {
|
|
799
|
+
/**
|
|
800
|
+
* Enter `hold` state when `some avg10` exceeds this value.
|
|
801
|
+
* @defaultValue 10
|
|
802
|
+
*/
|
|
803
|
+
holdSomeAvg10?: number;
|
|
804
|
+
/**
|
|
805
|
+
* Enter `backoff` state when `some avg10` exceeds this value.
|
|
806
|
+
* @defaultValue 20
|
|
807
|
+
*/
|
|
808
|
+
backoffSomeAvg10?: number;
|
|
809
|
+
/**
|
|
810
|
+
* Enter `hold` state when `full avg10` exceeds this value.
|
|
811
|
+
* @defaultValue 5
|
|
812
|
+
*/
|
|
813
|
+
holdFullAvg10?: number;
|
|
814
|
+
/**
|
|
815
|
+
* Enter `backoff` state when `full avg10` exceeds this value.
|
|
816
|
+
* @defaultValue 10
|
|
817
|
+
*/
|
|
818
|
+
backoffFullAvg10?: number;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Resource monitor configuration.
|
|
823
|
+
*
|
|
824
|
+
* Optional block — all fields have safe defaults. Maps to the
|
|
825
|
+
* `resources.*` config namespace (Amendment 5 · T11994).
|
|
826
|
+
*
|
|
827
|
+
* @task T11994
|
|
828
|
+
*/
|
|
829
|
+
export interface ResourcesConfig {
|
|
830
|
+
/**
|
|
831
|
+
* PSI pressure thresholds (percentage points).
|
|
832
|
+
*
|
|
833
|
+
* @defaultValue undefined (monitor uses built-in defaults)
|
|
834
|
+
*/
|
|
835
|
+
psi?: ResourcesPsiConfig;
|
|
836
|
+
/**
|
|
837
|
+
* Minimum free memory headroom in MiB.
|
|
838
|
+
*
|
|
839
|
+
* Used in degraded mode (PSI absent) as the sole availability signal.
|
|
840
|
+
*
|
|
841
|
+
* @defaultValue 256
|
|
842
|
+
*/
|
|
843
|
+
headroomMb?: number;
|
|
844
|
+
}
|
|
845
|
+
|
|
754
846
|
/** CLEO project configuration (config.json). */
|
|
755
847
|
export interface CleoConfig {
|
|
756
848
|
/** Configuration schema version string. */
|
|
@@ -838,6 +930,28 @@ export interface CleoConfig {
|
|
|
838
930
|
* @saga T10377
|
|
839
931
|
*/
|
|
840
932
|
leadRollup?: LeadRollupConfig;
|
|
933
|
+
/**
|
|
934
|
+
* Daemon lifecycle settings.
|
|
935
|
+
*
|
|
936
|
+
* When absent, defaults to `{ autoStart: true }` — matching the legacy
|
|
937
|
+
* install behaviour. Set `autoStart: false` to prevent postinstall from
|
|
938
|
+
* ever enabling or starting the cleo-daemon (persistent opt-out).
|
|
939
|
+
*
|
|
940
|
+
* @defaultValue undefined (treated as { autoStart: true })
|
|
941
|
+
* @task T11984
|
|
942
|
+
*/
|
|
943
|
+
daemon?: DaemonConfig;
|
|
944
|
+
/**
|
|
945
|
+
* Resource monitor configuration — PSI pressure thresholds and memory
|
|
946
|
+
* headroom for the daemon-off governor and continuous supervisor mode.
|
|
947
|
+
*
|
|
948
|
+
* When absent, the ResourceMonitor uses built-in defaults which sit well
|
|
949
|
+
* below systemd-oomd's Fedora kill line (80%/20s on user@1000.service).
|
|
950
|
+
*
|
|
951
|
+
* @defaultValue undefined (ResourceMonitor uses built-in defaults)
|
|
952
|
+
* @task T11994
|
|
953
|
+
*/
|
|
954
|
+
resources?: ResourcesConfig;
|
|
841
955
|
}
|
|
842
956
|
|
|
843
957
|
/**
|
|
@@ -9216,6 +9216,24 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
9216
9216
|
] satisfies ParamDef[],
|
|
9217
9217
|
},
|
|
9218
9218
|
|
|
9219
|
+
// ── selfimprove query: probe (T11988 — seeded-code-regression scenario) ────────
|
|
9220
|
+
// Pure read-only op that returns `{ probe: 'ok', version: probeVersion() }`.
|
|
9221
|
+
// The `probe-helper.ts` intentionally ships with `probeVersion()` returning `2`
|
|
9222
|
+
// (should be `1`) so the seeded-code-regression scenario replay diverges from its
|
|
9223
|
+
// golden (`version: 1`) and gives the fix-gen LLM stage a real, patchable bug.
|
|
9224
|
+
{
|
|
9225
|
+
gateway: 'query',
|
|
9226
|
+
domain: 'selfimprove',
|
|
9227
|
+
operation: 'probe',
|
|
9228
|
+
description:
|
|
9229
|
+
'selfimprove.probe (query) — returns { probe: "ok", version: 1 } (health/version probe). Used by the seeded-code-regression scenario to validate the fix-gen pipeline (T11988).',
|
|
9230
|
+
tier: 2,
|
|
9231
|
+
idempotent: true,
|
|
9232
|
+
sessionRequired: false,
|
|
9233
|
+
requiredParams: [],
|
|
9234
|
+
params: [] satisfies ParamDef[],
|
|
9235
|
+
},
|
|
9236
|
+
|
|
9219
9237
|
// ── selfimprove mutate: run (T11889 / T11889-D — the self-dogfooding loop) ──
|
|
9220
9238
|
// Boots ONE sandbox → replays the named canned scenario → diffs result
|
|
9221
9239
|
// envelopes vs the golden → on a regression emits ONE leased `selfimprove_dhq`
|
|
@@ -9863,4 +9881,31 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
9863
9881
|
},
|
|
9864
9882
|
] satisfies ParamDef[],
|
|
9865
9883
|
},
|
|
9884
|
+
// T11995 — Janitor MVP: orphan process reaper + stale scope/lock/debris sweep
|
|
9885
|
+
{
|
|
9886
|
+
gateway: 'mutate',
|
|
9887
|
+
domain: 'admin',
|
|
9888
|
+
operation: 'janitor.run',
|
|
9889
|
+
description:
|
|
9890
|
+
'admin.janitor.run (mutate) — run the janitor sweep: reap orphan processes, stop dead cleo-owned scopes, reclaim stale locks, prune tmp debris',
|
|
9891
|
+
tier: 1,
|
|
9892
|
+
idempotent: true,
|
|
9893
|
+
sessionRequired: false,
|
|
9894
|
+
requiredParams: [],
|
|
9895
|
+
params: [
|
|
9896
|
+
{
|
|
9897
|
+
name: 'dryRun',
|
|
9898
|
+
type: 'boolean',
|
|
9899
|
+
required: false,
|
|
9900
|
+
description: 'Report planned actions without mutating anything.',
|
|
9901
|
+
},
|
|
9902
|
+
{
|
|
9903
|
+
name: 'gracePeriodMs',
|
|
9904
|
+
type: 'number',
|
|
9905
|
+
required: false,
|
|
9906
|
+
description:
|
|
9907
|
+
'Minimum age (ms) of an unregistered process before reap eligibility (default: 600000).',
|
|
9908
|
+
},
|
|
9909
|
+
] satisfies ParamDef[],
|
|
9910
|
+
},
|
|
9866
9911
|
];
|
package/src/index.ts
CHANGED
|
@@ -261,6 +261,7 @@ export type {
|
|
|
261
261
|
ClaudeSpawnMode,
|
|
262
262
|
CleoConfig,
|
|
263
263
|
ConfigSource,
|
|
264
|
+
DaemonConfig,
|
|
264
265
|
DateFormat,
|
|
265
266
|
DecisionsConfig,
|
|
266
267
|
DepsRequiredAt,
|
|
@@ -285,6 +286,8 @@ export type {
|
|
|
285
286
|
OutputFormat,
|
|
286
287
|
ProviderConfig,
|
|
287
288
|
ResolvedValue,
|
|
289
|
+
ResourcesConfig,
|
|
290
|
+
ResourcesPsiConfig,
|
|
288
291
|
RoleName,
|
|
289
292
|
SessionConfig,
|
|
290
293
|
SessionSummaryInput,
|
|
@@ -2146,7 +2149,13 @@ export type {
|
|
|
2146
2149
|
StatsSkillLifecycleState,
|
|
2147
2150
|
StatsSkillSourceType,
|
|
2148
2151
|
} from './skills/stats.js';
|
|
2149
|
-
export type {
|
|
2152
|
+
export type {
|
|
2153
|
+
AdapterSpawnProvider,
|
|
2154
|
+
AgentContainmentMode,
|
|
2155
|
+
AgentSuiteOwnership,
|
|
2156
|
+
SpawnContext,
|
|
2157
|
+
SpawnResult,
|
|
2158
|
+
} from './spawn.js';
|
|
2150
2159
|
// === CLEO Spawn Types (distinct from adapter spawn) ===
|
|
2151
2160
|
export type {
|
|
2152
2161
|
CAAMPSpawnOptions,
|
package/src/operations/llm.ts
CHANGED
|
@@ -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/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
|
// =============================================================================
|