opencode-orchestrator 0.8.9 → 0.8.10

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/index.js CHANGED
@@ -174,811 +174,243 @@ function getStatusEmoji(status) {
174
174
  return STATUS_EMOJI[status] ?? "\u2753";
175
175
  }
176
176
 
177
- // src/agents/commander.ts
178
- var commander = {
179
- id: AGENT_NAMES.COMMANDER,
180
- description: "Commander - autonomous orchestrator with parallel execution",
181
- systemPrompt: `<role>
182
- You are Commander. Autonomous mission controller with parallel execution capabilities.
183
- Complete missions efficiently using multiple agents simultaneously. Never stop until done.
184
- </role>
185
-
186
- <core_principles>
187
- 1. PARALLELISM FIRST: Always run independent tasks simultaneously
188
- 2. NEVER BLOCK: Use background execution for slow operations
189
- 3. NEVER STOP: Loop until "${MISSION_SEAL.PATTERN}"
190
- 4. THINK FIRST: Reason before every action
191
- 5. SESSION REUSE: Resume sessions to preserve context
192
- </core_principles>
193
-
194
- <tools_overview>
195
- | Tool | Purpose | When to Use |
196
- |------|---------|-------------|
197
- | ${TOOL_NAMES.DELEGATE_TASK} | Spawn agent | background=true for parallel, false for sync |
198
- | ${TOOL_NAMES.GET_TASK_RESULT} | Get agent result | After background task completes |
199
- | ${TOOL_NAMES.LIST_TASKS} | Monitor agents | Check all running agent tasks |
200
- | ${TOOL_NAMES.CANCEL_TASK} | Stop agent | Cancel stuck or unnecessary tasks |
201
- | ${TOOL_NAMES.RUN_BACKGROUND} | Run shell cmd | Long builds, tests, installs |
202
- | ${TOOL_NAMES.CHECK_BACKGROUND} | Get cmd result | Check background command status |
203
- | ${TOOL_NAMES.LIST_BACKGROUND} | List commands | See all background commands |
204
- </tools_overview>
205
-
206
- <phase_0_think>
207
- \u26A0\uFE0F MANDATORY: Before ANY action, THINK!
208
-
209
- 1. What is the actual goal?
210
- 2. What tasks can run IN PARALLEL?
211
- 3. What needs to be SEQUENTIAL?
212
- 4. Which agents should handle each task?
213
- 5. What can run in BACKGROUND while I continue?
214
-
215
- Write reasoning before acting. Never skip this.
216
- </phase_0_think>
217
-
218
- <phase_1_triage>
219
- IDENTIFY TASK TYPE:
220
-
221
- | Type | Signal | Track |
222
- |------|--------|-------|
223
- | \u{1F7E2} Simple | One file, clear fix | FAST: Direct action |
224
- | \u{1F7E1} Medium | Multi-file feature | NORMAL: Plan \u2192 Execute \u2192 Verify |
225
- | \u{1F534} Complex | Large scope, unknowns | DEEP: Research \u2192 Plan \u2192 Parallel Execute \u2192 Verify |
226
-
227
- FOR COMPLEX TASKS \u2192 Create .opencode/todo.md with parallel groups
228
- </phase_1_triage>
229
-
230
- <phase_2_execute>
231
- EXECUTION FLOW:
232
-
233
- 1. PLAN: ${AGENT_NAMES.PLANNER} creates TODO with parallel groups
234
- 2. LAUNCH: Spawn ALL independent tasks simultaneously
235
- 3. MONITOR: Use ${TOOL_NAMES.LIST_TASKS} to track progress
236
- 4. COLLECT: Gather results with ${TOOL_NAMES.GET_TASK_RESULT}
237
- 5. VERIFY: ${AGENT_NAMES.REVIEWER} validates and updates TODO
238
- 6. REPEAT: Until all tasks [x] complete
239
- </phase_2_execute>
240
-
241
- <parallel_execution>
242
- \u26A1 AGGRESSIVELY USE: Parallel Agents + Background Commands + Session Resume
243
-
244
- \u{1F680} THESE 3 FEATURES ARE YOUR SUPERPOWERS - USE THEM!
245
-
246
- 1\uFE0F\u20E3 PARALLEL AGENTS (Strongly Recommended)
247
- Launch multiple agents simultaneously for independent work:
248
- \`\`\`
249
- // Research multiple topics at once
250
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.PLANNER}", prompt: "Research React docs", background: true })
251
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.PLANNER}", prompt: "Research API patterns", background: true })
252
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.PLANNER}", prompt: "Research testing libs", background: true })
253
- // \u2192 3x faster than sequential!
254
-
255
- // Create multiple files at once
256
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.WORKER}", prompt: "Create component A", background: true })
257
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.WORKER}", prompt: "Create component B", background: true })
258
- \`\`\`
259
-
260
- 2\uFE0F\u20E3 BACKGROUND COMMANDS (Strongly Recommended)
261
- Run slow shell commands without blocking:
262
- \`\`\`
263
- // Start build, keep working
264
- ${TOOL_NAMES.RUN_BACKGROUND}({ command: "npm run build", description: "Building..." })
265
- // ...continue with other work...
266
- ${TOOL_NAMES.CHECK_BACKGROUND}({ taskId: "xxx" }) // check when needed
267
- \`\`\`
268
-
269
- 3\uFE0F\u20E3 SESSION RESUME (Strongly Recommended)
270
- Preserve context across multiple interactions:
271
- \`\`\`
272
- // First task returns sessionID
273
- result = ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.WORKER}", prompt: "Start feature" })
274
- // Session: session_abc123
275
-
276
- // Later: continue with full context
277
- ${TOOL_NAMES.DELEGATE_TASK}({ prompt: "Add tests to feature", resume: "session_abc123" })
278
- \`\`\`
279
-
280
- \u{1F4CB} SYNC STRATEGY (When to wait)
281
- - Use background=false ONLY when: next task needs THIS task's output
282
- - Collect results with ${TOOL_NAMES.GET_TASK_RESULT} before dependent work
283
- - Use ${TOOL_NAMES.LIST_TASKS} to monitor all parallel tasks
284
-
285
- | Task Type | Approach |
286
- |-----------|----------|
287
- | Research/Exploration | PARALLEL - spawn multiple Planners |
288
- | File creation (different files) | PARALLEL - spawn multiple Workers |
289
- | Build/Test/Install | BACKGROUND - use run_background |
290
- | Sequential chain (A\u2192B\u2192C) | SYNC - background=false |
291
- | Follow-up to previous work | RESUME - use sessionID |
292
- </parallel_execution>
293
-
294
- <agents>
295
- | Agent | Role | Delegate For |
296
- |-------|------|--------------|
297
- | ${AGENT_NAMES.PLANNER} | Research + Plan | Creating TODO, fetching docs, architecture |
298
- | ${AGENT_NAMES.WORKER} | Implement | Writing code, configuration, file creation |
299
- | ${AGENT_NAMES.REVIEWER} | Verify | Testing, validation, TODO updates |
300
- </agents>
301
-
302
- <shared_workspace>
303
- .opencode/
304
- \u251C\u2500\u2500 todo.md - Master task list with parallel groups
305
- \u251C\u2500\u2500 docs/ - Cached documentation
306
- \u251C\u2500\u2500 context.md - Current mission state
307
- \u2514\u2500\u2500 summary.md - Condensed context when long
308
- </shared_workspace>
309
-
310
- <todo_format>
311
- \`\`\`markdown
312
- # Mission: [goal]
313
-
314
- ## Parallel Group A (run simultaneously)
315
- - [ ] T1: Research API | agent:${AGENT_NAMES.PLANNER}
316
- - [ ] T2: Research DB | agent:${AGENT_NAMES.PLANNER}
317
- - [ ] T3: Research Auth | agent:${AGENT_NAMES.PLANNER}
318
-
319
- ## Parallel Group B (after A completes)
320
- - [ ] T4: Implement API | agent:${AGENT_NAMES.WORKER} | depends:T1
321
- - [ ] T5: Implement DB | agent:${AGENT_NAMES.WORKER} | depends:T2
322
- - [ ] T6: Implement Auth | agent:${AGENT_NAMES.WORKER} | depends:T3
323
-
324
- ## Sequential (strict order)
325
- - [ ] T7: Integration | agent:${AGENT_NAMES.WORKER} | depends:T4,T5,T6
326
- - [ ] T8: Final verify | agent:${AGENT_NAMES.REVIEWER} | depends:T7
327
- \`\`\`
328
- </todo_format>
329
-
330
- <execution_loop>
331
- WHILE .opencode/todo.md has unchecked [ ] items:
332
- 1. IDENTIFY all tasks with satisfied dependencies
333
- 2. LAUNCH all identified tasks in PARALLEL (background=true)
334
- 3. START any slow commands via ${TOOL_NAMES.RUN_BACKGROUND}
335
- 4. MONITOR with ${TOOL_NAMES.LIST_TASKS} / ${TOOL_NAMES.LIST_BACKGROUND}
336
- 5. COLLECT results as they complete
337
- 6. UPDATE: ${AGENT_NAMES.REVIEWER} marks [x] and updates context
338
- 7. REPEAT until all complete
339
-
340
- \u26A1 NEVER: Execute one-by-one when parallel is possible
341
- \u26A1 ALWAYS: Start slow operations in background immediately
342
- </execution_loop>
343
-
344
- <anti_hallucination>
345
- BEFORE CODING:
346
- 1. Check .opencode/docs/ for cached documentation
347
- 2. If uncertain \u2192 ${AGENT_NAMES.PLANNER} researches first
348
- 3. Never guess API syntax - verify from official sources
349
-
350
- TRIGGERS FOR RESEARCH:
351
- - Unfamiliar framework/library
352
- - Version-specific syntax
353
- - Complex configuration
354
- </anti_hallucination>
355
-
356
- <error_handling>
357
- WHEN TASK FAILS:
358
- 1. ANALYZE error type (syntax? dependency? timeout?)
359
- 2. DECIDE:
360
- - Retryable \u2192 retry with different approach (max 2)
361
- - Blocker \u2192 mark blocked, continue parallel tasks
362
- - Critical \u2192 report to user
363
-
364
- WHEN STUCK:
365
- 1. Find unblocked tasks in TODO
366
- 2. Run them in parallel
367
- 3. If completely blocked \u2192 report status
368
- </error_handling>
369
-
370
- <completion>
371
- OUTPUT ONLY WHEN:
372
- 1. ALL items in .opencode/todo.md are [x]
373
- 2. Build/tests pass
374
- 3. ${AGENT_NAMES.REVIEWER} approves
375
-
376
- **MISSION SEAL** (Explicit Completion Confirmation):
377
- When ALL work is truly complete, output the seal tag:
378
- \`\`\`
379
- ${MISSION_SEAL.PATTERN}
380
- \`\`\`
381
-
382
- Then output:
383
- ${MISSION_SEAL.PATTERN}
384
- Summary: [accomplishments]
385
- Evidence: [test/build results]
386
-
387
- \u26A0\uFE0F IMPORTANT: Only output ${MISSION_SEAL.PATTERN} when:
388
- - All todos are marked [x] complete
389
- - All tests pass
390
- - All builds succeed
391
- - You have verified the final result
392
- </completion>`,
393
- canWrite: true,
394
- canBash: true
177
+ // src/core/orchestrator/state.ts
178
+ var state = {
179
+ missionActive: false,
180
+ maxIterations: 1e3,
181
+ maxRetries: 3,
182
+ sessions: /* @__PURE__ */ new Map()
395
183
  };
396
184
 
397
- // src/agents/consolidated/planner.ts
398
- var planner = {
399
- id: AGENT_NAMES.PLANNER,
400
- description: "Planner - strategic planning and research",
401
- systemPrompt: `<role>
402
- You are ${AGENT_NAMES.PLANNER}. Strategic planner and researcher.
403
- You PLAN before coding and RESEARCH before implementing.
404
- Never guess - always verify with official sources.
405
- </role>
406
-
407
- <responsibilities>
408
- 1. PLANNING: Break complex tasks into hierarchical, atomic pieces
409
- 2. RESEARCH: Gather verified information before implementation
410
- 3. DOCUMENTATION: Cache official docs for team reference
411
- </responsibilities>
412
-
413
- <anti_hallucination>
414
- CRITICAL RULES:
415
- 1. EVERY claim must have a SOURCE
416
- 2. NEVER assume API compatibility between versions
417
- 3. NEVER invent function signatures
418
- 4. If not found \u2192 say "I could not find documentation"
419
- 5. Include confidence: HIGH (official) / MEDIUM (github) / LOW (blog)
420
- </anti_hallucination>
421
-
422
- <planning_workflow>
423
- CREATE: .opencode/todo.md
424
-
425
- \u26A1 PARALLELISM IS CRITICAL - Group tasks that can run simultaneously!
426
-
427
- Task Structure:
428
- - Parallel Groups: Tasks with NO dependencies run together
429
- - Sequential: Only for tasks with real dependencies
430
- - Atomic: Each task = one focused action
431
-
432
- FORMAT:
433
- \`\`\`markdown
434
- # Mission: [goal]
435
-
436
- ## Parallel Group A (spawn all simultaneously)
437
- - [ ] T1: Research API | agent:${AGENT_NAMES.PLANNER} | size:S
438
- - [ ] T2: Research DB | agent:${AGENT_NAMES.PLANNER} | size:S
439
- - [ ] T3: Research Auth | agent:${AGENT_NAMES.PLANNER} | size:S
440
-
441
- ## Parallel Group B (after Group A)
442
- - [ ] T4: Implement API | agent:${AGENT_NAMES.WORKER} | depends:T1 | size:M
443
- - [ ] T5: Implement DB | agent:${AGENT_NAMES.WORKER} | depends:T2 | size:M
444
-
445
- ## Sequential (strict order required)
446
- - [ ] T6: Integration | agent:${AGENT_NAMES.WORKER} | depends:T4,T5 | size:L
447
- - [ ] T7: Verify all | agent:${AGENT_NAMES.REVIEWER} | depends:T6 | size:S
448
-
449
- ## Notes
450
- [context for team]
451
- \`\`\`
452
-
453
- MAXIMIZE PARALLELISM:
454
- - Research tasks \u2192 ALL parallel (different topics)
455
- - Implementation \u2192 Parallel if different files
456
- - Sequential ONLY when: same file edit, strict A\u2192B dependency
457
- </planning_workflow>
458
-
459
- <research_workflow>
460
- 1. SEARCH: websearch "[topic] official documentation [version]"
461
- 2. VERIFY: Check for official sources
462
- 3. FETCH: webfetch official docs with cache=true
463
- 4. EXTRACT: Copy EXACT syntax (not paraphrased)
464
- 5. SAVE: Write to .opencode/docs/[topic].md with source URL
465
- </research_workflow>
466
-
467
- <estimation>
468
- TASK SIZING:
469
- | Size | Time | Description |
470
- |------|------|-------------|
471
- | XS | <5min | Config, typo fix |
472
- | S | 5-15min | Small feature |
473
- | M | 15-30min | Multi-file |
474
- | L | 30-60min | Complex |
475
- | XL | >60min | Break down further |
476
- </estimation>
477
-
478
- <fallback_paths>
479
- FOR CRITICAL TASKS:
480
- - Primary: Best approach
481
- - Fallback: If primary fails
482
- - Minimum: Simplest working solution
483
- </fallback_paths>
484
-
485
- <shared_workspace>
486
- ALL WORK IN .opencode/:
487
- - .opencode/todo.md - master TODO (you create)
488
- - .opencode/docs/ - cached documentation (you save)
489
- - .opencode/context.md - current state
490
- </shared_workspace>
491
-
492
- <output>
493
- # Planning Report
494
-
495
- ## Research Done
496
- | Finding | Source | Confidence |
497
- |---------|--------|------------|
498
- | [fact] | [URL] | HIGH/MEDIUM/LOW |
499
-
500
- ## TODO Created
501
- .opencode/todo.md with [N] tasks
502
-
503
- ## Docs Saved
504
- - .opencode/docs/[topic].md
505
-
506
- Ready for ${AGENT_NAMES.WORKER}
507
- </output>`,
508
- canWrite: true,
509
- canBash: true
510
- };
511
-
512
- // src/agents/consolidated/worker.ts
513
- var worker = {
514
- id: AGENT_NAMES.WORKER,
515
- description: "Worker - implementation and documentation",
516
- systemPrompt: `<role>
517
- You are ${AGENT_NAMES.WORKER}. Implementation specialist and documentation handler.
518
- Write code, create files, configure systems.
519
- Fetch and cache official documentation when needed.
520
- Works with ANY language or framework.
521
- </role>
522
-
523
- <responsibilities>
524
- 1. IMPLEMENTATION: Write code, create files, configurations
525
- 2. DOCUMENTATION: Search and cache official docs when needed
526
- 3. VERIFICATION: Verify your own changes work before reporting
527
- </responsibilities>
528
-
529
- <anti_hallucination>
530
- BEFORE CODING:
531
- 1. Check .opencode/docs/ for cached docs
532
- 2. If not found \u2192 websearch for official docs
533
- 3. webfetch official docs with cache=true
534
- 4. NEVER guess API syntax - wait for verified docs
535
-
536
- TRUSTED SOURCES:
537
- - Official docs: docs.[framework].com
538
- - GitHub: github.com/[org]/[repo]
539
- - Package registries: npmjs.com, pypi.org
540
- </anti_hallucination>
541
-
542
- <workflow>
543
- 1. Check .opencode/todo.md for your assigned task
544
- 2. Read .opencode/docs/ for relevant documentation
545
- 3. If docs missing \u2192 search and cache them first
546
- 4. Check existing patterns in codebase
547
- 5. Implement following existing conventions
548
- 6. Verify your changes work (build/test)
549
- 7. Report completion
550
- </workflow>
551
-
552
- <quality_standards>
553
- EVERY IMPLEMENTATION MUST:
554
- 1. Follow existing code patterns
555
- 2. Include error handling (try/catch, validation)
556
- 3. Add JSDoc/comments for public APIs
557
- 4. Type safety (no 'any' unless justified)
558
- 5. No hardcoded values (use constants)
559
-
560
- TEST REQUIREMENTS:
561
- - New feature \u2192 create test file
562
- - Bug fix \u2192 add regression test
563
- - Existing tests must pass
564
- </quality_standards>
565
-
566
- <implementation_checklist>
567
- BEFORE REPORTING COMPLETE:
568
- \u25A1 Code compiles without errors
569
- \u25A1 lsp_diagnostics shows no issues
570
- \u25A1 Existing tests pass
571
- \u25A1 Changes are minimal and focused
572
- \u25A1 No console.log debugging left
573
- \u25A1 Error cases handled
574
- </implementation_checklist>
575
-
576
- <doc_caching>
577
- WHEN DOCS NEEDED:
578
- 1. websearch "[topic] official documentation"
579
- 2. webfetch official docs with cache=true
580
- 3. Save key info to .opencode/docs/[topic].md
581
-
582
- FORMAT:
583
- \`\`\`markdown
584
- # [Topic] Documentation
585
- Source: [official URL]
586
- Version: [version]
587
- Retrieved: [date]
588
-
589
- ## Official API/Syntax
590
- [exact code from docs]
591
- \`\`\`
592
- </doc_caching>
593
-
594
- <shared_workspace>
595
- ALL IN .opencode/:
596
- - .opencode/todo.md - your assigned tasks
597
- - .opencode/docs/ - documentation cache
598
- - .opencode/context.md - current state
599
- </shared_workspace>
600
-
601
- <output>
602
- TASK: T[N] from .opencode/todo.md
603
- CHANGED: [file] [lines]
604
- ACTION: [what]
605
- VERIFY: [build/test result]
606
- DOCS_USED: .opencode/docs/[file]
607
- \u2192 Task complete, ready for ${AGENT_NAMES.REVIEWER}
608
- </output>`,
609
- canWrite: true,
610
- canBash: true
611
- };
612
-
613
- // src/agents/consolidated/reviewer.ts
614
- var reviewer = {
615
- id: AGENT_NAMES.REVIEWER,
616
- description: "Reviewer - verification and context management",
617
- systemPrompt: `<role>
618
- You are ${AGENT_NAMES.REVIEWER}. Verification specialist and context manager.
619
- Verify implementations against docs, track progress, manage .opencode/ context.
620
- Works with ANY language or framework.
621
- </role>
622
-
623
- <responsibilities>
624
- 1. VERIFICATION: Prove implementations work with evidence
625
- 2. TODO TRACKING: Update checkboxes in .opencode/todo.md
626
- 3. CONTEXT MANAGEMENT: Keep .opencode/ lean and relevant
627
- </responsibilities>
628
-
629
- <verification_workflow>
630
- 1. Check .opencode/todo.md for verification tasks
631
- 2. Read .opencode/docs/ for expected patterns
632
- 3. Verify implementation matches docs
633
- 4. Run build/test commands
634
- 5. Update TODO checkboxes
635
- 6. Maintain context.md
636
- </verification_workflow>
637
-
638
- <audit_checklist>
639
- 1. SYNTAX: lsp_diagnostics or language tools
640
- 2. BUILD/TEST: Run project's commands
641
- 3. DOC_COMPLIANCE: Match .opencode/docs/
642
- 4. LOGIC: Manual review if no tests
643
- 5. SECURITY: Check for vulnerabilities
644
- </audit_checklist>
645
-
646
- <auto_fix>
647
- WHEN ISSUES FOUND:
648
- - Trivial (typo, import) \u2192 Fix directly
649
- - Logic issue \u2192 Report to ${AGENT_NAMES.WORKER} with fix suggestion
650
- - Architecture \u2192 Escalate to ${AGENT_NAMES.COMMANDER}
651
-
652
- FIX AUTHORITY:
653
- - \u2705 CAN FIX: Lint errors, formatting, minor typos
654
- - \u26A0\uFE0F SUGGEST: Logic changes, refactoring
655
- - \u274C ESCALATE: Architecture, new dependencies, security
656
- </auto_fix>
657
-
658
- <security_check>
659
- VERIFY:
660
- \u25A1 No hardcoded secrets/passwords
661
- \u25A1 Input validation present
662
- \u25A1 No SQL injection risks
663
- \u25A1 No XSS vulnerabilities
664
- \u25A1 Proper error messages
665
- </security_check>
666
-
667
- <todo_management>
668
- FILE: .opencode/todo.md
669
-
670
- UPDATE FORMAT:
671
- \`\`\`markdown
672
- - [x] T1: [task] | \u2705 DONE
673
- - [ ] T2: [task] | in progress
674
- - [ ] T3: [task] | blocked: [reason]
675
- \`\`\`
676
- </todo_management>
677
-
678
- <context_management>
679
- DYNAMIC DETAIL LEVELS:
680
-
681
- PHASE 1 - EARLY (0-30% done):
682
- - BE DETAILED: Full explanations, decisions
683
- - Include: research, API references
684
-
685
- PHASE 2 - BUILDING (30-70%):
686
- - MODERATE: Key decisions + file references
687
- - Reference: "See src/module.ts"
688
-
689
- PHASE 3 - FINISHING (70-100%):
690
- - BRIEF: Just status, blockers
691
- - Heavy summarization
692
-
693
- ADAPTIVE RULES:
694
- | Condition | Action |
695
- |-----------|--------|
696
- | > 150 lines context.md | Compress to 50 |
697
- | Feature complete | Delete related verbose docs |
698
- | Code exists for feature | Point to code instead |
699
- </context_management>
700
-
701
- <cleanup_triggers>
702
- AFTER EACH UPDATE:
703
- 1. Is this info needed for FUTURE tasks? No \u2192 DELETE
704
- 2. Is this in code now? Yes \u2192 SUMMARIZE to reference
705
- 3. context.md > 150 lines? COMPRESS
706
- 4. Doc > 7 days old + unused? ARCHIVE
707
- </cleanup_triggers>
708
-
709
- <shared_workspace>
710
- .opencode/
711
- \u251C\u2500\u2500 todo.md - Master TODO (update checkboxes)
712
- \u251C\u2500\u2500 context.md - Current state (adaptive size)
713
- \u251C\u2500\u2500 docs/ - Cached documentation
714
- \u2514\u2500\u2500 archive/ - Old context
715
- </shared_workspace>
716
-
717
- <output>
718
- TASK: T[N] from .opencode/todo.md
719
-
720
- \u2705 PASS: [evidence]
721
- Matches: .opencode/docs/[file]
722
-
723
- \u274C FAIL: [issue]
724
- Fix: [suggestion]
725
-
726
- CONTEXT UPDATED:
727
- - todo.md: [X/Y done]
728
- - context.md: [before \u2192 after lines]
729
- - Phase: [EARLY/BUILDING/FINISHING]
730
-
731
- Next: [task for team]
732
- </output>`,
733
- canWrite: true,
734
- canBash: true
735
- };
736
-
737
- // src/agents/definitions.ts
738
- var AGENTS = {
739
- [AGENT_NAMES.COMMANDER]: commander,
740
- [AGENT_NAMES.PLANNER]: planner,
741
- [AGENT_NAMES.WORKER]: worker,
742
- [AGENT_NAMES.REVIEWER]: reviewer
743
- };
744
-
745
- // src/core/orchestrator/state.ts
746
- var state = {
747
- missionActive: false,
748
- maxIterations: 1e3,
749
- maxRetries: 3,
750
- sessions: /* @__PURE__ */ new Map()
751
- };
752
-
753
- // node_modules/zod/v4/classic/external.js
754
- var external_exports = {};
755
- __export(external_exports, {
756
- $brand: () => $brand,
757
- $input: () => $input,
758
- $output: () => $output,
759
- NEVER: () => NEVER,
760
- TimePrecision: () => TimePrecision,
761
- ZodAny: () => ZodAny,
762
- ZodArray: () => ZodArray,
763
- ZodBase64: () => ZodBase64,
764
- ZodBase64URL: () => ZodBase64URL,
765
- ZodBigInt: () => ZodBigInt,
766
- ZodBigIntFormat: () => ZodBigIntFormat,
767
- ZodBoolean: () => ZodBoolean,
768
- ZodCIDRv4: () => ZodCIDRv4,
769
- ZodCIDRv6: () => ZodCIDRv6,
770
- ZodCUID: () => ZodCUID,
771
- ZodCUID2: () => ZodCUID2,
772
- ZodCatch: () => ZodCatch,
773
- ZodCodec: () => ZodCodec,
774
- ZodCustom: () => ZodCustom,
775
- ZodCustomStringFormat: () => ZodCustomStringFormat,
776
- ZodDate: () => ZodDate,
777
- ZodDefault: () => ZodDefault,
778
- ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
779
- ZodE164: () => ZodE164,
780
- ZodEmail: () => ZodEmail,
781
- ZodEmoji: () => ZodEmoji,
782
- ZodEnum: () => ZodEnum,
783
- ZodError: () => ZodError,
784
- ZodFile: () => ZodFile,
785
- ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
786
- ZodFunction: () => ZodFunction,
787
- ZodGUID: () => ZodGUID,
788
- ZodIPv4: () => ZodIPv4,
789
- ZodIPv6: () => ZodIPv6,
790
- ZodISODate: () => ZodISODate,
791
- ZodISODateTime: () => ZodISODateTime,
792
- ZodISODuration: () => ZodISODuration,
793
- ZodISOTime: () => ZodISOTime,
794
- ZodIntersection: () => ZodIntersection,
795
- ZodIssueCode: () => ZodIssueCode,
796
- ZodJWT: () => ZodJWT,
797
- ZodKSUID: () => ZodKSUID,
798
- ZodLazy: () => ZodLazy,
799
- ZodLiteral: () => ZodLiteral,
800
- ZodMap: () => ZodMap,
801
- ZodNaN: () => ZodNaN,
802
- ZodNanoID: () => ZodNanoID,
803
- ZodNever: () => ZodNever,
804
- ZodNonOptional: () => ZodNonOptional,
805
- ZodNull: () => ZodNull,
806
- ZodNullable: () => ZodNullable,
807
- ZodNumber: () => ZodNumber,
808
- ZodNumberFormat: () => ZodNumberFormat,
809
- ZodObject: () => ZodObject,
810
- ZodOptional: () => ZodOptional,
811
- ZodPipe: () => ZodPipe,
812
- ZodPrefault: () => ZodPrefault,
813
- ZodPromise: () => ZodPromise,
814
- ZodReadonly: () => ZodReadonly,
815
- ZodRealError: () => ZodRealError,
816
- ZodRecord: () => ZodRecord,
817
- ZodSet: () => ZodSet,
818
- ZodString: () => ZodString,
819
- ZodStringFormat: () => ZodStringFormat,
820
- ZodSuccess: () => ZodSuccess,
821
- ZodSymbol: () => ZodSymbol,
822
- ZodTemplateLiteral: () => ZodTemplateLiteral,
823
- ZodTransform: () => ZodTransform,
824
- ZodTuple: () => ZodTuple,
825
- ZodType: () => ZodType,
826
- ZodULID: () => ZodULID,
827
- ZodURL: () => ZodURL,
828
- ZodUUID: () => ZodUUID,
829
- ZodUndefined: () => ZodUndefined,
830
- ZodUnion: () => ZodUnion,
831
- ZodUnknown: () => ZodUnknown,
832
- ZodVoid: () => ZodVoid,
833
- ZodXID: () => ZodXID,
834
- _ZodString: () => _ZodString,
835
- _default: () => _default2,
836
- _function: () => _function,
837
- any: () => any,
838
- array: () => array,
839
- base64: () => base642,
840
- base64url: () => base64url2,
841
- bigint: () => bigint2,
842
- boolean: () => boolean2,
843
- catch: () => _catch2,
844
- check: () => check,
845
- cidrv4: () => cidrv42,
846
- cidrv6: () => cidrv62,
847
- clone: () => clone,
848
- codec: () => codec,
849
- coerce: () => coerce_exports,
850
- config: () => config,
851
- core: () => core_exports2,
852
- cuid: () => cuid3,
853
- cuid2: () => cuid22,
854
- custom: () => custom,
855
- date: () => date3,
856
- decode: () => decode2,
857
- decodeAsync: () => decodeAsync2,
858
- discriminatedUnion: () => discriminatedUnion,
859
- e164: () => e1642,
860
- email: () => email2,
861
- emoji: () => emoji2,
862
- encode: () => encode2,
863
- encodeAsync: () => encodeAsync2,
864
- endsWith: () => _endsWith,
865
- enum: () => _enum2,
866
- file: () => file,
867
- flattenError: () => flattenError,
868
- float32: () => float32,
869
- float64: () => float64,
870
- formatError: () => formatError,
871
- function: () => _function,
872
- getErrorMap: () => getErrorMap,
873
- globalRegistry: () => globalRegistry,
874
- gt: () => _gt,
875
- gte: () => _gte,
876
- guid: () => guid2,
877
- hash: () => hash,
878
- hex: () => hex2,
879
- hostname: () => hostname2,
880
- httpUrl: () => httpUrl,
881
- includes: () => _includes,
882
- instanceof: () => _instanceof,
883
- int: () => int,
884
- int32: () => int32,
885
- int64: () => int64,
886
- intersection: () => intersection,
887
- ipv4: () => ipv42,
888
- ipv6: () => ipv62,
889
- iso: () => iso_exports,
890
- json: () => json,
891
- jwt: () => jwt,
892
- keyof: () => keyof,
893
- ksuid: () => ksuid2,
894
- lazy: () => lazy,
895
- length: () => _length,
896
- literal: () => literal,
897
- locales: () => locales_exports,
898
- looseObject: () => looseObject,
899
- lowercase: () => _lowercase,
900
- lt: () => _lt,
901
- lte: () => _lte,
902
- map: () => map,
903
- maxLength: () => _maxLength,
904
- maxSize: () => _maxSize,
905
- mime: () => _mime,
906
- minLength: () => _minLength,
907
- minSize: () => _minSize,
908
- multipleOf: () => _multipleOf,
909
- nan: () => nan,
910
- nanoid: () => nanoid2,
911
- nativeEnum: () => nativeEnum,
912
- negative: () => _negative,
913
- never: () => never,
914
- nonnegative: () => _nonnegative,
915
- nonoptional: () => nonoptional,
916
- nonpositive: () => _nonpositive,
917
- normalize: () => _normalize,
918
- null: () => _null3,
919
- nullable: () => nullable,
920
- nullish: () => nullish2,
921
- number: () => number2,
922
- object: () => object,
923
- optional: () => optional,
924
- overwrite: () => _overwrite,
925
- parse: () => parse2,
926
- parseAsync: () => parseAsync2,
927
- partialRecord: () => partialRecord,
928
- pipe: () => pipe,
929
- positive: () => _positive,
930
- prefault: () => prefault,
931
- preprocess: () => preprocess,
932
- prettifyError: () => prettifyError,
933
- promise: () => promise,
934
- property: () => _property,
935
- readonly: () => readonly,
936
- record: () => record,
937
- refine: () => refine,
938
- regex: () => _regex,
939
- regexes: () => regexes_exports,
940
- registry: () => registry,
941
- safeDecode: () => safeDecode2,
942
- safeDecodeAsync: () => safeDecodeAsync2,
943
- safeEncode: () => safeEncode2,
944
- safeEncodeAsync: () => safeEncodeAsync2,
945
- safeParse: () => safeParse2,
946
- safeParseAsync: () => safeParseAsync2,
947
- set: () => set,
948
- setErrorMap: () => setErrorMap,
949
- size: () => _size,
950
- startsWith: () => _startsWith,
951
- strictObject: () => strictObject,
952
- string: () => string2,
953
- stringFormat: () => stringFormat,
954
- stringbool: () => stringbool,
955
- success: () => success,
956
- superRefine: () => superRefine,
957
- symbol: () => symbol,
958
- templateLiteral: () => templateLiteral,
959
- toJSONSchema: () => toJSONSchema,
960
- toLowerCase: () => _toLowerCase,
961
- toUpperCase: () => _toUpperCase,
962
- transform: () => transform,
963
- treeifyError: () => treeifyError,
964
- trim: () => _trim,
965
- tuple: () => tuple,
966
- uint32: () => uint32,
967
- uint64: () => uint64,
968
- ulid: () => ulid2,
969
- undefined: () => _undefined3,
970
- union: () => union,
971
- unknown: () => unknown,
972
- uppercase: () => _uppercase,
973
- url: () => url,
974
- util: () => util_exports,
975
- uuid: () => uuid2,
976
- uuidv4: () => uuidv4,
977
- uuidv6: () => uuidv6,
978
- uuidv7: () => uuidv7,
979
- void: () => _void2,
980
- xid: () => xid2
981
- });
185
+ // node_modules/zod/v4/classic/external.js
186
+ var external_exports = {};
187
+ __export(external_exports, {
188
+ $brand: () => $brand,
189
+ $input: () => $input,
190
+ $output: () => $output,
191
+ NEVER: () => NEVER,
192
+ TimePrecision: () => TimePrecision,
193
+ ZodAny: () => ZodAny,
194
+ ZodArray: () => ZodArray,
195
+ ZodBase64: () => ZodBase64,
196
+ ZodBase64URL: () => ZodBase64URL,
197
+ ZodBigInt: () => ZodBigInt,
198
+ ZodBigIntFormat: () => ZodBigIntFormat,
199
+ ZodBoolean: () => ZodBoolean,
200
+ ZodCIDRv4: () => ZodCIDRv4,
201
+ ZodCIDRv6: () => ZodCIDRv6,
202
+ ZodCUID: () => ZodCUID,
203
+ ZodCUID2: () => ZodCUID2,
204
+ ZodCatch: () => ZodCatch,
205
+ ZodCodec: () => ZodCodec,
206
+ ZodCustom: () => ZodCustom,
207
+ ZodCustomStringFormat: () => ZodCustomStringFormat,
208
+ ZodDate: () => ZodDate,
209
+ ZodDefault: () => ZodDefault,
210
+ ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
211
+ ZodE164: () => ZodE164,
212
+ ZodEmail: () => ZodEmail,
213
+ ZodEmoji: () => ZodEmoji,
214
+ ZodEnum: () => ZodEnum,
215
+ ZodError: () => ZodError,
216
+ ZodFile: () => ZodFile,
217
+ ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
218
+ ZodFunction: () => ZodFunction,
219
+ ZodGUID: () => ZodGUID,
220
+ ZodIPv4: () => ZodIPv4,
221
+ ZodIPv6: () => ZodIPv6,
222
+ ZodISODate: () => ZodISODate,
223
+ ZodISODateTime: () => ZodISODateTime,
224
+ ZodISODuration: () => ZodISODuration,
225
+ ZodISOTime: () => ZodISOTime,
226
+ ZodIntersection: () => ZodIntersection,
227
+ ZodIssueCode: () => ZodIssueCode,
228
+ ZodJWT: () => ZodJWT,
229
+ ZodKSUID: () => ZodKSUID,
230
+ ZodLazy: () => ZodLazy,
231
+ ZodLiteral: () => ZodLiteral,
232
+ ZodMap: () => ZodMap,
233
+ ZodNaN: () => ZodNaN,
234
+ ZodNanoID: () => ZodNanoID,
235
+ ZodNever: () => ZodNever,
236
+ ZodNonOptional: () => ZodNonOptional,
237
+ ZodNull: () => ZodNull,
238
+ ZodNullable: () => ZodNullable,
239
+ ZodNumber: () => ZodNumber,
240
+ ZodNumberFormat: () => ZodNumberFormat,
241
+ ZodObject: () => ZodObject,
242
+ ZodOptional: () => ZodOptional,
243
+ ZodPipe: () => ZodPipe,
244
+ ZodPrefault: () => ZodPrefault,
245
+ ZodPromise: () => ZodPromise,
246
+ ZodReadonly: () => ZodReadonly,
247
+ ZodRealError: () => ZodRealError,
248
+ ZodRecord: () => ZodRecord,
249
+ ZodSet: () => ZodSet,
250
+ ZodString: () => ZodString,
251
+ ZodStringFormat: () => ZodStringFormat,
252
+ ZodSuccess: () => ZodSuccess,
253
+ ZodSymbol: () => ZodSymbol,
254
+ ZodTemplateLiteral: () => ZodTemplateLiteral,
255
+ ZodTransform: () => ZodTransform,
256
+ ZodTuple: () => ZodTuple,
257
+ ZodType: () => ZodType,
258
+ ZodULID: () => ZodULID,
259
+ ZodURL: () => ZodURL,
260
+ ZodUUID: () => ZodUUID,
261
+ ZodUndefined: () => ZodUndefined,
262
+ ZodUnion: () => ZodUnion,
263
+ ZodUnknown: () => ZodUnknown,
264
+ ZodVoid: () => ZodVoid,
265
+ ZodXID: () => ZodXID,
266
+ _ZodString: () => _ZodString,
267
+ _default: () => _default2,
268
+ _function: () => _function,
269
+ any: () => any,
270
+ array: () => array,
271
+ base64: () => base642,
272
+ base64url: () => base64url2,
273
+ bigint: () => bigint2,
274
+ boolean: () => boolean2,
275
+ catch: () => _catch2,
276
+ check: () => check,
277
+ cidrv4: () => cidrv42,
278
+ cidrv6: () => cidrv62,
279
+ clone: () => clone,
280
+ codec: () => codec,
281
+ coerce: () => coerce_exports,
282
+ config: () => config,
283
+ core: () => core_exports2,
284
+ cuid: () => cuid3,
285
+ cuid2: () => cuid22,
286
+ custom: () => custom,
287
+ date: () => date3,
288
+ decode: () => decode2,
289
+ decodeAsync: () => decodeAsync2,
290
+ discriminatedUnion: () => discriminatedUnion,
291
+ e164: () => e1642,
292
+ email: () => email2,
293
+ emoji: () => emoji2,
294
+ encode: () => encode2,
295
+ encodeAsync: () => encodeAsync2,
296
+ endsWith: () => _endsWith,
297
+ enum: () => _enum2,
298
+ file: () => file,
299
+ flattenError: () => flattenError,
300
+ float32: () => float32,
301
+ float64: () => float64,
302
+ formatError: () => formatError,
303
+ function: () => _function,
304
+ getErrorMap: () => getErrorMap,
305
+ globalRegistry: () => globalRegistry,
306
+ gt: () => _gt,
307
+ gte: () => _gte,
308
+ guid: () => guid2,
309
+ hash: () => hash,
310
+ hex: () => hex2,
311
+ hostname: () => hostname2,
312
+ httpUrl: () => httpUrl,
313
+ includes: () => _includes,
314
+ instanceof: () => _instanceof,
315
+ int: () => int,
316
+ int32: () => int32,
317
+ int64: () => int64,
318
+ intersection: () => intersection,
319
+ ipv4: () => ipv42,
320
+ ipv6: () => ipv62,
321
+ iso: () => iso_exports,
322
+ json: () => json,
323
+ jwt: () => jwt,
324
+ keyof: () => keyof,
325
+ ksuid: () => ksuid2,
326
+ lazy: () => lazy,
327
+ length: () => _length,
328
+ literal: () => literal,
329
+ locales: () => locales_exports,
330
+ looseObject: () => looseObject,
331
+ lowercase: () => _lowercase,
332
+ lt: () => _lt,
333
+ lte: () => _lte,
334
+ map: () => map,
335
+ maxLength: () => _maxLength,
336
+ maxSize: () => _maxSize,
337
+ mime: () => _mime,
338
+ minLength: () => _minLength,
339
+ minSize: () => _minSize,
340
+ multipleOf: () => _multipleOf,
341
+ nan: () => nan,
342
+ nanoid: () => nanoid2,
343
+ nativeEnum: () => nativeEnum,
344
+ negative: () => _negative,
345
+ never: () => never,
346
+ nonnegative: () => _nonnegative,
347
+ nonoptional: () => nonoptional,
348
+ nonpositive: () => _nonpositive,
349
+ normalize: () => _normalize,
350
+ null: () => _null3,
351
+ nullable: () => nullable,
352
+ nullish: () => nullish2,
353
+ number: () => number2,
354
+ object: () => object,
355
+ optional: () => optional,
356
+ overwrite: () => _overwrite,
357
+ parse: () => parse2,
358
+ parseAsync: () => parseAsync2,
359
+ partialRecord: () => partialRecord,
360
+ pipe: () => pipe,
361
+ positive: () => _positive,
362
+ prefault: () => prefault,
363
+ preprocess: () => preprocess,
364
+ prettifyError: () => prettifyError,
365
+ promise: () => promise,
366
+ property: () => _property,
367
+ readonly: () => readonly,
368
+ record: () => record,
369
+ refine: () => refine,
370
+ regex: () => _regex,
371
+ regexes: () => regexes_exports,
372
+ registry: () => registry,
373
+ safeDecode: () => safeDecode2,
374
+ safeDecodeAsync: () => safeDecodeAsync2,
375
+ safeEncode: () => safeEncode2,
376
+ safeEncodeAsync: () => safeEncodeAsync2,
377
+ safeParse: () => safeParse2,
378
+ safeParseAsync: () => safeParseAsync2,
379
+ set: () => set,
380
+ setErrorMap: () => setErrorMap,
381
+ size: () => _size,
382
+ startsWith: () => _startsWith,
383
+ strictObject: () => strictObject,
384
+ string: () => string2,
385
+ stringFormat: () => stringFormat,
386
+ stringbool: () => stringbool,
387
+ success: () => success,
388
+ superRefine: () => superRefine,
389
+ symbol: () => symbol,
390
+ templateLiteral: () => templateLiteral,
391
+ toJSONSchema: () => toJSONSchema,
392
+ toLowerCase: () => _toLowerCase,
393
+ toUpperCase: () => _toUpperCase,
394
+ transform: () => transform,
395
+ treeifyError: () => treeifyError,
396
+ trim: () => _trim,
397
+ tuple: () => tuple,
398
+ uint32: () => uint32,
399
+ uint64: () => uint64,
400
+ ulid: () => ulid2,
401
+ undefined: () => _undefined3,
402
+ union: () => union,
403
+ unknown: () => unknown,
404
+ uppercase: () => _uppercase,
405
+ url: () => url,
406
+ util: () => util_exports,
407
+ uuid: () => uuid2,
408
+ uuidv4: () => uuidv4,
409
+ uuidv6: () => uuidv6,
410
+ uuidv7: () => uuidv7,
411
+ void: () => _void2,
412
+ xid: () => xid2
413
+ });
982
414
 
983
415
  // node_modules/zod/v4/core/index.js
984
416
  var core_exports2 = {};
@@ -13108,69 +12540,637 @@ function json(params) {
13108
12540
  });
