@pugi/cli 0.1.0-beta.10 → 0.1.0-beta.101

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 (464) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +55 -11
  4. package/assets/pugi-prozr2-mascot.ansi +9 -0
  5. package/bin/run.js +33 -1
  6. package/dist/commands/deploy.js +40 -40
  7. package/dist/commands/flatten.js +191 -0
  8. package/dist/commands/jobs-watch.js +201 -0
  9. package/dist/commands/jobs.js +42 -27
  10. package/dist/commands/retro.js +210 -0
  11. package/dist/commands/smoke.js +133 -0
  12. package/dist/core/agent-progress/cleanup.js +134 -0
  13. package/dist/core/agent-progress/schema.js +144 -0
  14. package/dist/core/agent-progress/writer.js +101 -0
  15. package/dist/core/agents/adaptive-router.js +330 -0
  16. package/dist/core/agents/query-decomposer.js +297 -0
  17. package/dist/core/agents/registry.js +3 -3
  18. package/dist/core/approvals/shortcut-resolver.js +98 -0
  19. package/dist/core/artifact-chain/dispatcher.js +148 -0
  20. package/dist/core/artifact-chain/exporter.js +164 -0
  21. package/dist/core/artifact-chain/state.js +243 -0
  22. package/dist/core/artifact-chain/steps.js +169 -0
  23. package/dist/core/ask-user/question.js +92 -0
  24. package/dist/core/audit/audit-trail.js +275 -0
  25. package/dist/core/auth/ensure-authenticated.js +129 -0
  26. package/dist/core/auth/env-provider.js +238 -0
  27. package/dist/core/auto-open-browser.js +4 -4
  28. package/dist/core/auto-update/channels.js +122 -0
  29. package/dist/core/auto-update/checker.js +241 -0
  30. package/dist/core/auto-update/state.js +235 -0
  31. package/dist/core/bare-mode/index.js +107 -0
  32. package/dist/core/bash/redirect.js +281 -0
  33. package/dist/core/bash-classifier.js +436 -40
  34. package/dist/core/checkpoint/resumer.js +149 -0
  35. package/dist/core/checkpoint/rewinder.js +291 -0
  36. package/dist/core/checkpoints/shadow-git.js +670 -0
  37. package/dist/core/citations/parser.js +109 -0
  38. package/dist/core/classifier/yolo-classifier.js +88 -0
  39. package/dist/core/codegraph/db.js +506 -0
  40. package/dist/core/codegraph/decision-store.js +248 -0
  41. package/dist/core/codegraph/detect-repo.js +459 -0
  42. package/dist/core/codegraph/install.js +134 -0
  43. package/dist/core/codegraph/offer-hook.js +220 -0
  44. package/dist/core/codegraph/parser.js +598 -0
  45. package/dist/core/codegraph/queries/go.scm +57 -0
  46. package/dist/core/codegraph/queries/javascript.scm +56 -0
  47. package/dist/core/codegraph/queries/python.scm +55 -0
  48. package/dist/core/codegraph/queries/rust.scm +63 -0
  49. package/dist/core/codegraph/queries/typescript.scm +91 -0
  50. package/dist/core/codegraph/reindex.js +218 -0
  51. package/dist/core/codegraph/resolve-edges.js +107 -0
  52. package/dist/core/codegraph/types.js +34 -0
  53. package/dist/core/codegraph/watcher.js +440 -0
  54. package/dist/core/compact/auto-trigger.js +96 -0
  55. package/dist/core/compact/buffer-rewriter.js +115 -0
  56. package/dist/core/compact/summarizer.js +208 -0
  57. package/dist/core/compact/token-counter.js +108 -0
  58. package/dist/core/consensus/anvil-fanout.js +25 -25
  59. package/dist/core/consensus/diff-capture.js +121 -12
  60. package/dist/core/consensus/rubric.js +21 -21
  61. package/dist/core/context/builder.js +6 -6
  62. package/dist/core/context/compaction-events.js +8 -8
  63. package/dist/core/context/compaction.js +31 -31
  64. package/dist/core/context/index.js +15 -8
  65. package/dist/core/context/invariants.js +51 -51
  66. package/dist/core/context/markdown-loader.js +28 -10
  67. package/dist/core/context/markdown-traverse.js +255 -0
  68. package/dist/core/context/pugiignore.js +41 -41
  69. package/dist/core/context/repo-skeleton.js +37 -37
  70. package/dist/core/context/tool-eviction.js +55 -0
  71. package/dist/core/context/watcher.js +32 -32
  72. package/dist/core/context/working-set.js +23 -23
  73. package/dist/core/coordinator/agent-tools.js +77 -0
  74. package/dist/core/coordinator/agent-toolset.js +65 -0
  75. package/dist/core/coordinator/fsm.js +73 -0
  76. package/dist/core/coordinator/mode-fsm.js +70 -0
  77. package/dist/core/cost/rate-card.js +129 -0
  78. package/dist/core/cost/tracker.js +221 -0
  79. package/dist/core/credentials.js +13 -13
  80. package/dist/core/cron/scheduler.js +138 -0
  81. package/dist/core/denial-tracking/index.js +8 -0
  82. package/dist/core/denial-tracking/state.js +264 -0
  83. package/dist/core/diagnostics/probe-runner.js +93 -0
  84. package/dist/core/diagnostics/probes/api.js +46 -0
  85. package/dist/core/diagnostics/probes/auth.js +93 -0
  86. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  87. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  88. package/dist/core/diagnostics/probes/config.js +72 -0
  89. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  90. package/dist/core/diagnostics/probes/disk.js +81 -0
  91. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  92. package/dist/core/diagnostics/probes/git.js +65 -0
  93. package/dist/core/diagnostics/probes/hooks.js +118 -0
  94. package/dist/core/diagnostics/probes/mcp.js +75 -0
  95. package/dist/core/diagnostics/probes/node.js +59 -0
  96. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  97. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  98. package/dist/core/diagnostics/probes/sandbox.js +67 -0
  99. package/dist/core/diagnostics/probes/session.js +74 -0
  100. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  101. package/dist/core/diagnostics/probes/workspace.js +63 -0
  102. package/dist/core/diagnostics/types.js +70 -0
  103. package/dist/core/dispatch/cache-cleanup.js +197 -0
  104. package/dist/core/dispatch/cache-handoff.js +295 -0
  105. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  106. package/dist/core/edits/dispatch.js +333 -7
  107. package/dist/core/edits/format-detector.js +260 -0
  108. package/dist/core/edits/format-matrix.js +26 -0
  109. package/dist/core/edits/fuzzy-ladder.js +650 -0
  110. package/dist/core/edits/index.js +5 -1
  111. package/dist/core/edits/journal.js +199 -0
  112. package/dist/core/edits/layer-a-apply.js +15 -15
  113. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  114. package/dist/core/edits/layer-b-apply.js +9 -9
  115. package/dist/core/edits/layer-c-apply.js +6 -6
  116. package/dist/core/edits/layer-d-ast.js +557 -14
  117. package/dist/core/edits/marker-parser.js +12 -12
  118. package/dist/core/edits/security-gate.js +27 -27
  119. package/dist/core/edits/verify-hook.js +273 -0
  120. package/dist/core/edits/worktree.js +29 -29
  121. package/dist/core/engine/anvil-client.js +214 -26
  122. package/dist/core/engine/auto-compact.js +247 -0
  123. package/dist/core/engine/budgets.js +220 -0
  124. package/dist/core/engine/compact-llm-summarizer.js +124 -0
  125. package/dist/core/engine/context-prefix.js +155 -0
  126. package/dist/core/engine/index.js +1 -1
  127. package/dist/core/engine/intensity.js +163 -0
  128. package/dist/core/engine/intent.js +260 -0
  129. package/dist/core/engine/native-pugi.js +1559 -227
  130. package/dist/core/engine/prompts.js +219 -19
  131. package/dist/core/engine/strip-internal-fields.js +124 -0
  132. package/dist/core/engine/tool-bridge.js +1887 -59
  133. package/dist/core/engine/verification-patterns.js +195 -0
  134. package/dist/core/eval/v1/ledger.js +83 -0
  135. package/dist/core/eval/v1/runner.js +280 -0
  136. package/dist/core/eval/v1/scoring.js +68 -0
  137. package/dist/core/eval/v1/task-loader.js +191 -0
  138. package/dist/core/eval/v1/types.js +14 -0
  139. package/dist/core/eval/v1/verifier.js +176 -0
  140. package/dist/core/eval/v1/yaml-parser.js +250 -0
  141. package/dist/core/evaluation/golden-dataset.js +293 -0
  142. package/dist/core/feedback/queue.js +177 -0
  143. package/dist/core/feedback/submitter.js +145 -0
  144. package/dist/core/file-cache.js +113 -1
  145. package/dist/core/flatten/flatten-repo.js +439 -0
  146. package/dist/core/format/osc8-link.js +28 -0
  147. package/dist/core/hook-chains.js +392 -0
  148. package/dist/core/hooks/citation-verify-hook.js +138 -0
  149. package/dist/core/hooks/citation-verify.js +112 -0
  150. package/dist/core/hooks/events.js +46 -0
  151. package/dist/core/hooks/index.js +15 -0
  152. package/dist/core/hooks/registry.js +216 -0
  153. package/dist/core/hooks/runner.js +236 -0
  154. package/dist/core/hooks/v2/event-emitter.js +115 -0
  155. package/dist/core/hooks/v2/executor.js +282 -0
  156. package/dist/core/hooks/v2/index.js +25 -0
  157. package/dist/core/hooks/v2/lifecycle.js +104 -0
  158. package/dist/core/hooks/v2/loader.js +216 -0
  159. package/dist/core/hooks/v2/matcher.js +125 -0
  160. package/dist/core/hooks/v2/trust.js +143 -0
  161. package/dist/core/hooks/v2/types.js +86 -0
  162. package/dist/core/hooks/worktree-events.js +158 -0
  163. package/dist/core/image/renderer.js +71 -0
  164. package/dist/core/init/detector.js +582 -0
  165. package/dist/core/init/template-renderer.js +242 -0
  166. package/dist/core/jobs/registry.js +18 -18
  167. package/dist/core/ledger/results-tsv.js +142 -0
  168. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  169. package/dist/core/lsp/cache.js +105 -0
  170. package/dist/core/lsp/client.js +551 -41
  171. package/dist/core/lsp/language-detect.js +66 -0
  172. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  173. package/dist/core/lsp/server-detect.js +173 -0
  174. package/dist/core/lsp/symbol-cache.js +162 -0
  175. package/dist/core/lsp/symbol-tools.js +664 -0
  176. package/dist/core/mcp/client.js +97 -28
  177. package/dist/core/mcp/http-server.js +553 -0
  178. package/dist/core/mcp/orchestrator-config.js +192 -0
  179. package/dist/core/mcp/orchestrator-tools.js +806 -0
  180. package/dist/core/mcp/permission.js +190 -0
  181. package/dist/core/mcp/registry.js +39 -17
  182. package/dist/core/mcp/server-tools.js +219 -0
  183. package/dist/core/mcp/server.js +397 -0
  184. package/dist/core/mcp/trust.js +10 -10
  185. package/dist/core/memory/dual-write.js +416 -0
  186. package/dist/core/memory/passive-extract.js +130 -0
  187. package/dist/core/memory/phase1-kinds.js +20 -0
  188. package/dist/core/memory/secret-scanner.js +304 -0
  189. package/dist/core/memory-sync/queue.js +170 -0
  190. package/dist/core/metrics/extract.js +113 -0
  191. package/dist/core/modes/roo-modes.js +68 -0
  192. package/dist/core/notes/notes-paths.js +113 -0
  193. package/dist/core/notes/notes-recorder.js +140 -0
  194. package/dist/core/notes/notes-writer.js +53 -0
  195. package/dist/core/notes/renderers.js +0 -0
  196. package/dist/core/notes/slug.js +105 -0
  197. package/dist/core/onboarding/ensure-initialized.js +133 -0
  198. package/dist/core/onboarding/marker.js +111 -0
  199. package/dist/core/onboarding/telemetry-state.js +108 -0
  200. package/dist/core/output-style/presets.js +176 -0
  201. package/dist/core/output-style/state.js +185 -0
  202. package/dist/core/path-security.js +287 -5
  203. package/dist/core/permission.js +82 -22
  204. package/dist/core/permissions/auto-classifier.js +124 -0
  205. package/dist/core/permissions/bash-parser.js +371 -0
  206. package/dist/core/permissions/circuit-breaker.js +83 -0
  207. package/dist/core/permissions/constrained-edit.js +91 -0
  208. package/dist/core/permissions/gate.js +278 -0
  209. package/dist/core/permissions/index.js +20 -0
  210. package/dist/core/permissions/mode.js +174 -0
  211. package/dist/core/permissions/network-egress.js +137 -0
  212. package/dist/core/permissions/state.js +241 -0
  213. package/dist/core/permissions/tool-class.js +107 -0
  214. package/dist/core/plan-mode/ui-state.js +51 -0
  215. package/dist/core/plans/plan-artifact.js +721 -0
  216. package/dist/core/policy-limits/etag-store.js +122 -0
  217. package/dist/core/prd-check/parser.js +215 -0
  218. package/dist/core/prd-check/reporter.js +127 -0
  219. package/dist/core/prd-check/session-review.js +557 -0
  220. package/dist/core/prd-check/verifiers.js +223 -0
  221. package/dist/core/prompt-cache/client-cache.js +99 -0
  222. package/dist/core/prompts/assembly.js +29 -0
  223. package/dist/core/prompts/registry.js +364 -0
  224. package/dist/core/pugi-gitignore.js +52 -0
  225. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  226. package/dist/core/pugi-md/context-injector.js +76 -0
  227. package/dist/core/pugi-md/walk-up.js +207 -0
  228. package/dist/core/python/uv-installer.js +270 -0
  229. package/dist/core/python/uv-resolver.js +83 -0
  230. package/dist/core/rate-limit/narrator.js +146 -0
  231. package/dist/core/recipes/cli-types.js +20 -0
  232. package/dist/core/recipes/loader.js +103 -0
  233. package/dist/core/recipes/runner.js +345 -0
  234. package/dist/core/recipes/schema.js +587 -0
  235. package/dist/core/release-notes/parser.js +241 -0
  236. package/dist/core/release-notes/state.js +116 -0
  237. package/dist/core/repl/ask.js +37 -37
  238. package/dist/core/repl/cancellation.js +26 -26
  239. package/dist/core/repl/cap-warning.js +4 -4
  240. package/dist/core/repl/clipboard-read.js +11 -11
  241. package/dist/core/repl/dispatch-fsm.js +12 -12
  242. package/dist/core/repl/engine-bridge.js +303 -0
  243. package/dist/core/repl/history-search.js +15 -15
  244. package/dist/core/repl/history.js +28 -18
  245. package/dist/core/repl/kill-ring.js +5 -5
  246. package/dist/core/repl/model-pricing.js +135 -0
  247. package/dist/core/repl/privacy-banner.js +22 -22
  248. package/dist/core/repl/session.js +2690 -229
  249. package/dist/core/repl/slash-commands.js +540 -41
  250. package/dist/core/repl/store/index.js +1 -1
  251. package/dist/core/repl/store/jsonl-log.js +22 -22
  252. package/dist/core/repl/store/lockfile.js +10 -10
  253. package/dist/core/repl/store/session-store.js +136 -107
  254. package/dist/core/repl/store/types.js +15 -15
  255. package/dist/core/repl/store/uuid-v7.js +12 -12
  256. package/dist/core/repl/tool-route.js +382 -0
  257. package/dist/core/repl/workspace-context.js +43 -21
  258. package/dist/core/repo-map/build.js +125 -0
  259. package/dist/core/repo-map/cache.js +185 -0
  260. package/dist/core/repo-map/extractor.js +254 -0
  261. package/dist/core/repo-map/formatter.js +145 -0
  262. package/dist/core/repo-map/page-rank.js +105 -0
  263. package/dist/core/repo-map/scanner.js +211 -0
  264. package/dist/core/retro/git-collector.js +251 -0
  265. package/dist/core/retro/health-card.js +25 -0
  266. package/dist/core/retro/metrics.js +342 -0
  267. package/dist/core/retro/narrative.js +249 -0
  268. package/dist/core/retro/plane-collector.js +274 -0
  269. package/dist/core/retro/pr-issue-link.js +65 -0
  270. package/dist/core/retro/types.js +16 -0
  271. package/dist/core/retry-budget/budget.js +284 -0
  272. package/dist/core/retry-budget/index.js +5 -0
  273. package/dist/core/retry-budget/retry-cap.js +74 -0
  274. package/dist/core/routing/lead-worker.js +43 -0
  275. package/dist/core/routing/pre-flight-estimator.js +108 -0
  276. package/dist/core/runs/run-tree.js +103 -0
  277. package/dist/core/sandboxing/adapter.js +43 -0
  278. package/dist/core/sandboxing/bubblewrap.js +209 -0
  279. package/dist/core/sandboxing/index.js +78 -0
  280. package/dist/core/sandboxing/none.js +19 -0
  281. package/dist/core/sandboxing/policy.js +97 -0
  282. package/dist/core/sandboxing/seatbelt.js +231 -0
  283. package/dist/core/security/injection-scanner.js +367 -0
  284. package/dist/core/security/output-filter.js +418 -0
  285. package/dist/core/session/env-file.js +105 -0
  286. package/dist/core/session/section-budgets.js +140 -0
  287. package/dist/core/session.js +119 -0
  288. package/dist/core/settings.js +402 -5
  289. package/dist/core/share/formatter.js +271 -0
  290. package/dist/core/share/redactor.js +221 -0
  291. package/dist/core/share/uploader.js +267 -0
  292. package/dist/core/skills/defaults.js +30 -30
  293. package/dist/core/skills/loader.js +22 -22
  294. package/dist/core/skills/sources.js +27 -27
  295. package/dist/core/smoke/headless-driver.js +174 -0
  296. package/dist/core/smoke/orchestrator.js +194 -0
  297. package/dist/core/smoke/runner.js +238 -0
  298. package/dist/core/smoke/scenario-parser.js +316 -0
  299. package/dist/core/statusline.js +99 -0
  300. package/dist/core/subagents/dispatcher-real.js +600 -0
  301. package/dist/core/subagents/dispatcher.js +146 -52
  302. package/dist/core/subagents/index.js +19 -6
  303. package/dist/core/subagents/isolation-matrix.js +213 -0
  304. package/dist/core/subagents/spawn.js +19 -4
  305. package/dist/core/telemetry/emitter.js +229 -0
  306. package/dist/core/telemetry/queue.js +251 -0
  307. package/dist/core/theme/context.js +91 -0
  308. package/dist/core/theme/presets.js +228 -0
  309. package/dist/core/theme/state.js +181 -0
  310. package/dist/core/todos/invariant.js +10 -0
  311. package/dist/core/todos/state.js +177 -0
  312. package/dist/core/tool-schema/compressor.js +89 -0
  313. package/dist/core/transport/version-interceptor.js +166 -0
  314. package/dist/core/trust.js +2 -2
  315. package/dist/core/tui/thinking-block.js +64 -0
  316. package/dist/core/vim/keymap.js +288 -0
  317. package/dist/core/vim/state.js +92 -0
  318. package/dist/core/watch-markers/marker-watcher.js +133 -0
  319. package/dist/core/worktree/include-parser.js +249 -0
  320. package/dist/core/worktree-manager/cleanup.js +123 -0
  321. package/dist/core/worktree-manager/manager.js +303 -0
  322. package/dist/index.js +36 -0
  323. package/dist/runtime/bootstrap.js +190 -0
  324. package/dist/runtime/cli.js +4403 -561
  325. package/dist/runtime/commands/agents.js +31 -31
  326. package/dist/runtime/commands/budget.js +5 -5
  327. package/dist/runtime/commands/cancel.js +231 -0
  328. package/dist/runtime/commands/chain.js +489 -0
  329. package/dist/runtime/commands/codegraph-status.js +227 -0
  330. package/dist/runtime/commands/compact.js +297 -0
  331. package/dist/runtime/commands/config.js +74 -40
  332. package/dist/runtime/commands/cost.js +199 -0
  333. package/dist/runtime/commands/delegate.js +27 -4
  334. package/dist/runtime/commands/dispatch.js +126 -0
  335. package/dist/runtime/commands/doctor.js +579 -0
  336. package/dist/runtime/commands/eval-v1.js +266 -0
  337. package/dist/runtime/commands/feedback.js +184 -0
  338. package/dist/runtime/commands/hooks.js +187 -0
  339. package/dist/runtime/commands/index-cmd.js +459 -0
  340. package/dist/runtime/commands/init.js +254 -0
  341. package/dist/runtime/commands/lsp.js +200 -38
  342. package/dist/runtime/commands/mcp.js +935 -0
  343. package/dist/runtime/commands/memory.js +582 -0
  344. package/dist/runtime/commands/model.js +237 -0
  345. package/dist/runtime/commands/onboarding.js +275 -0
  346. package/dist/runtime/commands/patch.js +12 -12
  347. package/dist/runtime/commands/permissions.js +112 -0
  348. package/dist/runtime/commands/plan.js +143 -0
  349. package/dist/runtime/commands/prd-check.js +285 -0
  350. package/dist/runtime/commands/privacy.js +17 -17
  351. package/dist/runtime/commands/recipe.js +325 -0
  352. package/dist/runtime/commands/redo-blob-store.js +92 -0
  353. package/dist/runtime/commands/redo.js +361 -0
  354. package/dist/runtime/commands/release-notes.js +229 -0
  355. package/dist/runtime/commands/repo-map.js +95 -0
  356. package/dist/runtime/commands/report.js +299 -0
  357. package/dist/runtime/commands/resume.js +118 -0
  358. package/dist/runtime/commands/review-consensus.js +68 -53
  359. package/dist/runtime/commands/rewind.js +333 -0
  360. package/dist/runtime/commands/roster.js +14 -14
  361. package/dist/runtime/commands/servers-cli.js +182 -0
  362. package/dist/runtime/commands/servers.js +236 -0
  363. package/dist/runtime/commands/sessions.js +163 -0
  364. package/dist/runtime/commands/share.js +316 -0
  365. package/dist/runtime/commands/skills.js +31 -31
  366. package/dist/runtime/commands/status.js +186 -0
  367. package/dist/runtime/commands/stickers.js +82 -0
  368. package/dist/runtime/commands/style.js +194 -0
  369. package/dist/runtime/commands/theme.js +196 -0
  370. package/dist/runtime/commands/undo.js +54 -22
  371. package/dist/runtime/commands/update.js +289 -0
  372. package/dist/runtime/commands/vim.js +140 -0
  373. package/dist/runtime/commands/worktree.js +8 -8
  374. package/dist/runtime/commands/worktrees.js +155 -0
  375. package/dist/runtime/deprecation-warning.js +69 -0
  376. package/dist/runtime/engine-exit-code.js +50 -0
  377. package/dist/runtime/headless-repl.js +195 -0
  378. package/dist/runtime/headless.js +548 -0
  379. package/dist/runtime/load-hooks-or-exit.js +71 -0
  380. package/dist/runtime/plan-decompose.js +22 -22
  381. package/dist/runtime/sigint-guard.js +272 -0
  382. package/dist/runtime/stream-renderer.js +195 -0
  383. package/dist/runtime/update-check.js +28 -28
  384. package/dist/runtime/version.js +65 -0
  385. package/dist/runtime/worktree-bootstrap.js +579 -0
  386. package/dist/skills/bundled/batch.js +617 -0
  387. package/dist/skills/bundled/index.js +45 -0
  388. package/dist/skills/bundled/loop.js +358 -0
  389. package/dist/skills/bundled/remember.js +383 -0
  390. package/dist/skills/bundled/simplify.js +289 -0
  391. package/dist/skills/bundled/skillify.js +373 -0
  392. package/dist/skills/bundled/stuck.js +558 -0
  393. package/dist/skills/bundled/verify.js +439 -0
  394. package/dist/testing/vcr.js +486 -0
  395. package/dist/tools/agent-tool.js +229 -0
  396. package/dist/tools/apply-patch.js +89 -28
  397. package/dist/tools/ask-user-question.js +337 -0
  398. package/dist/tools/ask-user.js +115 -0
  399. package/dist/tools/bash.js +811 -49
  400. package/dist/tools/brief.js +224 -0
  401. package/dist/tools/cron.js +433 -0
  402. package/dist/tools/enter-worktree.js +250 -0
  403. package/dist/tools/exit-worktree.js +147 -0
  404. package/dist/tools/file-tools.js +161 -44
  405. package/dist/tools/http-request.js +336 -0
  406. package/dist/tools/lsp-tools.js +377 -1
  407. package/dist/tools/mcp-tool.js +260 -0
  408. package/dist/tools/multi-edit.js +361 -0
  409. package/dist/tools/powershell.js +268 -0
  410. package/dist/tools/registry.js +120 -5
  411. package/dist/tools/server-tools.js +892 -0
  412. package/dist/tools/skill-tool.js +96 -0
  413. package/dist/tools/sleep.js +99 -0
  414. package/dist/tools/synthetic-output.js +133 -0
  415. package/dist/tools/tasks.js +208 -0
  416. package/dist/tools/todo-write.js +184 -0
  417. package/dist/tools/verify-plan-execution.js +295 -0
  418. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  419. package/dist/tools/web-fetch.js +195 -10
  420. package/dist/tools/web-search.js +458 -0
  421. package/dist/tui/agent-progress-card.js +111 -0
  422. package/dist/tui/agent-tree.js +22 -1
  423. package/dist/tui/ask-modal.js +14 -14
  424. package/dist/tui/ask-user-question-chips.js +315 -0
  425. package/dist/tui/ask-user-question-prompt.js +203 -0
  426. package/dist/tui/compact-banner.js +81 -0
  427. package/dist/tui/conversation-pane.js +85 -11
  428. package/dist/tui/cost-table.js +111 -0
  429. package/dist/tui/device-flow.js +2 -2
  430. package/dist/tui/doctor-table.js +46 -0
  431. package/dist/tui/feedback-prompt.js +156 -0
  432. package/dist/tui/input-box.js +247 -32
  433. package/dist/tui/login-picker.js +3 -3
  434. package/dist/tui/markdown-render.js +6 -6
  435. package/dist/tui/multi-file-diff-approval.js +375 -0
  436. package/dist/tui/onboarding-wizard.js +240 -0
  437. package/dist/tui/permissions-picker.js +86 -0
  438. package/dist/tui/render.js +36 -1
  439. package/dist/tui/repl-render.js +239 -25
  440. package/dist/tui/repl-splash-art.js +16 -16
  441. package/dist/tui/repl-splash-mascot.js +48 -24
  442. package/dist/tui/repl-splash.js +22 -22
  443. package/dist/tui/repl.js +125 -45
  444. package/dist/tui/slash-palette.js +6 -6
  445. package/dist/tui/splash.js +2 -2
  446. package/dist/tui/status-bar.js +109 -31
  447. package/dist/tui/status-table.js +7 -0
  448. package/dist/tui/stickers-art.js +136 -0
  449. package/dist/tui/style-table.js +28 -0
  450. package/dist/tui/theme-table.js +29 -0
  451. package/dist/tui/thinking-spinner.js +123 -0
  452. package/dist/tui/tool-stream-pane.js +53 -4
  453. package/dist/tui/update-banner.js +27 -2
  454. package/dist/tui/vim-input.js +267 -0
  455. package/dist/tui/welcome-banner.js +107 -0
  456. package/dist/tui/welcome-data.js +293 -0
  457. package/dist/tui/workspace-context.js +2 -2
  458. package/package.json +29 -6
  459. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  460. package/test/scenarios/compact-force.scenario.txt +12 -0
  461. package/test/scenarios/identity.scenario.txt +11 -0
  462. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  463. package/test/scenarios/walkback.scenario.txt +12 -0
  464. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,254 @@
