one-code-extension 0.3.1 → 0.4.0

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 +88 -10
  2. package/docs/guide/README.md +1 -0
  3. package/docs/guide/configuration.md +2 -2
  4. package/docs/guide/differences-from-claude-code.md +13 -4
  5. package/docs/guide/hooks.md +14 -2
  6. package/docs/guide/installation.md +54 -6
  7. package/docs/guide/permissions-modes-and-auto-mode.md +23 -7
  8. package/docs/guide/reference.md +5 -2
  9. package/docs/guide/sessions-and-context.md +18 -0
  10. package/docs/guide/terminal-interface.md +1 -1
  11. package/docs/guide/tools.md +24 -2
  12. package/docs/guide/troubleshooting.md +14 -4
  13. package/docs/guide/windows.md +184 -0
  14. package/extensions/auto-mode/actions.ts +3 -1
  15. package/extensions/auto-mode/paths.ts +21 -23
  16. package/extensions/auto-mode/safety-floor.ts +44 -6
  17. package/extensions/auto-mode/shell-analysis.ts +25 -10
  18. package/extensions/auto-mode/transcript.ts +15 -5
  19. package/extensions/background/index.ts +83 -34
  20. package/extensions/background/monitor-batch.ts +7 -5
  21. package/extensions/background/wakeup.ts +18 -24
  22. package/extensions/bash/background.ts +19 -10
  23. package/extensions/bash/guards.ts +36 -16
  24. package/extensions/bash/index.ts +36 -166
  25. package/extensions/branding/index.ts +35 -4
  26. package/extensions/btw/index.ts +207 -0
  27. package/extensions/btw/panel.ts +179 -0
  28. package/extensions/btw/prompt.ts +45 -0
  29. package/extensions/clear/index.ts +15 -0
  30. package/extensions/compaction/fit.ts +9 -6
  31. package/extensions/doctor/build.ts +22 -2
  32. package/extensions/doctor/dependencies.ts +63 -31
  33. package/extensions/doctor/fix-prompt.ts +12 -4
  34. package/extensions/doctor/index.ts +1 -0
  35. package/extensions/doctor/models.ts +2 -1
  36. package/extensions/doctor/report.ts +2 -3
  37. package/extensions/doctor/update-lookup.ts +19 -11
  38. package/extensions/effort/index.ts +2 -1
  39. package/extensions/footer/footer-line.ts +19 -0
  40. package/extensions/footer/index.ts +25 -5
  41. package/extensions/hooks/executor.ts +84 -18
  42. package/extensions/hooks/index.ts +1 -0
  43. package/extensions/hooks/matcher.ts +23 -9
  44. package/extensions/hooks/settings.ts +15 -0
  45. package/extensions/lib/branch-restore.ts +12 -0
  46. package/extensions/lib/claude-context.ts +2 -3
  47. package/extensions/lib/claude-settings.ts +19 -0
  48. package/extensions/lib/command-launch.ts +71 -0
  49. package/extensions/lib/deferred.ts +173 -33
  50. package/extensions/lib/git.ts +16 -0
  51. package/extensions/lib/keys.ts +38 -0
  52. package/extensions/lib/local-command.ts +112 -0
  53. package/extensions/lib/model-facts.generated.json +263 -68
  54. package/extensions/lib/model-policy.ts +13 -0
  55. package/extensions/lib/model-tier.ts +16 -5
  56. package/extensions/lib/notifications.ts +547 -53
  57. package/extensions/lib/paths.ts +130 -2
  58. package/extensions/lib/pi-ai-estimate.ts +57 -26
  59. package/extensions/lib/pi-version.ts +1 -1
  60. package/extensions/lib/process-tree.ts +131 -5
  61. package/extensions/lib/reminders.ts +80 -27
  62. package/extensions/lib/scratchpad.ts +11 -10
  63. package/extensions/lib/shell-spawn.ts +298 -0
  64. package/extensions/lib/shell-tool.ts +252 -0
  65. package/extensions/lib/shell-tools.ts +13 -0
  66. package/extensions/lib/side-call.ts +76 -0
  67. package/extensions/lib/tui-render.ts +62 -11
  68. package/extensions/lib/update-check.mjs +155 -0
  69. package/extensions/lib/usage-bus.ts +1 -1
  70. package/extensions/lib/which.ts +62 -0
  71. package/extensions/lib/worktree-channel.ts +18 -0
  72. package/extensions/lib/worktree-isolation.ts +2 -1
  73. package/extensions/lsp/client.ts +14 -3
  74. package/extensions/lsp/index.ts +12 -5
  75. package/extensions/lsp/install-hints.ts +33 -3
  76. package/extensions/lsp/plugin-servers.ts +2 -2
  77. package/extensions/lsp/servers.ts +29 -7
  78. package/extensions/mcp/index.ts +3 -2
  79. package/extensions/memory/entries.ts +9 -6
  80. package/extensions/memory/index.ts +3 -2
  81. package/extensions/memory/open-external.ts +4 -1
  82. package/extensions/model-default/index.ts +21 -2
  83. package/extensions/permissions/index.ts +57 -28
  84. package/extensions/permissions/matcher.ts +120 -33
  85. package/extensions/permissions/modes.ts +14 -6
  86. package/extensions/permissions/powershell-rules.ts +549 -0
  87. package/extensions/permissions/session-grant.ts +9 -9
  88. package/extensions/plugins/index.ts +3 -2
  89. package/extensions/plugins/install/install.ts +1 -1
  90. package/extensions/powershell/description.ts +139 -0
  91. package/extensions/powershell/guards.ts +91 -0
  92. package/extensions/powershell/index.ts +89 -0
  93. package/extensions/powershell/policy.ts +91 -0
  94. package/extensions/recap/index.ts +10 -24
  95. package/extensions/recap/prompt.ts +3 -3
  96. package/extensions/session-title/index.ts +120 -0
  97. package/extensions/session-title/title.ts +111 -0
  98. package/extensions/skill/index.ts +40 -18
  99. package/extensions/skill/invoke.ts +1 -0
  100. package/extensions/subagents/hand-back-review.ts +10 -12
  101. package/extensions/subagents/index.ts +221 -78
  102. package/extensions/subagents/model-select.ts +75 -7
  103. package/extensions/system-prompt/environment.ts +14 -1
  104. package/extensions/system-reminder/index.ts +9 -0
  105. package/extensions/tasks/index.ts +2 -1
  106. package/extensions/tool-search/index.ts +41 -20
  107. package/extensions/workflow/agent-session.ts +6 -4
  108. package/extensions/workflow/index.ts +28 -5
  109. package/extensions/worktree/guards.ts +5 -4
  110. package/extensions/worktree/index.ts +15 -2
  111. package/extensions/worktree/rewrite.ts +17 -0
  112. package/package.json +7 -4
  113. package/types/app.d.ts +18 -2
