@wjarka/cezarion 0.10.0-pr30.54

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 (478) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +838 -0
  3. package/dist/agent-config/account-identity.d.ts +44 -0
  4. package/dist/agent-config/account-identity.js +128 -0
  5. package/dist/agent-config/account-identity.js.map +1 -0
  6. package/dist/agent-config/catalog.d.ts +72 -0
  7. package/dist/agent-config/catalog.js +223 -0
  8. package/dist/agent-config/catalog.js.map +1 -0
  9. package/dist/agent-config/files.d.ts +46 -0
  10. package/dist/agent-config/files.js +119 -0
  11. package/dist/agent-config/files.js.map +1 -0
  12. package/dist/agent-config/model-settings/claude.d.ts +2 -0
  13. package/dist/agent-config/model-settings/claude.js +11 -0
  14. package/dist/agent-config/model-settings/claude.js.map +1 -0
  15. package/dist/agent-config/model-settings/codex.d.ts +2 -0
  16. package/dist/agent-config/model-settings/codex.js +16 -0
  17. package/dist/agent-config/model-settings/codex.js.map +1 -0
  18. package/dist/agent-config/model-settings/opencode.d.ts +2 -0
  19. package/dist/agent-config/model-settings/opencode.js +8 -0
  20. package/dist/agent-config/model-settings/opencode.js.map +1 -0
  21. package/dist/agent-config/model-settings/pi.d.ts +12 -0
  22. package/dist/agent-config/model-settings/pi.js +18 -0
  23. package/dist/agent-config/model-settings/pi.js.map +1 -0
  24. package/dist/agent-config/model-settings/shared.d.ts +9 -0
  25. package/dist/agent-config/model-settings/shared.js +93 -0
  26. package/dist/agent-config/model-settings/shared.js.map +1 -0
  27. package/dist/agent-config/model-settings/types.d.ts +9 -0
  28. package/dist/agent-config/model-settings/types.js +2 -0
  29. package/dist/agent-config/model-settings/types.js.map +1 -0
  30. package/dist/agent-config/models.d.ts +9 -0
  31. package/dist/agent-config/models.js +32 -0
  32. package/dist/agent-config/models.js.map +1 -0
  33. package/dist/agent-config/seed.d.ts +7 -0
  34. package/dist/agent-config/seed.js +90 -0
  35. package/dist/agent-config/seed.js.map +1 -0
  36. package/dist/agent-config/service.d.ts +44 -0
  37. package/dist/agent-config/service.js +71 -0
  38. package/dist/agent-config/service.js.map +1 -0
  39. package/dist/agent-config/validate.d.ts +21 -0
  40. package/dist/agent-config/validate.js +76 -0
  41. package/dist/agent-config/validate.js.map +1 -0
  42. package/dist/automations/coordinator.d.ts +26 -0
  43. package/dist/automations/coordinator.js +66 -0
  44. package/dist/automations/coordinator.js.map +1 -0
  45. package/dist/automations/github-poller.d.ts +74 -0
  46. package/dist/automations/github-poller.js +234 -0
  47. package/dist/automations/github-poller.js.map +1 -0
  48. package/dist/automations/scheduler.d.ts +42 -0
  49. package/dist/automations/scheduler.js +192 -0
  50. package/dist/automations/scheduler.js.map +1 -0
  51. package/dist/automations/store.d.ts +65 -0
  52. package/dist/automations/store.js +298 -0
  53. package/dist/automations/store.js.map +1 -0
  54. package/dist/automations/task-template.d.ts +18 -0
  55. package/dist/automations/task-template.js +95 -0
  56. package/dist/automations/task-template.js.map +1 -0
  57. package/dist/automations/types.d.ts +255 -0
  58. package/dist/automations/types.js +159 -0
  59. package/dist/automations/types.js.map +1 -0
  60. package/dist/config.d.ts +77 -0
  61. package/dist/config.js +242 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/contract/agent-config.d.ts +153 -0
  64. package/dist/contract/agent-profiles.d.ts +347 -0
  65. package/dist/contract/automations.d.ts +935 -0
  66. package/dist/contract/events.d.ts +104 -0
  67. package/dist/contract/github.d.ts +556 -0
  68. package/dist/contract/health.d.ts +102 -0
  69. package/dist/contract/index.d.ts +16 -0
  70. package/dist/contract/index.js +1895 -0
  71. package/dist/contract/projects.d.ts +210 -0
  72. package/dist/contract/repo.d.ts +234 -0
  73. package/dist/contract/runs.d.ts +1473 -0
  74. package/dist/contract/skills.d.ts +232 -0
  75. package/dist/contract/workflows.d.ts +218 -0
  76. package/dist/contract/workspace.d.ts +579 -0
  77. package/dist/core/agent-env.d.ts +31 -0
  78. package/dist/core/agent-env.js +371 -0
  79. package/dist/core/agent-env.js.map +1 -0
  80. package/dist/core/agent-model-policy.d.ts +10 -0
  81. package/dist/core/agent-model-policy.js +36 -0
  82. package/dist/core/agent-model-policy.js.map +1 -0
  83. package/dist/core/agent-profiles.d.ts +62 -0
  84. package/dist/core/agent-profiles.js +90 -0
  85. package/dist/core/agent-profiles.js.map +1 -0
  86. package/dist/core/agent-runner.d.ts +211 -0
  87. package/dist/core/agent-runner.js +68 -0
  88. package/dist/core/agent-runner.js.map +1 -0
  89. package/dist/core/ask.d.ts +105 -0
  90. package/dist/core/ask.js +187 -0
  91. package/dist/core/ask.js.map +1 -0
  92. package/dist/core/backend-detect.d.ts +16 -0
  93. package/dist/core/backend-detect.js +155 -0
  94. package/dist/core/backend-detect.js.map +1 -0
  95. package/dist/core/claude-cli-runner.d.ts +59 -0
  96. package/dist/core/claude-cli-runner.js +483 -0
  97. package/dist/core/claude-cli-runner.js.map +1 -0
  98. package/dist/core/claude-ui-mapper.d.ts +80 -0
  99. package/dist/core/claude-ui-mapper.js +598 -0
  100. package/dist/core/claude-ui-mapper.js.map +1 -0
  101. package/dist/core/codex-app-server-runner.d.ts +41 -0
  102. package/dist/core/codex-app-server-runner.js +584 -0
  103. package/dist/core/codex-app-server-runner.js.map +1 -0
  104. package/dist/core/codex-app-server-transport.d.ts +35 -0
  105. package/dist/core/codex-app-server-transport.js +150 -0
  106. package/dist/core/codex-app-server-transport.js.map +1 -0
  107. package/dist/core/codex-model-catalog.d.ts +10 -0
  108. package/dist/core/codex-model-catalog.js +110 -0
  109. package/dist/core/codex-model-catalog.js.map +1 -0
  110. package/dist/core/codex-ui-mapper.d.ts +112 -0
  111. package/dist/core/codex-ui-mapper.js +766 -0
  112. package/dist/core/codex-ui-mapper.js.map +1 -0
  113. package/dist/core/model-identity.d.ts +125 -0
  114. package/dist/core/model-identity.js +132 -0
  115. package/dist/core/model-identity.js.map +1 -0
  116. package/dist/core/model-presets.d.ts +21 -0
  117. package/dist/core/model-presets.js +81 -0
  118. package/dist/core/model-presets.js.map +1 -0
  119. package/dist/core/ndjson.d.ts +6 -0
  120. package/dist/core/ndjson.js +23 -0
  121. package/dist/core/ndjson.js.map +1 -0
  122. package/dist/core/opencode-model-catalog.d.ts +32 -0
  123. package/dist/core/opencode-model-catalog.js +153 -0
  124. package/dist/core/opencode-model-catalog.js.map +1 -0
  125. package/dist/core/opencode-server-runner.d.ts +32 -0
  126. package/dist/core/opencode-server-runner.js +882 -0
  127. package/dist/core/opencode-server-runner.js.map +1 -0
  128. package/dist/core/opencode-ui-mapper.d.ts +137 -0
  129. package/dist/core/opencode-ui-mapper.js +800 -0
  130. package/dist/core/opencode-ui-mapper.js.map +1 -0
  131. package/dist/core/pi-model-catalog.d.ts +31 -0
  132. package/dist/core/pi-model-catalog.js +152 -0
  133. package/dist/core/pi-model-catalog.js.map +1 -0
  134. package/dist/core/pi-runner.d.ts +24 -0
  135. package/dist/core/pi-runner.js +403 -0
  136. package/dist/core/pi-runner.js.map +1 -0
  137. package/dist/core/pi-ui-mapper.d.ts +36 -0
  138. package/dist/core/pi-ui-mapper.js +304 -0
  139. package/dist/core/pi-ui-mapper.js.map +1 -0
  140. package/dist/core/process-usage.d.ts +66 -0
  141. package/dist/core/process-usage.js +193 -0
  142. package/dist/core/process-usage.js.map +1 -0
  143. package/dist/core/provider-auth.d.ts +154 -0
  144. package/dist/core/provider-auth.js +509 -0
  145. package/dist/core/provider-auth.js.map +1 -0
  146. package/dist/core/provider-availability.d.ts +3 -0
  147. package/dist/core/provider-availability.js +14 -0
  148. package/dist/core/provider-availability.js.map +1 -0
  149. package/dist/core/runner-factory.d.ts +8 -0
  150. package/dist/core/runner-factory.js +25 -0
  151. package/dist/core/runner-factory.js.map +1 -0
  152. package/dist/core/runner-model-catalog.d.ts +29 -0
  153. package/dist/core/runner-model-catalog.js +78 -0
  154. package/dist/core/runner-model-catalog.js.map +1 -0
  155. package/dist/core/secret-redaction.d.ts +37 -0
  156. package/dist/core/secret-redaction.js +115 -0
  157. package/dist/core/secret-redaction.js.map +1 -0
  158. package/dist/core/shell-env.d.ts +28 -0
  159. package/dist/core/shell-env.js +56 -0
  160. package/dist/core/shell-env.js.map +1 -0
  161. package/dist/core/tool-display.d.ts +31 -0
  162. package/dist/core/tool-display.js +179 -0
  163. package/dist/core/tool-display.js.map +1 -0
  164. package/dist/core/ui-events.d.ts +335 -0
  165. package/dist/core/ui-events.js +25 -0
  166. package/dist/core/ui-events.js.map +1 -0
  167. package/dist/core/usage-limit.d.ts +42 -0
  168. package/dist/core/usage-limit.js +209 -0
  169. package/dist/core/usage-limit.js.map +1 -0
  170. package/dist/core/usage.d.ts +11 -0
  171. package/dist/core/usage.js +15 -0
  172. package/dist/core/usage.js.map +1 -0
  173. package/dist/core/v1-text-coalescer.d.ts +36 -0
  174. package/dist/core/v1-text-coalescer.js +72 -0
  175. package/dist/core/v1-text-coalescer.js.map +1 -0
  176. package/dist/git-diff-base.d.ts +85 -0
  177. package/dist/git-diff-base.js +180 -0
  178. package/dist/git-diff-base.js.map +1 -0
  179. package/dist/git-refs.d.ts +11 -0
  180. package/dist/git-refs.js +14 -0
  181. package/dist/git-refs.js.map +1 -0
  182. package/dist/git-worktree.d.ts +161 -0
  183. package/dist/git-worktree.js +508 -0
  184. package/dist/git-worktree.js.map +1 -0
  185. package/dist/handoff.d.ts +62 -0
  186. package/dist/handoff.js +154 -0
  187. package/dist/handoff.js.map +1 -0
  188. package/dist/index.d.ts +2 -0
  189. package/dist/index.js +680 -0
  190. package/dist/index.js.map +1 -0
  191. package/dist/install-as-command.d.ts +40 -0
  192. package/dist/install-as-command.js +52 -0
  193. package/dist/install-as-command.js.map +1 -0
  194. package/dist/pack-check.d.ts +17 -0
  195. package/dist/pack-check.js +27 -0
  196. package/dist/pack-check.js.map +1 -0
  197. package/dist/paths.d.ts +140 -0
  198. package/dist/paths.js +192 -0
  199. package/dist/paths.js.map +1 -0
  200. package/dist/planner.d.ts +27 -0
  201. package/dist/planner.js +268 -0
  202. package/dist/planner.js.map +1 -0
  203. package/dist/release/manifests.d.ts +81 -0
  204. package/dist/release/manifests.js +74 -0
  205. package/dist/release/manifests.js.map +1 -0
  206. package/dist/release/snapshot.d.ts +67 -0
  207. package/dist/release/snapshot.js +97 -0
  208. package/dist/release/snapshot.js.map +1 -0
  209. package/dist/release/stable.d.ts +38 -0
  210. package/dist/release/stable.js +55 -0
  211. package/dist/release/stable.js.map +1 -0
  212. package/dist/runs/agent-tmpdir.d.ts +41 -0
  213. package/dist/runs/agent-tmpdir.js +183 -0
  214. package/dist/runs/agent-tmpdir.js.map +1 -0
  215. package/dist/runs/auto-name.d.ts +75 -0
  216. package/dist/runs/auto-name.js +179 -0
  217. package/dist/runs/auto-name.js.map +1 -0
  218. package/dist/runs/event-history.d.ts +50 -0
  219. package/dist/runs/event-history.js +613 -0
  220. package/dist/runs/event-history.js.map +1 -0
  221. package/dist/runs/retention.d.ts +60 -0
  222. package/dist/runs/retention.js +86 -0
  223. package/dist/runs/retention.js.map +1 -0
  224. package/dist/runs/review-gate.d.ts +18 -0
  225. package/dist/runs/review-gate.js +21 -0
  226. package/dist/runs/review-gate.js.map +1 -0
  227. package/dist/runs/run-index.d.ts +19 -0
  228. package/dist/runs/run-index.js +43 -0
  229. package/dist/runs/run-index.js.map +1 -0
  230. package/dist/runs/store.d.ts +446 -0
  231. package/dist/runs/store.js +1118 -0
  232. package/dist/runs/store.js.map +1 -0
  233. package/dist/runs/task-markers.d.ts +28 -0
  234. package/dist/runs/task-markers.js +74 -0
  235. package/dist/runs/task-markers.js.map +1 -0
  236. package/dist/runs/task-refs.d.ts +25 -0
  237. package/dist/runs/task-refs.js +74 -0
  238. package/dist/runs/task-refs.js.map +1 -0
  239. package/dist/runs/ui-event-sink.d.ts +81 -0
  240. package/dist/runs/ui-event-sink.js +210 -0
  241. package/dist/runs/ui-event-sink.js.map +1 -0
  242. package/dist/server/app-type.d.ts +21 -0
  243. package/dist/server/app-type.js +2 -0
  244. package/dist/server/app-type.js.map +1 -0
  245. package/dist/server/capabilities.d.ts +70 -0
  246. package/dist/server/capabilities.js +152 -0
  247. package/dist/server/capabilities.js.map +1 -0
  248. package/dist/server/checkout.d.ts +128 -0
  249. package/dist/server/checkout.js +296 -0
  250. package/dist/server/checkout.js.map +1 -0
  251. package/dist/server/forge/github.d.ts +513 -0
  252. package/dist/server/forge/github.js +2364 -0
  253. package/dist/server/forge/github.js.map +1 -0
  254. package/dist/server/forge/index.d.ts +40 -0
  255. package/dist/server/forge/index.js +72 -0
  256. package/dist/server/forge/index.js.map +1 -0
  257. package/dist/server/forge/types.d.ts +242 -0
  258. package/dist/server/forge/types.js +2 -0
  259. package/dist/server/forge/types.js.map +1 -0
  260. package/dist/server/fs-browse.d.ts +105 -0
  261. package/dist/server/fs-browse.js +182 -0
  262. package/dist/server/fs-browse.js.map +1 -0
  263. package/dist/server/git-changes.d.ts +213 -0
  264. package/dist/server/git-changes.js +555 -0
  265. package/dist/server/git-changes.js.map +1 -0
  266. package/dist/server/git.d.ts +28 -0
  267. package/dist/server/git.js +112 -0
  268. package/dist/server/git.js.map +1 -0
  269. package/dist/server/github.d.ts +9 -0
  270. package/dist/server/github.js +8 -0
  271. package/dist/server/github.js.map +1 -0
  272. package/dist/server/launch-key.d.ts +7 -0
  273. package/dist/server/launch-key.js +33 -0
  274. package/dist/server/launch-key.js.map +1 -0
  275. package/dist/server/open-in-app.d.ts +66 -0
  276. package/dist/server/open-in-app.js +211 -0
  277. package/dist/server/open-in-app.js.map +1 -0
  278. package/dist/server/open-in-terminal.d.ts +70 -0
  279. package/dist/server/open-in-terminal.js +179 -0
  280. package/dist/server/open-in-terminal.js.map +1 -0
  281. package/dist/server/pr.d.ts +7 -0
  282. package/dist/server/pr.js +7 -0
  283. package/dist/server/pr.js.map +1 -0
  284. package/dist/server/project-context.d.ts +120 -0
  285. package/dist/server/project-context.js +182 -0
  286. package/dist/server/project-context.js.map +1 -0
  287. package/dist/server/provider-action-gate.d.ts +8 -0
  288. package/dist/server/provider-action-gate.js +56 -0
  289. package/dist/server/provider-action-gate.js.map +1 -0
  290. package/dist/server/provider-auth-runtime.d.ts +21 -0
  291. package/dist/server/provider-auth-runtime.js +66 -0
  292. package/dist/server/provider-auth-runtime.js.map +1 -0
  293. package/dist/server/server.d.ts +13138 -0
  294. package/dist/server/server.js +5263 -0
  295. package/dist/server/server.js.map +1 -0
  296. package/dist/server/static-ui.d.ts +49 -0
  297. package/dist/server/static-ui.js +92 -0
  298. package/dist/server/static-ui.js.map +1 -0
  299. package/dist/server/validators.d.ts +97 -0
  300. package/dist/server/validators.js +86 -0
  301. package/dist/server/validators.js.map +1 -0
  302. package/dist/server/ws.d.ts +85 -0
  303. package/dist/server/ws.js +218 -0
  304. package/dist/server/ws.js.map +1 -0
  305. package/dist/server/wsl.d.ts +25 -0
  306. package/dist/server/wsl.js +92 -0
  307. package/dist/server/wsl.js.map +1 -0
  308. package/dist/server-install/engine.d.ts +50 -0
  309. package/dist/server-install/engine.js +324 -0
  310. package/dist/server-install/engine.js.map +1 -0
  311. package/dist/server-install/platforms/macosx-ngrok.d.ts +6 -0
  312. package/dist/server-install/platforms/macosx-ngrok.js +345 -0
  313. package/dist/server-install/platforms/macosx-ngrok.js.map +1 -0
  314. package/dist/server-install/platforms/ubuntu-vps.d.ts +78 -0
  315. package/dist/server-install/platforms/ubuntu-vps.js +1016 -0
  316. package/dist/server-install/platforms/ubuntu-vps.js.map +1 -0
  317. package/dist/server-install/state.d.ts +52 -0
  318. package/dist/server-install/state.js +182 -0
  319. package/dist/server-install/state.js.map +1 -0
  320. package/dist/server-install/steps.d.ts +109 -0
  321. package/dist/server-install/steps.js +334 -0
  322. package/dist/server-install/steps.js.map +1 -0
  323. package/dist/server-install/strategies.d.ts +4 -0
  324. package/dist/server-install/strategies.js +20 -0
  325. package/dist/server-install/strategies.js.map +1 -0
  326. package/dist/server-install/types.d.ts +287 -0
  327. package/dist/server-install/types.js +121 -0
  328. package/dist/server-install/types.js.map +1 -0
  329. package/dist/server-install/ui.d.ts +42 -0
  330. package/dist/server-install/ui.js +130 -0
  331. package/dist/server-install/ui.js.map +1 -0
  332. package/dist/skills-banner.d.ts +22 -0
  333. package/dist/skills-banner.js +41 -0
  334. package/dist/skills-banner.js.map +1 -0
  335. package/dist/skills-remote.d.ts +84 -0
  336. package/dist/skills-remote.js +468 -0
  337. package/dist/skills-remote.js.map +1 -0
  338. package/dist/skills-update.d.ts +88 -0
  339. package/dist/skills-update.js +392 -0
  340. package/dist/skills-update.js.map +1 -0
  341. package/dist/skills.d.ts +82 -0
  342. package/dist/skills.js +251 -0
  343. package/dist/skills.js.map +1 -0
  344. package/dist/todos.d.ts +48 -0
  345. package/dist/todos.js +201 -0
  346. package/dist/todos.js.map +1 -0
  347. package/dist/ui-state.d.ts +26 -0
  348. package/dist/ui-state.js +38 -0
  349. package/dist/ui-state.js.map +1 -0
  350. package/dist/update-check.d.ts +12 -0
  351. package/dist/update-check.js +41 -0
  352. package/dist/update-check.js.map +1 -0
  353. package/dist/workflows/load.d.ts +15 -0
  354. package/dist/workflows/load.js +56 -0
  355. package/dist/workflows/load.js.map +1 -0
  356. package/dist/workflows/run.d.ts +758 -0
  357. package/dist/workflows/run.js +3389 -0
  358. package/dist/workflows/run.js.map +1 -0
  359. package/dist/workflows/types.d.ts +153 -0
  360. package/dist/workflows/types.js +212 -0
  361. package/dist/workflows/types.js.map +1 -0
  362. package/dist/workspace/agent-accounts.d.ts +153 -0
  363. package/dist/workspace/agent-accounts.js +304 -0
  364. package/dist/workspace/agent-accounts.js.map +1 -0
  365. package/dist/workspace/agent-profiles.d.ts +78 -0
  366. package/dist/workspace/agent-profiles.js +115 -0
  367. package/dist/workspace/agent-profiles.js.map +1 -0
  368. package/dist/workspace/config.d.ts +169 -0
  369. package/dist/workspace/config.js +379 -0
  370. package/dist/workspace/config.js.map +1 -0
  371. package/dist/workspace/migrations.d.ts +45 -0
  372. package/dist/workspace/migrations.js +147 -0
  373. package/dist/workspace/migrations.js.map +1 -0
  374. package/dist/workspace/projects-cli.d.ts +25 -0
  375. package/dist/workspace/projects-cli.js +172 -0
  376. package/dist/workspace/projects-cli.js.map +1 -0
  377. package/dist/workspace/projects.d.ts +109 -0
  378. package/dist/workspace/projects.js +250 -0
  379. package/dist/workspace/projects.js.map +1 -0
  380. package/dist/workspace/semaphore.d.ts +179 -0
  381. package/dist/workspace/semaphore.js +195 -0
  382. package/dist/workspace/semaphore.js.map +1 -0
  383. package/dist/workspace/ui-state.d.ts +34 -0
  384. package/dist/workspace/ui-state.js +53 -0
  385. package/dist/workspace/ui-state.js.map +1 -0
  386. package/package.json +70 -0
  387. package/scripts/check-pack.mjs +46 -0
  388. package/scripts/inline-contract.mjs +112 -0
  389. package/scripts/install-as-command.mjs +120 -0
  390. package/scripts/mock-claude.mjs +520 -0
  391. package/scripts/mock-pi-rpc.mjs +83 -0
  392. package/scripts/sync-readme.mjs +20 -0
  393. package/scripts/test-process-usage.mjs +47 -0
  394. package/web/dist/assets/alert-dialog-B4Ofsgv7.js +1 -0
  395. package/web/dist/assets/arrow-down-Dy8dup7j.js +1 -0
  396. package/web/dist/assets/arrow-left-BJaucbhn.js +1 -0
  397. package/web/dist/assets/bundle-mjs-BT31bpU6.js +1 -0
  398. package/web/dist/assets/centered-state-duPW0phQ.js +43 -0
  399. package/web/dist/assets/chevron-right-Be4A5TCS.js +1 -0
  400. package/web/dist/assets/chunk-BO2N2NFS-DE6qKn3r.js +131 -0
  401. package/web/dist/assets/collapsible-DdcNBdSk.js +1 -0
  402. package/web/dist/assets/commit-list-CgvN9vec.js +1 -0
  403. package/web/dist/assets/compare-variants-CQA2nd65.js +1 -0
  404. package/web/dist/assets/core-BCsw8oQw.js +12 -0
  405. package/web/dist/assets/css-BsVw1vtW.js +1 -0
  406. package/web/dist/assets/diff-B6Agp5Hl.js +3 -0
  407. package/web/dist/assets/diff-stat-BoXuGkgq.js +1 -0
  408. package/web/dist/assets/diff-view-CD8XI-fj.js +6 -0
  409. package/web/dist/assets/diff-woXpYk--.js +1 -0
  410. package/web/dist/assets/dropdown-menu-B3SYw-k5.js +1 -0
  411. package/web/dist/assets/editable-title-B-hjp5wl.js +1 -0
  412. package/web/dist/assets/ellipsis-vertical-BYwzw0xl.js +1 -0
  413. package/web/dist/assets/engine-javascript-FQvzRocB.js +141 -0
  414. package/web/dist/assets/file-BRj5eISx.js +1 -0
  415. package/web/dist/assets/folder-z4oT5981.js +1 -0
  416. package/web/dist/assets/git-toolbar-owSEkYld.js +1 -0
  417. package/web/dist/assets/github-Bz2VgRX3.js +1 -0
  418. package/web/dist/assets/go-rLFTqkRN.js +1 -0
  419. package/web/dist/assets/highlighted-body-OFNGDK62-BL-MfFgl.js +1 -0
  420. package/web/dist/assets/highlighter-CdHqIwFr.js +3 -0
  421. package/web/dist/assets/html-BY76lXLH.js +1 -0
  422. package/web/dist/assets/image-preview-h3WFluuy.js +1 -0
  423. package/web/dist/assets/index-BbcQNT92.css +2 -0
  424. package/web/dist/assets/index-EtQQQ6Kj.js +7 -0
  425. package/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  426. package/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  427. package/web/dist/assets/javascript-BgS3c2Ky.js +1 -0
  428. package/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  429. package/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  430. package/web/dist/assets/json-qhed-kSA.js +1 -0
  431. package/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
  432. package/web/dist/assets/jsx-Bz0zcwM4.js +1 -0
  433. package/web/dist/assets/lib-BQXq3kEf.js +1 -0
  434. package/web/dist/assets/lib-BxQXEXDF.js +1 -0
  435. package/web/dist/assets/markdown-BYOwaDjH.js +1 -0
  436. package/web/dist/assets/markdown-DqBKYPiB.js +2 -0
  437. package/web/dist/assets/mermaid-GHXKKRXX-C4jxqUUb.js +1 -0
  438. package/web/dist/assets/new-task-form-BdJKRBJX.js +1 -0
  439. package/web/dist/assets/pill-BQfmfpYp.js +1 -0
  440. package/web/dist/assets/project-router-DxgFZY1l.js +1 -0
  441. package/web/dist/assets/prompt-templates-B6m16gq-.js +15 -0
  442. package/web/dist/assets/python-gzcpVVnB.js +1 -0
  443. package/web/dist/assets/react-runtime-CCIEwYL0.js +9 -0
  444. package/web/dist/assets/refresh-cw-mhSpxf2a.js +1 -0
  445. package/web/dist/assets/repo-git-CUNRxR3_.js +1 -0
  446. package/web/dist/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  447. package/web/dist/assets/run-diff-DsmmDVfx.js +3 -0
  448. package/web/dist/assets/run-header-BkhrseLJ.js +1 -0
  449. package/web/dist/assets/rust-Cfkwpbl8.js +1 -0
  450. package/web/dist/assets/search-x-BqDMB2g8.js +1 -0
  451. package/web/dist/assets/shellscript-CLZ0U2zV.js +1 -0
  452. package/web/dist/assets/skill-empty-hint-BWEvTggc.js +1 -0
  453. package/web/dist/assets/skills-9oR_oHse.js +1 -0
  454. package/web/dist/assets/skills-DwIxnnWO.js +1 -0
  455. package/web/dist/assets/sparkles-DIoTQpyx.js +1 -0
  456. package/web/dist/assets/sql-BsFa4tDR.js +1 -0
  457. package/web/dist/assets/square-terminal-Cc7CuQxc.js +1 -0
  458. package/web/dist/assets/tab-link-D1fQgpmO.js +1 -0
  459. package/web/dist/assets/task-changes-BKeLlDpK.js +1 -0
  460. package/web/dist/assets/task-commits-gcEFZIa5.js +1 -0
  461. package/web/dist/assets/task-files-BGAqoXTW.js +2 -0
  462. package/web/dist/assets/task-thread-DT8aUYTS.js +9 -0
  463. package/web/dist/assets/textarea-BOVbfy5C.js +1 -0
  464. package/web/dist/assets/thread-loading-CypW73KD.js +1 -0
  465. package/web/dist/assets/toml-CcmNWLt0.js +1 -0
  466. package/web/dist/assets/trash-2-CJq6LHWn.js +1 -0
  467. package/web/dist/assets/triangle-alert-CjDFvU27.js +1 -0
  468. package/web/dist/assets/tsx-udAQXfEw.js +1 -0
  469. package/web/dist/assets/typescript-bsJCZSQ-.js +1 -0
  470. package/web/dist/assets/upload-CPDZlJeK.js +1 -0
  471. package/web/dist/assets/use-desktop-5JsLmi0a.js +1 -0
  472. package/web/dist/assets/use-submit-shortcut-CHVFevty.js +1 -0
  473. package/web/dist/assets/utils-DiO6zyJd.js +64 -0
  474. package/web/dist/assets/workflows-rQDFzWRt.js +11 -0
  475. package/web/dist/assets/yaml-rwi0_p6S.js +1 -0
  476. package/web/dist/assets/zoomable-image-COWqb11v.js +1 -0
  477. package/web/dist/index.html +80 -0
  478. package/web/dist/open-mercato.svg +11 -0
