one-code-extension 0.4.1 → 0.5.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 (419) hide show
  1. package/README.md +16 -5
  2. package/agents/general-purpose.md +2 -2
  3. package/docs/guide/README.md +2 -1
  4. package/docs/guide/bring-your-claude-code-setup.md +60 -9
  5. package/docs/guide/configuration.md +48 -14
  6. package/docs/guide/differences-from-claude-code.md +32 -23
  7. package/docs/guide/doctor.md +20 -13
  8. package/docs/guide/hooks.md +18 -3
  9. package/docs/guide/installation.md +27 -4
  10. package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
  11. package/docs/guide/providers-and-models.md +137 -54
  12. package/docs/guide/reference.md +27 -15
  13. package/docs/guide/sessions-and-context.md +69 -16
  14. package/docs/guide/skills-plugins-and-mcp.md +57 -20
  15. package/docs/guide/subagents-and-workflows.md +95 -29
  16. package/docs/guide/tasks-and-background-work.md +101 -26
  17. package/docs/guide/terminal-interface.md +24 -12
  18. package/docs/guide/tools.md +46 -5
  19. package/docs/guide/troubleshooting.md +13 -9
  20. package/docs/guide/windows.md +58 -31
  21. package/extensions/artifacts/gallery.ts +227 -0
  22. package/extensions/artifacts/index.ts +288 -0
  23. package/extensions/artifacts/store.ts +570 -0
  24. package/extensions/artifacts/viewer.ts +199 -0
  25. package/extensions/ask-user/description.ts +67 -0
  26. package/extensions/ask-user/dialogs.ts +80 -0
  27. package/extensions/ask-user/index.ts +37 -33
  28. package/extensions/ask-user/questions.ts +32 -7
  29. package/extensions/ask-user/widget.ts +45 -25
  30. package/extensions/auto-mode/actions.ts +6 -0
  31. package/extensions/auto-mode/cache.ts +88 -0
  32. package/extensions/auto-mode/classifier-prompt.ts +5 -4
  33. package/extensions/auto-mode/classifier.ts +290 -65
  34. package/extensions/auto-mode/config.ts +72 -20
  35. package/extensions/auto-mode/decision-log.ts +2 -0
  36. package/extensions/auto-mode/defaults.ts +1 -1
  37. package/extensions/auto-mode/denials.ts +123 -0
  38. package/extensions/auto-mode/git-checkout-programs.ts +187 -0
  39. package/extensions/auto-mode/git-status-meta.ts +159 -0
  40. package/extensions/auto-mode/history.ts +189 -0
  41. package/extensions/auto-mode/instructions.ts +58 -52
  42. package/extensions/auto-mode/model-select.ts +159 -134
  43. package/extensions/auto-mode/paths.ts +57 -5
  44. package/extensions/auto-mode/pause.ts +57 -2
  45. package/extensions/auto-mode/prompt.ts +37 -21
  46. package/extensions/auto-mode/read-only-options.ts +724 -0
  47. package/extensions/auto-mode/resolved-paths-meta.ts +133 -0
  48. package/extensions/auto-mode/rules.ts +18 -1
  49. package/extensions/auto-mode/safety-floor.ts +361 -18
  50. package/extensions/auto-mode/setup-run.ts +20 -14
  51. package/extensions/auto-mode/shell-analysis.ts +764 -490
  52. package/extensions/auto-mode/shell-parse.ts +885 -0
  53. package/extensions/auto-mode/system-note.ts +33 -0
  54. package/extensions/auto-mode/transcript.ts +80 -51
  55. package/extensions/background/cron.ts +515 -0
  56. package/extensions/background/index.ts +514 -236
  57. package/extensions/background/loop-fire.ts +136 -0
  58. package/extensions/background/loop-preamble.ts +59 -0
  59. package/extensions/background/loop-skill.ts +163 -0
  60. package/extensions/background/monitor-batch.ts +53 -0
  61. package/extensions/background/noop-fold.ts +128 -0
  62. package/extensions/background/switch-guard.ts +52 -0
  63. package/extensions/background/wakeup.ts +159 -55
  64. package/extensions/bash/background.ts +53 -17
  65. package/extensions/bash/child.ts +7 -0
  66. package/extensions/bash/description.ts +188 -0
  67. package/extensions/bash/guards.ts +15 -67
  68. package/extensions/bash/index.ts +88 -35
  69. package/extensions/branding/compaction-keep.ts +63 -0
  70. package/extensions/branding/declined.ts +22 -0
  71. package/extensions/branding/index.ts +133 -9
  72. package/extensions/branding/prompt-editor.ts +53 -6
  73. package/extensions/branding/queued-edit.ts +31 -0
  74. package/extensions/branding/replaced-builtins.ts +68 -0
  75. package/extensions/branding/startup.ts +33 -71
  76. package/extensions/btw/index.ts +229 -71
  77. package/extensions/btw/panel.ts +228 -100
  78. package/extensions/btw/prompt.ts +41 -4
  79. package/extensions/claude-compat/index.ts +7 -11
  80. package/extensions/claude-context/index.ts +446 -58
  81. package/extensions/compaction/cut.ts +157 -0
  82. package/extensions/compaction/index.ts +216 -75
  83. package/extensions/compaction/kept-thinking.ts +62 -0
  84. package/extensions/compaction/prompt.ts +15 -12
  85. package/extensions/context-budget/index.ts +24 -5
  86. package/extensions/context-management/index.ts +25 -0
  87. package/extensions/doctor/build.ts +59 -8
  88. package/extensions/doctor/builtins.ts +84 -0
  89. package/extensions/doctor/cli.ts +7 -1
  90. package/extensions/doctor/compat.ts +88 -23
  91. package/extensions/doctor/dependencies.ts +41 -5
  92. package/extensions/doctor/fix-prompt.ts +9 -2
  93. package/extensions/doctor/index.ts +102 -58
  94. package/extensions/doctor/models.ts +102 -63
  95. package/extensions/doctor/presets.ts +42 -27
  96. package/extensions/doctor/report.ts +19 -2
  97. package/extensions/doctor/viewer.ts +49 -27
  98. package/extensions/effort/index.ts +72 -19
  99. package/extensions/effort/settings.ts +21 -0
  100. package/extensions/effort/slider.ts +24 -20
  101. package/extensions/exit/index.ts +32 -1
  102. package/extensions/file-tracker/index.ts +337 -26
  103. package/extensions/file-tracker/replay.ts +96 -10
  104. package/extensions/file-tracker/restore.ts +63 -0
  105. package/extensions/file-tracker/results.ts +66 -0
  106. package/extensions/file-tracker/shell-reads.ts +211 -0
  107. package/extensions/file-tracker/tracker.ts +32 -15
  108. package/extensions/footer/footer-line.ts +45 -24
  109. package/extensions/footer/index.ts +47 -2
  110. package/extensions/footer/pr.ts +34 -5
  111. package/extensions/hooks/compaction.ts +7 -0
  112. package/extensions/hooks/executor.ts +32 -30
  113. package/extensions/hooks/index.ts +198 -31
  114. package/extensions/hooks/matcher.ts +3 -0
  115. package/extensions/hooks/protocol.ts +41 -3
  116. package/extensions/hooks/settings.ts +50 -19
  117. package/extensions/hooks/subagent-bridge.ts +2 -0
  118. package/extensions/hooks/trust.ts +13 -5
  119. package/extensions/idle-compact/index.ts +119 -0
  120. package/extensions/idle-compact/policy.ts +143 -0
  121. package/extensions/init/index.ts +11 -10
  122. package/extensions/init/prompt.ts +25 -32
  123. package/extensions/interrupted/index.ts +13 -1
  124. package/extensions/kept-thinking/index.ts +27 -0
  125. package/extensions/lib/agent-cron.ts +130 -0
  126. package/extensions/lib/agent-loader.ts +15 -1
  127. package/extensions/lib/agent-view.ts +85 -0
  128. package/extensions/lib/anthropic-payload.ts +82 -1
  129. package/extensions/lib/anthropic-server-call.ts +230 -0
  130. package/extensions/lib/anthropic-server-tools.ts +485 -0
  131. package/extensions/lib/app-launch.mjs +94 -0
  132. package/extensions/lib/argument-hints.ts +190 -0
  133. package/extensions/lib/atomic-write.ts +6 -2
  134. package/extensions/lib/auto-memory.ts +75 -0
  135. package/extensions/lib/bash-parser.ts +84 -0
  136. package/extensions/lib/btw-fork.ts +93 -0
  137. package/extensions/lib/child-extensions.ts +42 -0
  138. package/extensions/lib/child-writes.ts +45 -0
  139. package/extensions/lib/claude-context.ts +515 -100
  140. package/extensions/lib/claude-external-includes.ts +68 -0
  141. package/extensions/lib/claude-id.ts +22 -0
  142. package/extensions/lib/claude-rules.ts +323 -0
  143. package/extensions/lib/claude-settings.ts +76 -4
  144. package/extensions/lib/compaction-boundary.ts +36 -0
  145. package/extensions/lib/compaction-keep.mjs +83 -0
  146. package/extensions/lib/config-mode.ts +112 -0
  147. package/extensions/lib/consent-dialogs.ts +63 -0
  148. package/extensions/lib/consent-preview.ts +5 -1
  149. package/extensions/lib/consent-stores.ts +48 -0
  150. package/extensions/lib/context-facts.ts +78 -0
  151. package/extensions/lib/context-stack.ts +81 -0
  152. package/extensions/lib/deferred.ts +219 -25
  153. package/extensions/lib/dock-rows.ts +60 -0
  154. package/extensions/lib/empty-tool-result.ts +27 -0
  155. package/extensions/lib/environment-block.ts +76 -0
  156. package/extensions/lib/fetch-timeout.ts +24 -6
  157. package/extensions/{system-prompt → lib}/git-status.ts +51 -13
  158. package/extensions/lib/git.ts +75 -13
  159. package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
  160. package/extensions/lib/grammars/README.md +2 -0
  161. package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
  162. package/extensions/lib/guide-docs.ts +45 -0
  163. package/extensions/lib/headless-output.ts +46 -0
  164. package/extensions/lib/hook-gate.ts +7 -7
  165. package/extensions/lib/interrupt.ts +20 -4
  166. package/extensions/lib/key-input.ts +455 -0
  167. package/extensions/lib/keys.ts +14 -1
  168. package/extensions/lib/local-command.ts +47 -13
  169. package/extensions/lib/mcp-overrides.ts +1 -1
  170. package/extensions/lib/mcp-share.ts +46 -0
  171. package/extensions/lib/memory-content.ts +146 -0
  172. package/extensions/lib/memory-index.ts +18 -0
  173. package/extensions/lib/memory.ts +134 -123
  174. package/extensions/lib/model-catalog/huggingface.json +174 -0
  175. package/extensions/lib/model-catalog/models-dev.json +18297 -0
  176. package/extensions/lib/model-catalog/openrouter.json +5252 -0
  177. package/extensions/lib/model-catalog-data.ts +513 -0
  178. package/extensions/lib/model-catalog.ts +462 -0
  179. package/extensions/lib/model-choice-warnings.ts +137 -0
  180. package/extensions/lib/model-pairings.ts +152 -0
  181. package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
  182. package/extensions/lib/model-policy.ts +112 -15
  183. package/extensions/lib/model-tier.ts +283 -355
  184. package/extensions/lib/model-unusable.ts +1 -1
  185. package/extensions/lib/newer-model.ts +100 -0
  186. package/extensions/lib/notices.ts +87 -0
  187. package/extensions/lib/notifications.ts +308 -64
  188. package/extensions/lib/one-code-settings.ts +74 -8
  189. package/extensions/lib/open-browser.ts +63 -0
  190. package/extensions/lib/openrouter-generation.ts +94 -0
  191. package/extensions/lib/operation-deadline.ts +30 -0
  192. package/extensions/lib/original-command.ts +4 -4
  193. package/extensions/lib/package-version.ts +1 -1
  194. package/extensions/lib/panel-focus.ts +134 -0
  195. package/extensions/lib/paths.ts +17 -2
  196. package/extensions/lib/permission-gate.ts +72 -6
  197. package/extensions/lib/persisted-output.ts +60 -8
  198. package/extensions/lib/pi-ai-estimate.ts +19 -3
  199. package/extensions/lib/pi-version.ts +21 -2
  200. package/extensions/lib/plan-mode-channels.ts +20 -5
  201. package/extensions/lib/plugins.ts +26 -17
  202. package/extensions/lib/powershell-parse-script.ts +208 -0
  203. package/extensions/lib/powershell-parser.ts +344 -0
  204. package/extensions/lib/process-tree.ts +131 -8
  205. package/extensions/lib/prompt-options.ts +82 -0
  206. package/extensions/lib/queued-delivery.ts +44 -0
  207. package/extensions/lib/reminders.ts +364 -58
  208. package/extensions/lib/replaced-builtins.mjs +199 -0
  209. package/extensions/lib/replay-call.ts +70 -0
  210. package/extensions/lib/request-replay.ts +439 -0
  211. package/extensions/lib/scratchpad.ts +81 -14
  212. package/extensions/lib/send-now-channel.ts +7 -0
  213. package/extensions/lib/session-model-tier.ts +51 -0
  214. package/extensions/lib/session-work.ts +64 -0
  215. package/extensions/lib/settings-channels.ts +4 -4
  216. package/extensions/lib/shell-exit-semantics.ts +170 -0
  217. package/extensions/lib/shell-quote.ts +11 -0
  218. package/extensions/lib/shell-result.ts +70 -0
  219. package/extensions/lib/shell-spawn.ts +70 -6
  220. package/extensions/lib/shell-tool.ts +75 -25
  221. package/extensions/lib/side-call-cache.ts +124 -0
  222. package/extensions/lib/side-call-run.ts +96 -0
  223. package/extensions/lib/side-call-usage.ts +38 -0
  224. package/extensions/lib/side-call.ts +13 -1
  225. package/extensions/lib/single-flight.ts +18 -0
  226. package/extensions/lib/skill-body.ts +42 -0
  227. package/extensions/lib/skill-scan.ts +63 -24
  228. package/extensions/lib/spill-file.ts +140 -0
  229. package/extensions/lib/subagent-handback.ts +113 -0
  230. package/extensions/lib/system-role.ts +156 -0
  231. package/extensions/lib/terminal-text.ts +114 -0
  232. package/extensions/lib/text-width.ts +47 -16
  233. package/extensions/lib/timer-ops.ts +20 -0
  234. package/extensions/lib/tool-additions.ts +149 -0
  235. package/extensions/lib/tool-call-corruption.ts +134 -0
  236. package/extensions/lib/tool-path.ts +66 -0
  237. package/extensions/lib/tool-variants.ts +69 -0
  238. package/extensions/lib/tui-render.ts +255 -27
  239. package/extensions/lib/turn-budget-layout.ts +143 -0
  240. package/extensions/lib/update-check.mjs +15 -2
  241. package/extensions/lib/usage-bus.ts +1 -1
  242. package/extensions/lib/user-denial.ts +38 -0
  243. package/extensions/lib/workspace-channel.ts +16 -0
  244. package/extensions/lib/worktree-channel.ts +31 -3
  245. package/extensions/lib/worktree-isolation.ts +40 -10
  246. package/extensions/lsp/client.ts +8 -9
  247. package/extensions/lsp/index.ts +70 -4
  248. package/extensions/lsp/keep-alive.ts +1 -1
  249. package/extensions/lsp/trust.ts +119 -0
  250. package/extensions/lsp/watcher.ts +1 -1
  251. package/extensions/mcp/announce.ts +87 -5
  252. package/extensions/mcp/client.ts +161 -48
  253. package/extensions/mcp/config.ts +132 -8
  254. package/extensions/mcp/discovery.ts +19 -0
  255. package/extensions/mcp/index.ts +209 -71
  256. package/extensions/mcp/oauth/browser.ts +38 -17
  257. package/extensions/mcp/oauth/flow.ts +25 -17
  258. package/extensions/mcp/oauth/provider.ts +14 -8
  259. package/extensions/mcp/oauth/store.ts +34 -16
  260. package/extensions/mcp/panel/keys.ts +12 -11
  261. package/extensions/mcp/panel/render.ts +9 -6
  262. package/extensions/mcp/schema.ts +104 -5
  263. package/extensions/mcp/trust.ts +151 -67
  264. package/extensions/memory/entries.ts +23 -14
  265. package/extensions/memory/index.ts +134 -28
  266. package/extensions/memory/open-external.ts +33 -18
  267. package/extensions/memory/panel.ts +135 -26
  268. package/extensions/newer-model/index.ts +31 -0
  269. package/extensions/notebook/description.ts +18 -0
  270. package/extensions/notebook/index.ts +6 -5
  271. package/extensions/notebook/notebook.ts +1 -1
  272. package/extensions/permissions/index.ts +1300 -381
  273. package/extensions/permissions/matcher.ts +425 -74
  274. package/extensions/permissions/modes.ts +6 -4
  275. package/extensions/permissions/panel/host.ts +130 -0
  276. package/extensions/permissions/panel/keys.ts +48 -0
  277. package/extensions/permissions/panel/render.ts +450 -0
  278. package/extensions/permissions/panel/state.ts +550 -0
  279. package/extensions/permissions/powershell-cmdlets.ts +198 -0
  280. package/extensions/permissions/powershell-paths.ts +197 -0
  281. package/extensions/permissions/powershell-rules.ts +207 -280
  282. package/extensions/permissions/powershell-tree.ts +557 -0
  283. package/extensions/permissions/project-trust.ts +27 -11
  284. package/extensions/permissions/protected-paths.ts +14 -2
  285. package/extensions/permissions/session-grant.ts +6 -0
  286. package/extensions/permissions/settings.ts +166 -31
  287. package/extensions/permissions/subagent-gate.ts +25 -0
  288. package/extensions/permissions/workspace.ts +78 -0
  289. package/extensions/plan-mode/index.ts +156 -69
  290. package/extensions/plan-mode/reminder.ts +89 -21
  291. package/extensions/plan-mode/texts.ts +177 -0
  292. package/extensions/plan-mode/viewer.ts +92 -27
  293. package/extensions/plugins/counts.ts +3 -3
  294. package/extensions/plugins/index.ts +61 -46
  295. package/extensions/plugins/install/install.ts +16 -0
  296. package/extensions/plugins/marketplace/sync.ts +9 -3
  297. package/extensions/plugins/marketplace/types.ts +3 -1
  298. package/extensions/plugins/panel/keys.ts +21 -24
  299. package/extensions/plugins/panel/render.ts +12 -6
  300. package/extensions/plugins/shell-expand.ts +107 -0
  301. package/extensions/plugins/template.ts +32 -15
  302. package/extensions/powershell/child.ts +7 -0
  303. package/extensions/powershell/description.ts +38 -6
  304. package/extensions/powershell/guards.ts +1 -1
  305. package/extensions/powershell/index.ts +12 -7
  306. package/extensions/recap/index.ts +65 -60
  307. package/extensions/recap/prompt.ts +2 -2
  308. package/extensions/recap/scheduler.ts +3 -5
  309. package/extensions/search-tools/grep-merge.ts +39 -0
  310. package/extensions/search-tools/index.ts +0 -0
  311. package/extensions/send-now/chord.ts +62 -0
  312. package/extensions/send-now/index.ts +133 -0
  313. package/extensions/session-title/index.ts +3 -0
  314. package/extensions/session-title/title.ts +4 -1
  315. package/extensions/skill/code-review.ts +97 -0
  316. package/extensions/skill/index.ts +421 -101
  317. package/extensions/skill/invoke.ts +128 -18
  318. package/extensions/skill/listing.ts +133 -9
  319. package/extensions/skill/panel/keys.ts +15 -16
  320. package/extensions/skill/panel/render.ts +5 -2
  321. package/extensions/skill/panel/state.ts +12 -1
  322. package/extensions/subagents/agent-args.ts +39 -0
  323. package/extensions/subagents/agent-description.ts +132 -0
  324. package/extensions/subagents/agents.ts +116 -23
  325. package/extensions/subagents/announce.ts +69 -0
  326. package/extensions/subagents/default-model.ts +2 -3
  327. package/extensions/subagents/delegation-steer.ts +4 -4
  328. package/extensions/subagents/fork-cache.ts +76 -0
  329. package/extensions/subagents/guide-agent.ts +189 -0
  330. package/extensions/subagents/hand-back-review.ts +3 -0
  331. package/extensions/subagents/index.ts +1493 -824
  332. package/extensions/subagents/live-runs.ts +26 -6
  333. package/extensions/subagents/model-select.ts +38 -25
  334. package/extensions/subagents/outcome.ts +2 -2
  335. package/extensions/subagents/panel-keys.ts +73 -31
  336. package/extensions/subagents/panel-render.ts +120 -96
  337. package/extensions/subagents/panel-widget.ts +60 -89
  338. package/extensions/subagents/runner.ts +108 -80
  339. package/extensions/subagents/runs.ts +39 -5
  340. package/extensions/subagents/send-to-main-tool.ts +1 -1
  341. package/extensions/subagents/session-turns.ts +32 -8
  342. package/extensions/subagents/shell-panel.ts +36 -178
  343. package/extensions/subagents/tasks-dialog.ts +170 -0
  344. package/extensions/subagents/viewport-mirror.ts +95 -0
  345. package/extensions/subagents/worktree.ts +57 -13
  346. package/extensions/system-prompt/environment.ts +19 -19
  347. package/extensions/system-prompt/idle-turn.ts +65 -0
  348. package/extensions/system-prompt/index.ts +131 -47
  349. package/extensions/system-prompt/template.ts +24 -50
  350. package/extensions/system-prompt/tiers/common.ts +23 -64
  351. package/extensions/system-prompt/tiers/frontier.ts +32 -11
  352. package/extensions/system-prompt/tiers/low.ts +67 -45
  353. package/extensions/system-prompt/tiers/mid.ts +96 -38
  354. package/extensions/system-reminder/index.ts +175 -13
  355. package/extensions/tasks/descriptions.ts +190 -0
  356. package/extensions/tasks/index.ts +120 -41
  357. package/extensions/tasks/store.ts +83 -16
  358. package/extensions/tool-call-corruption/child.ts +7 -0
  359. package/extensions/tool-call-corruption/index.ts +237 -0
  360. package/extensions/tool-search/announce.ts +16 -0
  361. package/extensions/tool-search/index.ts +189 -41
  362. package/extensions/tool-style/index.ts +68 -10
  363. package/extensions/tool-style/write-description.ts +40 -0
  364. package/extensions/tool-style/write-render.ts +237 -0
  365. package/extensions/turn-duration/index.ts +7 -3
  366. package/extensions/turn-duration/line.ts +47 -4
  367. package/extensions/web/backends.ts +6 -9
  368. package/extensions/web/description.ts +50 -0
  369. package/extensions/web/index.ts +118 -53
  370. package/extensions/web/native-call.ts +15 -0
  371. package/extensions/web/native-results.ts +41 -0
  372. package/extensions/web-fetch/description.ts +42 -0
  373. package/extensions/web-fetch/extract.ts +53 -6
  374. package/extensions/web-fetch/index.ts +125 -76
  375. package/extensions/web-fetch/page-content.ts +19 -0
  376. package/extensions/web-fetch/response.ts +49 -0
  377. package/extensions/web-fetch/summarize.ts +9 -10
  378. package/extensions/workflow/agent-session.ts +105 -18
  379. package/extensions/workflow/args.ts +24 -0
  380. package/extensions/workflow/description.ts +67 -0
  381. package/extensions/workflow/globals.ts +17 -3
  382. package/extensions/workflow/index.ts +145 -162
  383. package/extensions/workflow/records.ts +1 -0
  384. package/extensions/workflow/run-manager.ts +29 -6
  385. package/extensions/workflow/saved-workflows.ts +3 -2
  386. package/extensions/workflow/types.ts +22 -1
  387. package/extensions/workflow/viewer.ts +54 -24
  388. package/extensions/workflow/widget.ts +20 -0
  389. package/extensions/worktree/descriptions.ts +91 -0
  390. package/extensions/worktree/guards.ts +316 -54
  391. package/extensions/worktree/index.ts +121 -39
  392. package/extensions/worktree/powershell-guards.ts +167 -0
  393. package/extensions/worktree/rewrite.ts +14 -16
  394. package/package.json +18 -7
  395. package/skills/artifact-design/SKILL.md +85 -0
  396. package/skills/code-review/SKILL.md +20 -20
  397. package/skills/code-review/cells/arguments-and-flags.md +19 -0
  398. package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
  399. package/skills/code-review/cells/high-8-inline.md +122 -0
  400. package/skills/code-review/cells/low-1-pass-max4.md +27 -0
  401. package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
  402. package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
  403. package/skills/code-review/cells/medium-3x5-verify.md +132 -0
  404. package/skills/code-review/cells/minimal-prompt.md +32 -0
  405. package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
  406. package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
  407. package/skills/fewer-permission-prompts/SKILL.md +1 -1
  408. package/skills/loop/SKILL.md +11 -0
  409. package/skills/security-review/SKILL.md +2 -5
  410. package/skills/simplify/SKILL.md +7 -5
  411. package/skills/workflow-authoring/SKILL.md +143 -0
  412. package/themes/onecode-light.json +1 -1
  413. package/themes/onecode.json +1 -1
  414. package/types/app.d.ts +58 -0
  415. package/types/community-packages.d.ts +26 -1
  416. package/extensions/auto-mode/recoverability.ts +0 -229
  417. package/extensions/lib/capability-index.ts +0 -466
  418. package/extensions/lib/model-facts.generated.json +0 -2675
  419. package/extensions/lib/model-facts.ts +0 -162