@@ -11,6 +11,19 @@ export function isClaudeFamilyModel(model: { provider: string; id: string }): bo
11
11
  return model.provider === "anthropic" || /claude/i.test(model.id);
12
12
  }
13
13
 
14
+ /**
15
+ * Whether a model accepts image input, from pi's catalog `input` modality
16
+ * (`("text" | "image")[]`). PDFs count as image input too: pi's Read tool renders
17
+ * PDF pages visually, so a model that cannot take images cannot read a PDF a
18
+ * subagent opens either. A model whose modality is unknown (undefined `input`, as
19
+ * on some opaque/self-hosted providers, or a minimal test stub, or no model at all) reads as
20
+ * text-only here — the safe direction for a gate that only ever ADDS a
21
+ * requirement, never relaxes one. See `docs/decisions/model-policy.md`.
22
+ */
23
+ export function supportsImageInput(model: { input?: readonly string[] } | undefined): boolean {
24
+ return Array.isArray(model?.input) && model.input.includes("image");
25
+ }
26
+
14
27
  export type ProviderPolicyKind = "direct" | "hosted" | "gateway" | "opaque";
15
28
 
16
29
  export interface ProviderPolicy {
@@ -40,7 +40,7 @@ import {
40
40
  scoreFor,
41
41
  } from "./capability-index.ts";
42
42
  import { isPriorGeneration, lacksToolCalls, modelGeneration } from "./model-facts.ts";
43
- import { baseModelId, isDatedDuplicate, modelIdentity, modelsContainedToSession, modelSpec, pricedInput } from "./model-policy.ts";
43
+ import { baseModelId, isDatedDuplicate, modelIdentity, modelsContainedToSession, modelSpec, pricedInput, supportsImageInput } from "./model-policy.ts";
44
44
  import { oneCodeStateDir } from "./paths.ts";
45
45
 
46
46
  export type PromptTier = "frontier" | "workhorse" | "cheap" | "tiny";
@@ -340,14 +340,25 @@ export function resolveModelTier(model: Model<Api> | undefined, env: NodeJS.Proc
340
340
  * drops it. Budget ceilings and strictly-cheaper-than-session are caller policy —
341
341
  * this function ranks, it does not gate. A caller that already computed the
342
342
  * containment set may pass it as `contained` to skip the O(catalog) recompute.
343
+ *
344
+ * `requireImageInput` (default false) drops every candidate that cannot take
345
+ * image input — the modality gate a subagent selection sets when the session
346
+ * model is image-capable, so a delegated worker can still read an image or PDF
347
+ * the session may feed it. The classifier and the readers leave it false: the
348
+ * classifier renders the transcript to text and the readers strip images, so
349
+ * neither ever sends one. See `docs/decisions/model-policy.md`.
343
350
  */
344
351
  export function economicalContainedCandidates(
345
352
  available: Model<Api>[],
346
353
  sessionModel: Model<Api>,
347
354
  contained?: Model<Api>[],
355
+ requireImageInput = false,
348
356
  ): Model<Api>[] {
349
357
  const pool = contained ?? modelsContainedToSession(available, sessionModel);
350
358
  return pool
359
+ // Modality gate: when the session works with images/PDFs a subagent may
360
+ // need to read, a text-only worker cannot serve — drop it before ranking.
361
+ .filter((model) => !requireImageInput || supportsImageInput(model))
351
362
  // A dated snapshot whose undated alias is also listed is the same model
352
363
  // twice; rank the alias so every automatic pick (classifier, subagent,
353
364
  // reader, presets) names the model the way the user sees it in /model.
@@ -394,11 +405,11 @@ export function atLeastTier(tier: PromptTier, floor: PromptTier): boolean {
394
405
  export function cheaperContainedCandidates(
395
406
  available: Model<Api>[],
396
407
  sessionModel: Model<Api>,
397
- opts: { strict?: boolean; contained?: Model<Api>[]; role?: FloorRole } = {},
408
+ opts: { strict?: boolean; contained?: Model<Api>[]; role?: FloorRole; requireImageInput?: boolean } = {},
398
409
  ): Model<Api>[] {
399
410
  const sessionSpec = modelSpec(sessionModel);
400
411
  const sessionPrice = pricedInput(sessionModel);
401
- const cheaper = economicalContainedCandidates(available, sessionModel, opts.contained).filter((model) => {
412
+ const cheaper = economicalContainedCandidates(available, sessionModel, opts.contained, opts.requireImageInput).filter((model) => {
402
413
  if (modelSpec(model) === sessionSpec) return false;
403
414
  if (sessionPrice === undefined) return !opts.strict;
404
415
  const price = pricedInput(model);
@@ -435,7 +446,7 @@ export function capableContainedCandidates(
435
446
  available: Model<Api>[],
436
447
  sessionModel: Model<Api>,
437
448
  role: FloorRole,
438
- opts: { strict?: boolean; contained?: Model<Api>[] } = {},
449
+ opts: { strict?: boolean; contained?: Model<Api>[]; requireImageInput?: boolean } = {},
439
450
  ): Model<Api>[] {
440
451
  const floor = automaticTierFloor(sessionModel);
441
452
  return rankedContainedCandidates(available, sessionModel, role, opts)
@@ -458,7 +469,7 @@ function rankedContainedCandidates(
458
469
  available: Model<Api>[],
459
470
  sessionModel: Model<Api>,
460
471
  role: FloorRole,
461
- opts: { strict?: boolean; contained?: Model<Api>[] } = {},
472
+ opts: { strict?: boolean; contained?: Model<Api>[]; requireImageInput?: boolean } = {},
462
473
  ): RankedCandidate[] {
463
474
  return rankByCapability(cheaperContainedCandidates(available, sessionModel, opts), sessionModel, role);
464
475
  }