1
+ /**
2
+ * `pugi init` codebase scan → PUGI.md auto-gen (backlog #82).
3
+ *
4
+ * Extends the existing `init()` scaffold with a project-aware PUGI.md
5
+ * generator. Runs AFTER `scaffoldPugiWorkspace` so the `.pugi/` workspace
6
+ * exists for the `init-report.json` write.
7
+ *
8
+ * Flow:
9
+ *
10
+ * 1. Detect existing PUGI.md. If present without `--force`, refuse
11
+ * with `refused_existing`.
12
+ * 2. Run `detectWorkspace` against cwd.
13
+ * 3. Render PUGI.md content for the requested style.
14
+ * 4. Confirm with the operator unless `--yes` / `--json` / `--force`.
15
+ * 5. Write `<cwd>/PUGI.md` atomically (tmp + rename, fallback к
16
+ * direct write on EXDEV — happens когда tmp lives на a different
17
+ * volume).
18
+ * 6. Write `.pugi/init-report.json` (mode 0o600) with the raw
19
+ * detection payload for re-runs / auditing.
20
+ * 7. Emit a JSON envelope describing the outcome.
21
+ */
22
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
23
+ import { tmpdir } from 'node:os';
24
+ import { dirname, join, resolve } from 'node:path';
25
+ import { createInterface } from 'node:readline';
26
+ import { detectWorkspace } from '../../core/init/detector.js';
27
+ import { renderPugiMd, STYLE_WORD_CAPS, } from '../../core/init/template-renderer.js';
28
+ export const DEFAULT_PUGI_MD_STYLE = 'standard';
29
+ /** Entry point invoked by `cli.ts::init`. */
30
+ export async function runInitScanCommand(args, ctx) {
31
+ const cwd = resolve(ctx.cwd);
32
+ const pugiMdPath = join(cwd, 'PUGI.md');
33
+ const reportPath = join(cwd, '.pugi', 'init-report.json');
34
+ // `args` is currently consumed only via flags. Keep the parameter to
35
+ // mirror every other command surface so we can grow positional args
36
+ // (e.g. an explicit target path) without breaking the call site.
37
+ void args;
38
+ try {
39
+ if (existsSync(pugiMdPath) && !ctx.force) {
40
+ const envelope = {
41
+ command: 'init-scan',
42
+ status: 'refused_existing',
43
+ pugiMdPath,
44
+ reportPath,
45
+ style: ctx.style,
46
+ message: 'PUGI.md already exists. Re-run with --force to overwrite, or edit by hand.',
47
+ };
48
+ ctx.writeOutput(envelope, formatHuman(envelope));
49
+ return envelope;
50
+ }
51
+ const detection = detectWorkspace(cwd);
52
+ const rendered = renderPugiMd(detection, { style: ctx.style, now: ctx.now });
53
+ const shouldConfirm = !ctx.yes && !ctx.json && !ctx.force;
54
+ if (shouldConfirm) {
55
+ const confirm = ctx.confirm ?? defaultConfirm;
56
+ const ok = await confirm(`Write PUGI.md at ${pugiMdPath} (${rendered.wordCount} words, style: ${ctx.style})? [y/N] `);
57
+ if (!ok) {
58
+ const envelope = {
59
+ command: 'init-scan',
60
+ status: 'aborted',
61
+ pugiMdPath,
62
+ reportPath,
63
+ style: ctx.style,
64
+ message: 'Aborted by operator before write.',
65
+ };
66
+ ctx.writeOutput(envelope, formatHuman(envelope));
67
+ return envelope;
68
+ }
69
+ }
70
+ atomicWrite(pugiMdPath, rendered.content);
71
+ writeReport(reportPath, detection, rendered.wordCount, ctx.style);
72
+ const envelope = {
73
+ command: 'init-scan',
74
+ status: 'written',
75
+ pugiMdPath,
76
+ reportPath,
77
+ detection,
78
+ wordCount: rendered.wordCount,
79
+ style: ctx.style,
80
+ };
81
+ ctx.writeOutput(envelope, formatHuman(envelope));
82
+ return envelope;
83
+ }
84
+ catch (error) {
85
+ const message = error instanceof Error ? error.message : String(error);
86
+ const envelope = {
87
+ command: 'init-scan',
88
+ status: 'error',
89
+ pugiMdPath,
90
+ reportPath,
91
+ style: ctx.style,
92
+ message,
93
+ };
94
+ ctx.writeOutput(envelope, formatHuman(envelope));
95
+ return envelope;
96
+ }
97
+ }
98
+ /* ------------------------------------------------------------------ */
99
+ /* Atomic write */
100
+ /* ------------------------------------------------------------------ */
101
+ function atomicWrite(targetPath, content) {
102
+ const dir = dirname(targetPath);
103
+ mkdirSync(dir, { recursive: true });
104
+ const tmpName = `.pugi-md-${process.pid}-${Date.now()}.tmp`;
105
+ const tmpPath = join(tmpdir(), tmpName);
106
+ try {
107
+ writeFileSync(tmpPath, content, { encoding: 'utf8', mode: 0o644 });
108
+ renameSync(tmpPath, targetPath);
109
+ return;
110
+ }
111
+ catch (error) {
112
+ // EXDEV — cross-device link: tmpdir lives on a different volume
113
+ // than the workspace. Retry with the tmpfile inside the workspace.
114
+ cleanupTmp(tmpPath);
115
+ const code = error.code;
116
+ if (code !== 'EXDEV') {
117
+ // Fall through to the in-dir fallback for any rename failure so
118
+ // we keep the contract: PUGI.md is either fully written or not
119
+ // written. The direct writeFileSync at the end is the final
120
+ // safety net.
121
+ }
122
+ const localTmpPath = join(dir, `.pugi-md-${process.pid}-${Date.now()}.tmp`);
123
+ try {
124
+ writeFileSync(localTmpPath, content, { encoding: 'utf8', mode: 0o644 });
125
+ renameSync(localTmpPath, targetPath);
126
+ return;
127
+ }
128
+ catch {
129
+ cleanupTmp(localTmpPath);
130
+ }
131
+ // Final fallback — direct write. We sacrifice the atomicity guarantee
132
+ // here but keep behavioural correctness when both the tmp + in-dir
133
+ // strategies fail (rare; usually FS quirks).
134
+ writeFileSync(targetPath, content, { encoding: 'utf8', mode: 0o644 });
135
+ }
136
+ }
137
+ function cleanupTmp(path) {
138
+ try {
139
+ unlinkSync(path);
140
+ }
141
+ catch {
142
+ // best effort
143
+ }
144
+ }
145
+ function writeReport(reportPath, detection, wordCount, style) {
146
+ mkdirSync(dirname(reportPath), { recursive: true });
147
+ const payload = {
148
+ generatedAt: new Date().toISOString(),
149
+ style,
150
+ wordCap: STYLE_WORD_CAPS[style],
151
+ wordCount,
152
+ detection,
153
+ };
154
+ writeFileSync(reportPath, JSON.stringify(payload, null, 2), {
155
+ encoding: 'utf8',
156
+ mode: 0o600,
157
+ });
158
+ try {
159
+ chmodSync(reportPath, 0o600);
160
+ }
161
+ catch {
162
+ // Some filesystems (FAT, NTFS over CIFS) reject chmod; the mode
163
+ // option on writeFileSync is the primary guard. Best-effort here.
164
+ }
165
+ }
166
+ /* ------------------------------------------------------------------ */
167
+ /* Confirm prompt */
168
+ /* ------------------------------------------------------------------ */
169
+ async function defaultConfirm(question) {
170
+ if (process.stdin.isTTY !== true) {
171
+ return true;
172
+ }
173
+ const rl = createInterface({
174
+ input: process.stdin,
175
+ output: process.stderr,
176
+ });
177
+ return new Promise((resolveAnswer) => {
178
+ let settled = false;
179
+ const settle = (value) => {
180
+ if (settled)
181
+ return;
182
+ settled = true;
183
+ rl.close();
184
+ resolveAnswer(value);
185
+ };
186
+ rl.once('close', () => settle(false));
187
+ rl.question(question, (answer) => {
188
+ settle(/^y(es)?$/i.test(answer.trim()));
189
+ });
190
+ });
191
+ }
192
+ /* ------------------------------------------------------------------ */
193
+ /* Human-readable formatting */
194
+ /* ------------------------------------------------------------------ */
195
+ function formatHuman(env) {
196
+ switch (env.status) {
197
+ case 'written':
198
+ return [
199
+ `PUGI.md written to ${env.pugiMdPath}`,
200
+ ` Style: ${env.style}`,
201
+ ` Word count: ${env.wordCount ?? 0}`,
202
+ ` Report: ${env.reportPath}`,
203
+ ].join('\n');
204
+ case 'refused_existing':
205
+ return env.message ?? 'PUGI.md already exists. Use --force to overwrite.';
206
+ case 'aborted':
207
+ return env.message ?? 'Aborted.';
208
+ case 'error':
209
+ return `pugi init scan failed: ${env.message ?? 'unknown error'}`;
210
+ default:
211
+ return 'pugi init scan complete.';
212
+ }
213
+ }
214
+ /* ------------------------------------------------------------------ */
215
+ /* Helpers consumed by cli.ts */
216
+ /* ------------------------------------------------------------------ */
217
+ /** Parse `--style=<minimal|standard|detailed>` (or `--style minimal`). */
218
+ export function parseInitStyle(args) {
219
+ for (let i = 0; i < args.length; i += 1) {
220
+ const arg = args[i];
221
+ if (typeof arg !== 'string')
222
+ continue;
223
+ if (arg.startsWith('--style=')) {
224
+ const value = arg.slice('--style='.length);
225
+ const parsed = coerceStyle(value);
226
+ if (parsed)
227
+ return parsed;
228
+ }
229
+ else if (arg === '--style') {
230
+ const next = args[i + 1];
231
+ if (typeof next === 'string') {
232
+ const parsed = coerceStyle(next);
233
+ if (parsed)
234
+ return parsed;
235
+ }
236
+ }
237
+ }
238
+ return DEFAULT_PUGI_MD_STYLE;
239
+ }
240
+ function coerceStyle(value) {
241
+ if (value === 'minimal' || value === 'standard' || value === 'detailed')
242
+ return value;
243
+ return null;
244
+ }
245
+ /** Test surface: read back the on-disk report. */
246
+ export function readInitReport(reportPath) {
247
+ try {
248
+ return JSON.parse(readFileSync(reportPath, 'utf8'));
249
+ }
250
+ catch {
251
+ return null;
252
+ }
253
+ }
254
+ //# sourceMappingURL=init.js.map
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `pugi lsp <op> <file> [args...]` — α7.7 Phase 1.
2
+ * `pugi lsp <op> <file> [args...]` — Phase 1.
3
3
  *