@@ -12,25 +12,48 @@
12
12
  * The model then reads or greps the file for the parts it actually needs.
13
13
  */
14
14
 
15
- import { mkdirSync, writeFileSync } from "node:fs";
16
- import { tmpdir } from "node:os";
15
+ import { closeSync, mkdirSync, openSync, readSync, statSync, writeFileSync } from "node:fs";
16
+ import { StringDecoder } from "node:string_decoder";
17
17
  import { join } from "node:path";
18
+ import { oneCodeStateDir } from "./paths.ts";
19
+ import { privateSessionTempDir } from "./scratchpad.ts";
18
20
 
19
21
  /**
20
22
  * Where a session's oversized outputs are persisted — the session dir,
21
23
  * matching Claude Code's `<session-dir>/tool-results/<id>.txt`. A session-less
22
- * run (`--no-session`) has no such dir, so a temp folder serves; the model gets
23
- * the path either way. Shared by every producer that would otherwise truncate:
24
- * cutting text loses context, a file keeps it one `read` away.
24
+ * run (`--no-session`, every workflow agent, a subagent of a session-less
25
+ * parent) has no such dir, so the session's own private temp dir serves
26
+ * (`<tmp>/onecode-<uid>/<project-slug>/<session-id>`, 0700, beside its
27
+ * scratchpad). Until 2026-09-27 that fallback was one shared
28
+ * `<tmp>/one-code` with no uid or session in its name, which the gate then
29
+ * treated as working space: every session-less run on the machine, any
30
+ * project and any user, read the others' outputs with no prompt. When the
31
+ * temp dir cannot be made private, `~/.onecode/tmp/<session-id>` serves. The
32
+ * model gets the path either way. Shared by every producer that would
33
+ * otherwise truncate: cutting text loses context, a file keeps it one `read`
34
+ * away.
25
35
  */
