pi-ui-extend 1.0.39 → 1.0.41
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 +1 -1
- package/dist/app/commands/command-registry.js +2 -2
- package/dist/app/commands/command-session-actions.d.ts +0 -1
- package/dist/app/commands/command-session-actions.js +22 -13
- package/dist/app/icons.d.ts +14 -0
- package/dist/app/icons.js +33 -0
- package/dist/app/rendering/conversation-tool-renderer.js +2 -2
- package/dist/app/rendering/dcp-stats.d.ts +6 -1
- package/dist/app/rendering/dcp-stats.js +214 -46
- package/dist/app/rendering/editor-panels.js +8 -5
- package/dist/app/session/lazy-session-manager.js +12 -1
- package/dist/app/session/tabs-controller.d.ts +2 -5
- package/dist/app/session/tabs-controller.js +12 -21
- package/dist/app/subagents/subagents-model.d.ts +14 -1
- package/dist/app/subagents/subagents-model.js +34 -15
- package/dist/app/types.d.ts +2 -0
- package/dist/bundled-extensions/session-title/config.js +1 -1
- package/dist/markdown-format.js +27 -9
- package/dist/schemas/pi-tools-suite-schema.d.ts +29 -16
- package/dist/schemas/pi-tools-suite-schema.js +46 -31
- package/external/pi-tools-suite/README.md +392 -52
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +31 -21
- package/external/pi-tools-suite/docs/context-gateway-p00-adr.md +216 -0
- package/external/pi-tools-suite/docs/context-gateway-p01n-gate-review.md +122 -0
- package/external/pi-tools-suite/docs/context-gateway-p01n-measurement.md +133 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-ra-evidence.md +111 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rb-evidence.md +100 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rc-evidence.md +69 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rd-evidence.md +100 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-re-evidence.md +74 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rf-evidence.md +153 -0
- package/external/pi-tools-suite/docs/context-gateway-p01r-rg-evidence.md +235 -0
- package/external/pi-tools-suite/docs/evals.md +684 -0
- package/external/pi-tools-suite/docs/subagent-model-pools.md +109 -0
- package/external/pi-tools-suite/package.json +10 -3
- package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/scripts/browser-qa-runner.mjs +82 -1
- package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/SKILL.md → agents/browser-qa.md} +261 -12
- package/external/pi-tools-suite/src/async-subagents/agents/implement.md +20 -0
- package/external/pi-tools-suite/src/async-subagents/agents/oracle.md +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +18 -0
- package/external/pi-tools-suite/src/async-subagents/agents/verify.md +18 -0
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +27 -243
- package/external/pi-tools-suite/src/async-subagents/commands.ts +6 -2
- package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +41 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +13 -93
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +494 -0
- package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +9 -0
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +200 -143
- package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +54 -0
- package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +7 -6
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +52 -45
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +12 -4
- package/external/pi-tools-suite/src/async-subagents/index.ts +11 -1
- package/external/pi-tools-suite/src/async-subagents/lib.ts +6 -2
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +46 -18
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +3 -2
- package/external/pi-tools-suite/src/async-subagents/types.ts +2 -0
- package/external/pi-tools-suite/src/coding-discipline/index.ts +41 -142
- package/external/pi-tools-suite/src/config.ts +1 -22
- package/external/pi-tools-suite/src/context-gateway/accounting.ts +151 -0
- package/external/pi-tools-suite/src/context-gateway/config.ts +111 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +160 -0
- package/external/pi-tools-suite/src/context-gateway/metadata-normalization.ts +88 -0
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +89 -0
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +429 -0
- package/external/pi-tools-suite/src/context-gateway/test-output-parser.ts +326 -0
- package/external/pi-tools-suite/src/context-gateway/types.ts +152 -0
- package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +106 -0
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +810 -106
- package/external/pi-tools-suite/src/dcp/commands.ts +64 -139
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +369 -35
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +510 -64
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +113 -0
- package/external/pi-tools-suite/src/dcp/compression-progress.ts +70 -0
- package/external/pi-tools-suite/src/dcp/config.ts +36 -61
- package/external/pi-tools-suite/src/dcp/conversation-index.ts +421 -0
- package/external/pi-tools-suite/src/dcp/debug-log.ts +7 -5
- package/external/pi-tools-suite/src/dcp/index.ts +617 -203
- package/external/pi-tools-suite/src/dcp/journal.ts +566 -0
- package/external/pi-tools-suite/src/dcp/progress-controller.ts +244 -0
- package/external/pi-tools-suite/src/dcp/prompts.ts +10 -7
- package/external/pi-tools-suite/src/dcp/provider-tool-results.ts +189 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +298 -78
- package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +173 -281
- package/external/pi-tools-suite/src/dcp/pruner-emergency.ts +2 -4
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +17 -5
- package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +11 -1
- package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +30 -82
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +22 -133
- package/external/pi-tools-suite/src/dcp/pruner.ts +18 -33
- package/external/pi-tools-suite/src/dcp/recovery.ts +129 -0
- package/external/pi-tools-suite/src/dcp/shadow-plan.ts +127 -0
- package/external/pi-tools-suite/src/dcp/state-transaction.ts +102 -0
- package/external/pi-tools-suite/src/dcp/state.ts +158 -580
- package/external/pi-tools-suite/src/dcp/ui.ts +1 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +55 -220
- package/external/pi-tools-suite/src/index.ts +9 -0
- package/external/pi-tools-suite/src/model-tools/index.ts +76 -42
- package/external/pi-tools-suite/src/repo-discovery/index.ts +84 -18
- package/external/pi-tools-suite/src/repo-discovery/native-compact.ts +458 -0
- package/external/pi-tools-suite/src/session-recovery/index.ts +189 -43
- package/external/pi-tools-suite/src/tool-descriptions.ts +43 -38
- package/external/pi-tools-suite/src/truncation-metadata-normalizer/index.ts +17 -0
- package/package.json +6 -6
- package/schemas/pi-tools-suite.json +159 -78
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/auth-scaffold-spec.md +0 -78
- package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +0 -223
- package/external/pi-tools-suite/src/dcp/state-persistence.ts +0 -195
- /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-auth.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-flow.example.jsonc +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.LICENSE +0 -0
- /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.mjs +0 -0
|
@@ -5,6 +5,7 @@ import { modelKeysFromContext, resolveModelConfig, type DcpConfig } from "./conf
|
|
|
5
5
|
import type { DcpNudgeType } from "./pruner-types.js"
|
|
6
6
|
import { isToolRecordProtected, markToolPruned } from "./pruner.js"
|
|
7
7
|
import { ignoreStaleExtensionContextError, safeGetContextUsage } from "../context-usage.js"
|
|
8
|
+
import { captureDcpTransactionGuard, cloneDcpTransactionState, runDcpStateTransaction } from "./state-transaction.js"
|
|
8
9
|
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
10
11
|
// Constants
|
|
@@ -17,6 +18,12 @@ const DCP_STATS_DETAILS_KIND = "dcp-stats"
|
|
|
17
18
|
|
|
18
19
|
export interface DcpCommandHooks {
|
|
19
20
|
onStateChanged?: (ctx: ExtensionCommandContext) => void
|
|
21
|
+
persistState?: (
|
|
22
|
+
ctx: ExtensionCommandContext,
|
|
23
|
+
state: DcpState,
|
|
24
|
+
publication?: { beforePublish?: () => void; onPublished?: () => void },
|
|
25
|
+
) => Promise<void> | void
|
|
26
|
+
isSessionSupported?: () => boolean
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
// ---------------------------------------------------------------------------
|
|
@@ -73,6 +80,7 @@ async function staleSafe(action: () => void | Promise<void>): Promise<void> {
|
|
|
73
80
|
|
|
74
81
|
interface DcpNudgeStats {
|
|
75
82
|
emitted: number
|
|
83
|
+
reapplied: number
|
|
76
84
|
upgraded: number
|
|
77
85
|
clearedEvents: number
|
|
78
86
|
clearedAnchors: number
|
|
@@ -80,7 +88,7 @@ interface DcpNudgeStats {
|
|
|
80
88
|
activeByType: Record<DcpNudgeType, number>
|
|
81
89
|
last?: {
|
|
82
90
|
type: DcpNudgeType
|
|
83
|
-
event: "emitted" | "upgraded"
|
|
91
|
+
event: "emitted" | "reapplied" | "upgraded"
|
|
84
92
|
createdAt?: number
|
|
85
93
|
contextPercent?: number | null
|
|
86
94
|
}
|
|
@@ -89,6 +97,7 @@ interface DcpNudgeStats {
|
|
|
89
97
|
function collectNudgeStats(ctx: ExtensionCommandContext, state: DcpState): DcpNudgeStats {
|
|
90
98
|
const stats: DcpNudgeStats = {
|
|
91
99
|
emitted: 0,
|
|
100
|
+
reapplied: 0,
|
|
92
101
|
upgraded: 0,
|
|
93
102
|
clearedEvents: 0,
|
|
94
103
|
clearedAnchors: 0,
|
|
@@ -104,8 +113,9 @@ function collectNudgeStats(ctx: ExtensionCommandContext, state: DcpState): DcpNu
|
|
|
104
113
|
const data = customEntryData(entry, "dcp-nudge")
|
|
105
114
|
if (!data) continue
|
|
106
115
|
const event = data.event
|
|
107
|
-
if ((event === "emitted" || event === "upgraded") && isNudgeType(data.type)) {
|
|
116
|
+
if ((event === "emitted" || event === "reapplied" || event === "upgraded") && isNudgeType(data.type)) {
|
|
108
117
|
if (event === "emitted") stats.emitted++
|
|
118
|
+
else if (event === "reapplied") stats.reapplied++
|
|
109
119
|
else stats.upgraded++
|
|
110
120
|
stats.byType[data.type]++
|
|
111
121
|
const createdAt = typeof data.createdAt === "number" ? data.createdAt : undefined
|
|
@@ -173,10 +183,6 @@ Commands:
|
|
|
173
183
|
/dcp manual — Show manual mode status
|
|
174
184
|
/dcp manual on — Enable manual mode (disable autonomous compression nudges)
|
|
175
185
|
/dcp manual off — Disable manual mode (enable autonomous compression nudges)
|
|
176
|
-
/dcp decompress — List active compression blocks
|
|
177
|
-
/dcp decompress N — Restore compression block N
|
|
178
|
-
/dcp recompress — List blocks restored by /dcp decompress
|
|
179
|
-
/dcp recompress N — Re-apply a user-restored compression block
|
|
180
186
|
/dcp compress — Trigger compression (sends compress tool invocation to LLM)`
|
|
181
187
|
|
|
182
188
|
function handleHelp(ctx: ExtensionCommandContext): void {
|
|
@@ -223,7 +229,7 @@ function handleStats(pi: ExtensionAPI, ctx: ExtensionCommandContext, state: DcpS
|
|
|
223
229
|
const activeBlocks = state.compressionBlocks.filter((b) => b.active).length
|
|
224
230
|
const totalBlocks = state.compressionBlocks.length
|
|
225
231
|
const nudgeStats = collectNudgeStats(ctx, state)
|
|
226
|
-
const totalNudgeEvents = nudgeStats.emitted + nudgeStats.upgraded
|
|
232
|
+
const totalNudgeEvents = nudgeStats.emitted + nudgeStats.reapplied + nudgeStats.upgraded
|
|
227
233
|
const activeAnchors = state.nudgeAnchors.length
|
|
228
234
|
const lines: string[] = []
|
|
229
235
|
lines.push("DCP Session Statistics:")
|
|
@@ -233,7 +239,7 @@ function handleStats(pi: ExtensionAPI, ctx: ExtensionCommandContext, state: DcpS
|
|
|
233
239
|
lines.push(` Manual mode: ${state.manualMode ? "on" : "off"}`)
|
|
234
240
|
lines.push("")
|
|
235
241
|
lines.push("Nudge telemetry:")
|
|
236
|
-
lines.push(` Sent: ${fmt(nudgeStats.emitted)} emitted, ${fmt(nudgeStats.upgraded)} upgraded`)
|
|
242
|
+
lines.push(` Sent: ${fmt(nudgeStats.emitted)} emitted, ${fmt(nudgeStats.reapplied)} reapplied, ${fmt(nudgeStats.upgraded)} upgraded`)
|
|
237
243
|
lines.push(
|
|
238
244
|
` By type: ${NUDGE_TYPES.map((type) => `${nudgeLabel(type)}=${fmt(nudgeStats.byType[type])}`).join(", ")}`,
|
|
239
245
|
)
|
|
@@ -277,9 +283,7 @@ async function handleSweep(
|
|
|
277
283
|
const protectedTools = new Set<string>([
|
|
278
284
|
...ALWAYS_PROTECTED_TOOLS,
|
|
279
285
|
...config.compress.protectedTools,
|
|
280
|
-
...config.strategies.
|
|
281
|
-
...config.strategies.purgeErrors.protectedTools,
|
|
282
|
-
...config.strategies.autoToolPruning.protectedTools,
|
|
286
|
+
...config.strategies.emergencyCurrentTurnPruning.protectedTools,
|
|
283
287
|
])
|
|
284
288
|
|
|
285
289
|
// Walk the branch (root → leaf) collecting toolCallIds in encounter order,
|
|
@@ -383,122 +387,6 @@ function handleManual(
|
|
|
383
387
|
}
|
|
384
388
|
}
|
|
385
389
|
|
|
386
|
-
// ---------------------------------------------------------------------------
|
|
387
|
-
// Decompress
|
|
388
|
-
// ---------------------------------------------------------------------------
|
|
389
|
-
|
|
390
|
-
function handleDecompress(
|
|
391
|
-
ctx: ExtensionCommandContext,
|
|
392
|
-
state: DcpState,
|
|
393
|
-
nArg: string | undefined,
|
|
394
|
-
): void {
|
|
395
|
-
if (nArg === undefined) {
|
|
396
|
-
// List all active compression blocks.
|
|
397
|
-
const activeBlocks = state.compressionBlocks.filter((b) => b.active)
|
|
398
|
-
|
|
399
|
-
if (activeBlocks.length === 0) {
|
|
400
|
-
ctx.ui.notify("No active compression blocks.", "info")
|
|
401
|
-
return
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
const lines: string[] = ["Active compression blocks:"]
|
|
405
|
-
for (const block of activeBlocks) {
|
|
406
|
-
lines.push(
|
|
407
|
-
` b${block.id} — "${block.topic}" (est. ${fmt(block.summaryTokenEstimate)} tokens)`,
|
|
408
|
-
)
|
|
409
|
-
}
|
|
410
|
-
lines.push("")
|
|
411
|
-
lines.push("Run /dcp decompress N to restore a block.")
|
|
412
|
-
|
|
413
|
-
ctx.ui.notify(lines.join("\n"), "info")
|
|
414
|
-
} else {
|
|
415
|
-
// Restore block N.
|
|
416
|
-
const id = parseInt(nArg, 10)
|
|
417
|
-
|
|
418
|
-
if (isNaN(id)) {
|
|
419
|
-
ctx.ui.notify(
|
|
420
|
-
`Invalid block ID: "${nArg}". Usage: /dcp decompress N`,
|
|
421
|
-
"error",
|
|
422
|
-
)
|
|
423
|
-
return
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
const block = state.compressionBlocks.find((b) => b.id === id)
|
|
427
|
-
|
|
428
|
-
if (!block) {
|
|
429
|
-
ctx.ui.notify(`No compression block found with id ${id}.`, "error")
|
|
430
|
-
return
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
if (!block.active) {
|
|
434
|
-
ctx.ui.notify(`Compression block b${id} is already decompressed.`, "info")
|
|
435
|
-
return
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
block.active = false
|
|
439
|
-
block.deactivatedByUser = true
|
|
440
|
-
ctx.ui.notify(`Decompressed block b${id}: "${block.topic}"`, "info")
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// ---------------------------------------------------------------------------
|
|
445
|
-
// Recompress
|
|
446
|
-
// ---------------------------------------------------------------------------
|
|
447
|
-
|
|
448
|
-
function handleRecompress(
|
|
449
|
-
ctx: ExtensionCommandContext,
|
|
450
|
-
state: DcpState,
|
|
451
|
-
nArg: string | undefined,
|
|
452
|
-
): void {
|
|
453
|
-
const recompressible = state.compressionBlocks.filter((b) => !b.active && b.deactivatedByUser)
|
|
454
|
-
|
|
455
|
-
if (nArg === undefined) {
|
|
456
|
-
if (recompressible.length === 0) {
|
|
457
|
-
ctx.ui.notify("No user-decompressed compression blocks are available to recompress.", "info")
|
|
458
|
-
return
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const lines: string[] = ["Recompressible blocks:"]
|
|
462
|
-
for (const block of recompressible) {
|
|
463
|
-
lines.push(
|
|
464
|
-
` b${block.id} — "${block.topic}" (est. ${fmt(block.summaryTokenEstimate)} tokens)`,
|
|
465
|
-
)
|
|
466
|
-
}
|
|
467
|
-
lines.push("")
|
|
468
|
-
lines.push("Run /dcp recompress N to re-apply a block.")
|
|
469
|
-
ctx.ui.notify(lines.join("\n"), "info")
|
|
470
|
-
return
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const id = parseInt(nArg, 10)
|
|
474
|
-
if (isNaN(id)) {
|
|
475
|
-
ctx.ui.notify(`Invalid block ID: "${nArg}". Usage: /dcp recompress N`, "error")
|
|
476
|
-
return
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
const block = state.compressionBlocks.find((b) => b.id === id)
|
|
480
|
-
if (!block) {
|
|
481
|
-
ctx.ui.notify(`No compression block found with id ${id}.`, "error")
|
|
482
|
-
return
|
|
483
|
-
}
|
|
484
|
-
if (block.active) {
|
|
485
|
-
ctx.ui.notify(`Compression block b${id} is already active.`, "info")
|
|
486
|
-
return
|
|
487
|
-
}
|
|
488
|
-
if (!block.deactivatedByUser) {
|
|
489
|
-
ctx.ui.notify(`Compression block b${id} was superseded by another block and cannot be recompressed directly.`, "error")
|
|
490
|
-
return
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
for (const coveredId of block.coveredBlockIds ?? []) {
|
|
494
|
-
const covered = state.compressionBlocks.find((candidate) => candidate.id === coveredId)
|
|
495
|
-
if (covered) covered.active = false
|
|
496
|
-
}
|
|
497
|
-
block.active = true
|
|
498
|
-
block.deactivatedByUser = false
|
|
499
|
-
ctx.ui.notify(`Recompressed block b${id}: "${block.topic}"`, "info")
|
|
500
|
-
}
|
|
501
|
-
|
|
502
390
|
// ---------------------------------------------------------------------------
|
|
503
391
|
// Compress (trigger)
|
|
504
392
|
// ---------------------------------------------------------------------------
|
|
@@ -531,6 +419,15 @@ export function registerCommands(
|
|
|
531
419
|
config: DcpConfig,
|
|
532
420
|
hooks: DcpCommandHooks = {},
|
|
533
421
|
): void {
|
|
422
|
+
const persistState = hooks.persistState ?? (async (
|
|
423
|
+
_ctx: ExtensionCommandContext,
|
|
424
|
+
_state: DcpState,
|
|
425
|
+
publication?: { beforePublish?: () => void; onPublished?: () => void },
|
|
426
|
+
) => {
|
|
427
|
+
publication?.beforePublish?.()
|
|
428
|
+
publication?.onPublished?.()
|
|
429
|
+
})
|
|
430
|
+
const isSessionSupported = hooks.isSessionSupported ?? (() => true)
|
|
534
431
|
pi.registerCommand("dcp", {
|
|
535
432
|
description: "Dynamic Context Pruning — manage context window usage",
|
|
536
433
|
getArgumentCompletions(prefix: string): AutocompleteItem[] | null {
|
|
@@ -539,8 +436,6 @@ export function registerCommands(
|
|
|
539
436
|
{ value: "stats", label: "stats", description: "Show pruning statistics" },
|
|
540
437
|
{ value: "sweep", label: "sweep", description: "Prune tool outputs" },
|
|
541
438
|
{ value: "manual", label: "manual", description: "Toggle manual mode" },
|
|
542
|
-
{ value: "decompress", label: "decompress", description: "List or restore compression blocks" },
|
|
543
|
-
{ value: "recompress", label: "recompress", description: "Re-apply a decompressed block" },
|
|
544
439
|
{ value: "compress", label: "compress", description: "Trigger LLM compression" },
|
|
545
440
|
{ value: "help", label: "help", description: "Show help" },
|
|
546
441
|
]
|
|
@@ -554,8 +449,12 @@ export function registerCommands(
|
|
|
554
449
|
const parts = args.trim().split(/\s+/).filter(Boolean)
|
|
555
450
|
const sub = parts[0] ?? ""
|
|
556
451
|
const effectiveConfig = resolveModelConfig(config, modelKeysFromContext(ctx))
|
|
557
|
-
|
|
558
|
-
|
|
452
|
+
const mutating = sub === "sweep" || sub === "manual" || sub === "compress"
|
|
453
|
+
if (mutating && !isSessionSupported()) {
|
|
454
|
+
ctx.ui.notify("DCP is unavailable in this session. Start a new session to use the current DCP journal format.", "error")
|
|
455
|
+
return
|
|
456
|
+
}
|
|
457
|
+
const execute = async (state: DcpState, ctx: ExtensionCommandContext): Promise<void> => {
|
|
559
458
|
switch (sub) {
|
|
560
459
|
case "":
|
|
561
460
|
case "help":
|
|
@@ -581,14 +480,6 @@ export function registerCommands(
|
|
|
581
480
|
handleManual(ctx, state, parts[1])
|
|
582
481
|
break
|
|
583
482
|
|
|
584
|
-
case "decompress":
|
|
585
|
-
handleDecompress(ctx, state, parts[1])
|
|
586
|
-
break
|
|
587
|
-
|
|
588
|
-
case "recompress":
|
|
589
|
-
handleRecompress(ctx, state, parts[1])
|
|
590
|
-
break
|
|
591
|
-
|
|
592
483
|
case "compress":
|
|
593
484
|
await handleCompress(pi, ctx)
|
|
594
485
|
break
|
|
@@ -600,6 +491,40 @@ export function registerCommands(
|
|
|
600
491
|
)
|
|
601
492
|
break
|
|
602
493
|
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
try {
|
|
497
|
+
if (["sweep", "manual"].includes(sub)) {
|
|
498
|
+
// Wait outside the commit queue: the active run may need that same
|
|
499
|
+
// queue to complete provider evidence or a compression transaction.
|
|
500
|
+
if (sub === "sweep") await ctx.waitForIdle()
|
|
501
|
+
const assertCurrent = captureDcpTransactionGuard(state, effectiveConfig, undefined, ctx)
|
|
502
|
+
const epoch = state.sessionEpoch
|
|
503
|
+
await runDcpStateTransaction(state, async () => {
|
|
504
|
+
assertCurrent()
|
|
505
|
+
const working = cloneDcpTransactionState(state)
|
|
506
|
+
const notifications: Array<Parameters<typeof ctx.ui.notify>> = []
|
|
507
|
+
const stagedContext = {
|
|
508
|
+
...ctx,
|
|
509
|
+
waitForIdle: async () => {},
|
|
510
|
+
ui: { ...ctx.ui, notify: (...args: Parameters<typeof ctx.ui.notify>) => { notifications.push(args) } },
|
|
511
|
+
} as ExtensionCommandContext
|
|
512
|
+
await execute(working, stagedContext)
|
|
513
|
+
assertCurrent()
|
|
514
|
+
let published = false
|
|
515
|
+
await persistState(ctx, working, {
|
|
516
|
+
beforePublish: assertCurrent,
|
|
517
|
+
onPublished: () => { published = true },
|
|
518
|
+
})
|
|
519
|
+
if (!published) assertCurrent()
|
|
520
|
+
if (state.sessionEpoch === epoch) {
|
|
521
|
+
Object.assign(state, working)
|
|
522
|
+
for (const notification of notifications) await staleSafe(() => ctx.ui.notify(...notification))
|
|
523
|
+
}
|
|
524
|
+
})
|
|
525
|
+
} else {
|
|
526
|
+
await execute(state, ctx)
|
|
527
|
+
}
|
|
603
528
|
} finally {
|
|
604
529
|
await staleSafe(() => {
|
|
605
530
|
hooks.onStateChanged?.(ctx)
|