@pugi/cli 0.1.0-beta.99 → 1.0.0-alpha.1

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 (448) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +11 -191
  3. package/bin/pugi +8 -0
  4. package/package.json +15 -71
  5. package/postinstall.mjs +31 -0
  6. package/CHANGELOG.md +0 -132
  7. package/THIRD_PARTY_NOTICES.md +0 -40
  8. package/assets/pugi-mascot.ansi +0 -16
  9. package/assets/pugi-prozr2-mascot.ansi +0 -9
  10. package/bin/run.js +0 -34
  11. package/dist/commands/deploy.js +0 -439
  12. package/dist/commands/flatten.js +0 -191
  13. package/dist/commands/jobs-watch.js +0 -201
  14. package/dist/commands/jobs.js +0 -260
  15. package/dist/commands/retro.js +0 -210
  16. package/dist/commands/smoke.js +0 -133
  17. package/dist/core/agent-progress/cleanup.js +0 -134
  18. package/dist/core/agent-progress/schema.js +0 -144
  19. package/dist/core/agent-progress/writer.js +0 -101
  20. package/dist/core/agents/adaptive-router.js +0 -330
  21. package/dist/core/agents/loader.js +0 -104
  22. package/dist/core/agents/query-decomposer.js +0 -297
  23. package/dist/core/agents/registry.js +0 -69
  24. package/dist/core/approvals/shortcut-resolver.js +0 -98
  25. package/dist/core/artifact-chain/dispatcher.js +0 -148
  26. package/dist/core/artifact-chain/exporter.js +0 -164
  27. package/dist/core/artifact-chain/state.js +0 -243
  28. package/dist/core/artifact-chain/steps.js +0 -169
  29. package/dist/core/ask-user/question.js +0 -92
  30. package/dist/core/audit/audit-trail.js +0 -275
  31. package/dist/core/auth/ensure-authenticated.js +0 -129
  32. package/dist/core/auth/env-provider.js +0 -238
  33. package/dist/core/auto-open-browser.js +0 -128
  34. package/dist/core/auto-update/channels.js +0 -122
  35. package/dist/core/auto-update/checker.js +0 -241
  36. package/dist/core/auto-update/state.js +0 -235
  37. package/dist/core/bare-mode/index.js +0 -107
  38. package/dist/core/bash/redirect.js +0 -281
  39. package/dist/core/bash-classifier.js +0 -1397
  40. package/dist/core/checkpoint/resumer.js +0 -149
  41. package/dist/core/checkpoint/rewinder.js +0 -291
  42. package/dist/core/checkpoints/shadow-git.js +0 -670
  43. package/dist/core/citations/parser.js +0 -109
  44. package/dist/core/classifier/yolo-classifier.js +0 -88
  45. package/dist/core/clipboard.js +0 -70
  46. package/dist/core/codegraph/decision-store.js +0 -248
  47. package/dist/core/codegraph/detect-repo.js +0 -459
  48. package/dist/core/codegraph/install.js +0 -134
  49. package/dist/core/codegraph/offer-hook.js +0 -220
  50. package/dist/core/compact/auto-trigger.js +0 -96
  51. package/dist/core/compact/buffer-rewriter.js +0 -115
  52. package/dist/core/compact/summarizer.js +0 -208
  53. package/dist/core/compact/token-counter.js +0 -108
  54. package/dist/core/consensus/anvil-fanout.js +0 -276
  55. package/dist/core/consensus/diff-capture.js +0 -491
  56. package/dist/core/consensus/rubric.js +0 -233
  57. package/dist/core/context/builder.js +0 -114
  58. package/dist/core/context/compaction-events.js +0 -99
  59. package/dist/core/context/compaction.js +0 -602
  60. package/dist/core/context/index.js +0 -28
  61. package/dist/core/context/invariants.js +0 -250
  62. package/dist/core/context/markdown-loader.js +0 -288
  63. package/dist/core/context/markdown-traverse.js +0 -255
  64. package/dist/core/context/pugiignore.js +0 -316
  65. package/dist/core/context/repo-skeleton.js +0 -533
  66. package/dist/core/context/tool-eviction.js +0 -55
  67. package/dist/core/context/watcher.js +0 -342
  68. package/dist/core/context/working-set.js +0 -165
  69. package/dist/core/coordinator/agent-tools.js +0 -77
  70. package/dist/core/coordinator/agent-toolset.js +0 -65
  71. package/dist/core/coordinator/fsm.js +0 -73
  72. package/dist/core/coordinator/mode-fsm.js +0 -70
  73. package/dist/core/cost/rate-card.js +0 -129
  74. package/dist/core/cost/tracker.js +0 -221
  75. package/dist/core/credentials.js +0 -355
  76. package/dist/core/cron/scheduler.js +0 -138
  77. package/dist/core/denial-tracking/index.js +0 -8
  78. package/dist/core/denial-tracking/state.js +0 -264
  79. package/dist/core/diagnostics/probe-runner.js +0 -93
  80. package/dist/core/diagnostics/probes/api.js +0 -46
  81. package/dist/core/diagnostics/probes/auth.js +0 -93
  82. package/dist/core/diagnostics/probes/bare-mode.js +0 -42
  83. package/dist/core/diagnostics/probes/cli-version.js +0 -127
  84. package/dist/core/diagnostics/probes/config.js +0 -72
  85. package/dist/core/diagnostics/probes/denial-tracking.js +0 -57
  86. package/dist/core/diagnostics/probes/disk.js +0 -81
  87. package/dist/core/diagnostics/probes/engine-live.js +0 -46
  88. package/dist/core/diagnostics/probes/git.js +0 -65
  89. package/dist/core/diagnostics/probes/hooks.js +0 -118
  90. package/dist/core/diagnostics/probes/mcp.js +0 -75
  91. package/dist/core/diagnostics/probes/node.js +0 -59
  92. package/dist/core/diagnostics/probes/pnpm.js +0 -36
  93. package/dist/core/diagnostics/probes/pugi-md.js +0 -89
  94. package/dist/core/diagnostics/probes/sandbox.js +0 -72
  95. package/dist/core/diagnostics/probes/session.js +0 -74
  96. package/dist/core/diagnostics/probes/status-snapshot.js +0 -488
  97. package/dist/core/diagnostics/probes/workspace.js +0 -63
  98. package/dist/core/diagnostics/types.js +0 -70
  99. package/dist/core/dispatch/cache-cleanup.js +0 -197
  100. package/dist/core/dispatch/cache-handoff.js +0 -295
  101. package/dist/core/edits/apply-patch-layer-e.js +0 -189
  102. package/dist/core/edits/dispatch.js +0 -511
  103. package/dist/core/edits/format-detector.js +0 -260
  104. package/dist/core/edits/format-matrix.js +0 -26
  105. package/dist/core/edits/fuzzy-ladder.js +0 -650
  106. package/dist/core/edits/index.js +0 -19
  107. package/dist/core/edits/journal.js +0 -199
  108. package/dist/core/edits/layer-a-apply.js +0 -217
  109. package/dist/core/edits/layer-a-fuzzy-apply.js +0 -198
  110. package/dist/core/edits/layer-b-apply.js +0 -211
  111. package/dist/core/edits/layer-c-apply.js +0 -160
  112. package/dist/core/edits/layer-d-ast.js +0 -572
  113. package/dist/core/edits/marker-parser.js +0 -401
  114. package/dist/core/edits/security-gate.js +0 -223
  115. package/dist/core/edits/verify-hook.js +0 -273
  116. package/dist/core/edits/worktree.js +0 -322
  117. package/dist/core/engine/adapter-runner.js +0 -8
  118. package/dist/core/engine/anvil-client.js +0 -344
  119. package/dist/core/engine/auto-compact.js +0 -179
  120. package/dist/core/engine/budgets.js +0 -195
  121. package/dist/core/engine/context-prefix.js +0 -155
  122. package/dist/core/engine/index.js +0 -12
  123. package/dist/core/engine/intensity.js +0 -163
  124. package/dist/core/engine/intent.js +0 -260
  125. package/dist/core/engine/native-pugi.js +0 -1616
  126. package/dist/core/engine/noop.js +0 -27
  127. package/dist/core/engine/prompts.js +0 -236
  128. package/dist/core/engine/strip-internal-fields.js +0 -124
  129. package/dist/core/engine/tool-bridge.js +0 -2173
  130. package/dist/core/engine/verification-patterns.js +0 -195
  131. package/dist/core/evaluation/golden-dataset.js +0 -293
  132. package/dist/core/feedback/queue.js +0 -177
  133. package/dist/core/feedback/submitter.js +0 -145
  134. package/dist/core/file-cache.js +0 -141
  135. package/dist/core/flatten/flatten-repo.js +0 -439
  136. package/dist/core/format/osc8-link.js +0 -28
  137. package/dist/core/hook-chains.js +0 -392
  138. package/dist/core/hooks/citation-verify-hook.js +0 -138
  139. package/dist/core/hooks/citation-verify.js +0 -112
  140. package/dist/core/hooks/events.js +0 -46
  141. package/dist/core/hooks/index.js +0 -15
  142. package/dist/core/hooks/registry.js +0 -216
  143. package/dist/core/hooks/runner.js +0 -236
  144. package/dist/core/hooks/v2/event-emitter.js +0 -115
  145. package/dist/core/hooks/v2/executor.js +0 -282
  146. package/dist/core/hooks/v2/index.js +0 -25
  147. package/dist/core/hooks/v2/lifecycle.js +0 -104
  148. package/dist/core/hooks/v2/loader.js +0 -216
  149. package/dist/core/hooks/v2/matcher.js +0 -125
  150. package/dist/core/hooks/v2/trust.js +0 -143
  151. package/dist/core/hooks/v2/types.js +0 -86
  152. package/dist/core/hooks/worktree-events.js +0 -158
  153. package/dist/core/hooks.js +0 -415
  154. package/dist/core/image/renderer.js +0 -71
  155. package/dist/core/index-store.js +0 -260
  156. package/dist/core/init/detector.js +0 -582
  157. package/dist/core/init/template-renderer.js +0 -242
  158. package/dist/core/jobs/registry.js +0 -462
  159. package/dist/core/ledger/results-tsv.js +0 -142
  160. package/dist/core/log-discipline/stdout-redirect.js +0 -51
  161. package/dist/core/lsp/cache.js +0 -105
  162. package/dist/core/lsp/client.js +0 -1229
  163. package/dist/core/lsp/language-detect.js +0 -66
  164. package/dist/core/lsp/post-edit-diagnostics.js +0 -171
  165. package/dist/core/lsp/server-detect.js +0 -173
  166. package/dist/core/lsp/symbol-cache.js +0 -162
  167. package/dist/core/lsp/symbol-tools.js +0 -664
  168. package/dist/core/mcp/client.js +0 -385
  169. package/dist/core/mcp/http-server.js +0 -553
  170. package/dist/core/mcp/orchestrator-config.js +0 -192
  171. package/dist/core/mcp/orchestrator-tools.js +0 -806
  172. package/dist/core/mcp/permission.js +0 -190
  173. package/dist/core/mcp/registry.js +0 -193
  174. package/dist/core/mcp/server-tools.js +0 -219
  175. package/dist/core/mcp/server.js +0 -397
  176. package/dist/core/mcp/trust.js +0 -91
  177. package/dist/core/memory/dual-write.js +0 -416
  178. package/dist/core/memory/passive-extract.js +0 -130
  179. package/dist/core/memory/phase1-kinds.js +0 -20
  180. package/dist/core/memory/secret-scanner.js +0 -304
  181. package/dist/core/memory-sync/queue.js +0 -170
  182. package/dist/core/metrics/extract.js +0 -113
  183. package/dist/core/modes/roo-modes.js +0 -68
  184. package/dist/core/onboarding/ensure-initialized.js +0 -133
  185. package/dist/core/onboarding/marker.js +0 -111
  186. package/dist/core/onboarding/telemetry-state.js +0 -108
  187. package/dist/core/output-style/presets.js +0 -176
  188. package/dist/core/output-style/state.js +0 -185
  189. package/dist/core/path-security.js +0 -345
  190. package/dist/core/permission.js +0 -369
  191. package/dist/core/permissions/auto-classifier.js +0 -124
  192. package/dist/core/permissions/bash-parser.js +0 -371
  193. package/dist/core/permissions/circuit-breaker.js +0 -83
  194. package/dist/core/permissions/constrained-edit.js +0 -91
  195. package/dist/core/permissions/gate.js +0 -278
  196. package/dist/core/permissions/index.js +0 -20
  197. package/dist/core/permissions/mode.js +0 -174
  198. package/dist/core/permissions/network-egress.js +0 -137
  199. package/dist/core/permissions/state.js +0 -241
  200. package/dist/core/permissions/tool-class.js +0 -107
  201. package/dist/core/plan-mode/ui-state.js +0 -51
  202. package/dist/core/plans/plan-artifact.js +0 -721
  203. package/dist/core/policy-limits/etag-store.js +0 -122
  204. package/dist/core/prd-check/parser.js +0 -215
  205. package/dist/core/prd-check/reporter.js +0 -127
  206. package/dist/core/prd-check/session-review.js +0 -557
  207. package/dist/core/prd-check/verifiers.js +0 -223
  208. package/dist/core/prompt-cache/client-cache.js +0 -99
  209. package/dist/core/prompts/assembly.js +0 -29
  210. package/dist/core/prompts/registry.js +0 -364
  211. package/dist/core/pugi-gitignore.js +0 -52
  212. package/dist/core/pugi-md/cc-compat-rules.js +0 -735
  213. package/dist/core/pugi-md/context-injector.js +0 -76
  214. package/dist/core/pugi-md/walk-up.js +0 -207
  215. package/dist/core/python/uv-installer.js +0 -270
  216. package/dist/core/python/uv-resolver.js +0 -83
  217. package/dist/core/rate-limit/narrator.js +0 -146
  218. package/dist/core/recipes/cli-types.js +0 -20
  219. package/dist/core/recipes/loader.js +0 -103
  220. package/dist/core/recipes/runner.js +0 -345
  221. package/dist/core/recipes/schema.js +0 -587
  222. package/dist/core/release-notes/parser.js +0 -241
  223. package/dist/core/release-notes/state.js +0 -116
  224. package/dist/core/repl/ask.js +0 -512
  225. package/dist/core/repl/cancellation.js +0 -98
  226. package/dist/core/repl/cap-warning.js +0 -91
  227. package/dist/core/repl/clipboard-read.js +0 -174
  228. package/dist/core/repl/dispatch-fsm.js +0 -220
  229. package/dist/core/repl/engine-bridge.js +0 -303
  230. package/dist/core/repl/history-search.js +0 -175
  231. package/dist/core/repl/history.js +0 -182
  232. package/dist/core/repl/kill-ring.js +0 -138
  233. package/dist/core/repl/model-pricing.js +0 -135
  234. package/dist/core/repl/privacy-banner.js +0 -71
  235. package/dist/core/repl/session.js +0 -4962
  236. package/dist/core/repl/slash-commands.js +0 -747
  237. package/dist/core/repl/store/index.js +0 -12
  238. package/dist/core/repl/store/jsonl-log.js +0 -321
  239. package/dist/core/repl/store/lockfile.js +0 -155
  240. package/dist/core/repl/store/session-store.js +0 -821
  241. package/dist/core/repl/store/types.js +0 -44
  242. package/dist/core/repl/store/uuid-v7.js +0 -68
  243. package/dist/core/repl/tool-route.js +0 -382
  244. package/dist/core/repl/workspace-context.js +0 -206
  245. package/dist/core/repo-map/build.js +0 -125
  246. package/dist/core/repo-map/cache.js +0 -185
  247. package/dist/core/repo-map/extractor.js +0 -254
  248. package/dist/core/repo-map/formatter.js +0 -145
  249. package/dist/core/repo-map/page-rank.js +0 -105
  250. package/dist/core/repo-map/scanner.js +0 -211
  251. package/dist/core/retro/git-collector.js +0 -251
  252. package/dist/core/retro/health-card.js +0 -25
  253. package/dist/core/retro/metrics.js +0 -342
  254. package/dist/core/retro/narrative.js +0 -249
  255. package/dist/core/retro/plane-collector.js +0 -274
  256. package/dist/core/retro/pr-issue-link.js +0 -65
  257. package/dist/core/retro/types.js +0 -16
  258. package/dist/core/retry-budget/budget.js +0 -284
  259. package/dist/core/retry-budget/index.js +0 -5
  260. package/dist/core/retry-budget/retry-cap.js +0 -74
  261. package/dist/core/routing/lead-worker.js +0 -43
  262. package/dist/core/routing/pre-flight-estimator.js +0 -108
  263. package/dist/core/runs/run-tree.js +0 -103
  264. package/dist/core/sandboxing/adapter.js +0 -29
  265. package/dist/core/sandboxing/index.js +0 -49
  266. package/dist/core/sandboxing/none.js +0 -19
  267. package/dist/core/sandboxing/seatbelt.js +0 -183
  268. package/dist/core/security/injection-scanner.js +0 -367
  269. package/dist/core/security/output-filter.js +0 -418
  270. package/dist/core/session/env-file.js +0 -105
  271. package/dist/core/session/section-budgets.js +0 -140
  272. package/dist/core/session.js +0 -377
  273. package/dist/core/settings.js +0 -400
  274. package/dist/core/share/formatter.js +0 -271
  275. package/dist/core/share/redactor.js +0 -221
  276. package/dist/core/share/uploader.js +0 -267
  277. package/dist/core/skills/defaults.js +0 -457
  278. package/dist/core/skills/loader.js +0 -454
  279. package/dist/core/skills/sources.js +0 -480
  280. package/dist/core/skills/trust.js +0 -172
  281. package/dist/core/smoke/headless-driver.js +0 -174
  282. package/dist/core/smoke/orchestrator.js +0 -194
  283. package/dist/core/smoke/runner.js +0 -238
  284. package/dist/core/smoke/scenario-parser.js +0 -316
  285. package/dist/core/statusline.js +0 -99
  286. package/dist/core/subagents/dispatcher-real.js +0 -600
  287. package/dist/core/subagents/dispatcher.js +0 -352
  288. package/dist/core/subagents/index.js +0 -39
  289. package/dist/core/subagents/isolation-matrix.js +0 -213
  290. package/dist/core/subagents/spawn.js +0 -101
  291. package/dist/core/telemetry/emitter.js +0 -229
  292. package/dist/core/telemetry/queue.js +0 -251
  293. package/dist/core/theme/context.js +0 -91
  294. package/dist/core/theme/presets.js +0 -228
  295. package/dist/core/theme/state.js +0 -181
  296. package/dist/core/todos/invariant.js +0 -10
  297. package/dist/core/todos/state.js +0 -177
  298. package/dist/core/tool-schema/compressor.js +0 -89
  299. package/dist/core/transport/version-interceptor.js +0 -166
  300. package/dist/core/trust.js +0 -109
  301. package/dist/core/tui/thinking-block.js +0 -64
  302. package/dist/core/vim/keymap.js +0 -288
  303. package/dist/core/vim/state.js +0 -92
  304. package/dist/core/watch-markers/marker-watcher.js +0 -133
  305. package/dist/core/worktree/include-parser.js +0 -249
  306. package/dist/core/worktree-manager/cleanup.js +0 -123
  307. package/dist/core/worktree-manager/manager.js +0 -303
  308. package/dist/index.js +0 -44
  309. package/dist/runtime/bootstrap.js +0 -190
  310. package/dist/runtime/cli.js +0 -8121
  311. package/dist/runtime/commands/agents.js +0 -385
  312. package/dist/runtime/commands/budget.js +0 -192
  313. package/dist/runtime/commands/cancel.js +0 -231
  314. package/dist/runtime/commands/chain.js +0 -489
  315. package/dist/runtime/commands/codegraph-status.js +0 -227
  316. package/dist/runtime/commands/compact.js +0 -297
  317. package/dist/runtime/commands/config.js +0 -595
  318. package/dist/runtime/commands/cost.js +0 -199
  319. package/dist/runtime/commands/delegate.js +0 -312
  320. package/dist/runtime/commands/dispatch.js +0 -126
  321. package/dist/runtime/commands/doctor.js +0 -579
  322. package/dist/runtime/commands/feedback.js +0 -184
  323. package/dist/runtime/commands/hooks.js +0 -187
  324. package/dist/runtime/commands/init.js +0 -254
  325. package/dist/runtime/commands/lsp.js +0 -368
  326. package/dist/runtime/commands/mcp.js +0 -935
  327. package/dist/runtime/commands/memory.js +0 -582
  328. package/dist/runtime/commands/model.js +0 -237
  329. package/dist/runtime/commands/onboarding.js +0 -275
  330. package/dist/runtime/commands/patch.js +0 -128
  331. package/dist/runtime/commands/permissions.js +0 -112
  332. package/dist/runtime/commands/plan.js +0 -143
  333. package/dist/runtime/commands/prd-check.js +0 -285
  334. package/dist/runtime/commands/privacy.js +0 -107
  335. package/dist/runtime/commands/recipe.js +0 -325
  336. package/dist/runtime/commands/redo-blob-store.js +0 -92
  337. package/dist/runtime/commands/redo.js +0 -361
  338. package/dist/runtime/commands/release-notes.js +0 -229
  339. package/dist/runtime/commands/repo-map.js +0 -95
  340. package/dist/runtime/commands/report.js +0 -299
  341. package/dist/runtime/commands/resume.js +0 -118
  342. package/dist/runtime/commands/review-consensus.js +0 -414
  343. package/dist/runtime/commands/rewind.js +0 -333
  344. package/dist/runtime/commands/roster.js +0 -117
  345. package/dist/runtime/commands/sessions.js +0 -163
  346. package/dist/runtime/commands/share.js +0 -316
  347. package/dist/runtime/commands/skills.js +0 -401
  348. package/dist/runtime/commands/status.js +0 -186
  349. package/dist/runtime/commands/stickers.js +0 -82
  350. package/dist/runtime/commands/style.js +0 -194
  351. package/dist/runtime/commands/theme.js +0 -196
  352. package/dist/runtime/commands/undo.js +0 -361
  353. package/dist/runtime/commands/update.js +0 -289
  354. package/dist/runtime/commands/vim.js +0 -140
  355. package/dist/runtime/commands/worktree.js +0 -177
  356. package/dist/runtime/commands/worktrees.js +0 -155
  357. package/dist/runtime/deprecation-warning.js +0 -69
  358. package/dist/runtime/engine-exit-code.js +0 -50
  359. package/dist/runtime/headless-repl.js +0 -195
  360. package/dist/runtime/headless.js +0 -548
  361. package/dist/runtime/load-hooks-or-exit.js +0 -71
  362. package/dist/runtime/plan-decompose.js +0 -531
  363. package/dist/runtime/sigint-guard.js +0 -272
  364. package/dist/runtime/stream-renderer.js +0 -195
  365. package/dist/runtime/update-check.js +0 -294
  366. package/dist/runtime/version.js +0 -65
  367. package/dist/runtime/worktree-bootstrap.js +0 -579
  368. package/dist/skills/bundled/batch.js +0 -617
  369. package/dist/skills/bundled/index.js +0 -45
  370. package/dist/skills/bundled/loop.js +0 -358
  371. package/dist/skills/bundled/remember.js +0 -383
  372. package/dist/skills/bundled/simplify.js +0 -289
  373. package/dist/skills/bundled/skillify.js +0 -373
  374. package/dist/skills/bundled/stuck.js +0 -558
  375. package/dist/skills/bundled/verify.js +0 -439
  376. package/dist/testing/vcr.js +0 -486
  377. package/dist/tools/agent-tool.js +0 -229
  378. package/dist/tools/apply-patch.js +0 -556
  379. package/dist/tools/ask-user-question.js +0 -337
  380. package/dist/tools/ask-user.js +0 -115
  381. package/dist/tools/bash.js +0 -1238
  382. package/dist/tools/brief.js +0 -224
  383. package/dist/tools/cron.js +0 -433
  384. package/dist/tools/enter-worktree.js +0 -250
  385. package/dist/tools/exit-worktree.js +0 -147
  386. package/dist/tools/file-tools.js +0 -553
  387. package/dist/tools/http-request.js +0 -336
  388. package/dist/tools/lsp-tools.js +0 -565
  389. package/dist/tools/mcp-tool.js +0 -260
  390. package/dist/tools/multi-edit.js +0 -361
  391. package/dist/tools/powershell.js +0 -268
  392. package/dist/tools/registry.js +0 -166
  393. package/dist/tools/server-tools.js +0 -892
  394. package/dist/tools/skill-tool.js +0 -96
  395. package/dist/tools/sleep.js +0 -99
  396. package/dist/tools/synthetic-output.js +0 -133
  397. package/dist/tools/tasks.js +0 -208
  398. package/dist/tools/todo-write.js +0 -184
  399. package/dist/tools/verify-plan-execution.js +0 -295
  400. package/dist/tools/web-fetch-injection-scanner.js +0 -207
  401. package/dist/tools/web-fetch.js +0 -720
  402. package/dist/tools/web-search.js +0 -458
  403. package/dist/tui/agent-progress-card.js +0 -111
  404. package/dist/tui/agent-tree-pane.js +0 -9
  405. package/dist/tui/agent-tree.js +0 -87
  406. package/dist/tui/ask-cli.js +0 -52
  407. package/dist/tui/ask-modal.js +0 -211
  408. package/dist/tui/ask-user-question-chips.js +0 -315
  409. package/dist/tui/ask-user-question-prompt.js +0 -203
  410. package/dist/tui/compact-banner.js +0 -81
  411. package/dist/tui/conversation-pane.js +0 -164
  412. package/dist/tui/cost-table.js +0 -111
  413. package/dist/tui/device-flow.js +0 -142
  414. package/dist/tui/doctor-table.js +0 -46
  415. package/dist/tui/feedback-prompt.js +0 -156
  416. package/dist/tui/input-box.js +0 -732
  417. package/dist/tui/login-picker.js +0 -69
  418. package/dist/tui/markdown-render.js +0 -266
  419. package/dist/tui/multi-file-diff-approval.js +0 -375
  420. package/dist/tui/onboarding-wizard.js +0 -240
  421. package/dist/tui/permissions-picker.js +0 -86
  422. package/dist/tui/render.js +0 -160
  423. package/dist/tui/repl-render.js +0 -770
  424. package/dist/tui/repl-splash-art.js +0 -64
  425. package/dist/tui/repl-splash-mascot.js +0 -154
  426. package/dist/tui/repl-splash.js +0 -117
  427. package/dist/tui/repl.js +0 -378
  428. package/dist/tui/slash-palette.js +0 -106
  429. package/dist/tui/splash-data.js +0 -61
  430. package/dist/tui/splash.js +0 -31
  431. package/dist/tui/status-bar.js +0 -209
  432. package/dist/tui/status-table.js +0 -7
  433. package/dist/tui/stickers-art.js +0 -136
  434. package/dist/tui/style-table.js +0 -28
  435. package/dist/tui/theme-table.js +0 -29
  436. package/dist/tui/thinking-spinner.js +0 -123
  437. package/dist/tui/tool-stream-pane.js +0 -140
  438. package/dist/tui/update-banner.js +0 -33
  439. package/dist/tui/vim-input.js +0 -267
  440. package/dist/tui/welcome-banner.js +0 -107
  441. package/dist/tui/welcome-data.js +0 -293
  442. package/dist/tui/workspace-context.js +0 -105
  443. package/docs/examples/codegraph.mcp.json +0 -10
  444. package/test/scenarios/codegen-create-file.scenario.txt +0 -13
  445. package/test/scenarios/compact-force.scenario.txt +0 -12
  446. package/test/scenarios/identity.scenario.txt +0 -11
  447. package/test/scenarios/persona-handoff.scenario.txt +0 -12
  448. package/test/scenarios/walkback.scenario.txt +0 -12