26
- export function sessionResultsDir(ctx: { sessionManager?: { getSessionDir?: () => string | undefined } } | undefined): string {
36
+ export function sessionResultsDir(
37
+ ctx: { cwd?: string; sessionManager?: { getSessionDir?: () => string | undefined; getSessionId?: () => string } } | undefined,
38
+ ): string {
39
+ let sessionId: string | undefined;
27
40
  try {
28
41
  const dir = ctx?.sessionManager?.getSessionDir?.();
29
42
  if (dir) return dir;
43
+ sessionId = ctx?.sessionManager?.getSessionId?.();
30
44
  } catch {
31
- // fall through to the temp folder
45
+ // fall through to the private temp folder
32
46
  }
33
- return join(tmpdir(), "one-code");
47
+ const id = (sessionId || `process-${process.pid}`).replace(/[^A-Za-z0-9._-]/g, "_");
48
+ const temp = privateSessionTempDir(ctx?.cwd ?? process.cwd(), id);
49
+ if (temp) return temp;
50
+ const fallback = join(oneCodeStateDir(), "tmp", id);
51
+ try {
52
+ mkdirSync(fallback, { recursive: true, mode: 0o700 });
53
+ } catch {
54
+ // persistIfLarge names the failed write in its own result.
55
+ }
56
+ return fallback;
34
57
  }
35
58
 
36
59
  /** Claude Code persists around this size; pi's bash truncation uses 50KB too. */
@@ -76,6 +99,35 @@ export function persistIfLarge(text: string, options: PersistOptions): string {
76
99
  saved = `Output too large (${formatSize(size)}) and could not be saved to ${file}: ${(error as Error).message}. Only this preview survives — re-run with a narrower query if more is needed.`;
77
100
  }
78
101
 
102
+ return persistedBlock(saved, preview, previewBytes);
103
+ }
104
+
105
+ /**
106
+ * The block for output already whole in a file (a monitor's spool): its path,
107
+ * its size and a preview, the same shape `persistIfLarge` returns, without
108
+ * reading or copying the file.
109
+ */
110
+ export function persistedFileBlock(file: string, size: number, preview: string, previewBytes: number = PREVIEW_BYTES): string {
111
+ return persistedBlock(`Output too large (${formatSize(size)}). Full output saved to: ${file}`, preview, previewBytes);
112
+ }
113
+
114
+ /** Preview an existing spool without reading or copying the whole output. */
115
+ export function persistedFilePreview(path: string): string | undefined {
116
+ let fd: number | undefined;
117
+ try {
118
+ const { size } = statSync(path);
119
+ fd = openSync(path, "r");
120
+ const head = Buffer.alloc(Math.min(size, PREVIEW_BYTES));
121
+ const read = readSync(fd, head, 0, head.length, 0);
122
+ return persistedFileBlock(path, size, new StringDecoder("utf8").write(head.subarray(0, read)));
123
+ } catch {
124
+ return undefined;
125
+ } finally {
126
+ if (fd !== undefined) closeSync(fd);
127
+ }
128
+ }
129
+
130
+ function persistedBlock(saved: string, preview: string, previewBytes: number): string {
79
131
  return [
80
132
  "<persisted-output>",
81
133
  saved,
@@ -20,7 +20,8 @@
20
20
  * (which pi-ai re-exports from its entry point, so it needs no vendoring — unlike
21
21
  * the estimate/clamp helpers under `/utils/estimate` and `/api/simple-options`,
22
22
  * which have no bare re-export). The two exported helpers
23
- * are byte-identical to upstream; the one adaptation is the internal
23
+ * are byte-identical to upstream (pi-ai 1.1.0 changed only `CHARS_PER_TOKEN`,
24
+ * which `charsPerToken` picks for the running pi); the one adaptation is the internal
24
25
  * `estimateContextTokens`, narrowed to accept only `Context` (the sole shape we
25
26
  * call it with) rather than upstream's `Context | Message[]` overload — the
26
27
  * Message[] branch would be dead code here. `test/unit/pi-ai-estimate.test.ts`
@@ -48,8 +49,22 @@
48
49
  */
49
50
 
50
51
  import { getSystemMessageText, type Api, type Context, type ImageContent, type Message, type Model, type TextContent, type Usage } from "@earendil-works/pi-ai";
52
+ import { VERSION as PI_VERSION } from "@earendil-works/pi-coding-agent";
53
+ import { compareVersions } from "./pi-version.ts";
51
54
 
52
- const CHARS_PER_TOKEN = 4;
55
+ /**
56
+ * pi-ai's characters per token: 4 through pi-ai 1.0.x, 3.5 from pi-ai 1.1.0.
57
+ * pi-ai's entry point looks the same on both, so the running pi's version
58
+ * stands in: pi 0.x keeps pi-ai 0.x and pi 1.1.0 requires pi-ai ^1.1.0, but
59
+ * pi 1.0.x can float onto either (pi ships no shrinkwrap since 1.0.1). There
60
+ * 3.5 wins, as it predicts less output room than pi gives, never more.
61
+ */
62
+ export function charsPerToken(piVersion: string | undefined): number {
63
+ const order = piVersion === undefined ? undefined : compareVersions(piVersion, "1.0.0");
64
+ return order !== undefined && order < 0 ? 4 : 3.5;
65
+ }
66
+
67
+ const CHARS_PER_TOKEN = charsPerToken(PI_VERSION);
53
68
  const ESTIMATED_IMAGE_CHARS = 4800;
54
69
  const CONTEXT_SAFETY_TOKENS = 4096;
55
70
  const MIN_MAX_TOKENS = 1;
@@ -73,7 +88,8 @@ function estimateTextAndImageContentChars(content: string | Array<TextContent |
73
88
  return chars;
74
89
  }
75
90
 
76
- function estimateTextTokens(text: string): number {
91
+ /** pi-ai's chars-per-token estimate for plain text. */
92
+ export function estimateTextTokens(text: string): number {
77
93
  return Math.ceil(text.length / CHARS_PER_TOKEN);
78
94
  }
79
95
 
@@ -8,11 +8,17 @@
8
8
  * version to the range this release was verified against and warns — softly,
9
9
  * never blocking — when outside it. The bundled `one-code` app pins pi inside
10
10
  * the range, so it never warns.
11
+ *
12
+ * The minimum is the oldest pi the extension set loads on: 0.84.3 first
13
+ * exports `createPowerShellToolDefinition`, and on anything older the
14
+ * PowerShell extension fails at load, which stops pi before any warning can
15
+ * show. The peer range in package.json and the guide name the same floor
16
+ * (pi-version.test.ts), and CI runs `test/e2e/pi-floor-smoke.mjs` against it.
11
17
  */
12
18
 
13
19
  /** Inclusive minimum and exclusive maximum pi version this release is tested against. */
14
- export const TESTED_PI_MIN = "0.83.0";
15
- export const TESTED_PI_MAX_EXCLUSIVE = "0.87.0";
20
+ export const TESTED_PI_MIN = "0.84.3";
21
+ export const TESTED_PI_MAX_EXCLUSIVE = "1.4.0";
16
22
 
17
23
  /** Dotted-numeric parse; undefined for anything that is not plain x.y.z numbers. */
18
24
  export function parseVersion(version: string): number[] | undefined {
@@ -52,3 +58,16 @@ export function piVersionWarning(runningPiVersion: string | undefined): string |
52
58
  `(or pin pi inside the tested range).`
53
59
  );
54
60
  }
61
+
62
+ /**
63
+ * Whether the running pi ships built-in extensions that can replace ours'
64
+ * names (`builtin:tool-search`, `builtin:mcp`; lib/replaced-builtins.mjs).
65
+ * A version check, not a feature test: nothing an extension can see tells a
66
+ * pi with the built-ins from one without, and an unparseable version reads
67
+ * as no.
68
+ */
69
+ export function piHasBuiltinExtensions(runningPiVersion: string | undefined, firstVersion: string): boolean {
70
+ if (!runningPiVersion) return false;
71
+ const order = compareVersions(runningPiVersion, firstVersion);
72
+ return order !== undefined && order >= 0;
73
+ }
@@ -1,11 +1,26 @@
1
1
  /**
2
- * Bus channels between plan-mode and permissions. They live here, not in
3
- * either extension, because permissions cannot import plan-mode (plan-mode
4
- * already imports `permissions/modes.ts`) and a string literal typed in two
5
- * places is the one way a channel rename silently disconnects a listener.
2
+ * Bus channels between plan-mode and permissions, and the session entry that
3
+ * records the plan file (also read by the post-compaction file restore). They
4
+ * live here, not in either extension, because permissions cannot import
5
+ * plan-mode (plan-mode already imports `permissions/modes.ts`) and a string
6
+ * literal typed in two places is the one way a rename silently disconnects a
7
+ * reader.
6
8
  */
7
9
 
8
- /** Request a permission-mode change (`{ mode }`); permissions applies it. */
10
+ /** Request a permission-mode change (`{ mode, toolCallId? }`); permissions applies it and anchors a tool-driven switch to its result. */
9
11
  export const MODE_CHANNEL = "one-code:set-permission-mode";
10
12
  /** Announces plan mode's one writable file (`{ path }`); the permissions matcher consumes it. */
11
13
  export const PLAN_FILE_CHANNEL = "one-code:plan-file-path";
14
+ /** Session entry type persisting plan mode's allocated path across resume/branch (`{ path }`). */
15
+ export const PLAN_FILE_ENTRY = "one-code:plan-mode-file";
16
+
17
+ /** The plan file the branch's latest plan-file entry records, if any. */
18
+ export function planFileOnBranch(entries: readonly { type: string; customType?: string; data?: unknown }[]): string | undefined {
19
+ let path: string | undefined;
20
+ for (const entry of entries) {
21
+ if (entry.type !== "custom" || entry.customType !== PLAN_FILE_ENTRY) continue;
22
+ const recorded = (entry.data as { path?: unknown } | undefined)?.path;
23
+ if (typeof recorded === "string") path = recorded;
24
+ }
25
+ return path;
26
+ }
@@ -36,6 +36,7 @@ import { readEnabledPlugins } from "./claude-settings.ts";
36
36
  import { readOverrides } from "./plugin-overrides.ts";
37
37
  import { pluginRoot } from "./plugin-root.ts";
38
38
  import { isSkillEnabled, readSkillStates, skillOverrideKey } from "./skill-overrides.ts";
39
+ import { claudeSourcesOn } from "./config-mode.ts";
39
40
  import { claudeUserDir } from "./paths.ts";
40
41
 
41
42
  export interface PluginManifest {
@@ -144,7 +145,12 @@ export function loadInstalledPlugins(pluginsDir: string, cwd?: string): Installe
144
145
  const plugins: InstalledPlugin[] = [];
145
146
  for (const [key, entries] of Object.entries(registry.plugins)) {
146
147
  if (!Array.isArray(entries) || entries.length === 0) continue;
147
- const entry = entries.find((e) => e.installPath && existsSync(e.installPath) && entryAppliesToCwd(e, cwd));
148
+ const entry = entries.find((e) =>
149
+ e && typeof e === "object" && !Array.isArray(e) &&
150
+ typeof e.installPath === "string" && e.installPath.length > 0 &&
151
+ (e.projectPath === undefined || typeof e.projectPath === "string") &&
152
+ existsSync(e.installPath) && entryAppliesToCwd(e, cwd),
153
+ );
148
154
  if (!entry?.installPath) continue;
149
155
 
150
156
  const { name, marketplace } = splitPluginKey(key);
@@ -158,7 +164,7 @@ export function loadInstalledPlugins(pluginsDir: string, cwd?: string): Installe
158
164
  name: validPluginName(manifest?.name) ?? name,
159
165
  marketplace,
160
166
  path: entry.installPath,
161
- version: entry.version,
167
+ version: typeof entry.version === "string" ? entry.version : undefined,
162
168
  description: typeof manifest?.description === "string" ? manifest.description : undefined,
163
169
  rawEnabled: typeof entry.enabled === "boolean" ? entry.enabled : undefined,
164
170
  });
@@ -166,12 +172,12 @@ export function loadInstalledPlugins(pluginsDir: string, cwd?: string): Installe
166
172
  return plugins.sort((a, b) => a.name.localeCompare(b.name));
167
173
  }
168
174
 
169
- /** A manifest `name` usable as a namespace: a non-empty string free of path separators, colons and whitespace. */
175
+ /** A manifest `name` usable as a namespace and plugin identifier. */
170
176
  export function validPluginName(value: unknown): string | undefined {
171
177
  if (typeof value !== "string") return undefined;
172
178
  const trimmed = value.trim();
173
- if (trimmed.length === 0) return undefined;
174
- if (/[/\\:\s]/.test(trimmed)) return undefined;
179
+ if (trimmed.length === 0 || trimmed === "." || trimmed.includes("..")) return undefined;
180
+ if (/[/\\:@\s\p{Cc}\p{Cf}]/u.test(trimmed)) return undefined;
175
181
  return trimmed;
176
182
  }
177
183
 
@@ -244,8 +250,8 @@ export function findPluginCommands(plugin: Pick<Plugin, "name">, commandsDir: st
244
250
 
245
251
  /** The two roots + settings locations discovery reads from. */
246
252
  export interface DiscoverRoots {
247
- /** Claude Code's plugins dir (`~/.claude/plugins`) — read-only. */
248
- claudePluginsDir: string;
253
+ /** Claude Code's plugins dir (`~/.claude/plugins`) — read-only; unset in independent mode (lib/config-mode.ts). */
254
+ claudePluginsDir?: string;
249
255
  /** One Code's plugin root (`<agentDir>/plugins`) — ours to write. */
250
256
  oneCodeRoot: string;
251
257
  cwd: string;
@@ -255,7 +261,7 @@ export interface DiscoverRoots {
255
261
  /** The standard roots; wiring passes `getAgentDir()` (pure modules can't). */
256
262
  export function defaultDiscoverRoots(agentDir: string, cwd: string = process.cwd(), home: string = os.homedir()): DiscoverRoots {
257
263
  return {
258
- claudePluginsDir: join(claudeUserDir(home), "plugins"),
264
+ claudePluginsDir: claudeSourcesOn() ? join(claudeUserDir(home), "plugins") : undefined,
259
265
  oneCodeRoot: pluginRoot(agentDir),
260
266
  cwd,
261
267
  home,
@@ -330,20 +336,23 @@ export function invalidatePluginsCache(): void {
330
336
  }
331
337
 
332
338
  export function discoverPlugins(roots: DiscoverRoots): DiscoveredPlugins {
333
- const key = [roots.claudePluginsDir, roots.oneCodeRoot, roots.cwd, roots.home].join("\n");
339
+ const claudeDir = roots.claudePluginsDir;
340
+ const key = [claudeDir ?? "", roots.oneCodeRoot, roots.cwd, roots.home].join("\n");
334
341
  if (box.current?.key === key) return box.current.result;
335
342
 
336
- const ccEnabled = readEnabledPlugins(roots.cwd, roots.home);
343
+ const ccEnabled = claudeDir ? readEnabledPlugins(roots.cwd, roots.home) : {};
337
344
  const overrides = readOverrides(roots.oneCodeRoot);
338
345
  const skillOverrides = readSkillStates(roots.oneCodeRoot);
339
346
 
340
- const claudePlugins: Plugin[] = loadInstalledPlugins(roots.claudePluginsDir, roots.cwd).map((p) => ({
341
- ...p,
342
- originRoot: "claude" as const,
343
- enabled: claudePluginEnabled(p.id, ccEnabled, overrides),
344
- overridden: p.id in overrides,
345
- dataRoot: join(roots.claudePluginsDir, "data"),
346
- }));
347
+ const claudePlugins: Plugin[] = claudeDir
348
+ ? loadInstalledPlugins(claudeDir, roots.cwd).map((p) => ({
349
+ ...p,
350
+ originRoot: "claude" as const,
351
+ enabled: claudePluginEnabled(p.id, ccEnabled, overrides),
352
+ overridden: p.id in overrides,
353
+ dataRoot: join(claudeDir, "data"),
354
+ }))
355
+ : [];
347
356
 
348
357
  const oneCodePlugins: Plugin[] = loadInstalledPlugins(roots.oneCodeRoot, roots.cwd).map((p) => ({
349
358
  ...p,
@@ -0,0 +1,208 @@
1
+ /**
2
+ * The PowerShell side of the parse server (lib/powershell-parser.ts): a short
3
+ * bootstrap passed on the command line, and the walker script it reads from
4
+ * stdin and runs.
5
+ *
6
+ * The walker calls PowerShell's own `Parser::ParseInput` on each request and
7
+ * writes back every syntax-tree node, so the gate judges the line exactly as
8
+ * the PowerShell that runs it reads it (decisions/windows.md "The PowerShell
9
+ * pre-gate reads PowerShell's own parse"). All judgement stays in TypeScript;
10
+ * the walker only reports.
11
+ *
12
+ * Wire protocol, one line each way, ASCII only because every payload is
13
+ * base64: Windows PowerShell 5.1 reads and writes its console in the OEM code
14
+ * page, which would garble exactly the Unicode dashes and quotes a gate must
15
+ * see.
16
+ *
17
+ * - The first stdin line is the walker script (base64 UTF-8). The walker
18
+ * answers with a ready record, id 0: `{ id, ready, edition, version, language }`.
19
+ * - Each later stdin line is `<id> <base64 UTF-8 command>`. The walker answers
20
+ * `{ id, nodes, errors }`, or `{ id, failure }` when the walk itself threw.
21
+ * - Each stdout line is base64 UTF-8 JSON. EOF on stdin ends the walker.
22
+ *
23
+ * `nodes` is the tree in pre-order, root first. Each node carries its .NET
24
+ * type name, its parent's index (-1 for the root), its extent as UTF-16
25
+ * offsets into the command (the same units as a JS string index), and a few
26
+ * fields for the types a gate reads (see `nodeFields`). `errors` lists each
27
+ * parse error's ErrorId; PowerShell runs nothing from a line that has one.
28
+ *
29
+ * Pure: two string constants, no pi imports, shared with the BI fork.
30
+ */
31
+
32
+ /**
33
+ * Passed after `-Command`. It reads the first stdin line and runs it as the
34
+ * walker. It holds no double quote, so no platform's argument quoting can
35
+ * change it.
36
+ */
37
+ export const POWERSHELL_PARSE_BOOTSTRAP =
38
+ "$s=[Console]::In.ReadLine();if($null -ne $s){. ([ScriptBlock]::Create([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($s))))}";
39
+
40
+ /** The walker, sent as the first stdin line. Plain ASCII; no backtick, so it survives a template literal unchanged. */
41
+ export const POWERSHELL_PARSE_WALKER = String.raw`
42
+ $ErrorActionPreference = 'Stop'
43
+ $utf8 = New-Object System.Text.UTF8Encoding $false
44
+ $out = [Console]::Out
45
+
46
+ # Command lookup must never load or run a module: autoloading is off, and the
47
+ # built-in modules the gate's cmdlets live in are imported from $PSHOME by
48
+ # path, so a same-named module earlier on PSModulePath cannot stand in. The
49
+ # walker only reports what a name resolves to (type, module, path); the gate
50
+ # enforces which of those it trusts (powershell-tree.ts).
51
+ $PSModuleAutoLoadingPreference = 'None'
52
+ foreach ($module in 'Microsoft.PowerShell.Management', 'Microsoft.PowerShell.Utility', 'Microsoft.PowerShell.Security') {
53
+ $manifest = "$PSHOME/Modules/$module"
54
+ if ([System.IO.Directory]::Exists($manifest)) { try { Import-Module -Name $manifest } catch {} }
55
+ }
56
+ $binderType = 'System.Management.Automation.Language.StaticParameterBinder' -as [type]
57
+
58
+ function Send-Record($record) {
59
+ $json = ConvertTo-Json -InputObject $record -Depth 5 -Compress
60
+ $out.WriteLine([Convert]::ToBase64String($utf8.GetBytes($json)))
61
+ $out.Flush()
62
+ }
63
+
64
+ function Get-NodeFields($node) {
65
+ $f = @{}
66
+ switch ($node.GetType().Name) {
67
+ 'CommandAst' { $f.operator = [string]$node.InvocationOperator; $f.name = $node.GetCommandName() }
68
+ 'CommandParameterAst' { $f.name = $node.ParameterName }
69
+ 'StringConstantExpressionAst' { $f.value = $node.Value; $f.kind = [string]$node.StringConstantType }
70
+ 'ExpandableStringExpressionAst' { $f.value = $node.Value; $f.kind = [string]$node.StringConstantType }
71
+ 'ConstantExpressionAst' { $f.value = [string]$node.Value }
72
+ 'VariableExpressionAst' { $f.name = $node.VariablePath.UserPath; $f.splatted = $node.Splatted }
73
+ 'FileRedirectionAst' { $f.from = [string]$node.FromStream; $f.append = $node.Append }
74
+ 'MergingRedirectionAst' { $f.from = [string]$node.FromStream; $f.to = [string]$node.ToStream }
75
+ 'BinaryExpressionAst' { $f.operator = [string]$node.Operator }
76
+ 'UnaryExpressionAst' { $f.operator = [string]$node.TokenKind }
77
+ 'AssignmentStatementAst' { $f.operator = [string]$node.Operator }
78
+ 'PipelineChainAst' { $f.operator = [string]$node.Operator; $f.background = $node.Background }
79
+ 'PipelineAst' { if ($node.PSObject.Properties['Background']) { $f.background = $node.Background } }
80
+ 'TypeExpressionAst' { $f.name = $node.TypeName.FullName }
81
+ 'TypeConstraintAst' { $f.name = $node.TypeName.FullName }
82
+ 'MemberExpressionAst' { $f.static = $node.Static }
83
+ 'InvokeMemberExpressionAst' { $f.static = $node.Static }
84
+ }
85
+ $f
86
+ }
87
+
88
+ Send-Record @{
89
+ id = 0
90
+ ready = $true
91
+ edition = [string]$PSVersionTable.PSEdition
92
+ version = [string]$PSVersionTable.PSVersion
93
+ language = [string]$ExecutionContext.SessionState.LanguageMode
94
+ }
95
+
96
+ while ($null -ne ($line = [Console]::In.ReadLine())) {
97
+ $space = $line.IndexOf(' ')
98
+ if ($space -lt 1) { continue }
99
+ $id = [int]$line.Substring(0, $space)
100
+ try {
101
+ $command = $utf8.GetString([Convert]::FromBase64String($line.Substring($space + 1)))
102
+ $tokens = $null
103
+ $parseErrors = $null
104
+ $ast = [System.Management.Automation.Language.Parser]::ParseInput($command, [ref]$tokens, [ref]$parseErrors)
105
+ $all = @($ast.FindAll({ $true }, $true))
106
+ $index = New-Object 'System.Collections.Generic.Dictionary[System.Object,int]'
107
+ $nodes = New-Object System.Collections.ArrayList
108
+ $asts = New-Object System.Collections.ArrayList
109
+ foreach ($node in $all) {
110
+ if ($index.ContainsKey($node)) { continue }
111
+ $parent = -1
112
+ if ($null -ne $node.Parent -and $index.ContainsKey($node.Parent)) { $parent = $index[$node.Parent] }
113
+ $record = Get-NodeFields $node
114
+ $record.type = $node.GetType().Name
115
+ $record.parent = $parent
116
+ $record.start = $node.Extent.StartOffset
117
+ $record.end = $node.Extent.EndOffset
118
+ $index[$node] = $nodes.Count
119
+ [void]$nodes.Add($record)
120
+ [void]$asts.Add($node)
121
+ }
122
+ # Second pass, once every node has its index: what each static command
123
+ # name resolves to in this PowerShell, and for a cmdlet how PowerShell's
124
+ # own binder assigns its arguments to parameters.
125
+ for ($i = 0; $i -lt $nodes.Count; $i++) {
126
+ if ($nodes[$i].type -ne 'CommandAst' -or $null -eq $nodes[$i].name) { continue }
127
+ $command = $asts[$i]
128
+ $info = $null
129
+ try { $info = $ExecutionContext.InvokeCommand.GetCommand($nodes[$i].name, 'All') } catch {}
130
+ if ($null -eq $info) { continue }
131
+ if ($info -is [System.Management.Automation.AliasInfo]) {
132
+ $nodes[$i].alias = $true
133
+ $info = $info.ResolvedCommand
134
+ if ($null -eq $info) { continue }
135
+ }
136
+ $nodes[$i].commandType = [string]$info.CommandType
137
+ $nodes[$i].resolvedName = $info.Name
138
+ if ($info -is [System.Management.Automation.ApplicationInfo]) { $nodes[$i].resolvedName = $info.Path }
139
+ $nodes[$i].module = [string]$info.ModuleName
140
+ if ($info -isnot [System.Management.Automation.CmdletInfo]) { continue }
141
+ if ($null -eq $binderType) { $nodes[$i].bindingUnavailable = $true; continue }
142
+ try {
143
+ # An aliased command is bound as a copy spelled with the cmdlet's name,
144
+ # so the binding never depends on how an edition's binder treats an
145
+ # alias; each bound value is mapped back by extent.
146
+ $bindAst = $command
147
+ $origin = 0
148
+ $nameEnd = 0
149
+ $delta = 0
150
+ if ($nodes[$i].alias) {
151
+ $nameExtent = $command.CommandElements[0].Extent
152
+ $relative = $nameExtent.StartOffset - $command.Extent.StartOffset
153
+ $text = $command.Extent.Text
154
+ $copy = $text.Substring(0, $relative) + $info.Name + $text.Substring($relative + $nameExtent.Text.Length)
155
+ $bindAst = [System.Management.Automation.Language.Parser]::ParseInput($copy, [ref]$null, [ref]$null).Find({ param($n) $n -is [System.Management.Automation.Language.CommandAst] }, $false)
156
+ $origin = $command.Extent.StartOffset
157
+ $nameEnd = $relative + $info.Name.Length
158
+ $delta = $info.Name.Length - $nameExtent.Text.Length
159
+ }
160
+ # The node of the original command a bound value stands for, or -1:
161
+ # the value itself, or the node with the same (mapped) extent and type.
162
+ # The binder builds values of its own for a remaining-arguments
163
+ # parameter (Write-Output a b: an array of copies).
164
+ $original = {
165
+ param($ast)
166
+ if ([object]::ReferenceEquals($bindAst, $command) -and $index.ContainsKey($ast)) { return $index[$ast] }
167
+ $start = $ast.Extent.StartOffset
168
+ $end = $ast.Extent.EndOffset
169
+ if (-not [object]::ReferenceEquals($bindAst, $command)) {
170
+ if ($start -ge $nameEnd) { $start -= $delta }
171
+ if ($end -ge $nameEnd) { $end -= $delta }
172
+ $start += $origin
173
+ $end += $origin
174
+ }
175
+ $type = $ast.GetType().Name
176
+ for ($j = $i + 1; $j -lt $nodes.Count -and $nodes[$j].start -lt $command.Extent.EndOffset; $j++) {
177
+ if ($nodes[$j].start -eq $start -and $nodes[$j].end -eq $end -and $nodes[$j].type -eq $type) { return $j }
178
+ }
179
+ return -1
180
+ }
181
+ $bound = $binderType::BindCommand($bindAst, $true)
182
+ $nodes[$i].bindings = @(foreach ($key in $bound.BoundParameters.Keys) {
183
+ $result = $bound.BoundParameters[$key]
184
+ $record = @{ parameter = [string]$key; value = -1 }
185
+ if ($null -ne $result.Value) {
186
+ $record.value = & $original $result.Value
187
+ # -2 marks a value the binder built: its elements, if an array,
188
+ # are mapped one by one.
189
+ if ($record.value -lt 0) {
190
+ $record.value = -2
191
+ if ($result.Value -is [System.Management.Automation.Language.ArrayLiteralAst]) {
192
+ $record.elements = @(foreach ($element in $result.Value.Elements) { & $original $element })
193
+ }
194
+ }
195
+ }
196
+ $record
197
+ })
198
+ $nodes[$i].bindingErrors = @(foreach ($key in $bound.BindingExceptions.Keys) { [string]$key })
199
+ } catch {
200
+ $nodes[$i].bindingUnavailable = $true
201
+ }
202
+ }
203
+ Send-Record @{ id = $id; nodes = @($nodes); errors = @($parseErrors | ForEach-Object { $_.ErrorId }) }
204
+ } catch {
205
+ Send-Record @{ id = $id; failure = $_.Exception.Message }
206
+ }
207
+ }
208
+ `;