@north-light/cli 0.3.561 → 0.3.562

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 (573) hide show
  1. package/dist/api/client.d.ts +27 -4
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/bash-jobs.d.ts +5 -1
  6. package/dist/api/dto/broker-ops.d.ts +25 -1
  7. package/dist/api/dto/charges.d.ts +9 -2
  8. package/dist/api/dto/delivery.d.ts +26 -2
  9. package/dist/api/dto/execution-start.d.ts +57 -0
  10. package/dist/api/dto/execution-start.js +0 -0
  11. package/dist/api/dto/modelauth.d.ts +5 -0
  12. package/dist/api/dto/node-records.d.ts +16 -0
  13. package/dist/api/dto/objects.d.ts +1 -1
  14. package/dist/api/dto/reports.d.ts +0 -3
  15. package/dist/api/dto/run-events.d.ts +7 -1
  16. package/dist/api/dto/settings.d.ts +55 -0
  17. package/dist/api/dto/settings.js +0 -0
  18. package/dist/api/index.d.ts +2 -0
  19. package/dist/api/index.js +1 -1
  20. package/dist/api/routes.d.ts +11 -0
  21. package/dist/api/routes.js +1 -1
  22. package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
  23. package/dist/cli.js +7 -7
  24. package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
  25. package/dist/clients/attach/chrome/bash-jobs.js +1 -1
  26. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  27. package/dist/clients/attach/chrome/roster.js +6 -4
  28. package/dist/clients/attach/overlays/auth.js +2 -2
  29. package/dist/clients/attach/render/chat-view.js +1 -1
  30. package/dist/clients/attach/viewer.js +550 -567
  31. package/dist/commands/canvas-config.js +2 -2
  32. package/dist/commands/canvas-use.js +1 -1
  33. package/dist/commands/human.js +2 -2
  34. package/dist/commands/node/bash.js +3 -3
  35. package/dist/commands/node/create.js +2 -2
  36. package/dist/commands/person-settings.d.ts +1 -0
  37. package/dist/commands/person-settings.js +1 -0
  38. package/dist/commands/pkg/market-manage.d.ts +2 -2
  39. package/dist/commands/pkg/market-manage.js +1 -1
  40. package/dist/commands/pkg/plugin-manage.js +13 -13
  41. package/dist/commands/pkg/shared.js +1 -1
  42. package/dist/commands/profile/default.js +1 -1
  43. package/dist/commands/push.js +2 -3
  44. package/dist/commands/sys/config.js +1 -1
  45. package/dist/commands/sys/connect.js +1 -1
  46. package/dist/commands/sys/context/sysprompt.js +2 -2
  47. package/dist/commands/sys/doctor.js +1 -1
  48. package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
  49. package/dist/commands/sys/panels/keybindings-panel.js +1 -1
  50. package/dist/commands/sys/panels/models-panel.d.ts +8 -2
  51. package/dist/commands/sys/panels/models-panel.js +1 -1
  52. package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
  53. package/dist/commands/sys/panels/prefs-panel.js +1 -1
  54. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  55. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  56. package/dist/commands/sys/panels/provider-panel.js +1 -1
  57. package/dist/commands/sys/provider-login.js +5 -5
  58. package/dist/commands/sys/setup-core.js +3 -3
  59. package/dist/commands/sys/setup-settings-runner.js +1 -1
  60. package/dist/commands/sys/spend.js +3 -3
  61. package/dist/commands/sys/update.js +1 -1
  62. package/dist/core/auth-file.d.ts +11 -19
  63. package/dist/core/auth-file.js +1 -2
  64. package/dist/core/auto-update.d.ts +1 -1
  65. package/dist/core/auto-update.js +4 -4
  66. package/dist/core/bash-jobs.d.ts +29 -71
  67. package/dist/core/bash-jobs.js +9 -10
  68. package/dist/core/blobs/directory.d.ts +3 -0
  69. package/dist/core/blobs/directory.js +1 -0
  70. package/dist/core/blobs/fault.d.ts +3 -0
  71. package/dist/core/blobs/fault.js +1 -0
  72. package/dist/core/blobs/index.d.ts +21 -0
  73. package/dist/core/blobs/index.js +1 -0
  74. package/dist/core/blobs/r2.d.ts +9 -0
  75. package/dist/core/blobs/r2.js +4 -0
  76. package/dist/core/bootstrap.d.ts +1 -1
  77. package/dist/core/bootstrap.js +2 -2
  78. package/dist/core/canvas/canvas.d.ts +9 -7
  79. package/dist/core/canvas/canvas.js +8 -8
  80. package/dist/core/canvas/crons.d.ts +3 -2
  81. package/dist/core/canvas/crons.js +3 -3
  82. package/dist/core/canvas/daemon-owner.d.ts +5 -0
  83. package/dist/core/canvas/daemon-owner.js +1 -1
  84. package/dist/core/canvas/db.d.ts +10 -9
  85. package/dist/core/canvas/db.js +4 -4
  86. package/dist/core/canvas/executions.d.ts +100 -4
  87. package/dist/core/canvas/executions.js +1 -1
  88. package/dist/core/canvas/export-sqlite.js +1 -1
  89. package/dist/core/canvas/focuses.d.ts +4 -0
  90. package/dist/core/canvas/focuses.js +1 -1
  91. package/dist/core/canvas/history.js +9 -9
  92. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
  93. package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
  94. package/dist/core/canvas/node-tokens.d.ts +1 -4
  95. package/dist/core/canvas/node-tokens.js +3 -3
  96. package/dist/core/canvas/paths.d.ts +0 -1
  97. package/dist/core/canvas/paths.js +1 -1
  98. package/dist/core/canvas/person-state.d.ts +26 -0
  99. package/dist/core/canvas/person-state.js +1 -0
  100. package/dist/core/canvas/person.d.ts +3 -10
  101. package/dist/core/canvas/person.js +7 -7
  102. package/dist/core/canvas/reconciler-leases.d.ts +12 -0
  103. package/dist/core/canvas/reconciler-leases.js +8 -0
  104. package/dist/core/canvas/recovery.d.ts +4 -0
  105. package/dist/core/canvas/recovery.js +1 -1
  106. package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
  107. package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
  108. package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
  109. package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
  110. package/dist/core/canvas/schema-version.d.ts +1 -1
  111. package/dist/core/canvas/schema-version.js +1 -1
  112. package/dist/core/canvas/sessions.d.ts +8 -11
  113. package/dist/core/canvas/sessions.js +1 -4
  114. package/dist/core/canvas/tree.d.ts +4 -2
  115. package/dist/core/canvas/tree.js +6 -6
  116. package/dist/core/canvas/types.d.ts +7 -0
  117. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  118. package/dist/core/command-plugins/bundle.d.ts +1 -1
  119. package/dist/core/command-plugins/bundle.js +1 -1
  120. package/dist/core/command-plugins/compose.d.ts +1 -1
  121. package/dist/core/command-plugins/discovery.d.ts +0 -1
  122. package/dist/core/command-plugins/discovery.js +1 -1
  123. package/dist/core/command-plugins/help-addenda.js +1 -1
  124. package/dist/core/command-plugins/presence.d.ts +2 -0
  125. package/dist/core/command-plugins/presence.js +1 -1
  126. package/dist/core/config.d.ts +16 -15
  127. package/dist/core/config.js +1 -1
  128. package/dist/core/conversation-store/client-worker.js +1 -1
  129. package/dist/core/conversation-store/client.js +2 -2
  130. package/dist/core/conversation-store/index.d.ts +9 -11
  131. package/dist/core/conversation-store/index.js +1 -1
  132. package/dist/core/conversation-store/patch.js +1 -1
  133. package/dist/core/conversation-store/row-store.d.ts +14 -0
  134. package/dist/core/conversation-store/row-store.js +13 -0
  135. package/dist/core/directory/join.js +1 -1
  136. package/dist/core/env-name.d.ts +1 -0
  137. package/dist/core/env-name.js +1 -1
  138. package/dist/core/environment-recipe.d.ts +15 -0
  139. package/dist/core/environment-recipe.js +1 -0
  140. package/dist/core/environments.js +1 -1
  141. package/dist/core/events/emit.js +2 -2
  142. package/dist/core/events/run-event-chunks.d.ts +25 -0
  143. package/dist/core/events/run-event-chunks.js +5 -0
  144. package/dist/core/feed/messages.js +5 -5
  145. package/dist/core/grants/mirror.d.ts +15 -0
  146. package/dist/core/grants/mirror.js +15 -3
  147. package/dist/core/grants/on-sync.d.ts +9 -5
  148. package/dist/core/grants/on-sync.js +1 -1
  149. package/dist/core/grants/remove.d.ts +1 -6
  150. package/dist/core/grants/remove.js +1 -1
  151. package/dist/core/grants/sync.js +1 -1
  152. package/dist/core/grants/watch.d.ts +15 -9
  153. package/dist/core/grants/watch.js +1 -1
  154. package/dist/core/graph/custom.js +8 -8
  155. package/dist/core/graph/jobs.d.ts +83 -5
  156. package/dist/core/graph/jobs.js +11 -2
  157. package/dist/core/graph/kinds/job.js +2 -2
  158. package/dist/core/graph/names.js +7 -7
  159. package/dist/core/graph/objects.d.ts +5 -1
  160. package/dist/core/graph/objects.js +11 -11
  161. package/dist/core/graph/reader.d.ts +3 -0
  162. package/dist/core/graph/reader.js +3 -3
  163. package/dist/core/graph/repo-sync/identity.d.ts +3 -1
  164. package/dist/core/graph/repo-sync/identity.js +1 -1
  165. package/dist/core/graph/repo-sync/repos.d.ts +1 -1
  166. package/dist/core/graph/repo-sync/repos.js +2 -2
  167. package/dist/core/graph/repo-sync/sync.js +2 -2
  168. package/dist/core/installed-plugins.js +1 -1
  169. package/dist/core/keybindings/persistence.d.ts +1 -1
  170. package/dist/core/keybindings/persistence.js +1 -1
  171. package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
  172. package/dist/core/layout-migrate/loose-keys.js +1 -1
  173. package/dist/core/ledger/account.d.ts +12 -0
  174. package/dist/core/ledger/account.js +2 -0
  175. package/dist/core/ledger/charges.d.ts +2 -2
  176. package/dist/core/ledger/charges.js +1 -1
  177. package/dist/core/ledger/check.d.ts +5 -1
  178. package/dist/core/ledger/check.js +1 -7
  179. package/dist/core/ledger/chunks.d.ts +8 -0
  180. package/dist/core/ledger/chunks.js +2 -0
  181. package/dist/core/ledger/index.d.ts +2 -1
  182. package/dist/core/ledger/index.js +1 -1
  183. package/dist/core/ledger/infra-allowance.d.ts +9 -0
  184. package/dist/core/ledger/infra-allowance.js +1 -0
  185. package/dist/core/ledger/limits.js +3 -3
  186. package/dist/core/ledger/payer.d.ts +1 -1
  187. package/dist/core/ledger/payer.js +1 -1
  188. package/dist/core/ledger/read.d.ts +14 -4
  189. package/dist/core/ledger/read.js +2 -3
  190. package/dist/core/ledger/totals.d.ts +5 -16
  191. package/dist/core/ledger/totals.js +4 -4
  192. package/dist/core/ledger/types.d.ts +12 -3
  193. package/dist/core/llm/run.js +2 -2
  194. package/dist/core/managed-providers.d.ts +72 -0
  195. package/dist/core/managed-providers.js +1 -0
  196. package/dist/core/model-auth/api-credential-store.d.ts +10 -0
  197. package/dist/core/model-auth/api-credential-store.js +1 -0
  198. package/dist/core/model-auth/daemon-login.d.ts +1 -1
  199. package/dist/core/model-auth/daemon-login.js +1 -1
  200. package/dist/core/model-auth/flows.d.ts +5 -4
  201. package/dist/core/model-auth/flows.js +1 -1
  202. package/dist/core/model-auth/handoff-jti.d.ts +3 -4
  203. package/dist/core/model-auth/handoff-jti.js +1 -1
  204. package/dist/core/model-auth/readiness.js +1 -1
  205. package/dist/core/model-config.d.ts +1 -1
  206. package/dist/core/model-config.js +1 -1
  207. package/dist/core/model-routes-pool.d.ts +14 -0
  208. package/dist/core/model-routes-pool.js +1 -0
  209. package/dist/core/model-routes.d.ts +11 -16
  210. package/dist/core/model-routes.js +1 -1
  211. package/dist/core/peer/ingest.d.ts +2 -0
  212. package/dist/core/peer/ingest.js +1 -1
  213. package/dist/core/peer/stubs.d.ts +8 -0
  214. package/dist/core/peer/stubs.js +1 -1
  215. package/dist/core/permissions/evaluator.d.ts +7 -2
  216. package/dist/core/permissions/evaluator.js +2 -2
  217. package/dist/core/plugin-env.js +1 -1
  218. package/dist/core/pool-credential-store.d.ts +2 -5
  219. package/dist/core/pool-credential-store.js +1 -1
  220. package/dist/core/profiles/app-env-store.d.ts +5 -5
  221. package/dist/core/profiles/app-env-store.js +1 -2
  222. package/dist/core/profiles/default-binding.d.ts +5 -5
  223. package/dist/core/profiles/default-binding.js +1 -1
  224. package/dist/core/profiles/env-store.d.ts +10 -21
  225. package/dist/core/profiles/env-store.js +1 -2
  226. package/dist/core/profiles/manifest.d.ts +14 -18
  227. package/dist/core/profiles/manifest.js +1 -1
  228. package/dist/core/profiles/relocate.js +1 -1
  229. package/dist/core/profiles/select.js +21 -21
  230. package/dist/core/provider-credential.d.ts +1 -1
  231. package/dist/core/provider-credential.js +1 -1
  232. package/dist/core/provider-management.d.ts +3 -4
  233. package/dist/core/provider-management.js +1 -1
  234. package/dist/core/providers/bundles.js +2 -2
  235. package/dist/core/providers/call.d.ts +3 -34
  236. package/dist/core/providers/description.d.ts +34 -0
  237. package/dist/core/providers/description.js +0 -0
  238. package/dist/core/providers/token-cache.d.ts +14 -14
  239. package/dist/core/providers/token-cache.js +1 -1
  240. package/dist/core/review/companion.js +1 -1
  241. package/dist/core/runs/activity.d.ts +1 -1
  242. package/dist/core/runs/activity.js +1 -1
  243. package/dist/core/runs/events.d.ts +7 -5
  244. package/dist/core/runs/events.js +2 -6
  245. package/dist/core/runs/operations.d.ts +1 -1
  246. package/dist/core/runs/operations.js +6 -6
  247. package/dist/core/runtime/bearings.js +1 -1
  248. package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
  249. package/dist/core/runtime/broker/attachments-fetch.js +1 -0
  250. package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
  251. package/dist/core/runtime/broker/bash-job-launch.js +1 -1
  252. package/dist/core/runtime/broker/boot-state.d.ts +9 -0
  253. package/dist/core/runtime/broker/boot-state.js +1 -0
  254. package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
  255. package/dist/core/runtime/broker/cli-relay.js +1 -1
  256. package/dist/core/runtime/broker/client-registry.d.ts +3 -3
  257. package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
  258. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  259. package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
  260. package/dist/core/runtime/broker/fault-retry.js +1 -1
  261. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  262. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
  263. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  264. package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
  265. package/dist/core/runtime/broker/job-reporter.js +2 -0
  266. package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
  267. package/dist/core/runtime/broker/model-adapter.js +3 -2
  268. package/dist/core/runtime/broker/signal-stream.js +1 -1
  269. package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
  270. package/dist/core/runtime/broker/spilled-body.js +1 -0
  271. package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
  272. package/dist/core/runtime/broker/summaries-post.js +1 -0
  273. package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
  274. package/dist/core/runtime/broker/tool-groups.js +1 -1
  275. package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
  276. package/dist/core/runtime/broker/turn-replies.js +1 -1
  277. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  278. package/dist/core/runtime/broker.js +1 -1
  279. package/dist/core/runtime/deliver-live.js +1 -1
  280. package/dist/core/runtime/first-boot-rows.d.ts +8 -0
  281. package/dist/core/runtime/first-boot-rows.js +2 -0
  282. package/dist/core/runtime/fleet.d.ts +13 -12
  283. package/dist/core/runtime/front-door-login.js +1 -1
  284. package/dist/core/runtime/front-door.js +6 -6
  285. package/dist/core/runtime/headless-pi.js +1 -1
  286. package/dist/core/runtime/host.d.ts +14 -3
  287. package/dist/core/runtime/host.js +3 -3
  288. package/dist/core/runtime/invocation.d.ts +6 -0
  289. package/dist/core/runtime/kickoff.d.ts +2 -14
  290. package/dist/core/runtime/kickoff.js +17 -19
  291. package/dist/core/runtime/launch-config-worker.js +1 -1
  292. package/dist/core/runtime/launch.js +2 -2
  293. package/dist/core/runtime/model-registry.js +1 -1
  294. package/dist/core/runtime/node-read.d.ts +4 -6
  295. package/dist/core/runtime/node-read.js +3 -3
  296. package/dist/core/runtime/nodes.js +1 -1
  297. package/dist/core/runtime/outcome-document.d.ts +0 -1
  298. package/dist/core/runtime/outcome-document.js +1 -1
  299. package/dist/core/runtime/output-result.d.ts +15 -0
  300. package/dist/core/runtime/output-result.js +5 -0
  301. package/dist/core/runtime/placement.d.ts +17 -1
  302. package/dist/core/runtime/placement.js +1 -1
  303. package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
  304. package/dist/core/runtime/provider-credential-gate.js +2 -2
  305. package/dist/core/runtime/recovery-hold.d.ts +21 -2
  306. package/dist/core/runtime/recovery-hold.js +2 -1
  307. package/dist/core/runtime/recycle.js +1 -1
  308. package/dist/core/runtime/reset.js +1 -1
  309. package/dist/core/runtime/revive.d.ts +2 -2
  310. package/dist/core/runtime/revive.js +2 -2
  311. package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
  312. package/dist/core/runtime/runner/blaxel/client.js +1 -0
  313. package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
  314. package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
  315. package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
  316. package/dist/core/runtime/runner/blaxel/runner.js +3 -0
  317. package/dist/core/runtime/runner/index.d.ts +8 -0
  318. package/dist/core/runtime/runner/index.js +1 -0
  319. package/dist/core/runtime/runner/process.d.ts +11 -0
  320. package/dist/core/runtime/runner/process.js +1 -0
  321. package/dist/core/runtime/runner/types.d.ts +95 -0
  322. package/dist/core/runtime/runner/types.js +0 -0
  323. package/dist/core/runtime/situational-context.d.ts +3 -6
  324. package/dist/core/runtime/situational-context.js +2 -2
  325. package/dist/core/runtime/situational-live.js +1 -1
  326. package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
  327. package/dist/core/runtime/spawn-env-rows.js +1 -0
  328. package/dist/core/runtime/spawn-env.d.ts +4 -18
  329. package/dist/core/runtime/spawn-env.js +1 -1
  330. package/dist/core/runtime/spawn.js +2 -2
  331. package/dist/core/runtime/stop-guard.d.ts +1 -1
  332. package/dist/core/runtime/stop-guard.js +2 -8
  333. package/dist/core/runtime/structured-output.d.ts +0 -67
  334. package/dist/core/runtime/structured-output.js +3 -8
  335. package/dist/core/runtime/tmux-driver.d.ts +8 -0
  336. package/dist/core/runtime/tmux-driver.js +6 -6
  337. package/dist/core/runtime/view-socket.d.ts +20 -0
  338. package/dist/core/runtime/view-socket.js +3 -1
  339. package/dist/core/runtime/warm-pool.d.ts +13 -1
  340. package/dist/core/runtime/warm-pool.js +1 -1
  341. package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
  342. package/dist/core/scoped-state/legacy-profiles.js +1 -0
  343. package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
  344. package/dist/core/scoped-state/materialized-plugins.js +1 -0
  345. package/dist/core/scoped-state/migrate.d.ts +8 -1
  346. package/dist/core/scoped-state/migrate.js +3 -3
  347. package/dist/core/scoped-state/person-rows.d.ts +10 -0
  348. package/dist/core/scoped-state/person-rows.js +6 -0
  349. package/dist/core/scoped-state/person-store.d.ts +72 -0
  350. package/dist/core/scoped-state/person-store.js +1 -0
  351. package/dist/core/secrets/blaxel-launch.d.ts +24 -0
  352. package/dist/core/secrets/blaxel-launch.js +4 -0
  353. package/dist/core/secrets/blaxel-register.d.ts +2 -0
  354. package/dist/core/secrets/blaxel-register.js +1 -0
  355. package/dist/core/secrets/env-rows.d.ts +17 -0
  356. package/dist/core/secrets/env-rows.js +4 -0
  357. package/dist/core/secrets/environment-owner.d.ts +8 -0
  358. package/dist/core/secrets/environment-owner.js +1 -0
  359. package/dist/core/secrets/environment-secrets.d.ts +14 -0
  360. package/dist/core/secrets/environment-secrets.js +1 -0
  361. package/dist/core/secrets/index.d.ts +2 -0
  362. package/dist/core/secrets/index.js +1 -0
  363. package/dist/core/secrets/key.d.ts +3 -0
  364. package/dist/core/secrets/key.js +2 -0
  365. package/dist/core/secrets/seal.d.ts +18 -0
  366. package/dist/core/secrets/seal.js +1 -0
  367. package/dist/core/spaces/mounts.d.ts +1 -1
  368. package/dist/core/spaces/mounts.js +1 -1
  369. package/dist/core/spaces/process.d.ts +1 -1
  370. package/dist/core/spaces/stop.d.ts +7 -5
  371. package/dist/core/spaces/stop.js +2 -2
  372. package/dist/core/spaces/users.d.ts +2 -1
  373. package/dist/core/spaces/users.js +1 -1
  374. package/dist/core/storage/attachments.d.ts +11 -8
  375. package/dist/core/storage/attachments.js +1 -1
  376. package/dist/core/storage/tables.d.ts +4 -0
  377. package/dist/core/storage/tables.js +3 -3
  378. package/dist/core/subscription-state.d.ts +34 -72
  379. package/dist/core/subscription-state.js +1 -4
  380. package/dist/core/substrate/delivery/plan.js +1 -1
  381. package/dist/core/user-settings.js +1 -1
  382. package/dist/daemon/api/app-listener.js +10 -10
  383. package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
  384. package/dist/daemon/api/auth/person-bearer.js +1 -0
  385. package/dist/daemon/api/bridge.js +4 -4
  386. package/dist/daemon/api/document-listener.js +3 -3
  387. package/dist/daemon/api/environment-of.d.ts +18 -0
  388. package/dist/daemon/api/environment-of.js +5 -0
  389. package/dist/daemon/api/handlers/analytics.js +1 -1
  390. package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
  391. package/dist/daemon/api/handlers/app-profiles.js +1 -1
  392. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  393. package/dist/daemon/api/handlers/bash.js +1 -1
  394. package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
  395. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  396. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  397. package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
  398. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  399. package/dist/daemon/api/handlers/canvas.js +4 -4
  400. package/dist/daemon/api/handlers/charges.d.ts +1 -1
  401. package/dist/daemon/api/handlers/charges.js +1 -1
  402. package/dist/daemon/api/handlers/conversations.d.ts +2 -0
  403. package/dist/daemon/api/handlers/conversations.js +3 -0
  404. package/dist/daemon/api/handlers/crons.js +1 -1
  405. package/dist/daemon/api/handlers/daemon.js +1 -1
  406. package/dist/daemon/api/handlers/delivery.d.ts +1 -1
  407. package/dist/daemon/api/handlers/delivery.js +1 -1
  408. package/dist/daemon/api/handlers/docs.js +1 -1
  409. package/dist/daemon/api/handlers/exec.js +1 -1
  410. package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
  411. package/dist/daemon/api/handlers/execution-start.js +2 -0
  412. package/dist/daemon/api/handlers/files.js +1 -1
  413. package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
  414. package/dist/daemon/api/handlers/git-credential.js +1 -0
  415. package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
  416. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  417. package/dist/daemon/api/handlers/human-requests.js +1 -1
  418. package/dist/daemon/api/handlers/inbox.js +1 -1
  419. package/dist/daemon/api/handlers/messages.js +1 -1
  420. package/dist/daemon/api/handlers/model-config.js +1 -1
  421. package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
  422. package/dist/daemon/api/handlers/modelauth.js +1 -1
  423. package/dist/daemon/api/handlers/node-events.d.ts +6 -0
  424. package/dist/daemon/api/handlers/node-events.js +3 -3
  425. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  426. package/dist/daemon/api/handlers/node-records.js +3 -2
  427. package/dist/daemon/api/handlers/nodes.js +1 -1
  428. package/dist/daemon/api/handlers/objects.js +3 -3
  429. package/dist/daemon/api/handlers/profiles.js +1 -1
  430. package/dist/daemon/api/handlers/providers.js +1 -1
  431. package/dist/daemon/api/handlers/reports.js +9 -13
  432. package/dist/daemon/api/handlers/reviews.js +1 -1
  433. package/dist/daemon/api/handlers/runs.js +1 -1
  434. package/dist/daemon/api/handlers/settings.d.ts +2 -0
  435. package/dist/daemon/api/handlers/settings.js +1 -0
  436. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  437. package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
  438. package/dist/daemon/api/handlers/vendor-status.js +1 -1
  439. package/dist/daemon/api/handlers/worktree.js +1 -1
  440. package/dist/daemon/api/map.d.ts +2 -2
  441. package/dist/daemon/api/map.js +2 -2
  442. package/dist/daemon/api/operations.js +1 -1
  443. package/dist/daemon/api/reader.d.ts +8 -1
  444. package/dist/daemon/api/reader.js +1 -1
  445. package/dist/daemon/api/router.d.ts +4 -2
  446. package/dist/daemon/api/router.js +1 -1
  447. package/dist/daemon/api/server.d.ts +15 -3
  448. package/dist/daemon/api/server.js +1 -1
  449. package/dist/daemon/api/vendor-signin.d.ts +2 -1
  450. package/dist/daemon/api/vendor-signin.js +19 -19
  451. package/dist/daemon/api/viewer-presence.d.ts +20 -6
  452. package/dist/daemon/api/viewer-presence.js +2 -1
  453. package/dist/daemon/broker-signals/bus.d.ts +48 -11
  454. package/dist/daemon/broker-signals/bus.js +1 -1
  455. package/dist/daemon/cron/armed-context.js +1 -1
  456. package/dist/daemon/cron/lease-recovery.js +1 -1
  457. package/dist/daemon/cron/live-runs.d.ts +6 -0
  458. package/dist/daemon/cron/live-runs.js +1 -1
  459. package/dist/daemon/cron/run-socket.js +1 -1
  460. package/dist/daemon/cron-run.js +2 -2
  461. package/dist/daemon/crtrd-cli.js +1 -1
  462. package/dist/daemon/crtrd.d.ts +10 -0
  463. package/dist/daemon/crtrd.js +18 -17
  464. package/dist/daemon/delivery/run-delivery.d.ts +1 -1
  465. package/dist/daemon/delivery/run-delivery.js +1 -1
  466. package/dist/daemon/due-sources.d.ts +1 -1
  467. package/dist/daemon/due-sources.js +1 -1
  468. package/dist/daemon/due.js +7 -6
  469. package/dist/daemon/fleet.d.ts +6 -6
  470. package/dist/daemon/fleet.js +9 -9
  471. package/dist/daemon/park-activity.d.ts +2 -1
  472. package/dist/daemon/park-activity.js +1 -1
  473. package/dist/daemon/park-pending.d.ts +20 -13
  474. package/dist/daemon/park-pending.js +3 -1
  475. package/dist/daemon/profile-delete.js +1 -1
  476. package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
  477. package/dist/daemon/reconcilers/bash-deadline.js +1 -3
  478. package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
  479. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  480. package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
  481. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  482. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
  483. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  484. package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
  485. package/dist/daemon/reconcilers/grant-effects.js +1 -0
  486. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
  487. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  488. package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
  489. package/dist/daemon/reconcilers/ledger-r2.js +7 -0
  490. package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
  491. package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
  492. package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
  493. package/dist/daemon/reconcilers/ledger-storage.js +5 -0
  494. package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
  495. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  496. package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
  497. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  498. package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
  499. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  500. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
  501. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  502. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
  503. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
  504. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
  505. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
  506. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  507. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  508. package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
  509. package/dist/daemon/reconcilers/recipe-image.js +7 -0
  510. package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
  511. package/dist/daemon/reconcilers/row-claim.js +2 -0
  512. package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
  513. package/dist/daemon/reconcilers/storage-due-work.js +2 -1
  514. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
  515. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  516. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  517. package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
  518. package/dist/daemon/reconcilers/throttled-lane.js +1 -0
  519. package/dist/daemon/review/finish.js +1 -1
  520. package/dist/daemon/run-notices.d.ts +3 -0
  521. package/dist/daemon/run-notices.js +1 -1
  522. package/dist/daemon/runs/append-section.d.ts +4 -1
  523. package/dist/daemon/runs/append-section.js +2 -2
  524. package/dist/daemon/runs/observer.d.ts +3 -2
  525. package/dist/daemon/runs/observer.js +3 -2
  526. package/dist/daemon/runs/view-transport.d.ts +19 -0
  527. package/dist/daemon/runs/view-transport.js +1 -0
  528. package/dist/daemon/structured-requests/boot.d.ts +2 -1
  529. package/dist/daemon/structured-requests/boot.js +1 -1
  530. package/dist/daemon/structured-requests/effects.d.ts +4 -3
  531. package/dist/daemon/structured-requests/effects.js +1 -1
  532. package/dist/daemon/structured-requests/notifier.d.ts +2 -0
  533. package/dist/daemon/structured-requests/notifier.js +1 -1
  534. package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
  535. package/dist/daemon/structured-requests/sidecar.js +1 -1
  536. package/dist/launcher/validate.js +1 -1
  537. package/dist/migrations/004-canvas-documents/index.js +2 -2
  538. package/dist/pi-extensions/broker-local.d.ts +3 -3
  539. package/dist/pi-extensions/broker-local.js +1 -2
  540. package/dist/pi-extensions/canvas-bash-valve.js +6 -6
  541. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  542. package/dist/pi-extensions/canvas-elapsed.js +2 -2
  543. package/dist/pi-extensions/canvas-goal-capture.js +1 -1
  544. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  545. package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
  546. package/dist/pi-extensions/canvas-review-boundary.js +3 -3
  547. package/dist/pi-extensions/canvas-stophook.js +1 -1
  548. package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
  549. package/dist/pi-extensions/canvas-structured-output.js +6 -11
  550. package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
  551. package/dist/pi-extensions/canvas-tool-guide.js +6 -6
  552. package/dist/shared/inbox-entry-body.js +7 -7
  553. package/dist/types.d.ts +12 -0
  554. package/docs/sdk/release-notes.md +4 -0
  555. package/package.json +7 -4
  556. package/packages/crouter-identity/package.json +1 -1
  557. package/runtime.lock.json +13 -13
  558. package/scripts/git-credential-crtr +33 -0
  559. package/scripts/sandbox-bootstrap.sh +54 -0
  560. package/scripts/sandbox-start.mjs +320 -0
  561. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
  562. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
  563. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
  564. package/dist/core/conversation-store/file-store.d.ts +0 -37
  565. package/dist/core/conversation-store/file-store.js +0 -9
  566. package/dist/core/conversation-store/listener.d.ts +0 -4
  567. package/dist/core/conversation-store/listener.js +0 -8
  568. package/dist/core/scoped-state/profiles.d.ts +0 -27
  569. package/dist/core/scoped-state/profiles.js +0 -1
  570. package/dist/core/scoped-state/providers.d.ts +0 -24
  571. package/dist/core/scoped-state/providers.js +0 -1
  572. package/dist/core/scoped-state/settings.d.ts +0 -28
  573. package/dist/core/scoped-state/settings.js +0 -1
