@cleocode/contracts 2026.5.134 → 2026.6.0
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/__tests__/operations-registry.test.js +13 -0
- package/dist/__tests__/operations-registry.test.js.map +1 -1
- package/dist/__tests__/skill-executor-contract.test.d.ts +14 -0
- package/dist/__tests__/skill-executor-contract.test.d.ts.map +1 -0
- package/dist/__tests__/skill-executor-contract.test.js +85 -0
- package/dist/__tests__/skill-executor-contract.test.js.map +1 -0
- package/dist/backup-manifest.d.ts +1 -1
- package/dist/brain-graph.d.ts +2 -2
- package/dist/brain-graph.d.ts.map +1 -1
- package/dist/config.d.ts +71 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/db-inventory.json +4 -4
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +44 -0
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/exit-codes.d.ts +20 -1
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +19 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/migration-parity.d.ts +174 -0
- package/dist/migration-parity.d.ts.map +1 -0
- package/dist/migration-parity.js +39 -0
- package/dist/migration-parity.js.map +1 -0
- package/dist/operations/admin.d.ts +4 -2
- package/dist/operations/admin.d.ts.map +1 -1
- package/dist/operations/brain.d.ts +2 -2
- package/dist/operations/brain.d.ts.map +1 -1
- package/dist/operations/llm.d.ts +6 -3
- package/dist/operations/llm.d.ts.map +1 -1
- package/dist/operations/tasks.d.ts +10 -0
- package/dist/operations/tasks.d.ts.map +1 -1
- package/dist/operations/tasks.js.map +1 -1
- package/dist/sub-accessors.d.ts +4 -4
- package/dist/sub-accessors.d.ts.map +1 -1
- package/dist/sub-accessors.js +1 -1
- package/dist/tools/skill-executor.d.ts +156 -0
- package/dist/tools/skill-executor.d.ts.map +1 -0
- package/dist/tools/skill-executor.js +47 -0
- package/dist/tools/skill-executor.js.map +1 -0
- package/package.json +6 -2
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/__tests__/operations-registry.test.ts +14 -0
- package/src/__tests__/skill-executor-contract.test.ts +104 -0
- package/src/backup-manifest.ts +1 -1
- package/src/brain-graph.ts +2 -2
- package/src/config.ts +73 -1
- package/src/db-inventory.json +4 -4
- package/src/dispatch/operations-registry.ts +45 -0
- package/src/exit-codes.ts +20 -0
- package/src/index.ts +11 -1
- package/src/migration-parity.ts +178 -0
- package/src/operations/admin.ts +4 -2
- package/src/operations/brain.ts +2 -2
- package/src/operations/llm.ts +12 -4
- package/src/operations/tasks.ts +10 -0
- package/src/sub-accessors.ts +5 -5
- package/src/tools/skill-executor.ts +183 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `SkillExecutor` — the Dependency-Inversion (DIP) seam for the GenKit-phase
|
|
3
|
+
* skill dispatcher (P1 · T11476 · E-SKILL-EXECUTOR-CONTRACT · epic T11391).
|
|
4
|
+
*
|
|
5
|
+
* A **skill** is a multi-step capability composed from the atomic tool
|
|
6
|
+
* primitives ({@link ./atomic.js}) — read/write/search/shell/etc. The atomic
|
|
7
|
+
* tool layer is pure side-effect plumbing; the SKILLS layer is where those
|
|
8
|
+
* primitives are sequenced into a unit of agent work (run a lint, scaffold a
|
|
9
|
+
* file, summarize a tree). This module declares the ABSTRACTION the dispatcher
|
|
10
|
+
* depends on so the concrete in-process implementation
|
|
11
|
+
* (`SkillExecutorAdapter`, T11477) can be INJECTED rather than imported. That is
|
|
12
|
+
* the classic DIP move: high-level dispatch policy and low-level execution
|
|
13
|
+
* mechanism both depend on this contract, not on each other.
|
|
14
|
+
*
|
|
15
|
+
* ## Why it lives in `@cleocode/contracts`
|
|
16
|
+
*
|
|
17
|
+
* The skill dispatcher (a high-level orchestration concern) and the executor
|
|
18
|
+
* adapter (a low-level mechanism wiring an LLM/GenKit flow over the guarded
|
|
19
|
+
* tools) must agree on ONE shape without either importing the other. Putting the
|
|
20
|
+
* interface here — alongside the atomic-tool I/O shapes it builds on — lets
|
|
21
|
+
* `core`, `mcp-adapter`, `caamp`, and `cleo-os` bind to a single seam and lets
|
|
22
|
+
* tests substitute a fake executor with no runtime dependency.
|
|
23
|
+
*
|
|
24
|
+
* ## Boundary contract (T11476 acceptance)
|
|
25
|
+
*
|
|
26
|
+
* - **AC1** — `execute({ skillId, context, tools }) -> Promise<{ status, output,
|
|
27
|
+
* error }>`. The result envelope intentionally mirrors the playbook runtime's
|
|
28
|
+
* `AgentDispatcher.dispatch()` result so a `SkillExecutor` reads as an
|
|
29
|
+
* in-process `AgentDispatcher` specialization (NOT a clone of it).
|
|
30
|
+
* - **AC2** — depends ONLY on the guarded-tool surface ({@link GuardedToolSurface},
|
|
31
|
+
* itself derived purely from {@link ./atomic.js} I/O shapes) and contract-local
|
|
32
|
+
* types. ZERO `@cleocode/*` runtime coupling: the `tools` dependency is the
|
|
33
|
+
* structural shape of `@cleocode/core`'s `createToolGuard()` result, declared
|
|
34
|
+
* here so neither contracts nor the dispatcher import `core`.
|
|
35
|
+
* - **AC3** — deliberately NOT named `SessionEngine` (that collides with
|
|
36
|
+
* `core/src/sessions/`). A `SkillExecutor` is an in-process
|
|
37
|
+
* `AgentDispatcher`-shaped executor, not a session lifecycle owner.
|
|
38
|
+
*
|
|
39
|
+
* Types-only — no runtime logic (Gate 10 `contracts-purity`).
|
|
40
|
+
*
|
|
41
|
+
* @epic T11391
|
|
42
|
+
* @task T11476
|
|
43
|
+
* @saga T11387
|
|
44
|
+
* @see ./atomic.js — the tool I/O shapes this seam composes over
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
import type {
|
|
48
|
+
ExecuteShellInput,
|
|
49
|
+
ExecuteShellResult,
|
|
50
|
+
PathExistsInput,
|
|
51
|
+
PathExistsResult,
|
|
52
|
+
ReadFileInput,
|
|
53
|
+
ReadFileResult,
|
|
54
|
+
RunGitInput,
|
|
55
|
+
WriteFileInput,
|
|
56
|
+
WriteFileResult,
|
|
57
|
+
} from './atomic.js';
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Guarded tool surface — the dependency a SkillExecutor receives by injection
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The deny-first guarded primitive surface a {@link SkillExecutor} is handed to
|
|
65
|
+
* perform side-effecting work. Every method is built purely from the atomic-tool
|
|
66
|
+
* I/O shapes in {@link ./atomic.js}, so this interface carries ZERO coupling to
|
|
67
|
+
* any `@cleocode/*` runtime package.
|
|
68
|
+
*
|
|
69
|
+
* This is the contract-pure SHAPE of `@cleocode/core`'s `createToolGuard()`
|
|
70
|
+
* result (`ToolGuard` in `packages/core/src/tools/guard.ts`). It is declared
|
|
71
|
+
* here — not imported from `core` — so the skill dispatcher depends on an
|
|
72
|
+
* abstraction (DIP) and the concrete guard is injected. The `core` `ToolGuard`
|
|
73
|
+
* remains structurally assignable to this surface.
|
|
74
|
+
*
|
|
75
|
+
* @remarks Mirrors `ToolGuard` member-for-member. When a new atomic primitive is
|
|
76
|
+
* added to the guard chokepoint, add it here too so the surfaces stay in sync.
|
|
77
|
+
*/
|
|
78
|
+
export interface GuardedToolSurface {
|
|
79
|
+
/** Read a file as text through the guard. */
|
|
80
|
+
readFileText(input: ReadFileInput): Promise<ReadFileResult>;
|
|
81
|
+
/** Read + parse a JSON file through the guard. */
|
|
82
|
+
readJson<T>(path: string): Promise<T>;
|
|
83
|
+
/** Atomically write a file (tmp-then-rename) through the guard. */
|
|
84
|
+
writeFileAtomic(input: WriteFileInput): Promise<WriteFileResult>;
|
|
85
|
+
/** Test path existence + kind through the guard. */
|
|
86
|
+
pathExists(input: PathExistsInput): Promise<PathExistsResult>;
|
|
87
|
+
/** Run a command with explicit cwd/env/timeout through the guard. */
|
|
88
|
+
executeShell(input: ExecuteShellInput): Promise<ExecuteShellResult>;
|
|
89
|
+
/** Run a git subcommand through the guard. */
|
|
90
|
+
runGit(input: RunGitInput): Promise<ExecuteShellResult>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Execution I/O — input envelope + terminal result
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Terminal status of a single skill execution. Mirrors the playbook runtime's
|
|
99
|
+
* `DispatchResult.status` so a {@link SkillExecutor} envelope is structurally
|
|
100
|
+
* compatible with an `AgentDispatcher` result.
|
|
101
|
+
*/
|
|
102
|
+
export type SkillExecuteStatus = 'success' | 'failure';
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Input envelope for a single skill execution (AC1: `{ skillId, context, tools }`).
|
|
106
|
+
*
|
|
107
|
+
* The executor receives the skill identity, an opaque accumulated context, and
|
|
108
|
+
* the guarded tool surface it is permitted to use. It MUST NOT reach for
|
|
109
|
+
* ambient/global tools — all side effects flow through {@link SkillExecuteInput.tools}.
|
|
110
|
+
*/
|
|
111
|
+
export interface SkillExecuteInput {
|
|
112
|
+
/** Stable identifier of the skill to execute (registry slug / id). */
|
|
113
|
+
readonly skillId: string;
|
|
114
|
+
/**
|
|
115
|
+
* Accumulated bindings / inputs for this execution. Opaque key-value map so
|
|
116
|
+
* the contract stays decoupled from any concrete skill's parameter schema;
|
|
117
|
+
* each skill validates its own slice of this at the adapter boundary.
|
|
118
|
+
*/
|
|
119
|
+
readonly context: Readonly<Record<string, unknown>>;
|
|
120
|
+
/**
|
|
121
|
+
* The deny-first guarded tool surface the executor may use. Injected by the
|
|
122
|
+
* caller (DIP) — the executor never constructs its own guard.
|
|
123
|
+
*/
|
|
124
|
+
readonly tools: GuardedToolSurface;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Terminal result envelope of a single skill execution (AC1: `{ status, output,
|
|
129
|
+
* error }`). Mirrors the playbook runtime's `DispatchResult` shape so callers
|
|
130
|
+
* that already consume `AgentDispatcher` results can consume a `SkillExecutor`
|
|
131
|
+
* result without a wrapper.
|
|
132
|
+
*/
|
|
133
|
+
export interface SkillExecuteResult {
|
|
134
|
+
/** Whether the skill execution succeeded or failed. */
|
|
135
|
+
readonly status: SkillExecuteStatus;
|
|
136
|
+
/**
|
|
137
|
+
* Key-value pairs produced by the skill, merged into the caller's context on
|
|
138
|
+
* success. Empty (not absent) when a skill produces no bindings.
|
|
139
|
+
*/
|
|
140
|
+
readonly output: Readonly<Record<string, unknown>>;
|
|
141
|
+
/**
|
|
142
|
+
* Human-readable failure reason. Present iff
|
|
143
|
+
* `status === 'failure'`; omitted on success.
|
|
144
|
+
*/
|
|
145
|
+
readonly error?: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// The DIP seam
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Dependency-Inversion abstraction for the in-process skill executor.
|
|
154
|
+
*
|
|
155
|
+
* The skill dispatcher depends on THIS interface; the concrete
|
|
156
|
+
* `SkillExecutorAdapter` (T11477) — which wires a GenKit/LLM flow over the
|
|
157
|
+
* injected {@link GuardedToolSurface} — is supplied by injection. A
|
|
158
|
+
* `SkillExecutor` is an in-process `AgentDispatcher`-shaped executor: it
|
|
159
|
+
* resolves and runs a single skill and returns a success/failure envelope; it
|
|
160
|
+
* is NOT a session lifecycle owner (deliberately NOT `SessionEngine`, AC3).
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```ts
|
|
164
|
+
* // High-level dispatch policy depends on the abstraction, not the adapter.
|
|
165
|
+
* async function runOneSkill(
|
|
166
|
+
* executor: SkillExecutor,
|
|
167
|
+
* skillId: string,
|
|
168
|
+
* tools: GuardedToolSurface,
|
|
169
|
+
* ): Promise<SkillExecuteResult> {
|
|
170
|
+
* return executor.execute({ skillId, context: {}, tools });
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export interface SkillExecutor {
|
|
175
|
+
/**
|
|
176
|
+
* Execute a single skill and return a terminal success/failure envelope.
|
|
177
|
+
*
|
|
178
|
+
* @param input - Skill identity, accumulated context, and the guarded tool
|
|
179
|
+
* surface the skill is permitted to use.
|
|
180
|
+
* @returns The terminal {@link SkillExecuteResult} for this execution.
|
|
181
|
+
*/
|
|
182
|
+
execute(input: SkillExecuteInput): Promise<SkillExecuteResult>;
|
|
183
|
+
}
|