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.
Files changed (113) hide show
  1. package/README.md +1 -1
  2. package/dist/app/commands/command-registry.js +2 -2
  3. package/dist/app/commands/command-session-actions.d.ts +0 -1
  4. package/dist/app/commands/command-session-actions.js +22 -13
  5. package/dist/app/icons.d.ts +14 -0
  6. package/dist/app/icons.js +33 -0
  7. package/dist/app/rendering/conversation-tool-renderer.js +2 -2
  8. package/dist/app/rendering/dcp-stats.d.ts +6 -1
  9. package/dist/app/rendering/dcp-stats.js +214 -46
  10. package/dist/app/rendering/editor-panels.js +8 -5
  11. package/dist/app/session/lazy-session-manager.js +12 -1
  12. package/dist/app/session/tabs-controller.d.ts +2 -5
  13. package/dist/app/session/tabs-controller.js +12 -21
  14. package/dist/app/subagents/subagents-model.d.ts +14 -1
  15. package/dist/app/subagents/subagents-model.js +34 -15
  16. package/dist/app/types.d.ts +2 -0
  17. package/dist/bundled-extensions/session-title/config.js +1 -1
  18. package/dist/markdown-format.js +27 -9
  19. package/dist/schemas/pi-tools-suite-schema.d.ts +29 -16
  20. package/dist/schemas/pi-tools-suite-schema.js +46 -31
  21. package/external/pi-tools-suite/README.md +392 -52
  22. package/external/pi-tools-suite/docs/browser-qa-subagent.md +31 -21
  23. package/external/pi-tools-suite/docs/context-gateway-p00-adr.md +216 -0
  24. package/external/pi-tools-suite/docs/context-gateway-p01n-gate-review.md +122 -0
  25. package/external/pi-tools-suite/docs/context-gateway-p01n-measurement.md +133 -0
  26. package/external/pi-tools-suite/docs/context-gateway-p01r-ra-evidence.md +111 -0
  27. package/external/pi-tools-suite/docs/context-gateway-p01r-rb-evidence.md +100 -0
  28. package/external/pi-tools-suite/docs/context-gateway-p01r-rc-evidence.md +69 -0
  29. package/external/pi-tools-suite/docs/context-gateway-p01r-rd-evidence.md +100 -0
  30. package/external/pi-tools-suite/docs/context-gateway-p01r-re-evidence.md +74 -0
  31. package/external/pi-tools-suite/docs/context-gateway-p01r-rf-evidence.md +153 -0
  32. package/external/pi-tools-suite/docs/context-gateway-p01r-rg-evidence.md +235 -0
  33. package/external/pi-tools-suite/docs/evals.md +684 -0
  34. package/external/pi-tools-suite/docs/subagent-model-pools.md +109 -0
  35. package/external/pi-tools-suite/package.json +10 -3
  36. package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/scripts/browser-qa-runner.mjs +82 -1
  37. package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/SKILL.md → agents/browser-qa.md} +261 -12
  38. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +20 -0
  39. package/external/pi-tools-suite/src/async-subagents/agents/oracle.md +16 -0
  40. package/external/pi-tools-suite/src/async-subagents/agents/research.md +18 -0
  41. package/external/pi-tools-suite/src/async-subagents/agents/verify.md +18 -0
  42. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +27 -243
  43. package/external/pi-tools-suite/src/async-subagents/commands.ts +6 -2
  44. package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +41 -0
  45. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +13 -93
  46. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +494 -0
  47. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +9 -0
  48. package/external/pi-tools-suite/src/async-subagents/core/config.ts +200 -143
  49. package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +1 -1
  50. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +54 -0
  51. package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +7 -6
  52. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +52 -45
  53. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +12 -4
  54. package/external/pi-tools-suite/src/async-subagents/index.ts +11 -1
  55. package/external/pi-tools-suite/src/async-subagents/lib.ts +6 -2
  56. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +46 -18
  57. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +3 -2
  58. package/external/pi-tools-suite/src/async-subagents/types.ts +2 -0
  59. package/external/pi-tools-suite/src/coding-discipline/index.ts +41 -142
  60. package/external/pi-tools-suite/src/config.ts +1 -22
  61. package/external/pi-tools-suite/src/context-gateway/accounting.ts +151 -0
  62. package/external/pi-tools-suite/src/context-gateway/config.ts +111 -0
  63. package/external/pi-tools-suite/src/context-gateway/index.ts +160 -0
  64. package/external/pi-tools-suite/src/context-gateway/metadata-normalization.ts +88 -0
  65. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +89 -0
  66. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +429 -0
  67. package/external/pi-tools-suite/src/context-gateway/test-output-parser.ts +326 -0
  68. package/external/pi-tools-suite/src/context-gateway/types.ts +152 -0
  69. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +106 -0
  70. package/external/pi-tools-suite/src/dcp/auto-compress.ts +810 -106
  71. package/external/pi-tools-suite/src/dcp/commands.ts +64 -139
  72. package/external/pi-tools-suite/src/dcp/compress-tool.ts +369 -35
  73. package/external/pi-tools-suite/src/dcp/compression-blocks.ts +510 -64
  74. package/external/pi-tools-suite/src/dcp/compression-preview.ts +113 -0
  75. package/external/pi-tools-suite/src/dcp/compression-progress.ts +70 -0
  76. package/external/pi-tools-suite/src/dcp/config.ts +36 -61
  77. package/external/pi-tools-suite/src/dcp/conversation-index.ts +421 -0
  78. package/external/pi-tools-suite/src/dcp/debug-log.ts +7 -5
  79. package/external/pi-tools-suite/src/dcp/index.ts +617 -203
  80. package/external/pi-tools-suite/src/dcp/journal.ts +566 -0
  81. package/external/pi-tools-suite/src/dcp/progress-controller.ts +244 -0
  82. package/external/pi-tools-suite/src/dcp/prompts.ts +10 -7
  83. package/external/pi-tools-suite/src/dcp/provider-tool-results.ts +189 -0
  84. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +298 -78
  85. package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +173 -281
  86. package/external/pi-tools-suite/src/dcp/pruner-emergency.ts +2 -4
  87. package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +17 -5
  88. package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +11 -1
  89. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +30 -82
  90. package/external/pi-tools-suite/src/dcp/pruner-tools.ts +22 -133
  91. package/external/pi-tools-suite/src/dcp/pruner.ts +18 -33
  92. package/external/pi-tools-suite/src/dcp/recovery.ts +129 -0
  93. package/external/pi-tools-suite/src/dcp/shadow-plan.ts +127 -0
  94. package/external/pi-tools-suite/src/dcp/state-transaction.ts +102 -0
  95. package/external/pi-tools-suite/src/dcp/state.ts +158 -580
  96. package/external/pi-tools-suite/src/dcp/ui.ts +1 -0
  97. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +55 -220
  98. package/external/pi-tools-suite/src/index.ts +9 -0
  99. package/external/pi-tools-suite/src/model-tools/index.ts +76 -42
  100. package/external/pi-tools-suite/src/repo-discovery/index.ts +84 -18
  101. package/external/pi-tools-suite/src/repo-discovery/native-compact.ts +458 -0
  102. package/external/pi-tools-suite/src/session-recovery/index.ts +189 -43
  103. package/external/pi-tools-suite/src/tool-descriptions.ts +43 -38
  104. package/external/pi-tools-suite/src/truncation-metadata-normalizer/index.ts +17 -0
  105. package/package.json +6 -6
  106. package/schemas/pi-tools-suite.json +159 -78
  107. package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/auth-scaffold-spec.md +0 -78
  108. package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +0 -223
  109. package/external/pi-tools-suite/src/dcp/state-persistence.ts +0 -195
  110. /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-auth.example.jsonc +0 -0
  111. /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-flow.example.jsonc +0 -0
  112. /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.LICENSE +0 -0
  113. /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.deduplication.protectedTools,
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
- try {
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)