@@ -0,0 +1,250 @@
1
+ import { realpath, stat } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { basename, join, resolve, sep } from 'node:path';
4
+ import { PROJECT_TAGS_MAX, PROJECT_TAG_MAX_LENGTH } from '../contract/index.js';
5
+ import { forgeKindOfRemote, forgeWebRoot } from '../server/forge/index.js';
6
+ import { getRepoInfo } from '../server/git.js';
7
+ import { mergeWriteWorkspaceConfig, loadWorkspaceConfig, } from './config.js';
8
+ /**
9
+ * Project registry operations over `~/.cezar/config.json` (spec
10
+ * 2026-07-20-multi-project-workspace, "Project identity" + "Boot flow"):
11
+ *
12
+ * - `registerProject(root)` — realpath-normalize, dedupe by realpath, allocate
13
+ * a human-readable slug from `basename(root)`. Registration is additive and
14
+ * goes through the read-modify-write merge, so the worst race outcome
15
+ * between concurrent `cezar serve` processes is a lost `lastOpenedAt` bump —
16
+ * never a lost project.
17
+ * - `listProjects()` — registry entries + a cheap per-root status/branch probe
18
+ * behind a short TTL cache, so a sidebar render never shells `git` N times.
19
+ * - `removeProject(id)` — unregister only. It never touches any file inside
20
+ * the repo (a project's own state stays in `<repo>/.ai/cezar/`).
21
+ */
22
+ /**
23
+ * Slugs the allocator must never hand out: `default` is the reserved alias
24
+ * for the boot project, the rest are the cockpit shell's own top-level path
25
+ * segments. A repo named `default/` becomes `default-2` and can never shadow
26
+ * the alias or a route.
27
+ */
28
+ export const RESERVED_PROJECT_IDS = new Set([
29
+ 'default',
30
+ 'new',
31
+ 'settings',
32
+ 'api',
33
+ 'p',
34
+ 'assets',
35
+ ]);
36
+ /** Slug length cap — mirrors `PROJECT_ID_RE` (1 head char + up to 63 more). */
37
+ const SLUG_MAX = 64;
38
+ /**
39
+ * `basename(root)` → slug base: lowercase, runs of `[^a-z0-9-]` become one
40
+ * `-`, edge dashes trimmed so the result matches `^[a-z0-9][a-z0-9-]{0,63}$`.
41
+ * A degenerate basename (e.g. `日本語/`) falls back to `project` rather than
42
+ * ever escaping the slug shape.
43
+ */
44
+ function slugBase(root) {
45
+ const base = basename(root)
46
+ .toLowerCase()
47
+ .replace(/[^a-z0-9-]+/g, '-')
48
+ .replace(/^-+|-+$/g, '')
49
+ .slice(0, SLUG_MAX);
50
+ return base || 'project';
51
+ }
52
+ /**
53
+ * Allocate a unique slug for `root`: the slug base, deduplicated against
54
+ * `taken` ids AND the reserved ids with a numeric suffix (`api`, `api-2`,
55
+ * `api-3`, …). Suffixed candidates stay within the 64-char cap by truncating
56
+ * the base, never the suffix.
57
+ */
58
+ export function allocateProjectSlug(root, taken) {
59
+ const used = new Set(RESERVED_PROJECT_IDS);
60
+ for (const id of taken)
61
+ used.add(id);
62
+ const base = slugBase(root);
63
+ if (!used.has(base))
64
+ return base;
65
+ for (let n = 2;; n++) {
66
+ const suffix = `-${n}`;
67
+ const candidate = `${base.slice(0, SLUG_MAX - suffix.length)}${suffix}`;
68
+ if (!used.has(candidate))
69
+ return candidate;
70
+ }
71
+ }
72
+ /**
73
+ * Realpath-normalize a root: resolves symlinks and drops trailing slashes, so
74
+ * every spelling of the same directory dedupes to one registry entry. A path
75
+ * that cannot be realpath'd (doesn't exist yet, unreadable) degrades to plain
76
+ * `resolve()` — registration callers guard existence; this module never throws
77
+ * over it.
78
+ */
79
+ async function normalizeRoot(root) {
80
+ try {
81
+ return await realpath(root);
82
+ }
83
+ catch {
84
+ return resolve(root);
85
+ }
86
+ }
87
+ /** True when `path` sits inside a cezar task worktree (`…/.ai/cezar/worktrees/…`). */
88
+ function isInsideTaskWorktree(path) {
89
+ const marker = `${sep}.ai${sep}cezar${sep}worktrees${sep}`;
90
+ return `${path}${sep}`.includes(marker);
91
+ }
92
+ /**
93
+ * Registration guard (spec 2026-07-20-multi-project-workspace, "Boot flow"):
94
+ * auto-registration is suppressed — the process still serves the folder
95
+ * normally, it just doesn't pollute the registry — when the resolved
96
+ * `repoRoot` is:
97
+ *
98
+ * - inside any `…/.ai/cezar/worktrees/…` path (task worktrees and nested
99
+ * `cez` invocations — the same nesting reality the `CEZ_TODOS_FILE=''`
100
+ * guard in `workflows/run.ts` acknowledges), checked on both the raw and
101
+ * realpath'd spelling so neither a symlinked prefix nor a literal one
102
+ * slips through; or
103
+ * - the user's home directory itself (realpath-compared, so a symlinked
104
+ * `$HOME` still matches).
105
+ */
106
+ export async function shouldRegisterProject(repoRoot) {
107
+ const real = await normalizeRoot(repoRoot);
108
+ if (isInsideTaskWorktree(real) || isInsideTaskWorktree(resolve(repoRoot)))
109
+ return false;
110
+ const home = await normalizeRoot(homedir());
111
+ return real !== home;
112
+ }
113
+ /**
114
+ * Register `root` in the workspace registry (idempotent). Known root (by
115
+ * realpath) → bump its `lastOpenedAt` and return the existing entry, id and
116
+ * all. Unknown → allocate a slug and append a new entry via merge-write.
117
+ */
118
+ export async function registerProject(root, source = 'local') {
119
+ const real = await normalizeRoot(root);
120
+ const now = new Date().toISOString();
121
+ let entry;
122
+ await mergeWriteWorkspaceConfig((config) => {
123
+ const existing = config.projects.find((p) => p.root === real);
124
+ if (existing) {
125
+ existing.lastOpenedAt = now;
126
+ entry = existing;
127
+ return;
128
+ }
129
+ entry = {
130
+ id: allocateProjectSlug(real, config.projects.map((p) => p.id)),
131
+ root: real,
132
+ name: basename(real),
133
+ addedAt: now,
134
+ lastOpenedAt: now,
135
+ source,
136
+ };
137
+ config.projects.push(entry);
138
+ });
139
+ // The mutator always runs, so `entry` is always set — this satisfies TS.
140
+ if (!entry)
141
+ throw new Error('registerProject: merge-write did not run the mutator');
142
+ return entry;
143
+ }
144
+ /**
145
+ * The ONE spelling rule for project tags — applied on every write, never on read.
146
+ *
147
+ * Trimmed, empties dropped, over-long ones truncated, deduped CASE-INSENSITIVELY (the first
148
+ * spelling wins, so `Storefront` typed before `storefront` keeps its capital), capped at
149
+ * `PROJECT_TAGS_MAX`, and sorted so two projects tagged with the same set store and render the
150
+ * same list. Case-insensitive dedupe is what makes tags usable as a grouping key: `API` and `api`
151
+ * grouping into two columns of the same thing is the whole failure this prevents.
152
+ *
153
+ * Returns `undefined` — never `[]` — for an empty result, because the registry stores nothing for
154
+ * an untagged project and `delete entry.tags` is what the writers then do.
155
+ */
156
+ export function normalizeProjectTags(tags) {
157
+ if (!tags)
158
+ return undefined;
159
+ const bySpelling = new Map();
160
+ for (const raw of tags) {
161
+ const tag = raw.trim().slice(0, PROJECT_TAG_MAX_LENGTH);
162
+ if (!tag)
163
+ continue;
164
+ const key = tag.toLowerCase();
165
+ if (!bySpelling.has(key))
166
+ bySpelling.set(key, tag);
167
+ if (bySpelling.size >= PROJECT_TAGS_MAX)
168
+ break;
169
+ }
170
+ const normalized = [...bySpelling.values()].sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
171
+ return normalized.length > 0 ? normalized : undefined;
172
+ }
173
+ /** Probe TTL — long enough to coalesce a burst of sidebar renders, short
174
+ * enough that a deleted repo shows as `missing` on the next real look. */
175
+ const PROBE_TTL_MS = 5_000;
176
+ const probeCache = new Map();
177
+ /** Test hook: drop cached probes so status changes are visible immediately. */
178
+ export function clearProjectProbeCache() {
179
+ probeCache.clear();
180
+ }
181
+ async function computeProbe(root) {
182
+ try {
183
+ if (!(await stat(root)).isDirectory())
184
+ return { status: 'missing' };
185
+ }
186
+ catch {
187
+ return { status: 'missing' };
188
+ }
189
+ try {
190
+ // `.git` may be a dir (normal clone) or a file (worktree/submodule) —
191
+ // a bare stat covers both without shelling out.
192
+ await stat(join(root, '.git'));
193
+ }
194
+ catch {
195
+ return { status: 'not-git' };
196
+ }
197
+ // Branch and forge are best-effort garnish: getRepoInfo never throws (null
198
+ // on e.g. an unborn HEAD), and a repo without either is still status ok.
199
+ const info = await getRepoInfo(root);
200
+ const forge = forgeKindOfRemote(info?.remote);
201
+ // Free: `getRepoInfo` already ran for the branch, and the remote is already parsed for `forge`.
202
+ const repoUrl = forgeWebRoot(info?.remote);
203
+ return {
204
+ status: 'ok',
205
+ ...(info?.branch ? { branch: info.branch } : {}),
206
+ ...(forge ? { forge } : {}),
207
+ ...(repoUrl ? { repoUrl } : {}),
208
+ };
209
+ }
210
+ async function probeRoot(root) {
211
+ const cached = probeCache.get(root);
212
+ if (cached && Date.now() - cached.at < PROBE_TTL_MS)
213
+ return cached.probe;
214
+ const probe = await computeProbe(root);
215
+ probeCache.set(root, { at: Date.now(), probe });
216
+ return probe;
217
+ }
218
+ /**
219
+ * One root's `status` (+`branch`) through the same TTL cache `listProjects`
220
+ * uses. Exported for `POST /api/projects` (step 4.2): the register route
221
+ * answers with the freshly registered entry and must hand the cockpit the
222
+ * SAME shape the list route does — one project, one shape, whichever route
223
+ * produced it.
224
+ */
225
+ export async function probeProjectStatus(root) {
226
+ return probeRoot(root);
227
+ }
228
+ export async function listProjects(selector) {
229
+ const config = await loadWorkspaceConfig();
230
+ const projects = selector
231
+ ? config.projects.filter((project) => project.id === selector.projectId)
232
+ : config.projects;
233
+ return Promise.all(projects.map(async (project) => ({ ...project, ...(await probeRoot(project.root)) })));
234
+ }
235
+ /**
236
+ * Remove `id` from the registry. Returns false when no such entry exists.
237
+ * Pure unregistration: nothing inside the repo (worktrees, `.ai/cezar/`,
238
+ * run history) is touched — re-registering the same root later gets a fresh
239
+ * slug but finds all its state intact.
240
+ */
241
+ export async function removeProject(id) {
242
+ let removed = false;
243
+ await mergeWriteWorkspaceConfig((config) => {
244
+ const next = config.projects.filter((p) => p.id !== id);
245
+ removed = next.length !== config.projects.length;
246
+ config.projects = next;
247
+ });
248
+ return removed;
249
+ }
250
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/workspace/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Workspace-wide resource governance (spec 2026-07-20-multi-project-workspace,
3
+ * "Resource governance", step 2.5): `maxParallel` and `memoryLimitMb` protect
4
+ * the *host*, not a repo, so they live in `~/.cezar/config.json` `resources`
5
+ * and are enforced by ONE shared object across every `RunManager` — the boot
6
+ * path constructs a single `WorkspaceSemaphore` and threads it through
7
+ * `ProjectContexts` and the boot manager.
8
+ *
9
+ * Two jobs, deliberately fused because they cache the same file:
10
+ *
11
+ * 1. **Parallel cap** — `busy()` sums every registered manager's held slots;
12
+ * a manager's `pump()` starts queued runs only while `busy() <
13
+ * maxParallel()`. Slot accounting stays inside each manager (its
14
+ * `active + starting − waiting` count), which is what carries the #347
15
+ * exemption verbatim: a `waiting` run holds no slot, and a message into a
16
+ * waiting run resumes it immediately even when that momentarily exceeds
17
+ * the cap — a resume must never wait on other projects' runs.
18
+ * 2. **Cached resource config** — `maxParallel()`/`memoryLimitMb()` answer
19
+ * from an in-memory snapshot, NOT the file: the memory guard ticks ~every
20
+ * 2 s per manager, and N projects re-reading `~/.cezar/config.json` every
21
+ * tick is exactly what the spec forbids. `refresh()` is the single cache
22
+ * hook: boot calls it once, and `PUT /api/workspace/config` (step 2.7)
23
+ * calls it after a write — it re-reads the file and pumps every manager so
24
+ * a raised cap starts queued runs without a restart.
25
+ *
26
+ * Per-repo legacy `maxParallel`/`memoryLimitMb` keys are ignored by
27
+ * enforcement post-migration (`loadConfig` still parses them for old files;
28
+ * nothing consults them here).
29
+ */
30
+ /** The cached `resources` slice run enforcement consults. */
31
+ export interface WorkspaceResourceLimits {
32
+ /** Workspace-wide cap on concurrently *running* agent runs. */
33
+ maxParallel: number;
34
+ /** Durable monitoring sessions that do not consume active-task capacity. */
35
+ maxMonitoringSessions?: number;
36
+ /** Automatic monitoring re-check cadence in minutes. Default ON at
37
+ * `DEFAULT_MONITORING_WAKE_MINUTES`; explicit `null` means stay parked; absent means
38
+ * "this loader predates the key" and reads as the default. */
39
+ monitoringWakeIntervalMinutes?: number | null;
40
+ /** Resume a run stopped by a provider usage limit when that limit resets. Default ON. */
41
+ autoResumeOnUsageLimit?: boolean;
42
+ /** Per-task process-tree memory ceiling in MiB; null = no limit. */
43
+ memoryLimitMb: number | null;
44
+ /**
45
+ * Per-project concurrency ceilings, keyed by realpath-normalized project
46
+ * root (the registry stores normalized `root`). A root absent from the map
47
+ * inherits the workspace `maxParallel`. Optional so older `load` stubs that
48
+ * only return the resource slice keep working — an absent map means "no
49
+ * project has an override", i.e. every project inherits.
50
+ */
51
+ projectLimits?: ReadonlyMap<string, number>;
52
+ }
53
+ /**
54
+ * The two kinds of usage-limit hold an account can be under, kept apart because they bind
55
+ * different work (spec 2026-08-03-auto-resume-after-usage-limit):
56
+ *
57
+ * - `deadline` — a run is parked on a reset instant that has not arrived. The window is known to
58
+ * be shut, so this blocks EVERYTHING on that account, resumes included.
59
+ * - `inFlight` — a resume is running right now, re-testing the window. Nothing is proven yet, so
60
+ * this blocks fresh work but NOT other resumes: a resume blocked by a resume is the deadlock
61
+ * that stopped a live workspace dead.
62
+ */
63
+ export interface AccountHolds {
64
+ deadline: ReadonlySet<string>;
65
+ inFlight: ReadonlySet<string>;
66
+ }
67
+ /** One manager's seam into the shared counter. */
68
+ export interface SemaphoreParticipant {
69
+ /** Slots this manager currently holds. The #347 exemption lives in the
70
+ * participant's own accounting: `waiting` runs are already subtracted. */
71
+ busySlots(): number;
72
+ /** Kick the manager's queue — capacity may have appeared. Awaited by
73
+ * `release()` so the manager taking a freed slot has registered it before
74
+ * the next participant evaluates capacity. */
75
+ pump(): void | Promise<void>;
76
+ /** Epoch ms of this manager's oldest queued run, or null when its queue is
77
+ * empty — `release()`'s ordering key, so a freed slot goes to the
78
+ * workspace's longest-waiting run instead of whichever manager happens to
79
+ * have registered first. */
80
+ oldestQueuedAt(): number | null;
81
+ /**
82
+ * Agent accounts this participant is holding, by KIND (spec
83
+ * 2026-08-03-auto-resume-after-usage-limit, `RunManager.accountHolds`).
84
+ *
85
+ * Workspace-scoped for the same reason the parallel cap is: a limit closes an ACCOUNT, and one
86
+ * account can be driving tasks in several projects at once. Optional so a stub participant —
87
+ * and any caller that predates the hold — keeps working; absent simply holds nothing.
88
+ */
89
+ accountHolds?(): AccountHolds;
90
+ }
91
+ export interface WorkspaceSemaphoreOptions {
92
+ /** Snapshot source for `refresh()` — tests inject a stub; production keeps
93
+ * the `~/.cezar/config.json` reader. */
94
+ load?: () => Promise<WorkspaceResourceLimits>;
95
+ /** Starting cache, before any `refresh()` — defaults to the workspace
96
+ * schema's own defaults (`maxParallel: 2`, no memory limit), so a manager
97
+ * constructed without boot wiring behaves like a fresh workspace. */
98
+ initial?: Partial<WorkspaceResourceLimits>;
99
+ }
100
+ export declare class WorkspaceSemaphore {
101
+ private readonly participants;
102
+ private readonly load;
103
+ private limits;
104
+ /** A `release()` sweep is in flight — see `pendingRelease`. */
105
+ private broadcasting;
106
+ /** A slot freed DURING a sweep. The in-flight sweep may already have pumped
107
+ * the manager that should get it, so re-run rather than drop the wakeup. */
108
+ private pendingRelease;
109
+ constructor(options?: WorkspaceSemaphoreOptions);
110
+ /** Join the shared counter. Returns the unregister handle — the manager's
111
+ * `dispose()` must call it so a torn-down project stops counting. */
112
+ register(participant: SemaphoreParticipant): () => void;
113
+ /** Slots held across EVERY registered manager (waiting runs excluded by
114
+ * each participant — the #347 rule). */
115
+ busy(): number;
116
+ /** Cached workspace-wide parallel cap. */
117
+ maxParallel(): number;
118
+ maxMonitoringSessions(): number;
119
+ /** Cadence for automatic monitoring re-checks, or null when the operator chose "park
120
+ * until resumed". Deliberately NOT `?? DEFAULT`: `null` is a real user choice and
121
+ * `null ?? 5` would silently override it (#810). Only an ABSENT key — an older `load`
122
+ * stub, a partial `initial` — falls back to the shipped default. */
123
+ monitoringWakeIntervalMinutes(): number | null;
124
+ /** Whether a usage-limit stop schedules its own resume. Absent (an older `load` stub, a config
125
+ * written before the key existed) reads as ON — the shipped default. */
126
+ autoResumeOnUsageLimit(): boolean;
127
+ /** Cached per-task memory ceiling (MiB), or null for no limit. */
128
+ memoryLimitMb(): number | null;
129
+ /**
130
+ * Every agent account held across the WHOLE workspace, by kind — the union of what each manager
131
+ * reports (spec 2026-08-03-auto-resume-after-usage-limit). A `pump()` consults this before
132
+ * starting a queued run, so a limit hit in one project also stops the same account being walked
133
+ * into the wall from another.
134
+ *
135
+ * Asked live rather than cached: the underlying answer is derived from run records that change
136
+ * on every schedule, resume and cancel, and a stale snapshot here would either stall a queue
137
+ * whose window has reopened or leak a stampede through one that has not.
138
+ */
139
+ accountHolds(): AccountHolds;
140
+ /**
141
+ * A slot came free somewhere in the workspace: pump EVERY manager,
142
+ * longest-waiting-queue first.
143
+ *
144
+ * This is the counterpart to `busy()` being workspace-wide. A `RunManager`
145
+ * only ever pumps itself, so before this existed a freed slot reached
146
+ * exactly one project's queue: a run queued in project B stayed `queued`
147
+ * while project A's runs came and went, until B happened to start or finish
148
+ * a run of its own (or someone saved the workspace config). Every
149
+ * slot-freeing transition — a run settling, a session parking at `waiting`
150
+ * — routes here instead.
151
+ *
152
+ * Pumps are awaited in turn so the manager that takes the slot has it
153
+ * counted (`starting`) before the next manager evaluates capacity — two
154
+ * managers pumping concurrently could both read the same free slot and
155
+ * overshoot `maxParallel`. Ordering is best-effort fairness, not a global
156
+ * FIFO gate: a manager whose head-of-queue can't start (non-git root,
157
+ * spec 006 degradation) must never block the rest of the workspace.
158
+ */
159
+ release(): Promise<void>;
160
+ /**
161
+ * The effective per-project concurrency cap for a manager's repo root: the
162
+ * project's own `maxParallel` if set in the registry, else the workspace cap
163
+ * (`maxParallel()`). Answered from the cached snapshot — the class's
164
+ * no-per-tick-file-read invariant is preserved; the only syscall is a
165
+ * `realpathSync` to key the lookup the same way the registry normalizes
166
+ * `root` (once per `pump()`, alongside the existing `getRepoInfo` stat). A
167
+ * root with no registry entry (an ad-hoc run outside the registry) has no
168
+ * override and inherits the workspace cap.
169
+ */
170
+ projectMaxParallel(repoRoot: string): number;
171
+ /**
172
+ * The workspace resource-cache hook: re-read the config and pump every
173
+ * registered manager, so a config change takes effect without a restart.
174
+ * Called at boot and by `PUT /api/workspace/config` (step 2.7). A failed
175
+ * read keeps the last good cache — enforcement never degrades to unlimited
176
+ * because the file was momentarily unreadable.
177
+ */
178
+ refresh(): Promise<void>;
179
+ }
@@ -0,0 +1,195 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { DEFAULT_MONITORING_WAKE_MINUTES, loadWorkspaceConfig } from './config.js';
4
+ /** Realpath-normalize a root the same way the registry does
5
+ * (`workspace/projects.ts` `normalizeRoot`), but synchronously — this answers
6
+ * a manager's hot-path lookup and must not `await`. A path that cannot be
7
+ * realpath'd degrades to `resolve()`, matching the registry's own fallback. */
8
+ function normalizeRootSync(root) {
9
+ try {
10
+ return realpathSync(root);
11
+ }
12
+ catch {
13
+ return resolve(root);
14
+ }
15
+ }
16
+ const DEFAULT_LIMITS = {
17
+ maxParallel: 2,
18
+ maxMonitoringSessions: 2,
19
+ monitoringWakeIntervalMinutes: DEFAULT_MONITORING_WAKE_MINUTES,
20
+ autoResumeOnUsageLimit: true,
21
+ memoryLimitMb: null,
22
+ };
23
+ /** Production loader: the `resources` slice of `~/.cezar/config.json`
24
+ * (schema-defaulted, so a missing/corrupt file yields the zero-config
25
+ * 2 parallel / 2 monitoring / 5-minute wake / no memory cap),
26
+ * plus the per-project `maxParallel` overrides built into a root→limit map.
27
+ * The registry `root` is already realpath-normalized (`registerProject`), so
28
+ * the keys match `normalizeRootSync`'s output at lookup time. */
29
+ async function loadResourceLimits() {
30
+ const { resources, projects } = await loadWorkspaceConfig();
31
+ const projectLimits = new Map();
32
+ for (const project of projects) {
33
+ if (typeof project.maxParallel === 'number')
34
+ projectLimits.set(project.root, project.maxParallel);
35
+ }
36
+ return {
37
+ maxParallel: resources.maxParallel,
38
+ maxMonitoringSessions: resources.maxMonitoringSessions,
39
+ monitoringWakeIntervalMinutes: resources.monitoringWakeIntervalMinutes,
40
+ autoResumeOnUsageLimit: resources.autoResumeOnUsageLimit,
41
+ memoryLimitMb: resources.memoryLimitMb,
42
+ projectLimits,
43
+ };
44
+ }
45
+ export class WorkspaceSemaphore {
46
+ participants = new Set();
47
+ load;
48
+ limits;
49
+ /** A `release()` sweep is in flight — see `pendingRelease`. */
50
+ broadcasting = false;
51
+ /** A slot freed DURING a sweep. The in-flight sweep may already have pumped
52
+ * the manager that should get it, so re-run rather than drop the wakeup. */
53
+ pendingRelease = false;
54
+ constructor(options = {}) {
55
+ this.load = options.load ?? loadResourceLimits;
56
+ this.limits = { ...DEFAULT_LIMITS, ...options.initial };
57
+ }
58
+ /** Join the shared counter. Returns the unregister handle — the manager's
59
+ * `dispose()` must call it so a torn-down project stops counting. */
60
+ register(participant) {
61
+ this.participants.add(participant);
62
+ return () => this.participants.delete(participant);
63
+ }
64
+ /** Slots held across EVERY registered manager (waiting runs excluded by
65
+ * each participant — the #347 rule). */
66
+ busy() {
67
+ let total = 0;
68
+ for (const participant of this.participants)
69
+ total += participant.busySlots();
70
+ return total;
71
+ }
72
+ /** Cached workspace-wide parallel cap. */
73
+ maxParallel() {
74
+ return this.limits.maxParallel;
75
+ }
76
+ maxMonitoringSessions() {
77
+ return this.limits.maxMonitoringSessions ?? 2;
78
+ }
79
+ /** Cadence for automatic monitoring re-checks, or null when the operator chose "park
80
+ * until resumed". Deliberately NOT `?? DEFAULT`: `null` is a real user choice and
81
+ * `null ?? 5` would silently override it (#810). Only an ABSENT key — an older `load`
82
+ * stub, a partial `initial` — falls back to the shipped default. */
83
+ monitoringWakeIntervalMinutes() {
84
+ const configured = this.limits.monitoringWakeIntervalMinutes;
85
+ return configured === undefined ? DEFAULT_MONITORING_WAKE_MINUTES : configured;
86
+ }
87
+ /** Whether a usage-limit stop schedules its own resume. Absent (an older `load` stub, a config
88
+ * written before the key existed) reads as ON — the shipped default. */
89
+ autoResumeOnUsageLimit() {
90
+ return this.limits.autoResumeOnUsageLimit ?? true;
91
+ }
92
+ /** Cached per-task memory ceiling (MiB), or null for no limit. */
93
+ memoryLimitMb() {
94
+ return this.limits.memoryLimitMb;
95
+ }
96
+ /**
97
+ * Every agent account held across the WHOLE workspace, by kind — the union of what each manager
98
+ * reports (spec 2026-08-03-auto-resume-after-usage-limit). A `pump()` consults this before
99
+ * starting a queued run, so a limit hit in one project also stops the same account being walked
100
+ * into the wall from another.
101
+ *
102
+ * Asked live rather than cached: the underlying answer is derived from run records that change
103
+ * on every schedule, resume and cancel, and a stale snapshot here would either stall a queue
104
+ * whose window has reopened or leak a stampede through one that has not.
105
+ */
106
+ accountHolds() {
107
+ const deadline = new Set();
108
+ const inFlight = new Set();
109
+ for (const participant of this.participants) {
110
+ const holds = participant.accountHolds?.();
111
+ if (!holds)
112
+ continue;
113
+ for (const key of holds.deadline)
114
+ deadline.add(key);
115
+ for (const key of holds.inFlight)
116
+ inFlight.add(key);
117
+ }
118
+ return { deadline, inFlight };
119
+ }
120
+ /**
121
+ * A slot came free somewhere in the workspace: pump EVERY manager,
122
+ * longest-waiting-queue first.
123
+ *
124
+ * This is the counterpart to `busy()` being workspace-wide. A `RunManager`
125
+ * only ever pumps itself, so before this existed a freed slot reached
126
+ * exactly one project's queue: a run queued in project B stayed `queued`
127
+ * while project A's runs came and went, until B happened to start or finish
128
+ * a run of its own (or someone saved the workspace config). Every
129
+ * slot-freeing transition — a run settling, a session parking at `waiting`
130
+ * — routes here instead.
131
+ *
132
+ * Pumps are awaited in turn so the manager that takes the slot has it
133
+ * counted (`starting`) before the next manager evaluates capacity — two
134
+ * managers pumping concurrently could both read the same free slot and
135
+ * overshoot `maxParallel`. Ordering is best-effort fairness, not a global
136
+ * FIFO gate: a manager whose head-of-queue can't start (non-git root,
137
+ * spec 006 degradation) must never block the rest of the workspace.
138
+ */
139
+ async release() {
140
+ if (this.broadcasting) {
141
+ this.pendingRelease = true;
142
+ return;
143
+ }
144
+ this.broadcasting = true;
145
+ try {
146
+ do {
147
+ this.pendingRelease = false;
148
+ const ordered = [...this.participants]
149
+ .map((participant) => ({
150
+ participant,
151
+ // Empty queues sort last — they have nothing to claim the slot with.
152
+ since: participant.oldestQueuedAt() ?? Number.MAX_SAFE_INTEGER,
153
+ }))
154
+ .sort((a, b) => a.since - b.since);
155
+ for (const { participant } of ordered)
156
+ await participant.pump();
157
+ } while (this.pendingRelease);
158
+ }
159
+ finally {
160
+ this.broadcasting = false;
161
+ }
162
+ }
163
+ /**
164
+ * The effective per-project concurrency cap for a manager's repo root: the
165
+ * project's own `maxParallel` if set in the registry, else the workspace cap
166
+ * (`maxParallel()`). Answered from the cached snapshot — the class's
167
+ * no-per-tick-file-read invariant is preserved; the only syscall is a
168
+ * `realpathSync` to key the lookup the same way the registry normalizes
169
+ * `root` (once per `pump()`, alongside the existing `getRepoInfo` stat). A
170
+ * root with no registry entry (an ad-hoc run outside the registry) has no
171
+ * override and inherits the workspace cap.
172
+ */
173
+ projectMaxParallel(repoRoot) {
174
+ const override = this.limits.projectLimits?.get(normalizeRootSync(repoRoot));
175
+ return override ?? this.maxParallel();
176
+ }
177
+ /**
178
+ * The workspace resource-cache hook: re-read the config and pump every
179
+ * registered manager, so a config change takes effect without a restart.
180
+ * Called at boot and by `PUT /api/workspace/config` (step 2.7). A failed
181
+ * read keeps the last good cache — enforcement never degrades to unlimited
182
+ * because the file was momentarily unreadable.
183
+ */
184
+ async refresh() {
185
+ try {
186
+ this.limits = await this.load();
187
+ }
188
+ catch {
189
+ // keep the last good snapshot
190
+ }
191
+ // A raised cap is capacity appearing everywhere at once — same sweep.
192
+ await this.release();
193
+ }
194
+ }
195
+ //# sourceMappingURL=semaphore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semaphore.js","sourceRoot":"","sources":["../../src/workspace/semaphore.ts"],"names":[],"mappings":"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"}