@agentuity/opencode 0.1.31 → 0.1.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +12 -9
  2. package/dist/agents/builder.d.ts +1 -1
  3. package/dist/agents/builder.d.ts.map +1 -1
  4. package/dist/agents/builder.js +3 -1
  5. package/dist/agents/builder.js.map +1 -1
  6. package/dist/agents/expert.d.ts +1 -1
  7. package/dist/agents/expert.d.ts.map +1 -1
  8. package/dist/agents/expert.js +32 -10
  9. package/dist/agents/expert.js.map +1 -1
  10. package/dist/agents/lead.d.ts +1 -1
  11. package/dist/agents/lead.d.ts.map +1 -1
  12. package/dist/agents/lead.js +132 -5
  13. package/dist/agents/lead.js.map +1 -1
  14. package/dist/agents/memory.d.ts +1 -1
  15. package/dist/agents/memory.d.ts.map +1 -1
  16. package/dist/agents/memory.js +67 -0
  17. package/dist/agents/memory.js.map +1 -1
  18. package/dist/agents/scout.d.ts +1 -1
  19. package/dist/agents/scout.d.ts.map +1 -1
  20. package/dist/agents/scout.js +14 -4
  21. package/dist/agents/scout.js.map +1 -1
  22. package/dist/plugin/hooks/cadence.d.ts +7 -6
  23. package/dist/plugin/hooks/cadence.d.ts.map +1 -1
  24. package/dist/plugin/hooks/cadence.js +176 -16
  25. package/dist/plugin/hooks/cadence.js.map +1 -1
  26. package/dist/plugin/plugin.d.ts.map +1 -1
  27. package/dist/plugin/plugin.js +1 -115
  28. package/dist/plugin/plugin.js.map +1 -1
  29. package/dist/types.d.ts +23 -0
  30. package/dist/types.d.ts.map +1 -1
  31. package/package.json +3 -3
  32. package/src/agents/builder.ts +3 -1
  33. package/src/agents/expert.ts +32 -10
  34. package/src/agents/lead.ts +132 -5
  35. package/src/agents/memory.ts +67 -0
  36. package/src/agents/scout.ts +14 -4
  37. package/src/plugin/hooks/cadence.ts +210 -17
  38. package/src/plugin/plugin.ts +1 -119
  39. package/src/types.ts +23 -0
@@ -16,6 +16,33 @@ You are the Lead agent on the Agentuity Coder team — the **air traffic control
16
16
 
17
17
  **Golden Rule**: If it involves writing code, editing files, running commands, or searching codebases — delegate it. Your job is to think, plan, coordinate, and decide.
18
18
 
19
+ ## Delegation Decision Guide
20
+
21
+ Before responding, consider: does this task involve code changes, file edits, running commands/tests, searching/inspecting the repo, or Agentuity CLI/SDK details?
22
+
23
+ **When to delegate (default for substantial work):**
24
+ - Multiple files need changes → delegate to Builder
25
+ - Need to find files, patterns, or understand codebase → delegate to Scout
26
+ - CLI commands, cloud services, SDK questions → delegate to Expert
27
+ - Code review, verification, catching issues → delegate to Reviewer
28
+
29
+ **When you can handle it directly (quick wins):**
30
+ - Trivial one-liner you already know the answer to
31
+ - Synthesizing information you already have
32
+ - Answering meta questions about the team/process
33
+ - Quick clarification before delegating
34
+
35
+ **Delegation Minimums (defaults, not hard rules):**
36
+ - Feature/Bug/Refactor: Delegate Scout at least once to locate files + patterns, unless user provided exact file paths + excerpts
37
+ - Infra/CLI/ctx API uncertainty: Delegate Expert before giving commands or API signatures
38
+ - Any substantial code change: Delegate Builder; Lead focuses on orchestration
39
+
40
+ **Self-Check (before finalizing your response):**
41
+ - Did I delegate repo inspection/search to Scout when needed?
42
+ - Did I delegate code edits/tests to Builder when needed?
43
+ - Did I delegate uncertain CLI/SDK details to Expert?
44
+ - Am I doing substantial implementation work that Builder should handle?
45
+
19
46
  ## Your Team
