@pugi/cli 0.1.0-beta.9 → 0.1.0-beta.90

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 (409) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/assets/pugi-prozr2-mascot.ansi +9 -0
  4. package/bin/run.js +33 -1
  5. package/dist/commands/deploy.js +40 -40
  6. package/dist/commands/flatten.js +191 -0
  7. package/dist/commands/jobs-watch.js +201 -0
  8. package/dist/commands/jobs.js +42 -27
  9. package/dist/commands/smoke.js +133 -0
  10. package/dist/core/agent-progress/cleanup.js +134 -0
  11. package/dist/core/agent-progress/schema.js +144 -0
  12. package/dist/core/agent-progress/writer.js +101 -0
  13. package/dist/core/agents/adaptive-router.js +330 -0
  14. package/dist/core/agents/query-decomposer.js +297 -0
  15. package/dist/core/agents/registry.js +3 -3
  16. package/dist/core/approvals/shortcut-resolver.js +98 -0
  17. package/dist/core/artifact-chain/dispatcher.js +148 -0
  18. package/dist/core/artifact-chain/exporter.js +164 -0
  19. package/dist/core/artifact-chain/state.js +243 -0
  20. package/dist/core/artifact-chain/steps.js +169 -0
  21. package/dist/core/ask-user/question.js +92 -0
  22. package/dist/core/audit/audit-trail.js +275 -0
  23. package/dist/core/auth/ensure-authenticated.js +129 -0
  24. package/dist/core/auth/env-provider.js +238 -0
  25. package/dist/core/auto-open-browser.js +4 -4
  26. package/dist/core/auto-update/channels.js +122 -0
  27. package/dist/core/auto-update/checker.js +241 -0
  28. package/dist/core/auto-update/state.js +235 -0
  29. package/dist/core/bare-mode/index.js +107 -0
  30. package/dist/core/bash/redirect.js +281 -0
  31. package/dist/core/bash-classifier.js +436 -40
  32. package/dist/core/checkpoint/resumer.js +149 -0
  33. package/dist/core/checkpoint/rewinder.js +291 -0
  34. package/dist/core/checkpoints/shadow-git.js +670 -0
  35. package/dist/core/citations/parser.js +109 -0
  36. package/dist/core/classifier/yolo-classifier.js +88 -0
  37. package/dist/core/codegraph/decision-store.js +248 -0
  38. package/dist/core/codegraph/detect-repo.js +459 -0
  39. package/dist/core/codegraph/install.js +134 -0
  40. package/dist/core/codegraph/offer-hook.js +220 -0
  41. package/dist/core/compact/auto-trigger.js +96 -0
  42. package/dist/core/compact/buffer-rewriter.js +115 -0
  43. package/dist/core/compact/summarizer.js +208 -0
  44. package/dist/core/compact/token-counter.js +108 -0
  45. package/dist/core/consensus/anvil-fanout.js +25 -25
  46. package/dist/core/consensus/diff-capture.js +121 -12
  47. package/dist/core/consensus/rubric.js +21 -21
  48. package/dist/core/context/builder.js +6 -6
  49. package/dist/core/context/compaction-events.js +8 -8
  50. package/dist/core/context/compaction.js +31 -31
  51. package/dist/core/context/index.js +15 -8
  52. package/dist/core/context/invariants.js +51 -51
  53. package/dist/core/context/markdown-loader.js +28 -10
  54. package/dist/core/context/markdown-traverse.js +255 -0
  55. package/dist/core/context/pugiignore.js +41 -41
  56. package/dist/core/context/repo-skeleton.js +37 -37
  57. package/dist/core/context/tool-eviction.js +55 -0
  58. package/dist/core/context/watcher.js +32 -32
  59. package/dist/core/context/working-set.js +23 -23
  60. package/dist/core/coordinator/agent-tools.js +77 -0
  61. package/dist/core/coordinator/agent-toolset.js +65 -0
  62. package/dist/core/coordinator/fsm.js +73 -0
  63. package/dist/core/coordinator/mode-fsm.js +70 -0
  64. package/dist/core/cost/rate-card.js +129 -0
  65. package/dist/core/cost/tracker.js +221 -0
  66. package/dist/core/credentials.js +13 -13
  67. package/dist/core/cron/scheduler.js +138 -0
  68. package/dist/core/denial-tracking/index.js +8 -0
  69. package/dist/core/denial-tracking/state.js +264 -0
  70. package/dist/core/diagnostics/probe-runner.js +93 -0
  71. package/dist/core/diagnostics/probes/api.js +46 -0
  72. package/dist/core/diagnostics/probes/auth.js +93 -0
  73. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  74. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  75. package/dist/core/diagnostics/probes/config.js +72 -0
  76. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  77. package/dist/core/diagnostics/probes/disk.js +81 -0
  78. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  79. package/dist/core/diagnostics/probes/git.js +65 -0
  80. package/dist/core/diagnostics/probes/hooks.js +118 -0
  81. package/dist/core/diagnostics/probes/mcp.js +75 -0
  82. package/dist/core/diagnostics/probes/node.js +59 -0
  83. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  84. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  85. package/dist/core/diagnostics/probes/sandbox.js +40 -0
  86. package/dist/core/diagnostics/probes/session.js +74 -0
  87. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  88. package/dist/core/diagnostics/probes/workspace.js +63 -0
  89. package/dist/core/diagnostics/types.js +70 -0
  90. package/dist/core/dispatch/cache-cleanup.js +197 -0
  91. package/dist/core/dispatch/cache-handoff.js +295 -0
  92. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  93. package/dist/core/edits/dispatch.js +333 -7
  94. package/dist/core/edits/format-detector.js +260 -0
  95. package/dist/core/edits/format-matrix.js +26 -0
  96. package/dist/core/edits/fuzzy-ladder.js +650 -0
  97. package/dist/core/edits/index.js +5 -1
  98. package/dist/core/edits/journal.js +199 -0
  99. package/dist/core/edits/layer-a-apply.js +15 -15
  100. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  101. package/dist/core/edits/layer-b-apply.js +9 -9
  102. package/dist/core/edits/layer-c-apply.js +6 -6
  103. package/dist/core/edits/layer-d-ast.js +557 -14
  104. package/dist/core/edits/marker-parser.js +12 -12
  105. package/dist/core/edits/security-gate.js +27 -27
  106. package/dist/core/edits/verify-hook.js +273 -0
  107. package/dist/core/edits/worktree.js +29 -29
  108. package/dist/core/engine/anvil-client.js +214 -26
  109. package/dist/core/engine/auto-compact.js +179 -0
  110. package/dist/core/engine/budgets.js +186 -0
  111. package/dist/core/engine/context-prefix.js +155 -0
  112. package/dist/core/engine/index.js +1 -1
  113. package/dist/core/engine/intensity.js +158 -0
  114. package/dist/core/engine/intent.js +260 -0
  115. package/dist/core/engine/native-pugi.js +1295 -227
  116. package/dist/core/engine/prompts.js +129 -19
  117. package/dist/core/engine/strip-internal-fields.js +124 -0
  118. package/dist/core/engine/tool-bridge.js +1731 -59
  119. package/dist/core/evaluation/golden-dataset.js +293 -0
  120. package/dist/core/feedback/queue.js +177 -0
  121. package/dist/core/feedback/submitter.js +145 -0
  122. package/dist/core/file-cache.js +113 -1
  123. package/dist/core/flatten/flatten-repo.js +439 -0
  124. package/dist/core/format/osc8-link.js +28 -0
  125. package/dist/core/hook-chains.js +392 -0
  126. package/dist/core/hooks/citation-verify-hook.js +138 -0
  127. package/dist/core/hooks/citation-verify.js +112 -0
  128. package/dist/core/hooks/events.js +46 -0
  129. package/dist/core/hooks/index.js +15 -0
  130. package/dist/core/hooks/registry.js +216 -0
  131. package/dist/core/hooks/runner.js +236 -0
  132. package/dist/core/hooks/v2/event-emitter.js +115 -0
  133. package/dist/core/hooks/v2/executor.js +282 -0
  134. package/dist/core/hooks/v2/index.js +25 -0
  135. package/dist/core/hooks/v2/lifecycle.js +104 -0
  136. package/dist/core/hooks/v2/loader.js +216 -0
  137. package/dist/core/hooks/v2/matcher.js +125 -0
  138. package/dist/core/hooks/v2/trust.js +143 -0
  139. package/dist/core/hooks/v2/types.js +86 -0
  140. package/dist/core/hooks/worktree-events.js +158 -0
  141. package/dist/core/image/renderer.js +71 -0
  142. package/dist/core/init/detector.js +582 -0
  143. package/dist/core/init/template-renderer.js +242 -0
  144. package/dist/core/jobs/registry.js +18 -18
  145. package/dist/core/ledger/results-tsv.js +142 -0
  146. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  147. package/dist/core/lsp/cache.js +105 -0
  148. package/dist/core/lsp/client.js +551 -41
  149. package/dist/core/lsp/language-detect.js +66 -0
  150. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  151. package/dist/core/lsp/server-detect.js +173 -0
  152. package/dist/core/lsp/symbol-cache.js +162 -0
  153. package/dist/core/lsp/symbol-tools.js +664 -0
  154. package/dist/core/mcp/client.js +97 -28
  155. package/dist/core/mcp/http-server.js +553 -0
  156. package/dist/core/mcp/orchestrator-tools.js +662 -0
  157. package/dist/core/mcp/permission.js +190 -0
  158. package/dist/core/mcp/registry.js +39 -17
  159. package/dist/core/mcp/server-tools.js +219 -0
  160. package/dist/core/mcp/server.js +397 -0
  161. package/dist/core/mcp/trust.js +10 -10
  162. package/dist/core/memory/dual-write.js +416 -0
  163. package/dist/core/memory/passive-extract.js +130 -0
  164. package/dist/core/memory/phase1-kinds.js +20 -0
  165. package/dist/core/memory/secret-scanner.js +304 -0
  166. package/dist/core/memory-sync/queue.js +170 -0
  167. package/dist/core/metrics/extract.js +113 -0
  168. package/dist/core/modes/roo-modes.js +68 -0
  169. package/dist/core/onboarding/ensure-initialized.js +133 -0
  170. package/dist/core/onboarding/marker.js +111 -0
  171. package/dist/core/onboarding/telemetry-state.js +108 -0
  172. package/dist/core/output-style/presets.js +176 -0
  173. package/dist/core/output-style/state.js +185 -0
  174. package/dist/core/path-security.js +287 -5
  175. package/dist/core/permission.js +82 -22
  176. package/dist/core/permissions/auto-classifier.js +124 -0
  177. package/dist/core/permissions/bash-parser.js +371 -0
  178. package/dist/core/permissions/circuit-breaker.js +83 -0
  179. package/dist/core/permissions/constrained-edit.js +91 -0
  180. package/dist/core/permissions/gate.js +278 -0
  181. package/dist/core/permissions/index.js +20 -0
  182. package/dist/core/permissions/mode.js +174 -0
  183. package/dist/core/permissions/network-egress.js +137 -0
  184. package/dist/core/permissions/state.js +241 -0
  185. package/dist/core/permissions/tool-class.js +93 -0
  186. package/dist/core/plan-mode/ui-state.js +51 -0
  187. package/dist/core/plans/plan-artifact.js +721 -0
  188. package/dist/core/policy-limits/etag-store.js +122 -0
  189. package/dist/core/prd-check/parser.js +215 -0
  190. package/dist/core/prd-check/reporter.js +127 -0
  191. package/dist/core/prd-check/session-review.js +557 -0
  192. package/dist/core/prd-check/verifiers.js +223 -0
  193. package/dist/core/prompt-cache/client-cache.js +99 -0
  194. package/dist/core/prompts/assembly.js +29 -0
  195. package/dist/core/prompts/registry.js +364 -0
  196. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  197. package/dist/core/pugi-md/context-injector.js +76 -0
  198. package/dist/core/pugi-md/walk-up.js +207 -0
  199. package/dist/core/python/uv-installer.js +270 -0
  200. package/dist/core/python/uv-resolver.js +83 -0
  201. package/dist/core/rate-limit/narrator.js +146 -0
  202. package/dist/core/recipes/cli-types.js +20 -0
  203. package/dist/core/recipes/loader.js +103 -0
  204. package/dist/core/recipes/runner.js +345 -0
  205. package/dist/core/recipes/schema.js +587 -0
  206. package/dist/core/release-notes/parser.js +241 -0
  207. package/dist/core/release-notes/state.js +116 -0
  208. package/dist/core/repl/ask.js +37 -37
  209. package/dist/core/repl/cancellation.js +26 -26
  210. package/dist/core/repl/cap-warning.js +4 -4
  211. package/dist/core/repl/clipboard-read.js +11 -11
  212. package/dist/core/repl/dispatch-fsm.js +12 -12
  213. package/dist/core/repl/history-search.js +15 -15
  214. package/dist/core/repl/history.js +28 -18
  215. package/dist/core/repl/kill-ring.js +5 -5
  216. package/dist/core/repl/model-pricing.js +135 -0
  217. package/dist/core/repl/privacy-banner.js +22 -22
  218. package/dist/core/repl/session.js +2148 -217
  219. package/dist/core/repl/slash-commands.js +501 -41
  220. package/dist/core/repl/store/index.js +1 -1
  221. package/dist/core/repl/store/jsonl-log.js +22 -22
  222. package/dist/core/repl/store/lockfile.js +10 -10
  223. package/dist/core/repl/store/session-store.js +136 -107
  224. package/dist/core/repl/store/types.js +15 -15
  225. package/dist/core/repl/store/uuid-v7.js +12 -12
  226. package/dist/core/repl/workspace-context.js +43 -21
  227. package/dist/core/repo-map/build.js +125 -0
  228. package/dist/core/repo-map/cache.js +185 -0
  229. package/dist/core/repo-map/extractor.js +254 -0
  230. package/dist/core/repo-map/formatter.js +145 -0
  231. package/dist/core/repo-map/page-rank.js +105 -0
  232. package/dist/core/repo-map/scanner.js +211 -0
  233. package/dist/core/retry-budget/budget.js +284 -0
  234. package/dist/core/retry-budget/index.js +5 -0
  235. package/dist/core/retry-budget/retry-cap.js +74 -0
  236. package/dist/core/routing/lead-worker.js +43 -0
  237. package/dist/core/routing/pre-flight-estimator.js +108 -0
  238. package/dist/core/runs/run-tree.js +103 -0
  239. package/dist/core/security/injection-scanner.js +367 -0
  240. package/dist/core/security/output-filter.js +418 -0
  241. package/dist/core/session/env-file.js +105 -0
  242. package/dist/core/session/section-budgets.js +140 -0
  243. package/dist/core/session.js +92 -0
  244. package/dist/core/settings.js +324 -5
  245. package/dist/core/share/formatter.js +271 -0
  246. package/dist/core/share/redactor.js +221 -0
  247. package/dist/core/share/uploader.js +267 -0
  248. package/dist/core/skills/defaults.js +30 -30
  249. package/dist/core/skills/loader.js +22 -22
  250. package/dist/core/skills/sources.js +27 -27
  251. package/dist/core/smoke/headless-driver.js +174 -0
  252. package/dist/core/smoke/orchestrator.js +194 -0
  253. package/dist/core/smoke/runner.js +238 -0
  254. package/dist/core/smoke/scenario-parser.js +316 -0
  255. package/dist/core/statusline.js +99 -0
  256. package/dist/core/subagents/dispatcher-real.js +600 -0
  257. package/dist/core/subagents/dispatcher.js +132 -43
  258. package/dist/core/subagents/index.js +19 -6
  259. package/dist/core/subagents/isolation-matrix.js +213 -0
  260. package/dist/core/subagents/spawn.js +19 -4
  261. package/dist/core/telemetry/emitter.js +229 -0
  262. package/dist/core/telemetry/queue.js +251 -0
  263. package/dist/core/theme/context.js +91 -0
  264. package/dist/core/theme/presets.js +228 -0
  265. package/dist/core/theme/state.js +181 -0
  266. package/dist/core/todos/invariant.js +10 -0
  267. package/dist/core/todos/state.js +177 -0
  268. package/dist/core/tool-schema/compressor.js +89 -0
  269. package/dist/core/transport/version-interceptor.js +166 -0
  270. package/dist/core/trust.js +2 -2
  271. package/dist/core/tui/thinking-block.js +64 -0
  272. package/dist/core/vim/keymap.js +288 -0
  273. package/dist/core/vim/state.js +92 -0
  274. package/dist/core/watch-markers/marker-watcher.js +133 -0
  275. package/dist/core/worktree/include-parser.js +249 -0
  276. package/dist/core/worktree-manager/cleanup.js +123 -0
  277. package/dist/core/worktree-manager/manager.js +303 -0
  278. package/dist/index.js +36 -0
  279. package/dist/runtime/bootstrap.js +190 -0
  280. package/dist/runtime/cli.js +4185 -549
  281. package/dist/runtime/commands/agents.js +31 -31
  282. package/dist/runtime/commands/budget.js +5 -5
  283. package/dist/runtime/commands/cancel.js +231 -0
  284. package/dist/runtime/commands/chain.js +489 -0
  285. package/dist/runtime/commands/codegraph-status.js +227 -0
  286. package/dist/runtime/commands/compact.js +297 -0
  287. package/dist/runtime/commands/config.js +73 -39
  288. package/dist/runtime/commands/cost.js +199 -0
  289. package/dist/runtime/commands/delegate.js +27 -4
  290. package/dist/runtime/commands/dispatch.js +126 -0
  291. package/dist/runtime/commands/doctor.js +579 -0
  292. package/dist/runtime/commands/feedback.js +184 -0
  293. package/dist/runtime/commands/hooks.js +187 -0
  294. package/dist/runtime/commands/init.js +254 -0
  295. package/dist/runtime/commands/lsp.js +200 -38
  296. package/dist/runtime/commands/mcp.js +879 -0
  297. package/dist/runtime/commands/memory.js +582 -0
  298. package/dist/runtime/commands/model.js +237 -0
  299. package/dist/runtime/commands/onboarding.js +275 -0
  300. package/dist/runtime/commands/patch.js +12 -12
  301. package/dist/runtime/commands/permissions.js +112 -0
  302. package/dist/runtime/commands/plan.js +143 -0
  303. package/dist/runtime/commands/prd-check.js +285 -0
  304. package/dist/runtime/commands/privacy.js +17 -17
  305. package/dist/runtime/commands/recipe.js +325 -0
  306. package/dist/runtime/commands/redo-blob-store.js +92 -0
  307. package/dist/runtime/commands/redo.js +361 -0
  308. package/dist/runtime/commands/release-notes.js +229 -0
  309. package/dist/runtime/commands/repo-map.js +95 -0
  310. package/dist/runtime/commands/report.js +299 -0
  311. package/dist/runtime/commands/resume.js +118 -0
  312. package/dist/runtime/commands/review-consensus.js +68 -53
  313. package/dist/runtime/commands/rewind.js +333 -0
  314. package/dist/runtime/commands/roster.js +14 -14
  315. package/dist/runtime/commands/sessions.js +163 -0
  316. package/dist/runtime/commands/share.js +316 -0
  317. package/dist/runtime/commands/skills.js +31 -31
  318. package/dist/runtime/commands/status.js +186 -0
  319. package/dist/runtime/commands/stickers.js +82 -0
  320. package/dist/runtime/commands/style.js +194 -0
  321. package/dist/runtime/commands/theme.js +196 -0
  322. package/dist/runtime/commands/undo.js +54 -22
  323. package/dist/runtime/commands/update.js +289 -0
  324. package/dist/runtime/commands/vim.js +140 -0
  325. package/dist/runtime/commands/worktree.js +8 -8
  326. package/dist/runtime/commands/worktrees.js +155 -0
  327. package/dist/runtime/headless-repl.js +195 -0
  328. package/dist/runtime/headless.js +543 -0
  329. package/dist/runtime/load-hooks-or-exit.js +71 -0
  330. package/dist/runtime/plan-decompose.js +22 -22
  331. package/dist/runtime/sigint-guard.js +272 -0
  332. package/dist/runtime/update-check.js +28 -28
  333. package/dist/runtime/version.js +65 -0
  334. package/dist/runtime/worktree-bootstrap.js +579 -0
  335. package/dist/skills/bundled/batch.js +617 -0
  336. package/dist/skills/bundled/index.js +45 -0
  337. package/dist/skills/bundled/loop.js +358 -0
  338. package/dist/skills/bundled/remember.js +383 -0
  339. package/dist/skills/bundled/simplify.js +289 -0
  340. package/dist/skills/bundled/skillify.js +373 -0
  341. package/dist/skills/bundled/stuck.js +558 -0
  342. package/dist/skills/bundled/verify.js +439 -0
  343. package/dist/testing/vcr.js +486 -0
  344. package/dist/tools/agent-tool.js +229 -0
  345. package/dist/tools/apply-patch.js +89 -28
  346. package/dist/tools/ask-user-question.js +337 -0
  347. package/dist/tools/ask-user.js +115 -0
  348. package/dist/tools/bash.js +624 -46
  349. package/dist/tools/brief.js +224 -0
  350. package/dist/tools/enter-worktree.js +250 -0
  351. package/dist/tools/exit-worktree.js +147 -0
  352. package/dist/tools/file-tools.js +161 -44
  353. package/dist/tools/lsp-tools.js +377 -1
  354. package/dist/tools/mcp-tool.js +260 -0
  355. package/dist/tools/multi-edit.js +361 -0
  356. package/dist/tools/powershell.js +268 -0
  357. package/dist/tools/registry.js +86 -4
  358. package/dist/tools/skill-tool.js +96 -0
  359. package/dist/tools/sleep.js +99 -0
  360. package/dist/tools/synthetic-output.js +133 -0
  361. package/dist/tools/tasks.js +208 -0
  362. package/dist/tools/todo-write.js +184 -0
  363. package/dist/tools/verify-plan-execution.js +295 -0
  364. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  365. package/dist/tools/web-fetch.js +195 -10
  366. package/dist/tools/web-search.js +458 -0
  367. package/dist/tui/agent-progress-card.js +111 -0
  368. package/dist/tui/agent-tree.js +11 -1
  369. package/dist/tui/ask-modal.js +14 -14
  370. package/dist/tui/ask-user-question-chips.js +315 -0
  371. package/dist/tui/ask-user-question-prompt.js +203 -0
  372. package/dist/tui/compact-banner.js +81 -0
  373. package/dist/tui/conversation-pane.js +85 -11
  374. package/dist/tui/cost-table.js +111 -0
  375. package/dist/tui/device-flow.js +2 -2
  376. package/dist/tui/doctor-table.js +46 -0
  377. package/dist/tui/feedback-prompt.js +156 -0
  378. package/dist/tui/input-box.js +247 -32
  379. package/dist/tui/login-picker.js +3 -3
  380. package/dist/tui/markdown-render.js +6 -6
  381. package/dist/tui/onboarding-wizard.js +240 -0
  382. package/dist/tui/permissions-picker.js +86 -0
  383. package/dist/tui/render.js +36 -1
  384. package/dist/tui/repl-render.js +176 -25
  385. package/dist/tui/repl-splash-art.js +16 -16
  386. package/dist/tui/repl-splash-mascot.js +48 -24
  387. package/dist/tui/repl-splash.js +22 -22
  388. package/dist/tui/repl.js +125 -45
  389. package/dist/tui/slash-palette.js +6 -6
  390. package/dist/tui/splash.js +2 -2
  391. package/dist/tui/status-bar.js +109 -31
  392. package/dist/tui/status-table.js +7 -0
  393. package/dist/tui/stickers-art.js +136 -0
  394. package/dist/tui/style-table.js +28 -0
  395. package/dist/tui/theme-table.js +29 -0
  396. package/dist/tui/thinking-spinner.js +123 -0
  397. package/dist/tui/tool-stream-pane.js +53 -4
  398. package/dist/tui/update-banner.js +27 -2
  399. package/dist/tui/vim-input.js +267 -0
  400. package/dist/tui/welcome-banner.js +107 -0
  401. package/dist/tui/welcome-data.js +293 -0
  402. package/dist/tui/workspace-context.js +2 -2
  403. package/package.json +31 -16
  404. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  405. package/test/scenarios/compact-force.scenario.txt +12 -0
  406. package/test/scenarios/identity.scenario.txt +12 -0
  407. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  408. package/test/scenarios/walkback.scenario.txt +12 -0
  409. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,664 @@
