pantheon-opencode 1.4.3 → 1.5.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.pantheon/code-mode/.gitkeep +0 -0
  2. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-1.json +8 -0
  3. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-10.json +8 -0
  4. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-11.json +8 -0
  5. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-2.json +8 -0
  6. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-3.json +8 -0
  7. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-4.json +8 -0
  8. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-5.json +8 -0
  9. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-6.json +8 -0
  10. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-7.json +8 -0
  11. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-8.json +8 -0
  12. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-9.json +8 -0
  13. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/heartbeat.json +8 -0
  14. package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/session.json +11 -0
  15. package/.pantheon/code-mode/README.md +93 -0
  16. package/.pantheon/code-mode/checkpoint-session.py +7 -0
  17. package/.pantheon/code-mode/checkpoint-session.sh +11 -0
  18. package/.pantheon/code-mode/checkpoint_session.py +481 -0
  19. package/.pantheon/code-mode/compress-inline.py +450 -0
  20. package/.pantheon/code-mode/eval-llm-judge.py +255 -0
  21. package/.pantheon/code-mode/eval-monte-carlo.py +368 -0
  22. package/.pantheon/code-mode/eval-run.py +197 -0
  23. package/.pantheon/code-mode/eval-static.py +321 -0
  24. package/.pantheon/code-mode/example-sync.sh +5 -0
  25. package/.pantheon/code-mode/session-end-save.py +186 -0
  26. package/.pantheon/code-mode/session-end-save.sh +18 -0
  27. package/.pantheon/code-mode/test-allowed.sh +5 -0
  28. package/.pantheon/code-mode/test-auto-continue-checkpoint.sh +179 -0
  29. package/.pantheon/code-mode/test-env.sh +7 -0
  30. package/.pantheon/code-mode/test-prlimit.sh +9 -0
  31. package/.pantheon/code-mode/test-timeout.sh +6 -0
  32. package/README.md +158 -1101
  33. package/README.pt-BR.md +222 -0
  34. package/bin/pantheon-init.mjs +30 -11
  35. package/opencode.json +1 -0
  36. package/package.json +14 -3
  37. package/plugin.json +15 -0
  38. package/scripts/_pantheon_paths.py +48 -7
  39. package/scripts/ci-validate-yaml.py +7 -2
  40. package/scripts/code_mode_server.py +33 -2
  41. package/scripts/doctor.mjs +135 -127
  42. package/scripts/generate-preset-docs.mjs +127 -66
  43. package/scripts/generate-prompts.sh +2 -2
  44. package/scripts/install/cli-ui.mjs +8 -1
  45. package/scripts/install/config-migration.mjs +401 -0
  46. package/scripts/install/health-check.mjs +3 -3
  47. package/scripts/install/model-picker.mjs +72 -23
  48. package/scripts/install/opencode-version.mjs +47 -0
  49. package/scripts/install/opencode.mjs +261 -88
  50. package/scripts/install/plugin.mjs +112 -42
  51. package/scripts/install/shared.mjs +13 -158
  52. package/scripts/install-mcp.mjs +44 -232
  53. package/scripts/mcp_persistence_server.py +344 -15
  54. package/scripts/mcp_resources_server.py +144 -40
  55. package/scripts/memory_mcp_server.py +2 -2
  56. package/scripts/recover-zenodo-deposition.mjs +146 -0
  57. package/scripts/sync-tui.mjs +32 -7
  58. package/scripts/test-opencode-v1-v2-sandbox.sh +591 -0
  59. package/scripts/uninstall.mjs +298 -954
  60. package/scripts/validate-zenodo-release.mjs +154 -0
  61. package/scripts/zenodo-artifact.mjs +21 -0
  62. package/scripts/zenodo-release-state.mjs +53 -0
  63. package/src/agents/zeus.md +25 -14
  64. package/src/mcp/_pantheon_paths.py +48 -7
  65. package/src/mcp/code_mode_server.py +33 -2
  66. package/src/mcp/eval_store.py +1 -1
  67. package/src/mcp/mcp_persistence_server.py +344 -15
  68. package/src/mcp/mcp_resources_server.py +144 -40
  69. package/src/mcp/pantheon_vision_server.py +1 -1
  70. package/src/mcp/toon_codec.py +491 -0
  71. package/src/pantheon/background-job-board.ts +67 -1
  72. package/src/pantheon/cost-command.ts +13 -9
  73. package/src/pantheon/delegate-manager.ts +384 -0
  74. package/src/pantheon/delegate-task-adapter.ts +444 -0
  75. package/src/pantheon/delegation-classifier.ts +307 -0
  76. package/src/pantheon/delegation-enforce.ts +13 -12
  77. package/src/pantheon/delegation-finalize.ts +374 -0
  78. package/src/pantheon/delegation-notify.ts +212 -0
  79. package/src/pantheon/delegation-toast.ts +73 -0
  80. package/src/pantheon/delegation.ts +1120 -0
  81. package/src/pantheon/goal-loop.ts +2 -2
  82. package/src/pantheon/goal-store.ts +1 -1
  83. package/src/pantheon/hashline/tool.ts +2 -2
  84. package/src/pantheon/model-command.ts +2 -1
  85. package/src/pantheon/permission-eval.ts +284 -0
  86. package/src/pantheon/step-cap.ts +110 -0
  87. package/src/pantheon/token-opt.ts +555 -0
  88. package/src/pantheon/toon-codec.ts +481 -0
  89. package/src/pantheon/tui-version-check.ts +1 -3
  90. package/src/pantheon/v2-bridge.ts +129 -0
  91. package/src/pantheon/v2-events.ts +131 -0
  92. package/src/pantheon/v2-hooks.ts +287 -0
  93. package/src/pantheon/v2-tool-definitions.ts +331 -0
  94. package/src/pantheon/zeus-delegate-with-retry.ts +406 -0
  95. package/src/plugin-v2/index.ts +21 -0
  96. package/src/plugin-v2.ts +836 -0
  97. package/src/plugin.ts +241 -42
  98. package/src/plugins/tui/dist/server.d.ts +1 -1
  99. package/src/plugins/tui/dist/server.d.ts.map +1 -1
  100. package/src/plugins/tui/dist/server.js +1 -1
  101. package/src/plugins/tui/dist/server.js.map +1 -1
  102. package/src/plugins/tui/dist/tui.d.ts +10 -7
  103. package/src/plugins/tui/dist/tui.d.ts.map +1 -1
  104. package/src/plugins/tui/dist/tui.js +11 -8
  105. package/src/plugins/tui/dist/tui.js.map +1 -1
  106. package/src/plugins/tui/dist/tui.tsx +22 -16
  107. package/src/plugins/tui/package-lock.json +51 -51
  108. package/src/plugins/tui/package.json +7 -7
  109. package/src/plugins/tui/src/index.tsx +28 -24
  110. package/src/skills/README.md +0 -2
  111. package/src/pantheon/tool-context.ts +0 -41
