cloving 1.0.1 → 1.2.0

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 (309) hide show
  1. package/README.md +251 -20
  2. package/assets/watch-fonts/fira-code-OFL.md +93 -0
  3. package/assets/watch-fonts/fira-code-latin-400-normal.woff2 +0 -0
  4. package/assets/watch-fonts/fira-code-latin-500-normal.woff2 +0 -0
  5. package/assets/watch-fonts/heebo-OFL.md +93 -0
  6. package/assets/watch-fonts/heebo-latin-500-normal.woff2 +0 -0
  7. package/assets/watch-fonts/heebo-latin-700-normal.woff2 +0 -0
  8. package/assets/watch-fonts/heebo-latin-800-normal.woff2 +0 -0
  9. package/assets/watch-fonts/manifest.json +112 -0
  10. package/assets/watch-fonts/space-grotesk-OFL.md +93 -0
  11. package/assets/watch-fonts/space-grotesk-latin-400-normal.woff2 +0 -0
  12. package/assets/watch-fonts/space-grotesk-latin-500-normal.woff2 +0 -0
  13. package/assets/watch-fonts/space-grotesk-latin-600-normal.woff2 +0 -0
  14. package/assets/watch-fonts/space-grotesk-latin-700-normal.woff2 +0 -0
  15. package/dist/src/authority/commands.d.ts +1 -0
  16. package/dist/src/authority/commands.js +33 -4
  17. package/dist/src/authority/dispatch-decision.d.ts +1 -0
  18. package/dist/src/authority/dispatch-decision.js +7 -4
  19. package/dist/src/authority/events.js +2 -2
  20. package/dist/src/authority/handoff-chain.d.ts +24 -0
  21. package/dist/src/authority/handoff-chain.js +46 -0
  22. package/dist/src/authority/reconciliation.d.ts +3 -0
  23. package/dist/src/authority/reconciliation.js +21 -5
  24. package/dist/src/authority/transitions.d.ts +1 -1
  25. package/dist/src/authority/transitions.js +5 -0
  26. package/dist/src/broker/actor/authority-queries.d.ts +4 -0
  27. package/dist/src/broker/actor/authority-queries.js +51 -2
  28. package/dist/src/broker/actor/authority-session.d.ts +2 -0
  29. package/dist/src/broker/actor/authority-session.js +3 -4
  30. package/dist/src/broker/actor/delivery-intents.d.ts +1 -0
  31. package/dist/src/broker/actor/effect-delivery.js +9 -0
  32. package/dist/src/broker/authority-admission.js +13 -5
  33. package/dist/src/chats/analysis-batches.d.ts +42 -0
  34. package/dist/src/chats/analysis-batches.js +97 -0
  35. package/dist/src/chats/analysis-checkpoint.d.ts +29 -0
  36. package/dist/src/chats/analysis-checkpoint.js +31 -0
  37. package/dist/src/chats/analysis-contract.d.ts +80 -0
  38. package/dist/src/chats/analysis-contract.js +16 -0
  39. package/dist/src/chats/analysis-data.d.ts +3 -0
  40. package/dist/src/chats/analysis-data.js +85 -0
  41. package/dist/src/chats/analysis-input.d.ts +18 -0
  42. package/dist/src/chats/analysis-input.js +97 -0
  43. package/dist/src/chats/analysis-links.d.ts +2 -0
  44. package/dist/src/chats/analysis-links.js +25 -0
  45. package/dist/src/chats/analysis-merge.d.ts +16 -0
  46. package/dist/src/chats/analysis-merge.js +134 -0
  47. package/dist/src/chats/analysis-prompt.d.ts +18 -0
  48. package/dist/src/chats/analysis-prompt.js +42 -0
  49. package/dist/src/chats/analysis-proposal.d.ts +4 -0
  50. package/dist/src/chats/analysis-proposal.js +41 -0
  51. package/dist/src/chats/analysis-provenance.d.ts +4 -0
  52. package/dist/src/chats/analysis-provenance.js +99 -0
  53. package/dist/src/chats/analysis-shape.d.ts +4 -0
  54. package/dist/src/chats/analysis-shape.js +235 -0
  55. package/dist/src/chats/analysis.d.ts +3 -0
  56. package/dist/src/chats/analysis.js +42 -0
  57. package/dist/src/chats/corpus-input.d.ts +5 -0
  58. package/dist/src/chats/corpus-input.js +288 -0
  59. package/dist/src/chats/destination.js +3 -1
  60. package/dist/src/chats/import.d.ts +8 -6
  61. package/dist/src/chats/import.js +195 -23
  62. package/dist/src/chats/input-file.d.ts +3 -0
  63. package/dist/src/chats/input-file.js +32 -0
  64. package/dist/src/chats/normalize.d.ts +11 -2
  65. package/dist/src/chats/normalize.js +18 -2
  66. package/dist/src/chats/previous-import.d.ts +5 -0
  67. package/dist/src/chats/previous-import.js +34 -0
  68. package/dist/src/chats/reader.d.ts +7 -1
  69. package/dist/src/chats/reader.js +46 -15
  70. package/dist/src/chats/redact-import.d.ts +14 -0
  71. package/dist/src/chats/redact-import.js +141 -0
  72. package/dist/src/chats/redaction.d.ts +41 -0
  73. package/dist/src/chats/redaction.js +161 -0
  74. package/dist/src/chats/reference-mapping.d.ts +16 -0
  75. package/dist/src/chats/reference-mapping.js +153 -0
  76. package/dist/src/chats/revision-input.d.ts +3 -0
  77. package/dist/src/chats/revision-input.js +180 -0
  78. package/dist/src/chats/revision.d.ts +48 -0
  79. package/dist/src/chats/revision.js +94 -0
  80. package/dist/src/chats/selection.d.ts +25 -0
  81. package/dist/src/chats/selection.js +109 -0
  82. package/dist/src/chats/source.d.ts +23 -0
  83. package/dist/src/chats/source.js +135 -0
  84. package/dist/src/chats/structure.d.ts +57 -0
  85. package/dist/src/chats/structure.js +216 -0
  86. package/dist/src/chats/workflow-generation-projection.d.ts +8 -0
  87. package/dist/src/chats/workflow-generation-projection.js +75 -0
  88. package/dist/src/chats/workflow-generation-source.d.ts +25 -0
  89. package/dist/src/chats/workflow-generation-source.js +124 -0
  90. package/dist/src/chats/workflow-generation-text.d.ts +23 -0
  91. package/dist/src/chats/workflow-generation-text.js +74 -0
  92. package/dist/src/chats/workflow-generation.d.ts +69 -0
  93. package/dist/src/chats/workflow-generation.js +142 -0
  94. package/dist/src/cli/arguments.d.ts +8 -0
  95. package/dist/src/cli/arguments.js +94 -13
  96. package/dist/src/cli/client.d.ts +1 -0
  97. package/dist/src/cli/client.js +38 -1
  98. package/dist/src/cli/commands.d.ts +3 -0
  99. package/dist/src/cli/commands.js +29 -11
  100. package/dist/src/cli/main.d.ts +2 -1
  101. package/dist/src/cli/main.js +61 -14
  102. package/dist/src/cli/render.d.ts +3 -0
  103. package/dist/src/cli/render.js +122 -7
  104. package/dist/src/cli/usage-render.d.ts +3 -0
  105. package/dist/src/cli/usage-render.js +28 -0
  106. package/dist/src/cli/usage.d.ts +3 -2
  107. package/dist/src/cli/usage.js +42 -7
  108. package/dist/src/cli/watch-actions.d.ts +10 -0
  109. package/dist/src/cli/watch-actions.js +58 -0
  110. package/dist/src/cli/watch-board-view.d.ts +44 -1
  111. package/dist/src/cli/watch-board-view.js +137 -18
  112. package/dist/src/cli/watch-board.d.ts +7 -1
  113. package/dist/src/cli/watch-board.js +48 -11
  114. package/dist/src/cli/watch-card-client.d.ts +1 -0
  115. package/dist/src/cli/watch-card-client.js +44 -0
  116. package/dist/src/cli/watch-card-forms.d.ts +2 -0
  117. package/dist/src/cli/watch-card-forms.js +33 -0
  118. package/dist/src/cli/watch-card-reply.d.ts +5 -0
  119. package/dist/src/cli/watch-card-reply.js +34 -0
  120. package/dist/src/cli/watch-card-view.d.ts +40 -0
  121. package/dist/src/cli/watch-card-view.js +86 -0
  122. package/dist/src/cli/watch-client.d.ts +1 -0
  123. package/dist/src/cli/watch-client.js +122 -0
  124. package/dist/src/cli/watch-model.d.ts +10 -4
  125. package/dist/src/cli/watch-model.js +61 -67
  126. package/dist/src/cli/watch-page.d.ts +1 -1
  127. package/dist/src/cli/watch-page.js +89 -86
  128. package/dist/src/cli/watch-phases.js +3 -3
  129. package/dist/src/cli/watch-pr-board.d.ts +3 -0
  130. package/dist/src/cli/watch-pr-board.js +26 -0
  131. package/dist/src/cli/watch-pr-command.d.ts +18 -0
  132. package/dist/src/cli/watch-pr-command.js +74 -0
  133. package/dist/src/cli/watch-pr-identity.d.ts +32 -0
  134. package/dist/src/cli/watch-pr-identity.js +87 -0
  135. package/dist/src/cli/watch-pr-observer.d.ts +20 -0
  136. package/dist/src/cli/watch-pr-observer.js +150 -0
  137. package/dist/src/cli/watch-pr-settings.d.ts +8 -0
  138. package/dist/src/cli/watch-pr-settings.js +47 -0
  139. package/dist/src/cli/watch-pull-request.d.ts +10 -0
  140. package/dist/src/cli/watch-pull-request.js +130 -0
  141. package/dist/src/cli/watch-reads.d.ts +7 -1
  142. package/dist/src/cli/watch-reads.js +44 -18
  143. package/dist/src/cli/watch-render.d.ts +29 -2
  144. package/dist/src/cli/watch-render.js +11 -3
  145. package/dist/src/cli/watch-run-input.d.ts +14 -0
  146. package/dist/src/cli/watch-run-input.js +49 -0
  147. package/dist/src/cli/watch-server.d.ts +3 -0
  148. package/dist/src/cli/watch-server.js +77 -8
  149. package/dist/src/cli/watch-start-view.d.ts +18 -0
  150. package/dist/src/cli/watch-start-view.js +77 -0
  151. package/dist/src/cli/watch-turn.d.ts +1 -0
  152. package/dist/src/cli/watch-turn.js +8 -3
  153. package/dist/src/cli/watch-usage.d.ts +6 -0
  154. package/dist/src/cli/watch-usage.js +65 -0
  155. package/dist/src/cli/watch-view.d.ts +22 -0
  156. package/dist/src/cli/watch-view.js +111 -19
  157. package/dist/src/cli.js +48 -6
  158. package/dist/src/daemon/analysis-launch.d.ts +5 -0
  159. package/dist/src/daemon/analysis-launch.js +81 -0
  160. package/dist/src/daemon/analysis-token.d.ts +6 -0
  161. package/dist/src/daemon/analysis-token.js +88 -0
  162. package/dist/src/daemon/analysis-worker.d.ts +20 -0
  163. package/dist/src/daemon/analysis-worker.js +271 -0
  164. package/dist/src/daemon/chats-batch-binding.d.ts +23 -0
  165. package/dist/src/daemon/chats-batch-binding.js +99 -0
  166. package/dist/src/daemon/chats-capture.d.ts +18 -0
  167. package/dist/src/daemon/chats-capture.js +194 -0
  168. package/dist/src/daemon/chats-checkpoints.d.ts +41 -0
  169. package/dist/src/daemon/chats-checkpoints.js +186 -0
  170. package/dist/src/daemon/chats-files.d.ts +42 -0
  171. package/dist/src/daemon/chats-files.js +252 -0
  172. package/dist/src/daemon/chats-follow-up.d.ts +38 -0
  173. package/dist/src/daemon/chats-follow-up.js +180 -0
  174. package/dist/src/daemon/chats-question.d.ts +15 -0
  175. package/dist/src/daemon/chats-question.js +93 -0
  176. package/dist/src/daemon/chats-worker.d.ts +13 -0
  177. package/dist/src/daemon/chats-worker.js +201 -0
  178. package/dist/src/daemon/claude-turn.d.ts +11 -0
  179. package/dist/src/daemon/claude-turn.js +96 -15
  180. package/dist/src/daemon/claude-worker.d.ts +2 -1
  181. package/dist/src/daemon/claude-worker.js +92 -45
  182. package/dist/src/daemon/codex-stream.js +16 -0
  183. package/dist/src/daemon/daemon.d.ts +8 -1
  184. package/dist/src/daemon/daemon.js +51 -14
  185. package/dist/src/daemon/delivery-router.js +6 -0
  186. package/dist/src/daemon/github-calls.d.ts +4 -0
  187. package/dist/src/daemon/github-calls.js +16 -7
  188. package/dist/src/daemon/github-ci.d.ts +6 -0
  189. package/dist/src/daemon/github-ci.js +170 -0
  190. package/dist/src/daemon/github-merge-call.d.ts +14 -0
  191. package/dist/src/daemon/github-merge-call.js +73 -0
  192. package/dist/src/daemon/github-merge.d.ts +3 -5
  193. package/dist/src/daemon/github-merge.js +52 -95
  194. package/dist/src/daemon/github-methods.d.ts +28 -0
  195. package/dist/src/daemon/github-methods.js +84 -16
  196. package/dist/src/daemon/github-operation.d.ts +2 -0
  197. package/dist/src/daemon/github-retry.d.ts +6 -0
  198. package/dist/src/daemon/github-retry.js +49 -0
  199. package/dist/src/daemon/github-ticket-status.d.ts +3 -0
  200. package/dist/src/daemon/github-ticket-status.js +294 -0
  201. package/dist/src/daemon/github-worker.js +2 -1
  202. package/dist/src/daemon/handoff-worker.d.ts +10 -0
  203. package/dist/src/daemon/handoff-worker.js +232 -0
  204. package/dist/src/daemon/issue-queue.d.ts +2 -0
  205. package/dist/src/daemon/issue-queue.js +186 -43
  206. package/dist/src/daemon/notify-journal.d.ts +18 -0
  207. package/dist/src/daemon/notify-journal.js +108 -0
  208. package/dist/src/daemon/notify-message.js +2 -1
  209. package/dist/src/daemon/notify.js +176 -37
  210. package/dist/src/daemon/operation-journal.d.ts +1 -0
  211. package/dist/src/daemon/operation-journal.js +4 -2
  212. package/dist/src/daemon/retrying-turn.d.ts +12 -0
  213. package/dist/src/daemon/retrying-turn.js +231 -0
  214. package/dist/src/daemon/ticket-dependency-waits.d.ts +18 -0
  215. package/dist/src/daemon/ticket-dependency-waits.js +60 -0
  216. package/dist/src/daemon/ticket-registration.d.ts +8 -4
  217. package/dist/src/daemon/ticket-registration.js +76 -22
  218. package/dist/src/daemon/ticket-source.d.ts +4 -1
  219. package/dist/src/daemon/ticket-source.js +8 -2
  220. package/dist/src/decision-visibility.d.ts +2 -0
  221. package/dist/src/decision-visibility.js +10 -0
  222. package/dist/src/execution-pin.d.ts +4 -0
  223. package/dist/src/execution-pin.js +23 -2
  224. package/dist/src/host/start-delivery.d.ts +2 -1
  225. package/dist/src/host/start-delivery.js +1 -1
  226. package/dist/src/host/step-bridge-host.d.ts +1 -0
  227. package/dist/src/host/step-bridge-host.js +16 -0
  228. package/dist/src/host/world-reconciliation.d.ts +3 -0
  229. package/dist/src/host/world-reconciliation.js +9 -0
  230. package/dist/src/host/world-runs.js +14 -1
  231. package/dist/src/issue-identity.d.ts +6 -0
  232. package/dist/src/issue-identity.js +23 -0
  233. package/dist/src/service/queue-runs.d.ts +3 -0
  234. package/dist/src/service/queue-runs.js +39 -0
  235. package/dist/src/service/registry.d.ts +8 -2
  236. package/dist/src/service/registry.js +20 -8
  237. package/dist/src/service/replies.d.ts +2 -0
  238. package/dist/src/service/run-handlers.js +54 -30
  239. package/dist/src/service/service.d.ts +3 -0
  240. package/dist/src/service/service.js +3 -1
  241. package/dist/src/service/submission-handler.d.ts +1 -0
  242. package/dist/src/service/submission-handler.js +92 -13
  243. package/dist/src/service/worker-totals.d.ts +3 -0
  244. package/dist/src/service/worker-totals.js +52 -0
  245. package/dist/src/step-bridge.d.ts +9 -0
  246. package/dist/src/steps/handoff.d.ts +2 -0
  247. package/dist/src/steps/handoff.js +13 -0
  248. package/dist/src/ticket-dependencies.d.ts +1 -0
  249. package/dist/src/ticket-dependencies.js +15 -0
  250. package/dist/src/ticket-status.d.ts +8 -0
  251. package/dist/src/ticket-status.js +48 -0
  252. package/dist/src/token-prices.d.ts +21 -0
  253. package/dist/src/token-prices.js +108 -0
  254. package/dist/src/worker-usage.d.ts +31 -0
  255. package/dist/src/worker-usage.js +44 -0
  256. package/dist/src/workflow-admission.d.ts +1 -0
  257. package/dist/src/workflow-candidate.d.ts +29 -0
  258. package/dist/src/workflow-candidate.js +60 -0
  259. package/dist/src/workflow-contracts.d.ts +4 -0
  260. package/dist/src/workflow-contracts.js +32 -5
  261. package/dist/src/workflow-declaration.d.ts +12 -1
  262. package/dist/src/workflow-declaration.js +71 -13
  263. package/dist/src/workflow-discovery.d.ts +18 -0
  264. package/dist/src/workflow-discovery.js +33 -0
  265. package/dist/src/workflow-refusals.d.ts +6 -0
  266. package/dist/src/workflow-refusals.js +39 -0
  267. package/dist/src/workflows.d.ts +3 -1
  268. package/dist/src/workflows.js +2 -0
  269. package/dist/tools/admit-workflow.d.ts +13 -0
  270. package/dist/tools/admit-workflow.js +94 -0
  271. package/dist/tools/self-host-processes.js +7 -2
  272. package/dist/tools/self-host-project.d.ts +17 -0
  273. package/dist/tools/self-host-project.js +177 -0
  274. package/dist/tools/self-host-workflows.d.ts +1 -1
  275. package/dist/tools/self-host-workflows.js +2 -2
  276. package/dist/tools/self-host.js +30 -84
  277. package/dist/tools/self-update-host.d.ts +7 -0
  278. package/dist/tools/self-update-host.js +48 -1
  279. package/dist/tools/self-update.d.ts +1 -0
  280. package/dist/tools/self-update.js +85 -13
  281. package/dist/tools/workflow-bundle-dependencies.d.ts +5 -0
  282. package/dist/tools/workflow-bundle-dependencies.js +93 -0
  283. package/dist/tools/workflow-bundles.d.ts +20 -0
  284. package/dist/tools/workflow-bundles.js +173 -0
  285. package/dist/tools/workflow-candidate-counts.d.ts +8 -0
  286. package/dist/tools/workflow-candidate-counts.js +251 -0
  287. package/dist/tools/workflow-candidate-program.d.ts +11 -0
  288. package/dist/tools/workflow-candidate-program.js +78 -0
  289. package/dist/tools/workflow-candidate-source.d.ts +6 -0
  290. package/dist/tools/workflow-candidate-source.js +107 -0
  291. package/dist/tools/workflow-candidate-syntax.d.ts +15 -0
  292. package/dist/tools/workflow-candidate-syntax.js +219 -0
  293. package/dist/tools/workflow-folder-capture.d.ts +17 -0
  294. package/dist/tools/workflow-folder-capture.js +216 -0
  295. package/dist/tools/workflow-folders.d.ts +33 -0
  296. package/dist/tools/workflow-folders.js +150 -0
  297. package/dist/tools/workflow-source-effects.d.ts +10 -0
  298. package/dist/tools/workflow-source-effects.js +213 -0
  299. package/dist/workflows/analyze-chats.d.ts +15 -0
  300. package/dist/workflows/analyze-chats.declaration.json +22 -0
  301. package/dist/workflows/analyze-chats.js +250 -0
  302. package/dist/workflows/develop-prd.js +71 -3
  303. package/dist/workflows/develop-ticket.d.ts +1 -7
  304. package/dist/workflows/develop-ticket.js +47 -141
  305. package/dist/workflows/issue-labels.d.ts +3 -1
  306. package/dist/workflows/issue-labels.js +34 -0
  307. package/dist/workflows/ticket-prompts.d.ts +35 -0
  308. package/dist/workflows/ticket-prompts.js +143 -0
  309. package/package.json +25 -5
