@cleocode/skills 2026.4.70 → 2026.4.73
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/package.json
CHANGED
package/skills/ct-cleo/SKILL.md
CHANGED
|
@@ -9,130 +9,6 @@ CLEO is the task management protocol for AI coding agents. It provides structure
|
|
|
9
9
|
|
|
10
10
|
**Operation set**: 164 operations (97 query + 67 mutate) across 10 canonical domains.
|
|
11
11
|
|
|
12
|
-
## CLI-First Workflow
|
|
13
|
-
|
|
14
|
-
CLI (`cleo` / `ct`) is the **only** dispatch method. All operations use `cleo <command>` syntax.
|
|
15
|
-
|
|
16
|
-
### Tier-0 Read Operations — Always Available
|
|
17
|
-
|
|
18
|
-
| Domain | Operation | Description |
|
|
19
|
-
|--------|-----------|-------------|
|
|
20
|
-
| `tasks` | `show` | Get task details (`params: { taskId }`) |
|
|
21
|
-
| `tasks` | `find` | Search tasks (`params: { query }` or `{ id }`) |
|
|
22
|
-
| `tasks` | `next` | Auto-select highest-priority next task |
|
|
23
|
-
| `tasks` | `plan` | Composite planning view: upcoming tasks, blockers, dependencies |
|
|
24
|
-
| `tasks` | `current` | Show currently active (started) task |
|
|
25
|
-
| `session` | `status` | Current session state — **mandatory first call** |
|
|
26
|
-
| `session` | `handoff.show` | Resume prior context from last session |
|
|
27
|
-
| `session` | `briefing.show` | Composite cold-start briefing (status + handoff combined) |
|
|
28
|
-
| `memory` | `find` | Search brain for past observations, decisions, patterns (`params: { query }`) |
|
|
29
|
-
| `admin` | `version` | CLEO version number |
|
|
30
|
-
| `admin` | `health` | Installation health check |
|
|
31
|
-
| `admin` | `dash` | Project dashboard — mandatory efficiency sequence step 2 |
|
|
32
|
-
| `admin` | `help` | Discover available operations; use `{tier:2}` to reveal advanced ops |
|
|
33
|
-
| `tools` | `skill.list` | List all installed agent skills |
|
|
34
|
-
| `tools` | `provider.list` | List all known LLM/agent providers |
|
|
35
|
-
| `tools` | `provider.detect` | Detect currently active provider |
|
|
36
|
-
|
|
37
|
-
### Tier-1 Read Operations — After Session Init
|
|
38
|
-
|
|
39
|
-
| Domain | Operation | Description |
|
|
40
|
-
|--------|-----------|-------------|
|
|
41
|
-
| `tasks` | `list` | List direct children (`--parent <id>`) — **requires parent filter; prefer `cleo find` for discovery** |
|
|
42
|
-
| `tasks` | `tree` | Full subtask hierarchy (`params: { taskId }`) |
|
|
43
|
-
| `tasks` | `analyze` | Leverage-sorted task discovery |
|
|
44
|
-
| `tasks` | `blockers` | Tasks blocking a specific task (`params: { taskId }`) |
|
|
45
|
-
| `tasks` | `depends` | Full dependency graph for a task (`params: { taskId }`) |
|
|
46
|
-
| `session` | `list` | List sessions (prefer `session.find` for discovery) |
|
|
47
|
-
| `session` | `decision.log` | Recorded decisions for the current session |
|
|
48
|
-
| `session` | `find` | Search sessions (`params: { query }`) |
|
|
49
|
-
| `session` | `show` | Full session record (`params: { sessionId }`) |
|
|
50
|
-
| `session` | `context.drift` | Inspect context drift during long sessions |
|
|
51
|
-
| `memory` | `timeline` | Context around an anchor entry (`params: { anchorId }`) |
|
|
52
|
-
| `memory` | `fetch` | Batch-fetch brain entries (`params: { ids: [...] }`) |
|
|
53
|
-
| `memory` | `decision.find` | Search stored decisions (`params: { query, taskId? }`) |
|
|
54
|
-
| `memory` | `pattern.find` | Search stored patterns (`params: { query, type? }`) |
|
|
55
|
-
| `memory` | `learning.find` | Search stored learnings (`params: { query, minConfidence? }`) |
|
|
56
|
-
| `orchestrate` | `analyze` | Dependency wave analysis (`params: { epicId }`) |
|
|
57
|
-
| `orchestrate` | `ready` | Tasks ready to spawn (`params: { epicId }`) |
|
|
58
|
-
| `orchestrate` | `next` | Next task suggestion (`params: { epicId }`) |
|
|
59
|
-
| `orchestrate` | `status` | Current orchestration state |
|
|
60
|
-
| `check` | `schema` | Validate task data schema integrity |
|
|
61
|
-
| `check` | `protocol` | Protocol compliance for a task (`params: { taskId, protocolType? }`) |
|
|
62
|
-
| `check` | `task` | Validate task fields (`params: { taskId }`) |
|
|
63
|
-
| `check` | `compliance.summary` | Overall compliance summary |
|
|
64
|
-
| `check` | `test` | Test status or coverage (`params: { format: "status" | "coverage" }`) |
|
|
65
|
-
| `check` | `gate.status` | Lifecycle gate status |
|
|
66
|
-
| `pipeline` | `stage.status` | Pipeline stage for epic (`params: { epicId }`) |
|
|
67
|
-
| `pipeline` | `stage.validate` | Validate gate before advancing |
|
|
68
|
-
| `pipeline` | `manifest.show` | Read manifest entry (`params: { id }`) |
|
|
69
|
-
| `pipeline` | `manifest.list` | List manifest entries (`params: { filter?: "pending" }`) |
|
|
70
|
-
| `pipeline` | `manifest.find` | Search manifest entries (`params: { query }`) |
|
|
71
|
-
| `nexus` | `status` | Check if nexus is initialized |
|
|
72
|
-
| `nexus` | `list` | List registered projects |
|
|
73
|
-
| `admin` | `config.show` | Inspect current configuration |
|
|
74
|
-
| `admin` | `adr.find` | Search architecture decision records |
|
|
75
|
-
| `tools` | `skill.show` | Skill details (`params: { skillId }`) |
|
|
76
|
-
| `sticky` | `list` | List sticky notes (`params: { status?, tag? }`) |
|
|
77
|
-
| `sticky` | `show` | Show sticky details (`params: { stickyId }`) |
|
|
78
|
-
|
|
79
|
-
### Tier-0 Write Operations — Always Available
|
|
80
|
-
|
|
81
|
-
| Domain | Operation | Description |
|
|
82
|
-
|--------|-----------|-------------|
|
|
83
|
-
| `tasks` | `add` | Create task (`params: { title, description, parentId?, status? }`) |
|
|
84
|
-
| `tasks` | `update` | Update task (`params: { taskId, title?, status?, notes? }`) |
|
|
85
|
-
| `tasks` | `complete` | Mark task done (`params: { taskId }`) |
|
|
86
|
-
| `tasks` | `start` | Start working on a task (`params: { taskId }`) |
|
|
87
|
-
| `tasks` | `stop` | Stop working on current task |
|
|
88
|
-
| `session` | `start` | Start session (`params: { scope }`) — scope is **required** |
|
|
89
|
-
| `session` | `end` | End session (`params: { note? }`) |
|
|
90
|
-
| `memory` | `observe` | Save observation to brain (`params: { text, title? }`) |
|
|
91
|
-
|
|
92
|
-
### Tier-1 Write Operations — After Session Init
|
|
93
|
-
|
|
94
|
-
| Domain | Operation | Description |
|
|
95
|
-
|--------|-----------|-------------|
|
|
96
|
-
| `tasks` | `cancel` | Cancel task (`params: { taskId }`) |
|
|
97
|
-
| `tasks` | `archive` | Archive completed task (`params: { taskId }`) |
|
|
98
|
-
| `tasks` | `restore` | Restore from done/archive (`params: { taskId, from: "done" \| "archive" }`) |
|
|
99
|
-
| `tasks` | `delete` | Hard delete — irreversible (`params: { taskId }`) |
|
|
100
|
-
| `tasks` | `reparent` | Move to different parent (`params: { taskId, newParentId }`) |
|
|
101
|
-
| `tasks` | `reorder` | Reorder tasks within their parent (`params: { taskId, position }`) |
|
|
102
|
-
| `session` | `resume` | Resume a prior session (`params: { sessionId }`) |
|
|
103
|
-
| `session` | `suspend` | Pause session without ending it |
|
|
104
|
-
| `session` | `record.decision` | Record a session decision (`params: { text, rationale }`) |
|
|
105
|
-
| `session` | `record.assumption` | Record a session assumption (`params: { text }`) |
|
|
106
|
-
| `admin` | `context.inject` | Inject protocol content into context (`params: { protocolType }`) — **moved from session domain** |
|
|
107
|
-
| `memory` | `link` | Link memory entry to task (`params: { memoryId, taskId }`) |
|
|
108
|
-
| `memory` | `decision.store` | Store structured decision (`params: { decision, rationale, taskId, alternatives? }`) |
|
|
109
|
-
| `memory` | `pattern.store` | Store recurring pattern (`params: { name, type, impact, success, antiPattern? }`) |
|
|
110
|
-
| `memory` | `learning.store` | Store a learning (`params: { text, confidence, taskId? }`) |
|
|
111
|
-
| `orchestrate` | `start` | Start orchestrating an epic (`params: { epicId }`) |
|
|
112
|
-
| `orchestrate` | `spawn` | Spawn prep for a task (`params: { taskId, skillIds? }`) |
|
|
113
|
-
| `orchestrate` | `spawn.execute` | Execute spawn via adapter registry (`params: { taskId }`) |
|
|
114
|
-
| `orchestrate` | `handoff` | Hand off context to subagent (`params: { taskId, context }`) |
|
|
115
|
-
| `orchestrate` | `validate` | Pre-spawn gate check (`params: { taskId }`) |
|
|
116
|
-
| `orchestrate` | `parallel` | Run parallel agent wave (`params: { action: "start" \| "end", waveId? }`) |
|
|
117
|
-
| `check` | `test.run` | Run tests |
|
|
118
|
-
| `check` | `gate.set` | Set or reset a lifecycle gate |
|
|
119
|
-
| `pipeline` | `stage.record` | Record pipeline stage progress |
|
|
120
|
-
| `pipeline` | `stage.gate.pass` | Pass a pipeline gate (`params: { stageId, gateId }`) |
|
|
121
|
-
| `pipeline` | `stage.gate.fail` | Fail a gate with reason (`params: { stageId, gateId, reason }`) |
|
|
122
|
-
| `pipeline` | `manifest.append` | Append manifest entry (`params: { entry }`) — **MANDATORY per BASE protocol** |
|
|
123
|
-
| `pipeline` | `phase.set` | Set pipeline phase (`params: { phaseId, action: "start" \| "complete" }`) |
|
|
124
|
-
| `pipeline` | `release.ship` | Ship a release (`params: { step? }`) |
|
|
125
|
-
| `admin` | `config.set` | Update configuration (`params: { key, value }`) |
|
|
126
|
-
| `tools` | `skill.install` | Install a skill (`params: { skillId }`) |
|
|
127
|
-
| `tools` | `skill.uninstall` | Uninstall a skill (`params: { skillId }`) |
|
|
128
|
-
| `tools` | `skill.refresh` | Bulk update all installed skills |
|
|
129
|
-
| `sticky` | `add` | Create sticky note (`params: { content, tags?, color?, priority? }`) |
|
|
130
|
-
| `sticky` | `convert` | Convert to task/memory (`params: { stickyId, targetType }`) |
|
|
131
|
-
| `sticky` | `archive` | Archive sticky (`params: { stickyId }`) |
|
|
132
|
-
| `sticky` | `purge` | Permanently delete sticky notes (`params: { stickyId }`) |
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
12
|
## Canonical Decision Tree
|
|
137
13
|
|
|
138
14
|
Every agent MUST use this tree to select the minimum-cost operation path.
|
|
@@ -162,6 +38,22 @@ Agent starts work
|
|
|
162
38
|
|
|
163
39
|
---
|
|
164
40
|
|
|
41
|
+
### Phase Mapping (RCASD-IVTR+C)
|
|
42
|
+
|
|
43
|
+
Each task lives in a lifecycle phase. Match your tooling to the current phase:
|
|
44
|
+
|
|
45
|
+
| Phase | When | Key Commands |
|
|
46
|
+
|-------|------|--------------|
|
|
47
|
+
| `research` | Gathering information, reading docs, exploring codebase | `cleo memory find`, `cleo docs add`, `cleo show` |
|
|
48
|
+
| `implement` | Writing code, making changes, building features | `cleo start`, `cleo verify`, code tools |
|
|
49
|
+
| `validate` | Verifying correctness, running acceptance criteria | `cleo verify <id> --run`, `cleo check gate.status` |
|
|
50
|
+
| `test` | Running test suites, asserting coverage | `pnpm run test`, `cleo check test` |
|
|
51
|
+
| `release` | Versioning, changelog, publishing | `cleo release ship`, `cleo pipeline stage.record` |
|
|
52
|
+
|
|
53
|
+
**Check current phase**: `cleo show <id>` → `pipelineStage` field.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
165
57
|
### Goal: Discover Work
|
|
166
58
|
|
|
167
59
|
```
|
|
@@ -200,7 +92,7 @@ I need to find what to work on
|
|
|
200
92
|
I need to save or recall information across sessions
|
|
201
93
|
│
|
|
202
94
|
├── Save an observation right now (free-form)
|
|
203
|
-
│ └── cleo observe "text" --title "title" [tier 0]
|
|
95
|
+
│ └── cleo memory observe "text" --title "title" [tier 0]
|
|
204
96
|
│
|
|
205
97
|
├── Search for something I or a prior agent observed
|
|
206
98
|
│ └── cleo memory find "..." [tier 0] ← ALWAYS start here (cheap)
|
|
@@ -220,28 +112,6 @@ I need to save or recall information across sessions
|
|
|
220
112
|
|
|
221
113
|
---
|
|
222
114
|
|
|
223
|
-
### Goal: Multi-Agent Coordination
|
|
224
|
-
|
|
225
|
-
```
|
|
226
|
-
I need to coordinate agent work (orchestrator role)
|
|
227
|
-
│
|
|
228
|
-
├── I am the orchestrator — start coordinating an epic
|
|
229
|
-
│ └── cleo orchestrator start --epic {epicId} [tier 1]
|
|
230
|
-
│ └── cleo orchestrator status [tier 1] → current orchestration state
|
|
231
|
-
│
|
|
232
|
-
├── Spawn a subagent for a task
|
|
233
|
-
│ └── (1) cleo orchestrator validate {taskId} [tier 1] → pre-spawn gate check
|
|
234
|
-
│ (2) cleo orchestrator spawn {taskId} [tier 1] → spawn prep
|
|
235
|
-
│
|
|
236
|
-
└── I am a subagent — complete my work and report
|
|
237
|
-
└── cleo manifest append {entry} [tier 1] ← MANDATORY per BASE protocol
|
|
238
|
-
cleo complete {taskId} [tier 0]
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
**Subagent BASE protocol**: Every subagent MUST append one entry to MANIFEST.jsonl via `pipeline.manifest.append` BEFORE calling `tasks.complete`. Omitting this is a protocol violation (exit code 62).
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
115
|
### Goal: Track Session Context
|
|
246
116
|
|
|
247
117
|
```
|
|
@@ -303,7 +173,215 @@ I need system or configuration info
|
|
|
303
173
|
|
|
304
174
|
---
|
|
305
175
|
|
|
306
|
-
##
|
|
176
|
+
## Pre-Complete Gate Ritual
|
|
177
|
+
|
|
178
|
+
MANDATORY before every `cleo complete <id>`:
|
|
179
|
+
|
|
180
|
+
1. `cleo show <id>` — inspect gates
|
|
181
|
+
2. Run each acceptance criterion verifiable (tests, lint, file checks)
|
|
182
|
+
3. `cleo verify <id> --run` — executes programmatic gates
|
|
183
|
+
4. `cleo memory observe "..." --title "..."` — capture learnings
|
|
184
|
+
5. `cleo complete <id>` — should pass cleanly
|
|
185
|
+
|
|
186
|
+
Anti-patterns:
|
|
187
|
+
- `cleo complete` without `cleo verify --run`
|
|
188
|
+
- `cleo verify --all` to bypass programmatic gates
|
|
189
|
+
- Skipping memory observe on non-trivial work
|
|
190
|
+
- Self-attesting without programmatic proof (IVTR validate phase exists to prevent this)
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Multi-Agent Coordination
|
|
195
|
+
|
|
196
|
+
FIRST: do I have >= 5 tasks under one epic?
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
Do I have an epic with >= 5 tasks?
|
|
200
|
+
│
|
|
201
|
+
├── YES → cleo orchestrate start <epicId> (auto-inits LOOM) — MANDATORY before touching any child task
|
|
202
|
+
│ │
|
|
203
|
+
│ └── For each wave:
|
|
204
|
+
│ cleo orchestrate ready --epic <id> → get parallel-safe task set
|
|
205
|
+
│ │
|
|
206
|
+
│ └── For each task in wave:
|
|
207
|
+
│ cleo orchestrate spawn <taskId> → get resolved prompt
|
|
208
|
+
│ Dispatch subagent via Agent tool
|
|
209
|
+
│ On return: cleo manifest show <id> → read key_findings
|
|
210
|
+
│
|
|
211
|
+
└── NO → continue as solo executor
|
|
212
|
+
└── proceed through standard work loop (cleo next → cleo show → implement → cleo complete)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Gate-failure loop (IVTR)**:
|
|
216
|
+
|
|
217
|
+
```
|
|
218
|
+
Task returns blocked
|
|
219
|
+
│
|
|
220
|
+
├── Read failure in manifest (cleo manifest show <id>)
|
|
221
|
+
│
|
|
222
|
+
└── cleo orchestrate ivtr <id> --loop-back --phase implement --reason "..." → re-spawn
|
|
223
|
+
├── Max 2 retries → escalate to HITL
|
|
224
|
+
└── Document blocker in manifest before escalating
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Greenfield Bootstrap (new project)
|
|
230
|
+
|
|
231
|
+
Copy-paste sequence:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
cd /path/to/new-project
|
|
235
|
+
cleo init # creates .cleo/, tasks.db, brain.db
|
|
236
|
+
cleo session start --scope global
|
|
237
|
+
cleo add "Epic: <your goal>" --type epic --lifecycle auto \
|
|
238
|
+
--description "..." \
|
|
239
|
+
--acceptance "REQ-1|REQ-2|REQ-3|REQ-4|REQ-5"
|
|
240
|
+
EPIC_ID=$(cleo current | jq -r '.data.currentTask.id')
|
|
241
|
+
|
|
242
|
+
# Attach research/spec documents
|
|
243
|
+
cleo docs add $EPIC_ID ./spec.md --desc "initial spec" --labels spec
|
|
244
|
+
|
|
245
|
+
# Decompose into atomic tasks with typed gates
|
|
246
|
+
cleo add "Task A" --type task --parent $EPIC_ID
|
|
247
|
+
cleo req add <taskA-id> IMPL-01 --gate '{"kind":"test","command":"npm test","expect":"pass","description":"..."}'
|
|
248
|
+
|
|
249
|
+
# Start orchestrator — auto-inits LOOM
|
|
250
|
+
cleo orchestrate start $EPIC_ID
|
|
251
|
+
|
|
252
|
+
# Drive IVTR on first task
|
|
253
|
+
cleo orchestrate ivtr <taskA-id> --start # begins Implement phase
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Reference
|
|
259
|
+
|
|
260
|
+
### CLI-First Workflow
|
|
261
|
+
|
|
262
|
+
CLI (`cleo` / `ct`) is the **only** dispatch method. All operations use `cleo <command>` syntax.
|
|
263
|
+
|
|
264
|
+
#### Tier-0 Read Operations — Always Available
|
|
265
|
+
|
|
266
|
+
| Domain | Operation | Description |
|
|
267
|
+
|--------|-----------|-------------|
|
|
268
|
+
| `tasks` | `show` | Get task details (`params: { taskId }`) |
|
|
269
|
+
| `tasks` | `find` | Search tasks (`params: { query }` or `{ id }`) |
|
|
270
|
+
| `tasks` | `next` | Auto-select highest-priority next task |
|
|
271
|
+
| `tasks` | `plan` | Composite planning view: upcoming tasks, blockers, dependencies |
|
|
272
|
+
| `tasks` | `current` | Show currently active (started) task |
|
|
273
|
+
| `session` | `status` | Current session state — **mandatory first call** |
|
|
274
|
+
| `session` | `handoff.show` | Resume prior context from last session |
|
|
275
|
+
| `session` | `briefing.show` | Composite cold-start briefing (status + handoff combined) |
|
|
276
|
+
| `memory` | `find` | Search brain for past observations, decisions, patterns (`params: { query }`) |
|
|
277
|
+
| `admin` | `version` | CLEO version number |
|
|
278
|
+
| `admin` | `health` | Installation health check |
|
|
279
|
+
| `admin` | `dash` | Project dashboard — mandatory efficiency sequence step 2 |
|
|
280
|
+
| `admin` | `help` | Discover available operations; use `{tier:2}` to reveal advanced ops |
|
|
281
|
+
| `tools` | `skill.list` | List all installed agent skills |
|
|
282
|
+
| `tools` | `provider.list` | List all known LLM/agent providers |
|
|
283
|
+
| `tools` | `provider.detect` | Detect currently active provider |
|
|
284
|
+
|
|
285
|
+
#### Tier-1 Read Operations — After Session Init
|
|
286
|
+
|
|
287
|
+
| Domain | Operation | Description |
|
|
288
|
+
|--------|-----------|-------------|
|
|
289
|
+
| `tasks` | `list` | List direct children (`--parent <id>`) — **requires parent filter; prefer `cleo find` for discovery** |
|
|
290
|
+
| `tasks` | `tree` | Full subtask hierarchy (`params: { taskId }`) |
|
|
291
|
+
| `tasks` | `analyze` | Leverage-sorted task discovery |
|
|
292
|
+
| `tasks` | `blockers` | Tasks blocking a specific task (`params: { taskId }`) |
|
|
293
|
+
| `tasks` | `depends` | Full dependency graph for a task (`params: { taskId }`) |
|
|
294
|
+
| `session` | `list` | List sessions (prefer `session.find` for discovery) |
|
|
295
|
+
| `session` | `decision.log` | Recorded decisions for the current session |
|
|
296
|
+
| `session` | `find` | Search sessions (`params: { query }`) |
|
|
297
|
+
| `session` | `show` | Full session record (`params: { sessionId }`) |
|
|
298
|
+
| `session` | `context.drift` | Inspect context drift during long sessions |
|
|
299
|
+
| `memory` | `timeline` | Context around an anchor entry (`params: { anchorId }`) |
|
|
300
|
+
| `memory` | `fetch` | Batch-fetch brain entries (`params: { ids: [...] }`) |
|
|
301
|
+
| `memory` | `decision.find` | Search stored decisions (`params: { query, taskId? }`) |
|
|
302
|
+
| `memory` | `pattern.find` | Search stored patterns (`params: { query, type? }`) |
|
|
303
|
+
| `memory` | `learning.find` | Search stored learnings (`params: { query, minConfidence? }`) |
|
|
304
|
+
| `orchestrate` | `analyze` | Dependency wave analysis (`params: { epicId }`) |
|
|
305
|
+
| `orchestrate` | `ready` | Tasks ready to spawn (`params: { epicId }`) |
|
|
306
|
+
| `orchestrate` | `next` | Next task suggestion (`params: { epicId }`) |
|
|
307
|
+
| `orchestrate` | `status` | Current orchestration state |
|
|
308
|
+
| `check` | `schema` | Validate task data schema integrity |
|
|
309
|
+
| `check` | `protocol` | Protocol compliance for a task (`params: { taskId, protocolType? }`) |
|
|
310
|
+
| `check` | `task` | Validate task fields (`params: { taskId }`) |
|
|
311
|
+
| `check` | `compliance.summary` | Overall compliance summary |
|
|
312
|
+
| `check` | `test` | Test status or coverage (`params: { format: "status" | "coverage" }`) |
|
|
313
|
+
| `check` | `gate.status` | Lifecycle gate status |
|
|
314
|
+
| `pipeline` | `stage.status` | Pipeline stage for epic (`params: { epicId }`) |
|
|
315
|
+
| `pipeline` | `stage.validate` | Validate gate before advancing |
|
|
316
|
+
| `pipeline` | `manifest.show` | Read manifest entry (`params: { id }`) |
|
|
317
|
+
| `pipeline` | `manifest.list` | List manifest entries (`params: { filter?: "pending" }`) |
|
|
318
|
+
| `pipeline` | `manifest.find` | Search manifest entries (`params: { query }`) |
|
|
319
|
+
| `nexus` | `status` | Check if nexus is initialized |
|
|
320
|
+
| `nexus` | `list` | List registered projects |
|
|
321
|
+
| `admin` | `config.show` | Inspect current configuration |
|
|
322
|
+
| `admin` | `adr.find` | Search architecture decision records |
|
|
323
|
+
| `tools` | `skill.show` | Skill details (`params: { skillId }`) |
|
|
324
|
+
| `sticky` | `list` | List sticky notes (`params: { status?, tag? }`) |
|
|
325
|
+
| `sticky` | `show` | Show sticky details (`params: { stickyId }`) |
|
|
326
|
+
|
|
327
|
+
#### Tier-0 Write Operations — Always Available
|
|
328
|
+
|
|
329
|
+
| Domain | Operation | Description |
|
|
330
|
+
|--------|-----------|-------------|
|
|
331
|
+
| `tasks` | `add` | Create task (`params: { title, description, parentId?, status? }`) |
|
|
332
|
+
| `tasks` | `update` | Update task (`params: { taskId, title?, status?, notes? }`) |
|
|
333
|
+
| `tasks` | `complete` | Mark task done (`params: { taskId }`) |
|
|
334
|
+
| `tasks` | `start` | Start working on a task (`params: { taskId }`) |
|
|
335
|
+
| `tasks` | `stop` | Stop working on current task |
|
|
336
|
+
| `session` | `start` | Start session (`params: { scope }`) — scope is **required** |
|
|
337
|
+
| `session` | `end` | End session (`params: { note? }`) |
|
|
338
|
+
| `memory` | `observe` | Save observation to brain (`params: { text, title? }`) |
|
|
339
|
+
|
|
340
|
+
#### Tier-1 Write Operations — After Session Init
|
|
341
|
+
|
|
342
|
+
| Domain | Operation | Description |
|
|
343
|
+
|--------|-----------|-------------|
|
|
344
|
+
| `tasks` | `cancel` | Cancel task (`params: { taskId }`) |
|
|
345
|
+
| `tasks` | `archive` | Archive completed task (`params: { taskId }`) |
|
|
346
|
+
| `tasks` | `restore` | Restore from done/archive (`params: { taskId, from: "done" \| "archive" }`) |
|
|
347
|
+
| `tasks` | `delete` | Hard delete — irreversible (`params: { taskId }`) |
|
|
348
|
+
| `tasks` | `reparent` | Move to different parent (`params: { taskId, newParentId }`) |
|
|
349
|
+
| `tasks` | `reorder` | Reorder tasks within their parent (`params: { taskId, position }`) |
|
|
350
|
+
| `session` | `resume` | Resume a prior session (`params: { sessionId }`) |
|
|
351
|
+
| `session` | `suspend` | Pause session without ending it |
|
|
352
|
+
| `session` | `record.decision` | Record a session decision (`params: { text, rationale }`) |
|
|
353
|
+
| `session` | `record.assumption` | Record a session assumption (`params: { text }`) |
|
|
354
|
+
| `admin` | `context.inject` | Inject protocol content into context (`params: { protocolType }`) — **moved from session domain** |
|
|
355
|
+
| `memory` | `link` | Link memory entry to task (`params: { memoryId, taskId }`) |
|
|
356
|
+
| `memory` | `decision.store` | Store structured decision (`params: { decision, rationale, taskId, alternatives? }`) |
|
|
357
|
+
| `memory` | `pattern.store` | Store recurring pattern (`params: { name, type, impact, success, antiPattern? }`) |
|
|
358
|
+
| `memory` | `learning.store` | Store a learning (`params: { text, confidence, taskId? }`) |
|
|
359
|
+
| `orchestrate` | `start` | Start orchestrating an epic (`params: { epicId }`) |
|
|
360
|
+
| `orchestrate` | `spawn` | Spawn prep for a task (`params: { taskId, skillIds? }`) |
|
|
361
|
+
| `orchestrate` | `spawn.execute` | Execute spawn via adapter registry (`params: { taskId }`) |
|
|
362
|
+
| `orchestrate` | `handoff` | Hand off context to subagent (`params: { taskId, context }`) |
|
|
363
|
+
| `orchestrate` | `validate` | Pre-spawn gate check (`params: { taskId }`) |
|
|
364
|
+
| `orchestrate` | `parallel` | Run parallel agent wave (`params: { action: "start" \| "end", waveId? }`) |
|
|
365
|
+
| `check` | `test.run` | Run tests |
|
|
366
|
+
| `check` | `gate.set` | Set or reset a lifecycle gate |
|
|
367
|
+
| `pipeline` | `stage.record` | Record pipeline stage progress |
|
|
368
|
+
| `pipeline` | `stage.gate.pass` | Pass a pipeline gate (`params: { stageId, gateId }`) |
|
|
369
|
+
| `pipeline` | `stage.gate.fail` | Fail a gate with reason (`params: { stageId, gateId, reason }`) |
|
|
370
|
+
| `pipeline` | `manifest.append` | Append manifest entry (`params: { entry }`) — **MANDATORY per BASE protocol** |
|
|
371
|
+
| `pipeline` | `phase.set` | Set pipeline phase (`params: { phaseId, action: "start" \| "complete" }`) |
|
|
372
|
+
| `pipeline` | `release.ship` | Ship a release (`params: { step? }`) |
|
|
373
|
+
| `admin` | `config.set` | Update configuration (`params: { key, value }`) |
|
|
374
|
+
| `tools` | `skill.install` | Install a skill (`params: { skillId }`) |
|
|
375
|
+
| `tools` | `skill.uninstall` | Uninstall a skill (`params: { skillId }`) |
|
|
376
|
+
| `tools` | `skill.refresh` | Bulk update all installed skills |
|
|
377
|
+
| `sticky` | `add` | Create sticky note (`params: { content, tags?, color?, priority? }`) |
|
|
378
|
+
| `sticky` | `convert` | Convert to task/memory (`params: { stickyId, targetType }`) |
|
|
379
|
+
| `sticky` | `archive` | Archive sticky (`params: { stickyId }`) |
|
|
380
|
+
| `sticky` | `purge` | Permanently delete sticky notes (`params: { stickyId }`) |
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### CLI Reference (Primary)
|
|
307
385
|
|
|
308
386
|
Use `ct` (alias for `cleo`) as the interface. CLI is the only dispatch method.
|
|
309
387
|
|
|
@@ -323,7 +401,7 @@ ct sticky show SN-001 # Show sticky details
|
|
|
323
401
|
|
|
324
402
|
---
|
|
325
403
|
|
|
326
|
-
|
|
404
|
+
### Task Discovery (Context Efficiency)
|
|
327
405
|
|
|
328
406
|
**MUST** use efficient commands — `find` for discovery, `show` for details:
|
|
329
407
|
|
|
@@ -331,7 +409,7 @@ ct sticky show SN-001 # Show sticky details
|
|
|
331
409
|
- `find` returns minimal fields only (99% less context)
|
|
332
410
|
- Use `show` only when you need full details for a specific task
|
|
333
411
|
|
|
334
|
-
|
|
412
|
+
#### Context Bloat Anti-Patterns
|
|
335
413
|
|
|
336
414
|
| Anti-Pattern | Token Cost | Efficient Alternative | Savings |
|
|
337
415
|
|-------------|-----------|----------------------|---------|
|
|
@@ -344,7 +422,7 @@ ct sticky show SN-001 # Show sticky details
|
|
|
344
422
|
|
|
345
423
|
---
|
|
346
424
|
|
|
347
|
-
|
|
425
|
+
### Anti-Pattern Reference
|
|
348
426
|
|
|
349
427
|
| Bad Pattern | Correct Pattern | Why |
|
|
350
428
|
|-------------|----------------|-----|
|
|
@@ -365,10 +443,11 @@ ct sticky show SN-001 # Show sticky details
|
|
|
365
443
|
| `memory.fetch` without `memory.find` | `memory.find` → filter → `memory.fetch` | fetch without filter returns everything |
|
|
366
444
|
| Completing task without manifest append | `pipeline.manifest.append` then `tasks.complete` | BASE protocol violation (exit 62) |
|
|
367
445
|
| Skipping `session.status` at start | Always check `session.status` first | loses prior context, causes duplicate work |
|
|
446
|
+
| `cleo observe` | `cleo memory observe` | observe is not a top-level command |
|
|
368
447
|
|
|
369
448
|
---
|
|
370
449
|
|
|
371
|
-
|
|
450
|
+
### Progressive Disclosure
|
|
372
451
|
|
|
373
452
|
Load only what you need. Escalate tiers when the task demands it:
|
|
374
453
|
|
|
@@ -391,11 +470,11 @@ Load only what you need. Escalate tiers when the task demands it:
|
|
|
391
470
|
|
|
392
471
|
---
|
|
393
472
|
|
|
394
|
-
|
|
473
|
+
### Session Protocol
|
|
395
474
|
|
|
396
475
|
Sessions track work context across agent interactions.
|
|
397
476
|
|
|
398
|
-
|
|
477
|
+
#### Quick Start
|
|
399
478
|
|
|
400
479
|
```bash
|
|
401
480
|
# 1. CHECK session state first (always)
|
|
@@ -416,7 +495,7 @@ ct session end
|
|
|
416
495
|
|
|
417
496
|
---
|
|
418
497
|
|
|
419
|
-
|
|
498
|
+
### Error Handling
|
|
420
499
|
|
|
421
500
|
**CRITICAL: NEVER ignore exit codes. Failed commands = tasks NOT created/updated.**
|
|
422
501
|
|
|
@@ -436,13 +515,13 @@ After EVERY command:
|
|
|
436
515
|
|
|
437
516
|
---
|
|
438
517
|
|
|
439
|
-
|
|
518
|
+
### RCASD-IVTR+C Lifecycle (LOOM)
|
|
440
519
|
|
|
441
520
|
**LOOM** (Logical Order of Operations Methodology) is the systematic framework for how CLEO processes project threads through the RCASD-IVTR+C pipeline. See `docs/concepts/CLEO-VISION.md` for the complete LOOM framework.
|
|
442
521
|
|
|
443
522
|
**Lifecycle**: See `references/loom-lifecycle.md` for gate enforcement and subagent architecture.
|
|
444
523
|
|
|
445
|
-
|
|
524
|
+
### Pipeline Awareness
|
|
446
525
|
|
|
447
526
|
Epics follow the RCASD-IVTR+C lifecycle managed through pipeline stages. Use `pipeline.stage.status` to check where an epic is in its lifecycle:
|
|
448
527
|
|
|
@@ -461,7 +540,7 @@ Epics follow the RCASD-IVTR+C lifecycle managed through pipeline stages. Use `pi
|
|
|
461
540
|
|
|
462
541
|
---
|
|
463
542
|
|
|
464
|
-
|
|
543
|
+
### Time Estimates Prohibited
|
|
465
544
|
|
|
466
545
|
- **MUST NOT** estimate hours, days, weeks, or temporal duration
|
|
467
546
|
- **MUST** use relative sizing: `small` / `medium` / `large`
|
|
@@ -469,7 +548,7 @@ Epics follow the RCASD-IVTR+C lifecycle managed through pipeline stages. Use `pi
|
|
|
469
548
|
|
|
470
549
|
---
|
|
471
550
|
|
|
472
|
-
|
|
551
|
+
### Further Reading
|
|
473
552
|
|
|
474
553
|
For detailed guidance on specific topics, see:
|
|
475
554
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for ct-cleo/SKILL.md (SKILL-14).
|
|
3
|
+
*
|
|
4
|
+
* Asserts that all required protocol markers are present in the skill file,
|
|
5
|
+
* protecting against content drift as the file evolves.
|
|
6
|
+
*
|
|
7
|
+
* Checks:
|
|
8
|
+
* - Required section markers exist: Decision Tree, Pre-Complete Gate Ritual,
|
|
9
|
+
* Multi-Agent Coordination, Greenfield Bootstrap
|
|
10
|
+
* - `cleo memory observe` is used (not the deprecated bare `cleo observe`)
|
|
11
|
+
* - `cleo orchestrate ivtr` is referenced at least once
|
|
12
|
+
* - At least 4 distinct `cleo <verb>` command patterns exist
|
|
13
|
+
*
|
|
14
|
+
* @task T808
|
|
15
|
+
* @skill-version SKILL-14
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { readFileSync } from 'node:fs';
|
|
19
|
+
import { dirname, join, resolve } from 'node:path';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
import { describe, expect, it } from 'vitest';
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Setup
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
28
|
+
|
|
29
|
+
/** Absolute path to the ct-cleo skill root directory */
|
|
30
|
+
const skillRoot = resolve(dirname(thisFile), '..');
|
|
31
|
+
|
|
32
|
+
/** Full path to the SKILL.md file under test */
|
|
33
|
+
const skillPath = join(skillRoot, 'SKILL.md');
|
|
34
|
+
|
|
35
|
+
/** Read once — all assertions operate on this string */
|
|
36
|
+
const skillContent = readFileSync(skillPath, 'utf-8');
|
|
37
|
+
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Required section markers (SKILL-10 through SKILL-13)
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
describe('ct-cleo SKILL.md — required section markers', () => {
|
|
43
|
+
it('contains "Decision Tree" section', () => {
|
|
44
|
+
expect(skillContent).toContain('Decision Tree');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('contains "Pre-Complete Gate Ritual" section', () => {
|
|
48
|
+
expect(skillContent).toContain('Pre-Complete Gate Ritual');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('contains "Multi-Agent Coordination" section', () => {
|
|
52
|
+
expect(skillContent).toContain('Multi-Agent Coordination');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('contains "Greenfield Bootstrap" section', () => {
|
|
56
|
+
expect(skillContent).toContain('Greenfield Bootstrap');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('Decision Tree is the first H2 heading', () => {
|
|
60
|
+
// Find the position of the first H2 (## ...) after the frontmatter
|
|
61
|
+
const afterFrontmatter = skillContent.replace(/^---[\s\S]*?---\n/, '');
|
|
62
|
+
const firstH2Match = /^## (.+)$/m.exec(afterFrontmatter);
|
|
63
|
+
expect(firstH2Match).not.toBeNull();
|
|
64
|
+
expect(firstH2Match![1]).toContain('Decision Tree');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Command usage correctness (SKILL-11 / SKILL-12)
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
describe('ct-cleo SKILL.md — command correctness', () => {
|
|
73
|
+
it('uses "cleo memory observe" not bare "cleo observe" for memory writes', () => {
|
|
74
|
+
// Must contain the correct form
|
|
75
|
+
expect(skillContent).toContain('cleo memory observe');
|
|
76
|
+
|
|
77
|
+
// The bare `cleo observe` form should only appear as a deprecated anti-pattern
|
|
78
|
+
// in a table row (prefixed with `| `), never as an instruction to execute.
|
|
79
|
+
// Count bare `cleo observe` occurrences that are NOT inside table pipe columns.
|
|
80
|
+
const lines = skillContent.split('\n');
|
|
81
|
+
const badLines = lines.filter((line) => {
|
|
82
|
+
// Skip table rows — those document deprecated patterns intentionally
|
|
83
|
+
if (/^\s*\|/.test(line)) return false;
|
|
84
|
+
// Skip comment-style lines and code-block lines showing anti-patterns
|
|
85
|
+
return /\bcleo observe\b/.test(line);
|
|
86
|
+
});
|
|
87
|
+
expect(badLines).toHaveLength(0);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('references "cleo orchestrate ivtr" at least once', () => {
|
|
91
|
+
expect(skillContent).toMatch(/cleo orchestrate ivtr/);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Command diversity — at least 4 distinct cleo <verb> patterns
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
describe('ct-cleo SKILL.md — command diversity', () => {
|
|
100
|
+
it('contains at least 4 distinct "cleo <verb>" command patterns', () => {
|
|
101
|
+
// Extract all `cleo <word>` patterns (first word after cleo)
|
|
102
|
+
const verbs = new Set<string>();
|
|
103
|
+
const pattern = /\bcleo\s+([a-z][a-z0-9-]*)/g;
|
|
104
|
+
let match: RegExpExecArray | null;
|
|
105
|
+
|
|
106
|
+
// eslint-disable-next-line no-cond-assign
|
|
107
|
+
while ((match = pattern.exec(skillContent)) !== null) {
|
|
108
|
+
verbs.add(match[1]);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
expect(verbs.size).toBeGreaterThanOrEqual(4);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Phase mapping (SKILL-10 enhancement)
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
describe('ct-cleo SKILL.md — phase mapping', () => {
|
|
120
|
+
it('includes phase mapping for research phase', () => {
|
|
121
|
+
expect(skillContent).toContain('research');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('includes phase mapping for implement phase', () => {
|
|
125
|
+
expect(skillContent).toMatch(/implement/i);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('includes phase mapping for validate phase', () => {
|
|
129
|
+
expect(skillContent).toMatch(/validate|validation/i);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('includes phase mapping for test phase', () => {
|
|
133
|
+
expect(skillContent).toMatch(/\btest\b/i);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('includes phase mapping for release phase', () => {
|
|
137
|
+
expect(skillContent).toContain('release');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for CLEO-INJECTION.md content (T778).
|
|
3
|
+
*
|
|
4
|
+
* Asserts that the CLEO protocol template file contains required content
|
|
5
|
+
* and uses correct command forms, protecting against accidental simplification
|
|
6
|
+
* or command-form drift.
|
|
7
|
+
*
|
|
8
|
+
* Checks:
|
|
9
|
+
* - Contains `cleo memory observe` (not bare `cleo observe`)
|
|
10
|
+
* - Contains `cleo orchestrate start` in Session Start section
|
|
11
|
+
* - Contains "Memory Protocol (JIT)" H2 section
|
|
12
|
+
* - Contains "Escalation" H2 section
|
|
13
|
+
* - At least 6 distinct `cleo <verb>` command patterns
|
|
14
|
+
*
|
|
15
|
+
* @task T778
|
|
16
|
+
* @injectable-file /home/keatonhoskins/.local/share/cleo/templates/CLEO-INJECTION.md
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readFileSync } from 'node:fs';
|
|
20
|
+
import { resolve } from 'node:path';
|
|
21
|
+
import { describe, expect, it } from 'vitest';
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Setup
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
/** Absolute path to CLEO-INJECTION.md template file */
|
|
28
|
+
const injectionPath = resolve(
|
|
29
|
+
'/home/keatonhoskins/.local/share/cleo/templates/CLEO-INJECTION.md'
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
/** Read once — all assertions operate on this string */
|
|
33
|
+
const injectionContent = readFileSync(injectionPath, 'utf-8');
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Required section markers
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
describe('CLEO-INJECTION.md — required section markers', () => {
|
|
40
|
+
it('contains "Memory Protocol (JIT)" H2 section', () => {
|
|
41
|
+
expect(injectionContent).toMatch(/^## Memory Protocol \(JIT\)/m);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('contains "Escalation" H2 section', () => {
|
|
45
|
+
expect(injectionContent).toMatch(/^## Escalation/m);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('contains "Session Start" H2 section', () => {
|
|
49
|
+
expect(injectionContent).toMatch(/^## Session Start/m);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('contains "Work Loop" H2 section', () => {
|
|
53
|
+
expect(injectionContent).toMatch(/^## Work Loop/m);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('contains "Task Discovery" H2 section', () => {
|
|
57
|
+
expect(injectionContent).toMatch(/^## Task Discovery/m);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Command correctness
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
describe('CLEO-INJECTION.md — command correctness', () => {
|
|
66
|
+
it('contains "cleo memory observe" (not bare "cleo observe")', () => {
|
|
67
|
+
// Must contain the correct form
|
|
68
|
+
expect(injectionContent).toContain('cleo memory observe');
|
|
69
|
+
|
|
70
|
+
// The bare `cleo observe` form should NOT appear as an active command
|
|
71
|
+
// (it may appear historically in comments, but check context)
|
|
72
|
+
const lines = injectionContent.split('\n');
|
|
73
|
+
const bareObserveInstructions = lines.filter((line) => {
|
|
74
|
+
// Skip table rows and markdown formatting
|
|
75
|
+
if (/^\s*\|/.test(line)) return false;
|
|
76
|
+
if (line.trim().startsWith('-')) return false;
|
|
77
|
+
// Check for bare `cleo observe` in code examples or instructions
|
|
78
|
+
return (
|
|
79
|
+
/\bcleo observe\b/.test(line) &&
|
|
80
|
+
!line.includes('cleo memory observe')
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Should be zero or only in legacy/comment context
|
|
85
|
+
expect(bareObserveInstructions).toHaveLength(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('contains "cleo orchestrate start" in documentation', () => {
|
|
89
|
+
expect(injectionContent).toMatch(/cleo orchestrate start/);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('contains "cleo session status" command', () => {
|
|
93
|
+
expect(injectionContent).toContain('cleo session status');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('contains "cleo show" command', () => {
|
|
97
|
+
expect(injectionContent).toContain('cleo show');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('contains "cleo find" command', () => {
|
|
101
|
+
expect(injectionContent).toContain('cleo find');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Command diversity — at least 6 distinct cleo <verb> patterns
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
describe('CLEO-INJECTION.md — command diversity', () => {
|
|
110
|
+
it('contains at least 6 distinct "cleo <verb>" command patterns', () => {
|
|
111
|
+
// Extract all `cleo <word>` patterns (first word after cleo)
|
|
112
|
+
const verbs = new Set<string>();
|
|
113
|
+
const pattern = /\bcleo\s+([a-z][a-z0-9-]*)/g;
|
|
114
|
+
let match: RegExpExecArray | null;
|
|
115
|
+
|
|
116
|
+
// eslint-disable-next-line no-cond-assign
|
|
117
|
+
while ((match = pattern.exec(injectionContent)) !== null) {
|
|
118
|
+
verbs.add(match[1]);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// List them for debugging if needed
|
|
122
|
+
const verbsArray = Array.from(verbs).sort();
|
|
123
|
+
expect(verbs.size).toBeGreaterThanOrEqual(6);
|
|
124
|
+
expect(verbsArray).toContain('session');
|
|
125
|
+
expect(verbsArray).toContain('show');
|
|
126
|
+
expect(verbsArray).toContain('find');
|
|
127
|
+
expect(verbsArray).toContain('memory');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Content completeness
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
describe('CLEO-INJECTION.md — content completeness', () => {
|
|
136
|
+
it('references Protocol version in header', () => {
|
|
137
|
+
expect(injectionContent).toMatch(/Version:\s*[\d.]+/);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('contains error handling section', () => {
|
|
141
|
+
expect(injectionContent).toMatch(/## Error Handling/);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('contains Rules section', () => {
|
|
145
|
+
expect(injectionContent).toMatch(/## Rules/);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('mentions worktree or isolation pattern', () => {
|
|
149
|
+
// The protocol should reference some form of process isolation
|
|
150
|
+
expect(injectionContent).toMatch(
|
|
151
|
+
/worktree|isolation|scope|namespace|context|dedicated/i
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
});
|