pantheon-opencode 1.3.2 → 1.3.3

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.
@@ -1427,17 +1427,24 @@ const plugin: Plugin = async ({ client, directory }) => {
1427
1427
  // tui.toast.show events on opencode 1.18.13 (untagged — see header), so
1428
1428
  // queued agent-lifecycle signals (delegation start/done, hook failures,
1429
1429
  // olympians/council summaries) are injected here as ONE <system-reminder> text
1430
- // part into the next user message, then cleared. chat.message fires only
1431
- // for user-initiated messages (subagent prompts use a different path), so
1432
- // this surfaces in the main session exactly when the user is watching.
1433
- // session.idle flushes the buffer into ONE fresh aggregated entry first
1434
- // (flushIdleReminders). Same PANTHEON_TOASTS gate as toasts: the buffer
1435
- // only receives gated signals, and the empty-set check below is a
1436
- // defensive backstop.
1430
+ // part into the next user message, then cleared.
1431
+ // P0 (2026-08-11, live E2E — release blocker): this hook ALSO fires for the
1432
+ // child session's client.session.promptAsync (the old "subagent prompts use
1433
+ // a different path" claim is FALSE on 1.18.13), where input.messageID is
1434
+ // EMPTY/undefined. Injecting there with `?? ''` produced a part opencode's
1435
+ // schema rejects (SchemaError: Expected a string starting with "msg", got
1436
+ // "") → prompt_async failed → every delegation died in ~20ms. The guard
1437
+ // below skips injection ENTIRELY on that path WITHOUT draining the buffer,
1438
+ // so the reminder still lands on the parent's next real message.
1437
1439
  'chat.message': async (input, output) => {
1438
1440
  try {
1439
1441
  if (ENABLED_TOAST_CATEGORIES.size === 0) return
1440
1442
  if (pendingChatReminders.length === 0) return
1443
+ // Subagent promptAsync fires have no messageID — injecting any part
1444
+ // with an empty messageID crashes the child session (schema reject).
1445
+ // Early return BEFORE the buffer drain keeps the reminder queued for
1446
+ // the parent's next real (msg_-ID'd) message.
1447
+ if (!input.messageID) return
1441
1448
  const now = Date.now()
1442
1449
  const fresh = pendingChatReminders.filter((r) => now - r.at <= CHAT_REMINDER_TTL_MS)
1443
1450
  pendingChatReminders.length = 0
@@ -1445,10 +1452,12 @@ const plugin: Plugin = async ({ client, directory }) => {
1445
1452
  const body = fresh.map((r) => r.text).join('\n')
1446
1453
  // Minimal TextPart — the core backfills messageID/sessionID for
1447
1454
  // hook-injected parts (see opencode chat.message trigger pipeline).
1455
+ // The guard above guarantees input.messageID is a non-empty string,
1456
+ // so no `?? ''` fallback is needed (an explicit "" is schema-rejected).
1448
1457
  output.parts.push({
1449
1458
  id: `prt_${crypto.randomUUID()}`,
1450
1459
  sessionID: input.sessionID,
1451
- messageID: input.messageID ?? '',
1460
+ messageID: input.messageID,
1452
1461
  type: 'text',
1453
1462
  text: `<system-reminder>\n${body}\n</system-reminder>`,
1454
1463
  } satisfies Part)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pantheon-tui",
3
3
  "type": "module",
4
- "version": "1.3.2",
4
+ "version": "1.3.3",
5
5
  "description": "Pantheon TUI plugin — sidebar (agents, sessions, commands, config, memory, active preset) + AI subscription usage gauges incl. OpenCode Go/Zen dollar limits (vendored, MIT)",
6
6
  "license": "MIT",
7
7
  "exports": {
package/src/routing.yml CHANGED
@@ -14,7 +14,8 @@ presets:
14
14
  apiKeyEnv: PANTHEON_OPENCODE_API_KEY
15
15
  agents:
16
16
  athena: { model: opencode/deepseek-v4-pro, reasoning_effort: high, fallback_models: [opencode/mimo-v2.5] }
17
- themis: { model: opencode/deepseek-v4-pro, reasoning_effort: high, fallback_models: [opencode/mimo-v2.5] }
17
+ # themis (PR #46 W4): phase reviews run on v4-flash (cost/empty-signature fix); pro only for the FINAL gate (manual override).
18
+ themis: { model: opencode/deepseek-v4-flash, reasoning_effort: high, fallback_models: [opencode/mimo-v2.5] }
18
19
  zeus: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
19
20
  hermes: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
20
21
  aphrodite: { model: opencode/deepseek-v4-flash, reasoning_effort: medium, fallback_models: [opencode/mimo-v2.5] }
@@ -555,4 +556,34 @@ platforms:
555
556
  background_job_board:
556
557
  max_concurrent_per_agent: 3
557
558
  signal_dir: .pantheon/deepwork/board-signals/
558
- persistence_dir: .pantheon/board/jobs/
559
+ persistence_path: .pantheon/board/state.json
560
+ background_delegation:
561
+ timeout_ms: 900000 # 15 min
562
+ poll_ms: 250
563
+ max_compaction_items: 10
564
+ prune_ttl_ms: 86400000 # 24h
565
+ read_only_agents: [apollo, gaia]
566
+ session_max: 3
567
+ retry_count: 1
568
+ todo_enforcer:
569
+ enabled: true
570
+ cooldown_base_ms: 5000 # base backoff between injections
571
+ max_consecutive_failures: 5 # stop injecting after this many failures
572
+ failure_reset_ms: 300000 # quiet period before the counter resets (5 min)
573
+ user_activity_quiet_ms: 30000 # skip injection this long after a user message (30s)
574
+ child_active_ms: 120000 # native background child newer than this = still running → skip (2 min)
575
+ # Runtime kill-switch: PANTHEON_TODO_ENFORCER=off (doc mirror only — the
576
+ # env var is the real switch, read at plugin construction).
577
+ hashline:
578
+ enabled: true
579
+ enhance_read: true
580
+ # Wave 2 (PR #46): tag-anchored edits. enhance_read augments `read` output
581
+ # with per-line sha256 tags (12#XJ|content); hashline_edit anchors edits to
582
+ # those refs. Documentation mirror — the plugin resolves behavior in code.
583
+ full_auto:
584
+ enabled: false # opt-in: goal continuations are OFF by default
585
+ max_continuations: 25 # hard cap on goal continuations per session
586
+ # Wave 3 (PR #46): full-auto goal loop. One active goal per session
587
+ # (pending → in_progress → done); while active, idle sessions are
588
+ # continued automatically toward the objective. Documentation mirror —
589
+ # the plugin resolves behavior in code (GOAL_LOOP_DEFAULTS).