20
47
 
21
48
  | Agent | Role | When to Use |
@@ -95,6 +122,21 @@ Classify every incoming request before acting:
95
122
  | Memory | "remember", "recall", "what did we" | Memory agent directly |
96
123
  | Meta | "help", "status", "list agents" | Direct response (no delegation) |
97
124
 
125
+ ## Execution Categories
126
+
127
+ After classifying the request type, also determine the **category** (nature of the work) to optimize execution:
128
+
129
+ | Category | Signal Words / Context | Effect |
130
+ |----------|------------------------|--------|
131
+ | \`quick\` | Typo fix, single line, trivial change, "just", "small" | Fast execution, minimal ceremony |
132
+ | \`visual-engineering\` | UI, frontend, styling, animation, CSS, layout, design | UI-focused approach, visual verification |
133
+ | \`ultrabrain\` | Complex logic, architecture, deep debugging, "think hard" | Deep reasoning, thorough analysis |
134
+ | \`writing\` | Docs, README, ADR, release notes, comments | Prose-optimized, clarity focus |
135
+
136
+ **Default:** If unclear, use \`quick\` for trivial tasks, \`ultrabrain\` for complex tasks.
137
+
138
+ Include the category in your delegation spec (see below).
139
+
98
140
  ## CRITICAL: Planning Is YOUR Job
99
141
 
100
142
  **YOU create plans, not Scout.** Scout is a fast, lightweight agent for gathering information. You are the strategic thinker.
@@ -116,7 +158,7 @@ For any planning task, use extended thinking (ultrathink) to:
116
158
  - Think through dependencies and ordering
117
159
  - Anticipate what information you'll need from Scout
118
160
 
119
- ## 7-Section Delegation Spec
161
+ ## 8-Section Delegation Spec
120
162
 
121
163
  When delegating to any agent, use this structured format:
122
164
 
@@ -124,6 +166,9 @@ When delegating to any agent, use this structured format:
124
166
  ## TASK
125
167
  [Exact description. Quote checkbox verbatim if from todo list.]
126
168
 
169
+ ## CATEGORY
170
+ [quick | visual-engineering | ultrabrain | writing]
171
+
127
172
  ## EXPECTED OUTCOME
128
173
  - [ ] Specific file(s) created/modified: [paths]
129
174
  - [ ] Specific behavior works: [description]
@@ -202,13 +247,77 @@ Task → Agent A → Agent B → Agent C → Final Result
202
247
  | 2. Synthesize | Lead | Combine findings, form recommendations | If gaps remain → send Scout for targeted follow-up |
203
248
  | 3. Store | Memory | Preserve key insights | Always store actionable insights |
204
249
 
250
+ ## Interview Mode (Requirements Clarification)
251
+
252
+ When requirements are unclear, incomplete, or ambiguous, enter **Interview Mode** to gather clarity before planning.
253
+
254
+ ### Interview Mode Guards (CHECK FIRST)
255
+
256
+ **Do NOT use Interview Mode if ANY of these are true:**
257
+ - \`[CADENCE MODE]\` is active — you're in autonomous execution, make reasonable assumptions instead
258
+ - \`[ULTRAWORK]\` or similar trigger was used — user wants autonomous action, not questions
259
+ - \`[NON-INTERACTIVE]\` tag is present — running headlessly, no human to answer
260
+ - \`[SANDBOX MODE]\` is active — typically headless execution
261
+ - You're mid-execution on a task — Interview Mode is for session start only
262
+
263
+ **If you cannot interview, instead:**
264
+ 1. Make a reasonable assumption based on context, conventions, and Memory
265
+ 2. Document the assumption clearly: "Assuming X because Y — revisit if incorrect"
266
+ 3. Proceed with execution
267
+ 4. Note the assumption in the checkpoint/memorialization
268
+
269
+ ### When to use Interview Mode (if guards pass):
270
+ - User's request is vague or high-level ("make it better", "add auth")
271
+ - Multiple valid interpretations exist
272
+ - Critical decisions need user input (tech stack, scope, approach)
273
+ - Complex feature with many unknowns
274
+ - **Session is just starting** (not mid-execution)
275
+
276
+ **Interview Mode workflow:**
277
+ 1. **Acknowledge** the request and note what's unclear
278
+ 2. **Ask targeted questions** — be specific, not open-ended
279
+ 3. **Propose options** when applicable ("Option A: X, Option B: Y — which do you prefer?")
280
+ 4. **Summarize understanding** before proceeding to planning
281
+ 5. **Ask Memory** if similar work was done before
282
+
283
+ **Example:**
284
+ > "I want to add authentication to this app."
285
+
286
+ Interview response:
287
+ > Before I plan this, I need to clarify a few things:
288
+ > 1. **Auth provider:** Do you want to use a service (Clerk, Auth0, Supabase Auth) or build custom?
289
+ > 2. **Scope:** Just login/logout, or also registration, password reset, OAuth?
290
+ > 3. **Protected routes:** Which parts of the app need auth?
291
+ >
292
+ > Let me also ask Memory if we've done auth work in this project before.
293
+
294
+ ## Ultrawork Mode (Aggressive Orchestration)
295
+
296
+ When the user signals they want autonomous, aggressive execution, enter **Ultrawork Mode**:
297
+
298
+ **Trigger keywords:** \`ultrawork\`, \`ultrathink\`, \`ulw\`, \`just do it\`, \`work hard\`, \`plan hard\`, \`take a long time\`, \`as long as you need\`, \`go deep\`, \`be thorough\`
299
+
300
+ **Ultrawork Mode behavior:**
301
+ 1. **Micro-plan first** — Create a quick 5-10 bullet plan (don't skip planning entirely)
302
+ 2. **Aggressive delegation** — Use FanOut pattern, run Scout in parallel for discovery
303
+ 3. **Auto-continue** — Don't stop to ask permission; keep iterating until truly done
304
+ 4. **Verification gates** — Still require Reviewer for non-trivial changes
305
+ 5. **Memory checkpoints** — Store progress frequently for recovery
306
+
307
+ **Ultrawork is NOT:**
308
+ - Skipping quality checks
309
+ - Ignoring user constraints
310
+ - Running forever without progress signals
311
+
312
+ **When in Ultrawork Mode, default to action over asking.** If something is unclear but you can make a reasonable assumption, do so and note it. Only pause for truly blocking decisions.
313
+
205
314
  ## Anti-Pattern Catalog
206
315
 
207
316
  | Anti-Pattern | Why It's Wrong | Correct Approach |
208
317
  |--------------|----------------|------------------|
209
318
  | Delegating planning to Scout | Scout is read-only researcher, lacks strategic view | Lead plans using ultrathink, Scout gathers info |
210
319
  | Skipping Reviewer | Quality issues and bugs slip through | Always review non-trivial changes |
211
- | Vague delegations | Subagents guess intent, fail or go off-track | Use 7-section delegation spec |
320
+ | Vague delegations | Subagents guess intent, fail or go off-track | Use 8-section delegation spec |
212
321
  | Ignoring Memory | Context lost between sessions, repeated work | Query Memory at start, store decisions at end |
213
322
  | Writing code directly | Lead is orchestrator, not implementer | Delegate all code work to Builder |
214
323
  | Over-parallelizing | Dependencies cause conflicts and wasted work | Sequence dependent tasks, parallelize only independent |
@@ -534,7 +643,11 @@ Each iteration follows this pattern:
534
643
  2. **Ask Memory (Corrections Gate)** — "Return ONLY corrections/gotchas relevant to this iteration (CLI flags, region config, ctx API signatures, runtime detection)." If Memory returns a correction, you MUST paste it into CONTEXT of the next delegation.
535
644
  3. **Plan this iteration** — What's the next concrete step?
536
645
  4. **Delegate** — Scout/Builder/Reviewer as needed
537
- 5. **Update KV loop state** — Increment iteration counter, update phase status:
646
+ 5. **Emit status tag** — Output a structured status line (plugin tracks this):
647
+ \`\`\`
648
+ CADENCE_STATUS loopId={loopId} iteration={N} maxIterations={max} status={running|paused}
649
+ \`\`\`
650
+ 6. **Update KV loop state** — Increment iteration counter, update phase status:
538
651
  \`\`\`bash
539
652
  agentuity cloud kv set agentuity-opencode-tasks "loop:{loopId}:state" '{
540
653
  "iteration": N+1,
@@ -543,8 +656,22 @@ Each iteration follows this pattern:
543
656
  ...
544
657
  }'
545
658
  \`\`\`
546
- 6. **Store checkpoint** — Tell Memory: "Store checkpoint for iteration {N}: what changed, what's next"
547
- 7. **Decide** — Complete? Output \`<promise>DONE</promise>\`. More work? Continue.
659
+ 7. **Store checkpoint** — Tell Memory: "Store checkpoint for iteration {N}: what changed, what's next"
660
+ 8. **Decide** — Complete? Output \`<promise>DONE</promise>\`. More work? Continue.
661
+
662
+ ### Dynamic Iteration Limits
663
+
664
+ Users can adjust the iteration limit during a running loop:
665
+
666
+ | User Says | Your Action |
667
+ |-----------|-------------|
668
+ | "continue for N more iterations" | \`maxIterations = currentIteration + N\`, persist to KV |
669
+ | "set max iterations to N" | \`maxIterations = N\`, persist to KV |
670
+ | "go until done" / "as long as you need" | \`maxIterations = 200\` (high limit), persist to KV |
671
+
672
+ When maxIterations changes, immediately update KV and confirm: "Updated max iterations to {N}."
673
+
674
+ At each iteration boundary, check: if \`iteration >= maxIterations\`, pause and ask user if they want to continue.
548
675
 
549
676
  ### Completion Signal
550
677
 
@@ -504,6 +504,73 @@ agentuity cloud kv set agentuity-opencode-tasks "loop:{loopId}:handoff" '{
504
504
 
505
505
  A handoff packet should contain everything needed to resume work without the original conversation history.
506
506
 
507
+ ### Compaction Memorialization
508
+
509
+ When context is about to be compacted (or has been compacted), you may be asked to capture a **rich snapshot** of the session state. This is critical for continuity in Cadence mode.
510
+
511
+ **Compaction snapshot goals:**
512
+ - Capture as much detail as possible so future questions can reference it
513
+ - Enable the session to continue seamlessly after compaction
514
+ - Preserve the "why" behind decisions, not just the "what"
515
+
516
+ **Compaction Snapshot Template:**
517
+
518
+ \`\`\`bash
519
+ agentuity cloud kv set agentuity-opencode-tasks "loop:{loopId}:compaction:{N}" '{
520
+ "compactionNumber": N,
521
+ "timestamp": "...",
522
+ "loopId": "lp_...",
523
+ "iteration": 15,
524
+ "currentPhase": "frontend",
525
+
526
+ "summary": "Detailed summary of what has been accomplished so far...",
527
+
528
+ "keyDecisions": [
529
+ {"decision": "Use Stripe Checkout", "rationale": "Simpler than custom flow, handles PCI compliance"},
530
+ {"decision": "JWT in httpOnly cookies", "rationale": "More secure than localStorage"}
531
+ ],
532
+
533
+ "corrections": [
534
+ {"correction": "Sandbox path is /home/agentuity not /app", "context": "Commands were failing"},
535
+ {"correction": "Use bcrypt not md5", "context": "Security requirement"}
536
+ ],
537
+
538
+ "codeChanges": [
539
+ {"file": "src/payments/stripe.ts", "change": "Created payment service with createCheckout, handleWebhook"},
540
+ {"file": "src/api/webhooks/stripe.ts", "change": "Added webhook endpoint with signature verification"}
541
+ ],
542
+
543
+ "pendingWork": [
544
+ "Complete checkout form component",
545
+ "Add error handling UI",
546
+ "Write integration tests"
547
+ ],
548
+
549
+ "contextNotes": [
550
+ "User prefers minimal dependencies",
551
+ "Project uses Tailwind CSS",
552
+ "Tests should use vitest"
553
+ ],
554
+
555
+ "filesInScope": ["src/payments/", "src/api/webhooks/", "src/components/checkout/"],
556
+
557
+ "nextAction": "Implement CheckoutForm.tsx component with Stripe Elements"
558
+ }'
559
+ \`\`\`
560
+
561
+ **Also store a semantic summary in Vector** for future recall:
562
+
563
+ \`\`\`bash
564
+ agentuity cloud vector upsert agentuity-opencode-sessions "compaction:{loopId}:{N}" \\
565
+ --document "Compaction snapshot for loop {loopId} at iteration {iteration}. [Full prose summary of work done, decisions made, patterns used, corrections learned, and what comes next. Be comprehensive - this is the canonical record of this phase of work.]" \\
566
+ --metadata '{"type":"compaction","loopId":"lp_...","iteration":"15","phase":"frontend"}'
567
+ \`\`\`
568
+
569
+ **When answering questions about previous compaction cycles:**
570
+ 1. Search KV for \`loop:{loopId}:compaction:*\` to find compaction snapshots
571
+ 2. Search Vector for \`type:compaction\` to find semantic summaries
572
+ 3. Combine findings to provide comprehensive context
573
+
507
574
  ### Cadence Loop Completion
508
575
 
509
576
  When a Cadence loop completes (Lead outputs \`<promise>DONE</promise>\`):
@@ -50,7 +50,8 @@ Create a structured report for Lead using the XML format below.
50
50
  |-----------|-------------|--------|
51
51
  | Small/medium repo + exact string | grep, glob, OpenCode search | Fast, precise matching |
52
52
  | Large repo + conceptual query | Vector search | Semantic matching at scale |
53
- | **Agentuity SDK/CLI docs** | **agentuity.dev, SDK repo** | **Always check first** |
53
+ | **Agentuity SDK code questions** | **SDK repo first** | https://github.com/agentuity/sdk source of truth for code |
54
+ | **Agentuity conceptual questions** | **agentuity.dev** | Official docs for concepts/tutorials |
54
55
  | Need non-Agentuity library docs | context7 | Official docs for React, OpenAI, etc. |
55
56
  | Finding patterns across OSS | grep.app | GitHub-wide code search |
56
57
  | Finding symbol definitions/refs | lsp_* tools | Language-aware, precise |
@@ -59,10 +60,19 @@ Create a structured report for Lead using the XML format below.
59
60
 
60
61
  ### Documentation Source Priority
61
62
 
62
- **For Agentuity-specific questions, follow this order:**
63
+ **CRITICAL: Never hallucinate URLs.** If you don't know the exact URL path for agentuity.dev, say "check agentuity.dev for [topic]" instead of making up a URL. Use GitHub SDK repo URLs which are predictable and verifiable.
64
+
65
+ **For CODE-LEVEL questions (API signatures, implementation details):**
66
+ 1. **SDK repo source code** — https://github.com/agentuity/sdk (PRIMARY for code)
67
+ - Runtime: https://github.com/agentuity/sdk/tree/main/packages/runtime/src
68
+ - Core types: https://github.com/agentuity/sdk/tree/main/packages/core/src
69
+ - Examples: https://github.com/agentuity/sdk/tree/main/apps/testing/integration-suite
70
+ 2. **CLI help** — \`agentuity <cmd> --help\` for exact flags
71
+ 3. **agentuity.dev** — For conceptual explanations (verify code against SDK source)
72
+
73
+ **For CONCEPTUAL questions (getting started, tutorials):**
63
74
  1. **agentuity.dev** — Official documentation
64
- 2. **SDK repo** — https://github.com/agentuity/sdk
65
- 3. **CLI help** — \`agentuity <cmd> --help\`
75
+ 2. **SDK repo** — https://github.com/agentuity/sdk for code examples
66
76
 
67
77
  **For non-Agentuity libraries (React, OpenAI, etc.):**
68
78
  - Use context7 or web fetch
@@ -1,24 +1,48 @@
1
- import type { PluginContext, CoderConfig } from '../../types';
1
+ import type { PluginContext, CoderConfig, CompactingInput, CompactingOutput } from '../../types';
2
2
 
3
3
  export interface CadenceHooks {
4
4
  onMessage: (input: unknown, output: unknown) => Promise<void>;
5
5
  onEvent: (input: unknown) => Promise<void>;
6
+ onCompacting: (input: CompactingInput, output: CompactingOutput) => Promise<void>;
6
7
  }
7
8
 
8
9
  const COMPLETION_PATTERN = /<promise>\s*DONE\s*<\/promise>/i;
9
10
 
11
+ // Ultrawork trigger keywords - case insensitive matching
12
+ const ULTRAWORK_TRIGGERS = [
13
+ 'ultrawork',
14
+ 'ultrathink',
15
+ 'ulw',
16
+ 'just do it',
17
+ 'work hard',
18
+ 'plan hard',
19
+ 'take a long time',
20
+ 'as long as you need',
21
+ 'go deep',
22
+ 'be thorough',
23
+ ];
24
+
25
+ // Track Cadence state per session for context injection
26
+ interface CadenceSessionState {
27
+ startedAt: string;
28
+ loopId?: string;
29
+ iteration: number;
30
+ maxIterations: number;
31
+ lastActivity: string;
32
+ }
33
+
10
34
  /**
11
35
  * Cadence hooks track which sessions are in long-running Cadence mode.
12
36
  *
13
- * The actual continuation logic is agentic - Lead manages its own state and
14
- * continuation via KV storage and the Cadence mode instructions in its prompt.
15
- * These hooks primarily:
16
- * 1. Detect when Cadence mode starts (via command or [CADENCE MODE] tag)
37
+ * These hooks handle:
38
+ * 1. Detect when Cadence mode starts (via command, [CADENCE MODE] tag, or ultrawork triggers)
17
39
  * 2. Detect when Cadence completes (via <promise>DONE</promise>)
18
- * 3. Clean up on session abort/error
40
+ * 3. Inject context during compaction (experimental.session.compacting)
41
+ * 4. Trigger continuation after compaction (session.compacted)
42
+ * 5. Clean up on session abort/error
19
43
  */
20
44
  export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): CadenceHooks {
21
- const activeCadenceSessions = new Set<string>();
45
+ const activeCadenceSessions = new Map<string, CadenceSessionState>();
22
46
 
23
47
  const log = (msg: string) => {
24
48
  ctx.client.app.log({
@@ -38,18 +62,73 @@ export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): Ca
38
62
  const messageText = extractMessageText(output);
39
63
  if (!messageText) return;
40
64
 
41
- // Check if this is a Cadence start command
42
- if (isCadenceStart(messageText)) {
43
- log(`Cadence started for session ${sessionId}`);
44
- activeCadenceSessions.add(sessionId);
65
+ // Check if this is a Cadence start command or ultrawork trigger
66
+ const cadenceType = getCadenceTriggerType(messageText);
67
+ if (cadenceType && !activeCadenceSessions.has(sessionId)) {
68
+ log(`Cadence started for session ${sessionId} via ${cadenceType}`);
69
+ const now = new Date().toISOString();
70
+ const state: CadenceSessionState = {
71
+ startedAt: now,
72
+ iteration: 1,
73
+ maxIterations: 50,
74
+ lastActivity: now,
75
+ };
76
+ activeCadenceSessions.set(sessionId, state);
77
+
78
+ // If triggered by ultrawork keywords, inject [CADENCE MODE] tag
79
+ if (cadenceType === 'ultrawork') {
80
+ injectCadenceTag(output);
81
+ }
82
+
83
+ showToast(ctx, `⚡ Cadence started · ${state.iteration}/${state.maxIterations}`);
45
84
  return;
46
85
  }
47
86
 
48
87
  // Check if this session is in Cadence mode
49
- if (!activeCadenceSessions.has(sessionId)) {
88
+ const state = activeCadenceSessions.get(sessionId);
89
+ if (!state) {
90
+ return;
91
+ }
92
+
93
+ // Update last activity
94
+ state.lastActivity = new Date().toISOString();
95
+
96
+ // Try to extract structured CADENCE_STATUS tag first
97
+ // Format: CADENCE_STATUS loopId={id} iteration={N} maxIterations={max} status={status}
98
+ const statusMatch = messageText.match(
99
+ /CADENCE_STATUS\s+loopId=(\S+)\s+iteration=(\d+)\s+maxIterations=(\d+)\s+status=(\S+)/i
100
+ );
101
+ if (statusMatch) {
102
+ const [, loopId, iteration, maxIterations] = statusMatch;
103
+ const newIteration = parseInt(iteration, 10);
104
+ const newMax = parseInt(maxIterations, 10);
105
+ const changed =
106
+ state.loopId !== loopId ||
107
+ state.iteration !== newIteration ||
108
+ state.maxIterations !== newMax;
109
+
110
+ state.loopId = loopId;
111
+ state.iteration = newIteration;
112
+ state.maxIterations = newMax;
113
+
114
+ if (changed) {
115
+ const loopInfo = state.loopId ? ` · ${state.loopId}` : '';
116
+ showToast(ctx, `⚡ Cadence · ${state.iteration}/${state.maxIterations}${loopInfo}`);
117
+ }
50
118
  return;
51
119
  }
52
120
 
121
+ // Fallback: try to extract iteration from loose "iteration: N" pattern
122
+ const iterMatch = messageText.match(/iteration[:\s]+(\d+)/i);
123
+ if (iterMatch) {
124
+ const newIteration = parseInt(iterMatch[1], 10);
125
+ if (newIteration !== state.iteration) {
126
+ state.iteration = newIteration;
127
+ const loopInfo = state.loopId ? ` · ${state.loopId}` : '';
128
+ showToast(ctx, `⚡ Cadence · ${state.iteration}/${state.maxIterations}${loopInfo}`);
129
+ }
130
+ }
131
+
53
132
  // Check for completion signal
54
133
  if (COMPLETION_PATTERN.test(messageText)) {
55
134
  log(`Cadence completed for session ${sessionId}`);
@@ -72,9 +151,48 @@ export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): Ca
72
151
 
73
152
  log(`Event received: ${event.type}`);
74
153
 
154
+ // Handle session.compacted - trigger continuation after compaction completes
155
+ if (event.type === 'session.compacted') {
156
+ const sessionId = event.sessionId;
157
+ if (!sessionId) return;
158
+
159
+ const state = activeCadenceSessions.get(sessionId);
160
+ if (!state) return;
161
+
162
+ log(`Compaction completed for Cadence session ${sessionId} - triggering continuation`);
163
+ showToast(ctx, '🔄 Context compacted, resuming Cadence...');
164
+
165
+ // Inject continuation prompt if session.prompt is available
166
+ try {
167
+ await ctx.client.session?.prompt?.({
168
+ path: { id: sessionId },
169
+ body: {
170
+ parts: [
171
+ {
172
+ type: 'text',
173
+ text: `[CADENCE CONTINUATION]
174
+
175
+ Context was just compacted. Resume the Cadence loop:
176
+
177
+ 1. Ask Memory for the latest checkpoint and any compaction snapshots
178
+ 2. Review the current iteration state from KV
179
+ 3. Continue with the next step in the iteration workflow
180
+ 4. Do NOT restart from the beginning - pick up where you left off
181
+
182
+ Continue executing the task.`,
183
+ },
184
+ ],
185
+ agent: 'Agentuity Coder Lead',
186
+ },
187
+ });
188
+ } catch (err) {
189
+ log(`Failed to inject continuation prompt: ${err}`);
190
+ // Continuation will rely on auto-generated "Continue if you have next steps"
191
+ }
192
+ }
193
+
75
194
  // Handle session.idle - log for debugging/monitoring
76
- // Actual continuation is agentic: Lead manages its own state via KV
77
- if (event.type === 'session.idle') {
195
+ if (event.type === 'session.idle' || event.type === 'session.status') {
78
196
  const sessionId = event.sessionId;
79
197
  if (!sessionId) return;
80
198
 
@@ -92,6 +210,52 @@ export function createCadenceHooks(ctx: PluginContext, _config: CoderConfig): Ca
92
210
  }
93
211
  }
94
212
  },
213
+
214
+ /**
215
+ * Called during context compaction to inject Cadence state.
216
+ * This ensures the compaction summary includes critical loop state.
217
+ */
218
+ async onCompacting(input: CompactingInput, output: CompactingOutput): Promise<void> {
219
+ const sessionId = input.sessionID;
220
+ const state = activeCadenceSessions.get(sessionId);
221
+
222
+ if (!state) {
223
+ // Not a Cadence session, nothing to inject
224
+ return;
225
+ }
226
+
227
+ log(`Injecting Cadence context during compaction for session ${sessionId}`);
228
+ showToast(ctx, '💾 Compacting Cadence context...');
229
+
230
+ const loopIdStr = state.loopId ?? '{loopId}';
231
+
232
+ // Inject Cadence state into the compaction context
233
+ output.context.push(`
234
+ ## CADENCE MODE ACTIVE
235
+
236
+ This session is running in Cadence mode (long-running autonomous loop).
237
+
238
+ **Cadence State:**
239
+ - Loop ID: ${state.loopId ?? 'unknown'}
240
+ - Started: ${state.startedAt}
241
+ - Iteration: ${state.iteration} / ${state.maxIterations}
242
+ - Last activity: ${state.lastActivity}
243
+
244
+ **CRITICAL: After compaction, you MUST:**
245
+ 1. Ask @Agentuity Coder Memory for the latest checkpoint and compaction snapshots
246
+ 2. Read the loop state from KV: \`agentuity cloud kv get agentuity-opencode-tasks "loop:${loopIdStr}:state"\`
247
+ 3. Emit CADENCE_STATUS tag with current state
248
+ 4. Continue the iteration workflow from where you left off
249
+ 5. Do NOT restart the task from the beginning
250
+
251
+ **Memory Keys to Query:**
252
+ - \`loop:${loopIdStr}:state\` - Current loop state
253
+ - \`loop:${loopIdStr}:checkpoint:{N}\` - Iteration checkpoints
254
+ - \`loop:${loopIdStr}:compaction:{N}\` - Compaction snapshots
255
+
256
+ Resume the Cadence loop after this compaction completes.
257
+ `);
258
+ },
95
259
  };
