@cleocode/contracts 2026.10.18 → 2026.10.19
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 +14 -3
- package/dist/branch-lock.d.ts.map +1 -1
- package/dist/branch-lock.js +8 -3
- 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 -0
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/done-plan.d.ts +69 -0
- package/dist/done-plan.d.ts.map +1 -1
- package/dist/goal-contract.d.ts +44 -4
- package/dist/goal-contract.d.ts.map +1 -1
- package/dist/goal-contract.js +2 -2
- package/dist/goal-contract.js.map +1 -1
- package/dist/goal-runtime.d.ts +89 -0
- package/dist/goal-runtime.d.ts.map +1 -0
- package/dist/goal-runtime.js +13 -0
- package/dist/goal-runtime.js.map +1 -0
- package/dist/goal.d.ts +12 -116
- package/dist/goal.d.ts.map +1 -1
- package/dist/goal.js +9 -72
- package/dist/goal.js.map +1 -1
- package/dist/heavy-command-hook.d.ts +6 -0
- package/dist/heavy-command-hook.d.ts.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/invariants/sync-write-invariants.js +6 -5
- package/dist/invariants/sync-write-invariants.js.map +1 -1
- package/dist/operations/docs.d.ts +2 -2
- package/dist/operations/docs.d.ts.map +1 -1
- package/dist/project-hooks.d.ts +15 -2
- package/dist/project-hooks.d.ts.map +1 -1
- package/dist/project-hooks.js +8 -0
- package/dist/project-hooks.js.map +1 -1
- package/dist/release/hook-pilot.d.ts +141 -2
- package/dist/release/hook-pilot.d.ts.map +1 -1
- package/dist/release/hook-pilot.js +75 -3
- package/dist/release/hook-pilot.js.map +1 -1
- package/dist/task.d.ts +23 -0
- package/dist/task.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/branch-lock.ts +14 -3
- package/src/dispatch/operations-registry.ts +8 -0
- package/src/done-plan.ts +73 -0
- package/src/goal-contract.ts +48 -4
- package/src/goal-runtime.ts +105 -0
- package/src/goal.ts +12 -133
- package/src/heavy-command-hook.ts +9 -0
- package/src/index.ts +18 -7
- package/src/invariants/sync-write-invariants.ts +5 -5
- package/src/operations/docs.ts +3 -2
- package/src/project-hooks.ts +15 -1
- package/src/release/hook-pilot.ts +85 -3
- package/src/task.ts +23 -0
package/src/branch-lock.ts
CHANGED
|
@@ -294,6 +294,12 @@ export interface OwnerOverrideAuditRecord {
|
|
|
294
294
|
reason: string;
|
|
295
295
|
/** Process ID. */
|
|
296
296
|
pid: number;
|
|
297
|
+
/** The owner setting a set or refused set targeted (T13787). */
|
|
298
|
+
setting?: string;
|
|
299
|
+
/** The setting's value before the attempt (T13787). */
|
|
300
|
+
old_value?: number;
|
|
301
|
+
/** The value the attempt asked for, or set (T13787). */
|
|
302
|
+
new_value?: number;
|
|
297
303
|
}
|
|
298
304
|
|
|
299
305
|
/**
|
|
@@ -340,9 +346,14 @@ export const BRANCH_LOCK_ERROR_CODES = {
|
|
|
340
346
|
/** L4d: session override limit exceeded. */
|
|
341
347
|
E_OVERRIDE_RATE_LIMIT: 'E_OVERRIDE_RATE_LIMIT',
|
|
342
348
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
349
|
+
* T13790: CLEO_OWNER_OVERRIDE from a caller that is not the owner — no
|
|
350
|
+
* owner-marked session (`cleo session start … --owner-auth`), or not on the
|
|
351
|
+
* owner's own terminal.
|
|
352
|
+
*/
|
|
353
|
+
E_OVERRIDE_NOT_OWNER: 'E_OVERRIDE_NOT_OWNER',
|
|
354
|
+
/**
|
|
355
|
+
* T1501 / P0-5: per-session cap exceeded. The cap is the owner's sealed
|
|
356
|
+
* `evidence.overrideCapPerSession` (default 10, T13787); no waiver lifts it.
|
|
346
357
|
*/
|
|
347
358
|
E_OVERRIDE_CAP_EXCEEDED: 'E_OVERRIDE_CAP_EXCEEDED',
|
|
348
359
|
/**
|
|
@@ -9705,6 +9705,14 @@ export const OPERATIONS: OperationDef[] = [
|
|
|
9705
9705
|
description:
|
|
9706
9706
|
'Comma-separated task IDs forwarded as the plan scope for a task-scoped release',
|
|
9707
9707
|
},
|
|
9708
|
+
// T13825: the single release PR's plan branch.
|
|
9709
|
+
{
|
|
9710
|
+
name: 'ref',
|
|
9711
|
+
type: 'string',
|
|
9712
|
+
required: false,
|
|
9713
|
+
description:
|
|
9714
|
+
'Branch to dispatch release-prepare on (release/plan-<version>: the plan + CHANGELOG commit on top of the default branch), so the bump PR carries the plan too',
|
|
9715
|
+
},
|
|
9708
9716
|
] satisfies ParamDef[],
|
|
9709
9717
|
},
|
|
9710
9718
|
|
package/src/done-plan.ts
CHANGED
|
@@ -89,6 +89,8 @@ export interface DonePlanBlocker {
|
|
|
89
89
|
next: DoneNextStep;
|
|
90
90
|
/** Original evidence error code when the blocker wraps a validator refusal. */
|
|
91
91
|
cause?: string;
|
|
92
|
+
/** The verification gate the blocker holds back, when it is one gate's (T13795). */
|
|
93
|
+
gate?: VerificationGate;
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
/** A merged PR that cites the task. */
|
|
@@ -373,3 +375,74 @@ export interface DoneBlockedDetails {
|
|
|
373
375
|
/** The plan, for tooling. */
|
|
374
376
|
plan: DonePlan;
|
|
375
377
|
}
|
|
378
|
+
|
|
379
|
+
/** A test file a covering test-run report must run, and why. */
|
|
380
|
+
export interface OwedTestFile {
|
|
381
|
+
/** Repo-relative test file. */
|
|
382
|
+
file: string;
|
|
383
|
+
/** Why the binding requires it. */
|
|
384
|
+
reason: string;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** An affected package a covering report must run at least one test file of. */
|
|
388
|
+
export interface OwedTestPackage {
|
|
389
|
+
/** Workspace package name. */
|
|
390
|
+
name: string;
|
|
391
|
+
/** Changed itself, or depends on a changed package. */
|
|
392
|
+
reason: 'changed' | 'depends on a changed package';
|
|
393
|
+
/** Test files of this package the change adds or edits (the natural choice). */
|
|
394
|
+
changedTestFiles: string[];
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* The tests a task's change owes, as the `test-run:` binding and
|
|
399
|
+
* `cleo done --plan` enforce them (T13795).
|
|
400
|
+
*
|
|
401
|
+
* - `targeted`: a passing report of every `files` entry plus at least one test
|
|
402
|
+
* file of every `packages` entry binds (config files and typecheck-only
|
|
403
|
+
* dependents are owed their own results).
|
|
404
|
+
* - `full`: the change is workspace-wide; only `tool:test` (or `ci:<pr>`) binds.
|
|
405
|
+
* - `none`: no changed path to judge (no origin default branch, or no change).
|
|
406
|
+
*/
|
|
407
|
+
export interface TaskTestPlan {
|
|
408
|
+
/** Changed paths judged, or null when none could be read. */
|
|
409
|
+
changedPaths: string[] | null;
|
|
410
|
+
/** How the change can be tested. */
|
|
411
|
+
scope: 'targeted' | 'full' | 'none';
|
|
412
|
+
/** Why only a full run binds (`scope === 'full'`). */
|
|
413
|
+
reason?: string;
|
|
414
|
+
/** Exact test files a covering report must run. */
|
|
415
|
+
files: OwedTestFile[];
|
|
416
|
+
/** Packages a covering report must run at least one test file of. */
|
|
417
|
+
packages: OwedTestPackage[];
|
|
418
|
+
/** Affected packages with no test file at all. */
|
|
419
|
+
untestedPackages: string[];
|
|
420
|
+
/** CLEO config files the change edits, owed `tool:config-schema` instead of a test. */
|
|
421
|
+
configPaths: string[];
|
|
422
|
+
/** Typecheck-only dependent package dirs, owed a typecheck instead of a test. */
|
|
423
|
+
typecheckDirs: string[];
|
|
424
|
+
/**
|
|
425
|
+
* Whether the change has merged. A merged change is judged as `cleo complete`
|
|
426
|
+
* judges it: the task's own part of the landed change, and every test file it
|
|
427
|
+
* adds or edits owed by a test-run recorded on the default branch.
|
|
428
|
+
*/
|
|
429
|
+
merged: boolean;
|
|
430
|
+
/** Whether the task already holds a standing testsPassed gate. */
|
|
431
|
+
gatePassed: boolean;
|
|
432
|
+
/** The testsPassed tool runs `cleo done` would use. */
|
|
433
|
+
toolRuns: DonePlanToolRun[];
|
|
434
|
+
/** The testsPassed blockers `cleo done --plan` reports. */
|
|
435
|
+
blockers: DonePlanBlocker[];
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/** Result of `cleo tasks changeset <id> [--test-plan]` (T13795). */
|
|
439
|
+
export interface TaskChangeSetReport {
|
|
440
|
+
/** Task id. */
|
|
441
|
+
taskId: string;
|
|
442
|
+
/** The change set `cleo done` derives. */
|
|
443
|
+
changeSet: TaskChangeSet;
|
|
444
|
+
/** Commits of the change, oldest first. */
|
|
445
|
+
commits: string[];
|
|
446
|
+
/** The tests owed (with `--test-plan`). */
|
|
447
|
+
testPlan?: TaskTestPlan;
|
|
448
|
+
}
|
package/src/goal-contract.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* goal/v1 — the contract a goal runtime executes against, and what CLEO reads
|
|
3
3
|
* back from a run.
|
|
4
4
|
*
|
|
5
|
-
* CLEO owns the goal protocol;
|
|
5
|
+
* CLEO owns the goal protocol; CLEO Goal (`@cleocode/goal`, bin `cleo-goal`, alias `ocg`) is the goal runtime (owner
|
|
6
6
|
* decision 2026-10-16, epic T13791). The two stay separate packages and talk
|
|
7
7
|
* only through the `cleo` CLI and LAFS envelopes:
|
|
8
8
|
*
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 3. `cleo goal close` reads the outcome and records evidence for each passing
|
|
14
14
|
* criterion on the gate it demonstrates, via {@link GoalCriterion.proves}.
|
|
15
15
|
*
|
|
16
|
-
* The shapes mirror
|
|
16
|
+
* The shapes mirror CLEO Goal's `src/contract/types.ts` field for field, in CLEO Goal's
|
|
17
17
|
* snake_case YAML spelling, so one file means the same thing on both sides.
|
|
18
18
|
* The only addition is the optional per-criterion `proves` list.
|
|
19
19
|
*
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
* @task T13792
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
+
import type { GoalRuntimeStatus } from './goal-runtime.js';
|
|
35
|
+
|
|
34
36
|
/** The schema tag every goal/v1 contract carries. */
|
|
35
37
|
export const GOAL_CONTRACT_SCHEMA = 'goal/v1' as const;
|
|
36
38
|
|
|
@@ -243,9 +245,9 @@ export type GoalVerificationMode = 'host' | 'host+verifier' | 'strict';
|
|
|
243
245
|
export type GoalCleoGate = 'implemented' | 'testsPassed' | 'qaPassed';
|
|
244
246
|
|
|
245
247
|
/**
|
|
246
|
-
* A CLEO task the goal serves (
|
|
248
|
+
* A CLEO task the goal serves (CLEO Goal `CleoTaskLink`).
|
|
247
249
|
*
|
|
248
|
-
* The bare id links the task for reporting. `acs` is
|
|
250
|
+
* The bare id links the task for reporting. `acs` is CLEO Goal's older per-gate
|
|
249
251
|
* claim of which AC aliases a gate's evidence proves; per-criterion
|
|
250
252
|
* {@link GoalCriterion.proves} is the precise form and what `cleo goal draft`
|
|
251
253
|
* writes. An AC neither form claims stays open.
|
|
@@ -436,3 +438,45 @@ export interface GoalOutcome {
|
|
|
436
438
|
/** Per-criterion and per-invariant verdicts. */
|
|
437
439
|
results: GoalCriterionOutcome[];
|
|
438
440
|
}
|
|
441
|
+
|
|
442
|
+
/** A drafted goal and the CLEO tasks it serves, from its `goal.yaml` (T13821). */
|
|
443
|
+
export interface GoalDraftEntry {
|
|
444
|
+
/** Goal slug (its directory under `.opencode/goals/`). */
|
|
445
|
+
slug: string;
|
|
446
|
+
/** Contract title, when the contract parses. */
|
|
447
|
+
title: string | null;
|
|
448
|
+
/** CLEO tasks the goal serves: `cleo.tasks` plus every task a criterion proves. */
|
|
449
|
+
tasks: string[];
|
|
450
|
+
/** Why the contract could not be read, when it could not. */
|
|
451
|
+
problem?: string;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* `cleo goal status` (T13821): the drafted goals and the live run, which CLEO
|
|
456
|
+
* reads only through `cleo-goal status --json`, never the runtime's files.
|
|
457
|
+
*/
|
|
458
|
+
export interface GoalStatusReport {
|
|
459
|
+
/** Whether the CLEO Goal bin (`cleo-goal`, alias `ocg`) is installed. */
|
|
460
|
+
runtime: 'installed' | 'not-installed';
|
|
461
|
+
/** The commands that install it, when it is not installed. */
|
|
462
|
+
install?: string[];
|
|
463
|
+
/** The live run, from `cleo-goal status --json`; null when not installed. */
|
|
464
|
+
live: GoalRuntimeStatus | null;
|
|
465
|
+
/** The drafted goals (filtered to one task with `--task`). */
|
|
466
|
+
goals: GoalDraftEntry[];
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* The goal runtime (CLEO Goal) as `cleo go` finds it, and the exact next step
|
|
471
|
+
* in the current harness (T13821).
|
|
472
|
+
*/
|
|
473
|
+
export interface GoalRuntimeHandoff {
|
|
474
|
+
/** Whether the CLEO Goal bin (`cleo-goal`, then `ocg`) resolves. */
|
|
475
|
+
installed: boolean;
|
|
476
|
+
/** The resolved bin, when installed. */
|
|
477
|
+
bin?: string;
|
|
478
|
+
/** The commands that install it, when it is not installed. */
|
|
479
|
+
install?: string[];
|
|
480
|
+
/** The one next step, in plain words. */
|
|
481
|
+
next: string;
|
|
482
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire shapes of the CLEO Goal runtime bin (`@cleocode/goal`, bin `cleo-goal`,
|
|
3
|
+
* alias `ocg`) that CLEO parses. CLEO talks to the runtime only through these
|
|
4
|
+
* JSON outputs (T13791); an unknown `schemaVersion` is refused, never guessed.
|
|
5
|
+
*
|
|
6
|
+
* @task T13819
|
|
7
|
+
* @task T13820
|
|
8
|
+
* @task T13821
|
|
9
|
+
* @epic T13791
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** The only `schemaVersion` this CLEO understands for every shape below. */
|
|
13
|
+
export const GOAL_RUNTIME_SCHEMA_VERSION = 1;
|
|
14
|
+
|
|
15
|
+
/** Run state reported by `cleo-goal status --json`; `none` when no goal is live. */
|
|
16
|
+
export type GoalRuntimeRunStatus =
|
|
17
|
+
| 'running'
|
|
18
|
+
| 'waiting'
|
|
19
|
+
| 'verifying'
|
|
20
|
+
| 'paused'
|
|
21
|
+
| 'blocked'
|
|
22
|
+
| 'needs_review'
|
|
23
|
+
| 'budget_limited'
|
|
24
|
+
| 'complete'
|
|
25
|
+
| 'failed'
|
|
26
|
+
| 'aborted'
|
|
27
|
+
| 'superseded'
|
|
28
|
+
| 'none';
|
|
29
|
+
|
|
30
|
+
/** One criterion of the live goal. */
|
|
31
|
+
export interface GoalRuntimeCriterion {
|
|
32
|
+
readonly id: string;
|
|
33
|
+
readonly statement: string;
|
|
34
|
+
readonly status: string;
|
|
35
|
+
readonly essential: boolean;
|
|
36
|
+
readonly invariant: boolean;
|
|
37
|
+
readonly by: string;
|
|
38
|
+
readonly detail: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** One budget dimension (turns, tokens, time, …). */
|
|
42
|
+
export interface GoalRuntimeBudgetPart {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly used: number;
|
|
45
|
+
readonly limit: number;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* `cleo-goal status --json` stdout. The bin exits 0 whenever the project was
|
|
50
|
+
* readable, including with no goal (`goal: null`, `status: 'none'`).
|
|
51
|
+
*/
|
|
52
|
+
export interface GoalRuntimeStatus {
|
|
53
|
+
readonly schemaVersion: typeof GOAL_RUNTIME_SCHEMA_VERSION;
|
|
54
|
+
readonly goal: string | null;
|
|
55
|
+
readonly runId: string | null;
|
|
56
|
+
readonly title: string;
|
|
57
|
+
readonly status: GoalRuntimeRunStatus;
|
|
58
|
+
readonly priority?: string;
|
|
59
|
+
readonly turn: number;
|
|
60
|
+
readonly reason: string | null;
|
|
61
|
+
readonly criteria: readonly GoalRuntimeCriterion[];
|
|
62
|
+
readonly proven: number;
|
|
63
|
+
readonly total: number;
|
|
64
|
+
readonly budget: { readonly ratio: number; readonly parts: readonly GoalRuntimeBudgetPart[] };
|
|
65
|
+
readonly verdict: {
|
|
66
|
+
readonly passed: boolean;
|
|
67
|
+
readonly lines: readonly string[];
|
|
68
|
+
readonly turn: number;
|
|
69
|
+
} | null;
|
|
70
|
+
readonly blocker: {
|
|
71
|
+
readonly key: string;
|
|
72
|
+
readonly count: number;
|
|
73
|
+
readonly reason: string;
|
|
74
|
+
} | null;
|
|
75
|
+
/** Epoch milliseconds. */
|
|
76
|
+
readonly updatedAt: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* One OpenCode v2 `plugins` entry: a spec, a `[spec, options]` tuple, or a
|
|
81
|
+
* `{ package, options }` object.
|
|
82
|
+
*/
|
|
83
|
+
export type GoalRuntimePluginEntry =
|
|
84
|
+
| string
|
|
85
|
+
| readonly [string, Readonly<Record<string, unknown>>]
|
|
86
|
+
| { readonly package: string; readonly options?: Readonly<Record<string, unknown>> };
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* `cleo-goal install --project --json` stdout on exit 0. Writes only the
|
|
90
|
+
* project's `.opencode/opencode.json` (OpenCode v2 `plugins` key).
|
|
91
|
+
*/
|
|
92
|
+
export interface GoalRuntimeInstall {
|
|
93
|
+
readonly schemaVersion: typeof GOAL_RUNTIME_SCHEMA_VERSION;
|
|
94
|
+
readonly action: 'installed' | 'already-present' | 'updated' | 'dry-run';
|
|
95
|
+
readonly file: string;
|
|
96
|
+
/** The npm or git spec registered (`github:…#vX.Y.Z` until npm publish). */
|
|
97
|
+
readonly spec: string;
|
|
98
|
+
readonly plugins: readonly GoalRuntimePluginEntry[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** `cleo-goal` stdout on exit 1 (exit 2 is a usage error on stderr only). */
|
|
102
|
+
export interface GoalRuntimeError {
|
|
103
|
+
readonly schemaVersion: typeof GOAL_RUNTIME_SCHEMA_VERSION;
|
|
104
|
+
readonly error: string;
|
|
105
|
+
}
|
package/src/goal.ts
CHANGED
|
@@ -1,38 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLEO
|
|
2
|
+
* CLEO goal record contracts.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - **Hermes** — a post-turn loop with a turn budget and parse-failure
|
|
12
|
-
* auto-pause, but it still judges *fuzzy* intent against transcript text.
|
|
13
|
-
*
|
|
14
|
-
* CLEO's differentiator is the **evidence-gate-aware judge**: when a goal is to
|
|
15
|
-
* *complete a task* (`complete T123`), the judge does NOT read the transcript.
|
|
16
|
-
* It resolves the target task's actual `status` and re-uses the shipped ADR-051
|
|
17
|
-
* evidence infrastructure ({@link GateEvidenceRequirement} +
|
|
18
|
-
* `validateEvidenceForGate`) — the goal is satisfied ONLY when the task is
|
|
19
|
-
* `done` with its required gates backed by real, validated evidence atoms
|
|
20
|
-
* (commit reachable, file sha256 match, test-run hash match). Transcript text
|
|
21
|
-
* can never satisfy a task-completion goal. Fuzzy goals fall back to an
|
|
22
|
-
* injectable LLM judge (see {@link GoalJudge}) so the model is consulted only
|
|
23
|
-
* where no machine-checkable artifact exists.
|
|
24
|
-
*
|
|
25
|
-
* This module is the LEAF contract: it declares the persisted record shape
|
|
26
|
-
* ({@link GoalRecord}), the lifecycle status union ({@link GoalStatus}), the
|
|
27
|
-
* discriminated goal-kind union ({@link GoalKind}), and the judge verdict shape
|
|
28
|
-
* ({@link GoalJudgeVerdict}) that every layer (store, judge, loop, continuation,
|
|
29
|
-
* CLI) agrees on. It has ZERO runtime dependencies beyond sibling contracts.
|
|
4
|
+
* CLEO owns the goal protocol and CLEO Goal is the goal runtime (owner
|
|
5
|
+
* decision 2026-10-16, epic T13791, ADR-097 `adr-097-goal-protocol-ocg-runtime`). The
|
|
6
|
+
* protocol's portable shapes (goal/v1 contract, task link, outcome) live in
|
|
7
|
+
* `./goal-contract.ts`. This module keeps the DB-persisted per-agent goal
|
|
8
|
+
* record ({@link GoalRecord}) and its status and kind unions. CLEO's own
|
|
9
|
+
* turn-budgeted goal loop (judge, continuation builder, Stop-hook advance) was
|
|
10
|
+
* retired in T13797, with its judge and continuation contracts.
|
|
30
11
|
*
|
|
31
12
|
* @packageDocumentation
|
|
32
13
|
* @module @cleocode/contracts/goal
|
|
33
14
|
*
|
|
34
15
|
* @epic T11290 EP-CLEO-GOAL-SYSTEM
|
|
35
16
|
* @task T11376
|
|
17
|
+
* @task T13797
|
|
36
18
|
* @saga T11283 SG-COGNITIVE-SUBSTRATE
|
|
37
19
|
*/
|
|
38
20
|
|
|
@@ -81,21 +63,6 @@ export const GOAL_STATUSES: readonly GoalStatus[] = Object.freeze([
|
|
|
81
63
|
'impossible',
|
|
82
64
|
]);
|
|
83
65
|
|
|
84
|
-
/**
|
|
85
|
-
* The terminal {@link GoalStatus} values a continuation builder must NOT nudge:
|
|
86
|
-
* a satisfied/abandoned/impossible goal yields no next-turn message.
|
|
87
|
-
*
|
|
88
|
-
* `paused` is intentionally absent — a paused goal CAN be resumed, so the
|
|
89
|
-
* continuation builder still emits a nudge for it (see `buildContinuation`).
|
|
90
|
-
*
|
|
91
|
-
* @public
|
|
92
|
-
*/
|
|
93
|
-
export const GOAL_TERMINAL_STATUSES: readonly GoalStatus[] = Object.freeze([
|
|
94
|
-
'satisfied',
|
|
95
|
-
'abandoned',
|
|
96
|
-
'impossible',
|
|
97
|
-
]);
|
|
98
|
-
|
|
99
66
|
/**
|
|
100
67
|
* Discriminant tag for the {@link GoalKind} union.
|
|
101
68
|
*
|
|
@@ -125,7 +92,7 @@ export interface TaskCompletionGoal {
|
|
|
125
92
|
|
|
126
93
|
/**
|
|
127
94
|
* A goal with no machine-checkable completion artifact — satisfaction is
|
|
128
|
-
* decided by
|
|
95
|
+
* decided by an LLM judge as a fallback.
|
|
129
96
|
*
|
|
130
97
|
* The fuzzy path NEVER touches the evidence infrastructure; it exists only for
|
|
131
98
|
* intents that cannot be reduced to a task + gates (e.g. "explore the auth
|
|
@@ -207,8 +174,8 @@ export interface GoalRecord {
|
|
|
207
174
|
*/
|
|
208
175
|
readonly pausedReason: string | null;
|
|
209
176
|
/**
|
|
210
|
-
* The most recent judge verdict, persisted
|
|
211
|
-
*
|
|
177
|
+
* The most recent judge verdict, persisted with the record. `null` before
|
|
178
|
+
* the first judge.
|
|
212
179
|
*/
|
|
213
180
|
readonly lastVerdict: GoalJudgeVerdict | null;
|
|
214
181
|
/** ISO-8601 creation timestamp. */
|
|
@@ -248,82 +215,6 @@ export interface GoalJudgeVerdict {
|
|
|
248
215
|
readonly evidence?: readonly string[];
|
|
249
216
|
}
|
|
250
217
|
|
|
251
|
-
/**
|
|
252
|
-
* Injectable LLM-judge interface for {@link FuzzyGoal} evaluation.
|
|
253
|
-
*
|
|
254
|
-
* The goal judge depends on THIS interface, never on a concrete model client,
|
|
255
|
-
* so vitest can pass a deterministic mock and stay fully offline/hermetic — CI
|
|
256
|
-
* must never flake on a live model call. Production wires a real LLM-backed
|
|
257
|
-
* implementation; tests wire a stub that returns a canned verdict.
|
|
258
|
-
*
|
|
259
|
-
* @public
|
|
260
|
-
*/
|
|
261
|
-
export interface GoalJudge {
|
|
262
|
-
/**
|
|
263
|
-
* Judge a fuzzy goal from its record alone (no transcript dependency in the
|
|
264
|
-
* contract — an implementation MAY consult external context, but the
|
|
265
|
-
* interface keeps the judge a pure function of the goal for testability).
|
|
266
|
-
*
|
|
267
|
-
* @param goal - The goal record under evaluation.
|
|
268
|
-
* @returns The verdict (same shape as the evidence path).
|
|
269
|
-
*/
|
|
270
|
-
judge(goal: GoalRecord): Promise<GoalJudgeVerdict>;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* A single next-turn continuation message produced by the cache-safe builder.
|
|
275
|
-
*
|
|
276
|
-
* Critically, the role is ALWAYS `'user'`: the goal loop nudges the agent by
|
|
277
|
-
* appending a user-style message, NEVER by mutating the system prompt. A stable
|
|
278
|
-
* system-prompt prefix is what makes prompt-caching effective; rewriting it on
|
|
279
|
-
* every turn would bust the cache. See `buildContinuation` for the full
|
|
280
|
-
* prompt-cache-safety contract.
|
|
281
|
-
*
|
|
282
|
-
* @public
|
|
283
|
-
*/
|
|
284
|
-
export interface GoalContinuation {
|
|
285
|
-
/** Always `'user'` — the nudge is a user message, never a system mutation. */
|
|
286
|
-
readonly role: 'user';
|
|
287
|
-
/** The continuation text: goal intent + outstanding criteria + judge reason. */
|
|
288
|
-
readonly content: string;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Result of advancing a goal one turn through the turn-budgeted loop.
|
|
293
|
-
*
|
|
294
|
-
* @public
|
|
295
|
-
*/
|
|
296
|
-
export interface GoalAdvanceResult {
|
|
297
|
-
/** The verdict the judge returned this turn. */
|
|
298
|
-
readonly verdict: GoalJudgeVerdict;
|
|
299
|
-
/** The status the goal transitions to after this turn. */
|
|
300
|
-
readonly nextStatus: GoalStatus;
|
|
301
|
-
/** Turns left after this one. Never negative. */
|
|
302
|
-
readonly turnsRemaining: number;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Type guard: is this a {@link TaskCompletionGoal} (evidence-judged)?
|
|
307
|
-
*
|
|
308
|
-
* @param kind - A {@link GoalKind} discriminated union value.
|
|
309
|
-
* @returns `true` when the goal is judged via task status + evidence atoms.
|
|
310
|
-
* @public
|
|
311
|
-
*/
|
|
312
|
-
export function isTaskCompletionGoal(kind: GoalKind): kind is TaskCompletionGoal {
|
|
313
|
-
return kind.kind === 'task-completion';
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Type guard: is this a {@link FuzzyGoal} (LLM-judged fallback)?
|
|
318
|
-
*
|
|
319
|
-
* @param kind - A {@link GoalKind} discriminated union value.
|
|
320
|
-
* @returns `true` when the goal is judged by the injectable LLM judge.
|
|
321
|
-
* @public
|
|
322
|
-
*/
|
|
323
|
-
export function isFuzzyGoal(kind: GoalKind): kind is FuzzyGoal {
|
|
324
|
-
return kind.kind === 'fuzzy';
|
|
325
|
-
}
|
|
326
|
-
|
|
327
218
|
/**
|
|
328
219
|
* Test whether a string is a valid goal target task id (`T` + 1–7 digits).
|
|
329
220
|
*
|
|
@@ -334,15 +225,3 @@ export function isFuzzyGoal(kind: GoalKind): kind is FuzzyGoal {
|
|
|
334
225
|
export function isValidGoalTargetTaskId(value: string): boolean {
|
|
335
226
|
return GOAL_TARGET_TASK_ID_REGEX.test(value);
|
|
336
227
|
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Test whether a {@link GoalStatus} is terminal (no further turns / nudges that
|
|
340
|
-
* advance work). A terminal status yields NO continuation.
|
|
341
|
-
*
|
|
342
|
-
* @param status - A goal status.
|
|
343
|
-
* @returns `true` for `satisfied` / `abandoned` / `impossible`.
|
|
344
|
-
* @public
|
|
345
|
-
*/
|
|
346
|
-
export function isTerminalGoalStatus(status: GoalStatus): boolean {
|
|
347
|
-
return GOAL_TERMINAL_STATUSES.includes(status);
|
|
348
|
-
}
|
|
@@ -303,4 +303,13 @@ export interface HeavyHookDeliveryApi {
|
|
|
303
303
|
projectDir: string,
|
|
304
304
|
options?: HeavyHookDeliveryOptions,
|
|
305
305
|
) => HeavyHookCliProbe;
|
|
306
|
+
/**
|
|
307
|
+
* Install only the Stop dispatcher (`cleo hook stop`) for one provider,
|
|
308
|
+
* regardless of the heavy-command mode (T13820). Optional: an older
|
|
309
|
+
* adapters build lacks it. Never throws.
|
|
310
|
+
*/
|
|
311
|
+
readonly syncProjectStopDispatch?: (
|
|
312
|
+
projectDir: string,
|
|
313
|
+
provider: 'claude-code' | 'codex',
|
|
314
|
+
) => Promise<HeavyHookDeliveryOutcome>;
|
|
306
315
|
}
|
package/src/index.ts
CHANGED
|
@@ -551,7 +551,11 @@ export type {
|
|
|
551
551
|
DonePlanTypedGate,
|
|
552
552
|
DoneRecordResult,
|
|
553
553
|
DoneToolResult,
|
|
554
|
+
OwedTestFile,
|
|
555
|
+
OwedTestPackage,
|
|
554
556
|
TaskChangeSet,
|
|
557
|
+
TaskChangeSetReport,
|
|
558
|
+
TaskTestPlan,
|
|
555
559
|
} from './done-plan.js';
|
|
556
560
|
export type {
|
|
557
561
|
EngineErrorPayload,
|
|
@@ -730,9 +734,6 @@ export {
|
|
|
730
734
|
// === CLEO-native Goal System (T11376 · Epic T11290 · Saga T11283) ===
|
|
731
735
|
export type {
|
|
732
736
|
FuzzyGoal,
|
|
733
|
-
GoalAdvanceResult,
|
|
734
|
-
GoalContinuation,
|
|
735
|
-
GoalJudge,
|
|
736
737
|
GoalJudgeVerdict,
|
|
737
738
|
GoalKind,
|
|
738
739
|
GoalKindTag,
|
|
@@ -743,10 +744,6 @@ export type {
|
|
|
743
744
|
export {
|
|
744
745
|
GOAL_STATUSES,
|
|
745
746
|
GOAL_TARGET_TASK_ID_REGEX,
|
|
746
|
-
GOAL_TERMINAL_STATUSES,
|
|
747
|
-
isFuzzyGoal,
|
|
748
|
-
isTaskCompletionGoal,
|
|
749
|
-
isTerminalGoalStatus,
|
|
750
747
|
isValidGoalTargetTaskId,
|
|
751
748
|
} from './goal.js';
|
|
752
749
|
// === goal/v1 protocol: contract, task link, outcome (T13792 · Epic T13791) ===
|
|
@@ -769,12 +766,15 @@ export type {
|
|
|
769
766
|
GoalCriterion,
|
|
770
767
|
GoalCriterionOutcome,
|
|
771
768
|
GoalDiffCheck,
|
|
769
|
+
GoalDraftEntry,
|
|
772
770
|
GoalFileCheck,
|
|
773
771
|
GoalHumanCheck,
|
|
774
772
|
GoalHumanEvidence,
|
|
775
773
|
GoalOutcome,
|
|
776
774
|
GoalPathEvidence,
|
|
777
775
|
GoalPriority,
|
|
776
|
+
GoalRuntimeHandoff,
|
|
777
|
+
GoalStatusReport,
|
|
778
778
|
GoalStep,
|
|
779
779
|
GoalTaskLink,
|
|
780
780
|
GoalVerdictSource,
|
|
@@ -784,6 +784,17 @@ export type {
|
|
|
784
784
|
GoalVerifierQuote,
|
|
785
785
|
} from './goal-contract.js';
|
|
786
786
|
export { GOAL_CONTRACT_SCHEMA, GOAL_HOST_CHECK_KINDS } from './goal-contract.js';
|
|
787
|
+
// === CLEO Goal runtime bin wire shapes (T13819 / T13820 / T13821) ===
|
|
788
|
+
export type {
|
|
789
|
+
GoalRuntimeBudgetPart,
|
|
790
|
+
GoalRuntimeCriterion,
|
|
791
|
+
GoalRuntimeError,
|
|
792
|
+
GoalRuntimeInstall,
|
|
793
|
+
GoalRuntimePluginEntry,
|
|
794
|
+
GoalRuntimeRunStatus,
|
|
795
|
+
GoalRuntimeStatus,
|
|
796
|
+
} from './goal-runtime.js';
|
|
797
|
+
export { GOAL_RUNTIME_SCHEMA_VERSION } from './goal-runtime.js';
|
|
787
798
|
// === Graph Intelligence Types (T512, T529, T1862, T9145) ===
|
|
788
799
|
export type {
|
|
789
800
|
AmbiguousProvenance,
|
|
@@ -490,7 +490,6 @@ export const SYNC_WRITE_INVARIANTS: readonly SyncWriteInvariant[] = Object.freez
|
|
|
490
490
|
['status'],
|
|
491
491
|
['PB-1', 'PB-4', 'PB-7', 'P33'],
|
|
492
492
|
'an approval goes pending→decided once',
|
|
493
|
-
['tasks_playbook_approvals', 'playbook_approvals'],
|
|
494
493
|
),
|
|
495
494
|
),
|
|
496
495
|
implemented(
|
|
@@ -548,15 +547,16 @@ export const SYNC_WRITE_INVARIANTS: readonly SyncWriteInvariant[] = Object.freez
|
|
|
548
547
|
'the projection keeps the max-HLC head; a losing concurrent head is recorded (conflict_count/last_conflict_json), never silently shadowed',
|
|
549
548
|
},
|
|
550
549
|
// T13355 — the docs write path adopts a legacy doc into the conduit family
|
|
551
|
-
// once (identity shell keyed by the immutable uid)
|
|
552
|
-
//
|
|
550
|
+
// once (identity shell keyed by the immutable uid). T13586: the rule is
|
|
551
|
+
// about id minting across replicas, so it is identity-layer — the shell's
|
|
552
|
+
// uid and birth_fp derive from the legacy doc, not the adopting device.
|
|
553
553
|
{
|
|
554
554
|
id: 'docs.doc.adopt-once',
|
|
555
|
-
class: '
|
|
555
|
+
class: 'identity-layer',
|
|
556
556
|
tables: ['conduit_attachments'],
|
|
557
557
|
sites: [],
|
|
558
558
|
reason:
|
|
559
|
-
'adopting
|
|
559
|
+
'two devices adopting one legacy doc must mint one uid: the shell takes the legacy birth and sentinel facts, so (uid, birth_fp) converge and receive places the peer copy as a duplicate; a lost local write is refused loudly at the writer',
|
|
560
560
|
},
|
|
561
561
|
// T13359 (D11165) — decisions-vs-ADRs link table; the natural composite key
|
|
562
562
|
// makes identical links merge to one row, and the revoke is a one-way latch.
|
package/src/operations/docs.ts
CHANGED
|
@@ -1114,7 +1114,8 @@ export interface DocsDoctorDiagnostic {
|
|
|
1114
1114
|
| 'wikilinks-drift'
|
|
1115
1115
|
| 'legacy-store-present'
|
|
1116
1116
|
| 'legacy-blob-coverage'
|
|
1117
|
-
| 'stale-drafts'
|
|
1117
|
+
| 'stale-drafts'
|
|
1118
|
+
| 'conduit-history-gaps';
|
|
1118
1119
|
/** `error` should be fixed promptly; `info` is observational. */
|
|
1119
1120
|
severity: 'info' | 'warn' | 'error';
|
|
1120
1121
|
/** Total offenders found (may exceed `items.length`). */
|
|
@@ -1157,7 +1158,7 @@ export interface DocsDoctorResult {
|
|
|
1157
1158
|
olderThanDays: number;
|
|
1158
1159
|
/** Backup receipt that authorised this run (null on dry runs). */
|
|
1159
1160
|
backupReceiptPath: string | null;
|
|
1160
|
-
/** All
|
|
1161
|
+
/** All eight diagnostics, in declaration order. */
|
|
1161
1162
|
diagnostics: readonly DocsDoctorDiagnostic[];
|
|
1162
1163
|
/** Repair plan (dry run) or executed repairs (apply). */
|
|
1163
1164
|
repairs: readonly DocsDoctorRepairAction[];
|