opencode-orchestrator 0.8.8 → 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/core/loop/todo-continuation.d.ts +5 -0
- package/dist/index.d.ts +1 -5
- package/dist/index.js +1717 -1625
- 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 = {};
|
|
@@ -13112,65 +12544,633 @@ function preprocess(fn, schema) {
|
|
|
13112
12544
|
return pipe(transform(fn), schema);
|
|
13113
12545
|
}
|
|
13114
12546
|
|
|
13115
|
-
// node_modules/zod/v4/classic/compat.js
|
|
13116
|
-
var ZodIssueCode = {
|
|
13117
|
-
invalid_type: "invalid_type",
|
|
13118
|
-
too_big: "too_big",
|
|
13119
|
-
too_small: "too_small",
|
|
13120
|
-
invalid_format: "invalid_format",
|
|
13121
|
-
not_multiple_of: "not_multiple_of",
|
|
13122
|
-
unrecognized_keys: "unrecognized_keys",
|
|
13123
|
-
invalid_union: "invalid_union",
|
|
13124
|
-
invalid_key: "invalid_key",
|
|
13125
|
-
invalid_element: "invalid_element",
|
|
13126
|
-
invalid_value: "invalid_value",
|
|
13127
|
-
custom: "custom"
|
|
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;
|
|
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
|
|
13128
12940
|
};
|
|
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 = {}));
|
|
13140
12941
|
|
|
13141
|
-
//
|
|
13142
|
-
var
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
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>
|
|
13107
|
+
|
|
13108
|
+
<context_management>
|
|
13109
|
+
DYNAMIC DETAIL LEVELS:
|
|
13110
|
+
|
|
13111
|
+
PHASE 1 - EARLY (0-30% done):
|
|
13112
|
+
- BE DETAILED: Full explanations, decisions
|
|
13113
|
+
- Include: research, API references
|
|
13114
|
+
|
|
13115
|
+
PHASE 2 - BUILDING (30-70%):
|
|
13116
|
+
- MODERATE: Key decisions + file references
|
|
13117
|
+
- Reference: "See src/module.ts"
|
|
13118
|
+
|
|
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
|
|
13165
13149
|
|
|
13166
|
-
|
|
13167
|
-
|
|
13150
|
+
\u2705 PASS: [evidence]
|
|
13151
|
+
Matches: .opencode/docs/[file]
|
|
13168
13152
|
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
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({
|
|
@@ -15387,138 +15387,6 @@ function createAsyncAgentTools(manager, client) {
|
|
|
15387
15387
|
};
|
|
15388
15388
|
}
|
|
15389
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>`;
|
|
15521
|
-
|
|
15522
15390
|
// src/core/cache/constants.ts
|
|
15523
15391
|
var CACHE_DIR = PATHS.DOCS;
|
|
15524
15392
|
var METADATA_FILE = PATHS.DOC_METADATA;
|
|
@@ -16262,135 +16130,118 @@ Try:
|
|
|
16262
16130
|
}
|
|
16263
16131
|
let output = `\u{1F50D} **Code Search Results for: "${query}"**
|
|
16264
16132
|
|
|
16265
|
-
`;
|
|
16266
|
-
output += `Found ${results.length} results${language ? ` (${language})` : ""}
|
|
16267
|
-
|
|
16268
|
-
---
|
|
16269
|
-
|
|
16270
|
-
`;
|
|
16271
|
-
for (let i = 0; i < results.length; i++) {
|
|
16272
|
-
const r = results[i];
|
|
16273
|
-
output += `### ${i + 1}. ${r.repo}
|
|
16274
|
-
`;
|
|
16275
|
-
output += `\u{1F4C4} \`${r.file}\`${r.line ? `:${r.line}` : ""}
|
|
16276
|
-
`;
|
|
16277
|
-
output += `\u{1F517} [View on GitHub](${r.url})
|
|
16278
|
-
|
|
16279
|
-
`;
|
|
16280
|
-
if (r.content && r.content !== "(Use webfetch for full content)") {
|
|
16281
|
-
output += `\`\`\`
|
|
16282
|
-
${r.content}
|
|
16283
|
-
\`\`\`
|
|
16284
|
-
|
|
16285
|
-
`;
|
|
16286
|
-
}
|
|
16287
|
-
}
|
|
16288
|
-
output += `---
|
|
16289
|
-
|
|
16290
|
-
`;
|
|
16291
|
-
output += `\u{1F4A1} **Tip**: Use \`webfetch\` to get the full file content from any of these URLs.`;
|
|
16292
|
-
return output;
|
|
16293
|
-
}
|
|
16294
|
-
});
|
|
16295
|
-
|
|
16296
|
-
// src/core/loop/stats.ts
|
|
16297
|
-
function getIncompleteCount(todos) {
|
|
16298
|
-
return todos.filter(
|
|
16299
|
-
(t) => t.status !== TODO_STATUS.COMPLETED && t.status !== TODO_STATUS.CANCELLED
|
|
16300
|
-
).length;
|
|
16301
|
-
}
|
|
16302
|
-
function hasRemainingWork(todos) {
|
|
16303
|
-
return getIncompleteCount(todos) > 0;
|
|
16304
|
-
}
|
|
16305
|
-
function getNextPending(todos) {
|
|
16306
|
-
const pending = todos.filter(
|
|
16307
|
-
(t) => t.status === TODO_STATUS.PENDING || t.status === TODO_STATUS.IN_PROGRESS
|
|
16308
|
-
);
|
|
16309
|
-
const priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
16310
|
-
pending.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
|
|
16311
|
-
return pending[0];
|
|
16312
|
-
}
|
|
16313
|
-
function getStats(todos) {
|
|
16314
|
-
const stats2 = {
|
|
16315
|
-
total: todos.length,
|
|
16316
|
-
pending: todos.filter((t) => t.status === TODO_STATUS.PENDING).length,
|
|
16317
|
-
inProgress: todos.filter((t) => t.status === TODO_STATUS.IN_PROGRESS).length,
|
|
16318
|
-
completed: todos.filter((t) => t.status === TODO_STATUS.COMPLETED).length,
|
|
16319
|
-
cancelled: todos.filter((t) => t.status === TODO_STATUS.CANCELLED).length,
|
|
16320
|
-
percentComplete: 0
|
|
16321
|
-
};
|
|
16322
|
-
if (stats2.total > 0) {
|
|
16323
|
-
stats2.percentComplete = Math.round(
|
|
16324
|
-
(stats2.completed + stats2.cancelled) / stats2.total * 100
|
|
16325
|
-
);
|
|
16326
|
-
}
|
|
16327
|
-
return stats2;
|
|
16328
|
-
}
|
|
16133
|
+
`;
|
|
16134
|
+
output += `Found ${results.length} results${language ? ` (${language})` : ""}
|
|
16329
16135
|
|
|
16330
|
-
|
|
16331
|
-
function formatProgress(todos) {
|
|
16332
|
-
const stats2 = getStats(todos);
|
|
16333
|
-
const done = stats2.completed + stats2.cancelled;
|
|
16334
|
-
return `${done}/${stats2.total} (${stats2.percentComplete}%)`;
|
|
16335
|
-
}
|
|
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)}
|
|
16136
|
+
---
|
|
16348
16137
|
|
|
16349
|
-
**Incomplete Tasks** (${incomplete.length} remaining):
|
|
16350
16138
|
`;
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
prompt += `${status} ${priority} [${todo.id}] ${todo.content}
|
|
16139
|
+
for (let i = 0; i < results.length; i++) {
|
|
16140
|
+
const r = results[i];
|
|
16141
|
+
output += `### ${i + 1}. ${r.repo}
|
|
16355
16142
|
`;
|
|
16356
|
-
|
|
16357
|
-
if (incomplete.length > 5) {
|
|
16358
|
-
prompt += `... and ${incomplete.length - 5} more
|
|
16143
|
+
output += `\u{1F4C4} \`${r.file}\`${r.line ? `:${r.line}` : ""}
|
|
16359
16144
|
`;
|
|
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:
|
|
16145
|
+
output += `\u{1F517} [View on GitHub](${r.url})
|
|
16365
16146
|
|
|
16366
|
-
\`\`\`
|
|
16367
|
-
// EXECUTE NOW - Launch all ${pendingCount} tasks simultaneously:
|
|
16368
16147
|
`;
|
|
16369
|
-
|
|
16370
|
-
|
|
16148
|
+
if (r.content && r.content !== "(Use webfetch for full content)") {
|
|
16149
|
+
output += `\`\`\`
|
|
16150
|
+
${r.content}
|
|
16151
|
+
\`\`\`
|
|
16152
|
+
|
|
16371
16153
|
`;
|
|
16154
|
+
}
|
|
16372
16155
|
}
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
\u26A0\uFE0F Do NOT run these sequentially. Use background=true for ALL.
|
|
16376
|
-
After launching, use list_tasks to monitor progress.
|
|
16156
|
+
output += `---
|
|
16377
16157
|
|
|
16378
16158
|
`;
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
2. Mark each task complete when finished
|
|
16384
|
-
3. Do NOT stop until all todos are completed or cancelled
|
|
16159
|
+
output += `\u{1F4A1} **Tip**: Use \`webfetch\` to get the full file content from any of these URLs.`;
|
|
16160
|
+
return output;
|
|
16161
|
+
}
|
|
16162
|
+
});
|
|
16385
16163
|
|
|
16386
|
-
|
|
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, []);
|
|
16171
|
+
}
|
|
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()
|
|
16197
|
+
};
|
|
16198
|
+
const history = progressHistory.get(sessionId) || [];
|
|
16199
|
+
history.push(snapshot);
|
|
16200
|
+
if (history.length > MAX_HISTORY2) {
|
|
16201
|
+
history.shift();
|
|
16387
16202
|
}
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16203
|
+
progressHistory.set(sessionId, history);
|
|
16204
|
+
return snapshot;
|
|
16205
|
+
}
|
|
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);
|
|
16213
|
+
}
|
|
16214
|
+
|
|
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`;
|
|
16224
|
+
} else {
|
|
16225
|
+
return `${seconds}s`;
|
|
16391
16226
|
}
|
|
16392
|
-
|
|
16393
|
-
|
|
16227
|
+
}
|
|
16228
|
+
function formatCompact(snapshot) {
|
|
16229
|
+
const parts = [];
|
|
16230
|
+
if (snapshot.todos.total > 0) {
|
|
16231
|
+
parts.push(`\u2705${snapshot.todos.completed}/${snapshot.todos.total}`);
|
|
16232
|
+
}
|
|
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;
|
|
@@ -16632,19 +16483,119 @@ async function handleSessionError(client, sessionID, error45, properties) {
|
|
|
16632
16483
|
state2.isRecovering = false;
|
|
16633
16484
|
return false;
|
|
16634
16485
|
}
|
|
16635
|
-
}
|
|
16636
|
-
function markRecoveryComplete(sessionID) {
|
|
16637
|
-
const state2 = recoveryState.get(sessionID);
|
|
16638
|
-
if (state2) {
|
|
16639
|
-
state2.isRecovering = false;
|
|
16640
|
-
state2.errorCount = 0;
|
|
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
|
+
`;
|
|
16592
|
+
}
|
|
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
|
|
@@ -16652,6 +16603,8 @@ var sessionStates = /* @__PURE__ */ new Map();
|
|
|
16652
16603
|
var COUNTDOWN_SECONDS = 2;
|
|
16653
16604
|
var TOAST_DURATION_MS = 1500;
|
|
16654
16605
|
var MIN_TIME_BETWEEN_CONTINUATIONS_MS = 3e3;
|
|
16606
|
+
var COUNTDOWN_GRACE_PERIOD_MS = 500;
|
|
16607
|
+
var ABORT_WINDOW_MS = 3e3;
|
|
16655
16608
|
function getState2(sessionID) {
|
|
16656
16609
|
let state2 = sessionStates.get(sessionID);
|
|
16657
16610
|
if (!state2) {
|
|
@@ -16757,6 +16710,15 @@ async function handleSessionIdle(client, sessionID, mainSessionID) {
|
|
|
16757
16710
|
log2("[todo-continuation] Skipped: in recovery mode", { sessionID });
|
|
16758
16711
|
return;
|
|
16759
16712
|
}
|
|
16713
|
+
if (state2.abortDetectedAt) {
|
|
16714
|
+
const timeSinceAbort = Date.now() - state2.abortDetectedAt;
|
|
16715
|
+
if (timeSinceAbort < ABORT_WINDOW_MS) {
|
|
16716
|
+
log2("[todo-continuation] Skipped: abort detected recently", { sessionID, timeSinceAbort });
|
|
16717
|
+
state2.abortDetectedAt = void 0;
|
|
16718
|
+
return;
|
|
16719
|
+
}
|
|
16720
|
+
state2.abortDetectedAt = void 0;
|
|
16721
|
+
}
|
|
16760
16722
|
if (hasRunningBackgroundTasks(sessionID)) {
|
|
16761
16723
|
log2("[todo-continuation] Skipped: background tasks running", { sessionID });
|
|
16762
16724
|
return;
|
|
@@ -16799,11 +16761,28 @@ async function handleSessionIdle(client, sessionID, mainSessionID) {
|
|
|
16799
16761
|
}
|
|
16800
16762
|
function handleUserMessage(sessionID) {
|
|
16801
16763
|
const state2 = getState2(sessionID);
|
|
16764
|
+
if (state2.countdownStartedAt) {
|
|
16765
|
+
const elapsed = Date.now() - state2.countdownStartedAt;
|
|
16766
|
+
if (elapsed < COUNTDOWN_GRACE_PERIOD_MS) {
|
|
16767
|
+
log2("[todo-continuation] Ignoring message in grace period", { sessionID, elapsed });
|
|
16768
|
+
return;
|
|
16769
|
+
}
|
|
16770
|
+
}
|
|
16802
16771
|
if (state2.countdownTimer) {
|
|
16803
16772
|
log2("[todo-continuation] Cancelled: user interaction", { sessionID });
|
|
16804
16773
|
cancelCountdown(sessionID);
|
|
16805
16774
|
}
|
|
16806
16775
|
state2.isAborting = false;
|
|
16776
|
+
state2.abortDetectedAt = void 0;
|
|
16777
|
+
}
|
|
16778
|
+
function handleSessionError2(sessionID, error45) {
|
|
16779
|
+
const state2 = getState2(sessionID);
|
|
16780
|
+
const errorObj = error45;
|
|
16781
|
+
if (errorObj?.name === "MessageAbortedError" || errorObj?.name === "AbortError") {
|
|
16782
|
+
state2.abortDetectedAt = Date.now();
|
|
16783
|
+
log2("[todo-continuation] Abort detected", { sessionID, errorName: errorObj.name });
|
|
16784
|
+
}
|
|
16785
|
+
cancelCountdown(sessionID);
|
|
16807
16786
|
}
|
|
16808
16787
|
function cleanupSession(sessionID) {
|
|
16809
16788
|
cancelCountdown(sessionID);
|
|
@@ -16898,33 +16877,61 @@ async function detectSealInSession(client, sessionID) {
|
|
|
16898
16877
|
return false;
|
|
16899
16878
|
}
|
|
16900
16879
|
}
|
|
16880
|
+
function startMissionLoop(directory, sessionID, prompt, options = {}) {
|
|
16881
|
+
const state2 = {
|
|
16882
|
+
active: true,
|
|
16883
|
+
iteration: 1,
|
|
16884
|
+
maxIterations: options.maxIterations ?? DEFAULT_MAX_ITERATIONS,
|
|
16885
|
+
prompt,
|
|
16886
|
+
sessionID,
|
|
16887
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
16888
|
+
};
|
|
16889
|
+
const success2 = writeLoopState(directory, state2);
|
|
16890
|
+
if (success2) {
|
|
16891
|
+
log2(`[mission-seal] Loop started`, {
|
|
16892
|
+
sessionID,
|
|
16893
|
+
maxIterations: state2.maxIterations
|
|
16894
|
+
});
|
|
16895
|
+
}
|
|
16896
|
+
return success2;
|
|
16897
|
+
}
|
|
16901
16898
|
function isLoopActive(directory, sessionID) {
|
|
16902
16899
|
const state2 = readLoopState(directory);
|
|
16903
16900
|
return state2?.active === true && state2?.sessionID === sessionID;
|
|
16904
16901
|
}
|
|
16905
16902
|
function generateMissionContinuationPrompt(state2) {
|
|
16906
16903
|
return `<mission_loop iteration="${state2.iteration}" max="${state2.maxIterations}">
|
|
16907
|
-
\
|
|
16904
|
+
\u26A0\uFE0F **MISSION NOT COMPLETE** - Iteration ${state2.iteration}/${state2.maxIterations}
|
|
16905
|
+
|
|
16906
|
+
The mission is INCOMPLETE. You MUST continue working NOW.
|
|
16907
|
+
|
|
16908
|
+
**FORBIDDEN**:
|
|
16909
|
+
\u274C Do NOT stop or ask for permission
|
|
16910
|
+
\u274C Do NOT say "I've completed..." without SEAL
|
|
16911
|
+
\u274C Do NOT output partial results
|
|
16912
|
+
\u274C Do NOT wait for user input
|
|
16908
16913
|
|
|
16909
|
-
|
|
16914
|
+
**REQUIRED SEQUENCE**:
|
|
16915
|
+
1\uFE0F\u20E3 Check .opencode/todo.md for [ ] incomplete items
|
|
16916
|
+
2\uFE0F\u20E3 Execute the NEXT pending task
|
|
16917
|
+
3\uFE0F\u20E3 Use delegate_task with background=true for parallel work
|
|
16918
|
+
4\uFE0F\u20E3 Mark completed items as [x]
|
|
16919
|
+
5\uFE0F\u20E3 Repeat until ALL items are [x]
|
|
16910
16920
|
|
|
16911
|
-
**
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16921
|
+
**ONLY WHEN TRULY DONE**:
|
|
16922
|
+
- All todos marked [x]
|
|
16923
|
+
- All tests pass
|
|
16924
|
+
- All builds succeed
|
|
16925
|
+
Then and ONLY then output:
|
|
16916
16926
|
|
|
16917
16927
|
\`\`\`
|
|
16918
16928
|
${SEAL_PATTERN}
|
|
16919
16929
|
\`\`\`
|
|
16920
16930
|
|
|
16921
|
-
**
|
|
16922
|
-
- Do NOT seal until the mission is genuinely complete
|
|
16923
|
-
- Verify all todos are marked [x] before sealing
|
|
16924
|
-
- Run tests/builds if applicable before sealing
|
|
16925
|
-
|
|
16926
|
-
**Original Task**:
|
|
16931
|
+
**Your Original Task**:
|
|
16927
16932
|
${state2.prompt}
|
|
16933
|
+
|
|
16934
|
+
**NOW**: Continue executing until ${SEAL_PATTERN} is output!
|
|
16928
16935
|
</mission_loop>`;
|
|
16929
16936
|
}
|
|
16930
16937
|
|
|
@@ -17113,95 +17120,464 @@ async function handleMissionSealIdle(client, directory, sessionID, mainSessionID
|
|
|
17113
17120
|
seconds: COUNTDOWN_SECONDS2
|
|
17114
17121
|
});
|
|
17115
17122
|
}
|
|
17123
|
+
function handleAbort(sessionID) {
|
|
17124
|
+
const state2 = getState3(sessionID);
|
|
17125
|
+
state2.isAborting = true;
|
|
17126
|
+
cancelCountdown2(sessionID);
|
|
17127
|
+
log2("[mission-seal-handler] Marked as aborting");
|
|
17128
|
+
}
|
|
17116
17129
|
|
|
17117
|
-
// src/
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
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
|
+
};
|
|
17124
17226
|
}
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
const
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17132
|
-
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17138
|
-
|
|
17139
|
-
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
|
|
17144
|
-
|
|
17145
|
-
|
|
17146
|
-
|
|
17147
|
-
|
|
17148
|
-
|
|
17149
|
-
|
|
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}`);
|
|
17150
17297
|
};
|
|
17151
|
-
const history = progressHistory.get(sessionId) || [];
|
|
17152
|
-
history.push(snapshot);
|
|
17153
|
-
if (history.length > MAX_HISTORY3) {
|
|
17154
|
-
history.shift();
|
|
17155
|
-
}
|
|
17156
|
-
progressHistory.set(sessionId, history);
|
|
17157
|
-
return snapshot;
|
|
17158
17298
|
}
|
|
17159
|
-
|
|
17160
|
-
|
|
17161
|
-
|
|
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] || "" };
|
|
17162
17305
|
}
|
|
17163
|
-
function
|
|
17164
|
-
|
|
17165
|
-
|
|
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 };
|
|
17166
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>
|
|
17167
17489
|
|
|
17168
|
-
|
|
17169
|
-
|
|
17170
|
-
|
|
17171
|
-
|
|
17172
|
-
const hours = Math.floor(minutes / 60);
|
|
17173
|
-
if (hours > 0) {
|
|
17174
|
-
return `${hours}h ${minutes % 60}m`;
|
|
17175
|
-
} else if (minutes > 0) {
|
|
17176
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
17177
|
-
} else {
|
|
17178
|
-
return `${seconds}s`;
|
|
17179
|
-
}
|
|
17180
|
-
}
|
|
17181
|
-
function formatCompact(snapshot) {
|
|
17182
|
-
const parts = [];
|
|
17183
|
-
if (snapshot.todos.total > 0) {
|
|
17184
|
-
parts.push(`\u2705${snapshot.todos.completed}/${snapshot.todos.total}`);
|
|
17185
|
-
}
|
|
17186
|
-
if (snapshot.tasks.running > 0) {
|
|
17187
|
-
parts.push(`\u26A1${snapshot.tasks.running}`);
|
|
17188
|
-
}
|
|
17189
|
-
parts.push(`\u23F1${formatElapsed(snapshot.elapsedMs)}`);
|
|
17190
|
-
return parts.join(" | ");
|
|
17191
|
-
}
|
|
17490
|
+
<diagnosis>
|
|
17491
|
+
The current approach is producing corrupted output.
|
|
17492
|
+
This may indicate: context overload, model instability, or task complexity.
|
|
17493
|
+
</diagnosis>
|
|
17192
17494
|
|
|
17193
|
-
|
|
17194
|
-
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
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
|
+
};
|
|
17198
17578
|
}
|
|
17199
17579
|
|
|
17200
|
-
// src/
|
|
17201
|
-
var require2 = createRequire(import.meta.url);
|
|
17202
|
-
var { version: PLUGIN_VERSION } = require2("../package.json");
|
|
17203
|
-
var UNLIMITED_MODE = true;
|
|
17204
|
-
var DEFAULT_MAX_STEPS = UNLIMITED_MODE ? Infinity : 500;
|
|
17580
|
+
// src/plugin-handlers/assistant-done-handler.ts
|
|
17205
17581
|
var CONTINUE_INSTRUCTION = `<auto_continue>
|
|
17206
17582
|
<status>Mission not complete. Keep executing.</status>
|
|
17207
17583
|
|
|
@@ -17229,6 +17605,120 @@ You are ONLY done when:
|
|
|
17229
17605
|
Then output: ${MISSION_SEAL.PATTERN}
|
|
17230
17606
|
</completion_criteria>
|
|
17231
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");
|
|
17232
17722
|
var OrchestratorPlugin = async (input) => {
|
|
17233
17723
|
const { directory, client } = input;
|
|
17234
17724
|
console.log(`[orchestrator] v${PLUGIN_VERSION} loaded`);
|
|
@@ -17242,6 +17732,12 @@ var OrchestratorPlugin = async (input) => {
|
|
|
17242
17732
|
const asyncAgentTools = createAsyncAgentTools(parallelAgentManager2, client);
|
|
17243
17733
|
taskToastManager.setConcurrencyController(parallelAgentManager2.getConcurrency());
|
|
17244
17734
|
log2("[index.ts] ParallelAgentManager initialized with TaskToastManager integration");
|
|
17735
|
+
const handlerContext = {
|
|
17736
|
+
client,
|
|
17737
|
+
directory,
|
|
17738
|
+
sessions,
|
|
17739
|
+
state
|
|
17740
|
+
};
|
|
17245
17741
|
return {
|
|
17246
17742
|
// -----------------------------------------------------------------
|
|
17247
17743
|
// Tools we expose to the LLM
|
|
@@ -17252,443 +17748,39 @@ var OrchestratorPlugin = async (input) => {
|
|
|
17252
17748
|
[TOOL_NAMES.GREP_SEARCH]: grepSearchTool(directory),
|
|
17253
17749
|
[TOOL_NAMES.GLOB_SEARCH]: globSearchTool(directory),
|
|
17254
17750
|
[TOOL_NAMES.MGREP]: mgrepTool(directory),
|
|
17255
|
-
//
|
|
17256
|
-
// Background task tools - run shell commands asynchronously
|
|
17751
|
+
// Background task tools
|
|
17257
17752
|
[TOOL_NAMES.RUN_BACKGROUND]: runBackgroundTool,
|
|
17258
17753
|
[TOOL_NAMES.CHECK_BACKGROUND]: checkBackgroundTool,
|
|
17259
17754
|
[TOOL_NAMES.LIST_BACKGROUND]: listBackgroundTool,
|
|
17260
17755
|
[TOOL_NAMES.KILL_BACKGROUND]: killBackgroundTool,
|
|
17261
|
-
// Web tools
|
|
17756
|
+
// Web tools
|
|
17262
17757
|
[TOOL_NAMES.WEBFETCH]: webfetchTool,
|
|
17263
17758
|
[TOOL_NAMES.WEBSEARCH]: websearchTool,
|
|
17264
17759
|
[TOOL_NAMES.CACHE_DOCS]: cacheDocsTool,
|
|
17265
17760
|
[TOOL_NAMES.CODESEARCH]: codesearchTool,
|
|
17266
|
-
// Async agent tools
|
|
17761
|
+
// Async agent tools
|
|
17267
17762
|
...asyncAgentTools
|
|
17268
17763
|
},
|
|
17269
17764
|
// -----------------------------------------------------------------
|
|
17270
17765
|
// Config hook - registers our commands and agents with OpenCode
|
|
17271
17766
|
// -----------------------------------------------------------------
|
|
17272
|
-
config:
|
|
17273
|
-
const existingCommands = config2.command ?? {};
|
|
17274
|
-
const existingAgents = config2.agent ?? {};
|
|
17275
|
-
const orchestratorCommands = {};
|
|
17276
|
-
for (const [name, cmd] of Object.entries(COMMANDS)) {
|
|
17277
|
-
orchestratorCommands[name] = {
|
|
17278
|
-
description: cmd.description,
|
|
17279
|
-
template: cmd.template,
|
|
17280
|
-
argumentHint: cmd.argumentHint
|
|
17281
|
-
};
|
|
17282
|
-
}
|
|
17283
|
-
const commanderPrompt = AGENTS[AGENT_NAMES.COMMANDER]?.systemPrompt || "";
|
|
17284
|
-
console.log(`[orchestrator] Commander prompt length: ${commanderPrompt.length} chars`);
|
|
17285
|
-
const orchestratorAgents = {
|
|
17286
|
-
// Primary agent - the main orchestrator
|
|
17287
|
-
[AGENT_NAMES.COMMANDER]: {
|
|
17288
|
-
description: "Autonomous orchestrator - executes until mission complete",
|
|
17289
|
-
mode: "primary",
|
|
17290
|
-
prompt: commanderPrompt,
|
|
17291
|
-
maxTokens: 64e3,
|
|
17292
|
-
thinking: { type: "enabled", budgetTokens: 32e3 },
|
|
17293
|
-
color: "#FF6B6B"
|
|
17294
|
-
},
|
|
17295
|
-
// Consolidated subagents (4 agents instead of 6)
|
|
17296
|
-
[AGENT_NAMES.PLANNER]: {
|
|
17297
|
-
description: "Strategic planning and research specialist",
|
|
17298
|
-
mode: "subagent",
|
|
17299
|
-
hidden: true,
|
|
17300
|
-
prompt: AGENTS[AGENT_NAMES.PLANNER]?.systemPrompt || "",
|
|
17301
|
-
maxTokens: 32e3,
|
|
17302
|
-
color: "#9B59B6"
|
|
17303
|
-
},
|
|
17304
|
-
[AGENT_NAMES.WORKER]: {
|
|
17305
|
-
description: "Implementation and documentation specialist",
|
|
17306
|
-
mode: "subagent",
|
|
17307
|
-
hidden: true,
|
|
17308
|
-
prompt: AGENTS[AGENT_NAMES.WORKER]?.systemPrompt || "",
|
|
17309
|
-
maxTokens: 32e3,
|
|
17310
|
-
color: "#E67E22"
|
|
17311
|
-
},
|
|
17312
|
-
[AGENT_NAMES.REVIEWER]: {
|
|
17313
|
-
description: "Verification and context management specialist",
|
|
17314
|
-
mode: "subagent",
|
|
17315
|
-
hidden: true,
|
|
17316
|
-
prompt: AGENTS[AGENT_NAMES.REVIEWER]?.systemPrompt || "",
|
|
17317
|
-
maxTokens: 32e3,
|
|
17318
|
-
color: "#27AE60"
|
|
17319
|
-
}
|
|
17320
|
-
};
|
|
17321
|
-
const processedExistingAgents = { ...existingAgents };
|
|
17322
|
-
if (processedExistingAgents.build) {
|
|
17323
|
-
processedExistingAgents.build = {
|
|
17324
|
-
...processedExistingAgents.build,
|
|
17325
|
-
mode: "subagent",
|
|
17326
|
-
hidden: true
|
|
17327
|
-
};
|
|
17328
|
-
}
|
|
17329
|
-
if (processedExistingAgents.plan) {
|
|
17330
|
-
processedExistingAgents.plan = {
|
|
17331
|
-
...processedExistingAgents.plan,
|
|
17332
|
-
mode: "subagent"
|
|
17333
|
-
};
|
|
17334
|
-
}
|
|
17335
|
-
config2.command = { ...existingCommands, ...orchestratorCommands };
|
|
17336
|
-
config2.agent = { ...processedExistingAgents, ...orchestratorAgents };
|
|
17337
|
-
config2.default_agent = AGENT_NAMES.COMMANDER;
|
|
17338
|
-
console.log(`[orchestrator] Registered agents: ${Object.keys(orchestratorAgents).join(", ")}`);
|
|
17339
|
-
console.log(`[orchestrator] Default agent: ${AGENT_NAMES.COMMANDER}`);
|
|
17340
|
-
},
|
|
17767
|
+
config: createConfigHandler(),
|
|
17341
17768
|
// -----------------------------------------------------------------
|
|
17342
|
-
// Event hook - handles OpenCode events
|
|
17343
|
-
// Replaces non-standard session.start/session.end hooks
|
|
17769
|
+
// Event hook - handles OpenCode events
|
|
17344
17770
|
// -----------------------------------------------------------------
|
|
17345
|
-
event:
|
|
17346
|
-
const { event } = input2;
|
|
17347
|
-
try {
|
|
17348
|
-
const manager = ParallelAgentManager.getInstance();
|
|
17349
|
-
manager.handleEvent(event);
|
|
17350
|
-
} catch {
|
|
17351
|
-
}
|
|
17352
|
-
if (event.type === "session.created") {
|
|
17353
|
-
const sessionID = event.properties?.id || "";
|
|
17354
|
-
log2("[index.ts] event: session.created", { sessionID });
|
|
17355
|
-
presets.missionStarted(`Session ${sessionID.slice(0, 12)}...`);
|
|
17356
|
-
}
|
|
17357
|
-
if (event.type === "session.deleted") {
|
|
17358
|
-
const sessionID = event.properties?.id || event.properties?.info?.id || "";
|
|
17359
|
-
const session = sessions.get(sessionID);
|
|
17360
|
-
if (session) {
|
|
17361
|
-
const totalTime = Date.now() - session.startTime;
|
|
17362
|
-
const duration3 = totalTime < 6e4 ? `${Math.round(totalTime / 1e3)}s` : `${Math.round(totalTime / 6e4)}m`;
|
|
17363
|
-
log2("[index.ts] event: session.deleted", {
|
|
17364
|
-
sessionID,
|
|
17365
|
-
steps: session.step,
|
|
17366
|
-
duration: duration3
|
|
17367
|
-
});
|
|
17368
|
-
sessions.delete(sessionID);
|
|
17369
|
-
state.sessions.delete(sessionID);
|
|
17370
|
-
clearSession(sessionID);
|
|
17371
|
-
cleanupSessionRecovery(sessionID);
|
|
17372
|
-
cleanupSession(sessionID);
|
|
17373
|
-
presets.sessionCompleted(sessionID, duration3);
|
|
17374
|
-
}
|
|
17375
|
-
}
|
|
17376
|
-
if (event.type === "session.error") {
|
|
17377
|
-
const sessionID = event.properties?.sessionId || event.properties?.sessionID || "";
|
|
17378
|
-
const error45 = event.properties?.error;
|
|
17379
|
-
log2("[index.ts] event: session.error", { sessionID, error: error45 });
|
|
17380
|
-
if (sessionID && error45) {
|
|
17381
|
-
const recovered = await handleSessionError(
|
|
17382
|
-
client,
|
|
17383
|
-
sessionID,
|
|
17384
|
-
error45,
|
|
17385
|
-
event.properties
|
|
17386
|
-
);
|
|
17387
|
-
if (recovered) {
|
|
17388
|
-
log2("[index.ts] session.error: auto-recovery initiated", { sessionID });
|
|
17389
|
-
return;
|
|
17390
|
-
}
|
|
17391
|
-
}
|
|
17392
|
-
presets.taskFailed("session", String(error45).slice(0, 50));
|
|
17393
|
-
}
|
|
17394
|
-
if (event.type === "message.updated") {
|
|
17395
|
-
const messageInfo = event.properties?.info;
|
|
17396
|
-
const sessionID = messageInfo?.sessionID;
|
|
17397
|
-
const role = messageInfo?.role;
|
|
17398
|
-
if (sessionID && role === "assistant") {
|
|
17399
|
-
markRecoveryComplete(sessionID);
|
|
17400
|
-
}
|
|
17401
|
-
}
|
|
17402
|
-
if (event.type === "session.idle") {
|
|
17403
|
-
const sessionID = event.properties?.sessionID || "";
|
|
17404
|
-
if (sessionID) {
|
|
17405
|
-
const isMainSession = sessions.has(sessionID);
|
|
17406
|
-
if (isMainSession) {
|
|
17407
|
-
setTimeout(async () => {
|
|
17408
|
-
const session = sessions.get(sessionID);
|
|
17409
|
-
if (session?.active) {
|
|
17410
|
-
if (isLoopActive(directory, sessionID)) {
|
|
17411
|
-
await handleMissionSealIdle(
|
|
17412
|
-
client,
|
|
17413
|
-
directory,
|
|
17414
|
-
sessionID,
|
|
17415
|
-
sessionID
|
|
17416
|
-
).catch((err) => {
|
|
17417
|
-
log2("[index.ts] mission-seal-handler error", err);
|
|
17418
|
-
});
|
|
17419
|
-
} else {
|
|
17420
|
-
await handleSessionIdle(
|
|
17421
|
-
client,
|
|
17422
|
-
sessionID,
|
|
17423
|
-
sessionID
|
|
17424
|
-
).catch((err) => {
|
|
17425
|
-
log2("[index.ts] todo-continuation error", err);
|
|
17426
|
-
});
|
|
17427
|
-
}
|
|
17428
|
-
}
|
|
17429
|
-
}, 500);
|
|
17430
|
-
}
|
|
17431
|
-
}
|
|
17432
|
-
}
|
|
17433
|
-
},
|
|
17771
|
+
event: createEventHandler(handlerContext),
|
|
17434
17772
|
// -----------------------------------------------------------------
|
|
17435
|
-
// chat.message hook -
|
|
17436
|
-
// This is where we intercept commands and set up sessions
|
|
17773
|
+
// chat.message hook - intercepts commands and sets up sessions
|
|
17437
17774
|
// -----------------------------------------------------------------
|
|
17438
|
-
"chat.message":
|
|
17439
|
-
const parts = msgOutput.parts;
|
|
17440
|
-
const textPartIndex = parts.findIndex((p) => p.type === PART_TYPES.TEXT && p.text);
|
|
17441
|
-
if (textPartIndex === -1) return;
|
|
17442
|
-
const originalText = parts[textPartIndex].text || "";
|
|
17443
|
-
const parsed = detectSlashCommand(originalText);
|
|
17444
|
-
const sessionID = msgInput.sessionID;
|
|
17445
|
-
const agentName = (msgInput.agent || "").toLowerCase();
|
|
17446
|
-
log2("[index.ts] chat.message hook", { sessionID, agent: agentName, textLength: originalText.length });
|
|
17447
|
-
if (sessionID) {
|
|
17448
|
-
handleUserMessage(sessionID);
|
|
17449
|
-
}
|
|
17450
|
-
if (agentName === AGENT_NAMES.COMMANDER) {
|
|
17451
|
-
if (!sessions.has(sessionID)) {
|
|
17452
|
-
const now = Date.now();
|
|
17453
|
-
sessions.set(sessionID, {
|
|
17454
|
-
active: true,
|
|
17455
|
-
step: 0,
|
|
17456
|
-
maxSteps: DEFAULT_MAX_STEPS,
|
|
17457
|
-
timestamp: now,
|
|
17458
|
-
startTime: now,
|
|
17459
|
-
lastStepTime: now
|
|
17460
|
-
});
|
|
17461
|
-
state.missionActive = true;
|
|
17462
|
-
state.sessions.set(sessionID, {
|
|
17463
|
-
enabled: true,
|
|
17464
|
-
iterations: 0,
|
|
17465
|
-
taskRetries: /* @__PURE__ */ new Map(),
|
|
17466
|
-
currentTask: "",
|
|
17467
|
-
anomalyCount: 0
|
|
17468
|
-
});
|
|
17469
|
-
startSession(sessionID);
|
|
17470
|
-
presets.taskStarted(sessionID, AGENT_NAMES.COMMANDER);
|
|
17471
|
-
}
|
|
17472
|
-
if (!parsed || parsed.command !== "task") {
|
|
17473
|
-
const taskTemplate = COMMANDS["task"].template;
|
|
17474
|
-
const userMessage = parsed?.args || originalText;
|
|
17475
|
-
parts[textPartIndex].text = taskTemplate.replace(
|
|
17476
|
-
/\$ARGUMENTS/g,
|
|
17477
|
-
userMessage || PROMPTS.CONTINUE
|
|
17478
|
-
);
|
|
17479
|
-
log2("[index.ts] Auto-applied mission mode", { originalLength: originalText.length });
|
|
17480
|
-
}
|
|
17481
|
-
}
|
|
17482
|
-
if (parsed) {
|
|
17483
|
-
const command = COMMANDS[parsed.command];
|
|
17484
|
-
if (command && agentName !== AGENT_NAMES.COMMANDER) {
|
|
17485
|
-
parts[textPartIndex].text = command.template.replace(
|
|
17486
|
-
/\$ARGUMENTS/g,
|
|
17487
|
-
parsed.args || PROMPTS.CONTINUE
|
|
17488
|
-
);
|
|
17489
|
-
} else if (command && parsed.command === "task") {
|
|
17490
|
-
parts[textPartIndex].text = command.template.replace(
|
|
17491
|
-
/\$ARGUMENTS/g,
|
|
17492
|
-
parsed.args || PROMPTS.CONTINUE
|
|
17493
|
-
);
|
|
17494
|
-
}
|
|
17495
|
-
}
|
|
17496
|
-
},
|
|
17775
|
+
"chat.message": createChatMessageHandler(handlerContext),
|
|
17497
17776
|
// -----------------------------------------------------------------
|
|
17498
17777
|
// tool.execute.after hook - runs after any tool call completes
|
|
17499
|
-
// We use this to track progress and detect problems
|
|
17500
17778
|
// -----------------------------------------------------------------
|
|
17501
|
-
"tool.execute.after":
|
|
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 (session.step >= session.maxSteps) {
|
|
17546
|
-
session.active = false;
|
|
17547
|
-
state.missionActive = false;
|
|
17548
|
-
return;
|
|
17549
|
-
}
|
|
17550
|
-
if (stateSession) {
|
|
17551
|
-
const taskId = stateSession.currentTask;
|
|
17552
|
-
if (toolOutput.output.includes("\u2705 PASS") || toolOutput.output.includes("AUDIT RESULT: PASS")) {
|
|
17553
|
-
if (taskId) {
|
|
17554
|
-
stateSession.taskRetries.clear();
|
|
17555
|
-
toolOutput.output += `
|
|
17556
|
-
|
|
17557
|
-
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
17558
|
-
\u2705 ${taskId} VERIFIED`;
|
|
17559
|
-
}
|
|
17560
|
-
} else if (toolOutput.output.includes("\u274C FAIL") || toolOutput.output.includes("AUDIT RESULT: FAIL")) {
|
|
17561
|
-
if (taskId) {
|
|
17562
|
-
const retries = (stateSession.taskRetries.get(taskId) || 0) + 1;
|
|
17563
|
-
stateSession.taskRetries.set(taskId, retries);
|
|
17564
|
-
if (retries >= state.maxRetries) {
|
|
17565
|
-
toolOutput.output += `
|
|
17566
|
-
|
|
17567
|
-
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
17568
|
-
\u26A0\uFE0F ${taskId} FAILED (${retries}x)`;
|
|
17569
|
-
} else {
|
|
17570
|
-
toolOutput.output += `
|
|
17571
|
-
|
|
17572
|
-
\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
|
|
17573
|
-
\u{1F504} RETRY ${retries}/${state.maxRetries}`;
|
|
17574
|
-
}
|
|
17575
|
-
}
|
|
17576
|
-
}
|
|
17577
|
-
}
|
|
17578
|
-
const currentTime = formatTimestamp();
|
|
17579
|
-
toolOutput.output += `
|
|
17580
|
-
|
|
17581
|
-
\u23F1\uFE0F [${currentTime}] Step ${session.step}/${session.maxSteps} | This step: ${stepDuration} | Total: ${totalElapsed}`;
|
|
17582
|
-
},
|
|
17779
|
+
"tool.execute.after": createToolExecuteAfterHandler(handlerContext),
|
|
17583
17780
|
// -----------------------------------------------------------------
|
|
17584
17781
|
// assistant.done hook - runs when the LLM finishes responding
|
|
17585
|
-
// This is the heart of the "relentless loop" - we keep pushing it
|
|
17586
|
-
// to continue until we see <mission_seal>SEALED</mission_seal> or hit the limit
|
|
17587
17782
|
// -----------------------------------------------------------------
|
|
17588
|
-
"assistant.done":
|
|
17589
|
-
const sessionID = assistantInput.sessionID;
|
|
17590
|
-
const session = sessions.get(sessionID);
|
|
17591
|
-
if (!session?.active) return;
|
|
17592
|
-
const parts = assistantOutput.parts;
|
|
17593
|
-
const textContent = parts?.filter((p) => p.type === PART_TYPES.TEXT || p.type === PART_TYPES.REASONING).map((p) => p.text || "").join("\n") || "";
|
|
17594
|
-
const stateSession = state.sessions.get(sessionID);
|
|
17595
|
-
const sanityResult = checkOutputSanity(textContent);
|
|
17596
|
-
if (!sanityResult.isHealthy && stateSession) {
|
|
17597
|
-
stateSession.anomalyCount = (stateSession.anomalyCount || 0) + 1;
|
|
17598
|
-
session.step++;
|
|
17599
|
-
session.timestamp = Date.now();
|
|
17600
|
-
const recoveryText = stateSession.anomalyCount >= 2 ? ESCALATION_PROMPT : RECOVERY_PROMPT;
|
|
17601
|
-
try {
|
|
17602
|
-
if (client?.session?.prompt) {
|
|
17603
|
-
await client.session.prompt({
|
|
17604
|
-
path: { id: sessionID },
|
|
17605
|
-
body: {
|
|
17606
|
-
parts: [{
|
|
17607
|
-
type: PART_TYPES.TEXT,
|
|
17608
|
-
text: `\u26A0\uFE0F ANOMALY #${stateSession.anomalyCount}: ${sanityResult.reason}
|
|
17609
|
-
|
|
17610
|
-
` + recoveryText + `
|
|
17611
|
-
|
|
17612
|
-
[Recovery Step ${session.step}/${session.maxSteps}]`
|
|
17613
|
-
}]
|
|
17614
|
-
}
|
|
17615
|
-
});
|
|
17616
|
-
}
|
|
17617
|
-
} catch {
|
|
17618
|
-
session.active = false;
|
|
17619
|
-
state.missionActive = false;
|
|
17620
|
-
}
|
|
17621
|
-
return;
|
|
17622
|
-
}
|
|
17623
|
-
if (stateSession && stateSession.anomalyCount > 0) {
|
|
17624
|
-
stateSession.anomalyCount = 0;
|
|
17625
|
-
}
|
|
17626
|
-
if (detectSealInText(textContent)) {
|
|
17627
|
-
session.active = false;
|
|
17628
|
-
state.missionActive = false;
|
|
17629
|
-
clearLoopState(directory);
|
|
17630
|
-
presets.missionComplete("\u{1F396}\uFE0F Mission Sealed - Explicit completion confirmed");
|
|
17631
|
-
log2("[index.ts] Mission sealed detected", { sessionID });
|
|
17632
|
-
clearSession(sessionID);
|
|
17633
|
-
sessions.delete(sessionID);
|
|
17634
|
-
state.sessions.delete(sessionID);
|
|
17635
|
-
return;
|
|
17636
|
-
}
|
|
17637
|
-
if (textContent.includes(MISSION.STOP_COMMAND) || textContent.includes(MISSION.CANCEL_COMMAND)) {
|
|
17638
|
-
session.active = false;
|
|
17639
|
-
state.missionActive = false;
|
|
17640
|
-
presets.taskFailed(sessionID, "Cancelled by user");
|
|
17641
|
-
clearSession(sessionID);
|
|
17642
|
-
sessions.delete(sessionID);
|
|
17643
|
-
state.sessions.delete(sessionID);
|
|
17644
|
-
return;
|
|
17645
|
-
}
|
|
17646
|
-
const now = Date.now();
|
|
17647
|
-
const stepDuration = formatElapsedTime(session.lastStepTime, now);
|
|
17648
|
-
const totalElapsed = formatElapsedTime(session.startTime, now);
|
|
17649
|
-
session.step++;
|
|
17650
|
-
session.timestamp = now;
|
|
17651
|
-
session.lastStepTime = now;
|
|
17652
|
-
const currentTime = formatTimestamp();
|
|
17653
|
-
if (session.step >= session.maxSteps) {
|
|
17654
|
-
session.active = false;
|
|
17655
|
-
state.missionActive = false;
|
|
17656
|
-
return;
|
|
17657
|
-
}
|
|
17658
|
-
recordSnapshot(sessionID, {
|
|
17659
|
-
currentStep: session.step,
|
|
17660
|
-
maxSteps: session.maxSteps
|
|
17661
|
-
});
|
|
17662
|
-
const progressInfo = formatCompact2(sessionID);
|
|
17663
|
-
try {
|
|
17664
|
-
if (client?.session?.prompt) {
|
|
17665
|
-
await client.session.prompt({
|
|
17666
|
-
path: { id: sessionID },
|
|
17667
|
-
body: {
|
|
17668
|
-
parts: [{
|
|
17669
|
-
type: PART_TYPES.TEXT,
|
|
17670
|
-
text: CONTINUE_INSTRUCTION + `
|
|
17671
|
-
|
|
17672
|
-
\u23F1\uFE0F [${currentTime}] Step ${session.step}/${session.maxSteps} | ${progressInfo} | This step: ${stepDuration} | Total: ${totalElapsed}`
|
|
17673
|
-
}]
|
|
17674
|
-
}
|
|
17675
|
-
});
|
|
17676
|
-
}
|
|
17677
|
-
} catch {
|
|
17678
|
-
try {
|
|
17679
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
17680
|
-
if (client?.session?.prompt) {
|
|
17681
|
-
await client.session.prompt({
|
|
17682
|
-
path: { id: sessionID },
|
|
17683
|
-
body: { parts: [{ type: PART_TYPES.TEXT, text: PROMPTS.CONTINUE }] }
|
|
17684
|
-
});
|
|
17685
|
-
}
|
|
17686
|
-
} catch {
|
|
17687
|
-
session.active = false;
|
|
17688
|
-
state.missionActive = false;
|
|
17689
|
-
}
|
|
17690
|
-
}
|
|
17691
|
-
}
|
|
17783
|
+
"assistant.done": createAssistantDoneHandler(handlerContext)
|
|
17692
17784
|
};
|
|
17693
17785
|
};
|
|
17694
17786
|
var index_default = OrchestratorPlugin;
|