1
+ /**
2
+ * LSP `SymbolKind` enum — mirrors the official numbering from the LSP
3
+ * spec §3.17.7. We re-export the integers (not the names) because the
4
+ * Aider repomap stores numeric kinds verbatim. Callers that want a
5
+ * human label use `symbolKindLabel`.
6
+ */
7
+ export const SYMBOL_KIND = {
8
+ File: 1,
9
+ Module: 2,
10
+ Namespace: 3,
11
+ Package: 4,
12
+ Class: 5,
13
+ Method: 6,
14
+ Property: 7,
15
+ Field: 8,
16
+ Constructor: 9,
17
+ Enum: 10,
18
+ Interface: 11,
19
+ Function: 12,
20
+ Variable: 13,
21
+ Constant: 14,
22
+ String: 15,
23
+ Number: 16,
24
+ Boolean: 17,
25
+ Array: 18,
26
+ Object: 19,
27
+ Key: 20,
28
+ Null: 21,
29
+ EnumMember: 22,
30
+ Struct: 23,
31
+ Event: 24,
32
+ Operator: 25,
33
+ TypeParameter: 26,
34
+ };
35
+ const SYMBOL_KIND_LABELS = {
36
+ 1: 'file',
37
+ 2: 'module',
38
+ 3: 'namespace',
39
+ 4: 'package',
40
+ 5: 'class',
41
+ 6: 'method',
42
+ 7: 'property',
43
+ 8: 'field',
44
+ 9: 'constructor',
45
+ 10: 'enum',
46
+ 11: 'interface',
47
+ 12: 'function',
48
+ 13: 'variable',
49
+ 14: 'constant',
50
+ 15: 'string',
51
+ 16: 'number',
52
+ 17: 'boolean',
53
+ 18: 'array',
54
+ 19: 'object',
55
+ 20: 'key',
56
+ 21: 'null',
57
+ 22: 'enum-member',
58
+ 23: 'struct',
59
+ 24: 'event',
60
+ 25: 'operator',
61
+ 26: 'type-parameter',
62
+ };
63
+ /** Human-readable kind label (`'function'`, `'class'`, ...) for printing. */
64
+ export function symbolKindLabel(kind) {
65
+ if (typeof kind !== 'number')
66
+ return 'unknown';
67
+ return SYMBOL_KIND_LABELS[kind] ?? 'unknown';
68
+ }
69
+ /**
70
+ * Build a `SymbolToolsTransport` from a real `LspClient`. PUGI-78 Phase
71
+ * 1: wires every method the client exposes (13 total). Methods the
72
+ * `LspClient` does NOT support yet stay omitted on the returned
73
+ * transport so the symbol-tools surface degrades to null / [] without
74
+ * forcing the caller to wrap.
75
+ */
76
+ export function transportFromLspClient(client) {
77
+ return {
78
+ definition: (file, pos) => client.definition(file, pos),
79
+ references: (file, pos) => client.references(file, pos),
80
+ documentSymbols: (file) => client.documentSymbols(file),
81
+ workspaceSymbols: (query) => client.workspaceSymbols(query),
82
+ hover: (file, pos) => client.hover(file, pos),
83
+ signatureHelp: (file, pos) => client.signatureHelp(file, pos),
84
+ implementations: (file, pos) => client.implementations(file, pos),
85
+ typeDefinition: (file, pos) => client.typeDefinition(file, pos),
86
+ rename: (file, pos, newName) => client.rename(file, pos, newName),
87
+ prepareRename: (file, pos) => client.prepareRename(file, pos),
88
+ codeActions: (file, range) => client.codeActions(file, range),
89
+ formatting: (file, options) => client.formatting(file, undefined, options),
90
+ diagnostics: (file) => client.diagnostics(file),
91
+ callHierarchy: (file, pos) => client.callHierarchy(file, pos),
92
+ };
93
+ }
94
+ /**
95
+ * Resolve the first definition for the symbol at `(line, character)`
96
+ * in `filePath`. Returns `null` when:
97
+ *
98
+ * - `filePath` is empty / whitespace
99
+ * - the transport's `definition` call returns `ok: false`
100
+ * - the server reports an empty array
101
+ * - the transport itself throws (caught — never re-raised)
102
+ *
103
+ * Multi-hit definitions (TS overloads, polymorphic methods) collapse
104
+ * to the first location; the engine can call `findReferences` to fan
105
+ * out from there. Matches Aider's `repomap.find_definition` shape.
106
+ */
107
+ export async function findDefinition(transport, filePath, line, character) {
108
+ if (!isNonEmptyString(filePath))
109
+ return null;
110
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character)) {
111
+ return null;
112
+ }
113
+ let result;
114
+ try {
115
+ result = await transport.definition(filePath, { line, character });
116
+ }
117
+ catch {
118
+ return null;
119
+ }
120
+ if (!result.ok)
121
+ return null;
122
+ const first = result.value[0];
123
+ if (!first)
124
+ return null;
125
+ const file = pickFilePath(first);
126
+ if (!isNonEmptyString(file))
127
+ return null;
128
+ return {
129
+ file,
130
+ line: first.range.start.line,
131
+ character: first.range.start.character,
132
+ };
133
+ }
134
+ /**
135
+ * List every reference (including the declaration) for the symbol at
136
+ * `(line, character)` in `filePath`. Returns `[]` on any failure mode
137
+ * matching `findDefinition` plus the empty-array server response.
138
+ */
139
+ export async function findReferences(transport, filePath, line, character) {
140
+ if (!isNonEmptyString(filePath))
141
+ return [];
142
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character)) {
143
+ return [];
144
+ }
145
+ let result;
146
+ try {
147
+ result = await transport.references(filePath, { line, character });
148
+ }
149
+ catch {
150
+ return [];
151
+ }
152
+ if (!result.ok)
153
+ return [];
154
+ const out = [];
155
+ for (const loc of result.value) {
156
+ const file = pickFilePath(loc);
157
+ if (!isNonEmptyString(file))
158
+ continue;
159
+ out.push({
160
+ file,
161
+ line: loc.range.start.line,
162
+ character: loc.range.start.character,
163
+ });
164
+ }
165
+ return out;
166
+ }
167
+ /**
168
+ * Outline the symbols defined in `filePath`. Returns `[]` when:
169
+ *
170
+ * - `filePath` is empty
171
+ * - the transport does not implement `documentSymbols` (Phase 1
172
+ * default — the `LspClient` lacks the wire call)
173
+ * - the transport's `documentSymbols` call returns `ok: false`
174
+ * - the server returns an empty / malformed list
175
+ * - the transport throws
176
+ *
177
+ * Handles BOTH LSP response shapes: hierarchical `DocumentSymbol[]`
178
+ * (with `selectionRange` + `children`) and flat `SymbolInformation[]`
179
+ * (with `location.range`). Children are flattened into the same array
180
+ * so the engine sees one row per symbol regardless of nesting; the
181
+ * `containerName` field records the parent's name for hierarchy.
182
+ */
183
+ export async function listDocumentSymbols(transport, filePath) {
184
+ if (!isNonEmptyString(filePath))
185
+ return [];
186
+ if (!transport.documentSymbols)
187
+ return [];
188
+ let result;
189
+ try {
190
+ result = await transport.documentSymbols(filePath);
191
+ }
192
+ catch {
193
+ return [];
194
+ }
195
+ if (!result.ok)
196
+ return [];
197
+ const out = [];
198
+ for (const raw of result.value) {
199
+ walkDocumentSymbol(raw, undefined, out);
200
+ }
201
+ return out;
202
+ }
203
+ /**
204
+ * Workspace-wide symbol fuzzy search. Returns `[]` when:
205
+ *
206
+ * - `query` is empty / whitespace
207
+ * - the transport does not implement `workspaceSymbols`
208
+ * - the transport's call returns `ok: false`
209
+ * - the server returns an empty / malformed list
210
+ * - the transport throws
211
+ *
212
+ * Per LSP §3.17.13, the server is free to define its own matching
213
+ * algorithm (substring / fuzzy / prefix). We do not re-rank — the
214
+ * server's ranking is authoritative.
215
+ */
216
+ export async function findWorkspaceSymbol(transport, query) {
217
+ if (!isNonEmptyString(query))
218
+ return [];
219
+ if (!transport.workspaceSymbols)
220
+ return [];
221
+ let result;
222
+ try {
223
+ result = await transport.workspaceSymbols(query);
224
+ }
225
+ catch {
226
+ return [];
227
+ }
228
+ if (!result.ok)
229
+ return [];
230
+ const out = [];
231
+ for (const raw of result.value) {
232
+ const parsed = parseWorkspaceSymbol(raw);
233
+ if (parsed)
234
+ out.push(parsed);
235
+ }
236
+ return out;
237
+ }
238
+ /**
239
+ * PUGI-78 Phase 1: hover (type info + docstring). Returns null when:
240
+ *
241
+ * - `filePath` is empty / whitespace
242
+ * - `line` / `character` non-finite or negative
243
+ * - the transport does not implement `hover`
244
+ * - `ok: false` from the transport
245
+ * - the server reports no hover (cursor not on a symbol)
246
+ * - the transport throws
247
+ *
248
+ * Caps the body at 4 KB so a verbose generic type signature does not
249
+ * blow the agent's context window. The cap mirrors the `lspHover`
250
+ * tool's 8 KB cap halved — the symbol surface is closer to "give me
251
+ * one sentence" than the full hover blob.
252
+ */
253
+ export async function hoverSymbol(transport, filePath, line, character) {
254
+ if (!isNonEmptyString(filePath))
255
+ return null;
256
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character))
257
+ return null;
258
+ if (!transport.hover)
259
+ return null;
260
+ let result;
261
+ try {
262
+ result = await transport.hover(filePath, { line, character });
263
+ }
264
+ catch {
265
+ return null;
266
+ }
267
+ if (!result.ok)
268
+ return null;
269
+ if (!result.value)
270
+ return null;
271
+ const HOVER_CAP_BYTES = 4 * 1024;
272
+ const raw = result.value.content;
273
+ const bytes = Buffer.byteLength(raw, 'utf8');
274
+ const truncated = bytes > HOVER_CAP_BYTES;
275
+ const content = truncated
276
+ ? Buffer.from(raw, 'utf8').subarray(0, HOVER_CAP_BYTES).toString('utf8') + '\n... [truncated]'
277
+ : raw;
278
+ return {
279
+ content,
280
+ ...(result.value.range ? { range: result.value.range } : {}),
281
+ ...(truncated ? { truncated: true } : {}),
282
+ };
283
+ }
284
+ /**
285
+ * PUGI-78 Phase 1: function signature at a call site. Returns null when
286
+ * the transport does not implement `signatureHelp` OR the server
287
+ * reports no signature OR the transport fails / throws.
288
+ */
289
+ export async function signatureAt(transport, filePath, line, character) {
290
+ if (!isNonEmptyString(filePath))
291
+ return null;
292
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character))
293
+ return null;
294
+ if (!transport.signatureHelp)
295
+ return null;
296
+ let result;
297
+ try {
298
+ result = await transport.signatureHelp(filePath, { line, character });
299
+ }
300
+ catch {
301
+ return null;
302
+ }
303
+ if (!result.ok)
304
+ return null;
305
+ if (!result.value)
306
+ return null;
307
+ const out = { label: result.value.label, parameters: result.value.parameters };
308
+ if (result.value.documentation)
309
+ out.documentation = result.value.documentation;
310
+ if (typeof result.value.activeParameter === 'number')
311
+ out.activeParameter = result.value.activeParameter;
312
+ return out;
313
+ }
314
+ /**
315
+ * PUGI-78 Phase 1: implementations of an interface / abstract method.
316
+ * Returns `[]` on any failure mode (parity with `findReferences`).
317
+ */
318
+ export async function findImplementations(transport, filePath, line, character) {
319
+ if (!isNonEmptyString(filePath))
320
+ return [];
321
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character))
322
+ return [];
323
+ if (!transport.implementations)
324
+ return [];
325
+ let result;
326
+ try {
327
+ result = await transport.implementations(filePath, { line, character });
328
+ }
329
+ catch {
330
+ return [];
331
+ }
332
+ if (!result.ok)
333
+ return [];
334
+ return collapseLocations(result.value);
335
+ }
336
+ /**
337
+ * PUGI-78 Phase 1: type-definition (vs value-definition). Returns null
338
+ * matching `findDefinition`'s contract.
339
+ */
340
+ export async function findTypeDefinition(transport, filePath, line, character) {
341
+ if (!isNonEmptyString(filePath))
342
+ return null;
343
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character))
344
+ return null;
345
+ if (!transport.typeDefinition)
346
+ return null;
347
+ let result;
348
+ try {
349
+ result = await transport.typeDefinition(filePath, { line, character });
350
+ }
351
+ catch {
352
+ return null;
353
+ }
354
+ if (!result.ok)
355
+ return null;
356
+ const first = result.value[0];
357
+ if (!first)
358
+ return null;
359
+ const file = pickFilePath(first);
360
+ if (!isNonEmptyString(file))
361
+ return null;
362
+ return { file, line: first.range.start.line, character: first.range.start.character };
363
+ }
364
+ export async function renameSymbol(transport, filePath, line, character, newName) {
365
+ if (!isNonEmptyString(filePath))
366
+ return null;
367
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character))
368
+ return null;
369
+ if (!isNonEmptyString(newName))
370
+ return null;
371
+ if (!transport.rename)
372
+ return null;
373
+ // Best-effort prepare-rename precheck. If the server says the cursor
374
+ // is not on a renameable token, we return null without dispatching
375
+ // the full rename — saves a wasted round-trip + avoids returning a
376
+ // misleading "0 edits" preview.
377
+ if (transport.prepareRename) {
378
+ try {
379
+ const prep = await transport.prepareRename(filePath, { line, character });
380
+ if (prep.ok && prep.value === null)
381
+ return null;
382
+ }
383
+ catch {
384
+ // Continue — some servers fail prepare-rename but still execute
385
+ // the full rename. Phase 1 honors the looser fallback.
386
+ }
387
+ }
388
+ let result;
389
+ try {
390
+ result = await transport.rename(filePath, { line, character }, newName);
391
+ }
392
+ catch {
393
+ return null;
394
+ }
395
+ if (!result.ok)
396
+ return null;
397
+ if (!result.value)
398
+ return null;
399
+ if (result.value.edits.length === 0)
400
+ return null;
401
+ return { files: result.value.files, edits: result.value.edits };
402
+ }
403
+ /**
404
+ * PUGI-78 Phase 1: code-action / quick-fix list at a range. Returns
405
+ * `[]` on any failure mode.
406
+ */
407
+ export async function codeActionsAt(transport, filePath, startLine, startChar, endLine, endChar) {
408
+ if (!isNonEmptyString(filePath))
409
+ return [];
410
+ if (!isFiniteNonNegativeInt(startLine) ||
411
+ !isFiniteNonNegativeInt(startChar) ||
412
+ !isFiniteNonNegativeInt(endLine) ||
413
+ !isFiniteNonNegativeInt(endChar)) {
414
+ return [];
415
+ }
416
+ if (!transport.codeActions)
417
+ return [];
418
+ const range = {
419
+ start: { line: startLine, character: startChar },
420
+ end: { line: endLine, character: endChar },
421
+ };
422
+ let result;
423
+ try {
424
+ result = await transport.codeActions(filePath, range);
425
+ }
426
+ catch {
427
+ return [];
428
+ }
429
+ if (!result.ok)
430
+ return [];
431
+ return [...result.value];
432
+ }
433
+ /**
434
+ * PUGI-78 Phase 1: formatter — returns the text edits the server would
435
+ * apply. Returns `[]` on any failure mode.
436
+ */
437
+ export async function formatFile(transport, filePath, options) {
438
+ if (!isNonEmptyString(filePath))
439
+ return [];
440
+ if (!transport.formatting)
441
+ return [];
442
+ let result;
443
+ try {
444
+ result = await transport.formatting(filePath, options);
445
+ }
446
+ catch {
447
+ return [];
448
+ }
449
+ if (!result.ok)
450
+ return [];
451
+ return [...result.value];
452
+ }
453
+ /**
454
+ * PUGI-78 Phase 1: diagnostics for `filePath`. Returns `[]` on any
455
+ * failure mode. Mirrors the agent surface of `lspDiagnostics` but
456
+ * folded into the symbols.* namespace for ergonomic discoverability.
457
+ */
458
+ export async function diagnosticsFor(transport, filePath) {
459
+ if (!isNonEmptyString(filePath))
460
+ return [];
461
+ if (!transport.diagnostics)
462
+ return [];
463
+ let result;
464
+ try {
465
+ result = await transport.diagnostics(filePath);
466
+ }
467
+ catch {
468
+ return [];
469
+ }
470
+ if (!result.ok)
471
+ return [];
472
+ return [...result.value];
473
+ }
474
+ /**
475
+ * PUGI-78 Phase 1: call hierarchy at a symbol position. Returns the
476
+ * incoming and outgoing edges. Empty arrays on any failure mode.
477
+ */
478
+ export async function callHierarchyAt(transport, filePath, line, character) {
479
+ const empty = { incoming: [], outgoing: [] };
480
+ if (!isNonEmptyString(filePath))
481
+ return empty;
482
+ if (!isFiniteNonNegativeInt(line) || !isFiniteNonNegativeInt(character))
483
+ return empty;
484
+ if (!transport.callHierarchy)
485
+ return empty;
486
+ let result;
487
+ try {
488
+ result = await transport.callHierarchy(filePath, { line, character });
489
+ }
490
+ catch {
491
+ return empty;
492
+ }
493
+ if (!result.ok)
494
+ return empty;
495
+ return { incoming: [...result.value.incoming], outgoing: [...result.value.outgoing] };
496
+ }
497
+ /**
498
+ * Internal: collapse `LspLocation[]` to flat references the agent
499
+ * surface ships. Identical to the `findReferences` loop body — lifted
500
+ * to avoid a second copy.
501
+ */
502
+ function collapseLocations(locations) {
503
+ const out = [];
504
+ for (const loc of locations) {
505
+ const file = pickFilePath(loc);
506
+ if (!isNonEmptyString(file))
507
+ continue;
508
+ out.push({
509
+ file,
510
+ line: loc.range.start.line,
511
+ character: loc.range.start.character,
512
+ });
513
+ }
514
+ return out;
515
+ }
516
+ // -- internals ---------------------------------------------------------------
517
+ function isNonEmptyString(value) {
518
+ return typeof value === 'string' && value.trim().length > 0;
519
+ }
520
+ function isFiniteNonNegativeInt(value) {
521
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0;
522
+ }
523
+ /**
524
+ * Prefer the workspace-relative `path` from `client.ts::normalizeLocations`;
525
+ * fall back to the raw URI when the server reports an out-of-workspace
526
+ * location. Either form is a valid identifier for the caller — the
527
+ * engine prefers relative paths for prompts but URIs are still useful
528
+ * for tracing.
529
+ */
530
+ function pickFilePath(loc) {
531
+ if (isNonEmptyString(loc.path))
532
+ return loc.path;
533
+ if (isNonEmptyString(loc.uri))
534
+ return loc.uri;
535
+ return '';
536
+ }
537
+ /**
538
+ * Recursive walk over a (possibly hierarchical) `DocumentSymbol`.
539
+ * Emits one `DocumentSymbol` row per node — children inherit the
540
+ * parent's `name` as their `containerName`. Tolerates both
541
+ * `SymbolInformation` (flat, has `location.range`) and the modern
542
+ * hierarchical shape (`selectionRange` + `children`).
543
+ */
544
+ function walkDocumentSymbol(raw, parentName, out) {
545
+ if (!raw || typeof raw !== 'object')
546
+ return;
547
+ const name = typeof raw.name === 'string' ? raw.name : '';
548
+ const kind = typeof raw.kind === 'number' ? raw.kind : 0;
549
+ if (!name || !kind)
550
+ return;
551
+ const pos = pickDocumentSymbolPosition(raw);
552
+ if (!pos)
553
+ return;
554
+ const containerName = typeof raw.containerName === 'string' && raw.containerName.length > 0
555
+ ? raw.containerName
556
+ : parentName;
557
+ out.push({
558
+ name,
559
+ kind,
560
+ line: pos.line,
561
+ character: pos.character,
562
+ ...(containerName ? { containerName } : {}),
563
+ });
564
+ if (Array.isArray(raw.children)) {
565
+ for (const child of raw.children) {
566
+ walkDocumentSymbol(child, name, out);
567
+ }
568
+ }
569
+ }
570
+ /**
571
+ * LSP `DocumentSymbol` (hierarchical) carries `selectionRange.start`,
572
+ * the precise character position of the symbol name. The legacy
573
+ * `SymbolInformation` shape carries `location.range.start` instead.
574
+ * Tolerate both; prefer `selectionRange` when present (more precise).
575
+ */
576
+ function pickDocumentSymbolPosition(raw) {
577
+ const sel = pickRangeStart(raw.selectionRange);
578
+ if (sel)
579
+ return sel;
580
+ const range = pickRangeStart(raw.range);
581
+ if (range)
582
+ return range;
583
+ if (raw.location && typeof raw.location === 'object') {
584
+ const locRange = pickRangeStart(raw.location.range);
585
+ if (locRange)
586
+ return locRange;
587
+ }
588
+ return null;
589
+ }
590
+ function pickRangeStart(rawRange) {
591
+ if (!rawRange || typeof rawRange !== 'object')
592
+ return null;
593
+ const start = rawRange.start;
594
+ if (!start || typeof start !== 'object')
595
+ return null;
596
+ const line = start.line;
597
+ const character = start.character;
598
+ if (typeof line !== 'number' || typeof character !== 'number')
599
+ return null;
600
+ if (!Number.isFinite(line) || !Number.isFinite(character))
601
+ return null;
602
+ if (line < 0 || character < 0)
603
+ return null;
604
+ return { line, character };
605
+ }
606
+ function parseWorkspaceSymbol(raw) {
607
+ if (!raw || typeof raw !== 'object')
608
+ return null;
609
+ const name = typeof raw.name === 'string' ? raw.name : '';
610
+ const kind = typeof raw.kind === 'number' ? raw.kind : 0;
611
+ if (!name || !kind)
612
+ return null;
613
+ const location = raw.location;
614
+ if (!location || typeof location !== 'object')
615
+ return null;
616
+ const file = pickWorkspaceSymbolFile(location);
617
+ if (!file)
618
+ return null;
619
+ const pos = pickRangeStart(location.range);
620
+ if (!pos)
621
+ return null;
622
+ const containerName = typeof raw.containerName === 'string' && raw.containerName.length > 0
623
+ ? raw.containerName
624
+ : undefined;
625
+ return {
626
+ name,
627
+ file,
628
+ line: pos.line,
629
+ kind,
630
+ ...(containerName ? { containerName } : {}),
631
+ };
632
+ }
633
+ /**
634
+ * Workspace-symbol locations land as either a full `Location`
635
+ * (`{ uri, range }`) or LSP 3.17's `LocationLink` shape
636
+ * (`{ targetUri, targetRange, ... }`). Either form is acceptable;
637
+ * we surface the URI string verbatim and let the engine layer
638
+ * convert to a workspace-relative path when needed (mirrors how
639
+ * `client.ts::normalizeLocations` handles definition results).
640
+ */
641
+ function pickWorkspaceSymbolFile(location) {
642
+ const uri = location['uri'];
643
+ if (typeof uri === 'string' && uri.length > 0)
644
+ return uri;
645
+ const targetUri = location['targetUri'];
646
+ if (typeof targetUri === 'string' && targetUri.length > 0)
647
+ return targetUri;
648
+ return '';
649
+ }
650
+ /**
651
+ * Test-only surface — re-exports internals for direct assertion of
652
+ * parsing rules without running every primitive end-to-end. Keeping
653
+ * the seam typed (instead of using `@ts-ignore` in the spec) preserves
654
+ * `noImplicitAny` compliance project-wide.
655
+ */
656
+ export const __test__ = {
657
+ parseWorkspaceSymbol,
658
+ pickDocumentSymbolPosition,
659
+ pickRangeStart,
660
+ symbolKindLabel,
661
+ walkDocumentSymbol,
662
+ collapseLocations,
663
+ };
664
+ //# sourceMappingURL=symbol-tools.js.map