pantheon-opencode 1.5.0-beta.1 → 1.5.0-beta.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.
- package/README.md +44 -15
- package/README.pt-BR.md +39 -12
- package/package.json +7 -3
- package/plugin.json +1 -1
- package/pyproject.toml +57 -0
- package/scripts/code_mode_server.py +101 -36
- package/scripts/cost.mjs +30 -14
- package/scripts/install/opencode.mjs +6 -0
- package/scripts/install/plugin.mjs +3 -33
- package/scripts/manifest-inventory.mjs +410 -0
- package/scripts/mcp_persistence_server.py +518 -128
- package/scripts/package-evidence.mjs +242 -0
- package/scripts/probe-context-rehydrate.mjs +240 -0
- package/scripts/probe-pantheon-cost.mjs +304 -0
- package/scripts/release-beta-version.mjs +61 -60
- package/scripts/sync-tui.mjs +5 -27
- package/scripts/test-opencode-v1-v2-sandbox.sh +367 -96
- package/scripts/validation-policy.mjs +7 -7
- package/scripts/version-check.mjs +113 -108
- package/scripts/versioning.mjs +131 -88
- package/src/mcp/code_mode_server.py +101 -36
- package/src/mcp/mcp_persistence_server.py +518 -128
- package/src/pantheon/compaction-handoff.ts +304 -0
- package/src/pantheon/cost-command.ts +49 -32
- package/src/pantheon/delegate-manager.ts +285 -0
- package/src/pantheon/provider-capabilities.ts +221 -0
- package/src/pantheon/provider-stream-tracker.ts +182 -0
- package/src/pantheon/token-opt.ts +237 -11
- package/src/plugin-v2.ts +2 -14
- package/src/plugin.ts +3 -8
- package/src/plugins/tui/package-lock.json +2 -2
- package/src/plugins/tui/package.json +1 -1
- package/.pantheon/code-mode/.gitkeep +0 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-1.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-10.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-11.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-2.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-3.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-4.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-5.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-6.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-7.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-8.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-9.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/heartbeat.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/session.json +0 -11
- package/src/pantheon/delegate-task-adapter.ts +0 -444
|
@@ -173,7 +173,7 @@ export function applyGate(
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/** Kill-switch: `PANTHEON_TOKEN_OPT=off` disables the whole WS3 layer. */
|
|
176
|
-
export function isTokenOptEnabled(env: Record<string, string | undefined
|
|
176
|
+
export function isTokenOptEnabled(env: Readonly<Record<string, string | undefined>> = {}): boolean {
|
|
177
177
|
return env.PANTHEON_TOKEN_OPT !== 'off'
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -193,12 +193,24 @@ export interface C9Chunk {
|
|
|
193
193
|
text: string
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/** Immutable input batch for the safe C9 context-preparation contract. */
|
|
197
|
+
export interface C9CandidateBatch {
|
|
198
|
+
query: string
|
|
199
|
+
candidates: readonly C9Chunk[]
|
|
200
|
+
}
|
|
201
|
+
|
|
196
202
|
/** Per-category override of top-k / cutoff. */
|
|
197
203
|
export interface C9CategoryConfig {
|
|
198
204
|
topK?: number
|
|
199
205
|
cutoff?: number
|
|
200
206
|
}
|
|
201
207
|
|
|
208
|
+
/** Optional query used only to activate the explicit low-score fallback. */
|
|
209
|
+
export interface C9FilterOptions {
|
|
210
|
+
perCategory?: Readonly<Record<string, C9CategoryConfig>>
|
|
211
|
+
query?: string
|
|
212
|
+
}
|
|
213
|
+
|
|
202
214
|
/** Result of C9 filtering with debited injection cost. */
|
|
203
215
|
export interface C9FilterResult {
|
|
204
216
|
selected: C9Chunk[]
|
|
@@ -210,10 +222,15 @@ export interface C9FilterResult {
|
|
|
210
222
|
* - `ok` — at least one chunk selected;
|
|
211
223
|
* - `empty-input` — no chunks retrieved at all (fallback: proceed without
|
|
212
224
|
* injected context, caller should log `notice`);
|
|
213
|
-
* - `all-dropped` — chunks existed but none survived cutoff/top-k
|
|
214
|
-
*
|
|
225
|
+
* - `all-dropped` — chunks existed but none survived cutoff/top-k and no
|
|
226
|
+
* lexical query fallback was available;
|
|
227
|
+
* - `fallback-relative` — the absolute cutoff rejected every chunk, but a
|
|
228
|
+
* query-matching lexical/relative ranking selected auditable low-score
|
|
229
|
+
* chunks;
|
|
230
|
+
* - `nonsense` — a supplied query had no lexical overlap, so nothing is
|
|
231
|
+
* injected.
|
|
215
232
|
*/
|
|
216
|
-
signal: 'ok' | 'empty-input' | 'all-dropped'
|
|
233
|
+
signal: 'ok' | 'empty-input' | 'all-dropped' | 'fallback-relative' | 'nonsense'
|
|
217
234
|
/** Human-readable alert for the non-`ok` signals (null when `ok`). */
|
|
218
235
|
notice: string | null
|
|
219
236
|
/**
|
|
@@ -228,12 +245,27 @@ export interface C9FilterResult {
|
|
|
228
245
|
|
|
229
246
|
/**
|
|
230
247
|
* Filter scored chunks per category: drop below cutoff, keep top-k by
|
|
231
|
-
* score desc.
|
|
248
|
+
* score desc. An optional query enables only the explicit low-score fallback.
|
|
249
|
+
* The injected context cost is debited (`injectedTokens`).
|
|
232
250
|
*/
|
|
233
251
|
export function c9Filter(
|
|
234
|
-
chunks: C9Chunk[],
|
|
235
|
-
|
|
252
|
+
chunks: readonly C9Chunk[],
|
|
253
|
+
perCategoryOrOptions?: Readonly<Record<string, C9CategoryConfig>> | C9FilterOptions | string,
|
|
254
|
+
query?: string,
|
|
236
255
|
): C9FilterResult {
|
|
256
|
+
const isOptions = isC9FilterOptions(perCategoryOrOptions)
|
|
257
|
+
const perCategory =
|
|
258
|
+
typeof perCategoryOrOptions === 'string'
|
|
259
|
+
? undefined
|
|
260
|
+
: isOptions
|
|
261
|
+
? perCategoryOrOptions.perCategory
|
|
262
|
+
: perCategoryOrOptions
|
|
263
|
+
const filterQuery =
|
|
264
|
+
typeof perCategoryOrOptions === 'string'
|
|
265
|
+
? (query ?? perCategoryOrOptions)
|
|
266
|
+
: isOptions
|
|
267
|
+
? (query ?? perCategoryOrOptions.query)
|
|
268
|
+
: query
|
|
237
269
|
const byCategory = new Map<string, C9Chunk[]>()
|
|
238
270
|
for (const chunk of chunks) {
|
|
239
271
|
const group = byCategory.get(chunk.category)
|
|
@@ -256,15 +288,42 @@ export function c9Filter(
|
|
|
256
288
|
dropped.push(...group.filter((c) => c.score < cutoff))
|
|
257
289
|
dropped.push(...eligible.slice(topK))
|
|
258
290
|
}
|
|
259
|
-
|
|
260
|
-
const signal: C9FilterResult['signal'] =
|
|
291
|
+
let signal: C9FilterResult['signal'] =
|
|
261
292
|
chunks.length === 0 ? 'empty-input' : selected.length === 0 ? 'all-dropped' : 'ok'
|
|
262
|
-
|
|
293
|
+
let notice =
|
|
263
294
|
signal === 'empty-input'
|
|
264
295
|
? 'C9: empty input — no chunks retrieved; fallback: proceed without injected context'
|
|
265
296
|
: signal === 'all-dropped'
|
|
266
297
|
? 'C9: all chunks dropped by cutoff/top-k; fallback: relax cutoff/top-k or proceed without context'
|
|
267
298
|
: null
|
|
299
|
+
|
|
300
|
+
// Keep the absolute cutoff intact. This fallback is deliberately entered
|
|
301
|
+
// only after it rejects every chunk, and only lexical overlap can authorize
|
|
302
|
+
// injecting one of those low-score chunks.
|
|
303
|
+
if (chunks.length > 0 && selected.length === 0 && filterQuery !== undefined) {
|
|
304
|
+
const queryTerms = lexicalTerms(filterQuery)
|
|
305
|
+
const fallbackSelected =
|
|
306
|
+
queryTerms.length > 0 ? relativeLexicalSelection(byCategory, perCategory, queryTerms) : []
|
|
307
|
+
if (fallbackSelected.length > 0) {
|
|
308
|
+
selected.push(...fallbackSelected)
|
|
309
|
+
signal = 'fallback-relative'
|
|
310
|
+
notice =
|
|
311
|
+
`C9: absolute cutoff ${C9_DEFAULT_CUTOFF} yielded no eligible chunks; ` +
|
|
312
|
+
`lexical/relative fallback selected ${fallbackSelected.length} auditable ` +
|
|
313
|
+
`low-score chunk(s) (${queryTerms.length} query term(s)); selected scores remain below cutoff`
|
|
314
|
+
} else if (filterQuery.trim().length > 0) {
|
|
315
|
+
signal = 'nonsense'
|
|
316
|
+
notice =
|
|
317
|
+
'C9: query has no lexical overlap with low-score chunks; fallback returned zero and no context was injected'
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (selected.length > 0 && signal === 'fallback-relative') {
|
|
322
|
+
const selectedSet = new Set(selected)
|
|
323
|
+
dropped.length = 0
|
|
324
|
+
dropped.push(...chunks.filter((chunk) => !selectedSet.has(chunk)))
|
|
325
|
+
}
|
|
326
|
+
const context = buildC9Context(selected)
|
|
268
327
|
return {
|
|
269
328
|
selected,
|
|
270
329
|
dropped,
|
|
@@ -276,8 +335,175 @@ export function c9Filter(
|
|
|
276
335
|
}
|
|
277
336
|
}
|
|
278
337
|
|
|
338
|
+
/** Configuration for the pure C9 context-preparation boundary. */
|
|
339
|
+
export interface C9ContextOptions {
|
|
340
|
+
env?: Readonly<Record<string, string | undefined>>
|
|
341
|
+
perCategory?: Readonly<Record<string, C9CategoryConfig>>
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Metrics emitted by C9; deliberately contains no candidate or context text. */
|
|
345
|
+
export interface C9Telemetry {
|
|
346
|
+
signal: C9FilterResult['signal'] | 'disabled' | 'empty-query'
|
|
347
|
+
counts: {
|
|
348
|
+
candidates: number
|
|
349
|
+
selected: number
|
|
350
|
+
dropped: number
|
|
351
|
+
}
|
|
352
|
+
recall: number
|
|
353
|
+
injectedChars: number
|
|
354
|
+
injectedTokens: number
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** C9 result with the kill-switch state available as a type discriminator. */
|
|
358
|
+
export type C9ContextResult =
|
|
359
|
+
| {
|
|
360
|
+
enabled: true
|
|
361
|
+
context: string
|
|
362
|
+
telemetry: C9Telemetry
|
|
363
|
+
}
|
|
364
|
+
| {
|
|
365
|
+
enabled: false
|
|
366
|
+
context: ''
|
|
367
|
+
telemetry: C9Telemetry
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function telemetry(
|
|
371
|
+
signal: C9Telemetry['signal'],
|
|
372
|
+
candidates: number,
|
|
373
|
+
selected: number,
|
|
374
|
+
dropped: number,
|
|
375
|
+
recall: number,
|
|
376
|
+
context = '',
|
|
377
|
+
): C9Telemetry {
|
|
378
|
+
return {
|
|
379
|
+
signal,
|
|
380
|
+
counts: { candidates, selected, dropped },
|
|
381
|
+
recall,
|
|
382
|
+
injectedChars: context.length,
|
|
383
|
+
injectedTokens: estimateTokens(context),
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function hasLexicalOverlap(query: string, chunks: readonly C9Chunk[]): boolean {
|
|
388
|
+
const queryTerms = lexicalTerms(query)
|
|
389
|
+
if (queryTerms.length === 0) return false
|
|
390
|
+
return chunks.some((chunk) => {
|
|
391
|
+
const chunkTerms = new Set(lexicalTerms(chunk.text))
|
|
392
|
+
return queryTerms.some((term) => chunkTerms.has(term))
|
|
393
|
+
})
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Prepare auditable context without performing retrieval or side effects.
|
|
398
|
+
*
|
|
399
|
+
* The caller supplies the query and candidates already retrieved. The
|
|
400
|
+
* kill-switch is read only from the supplied environment object, so this
|
|
401
|
+
* boundary remains deterministic and testable. C9 always receives the batch
|
|
402
|
+
* query explicitly; no option can replace it with an implicit query.
|
|
403
|
+
*/
|
|
404
|
+
export function prepareC9Context(
|
|
405
|
+
batch: C9CandidateBatch,
|
|
406
|
+
options: C9ContextOptions = {},
|
|
407
|
+
): C9ContextResult {
|
|
408
|
+
const candidateCount = batch.candidates.length
|
|
409
|
+
if (!isTokenOptEnabled(options.env)) {
|
|
410
|
+
return {
|
|
411
|
+
enabled: false,
|
|
412
|
+
context: '',
|
|
413
|
+
telemetry: telemetry('disabled', candidateCount, 0, 0, 0),
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const filtered = c9Filter(batch.candidates, options.perCategory, batch.query)
|
|
418
|
+
if (batch.query.trim().length === 0) {
|
|
419
|
+
return {
|
|
420
|
+
enabled: true,
|
|
421
|
+
context: '',
|
|
422
|
+
telemetry: telemetry(
|
|
423
|
+
'empty-query',
|
|
424
|
+
candidateCount,
|
|
425
|
+
0,
|
|
426
|
+
candidateCount,
|
|
427
|
+
candidateCount === 0 ? filtered.recall : 0,
|
|
428
|
+
),
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const context =
|
|
433
|
+
filtered.signal === 'nonsense' ||
|
|
434
|
+
(filtered.signal === 'ok' && !hasLexicalOverlap(batch.query, filtered.selected))
|
|
435
|
+
? ''
|
|
436
|
+
: buildC9Context(filtered.selected)
|
|
437
|
+
const signal =
|
|
438
|
+
context.length === 0 && filtered.signal === 'ok' ? ('nonsense' as const) : filtered.signal
|
|
439
|
+
const selectedCount = context.length === 0 ? 0 : filtered.selected.length
|
|
440
|
+
const droppedCount = context.length === 0 ? candidateCount : filtered.dropped.length
|
|
441
|
+
const recall = context.length === 0 && filtered.signal === 'ok' ? 0 : filtered.recall
|
|
442
|
+
return {
|
|
443
|
+
enabled: true,
|
|
444
|
+
context,
|
|
445
|
+
telemetry: telemetry(signal, candidateCount, selectedCount, droppedCount, recall, context),
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** Normalize query/text terms without introducing a semantic or runtime dependency. */
|
|
450
|
+
function lexicalTerms(value: string): string[] {
|
|
451
|
+
return [
|
|
452
|
+
...new Set(
|
|
453
|
+
value
|
|
454
|
+
.normalize('NFKD')
|
|
455
|
+
.replace(/\p{M}/gu, '')
|
|
456
|
+
.toLowerCase()
|
|
457
|
+
.match(/[\p{L}\p{N}]+/gu)
|
|
458
|
+
?.filter((term) => term.length > 1) ?? [],
|
|
459
|
+
),
|
|
460
|
+
]
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/** Select only query-matching low-score chunks, ranked lexically then relatively. */
|
|
464
|
+
function relativeLexicalSelection(
|
|
465
|
+
byCategory: Map<string, C9Chunk[]>,
|
|
466
|
+
perCategory: Readonly<Record<string, C9CategoryConfig>> | undefined,
|
|
467
|
+
queryTerms: string[],
|
|
468
|
+
): C9Chunk[] {
|
|
469
|
+
const selected: C9Chunk[] = []
|
|
470
|
+
for (const [category, group] of byCategory) {
|
|
471
|
+
const config = perCategory?.[category]
|
|
472
|
+
const topK = config?.topK ?? C9_DEFAULT_TOP_K
|
|
473
|
+
const maxScore = Math.max(...group.map((chunk) => chunk.score), 0)
|
|
474
|
+
const ranked = group
|
|
475
|
+
.map((chunk, index) => {
|
|
476
|
+
const textSet = new Set(lexicalTerms(chunk.text))
|
|
477
|
+
const overlap = queryTerms.filter((term) => textSet.has(term)).length
|
|
478
|
+
const lexicalScore = overlap / queryTerms.length
|
|
479
|
+
const relativeScore = maxScore > 0 ? chunk.score / maxScore : 0
|
|
480
|
+
return { chunk, index, lexicalScore, relativeScore }
|
|
481
|
+
})
|
|
482
|
+
.filter((entry) => entry.lexicalScore > 0)
|
|
483
|
+
.sort(
|
|
484
|
+
(left, right) =>
|
|
485
|
+
right.lexicalScore - left.lexicalScore ||
|
|
486
|
+
right.relativeScore - left.relativeScore ||
|
|
487
|
+
right.chunk.score - left.chunk.score ||
|
|
488
|
+
left.index - right.index,
|
|
489
|
+
)
|
|
490
|
+
selected.push(...ranked.slice(0, topK).map((entry) => entry.chunk))
|
|
491
|
+
}
|
|
492
|
+
return selected
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function isC9FilterOptions(
|
|
496
|
+
value: Readonly<Record<string, C9CategoryConfig>> | C9FilterOptions | string | undefined,
|
|
497
|
+
): value is C9FilterOptions {
|
|
498
|
+
return (
|
|
499
|
+
value !== undefined &&
|
|
500
|
+
typeof value !== 'string' &&
|
|
501
|
+
('perCategory' in value || ('query' in value && typeof value.query === 'string'))
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
|
|
279
505
|
/** Build the injected context: only auditable chunks (id + score + text). */
|
|
280
|
-
export function buildC9Context(selected: C9Chunk[]): string {
|
|
506
|
+
export function buildC9Context(selected: readonly C9Chunk[]): string {
|
|
281
507
|
return selected.map((c) => `[${c.category}:${c.id}|${c.score}] ${c.text}`).join('\n')
|
|
282
508
|
}
|
|
283
509
|
|
package/src/plugin-v2.ts
CHANGED
|
@@ -612,18 +612,6 @@ export interface V2ToolResult {
|
|
|
612
612
|
output: string
|
|
613
613
|
}
|
|
614
614
|
|
|
615
|
-
/**
|
|
616
|
-
* Wrap raw tool text into the object shape the V2 beta host requires.
|
|
617
|
-
* Never throws (fail-open): non-string input degrades to String(input).
|
|
618
|
-
*/
|
|
619
|
-
export function toV2ToolResult(text: unknown): V2ToolResult {
|
|
620
|
-
try {
|
|
621
|
-
return { output: typeof text === 'string' ? text : String(text) }
|
|
622
|
-
} catch {
|
|
623
|
-
return { output: '[pantheon] tool output unavailable' }
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
615
|
/**
|
|
628
616
|
* A V2 tool definition ready for registration.
|
|
629
617
|
*/
|
|
@@ -698,9 +686,9 @@ function createV2ToolDefinitionsFromContext(_context: PluginContext): V2ToolDef[
|
|
|
698
686
|
// costCommand/goalTools) once V1 infrastructure is resolvable in the V2
|
|
699
687
|
// standalone context. The before/after factories in v2-hooks.ts:216-282
|
|
700
688
|
// are likewise unwired. Until then, placeholders resolve to the object
|
|
701
|
-
// shape
|
|
689
|
+
// shape so the beta host never sees a bare string.
|
|
702
690
|
execute: async (_input: Record<string, unknown>, _context: unknown): Promise<V2ToolResult> => {
|
|
703
|
-
return
|
|
691
|
+
return { output: `${name}: ${v2UnavailableMessage}` }
|
|
704
692
|
},
|
|
705
693
|
}))
|
|
706
694
|
}
|
package/src/plugin.ts
CHANGED
|
@@ -12,11 +12,7 @@ import {
|
|
|
12
12
|
DEFAULT_LIMITS as SANDBOX_DEFAULT_LIMITS,
|
|
13
13
|
} from './pantheon/context-sandbox.ts'
|
|
14
14
|
import { createCostCommand } from './pantheon/cost-command.ts'
|
|
15
|
-
import {
|
|
16
|
-
buildPluginNativeDelegation,
|
|
17
|
-
resolveDelegateMode,
|
|
18
|
-
withDelegationKillSwitch,
|
|
19
|
-
} from './pantheon/delegate-task-adapter.ts'
|
|
15
|
+
import { buildPluginNativeDelegation, resolveDelegateMode } from './pantheon/delegate-manager.ts'
|
|
20
16
|
import {
|
|
21
17
|
collectRootSessionIDs,
|
|
22
18
|
createDelegationTools,
|
|
@@ -375,8 +371,7 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
375
371
|
// WS1 (PR #94): delegation backend gate. Default = legacy (the V1
|
|
376
372
|
// fire-and-forget toolset, intact); PANTHEON_DELEGATE_MODE=native selects
|
|
377
373
|
// the thin manager over native task() semantics. Kill-switch
|
|
378
|
-
// PANTHEON_DELEGATION=off covers
|
|
379
|
-
// legacy via withDelegationKillSwitch). finalizeDelegation always stays on
|
|
374
|
+
// PANTHEON_DELEGATION=off covers the native manager; finalizeDelegation stays on
|
|
380
375
|
// the legacy observer: it works on the shared board in both modes and must
|
|
381
376
|
// never be kill-switched, so children never orphan. The idle hook below is
|
|
382
377
|
// untouched.
|
|
@@ -428,7 +423,7 @@ const plugin: Plugin = async (input: PluginInput) => {
|
|
|
428
423
|
...(wallClockTimeoutMs !== undefined ? { wallClockTimeoutMs } : {}),
|
|
429
424
|
finalizeDelegation: legacyDelegation.finalizeDelegation,
|
|
430
425
|
})
|
|
431
|
-
:
|
|
426
|
+
: legacyDelegation
|
|
432
427
|
|
|
433
428
|
// Proactive idle-child scan (Fix 2): finalize children that are idle on the
|
|
434
429
|
// board but have no MD report on disk — eliminates the phantom "running"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-tui",
|
|
3
|
-
"version": "1.5.0",
|
|
3
|
+
"version": "1.5.0-beta.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pantheon-tui",
|
|
9
|
-
"version": "1.5.0",
|
|
9
|
+
"version": "1.5.0-beta.3",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@opencode-ai/plugin": ">=1.14.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon-tui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.5.0-beta.
|
|
4
|
+
"version": "1.5.0-beta.3",
|
|
5
5
|
"description": "Pantheon TUI plugin — sidebar (version, preset, sessions, real-time delegations) + AI subscription usage gauges incl. OpenCode Go/Zen dollar limits (vendored, MIT)",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
File without changes
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"task_id": "initial-token-40k",
|
|
3
|
-
"mode": "deepwork",
|
|
4
|
-
"start_time": "2026-07-24T10:57:06.212552+00:00",
|
|
5
|
-
"last_activity": "2026-07-24T11:21:25.938170+00:00",
|
|
6
|
-
"status": "in_progress",
|
|
7
|
-
"gate_history": [],
|
|
8
|
-
"stop_reason": null,
|
|
9
|
-
"stopped_at": null,
|
|
10
|
-
"turn_count": 11
|
|
11
|
-
}
|