4
4
  * Direct LSP queries from the CLI surface. Operators use this for
5
5
  * debugging and scripting; the agent loop reaches the same operations
@@ -8,10 +8,10 @@
8
8
  *
9
9
  * Supported subcommands:
10
10
  *
11
- * pugi lsp hover <file> <line> <col> [--lang ts|js|py|go|rust]
12
- * pugi lsp definition <file> <line> <col> [--lang ...]
13
- * pugi lsp references <file> <line> <col> [--lang ...]
14
- * pugi lsp diagnostics <file> [--lang ...]
11
+ * pugi lsp hover <file> <line> <col> [--lang ts|js|py|go|rust]
12
+ * pugi lsp definition <file> <line> <col> [--lang ...]
13
+ * pugi lsp references <file> <line> <col> [--lang ...]
14
+ * pugi lsp diagnostics <file> [--lang ...]
15
15
  *
16
16
  * When `--lang` is omitted we infer from the file extension. An unknown
17
17
  * extension surfaces `language_unsupported` so the operator can specify
@@ -20,21 +20,68 @@
20
20
  * Lifecycle: we spawn an LSP server per invocation and stop it before
21
21
  * returning. This is slow on cold start (TS server takes ~2-3s the
22
22
  * first time) but the single-shot scripting path doesn't need a