@@ -1,770 +0,0 @@
1
- /**
2
- * Production REPL mount + transport - Sprint .
3
- *
4
- * Owns the Ink mount lifecycle for `<Repl />` and wires the real
5
- * fetch + SSE transport. The CLI dispatcher in `runtime/cli.ts` calls
6
- * `renderRepl` on the bare-`pugi` path when stdin / stdout are TTYs.
7
- *
8
- * The transport speaks to admin-api:
9
- * POST /api/pugi/sessions → { sessionId }
10
- * POST /api/pugi/sessions/:id/brief → { dispatchId }
11
- * POST /api/pugi/sessions/:id/stop → { stopped }
12
- * GET /api/pugi/sessions/:id/stream → text/event-stream
13
- *
14
- * SSE is parsed client-side from a streaming fetch response - Node 22
15
- * native fetch returns a WHATWG `ReadableStream` which we feed through
16
- * a tiny `event:`/`data:`/`id:` parser. This keeps the dependency
17
- * graph at zero new packages.
18
- */
19
- import { existsSync } from 'node:fs';
20
- import { resolve } from 'node:path';
21
- import React from 'react';
22
- import { render } from 'ink';
23
- import { Repl } from './repl.js';
24
- import { printPugMascotPreInk } from './repl-splash-mascot.js';
25
- import { collectWelcomeData } from './welcome-data.js';
26
- import { ThemeProvider } from '../core/theme/context.js';
27
- import { resolveTheme } from '../core/theme/state.js';
28
- import { ReplSession, } from '../core/repl/session.js';
29
- import { resolveWorkspaceContext } from '../core/repl/workspace-context.js';
30
- import { createEngineBridge } from '../core/repl/engine-bridge.js';
31
- import { profileFor, resolveIntensity } from '../core/engine/intensity.js';
32
- import { SqliteSessionStore } from '../core/repl/store/index.js';
33
- import { slugForCwd } from '../core/repl/history.js';
34
- import { loadSettings } from '../core/settings.js';
35
- import { buildRuntimeConfig } from '@pugi/sdk';
36
- import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../core/context/index.js';
37
- /**
38
- * Mount the REPL and resolve when the user exits via Ctrl+C × 2 or
39
- * `/quit`. The session is closed (server-side stays alive; resume via
40
- * `pugi resume <sessionId>` once that command exists).
41
- */
42
- export async function renderRepl(options) {
43
- // beta.9 CEO dogfood: claim stdin raw mode + alt-screen
44
- // BEFORE any async bootstrap step so keystrokes typed during the
45
- // [launch -> Ink mount] window cannot echo into the terminal in
46
- // cooked mode. Previously openLocalStore (SQLite open) +
47
- // bootstrapContext (chokidar start) could take hundreds of ms to
48
- // multiple seconds on a fresh install / large repo; during that
49
- // window stdin stayed in cooked mode and the terminal echoed
50
- // every typed character literally onto the screen below the
51
- // pre-printed mascot/header. The visible result was the operator's
52
- // "ssssss" landing on the rendered status-bar bottom row (CEO
53
- // screenshot: beta.8 REPL bug 2).
54
- //
55
- // The claim is idempotent with Ink's own raw-mode enable: Ink
56
- // ref-counts setRawMode calls, and Node's stdin.setRawMode is
57
- // safe to call twice with the same value. The pre-Ink claim acts
58
- // as a "raw-mode floor" - whatever Ink does after mount layers on
59
- // top, and our finally{} restore drops the floor only after Ink
60
- // has cleanly torn down (or never mounted on a bootstrap crash).
61
- const bootstrap = claimTerminalForRepl();
62
- // beta.13 auto-init wire (CEO dogfood): scaffold the
63
- // `.pugi/` workspace silently on REPL boot so launching `pugi` in a
64
- // fresh cwd no longer demands an explicit `pugi init` round-trip.
65
- // Idempotent — every helper inside scaffoldPugiWorkspace is a
66
- // `*_IfMissing` write, so re-running over an existing workspace is
67
- // a no-op. Fail-safe: any FS / perms error never blocks REPL launch.
68
- // Operator escape hatch: PUGI_NO_AUTO_INIT=1.
69
- //
70
- // Beta.13 P2 fix: gate the scaffold on project-root markers
71
- // so launching `pugi` from `$HOME` / `/tmp` / arbitrary dirs does NOT
72
- // sprinkle `.pugi/` directories all over the filesystem. The gate
73
- // mirrors `isBoundWorkspace` from workspace-context.ts but also
74
- // accepts non-JS roots (Cargo / pyproject / go.mod) because the CLI
75
- // is language-agnostic and an operator working in a Rust repo deserves
76
- // the same auto-init UX as a Node operator. Already-bound `.pugi/`
77
- // dirs also opt back in so the scaffold can fill any missing
78
- // sub-artifacts the operator deleted.
79
- // `--bare` (PUGI_BARE=1) ALSO suppresses the
80
- // auto-init scaffold. Bare mode is the deterministic "fresh install
81
- // anywhere" path — no `.pugi/` writes, no PUGI.md scaffold, no
82
- // settings.json seed. The pre-existing PUGI_NO_AUTO_INIT escape
83
- // hatch stays — bare mode just unions with it.
84
- const { isBareMode } = await import('../core/bare-mode/index.js');
85
- if (process.env.PUGI_NO_AUTO_INIT !== '1' &&
86
- !isBareMode() &&
87
- isProjectRoot(process.cwd())) {
88
- try {
89
- const { scaffoldPugiWorkspace } = await import('../runtime/cli.js');
90
- await scaffoldPugiWorkspace({
91
- cwd: process.cwd(),
92
- noDefaults: true,
93
- log: () => {
94
- /* silent — never leak scaffold progress into the REPL alt-screen */
95
- },
96
- });
97
- }
98
- catch (err) {
99
- // Fail-safe: read-only FS or perms error never blocks REPL launch.
100
- // Beta.13 P2 fix: bare-catch swallowed the diagnostic;
101
- // surface it on stderr under PUGI_DEBUG=1 so operator-triage on
102
- // "why isn't .pugi/ being created?" has a starting point without
103
- // having to re-instrument the bootstrap.
104
- if (process.env.PUGI_DEBUG === '1') {
105
- const msg = err instanceof Error ? err.message : String(err);
106
- process.stderr.write(`[pugi-debug] auto-init failed: ${msg}\n`);
107
- }
108
- }
109
- }
110
- const transport = createProductionTransport();
111
- // Auto-bind the workspace context from process.cwd() so Pugi knows
112
- // which repo the operator launched the CLI in. The resolver is
113
- // best-effort — any FS error falls back to a basename-only summary,
114
- // never blocks REPL launch. fix.
115
- const workspace = options.workspace ?? resolveWorkspaceContext(process.cwd());
116
- // Beta.13 P1 fix: read `ui.cyberZoo` from
117
- // `.pugi/settings.json` so the operator's splash posture flows to
118
- // admin-api on session open. Without this, the renderer's `cyberZoo`
119
- // parameter (added beta.13) was always defaulted to 'on' regardless
120
- // of the operator's actual setting.
121
- const cyberZoo = readCyberZooSetting(process.cwd());
122
- // : open the local SessionStore for `/resume` persistence. The
123
- // store lives under `~/.pugi/projects/<slug>/`; failure is fail-safe
124
- // — we log a one-line warning to stderr and continue with the REPL
125
- // in memory-only mode. Lock-busy errors get the friendliest message
126
- // so an operator running two REPLs in the same project understands
127
- // the constraint.
128
- const projectSlug = slugForCwd(process.cwd());
129
- const { store, openedSessionId } = await openLocalStore({
130
- projectSlug,
131
- workspaceRoot: process.cwd(),
132
- resumeLocalSessionId: options.resumeLocalSessionId,
133
- });
134
- // three-tier context bootstrap. The skeleton + working set
135
- // + watcher are local-first and best-effort: every step is wrapped
136
- // in try/catch so an unreadable workspace never blocks REPL launch.
137
- // Opt-out via PUGI_DISABLE_CONTEXT=1 for hermetic test runs.
138
- const { skeleton, workingSet, watcher } = await bootstrapContext({
139
- cwd: process.cwd(),
140
- env: process.env,
141
- });
142
- // PUGI-538c () -- wire the production engine bridge so
143
- // `<pugi-tool-route>` envelopes emitted by Pugi's coordinator
144
- // actually drive a local `NativePugiEngineAdapter` run instead of
145
- // surfacing "Engine bridge not configured" on the system line. The
146
- // factory closure resolves `cwd` per invocation so an operator who
147
- // `cd`-ed mid-session writes files into the new directory (matches
148
- // `pugi code` direct-path behaviour).
149
- //
150
- // The bridge runtime config reuses the REPL transport credentials so
151
- // a single token authenticates both the coordinator brief (via
152
- // admin-api /api/pugi/sessions) AND the bridged engine call (via
153
- // /api/pugi/engine). No new credential surface, no double login.
154
- //
155
- // Fail-safe construction: `buildRuntimeConfig` validates apiUrl via
156
- // `z.string().url()` and throws on a malformed value. We must not
157
- // crash REPL launch on that path -- every other bootstrap step in
158
- // this file (auto-init, openLocalStore, bootstrapContext, watcher)
159
- // is fail-safe. On construction failure we surface a one-line stderr
160
- // diagnostic under PUGI_DEBUG=1 and pass `engineBridge: undefined`
161
- // so the REPL launches; the operator sees the legacy "Engine bridge
162
- // not configured" system line on the first routed brief, which is
163
- // the same UX as a pre-PUGI-538c CLI build.
164
- let engineBridge;
165
- try {
166
- // PR A (2026-06-05): resolve intensity profile once at bridge
167
- // construction time. The bridge stays pure and re-uses the resolved
168
- // profile across every routed brief. `resolveIntensity` reads env
169
- // (`PUGI_INTENSITY`) и settings.json; the REPL launch lifecycle is
170
- // the natural binding point. A future `/intensity` REPL command
171
- // will rebuild the bridge to swap the profile mid-session.
172
- const intensityLevel = resolveIntensity({});
173
- const intensityProfile = profileFor(intensityLevel);
174
- engineBridge = createEngineBridge({
175
- config: buildRuntimeConfig({
176
- apiUrl: options.apiUrl,
177
- apiKey: options.apiKey,
178
- }),
179
- cwd: () => process.cwd(),
180
- intensityProfile,
181
- });
182
- }
183
- catch (err) {
184
- if (process.env.PUGI_DEBUG === '1') {
185
- const msg = err instanceof Error ? err.message : String(err);
186
- process.stderr.write(`[pugi-debug] engine bridge bootstrap failed: ${msg}\n`);
187
- }
188
- engineBridge = undefined;
189
- }
190
- const session = new ReplSession({
191
- apiUrl: options.apiUrl,
192
- apiKey: options.apiKey,
193
- workspaceLabel: options.workspaceLabel,
194
- cliVersion: options.cliVersion,
195
- transport,
196
- ...(engineBridge !== undefined ? { engineBridge } : {}),
197
- workspace,
198
- cyberZoo,
199
- store,
200
- localSessionId: openedSessionId,
201
- repoSkeleton: skeleton,
202
- workingSet,
203
- watcher,
204
- });
205
- // Restore the transcript from the JSONL log if we resumed an
206
- // existing session. The restore is idempotent and bypasses persist
207
- // (no double-write of replayed rows).
208
- if (store && openedSessionId && options.resumeLocalSessionId) {
209
- try {
210
- const events = await store.loadEvents(openedSessionId, { limit: 500 });
211
- session.restoreTranscript(events);
212
- }
213
- catch (error) {
214
- const msg = error instanceof Error ? error.message : String(error);
215
- process.stderr.write(`[pugi] Could not restore session ${openedSessionId.slice(0, 13)}: ${msg}\n`);
216
- }
217
- }
218
- // Kick off the connect; the Repl renders the connecting state until
219
- // the session pushes `connection: 'on_watch'` from the SSE onOpen.
220
- void session.start();
221
- // beta.9: drain any keystrokes that landed in stdin between the
222
- // pre-Ink raw-mode claim and now. Without this, the queued bytes
223
- // would feed Ink's first useInput tick as a flood of "stale"
224
- // characters once the InputBox mounts - the operator would see
225
- // their pre-typed input materialise in the prompt as if they had
226
- // typed it after the REPL became interactive. Idempotent: no-op
227
- // when stdin is not a TTY or no bytes were buffered.
228
- drainBufferedStdin(process.stdin);
229
- // wave 5: paint the chafa-baked brand-pug ANSI render to
230
- // stdout BEFORE Ink mounts (but AFTER alt-screen enter). Ink's
231
- // layout engine would mis-measure the truecolor escape sequences,
232
- // so the pug must land verbatim. The flag is passed into <Repl />
233
- // so the splash component knows to skip its own hand-crafted
234
- // PUG_MASCOT column - otherwise the operator sees both the chafa
235
- // pug AND the ASCII fallback stacked. When skipSplash is true
236
- // (operator opted out via --no-splash), we suppress the pre-print
237
- // too so the boot stays silent.
238
- const mascotPrePrinted = options.skipSplash === true ? false : printPugMascotPreInk(process.stdout);
239
- // resolve the active theme ONCE at mount
240
- // and wrap `<Repl />` in `<ThemeProvider>` so every Ink consumer
241
- // (`<Header>`, `<DoctorTable>`, `<StyleTable>`, `<ThemeTable>`,
242
- // …) picks up the same color tokens. The provider is stable for
243
- // the lifetime of the REPL — operator `/theme <name>` writes to
244
- // disk + appends a system line, and the next `pugi` launch re-
245
- // mounts with the new slug. Re-mounting mid-session would race
246
- // against Ink's raw-mode handler so we deliberately keep the
247
- // session-lifetime contract instead of polling the config file.
248
- const resolvedTheme = resolveTheme({
249
- workspaceRoot: process.cwd(),
250
- env: process.env,
251
- });
252
- // CEO P0 #2 : collect welcome banner data BEFORE Ink
253
- // mounts so the banner paints on the first frame instead of swapping
254
- // in mid-render. The collector swallows every IO error so а missing
255
- // CHANGELOG / unreadable credential / malformed settings never
256
- // blocks the boot.
257
- let welcomeData;
258
- if (options.skipSplash !== true) {
259
- try {
260
- welcomeData = collectWelcomeData({
261
- cliVersion: options.cliVersion,
262
- cwd: process.cwd(),
263
- });
264
- }
265
- catch {
266
- welcomeData = undefined;
267
- }
268
- }
269
- const instance = render(React.createElement(ThemeProvider, { slug: resolvedTheme.slug }, React.createElement(Repl, {
270
- session,
271
- updateBanner: options.updateBanner ?? null,
272
- skipSplash: options.skipSplash === true,
273
- hideToolStream: options.hideToolStream === true,
274
- mascotPrePrinted,
275
- welcomeData,
276
- autoInitStatus: options.autoInitStatus ?? null,
277
- })), {
278
- // PUGI-534 — Ink kills the process on the first raw Ctrl+C by
279
- // default, which beat the InputBox useInput double-tap timer to
280
- // the punch (operator reported single ^C exits the REPL). Disable
281
- // Ink's built-in handler so the InputBox `lastCtrlCAt` window owns
282
- // the exit gesture: first press → cancel + toast, second press
283
- // within 1s → `handleExit()` → `useApp().exit()`. SIGINT handlers
284
- // on the process object (sigint-guard + per-engine-task in
285
- // runtime/cli.ts) still fire as defence-in-depth on the rare
286
- // non-raw fallback path.
287
- exitOnCtrlC: false,
288
- });
289
- // Make sure we leave the alt screen on abrupt exits too. Without
290
- // this the operator's shell stays "frozen" on the Pugi splash.
291
- process.once('exit', bootstrap.restore);
292
- process.once('SIGINT', bootstrap.restore);
293
- process.once('SIGTERM', bootstrap.restore);
294
- try {
295
- await instance.waitUntilExit();
296
- }
297
- finally {
298
- bootstrap.restore();
299
- session.close();
300
- if (store) {
301
- try {
302
- await store.close();
303
- }
304
- catch {
305
- /* idempotent — already closed */
306
- }
307
- }
308
- if (watcher) {
309
- try {
310
- await watcher.close();
311
- }
312
- catch {
313
- /* idempotent — chokidar may already be torn down */
314
- }
315
- }
316
- }
317
- }
318
- export function claimTerminalForRepl(stdin = process.stdin, stdout = process.stdout) {
319
- const isStdoutTty = stdout.isTTY === true;
320
- const isStdinTty = stdin.isTTY === true && typeof stdin.setRawMode === 'function';
321
- let altScreenEntered = false;
322
- if (isStdoutTty) {
323
- try {
324
- stdout.write('\x1b[?1049h');
325
- stdout.write('\x1b[H');
326
- altScreenEntered = true;
327
- }
328
- catch {
329
- /* terminal already detached */
330
- }
331
- }
332
- let rawModeClaimed = false;
333
- if (isStdinTty) {
334
- try {
335
- stdin.setEncoding('utf8');
336
- stdin.setRawMode(true);
337
- // Resume so the kernel actually delivers bytes to Node's event
338
- // loop. Without resume, raw mode is set but data does not flow
339
- // until something else (e.g. Ink) attaches a 'data' listener.
340
- stdin.resume();
341
- rawModeClaimed = true;
342
- }
343
- catch {
344
- /* raw mode unsupported - the operator's shell still works */
345
- }
346
- }
347
- let restored = false;
348
- const restore = () => {
349
- if (restored)
350
- return;
351
- restored = true;
352
- if (rawModeClaimed && isStdinTty) {
353
- try {
354
- stdin.setRawMode(false);
355
- }
356
- catch {
357
- /* terminal already detached */
358
- }
359
- }
360
- if (altScreenEntered) {
361
- try {
362
- stdout.write('\x1b[?1049l');
363
- }
364
- catch {
365
- /* shutdown race - terminal already detached */
366
- }
367
- }
368
- };
369
- return { altScreenEntered, rawModeClaimed, restore };
370
- }
371
- /**
372
- * Read and discard any bytes buffered in stdin between
373
- * `claimTerminalForRepl()` and the Ink mount. Returns the number of
374
- * bytes drained so tests can assert the behaviour without intercepting
375
- * the side effect.
376
- *
377
- * `stdin.read()` is a no-op when no data is buffered, so this is safe
378
- * to call whether or not the operator actually typed during bootstrap.
379
- * Wrapped in try/catch because a closed / piped stdin will throw on
380
- * read in some Node versions.
381
- */
382
- export function drainBufferedStdin(stdin = process.stdin) {
383
- if (stdin.isTTY !== true)
384
- return 0;
385
- try {
386
- let bytesDrained = 0;
387
- // Loop until read() returns null - readable streams may chunk
388
- // buffered bytes across multiple read() calls when the operator
389
- // typed faster than the kernel could deliver to Node's loop.
390
- for (;;) {
391
- const chunk = stdin.read();
392
- if (chunk === null)
393
- return bytesDrained;
394
- bytesDrained += typeof chunk === 'string' ? chunk.length : chunk.byteLength;
395
- }
396
- }
397
- catch {
398
- return 0;
399
- }
400
- }
401
- /**
402
- * Project-root probe — beta.13 P2 fix.
403
- *
404
- * Beta.13 auto-init was unconditional and silently created `.pugi/` in
405
- * every cwd the REPL was launched from, including `$HOME` and `/tmp`.
406
- * Operators who ran `pugi` to ask a quick question outside of any
407
- * project ended up with stray `.pugi/` directories polluting their
408
- * filesystem. The gate looks for any of six project-root markers
409
- * before scaffolding:
410
- *
411
- * - `package.json` — JS / TS workspaces
412
- * - `.git` — any cloned repo regardless of language
413
- * - `.pugi` — already-bound Pugi workspace (re-scaffold
414
- * fills any missing artifacts the operator
415
- * deleted, idempotent over existing files)
416
- * - `Cargo.toml` — Rust crates
417
- * - `pyproject.toml` — Python projects (PEP 518)
418
- * - `go.mod` — Go modules
419
- *
420
- * The probe is six cheap `existsSync` calls; the cost is negligible
421
- * compared with the alt-screen + Ink mount that follows. Exported so a
422
- * future unit spec can lock the contract.
423
- */
424
- export function isProjectRoot(cwd) {
425
- // ESM static imports — `require()` is not defined in a `"type": "module"`
426
- // bundle and would throw `ReferenceError: require is not defined` the
427
- // moment the REPL bootstrap calls this gate. Beta.16 P0 fix.
428
- return (existsSync(resolve(cwd, 'package.json')) ||
429
- existsSync(resolve(cwd, '.git')) ||
430
- existsSync(resolve(cwd, '.pugi')) ||
431
- existsSync(resolve(cwd, 'Cargo.toml')) ||
432
- existsSync(resolve(cwd, 'pyproject.toml')) ||
433
- existsSync(resolve(cwd, 'go.mod')));
434
- }
435
- /**
436
- * Read the operator's cyber-zoo posture from `.pugi/settings.json`.
437
- * Best-effort: when the file is missing / malformed, fall through to
438
- * the historical 'on' default so the REPL never refuses to launch on
439
- * a settings error. Beta.13 P1 fix.
440
- */
441
- function readCyberZooSetting(cwd) {
442
- try {
443
- const settings = loadSettings(cwd);
444
- return settings.ui?.cyberZoo ?? 'on';
445
- }
446
- catch {
447
- return 'on';
448
- }
449
- }
450
- /**
451
- * Open the local SessionStore for the REPL bootstrap. Returns
452
- * `{ store: null, openedSessionId: undefined }` on any error so the
453
- * caller falls through to memory-only mode rather than failing the
454
- * launch. The one error we surface verbatim is the lock-busy case —
455
- * that one is operator-actionable.
456
- */
457
- async function openLocalStore(input) {
458
- // Honour an explicit opt-out for offline-strict environments / CI.
459
- // PUGI_DISABLE_SESSION_STORE=1 wipes the integration to zero. Useful
460
- // for hermetic test runs and for operators who do not want any
461
- // persistence under $HOME.
462
- if (process.env.PUGI_DISABLE_SESSION_STORE === '1') {
463
- return { store: null, openedSessionId: undefined };
464
- }
465
- try {
466
- const store = new SqliteSessionStore({ projectSlug: input.projectSlug });
467
- const row = await store.open({
468
- id: input.resumeLocalSessionId,
469
- workspaceRoot: input.workspaceRoot,
470
- projectSlug: input.projectSlug,
471
- });
472
- return { store, openedSessionId: row.id };
473
- }
474
- catch (error) {
475
- const code = error?.code;
476
- const msg = error instanceof Error ? error.message : String(error);
477
- if (code === 'EBUSY_SESSION_LOCK') {
478
- process.stderr.write(`[pugi] ${msg} Continuing without local session persistence.\n`);
479
- }
480
- else {
481
- process.stderr.write(`[pugi] Local session store unavailable (${msg}). Continuing in memory-only mode.\n`);
482
- }
483
- return { store: null, openedSessionId: undefined };
484
- }
485
- }
486
- /**
487
- * Bootstrap the three-tier context primitives:
488
- *
489
- * - Tier 0: `RepoSkeleton` (~5KB ASCII tree + meta) for prompt injection.
490
- * - Tier 1: `WorkingSet` LRU bounded at 50 entries.
491
- * - Filewatch: chokidar started against cwd, ignore-filtered.
492
- *
493
- * The bootstrap is fail-safe: every primitive is wrapped so the REPL
494
- * still launches when (e.g.) chokidar refuses to start on a
495
- * permission-blocked dir. The PUGI_DISABLE_CONTEXT=1 env var skips
496
- * the bootstrap entirely for hermetic test runs and for operators
497
- * who want a zero-touch REPL.
498
- */
499
- async function bootstrapContext(input) {
500
- if (input.env.PUGI_DISABLE_CONTEXT === '1') {
501
- return { skeleton: null, workingSet: null, watcher: null };
502
- }
503
- let ignore;
504
- try {
505
- ignore = loadPugiIgnore(input.cwd);
506
- }
507
- catch (error) {
508
- const msg = error instanceof Error ? error.message : String(error);
509
- process.stderr.write(`[pugi] Three-tier context bootstrap skipped (ignore matcher failed: ${msg}).\n`);
510
- return { skeleton: null, workingSet: null, watcher: null };
511
- }
512
- let skeleton = null;
513
- try {
514
- skeleton = buildRepoSkeleton(input.cwd, { ignore });
515
- }
516
- catch (error) {
517
- const msg = error instanceof Error ? error.message : String(error);
518
- process.stderr.write(`[pugi] Repo skeleton bootstrap failed (${msg}). Continuing without Tier 0.\n`);
519
- }
520
- const workingSet = new WorkingSet();
521
- let watcher = null;
522
- // chokidar opt-out: PUGI_DISABLE_FILEWATCH=1 keeps Tier 0/1 wired
523
- // but skips the live-update channel. Useful on CI runners and on
524
- // network mounts where fsevents misbehaves.
525
- if (input.env.PUGI_DISABLE_FILEWATCH !== '1') {
526
- try {
527
- const w = new PugiWatcher({ cwd: input.cwd, ignore });
528
- await w.start();
529
- watcher = w;
530
- }
531
- catch (error) {
532
- const msg = error instanceof Error ? error.message : String(error);
533
- process.stderr.write(`[pugi] Filewatch bootstrap failed (${msg}). Continuing without live updates.\n`);
534
- }
535
- }
536
- return { skeleton, workingSet, watcher };
537
- }
538
- /* ------------------------------------------------------------------ */
539
- /* Production transport */
540
- /* ------------------------------------------------------------------ */
541
- export function createProductionTransport() {
542
- return {
543
- async createSession({ apiUrl, apiKey, workspace, cyberZoo }) {
544
- // Forward the workspace bundle in the POST body so admin-api can
545
- // surface `<workspace-context>` in Pugi's prompt. Older admin-api
546
- // builds ignore unknown fields, so this stays forward-compatible.
547
- // fix.
548
- //
549
- // Beta.13 P1 fix: also forward `cyberZoo` so admin-api
550
- // can render Pugi's `<cyber-zoo>` marker matching the operator's
551
- // `.pugi/settings.json::ui.cyberZoo` toggle instead of the
552
- // historical 'on' default. Only included on the wire when set
553
- // explicitly so a missing setting still survives older admin-api
554
- // builds that do not declare the DTO field.
555
- const body = {};
556
- if (workspace?.workspaceCwd)
557
- body.workspaceCwd = workspace.workspaceCwd;
558
- if (workspace?.workspaceSlug)
559
- body.workspaceSlug = workspace.workspaceSlug;
560
- if (workspace?.workspaceSummary)
561
- body.workspaceSummary = workspace.workspaceSummary;
562
- if (cyberZoo === 'on' || cyberZoo === 'off')
563
- body.cyberZoo = cyberZoo;
564
- const response = await fetch(joinUrl(apiUrl, '/api/pugi/sessions'), {
565
- method: 'POST',
566
- headers: jsonHeaders(apiKey),
567
- body: JSON.stringify(body),
568
- });
569
- const json = await readJson(response);
570
- const sessionId = json.sessionId;
571
- if (typeof sessionId !== 'string' || sessionId.length === 0) {
572
- throw new Error('admin-api did not return a sessionId');
573
- }
574
- return { sessionId };
575
- },
576
- async postBrief({ apiUrl, apiKey, sessionId, brief }) {
577
- const response = await fetch(joinUrl(apiUrl, `/api/pugi/sessions/${encodeURIComponent(sessionId)}/brief`), {
578
- method: 'POST',
579
- headers: jsonHeaders(apiKey),
580
- body: JSON.stringify({ brief }),
581
- });
582
- const json = await readJson(response);
583
- const dispatchId = json.dispatchId;
584
- if (typeof dispatchId !== 'string' || dispatchId.length === 0) {
585
- throw new Error('admin-api did not return a dispatchId');
586
- }
587
- return { dispatchId };
588
- },
589
- async postStop({ apiUrl, apiKey, sessionId, persona }) {
590
- const response = await fetch(joinUrl(apiUrl, `/api/pugi/sessions/${encodeURIComponent(sessionId)}/stop`), {
591
- method: 'POST',
592
- headers: jsonHeaders(apiKey),
593
- body: JSON.stringify({ persona }),
594
- });
595
- const json = await readJson(response);
596
- const stopped = Boolean(json.stopped);
597
- return { stopped };
598
- },
599
- subscribe({ apiUrl, apiKey, sessionId, lastEventId, onEvent, onError, onOpen }) {
600
- const controller = new AbortController();
601
- const url = joinUrl(apiUrl, `/api/pugi/sessions/${encodeURIComponent(sessionId)}/stream`);
602
- const headers = {
603
- Accept: 'text/event-stream',
604
- Authorization: `Bearer ${apiKey}`,
605
- };
606
- if (lastEventId) {
607
- headers['Last-Event-ID'] = lastEventId;
608
- }
609
- // beta.9 CEO dogfood: hard timeout on the SSE
610
- // handshake so a CDN/proxy that buffers the response (or an
611
- // admin-api that accepted the route but never flushed headers)
612
- // cannot freeze the REPL in `connecting` forever. The 5s budget
613
- // is generous - admin-api routinely responds in <500ms when
614
- // healthy - but tight enough that an operator who launched
615
- // `pugi` and is staring at the screen will see the status flip
616
- // to `reconnecting` instead of an indefinite hang. The
617
- // AbortController bound to the fetch aborts the in-flight
618
- // request when the timer fires, which surfaces as an
619
- // `AbortError` and routes through the existing onError handler
620
- // (which calls scheduleReconnect via the session). The timer
621
- // is cleared the moment onOpen fires so a slow-but-eventually-
622
- // successful handshake still works.
623
- const handshakeDeadlineMs = 5_000;
624
- const handshakeTimer = setTimeout(() => {
625
- controller.abort();
626
- // onError is called from the catch block below (the abort
627
- // synthesises an AbortError that consumeSseStream / fetch
628
- // will throw). No explicit onError call here - we let the
629
- // catch path normalise the error message so the operator
630
- // sees the consistent "SSE handshake timed out (5s)" prose
631
- // through the same plumbing that surfaces every other
632
- // transport failure.
633
- }, handshakeDeadlineMs);
634
- void (async () => {
635
- try {
636
- const response = await fetch(url, {
637
- method: 'GET',
638
- headers,
639
- signal: controller.signal,
640
- });
641
- if (!response.ok) {
642
- throw new Error(`HTTP ${response.status} on SSE stream`);
643
- }
644
- if (!response.body) {
645
- throw new Error('SSE response has no body');
646
- }
647
- // Handshake survived; cancel the deadline so a slow
648
- // first-event stream does not get aborted later.
649
- clearTimeout(handshakeTimer);
650
- onOpen();
651
- await consumeSseStream(response.body, onEvent);
652
- // Server closed the stream cleanly. Treat as an error so
653
- // the session reconnects (the spec says "transient
654
- // disconnect" - a clean close from the server side is also
655
- // transient because the operator may have toggled wifi).
656
- onError(new Error('SSE stream ended'));
657
- }
658
- catch (error) {
659
- clearTimeout(handshakeTimer);
660
- if (controller.signal.aborted) {
661
- // Distinguish operator-driven close (session.close())
662
- // from the handshake-deadline abort. The session sets a
663
- // `closed` flag before calling controller.abort(); the
664
- // handshake-deadline abort fires while the session is
665
- // still expecting onOpen. We cannot read session state
666
- // from here, so we surface a single error class with a
667
- // clear message - the session-side onError handler
668
- // already short-circuits when `closed=true`.
669
- onError(new Error(`SSE handshake timed out after ${handshakeDeadlineMs}ms`));
670
- return;
671
- }
672
- onError(error instanceof Error ? error : new Error(String(error)));
673
- }
674
- })();
675
- return {
676
- close: () => {
677
- clearTimeout(handshakeTimer);
678
- controller.abort();
679
- },
680
- };
681
- },
682
- };
683
- }
684
- /* ------------------------------------------------------------------ */
685
- /* SSE parser */
686
- /* ------------------------------------------------------------------ */
687
- /**
688
- * Minimal SSE parser. Reads a UTF-8 stream of `id:` / `event:` / `data:`
689
- * lines separated by blank lines. We only need the `data` payload (a
690
- * JSON object) and the `id` field (so we can replay on reconnect via
691
- * Last-Event-ID).
692
- */
693
- async function consumeSseStream(body, onEvent) {
694
- const reader = body.getReader();
695
- const decoder = new TextDecoder('utf-8');
696
- let buffer = '';
697
- let currentId = '';
698
- let currentData = '';
699
- while (true) {
700
- const { value, done } = await reader.read();
701
- if (done)
702
- break;
703
- buffer += decoder.decode(value, { stream: true });
704
- let newlineIndex;
705
- while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
706
- const rawLine = buffer.slice(0, newlineIndex).replace(/\r$/, '');
707
- buffer = buffer.slice(newlineIndex + 1);
708
- if (rawLine.length === 0) {
709
- // Dispatch - only if we have a data payload.
710
- if (currentData.length > 0) {
711
- try {
712
- const parsed = JSON.parse(currentData);
713
- onEvent(parsed, currentId);
714
- }
715
- catch {
716
- // Drop malformed frames silently - protocol-level
717
- // robustness is the controller's job, not the client's.
718
- }
719
- }
720
- currentData = '';
721
- currentId = '';
722
- continue;
723
- }
724
- if (rawLine.startsWith(':'))
725
- continue; // Comment / keepalive.
726
- const colonIndex = rawLine.indexOf(':');
727
- const field = colonIndex === -1 ? rawLine : rawLine.slice(0, colonIndex);
728
- const value = colonIndex === -1 ? '' : rawLine.slice(colonIndex + 1).replace(/^ /, '');
729
- switch (field) {
730
- case 'id':
731
- currentId = value;
732
- break;
733
- case 'data':
734
- currentData = currentData.length === 0 ? value : `${currentData}\n${value}`;
735
- break;
736
- case 'event':
737
- case 'retry':
738
- default:
739
- // We do not surface the `event:` name to the consumer - the
740
- // payload itself carries `type`. Future events that need
741
- // dispatcher-side routing without parsing JSON can wire
742
- // through this branch.
743
- break;
744
- }
745
- }
746
- }
747
- }
748
- /* ------------------------------------------------------------------ */
749
- /* Small helpers */
750
- /* ------------------------------------------------------------------ */
751
- function jsonHeaders(apiKey) {
752
- return {
753
- 'Content-Type': 'application/json',
754
- Accept: 'application/json',
755
- Authorization: `Bearer ${apiKey}`,
756
- };
757
- }
758
- async function readJson(response) {
759
- if (!response.ok) {
760
- const detail = await response.text().catch(() => '');
761
- throw new Error(`HTTP ${response.status}${detail ? `: ${detail.slice(0, 200)}` : ''}`);
762
- }
763
- return response.json();
764
- }
765
- function joinUrl(base, path) {
766
- const trimmedBase = base.endsWith('/') ? base.slice(0, -1) : base;
767
- const trimmedPath = path.startsWith('/') ? path : `/${path}`;
768
- return `${trimmedBase}${trimmedPath}`;
769
- }
770
- //# sourceMappingURL=repl-render.js.map