@@ -1,9 +1,9 @@
1
- var re=Object.defineProperty;var a=(e,t)=>re(e,"name",{value:t,configurable:!0});import{spawn as ie,spawnSync as se}from"node:child_process";import{homedir as w,tmpdir as ae}from"node:os";import{mkdtempSync as oe,rmSync as ce}from"node:fs";import{piAgentDir as P}from"../../core/runtime/package-health.js";import{basename as le,dirname as _,join as m,relative as ue,resolve as de}from"node:path";import{isDeepStrictEqual as x}from"node:util";import{BINDING_CATALOG as pe,normalizeGesture as fe,splitGestureExpression as he,inboxShortcut as me,resolveKeybindings as S}from"../../core/keybindings/index.js";import{runtimeManifest as ge}from"./shared.js";import{atomicWriteJson as ke,readJsonIfExists as ve,readJsonOrNull as L}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as xe}from"../../core/runtime/pi-cli.js";import{crtrVersion as we}from"../../shared/crtr-version.js";import{installTmuxBindings as be}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as ye}from"../../core/config.js";import{detectNerdFont as Ie,nerdFontInstallCommand as Pe,createCurlPercentReader as Se,NERD_FONT_MANUAL_LINUX_COMMAND as Ce,NERD_FONT_SELECT_HINT as Ee}from"../../core/runtime/nerd-font.js";import{startProgressBar as Ae}from"../../core/runtime/progress-bar.js";import{ensureRenderer as $e,isRendererReady as K}from"../../core/termrender/termrender.js";import{installFromMarketplace as Re,isMarketplaceRelativeSource as De}from"../pkg/plugin-manage.js";import{requiredPluginEnv as Me}from"../../core/plugin-env.js";import{readPluginManifest as Ne}from"../../core/manifest.js";import{addMarketplace as j}from"../pkg/market-manage.js";import{clone as Te}from"../../core/git.js";import{readMarketplaceManifest as Oe}from"../../core/manifest.js";import{findPluginByName as F,findMarketplaceByName as C}from"../../core/resolver.js";import{expandTilde as _e}from"../../core/fs-utils.js";import{applyTerminalEdit as Le}from"./terminal-option.js";const E="crouter-official-marketplace",A="https://github.com/crouton-labs/crouter-official-marketplace.git",$="main";function It(e){const t=[],n=new Set,r=new Map;try{for(const o of e){if(o.sourceKind!=="marketplace-plugin")continue;const[l,c]=o.installSource.split("/");if(!l||!c)continue;const u=F(c,"user")?.manifest;let d=C(l,"user");if(!d&&!u&&l===E)try{let i=r.get(l);i||(i=oe(m(ae(),"crtr-setup-market-")),r.set(l,i),Te(A,m(i,"checkout"),{ref:$,depth:1}));const p=m(i,"checkout"),v=Oe(p);v&&(d={root:p,manifest:v})}catch{}const h=d?.manifest.plugins.find(i=>i.name===c)?.source,f=h&&De(h)?Ne(m(d.root,h))??u:u;if(f)for(const i of Me(f.env))n.has(i)||(n.add(i),t.push({name:i,plugin:c,declaration:f.env[i]}))}}finally{for(const o of r.values())ce(o,{recursive:!0,force:!0})}return t}a(It,"setupPluginEnvFields");function G(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}a(G,"isKeybindingsObject");function g(e){return G(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}a(g,"cloneKeybindings");class Pt{static{a(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=g(t),this.current=g(t),this.baselineInvalidRoot=t!==void 0&&!G(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=ye(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!x(this.current,this.baseline)||!x(this.invalidRoot,this.baselineInvalidRoot)||!x(this.currentPassthrough,this.baselinePassthrough)}overrides(){return g(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=S(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=pe.find(f=>f.id===t);let o;try{o=n.trim()===""?[]:he(n).map(f=>fe(f.trim(),r))}catch(f){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:f instanceof Error?f.message:String(f)}]}}const l=[...new Set(o)],c={...this.current};delete c[t];const u=[...S(c).gestures(t)],s=x(l,u)?c:{...this.current,[t]:l},d=S(s),h=d.diagnostics.filter(f=>f.bindingId===t||f.relatedBindingIds?.includes(t));return h.length>0?{ok:!1,diagnostics:h}:(this.current=s,this.resolutionCache=void 0,{ok:!0,diagnostics:d.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=g(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:g(t),this.baseline=g(t),this.current=g(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const Ke={"official-marketplace":{name:E,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.2.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"exa-search-plugin":{name:"exa-search",shortDescription:"crtr plugin mounting `crtr exa-search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `exa-search` plugin from the official crtr marketplace. It mounts `crtr exa-search` and calls Exa directly with EXA_API_KEY, collected during install or set through `crtr sys env set --name EXA_API_KEY` in the app env store. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."},"dev-plugin":{name:"dev",shortDescription:"crtr plugin mounting the development workflow \u2014 repository setup, worktrees, pull requests, and a dev track in the tutorial.",longDescription:"Installs the dev plugin from the official crtr marketplace. It adds the /dev: workflow commands (init, spec, design, plan, pr-loop), mounts crtr dev for a repository's own lifecycle commands and Grove instances, and contributes the crtr sys tutorial dev track. Uncheck it on a machine whose agents do not work in source repositories."}},R={"official-marketplace":{kind:"marketplace-source",source:A},"crtr-extensions":{kind:"local-path",source:U("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.2.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"exa-search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/exa-search"},"dev-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/dev"}},B=["extensions/*.ts","extensions/*/index.ts","!extensions/**/*.d.ts"],je={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"exa-search-plugin":[],"dev-plugin":[]};function U(e){return m(ge.runtimeHome(),"selected","dist","builtin-pi-packages",e)}a(U,"selectedPiPackageDir");function D(e=U){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","exa-search-plugin","dev-plugin"].map(t=>{const n=Ke[t],r=R[t].kind==="local-path"?e(n.name):R[t].source;return{id:t,name:n.name,sourceKind:R[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}a(D,"buildSetupManifest");function St(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}a(St,"packagePlanAction");function Fe(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}a(Fe,"npmPackageName");function b(e,t,n){const r=Fe(e);if(r!==null)return`npm:${r}`;const o=_e(e,n);return de(t,o)}a(b,"normalizePackageIdentity");function y(e){return`package:${e}`}a(y,"packageNameIdentity");function Y(e){return e.startsWith("npm:")?[]:[y(le(e))]}a(Y,"localPackageNameIdentities");function Ge(e,t,n){const r=[b(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(y(e.name));for(const o of je[e.id])r.push(y(o))}return r}a(Ge,"manifestIdentities");function z(e,t=D(),n=m(P(),"settings.json"),r=w()){const o=_(n),l=new Set,c=new Map;for(const s of t)for(const d of Ge(s,o,r))c.set(d,s.id);const u=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(u))return l;for(const s of u){const d=typeof s=="string"?s:s&&typeof s=="object"&&typeof s.source=="string"?s.source:null;if(d===null)continue;const h=[b(d,o,r),...Y(d)];for(const f of h){const i=c.get(f);if(i==="crtr-extensions"){const p=t.find(v=>v.id===i);if(b(d,o,r)!==b(p.installSource,o,r)||!s||typeof s!="object"||!x(s.extensions,B))continue}i!==void 0&&l.add(i)}}return l}a(z,"detectInstalledSetupPackageIds");function k(e){return se("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}a(k,"detectCommandOnPath");function Be(e=process.platform,t=k){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}a(Be,"detectPackageManager");function Ue(e,t,n=k){if(e==="nerd-font"?Ie().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const l=Pe(t);return{tool:e,installed:!1,command:l.command,hint:`${l.hint} \u2014 ${Ee}`,autoInstall:l.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}a(Ue,"buildSystemInstallPlan");function M(e=w()){return m(e===w()?P():m(e,".pi","agent"),"settings.json")}a(M,"resolveSettingsPath");function Ct(e={}){const t=e.homeDir??w(),n=e.settingsPath??M(t),r=e.manifest??D(),o=ve(n),l=z(o,r,n,t);for(const d of V(r))l.add(d);const c=e.commandExists??k,u=e.packageManager??Be(process.platform,c),s=["tmux","nvim","nerd-font"].map(d=>Ue(d,u,c));return{manifest:r,installedPackageIds:l,systemPlans:s}}a(Ct,"buildSetupInitialState");function Et(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${me()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
1
+ var re=Object.defineProperty;var a=(e,t)=>re(e,"name",{value:t,configurable:!0});import{spawn as ie,spawnSync as se}from"node:child_process";import{homedir as x,tmpdir as ae}from"node:os";import{mkdtempSync as oe,rmSync as ce}from"node:fs";import{piAgentDir as P}from"../../core/runtime/package-health.js";import{basename as le,dirname as _,join as m,relative as ue,resolve as de}from"node:path";import{isDeepStrictEqual as w}from"node:util";import{BINDING_CATALOG as pe,normalizeGesture as fe,splitGestureExpression as he,inboxShortcut as me,resolveKeybindings as S}from"../../core/keybindings/index.js";import{runtimeManifest as ge}from"./shared.js";import{atomicWriteJson as ke,readJsonIfExists as ve,readJsonOrNull as L}from"../../core/fs-utils.js";import{resolveBundledPiCliPath as we}from"../../core/runtime/pi-cli.js";import{crtrVersion as xe}from"../../shared/crtr-version.js";import{installTmuxBindings as be}from"../../core/runtime/tmux-chrome.js";import{normalizeTmuxPassthrough as ye}from"../../core/config.js";import{detectNerdFont as Ie,nerdFontInstallCommand as Pe,createCurlPercentReader as Se,NERD_FONT_MANUAL_LINUX_COMMAND as Ce,NERD_FONT_SELECT_HINT as Ee}from"../../core/runtime/nerd-font.js";import{startProgressBar as Ae}from"../../core/runtime/progress-bar.js";import{ensureRenderer as $e,isRendererReady as K}from"../../core/termrender/termrender.js";import{installFromMarketplace as Re,isMarketplaceRelativeSource as De}from"../pkg/plugin-manage.js";import{requiredPluginEnv as Me}from"../../core/plugin-env.js";import{readPluginManifest as Ne}from"../../core/manifest.js";import{addMarketplace as j}from"../pkg/market-manage.js";import{clone as Te}from"../../core/git.js";import{readMarketplaceManifest as Oe}from"../../core/manifest.js";import{findPluginByName as F,findMarketplaceByName as C}from"../../core/resolver.js";import{expandTilde as _e}from"../../core/fs-utils.js";import{applyTerminalEdit as Le}from"./terminal-option.js";const E="crouter-official-marketplace",A="https://github.com/crouton-labs/crouter-official-marketplace.git",$="main";function It(e){const t=[],n=new Set,r=new Map;try{for(const o of e){if(o.sourceKind!=="marketplace-plugin")continue;const[l,c]=o.installSource.split("/");if(!l||!c)continue;const u=F(c,"user")?.manifest;let d=C(l,"user");if(!d&&!u&&l===E)try{let i=r.get(l);i||(i=oe(m(ae(),"crtr-setup-market-")),r.set(l,i),Te(A,m(i,"checkout"),{ref:$,depth:1}));const p=m(i,"checkout"),v=Oe(p);v&&(d={root:p,manifest:v})}catch{}const h=d?.manifest.plugins.find(i=>i.name===c)?.source,f=h&&De(h)?Ne(m(d.root,h))??u:u;if(f)for(const i of Me(f.env))n.has(i)||(n.add(i),t.push({name:i,plugin:c,declaration:f.env[i]}))}}finally{for(const o of r.values())ce(o,{recursive:!0,force:!0})}return t}a(It,"setupPluginEnvFields");function G(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}a(G,"isKeybindingsObject");function g(e){return G(e)?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Array.isArray(n)?[...n]:n])):{}}a(g,"cloneKeybindings");class Pt{static{a(this,"SetupKeybindingsDraft")}expected;baseline;current;baselineInvalidRoot;invalidRoot;resolutionCache;expectedPassthrough;baselinePassthrough;currentPassthrough;constructor(t,n=void 0){this.expected=t,this.baseline=g(t),this.current=g(t),this.baselineInvalidRoot=t!==void 0&&!G(t)?t:void 0,this.invalidRoot=this.baselineInvalidRoot,this.expectedPassthrough=n,this.baselinePassthrough=ye(n),this.currentPassthrough=[...this.baselinePassthrough]}get dirty(){return!w(this.current,this.baseline)||!w(this.invalidRoot,this.baselineInvalidRoot)||!w(this.currentPassthrough,this.baselinePassthrough)}overrides(){return g(this.current)}expectedKeybindings(){return this.expected}tmuxPassthrough(){return[...this.currentPassthrough]}expectedTmuxPassthrough(){return this.expectedPassthrough}usesTmuxPassthrough(t){return this.currentPassthrough.includes(t)}toggleTmuxPassthrough(t){this.currentPassthrough=this.currentPassthrough.includes(t)?this.currentPassthrough.filter(n=>n!==t):[...this.currentPassthrough,t]}resolution(){return this.resolutionCache===void 0&&(this.resolutionCache=S(this.invalidRoot===void 0?this.current:this.invalidRoot)),this.resolutionCache}hasInvalidRoot(){return this.invalidRoot!==void 0}expression(t){return this.resolution().gestures(t).join(", ")}edit(t,n){if(this.invalidRoot!==void 0)return{ok:!1,diagnostics:[{severity:"error",code:"invalid-keybindings",offendingValue:this.invalidRoot,message:"Reset all before editing: the saved keybindings root is invalid."}]};const r=pe.find(f=>f.id===t);let o;try{o=n.trim()===""?[]:he(n).map(f=>fe(f.trim(),r))}catch(f){return{ok:!1,diagnostics:[{severity:"error",code:"invalid-override",bindingId:t,offendingValue:n,message:f instanceof Error?f.message:String(f)}]}}const l=[...new Set(o)],c={...this.current};delete c[t];const u=[...S(c).gestures(t)],s=w(l,u)?c:{...this.current,[t]:l},d=S(s),h=d.diagnostics.filter(f=>f.bindingId===t||f.relatedBindingIds?.includes(t));return h.length>0?{ok:!1,diagnostics:h}:(this.current=s,this.resolutionCache=void 0,{ok:!0,diagnostics:d.diagnostics})}unbind(t){return this.edit(t,"")}resetRow(t){delete this.current[t],this.resolutionCache=void 0}resetAll(){this.current={},this.currentPassthrough=[],this.invalidRoot=void 0,this.resolutionCache=void 0}discard(){this.current=g(this.baseline),this.currentPassthrough=[...this.baselinePassthrough],this.invalidRoot=this.baselineInvalidRoot,this.resolutionCache=void 0}markSaved(t,n=[]){this.expected=Object.keys(t).length===0?void 0:g(t),this.baseline=g(t),this.current=g(t),this.expectedPassthrough=n.length===0?void 0:[...n],this.baselinePassthrough=[...n],this.currentPassthrough=[...n],this.baselineInvalidRoot=void 0,this.invalidRoot=void 0,this.resolutionCache=void 0}}const Ke={"official-marketplace":{name:E,shortDescription:"the official crtr plugin catalog \u2014 registered as a source so its plugins are installable by ref.",longDescription:"Shallow-clones github.com/crouton-labs/crouter-official-marketplace into the user scope and registers it, which is what makes `crtr pkg plugin install crouter-official-marketplace/<name>` resolve and what fills `crtr pkg market browse`. Registering the source installs no plugin by itself. Uncheck it on a machine that should reach no external catalog \u2014 a plugin selected below still registers the marketplace it comes from, because its ref cannot resolve otherwise."},"crtr-extensions":{name:"pi-crtr-extensions",shortDescription:"crtr companion extensions \u2014 command palette, help gating, subscription/OAuth rotation, nested context.",longDescription:"Bundles the extensions built for crtr: a crtr slash-command palette, crtr/crouter help gating, surfacing of Claude Code marketplace plugin commands, nested AGENTS.md/CLAUDE.md loading, OAuth login + rotation across multiple Claude subscriptions (provider-rotation), and system-prompt trimming. The OAuth/rotation piece is what lets crtr authenticate your Claude account."},"oauth-adapter":{name:"pi-claude-oauth-adapter",shortDescription:"Anthropic OAuth / Claude Code credential compatibility for pi.",longDescription:"Third-party adapter (minzique/dotfiles-agents) letting pi authenticate with Claude using Claude Code OAuth credentials. Installed from npm, pinned to 0.2.2."},"capture-plugin":{name:"capture",shortDescription:"crtr plugin mounting `crtr capture` \u2014 browser automation and UI measurement over CDP.",longDescription:"Installs the `capture` plugin from the official crtr marketplace. It mounts `crtr capture` as a transparent passthrough to the external Capture CLI (`npm install -g @crouton-kit/capture`) for CDP screenshots, rendered-geometry measurement, HAR, accessibility trees, and JS execution against a live page. Uncheck it on a machine where agents never drive a browser \u2014 the command then costs nothing in their root prompt."},"exa-search-plugin":{name:"exa-search",shortDescription:"crtr plugin mounting `crtr exa-search` \u2014 public-web discovery, grounded answers, and content extraction.",longDescription:"Installs the `exa-search` plugin from the official crtr marketplace. It mounts `crtr exa-search` and calls Exa directly with EXA_API_KEY, collected during install or set through `crtr sys env set --name EXA_API_KEY` in the app env store. Uncheck it on a machine whose agents get web search from somewhere else, such as a Northlight home where the platform serves `crtr search` from its own plugin."},"dev-plugin":{name:"dev",shortDescription:"crtr plugin mounting the development workflow \u2014 repository setup, worktrees, pull requests, and a dev track in the tutorial.",longDescription:"Installs the dev plugin from the official crtr marketplace. It adds the /dev: workflow commands (init, spec, design, plan, pr-loop), mounts crtr dev for a repository's own lifecycle commands and Grove instances, and contributes the crtr sys tutorial dev track. Uncheck it on a machine whose agents do not work in source repositories."}},R={"official-marketplace":{kind:"marketplace-source",source:A},"crtr-extensions":{kind:"local-path",source:U("pi-crtr-extensions")},"oauth-adapter":{kind:"npm",source:"npm:pi-claude-oauth-adapter@0.2.2"},"capture-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/capture"},"exa-search-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/exa-search"},"dev-plugin":{kind:"marketplace-plugin",source:"crouter-official-marketplace/dev"}},B=["extensions/*.ts","extensions/*/index.ts","!extensions/**/*.d.ts"],je={"official-marketplace":[],"crtr-extensions":["pi-crtr-extensions"],"oauth-adapter":[],"capture-plugin":[],"exa-search-plugin":[],"dev-plugin":[]};function U(e){return m(ge.runtimeHome(),"selected","dist","builtin-pi-packages",e)}a(U,"selectedPiPackageDir");function D(e=U){return["official-marketplace","crtr-extensions","oauth-adapter","capture-plugin","exa-search-plugin","dev-plugin"].map(t=>{const n=Ke[t],r=R[t].kind==="local-path"?e(n.name):R[t].source;return{id:t,name:n.name,sourceKind:R[t].kind,installSource:r,shortDescription:n.shortDescription,longDescription:n.longDescription}})}a(D,"buildSetupManifest");function St(e){switch(e.sourceKind){case"marketplace-source":return`clone + register ${e.installSource}`;case"marketplace-plugin":return`crtr pkg plugin install ${e.installSource}`;default:return`pi install ${e.installSource}`}}a(St,"packagePlanAction");function Fe(e){if(!e.startsWith("npm:"))return null;const t=e.slice(4),n=t.startsWith("@")?t.indexOf("@",1):t.lastIndexOf("@");return n>0?t.slice(0,n):t}a(Fe,"npmPackageName");function b(e,t,n){const r=Fe(e);if(r!==null)return`npm:${r}`;const o=_e(e,n);return de(t,o)}a(b,"normalizePackageIdentity");function y(e){return`package:${e}`}a(y,"packageNameIdentity");function Y(e){return e.startsWith("npm:")?[]:[y(le(e))]}a(Y,"localPackageNameIdentities");function Ge(e,t,n){const r=[b(e.installSource,t,n)];if(e.sourceKind==="local-path"){r.push(y(e.name));for(const o of je[e.id])r.push(y(o))}return r}a(Ge,"manifestIdentities");function z(e,t=D(),n=m(P(),"settings.json"),r=x()){const o=_(n),l=new Set,c=new Map;for(const s of t)for(const d of Ge(s,o,r))c.set(d,s.id);const u=e&&typeof e=="object"?e.packages:void 0;if(!Array.isArray(u))return l;for(const s of u){const d=typeof s=="string"?s:s&&typeof s=="object"&&typeof s.source=="string"?s.source:null;if(d===null)continue;const h=[b(d,o,r),...Y(d)];for(const f of h){const i=c.get(f);if(i==="crtr-extensions"){const p=t.find(v=>v.id===i);if(b(d,o,r)!==b(p.installSource,o,r)||!s||typeof s!="object"||!w(s.extensions,B))continue}i!==void 0&&l.add(i)}}return l}a(z,"detectInstalledSetupPackageIds");function k(e){return se("sh",["-lc",`command -v ${e} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}a(k,"detectCommandOnPath");function Be(e=process.platform,t=k){switch(e){case"darwin":return t("brew")?"brew":"manual";case"linux":return t("apt-get")?"apt-get":t("dnf")?"dnf":t("pacman")?"pacman":"manual";default:return"manual"}}a(Be,"detectPackageManager");function Ue(e,t,n=k){if(e==="nerd-font"?Ie().installed:n(e))return{tool:e,installed:!0,command:null,hint:"already installed",autoInstall:!1};if(e==="nerd-font"){const l=Pe(t);return{tool:e,installed:!1,command:l.command,hint:`${l.hint} \u2014 ${Ee}`,autoInstall:l.autoInstall}}const o=e==="nvim"?"neovim":"tmux";switch(t){case"brew":return{tool:e,installed:!1,command:`brew install ${o}`,hint:"Homebrew install",autoInstall:!0};case"apt-get":return{tool:e,installed:!1,command:`sudo apt-get update && sudo apt-get install -y ${o}`,hint:"apt-get install",autoInstall:!0};case"dnf":return{tool:e,installed:!1,command:`sudo dnf install -y ${o}`,hint:"dnf install",autoInstall:!0};case"pacman":return{tool:e,installed:!1,command:`sudo pacman -S --noconfirm ${o}`,hint:"pacman install",autoInstall:!0};default:return{tool:e,installed:!1,command:null,hint:`manual install required for ${e}`,autoInstall:!1}}}a(Ue,"buildSystemInstallPlan");function M(e=x()){return m(e===x()?P():m(e,".pi","agent"),"settings.json")}a(M,"resolveSettingsPath");function Ct(e={}){const t=e.homeDir??x(),n=e.settingsPath??M(t),r=e.manifest??D(),o=ve(n),l=z(o,r,n,t);for(const d of V(r))l.add(d);const c=e.commandExists??k,u=e.packageManager??Be(process.platform,c),s=["tmux","nvim","nerd-font"].map(d=>Ue(d,u,c));return{manifest:r,installedPackageIds:l,systemPlans:s}}a(Ct,"buildSetupInitialState");function Et(e){const t=e.manifest.map(r=>{const o=e.installedPackageIds.has(r.id)?"installed":"not installed";return`- ${r.name} \u2014 ${r.shortDescription} (${o})`}),n=e.systemPlans.map(r=>r.installed?`- ${r.tool}: \u2713 installed`:r.command?`- ${r.tool}: ${r.command}`:`- ${r.tool}: ${r.hint}`);return["crtr sys setup (non-interactive)","","Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.","","Packages:",...t,"","System deps:",...n,"",`Inbox: the inbox-toggle key (${me()??"disabled"}) is a crouter keybinding \u2014 view or rebind it in \`crtr sys settings\`; it is installed on the same tmux server as every other crouter binding.`,"Run `crtr sys setup` in a TTY to open the wizard."].join(`
2
2
  `)+`
3
- `}a(Et,"renderSetupStaticInstructions");class I extends Error{static{a(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function At(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}a(At,"commandOutput");function q(e,t,n,r=process.env){return new Promise((o,l)=>{const c=ie(e,t,{stdio:["ignore","pipe","pipe"],env:r});let u="";c.stdout.setEncoding("utf8"),c.stderr.setEncoding("utf8"),c.stdout.on("data",s=>{u+=s}),c.stderr.on("data",s=>{u+=s,n?.(s)}),c.on("error",s=>l(new I(`${e} failed: ${s.message}`,u))),c.on("close",s=>{s===0?o():l(new I(`${e} failed with status ${s??"unknown"}`,u))})})}a(q,"runCapturedCommand");function N(e,t){return q("sh",["-lc",e],t)}a(N,"runShellCommand");function Ye(e,t=xe()){return q(process.execPath,[t,"install",e],void 0,{...process.env,PI_CODING_AGENT_DIR:P()})}a(Ye,"installPiPackage");async function W(){k("capture")||await N("npm install -g @crouton-kit/capture")}a(W,"installCaptureCliIfMissing");function H(e){return e instanceof I?e.output:void 0}a(H,"capturedFailureOutput");function ze(e){const n=H(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}a(ze,"firstFailureLine");function qe(e){const t=H(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
3
+ `}a(Et,"renderSetupStaticInstructions");class I extends Error{static{a(this,"SetupCommandError")}output;constructor(t,n){super(t),this.output=n}}function At(e){return`${e.stdout?.toString()??""}${e.stderr?.toString()??""}`}a(At,"commandOutput");function q(e,t,n,r=process.env){return new Promise((o,l)=>{const c=ie(e,t,{stdio:["ignore","pipe","pipe"],env:r});let u="";c.stdout.setEncoding("utf8"),c.stderr.setEncoding("utf8"),c.stdout.on("data",s=>{u+=s}),c.stderr.on("data",s=>{u+=s,n?.(s)}),c.on("error",s=>l(new I(`${e} failed: ${s.message}`,u))),c.on("close",s=>{s===0?o():l(new I(`${e} failed with status ${s??"unknown"}`,u))})})}a(q,"runCapturedCommand");function N(e,t){return q("sh",["-lc",e],t)}a(N,"runShellCommand");function Ye(e,t=we()){return q(process.execPath,[t,"install",e],void 0,{...process.env,PI_CODING_AGENT_DIR:P()})}a(Ye,"installPiPackage");async function W(){k("capture")||await N("npm install -g @crouton-kit/capture")}a(W,"installCaptureCliIfMissing");function H(e){return e instanceof I?e.output:void 0}a(H,"capturedFailureOutput");function ze(e){const n=H(e)?.split(/\r?\n/).find(r=>r.trim()!=="");return n!==void 0?n.trim():e instanceof Error?e.message:String(e)}a(ze,"firstFailureLine");function qe(e){const t=H(e);t===void 0||t.length===0||process.stderr.write(t.endsWith(`
4
4
  `)?t:`${t}
5
5
  `)}a(qe,"printCapturedFailure");class We{static{a(this,"SetupProgress")}interactive;bar=null;constructor(t=!!process.stdout.isTTY){this.interactive=t}start(t){return this.interactive?(this.bar=Ae(`Installing ${t}\u2026`),this.bar):null}async clear(){await this.bar?.stop(),this.bar=null}async succeed(t){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2713 ${t}
6
6
  `)}async fail(t,n){await this.clear(),this.interactive&&process.stdout.write(`\r\x1B[2K\u2717 ${t} \u2014 ${ze(n)}
7
7
  `),qe(n)}async run(t,n){const r=this.start(t);try{const o=await n(r);return await this.succeed(t),o}catch(o){throw await this.fail(t,o),o}}}function X(e,t){return K()?"current":(e?.(),$e(t),K()?"provisioned":"unavailable")}a(X,"ensureManagedRenderer");async function He(){try{be()}catch{}}a(He,"reconcileInboxFrontDoor");function J(e,t){return t.length===0?[`${e}: none`]:[`${e}:`,...t.map(n=>` - ${n}`)]}a(J,"summarySection");function $t(e){return["crtr sys setup complete",...J("installed",e.installed),...J("skipped",e.skipped),"New to crouter? Ask for the tutorial in your first conversation, or run /tutorial any time."].join(`
8
8
  `)+`
9
- `}a($t,"formatSetupExecutionSummary");function V(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?C(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&F(r.name,t)!==null&&n.push(r.id)}catch{}return n}a(V,"detectInstalledMarketplaceEntries");function Xe(e,t="user"){if(C(e,t)!==null)return null;if(e!==E)throw new Error(`marketplace not registered: ${e}`);return j({url:A,ref:$,scope:t}),e}a(Xe,"ensureMarketplaceRegistered");function Je(e){const t=M(),n=L(t);if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`invalid pi settings: ${t}`);const r=n.packages;if(!Array.isArray(r))throw new Error(`invalid pi packages: ${t}`);const o=a(u=>{const s=typeof u=="string"?u:u&&typeof u=="object"?u.source:void 0;return typeof s=="string"&&Y(s).includes(y("pi-crtr-extensions"))},"isCrtrExtensions"),l=r.findIndex(o),c=r.filter(u=>!o(u));c.splice(l<0?c.length:l,0,{source:ue(_(t),e),extensions:B}),ke(t,{...n,packages:c})}a(Je,"configureCrtrExtensions");const Q="git is not installed \u2014 install it (Debian/Ubuntu: apt-get install git), then run `crtr sys setup`";function Z(e){return e.sourceKind==="marketplace-source"||e.sourceKind==="marketplace-plugin"}a(Z,"isMarketplaceEntry");async function ee(e){if(e.sourceKind==="marketplace-source")return j({url:e.installSource,ref:$,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=Xe(t);return await Re({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await W(),r===null?[e.name]:[r,e.name]}return await Ye(e.installSource),e.id==="crtr-extensions"&&Je(e.installSource),[e.name]}a(ee,"installSetupPackage");async function Rt(e,t=k){const n=D(),r=z(L(M()),n);for(const s of V(n,"user"))r.add(s);const o=new Map(n.map(s=>[s.id,s])),l=process.stdin.isTTY&&process.stdout.isTTY?["crtr-extensions","official-marketplace","oauth-adapter","capture-plugin","exa-search-plugin"]:["crtr-extensions","official-marketplace","capture-plugin","exa-search-plugin"];let c,u=!1;for(const s of l){const d=o.get(s);if(!r.has(s)){if(Z(d)&&(c??=!t("git"),c)){u||e("marketplace packages",new Error(Q)),u=!0;continue}try{await ee(d)}catch(h){e(d.name,h)}}}try{X(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(s){e("termrender renderer",s)}return we()}a(Rt,"reconcileFirstRun");async function Dt(e,t=k){const n=[],r=[],o=[],l=[],c=new We;let u,s=!1;for(const i of e.packages){if(e.installedPackageIds.has(i.id)){if(r.push(`${i.name} (already installed)`),i.id==="capture-plugin"&&!k("capture"))try{await c.run("Capture CLI",()=>W()),n.push("Capture CLI")}catch(p){r.push(`Capture CLI (${p instanceof Error?p.message:String(p)})`)}continue}if(Z(i)&&(u??=!t("git"),u)){s||r.push(`marketplace packages (${Q})`),s=!0;continue}try{n.push(...await c.run(i.name,()=>ee(i)))}catch(p){if(i.sourceKind!=="marketplace-source"&&i.sourceKind!=="marketplace-plugin")throw p;r.push(`${i.name} (${p instanceof Error?p.message:String(p)})`)}}for(const i of e.systemDeps){if(i.installed){l.push(`${i.tool} (already installed)`);continue}if(!i.autoInstall||!i.command){l.push(`${i.tool} (${i.hint})`);continue}const p=i.command,v=p===Ce;await c.run(i.tool,T=>{if(!v||T===null)return N(p);const te=Se();return N(p,ne=>{const O=te(ne);O!==null&&T.setFraction(O/100)})}),o.push(i.tool)}const d=[];let h=!1,f;try{f=X(()=>{h=!0,c.start("termrender renderer")},i=>d.push(i))}catch(i){throw h&&await c.fail("termrender renderer",i),i}switch(f){case"provisioned":h&&await c.succeed("termrender renderer"),n.push("termrender renderer");break;case"current":r.push("termrender renderer (current)");break;case"unavailable":{const i=new I("unavailable \u2014 install uv",d.join(""));h&&await c.fail("termrender renderer",i),r.push("termrender renderer (unavailable \u2014 install uv)");break}}if(e.terminalEdit!==void 0){const i=`Option as Alt (${e.terminalEdit.path})`,p=Le(e.terminalEdit);p.ok?n.push(`${i} \u2014 ${e.terminalEdit.reload}`):r.push(`${i} (${p.message})`)}return await He(),{installed:[...n,...o],skipped:[...r,...l]}}a(Dt,"executeSetupSubmission");export{E as OFFICIAL_MARKETPLACE_NAME,$ as OFFICIAL_MARKETPLACE_REF,A as OFFICIAL_MARKETPLACE_URL,Pt as SetupKeybindingsDraft,Ct as buildSetupInitialState,D as buildSetupManifest,Ue as buildSystemInstallPlan,k as detectCommandOnPath,z as detectInstalledSetupPackageIds,Be as detectPackageManager,Dt as executeSetupSubmission,$t as formatSetupExecutionSummary,b as normalizePackageIdentity,St as packagePlanAction,Rt as reconcileFirstRun,He as reconcileInboxFrontDoor,Et as renderSetupStaticInstructions,M as resolveSettingsPath,It as setupPluginEnvFields};
9
+ `}a($t,"formatSetupExecutionSummary");function V(e,t){const n=[];for(const r of e)try{r.sourceKind==="marketplace-source"?C(r.name,t)!==null&&n.push(r.id):r.sourceKind==="marketplace-plugin"&&F(r.name,t)!==null&&n.push(r.id)}catch{}return n}a(V,"detectInstalledMarketplaceEntries");async function Xe(e,t="user"){if(C(e,t)!==null)return null;if(e!==E)throw new Error(`marketplace not registered: ${e}`);return await j({url:A,ref:$,scope:t}),e}a(Xe,"ensureMarketplaceRegistered");function Je(e){const t=M(),n=L(t);if(!n||typeof n!="object"||Array.isArray(n))throw new Error(`invalid pi settings: ${t}`);const r=n.packages;if(!Array.isArray(r))throw new Error(`invalid pi packages: ${t}`);const o=a(u=>{const s=typeof u=="string"?u:u&&typeof u=="object"?u.source:void 0;return typeof s=="string"&&Y(s).includes(y("pi-crtr-extensions"))},"isCrtrExtensions"),l=r.findIndex(o),c=r.filter(u=>!o(u));c.splice(l<0?c.length:l,0,{source:ue(_(t),e),extensions:B}),ke(t,{...n,packages:c})}a(Je,"configureCrtrExtensions");const Q="git is not installed \u2014 install it (Debian/Ubuntu: apt-get install git), then run `crtr sys setup`";function Z(e){return e.sourceKind==="marketplace-source"||e.sourceKind==="marketplace-plugin"}a(Z,"isMarketplaceEntry");async function ee(e){if(e.sourceKind==="marketplace-source")return await j({url:e.installSource,ref:$,scope:"user"}),[e.name];if(e.sourceKind==="marketplace-plugin"){const[t,n]=e.installSource.split("/"),r=await Xe(t);return await Re({marketplace:t,plugin:n},"user"),e.id==="capture-plugin"&&await W(),r===null?[e.name]:[r,e.name]}return await Ye(e.installSource),e.id==="crtr-extensions"&&Je(e.installSource),[e.name]}a(ee,"installSetupPackage");async function Rt(e,t=k){const n=D(),r=z(L(M()),n);for(const s of V(n,"user"))r.add(s);const o=new Map(n.map(s=>[s.id,s])),l=process.stdin.isTTY&&process.stdout.isTTY?["crtr-extensions","official-marketplace","oauth-adapter","capture-plugin","exa-search-plugin"]:["crtr-extensions","official-marketplace","capture-plugin","exa-search-plugin"];let c,u=!1;for(const s of l){const d=o.get(s);if(!r.has(s)){if(Z(d)&&(c??=!t("git"),c)){u||e("marketplace packages",new Error(Q)),u=!0;continue}try{await ee(d)}catch(h){e(d.name,h)}}}try{X(void 0,()=>{})==="unavailable"&&e("termrender renderer",new Error("unavailable \u2014 install uv"))}catch(s){e("termrender renderer",s)}return xe()}a(Rt,"reconcileFirstRun");async function Dt(e,t=k){const n=[],r=[],o=[],l=[],c=new We;let u,s=!1;for(const i of e.packages){if(e.installedPackageIds.has(i.id)){if(r.push(`${i.name} (already installed)`),i.id==="capture-plugin"&&!k("capture"))try{await c.run("Capture CLI",()=>W()),n.push("Capture CLI")}catch(p){r.push(`Capture CLI (${p instanceof Error?p.message:String(p)})`)}continue}if(Z(i)&&(u??=!t("git"),u)){s||r.push(`marketplace packages (${Q})`),s=!0;continue}try{n.push(...await c.run(i.name,()=>ee(i)))}catch(p){if(i.sourceKind!=="marketplace-source"&&i.sourceKind!=="marketplace-plugin")throw p;r.push(`${i.name} (${p instanceof Error?p.message:String(p)})`)}}for(const i of e.systemDeps){if(i.installed){l.push(`${i.tool} (already installed)`);continue}if(!i.autoInstall||!i.command){l.push(`${i.tool} (${i.hint})`);continue}const p=i.command,v=p===Ce;await c.run(i.tool,T=>{if(!v||T===null)return N(p);const te=Se();return N(p,ne=>{const O=te(ne);O!==null&&T.setFraction(O/100)})}),o.push(i.tool)}const d=[];let h=!1,f;try{f=X(()=>{h=!0,c.start("termrender renderer")},i=>d.push(i))}catch(i){throw h&&await c.fail("termrender renderer",i),i}switch(f){case"provisioned":h&&await c.succeed("termrender renderer"),n.push("termrender renderer");break;case"current":r.push("termrender renderer (current)");break;case"unavailable":{const i=new I("unavailable \u2014 install uv",d.join(""));h&&await c.fail("termrender renderer",i),r.push("termrender renderer (unavailable \u2014 install uv)");break}}if(e.terminalEdit!==void 0){const i=`Option as Alt (${e.terminalEdit.path})`,p=Le(e.terminalEdit);p.ok?n.push(`${i} \u2014 ${e.terminalEdit.reload}`):r.push(`${i} (${p.message})`)}return await He(),{installed:[...n,...o],skipped:[...r,...l]}}a(Dt,"executeSetupSubmission");export{E as OFFICIAL_MARKETPLACE_NAME,$ as OFFICIAL_MARKETPLACE_REF,A as OFFICIAL_MARKETPLACE_URL,Pt as SetupKeybindingsDraft,Ct as buildSetupInitialState,D as buildSetupManifest,Ue as buildSystemInstallPlan,k as detectCommandOnPath,z as detectInstalledSetupPackageIds,Be as detectPackageManager,Dt as executeSetupSubmission,$t as formatSetupExecutionSummary,b as normalizePackageIdentity,St as packagePlanAction,Rt as reconcileFirstRun,He as reconcileInboxFrontDoor,Et as renderSetupStaticInstructions,M as resolveSettingsPath,It as setupPluginEnvFields};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var i=(r,o)=>c(r,"name",{value:o,configurable:!0});import{ModelRegistry as d,ModelRuntime as u}from"@earendil-works/pi-coding-agent";import{join as n}from"node:path";import{piAgentDir as f}from"../../core/runtime/package-health.js";import{secretsDir as m}from"../../core/layout.js";import{PoolCredentialStore as l}from"../../core/pool-credential-store.js";import{initializeFreshScopedStore as g}from"../../core/scoped-state/migrate.js";import{runTuiPage as S}from"../../core/tui/page-host.js";async function k(r,o){const t=f();g({kind:"provider",root:m()});const e=await u.create({credentials:new l(n(m(),"auth.json")),modelsPath:n(t,"models.json")}),s=new d(e);return S((p,a)=>r({...p,agentDir:t,runtime:e,registry:s},a),o)}i(k,"runSetupSettingsProcess");export{k as runSetupSettingsProcess};
1
+ var p=Object.defineProperty;var i=(r,t)=>p(r,"name",{value:t,configurable:!0});import{ModelRegistry as a,ModelRuntime as c}from"@earendil-works/pi-coding-agent";import{join as l}from"node:path";import{piAgentDir as u}from"../../core/runtime/package-health.js";import{ApiCredentialStore as f}from"../../core/model-auth/api-credential-store.js";import{cliClient as d}from"../api-client.js";import{runTuiPage as g}from"../../core/tui/page-host.js";async function D(r,t){const e=u(),o=await c.create({credentials:new f(()=>d()),modelsPath:l(e,"models.json")}),n=new a(o);return g((m,s)=>r({...m,agentDir:e,runtime:o,registry:n},s),t)}i(D,"runSetupSettingsProcess");export{D as runSetupSettingsProcess};
@@ -1,3 +1,3 @@
1
- var y=Object.defineProperty;var t=(e,r)=>y(e,"name",{value:r,configurable:!0});import{defineBranch as w,defineLeaf as c}from"../../core/command.js";import{InputError as l}from"../../core/io.js";import{cliClient as m}from"../api-client.js";const d=t(e=>e===null?"unpriced":`$${e.toFixed(e<1?4:2)}`,"usd"),$=t(e=>[e.funding&&`funding ${e.funding}`,e.grantee&&`grantee ${e.grantee}`,e.provider&&`provider ${e.provider}`,e.sub&&`sub ${e.sub}`].filter(Boolean).join(", ")||"everything","filters"),p=t(e=>`- \`${e.id}\` ${e.payer} ${d(e.usd_per_month)}/month on ${$(e)} (${e.source})`,"limitLine"),b=c({name:"show",description:"show a month's spend by payer and funding, with the limits",whenToUse:"checking what a payer has spent this month and which limits apply",help:{name:"sys spend show",summary:"month totals by payer and by payer and funding from the ledger, then every limit row",params:[{kind:"flag",name:"month",type:"string",required:!1,constraint:"UTC month YYYY-MM. Default: the current month."}],output:[{name:"month",type:"string",required:!0,constraint:"The month shown, YYYY-MM."},{name:"totals",type:"ChargeTotalsDTO",required:!0,constraint:"Record: {month, by_payer, by_funding, limits}. Migrated user-paid model history has funding `legacy`."}],outputKind:"object",effects:["None. Read-only."]},run:t(async e=>{const r=await m().listCharges({limit:1,...e.month===void 0?{}:{month:String(e.month)}});if(r.totals===void 0)throw new l({error:"owner_only",message:"month totals and limits are read by the person; this caller sees only its own app's charges",next:"Run `crtr sys spend show` from the person's own shell, not from inside a node."});return{month:r.month,totals:r.totals}},"run"),render:t(e=>{const r=e.totals;return[`Spend for ${r.month}:`,...r.by_payer.length===0?["- nothing charged"]:r.by_payer.map(i=>`- ${i.payer} ${d(i.usd)}${r.by_funding.filter(s=>s.payer===i.payer).map(s=>` ${s.funding} ${d(s.usd)}`).join("")}`),"Limits:",...r.limits.length===0?["- none"]:r.limits.map(p)].join(`
2
- `)},"render")});function v(e){const r=new Map;for(const n of e)r.set(n.provider??"(none)",(r.get(n.provider??"(none)")??0)+(n.usd??0));const i=new Set(e.map(n=>n.request)),s=t(n=>e.filter(o=>(o.caused_by??null)===n),"children"),a=[],u=new Set,h=t((n,o)=>{if(!u.has(n.id)&&(u.add(n.id),a.push(`${" ".repeat(o)}- ${n.at} ${n.kind} ${n.what} ${d(n.usd)} ${n.payer}/${n.funding}${n.provider?` \u2192 ${n.provider}`:""} vendor_ref ${n.vendor_ref??"none"}${n.refused?` REFUSED by ${n.refused.limit}`:""}`),n.request!==null))for(const g of s(`request:${n.request}`))h(g,o+1)},"print"),f=e.filter(n=>n.caused_by===null||!(n.caused_by.startsWith("request:")&&i.has(n.caused_by.slice(8))));for(const n of f)h(n,0);for(const n of e)h(n,0);return[...a,"Total per provider:",...[...r].map(([n,o])=>`- ${n} ${d(o)}`)].join(`
3
- `)}t(v,"tree");const q=c({name:"chain",description:"list the charge rows under a run, message, request or charge on this runtime",whenToUse:"finding what one run, message or request cost and matching its vendor_ref to a vendor's usage line",help:{name:"sys spend chain",summary:"the rows under a reference as a tree, with each row's vendor_ref and a total per provider",params:[{kind:"positional",name:"reference",type:"string",required:!0,constraint:"`run:<id>`, `message:<id>`, `request:<id>`, `cron_run:<id>` or a charge id. Reads this runtime only."}],output:[{name:"reference",type:"string",required:!0,constraint:"The reference read."},{name:"charges",type:"ChargeDTO[]",required:!0,constraint:"Rows in time order; empty when this runtime holds none under the reference."}],outputKind:"object",effects:["None. Read-only."]},run:t(async e=>{const r=String(e.reference),i=[];for(let s;;){const a=await m().listCharges({under:r,...s===void 0?{}:{after:s}});if(i.push(...a.charges),a.next===null)break;s=a.next}return{reference:r,charges:i}},"run"),render:t(e=>{const r=e.charges;return r.length===0?`No charges under ${String(e.reference)} on this runtime.`:v(r)},"render")}),_=c({name:"limit",description:"set or clear one of the person's dollar limits",whenToUse:"stopping a payer's spend (0 is an emergency stop) or capping it per month; clearing a limit you set",help:{name:"sys spend limit",summary:"write or remove the limit row `person:<name>`; the check refuses calls billed to the payer once the month reaches it",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"A name for the row; the id is `person:<name>`."},{kind:"flag",name:"payer",type:"string",required:!1,constraint:"`user:<id>` (the person) or `app:<id>`. Required unless --clear."},{kind:"flag",name:"usd",type:"string",required:!1,constraint:"Dollars per month, 0 or more; 0 stops the payer. Required unless --clear."},{kind:"flag",name:"funding",type:"enum",choices:["bill","subscription","key","endpoint","take","legacy"],required:!1,constraint:"Limit only this funding. Default: any."},{kind:"flag",name:"grantee",type:"string",required:!1,constraint:"Limit only charges attributed to this app, such as `app:terminal`. Default: any."},{kind:"flag",name:"provider",type:"string",required:!1,constraint:"Limit only money going to this vendor or provider app, such as `anthropic`. Default: any."},{kind:"flag",name:"clear",type:"bool",required:!1,constraint:"Remove the row instead of writing it."}],output:[{name:"limit",type:"LimitDTO",required:!1,constraint:"The row written; absent with --clear."},{name:"removed",type:"string",required:!1,constraint:"The id removed with --clear."}],outputKind:"object",effects:["Writes or deletes one `limits` row with source `person`. Takes effect on the next call."]},run:t(async e=>{const r=`person:${String(e.name)}`;if(e.clear===!0)return{removed:(await m().removeSpendLimit(r)).id};const i=e.usd===void 0?Number.NaN:Number(e.usd);if(typeof e.payer!="string"||!Number.isFinite(i)||i<0)throw new l({error:"nothing_to_set",message:"a limit needs --payer and --usd (0 or more), or --clear",next:"Pass --payer user:<id> --usd 20, or --clear to remove the row."});return{limit:await m().setSpendLimit(r,{payer:e.payer,usd_per_month:i,...e.funding===void 0?{}:{funding:e.funding},...e.grantee===void 0?{}:{grantee:String(e.grantee)},...e.provider===void 0?{}:{provider:String(e.provider)}})}},"run"),render:t(e=>e.removed!==void 0?`Removed ${String(e.removed)}.`:p(e.limit),"render")}),D=w({name:"spend",description:"the money ledger: spend by payer, the chain under a run, and dollar limits",whenToUse:"reading what was spent and why, or stopping or capping a payer's spend",help:{name:"sys spend",summary:"read this runtime's charges and set the person's dollar limits",model:"Every model call and priced tool call is one charge row naming its payer, funding and cause. A limit row bounds a payer's month; the check refuses calls billed to that payer once it is reached. `sys limits` is the unrelated per-app memory and disk cap."},children:[b,q,_]});export{D as sysSpendBranch};
1
+ var y=Object.defineProperty;var t=(e,r)=>y(e,"name",{value:r,configurable:!0});import{defineBranch as w,defineLeaf as h}from"../../core/command.js";import{InputError as l}from"../../core/io.js";import{cliClient as m}from"../api-client.js";const d=t(e=>e===null?"unpriced":`$${e.toFixed(e<1?4:2)}`,"usd"),$=t(e=>[e.funding&&`funding ${e.funding}`,e.grantee&&`grantee ${e.grantee}`,e.provider&&`provider ${e.provider}`,e.sub&&`sub ${e.sub}`].filter(Boolean).join(", ")||"everything","filters"),p=t(e=>`- \`${e.id}\` ${e.payer??e.account} ${d(e.usd_per_month)}/month on ${$(e)} (${e.source})`,"limitLine"),b=h({name:"show",description:"show a month's spend by payer and funding, with the limits",whenToUse:"checking what a payer has spent this month and which limits apply",help:{name:"sys spend show",summary:"month totals by payer and by payer and funding from the ledger, then every limit row",params:[{kind:"flag",name:"month",type:"string",required:!1,constraint:"UTC month YYYY-MM. Default: the current month."}],output:[{name:"month",type:"string",required:!0,constraint:"The month shown, YYYY-MM."},{name:"totals",type:"ChargeTotalsDTO",required:!0,constraint:"Record: {month, by_payer, by_funding, limits}. Migrated user-paid model history has funding `legacy`."}],outputKind:"object",effects:["None. Read-only."]},run:t(async e=>{const r=await m().listCharges({limit:1,...e.month===void 0?{}:{month:String(e.month)}});if(r.totals===void 0)throw new l({error:"owner_only",message:"month totals and limits are read by the person; this caller sees only its own app's charges",next:"Run `crtr sys spend show` from the person's own shell, not from inside a node."});return{month:r.month,totals:r.totals}},"run"),render:t(e=>{const r=e.totals;return[`Spend for ${r.month}:`,...r.by_payer.length===0?["- nothing charged"]:r.by_payer.map(i=>`- ${i.payer} ${d(i.usd)}${r.by_funding.filter(s=>s.payer===i.payer).map(s=>` ${s.funding} ${d(s.usd)}`).join("")}`),"Limits:",...r.limits.length===0?["- none"]:r.limits.map(p)].join(`
2
+ `)},"render")});function v(e){const r=new Map;for(const n of e)r.set(n.provider??"(none)",(r.get(n.provider??"(none)")??0)+(n.usd??0));const i=new Set(e.map(n=>n.request)),s=t(n=>e.filter(o=>(o.caused_by??null)===n),"children"),a=[],u=new Set,c=t((n,o)=>{if(!u.has(n.id)&&(u.add(n.id),a.push(`${" ".repeat(o)}- ${n.at} ${n.kind} ${n.what} ${d(n.usd)} ${n.payer}/${n.funding}${n.provider?` \u2192 ${n.provider}`:""} vendor_ref ${n.vendor_ref??"none"}${n.refused?` REFUSED by ${n.refused.limit}`:""}`),n.request!==null))for(const g of s(`request:${n.request}`))c(g,o+1)},"print"),f=e.filter(n=>n.caused_by===null||!(n.caused_by.startsWith("request:")&&i.has(n.caused_by.slice(8))));for(const n of f)c(n,0);for(const n of e)c(n,0);return[...a,"Total per provider:",...[...r].map(([n,o])=>`- ${n} ${d(o)}`)].join(`
3
+ `)}t(v,"tree");const q=h({name:"chain",description:"list the charge rows under a run, message, request or charge on this runtime",whenToUse:"finding what one run, message or request cost and matching its vendor_ref to a vendor's usage line",help:{name:"sys spend chain",summary:"the rows under a reference as a tree, with each row's vendor_ref and a total per provider",params:[{kind:"positional",name:"reference",type:"string",required:!0,constraint:"`run:<id>`, `message:<id>`, `request:<id>`, `cron_run:<id>` or a charge id. Reads this runtime only."}],output:[{name:"reference",type:"string",required:!0,constraint:"The reference read."},{name:"charges",type:"ChargeDTO[]",required:!0,constraint:"Rows in time order; empty when this runtime holds none under the reference."}],outputKind:"object",effects:["None. Read-only."]},run:t(async e=>{const r=String(e.reference),i=[];for(let s;;){const a=await m().listCharges({under:r,...s===void 0?{}:{after:s}});if(i.push(...a.charges),a.next===null)break;s=a.next}return{reference:r,charges:i}},"run"),render:t(e=>{const r=e.charges;return r.length===0?`No charges under ${String(e.reference)} on this runtime.`:v(r)},"render")}),_=h({name:"limit",description:"set or clear one of the person's dollar limits",whenToUse:"stopping a payer's spend (0 is an emergency stop) or capping it per month; clearing a limit you set",help:{name:"sys spend limit",summary:"write or remove the limit row `person:<name>`; the check refuses calls billed to the payer once the month reaches it",params:[{kind:"positional",name:"name",type:"string",required:!0,constraint:"A name for the row; the id is `person:<name>`."},{kind:"flag",name:"payer",type:"string",required:!1,constraint:"`user:<id>` (the person) or `app:<id>`. Required unless --clear."},{kind:"flag",name:"usd",type:"string",required:!1,constraint:"Dollars per month, 0 or more; 0 stops the payer. Required unless --clear."},{kind:"flag",name:"funding",type:"enum",choices:["bill","subscription","key","endpoint","take","legacy"],required:!1,constraint:"Limit only this funding. Default: any."},{kind:"flag",name:"grantee",type:"string",required:!1,constraint:"Limit only charges attributed to this app, such as `app:terminal`. Default: any."},{kind:"flag",name:"provider",type:"string",required:!1,constraint:"Limit only money going to this vendor or provider app, such as `anthropic`. Default: any."},{kind:"flag",name:"clear",type:"bool",required:!1,constraint:"Remove the row instead of writing it."}],output:[{name:"limit",type:"LimitDTO",required:!1,constraint:"The row written; absent with --clear."},{name:"removed",type:"string",required:!1,constraint:"The id removed with --clear."}],outputKind:"object",effects:["Writes or deletes one `limits` row with source `person`. Takes effect on the next call."]},run:t(async e=>{const r=`person:${String(e.name)}`;if(e.clear===!0)return{removed:(await m().removeSpendLimit(r)).id};const i=e.usd===void 0?Number.NaN:Number(e.usd);if(typeof e.payer!="string"||!Number.isFinite(i)||i<0)throw new l({error:"nothing_to_set",message:"a limit needs --payer and --usd (0 or more), or --clear",next:"Pass --payer user:<id> --usd 20, or --clear to remove the row."});return{limit:await m().setSpendLimit(r,{payer:e.payer,usd_per_month:i,...e.funding===void 0?{}:{funding:e.funding},...e.grantee===void 0?{}:{grantee:String(e.grantee)},...e.provider===void 0?{}:{provider:String(e.provider)}})}},"run"),render:t(e=>e.removed!==void 0?`Removed ${String(e.removed)}.`:p(e.limit),"render")}),D=w({name:"spend",description:"the money ledger: spend by payer, the chain under a run, and dollar limits",whenToUse:"reading what was spent and why, or stopping or capping a payer's spend",help:{name:"sys spend",summary:"read this runtime's charges and set the person's dollar limits",model:"Every model call and priced tool call is one charge row naming its payer, funding and cause. A limit row bounds a payer's month; the check refuses calls billed to that payer once it is reached. `sys limits` is the unrelated per-app memory and disk cap."},children:[b,q,_]});export{D as sysSpendBranch};
@@ -1 +1 @@
1
- var d=Object.defineProperty;var l=(i,a)=>d(i,"name",{value:a,configurable:!0});import{defineLeaf as u}from"../../core/command.js";import{updateState as p}from"../../core/config.js";import{projectScopeRoot as f}from"../../core/scope.js";import{selfCheck as h,selfUpdate as m,contentCheck as g}from"../../core/self-update.js";import{marketUpdate as y}from"../pkg/market-manage.js";import{pluginUpdate as k}from"../pkg/plugin-manage.js";import{nowIso as b}from"../../core/fs-utils.js";import{processLocatedGeneration as w,readPackageVersion as _,runtimeManifest as v,selectedGeneration as j}from"./shared.js";const E=u({name:"update",description:"update binary and content",whenToUse:"upgrading crtr or its installed plugins and marketplaces \u2014 pull the latest binary, refresh installed content, or both, or just check what is out of date without applying anything.",help:{name:"sys update",summary:"update the crtr binary and/or installed plugins and marketplaces",params:[{kind:"flag",name:"target",type:"enum",choices:["self","content","all"],required:!1,constraint:"What to update. Default: all."},{kind:"flag",name:"check",type:"bool",required:!1,constraint:"Check for updates without applying them (bounded, blocking)."}],output:[{name:"target",type:"string",required:!1,constraint:"Present when applying updates: self | content | all."},{name:"status",type:"string",required:!1,constraint:"done | failed when applying updates."},{name:"error",type:"string",required:!1,constraint:"Failure message when status is failed."},{name:"warning",type:"string",required:!1,constraint:"Present when the update was applied but recording the self-check time failed; status stays done."},{name:"updates",type:"object[]",required:!1,constraint:"Present when --check. Each: {name, current, latest, up_to_date, unreachable, kind}."},{name:"up_to_date",type:"boolean",required:!1,constraint:"Present when --check. True when all items are up to date."}],outputKind:"object",effects:["--check \u2014 read-only, bounded network calls.","Default (no --check) \u2014 launches a background job; returns job handle immediately.","Content update replaces each marketplace and source-installed plugin checkout with a freshly staged revision, discarding local modifications in those directories."]},run:l(async i=>{const a=i.target,c=i.check,t=a!==void 0?a:"all";if(c){const n=[];if(t==="self"||t==="all"){const e=h();e!==null?n.push({name:e.package,kind:"self",current:e.current,latest:e.latest,up_to_date:!e.migrating&&e.current===e.latest,unreachable:!1}):n.push({name:"@north-light/cli",kind:"self",current:null,latest:null,up_to_date:!0,unreachable:!0})}if(t==="content"||t==="all"){const e=g();for(const o of e)n.push({name:o.name,kind:o.kind,current:o.current,latest:o.latest,up_to_date:o.up_to_date,unreachable:o.unreachable})}const r=n.every(e=>e.up_to_date||e.unreachable);return{updates:n,up_to_date:r}}const s=[];try{if(t==="self"||t==="all"){m();const n=["user"];f()&&n.unshift("project");for(const r of n)try{p(r,e=>{e.last_self_check=b()})}catch(e){s.push(`recording the ${r}-scope self-check failed: ${e instanceof Error?e.message:String(e)}`)}}return(t==="content"||t==="all")&&(await y.run({}),await k.run({})),s.length===0?{target:t,status:"done"}:{target:t,status:"done",warning:`update installed, but ${s.join("; ")}`}}catch(n){const r=n instanceof Error?n.message:String(n);return{target:t,status:"failed",error:r}}},"run")}),G=u({name:"version",description:"print installed version",whenToUse:"you need the installed crtr version \u2014 to report it in a bug or confirm an upgrade landed.",help:{name:"sys version",summary:"report selected and process runtime generations",params:[],output:[{name:"version",type:"string",required:!0,constraint:"Version from this process generation manifest; package.json version in a development checkout."},{name:"selected_generation",type:"object",required:!0,constraint:"Selected runtime generation: {id, version, status}; id/version are null when no selection exists."},{name:"process_generation",type:"object",required:!0,constraint:"Generation containing this loaded module: {id, version, status}; id/version are null in a development checkout."},{name:"drift",type:"boolean",required:!0,constraint:"True when selected and process generation ids differ."}],outputKind:"object",effects:["None. Read-only."]},run:l(async i=>{const a=l(s=>{if(s.generation===null)return{id:null,version:null,status:s.error??"no runtime generation"};const{id:n,manifest:r}=s.generation,e=v.validateManifestShape(r,{id:n,entryName:"cli"});return{id:n,version:typeof r.packageVersion=="string"?r.packageVersion:null,status:e.ok?"valid":e.error}},"describe"),c=a(j()),t=a(w());return{version:t.version??_(),selected_generation:c,process_generation:t,drift:c.id!==null&&t.id!==null&&c.id!==t.id}},"run")});export{E as sysUpdateLeaf,G as sysVersionLeaf};
1
+ var d=Object.defineProperty;var l=(i,r)=>d(i,"name",{value:r,configurable:!0});import{defineLeaf as u}from"../../core/command.js";import{updateState as p}from"../../core/config.js";import{projectScopeRoot as f}from"../../core/scope.js";import{selfCheck as h,selfUpdate as m,contentCheck as g}from"../../core/self-update.js";import{marketUpdate as y}from"../pkg/market-manage.js";import{pluginUpdate as k}from"../pkg/plugin-manage.js";import{nowIso as b}from"../../core/fs-utils.js";import{processLocatedGeneration as w,readPackageVersion as _,runtimeManifest as v,selectedGeneration as j}from"./shared.js";const E=u({name:"update",description:"update binary and content",whenToUse:"upgrading crtr or its installed plugins and marketplaces \u2014 pull the latest binary, refresh installed content, or both, or just check what is out of date without applying anything.",help:{name:"sys update",summary:"update the crtr binary and/or installed plugins and marketplaces",params:[{kind:"flag",name:"target",type:"enum",choices:["self","content","all"],required:!1,constraint:"What to update. Default: all."},{kind:"flag",name:"check",type:"bool",required:!1,constraint:"Check for updates without applying them (bounded, blocking)."}],output:[{name:"target",type:"string",required:!1,constraint:"Present when applying updates: self | content | all."},{name:"status",type:"string",required:!1,constraint:"done | failed when applying updates."},{name:"error",type:"string",required:!1,constraint:"Failure message when status is failed."},{name:"warning",type:"string",required:!1,constraint:"Present when the update was applied but recording the self-check time failed; status stays done."},{name:"updates",type:"object[]",required:!1,constraint:"Present when --check. Each: {name, current, latest, up_to_date, unreachable, kind}."},{name:"up_to_date",type:"boolean",required:!1,constraint:"Present when --check. True when all items are up to date."}],outputKind:"object",effects:["--check \u2014 read-only, bounded network calls.","Default (no --check) \u2014 launches a background job; returns job handle immediately.","Content update replaces each marketplace and source-installed plugin checkout with a freshly staged revision, discarding local modifications in those directories."]},run:l(async i=>{const r=i.target,c=i.check,t=r!==void 0?r:"all";if(c){const n=[];if(t==="self"||t==="all"){const e=h();e!==null?n.push({name:e.package,kind:"self",current:e.current,latest:e.latest,up_to_date:!e.migrating&&e.current===e.latest,unreachable:!1}):n.push({name:"@north-light/cli",kind:"self",current:null,latest:null,up_to_date:!0,unreachable:!0})}if(t==="content"||t==="all"){const e=g();for(const o of e)n.push({name:o.name,kind:o.kind,current:o.current,latest:o.latest,up_to_date:o.up_to_date,unreachable:o.unreachable})}const a=n.every(e=>e.up_to_date||e.unreachable);return{updates:n,up_to_date:a}}const s=[];try{if(t==="self"||t==="all"){m();const n=["user"];f()&&n.unshift("project");for(const a of n)try{await p(a,e=>{e.last_self_check=b()})}catch(e){s.push(`recording the ${a}-scope self-check failed: ${e instanceof Error?e.message:String(e)}`)}}return(t==="content"||t==="all")&&(await y.run({}),await k.run({})),s.length===0?{target:t,status:"done"}:{target:t,status:"done",warning:`update installed, but ${s.join("; ")}`}}catch(n){const a=n instanceof Error?n.message:String(n);return{target:t,status:"failed",error:a}}},"run")}),G=u({name:"version",description:"print installed version",whenToUse:"you need the installed crtr version \u2014 to report it in a bug or confirm an upgrade landed.",help:{name:"sys version",summary:"report selected and process runtime generations",params:[],output:[{name:"version",type:"string",required:!0,constraint:"Version from this process generation manifest; package.json version in a development checkout."},{name:"selected_generation",type:"object",required:!0,constraint:"Selected runtime generation: {id, version, status}; id/version are null when no selection exists."},{name:"process_generation",type:"object",required:!0,constraint:"Generation containing this loaded module: {id, version, status}; id/version are null in a development checkout."},{name:"drift",type:"boolean",required:!0,constraint:"True when selected and process generation ids differ."}],outputKind:"object",effects:["None. Read-only."]},run:l(async i=>{const r=l(s=>{if(s.generation===null)return{id:null,version:null,status:s.error??"no runtime generation"};const{id:n,manifest:a}=s.generation,e=v.validateManifestShape(a,{id:n,entryName:"cli"});return{id:n,version:typeof a.packageVersion=="string"?a.packageVersion:null,status:e.ok?"valid":e.error}},"describe"),c=r(j()),t=r(w());return{version:t.version??_(),selected_generation:c,process_generation:t,drift:c.id!==null&&t.id!==null&&c.id!==t.id}},"run")});export{E as sysUpdateLeaf,G as sysVersionLeaf};
@@ -1,6 +1,5 @@
1
1
  import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai';
2
2
  type AuthFileData = Record<string, Credential>;
3
- export declare function defaultAuthPath(): string;
4
3
  /**
5
4
  * Resolve a stored api-key value the way pi does before handing it to a provider: a leading
6
5
  * `!` runs the rest as a shell command (cached for the process), and `$VAR` / `${VAR}`
@@ -11,28 +10,21 @@ export declare function defaultAuthPath(): string;
11
10
  * be sent to the provider verbatim.
12
11
  */
13
12
  export declare function resolveCredentialValue(config: string, env?: Record<string, string>): string | undefined;
14
- /** Read all stored credentials. Lock-free: every writer replaces auth.json by atomic
15
- * rename, so a reader either sees the old whole file or the new one. Taking the lock here
16
- * would be pure cost — pi asks for every registered provider (~75 reads) each time it
17
- * builds a model runtime, and those contended acquisitions cost seconds per broker boot. */
18
- export declare function readAuthCredentials(authPath?: string): Promise<AuthFileData>;
13
+ /** Read all stored credentials. */
14
+ export declare function readAuthCredentials(): Promise<AuthFileData>;
19
15
  /** Read one provider's stored credential. */
20
- export declare function readAuthCredential(providerId: string, authPath?: string): Promise<Credential | undefined>;
21
- /** Persist one provider's credential under the auth.json lock, leaving every other entry intact. */
22
- export declare function setAuthCredential(providerId: string, credential: Credential, authPath?: string): Promise<void>;
23
- /** Remove one provider's credential (logout) under the auth.json lock. Returns
24
- * whether a record was removed from the exact snapshot this write replaced. */
25
- export declare function deleteAuthCredential(providerId: string, authPath?: string): Promise<boolean>;
16
+ export declare function readAuthCredential(providerId: string): Promise<Credential | undefined>;
17
+ /** Persist one provider's credential, leaving every other entry intact. */
18
+ export declare function setAuthCredential(providerId: string, credential: Credential): Promise<void>;
19
+ /** Remove one provider's credential (logout). Returns whether a row was removed. */
20
+ export declare function deleteAuthCredential(providerId: string): Promise<boolean>;
26
21
  /**
27
- * The `CredentialStore` crouter hands to `ModelRuntime`. Backed directly by auth.json rather
28
- * than by an in-memory cache, so `modify` is a real cross-process read-modify-write: pi's
29
- * locked OAuth refresh inside `Models.getAuth()` and crouter's own credential writes serialize
30
- * against each other on one lock.
22
+ * The `CredentialStore` crouter hands to `ModelRuntime`. Backed directly by the rows rather than
23
+ * by an in-memory cache, so `modify` is a real cross-process read-modify-write: pi's
24
+ * OAuth refresh inside `Models.getAuth()` and crouter's own credential writes serialize
25
+ * against each other on the row lock.
31
26
  */
32
27
  export declare class CrouterCredentialStore implements CredentialStore {
33
- private readonly authPath;
34
- private readonly file;
35
- constructor(authPath?: string);
36
28
  read(providerId: string): Promise<Credential | undefined>;
37
29
  list(): Promise<readonly CredentialInfo[]>;
38
30
  modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>): Promise<Credential | undefined>;
@@ -1,2 +1 @@
1
- var w=Object.defineProperty;var s=(e,t)=>w(e,"name",{value:t,configurable:!0});import{execSync as m}from"node:child_process";import{join as A}from"node:path";import{secretsDir as k}from"./layout.js";import{LockedJsonFile as d}from"./locked-file.js";function o(){return A(k(),"auth.json")}s(o,"defaultAuthPath");function l(e){if(e===void 0||e.trim()==="")return{};const t=JSON.parse(e);return t!==null&&typeof t=="object"?t:{}}s(l,"parse");function p(e){return`${JSON.stringify(e,null,2)}
2
- `}s(p,"serialize");const _=/^[A-Za-z_][A-Za-z0-9_]*/,C=/^[A-Za-z_][A-Za-z0-9_]*$/,x=new Map;function O(e){if(x.has(e))return x.get(e);let t;try{t=m(e,{encoding:"utf-8",timeout:1e4,stdio:["ignore","pipe","ignore"]}).trim()||void 0}catch{t=void 0}return x.set(e,t),t}s(O,"runValueCommand");function N(e,t){if(e.startsWith("!"))return O(e.slice(1));let n="",i=0;for(;i<e.length;){const r=e.indexOf("$",i);if(r<0){n+=e.slice(i);break}n+=e.slice(i,r);const a=e[r+1];if(a==="$"||a==="!"){n+=a,i=r+2;continue}let u,f=r+1;if(a==="{"){const c=e.indexOf("}",r+2),y=c<0?void 0:e.slice(r+2,c);y!==void 0&&C.test(y)&&(u=y,f=c+1)}else{const c=_.exec(e.slice(r+1));c!==null&&(u=c[0],f=r+1+u.length)}if(u===void 0){n+="$",i=r+1;continue}const h=t?.[u]||process.env[u];if(h===void 0||h==="")return;n+=h,i=f}return n}s(N,"resolveCredentialValue");async function j(e=o()){return l(new d(e).readUnlocked())}s(j,"readAuthCredentials");async function z(e,t=o()){return(await j(t))[e]}s(z,"readAuthCredential");async function L(e,t,n=o()){await new d(n).withLockAsync(async i=>{const r=l(i);return r[e]=t,{result:void 0,next:p(r)}})}s(L,"setAuthCredential");async function E(e,t=o()){return new d(t).withLockAsync(async n=>{const i=l(n),r=Object.hasOwn(i,e);return delete i[e],{result:r,next:p(i)}})}s(E,"deleteAuthCredential");class S{static{s(this,"CrouterCredentialStore")}authPath;file;constructor(t=o()){this.authPath=t,this.file=new d(t)}async read(t){const n=await z(t,this.authPath);return n?.type!=="api_key"||n.key===void 0?n:{...n,key:N(n.key,n.env)}}async list(){return Object.entries(l(this.file.readUnlocked())).map(([t,n])=>({providerId:t,type:n.type}))}async modify(t,n){return this.file.withLockAsync(async i=>{const r=l(i),a=await n(r[t]);return a===void 0?{result:r[t]}:(r[t]=a,{result:a,next:p(r)})})}async delete(t){await E(t,this.authPath)}}export{S as CrouterCredentialStore,o as defaultAuthPath,E as deleteAuthCredential,z as readAuthCredential,j as readAuthCredentials,N as resolveCredentialValue,L as setAuthCredential};
1
+ var O=Object.defineProperty;var a=(t,e)=>O(t,"name",{value:e,configurable:!0});import{execSync as A}from"node:child_process";import{openDb as _,withCanvasWrite as f}from"./canvas/db.js";import{personIdAsync as l}from"./canvas/person.js";import{loadSecretsKey as w,open as C,seal as v}from"./secrets/index.js";const m=a((t,e)=>`model_api_keys|${t}|${e}`,"aadOf");function y(t,e){return JSON.parse(C(e.credential_sealed,e.key_id,w(),m(t,e.provider_id)))}a(y,"openRow");async function k(t,e,n,i){const{sealed:r,keyId:d}=v(JSON.stringify(i),w(),m(e,n));await t.prepare("INSERT INTO model_api_keys(person,provider_id,credential_sealed,key_id,updated_at) VALUES(?,?,?,?,?) ON CONFLICT(person,provider_id) DO UPDATE SET credential_sealed=EXCLUDED.credential_sealed,key_id=EXCLUDED.key_id,updated_at=EXCLUDED.updated_at").run(e,n,r,d,new Date().toISOString())}a(k,"put");const D=/^[A-Za-z_][A-Za-z0-9_]*/,x=/^[A-Za-z_][A-Za-z0-9_]*$/,E=new Map;function R(t){if(E.has(t))return E.get(t);let e;try{e=A(t,{encoding:"utf-8",timeout:1e4,stdio:["ignore","pipe","ignore"]}).trim()||void 0}catch{e=void 0}return E.set(t,e),e}a(R,"runValueCommand");function S(t,e){if(t.startsWith("!"))return R(t.slice(1));let n="",i=0;for(;i<t.length;){const r=t.indexOf("$",i);if(r<0){n+=t.slice(i);break}n+=t.slice(i,r);const d=t[r+1];if(d==="$"||d==="!"){n+=d,i=r+2;continue}let s,o=r+1;if(d==="{"){const p=t.indexOf("}",r+2),u=p<0?void 0:t.slice(r+2,p);u!==void 0&&x.test(u)&&(s=u,o=p+1)}else{const p=D.exec(t.slice(r+1));p!==null&&(s=p[0],o=r+1+s.length)}if(s===void 0){n+="$",i=r+1;continue}const c=e?.[s]||process.env[s];if(c===void 0||c==="")return;n+=c,i=o}return n}a(S,"resolveCredentialValue");async function h(){const t=await l(),e=await(await _()).prepare("SELECT provider_id,credential_sealed,key_id FROM model_api_keys WHERE person=? ORDER BY provider_id").all(t);return Object.fromEntries(e.map(n=>[n.provider_id,y(t,n)]))}a(h,"readAuthCredentials");async function N(t){const e=await l(),n=await(await _()).prepare("SELECT provider_id,credential_sealed,key_id FROM model_api_keys WHERE person=? AND provider_id=?").get(e,t);return n?y(e,n):void 0}a(N,"readAuthCredential");async function W(t,e){const n=await l();await f(i=>k(i,n,t,e))}a(W,"setAuthCredential");async function L(t){const e=await l();return(await(await _()).prepare("DELETE FROM model_api_keys WHERE person=? AND provider_id=?").run(e,t)).changes>0}a(L,"deleteAuthCredential");class ${static{a(this,"CrouterCredentialStore")}async read(e){const n=await N(e);return n?.type!=="api_key"||n.key===void 0?n:{...n,key:S(n.key,n.env)}}async list(){return Object.entries(await h()).map(([e,n])=>({providerId:e,type:n.type}))}async modify(e,n){const i=await l();return f(async r=>{await r.exec("SET LOCAL lock_timeout = '15s'");const d=await r.prepare("SELECT provider_id,credential_sealed,key_id FROM model_api_keys WHERE person=? AND provider_id=? FOR UPDATE").get(i,e),s=d?y(i,d):void 0,o=await n(s);return o===void 0?s:(await k(r,i,e,o),o)})}async delete(e){await L(e)}}export{$ as CrouterCredentialStore,L as deleteAuthCredential,N as readAuthCredential,h as readAuthCredentials,S as resolveCredentialValue,W as setAuthCredential};
@@ -1 +1 @@
1
- export declare function maybeAutoUpdate(argv: string[]): void;
1
+ export declare function maybeAutoUpdate(argv: string[]): Promise<void>;
@@ -1,4 +1,4 @@
1
- var h=Object.defineProperty;var s=(r,t)=>h(r,"name",{value:t,configurable:!0});import{spawn as u}from"node:child_process";import{readConfig as m,readState as g,updateState as f}from"./config.js";import{nowIso as l}from"./fs-utils.js";import{info as p}from"./output.js";import{SELF_UPDATE_SCRIPT as _,selfCheck as k,contentCheck as S}from"./self-update.js";import{envDebug as v}from"../shared/env.js";const w=3600*1e3,y=new Set(["update","help","--help","-h","--version","-v"]);function b(r){const t=r[2];return t===void 0?!0:y.has(t)}s(b,"shouldSkipForArgv");function D(r,t){if(!r)return!1;const n=Date.parse(r);return Number.isFinite(n)?Date.now()-n<t*w:!1}s(D,"withinInterval");function U(){u(process.execPath,[_],{detached:!0,stdio:"ignore"}).unref()}s(U,"spawnDetachedSelfUpdate");function $(){u("crtr",["update","--content"],{detached:!0,stdio:"ignore"}).unref()}s($,"spawnDetachedContentUpdate");function F(r){try{if(process.env.CRTR_NO_AUTO_UPDATE==="1"||b(r))return;const t=m("user"),{crtr:n,content:o,interval_hours:d}=t.auto_update;if(n===!1&&o===!1)return;const i=g("user");if(i.last_self_check===void 0){f("user",e=>{e.last_self_check=l()});return}if(D(i.last_self_check,d))return;if(f("user",e=>{e.last_self_check=l()}),n==="notify"){const e=k();e!==null&&(e.migrating||e.latest!==e.current)&&process.stderr.write(`crtr: ${e.package} v${e.latest} available (current ${e.current}${e.migrating?"; this install moves to the new package name":""}) \u2014 run \`crtr sys update\`
2
- `)}else n==="apply"&&(p("applying self-update in background"),U());if(o==="notify"){const e=S().filter(a=>!a.up_to_date&&!a.unreachable);if(e.length>0){const a=e.map(c=>`${c.kind} ${c.name}`).join(", ");process.stderr.write(`crtr: updates available for ${a} \u2014 run \`crtr sys update\`
3
- `)}}else o==="apply"&&(p("applying content updates in background"),$())}catch(t){if(v()){const n=t instanceof Error?t.message:String(t);process.stderr.write(`crtr: auto-update hook error: ${n}
4
- `)}}}s(F,"maybeAutoUpdate");export{F as maybeAutoUpdate};
1
+ var h=Object.defineProperty;var a=(r,t)=>h(r,"name",{value:t,configurable:!0});import{spawn as u}from"node:child_process";import{readConfig as m,readState as g,updateState as f}from"./config.js";import{nowIso as l}from"./fs-utils.js";import{info as p}from"./output.js";import{SELF_UPDATE_SCRIPT as _,selfCheck as k,contentCheck as w}from"./self-update.js";import{envDebug as S}from"../shared/env.js";const v=3600*1e3,y=new Set(["update","help","--help","-h","--version","-v"]);function b(r){const t=r[2];return t===void 0?!0:y.has(t)}a(b,"shouldSkipForArgv");function D(r,t){if(!r)return!1;const n=Date.parse(r);return Number.isFinite(n)?Date.now()-n<t*v:!1}a(D,"withinInterval");function U(){u(process.execPath,[_],{detached:!0,stdio:"ignore"}).unref()}a(U,"spawnDetachedSelfUpdate");function $(){u("crtr",["update","--content"],{detached:!0,stdio:"ignore"}).unref()}a($,"spawnDetachedContentUpdate");async function F(r){try{if(process.env.CRTR_NO_AUTO_UPDATE==="1"||b(r))return;const t=m("user"),{crtr:n,content:i,interval_hours:d}=t.auto_update;if(n===!1&&i===!1)return;const o=g("user");if(o.last_self_check===void 0){await f("user",e=>{e.last_self_check=l()});return}if(D(o.last_self_check,d))return;if(await f("user",e=>{e.last_self_check=l()}),n==="notify"){const e=k();e!==null&&(e.migrating||e.latest!==e.current)&&process.stderr.write(`crtr: ${e.package} v${e.latest} available (current ${e.current}${e.migrating?"; this install moves to the new package name":""}) \u2014 run \`crtr sys update\`
2
+ `)}else n==="apply"&&(p("applying self-update in background"),U());if(i==="notify"){const e=w().filter(s=>!s.up_to_date&&!s.unreachable);if(e.length>0){const s=e.map(c=>`${c.kind} ${c.name}`).join(", ");process.stderr.write(`crtr: updates available for ${s} \u2014 run \`crtr sys update\`
3
+ `)}}else i==="apply"&&(p("applying content updates in background"),$())}catch(t){if(S()){const n=t instanceof Error?t.message:String(t);process.stderr.write(`crtr: auto-update hook error: ${n}
4
+ `)}}}a(F,"maybeAutoUpdate");export{F as maybeAutoUpdate};
@@ -18,20 +18,14 @@ export interface BashJobPaths {
18
18
  /** Launch-time identity of the detached supervisor, used to refuse a PID that
19
19
  * has since been reused by an unrelated process. */
20
20
  jobPgidIdentity: string;
21
- /** Human-readable label supplied with the bash call, when any. */
22
- jobPurpose: string;
23
- /** Epoch-ms cancel deadline for an AUTO-backgrounded job. Present only when
24
- * the valve backgrounded the job on its own; its presence marks the job as
25
- * subject to the daemon's claim-or-cancel deadline. Absent for a deliberate
26
- * handoff (tmux menu, broker termination), which runs to completion. */
27
- jobDeadline: string;
28
21
  /** Written beside the job by its supervisor's activity sampler: when the job last
29
22
  * showed life and which files it was watched through (see `readJobActivity`). */
30
23
  jobActivity: string;
31
- /** Present when the job's owner declared that it legitimately sits idle: it gets no silence messages. */
32
- jobQuietOk: string;
33
- /** The daemon's record of the last silence message sent: `<last-activity-ms> <threshold-ms>`. */
34
- jobSilence: string;
24
+ /** The auto-handoff cancel deadline (epoch ms) the valve leaves until its job row exists with the deadline on it;
25
+ * the daemon moves it into the row (see `readJobSupervisorState`) and removes the file. */
26
+ jobDeadline: string;
27
+ /** Written by a sandbox broker's job reporter: how much of the output and whether the exit reached the control plane. */
28
+ jobReported: string;
35
29
  }
36
30
  /** A purpose is display text, never shell input. Keep the file-backed control
37
31
  * plane to one bounded, visible line so old or hand-written job directories
@@ -49,9 +43,27 @@ export declare function readJobPgid(contextDir: string, jobId: string): number |
49
43
  /** Launch-time identity of the supervisor. Missing for jobs created before
50
44
  * process-identity persistence, which are deliberately not safe to signal. */
51
45
  export declare function readJobPgidIdentity(contextDir: string, jobId: string): string | undefined;
52
- /** The optional human-readable job label. Jobs created before labels existed
53
- * have no file and deliberately project null. */
54
- export declare function readJobPurpose(contextDir: string, jobId: string): string | null;
46
+ /** What the job's detached supervisor wrote beside the job: its process identity, the activity sample
47
+ * and, once it ended, the exit code. Each field is absent until written. */
48
+ export interface JobSupervisorState {
49
+ pgid?: number;
50
+ pgidIdentity?: string;
51
+ exitCode?: number;
52
+ activity?: {
53
+ lastActivityMs: number;
54
+ sampledAtMs: number;
55
+ files: string[];
56
+ };
57
+ /** A cancel deadline still on disk: left by the valve before its job row existed, or by a job started before deadlines lived on rows. */
58
+ deadlineMs?: number;
59
+ }
60
+ export declare function readJobSupervisorState(contextDir: string, jobId: string): JobSupervisorState;
61
+ /** Write the auto-handoff cancel deadline beside the job; `clearJobDeadlineFile` removes it once the job row carries it. */
62
+ export declare function writeJobDeadlineFile(paths: BashJobPaths, deadlineMs: number): void;
63
+ export declare function clearJobDeadlineFile(paths: BashJobPaths): void;
64
+ /** Ids of this node's job directories whose command has not exited — foreground (job.run) or backgrounded (job.bg),
65
+ * with or without a job row. What a node stop must signal. */
66
+ export declare function unfinishedBashJobIds(contextDir: string): string[];
55
67
  /** Scheduler niceness every command a node runs is started with. Agent work —
56
68
  * builds, test suites, typechecks — sits below the daemon, the brokers, the
57
69
  * viewers, and the person's own shell, so a fan-out of release builds cannot
@@ -74,36 +86,6 @@ export declare function readBashNiceness(contextDir: string): number;
74
86
  /** Set the node's bash niceness. The caller owns validation; the store keeps
75
87
  * one integer so the valve's read stays a single file read per command. */
76
88
  export declare function writeBashNiceness(contextDir: string, niceness: number): void;
77
- /** The auto-background cancel deadline (epoch ms), or undefined for a job with
78
- * no deadline (a deliberate handoff, or a legacy job dir). A non-finite or
79
- * malformed file reads as no deadline rather than an instant expiry. */
80
- export declare function readJobDeadlineMs(contextDir: string, jobId: string): number | undefined;
81
- /** Arm or move an auto-backgrounded job's cancel deadline to `deadlineMs`
82
- * (epoch ms). Written by the valve at auto-handoff and rewritten when the
83
- * owning node claims more time. */
84
- export declare function writeJobDeadlineMs(paths: BashJobPaths, deadlineMs: number): void;
85
- /** Drop a job's cancel deadline so it runs to completion — the node has claimed
86
- * it. Best-effort: a job with no deadline file is already in this state. */
87
- export declare function clearJobDeadline(paths: BashJobPaths): void;
88
- /** What the job's activity sampler last recorded: when the job last showed life (its process tree
89
- * used CPU, or a regular file one of its processes holds open for writing changed), when that was
90
- * sampled, and the files it was watched through. undefined for a job with no readable record. */
91
- export declare function readJobActivity(contextDir: string, jobId: string): {
92
- lastActivityMs: number;
93
- sampledAtMs: number;
94
- files: string[];
95
- } | undefined;
96
- /** Whether the owner declared the job an expected wait, so it gets no silence messages. */
97
- export declare function isJobQuietOk(contextDir: string, jobId: string): boolean;
98
- /** Declare a job an expected wait (`node bash run --quiet-ok`, `node bash quiet`). */
99
- export declare function markJobQuietOk(paths: BashJobPaths): void;
100
- /** The silence message the daemon last sent for a job: the last-activity time it was sent for and
101
- * the threshold it announced. undefined when none was sent. */
102
- export declare function readJobSilence(contextDir: string, jobId: string): {
103
- lastActivityMs: number;
104
- thresholdMs: number;
105
- } | undefined;
106
- export declare function writeJobSilence(paths: BashJobPaths, lastActivityMs: number, thresholdMs: number): void;
107
89
  /** Launcher jobs have a root-owned bwrap pid, not a process group; direct
108
90
  * jobs keep their detached supervisor process group. */
109
91
  export declare function isBashJobProcessGroupAlive(pgid: number, identity?: string): boolean;
@@ -117,6 +99,9 @@ export declare function isBashJobProcessConfirmedGone(pgid: number | undefined,
117
99
  * escalation. A descendant that detached and reparented before this snapshot
118
100
  * is outside this guarantee. */
119
101
  export declare function cancelBashJobProcessTree(pgid: number, expectedIdentity: string): Promise<boolean>;
102
+ /** Stop a job's process: a launcher job through the launcher, a direct job by its supervisor's process tree.
103
+ * False when no process was left to signal. */
104
+ export declare function signalBashJob(pgid: number, identity: string, nodeId: string | undefined): Promise<boolean>;
120
105
  export type StopBackgroundBashJobResult = {
121
106
  kind: 'stopped';
122
107
  signaled: boolean;
@@ -166,33 +151,6 @@ export declare function formatBashElapsed(ms: number): string;
166
151
  /** The command line worth SHOWING for a job: the first non-empty line of
167
152
  * `cmd.sh`, whitespace-collapsed to one line. */
168
153
  export declare function bashJobCommandLine(command: string): string;
169
- export interface BashJobStatus {
170
- jobId: string;
171
- /** Full text of cmd.sh. */
172
- command: string;
173
- /** Human-readable label, or null for an unlabeled or legacy job. */
174
- purpose: string | null;
175
- startedAtMs: number;
176
- logPath: string;
177
- /** Auto-background cancel deadline (epoch ms), or null for a job that runs to
178
- * completion (a deliberate handoff, or one the node has claimed). */
179
- deadlineAtMs: number | null;
180
- }
181
- /** Every live backgrounded bash job for this node — job.bg present, job.exit
182
- * absent — whether handed off by the menu, the valve deadline, or broker
183
- * termination. Read-only; never mutates. Skips malformed/partially-written
184
- * directories. Returns oldest-first by startedAtMs. */
185
- export declare function activeBackgroundBashJobs(contextDir: string, includeForeground?: boolean): BashJobStatus[];
186
- /** Every live background job for this node whose auto-cancel deadline has
187
- * passed at `now`. The daemon's deadline lane stops exactly these. A job with
188
- * no deadline (deliberate handoff, or one the node claimed) never appears. */
189
- export declare function expiredAutoBackgroundBashJobs(contextDir: string, now: number): BashJobStatus[];
190
- /** Credit every armed auto-cancel deadline for an interval the node was not
191
- * permitted to run. A profile pause stops the owning node, so without this the
192
- * claim window burns down while the only agent that could claim it is stopped,
193
- * and resume greets it with a job already canceled for not being claimed. A
194
- * deliberate handoff carries no deadline and is untouched. */
195
- export declare function shiftAutoBackgroundBashDeadlines(contextDir: string, byMs: number): number;
196
154
  export type BackgroundBashJobResult = 'backgrounded' | 'already-backgrounded' | 'finished' | 'missing';
197
155
  /** Atomically hand one foreground job to its detached supervisor. The rename
198
156
  * is the ownership decision: exactly one caller can move job.run to job.bg,
@@ -1,10 +1,9 @@
1
- var $=Object.defineProperty;var o=(t,e)=>$(t,"name",{value:e,configurable:!0});import{randomBytes as R}from"node:crypto";import{closeSync as y,openSync as B,readSync as S,statSync as v}from"node:fs";import{dirname as m,join as c}from"node:path";import{captureTeardownSnapshot as O,isAnyPidAlive as T,isPidAlive as M,killProcessTreePids as x}from"./canvas/pid.js";import{launcherRequest as F}from"../launcher/client.js";import{LaunchRefused as _}from"../launcher/spec.js";import{createFileBeneath as A,existsBeneath as I,readdirBeneath as C,readFileBeneath as Q,renameBeneath as z,unlinkBeneath as G,writeFileBeneath as g}from"./spaces/open-beneath.js";const H=280;function X(t){if(typeof t!="string"||/[\p{Cc}\p{Cf}]/u.test(t))return null;const e=t.trim();return e===""?null:Buffer.byteLength(e,"utf8")<=H?e:null}o(X,"normalizeBashJobPurpose");function j(t){return c(t,"jobs")}o(j,"bashJobsDir");function b(t,e){return Q(m(t),e).toString("utf8")}o(b,"readJobText");function J(t){return C(m(t),j(t)).map(e=>e.name)}o(J,"jobIds");function a(t,e){return I(t.root,e)}o(a,"has");function k(t,e){try{G(t,e)}catch(n){if(n.code!=="ENOENT")throw n}}o(k,"unlinkIfPresent");function ct(t){return typeof t=="string"&&t!==""&&t!=="."&&t!==".."&&/^[A-Za-z0-9._~-]+$/u.test(t)&&Buffer.byteLength(t,"utf8")<=128}o(ct,"isSafeBashJobId");function f(t,e){const n=c(j(t),e);return{jobId:e,root:m(t),dir:n,cmdSh:c(n,"cmd.sh"),jobLog:c(n,"job.log"),jobExit:c(n,"job.exit"),jobRun:c(n,"job.run"),jobBg:c(n,"job.bg"),jobDone:c(n,"job.done"),jobPgid:c(n,"job.pgid"),jobPgidIdentity:c(n,"job.pgid-identity"),jobPurpose:c(n,"purpose"),jobDeadline:c(n,"job.deadline"),jobActivity:c(n,"job.activity"),jobQuietOk:c(n,"job.quiet-ok"),jobSilence:c(n,"job.silence")}}o(f,"bashJobPaths");function q(t,e){try{const n=Number(b(t,f(t,e).jobPgid).trim());return Number.isInteger(n)&&n>1?n:void 0}catch{return}}o(q,"readJobPgid");function U(t,e){try{const n=b(t,f(t,e).jobPgidIdentity).trim();return n===""?void 0:n}catch{return}}o(U,"readJobPgidIdentity");function W(t,e){try{return X(b(t,f(t,e).jobPurpose))}catch{return null}}o(W,"readJobPurpose");const P=10,K=19;function N(t){return c(j(t),"niceness")}o(N,"bashNicenessPath");function at(t){try{const e=Number(b(t,N(t)).trim());return!Number.isInteger(e)||e<0||e>K?P:e}catch{return P}}o(at,"readBashNiceness");function ft(t,e){g(m(t),N(t),`${Math.trunc(e)}
2
- `)}o(ft,"writeBashNiceness");function Y(t,e){try{const n=Number(b(t,f(t,e).jobDeadline).trim());return Number.isFinite(n)?n:void 0}catch{return}}o(Y,"readJobDeadlineMs");function Z(t,e){g(t.root,t.jobDeadline,`${Math.trunc(e)}
3
- `)}o(Z,"writeJobDeadlineMs");function dt(t){try{k(t.root,t.jobDeadline)}catch{}}o(dt,"clearJobDeadline");function lt(t,e){try{const[n,...r]=b(t,f(t,e).jobActivity).split(`
4
- `),[s,i]=(n??"").split(" ").map(Number);return!Number.isFinite(s)||!Number.isFinite(i)?void 0:{lastActivityMs:s,sampledAtMs:i,files:r.filter(u=>u!=="")}}catch{return}}o(lt,"readJobActivity");function bt(t,e){return a(f(t,e),f(t,e).jobQuietOk)}o(bt,"isJobQuietOk");function ht(t){g(t.root,t.jobQuietOk,"")}o(ht,"markJobQuietOk");function pt(t,e){try{const[n,r]=b(t,f(t,e).jobSilence).trim().split(" ").map(Number);return Number.isFinite(n)&&Number.isFinite(r)?{lastActivityMs:n,thresholdMs:r}:void 0}catch{return}}o(pt,"readJobSilence");function mt(t,e,n){g(t.root,t.jobSilence,`${Math.trunc(e)} ${Math.trunc(n)}
5
- `)}o(mt,"writeJobSilence");function gt(t,e){if(e===`launcher:${t}`)return M(t);try{return process.kill(-t,0),!0}catch(n){return n.code==="EPERM"}}o(gt,"isBashJobProcessGroupAlive");function jt(t,e){if(t===void 0||e===void 0)return!1;if(e===`launcher:${t}`)return!M(t);try{return process.kill(-t,0),!1}catch(n){return n.code==="ESRCH"}}o(jt,"isBashJobProcessConfirmedGone");async function V(t,e){const n=O(t,e);if(n.reused||n.tree.length===0)return!1;const r=[...n.tree].reverse(),s=T(r);return x(r,"SIGTERM",n.identities),await new Promise(i=>setTimeout(i,400)),x(r,"SIGKILL",n.identities),s}o(V,"cancelBashJobProcessTree");async function yt(t,e,n=!1,r,s){const i=f(t,e);if(!a(i,i.dir))return{kind:"missing"};if(!a(i,i.jobBg)&&!(n&&a(i,i.jobRun))||a(i,i.jobExit))return{kind:"retired",logPath:i.jobLog};const u=q(t,e),d=U(t,e);if(u===void 0||d===void 0)return{kind:"not-stoppable",logPath:i.jobLog};const h=c(i.dir,"job.stop");try{A(i.root,h,s===void 0?"":`${s}
6
- `)}catch(l){if(l.code==="EEXIST")return{kind:"retired",logPath:i.jobLog};throw l}try{let l;if(d===`launcher:${u}`){if(r===void 0)throw new Error("launcher job stop requires its owning node");try{if(!("ok"in await F({operation:"stop",pid:u,nodeId:r})))throw new Error("launcher did not stop job");l=!0}catch(p){if(!(p instanceof _&&p.refusal==="invalid_spec"))throw p;l=!1}}else l=await V(u,d);try{A(i.root,i.jobExit,`143
7
- `)}catch(p){if(p.code!=="EEXIST")throw p}return{kind:"stopped",signaled:l,pgid:u,logPath:i.jobLog}}catch(l){throw k(i.root,h),l}}o(yt,"stopBackgroundBashJob");function Bt(t,e){if(e<=0)return[];const n=64*1024;let r;try{const s=v(t).size,i=Math.max(0,s-n),u=Buffer.alloc(Math.min(s,n));r=B(t,"r"),S(r,u,0,u.length,i);const d=u.toString("utf8"),h=(i>0?d.slice(d.indexOf(`
8
- `)+1):d).split(`
9
- `);return h[h.length-1]===""&&h.pop(),h.slice(-e)}catch{return[]}finally{r!==void 0&&y(r)}}o(Bt,"tailJobLog");function St(t){let e;try{e=B(t,"r");const n=Buffer.alloc(64*1024);let r=0,s=0;for(;;){const i=S(e,n,0,n.length,null);if(i===0)break;for(let u=0;u<i;u+=1)n[u]===10&&(r+=1);s=n[i-1]}return s!==0&&s!==10?r+1:r}catch{return 0}finally{e!==void 0&&y(e)}}o(St,"countJobLogLines");function Mt(){return`${Date.now()}-${R(4).toString("hex")}`}o(Mt,"newBashJobId");function E(t){const e=t.indexOf("-");if(e<=0||e===t.length-1)return;const n=Number(t.slice(0,e));return Number.isFinite(n)?n:void 0}o(E,"jobStartedAtMs");function xt(t){const e=Math.max(0,Math.floor(t/1e3));if(e<60)return`${e}s`;const n=Math.floor(e/60),r=e%60;if(n<60)return`${n}m ${String(r).padStart(2,"0")}s`;const s=Math.floor(n/60),i=n%60;return`${s}h ${String(i).padStart(2,"0")}m`}o(xt,"formatBashElapsed");function At(t){return(t.split(`
10
- `).map(n=>n.trim()).find(n=>n!=="")??"").replace(/\s+/g," ")}o(At,"bashJobCommandLine");function w(t,e=!1){let n;try{n=J(t)}catch{return[]}const r=[];for(const s of n){const i=E(s);if(i===void 0)continue;const u=f(t,s);let d;try{if(!a(u,u.jobBg)&&!(e&&a(u,u.jobRun))||a(u,u.jobExit))continue;d=b(t,u.cmdSh)}catch{continue}r.push({jobId:s,command:d,purpose:W(t,s),startedAtMs:i,logPath:u.jobLog,deadlineAtMs:Y(t,s)??null})}return r.sort((s,i)=>s.startedAtMs-i.startedAtMs)}o(w,"activeBackgroundBashJobs");function Jt(t,e){return w(t).filter(n=>n.deadlineAtMs!==null&&e>=n.deadlineAtMs)}o(Jt,"expiredAutoBackgroundBashJobs");function kt(t,e){if(!Number.isFinite(e)||e<=0)return 0;let n=0;for(const r of w(t))if(r.deadlineAtMs!==null)try{Z(f(t,r.jobId),r.deadlineAtMs+e),n+=1}catch{}return n}o(kt,"shiftAutoBackgroundBashDeadlines");function D(t){try{return z(t.root,t.jobRun,t.jobBg),"backgrounded"}catch(e){if(e.code!=="ENOENT")throw e;return a(t,t.jobBg)?"already-backgrounded":a(t,t.jobDone)?"finished":"missing"}}o(D,"backgroundBashJob");function L(t){let e;try{e=J(t)}catch{return[]}return e.flatMap(n=>{const r=f(t,n);try{return a(r,r.cmdSh)&&a(r,r.jobLog)&&a(r,r.jobRun)?[r]:[]}catch{return[]}})}o(L,"runningBashJobs");function Pt(t){let e;for(const n of L(t)){const r=E(n.jobId);r!==void 0&&(e===void 0||r<e)&&(e=r)}return e}o(Pt,"oldestRunningBashJobStartedAtMs");function Nt(t){const e=[];for(const n of L(t))D(n)==="backgrounded"&&e.push(n);return e}o(Nt,"backgroundRunningBashJobs");export{P as DEFAULT_BASH_NICENESS,K as MAX_BASH_NICENESS,w as activeBackgroundBashJobs,D as backgroundBashJob,Nt as backgroundRunningBashJobs,At as bashJobCommandLine,f as bashJobPaths,j as bashJobsDir,N as bashNicenessPath,V as cancelBashJobProcessTree,dt as clearJobDeadline,St as countJobLogLines,Jt as expiredAutoBackgroundBashJobs,xt as formatBashElapsed,jt as isBashJobProcessConfirmedGone,gt as isBashJobProcessGroupAlive,bt as isJobQuietOk,ct as isSafeBashJobId,E as jobStartedAtMs,ht as markJobQuietOk,Mt as newBashJobId,X as normalizeBashJobPurpose,Pt as oldestRunningBashJobStartedAtMs,at as readBashNiceness,lt as readJobActivity,Y as readJobDeadlineMs,q as readJobPgid,U as readJobPgidIdentity,W as readJobPurpose,pt as readJobSilence,kt as shiftAutoBackgroundBashDeadlines,yt as stopBackgroundBashJob,Bt as tailJobLog,ft as writeBashNiceness,Z as writeJobDeadlineMs,mt as writeJobSilence};
1
+ var F=Object.defineProperty;var o=(t,e)=>F(t,"name",{value:e,configurable:!0});import{randomBytes as I}from"node:crypto";import{closeSync as x,openSync as S,readSync as E,statSync as _}from"node:fs";import{dirname as p,join as a}from"node:path";import{captureTeardownSnapshot as C,isAnyPidAlive as O,isPidAlive as N,killProcessTreePids as J}from"./canvas/pid.js";import{launcherRequest as z}from"../launcher/client.js";import{LaunchRefused as G}from"../launcher/spec.js";import{createFileBeneath as P,existsBeneath as H,readTextBeneathIfExists as m,readdirBeneath as X,readFileBeneath as q,renameBeneath as U,unlinkBeneath as W,writeFileBeneath as w}from"./spaces/open-beneath.js";const K=280;function at(t){if(typeof t!="string"||/[\p{Cc}\p{Cf}]/u.test(t))return null;const e=t.trim();return e===""?null:Buffer.byteLength(e,"utf8")<=K?e:null}o(at,"normalizeBashJobPurpose");function g(t){return a(t,"jobs")}o(g,"bashJobsDir");function y(t,e){return q(p(t),e).toString("utf8")}o(y,"readJobText");function M(t){return X(p(t),g(t)).map(e=>e.name)}o(M,"jobIds");function c(t,e){return H(t.root,e)}o(c,"has");function k(t,e){try{W(t,e)}catch(n){if(n.code!=="ENOENT")throw n}}o(k,"unlinkIfPresent");function ct(t){return typeof t=="string"&&t!==""&&t!=="."&&t!==".."&&/^[A-Za-z0-9._~-]+$/u.test(t)&&Buffer.byteLength(t,"utf8")<=128}o(ct,"isSafeBashJobId");function b(t,e){const n=a(g(t),e);return{jobId:e,root:p(t),dir:n,cmdSh:a(n,"cmd.sh"),jobLog:a(n,"job.log"),jobExit:a(n,"job.exit"),jobRun:a(n,"job.run"),jobBg:a(n,"job.bg"),jobDone:a(n,"job.done"),jobPgid:a(n,"job.pgid"),jobPgidIdentity:a(n,"job.pgid-identity"),jobActivity:a(n,"job.activity"),jobDeadline:a(n,"job.deadline"),jobReported:a(n,"job.reported")}}o(b,"bashJobPaths");function A(t,e){try{const n=Number(y(t,b(t,e).jobPgid).trim());return Number.isInteger(n)&&n>1?n:void 0}catch{return}}o(A,"readJobPgid");function L(t,e){try{const n=y(t,b(t,e).jobPgidIdentity).trim();return n===""?void 0:n}catch{return}}o(L,"readJobPgidIdentity");function ft(t,e){const n=b(t,e),r={},s=A(t,e),i=L(t,e);s!==void 0&&(r.pgid=s),i!==void 0&&(r.pgidIdentity=i);const u=m(n.root,n.jobExit);u!==null&&Number.isSafeInteger(Number(u.trim()))&&u.trim()!==""&&(r.exitCode=Number(u.trim()));const f=m(n.root,n.jobDeadline);f!==null&&f.trim()!==""&&Number.isFinite(Number(f.trim()))&&(r.deadlineMs=Number(f.trim()));const d=m(n.root,n.jobActivity);if(d!==null){const[l,...h]=d.split(`
2
+ `),[B,j]=(l??"").split(" ").map(Number);Number.isFinite(B)&&Number.isFinite(j)&&(r.activity={lastActivityMs:B,sampledAtMs:j,files:h.filter(v=>v!=="")})}return r}o(ft,"readJobSupervisorState");function dt(t,e){w(t.root,t.jobDeadline,`${Math.trunc(e)}
3
+ `)}o(dt,"writeJobDeadlineFile");function lt(t){k(t.root,t.jobDeadline)}o(lt,"clearJobDeadlineFile");function bt(t){let e;try{e=M(t)}catch{return[]}return e.filter(n=>{const r=b(t,n);try{return(c(r,r.jobRun)||c(r,r.jobBg))&&!c(r,r.jobExit)}catch{return!1}})}o(bt,"unfinishedBashJobIds");const R=10,Y=19;function $(t){return a(g(t),"niceness")}o($,"bashNicenessPath");function ht(t){try{const e=Number(y(t,$(t)).trim());return!Number.isInteger(e)||e<0||e>Y?R:e}catch{return R}}o(ht,"readBashNiceness");function pt(t,e){w(p(t),$(t),`${Math.trunc(e)}
4
+ `)}o(pt,"writeBashNiceness");function mt(t,e){if(e===`launcher:${t}`)return N(t);try{return process.kill(-t,0),!0}catch(n){return n.code==="EPERM"}}o(mt,"isBashJobProcessGroupAlive");function gt(t,e){if(t===void 0||e===void 0)return!1;if(e===`launcher:${t}`)return!N(t);try{return process.kill(-t,0),!1}catch(n){return n.code==="ESRCH"}}o(gt,"isBashJobProcessConfirmedGone");async function Z(t,e){const n=C(t,e);if(n.reused||n.tree.length===0)return!1;const r=[...n.tree].reverse(),s=O(r);return J(r,"SIGTERM",n.identities),await new Promise(i=>setTimeout(i,400)),J(r,"SIGKILL",n.identities),s}o(Z,"cancelBashJobProcessTree");async function D(t,e,n){if(e!==`launcher:${t}`)return await Z(t,e);if(n===void 0)throw new Error("launcher job stop requires its owning node");try{if(!("ok"in await z({operation:"stop",pid:t,nodeId:n})))throw new Error("launcher did not stop job");return!0}catch(r){if(!(r instanceof G&&r.refusal==="invalid_spec"))throw r;return!1}}o(D,"signalBashJob");async function yt(t,e,n=!1,r,s){const i=b(t,e);if(!c(i,i.dir))return{kind:"missing"};if(!c(i,i.jobBg)&&!(n&&c(i,i.jobRun))||c(i,i.jobExit))return{kind:"retired",logPath:i.jobLog};const u=A(t,e),f=L(t,e);if(u===void 0||f===void 0)return{kind:"not-stoppable",logPath:i.jobLog};const d=a(i.dir,"job.stop");try{P(i.root,d,s===void 0?"":`${s}
5
+ `)}catch(l){if(l.code==="EEXIST")return{kind:"retired",logPath:i.jobLog};throw l}try{const l=await D(u,f,r);try{P(i.root,i.jobExit,`143
6
+ `)}catch(h){if(h.code!=="EEXIST")throw h}return{kind:"stopped",signaled:l,pgid:u,logPath:i.jobLog}}catch(l){throw k(i.root,d),l}}o(yt,"stopBackgroundBashJob");function Bt(t,e){if(e<=0)return[];const n=64*1024;let r;try{const s=_(t).size,i=Math.max(0,s-n),u=Buffer.alloc(Math.min(s,n));r=S(t,"r"),E(r,u,0,u.length,i);const f=u.toString("utf8"),d=(i>0?f.slice(f.indexOf(`
7
+ `)+1):f).split(`
8
+ `);return d[d.length-1]===""&&d.pop(),d.slice(-e)}catch{return[]}finally{r!==void 0&&x(r)}}o(Bt,"tailJobLog");function jt(t){let e;try{e=S(t,"r");const n=Buffer.alloc(64*1024);let r=0,s=0;for(;;){const i=E(e,n,0,n.length,null);if(i===0)break;for(let u=0;u<i;u+=1)n[u]===10&&(r+=1);s=n[i-1]}return s!==0&&s!==10?r+1:r}catch{return 0}finally{e!==void 0&&x(e)}}o(jt,"countJobLogLines");function xt(){return`${Date.now()}-${I(4).toString("hex")}`}o(xt,"newBashJobId");function Q(t){const e=t.indexOf("-");if(e<=0||e===t.length-1)return;const n=Number(t.slice(0,e));return Number.isFinite(n)?n:void 0}o(Q,"jobStartedAtMs");function St(t){const e=Math.max(0,Math.floor(t/1e3));if(e<60)return`${e}s`;const n=Math.floor(e/60),r=e%60;if(n<60)return`${n}m ${String(r).padStart(2,"0")}s`;const s=Math.floor(n/60),i=n%60;return`${s}h ${String(i).padStart(2,"0")}m`}o(St,"formatBashElapsed");function Et(t){return(t.split(`
9
+ `).map(n=>n.trim()).find(n=>n!=="")??"").replace(/\s+/g," ")}o(Et,"bashJobCommandLine");function V(t){try{return U(t.root,t.jobRun,t.jobBg),"backgrounded"}catch(e){if(e.code!=="ENOENT")throw e;return c(t,t.jobBg)?"already-backgrounded":c(t,t.jobDone)?"finished":"missing"}}o(V,"backgroundBashJob");function T(t){let e;try{e=M(t)}catch{return[]}return e.flatMap(n=>{const r=b(t,n);try{return c(r,r.cmdSh)&&c(r,r.jobLog)&&c(r,r.jobRun)?[r]:[]}catch{return[]}})}o(T,"runningBashJobs");function Nt(t){let e;for(const n of T(t)){const r=Q(n.jobId);r!==void 0&&(e===void 0||r<e)&&(e=r)}return e}o(Nt,"oldestRunningBashJobStartedAtMs");function Jt(t){const e=[];for(const n of T(t))V(n)==="backgrounded"&&e.push(n);return e}o(Jt,"backgroundRunningBashJobs");export{R as DEFAULT_BASH_NICENESS,Y as MAX_BASH_NICENESS,V as backgroundBashJob,Jt as backgroundRunningBashJobs,Et as bashJobCommandLine,b as bashJobPaths,g as bashJobsDir,$ as bashNicenessPath,Z as cancelBashJobProcessTree,lt as clearJobDeadlineFile,jt as countJobLogLines,St as formatBashElapsed,gt as isBashJobProcessConfirmedGone,mt as isBashJobProcessGroupAlive,ct as isSafeBashJobId,Q as jobStartedAtMs,xt as newBashJobId,at as normalizeBashJobPurpose,Nt as oldestRunningBashJobStartedAtMs,ht as readBashNiceness,A as readJobPgid,L as readJobPgidIdentity,ft as readJobSupervisorState,D as signalBashJob,yt as stopBackgroundBashJob,Bt as tailJobLog,bt as unfinishedBashJobIds,pt as writeBashNiceness,dt as writeJobDeadlineFile};
@@ -0,0 +1,3 @@
1
+ import { type BlobStore } from './index.js';
2
+ /** Objects as files under `root`: written to a temp file, fsynced, renamed into place, and the directory fsynced. */
3
+ export declare function createDirectoryBlobStore(root: string): BlobStore;
@@ -0,0 +1 @@
1
+ var S=Object.defineProperty;var i=(s,c)=>S(s,"name",{value:c,configurable:!0});import{randomUUID as w}from"node:crypto";import{closeSync as u,fsyncSync as a,mkdirSync as B,openSync as m,readFileSync as b,readSync as D,readdirSync as E,renameSync as N,rmSync as p,writeSync as $}from"node:fs";import{dirname as h,join as d}from"node:path";import{assertBlobKey as g}from"./index.js";import{blobFault as F}from"./fault.js";function O(s){const c=m(s,"r");try{a(c)}finally{u(c)}}i(O,"syncDir");function x(s){const c=i(e=>(g(e),d(s,...e.split("/"))),"pathOf");function l(e,n,r){let o;try{o=E(e,{withFileTypes:!0})}catch(t){if(t.code==="ENOENT")return;throw t}for(const t of o){if(t.name.endsWith(".tmp"))continue;const f=n===""?t.name:`${n}/${t.name}`;t.isDirectory()?l(d(e,t.name),f,r):r.push(f)}}return i(l,"walk"),{async put(e,n){F("put");const r=c(e);B(h(r),{recursive:!0,mode:448});const o=`${r}.${w()}.tmp`,t=m(o,"wx",384);try{const f=typeof n=="string"?Buffer.from(n,"utf8"):Buffer.from(n);let y=0;for(;y<f.length;)y+=$(t,f,y);a(t)}catch(f){throw u(t),p(o,{force:!0}),f}u(t),N(o,r),O(h(r))},async get(e,n){try{if(!n)return b(c(e));const r=m(c(e),"r");try{const o=Buffer.allocUnsafe(n.length),t=D(r,o,0,n.length,n.start);return o.subarray(0,t)}finally{u(r)}}catch(r){if(r.code==="ENOENT")return null;throw r}},async list(e){const n=[];return l(s,"",n),n.filter(r=>r.startsWith(e)).sort((r,o)=>Buffer.compare(Buffer.from(r),Buffer.from(o)))},async delete(e){p(c(e),{force:!0})}}}i(x,"createDirectoryBlobStore");export{x as createDirectoryBlobStore};
@@ -0,0 +1,3 @@
1
+ /** Fault switch for the blob store (design-fleet, faulting-store seam): `CRTR_FAULT_BLOB=put_fail` makes every `put`
2
+ * throw. Read on each call so a seam test can flip it in the serving process's environment. */
3
+ export declare function blobFault(op: 'put'): void;
@@ -0,0 +1 @@
1
+ var u=Object.defineProperty;var o=(t,r)=>u(t,"name",{value:r,configurable:!0});function p(t){if(t==="put"&&process.env.CRTR_FAULT_BLOB==="put_fail")throw new Error("blob put refused (CRTR_FAULT_BLOB=put_fail)")}o(p,"blobFault");export{p as blobFault};
@@ -0,0 +1,21 @@
1
+ /** The one blob-store interface: conversation objects, run-event chunks, job output, attachments and releases are
2
+ * objects under slash-separated keys (`conversations/<node>/<session>/<seq>.jsonl`). Implementations: a directory
3
+ * (a Mac, `~/.crouter/blobs/`) and R2 (the cloud). A key never starts with `/` and has no `.` or `..` segment. */
4
+ export interface BlobStore {
5
+ /** Write `data` at `key`, replacing any object there. Resolves once the object is durable. */
6
+ put(key: string, data: Buffer | Uint8Array | string): Promise<void>;
7
+ /** The object's bytes (just `length` bytes from `start` when a range is given; fewer at the end), or `null` when no object has this key. */
8
+ get(key: string, range?: {
9
+ start: number;
10
+ length: number;
11
+ }): Promise<Buffer | null>;
12
+ /** Every key beginning with `prefix`, in ascending byte order. */
13
+ list(prefix: string): Promise<string[]>;
14
+ /** Remove the object at `key`; removing an absent key is not an error. */
15
+ delete(key: string): Promise<void>;
16
+ }
17
+ /** A key is safe when it is a relative path of plain segments. Throws on anything else. */
18
+ export declare function assertBlobKey(key: string): void;
19
+ export declare function blobStore(): Promise<BlobStore>;
20
+ /** Drop the selected store (tests that change the environment). */
21
+ export declare function resetBlobStore(): void;
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var r=(e,t)=>c(e,"name",{value:t,configurable:!0});function l(e){if(e===""||e.startsWith("/")||e.endsWith("/")||e.split("/").some(t=>t===""||t==="."||t===".."))throw new Error(`invalid blob key: ${JSON.stringify(e)}`)}r(l,"assertBlobKey");let o;async function _(){if(o)return o;const e=process.env.CRTR_R2_BUCKET;if(e){const t=r(s=>{const n=process.env[s];if(!n)throw new Error(`${s} is required when CRTR_R2_BUCKET is set`);return n},"need"),{createR2BlobStore:i}=await import("./r2.js");o=i({bucket:e,endpoint:t("CRTR_R2_ENDPOINT"),accessKeyId:t("CRTR_R2_ACCESS_KEY_ID"),secretAccessKey:t("CRTR_R2_SECRET_ACCESS_KEY")})}else{const[{join:t},{layoutRoot:i},{createDirectoryBlobStore:s}]=await Promise.all([import("node:path"),import("../layout.js"),import("./directory.js")]);o=s(t(i(),"blobs"))}return o}r(_,"blobStore");function a(){o=void 0}r(a,"resetBlobStore");export{l as assertBlobKey,_ as blobStore,a as resetBlobStore};
@@ -0,0 +1,9 @@
1
+ import { type BlobStore } from './index.js';
2
+ export interface R2Config {
3
+ bucket: string;
4
+ endpoint: string;
5
+ accessKeyId: string;
6
+ secretAccessKey: string;
7
+ }
8
+ /** S3-compatible object store (R2) over `fetch`: path-style requests signed with SigV4, region `auto`. */
9
+ export declare function createR2BlobStore(config: R2Config): BlobStore;
@@ -0,0 +1,4 @@
1
+ var I=Object.defineProperty;var c=(a,o)=>I(a,"name",{value:o,configurable:!0});import{createHash as U,createHmac as C}from"node:crypto";import{assertBlobKey as g}from"./index.js";import{blobFault as z}from"./fault.js";const T=c(a=>U("sha256").update(a).digest("hex"),"sha256"),d=c((a,o)=>C("sha256",a).update(o).digest(),"hmac"),$=c(a=>encodeURIComponent(a).replace(/[!'()*]/g,o=>`%${o.charCodeAt(0).toString(16).toUpperCase()}`),"encode");function G(a){const o=new URL(a.endpoint);async function u(t,e,n,r,s){const l=`/${$(a.bucket)}${e===""?"":`/${e.split("/").map($).join("/")}`}`,h=[...n].sort(([i],[w])=>i<w?-1:1).map(([i,w])=>`${$(i)}=${$(w)}`).join("&"),m=new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),y=m.slice(0,8),B=T(r??""),p={host:o.host,"x-amz-content-sha256":B,"x-amz-date":m},S=Object.keys(p).sort(),b=S.map(i=>`${i}:${p[i]}
2
+ `).join(""),x=S.join(";"),A=`${y}/auto/s3/aws4_request`,j=[t,l,h,b,x,B].join(`
3
+ `),E=["AWS4-HMAC-SHA256",m,A,T(j)].join(`
4
+ `),K=d(d(d(d(`AWS4${a.secretAccessKey}`,y),"auto"),"s3"),"aws4_request"),q=C("sha256",K).update(E).digest("hex");p.authorization=`AWS4-HMAC-SHA256 Credential=${a.accessKeyId}/${A}, SignedHeaders=${x}, Signature=${q}`;const{host:R,...H}=p;return s&&(H.range=`bytes=${s.start}-${s.start+s.length-1}`),await fetch(`${o.origin}${l}${h?`?${h}`:""}`,{method:t,headers:H,...r?{body:new Uint8Array(r)}:{}})}c(u,"send");async function f(t,e){if(!t.ok)throw new Error(`R2 ${e} failed (${t.status}): ${(await t.text()).slice(0,300)}`);return t}return c(f,"ok"),{async put(t,e){z("put"),g(t),await f(await u("PUT",t,[],typeof e=="string"?Buffer.from(e,"utf8"):Buffer.from(e)),`put ${t}`)},async get(t,e){g(t);const n=await u("GET",t,[],void 0,e);return n.status===416?(await n.arrayBuffer(),Buffer.alloc(0)):n.status===404?(await n.arrayBuffer(),null):Buffer.from(await(await f(n,`get ${t}`)).arrayBuffer())},async list(t){const e=[];let n;do{const r=[["list-type","2"],["prefix",t],...n?[["continuation-token",n]]:[]],s=await(await f(await u("GET","",r),`list ${t}`)).text();for(const l of s.matchAll(/<Key>([^<]*)<\/Key>/g))e.push(l[1].replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'"));n=/<IsTruncated>true<\/IsTruncated>/.test(s)?/<NextContinuationToken>([^<]*)<\/NextContinuationToken>/.exec(s)?.[1]:void 0}while(n);return e.sort((r,s)=>Buffer.compare(Buffer.from(r),Buffer.from(s)))},async delete(t){g(t);const e=await u("DELETE",t,[]);e.status!==404?await f(e,`delete ${t}`):await e.arrayBuffer()}}}c(G,"createR2BlobStore");export{G as createR2BlobStore};
@@ -1 +1 @@
1
- export declare function ensureProjectScope(argv: string[]): void;
1
+ export declare function ensureProjectScope(argv: string[]): Promise<void>;