package/src/plugin.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { existsSync } from 'node:fs'
2
+ import { join } from 'node:path'
1
3
  import type { Plugin, PluginInput } from '@opencode-ai/plugin'
2
4
  import type { PluginConfig } from 'opencode'
3
5
  import { BackgroundJobBoard } from './pantheon/background-job-board.ts'
@@ -10,6 +12,19 @@ import {
10
12
  DEFAULT_LIMITS as SANDBOX_DEFAULT_LIMITS,
11
13
  } from './pantheon/context-sandbox.ts'
12
14
  import { createCostCommand } from './pantheon/cost-command.ts'
15
+ import {
16
+ buildPluginNativeDelegation,
17
+ resolveDelegateMode,
18
+ withDelegationKillSwitch,
19
+ } from './pantheon/delegate-task-adapter.ts'
20
+ import {
21
+ collectRootSessionIDs,
22
+ createDelegationTools,
23
+ type DelegationClient,
24
+ resolveDelegationBudgets,
25
+ resolveDelegationTimeoutMs,
26
+ startIdleChildScan,
27
+ } from './pantheon/delegation.ts'
13
28
  import { buildCompactionContext } from './pantheon/delegation-compaction.ts'
14
29
  import {
15
30
  createEnforcementGuard,
@@ -17,6 +32,8 @@ import {
17
32
  SessionHierarchyRegistry,
18
33
  zeusReadGuard,
19
34
  } from './pantheon/delegation-enforce.ts'
35
+ import { handleDelegationEvent } from './pantheon/delegation-notify.ts'
36
+ import { showDelegationTerminalToast, type ToastClient } from './pantheon/delegation-toast.ts'
20
37
  import { FilePersistenceAdapter } from './pantheon/file-persistence.ts'
21
38
  import { GOAL_LOOP_DEFAULTS, GoalLoop, GoalStore } from './pantheon/goal-loop.ts'
22
39
  import { createReadEnhancer } from './pantheon/hashline/read-enhancer.ts'
@@ -25,8 +42,14 @@ import { createIdleDispatcher } from './pantheon/idle-continuation.ts'
25
42
  import { createPantheonLogger } from './pantheon/logger.ts'
26
43
  import { createModelCommand } from './pantheon/model-command.ts'
27
44
  import { pantheonPluginOnce } from './pantheon/plugin-once.ts'
28
- import { applyActivePresetToConfig } from './pantheon/presets.mjs'
45
+ import {
46
+ applyActivePresetToConfig,
47
+ loadRoutingAgentModels,
48
+ loadRoutingMaxSteps,
49
+ loadRoutingPermissionTask,
50
+ } from './pantheon/presets.mjs'
29
51
  import { safeSessionPath } from './pantheon/session-guard.ts'
52
+ import { StepCapTracker } from './pantheon/step-cap.ts'
30
53
  import {
31
54
  TODO_ENFORCER_DEFAULTS,
32
55
  TodoEnforcer,
@@ -45,12 +68,24 @@ import { activePresetCandidates, createVisionHandler } from './pantheon/vision.t
45
68
  // .pantheon/logs/hooks.log; the console echo is opt-in via PANTHEON_HOOKS_LOG=1.
46
69
  const log = createPantheonLogger({ module: 'pantheon-plugin' })
47
70
 
71
+ // R4: per-agent step caps from routing.yml `agents.<name>.max_steps`
72
+ // (fail-open → {} = no agent capped). R1 retry_policy/cooldown are NOT
73
+ // wired here — the plugin has no retry path (opencode cannot intercept task
74
+ // completion); zeus waves load them via presets.mjs loaders and pass them
75
+ // to zeusDelegateWithRetry explicitly.
76
+ const stepCapTracker = new StepCapTracker(loadRoutingMaxSteps({ logger: log }))
77
+
78
+ // O5: permission.task glob rules from routing.yml `permission.task`
79
+ // (fail-open → undefined = existing runtime matrix only).
80
+ const routingPermissionTask = loadRoutingPermissionTask({ logger: log })
81
+
48
82
  const board = new BackgroundJobBoard({
49
83
  maxConcurrentPerAgent: 3,
50
84
  signalDir: '.pantheon/deepwork/board-signals',
51
85
  })
52
86
  const persistence = new FilePersistenceAdapter('.pantheon/board/state.json')
53
87
  board.setPersistence(persistence)
88
+ let terminalToastClient: ToastClient = {}
54
89
  board
55
90
  .recoverRunningJobs()
56
91
  .catch((err) => log.error('[Pantheon Plugin] Failed to recover running jobs:', err))
@@ -60,13 +95,17 @@ board
60
95
  // file-only log line (console echo opt-in via PANTHEON_HOOKS_LOG). There is
61
96
  // deliberately NO chat delivery — the user policy is zero delegation
62
97
  // notifications in the transcript. Completion visibility lives in the board
63
- // `[unread]` marker and compaction carry-forward.
98
+ // `[unread]` marker (pantheon_delegation_list), pantheon_delegation_read,
99
+ // TUI toasts (pantheon-hooks, PANTHEON_TOASTS gate) and compaction
100
+ // carry-forward.
64
101
  board.onTerminal((taskID: string) => {
65
102
  const job = board.get(taskID)
66
103
  if (!job) return
67
104
  log.info(
68
105
  `[Pantheon Plugin] Board terminal: [${job.alias}] ${job.description} → ${job.state}${job.resultSummary ? ` — ${job.resultSummary}` : ''}`,
69
106
  )
107
+ // Deliberately direct-to-TUI: onTerminal must not inject chat/transcript text.
108
+ void showDelegationTerminalToast(terminalToastClient, job)
70
109
  })
71
110
 
72
111
  // Periodically prune terminal/reconciled jobs (24h TTL, every 30 min).
@@ -84,15 +123,23 @@ setInterval(
84
123
 
85
124
  // ─── Phase 4: Read-Only Enforcement + Compaction Context ───────────────
86
125
 
87
- // The read-only registry is populated when a child session is launched
88
- // read-only (explicit flag or agent ∈ readOnlyAgents). The guard denies
89
- // edit/write/bash/task inside those sessions by throwing from
90
- // tool.execute.before; unknown sessions are allowed (safe default).
126
+ // WS1 (PR #94): root-session predicate shared by the Phase 4 enforcement
127
+ // guard and the native delegate toolset — both must agree on what a root is.
128
+ // (Hoisted function: `rootSessions`/`sessionHierarchy` below are resolved at
129
+ // call time, after module init.)
130
+ function isRootSession(sessionID: string): boolean {
131
+ return rootSessions.has(sessionID) || sessionHierarchy.isRoot(sessionID)
132
+ }
133
+
134
+ // The read-only registry is populated by createDelegationTools (delegation.ts)
135
+ // when a delegate is read-only (explicit flag or agent ∈ readOnlyAgents).
136
+ // The guard denies edit/write/bash/task inside those sessions by throwing
137
+ // from tool.execute.before; unknown sessions are allowed (safe default).
91
138
  const enforcementGuard = createEnforcementGuard({
92
139
  getReadOnlySessions: () => readOnlyRegistry.sessionIDs(),
93
140
  options: {
94
141
  getSessionAgent: (sessionID) => sessionAgents.get(sessionID),
95
- isRootSession: (sessionID) => rootSessions.has(sessionID) || sessionHierarchy.isRoot(sessionID),
142
+ isRootSession,
96
143
  isChildSession: (sessionID) => sessionHierarchy.isChild(sessionID),
97
144
  logger: log,
98
145
  },
@@ -108,7 +155,7 @@ const commandNormalizer = createCommandNormalizer({ logger: log })
108
155
  // Mirrors routing.yml background_delegation.max_compaction_items.
109
156
  const COMPACTION_MAX_ITEMS = 10
110
157
 
111
- // Root-session registry for the child-session depth guard: sessions created
158
+ // Root-session registry for the delegation depth guard: sessions created
112
159
  // without a parentID are roots. Populated from TWO sources:
113
160
  // 1. the `session.created` event hook (live roots — fires for sessions
114
161
  // created while the plugin runs);
@@ -116,9 +163,9 @@ const COMPACTION_MAX_ITEMS = 10
116
163
  // hook (compaction-134) — opencode does NOT replay session.created
117
164
  // events for sessions that exist before plugin load, so without the
118
165
  // seed a resumed root would never enter this set after a restart.
119
- // The hierarchy registry additionally falls back to known children ("any
120
- // session WE created is a sub-session; unknown sessions are roots") so the
121
- // depth guard works even when this set is incomplete.
166
+ // delegation.ts additionally falls back to knownChildren ("any session WE
167
+ // created is a sub-session; unknown sessions are roots") so the depth guard
168
+ // works even when this set is incomplete.
122
169
  const rootSessions = new Set<string>()
123
170
  const sessionHierarchy = new SessionHierarchyRegistry()
124
171
  const sessionAgents = new Map<string, string>()
@@ -127,14 +174,14 @@ const sessionAgents = new Map<string, string>()
127
174
  * Seed resumed root sessions without making OpenCode startup depend on the
128
175
  * session API responding. Some OpenCode environments do not have the API
129
176
  * ready while plugin config hooks run; awaiting session.list() there leaves
130
- * the TUI stuck before it can open. The hierarchy registry already treats an
177
+ * the TUI stuck before it can open. The delegation layer already treats an
131
178
  * unknown session as a root, so this enrichment is deliberately best-effort.
132
179
  */
133
180
  function seedRootSessionsInBackground(input: PluginInput): void {
134
181
  // Fail-open: environments without the session API (client.session absent or
135
182
  // not yet wired while config hooks run) must NOT break startup. `session`
136
183
  // is captured and the method invoked on it so `this` stays bound; the
137
- // hierarchy registry already treats unknown sessions as roots, so skipping
184
+ // delegation layer already treats unknown sessions as roots, so skipping
138
185
  // the seed is always safe.
139
186
  const session = input.client.session
140
187
  if (typeof session?.list !== 'function') return
@@ -144,15 +191,10 @@ function seedRootSessionsInBackground(input: PluginInput): void {
144
191
  .then((result) => {
145
192
  if (!result.error && Array.isArray(result.data)) {
146
193
  sessionHierarchy.completeSeed(result.data)
147
- let seeded = 0
148
- for (const info of result.data) {
149
- if (info.parentID === undefined) {
150
- rootSessions.add(info.id)
151
- seeded += 1
152
- }
153
- }
154
- if (seeded > 0) {
155
- log.info(`[Pantheon Plugin] Seeded ${seeded} root session(s) from session.list`)
194
+ const seeded = collectRootSessionIDs(result.data)
195
+ if (seeded.size > 0) {
196
+ for (const id of seeded) rootSessions.add(id)
197
+ log.info(`[Pantheon Plugin] Seeded ${seeded.size} root session(s) from session.list`)
156
198
  }
157
199
  } else {
158
200
  sessionHierarchy.failSeed()
@@ -170,6 +212,62 @@ function sdkErrorMessage(error: { data?: { message?: string } } | null | undefin
170
212
  return typeof message === 'string' && message.trim() !== '' ? message : 'request failed'
171
213
  }
172
214
 
215
+ /**
216
+ * Adapt the opencode SDK client to the structural DelegationClient the
217
+ * delegation toolset expects: the SDK wraps every call in a
218
+ * `{data, error, request, response}` result while delegation.ts uses direct
219
+ * returns. Errors surface as throws so the toolset's own error handling
220
+ * (tool errors returned as TEXT) keeps working.
221
+ */
222
+ function adaptDelegationClient(client: PluginInput['client']): DelegationClient {
223
+ return {
224
+ session: {
225
+ create: async (input) => {
226
+ const body: {
227
+ parentID?: string
228
+ title?: string
229
+ model?: { id: string; providerID: string }
230
+ } = { parentID: input.body.parentID }
231
+ if (input.body.title !== undefined) body.title = input.body.title
232
+ // Forward a model only when the active routing profile supplied one.
233
+ if (input.body.model !== undefined) body.model = input.body.model
234
+ const result = await client.session.create({ body })
235
+ if (result.error) throw new Error(sdkErrorMessage(result.error))
236
+ return { id: result.data.id }
237
+ },
238
+ promptAsync: async (input) => {
239
+ const path = safeSessionPath(input.path.id)
240
+ if (!path) {
241
+ log.warn(`[Pantheon Plugin] promptAsync skipped: invalid sessionID "${input.path.id}"`)
242
+ throw new Error(`invalid sessionID: ${input.path.id}`)
243
+ }
244
+ const result = await client.session.promptAsync({
245
+ path: path.path,
246
+ body: {
247
+ agent: input.body.agent,
248
+ ...(input.body.model !== undefined
249
+ ? { model: { providerID: input.body.model.providerID, modelID: input.body.model.id } }
250
+ : {}),
251
+ parts: input.body.parts,
252
+ },
253
+ })
254
+ if (result.error) throw new Error(sdkErrorMessage(result.error))
255
+ return result.data
256
+ },
257
+ messages: async (input) => {
258
+ const path = safeSessionPath(input.path.id)
259
+ if (!path) {
260
+ log.warn(`[Pantheon Plugin] messages skipped: invalid sessionID "${input.path.id}"`)
261
+ return []
262
+ }
263
+ const result = await client.session.messages({ path: path.path })
264
+ if (result.error) throw new Error(sdkErrorMessage(result.error))
265
+ return result.data
266
+ },
267
+ },
268
+ }
269
+ }
270
+
173
271
  /**
174
272
  * Adapt the opencode SDK client to the structural TodoEnforcerClient the
175
273
  * todo enforcer expects: unwraps the SDK `{data, error, request, response}`
@@ -250,6 +348,7 @@ function adaptTodoEnforcerClient(client: PluginInput['client']): TodoEnforcerCli
250
348
  * Helpers live in src/pantheon/vision.ts and are imported from there directly.
251
349
  */
252
350
  const plugin: Plugin = async (input: PluginInput) => {
351
+ terminalToastClient = input.client as unknown as ToastClient
253
352
  // release-134: runtime guard against DOUBLE registration (duplicate toasts +
254
353
  // duplicate task_ids in one process — 2026-08-12 live logs). opencode
255
354
  // merges the global config (npm-package plugin paths) with the project
@@ -264,12 +363,101 @@ const plugin: Plugin = async (input: PluginInput) => {
264
363
  // is older than the installed package. Runs once, fail-open, no auto-sync.
265
364
  checkTuiVersionStaleness((msg) => log.warn(msg))
266
365
  const vision = createVisionHandler(input)
366
+ // Phase 2/3: background delegation toolset + the bound finalize lifecycle
367
+ // hook. Completion is observed through the event hook below
368
+ // (session.idle / session.error on a child) → finalizeDelegation.
369
+ // Fase B3: runtime controls for the two read-only exceptions and the real
370
+ // per-child wall-clock timer. No task_budget field is injected into the
371
+ // plugin/frontmatter; these are enforced by delegation.ts itself.
372
+ const delegationBudgets = resolveDelegationBudgets()
373
+ const wallClockTimeoutMs = resolveDelegationTimeoutMs()
374
+
375
+ // WS1 (PR #94): delegation backend gate. Default = legacy (the V1
376
+ // fire-and-forget toolset, intact); PANTHEON_DELEGATE_MODE=native selects
377
+ // the thin manager over native task() semantics. Kill-switch
378
+ // PANTHEON_DELEGATION=off covers BOTH modes (native guards internally;
379
+ // legacy via withDelegationKillSwitch). finalizeDelegation always stays on
380
+ // the legacy observer: it works on the shared board in both modes and must
381
+ // never be kill-switched, so children never orphan. The idle hook below is
382
+ // untouched.
383
+ const delegationClient = adaptDelegationClient(input.client)
384
+ // Only an explicitly active routing profile may provide child models.
385
+ // An empty map deliberately lets OpenCode inherit the parent model.
386
+ const routingAgentModels = loadRoutingAgentModels({
387
+ candidates: activePresetCandidates(),
388
+ logger: log,
389
+ })
390
+ const readOnlyAgents = new Set(['apollo', 'gaia'])
391
+ const legacyDelegation = createDelegationTools({
392
+ board,
393
+ client: delegationClient,
394
+ options: {
395
+ rootSessions,
396
+ isChildSession: (sessionID) => sessionHierarchy.isChild(sessionID),
397
+ registerChildSession: (sessionID, parentID) => {
398
+ sessionHierarchy.register({ id: sessionID, parentID })
399
+ },
400
+ enforceRuntimeMatrix: true,
401
+ readOnlyAgents,
402
+ agentModels: routingAgentModels,
403
+ delegationBudgets,
404
+ stepCapTracker,
405
+ ...(routingPermissionTask != null ? { permissionTask: routingPermissionTask } : {}),
406
+ ...(wallClockTimeoutMs !== undefined ? { wallClockTimeoutMs } : {}),
407
+ },
408
+ })
409
+ const delegateMode = resolveDelegateMode()
410
+ if (delegateMode === 'native') {
411
+ log.info('[Pantheon Plugin] Delegation mode: native (PANTHEON_DELEGATE_MODE=native)')
412
+ }
413
+ const delegation =
414
+ delegateMode === 'native'
415
+ ? buildPluginNativeDelegation({
416
+ board,
417
+ client: delegationClient,
418
+ isRootSession,
419
+ registerChildSession: (sessionID, parentID) => {
420
+ sessionHierarchy.register({ id: sessionID, parentID })
421
+ },
422
+ registerReadOnlySession: (sessionID, info) => {
423
+ readOnlyRegistry.register(sessionID, info)
424
+ },
425
+ readOnlyAgents,
426
+ agentModels: routingAgentModels,
427
+ stepCap: stepCapTracker,
428
+ ...(wallClockTimeoutMs !== undefined ? { wallClockTimeoutMs } : {}),
429
+ finalizeDelegation: legacyDelegation.finalizeDelegation,
430
+ })
431
+ : withDelegationKillSwitch(legacyDelegation)
432
+
433
+ // Proactive idle-child scan (Fix 2): finalize children that are idle on the
434
+ // board but have no MD report on disk — eliminates the phantom "running"
435
+ // window. Runs every 30s (configurable via PANTHEON_IDLE_SCAN_INTERVAL_MS),
436
+ // unref'd so it never holds the process open. Fail-open by design.
437
+ const idleScanIntervalMs = Number(process.env.PANTHEON_IDLE_SCAN_INTERVAL_MS) || undefined
438
+ startIdleChildScan(
439
+ {
440
+ board,
441
+ finalize: (childSessionID, opts) => delegation.finalizeDelegation(childSessionID, opts),
442
+ hasReport: (job) => {
443
+ try {
444
+ const filePath = join('.pantheon/delegations', job.parentSessionID, `${job.alias}.md`)
445
+ return existsSync(filePath)
446
+ } catch {
447
+ return false
448
+ }
449
+ },
450
+ logger: log,
451
+ },
452
+ idleScanIntervalMs,
453
+ )
454
+
267
455
  // Wave 1 (PR #46): TODO continuation enforcer for root/non-board sessions.
268
456
  // Mirrors routing.yml `todo_enforcer` (plugin scope has no routing.yml
269
- // access — COMPACTION_MAX_ITEMS pattern). The event hook routes all
270
- // session.idle events here. Runtime kill-switch: PANTHEON_TODO_ENFORCER=off
271
- // (routing.yml is a doc mirror only — the env var is the real switch,
272
- // PANTHEON_TOASTS pattern).
457
+ // access — COMPACTION_MAX_ITEMS pattern). The event hook routes non-board
458
+ // session.idle events here; board-child idles go to finalizeDelegation.
459
+ // Runtime kill-switch: PANTHEON_TODO_ENFORCER=off (routing.yml is a doc
460
+ // mirror only — the env var is the real switch, PANTHEON_TOASTS pattern).
273
461
  const todoEnforcer = new TodoEnforcer({
274
462
  client: adaptTodoEnforcerClient(input.client),
275
463
  board,
@@ -326,7 +514,7 @@ const plugin: Plugin = async (input: PluginInput) => {
326
514
  await readEnhancer(input, output)
327
515
  }
328
516
 
329
- // Wave 4 (PR #46): /cost — cost + token visibility by agent. Reads
517
+ // Wave 4 (PR #46): /cost — delegation cost + token visibility. Reads
330
518
  // opencode.db read-only (node:sqlite, falls back to scripts/cost.mjs).
331
519
  // Fully wired (unlike dispatch-guard, which is manual-orchestration-only
332
520
  // because opencode 1.18.x cannot intercept task completion via hooks).
@@ -338,11 +526,11 @@ const plugin: Plugin = async (input: PluginInput) => {
338
526
  // compaction-134 seed: opencode does NOT replay `session.created`
339
527
  // events for sessions that exist before plugin load, so after a
340
528
  // restart the resumed ROOT session never enters rootSessions and the
341
- // depth guard would treat it as a child. Seed the registry from
342
- // session.list() in the background — every session WITHOUT a parentID
343
- // is a root. Fail-open: a failed/throttled list leaves the set
344
- // untouched (the hierarchy registry treats unknown sessions as roots),
345
- // and config setup must never wait for the session API.
529
+ // depth guard would reject its pantheon_delegate calls. Seed the
530
+ // registry from session.list() in the background — every session
531
+ // WITHOUT a parentID is a root. Fail-open: a failed/throttled list
532
+ // leaves the set untouched (delegation.ts treats unknown sessions as
533
+ // roots), and config setup must never wait for the session API.
346
534
  // Context sandbox config — opencode.json → context_sandbox: {enabled, limits}
347
535
  try {
348
536
  const raw = (config as unknown as Record<string, unknown>).context_sandbox
@@ -387,16 +575,18 @@ const plugin: Plugin = async (input: PluginInput) => {
387
575
  log.warn('[plugin] preset application failed (see logs for details)')
388
576
  }
389
577
  },
390
- // Phase 2: structural tool registrations (matches the `tool` hook field
391
- // shape). Native task() owns orchestration; the plugin registers the
392
- // deterministic /pantheon-model, /cost and full-auto goal tools.
578
+ // Phase 2: background delegation tools (structural — matches the `tool`
579
+ // hook field shape; read_only sessions feed the Phase 4 registry).
393
580
  tool: {
581
+ pantheon_delegate: delegation.pantheon_delegate,
582
+ pantheon_delegation_read: delegation.pantheon_delegation_read,
583
+ pantheon_delegation_list: delegation.pantheon_delegation_list,
394
584
  hashline_edit: hashlineEdit,
395
585
  // Wave 3 (PR #46): full-auto goal tools (single active goal/session).
396
586
  pantheon_goal_create: goalTools.pantheon_goal_create,
397
587
  pantheon_goal_update: goalTools.pantheon_goal_update,
398
588
  pantheon_goal_get: goalTools.pantheon_goal_get,
399
- // Wave 4 (PR #46): /cost — cost report by agent from opencode.db.
589
+ // Wave 4 (PR #46): /cost — delegation cost report from opencode.db.
400
590
  pantheon_cost: costCommand.pantheon_cost,
401
591
  // Deterministic /pantheon-model management of top-level model fields.
402
592
  pantheon_model: modelCommand.pantheon_model,
@@ -430,13 +620,22 @@ const plugin: Plugin = async (input: PluginInput) => {
430
620
  if (ev.type === 'session.compacted') {
431
621
  await todoPreserver.onCompacted(ev.properties.sessionID)
432
622
  }
433
- // Native task() children are owned by OpenCode. Idle routing for
434
- // generic root/non-board sessions remains priority ordered: an active
435
- // goal owns the idle (goal loop), otherwise the todo enforcer
436
- // re-injects. Neither onIdle ever throws (internal failures are logged
437
- // + swallowed), so the session is safe.
623
+ // Phase 3: observe completion on child sessions → finalizeDelegation.
624
+ // The board transition fires onTerminal → the file-only audit log (no
625
+ // chat delivery — see the onTerminal listener above). Unknown sessions
626
+ // are a no-op.
438
627
  try {
439
- if (ev.type === 'session.idle') {
628
+ const delegated = await handleDelegationEvent(ev, {
629
+ board,
630
+ finalize: (childSessionID, opts) => delegation.finalizeDelegation(childSessionID, opts),
631
+ })
632
+ // Wave 1/3: non-board idle → idle dispatcher. Board children are
633
+ // handled by handleDelegationEvent above; everything else (roots,
634
+ // non-board sessions) is routed by priority: an active goal owns the
635
+ // idle (goal loop), otherwise the todo enforcer re-injects. Neither
636
+ // onIdle ever throws (internal failures are logged + swallowed), so
637
+ // the session is safe.
638
+ if (!delegated && ev.type === 'session.idle') {
440
639
  await idleDispatcher.onIdle(ev.properties.sessionID)
441
640
  }
442
641
  } catch (err) {
@@ -14,4 +14,4 @@
14
14
  declare function server(): {};
15
15
  //#endregion
16
16
  export { server as default };
17
- //# sourceMappingURL=server.d.ts.map
17
+ //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;;;;;iBAYwB"}
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;;;;;iBAYwB"}
@@ -17,4 +17,4 @@ function server() {
17
17
  //#endregion
18
18
  export { server as default };
19
19
 
20
- //# sourceMappingURL=server.js.map
20
+ //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["/**\n * No-op server stub for the opencode plugin loader.\n *\n * The opencode plugin host requires every plugin (TUI included) to expose a\n * `server()` entry via `exports[\"./server\"]` (or package.json `main`). When\n * that entry is missing the host fails to attach the plugin's server half and\n * the TUI runtime never wires the reactive channel — the initial JSX mounts\n * but effects/refresh/events stay dead (the \"mudo panel\" symptom).\n *\n * This stub satisfies the loader contract; pantheon-tui is TUI-only and has\n * no background server work of its own.\n */\nexport default function server() {\n return {}\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAwB,SAAS;CAC/B,OAAO,CAAC;AACV"}
1
+ {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["/**\n * No-op server stub for the opencode plugin loader.\n *\n * The opencode plugin host requires every plugin (TUI included) to expose a\n * `server()` entry via `exports[\"./server\"]` (or package.json `main`). When\n * that entry is missing the host fails to attach the plugin's server half and\n * the TUI runtime never wires the reactive channel — the initial JSX mounts\n * but effects/refresh/events stay dead (the \"mudo panel\" symptom).\n *\n * This stub satisfies the loader contract; pantheon-tui is TUI-only and has\n * no background server work of its own.\n */\nexport default function server() {\n return {}\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAwB,SAAS;CAC/B,OAAO,CAAC;AACV"}
@@ -22,7 +22,7 @@ type DelegationEntry = {
22
22
  read?: boolean;
23
23
  /** Internal provenance used to keep a finalized md report authoritative.
24
24
  * 'children-only' = a native task() child session with NO board report
25
- * (rendered with the distinct `[task]` tag); 'md' = board report wins. */
25
+ * (rendered with the distinct `[native]` tag); 'md' = board report wins. */
26
26
  source?: 'child' | 'live' | 'md' | 'children-only';
27
27
  };
28
28
  /** Parse one delegation report md header into a structured entry.
@@ -59,7 +59,7 @@ declare function readAllDelegationEntries(root: string): Promise<DelegationEntry
59
59
  declare function resolveDelegationsDir(state: {
60
60
  directory?: string;
61
61
  worktree?: string;
62
- } | undefined, cwd?: string): string;
62
+ } | undefined, cwd?: any): string;
63
63
  /** Project root derived from the delegations dir: `<root>/.pantheon/delegations`
64
64
  * → `<root>`. Used to point the panel logger at the REAL hooks.log — passing
65
65
  * the delegations dir (or its dirname) directly made createTuiLogger append
@@ -279,10 +279,12 @@ type ChildDelegationLike = {
279
279
  * (fail-open: a freshly-seen child is assumed active; the 1s poll + md
280
280
  * correct it as soon as terminal data exists). */
281
281
  declare function childStatusToState(status: string | undefined): 'running' | 'completed';
282
- /** Row tag for a delegation entry: `[task]` for native task() children
283
- * (source 'children-only' — no board report), `[<alias>]` for board rows
284
- * ([apo-1]). The panel renders the tag with a distinct style so native
285
- * task() children are visually separable from pantheon_delegate jobs. */
282
+ /** Row tag for a delegation entry: `[native]` for native task() children
283
+ * (source 'children-only' — no board report), `[pantheon:<alias>]` for board
284
+ * rows ([pantheon:apo-1]) — the same tags the manager prints in
285
+ * pantheon_delegation_list, so panel rows and CLI list lines match. The
286
+ * panel renders the tag with a distinct style so native task() children are
287
+ * visually separable from pantheon_delegate jobs. */
286
288
  declare function delegationTag(entry: DelegationEntry): string;
287
289
  /** Turn child sessions (PRIMARY) enriched with md reports into the display
288
290
  * list. One entry per child id (duplicates across re-fetches collapse).
@@ -293,7 +295,7 @@ declare function delegationTag(entry: DelegationEntry): string;
293
295
  * time.created. A report-less child is a NATIVE task() child (every
294
296
  * child of the current session — pantheon_delegate OR the native `task()`
295
297
  * tool — carries parentID = caller), so it gets source 'children-only'
296
- * and the `[task]` tag instead of a board alias.
298
+ * and the `[native]` tag instead of a board alias.
297
299
  * Terminal md state wins over the derived state; a running md defers to
298
300
  * the child's live status. Sorted running-first (compareDelegationEntries).
299
301
  * Pure — no I/O. */
@@ -319,6 +321,7 @@ type LiveDelegationStore = {
319
321
  };
320
322
  declare const plugin: TuiPluginModule & {
321
323
  id: string;
324
+ setup: () => Promise<void>;
322
325
  };
323
326
  //#endregion
324
327
  export { ChildDelegationLike, DelegationActivity, DelegationEntry, DelegationToolPart, IDLE_SILENCE_MS, LiveDelegationEntry, LiveDelegationStore, ParsedDelegationToolPart, STALE_RUNNING_THRESHOLD_MS, TuiSessionSources, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationSpinnerFrame, delegationTag, fmtElapsed, isValidSessionId, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, toDelegationEntry, tuiLogPath, visibleDelegationList };
@@ -1 +1 @@
1
- {"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;KAo7BY;;EAEV;;EAEA;;;;EAIA;;EAEA;EACA;;EASA;;EAEA;EACA;EACA;;EAEA;;;;EAIA;;;;;;;;;;;iBAsBc,wBACd,aACA,oBACA,qBACC;;;;;;iBAkHmB,sBAAsB,cAAc,QAAQ;;;;;;;;iBAwC5C,yBAAyB,eAAe,QAAQ;;;;;;;;iBAWtD,sBACd;EAAS;EAAoB;eAC7B;;;;;;iBAYc,YAAY;;;iBAMZ,WAAW;;;;iBAOX,yBAAyB,GAAG,iBAAiB,GAAG;;;;;iBAWhD,sBACd,cAAc,mBACd,sBACA,cACA,4BACC;;cASU;;;;cAKA;;;;;;;;;iBAUG,mBACd,OAAO,iBACP,aACA,uBACC;;;iBAWa,WAAW;;;iBAcX,kBAAkB,OAAO,iBAAiB;;;KAQ9C;iBAQI,mBAAmB,OAAO,kBAAkB;iBAc5C,wBAAwB,OAAO;;iBAoB/B,uBAAuB;;;;;;;iBAWvB,4BACd,mBAAmB,mBACnB,eAAe,wBACd;;KAmFS;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ;IACR;IACA;IACA;MAAS;MAAgB;;;;;KAKjB;;EAEV;;EAEA;;EAEA;EACA;;EAEA;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;EAEA;;;KAIU;EACV;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBAac,wBACd,MAAM,oBACN,eACC;;;iBA+Ea,yBACd,KAAK,YAAY,sBACjB,MAAM,oBACN;;;iBA+Fc,sBACd,KAAK,YAAY,sBACjB;;;;;;iBAiBc,2BACd;EAAqB;EAAa;iBAClC,YAAY,uDACX;;;;;iBA2Ba,sBACd,KAAK,YAAY,sBACjB,gBAAgB,sBAChB;;;iBAWc,kBAAkB,MAAM,sBAAsB;;;;;;iBAqB9C,uBACd,eAAe,uBACf,aAAa,oBACZ;;;;;;;;;iBA8Da,iBAAiB,cAAc;;;;KAOnC;;EAEV;EACA;;IAEE;MAAU;;;IAEV;MAAU;QAAY;QAAe,SAAS;;;;;;;;;;iBASlC,wBAAwB,SAAS;;;;;;;;iBAmBjC,gBAAgB;EAAgB;IAAQ;;;;;;;iBASxC,kBAAkB;EAAkC;IAAQ;;;;KAKhE;;EAEV;;EAEA;;;EAGA;;;EAGA;EACA;IACE;IACA;;;;;;;iBAQY,mBAAmB;;;;;iBASnB,cAAc,OAAO;;;;;;;;;;;;;;iBAiBrB,4BACd,mBAAmB,mCACnB,aAAa,mBACb,eACC;;;;;;iBA0Ca,4BACd;EAAS,YAAY,cAAc,SAAS;eAC5C;;;;;KAiLU;EACV,KAAK,YAAY;;EAEjB;;EAEA;;cAucI,QAAQ;EAAoB"}
1
+ {"version":3,"file":"tui.d.ts","names":[],"sources":["../src/index.tsx"],"mappings":";;KAo7BY;;EAEV;;EAEA;;;;EAIA;;EAEA;EACA;;EASA;;EAEA;EACA;EACA;;EAEA;;;;EAIA;;;;;;;;;;;iBAsBc,wBACd,aACA,oBACA,qBACC;;;;;;iBAkHmB,sBAAsB,cAAc,QAAQ;;;;;;;;iBAwC5C,yBAAyB,eAAe,QAAQ;;;;;;;;iBAWtD,sBACd;EAAS;EAAoB;eAC7B;;;;;;iBAYc,YAAY;;;iBAMZ,WAAW;;;;iBAOX,yBAAyB,GAAG,iBAAiB,GAAG;;;;;iBAWhD,sBACd,cAAc,mBACd,sBACA,cACA,4BACC;;cASU;;;;cAKA;;;;;;;;;iBAUG,mBACd,OAAO,iBACP,aACA,uBACC;;;iBAWa,WAAW;;;iBAcX,kBAAkB,OAAO,iBAAiB;;;KAQ9C;iBAQI,mBAAmB,OAAO,kBAAkB;iBAc5C,wBAAwB,OAAO;;iBAoB/B,uBAAuB;;;;;;;iBAWvB,4BACd,mBAAmB,mBACnB,eAAe,wBACd;;KAmFS;EACV;EACA;EACA;EACA;EACA;EACA;IACE;IACA,QAAQ;IACR;IACA;IACA;MAAS;MAAgB;;;;;KAKjB;;EAEV;;EAEA;;EAEA;EACA;;EAEA;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;EAEA;;;KAIU;EACV;EACA;EACA;EACA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBAac,wBACd,MAAM,oBACN,eACC;;;iBA+Ea,yBACd,KAAK,YAAY,sBACjB,MAAM,oBACN;;;iBA+Fc,sBACd,KAAK,YAAY,sBACjB;;;;;;iBAiBc,2BACd;EAAqB;EAAa;iBAClC,YAAY,uDACX;;;;;iBA2Ba,sBACd,KAAK,YAAY,sBACjB,gBAAgB,sBAChB;;;iBAWc,kBAAkB,MAAM,sBAAsB;;;;;;iBAqB9C,uBACd,eAAe,uBACf,aAAa,oBACZ;;;;;;;;;iBA8Da,iBAAiB,cAAc;;;;KAOnC;;EAEV;EACA;;IAEE;MAAU;;;IAEV;MAAU;QAAY;QAAe,SAAS;;;;;;;;;;iBASlC,wBAAwB,SAAS;;;;;;;;iBAmBjC,gBAAgB;EAAgB;IAAQ;;;;;;;iBASxC,kBAAkB;EAAkC;IAAQ;;;;KAKhE;;EAEV;;EAEA;;;EAGA;;;EAGA;EACA;IACE;IACA;;;;;;;iBAQY,mBAAmB;;;;;;;iBAWnB,cAAc,OAAO;;;;;;;;;;;;;;iBAiBrB,4BACd,mBAAmB,mCACnB,aAAa,mBACb,eACC;;;;;;iBA0Ca,4BACd;EAAS,YAAY,cAAc,SAAS;eAC5C;;;;;KAiLU;EACV,KAAK,YAAY;;EAEjB;;EAEA;;cAucI,QAAQ;EAAoB;EAAY,aAAa"}
@@ -164,7 +164,7 @@ async function detectVersion(api) {
164
164
  if (ver) return ver;
165
165
  }
166
166
  } catch {}
167
- return "1.4.2";
167
+ return "1.5.0";
168
168
  }
169
169
  /**
170
170
  * usage-bar — AI subscription usage gauge for the opencode TUI.
@@ -1311,12 +1311,14 @@ function childStatusToState(status) {
1311
1311
  if (status === "idle") return "completed";
1312
1312
  return "running";
1313
1313
  }
1314
- /** Row tag for a delegation entry: `[task]` for native task() children
1315
- * (source 'children-only' — no board report), `[<alias>]` for board rows
1316
- * ([apo-1]). The panel renders the tag with a distinct style so native
1317
- * task() children are visually separable from pantheon_delegate jobs. */
1314
+ /** Row tag for a delegation entry: `[native]` for native task() children
1315
+ * (source 'children-only' — no board report), `[pantheon:<alias>]` for board
1316
+ * rows ([pantheon:apo-1]) — the same tags the manager prints in
1317
+ * pantheon_delegation_list, so panel rows and CLI list lines match. The
1318
+ * panel renders the tag with a distinct style so native task() children are
1319
+ * visually separable from pantheon_delegate jobs. */
1318
1320
  function delegationTag(entry) {
1319
- return entry.source === "children-only" ? "[task]" : `[${entry.alias}]`;
1321
+ return entry.source === "children-only" ? "[native]" : `[pantheon:${entry.alias}]`;
1320
1322
  }
1321
1323
  /** Turn child sessions (PRIMARY) enriched with md reports into the display
1322
1324
  * list. One entry per child id (duplicates across re-fetches collapse).
@@ -1327,7 +1329,7 @@ function delegationTag(entry) {
1327
1329
  * time.created. A report-less child is a NATIVE task() child (every
1328
1330
  * child of the current session — pantheon_delegate OR the native `task()`
1329
1331
  * tool — carries parentID = caller), so it gets source 'children-only'
1330
- * and the `[task]` tag instead of a board alias.
1332
+ * and the `[native]` tag instead of a board alias.
1331
1333
  * Terminal md state wins over the derived state; a running md defers to
1332
1334
  * the child's live status. Sorted running-first (compareDelegationEntries).
1333
1335
  * Pure — no I/O. */
@@ -1871,7 +1873,8 @@ const tui = (api, _options, _meta) => {
1871
1873
  };
1872
1874
  const plugin = {
1873
1875
  id: "pantheon.tui",
1874
- tui
1876
+ tui,
1877
+ setup: async () => {}
1875
1878
  };
1876
1879
  //#endregion
1877
1880
  export { IDLE_SILENCE_MS, STALE_RUNNING_THRESHOLD_MS, buildChildrenPath, childStatusToState, childrenToDelegationEntries, collectDelegationToolParts, compareDelegationEntries, plugin as default, delegationActivity, delegationActivityLabel, delegationElapsed, delegationSpinnerFrame, delegationTag, fmtElapsed, isValidSessionId, markStaleIfRunning, mergeChildDelegationSources, mergeDelegationSources, navigateToDelegationSession, panelLogDir, parseDelegationMarkdown, parseDelegationToolPart, readAllDelegationEntries, readDelegationEntries, reduceDelegationToolPart, removeDelegationEntry, resolveCurrentSessionID, resolveDelegationsDir, safeSessionPath, seedLiveDelegationMap, toDelegationEntry, tuiLogPath, visibleDelegationList };
@@ -1 +1 @@
1
- {"version":3,"file":"tui.js","names":[],"sources":[],"mappings":""}
1
+ {"version":3,"file":"tui.js","names":[],"sources":[],"mappings":""}