23
- * persistent daemon. Future work (α7.7b) wires a per-REPL daemon.
23
+ * persistent daemon. Future work wires a per-REPL daemon.
24
24
  *
25
25
  * Brand voice: ASCII only, no emoji, no banned words.
26
26
  */
27
- import { extname } from 'node:path';
28
- import { startLspClient } from '../../core/lsp/client.js';
27
+ import { inspectLspServers, startLspClient } from '../../core/lsp/client.js';
28
+ import { languageForFile as inferLanguage } from '../../core/lsp/language-detect.js';
29
+ import { loadSettings } from '../../core/settings.js';
29
30
  export async function runLspCommand(args, opts) {
30
31
  const [op, file, ...rest] = args;
31
- if (!op || !file) {
32
+ if (!op) {
32
33
  return usage();
33
34
  }
35
+ // β7 L9: introspection subcommand. `pugi lsp servers` reports the
36
+ // language matrix — binary-on-PATH + enabled-via-settings — so the
37
+ // operator can debug `lsp_unavailable` vs `lsp_disabled` without
38
+ // re-running an actual hover.
39
+ if (op === 'servers' || op === 'status') {
40
+ const settings = loadSettings(opts.cwd);
41
+ const lspSettings = settings.lsp;
42
+ const rows = inspectLspServers(lspSettings);
43
+ if (opts.json) {
44
+ return { ok: true, text: JSON.stringify(rows, null, 2), exitCode: 0 };
45
+ }
46
+ const lines = ['language\tcommand\tavailable\tenabled'];
47
+ for (const r of rows) {
48
+ lines.push(`${r.language}\t${r.command}\t${r.available ? 'yes' : 'no'}\t${r.enabled ? 'yes' : 'no'}`);
49
+ }
50
+ return { ok: true, text: lines.join('\n'), exitCode: 0 };
51
+ }
52
+ if (!file) {
53
+ return usage();
54
+ }
55
+ // β7 L6: `find_definition` convenience subcommand. Identical wire to
56
+ // `definition` but takes `<symbol>` instead of <line> <col>. We grep
57
+ // the workspace for the first hit on `<symbol>` (whole-word match) to
58
+ // recover a position, then route through LSP. Falls back cleanly when
59
+ // the symbol is not present in the file.
60
+ if (op === 'find_definition' || op === 'find-definition') {
61
+ const { lang: explicitLangFD, positional: positionalFD } = pullLangFlag(rest);
62
+ const symbol = positionalFD[0];
63
+ if (!symbol) {
64
+ return {
65
+ ok: false,
66
+ text: 'Usage: pugi lsp find_definition <file> <symbol> [--lang ts|js|py|go|rust]',
67
+ exitCode: 2,
68
+ };
69
+ }
70
+ const lang = explicitLangFD ?? inferLanguage(file);
71
+ if (!lang) {
72
+ return {
73
+ ok: false,
74
+ text: `cannot infer language from ${file}; pass --lang ts|js|py|go|rust. ` +
75
+ `Supported extensions: .ts/.tsx, .js/.jsx/.mjs, .py, .go, .rs`,
76
+ exitCode: 2,
77
+ };
78
+ }
79
+ return await findDefinition(file, symbol, lang, opts);
80
+ }
34
81
  if (!['hover', 'definition', 'references', 'diagnostics'].includes(op)) {
35
82
  return {
36
83
  ok: false,
37
- text: `unknown lsp operation: ${op}. Supported: hover, definition, references, diagnostics`,
84
+ text: `unknown lsp operation: ${op}. Supported: hover, definition, references, diagnostics, find_definition, servers`,
38
85
  exitCode: 2,
39
86
  };
40
87
  }
@@ -48,7 +95,30 @@ export async function runLspCommand(args, opts) {
48
95
  exitCode: 2,
49
96
  };
50
97
  }
51
- const clientResult = await startLspClient(lang, { cwd: opts.cwd });
98
+ const settings = loadSettings(opts.cwd);
99
+ // `pugi lsp check <file>` — manual probe of
100
+ // the post-edit diagnostics pipeline. Identical output to what the
101
+ // model sees appended to its tool envelope after a successful
102
+ // edit/write. Lets operators dry-run the auto-diagnostic surface
103
+ // without dispatching an actual edit.
104
+ if (op === 'check') {
105
+ const { runPostEditDiagnostics } = await import('../../core/lsp/post-edit-diagnostics.js');
106
+ const result = await runPostEditDiagnostics(file, {
107
+ cwd: opts.cwd,
108
+ ...(settings.lsp ? { lspSettings: settings.lsp } : {}),
109
+ });
110
+ if (opts.json) {
111
+ return { ok: true, text: JSON.stringify(result, null, 2), exitCode: 0 };
112
+ }
113
+ if (result.skip) {
114
+ return { ok: true, text: `${file}: skipped (${result.reason})`, exitCode: 0 };
115
+ }
116
+ return { ok: true, text: result.tail, exitCode: 0 };
117
+ }
118
+ const clientResult = await startLspClient(lang, {
119
+ cwd: opts.cwd,
120
+ ...(settings.lsp ? { lspSettings: settings.lsp } : {}),
121
+ });
52
122
  if (!clientResult.ok) {
53
123
  return {
54
124
  ok: false,
@@ -57,7 +127,7 @@ export async function runLspCommand(args, opts) {
57
127
  };
58
128
  }
59
129
  const client = clientResult.value;
60
- // R1 fix (2026-05-26, PR #413 r1, P2 #12): propagate SIGINT/SIGTERM
130
+ // R1 fix (2026-05-26, PR r1, P2 #12): propagate SIGINT/SIGTERM
61
131
  // to the LSP child process. Without this, ^C in the middle of a
62
132
  // hung definition request would kill the CLI but leave the spawned
63
133
  // language server orphaned (especially expensive for rust-analyzer
@@ -149,13 +219,123 @@ function usage() {
149
219
  return {
150
220
  ok: false,
151
221
  text: 'Usage: pugi lsp <op> <file> [line] [col] [--lang ts|js|py|go|rust]\n' +
152
- ' pugi lsp hover <file> <line> <col>\n' +
153
- ' pugi lsp definition <file> <line> <col>\n' +
154
- ' pugi lsp references <file> <line> <col>\n' +
155
- ' pugi lsp diagnostics <file>',
222
+ ' pugi lsp hover <file> <line> <col>\n' +
223
+ ' pugi lsp definition <file> <line> <col>\n' +
224
+ ' pugi lsp references <file> <line> <col>\n' +
225
+ ' pugi lsp diagnostics <file>\n' +
226
+ ' pugi lsp check <file> (probe post-edit tail)\n' +
227
+ ' pugi lsp find_definition <file> <symbol>\n' +
228
+ ' pugi lsp servers',
156
229
  exitCode: 2,
157
230
  };
158
231
  }
232
+ /**
233
+ * β7 L6: find_definition convenience.
234
+ *
235
+ * Reads the file, walks line-by-line looking for the first whole-word
236
+ * match of `<symbol>`, then runs `lsp definition` at that position.
237
+ * The result is a normal location array — empty when the LSP server
238
+ * can't resolve the symbol (typically because the workspace TS server
239
+ * hasn't indexed the import yet).
240
+ *
241
+ * "Whole-word match" uses the same identifier-boundary rules as Layer
242
+ * D's tokenizer: matches inside string literals / comments / partial
243
+ * identifiers are skipped. This keeps the result aligned with what the
244
+ * operator means by "where is foo defined" — not "any character sequence
245
+ * spelling foo".
246
+ */
247
+ async function findDefinition(file, symbol, lang, opts) {
248
+ const { readFileSync, existsSync } = await import('node:fs');
249
+ const { resolve } = await import('node:path');
250
+ const abs = resolve(opts.cwd, file);
251
+ if (!existsSync(abs)) {
252
+ return { ok: false, text: `file not found: ${file}`, exitCode: 1 };
253
+ }
254
+ let body;
255
+ try {
256
+ body = readFileSync(abs, 'utf8');
257
+ }
258
+ catch (error) {
259
+ const detail = error instanceof Error ? error.message : String(error);
260
+ return { ok: false, text: `cannot read ${file}: ${detail}`, exitCode: 1 };
261
+ }
262
+ const position = locateIdentifier(body, symbol);
263
+ if (!position) {
264
+ return {
265
+ ok: false,
266
+ text: `symbol '${symbol}' not found in ${file}`,
267
+ exitCode: 1,
268
+ };
269
+ }
270
+ const settings = loadSettings(opts.cwd);
271
+ const clientResult = await startLspClient(lang, {
272
+ cwd: opts.cwd,
273
+ ...(settings.lsp ? { lspSettings: settings.lsp } : {}),
274
+ });
275
+ if (!clientResult.ok) {
276
+ return { ok: false, text: `${clientResult.reason}: ${clientResult.detail}`, exitCode: 1 };
277
+ }
278
+ const client = clientResult.value;
279
+ try {
280
+ const result = await client.definition(file, position);
281
+ if (!result.ok) {
282
+ return { ok: false, text: `${result.reason}: ${result.detail}`, exitCode: 1 };
283
+ }
284
+ if (opts.json) {
285
+ return {
286
+ ok: true,
287
+ text: JSON.stringify({
288
+ symbol,
289
+ file,
290
+ sourcePosition: { line: position.line + 1, character: position.character + 1 },
291
+ definitions: result.value,
292
+ }, null, 2),
293
+ exitCode: 0,
294
+ };
295
+ }
296
+ if (result.value.length === 0) {
297
+ return { ok: true, text: `no definition for ${symbol}`, exitCode: 0 };
298
+ }
299
+ const lines = result.value.map((loc) => `${loc.path || loc.uri}:${loc.range.start.line + 1}:${loc.range.start.character + 1}`);
300
+ return { ok: true, text: lines.join('\n'), exitCode: 0 };
301
+ }
302
+ finally {
303
+ await client.stop();
304
+ }
305
+ }
306
+ /**
307
+ * Find the first whole-word occurrence of `symbol` in `body`. Returns
308
+ * the 0-based LSP position (line + character) or null when absent.
309
+ * Uses the same identifier boundary rule as Layer D's tokenizer to
310
+ * avoid matching inside larger identifiers.
311
+ */
312
+ export function locateIdentifier(body, symbol) {
313
+ const lines = body.split('\n');
314
+ // Build the boundary regex once. We can't use `\b` directly because
315
+ // it treats `$` as a word boundary and TS/JS allow `$` in identifiers;
316
+ // implement the boundary check with a manual lookaround.
317
+ const isIdent = (ch) => {
318
+ if (!ch)
319
+ return false;
320
+ return /[A-Za-z0-9_$]/.test(ch);
321
+ };
322
+ for (let line = 0; line < lines.length; line += 1) {
323
+ const text = lines[line];
324
+ let from = 0;
325
+ while (from < text.length) {
326
+ const idx = text.indexOf(symbol, from);
327
+ if (idx === -1)
328
+ break;
329
+ const before = idx > 0 ? text[idx - 1] : undefined;
330
+ const after = idx + symbol.length < text.length ? text[idx + symbol.length] : undefined;
331
+ if (!isIdent(before) && !isIdent(after)) {
332
+ return { line, character: idx };
333
+ }
334
+ from = idx + symbol.length;
335
+ }
336
+ }
337
+ return null;
338
+ }
159
339
  function pullLangFlag(args) {
160
340
  let lang;
161
341
  const positional = [];
@@ -181,26 +361,8 @@ function pullLangFlag(args) {
181
361
  function isLspLanguage(value) {
182
362
  return value === 'ts' || value === 'js' || value === 'py' || value === 'go' || value === 'rust';
183
363
  }
184
- export function inferLanguage(file) {
185
- const ext = extname(file).toLowerCase();
186
- switch (ext) {
187
- case '.ts':
188
- case '.tsx':
189
- return 'ts';
190
- case '.js':
191
- case '.jsx':
192
- case '.mjs':
193
- case '.cjs':
194
- return 'js';
195
- case '.py':
196
- case '.pyi':
197
- return 'py';
198
- case '.go':
199
- return 'go';
200
- case '.rs':
201
- return 'rust';
202
- default:
203
- return undefined;
204
- }
205
- }
364
+ // single source of truth for ext → language
365
+ // lives in `core/lsp/language-detect.ts`. The CLI surface re-exports
366
+ // the lookup so existing call sites keep their import path.
367
+ export { inferLanguage };
206
368
  //# sourceMappingURL=lsp.js.map