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.d.ts +1 -5
- package/dist/index.js +1627 -1599
- package/dist/plugin-handlers/assistant-done-handler.d.ts +21 -0
- package/dist/plugin-handlers/chat-message-handler.d.ts +21 -0
- package/dist/plugin-handlers/config-handler.d.ts +9 -0
- package/dist/plugin-handlers/event-handler.d.ts +43 -0
- package/dist/plugin-handlers/index.d.ts +10 -0
- package/dist/plugin-handlers/tool-execute-handler.d.ts +25 -0
- package/package.json +1 -1
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/
|
|
178
|
-
var
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
//
|
|
398
|
-
var
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
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
|
-
|
|
13116
|
-
|
|
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
|
-
|
|
13142
|
-
|
|
13143
|
-
|
|
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
|
-
|
|
13167
|
-
|
|
13115
|
+
PHASE 2 - BUILDING (30-70%):
|
|
13116
|
+
- MODERATE: Key decisions + file references
|
|
13117
|
+
- Reference: "See src/module.ts"
|
|
13168
13118
|
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
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/
|
|
16297
|
-
|
|
16298
|
-
|
|
16299
|
-
|
|
16300
|
-
|
|
16301
|
-
|
|
16302
|
-
|
|
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
|
|
16314
|
-
const
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
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
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
);
|
|
16198
|
+
const history = progressHistory.get(sessionId) || [];
|
|
16199
|
+
history.push(snapshot);
|
|
16200
|
+
if (history.length > MAX_HISTORY2) {
|
|
16201
|
+
history.shift();
|
|
16326
16202
|
}
|
|
16327
|
-
|
|
16203
|
+
progressHistory.set(sessionId, history);
|
|
16204
|
+
return snapshot;
|
|
16328
16205
|
}
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
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
|
-
|
|
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
|
-
|
|
16389
|
-
|
|
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
|
-
|
|
16393
|
-
|
|
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
|
|
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 >
|
|
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
|
-
|
|
16637
|
-
|
|
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
|
-
|
|
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/
|
|
17180
|
-
|
|
17181
|
-
|
|
17182
|
-
|
|
17183
|
-
|
|
17184
|
-
|
|
17185
|
-
|
|
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
|
-
|
|
17188
|
-
|
|
17189
|
-
|
|
17190
|
-
const
|
|
17191
|
-
|
|
17192
|
-
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17210
|
-
|
|
17211
|
-
|
|
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
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
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
|
|
17226
|
-
|
|
17227
|
-
|
|
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
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
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
|
-
|
|
17256
|
-
|
|
17257
|
-
|
|
17258
|
-
|
|
17259
|
-
|
|
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/
|
|
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
|
-
//
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
17403
|
-
// Replaces non-standard session.start/session.end hooks
|
|
17769
|
+
// Event hook - handles OpenCode events
|
|
17404
17770
|
// -----------------------------------------------------------------
|
|
17405
|
-
event:
|
|
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 -
|
|
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":
|
|
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":
|
|
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":
|
|
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;
|