@@ -0,0 +1,108 @@
1
+ import { priceOf, usageOf } from "./worker-usage.js";
2
+ import { record } from "./protocol.js";
3
+ export const builtInPriceTable = {
4
+ date: "2026-10-18",
5
+ source: "https://openai.com/api/pricing/",
6
+ prices: {
7
+ "gpt-6.1-sol": { input: 2, cachedInput: 0.1, output: 10 },
8
+ "gpt-6-astra": { input: 10, cachedInput: 1, output: 50 },
9
+ },
10
+ };
11
+ function tokenPrice(value) {
12
+ const fields = record(value);
13
+ const input = priceOf(fields?.["input"]);
14
+ const cachedInput = priceOf(fields?.["cachedInput"]);
15
+ const output = priceOf(fields?.["output"]);
16
+ if (input === null || cachedInput === null || output === null)
17
+ throw new Error("Invalid CLOVING_TOKEN_PRICES");
18
+ return { input, cachedInput, output };
19
+ }
20
+ export function parseTokenPrices(value) {
21
+ if (value === undefined)
22
+ return { ...builtInPriceTable.prices };
23
+ try {
24
+ const fields = record(JSON.parse(value));
25
+ if (fields === undefined)
26
+ throw new Error("Invalid CLOVING_TOKEN_PRICES");
27
+ return {
28
+ ...builtInPriceTable.prices,
29
+ ...Object.fromEntries(Object.entries(fields).map(([model, price]) => [
30
+ model,
31
+ tokenPrice(price),
32
+ ])),
33
+ };
34
+ }
35
+ catch {
36
+ throw new Error("Invalid CLOVING_TOKEN_PRICES");
37
+ }
38
+ }
39
+ export function parseFallbackModels(value) {
40
+ if (value === undefined)
41
+ return [];
42
+ try {
43
+ const models = JSON.parse(value);
44
+ if (Array.isArray(models) &&
45
+ models.length <= 3 &&
46
+ models.every((model) => typeof model === "string" && model.trim().length > 0))
47
+ return models.map(String);
48
+ }
49
+ catch {
50
+ throw new Error("The daemon did not start: invalid-fallback-models");
51
+ }
52
+ throw new Error("The daemon did not start: invalid-fallback-models");
53
+ }
54
+ export function priceForModel(prices, model) {
55
+ return model !== null && Object.hasOwn(prices, model)
56
+ ? prices[model]
57
+ : undefined;
58
+ }
59
+ function modelIndex(command) {
60
+ let selected;
61
+ const separator = command.indexOf("--", 1);
62
+ const end = separator === -1 ? command.length : separator;
63
+ for (let index = 1; index < end; index += 1) {
64
+ const argument = command[index] ?? "";
65
+ if (argument.startsWith("--model="))
66
+ selected = argument.slice(8) ? index : undefined;
67
+ if (["--model", "-m"].includes(argument)) {
68
+ const next = command[index + 1];
69
+ selected = next && !next.startsWith("-") ? index + 1 : undefined;
70
+ index += 1;
71
+ }
72
+ }
73
+ return selected;
74
+ }
75
+ export function commandModel(command) {
76
+ const index = modelIndex(command);
77
+ if (index === undefined)
78
+ return null;
79
+ const argument = command[index] ?? "";
80
+ return argument.startsWith("--model=") ? argument.slice(8) : argument;
81
+ }
82
+ export function replaceCommandModel(command, model) {
83
+ const index = modelIndex(command);
84
+ if (index === undefined)
85
+ return command;
86
+ return command.map((argument, position) => {
87
+ if (position !== index)
88
+ return argument;
89
+ return argument.startsWith("--model=") ? `--model=${model}` : model;
90
+ });
91
+ }
92
+ export function estimatedCostUsd(usage, pricing) {
93
+ const { worker, price } = pricing;
94
+ const counts = usageOf(usage);
95
+ const cached = counts.cache_read_input_tokens;
96
+ const output = counts.output_tokens;
97
+ if (price === undefined ||
98
+ counts.input_tokens === null ||
99
+ cached === null ||
100
+ output === null)
101
+ return null;
102
+ const input = counts.input_tokens - (worker === "codex" ? cached : 0);
103
+ if (input < 0)
104
+ return null;
105
+ return priceOf((input / 1_000_000) * price.input +
106
+ (cached / 1_000_000) * price.cachedInput +
107
+ (output / 1_000_000) * price.output);
108
+ }
@@ -0,0 +1,31 @@
1
+ export interface WorkerUsage {
2
+ readonly input_tokens: number | null;
3
+ readonly cache_read_input_tokens: number | null;
4
+ readonly output_tokens: number | null;
5
+ }
6
+ export interface WorkerTurnUsage {
7
+ readonly attempts?: readonly WorkerAttemptUsage[];
8
+ readonly estimatedCostUsd: number | null;
9
+ readonly operationId: string;
10
+ readonly usage: WorkerUsage;
11
+ readonly costUsd: number | null;
12
+ }
13
+ export interface WorkerAttemptUsage {
14
+ readonly attempt: number;
15
+ readonly model: string | null;
16
+ readonly usage: WorkerUsage;
17
+ readonly costUsd: number | null;
18
+ readonly estimatedCostUsd: number | null;
19
+ }
20
+ export interface WorkerTotals {
21
+ readonly estimatedCostUsd: number | null;
22
+ readonly workerTurns: readonly WorkerTurnUsage[];
23
+ readonly usage: WorkerUsage;
24
+ readonly claudeCostUsd: number | null;
25
+ }
26
+ export declare function priceOf(value: unknown): number | null;
27
+ export declare function tokenCount(value: unknown): number | null;
28
+ export declare function usageOf(value: unknown): WorkerUsage;
29
+ export declare function sumUsage(values: readonly WorkerUsage[]): WorkerUsage;
30
+ export declare function sumPrices(values: readonly (number | null)[]): number | null;
31
+ export declare function workerTotals(workerTurns: readonly WorkerTurnUsage[]): WorkerTotals;
@@ -0,0 +1,44 @@
1
+ export function priceOf(value) {
2
+ return typeof value === "number" && Number.isFinite(value) && value >= 0
3
+ ? value
4
+ : null;
5
+ }
6
+ export function tokenCount(value) {
7
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0
8
+ ? value
9
+ : null;
10
+ }
11
+ export function usageOf(value) {
12
+ const fields = typeof value === "object" && value !== null ? value : {};
13
+ return {
14
+ input_tokens: tokenCount(Reflect.get(fields, "input_tokens")),
15
+ cache_read_input_tokens: tokenCount(Reflect.get(fields, "cache_read_input_tokens")),
16
+ output_tokens: tokenCount(Reflect.get(fields, "output_tokens")),
17
+ };
18
+ }
19
+ function total(values) {
20
+ if (values.length === 0 || values.includes(null))
21
+ return null;
22
+ return tokenCount(values.reduce((sum, value) => sum + (value ?? 0), 0));
23
+ }
24
+ export function sumUsage(values) {
25
+ return {
26
+ input_tokens: total(values.map((value) => value.input_tokens)),
27
+ cache_read_input_tokens: total(values.map((value) => value.cache_read_input_tokens)),
28
+ output_tokens: total(values.map((value) => value.output_tokens)),
29
+ };
30
+ }
31
+ export function sumPrices(values) {
32
+ const prices = values.map(priceOf);
33
+ if (prices.length === 0 || prices.includes(null))
34
+ return null;
35
+ return priceOf(prices.reduce((sum, price) => sum + (price ?? 0), 0));
36
+ }
37
+ export function workerTotals(workerTurns) {
38
+ return {
39
+ workerTurns,
40
+ usage: sumUsage(workerTurns.map((turn) => turn.usage)),
41
+ claudeCostUsd: sumPrices(workerTurns.map((turn) => turn.costUsd)),
42
+ estimatedCostUsd: sumPrices(workerTurns.map((turn) => turn.estimatedCostUsd)),
43
+ };
44
+ }
@@ -27,6 +27,7 @@ export interface ExecutionManifest {
27
27
  readonly workflowId: string;
28
28
  readonly steps: readonly string[];
29
29
  readonly capabilities: readonly string[];
30
+ readonly handoffs?: readonly string[];
30
31
  readonly artifacts: Readonly<Record<string, string>>;
31
32
  readonly resources: Readonly<Record<string, string>>;
32
33
  readonly toolchain: ToolchainIdentity;
@@ -0,0 +1,29 @@
1
+ import { type WorkflowDeclaration } from "./workflow-declaration.ts";
2
+ export interface CandidateDeclaration {
3
+ readonly workflow: WorkflowDeclaration;
4
+ readonly methods: Readonly<Record<string, readonly string[]>>;
5
+ }
6
+ export interface CandidateImport {
7
+ readonly module: string;
8
+ readonly names: readonly string[];
9
+ }
10
+ export interface CandidateEffect {
11
+ readonly capability: string | null;
12
+ readonly method: string | null;
13
+ }
14
+ export interface CandidateAnalysis {
15
+ readonly imports: readonly CandidateImport[];
16
+ readonly effects: readonly CandidateEffect[];
17
+ readonly directEffects: readonly string[];
18
+ readonly unsupportedForms: readonly string[];
19
+ readonly knownCallCount: number;
20
+ readonly knownUnitTotal: number;
21
+ }
22
+ export type InstalledWorkflowExports = Readonly<Record<string, readonly string[]>>;
23
+ export type WorkflowCandidateCode = "invalid-declaration" | "forbidden-import" | "missing-export" | "unsupported-source" | "dynamic-effect" | "undeclared-effect" | "effect-limit" | "direct-effect";
24
+ export interface WorkflowCandidateInput {
25
+ readonly declaration: unknown;
26
+ readonly analysis: CandidateAnalysis;
27
+ readonly installedExports: InstalledWorkflowExports;
28
+ }
29
+ export declare function checkWorkflowCandidate(input: WorkflowCandidateInput): readonly WorkflowCandidateCode[];
@@ -0,0 +1,60 @@
1
+ import { record } from "./protocol.js";
2
+ import { isWorkflowDeclaration, } from "./workflow-declaration.js";
3
+ const workflowModules = [
4
+ "cloving/workflows",
5
+ "cloving/workflows/steps/decision-gate",
6
+ "cloving/workflows/steps/load-cycle",
7
+ "cloving/workflows/steps/protected-effect",
8
+ "cloving/workflows/steps/handoff",
9
+ ];
10
+ function isMethodList(value) {
11
+ return (Array.isArray(value) &&
12
+ value.length > 0 &&
13
+ Array.from(value).every((method) => typeof method === "string" && method.trim().length > 0) &&
14
+ new Set(value).size === value.length);
15
+ }
16
+ function isCandidateDeclaration(value) {
17
+ const fields = record(value);
18
+ if (!fields ||
19
+ Object.keys(fields).some((key) => key !== "workflow" && key !== "methods"))
20
+ return false;
21
+ const workflow = fields["workflow"];
22
+ const methods = record(fields["methods"]);
23
+ if (!isWorkflowDeclaration(workflow) || !methods)
24
+ return false;
25
+ const capabilities = workflow.capabilities;
26
+ return (Object.keys(methods).every((key) => capabilities.includes(key)) &&
27
+ capabilities.every((capability) => isMethodList(methods[capability])));
28
+ }
29
+ export function checkWorkflowCandidate(input) {
30
+ if (!isCandidateDeclaration(input.declaration))
31
+ return ["invalid-declaration"];
32
+ const { analysis, declaration, installedExports } = input;
33
+ const codes = [];
34
+ if (analysis.imports.some((entry) => !workflowModules.includes(entry.module)))
35
+ codes.push("forbidden-import");
36
+ if (analysis.imports.some((entry) => {
37
+ if (!workflowModules.includes(entry.module))
38
+ return false;
39
+ const names = installedExports[entry.module];
40
+ return (names === undefined || entry.names.some((name) => !names.includes(name)));
41
+ }))
42
+ codes.push("missing-export");
43
+ if (analysis.effects.some((effect) => effect.capability !== null &&
44
+ effect.method !== null &&
45
+ (!Object.hasOwn(declaration.methods, effect.capability) ||
46
+ !declaration.methods[effect.capability]?.includes(effect.method))))
47
+ codes.push("undeclared-effect");
48
+ if (analysis.effects.some((effect) => effect.capability === null || effect.method === null))
49
+ codes.push("dynamic-effect");
50
+ const counts = [analysis.knownCallCount, analysis.knownUnitTotal];
51
+ if (counts.some((count) => !Number.isSafeInteger(count) || count < 0))
52
+ codes.push("unsupported-source");
53
+ else if (counts.some((count) => count > declaration.workflow.effectLimit))
54
+ codes.push("effect-limit");
55
+ if (analysis.directEffects.length > 0)
56
+ codes.push("direct-effect");
57
+ if (analysis.unsupportedForms.length > 0)
58
+ codes.push("unsupported-source");
59
+ return [...new Set(codes)].sort();
60
+ }
@@ -14,6 +14,9 @@ export type CycleOutcome = {
14
14
  readonly kind: "handoff_requested";
15
15
  readonly cycleId: string;
16
16
  readonly promotionId: string;
17
+ readonly ticketStatus?: "complete" | "partial";
18
+ readonly issueUpdate?: "failed";
19
+ readonly reason?: string;
17
20
  };
18
21
  export type Validation<Value> = {
19
22
  readonly kind: "valid";
@@ -22,6 +25,7 @@ export type Validation<Value> = {
22
25
  readonly kind: "invalid";
23
26
  readonly reason: string;
24
27
  };
28
+ export declare function isPromotionId(value: unknown): value is string;
25
29
  export declare function isBlockedReason(value: unknown): value is string;
26
30
  export declare function validateDevelopmentInput(value: unknown): Validation<DevelopmentInput>;
27
31
  export declare function validateCycleOutcome(value: unknown, input: DevelopmentInput): Validation<CycleOutcome>;
@@ -1,5 +1,9 @@
1
+ import { isTicketStatus } from "./ticket-status.js";
1
2
  const identifier = /^[A-Za-z0-9._:-]{1,128}$/;
2
3
  const reason = /^\S[\s\S]{0,255}$/;
4
+ export function isPromotionId(value) {
5
+ return typeof value === "string" && identifier.test(value);
6
+ }
3
7
  export function isBlockedReason(value) {
4
8
  return typeof value === "string" && reason.test(value);
5
9
  }
@@ -39,6 +43,7 @@ const outcomes = {
39
43
  },
40
44
  handoff_requested: {
41
45
  keys: ["cycleId", "kind", "promotionId"],
46
+ optional: ["ticketStatus", "issueUpdate", "reason"],
42
47
  parse: (fields) => {
43
48
  const cycleId = textField(fields, {
44
49
  key: "cycleId",
@@ -50,12 +55,26 @@ const outcomes = {
50
55
  });
51
56
  if (cycleId === null || promotionId === null)
52
57
  return null;
53
- return { kind: "handoff_requested", cycleId, promotionId };
58
+ const ticketStatus = fields["ticketStatus"];
59
+ const issueUpdate = fields["issueUpdate"];
60
+ const reason = fields["reason"];
61
+ if (issueUpdate !== undefined && issueUpdate !== "failed")
62
+ return null;
63
+ if (ticketStatus !== undefined && !isTicketStatus(ticketStatus))
64
+ return null;
65
+ if (reason !== undefined && !isBlockedReason(reason))
66
+ return null;
67
+ return {
68
+ kind: "handoff_requested",
69
+ cycleId,
70
+ promotionId,
71
+ ...Object.fromEntries(Object.entries({ issueUpdate, ticketStatus, reason }).filter(([, value]) => value !== undefined)),
72
+ };
54
73
  },
55
74
  },
56
75
  };
57
76
  export function validateDevelopmentInput(value) {
58
- const fields = exactFields(value, ["cycleId"]);
77
+ const fields = exactFields(value, { required: ["cycleId"] });
59
78
  const cycleId = fields && textField(fields, { key: "cycleId", pattern: identifier });
60
79
  if (!cycleId)
61
80
  return { kind: "invalid", reason: "invalid-development-input" };
@@ -66,18 +85,26 @@ export function validateCycleOutcome(value, input) {
66
85
  const contract = typeof kind === "string" && Object.hasOwn(outcomes, kind)
67
86
  ? outcomes[kind]
68
87
  : undefined;
69
- const fields = contract && exactFields(value, contract.keys);
88
+ const fields = contract &&
89
+ exactFields(value, {
90
+ required: contract.keys,
91
+ optional: contract.optional ?? [],
92
+ });
70
93
  const outcome = fields && contract.parse(fields);
71
94
  if (!outcome || outcome.cycleId !== input.cycleId)
72
95
  return { kind: "invalid", reason: "invalid-cycle-outcome" };
73
96
  return { kind: "valid", value: outcome };
74
97
  }
75
- function exactFields(value, keys) {
98
+ function exactFields(value, shape) {
76
99
  if (!value || typeof value !== "object" || Array.isArray(value))
77
100
  return null;
78
101
  const fields = Object.fromEntries(Object.entries(value));
102
+ const keys = shape?.required;
103
+ const optional = shape?.optional ?? [];
79
104
  if (keys &&
80
- JSON.stringify(Object.keys(fields).sort()) !== JSON.stringify(keys))
105
+ JSON.stringify(Object.keys(fields)
106
+ .filter((key) => !optional.includes(key))
107
+ .sort()) !== JSON.stringify(keys))
81
108
  return null;
82
109
  return fields;
83
110
  }
@@ -1,11 +1,22 @@
1
1
  import type { SubmissionContract } from "./submission.ts";
2
+ export interface WorkflowStage {
3
+ readonly name: string;
4
+ readonly label: string;
5
+ readonly operations?: readonly string[];
6
+ readonly gateKinds?: readonly ("approval" | "question")[];
7
+ }
8
+ export type WorkflowStages = Readonly<Record<string, readonly WorkflowStage[]>>;
2
9
  export interface WorkflowDeclaration {
3
10
  readonly workflowId: string;
4
11
  readonly effectLimit: number;
5
- readonly capabilities: readonly ("claude" | "github")[];
12
+ readonly capabilities: readonly ("claude" | "github" | "chats")[];
6
13
  readonly input: SubmissionContract;
14
+ readonly stages?: readonly WorkflowStage[];
15
+ readonly handoffs?: readonly string[];
7
16
  }
8
17
  export interface DeclaredWorkflow extends WorkflowDeclaration {
9
18
  readonly functionName: string;
10
19
  }
20
+ export declare function isWorkflowStages(value: unknown): value is readonly WorkflowStage[];
21
+ export declare function isWorkflowHandoffs(value: unknown): value is readonly string[];
11
22
  export declare function isWorkflowDeclaration(value: unknown): value is WorkflowDeclaration;
@@ -1,6 +1,7 @@
1
1
  import { record } from "./protocol.js";
2
2
  function keys(fields, allowed) {
3
- return Object.keys(fields).every((key) => allowed.includes(key));
3
+ return (fields !== undefined &&
4
+ Object.keys(fields).every((key) => allowed.includes(key)));
4
5
  }
5
6
  function integer(value, bounds) {
6
7
  return (typeof value === "number" &&
@@ -20,8 +21,7 @@ function integerBounds(fields) {
20
21
  }
21
22
  function isField(value) {
22
23
  const fields = record(value);
23
- if (fields === undefined ||
24
- !keys(fields, ["type", "optional", "minimum", "maximum"]))
24
+ if (!keys(fields, ["type", "optional", "minimum", "maximum"]))
25
25
  return false;
26
26
  if (fields["optional"] !== undefined &&
27
27
  typeof fields["optional"] !== "boolean")
@@ -34,24 +34,82 @@ function isField(value) {
34
34
  }
35
35
  function isInput(value) {
36
36
  const input = record(value);
37
- if (input === undefined || !keys(input, ["maximumBytes", "fields"]))
37
+ if (!keys(input, ["maximumBytes", "fields"]))
38
38
  return false;
39
39
  const fields = record(input["fields"]);
40
40
  return (integer(input["maximumBytes"], { minimum: 1, maximum: 1_048_576 }) &&
41
41
  fields !== undefined &&
42
42
  Object.values(fields).every(isField));
43
43
  }
44
+ function matches(value, pattern) {
45
+ return typeof value === "string" && pattern.test(value);
46
+ }
47
+ function selectors(value, pattern) {
48
+ return (Array.isArray(value) &&
49
+ Array.from(value).every((item) => matches(item, pattern)));
50
+ }
51
+ function isStageLabel(label) {
52
+ return (typeof label === "string" &&
53
+ /^[^\p{C}\p{Zl}\p{Zp}]{1,40}$/u.test(label) &&
54
+ label.trim() === label &&
55
+ !["Other", "Done", "Stopped"].includes(label));
56
+ }
57
+ function isStage(value) {
58
+ const stage = record(value);
59
+ if (!keys(stage, ["name", "label", "operations", "gateKinds"]))
60
+ return false;
61
+ const { name, label } = stage;
62
+ const operations = Object.hasOwn(stage, "operations")
63
+ ? stage["operations"]
64
+ : [];
65
+ const gateKinds = Object.hasOwn(stage, "gateKinds") ? stage["gateKinds"] : [];
66
+ return (matches(name, /^[A-Za-z0-9-]{1,64}$/) &&
67
+ isStageLabel(label) &&
68
+ selectors(operations, /^[A-Za-z0-9._:/-]{1,128}$/) &&
69
+ selectors(gateKinds, /^(approval|question)$/) &&
70
+ operations.length + gateKinds.length > 0);
71
+ }
72
+ function unique(values) {
73
+ return new Set(values).size === values.length;
74
+ }
75
+ export function isWorkflowStages(value) {
76
+ if (!Array.isArray(value) || value.length < 1 || value.length > 12)
77
+ return false;
78
+ const stages = Array.from(value);
79
+ if (!stages.every(isStage))
80
+ return false;
81
+ return (unique(stages.map((stage) => stage.name)) &&
82
+ unique(stages.map((stage) => stage.label)) &&
83
+ unique(stages.flatMap((stage) => stage.operations ?? [])) &&
84
+ unique(stages.flatMap((stage) => stage.gateKinds ?? [])));
85
+ }
86
+ function isCapabilities(value) {
87
+ return (Array.isArray(value) &&
88
+ value.length > 0 &&
89
+ value.every((capability) => capability === "claude" ||
90
+ capability === "github" ||
91
+ capability === "chats"));
92
+ }
93
+ export function isWorkflowHandoffs(value) {
94
+ return selectors(value, /^[A-Za-z0-9-]{1,64}$/) && unique(value);
95
+ }
44
96
  export function isWorkflowDeclaration(value) {
45
97
  const declaration = record(value);
46
- if (declaration === undefined ||
47
- !keys(declaration, ["workflowId", "effectLimit", "capabilities", "input"]))
98
+ if (!keys(declaration, [
99
+ "workflowId",
100
+ "effectLimit",
101
+ "capabilities",
102
+ "input",
103
+ "stages",
104
+ "handoffs",
105
+ ]))
48
106
  return false;
49
- const { workflowId, effectLimit, capabilities, input } = declaration;
50
- return (typeof workflowId === "string" &&
51
- /^[A-Za-z0-9-]{1,64}$/.test(workflowId) &&
107
+ const { workflowId, effectLimit, capabilities, input, handoffs } = declaration;
108
+ return (matches(workflowId, /^[A-Za-z0-9-]{1,64}$/) &&
52
109
  integer(effectLimit, { minimum: 1, maximum: 100 }) &&
53
- Array.isArray(capabilities) &&
54
- capabilities.length > 0 &&
55
- capabilities.every((capability) => capability === "claude" || capability === "github") &&
56
- isInput(input));
110
+ isCapabilities(capabilities) &&
111
+ isInput(input) &&
112
+ (!Object.hasOwn(declaration, "stages") ||
113
+ isWorkflowStages(declaration["stages"])) &&
114
+ (!Object.hasOwn(declaration, "handoffs") || isWorkflowHandoffs(handoffs)));
57
115
  }
@@ -0,0 +1,18 @@
1
+ export interface WorkflowReservation {
2
+ readonly baseName?: string;
3
+ readonly workflowId?: string;
4
+ readonly functionName?: string;
5
+ }
6
+ export interface WorkflowDiscoveryIdentity {
7
+ readonly baseName: string;
8
+ readonly workflowId: string | undefined;
9
+ readonly functionNames: readonly string[];
10
+ }
11
+ export type WorkflowConflictCode = "workflow-conflict" | "bundled-name-reserved";
12
+ export declare function workflowConflicts(candidates: readonly WorkflowDiscoveryIdentity[], bundled: readonly WorkflowReservation[]): readonly (readonly WorkflowConflictCode[])[];
13
+ export declare const bundledWorkflowIds: {
14
+ readonly ticket: "develop-ticket";
15
+ readonly issue: "develop-issue";
16
+ readonly prompt: "develop-prompt";
17
+ readonly prd: "develop-prd";
18
+ };
@@ -0,0 +1,33 @@
1
+ function identityKeys(identity) {
2
+ return [
3
+ ...(identity.baseName === undefined ? [] : [`base:${identity.baseName}`]),
4
+ ...(identity.workflowId === undefined ? [] : [`id:${identity.workflowId}`]),
5
+ ...identity.functionNames.map((name) => `function:${name}`),
6
+ ];
7
+ }
8
+ export function workflowConflicts(candidates, bundled) {
9
+ const keys = candidates.map(identityKeys);
10
+ const counts = new Map();
11
+ for (const names of keys) {
12
+ for (const name of new Set(names))
13
+ counts.set(name, (counts.get(name) ?? 0) + 1);
14
+ }
15
+ const reserved = new Set(bundled.flatMap((entry) => identityKeys({
16
+ ...entry,
17
+ functionNames: entry.functionName === undefined ? [] : [entry.functionName],
18
+ })));
19
+ return keys.map((names) => {
20
+ const codes = [];
21
+ if (names.some((name) => reserved.has(name)))
22
+ codes.push("bundled-name-reserved");
23
+ if (names.some((name) => (counts.get(name) ?? 0) > 1))
24
+ codes.push("workflow-conflict");
25
+ return codes;
26
+ });
27
+ }
28
+ export const bundledWorkflowIds = {
29
+ ticket: "develop-ticket",
30
+ issue: "develop-issue",
31
+ prompt: "develop-prompt",
32
+ prd: "develop-prd",
33
+ };
@@ -0,0 +1,6 @@
1
+ export interface WorkflowRefusal {
2
+ readonly scope: "project" | "user";
3
+ readonly label: string;
4
+ readonly codes: readonly string[];
5
+ }
6
+ export declare function workflowRefusals(value: unknown): readonly WorkflowRefusal[];
@@ -0,0 +1,39 @@
1
+ import { record } from "./protocol.js";
2
+ const refusalCodes = new Set([
3
+ "invalid-declaration",
4
+ "forbidden-import",
5
+ "missing-export",
6
+ "unsupported-source",
7
+ "dynamic-effect",
8
+ "undeclared-effect",
9
+ "effect-limit",
10
+ "direct-effect",
11
+ "workflow-conflict",
12
+ "bundled-name-reserved",
13
+ "unsafe-workflow-path",
14
+ "workflow-read-failed",
15
+ "workflow-source-changed",
16
+ "compile-failed",
17
+ ]);
18
+ function refusal(value) {
19
+ const { scope, label, codes } = record(value) ?? {};
20
+ if ((scope !== "project" && scope !== "user") ||
21
+ typeof label !== "string" ||
22
+ /^(?:[A-Za-z0-9][A-Za-z0-9._-]{0,127}\.ts|file-[a-f0-9]{16}|workflows\/)$/u.exec(label)?.[0] !== label ||
23
+ !Array.isArray(codes) ||
24
+ codes.length === 0)
25
+ return [];
26
+ const known = codes.filter((code) => typeof code === "string" && refusalCodes.has(code));
27
+ if (known.length !== codes.length)
28
+ return [];
29
+ return [{ scope, label, codes: [...new Set(known)].sort() }];
30
+ }
31
+ export function workflowRefusals(value) {
32
+ if (!Array.isArray(value))
33
+ return [];
34
+ return value.flatMap(refusal).sort((left, right) => {
35
+ const a = `${left.scope}\0${left.label}`;
36
+ const b = `${right.scope}\0${right.label}`;
37
+ return a < b ? -1 : Number(a > b);
38
+ });
39
+ }
@@ -1,5 +1,7 @@
1
1
  export { loadCycle, type CycleLoad } from "./steps/load-cycle.ts";
2
2
  export { protectedEffect } from "./steps/protected-effect.ts";
3
3
  export { decisionGate } from "./steps/decision-gate.ts";
4
- export type { GateRequest, GateResult, ProtectedRequest, ProtectedResult, ProtectedScope, } from "./step-bridge.ts";
4
+ export { handoff } from "./steps/handoff.ts";
5
+ export type { GateRequest, GateResult, HandoffRequest, HandoffValue, ProtectedRequest, ProtectedResult, ProtectedScope, } from "./step-bridge.ts";
5
6
  export type { CycleOutcome, DevelopmentInput } from "./workflow-contracts.ts";
7
+ export { ticketStatus, type TicketStatus } from "./ticket-status.ts";
@@ -1,3 +1,5 @@
1
1
  export { loadCycle } from "./steps/load-cycle.js";
2
2
  export { protectedEffect } from "./steps/protected-effect.js";
3
3
  export { decisionGate } from "./steps/decision-gate.js";
4
+ export { handoff } from "./steps/handoff.js";
5
+ export { ticketStatus } from "./ticket-status.js";
@@ -0,0 +1,13 @@
1
+ import { type WorkflowCandidateCode } from "../src/workflow-candidate.ts";
2
+ import { type CandidatePackageOptions } from "./workflow-candidate-program.ts";
3
+ export type WorkflowCandidateAdmission = {
4
+ readonly kind: "admitted";
5
+ readonly artifactDigest: string;
6
+ } | {
7
+ readonly kind: "refused";
8
+ readonly codes: readonly (WorkflowCandidateCode | "compile-failed")[];
9
+ };
10
+ export declare function admitWorkflowCandidate(input: {
11
+ readonly source: string;
12
+ readonly declaration: unknown;
13
+ }, installed?: CandidatePackageOptions): Promise<WorkflowCandidateAdmission>;