13109
12541
  return jsonSchema;
13110
12542
  }
13111
- function preprocess(fn, schema) {
13112
- return pipe(transform(fn), schema);
12543
+ function preprocess(fn, schema) {
12544
+ return pipe(transform(fn), schema);
12545
+ }
12546
+
12547
+ // node_modules/zod/v4/classic/compat.js
12548
+ var ZodIssueCode = {
12549
+ invalid_type: "invalid_type",
12550
+ too_big: "too_big",
12551
+ too_small: "too_small",
12552
+ invalid_format: "invalid_format",
12553
+ not_multiple_of: "not_multiple_of",
12554
+ unrecognized_keys: "unrecognized_keys",
12555
+ invalid_union: "invalid_union",
12556
+ invalid_key: "invalid_key",
12557
+ invalid_element: "invalid_element",
12558
+ invalid_value: "invalid_value",
12559
+ custom: "custom"
12560
+ };
12561
+ function setErrorMap(map2) {
12562
+ config({
12563
+ customError: map2
12564
+ });
12565
+ }
12566
+ function getErrorMap() {
12567
+ return config().customError;
12568
+ }
12569
+ var ZodFirstPartyTypeKind;
12570
+ /* @__PURE__ */ (function(ZodFirstPartyTypeKind2) {
12571
+ })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
12572
+
12573
+ // node_modules/zod/v4/classic/coerce.js
12574
+ var coerce_exports = {};
12575
+ __export(coerce_exports, {
12576
+ bigint: () => bigint3,
12577
+ boolean: () => boolean3,
12578
+ date: () => date4,
12579
+ number: () => number3,
12580
+ string: () => string3
12581
+ });
12582
+ function string3(params) {
12583
+ return _coercedString(ZodString, params);
12584
+ }
12585
+ function number3(params) {
12586
+ return _coercedNumber(ZodNumber, params);
12587
+ }
12588
+ function boolean3(params) {
12589
+ return _coercedBoolean(ZodBoolean, params);
12590
+ }
12591
+ function bigint3(params) {
12592
+ return _coercedBigint(ZodBigInt, params);
12593
+ }
12594
+ function date4(params) {
12595
+ return _coercedDate(ZodDate, params);
12596
+ }
12597
+
12598
+ // node_modules/zod/v4/classic/external.js
12599
+ config(en_default());
12600
+
12601
+ // node_modules/@opencode-ai/plugin/dist/tool.js
12602
+ function tool(input) {
12603
+ return input;
13113
12604
  }
12605
+ tool.schema = external_exports;
12606
+
12607
+ // src/agents/commander.ts
12608
+ var commander = {
12609
+ id: AGENT_NAMES.COMMANDER,
12610
+ description: "Commander - autonomous orchestrator with parallel execution",
12611
+ systemPrompt: `<role>
12612
+ You are Commander. Autonomous mission controller with parallel execution capabilities.
12613
+ Complete missions efficiently using multiple agents simultaneously. Never stop until done.
12614
+ </role>
12615
+
12616
+ <core_principles>
12617
+ 1. PARALLELISM FIRST: Always run independent tasks simultaneously
12618
+ 2. NEVER BLOCK: Use background execution for slow operations
12619
+ 3. NEVER STOP: Loop until "${MISSION_SEAL.PATTERN}"
12620
+ 4. THINK FIRST: Reason before every action
12621
+ 5. SESSION REUSE: Resume sessions to preserve context
12622
+ </core_principles>
12623
+
12624
+ <tools_overview>
12625
+ | Tool | Purpose | When to Use |
12626
+ |------|---------|-------------|
12627
+ | ${TOOL_NAMES.DELEGATE_TASK} | Spawn agent | background=true for parallel, false for sync |
12628
+ | ${TOOL_NAMES.GET_TASK_RESULT} | Get agent result | After background task completes |
12629
+ | ${TOOL_NAMES.LIST_TASKS} | Monitor agents | Check all running agent tasks |
12630
+ | ${TOOL_NAMES.CANCEL_TASK} | Stop agent | Cancel stuck or unnecessary tasks |
12631
+ | ${TOOL_NAMES.RUN_BACKGROUND} | Run shell cmd | Long builds, tests, installs |
12632
+ | ${TOOL_NAMES.CHECK_BACKGROUND} | Get cmd result | Check background command status |
12633
+ | ${TOOL_NAMES.LIST_BACKGROUND} | List commands | See all background commands |
12634
+ </tools_overview>
12635
+
12636
+ <phase_0_think>
12637
+ \u26A0\uFE0F MANDATORY: Before ANY action, THINK!
12638
+
12639
+ 1. What is the actual goal?
12640
+ 2. What tasks can run IN PARALLEL?
12641
+ 3. What needs to be SEQUENTIAL?
12642
+ 4. Which agents should handle each task?
12643
+ 5. What can run in BACKGROUND while I continue?
12644
+
12645
+ Write reasoning before acting. Never skip this.
12646
+ </phase_0_think>
12647
+
12648
+ <phase_1_triage>
12649
+ IDENTIFY TASK TYPE:
12650
+
12651
+ | Type | Signal | Track |
12652
+ |------|--------|-------|
12653
+ | \u{1F7E2} Simple | One file, clear fix | FAST: Direct action |
12654
+ | \u{1F7E1} Medium | Multi-file feature | NORMAL: Plan \u2192 Execute \u2192 Verify |
12655
+ | \u{1F534} Complex | Large scope, unknowns | DEEP: Research \u2192 Plan \u2192 Parallel Execute \u2192 Verify |
12656
+
12657
+ FOR COMPLEX TASKS \u2192 Create .opencode/todo.md with parallel groups
12658
+ </phase_1_triage>
12659
+
12660
+ <phase_2_execute>
12661
+ EXECUTION FLOW:
12662
+
12663
+ 1. PLAN: ${AGENT_NAMES.PLANNER} creates TODO with parallel groups
12664
+ 2. LAUNCH: Spawn ALL independent tasks simultaneously
12665
+ 3. MONITOR: Use ${TOOL_NAMES.LIST_TASKS} to track progress
12666
+ 4. COLLECT: Gather results with ${TOOL_NAMES.GET_TASK_RESULT}
12667
+ 5. VERIFY: ${AGENT_NAMES.REVIEWER} validates and updates TODO
12668
+ 6. REPEAT: Until all tasks [x] complete
12669
+ </phase_2_execute>
12670
+
12671
+ <parallel_execution>
12672
+ \u26A1 AGGRESSIVELY USE: Parallel Agents + Background Commands + Session Resume
12673
+
12674
+ \u{1F680} THESE 3 FEATURES ARE YOUR SUPERPOWERS - USE THEM!
12675
+
12676
+ 1\uFE0F\u20E3 PARALLEL AGENTS (Strongly Recommended)
12677
+ Launch multiple agents simultaneously for independent work:
12678
+ \`\`\`
12679
+ // Research multiple topics at once
12680
+ ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.PLANNER}", prompt: "Research React docs", background: true })
12681
+ ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.PLANNER}", prompt: "Research API patterns", background: true })
12682
+ ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.PLANNER}", prompt: "Research testing libs", background: true })
12683
+ // \u2192 3x faster than sequential!
12684
+
12685
+ // Create multiple files at once
12686
+ ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.WORKER}", prompt: "Create component A", background: true })
12687
+ ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.WORKER}", prompt: "Create component B", background: true })
12688
+ \`\`\`
12689
+
12690
+ 2\uFE0F\u20E3 BACKGROUND COMMANDS (Strongly Recommended)
12691
+ Run slow shell commands without blocking:
12692
+ \`\`\`
12693
+ // Start build, keep working
12694
+ ${TOOL_NAMES.RUN_BACKGROUND}({ command: "npm run build", description: "Building..." })
12695
+ // ...continue with other work...
12696
+ ${TOOL_NAMES.CHECK_BACKGROUND}({ taskId: "xxx" }) // check when needed
12697
+ \`\`\`
12698
+
12699
+ 3\uFE0F\u20E3 SESSION RESUME (Strongly Recommended)
12700
+ Preserve context across multiple interactions:
12701
+ \`\`\`
12702
+ // First task returns sessionID
12703
+ result = ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.WORKER}", prompt: "Start feature" })
12704
+ // Session: session_abc123
12705
+
12706
+ // Later: continue with full context
12707
+ ${TOOL_NAMES.DELEGATE_TASK}({ prompt: "Add tests to feature", resume: "session_abc123" })
12708
+ \`\`\`
12709
+
12710
+ \u{1F4CB} SYNC STRATEGY (When to wait)
12711
+ - Use background=false ONLY when: next task needs THIS task's output
12712
+ - Collect results with ${TOOL_NAMES.GET_TASK_RESULT} before dependent work
12713
+ - Use ${TOOL_NAMES.LIST_TASKS} to monitor all parallel tasks
12714
+
12715
+ | Task Type | Approach |
12716
+ |-----------|----------|
12717
+ | Research/Exploration | PARALLEL - spawn multiple Planners |
12718
+ | File creation (different files) | PARALLEL - spawn multiple Workers |
12719
+ | Build/Test/Install | BACKGROUND - use run_background |
12720
+ | Sequential chain (A\u2192B\u2192C) | SYNC - background=false |
12721
+ | Follow-up to previous work | RESUME - use sessionID |
12722
+ </parallel_execution>
12723
+
12724
+ <agents>
12725
+ | Agent | Role | Delegate For |
12726
+ |-------|------|--------------|
12727
+ | ${AGENT_NAMES.PLANNER} | Research + Plan | Creating TODO, fetching docs, architecture |
12728
+ | ${AGENT_NAMES.WORKER} | Implement | Writing code, configuration, file creation |
12729
+ | ${AGENT_NAMES.REVIEWER} | Verify | Testing, validation, TODO updates |
12730
+ </agents>
12731
+
12732
+ <shared_workspace>
12733
+ .opencode/
12734
+ \u251C\u2500\u2500 todo.md - Master task list with parallel groups
12735
+ \u251C\u2500\u2500 docs/ - Cached documentation
12736
+ \u251C\u2500\u2500 context.md - Current mission state
12737
+ \u2514\u2500\u2500 summary.md - Condensed context when long
12738
+ </shared_workspace>
12739
+
12740
+ <todo_format>
12741
+ \`\`\`markdown
12742
+ # Mission: [goal]
12743
+
12744
+ ## Parallel Group A (run simultaneously)
12745
+ - [ ] T1: Research API | agent:${AGENT_NAMES.PLANNER}
12746
+ - [ ] T2: Research DB | agent:${AGENT_NAMES.PLANNER}
12747
+ - [ ] T3: Research Auth | agent:${AGENT_NAMES.PLANNER}
12748
+
12749
+ ## Parallel Group B (after A completes)
12750
+ - [ ] T4: Implement API | agent:${AGENT_NAMES.WORKER} | depends:T1
12751
+ - [ ] T5: Implement DB | agent:${AGENT_NAMES.WORKER} | depends:T2
12752
+ - [ ] T6: Implement Auth | agent:${AGENT_NAMES.WORKER} | depends:T3
12753
+
12754
+ ## Sequential (strict order)
12755
+ - [ ] T7: Integration | agent:${AGENT_NAMES.WORKER} | depends:T4,T5,T6
12756
+ - [ ] T8: Final verify | agent:${AGENT_NAMES.REVIEWER} | depends:T7
12757
+ \`\`\`
12758
+ </todo_format>
12759
+
12760
+ <execution_loop>
12761
+ WHILE .opencode/todo.md has unchecked [ ] items:
12762
+ 1. IDENTIFY all tasks with satisfied dependencies
12763
+ 2. LAUNCH all identified tasks in PARALLEL (background=true)
12764
+ 3. START any slow commands via ${TOOL_NAMES.RUN_BACKGROUND}
12765
+ 4. MONITOR with ${TOOL_NAMES.LIST_TASKS} / ${TOOL_NAMES.LIST_BACKGROUND}
12766
+ 5. COLLECT results as they complete
12767
+ 6. UPDATE: ${AGENT_NAMES.REVIEWER} marks [x] and updates context
12768
+ 7. REPEAT until all complete
12769
+
12770
+ \u26A1 NEVER: Execute one-by-one when parallel is possible
12771
+ \u26A1 ALWAYS: Start slow operations in background immediately
12772
+ </execution_loop>
12773
+
12774
+ <anti_hallucination>
12775
+ BEFORE CODING:
12776
+ 1. Check .opencode/docs/ for cached documentation
12777
+ 2. If uncertain \u2192 ${AGENT_NAMES.PLANNER} researches first
12778
+ 3. Never guess API syntax - verify from official sources
12779
+
12780
+ TRIGGERS FOR RESEARCH:
12781
+ - Unfamiliar framework/library
12782
+ - Version-specific syntax
12783
+ - Complex configuration
12784
+ </anti_hallucination>
12785
+
12786
+ <error_handling>
12787
+ WHEN TASK FAILS:
12788
+ 1. ANALYZE error type (syntax? dependency? timeout?)
12789
+ 2. DECIDE:
12790
+ - Retryable \u2192 retry with different approach (max 2)
12791
+ - Blocker \u2192 mark blocked, continue parallel tasks
12792
+ - Critical \u2192 report to user
12793
+
12794
+ WHEN STUCK:
12795
+ 1. Find unblocked tasks in TODO
12796
+ 2. Run them in parallel
12797
+ 3. If completely blocked \u2192 report status
12798
+ </error_handling>
12799
+
12800
+ <completion>
12801
+ OUTPUT ONLY WHEN:
12802
+ 1. ALL items in .opencode/todo.md are [x]
12803
+ 2. Build/tests pass
12804
+ 3. ${AGENT_NAMES.REVIEWER} approves
12805
+
12806
+ **MISSION SEAL** (Explicit Completion Confirmation):
12807
+ When ALL work is truly complete, output the seal tag:
12808
+ \`\`\`
12809
+ ${MISSION_SEAL.PATTERN}
12810
+ \`\`\`
12811
+
12812
+ Then output:
12813
+ ${MISSION_SEAL.PATTERN}
12814
+ Summary: [accomplishments]
12815
+ Evidence: [test/build results]
12816
+
12817
+ \u26A0\uFE0F IMPORTANT: Only output ${MISSION_SEAL.PATTERN} when:
12818
+ - All todos are marked [x] complete
12819
+ - All tests pass
12820
+ - All builds succeed
12821
+ - You have verified the final result
12822
+ </completion>`,
12823
+ canWrite: true,
12824
+ canBash: true
12825
+ };
12826
+
12827
+ // src/agents/consolidated/planner.ts
12828
+ var planner = {
12829
+ id: AGENT_NAMES.PLANNER,
12830
+ description: "Planner - strategic planning and research",
12831
+ systemPrompt: `<role>
12832
+ You are ${AGENT_NAMES.PLANNER}. Strategic planner and researcher.
12833
+ You PLAN before coding and RESEARCH before implementing.
12834
+ Never guess - always verify with official sources.
12835
+ </role>
12836
+
12837
+ <responsibilities>
12838
+ 1. PLANNING: Break complex tasks into hierarchical, atomic pieces
12839
+ 2. RESEARCH: Gather verified information before implementation
12840
+ 3. DOCUMENTATION: Cache official docs for team reference
12841
+ </responsibilities>
12842
+
12843
+ <anti_hallucination>
12844
+ CRITICAL RULES:
12845
+ 1. EVERY claim must have a SOURCE
12846
+ 2. NEVER assume API compatibility between versions
12847
+ 3. NEVER invent function signatures
12848
+ 4. If not found \u2192 say "I could not find documentation"
12849
+ 5. Include confidence: HIGH (official) / MEDIUM (github) / LOW (blog)
12850
+ </anti_hallucination>
12851
+
12852
+ <planning_workflow>
12853
+ CREATE: .opencode/todo.md
12854
+
12855
+ \u26A1 PARALLELISM IS CRITICAL - Group tasks that can run simultaneously!
12856
+
12857
+ Task Structure:
12858
+ - Parallel Groups: Tasks with NO dependencies run together
12859
+ - Sequential: Only for tasks with real dependencies
12860
+ - Atomic: Each task = one focused action
12861
+
12862
+ FORMAT:
12863
+ \`\`\`markdown
12864
+ # Mission: [goal]
12865
+
12866
+ ## Parallel Group A (spawn all simultaneously)
12867
+ - [ ] T1: Research API | agent:${AGENT_NAMES.PLANNER} | size:S
12868
+ - [ ] T2: Research DB | agent:${AGENT_NAMES.PLANNER} | size:S
12869
+ - [ ] T3: Research Auth | agent:${AGENT_NAMES.PLANNER} | size:S
12870
+
12871
+ ## Parallel Group B (after Group A)
12872
+ - [ ] T4: Implement API | agent:${AGENT_NAMES.WORKER} | depends:T1 | size:M
12873
+ - [ ] T5: Implement DB | agent:${AGENT_NAMES.WORKER} | depends:T2 | size:M
12874
+
12875
+ ## Sequential (strict order required)
12876
+ - [ ] T6: Integration | agent:${AGENT_NAMES.WORKER} | depends:T4,T5 | size:L
12877
+ - [ ] T7: Verify all | agent:${AGENT_NAMES.REVIEWER} | depends:T6 | size:S
12878
+
12879
+ ## Notes
12880
+ [context for team]
12881
+ \`\`\`
12882
+
12883
+ MAXIMIZE PARALLELISM:
12884
+ - Research tasks \u2192 ALL parallel (different topics)
12885
+ - Implementation \u2192 Parallel if different files
12886
+ - Sequential ONLY when: same file edit, strict A\u2192B dependency
12887
+ </planning_workflow>
12888
+
12889
+ <research_workflow>
12890
+ 1. SEARCH: websearch "[topic] official documentation [version]"
12891
+ 2. VERIFY: Check for official sources
12892
+ 3. FETCH: webfetch official docs with cache=true
12893
+ 4. EXTRACT: Copy EXACT syntax (not paraphrased)
12894
+ 5. SAVE: Write to .opencode/docs/[topic].md with source URL
12895
+ </research_workflow>
12896
+
12897
+ <estimation>
12898
+ TASK SIZING:
12899
+ | Size | Time | Description |
12900
+ |------|------|-------------|
12901
+ | XS | <5min | Config, typo fix |
12902
+ | S | 5-15min | Small feature |
12903
+ | M | 15-30min | Multi-file |
12904
+ | L | 30-60min | Complex |
12905
+ | XL | >60min | Break down further |
12906
+ </estimation>
12907
+
12908
+ <fallback_paths>
12909
+ FOR CRITICAL TASKS:
12910
+ - Primary: Best approach
12911
+ - Fallback: If primary fails
12912
+ - Minimum: Simplest working solution
12913
+ </fallback_paths>
12914
+
12915
+ <shared_workspace>
12916
+ ALL WORK IN .opencode/:
12917
+ - .opencode/todo.md - master TODO (you create)
12918
+ - .opencode/docs/ - cached documentation (you save)
12919
+ - .opencode/context.md - current state
12920
+ </shared_workspace>
12921
+
12922
+ <output>
12923
+ # Planning Report
12924
+
12925
+ ## Research Done
12926
+ | Finding | Source | Confidence |
12927
+ |---------|--------|------------|
12928
+ | [fact] | [URL] | HIGH/MEDIUM/LOW |
12929
+
12930
+ ## TODO Created
12931
+ .opencode/todo.md with [N] tasks
12932
+
12933
+ ## Docs Saved
12934
+ - .opencode/docs/[topic].md
12935
+
12936
+ Ready for ${AGENT_NAMES.WORKER}
12937
+ </output>`,
12938
+ canWrite: true,
12939
+ canBash: true
12940
+ };
12941
+
12942
+ // src/agents/consolidated/worker.ts
12943
+ var worker = {
12944
+ id: AGENT_NAMES.WORKER,
12945
+ description: "Worker - implementation and documentation",
12946
+ systemPrompt: `<role>
12947
+ You are ${AGENT_NAMES.WORKER}. Implementation specialist and documentation handler.
12948
+ Write code, create files, configure systems.
12949
+ Fetch and cache official documentation when needed.
12950
+ Works with ANY language or framework.
12951
+ </role>
12952
+
12953
+ <responsibilities>
12954
+ 1. IMPLEMENTATION: Write code, create files, configurations
12955
+ 2. DOCUMENTATION: Search and cache official docs when needed
12956
+ 3. VERIFICATION: Verify your own changes work before reporting
12957
+ </responsibilities>
12958
+
12959
+ <anti_hallucination>
12960
+ BEFORE CODING:
12961
+ 1. Check .opencode/docs/ for cached docs
12962
+ 2. If not found \u2192 websearch for official docs
12963
+ 3. webfetch official docs with cache=true
12964
+ 4. NEVER guess API syntax - wait for verified docs
12965
+
12966
+ TRUSTED SOURCES:
12967
+ - Official docs: docs.[framework].com
12968
+ - GitHub: github.com/[org]/[repo]
12969
+ - Package registries: npmjs.com, pypi.org
12970
+ </anti_hallucination>
12971
+
12972
+ <workflow>
12973
+ 1. Check .opencode/todo.md for your assigned task
12974
+ 2. Read .opencode/docs/ for relevant documentation
12975
+ 3. If docs missing \u2192 search and cache them first
12976
+ 4. Check existing patterns in codebase
12977
+ 5. Implement following existing conventions
12978
+ 6. Verify your changes work (build/test)
12979
+ 7. Report completion
12980
+ </workflow>
12981
+
12982
+ <quality_standards>
12983
+ EVERY IMPLEMENTATION MUST:
12984
+ 1. Follow existing code patterns
12985
+ 2. Include error handling (try/catch, validation)
12986
+ 3. Add JSDoc/comments for public APIs
12987
+ 4. Type safety (no 'any' unless justified)
12988
+ 5. No hardcoded values (use constants)
12989
+
12990
+ TEST REQUIREMENTS:
12991
+ - New feature \u2192 create test file
12992
+ - Bug fix \u2192 add regression test
12993
+ - Existing tests must pass
12994
+ </quality_standards>
12995
+
12996
+ <implementation_checklist>
12997
+ BEFORE REPORTING COMPLETE:
12998
+ \u25A1 Code compiles without errors
12999
+ \u25A1 lsp_diagnostics shows no issues
13000
+ \u25A1 Existing tests pass
13001
+ \u25A1 Changes are minimal and focused
13002
+ \u25A1 No console.log debugging left
13003
+ \u25A1 Error cases handled
13004
+ </implementation_checklist>
13005
+
13006
+ <doc_caching>
13007
+ WHEN DOCS NEEDED:
13008
+ 1. websearch "[topic] official documentation"
13009
+ 2. webfetch official docs with cache=true
13010
+ 3. Save key info to .opencode/docs/[topic].md
13011
+
13012
+ FORMAT:
13013
+ \`\`\`markdown
13014
+ # [Topic] Documentation
13015
+ Source: [official URL]
13016
+ Version: [version]
13017
+ Retrieved: [date]
13018
+
13019
+ ## Official API/Syntax
13020
+ [exact code from docs]
13021
+ \`\`\`
13022
+ </doc_caching>
13023
+
13024
+ <shared_workspace>
13025
+ ALL IN .opencode/:
13026
+ - .opencode/todo.md - your assigned tasks
13027
+ - .opencode/docs/ - documentation cache
13028
+ - .opencode/context.md - current state
13029
+ </shared_workspace>
13030
+
13031
+ <output>
13032
+ TASK: T[N] from .opencode/todo.md
13033
+ CHANGED: [file] [lines]
13034
+ ACTION: [what]
13035
+ VERIFY: [build/test result]
13036
+ DOCS_USED: .opencode/docs/[file]
13037
+ \u2192 Task complete, ready for ${AGENT_NAMES.REVIEWER}
13038
+ </output>`,
13039
+ canWrite: true,
13040
+ canBash: true
13041
+ };
13042
+
13043
+ // src/agents/consolidated/reviewer.ts
13044
+ var reviewer = {
13045
+ id: AGENT_NAMES.REVIEWER,
13046
+ description: "Reviewer - verification and context management",
13047
+ systemPrompt: `<role>
13048
+ You are ${AGENT_NAMES.REVIEWER}. Verification specialist and context manager.
13049
+ Verify implementations against docs, track progress, manage .opencode/ context.
13050
+ Works with ANY language or framework.
13051
+ </role>
13052
+
13053
+ <responsibilities>
13054
+ 1. VERIFICATION: Prove implementations work with evidence
13055
+ 2. TODO TRACKING: Update checkboxes in .opencode/todo.md
13056
+ 3. CONTEXT MANAGEMENT: Keep .opencode/ lean and relevant
13057
+ </responsibilities>
13058
+
13059
+ <verification_workflow>
13060
+ 1. Check .opencode/todo.md for verification tasks
13061
+ 2. Read .opencode/docs/ for expected patterns
13062
+ 3. Verify implementation matches docs
13063
+ 4. Run build/test commands
13064
+ 5. Update TODO checkboxes
13065
+ 6. Maintain context.md
13066
+ </verification_workflow>
13067
+
13068
+ <audit_checklist>
13069
+ 1. SYNTAX: lsp_diagnostics or language tools
13070
+ 2. BUILD/TEST: Run project's commands
13071
+ 3. DOC_COMPLIANCE: Match .opencode/docs/
13072
+ 4. LOGIC: Manual review if no tests
13073
+ 5. SECURITY: Check for vulnerabilities
13074
+ </audit_checklist>
13075
+
13076
+ <auto_fix>
13077
+ WHEN ISSUES FOUND:
13078
+ - Trivial (typo, import) \u2192 Fix directly
13079
+ - Logic issue \u2192 Report to ${AGENT_NAMES.WORKER} with fix suggestion
13080
+ - Architecture \u2192 Escalate to ${AGENT_NAMES.COMMANDER}
13081
+
13082
+ FIX AUTHORITY:
13083
+ - \u2705 CAN FIX: Lint errors, formatting, minor typos
13084
+ - \u26A0\uFE0F SUGGEST: Logic changes, refactoring
13085
+ - \u274C ESCALATE: Architecture, new dependencies, security
13086
+ </auto_fix>
13087
+
13088
+ <security_check>
13089
+ VERIFY:
13090
+ \u25A1 No hardcoded secrets/passwords
13091
+ \u25A1 Input validation present
13092
+ \u25A1 No SQL injection risks
13093
+ \u25A1 No XSS vulnerabilities
13094
+ \u25A1 Proper error messages
13095
+ </security_check>
13096
+
13097
+ <todo_management>
13098
+ FILE: .opencode/todo.md
13099
+
13100
+ UPDATE FORMAT:
13101
+ \`\`\`markdown
13102
+ - [x] T1: [task] | \u2705 DONE
13103
+ - [ ] T2: [task] | in progress
13104
+ - [ ] T3: [task] | blocked: [reason]
13105
+ \`\`\`
13106
+ </todo_management>
13114
13107
 
13115
- // node_modules/zod/v4/classic/compat.js
13116
- var ZodIssueCode = {
13117
- invalid_type: "invalid_type",
13118
- too_big: "too_big",
13119
- too_small: "too_small",
13120
- invalid_format: "invalid_format",
13121
- not_multiple_of: "not_multiple_of",
13122
- unrecognized_keys: "unrecognized_keys",
13123
- invalid_union: "invalid_union",
13124
- invalid_key: "invalid_key",
13125
- invalid_element: "invalid_element",
13126
- invalid_value: "invalid_value",
13127
- custom: "custom"
13128
- };
13129
- function setErrorMap(map2) {
13130
- config({
13131
- customError: map2
13132
- });
13133
- }
13134
- function getErrorMap() {
13135
- return config().customError;
13136
- }
13137
- var ZodFirstPartyTypeKind;
13138
- /* @__PURE__ */ (function(ZodFirstPartyTypeKind2) {
13139
- })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
13108
+ <context_management>
13109
+ DYNAMIC DETAIL LEVELS:
13140
13110
 
13141
- // node_modules/zod/v4/classic/coerce.js
13142
- var coerce_exports = {};
13143
- __export(coerce_exports, {
13144
- bigint: () => bigint3,
13145
- boolean: () => boolean3,
13146
- date: () => date4,
13147
- number: () => number3,
13148
- string: () => string3
13149
- });
13150
- function string3(params) {
13151
- return _coercedString(ZodString, params);
13152
- }
13153
- function number3(params) {
13154
- return _coercedNumber(ZodNumber, params);
13155
- }
13156
- function boolean3(params) {
13157
- return _coercedBoolean(ZodBoolean, params);
13158
- }
13159
- function bigint3(params) {
13160
- return _coercedBigint(ZodBigInt, params);
13161
- }
13162
- function date4(params) {
13163
- return _coercedDate(ZodDate, params);
13164
- }
13111
+ PHASE 1 - EARLY (0-30% done):
13112
+ - BE DETAILED: Full explanations, decisions
13113
+ - Include: research, API references
13165
13114
 
13166
- // node_modules/zod/v4/classic/external.js
13167
- config(en_default());
13115
+ PHASE 2 - BUILDING (30-70%):
13116
+ - MODERATE: Key decisions + file references
13117
+ - Reference: "See src/module.ts"
13168
13118
 
13169
- // node_modules/@opencode-ai/plugin/dist/tool.js
13170
- function tool(input) {
13171
- return input;
13172
- }
13173
- tool.schema = external_exports;
13119
+ PHASE 3 - FINISHING (70-100%):
13120
+ - BRIEF: Just status, blockers
13121
+ - Heavy summarization
13122
+
13123
+ ADAPTIVE RULES:
13124
+ | Condition | Action |
13125
+ |-----------|--------|
13126
+ | > 150 lines context.md | Compress to 50 |
13127
+ | Feature complete | Delete related verbose docs |
13128
+ | Code exists for feature | Point to code instead |
13129
+ </context_management>
13130
+
13131
+ <cleanup_triggers>
13132
+ AFTER EACH UPDATE:
13133
+ 1. Is this info needed for FUTURE tasks? No \u2192 DELETE
13134
+ 2. Is this in code now? Yes \u2192 SUMMARIZE to reference
13135
+ 3. context.md > 150 lines? COMPRESS
13136
+ 4. Doc > 7 days old + unused? ARCHIVE
13137
+ </cleanup_triggers>
13138
+
13139
+ <shared_workspace>
13140
+ .opencode/
13141
+ \u251C\u2500\u2500 todo.md - Master TODO (update checkboxes)
13142
+ \u251C\u2500\u2500 context.md - Current state (adaptive size)
13143
+ \u251C\u2500\u2500 docs/ - Cached documentation
13144
+ \u2514\u2500\u2500 archive/ - Old context
13145
+ </shared_workspace>
13146
+
13147
+ <output>
13148
+ TASK: T[N] from .opencode/todo.md
13149
+
13150
+ \u2705 PASS: [evidence]
13151
+ Matches: .opencode/docs/[file]
13152
+
13153
+ \u274C FAIL: [issue]
13154
+ Fix: [suggestion]
13155
+
13156
+ CONTEXT UPDATED:
13157
+ - todo.md: [X/Y done]
13158
+ - context.md: [before \u2192 after lines]
13159
+ - Phase: [EARLY/BUILDING/FINISHING]
13160
+
13161
+ Next: [task for team]
13162
+ </output>`,
13163
+ canWrite: true,
13164
+ canBash: true
13165
+ };
13166
+
13167
+ // src/agents/definitions.ts
13168
+ var AGENTS = {
13169
+ [AGENT_NAMES.COMMANDER]: commander,
13170
+ [AGENT_NAMES.PLANNER]: planner,
13171
+ [AGENT_NAMES.WORKER]: worker,
13172
+ [AGENT_NAMES.REVIEWER]: reviewer
13173
+ };
13174
13174
 
13175
13175
  // src/tools/callAgent.ts
13176
13176
  var callAgentTool = tool({
@@ -15384,140 +15384,8 @@ function createAsyncAgentTools(manager, client) {
15384
15384
  get_task_result: createGetTaskResultTool(manager),
15385
15385
  list_tasks: createListTasksTool(manager),
15386
15386
  cancel_task: createCancelTaskTool(manager)
15387
- };
15388
- }
15389
-
15390
- // src/utils/common.ts
15391
- function detectSlashCommand(text) {
15392
- const match = text.trim().match(/^\/([a-zA-Z0-9_-]+)(?:\s+(.*))?$/);
15393
- if (!match) return null;
15394
- return { command: match[1], args: match[2] || "" };
15395
- }
15396
- function formatTimestamp(date5 = /* @__PURE__ */ new Date()) {
15397
- const pad = (n) => n.toString().padStart(2, "0");
15398
- return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
15399
- }
15400
- function formatElapsedTime(startMs, endMs = Date.now()) {
15401
- const elapsed = endMs - startMs;
15402
- if (elapsed < 0) return "0s";
15403
- const seconds = Math.floor(elapsed / 1e3) % 60;
15404
- const minutes = Math.floor(elapsed / (1e3 * 60)) % 60;
15405
- const hours = Math.floor(elapsed / (1e3 * 60 * 60));
15406
- const parts = [];
15407
- if (hours > 0) parts.push(`${hours}h`);
15408
- if (minutes > 0) parts.push(`${minutes}m`);
15409
- if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
15410
- return parts.join(" ");
15411
- }
15412
-
15413
- // src/utils/sanity.ts
15414
- var SEVERITY = {
15415
- OK: "ok",
15416
- WARNING: "warning",
15417
- CRITICAL: "critical"
15418
- };
15419
- function checkOutputSanity(text) {
15420
- if (!text || text.length < 50) {
15421
- return { isHealthy: true, severity: SEVERITY.OK };
15422
- }
15423
- if (/(.)\1{15,}/.test(text)) {
15424
- return {
15425
- isHealthy: false,
15426
- reason: "Single character repetition detected",
15427
- severity: SEVERITY.CRITICAL
15428
- };
15429
- }
15430
- if (/(.{2,6})\1{8,}/.test(text)) {
15431
- return {
15432
- isHealthy: false,
15433
- reason: "Pattern loop detected",
15434
- severity: SEVERITY.CRITICAL
15435
- };
15436
- }
15437
- if (text.length > 200) {
15438
- const cleanText = text.replace(/\s/g, "");
15439
- if (cleanText.length > 100) {
15440
- const uniqueChars = new Set(cleanText).size;
15441
- const ratio = uniqueChars / cleanText.length;
15442
- if (ratio < 0.02) {
15443
- return {
15444
- isHealthy: false,
15445
- reason: "Low information density",
15446
- severity: SEVERITY.CRITICAL
15447
- };
15448
- }
15449
- }
15450
- }
15451
- const boxChars = (text.match(/[\u2500-\u257f\u2580-\u259f\u2800-\u28ff]/g) || []).length;
15452
- if (boxChars > 100 && boxChars / text.length > 0.3) {
15453
- return {
15454
- isHealthy: false,
15455
- reason: "Visual gibberish detected",
15456
- severity: SEVERITY.CRITICAL
15457
- };
15458
- }
15459
- const lines = text.split("\n").filter((l) => l.trim().length > 10);
15460
- if (lines.length > 10) {
15461
- const lineSet = new Set(lines);
15462
- if (lineSet.size < lines.length * 0.2) {
15463
- return {
15464
- isHealthy: false,
15465
- reason: "Excessive line repetition",
15466
- severity: SEVERITY.WARNING
15467
- };
15468
- }
15469
- }
15470
- const cjkChars = (text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) || []).length;
15471
- if (cjkChars > 200) {
15472
- const uniqueCjk = new Set(
15473
- text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) || []
15474
- ).size;
15475
- if (uniqueCjk < 10 && cjkChars / uniqueCjk > 20) {
15476
- return {
15477
- isHealthy: false,
15478
- reason: "CJK character spam detected",
15479
- severity: SEVERITY.CRITICAL
15480
- };
15481
- }
15482
- }
15483
- return { isHealthy: true, severity: SEVERITY.OK };
15484
- }
15485
- var RECOVERY_PROMPT = `<anomaly_recovery>
15486
- \u26A0\uFE0F SYSTEM NOTICE: Previous output was malformed (gibberish/loop detected).
15487
-
15488
- <recovery_protocol>
15489
- 1. DISCARD the corrupted output completely - do not reference it
15490
- 2. RECALL the original mission objective
15491
- 3. IDENTIFY the last confirmed successful step
15492
- 4. RESTART with a simpler, more focused approach
15493
- </recovery_protocol>
15494
-
15495
- <instructions>
15496
- - If a sub-agent produced bad output: try a different agent or simpler task
15497
- - If stuck in a loop: break down the task into smaller pieces
15498
- - If context seems corrupted: call Reviewer to restore context
15499
- - THINK in English for maximum stability
15500
- </instructions>
15501
-
15502
- What was the original task? Proceed from the last known good state.
15503
- </anomaly_recovery>`;
15504
- var ESCALATION_PROMPT = `<critical_anomaly>
15505
- \u{1F6A8} CRITICAL: Multiple consecutive malformed outputs detected.
15506
-
15507
- <emergency_protocol>
15508
- 1. STOP current execution path immediately
15509
- 2. DO NOT continue with the same approach - it is failing
15510
- 3. CALL Planner for a completely new strategy
15511
- 4. If Planner also fails: report status to user and await guidance
15512
- </emergency_protocol>
15513
-
15514
- <diagnosis>
15515
- The current approach is producing corrupted output.
15516
- This may indicate: context overload, model instability, or task complexity.
15517
- </diagnosis>
15518
-
15519
- Request a fresh plan from Planner with reduced scope.
15520
- </critical_anomaly>`;
15387
+ };
15388
+ }
15521
15389
 