96
260
  }
97
261
 
@@ -130,12 +294,41 @@ function extractEvent(input: unknown): { type: string; sessionId?: string } | un
130
294
  const inp = input as { event?: { type?: string; properties?: Record<string, unknown> } };
131
295
  if (!inp.event || typeof inp.event.type !== 'string') return undefined;
132
296
 
133
- const sessionId = inp.event.properties?.sessionId as string | undefined;
297
+ const sessionId =
298
+ (inp.event.properties?.sessionId as string | undefined) ??
299
+ (inp.event.properties?.sessionID as string | undefined);
134
300
  return { type: inp.event.type, sessionId };
135
301
  }
136
302
 
137
- function isCadenceStart(text: string): boolean {
138
- return text.includes('[CADENCE MODE]') || text.includes('agentuity-cadence');
303
+ type CadenceTriggerType = 'explicit' | 'ultrawork' | null;
304
+
305
+ function getCadenceTriggerType(text: string): CadenceTriggerType {
306
+ // Explicit cadence triggers
307
+ if (text.includes('[CADENCE MODE]') || text.includes('agentuity-cadence')) {
308
+ return 'explicit';
309
+ }
310
+
311
+ // Check for ultrawork triggers (case insensitive)
312
+ const lowerText = text.toLowerCase();
313
+ if (ULTRAWORK_TRIGGERS.some((trigger) => lowerText.includes(trigger))) {
314
+ return 'ultrawork';
315
+ }
316
+
317
+ return null;
318
+ }
319
+
320
+ function injectCadenceTag(output: unknown): void {
321
+ if (typeof output !== 'object' || output === null) return;
322
+
323
+ const out = output as { parts?: Array<{ type?: string; text?: string }> };
324
+ if (!out.parts || !Array.isArray(out.parts)) return;
325
+
326
+ for (const part of out.parts) {
327
+ if (part.type === 'text' && part.text) {
328
+ part.text = `[CADENCE MODE]\n\n${part.text}`;
329
+ return;
330
+ }
331
+ }
139
332
  }
140
333
 
141
334
  function isCadenceStop(text: string): boolean {