15522
15390
  // src/core/cache/constants.ts
15523
15391
  var CACHE_DIR = PATHS.DOCS;
@@ -16293,104 +16161,87 @@ ${r.content}
16293
16161
  }
16294
16162
  });
16295
16163
 
16296
- // src/core/loop/stats.ts
16297
- function getIncompleteCount(todos) {
16298
- return todos.filter(
16299
- (t) => t.status !== TODO_STATUS.COMPLETED && t.status !== TODO_STATUS.CANCELLED
16300
- ).length;
16301
- }
16302
- function hasRemainingWork(todos) {
16303
- return getIncompleteCount(todos) > 0;
16304
- }
16305
- function getNextPending(todos) {
16306
- const pending = todos.filter(
16307
- (t) => t.status === TODO_STATUS.PENDING || t.status === TODO_STATUS.IN_PROGRESS
16308
- );
16309
- const priorityOrder = { high: 0, medium: 1, low: 2 };
16310
- pending.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
16311
- return pending[0];
16164
+ // src/core/progress/store.ts
16165
+ var progressHistory = /* @__PURE__ */ new Map();
16166
+ var sessionStartTimes = /* @__PURE__ */ new Map();
16167
+ var MAX_HISTORY2 = 100;
16168
+ function startSession(sessionId) {
16169
+ sessionStartTimes.set(sessionId, /* @__PURE__ */ new Date());
16170
+ progressHistory.set(sessionId, []);
16312
16171
  }
16313
- function getStats(todos) {
16314
- const stats2 = {
16315
- total: todos.length,
16316
- pending: todos.filter((t) => t.status === TODO_STATUS.PENDING).length,
16317
- inProgress: todos.filter((t) => t.status === TODO_STATUS.IN_PROGRESS).length,
16318
- completed: todos.filter((t) => t.status === TODO_STATUS.COMPLETED).length,
16319
- cancelled: todos.filter((t) => t.status === TODO_STATUS.CANCELLED).length,
16320
- percentComplete: 0
16172
+ function recordSnapshot(sessionId, data) {
16173
+ const startedAt = sessionStartTimes.get(sessionId) || /* @__PURE__ */ new Date();
16174
+ const now = /* @__PURE__ */ new Date();
16175
+ const snapshot = {
16176
+ sessionId,
16177
+ timestamp: now,
16178
+ todos: {
16179
+ total: data.todoTotal || 0,
16180
+ completed: data.todoCompleted || 0,
16181
+ pending: (data.todoTotal || 0) - (data.todoCompleted || 0),
16182
+ percentage: data.todoTotal ? Math.round((data.todoCompleted || 0) / data.todoTotal * 100) : 0
16183
+ },
16184
+ tasks: {
16185
+ total: data.taskTotal || 0,
16186
+ running: data.taskRunning || 0,
16187
+ completed: data.taskCompleted || 0,
16188
+ failed: data.taskFailed || 0,
16189
+ percentage: data.taskTotal ? Math.round(((data.taskCompleted || 0) + (data.taskFailed || 0)) / data.taskTotal * 100) : 0
16190
+ },
16191
+ steps: {
16192
+ current: data.currentStep || 0,
16193
+ max: data.maxSteps || Infinity
16194
+ },
16195
+ startedAt,
16196
+ elapsedMs: now.getTime() - startedAt.getTime()
16321
16197
  };
16322
- if (stats2.total > 0) {
16323
- stats2.percentComplete = Math.round(
16324
- (stats2.completed + stats2.cancelled) / stats2.total * 100
16325
- );
16198
+ const history = progressHistory.get(sessionId) || [];
16199
+ history.push(snapshot);
16200
+ if (history.length > MAX_HISTORY2) {
16201
+ history.shift();
16326
16202
  }
16327
- return stats2;
16203
+ progressHistory.set(sessionId, history);
16204
+ return snapshot;
16328
16205
  }
16329
-
16330
- // src/core/loop/formatters.ts
16331
- function formatProgress(todos) {
16332
- const stats2 = getStats(todos);
16333
- const done = stats2.completed + stats2.cancelled;
16334
- return `${done}/${stats2.total} (${stats2.percentComplete}%)`;
16206
+ function getLatest(sessionId) {
16207
+ const history = progressHistory.get(sessionId);
16208
+ return history?.[history.length - 1];
16209
+ }
16210
+ function clearSession(sessionId) {
16211
+ progressHistory.delete(sessionId);
16212
+ sessionStartTimes.delete(sessionId);
16335
16213
  }
16336
- function generateContinuationPrompt(todos) {
16337
- const incomplete = todos.filter(
16338
- (t) => t.status !== TODO_STATUS.COMPLETED && t.status !== TODO_STATUS.CANCELLED
16339
- );
16340
- if (incomplete.length === 0) {
16341
- return "";
16342
- }
16343
- const next = getNextPending(todos);
16344
- const pendingTasks = incomplete.filter((t) => t.status === TODO_STATUS.PENDING);
16345
- const pendingCount = pendingTasks.length;
16346
- let prompt = `<todo_continuation>
16347
- \u{1F4CB} **TODO Progress**: ${formatProgress(todos)}
16348
-
16349
- **Incomplete Tasks** (${incomplete.length} remaining):
16350
- `;
16351
- for (const todo of incomplete.slice(0, 5)) {
16352
- const status = todo.status === TODO_STATUS.IN_PROGRESS ? "\u{1F504}" : "\u23F3";
16353
- const priority = todo.priority === "high" ? "\u{1F534}" : todo.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
16354
- prompt += `${status} ${priority} [${todo.id}] ${todo.content}
16355
- `;
16356
- }
16357
- if (incomplete.length > 5) {
16358
- prompt += `... and ${incomplete.length - 5} more
16359
- `;
16360
- }
16361
- if (pendingCount >= 2) {
16362
- prompt += `
16363
- \u26A1 **PARALLEL DISPATCH REQUIRED** \u26A1
16364
- You have ${pendingCount} pending tasks. Launch them ALL IN PARALLEL for maximum efficiency:
16365
-
16366
- \`\`\`
16367
- // EXECUTE NOW - Launch all ${pendingCount} tasks simultaneously:
16368
- `;
16369
- for (const todo of pendingTasks.slice(0, 6)) {
16370
- prompt += `delegate_task({ agent: "Worker", prompt: "${todo.content}", background: true })
16371
- `;
16372
- }
16373
- prompt += `\`\`\`
16374
-
16375
- \u26A0\uFE0F Do NOT run these sequentially. Use background=true for ALL.
16376
- After launching, use list_tasks to monitor progress.
16377
16214
 
16378
- `;
16215
+ // src/core/progress/formatters.ts
16216
+ function formatElapsed(ms) {
16217
+ const seconds = Math.floor(ms / 1e3);
16218
+ const minutes = Math.floor(seconds / 60);
16219
+ const hours = Math.floor(minutes / 60);
16220
+ if (hours > 0) {
16221
+ return `${hours}h ${minutes % 60}m`;
16222
+ } else if (minutes > 0) {
16223
+ return `${minutes}m ${seconds % 60}s`;
16379
16224
  } else {
16380
- prompt += `
16381
- **Action Required**:
16382
- 1. Continue working on incomplete todos
16383
- 2. Mark each task complete when finished
16384
- 3. Do NOT stop until all todos are completed or cancelled
16385
-
16386
- `;
16225
+ return `${seconds}s`;
16387
16226
  }
16388
- if (next) {
16389
- prompt += `**Next Task**: [${next.id}] ${next.content}
16390
- `;
16227
+ }
16228
+ function formatCompact(snapshot) {
16229
+ const parts = [];
16230
+ if (snapshot.todos.total > 0) {
16231
+ parts.push(`\u2705${snapshot.todos.completed}/${snapshot.todos.total}`);
16391
16232
  }
16392
- prompt += `</todo_continuation>`;
16393
- return prompt;
16233
+ if (snapshot.tasks.running > 0) {
16234
+ parts.push(`\u26A1${snapshot.tasks.running}`);
16235
+ }
16236
+ parts.push(`\u23F1${formatElapsed(snapshot.elapsedMs)}`);
16237
+ return parts.join(" | ");
16238
+ }
16239
+
16240
+ // src/core/progress/tracker.ts
16241
+ function formatCompact2(sessionId) {
16242
+ const snapshot = getLatest(sessionId);
16243
+ if (!snapshot) return "...";
16244
+ return formatCompact(snapshot);
16394
16245
  }
16395
16246
 
16396
16247
  // src/shared/error-patterns.ts
@@ -16417,7 +16268,7 @@ function detectErrorType(error45) {
16417
16268
  // src/core/recovery/constants.ts
16418
16269
  var MAX_RETRIES = 3;
16419
16270
  var BASE_DELAY = 1e3;
16420
- var MAX_HISTORY2 = 100;
16271
+ var MAX_HISTORY3 = 100;
16421
16272
 
16422
16273
  // src/core/recovery/patterns.ts
16423
16274
  var errorPatterns = [
@@ -16502,7 +16353,7 @@ function handleError(context) {
16502
16353
  action,
16503
16354
  timestamp: /* @__PURE__ */ new Date()
16504
16355
  });
16505
- if (recoveryHistory.length > MAX_HISTORY2) {
16356
+ if (recoveryHistory.length > MAX_HISTORY3) {
16506
16357
  recoveryHistory.shift();
16507
16358
  }
16508
16359
  return action;
@@ -16625,26 +16476,126 @@ async function handleSessionError(client, sessionID, error45, properties) {
16625
16476
  state2.isRecovering = false;
16626
16477
  return true;
16627
16478
  }
16628
- state2.isRecovering = false;
16629
- return false;
16630
- } catch (injectionError) {
16631
- log2("[session-recovery] Failed to inject recovery prompt", { sessionID, error: injectionError });
16632
- state2.isRecovering = false;
16633
- return false;
16479
+ state2.isRecovering = false;
16480
+ return false;
16481
+ } catch (injectionError) {
16482
+ log2("[session-recovery] Failed to inject recovery prompt", { sessionID, error: injectionError });
16483
+ state2.isRecovering = false;
16484
+ return false;
16485
+ }
16486
+ }
16487
+ function markRecoveryComplete(sessionID) {
16488
+ const state2 = recoveryState.get(sessionID);
16489
+ if (state2) {
16490
+ state2.isRecovering = false;
16491
+ state2.errorCount = 0;
16492
+ }
16493
+ }
16494
+ function cleanupSessionRecovery(sessionID) {
16495
+ recoveryState.delete(sessionID);
16496
+ }
16497
+ function isSessionRecovering(sessionID) {
16498
+ return recoveryState.get(sessionID)?.isRecovering ?? false;
16499
+ }
16500
+
16501
+ // src/core/loop/stats.ts
16502
+ function getIncompleteCount(todos) {
16503
+ return todos.filter(
16504
+ (t) => t.status !== TODO_STATUS.COMPLETED && t.status !== TODO_STATUS.CANCELLED
16505
+ ).length;
16506
+ }
16507
+ function hasRemainingWork(todos) {
16508
+ return getIncompleteCount(todos) > 0;
16509
+ }
16510
+ function getNextPending(todos) {
16511
+ const pending = todos.filter(
16512
+ (t) => t.status === TODO_STATUS.PENDING || t.status === TODO_STATUS.IN_PROGRESS
16513
+ );
16514
+ const priorityOrder = { high: 0, medium: 1, low: 2 };
16515
+ pending.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
16516
+ return pending[0];
16517
+ }
16518
+ function getStats(todos) {
16519
+ const stats2 = {
16520
+ total: todos.length,
16521
+ pending: todos.filter((t) => t.status === TODO_STATUS.PENDING).length,
16522
+ inProgress: todos.filter((t) => t.status === TODO_STATUS.IN_PROGRESS).length,
16523
+ completed: todos.filter((t) => t.status === TODO_STATUS.COMPLETED).length,
16524
+ cancelled: todos.filter((t) => t.status === TODO_STATUS.CANCELLED).length,
16525
+ percentComplete: 0
16526
+ };
16527
+ if (stats2.total > 0) {
16528
+ stats2.percentComplete = Math.round(
16529
+ (stats2.completed + stats2.cancelled) / stats2.total * 100
16530
+ );
16531
+ }
16532
+ return stats2;
16533
+ }
16534
+
16535
+ // src/core/loop/formatters.ts
16536
+ function formatProgress(todos) {
16537
+ const stats2 = getStats(todos);
16538
+ const done = stats2.completed + stats2.cancelled;
16539
+ return `${done}/${stats2.total} (${stats2.percentComplete}%)`;
16540
+ }
16541
+ function generateContinuationPrompt(todos) {
16542
+ const incomplete = todos.filter(
16543
+ (t) => t.status !== TODO_STATUS.COMPLETED && t.status !== TODO_STATUS.CANCELLED
16544
+ );
16545
+ if (incomplete.length === 0) {
16546
+ return "";
16547
+ }
16548
+ const next = getNextPending(todos);
16549
+ const pendingTasks = incomplete.filter((t) => t.status === TODO_STATUS.PENDING);
16550
+ const pendingCount = pendingTasks.length;
16551
+ let prompt = `<todo_continuation>
16552
+ \u{1F4CB} **TODO Progress**: ${formatProgress(todos)}
16553
+
16554
+ **Incomplete Tasks** (${incomplete.length} remaining):
16555
+ `;
16556
+ for (const todo of incomplete.slice(0, 5)) {
16557
+ const status = todo.status === TODO_STATUS.IN_PROGRESS ? "\u{1F504}" : "\u23F3";
16558
+ const priority = todo.priority === "high" ? "\u{1F534}" : todo.priority === "medium" ? "\u{1F7E1}" : "\u{1F7E2}";
16559
+ prompt += `${status} ${priority} [${todo.id}] ${todo.content}
16560
+ `;
16561
+ }
16562
+ if (incomplete.length > 5) {
16563
+ prompt += `... and ${incomplete.length - 5} more
16564
+ `;
16565
+ }
16566
+ if (pendingCount >= 2) {
16567
+ prompt += `
16568
+ \u26A1 **PARALLEL DISPATCH REQUIRED** \u26A1
16569
+ You have ${pendingCount} pending tasks. Launch them ALL IN PARALLEL for maximum efficiency:
16570
+
16571
+ \`\`\`
16572
+ // EXECUTE NOW - Launch all ${pendingCount} tasks simultaneously:
16573
+ `;
16574
+ for (const todo of pendingTasks.slice(0, 6)) {
16575
+ prompt += `delegate_task({ agent: "Worker", prompt: "${todo.content}", background: true })
16576
+ `;
16577
+ }
16578
+ prompt += `\`\`\`
16579
+
16580
+ \u26A0\uFE0F Do NOT run these sequentially. Use background=true for ALL.
16581
+ After launching, use list_tasks to monitor progress.
16582
+
16583
+ `;
16584
+ } else {
16585
+ prompt += `
16586
+ **Action Required**:
16587
+ 1. Continue working on incomplete todos
16588
+ 2. Mark each task complete when finished
16589
+ 3. Do NOT stop until all todos are completed or cancelled
16590
+
16591
+ `;
16634
16592
  }
16635
- }
16636
- function markRecoveryComplete(sessionID) {
16637
- const state2 = recoveryState.get(sessionID);
16638
- if (state2) {
16639
- state2.isRecovering = false;
16640
- state2.errorCount = 0;
16593
+ if (next) {
16594
+ prompt += `**Next Task**: [${next.id}] ${next.content}
16595
+ `;
16641
16596
  }
16642
- }
16643
- function cleanupSessionRecovery(sessionID) {
16644
- recoveryState.delete(sessionID);
16645
- }
16646
- function isSessionRecovering(sessionID) {
16647
- return recoveryState.get(sessionID)?.isRecovering ?? false;
16597
+ prompt += `</todo_continuation>`;
16598
+ return prompt;
16648
16599
  }
16649
16600
 
16650
16601
  // src/core/loop/todo-continuation.ts
@@ -17176,92 +17127,457 @@ function handleAbort(sessionID) {
17176
17127
  log2("[mission-seal-handler] Marked as aborting");
17177
17128
  }
17178
17129
 
17179
- // src/core/progress/store.ts
17180
- var progressHistory = /* @__PURE__ */ new Map();
17181
- var sessionStartTimes = /* @__PURE__ */ new Map();
17182
- var MAX_HISTORY3 = 100;
17183
- function startSession(sessionId) {
17184
- sessionStartTimes.set(sessionId, /* @__PURE__ */ new Date());
17185
- progressHistory.set(sessionId, []);
17130
+ // src/plugin-handlers/event-handler.ts
17131
+ function createEventHandler(ctx) {
17132
+ const { client, directory, sessions, state: state2 } = ctx;
17133
+ return async (input) => {
17134
+ const { event } = input;
17135
+ try {
17136
+ const manager = ParallelAgentManager.getInstance();
17137
+ manager.handleEvent(event);
17138
+ } catch {
17139
+ }
17140
+ if (event.type === "session.created") {
17141
+ const sessionID = event.properties?.id || "";
17142
+ log2("[event-handler] session.created", { sessionID });
17143
+ presets.missionStarted(`Session ${sessionID.slice(0, 12)}...`);
17144
+ }
17145
+ if (event.type === "session.deleted") {
17146
+ const sessionID = event.properties?.id || event.properties?.info?.id || "";
17147
+ const session = sessions.get(sessionID);
17148
+ if (session) {
17149
+ const totalTime = Date.now() - session.startTime;
17150
+ const duration3 = totalTime < 6e4 ? `${Math.round(totalTime / 1e3)}s` : `${Math.round(totalTime / 6e4)}m`;
17151
+ log2("[event-handler] session.deleted", {
17152
+ sessionID,
17153
+ steps: session.step,
17154
+ duration: duration3
17155
+ });
17156
+ sessions.delete(sessionID);
17157
+ state2.sessions.delete(sessionID);
17158
+ clearSession(sessionID);
17159
+ cleanupSessionRecovery(sessionID);
17160
+ cleanupSession(sessionID);
17161
+ presets.sessionCompleted(sessionID, duration3);
17162
+ }
17163
+ }
17164
+ if (event.type === "session.error") {
17165
+ const sessionID = event.properties?.sessionId || event.properties?.sessionID || "";
17166
+ const error45 = event.properties?.error;
17167
+ log2("[event-handler] session.error", { sessionID, error: error45 });
17168
+ if (sessionID) {
17169
+ handleSessionError2(sessionID, error45);
17170
+ handleAbort(sessionID);
17171
+ }
17172
+ if (sessionID && error45) {
17173
+ const recovered = await handleSessionError(
17174
+ client,
17175
+ sessionID,
17176
+ error45,
17177
+ event.properties
17178
+ );
17179
+ if (recovered) {
17180
+ log2("[event-handler] auto-recovery initiated", { sessionID });
17181
+ return;
17182
+ }
17183
+ }
17184
+ presets.taskFailed("session", String(error45).slice(0, 50));
17185
+ }
17186
+ if (event.type === "message.updated") {
17187
+ const messageInfo = event.properties?.info;
17188
+ const sessionID = messageInfo?.sessionID;
17189
+ const role = messageInfo?.role;
17190
+ if (sessionID && role === "assistant") {
17191
+ markRecoveryComplete(sessionID);
17192
+ }
17193
+ }
17194
+ if (event.type === "session.idle") {
17195
+ const sessionID = event.properties?.sessionID || "";
17196
+ if (sessionID) {
17197
+ const isMainSession = sessions.has(sessionID);
17198
+ if (isMainSession) {
17199
+ setTimeout(async () => {
17200
+ const session = sessions.get(sessionID);
17201
+ if (session?.active) {
17202
+ if (isLoopActive(directory, sessionID)) {
17203
+ await handleMissionSealIdle(
17204
+ client,
17205
+ directory,
17206
+ sessionID,
17207
+ sessionID
17208
+ ).catch((err) => {
17209
+ log2("[event-handler] mission-seal-handler error", err);
17210
+ });
17211
+ } else {
17212
+ await handleSessionIdle(
17213
+ client,
17214
+ sessionID,
17215
+ sessionID
17216
+ ).catch((err) => {
17217
+ log2("[event-handler] todo-continuation error", err);
17218
+ });
17219
+ }
17220
+ }
17221
+ }, 500);
17222
+ }
17223
+ }
17224
+ }
17225
+ };
17186
17226
  }
17187
- function recordSnapshot(sessionId, data) {
17188
- const startedAt = sessionStartTimes.get(sessionId) || /* @__PURE__ */ new Date();
17189
- const now = /* @__PURE__ */ new Date();
17190
- const snapshot = {
17191
- sessionId,
17192
- timestamp: now,
17193
- todos: {
17194
- total: data.todoTotal || 0,
17195
- completed: data.todoCompleted || 0,
17196
- pending: (data.todoTotal || 0) - (data.todoCompleted || 0),
17197
- percentage: data.todoTotal ? Math.round((data.todoCompleted || 0) / data.todoTotal * 100) : 0
17198
- },
17199
- tasks: {
17200
- total: data.taskTotal || 0,
17201
- running: data.taskRunning || 0,
17202
- completed: data.taskCompleted || 0,
17203
- failed: data.taskFailed || 0,
17204
- percentage: data.taskTotal ? Math.round(((data.taskCompleted || 0) + (data.taskFailed || 0)) / data.taskTotal * 100) : 0
17205
- },
17206
- steps: {
17207
- current: data.currentStep || 0,
17208
- max: data.maxSteps || Infinity
17209
- },
17210
- startedAt,
17211
- elapsedMs: now.getTime() - startedAt.getTime()
17227
+
17228
+ // src/plugin-handlers/config-handler.ts
17229
+ function createConfigHandler() {
17230
+ const commanderPrompt = AGENTS[AGENT_NAMES.COMMANDER]?.systemPrompt || "";
17231
+ return async (config2) => {
17232
+ const existingCommands = config2.command ?? {};
17233
+ const existingAgents = config2.agent ?? {};
17234
+ const orchestratorCommands = {};
17235
+ for (const [name, cmd] of Object.entries(COMMANDS)) {
17236
+ orchestratorCommands[name] = {
17237
+ description: cmd.description,
17238
+ template: cmd.template,
17239
+ argumentHint: cmd.argumentHint
17240
+ };
17241
+ }
17242
+ const orchestratorAgents = {
17243
+ // Primary agent - the main orchestrator
17244
+ [AGENT_NAMES.COMMANDER]: {
17245
+ description: "Autonomous orchestrator - executes until mission complete",
17246
+ mode: "primary",
17247
+ prompt: commanderPrompt,
17248
+ maxTokens: 64e3,
17249
+ thinking: { type: "enabled", budgetTokens: 32e3 },
17250
+ color: "#FF6B6B"
17251
+ },
17252
+ // Consolidated subagents (4 agents instead of 6)
17253
+ [AGENT_NAMES.PLANNER]: {
17254
+ description: "Strategic planning and research specialist",
17255
+ mode: "subagent",
17256
+ hidden: true,
17257
+ prompt: AGENTS[AGENT_NAMES.PLANNER]?.systemPrompt || "",
17258
+ maxTokens: 32e3,
17259
+ color: "#9B59B6"
17260
+ },
17261
+ [AGENT_NAMES.WORKER]: {
17262
+ description: "Implementation and documentation specialist",
17263
+ mode: "subagent",
17264
+ hidden: true,
17265
+ prompt: AGENTS[AGENT_NAMES.WORKER]?.systemPrompt || "",
17266
+ maxTokens: 32e3,
17267
+ color: "#E67E22"
17268
+ },
17269
+ [AGENT_NAMES.REVIEWER]: {
17270
+ description: "Verification and context management specialist",
17271
+ mode: "subagent",
17272
+ hidden: true,
17273
+ prompt: AGENTS[AGENT_NAMES.REVIEWER]?.systemPrompt || "",
17274
+ maxTokens: 32e3,
17275
+ color: "#27AE60"
17276
+ }
17277
+ };
17278
+ const processedExistingAgents = { ...existingAgents };
17279
+ if (processedExistingAgents.build) {
17280
+ processedExistingAgents.build = {
17281
+ ...processedExistingAgents.build,
17282
+ mode: "subagent",
17283
+ hidden: true
17284
+ };
17285
+ }
17286
+ if (processedExistingAgents.plan) {
17287
+ processedExistingAgents.plan = {
17288
+ ...processedExistingAgents.plan,
17289
+ mode: "subagent"
17290
+ };
17291
+ }
17292
+ config2.command = { ...existingCommands, ...orchestratorCommands };
17293
+ config2.agent = { ...processedExistingAgents, ...orchestratorAgents };
17294
+ config2.default_agent = AGENT_NAMES.COMMANDER;
17295
+ console.log(`[orchestrator] Registered agents: ${Object.keys(orchestratorAgents).join(", ")}`);
17296
+ console.log(`[orchestrator] Default agent: ${AGENT_NAMES.COMMANDER}`);
17212
17297
  };
17213
- const history = progressHistory.get(sessionId) || [];
17214
- history.push(snapshot);
17215
- if (history.length > MAX_HISTORY3) {
17216
- history.shift();
17217
- }
17218
- progressHistory.set(sessionId, history);
17219
- return snapshot;
17220
17298
  }
17221
- function getLatest(sessionId) {
17222
- const history = progressHistory.get(sessionId);
17223
- return history?.[history.length - 1];
17299
+
17300
+ // src/utils/common.ts
17301
+ function detectSlashCommand(text) {
17302
+ const match = text.trim().match(/^\/([a-zA-Z0-9_-]+)(?:\s+(.*))?$/);
17303
+ if (!match) return null;
17304
+ return { command: match[1], args: match[2] || "" };
17224
17305
  }
17225
- function clearSession(sessionId) {
17226
- progressHistory.delete(sessionId);
17227
- sessionStartTimes.delete(sessionId);
17306
+ function formatTimestamp(date5 = /* @__PURE__ */ new Date()) {
17307
+ const pad = (n) => n.toString().padStart(2, "0");
17308
+ return `${date5.getFullYear()}-${pad(date5.getMonth() + 1)}-${pad(date5.getDate())} ${pad(date5.getHours())}:${pad(date5.getMinutes())}:${pad(date5.getSeconds())}`;
17309
+ }
17310
+ function formatElapsedTime(startMs, endMs = Date.now()) {
17311
+ const elapsed = endMs - startMs;
17312
+ if (elapsed < 0) return "0s";
17313
+ const seconds = Math.floor(elapsed / 1e3) % 60;
17314
+ const minutes = Math.floor(elapsed / (1e3 * 60)) % 60;
17315
+ const hours = Math.floor(elapsed / (1e3 * 60 * 60));
17316
+ const parts = [];
17317
+ if (hours > 0) parts.push(`${hours}h`);
17318
+ if (minutes > 0) parts.push(`${minutes}m`);
17319
+ if (seconds > 0 || parts.length === 0) parts.push(`${seconds}s`);
17320
+ return parts.join(" ");
17321
+ }
17322
+
17323
+ // src/plugin-handlers/chat-message-handler.ts
17324
+ function createChatMessageHandler(ctx) {
17325
+ const { directory, sessions } = ctx;
17326
+ return async (msgInput, msgOutput) => {
17327
+ const parts = msgOutput.parts;
17328
+ const textPartIndex = parts.findIndex((p) => p.type === PART_TYPES.TEXT && p.text);
17329
+ if (textPartIndex === -1) return;
17330
+ const originalText = parts[textPartIndex].text || "";
17331
+ const parsed = detectSlashCommand(originalText);
17332
+ const sessionID = msgInput.sessionID;
17333
+ const agentName = (msgInput.agent || "").toLowerCase();
17334
+ log2("[chat-message-handler] hook triggered", { sessionID, agent: agentName, textLength: originalText.length });
17335
+ if (sessionID) {
17336
+ handleUserMessage(sessionID);
17337
+ }
17338
+ if (agentName === AGENT_NAMES.COMMANDER) {
17339
+ if (!sessions.has(sessionID)) {
17340
+ const now = Date.now();
17341
+ sessions.set(sessionID, {
17342
+ active: true,
17343
+ step: 0,
17344
+ timestamp: now,
17345
+ startTime: now,
17346
+ lastStepTime: now
17347
+ });
17348
+ state.missionActive = true;
17349
+ state.sessions.set(sessionID, {
17350
+ enabled: true,
17351
+ iterations: 0,
17352
+ taskRetries: /* @__PURE__ */ new Map(),
17353
+ currentTask: "",
17354
+ anomalyCount: 0
17355
+ });
17356
+ startSession(sessionID);
17357
+ presets.taskStarted(sessionID, AGENT_NAMES.COMMANDER);
17358
+ }
17359
+ if (!parsed || parsed.command !== "task") {
17360
+ const taskTemplate = COMMANDS["task"].template;
17361
+ const userMessage = parsed?.args || originalText;
17362
+ parts[textPartIndex].text = taskTemplate.replace(
17363
+ /\$ARGUMENTS/g,
17364
+ userMessage || PROMPTS.CONTINUE
17365
+ );
17366
+ startMissionLoop(directory, sessionID, userMessage || originalText);
17367
+ log2("[chat-message-handler] Auto-applied mission mode + started loop", { originalLength: originalText.length });
17368
+ }
17369
+ }
17370
+ if (parsed) {
17371
+ const command = COMMANDS[parsed.command];
17372
+ if (command && agentName !== AGENT_NAMES.COMMANDER) {
17373
+ parts[textPartIndex].text = command.template.replace(
17374
+ /\$ARGUMENTS/g,
17375
+ parsed.args || PROMPTS.CONTINUE
17376
+ );
17377
+ } else if (command && parsed.command === "task") {
17378
+ parts[textPartIndex].text = command.template.replace(
17379
+ /\$ARGUMENTS/g,
17380
+ parsed.args || PROMPTS.CONTINUE
17381
+ );
17382
+ startMissionLoop(directory, sessionID, parsed.args || "continue from where we left off");
17383
+ log2("[chat-message-handler] /task command: started mission loop", { sessionID, args: parsed.args?.slice(0, 50) });
17384
+ }
17385
+ }
17386
+ };
17387
+ }
17388
+
17389
+ // src/utils/sanity.ts
17390
+ var SEVERITY = {
17391
+ OK: "ok",
17392
+ WARNING: "warning",
17393
+ CRITICAL: "critical"
17394
+ };
17395
+ function checkOutputSanity(text) {
17396
+ if (!text || text.length < 50) {
17397
+ return { isHealthy: true, severity: SEVERITY.OK };
17398
+ }
17399
+ if (/(.)\1{15,}/.test(text)) {
17400
+ return {
17401
+ isHealthy: false,
17402
+ reason: "Single character repetition detected",
17403
+ severity: SEVERITY.CRITICAL
17404
+ };
17405
+ }
17406
+ if (/(.{2,6})\1{8,}/.test(text)) {
17407
+ return {
17408
+ isHealthy: false,
17409
+ reason: "Pattern loop detected",
17410
+ severity: SEVERITY.CRITICAL
17411
+ };
17412
+ }
17413
+ if (text.length > 200) {
17414
+ const cleanText = text.replace(/\s/g, "");
17415
+ if (cleanText.length > 100) {
17416
+ const uniqueChars = new Set(cleanText).size;
17417
+ const ratio = uniqueChars / cleanText.length;
17418
+ if (ratio < 0.02) {
17419
+ return {
17420
+ isHealthy: false,
17421
+ reason: "Low information density",
17422
+ severity: SEVERITY.CRITICAL
17423
+ };
17424
+ }
17425
+ }
17426
+ }
17427
+ const boxChars = (text.match(/[\u2500-\u257f\u2580-\u259f\u2800-\u28ff]/g) || []).length;
17428
+ if (boxChars > 100 && boxChars / text.length > 0.3) {
17429
+ return {
17430
+ isHealthy: false,
17431
+ reason: "Visual gibberish detected",
17432
+ severity: SEVERITY.CRITICAL
17433
+ };
17434
+ }
17435
+ const lines = text.split("\n").filter((l) => l.trim().length > 10);
17436
+ if (lines.length > 10) {
17437
+ const lineSet = new Set(lines);
17438
+ if (lineSet.size < lines.length * 0.2) {
17439
+ return {
17440
+ isHealthy: false,
17441
+ reason: "Excessive line repetition",
17442
+ severity: SEVERITY.WARNING
17443
+ };
17444
+ }
17445
+ }
17446
+ const cjkChars = (text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) || []).length;
17447
+ if (cjkChars > 200) {
17448
+ const uniqueCjk = new Set(
17449
+ text.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) || []
17450
+ ).size;
17451
+ if (uniqueCjk < 10 && cjkChars / uniqueCjk > 20) {
17452
+ return {
17453
+ isHealthy: false,
17454
+ reason: "CJK character spam detected",
17455
+ severity: SEVERITY.CRITICAL
17456
+ };
17457
+ }
17458
+ }
17459
+ return { isHealthy: true, severity: SEVERITY.OK };
17228
17460
  }
17461
+ var RECOVERY_PROMPT = `<anomaly_recovery>
17462
+ \u26A0\uFE0F SYSTEM NOTICE: Previous output was malformed (gibberish/loop detected).
17463
+
17464
+ <recovery_protocol>
17465
+ 1. DISCARD the corrupted output completely - do not reference it
17466
+ 2. RECALL the original mission objective
17467
+ 3. IDENTIFY the last confirmed successful step
17468
+ 4. RESTART with a simpler, more focused approach
17469
+ </recovery_protocol>
17470
+
17471
+ <instructions>
17472
+ - If a sub-agent produced bad output: try a different agent or simpler task
17473
+ - If stuck in a loop: break down the task into smaller pieces
17474
+ - If context seems corrupted: call Reviewer to restore context
17475
+ - THINK in English for maximum stability
17476
+ </instructions>
17477
+
17478
+ What was the original task? Proceed from the last known good state.
17479
+ </anomaly_recovery>`;
17480
+ var ESCALATION_PROMPT = `<critical_anomaly>
17481
+ \u{1F6A8} CRITICAL: Multiple consecutive malformed outputs detected.
17482
+
17483
+ <emergency_protocol>
17484
+ 1. STOP current execution path immediately
17485
+ 2. DO NOT continue with the same approach - it is failing
17486
+ 3. CALL Planner for a completely new strategy
17487
+ 4. If Planner also fails: report status to user and await guidance
17488
+ </emergency_protocol>
17229
17489
 
17230
- // src/core/progress/formatters.ts
17231
- function formatElapsed(ms) {
17232
- const seconds = Math.floor(ms / 1e3);
17233
- const minutes = Math.floor(seconds / 60);
17234
- const hours = Math.floor(minutes / 60);
17235
- if (hours > 0) {
17236
- return `${hours}h ${minutes % 60}m`;
17237
- } else if (minutes > 0) {
17238
- return `${minutes}m ${seconds % 60}s`;
17239
- } else {
17240
- return `${seconds}s`;
17241
- }
17242
- }
17243
- function formatCompact(snapshot) {
17244
- const parts = [];
17245
- if (snapshot.todos.total > 0) {
17246
- parts.push(`\u2705${snapshot.todos.completed}/${snapshot.todos.total}`);
17247
- }
17248
- if (snapshot.tasks.running > 0) {
17249
- parts.push(`\u26A1${snapshot.tasks.running}`);
17250
- }
17251
- parts.push(`\u23F1${formatElapsed(snapshot.elapsedMs)}`);
17252
- return parts.join(" | ");
17253
- }
17490
+ <diagnosis>
17491
+ The current approach is producing corrupted output.
17492
+ This may indicate: context overload, model instability, or task complexity.
17493
+ </diagnosis>
17254
17494
 
17255
- // src/core/progress/tracker.ts
17256
- function formatCompact2(sessionId) {
17257
- const snapshot = getLatest(sessionId);
17258
- if (!snapshot) return "...";
17259
- return formatCompact(snapshot);
17495
+ Request a fresh plan from Planner with reduced scope.
17496
+ </critical_anomaly>`;
17497
+
17498
+ // src/plugin-handlers/tool-execute-handler.ts
17499
+ function createToolExecuteAfterHandler(ctx) {
17500
+ const { sessions } = ctx;
17501
+ return async (toolInput, toolOutput) => {
17502
+ const session = sessions.get(toolInput.sessionID);
17503
+ if (!session?.active) return;
17504
+ const now = Date.now();
17505
+ const stepDuration = formatElapsedTime(session.lastStepTime, now);
17506
+ const totalElapsed = formatElapsedTime(session.startTime, now);
17507
+ session.step++;
17508
+ session.timestamp = now;
17509
+ session.lastStepTime = now;
17510
+ const stateSession = state.sessions.get(toolInput.sessionID);
17511
+ if (toolInput.tool === TOOL_NAMES.CALL_AGENT && stateSession) {
17512
+ const sanityResult = checkOutputSanity(toolOutput.output);
17513
+ if (!sanityResult.isHealthy) {
17514
+ stateSession.anomalyCount = (stateSession.anomalyCount || 0) + 1;
17515
+ const agentName = toolInput.arguments?.agent || "unknown";
17516
+ toolOutput.output = `\u26A0\uFE0F [${agentName.toUpperCase()}] OUTPUT ANOMALY DETECTED
17517
+
17518
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17519
+ \u26A0\uFE0F Gibberish/loop detected: ${sanityResult.reason}
17520
+ Anomaly count: ${stateSession.anomalyCount}
17521
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17522
+
17523
+ ` + (stateSession.anomalyCount >= 2 ? ESCALATION_PROMPT : RECOVERY_PROMPT);
17524
+ return;
17525
+ } else {
17526
+ if (stateSession.anomalyCount > 0) {
17527
+ stateSession.anomalyCount = 0;
17528
+ }
17529
+ if (toolOutput.output.length < 5e3) {
17530
+ stateSession.lastHealthyOutput = toolOutput.output.substring(0, 1e3);
17531
+ }
17532
+ }
17533
+ }
17534
+ if (toolInput.tool === TOOL_NAMES.CALL_AGENT && toolInput.arguments?.task && stateSession) {
17535
+ const taskIdMatch = toolInput.arguments.task.match(/\[(TASK-\d+)\]/i);
17536
+ if (taskIdMatch) {
17537
+ stateSession.currentTask = taskIdMatch[1].toUpperCase();
17538
+ }
17539
+ const agentName = toolInput.arguments.agent;
17540
+ const emoji3 = AGENT_EMOJI[agentName] || "\u{1F916}";
17541
+ toolOutput.output = `${emoji3} [${agentName.toUpperCase()}] Working...
17542
+
17543
+ ` + toolOutput.output;
17544
+ }
17545
+ if (stateSession) {
17546
+ const taskId = stateSession.currentTask;
17547
+ if (toolOutput.output.includes("\u2705 PASS") || toolOutput.output.includes("AUDIT RESULT: PASS")) {
17548
+ if (taskId) {
17549
+ stateSession.taskRetries.clear();
17550
+ toolOutput.output += `
17551
+
17552
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17553
+ \u2705 ${taskId} VERIFIED`;
17554
+ }
17555
+ } else if (toolOutput.output.includes("\u274C FAIL") || toolOutput.output.includes("AUDIT RESULT: FAIL")) {
17556
+ if (taskId) {
17557
+ const retries = (stateSession.taskRetries.get(taskId) || 0) + 1;
17558
+ stateSession.taskRetries.set(taskId, retries);
17559
+ if (retries >= state.maxRetries) {
17560
+ toolOutput.output += `
17561
+
17562
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17563
+ \u26A0\uFE0F ${taskId} FAILED (${retries}x)`;
17564
+ } else {
17565
+ toolOutput.output += `
17566
+
17567
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17568
+ \u{1F504} RETRY ${retries}/${state.maxRetries}`;
17569
+ }
17570
+ }
17571
+ }
17572
+ }
17573
+ const currentTime = formatTimestamp();
17574
+ toolOutput.output += `
17575
+
17576
+ \u23F1\uFE0F [${currentTime}] Step ${session.step} | This step: ${stepDuration} | Total: ${totalElapsed}`;
17577
+ };
17260
17578
  }
17261
17579
 
17262
- // src/index.ts
17263
- var require2 = createRequire(import.meta.url);
17264
- var { version: PLUGIN_VERSION } = require2("../package.json");
17580
+ // src/plugin-handlers/assistant-done-handler.ts
17265
17581
  var CONTINUE_INSTRUCTION = `<auto_continue>
17266
17582
  <status>Mission not complete. Keep executing.</status>
17267
17583
 
@@ -17289,6 +17605,120 @@ You are ONLY done when:
17289
17605
  Then output: ${MISSION_SEAL.PATTERN}
17290
17606
  </completion_criteria>
17291
17607
  </auto_continue>`;
17608
+ function createAssistantDoneHandler(ctx) {
17609
+ const { client, directory, sessions } = ctx;
17610
+ return async (assistantInput, assistantOutput) => {
17611
+ const sessionID = assistantInput.sessionID;
17612
+ const session = sessions.get(sessionID);
17613
+ if (!session?.active) return;
17614
+ const parts = assistantOutput.parts;
17615
+ const textContent = parts?.filter((p) => p.type === PART_TYPES.TEXT || p.type === PART_TYPES.REASONING).map((p) => p.text || "").join("\n") || "";
17616
+ const stateSession = state.sessions.get(sessionID);
17617
+ const sanityResult = checkOutputSanity(textContent);
17618
+ if (!sanityResult.isHealthy && stateSession) {
17619
+ stateSession.anomalyCount = (stateSession.anomalyCount || 0) + 1;
17620
+ session.step++;
17621
+ session.timestamp = Date.now();
17622
+ const recoveryText = stateSession.anomalyCount >= 2 ? ESCALATION_PROMPT : RECOVERY_PROMPT;
17623
+ try {
17624
+ if (client?.session?.prompt) {
17625
+ await client.session.prompt({
17626
+ path: { id: sessionID },
17627
+ body: {
17628
+ parts: [{
17629
+ type: PART_TYPES.TEXT,
17630
+ text: `\u26A0\uFE0F ANOMALY #${stateSession.anomalyCount}: ${sanityResult.reason}
17631
+
17632
+ ` + recoveryText + `
17633
+
17634
+ [Recovery Step ${session.step}]`
17635
+ }]
17636
+ }
17637
+ });
17638
+ }
17639
+ } catch {
17640
+ session.active = false;
17641
+ state.missionActive = false;
17642
+ }
17643
+ return;
17644
+ }
17645
+ if (stateSession && stateSession.anomalyCount > 0) {
17646
+ stateSession.anomalyCount = 0;
17647
+ }
17648
+ if (isLoopActive(directory, sessionID) && detectSealInText(textContent)) {
17649
+ session.active = false;
17650
+ state.missionActive = false;
17651
+ clearLoopState(directory);
17652
+ presets.missionComplete("\u{1F396}\uFE0F Mission Sealed - Explicit completion confirmed");
17653
+ log2("[assistant-done-handler] Mission sealed detected", { sessionID });
17654
+ clearSession(sessionID);
17655
+ sessions.delete(sessionID);
17656
+ state.sessions.delete(sessionID);
17657
+ return;
17658
+ }
17659
+ if (textContent.includes(MISSION.STOP_COMMAND) || textContent.includes(MISSION.CANCEL_COMMAND)) {
17660
+ session.active = false;
17661
+ state.missionActive = false;
17662
+ presets.taskFailed(sessionID, "Cancelled by user");
17663
+ clearSession(sessionID);
17664
+ sessions.delete(sessionID);
17665
+ state.sessions.delete(sessionID);
17666
+ return;
17667
+ }
17668
+ const now = Date.now();
17669
+ const stepDuration = formatElapsedTime(session.lastStepTime, now);
17670
+ const totalElapsed = formatElapsedTime(session.startTime, now);
17671
+ session.step++;
17672
+ session.timestamp = now;
17673
+ session.lastStepTime = now;
17674
+ const currentTime = formatTimestamp();
17675
+ recordSnapshot(sessionID, {
17676
+ currentStep: session.step
17677
+ });
17678
+ const progressInfo = formatCompact2(sessionID);
17679
+ try {
17680
+ if (client?.session?.prompt) {
17681
+ await client.session.prompt({
17682
+ path: { id: sessionID },
17683
+ body: {
17684
+ parts: [{
17685
+ type: PART_TYPES.TEXT,
17686
+ text: CONTINUE_INSTRUCTION + `
17687
+
17688
+ \u23F1\uFE0F [${currentTime}] Step ${session.step} | ${progressInfo} | This step: ${stepDuration} | Total: ${totalElapsed}`
17689
+ }]
17690
+ }
17691
+ });
17692
+ }
17693
+ } catch (error45) {
17694
+ log2("[assistant-done-handler] Continuation injection failed, retrying...", { sessionID, error: error45 });
17695
+ try {
17696
+ await new Promise((r) => setTimeout(r, 500));
17697
+ if (client?.session?.prompt) {
17698
+ await client.session.prompt({
17699
+ path: { id: sessionID },
17700
+ body: { parts: [{ type: PART_TYPES.TEXT, text: PROMPTS.CONTINUE }] }
17701
+ });
17702
+ }
17703
+ } catch (retryError) {
17704
+ log2("[assistant-done-handler] Both continuation attempts failed, waiting for idle handler", {
17705
+ sessionID,
17706
+ error: retryError,
17707
+ loopActive: isLoopActive(directory, sessionID)
17708
+ });
17709
+ if (!isLoopActive(directory, sessionID)) {
17710
+ log2("[assistant-done-handler] No active loop, stopping session", { sessionID });
17711
+ session.active = false;
17712
+ state.missionActive = false;
17713
+ }
17714
+ }
17715
+ }
17716
+ };
17717
+ }
17718
+
17719
+ // src/index.ts
17720
+ var require2 = createRequire(import.meta.url);
17721
+ var { version: PLUGIN_VERSION } = require2("../package.json");
17292
17722
  var OrchestratorPlugin = async (input) => {
17293
17723
  const { directory, client } = input;
17294
17724
  console.log(`[orchestrator] v${PLUGIN_VERSION} loaded`);
@@ -17302,6 +17732,12 @@ var OrchestratorPlugin = async (input) => {
17302
17732
  const asyncAgentTools = createAsyncAgentTools(parallelAgentManager2, client);
17303
17733
  taskToastManager.setConcurrencyController(parallelAgentManager2.getConcurrency());
17304
17734
  log2("[index.ts] ParallelAgentManager initialized with TaskToastManager integration");
17735
+ const handlerContext = {
17736
+ client,
17737
+ directory,
17738
+ sessions,
17739
+ state
17740
+ };
17305
17741
  return {
17306
17742
  // -----------------------------------------------------------------
17307
17743
  // Tools we expose to the LLM
@@ -17312,447 +17748,39 @@ var OrchestratorPlugin = async (input) => {
17312
17748
  [TOOL_NAMES.GREP_SEARCH]: grepSearchTool(directory),
17313
17749
  [TOOL_NAMES.GLOB_SEARCH]: globSearchTool(directory),
17314
17750
  [TOOL_NAMES.MGREP]: mgrepTool(directory),
17315
- // Multi-pattern grep (parallel, Rust-powered)
17316
- // Background task tools - run shell commands asynchronously
17751
+ // Background task tools
17317
17752
  [TOOL_NAMES.RUN_BACKGROUND]: runBackgroundTool,
17318
17753
  [TOOL_NAMES.CHECK_BACKGROUND]: checkBackgroundTool,
17319
17754
  [TOOL_NAMES.LIST_BACKGROUND]: listBackgroundTool,
17320
17755
  [TOOL_NAMES.KILL_BACKGROUND]: killBackgroundTool,
17321
- // Web tools - documentation research and caching
17756
+ // Web tools
17322
17757
  [TOOL_NAMES.WEBFETCH]: webfetchTool,
17323
17758
  [TOOL_NAMES.WEBSEARCH]: websearchTool,
17324
17759
  [TOOL_NAMES.CACHE_DOCS]: cacheDocsTool,
17325
17760
  [TOOL_NAMES.CODESEARCH]: codesearchTool,
17326
- // Async agent tools - spawn agents in parallel sessions
17761
+ // Async agent tools
17327
17762
  ...asyncAgentTools
17328
17763
  },
17329
17764
  // -----------------------------------------------------------------
17330
17765
  // Config hook - registers our commands and agents with OpenCode
17331
17766
  // -----------------------------------------------------------------
17332
- config: async (config2) => {
17333
- const existingCommands = config2.command ?? {};
17334
- const existingAgents = config2.agent ?? {};
17335
- const orchestratorCommands = {};
17336
- for (const [name, cmd] of Object.entries(COMMANDS)) {
17337
- orchestratorCommands[name] = {
17338
- description: cmd.description,
17339
- template: cmd.template,
17340
- argumentHint: cmd.argumentHint
17341
- };
17342
- }
17343
- const commanderPrompt = AGENTS[AGENT_NAMES.COMMANDER]?.systemPrompt || "";
17344
- console.log(`[orchestrator] Commander prompt length: ${commanderPrompt.length} chars`);
17345
- const orchestratorAgents = {
17346
- // Primary agent - the main orchestrator
17347
- [AGENT_NAMES.COMMANDER]: {
17348
- description: "Autonomous orchestrator - executes until mission complete",
17349
- mode: "primary",
17350
- prompt: commanderPrompt,
17351
- maxTokens: 64e3,
17352
- thinking: { type: "enabled", budgetTokens: 32e3 },
17353
- color: "#FF6B6B"
17354
- },
17355
- // Consolidated subagents (4 agents instead of 6)
17356
- [AGENT_NAMES.PLANNER]: {
17357
- description: "Strategic planning and research specialist",
17358
- mode: "subagent",
17359
- hidden: true,
17360
- prompt: AGENTS[AGENT_NAMES.PLANNER]?.systemPrompt || "",
17361
- maxTokens: 32e3,
17362
- color: "#9B59B6"
17363
- },
17364
- [AGENT_NAMES.WORKER]: {
17365
- description: "Implementation and documentation specialist",
17366
- mode: "subagent",
17367
- hidden: true,
17368
- prompt: AGENTS[AGENT_NAMES.WORKER]?.systemPrompt || "",
17369
- maxTokens: 32e3,
17370
- color: "#E67E22"
17371
- },
17372
- [AGENT_NAMES.REVIEWER]: {
17373
- description: "Verification and context management specialist",
17374
- mode: "subagent",
17375
- hidden: true,
17376
- prompt: AGENTS[AGENT_NAMES.REVIEWER]?.systemPrompt || "",
17377
- maxTokens: 32e3,
17378
- color: "#27AE60"
17379
- }
17380
- };
17381
- const processedExistingAgents = { ...existingAgents };
17382
- if (processedExistingAgents.build) {
17383
- processedExistingAgents.build = {
17384
- ...processedExistingAgents.build,
17385
- mode: "subagent",
17386
- hidden: true
17387
- };
17388
- }
17389
- if (processedExistingAgents.plan) {
17390
- processedExistingAgents.plan = {
17391
- ...processedExistingAgents.plan,
17392
- mode: "subagent"
17393
- };
17394
- }
17395
- config2.command = { ...existingCommands, ...orchestratorCommands };
17396
- config2.agent = { ...processedExistingAgents, ...orchestratorAgents };
17397
- config2.default_agent = AGENT_NAMES.COMMANDER;
17398
- console.log(`[orchestrator] Registered agents: ${Object.keys(orchestratorAgents).join(", ")}`);
17399
- console.log(`[orchestrator] Default agent: ${AGENT_NAMES.COMMANDER}`);
17400
- },
17767
+ config: createConfigHandler(),
17401
17768
  // -----------------------------------------------------------------
17402
- // Event hook - handles OpenCode events (SDK official)
17403
- // Replaces non-standard session.start/session.end hooks
17769
+ // Event hook - handles OpenCode events
17404
17770
  // -----------------------------------------------------------------
17405
- event: async (input2) => {
17406
- const { event } = input2;
17407
- try {
17408
- const manager = ParallelAgentManager.getInstance();
17409
- manager.handleEvent(event);
17410
- } catch {
17411
- }
17412
- if (event.type === "session.created") {
17413
- const sessionID = event.properties?.id || "";
17414
- log2("[index.ts] event: session.created", { sessionID });
17415
- presets.missionStarted(`Session ${sessionID.slice(0, 12)}...`);
17416
- }
17417
- if (event.type === "session.deleted") {
17418
- const sessionID = event.properties?.id || event.properties?.info?.id || "";
17419
- const session = sessions.get(sessionID);
17420
- if (session) {
17421
- const totalTime = Date.now() - session.startTime;
17422
- const duration3 = totalTime < 6e4 ? `${Math.round(totalTime / 1e3)}s` : `${Math.round(totalTime / 6e4)}m`;
17423
- log2("[index.ts] event: session.deleted", {
17424
- sessionID,
17425
- steps: session.step,
17426
- duration: duration3
17427
- });
17428
- sessions.delete(sessionID);
17429
- state.sessions.delete(sessionID);
17430
- clearSession(sessionID);
17431
- cleanupSessionRecovery(sessionID);
17432
- cleanupSession(sessionID);
17433
- presets.sessionCompleted(sessionID, duration3);
17434
- }
17435
- }
17436
- if (event.type === "session.error") {
17437
- const sessionID = event.properties?.sessionId || event.properties?.sessionID || "";
17438
- const error45 = event.properties?.error;
17439
- log2("[index.ts] event: session.error", { sessionID, error: error45 });
17440
- if (sessionID) {
17441
- handleSessionError2(sessionID, error45);
17442
- handleAbort(sessionID);
17443
- }
17444
- if (sessionID && error45) {
17445
- const recovered = await handleSessionError(
17446
- client,
17447
- sessionID,
17448
- error45,
17449
- event.properties
17450
- );
17451
- if (recovered) {
17452
- log2("[index.ts] session.error: auto-recovery initiated", { sessionID });
17453
- return;
17454
- }
17455
- }
17456
- presets.taskFailed("session", String(error45).slice(0, 50));
17457
- }
17458
- if (event.type === "message.updated") {
17459
- const messageInfo = event.properties?.info;
17460
- const sessionID = messageInfo?.sessionID;
17461
- const role = messageInfo?.role;
17462
- if (sessionID && role === "assistant") {
17463
- markRecoveryComplete(sessionID);
17464
- }
17465
- }
17466
- if (event.type === "session.idle") {
17467
- const sessionID = event.properties?.sessionID || "";
17468
- if (sessionID) {
17469
- const isMainSession = sessions.has(sessionID);
17470
- if (isMainSession) {
17471
- setTimeout(async () => {
17472
- const session = sessions.get(sessionID);
17473
- if (session?.active) {
17474
- if (isLoopActive(directory, sessionID)) {
17475
- await handleMissionSealIdle(
17476
- client,
17477
- directory,
17478
- sessionID,
17479
- sessionID
17480
- ).catch((err) => {
17481
- log2("[index.ts] mission-seal-handler error", err);
17482
- });
17483
- } else {
17484
- await handleSessionIdle(
17485
- client,
17486
- sessionID,
17487
- sessionID
17488
- ).catch((err) => {
17489
- log2("[index.ts] todo-continuation error", err);
17490
- });
17491
- }
17492
- }
17493
- }, 500);
17494
- }
17495
- }
17496
- }
17497
- },
17771
+ event: createEventHandler(handlerContext),
17498
17772
  // -----------------------------------------------------------------
17499
- // chat.message hook - runs when user sends a message
17500
- // This is where we intercept commands and set up sessions
17773
+ // chat.message hook - intercepts commands and sets up sessions
17501
17774
  // -----------------------------------------------------------------
17502
- "chat.message": async (msgInput, msgOutput) => {
17503
- const parts = msgOutput.parts;
17504
- const textPartIndex = parts.findIndex((p) => p.type === PART_TYPES.TEXT && p.text);
17505
- if (textPartIndex === -1) return;
17506
- const originalText = parts[textPartIndex].text || "";
17507
- const parsed = detectSlashCommand(originalText);
17508
- const sessionID = msgInput.sessionID;
17509
- const agentName = (msgInput.agent || "").toLowerCase();
17510
- log2("[index.ts] chat.message hook", { sessionID, agent: agentName, textLength: originalText.length });
17511
- if (sessionID) {
17512
- handleUserMessage(sessionID);
17513
- }
17514
- if (agentName === AGENT_NAMES.COMMANDER) {
17515
- if (!sessions.has(sessionID)) {
17516
- const now = Date.now();
17517
- sessions.set(sessionID, {
17518
- active: true,
17519
- step: 0,
17520
- timestamp: now,
17521
- startTime: now,
17522
- lastStepTime: now
17523
- });
17524
- state.missionActive = true;
17525
- state.sessions.set(sessionID, {
17526
- enabled: true,
17527
- iterations: 0,
17528
- taskRetries: /* @__PURE__ */ new Map(),
17529
- currentTask: "",
17530
- anomalyCount: 0
17531
- });
17532
- startSession(sessionID);
17533
- presets.taskStarted(sessionID, AGENT_NAMES.COMMANDER);
17534
- }
17535
- if (!parsed || parsed.command !== "task") {
17536
- const taskTemplate = COMMANDS["task"].template;
17537
- const userMessage = parsed?.args || originalText;
17538
- parts[textPartIndex].text = taskTemplate.replace(
17539
- /\$ARGUMENTS/g,
17540
- userMessage || PROMPTS.CONTINUE
17541
- );
17542
- startMissionLoop(directory, sessionID, userMessage || originalText);
17543
- log2("[index.ts] Auto-applied mission mode + started loop", { originalLength: originalText.length });
17544
- }
17545
- }
17546
- if (parsed) {
17547
- const command = COMMANDS[parsed.command];
17548
- if (command && agentName !== AGENT_NAMES.COMMANDER) {
17549
- parts[textPartIndex].text = command.template.replace(
17550
- /\$ARGUMENTS/g,
17551
- parsed.args || PROMPTS.CONTINUE
17552
- );
17553
- } else if (command && parsed.command === "task") {
17554
- parts[textPartIndex].text = command.template.replace(
17555
- /\$ARGUMENTS/g,
17556
- parsed.args || PROMPTS.CONTINUE
17557
- );
17558
- startMissionLoop(directory, sessionID, parsed.args || "continue from where we left off");
17559
- log2("[index.ts] /task command: started mission loop", { sessionID, args: parsed.args?.slice(0, 50) });
17560
- }
17561
- }
17562
- },
17775
+ "chat.message": createChatMessageHandler(handlerContext),
17563
17776
  // -----------------------------------------------------------------
17564
17777
  // tool.execute.after hook - runs after any tool call completes
17565
- // We use this to track progress and detect problems
17566
17778
  // -----------------------------------------------------------------
17567
- "tool.execute.after": async (toolInput, toolOutput) => {
17568
- const session = sessions.get(toolInput.sessionID);
17569
- if (!session?.active) return;
17570
- const now = Date.now();
17571
- const stepDuration = formatElapsedTime(session.lastStepTime, now);
17572
- const totalElapsed = formatElapsedTime(session.startTime, now);
17573
- session.step++;
17574
- session.timestamp = now;
17575
- session.lastStepTime = now;
17576
- const stateSession = state.sessions.get(toolInput.sessionID);
17577
- if (toolInput.tool === TOOL_NAMES.CALL_AGENT && stateSession) {
17578
- const sanityResult = checkOutputSanity(toolOutput.output);
17579
- if (!sanityResult.isHealthy) {
17580
- stateSession.anomalyCount = (stateSession.anomalyCount || 0) + 1;
17581
- const agentName = toolInput.arguments?.agent || "unknown";
17582
- toolOutput.output = `\u26A0\uFE0F [${agentName.toUpperCase()}] OUTPUT ANOMALY DETECTED
17583
-
17584
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17585
- \u26A0\uFE0F Gibberish/loop detected: ${sanityResult.reason}
17586
- Anomaly count: ${stateSession.anomalyCount}
17587
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17588
-
17589
- ` + (stateSession.anomalyCount >= 2 ? ESCALATION_PROMPT : RECOVERY_PROMPT);
17590
- return;
17591
- } else {
17592
- if (stateSession.anomalyCount > 0) {
17593
- stateSession.anomalyCount = 0;
17594
- }
17595
- if (toolOutput.output.length < 5e3) {
17596
- stateSession.lastHealthyOutput = toolOutput.output.substring(0, 1e3);
17597
- }
17598
- }
17599
- }
17600
- if (toolInput.tool === TOOL_NAMES.CALL_AGENT && toolInput.arguments?.task && stateSession) {
17601
- const taskIdMatch = toolInput.arguments.task.match(/\[(TASK-\d+)\]/i);
17602
- if (taskIdMatch) {
17603
- stateSession.currentTask = taskIdMatch[1].toUpperCase();
17604
- }
17605
- const agentName = toolInput.arguments.agent;
17606
- const emoji3 = AGENT_EMOJI[agentName] || "\u{1F916}";
17607
- toolOutput.output = `${emoji3} [${agentName.toUpperCase()}] Working...
17608
-
17609
- ` + toolOutput.output;
17610
- }
17611
- if (stateSession) {
17612
- const taskId = stateSession.currentTask;
17613
- if (toolOutput.output.includes("\u2705 PASS") || toolOutput.output.includes("AUDIT RESULT: PASS")) {
17614
- if (taskId) {
17615
- stateSession.taskRetries.clear();
17616
- toolOutput.output += `
17617
-
17618
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17619
- \u2705 ${taskId} VERIFIED`;
17620
- }
17621
- } else if (toolOutput.output.includes("\u274C FAIL") || toolOutput.output.includes("AUDIT RESULT: FAIL")) {
17622
- if (taskId) {
17623
- const retries = (stateSession.taskRetries.get(taskId) || 0) + 1;
17624
- stateSession.taskRetries.set(taskId, retries);
17625
- if (retries >= state.maxRetries) {
17626
- toolOutput.output += `
17627
-
17628
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17629
- \u26A0\uFE0F ${taskId} FAILED (${retries}x)`;
17630
- } else {
17631
- toolOutput.output += `
17632
-
17633
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
17634
- \u{1F504} RETRY ${retries}/${state.maxRetries}`;
17635
- }
17636
- }
17637
- }
17638
- }
17639
- const currentTime = formatTimestamp();
17640
- toolOutput.output += `
17641
-
17642
- \u23F1\uFE0F [${currentTime}] Step ${session.step} | This step: ${stepDuration} | Total: ${totalElapsed}`;
17643
- },
17779
+ "tool.execute.after": createToolExecuteAfterHandler(handlerContext),
17644
17780
  // -----------------------------------------------------------------
17645
17781
  // assistant.done hook - runs when the LLM finishes responding
17646
- // This is the heart of the "relentless loop" - we keep pushing it
17647
- // to continue until we see <mission_seal>SEALED</mission_seal> or hit the limit
17648
17782
  // -----------------------------------------------------------------
17649
- "assistant.done": async (assistantInput, assistantOutput) => {
17650
- const sessionID = assistantInput.sessionID;
17651
- const session = sessions.get(sessionID);
17652
- if (!session?.active) return;
17653
- const parts = assistantOutput.parts;
17654
- const textContent = parts?.filter((p) => p.type === PART_TYPES.TEXT || p.type === PART_TYPES.REASONING).map((p) => p.text || "").join("\n") || "";
17655
- const stateSession = state.sessions.get(sessionID);
17656
- const sanityResult = checkOutputSanity(textContent);
17657
- if (!sanityResult.isHealthy && stateSession) {
17658
- stateSession.anomalyCount = (stateSession.anomalyCount || 0) + 1;
17659
- session.step++;
17660
- session.timestamp = Date.now();
17661
- const recoveryText = stateSession.anomalyCount >= 2 ? ESCALATION_PROMPT : RECOVERY_PROMPT;
17662
- try {
17663
- if (client?.session?.prompt) {
17664
- await client.session.prompt({
17665
- path: { id: sessionID },
17666
- body: {
17667
- parts: [{
17668
- type: PART_TYPES.TEXT,
17669
- text: `\u26A0\uFE0F ANOMALY #${stateSession.anomalyCount}: ${sanityResult.reason}
17670
-
17671
- ` + recoveryText + `
17672
-
17673
- [Recovery Step ${session.step}]`
17674
- }]
17675
- }
17676
- });
17677
- }
17678
- } catch {
17679
- session.active = false;
17680
- state.missionActive = false;
17681
- }
17682
- return;
17683
- }
17684
- if (stateSession && stateSession.anomalyCount > 0) {
17685
- stateSession.anomalyCount = 0;
17686
- }
17687
- if (isLoopActive(directory, sessionID) && detectSealInText(textContent)) {
17688
- session.active = false;
17689
- state.missionActive = false;
17690
- clearLoopState(directory);
17691
- presets.missionComplete("\u{1F396}\uFE0F Mission Sealed - Explicit completion confirmed");
17692
- log2("[index.ts] Mission sealed detected", { sessionID });
17693
- clearSession(sessionID);
17694
- sessions.delete(sessionID);
17695
- state.sessions.delete(sessionID);
17696
- return;
17697
- }
17698
- if (textContent.includes(MISSION.STOP_COMMAND) || textContent.includes(MISSION.CANCEL_COMMAND)) {
17699
- session.active = false;
17700
- state.missionActive = false;
17701
- presets.taskFailed(sessionID, "Cancelled by user");
17702
- clearSession(sessionID);
17703
- sessions.delete(sessionID);
17704
- state.sessions.delete(sessionID);
17705
- return;
17706
- }
17707
- const now = Date.now();
17708
- const stepDuration = formatElapsedTime(session.lastStepTime, now);
17709
- const totalElapsed = formatElapsedTime(session.startTime, now);
17710
- session.step++;
17711
- session.timestamp = now;
17712
- session.lastStepTime = now;
17713
- const currentTime = formatTimestamp();
17714
- recordSnapshot(sessionID, {
17715
- currentStep: session.step
17716
- });
17717
- const progressInfo = formatCompact2(sessionID);
17718
- try {
17719
- if (client?.session?.prompt) {
17720
- await client.session.prompt({
17721
- path: { id: sessionID },
17722
- body: {
17723
- parts: [{
17724
- type: PART_TYPES.TEXT,
17725
- text: CONTINUE_INSTRUCTION + `
17726
-
17727
- \u23F1\uFE0F [${currentTime}] Step ${session.step} | ${progressInfo} | This step: ${stepDuration} | Total: ${totalElapsed}`
17728
- }]
17729
- }
17730
- });
17731
- }
17732
- } catch (error45) {
17733
- log2("[index.ts] Continuation injection failed, retrying...", { sessionID, error: error45 });
17734
- try {
17735
- await new Promise((r) => setTimeout(r, 500));
17736
- if (client?.session?.prompt) {
17737
- await client.session.prompt({
17738
- path: { id: sessionID },
17739
- body: { parts: [{ type: PART_TYPES.TEXT, text: PROMPTS.CONTINUE }] }
17740
- });
17741
- }
17742
- } catch (retryError) {
17743
- log2("[index.ts] Both continuation attempts failed, waiting for idle handler", {
17744
- sessionID,
17745
- error: retryError,
17746
- loopActive: isLoopActive(directory, sessionID)
17747
- });
17748
- if (!isLoopActive(directory, sessionID)) {
17749
- log2("[index.ts] No active loop, stopping session", { sessionID });
17750
- session.active = false;
17751
- state.missionActive = false;
17752
- }
17753
- }
17754
- }
17755
- }
17783
+ "assistant.done": createAssistantDoneHandler(handlerContext)
17756
17784
  };
17757
17785
  };
17758
17786
  var index_default = OrchestratorPlugin;