firedrill-run 2.2.4 → 3.0.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 (392) hide show
  1. package/README.md +178 -22
  2. package/bin/firedrill.mjs +29 -5
  3. package/dist/assembly.json +13 -0
  4. package/dist/cli/runtime/candidate_copy.py +395 -0
  5. package/dist/cli/runtime/source_snapshot.py +391 -0
  6. package/dist/cli/src/administration.js +295 -0
  7. package/dist/cli/src/agent-changes.js +496 -0
  8. package/dist/cli/src/assessment-requests.js +67 -0
  9. package/dist/cli/src/auth.js +465 -0
  10. package/dist/cli/src/billing-commerce-contracts.js +1 -0
  11. package/dist/cli/src/billing-usage.js +227 -0
  12. package/dist/cli/src/billing-wallet-contracts.js +1 -0
  13. package/dist/cli/src/billing.js +170 -0
  14. package/dist/cli/src/bootstrap-process-lock.js +136 -0
  15. package/dist/cli/src/browser-links.js +14 -0
  16. package/dist/cli/src/campaign-controls.js +122 -0
  17. package/dist/cli/src/campaign-diagnoses.js +118 -0
  18. package/dist/cli/src/campaign-reports.js +1215 -0
  19. package/dist/cli/src/campaign-world.js +156 -0
  20. package/dist/cli/src/candidate-copy.js +376 -0
  21. package/dist/cli/src/catalog-contracts.js +1 -0
  22. package/dist/cli/src/ci-access-contracts.js +1 -0
  23. package/dist/cli/src/ci-configuration-contracts.js +1 -0
  24. package/dist/cli/src/ci-coverage.js +64 -0
  25. package/dist/cli/src/ci-delivery-contracts.js +1 -0
  26. package/dist/cli/src/ci-result-contracts.js +1 -0
  27. package/dist/cli/src/ci-run-contracts.js +1 -0
  28. package/dist/cli/src/ci-setup-proposals.js +52 -0
  29. package/dist/cli/src/company-policies.js +229 -0
  30. package/dist/cli/src/completion.js +79 -0
  31. package/dist/cli/src/configuration-intents.js +277 -0
  32. package/dist/cli/src/configuration.js +369 -0
  33. package/dist/cli/src/continuous-simulation.js +277 -0
  34. package/dist/cli/src/coordinated-checkpoints.js +133 -0
  35. package/dist/cli/src/credential-mode.js +139 -0
  36. package/dist/cli/src/credentials.js +331 -0
  37. package/dist/cli/src/credit-format.js +8 -0
  38. package/dist/cli/src/dataset-contracts.js +1 -0
  39. package/dist/cli/src/dataset-export.js +154 -0
  40. package/dist/cli/src/dataset-reads.js +37 -0
  41. package/dist/cli/src/dependency-preparation.js +239 -0
  42. package/dist/cli/src/director-tool-setup.js +104 -0
  43. package/dist/cli/src/driver-review.js +225 -0
  44. package/dist/cli/src/evaluation-authoring.js +315 -0
  45. package/dist/cli/src/evidence-bundles.js +367 -0
  46. package/dist/cli/src/execution-proposals.js +36 -0
  47. package/dist/cli/src/http.js +302 -0
  48. package/dist/cli/src/local-container-boundary.js +38 -0
  49. package/dist/cli/src/local-container-policy.js +201 -0
  50. package/dist/cli/src/local-execution-setup.js +81 -0
  51. package/dist/cli/src/local-source-basis.js +73 -0
  52. package/dist/cli/src/local-source.js +66 -0
  53. package/dist/cli/src/local-value-store.js +91 -0
  54. package/dist/cli/src/local-values.js +163 -0
  55. package/dist/cli/src/login-organizations.js +70 -0
  56. package/dist/cli/src/main.js +1622 -0
  57. package/dist/cli/src/mcp-connection.js +109 -0
  58. package/dist/cli/src/native/bindings.js +137 -0
  59. package/dist/cli/src/native/canonical.js +370 -0
  60. package/dist/cli/src/native/cloud-resources.js +942 -0
  61. package/dist/cli/src/native/companion-channel.js +421 -0
  62. package/dist/cli/src/native/companion-ipc.js +473 -0
  63. package/dist/cli/src/native/contracts.js +218 -0
  64. package/dist/cli/src/native/control-plane.js +1354 -0
  65. package/dist/cli/src/native/credit-approval.js +15 -0
  66. package/dist/cli/src/native/dependency-proxy.js +1006 -0
  67. package/dist/cli/src/native/drill-cleanup.js +115 -0
  68. package/dist/cli/src/native/drill-runner.js +1562 -0
  69. package/dist/cli/src/native/drivers/action-trace.js +210 -0
  70. package/dist/cli/src/native/drivers/function-wrapper.js +152 -0
  71. package/dist/cli/src/native/drivers/http.js +442 -0
  72. package/dist/cli/src/native/drivers/index.js +47 -0
  73. package/dist/cli/src/native/drivers/jsonl-process.js +538 -0
  74. package/dist/cli/src/native/drivers/playwright.js +600 -0
  75. package/dist/cli/src/native/drivers/signed-event.js +244 -0
  76. package/dist/cli/src/native/drivers/types.js +578 -0
  77. package/dist/cli/src/native/evidence-filter.js +255 -0
  78. package/dist/cli/src/native/isolated-access.js +241 -0
  79. package/dist/cli/src/native/library-sharing.js +220 -0
  80. package/dist/cli/src/native/local-run.js +667 -0
  81. package/dist/cli/src/native/local-secrets.js +19 -0
  82. package/dist/cli/src/native/mcp-config.js +123 -0
  83. package/dist/cli/src/native/metadata-requests.js +120 -0
  84. package/dist/cli/src/native/observations.js +1159 -0
  85. package/dist/cli/src/native/owned-groups.js +46 -0
  86. package/dist/cli/src/native/plan.js +594 -0
  87. package/dist/cli/src/native/png.js +159 -0
  88. package/dist/cli/src/native/ports.js +43 -0
  89. package/dist/cli/src/native/readiness.js +139 -0
  90. package/dist/cli/src/native/reassessments.js +206 -0
  91. package/dist/cli/src/native/redaction.js +235 -0
  92. package/dist/cli/src/native/registration.js +155 -0
  93. package/dist/cli/src/native/roots.js +110 -0
  94. package/dist/cli/src/native/run-cleanup.js +199 -0
  95. package/dist/cli/src/native/scratch.js +117 -0
  96. package/dist/cli/src/native/screenshots.js +60 -0
  97. package/dist/cli/src/native/session.js +556 -0
  98. package/dist/cli/src/native/standalone-proxy.js +580 -0
  99. package/dist/cli/src/native/standalone-renewals.js +183 -0
  100. package/dist/cli/src/native/standalone-state.js +193 -0
  101. package/dist/cli/src/native/standalone-tools.js +187 -0
  102. package/dist/cli/src/native/supervisor.js +831 -0
  103. package/dist/cli/src/native/target-auth.js +161 -0
  104. package/dist/cli/src/native/target-state.js +330 -0
  105. package/dist/cli/src/native/tool-reuse.js +364 -0
  106. package/dist/cli/src/native/tool-setups.js +336 -0
  107. package/dist/cli/src/native/world-reuse.js +288 -0
  108. package/dist/cli/src/onboarding.js +23 -0
  109. package/dist/cli/src/priority-requests.js +70 -0
  110. package/dist/cli/src/priority.js +223 -0
  111. package/dist/cli/src/prompts.js +184 -0
  112. package/dist/cli/src/real-operations.js +221 -0
  113. package/dist/cli/src/recipe-intents.js +58 -0
  114. package/dist/cli/src/recorded-context-intents.js +59 -0
  115. package/dist/cli/src/recorded-context.js +248 -0
  116. package/dist/cli/src/recordings.js +69 -0
  117. package/dist/cli/src/registration-guide.js +39 -0
  118. package/dist/cli/src/report-exports.js +213 -0
  119. package/dist/cli/src/request-input.js +47 -0
  120. package/dist/cli/src/resource-lifecycle.js +141 -0
  121. package/dist/cli/src/revision-requests.js +55 -0
  122. package/dist/cli/src/runner-abandon.js +53 -0
  123. package/dist/cli/src/runner-campaign-controls.js +262 -0
  124. package/dist/cli/src/runner-claim-reads.js +36 -0
  125. package/dist/cli/src/runner-completion.js +65 -0
  126. package/dist/cli/src/runner-configuration.js +546 -0
  127. package/dist/cli/src/runner-container.js +794 -0
  128. package/dist/cli/src/runner-evidence-erasure.js +351 -0
  129. package/dist/cli/src/runner-evidence-privacy.js +37 -0
  130. package/dist/cli/src/runner-evidence-retention.js +161 -0
  131. package/dist/cli/src/runner-evidence.js +326 -0
  132. package/dist/cli/src/runner-execute.js +92 -0
  133. package/dist/cli/src/runner-execution-deadline.js +25 -0
  134. package/dist/cli/src/runner-grants.js +307 -0
  135. package/dist/cli/src/runner-identity.js +615 -0
  136. package/dist/cli/src/runner-inputs.js +308 -0
  137. package/dist/cli/src/runner-jobs.js +49 -0
  138. package/dist/cli/src/runner-model-transport.js +392 -0
  139. package/dist/cli/src/runner-ownership.js +332 -0
  140. package/dist/cli/src/runner-process-lock.js +175 -0
  141. package/dist/cli/src/runner-runtime.js +396 -0
  142. package/dist/cli/src/runner-session-channel.js +377 -0
  143. package/dist/cli/src/runner-trial-completion.js +34 -0
  144. package/dist/cli/src/runner-trial-journal.js +358 -0
  145. package/dist/cli/src/runner-trial-live.js +393 -0
  146. package/dist/cli/src/runner-trial-protocol.js +289 -0
  147. package/dist/cli/src/runner-trial-sync.js +110 -0
  148. package/dist/cli/src/runner-trial-transfer.js +107 -0
  149. package/dist/cli/src/runner-voice.js +40 -0
  150. package/dist/cli/src/runner-world-claim.js +21 -0
  151. package/dist/cli/src/runner-world-collector.js +159 -0
  152. package/dist/cli/src/runner-world-command-evidence.js +487 -0
  153. package/dist/cli/src/runner-world-commands.js +268 -0
  154. package/dist/cli/src/runner-world-completion.js +76 -0
  155. package/dist/cli/src/runner-world-erasure.js +95 -0
  156. package/dist/cli/src/runner-world-evidence-sync.js +91 -0
  157. package/dist/cli/src/runner-world-journal.js +510 -0
  158. package/dist/cli/src/runner-world-native-filters.js +134 -0
  159. package/dist/cli/src/runner-world-observations.js +50 -0
  160. package/dist/cli/src/runner-world-session-protocol.js +134 -0
  161. package/dist/cli/src/saved-records.js +40 -0
  162. package/dist/cli/src/scenario-authoring.js +212 -0
  163. package/dist/cli/src/scenario-discovery.js +216 -0
  164. package/dist/cli/src/scenario-paths.js +68 -0
  165. package/dist/cli/src/scenario-requests.js +4 -0
  166. package/dist/cli/src/service-receipts.js +105 -0
  167. package/dist/cli/src/simple/authoring.js +270 -0
  168. package/dist/cli/src/simple/credit-approval.js +16 -0
  169. package/dist/cli/src/simple/help.js +98 -0
  170. package/dist/cli/src/simple/init.js +61 -0
  171. package/dist/cli/src/simple/library-sharing.js +414 -0
  172. package/dist/cli/src/simple/metadata-requests.js +46 -0
  173. package/dist/cli/src/simple/native-report.js +841 -0
  174. package/dist/cli/src/simple/native-tools.js +780 -0
  175. package/dist/cli/src/simple/plan-apply.js +506 -0
  176. package/dist/cli/src/simple/reassessment.js +323 -0
  177. package/dist/cli/src/simple/register.js +123 -0
  178. package/dist/cli/src/simple/run.js +122 -0
  179. package/dist/cli/src/simple/status.js +49 -0
  180. package/dist/cli/src/simple/tool-renewal.js +308 -0
  181. package/dist/cli/src/simple/tool-reuse.js +526 -0
  182. package/dist/cli/src/simple/tool-start-catalog.js +100 -0
  183. package/dist/cli/src/simple/tool-state.js +426 -0
  184. package/dist/cli/src/simple/tools-author.js +222 -0
  185. package/dist/cli/src/simple/watch.js +28 -0
  186. package/dist/cli/src/simple/world-reuse.js +586 -0
  187. package/dist/cli/src/simulation-intents.js +406 -0
  188. package/dist/cli/src/simulation-run.js +1058 -0
  189. package/dist/cli/src/source-batch.js +322 -0
  190. package/dist/cli/src/source-connection.js +451 -0
  191. package/dist/cli/src/source-runtime.js +346 -0
  192. package/dist/cli/src/source-selection-intents.js +75 -0
  193. package/dist/cli/src/source-sets.js +214 -0
  194. package/dist/cli/src/target-models.js +109 -0
  195. package/dist/cli/src/tool-catalog.js +224 -0
  196. package/dist/cli/src/tool-command-contracts.js +1 -0
  197. package/dist/cli/src/tool-command-export.js +245 -0
  198. package/dist/cli/src/tool-connection-contracts.js +1 -0
  199. package/dist/cli/src/tool-connection-reads.js +23 -0
  200. package/dist/cli/src/tool-contributions.js +58 -0
  201. package/dist/cli/src/tool-data.js +116 -0
  202. package/dist/cli/src/tool-datasets.js +176 -0
  203. package/dist/cli/src/tool-group-contracts.js +1 -0
  204. package/dist/cli/src/tool-group-reads.js +26 -0
  205. package/dist/cli/src/tool-group-state.js +147 -0
  206. package/dist/cli/src/tool-groups.js +311 -0
  207. package/dist/cli/src/tool-instances.js +186 -0
  208. package/dist/cli/src/tool-lifecycle-contracts.js +1 -0
  209. package/dist/cli/src/tool-lifecycle-reads.js +30 -0
  210. package/dist/cli/src/tool-lifecycle.js +323 -0
  211. package/dist/cli/src/tool-package-contracts.js +1 -0
  212. package/dist/cli/src/tool-package-reads.js +41 -0
  213. package/dist/cli/src/tool-records.js +53 -0
  214. package/dist/cli/src/tool-runtime.js +96 -0
  215. package/dist/cli/src/tool-state-contracts.js +1 -0
  216. package/dist/cli/src/tool-state-reads.js +31 -0
  217. package/dist/cli/src/tools.js +306 -0
  218. package/dist/cli/src/trial-actions.js +93 -0
  219. package/dist/cli/src/trial-checkpoints.js +133 -0
  220. package/dist/cli/src/trial-checks.js +70 -0
  221. package/dist/cli/src/trial-state.js +197 -0
  222. package/dist/cli/src/vault.js +266 -0
  223. package/dist/cli/src/workspace-registration.js +383 -0
  224. package/dist/cli/src/workspace-team-contracts.js +1 -0
  225. package/dist/cli/src/world-access.js +231 -0
  226. package/dist/cli/src/world-agent.js +4 -0
  227. package/dist/cli/src/world-checkpoint-scopes.js +15 -0
  228. package/dist/cli/src/world-contracts.js +6 -0
  229. package/dist/cli/src/world-creation.js +201 -0
  230. package/dist/cli/src/world-datasets.js +207 -0
  231. package/dist/cli/src/world-inspection.js +257 -0
  232. package/dist/cli/src/world-recipes.js +103 -0
  233. package/dist/cli/src/world-requests.js +241 -0
  234. package/dist/cli/src/world-session-checkpoints.js +196 -0
  235. package/dist/cli/src/world-session-lifecycle.js +207 -0
  236. package/dist/cli/src/world-session-requests.js +215 -0
  237. package/dist/cli/src/world-session-state.js +145 -0
  238. package/dist/cli/src/world-session-voice.js +66 -0
  239. package/dist/cli/src/world-sessions.js +288 -0
  240. package/dist/cli/src/world-stream.js +99 -0
  241. package/dist/cli/src/world-time-report.js +58 -0
  242. package/dist/contracts/agent-change-contracts.js +75 -0
  243. package/dist/contracts/agent-execution-contracts.js +38 -0
  244. package/dist/contracts/application-state-contracts.js +26 -0
  245. package/dist/contracts/assessment-aggregate-contracts.js +15 -0
  246. package/dist/contracts/assessment-contracts.js +74 -0
  247. package/dist/contracts/billing-commerce-contracts.js +107 -0
  248. package/dist/contracts/billing-wallet-contracts.js +43 -0
  249. package/dist/contracts/campaign-lifecycle.js +1 -0
  250. package/dist/contracts/campaign-world-contracts.js +80 -0
  251. package/dist/contracts/catalog-contracts.js +73 -0
  252. package/dist/contracts/ci-access-contracts.js +68 -0
  253. package/dist/contracts/ci-configuration-contracts.js +88 -0
  254. package/dist/contracts/ci-coverage-contracts.js +65 -0
  255. package/dist/contracts/ci-coverage-labels.js +25 -0
  256. package/dist/contracts/ci-delivery-contracts.js +61 -0
  257. package/dist/contracts/ci-result-contracts.js +103 -0
  258. package/dist/contracts/ci-run-contracts.js +51 -0
  259. package/dist/contracts/ci-setup-contracts.js +88 -0
  260. package/dist/contracts/clip-contracts.js +32 -0
  261. package/dist/contracts/comparison-contracts.js +53 -0
  262. package/dist/contracts/composite-contracts.js +34 -0
  263. package/dist/contracts/context-contracts.js +76 -0
  264. package/dist/contracts/continuation-report-contracts.js +1 -0
  265. package/dist/contracts/continuity-requirements.js +8 -0
  266. package/dist/contracts/coordinated-checkpoint-contracts.js +34 -0
  267. package/dist/contracts/dataset-contracts.js +88 -0
  268. package/dist/contracts/dependency-decision-contracts.js +36 -0
  269. package/dist/contracts/dependency-protocol-contracts.js +43 -0
  270. package/dist/contracts/director-execution.js +51 -0
  271. package/dist/contracts/driver-review-contracts.js +99 -0
  272. package/dist/contracts/evidence-contracts.js +65 -0
  273. package/dist/contracts/evidence-coverage-contracts.js +10 -0
  274. package/dist/contracts/export-contracts.js +44 -0
  275. package/dist/contracts/github-directory-contracts.js +96 -0
  276. package/dist/contracts/insight-contracts.js +11 -0
  277. package/dist/contracts/inspection-contracts.js +1 -0
  278. package/dist/contracts/local-claim-contracts.js +39 -0
  279. package/dist/contracts/local-configuration-contracts.js +7 -0
  280. package/dist/contracts/local-evidence-contracts.js +32 -0
  281. package/dist/contracts/local-grant-contracts.js +83 -0
  282. package/dist/contracts/local-input-contracts.js +19 -0
  283. package/dist/contracts/local-runner-contracts.js +42 -0
  284. package/dist/contracts/local-trial-live-contracts.js +16 -0
  285. package/dist/contracts/local-value-source-contracts.js +92 -0
  286. package/dist/contracts/local-world-native-contracts.js +8 -0
  287. package/dist/contracts/mcp-contracts.js +42 -0
  288. package/dist/contracts/media-contracts.js +28 -0
  289. package/dist/contracts/native-check-contracts.js +31 -0
  290. package/dist/contracts/native-identity-contracts.js +52 -0
  291. package/dist/contracts/onboarding-contracts.js +32 -0
  292. package/dist/contracts/performance-contracts.js +85 -0
  293. package/dist/contracts/planning-contracts.js +81 -0
  294. package/dist/contracts/real-operation-contracts.js +30 -0
  295. package/dist/contracts/recommendation-contracts.js +54 -0
  296. package/dist/contracts/report-contracts.js +1 -0
  297. package/dist/contracts/resource-lifecycle-contracts.js +57 -0
  298. package/dist/contracts/revision-contracts.js +12 -0
  299. package/dist/contracts/revision-request-contracts.js +39 -0
  300. package/dist/contracts/saved-record-contracts.js +76 -0
  301. package/dist/contracts/scenario-draft-comparison.js +91 -0
  302. package/dist/contracts/scenario-world-contracts.js +14 -0
  303. package/dist/contracts/service-contracts.js +1 -0
  304. package/dist/contracts/session-command-contracts.js +56 -0
  305. package/dist/contracts/session-contracts.js +65 -0
  306. package/dist/contracts/session-state-contracts.js +67 -0
  307. package/dist/contracts/session-voice-contracts.js +45 -0
  308. package/dist/contracts/source-set-contracts.js +26 -0
  309. package/dist/contracts/source-upload-contracts.js +22 -0
  310. package/dist/contracts/tool-command-contracts.js +57 -0
  311. package/dist/contracts/tool-connection-contracts.js +87 -0
  312. package/dist/contracts/tool-contribution-contracts.js +35 -0
  313. package/dist/contracts/tool-group-contracts.js +53 -0
  314. package/dist/contracts/tool-group-state-contracts.js +63 -0
  315. package/dist/contracts/tool-lifecycle-contracts.js +94 -0
  316. package/dist/contracts/tool-package-contracts.js +91 -0
  317. package/dist/contracts/tool-protocol-contracts.js +71 -0
  318. package/dist/contracts/tool-runtime-billing-contracts.js +28 -0
  319. package/dist/contracts/tool-setup-proposal.js +59 -0
  320. package/dist/contracts/tool-state-contracts.js +79 -0
  321. package/dist/contracts/trial-state-contracts.js +30 -0
  322. package/dist/contracts/typescript/agent-change.js +1 -0
  323. package/dist/contracts/typescript/assessment-aggregate.js +1 -0
  324. package/dist/contracts/typescript/assessment.js +1 -0
  325. package/dist/contracts/typescript/billing-commerce.js +1 -0
  326. package/dist/contracts/typescript/campaigns.js +1 -0
  327. package/dist/contracts/typescript/catalog.js +1 -0
  328. package/dist/contracts/typescript/ci-access.js +1 -0
  329. package/dist/contracts/typescript/ci-configuration.js +1 -0
  330. package/dist/contracts/typescript/ci-delivery.js +1 -0
  331. package/dist/contracts/typescript/ci-result.js +1 -0
  332. package/dist/contracts/typescript/ci-runs.js +1 -0
  333. package/dist/contracts/typescript/clips.js +1 -0
  334. package/dist/contracts/typescript/comparison.js +1 -0
  335. package/dist/contracts/typescript/composite.js +1 -0
  336. package/dist/contracts/typescript/connections.js +1 -0
  337. package/dist/contracts/typescript/context.js +1 -0
  338. package/dist/contracts/typescript/datasets.js +1 -0
  339. package/dist/contracts/typescript/evidence-coverage.js +1 -0
  340. package/dist/contracts/typescript/export.js +1 -0
  341. package/dist/contracts/typescript/github-directory.js +1 -0
  342. package/dist/contracts/typescript/insight.js +1 -0
  343. package/dist/contracts/typescript/inspection.js +1 -0
  344. package/dist/contracts/typescript/intake.js +1 -0
  345. package/dist/contracts/typescript/local-claim.js +1 -0
  346. package/dist/contracts/typescript/local-configuration.js +1 -0
  347. package/dist/contracts/typescript/local-evidence.js +1 -0
  348. package/dist/contracts/typescript/local-grant.js +1 -0
  349. package/dist/contracts/typescript/local-input.js +1 -0
  350. package/dist/contracts/typescript/local-runner.js +1 -0
  351. package/dist/contracts/typescript/local-trial-live.js +1 -0
  352. package/dist/contracts/typescript/local-value-source.js +1 -0
  353. package/dist/contracts/typescript/local-world-native.js +1 -0
  354. package/dist/contracts/typescript/mcp.js +1 -0
  355. package/dist/contracts/typescript/media.js +1 -0
  356. package/dist/contracts/typescript/native-check.js +1 -0
  357. package/dist/contracts/typescript/native-identity.js +1 -0
  358. package/dist/contracts/typescript/onboarding.js +1 -0
  359. package/dist/contracts/typescript/performance.js +1 -0
  360. package/dist/contracts/typescript/planning.js +1 -0
  361. package/dist/contracts/typescript/preparation.js +1 -0
  362. package/dist/contracts/typescript/real-operation.js +1 -0
  363. package/dist/contracts/typescript/recommendation.js +1 -0
  364. package/dist/contracts/typescript/reports.js +1 -0
  365. package/dist/contracts/typescript/resource-lifecycle.js +1 -0
  366. package/dist/contracts/typescript/saved-record.js +1 -0
  367. package/dist/contracts/typescript/scenarios.js +1 -0
  368. package/dist/contracts/typescript/services.js +1 -0
  369. package/dist/contracts/typescript/session-command.js +1 -0
  370. package/dist/contracts/typescript/session-state.js +1 -0
  371. package/dist/contracts/typescript/session-voice.js +1 -0
  372. package/dist/contracts/typescript/session.js +1 -0
  373. package/dist/contracts/typescript/tool-command.js +1 -0
  374. package/dist/contracts/typescript/tool-connection.js +1 -0
  375. package/dist/contracts/typescript/tool-contribution.js +1 -0
  376. package/dist/contracts/typescript/tool-groups.js +1 -0
  377. package/dist/contracts/typescript/tool-lifecycle.js +1 -0
  378. package/dist/contracts/typescript/tool-package.js +1 -0
  379. package/dist/contracts/typescript/tool-state.js +1 -0
  380. package/dist/contracts/typescript/trial-state.js +1 -0
  381. package/dist/contracts/typescript/vault.js +1 -0
  382. package/dist/contracts/typescript/workspace-team.js +1 -0
  383. package/dist/contracts/typescript/world-stream.js +1 -0
  384. package/dist/contracts/workspace-team-contracts.js +55 -0
  385. package/dist/contracts/world-command.js +65 -0
  386. package/dist/contracts/world-lifetime-contracts.js +74 -0
  387. package/dist/contracts/world-recipe-contracts.js +27 -0
  388. package/dist/contracts/world-stream-contracts.js +27 -0
  389. package/dist/package.json +1 -0
  390. package/package.json +16 -16
  391. package/LICENSE.md +0 -23
  392. package/PACKAGING.json +0 -50
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Metadata-free PNG for root's `client-masked-png-v1` screenshot profile
3
+ * (Plan20 W12, root `native_image_evidence.py`, 2026-11-10).
4
+ *
5
+ * Root accepts only a bounded 8-bit RGB or RGBA, non-interlaced PNG made of
6
+ * IHDR, contiguous IDAT and IEND, with nothing after IEND: no text, EXIF, color
7
+ * profile, physical size, animation or private chunk. A browser's PNG carries
8
+ * some of those, so the capture is re-encoded here: its scanlines are inflated,
9
+ * checked against the declared dimensions and filter types, and deflated again
10
+ * into one IDAT. Pixels are not changed, so this removes metadata only; it is
11
+ * not redaction. Masking happens before capture (drivers/playwright.ts).
12
+ */
13
+ import { deflateSync, inflateSync } from 'node:zlib';
14
+ /** Root's image bounds. */
15
+ export const PNG_MAX_BYTES = 2 * 1024 * 1024;
16
+ export const PNG_MAX_EDGE = 4096;
17
+ export const PNG_MAX_PIXELS = 8_000_000;
18
+ const PNG_MIN_BYTES = 45;
19
+ const MAX_INPUT_BYTES = 64 * 1024 * 1024;
20
+ const MAX_CHUNKS = 4096;
21
+ const SIGNATURE = Uint8Array.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
22
+ const CRC_TABLE = (() => {
23
+ const table = new Uint32Array(256);
24
+ for (let n = 0; n < 256; n++) {
25
+ let c = n;
26
+ for (let k = 0; k < 8; k++)
27
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
28
+ table[n] = c >>> 0;
29
+ }
30
+ return table;
31
+ })();
32
+ function crc32(parts) {
33
+ let c = 0xffffffff;
34
+ for (const part of parts)
35
+ for (let i = 0; i < part.length; i++)
36
+ c = CRC_TABLE[(c ^ part[i]) & 0xff] ^ (c >>> 8);
37
+ return (c ^ 0xffffffff) >>> 0;
38
+ }
39
+ function chunk(type, data) {
40
+ const kind = Buffer.from(type, 'latin1');
41
+ const out = Buffer.alloc(12 + data.length);
42
+ out.writeUInt32BE(data.length, 0);
43
+ kind.copy(out, 4);
44
+ Buffer.from(data.buffer, data.byteOffset, data.byteLength).copy(out, 8);
45
+ out.writeUInt32BE(crc32([kind, data]), 8 + data.length);
46
+ return out;
47
+ }
48
+ /**
49
+ * The same image as a metadata-free PNG within root's bounds, or null when the
50
+ * input is not a well-formed 8-bit RGB/RGBA non-interlaced PNG, is too large
51
+ * once re-encoded, or exceeds the dimension limits. Never throws.
52
+ */
53
+ export function metadataFreePng(input) {
54
+ try {
55
+ if (!(input instanceof Uint8Array) || input.byteLength < PNG_MIN_BYTES || input.byteLength > MAX_INPUT_BYTES)
56
+ return null;
57
+ const body = Buffer.from(input.buffer, input.byteOffset, input.byteLength);
58
+ if (!body.subarray(0, 8).equals(SIGNATURE))
59
+ return null;
60
+ let offset = 8, chunks = 0, header = null, ended = false, dataEnded = false;
61
+ let width = 0, height = 0, channels = 0;
62
+ const compressed = [];
63
+ while (offset < body.length && !ended) {
64
+ if (++chunks > MAX_CHUNKS || offset + 12 > body.length)
65
+ return null;
66
+ const size = body.readUInt32BE(offset);
67
+ const end = offset + 12 + size;
68
+ if (size > 0x7fffffff || end > body.length)
69
+ return null;
70
+ const kind = body.subarray(offset + 4, offset + 8);
71
+ const data = body.subarray(offset + 8, end - 4);
72
+ if (crc32([kind, data]) !== body.readUInt32BE(end - 4))
73
+ return null;
74
+ const name = kind.toString('latin1');
75
+ if (!/^[A-Za-z]{4}$/.test(name))
76
+ return null;
77
+ // Transparency and animation affect displayed pixels, not just metadata.
78
+ // Dropping them could expose RGB values that were previously invisible.
79
+ if (['tRNS', 'acTL', 'fcTL', 'fdAT'].includes(name))
80
+ return null;
81
+ if (compressed.length && name !== 'IDAT')
82
+ dataEnded = true;
83
+ if (chunks === 1) {
84
+ if (name !== 'IHDR' || size !== 13)
85
+ return null;
86
+ width = data.readUInt32BE(0);
87
+ height = data.readUInt32BE(4);
88
+ const [depth, color, compression, filter, interlace] = [data[8], data[9], data[10], data[11], data[12]];
89
+ if (width < 1 || height < 1 || width > PNG_MAX_EDGE || height > PNG_MAX_EDGE || width * height > PNG_MAX_PIXELS
90
+ || depth !== 8 || (color !== 2 && color !== 6) || compression !== 0 || filter !== 0 || interlace !== 0)
91
+ return null;
92
+ channels = color === 2 ? 3 : 4;
93
+ header = Buffer.from(data);
94
+ }
95
+ else if (name === 'IDAT') {
96
+ if (dataEnded)
97
+ return null;
98
+ compressed.push(data);
99
+ }
100
+ else if (name === 'IEND') {
101
+ if (size !== 0)
102
+ return null;
103
+ ended = true;
104
+ }
105
+ else if (name === 'PLTE') {
106
+ // A suggested palette for a truecolor image: optional, dropped.
107
+ }
108
+ else if (name.charCodeAt(0) < 0x61) {
109
+ // Any other critical chunk changes how the image decodes: refuse rather than guess.
110
+ return null;
111
+ }
112
+ // Ancillary chunks (text, EXIF, color profile, physical size, time, private) are dropped.
113
+ offset = end;
114
+ }
115
+ if (!ended || offset !== body.length || !header || compressed.length === 0)
116
+ return null;
117
+ const expected = height * (1 + width * channels);
118
+ const pixels = inflateSync(Buffer.concat(compressed), { maxOutputLength: expected + 1 });
119
+ if (pixels.length !== expected)
120
+ return null;
121
+ const stride = 1 + width * channels;
122
+ for (let row = 0; row < height; row++)
123
+ if (pixels[row * stride] > 4)
124
+ return null;
125
+ const out = Buffer.concat([Buffer.from(SIGNATURE), chunk('IHDR', header), chunk('IDAT', deflateSync(pixels, { level: 9 })),
126
+ chunk('IEND', new Uint8Array(0))]);
127
+ return out.length >= PNG_MIN_BYTES && out.length <= PNG_MAX_BYTES ? new Uint8Array(out) : null;
128
+ }
129
+ catch {
130
+ return null;
131
+ }
132
+ }
133
+ /** Whether bytes already have root's metadata-free shape (signature, IHDR first, one IDAT run, IEND last). */
134
+ export function isMetadataFreePng(bytes) {
135
+ if (!(bytes instanceof Uint8Array) || bytes.byteLength < PNG_MIN_BYTES || bytes.byteLength > PNG_MAX_BYTES)
136
+ return false;
137
+ const body = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
138
+ if (!body.subarray(0, 8).equals(SIGNATURE))
139
+ return false;
140
+ let offset = 8, index = 0, seenData = false, dataEnded = false;
141
+ while (offset < body.length) {
142
+ if (offset + 12 > body.length)
143
+ return false;
144
+ const size = body.readUInt32BE(offset);
145
+ const end = offset + 12 + size;
146
+ if (end > body.length)
147
+ return false;
148
+ const name = body.subarray(offset + 4, offset + 8).toString('latin1');
149
+ if (index === 0 ? name !== 'IHDR' || size !== 13 : name === 'IDAT' ? dataEnded : name !== 'IEND' || size !== 0 || !seenData || end !== body.length)
150
+ return false;
151
+ if (name === 'IDAT')
152
+ seenData = true;
153
+ else if (index > 0)
154
+ dataEnded = true;
155
+ offset = end;
156
+ index++;
157
+ }
158
+ return dataEnded;
159
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Loopback port allocation (Plan20 W09).
3
+ *
4
+ * The operating system picks a free port on 127.0.0.1; the listener is closed
5
+ * before the port is returned, so another local process could take it before the
6
+ * service binds. Readiness checks surface that case as a readiness failure.
7
+ */
8
+ import { createServer } from 'node:net';
9
+ import { CliError } from '../http.js';
10
+ const unavailable = () => new CliError('native_port_unavailable', 'A free loopback port could not be reserved. No service was started on it.');
11
+ /** Bind 127.0.0.1:0, read the assigned port, release it and return the port number. */
12
+ export async function allocateLoopbackPort(signal) {
13
+ signal?.throwIfAborted();
14
+ const server = createServer(socket => socket.destroy());
15
+ return new Promise((resolve, reject) => {
16
+ let settled = false;
17
+ const finish = (error, port = 0) => {
18
+ if (settled)
19
+ return;
20
+ settled = true;
21
+ clearTimeout(timer);
22
+ signal?.removeEventListener('abort', onAbort);
23
+ server.off('error', onError);
24
+ const done = () => error ? reject(error) : resolve(port);
25
+ if (server.listening)
26
+ server.close(() => done());
27
+ else
28
+ done();
29
+ };
30
+ const onError = () => finish(unavailable());
31
+ const onAbort = () => finish(new CliError('canceled', 'Port allocation was canceled. No service was started.', 130));
32
+ const timer = setTimeout(onError, 5000);
33
+ server.once('error', onError);
34
+ signal?.addEventListener('abort', onAbort, { once: true });
35
+ server.listen({ host: '127.0.0.1', port: 0, exclusive: true }, () => {
36
+ const address = server.address();
37
+ if (!address || typeof address !== 'object' || !Number.isSafeInteger(address.port) || address.port < 1)
38
+ finish(unavailable());
39
+ else
40
+ finish(null, address.port);
41
+ });
42
+ });
43
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Drill readiness evidence (root `execution-readiness.v1`, Plan20 FIR-492).
3
+ *
4
+ * Root admits a drill (`starting` -> `ready`) on its own, after the client
5
+ * commits one signed readiness record (role `driver.started`) and the single
6
+ * `driver.started` observation that references it. This module assembles what
7
+ * that record attests, from what this client actually observed:
8
+ * - every declared service exactly once, with its launch identity and
9
+ * ownership: launched for this drill (`owned`), already running
10
+ * (`attached`), or launched once for the campaign's local run (`owned_run`);
11
+ * - the entry service's probe in the kind root requires for the driver
12
+ * profile (the driver attests it), and for other services the 2xx status of
13
+ * their approved HTTP readiness check, or that they are running;
14
+ * - one committed `state.observed` record per local state domain, naming its
15
+ * exact declared reset.
16
+ *
17
+ * Probe digests (agreed with root on Slack 2026-11-10; signed device
18
+ * observations, not platform probes): jsonl_handshake hashes the exact stdout
19
+ * line that matched the approved readiness text, UTF-8, without its line
20
+ * terminator; function_import the exact pinned wrapper bytes (equal to the
21
+ * descriptor adapter digest), only once the wrapper started; browser_document the
22
+ * document serialization a throwaway context returned after navigating to the
23
+ * approved start path; signed_event_handshake the exact body bytes of the approved
24
+ * HTTP readiness response. Raw content is never uploaded. Nothing unobserved is
25
+ * upgraded into success: a local domain without a reset, or a service that is
26
+ * not running, refuses readiness instead. Observation-only domains are not reset
27
+ * and are not listed.
28
+ */
29
+ import { CliError } from '../http.js';
30
+ import { READINESS_MAX_RESETS, READINESS_MAX_SERVICES, nativeError } from './contracts.js';
31
+ export const READINESS_ERRORS = {
32
+ /** A declared service is not running locally when the drill must become ready. */
33
+ service_missing: 'native_readiness_service_missing',
34
+ /** A shared launched service has no local-run launch identity to report it under. */
35
+ run_service: 'native_readiness_run_service',
36
+ /** Too many services or local state domains for root's evidence inspection. */
37
+ limit: 'native_readiness_limit',
38
+ /** A local domain's reset evidence record was refused or dropped, so readiness cannot cite it. */
39
+ evidence_missing: 'native_readiness_evidence_missing',
40
+ };
41
+ /**
42
+ * The local state domains root requires reset evidence for, checked before
43
+ * anything starts: each must have a reset this client performs. A local domain
44
+ * without one (declared `unavailable`, or a fresh session that does not reset
45
+ * its kind) can never be admitted, so the drill is refused up front.
46
+ */
47
+ export function readinessDomains(descriptor, statePlan) {
48
+ if (descriptor.services.length > READINESS_MAX_SERVICES) {
49
+ throw new CliError(READINESS_ERRORS.limit, `The service admits at most ${READINESS_MAX_SERVICES} declared services per drill. No drill was started.`);
50
+ }
51
+ const actions = new Map(statePlan.actions.map((action) => [action.alias, action]));
52
+ const local = [];
53
+ for (const domain of descriptor.state_domains) {
54
+ if (domain.location !== 'local')
55
+ continue;
56
+ const action = actions.get(domain.alias);
57
+ if (!action || (action.action !== 'fresh-session' && action.action !== 'fresh-process' && action.action !== 'approved-hook')) {
58
+ throw nativeError('state_unsupported', `Local state domain "${domain.alias}" has no reset this client performs, and the service admits a drill only with reset evidence for every local domain. No drill was started.`);
59
+ }
60
+ local.push(action);
61
+ }
62
+ if (local.length > READINESS_MAX_RESETS) {
63
+ throw new CliError(READINESS_ERRORS.limit, `The service admits at most ${READINESS_MAX_RESETS} local state domains per drill. No drill was started.`);
64
+ }
65
+ return local;
66
+ }
67
+ /**
68
+ * The `state.observed` content for one local domain's reset, once services and
69
+ * hooks ran. A hook or fresh process that did not apply throws (the drill never
70
+ * claims a reset it did not see); a fresh session is applied as each session
71
+ * opens, so it is recorded as scheduled for every driver session of this drill.
72
+ */
73
+ export function resetEvidence(action, tracker, freshLaunch) {
74
+ const base = { type: 'state.reset', domain: action.alias, reset: action.reset, hook_sha256: action.descriptor_hook_sha256 };
75
+ if (action.action === 'approved-hook') {
76
+ const run = tracker.hookRuns.find((entry) => entry.domain_alias === action.alias);
77
+ if (!run || run.result !== 'applied')
78
+ throw new CliError('native_state_reset_failed', `The reset hook for "${action.alias}" did not apply. No drill step was sent.`);
79
+ return { ...base, result: 'applied', exit_code: run.exit_code, duration_ms: run.duration_ms };
80
+ }
81
+ if (action.action === 'fresh-process') {
82
+ const launchId = freshLaunch(action.service_alias);
83
+ const applied = tracker.coverage().some((entry) => entry.alias === action.alias && entry.result === 'applied');
84
+ if (!applied || !launchId) {
85
+ throw new CliError('native_state_reset_failed', `"${action.alias}" was not reset: its service did not start as a fresh copy for this drill.`);
86
+ }
87
+ return { ...base, result: 'applied', service: action.service_alias, launch_id: launchId };
88
+ }
89
+ return { ...base, result: 'scheduled', scope: 'each-driver-session' };
90
+ }
91
+ /**
92
+ * Every declared service as it stands now, in descriptor order, for the
93
+ * readiness record. Throws when one is not running or cannot be reported
94
+ * truthfully (a shared launched service outside a registered local run).
95
+ */
96
+ export function readinessServices(descriptor, plan, handles, driver, entryProbe, drillKey, runService) {
97
+ const driverOwned = new Map((driver.ownedProcesses?.() ?? []).map((item) => [item.alias, item]));
98
+ const services = [];
99
+ for (const { alias } of descriptor.services) {
100
+ const probe = (handle) => {
101
+ if (alias === descriptor.entry_service)
102
+ return entryProbe;
103
+ const ready = handle?.ready() ?? null;
104
+ return ready?.kind === 'http' && ready.status_code >= 200 && ready.status_code <= 299
105
+ ? { kind: 'http', status_code: ready.status_code } : { kind: 'process', observation: 'running' };
106
+ };
107
+ const owned = driverOwned.get(alias);
108
+ if (owned) {
109
+ if (owned.exit !== null)
110
+ throw nativeError('process_exited', `Service ${alias} exited before the drill became ready.`);
111
+ services.push({ service: alias, launch_id: owned.launch_id, ownership: 'owned', run_id: null, probe: probe(null) });
112
+ continue;
113
+ }
114
+ const handle = handles.get(alias);
115
+ if (!handle || handle.ready() === null) {
116
+ const planned = plan.services.some((service) => service.alias === alias);
117
+ throw new CliError(READINESS_ERRORS.service_missing, planned
118
+ ? `Service ${alias} is not running, so the drill cannot become ready.`
119
+ : `Declared service ${alias} is not in the approved plan, so the drill cannot become ready. Approve a plan that runs or attaches it.`);
120
+ }
121
+ if (handle.mode === 'attach') {
122
+ services.push({ service: alias, launch_id: handle.launchId, ownership: 'attached', run_id: null, probe: probe(handle) });
123
+ continue;
124
+ }
125
+ if (handle.exit() !== null)
126
+ throw nativeError('process_exited', `Service ${alias} exited before the drill became ready.`);
127
+ if (handle.drillKey === drillKey) {
128
+ services.push({ service: alias, launch_id: handle.launchId, ownership: 'owned', run_id: null, probe: probe(handle) });
129
+ continue;
130
+ }
131
+ // Launched once for the run and shared by its drills: reported only under the run's registered identity.
132
+ const run = runService(alias);
133
+ if (!run || run.launch_id !== handle.launchId) {
134
+ throw new CliError(READINESS_ERRORS.run_service, `Shared service ${alias} has no launch registered in this campaign's local run, so the drill cannot become ready.`);
135
+ }
136
+ services.push({ service: alias, launch_id: run.launch_id, ownership: 'owned_run', run_id: run.run_id, probe: probe(handle) });
137
+ }
138
+ return services;
139
+ }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Native reassessment (Plan20 R34; root `native_reassessment*.py`).
3
+ *
4
+ * A reassessment is a separately quoted and approved new evaluation of one
5
+ * finished drill's retained evidence:
6
+ * - it never invokes the target again and never charges local compute;
7
+ * - it never merges into the drill's original result or its quality cohorts;
8
+ * each reassessment is its own attempt with its own criterion results.
9
+ *
10
+ * Root reviews it under the caller's request key and freezes a quote at once.
11
+ * Nothing is reserved or evaluated until `admit` names that exact quote with the
12
+ * human's consent. A reviewed reassessment can be cancelled; an admitted one
13
+ * cannot. Writes and the request-key read belong to the member who reviewed it.
14
+ */
15
+ import { api } from '../auth.js';
16
+ import { creditApprovalPolicy, withoutCreditPolicyKeys } from './credit-approval.js';
17
+ import { CliError } from '../http.js';
18
+ import { criterionRow } from './cloud-resources.js';
19
+ export const REASSESSMENT_STATES = ['reviewed', 'evaluating', 'completed', 'cancelled'];
20
+ const PAGE = 25;
21
+ const SCHEMA = 'firedrill.native-reassessment.v1';
22
+ /** Root's own bound on one reassessment's criteria. */
23
+ const MAX_CRITERIA = 256;
24
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25
+ const SHA256 = /^[0-9a-f]{64}$/;
26
+ const RESPONSE_LIMIT = 4 * 1024 * 1024;
27
+ const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
28
+ const uuid = (value) => typeof value === 'string' && UUID.test(value);
29
+ const count = (value, min = 0) => typeof value === 'number' && Number.isSafeInteger(value) && value >= min;
30
+ const time = (value) => typeof value === 'string' && Number.isFinite(Date.parse(value));
31
+ const text = (value, max) => typeof value === 'string' && value.length >= 1 && value.length <= max;
32
+ const keys = (value) => Object.keys(value).sort().join(',');
33
+ const lower = (value) => value.toLowerCase();
34
+ const unconfirmed = (what) => new CliError('native_response_unconfirmed', `The ${what} response could not be confirmed. Nothing further was sent for it.`);
35
+ const scoped = (scope, signal) => ({ actor: scope.owner, workspace: scope.workspace, signal, maximumResponseBytes: RESPONSE_LIMIT });
36
+ const base = (scope, assignmentId) => `/api/workspaces/${scope.workspace}/native/assignments/${assignmentId}/reassessments`;
37
+ /** A UUID argument exactly as Firedrill printed it, lowercased. */
38
+ export function reassessmentId(value, label) {
39
+ if (!uuid(value))
40
+ throw new CliError('arguments_invalid', `Use the ${label} exactly as Firedrill printed it. Nothing was sent.`, 2);
41
+ return lower(value);
42
+ }
43
+ const ROW_KEYS = 'assignment_id,basis_id,completed_at,created_at,criteria_count,id,profile_changed,profile_comparison,profile_digest,quote,'
44
+ + 'request_key,source_basis_id,state';
45
+ const COMPARISONS = ['same', 'different', 'unknown'];
46
+ const QUOTE_KEYS = 'activity,credit_scale,denomination,estimated_quantities,estimated_units,execution_location,expires_at,id,maximum_units,organization_id,'
47
+ + 'resource_class,scope,scope_digest,tariff_digest,tariff_version,workspace_id';
48
+ const PAGE_KEYS = 'count,next,page,page_size,previous,results';
49
+ /**
50
+ * One reassessment exactly as root defines it:
51
+ * - this drill's assignment, re-evaluating a basis other than its own;
52
+ * - no basis or completion time while reviewed; its own basis once admitted
53
+ * (evaluating), and a completion time as well once completed. A cancelled
54
+ * one has neither (cancelled before admission) or both (stopped by root
55
+ * after admission, before every criterion finished);
56
+ * - the evaluator comparison agrees with profile_changed;
57
+ * - a managed evaluation quote in this workspace, frozen to this reassessment,
58
+ * its source basis and its evaluator profile, that never charges local compute.
59
+ * The quote scope's identity fields are checked; its digests of the original are root's.
60
+ */
61
+ function reassessmentRow(scope, assignmentId) {
62
+ return (value) => {
63
+ const quote = object(value) ? value.quote : null;
64
+ const frozen = object(quote) ? quote.scope : null;
65
+ const quantities = object(quote) ? quote.estimated_quantities : null;
66
+ const based = object(value) && value.basis_id !== null;
67
+ const done = object(value) && value.completed_at !== null;
68
+ const lifecycle = !object(value) ? false
69
+ : value.state === 'reviewed' ? !based && !done
70
+ : value.state === 'evaluating' ? based && !done
71
+ : value.state === 'completed' ? based && done
72
+ : value.state === 'cancelled' && based === done;
73
+ if (!object(value) || keys(value) !== ROW_KEYS || !uuid(value.id) || value.assignment_id !== assignmentId
74
+ || !uuid(value.source_basis_id) || !(value.basis_id === null || uuid(value.basis_id)) || !lifecycle
75
+ || (value.basis_id !== null && lower(value.basis_id) === lower(value.source_basis_id))
76
+ || !uuid(value.request_key) || !time(value.created_at) || !(value.completed_at === null || time(value.completed_at))
77
+ || typeof value.profile_changed !== 'boolean' || !COMPARISONS.includes(value.profile_comparison)
78
+ || value.profile_changed !== (value.profile_comparison === 'different')
79
+ || typeof value.profile_digest !== 'string' || !SHA256.test(value.profile_digest)
80
+ || !count(value.criteria_count, 1) || value.criteria_count > MAX_CRITERIA
81
+ || !object(quote) || withoutCreditPolicyKeys(quote) !== QUOTE_KEYS || !uuid(quote.id) || quote.workspace_id !== lower(scope.workspace)
82
+ || !uuid(quote.organization_id) || quote.activity !== 'simulation' || quote.execution_location !== 'managed'
83
+ || !text(quote.resource_class, 64) || !text(quote.tariff_version, 64) || !text(quote.denomination, 64)
84
+ || typeof quote.scope_digest !== 'string' || !SHA256.test(quote.scope_digest)
85
+ || typeof quote.tariff_digest !== 'string' || !SHA256.test(quote.tariff_digest) || !count(quote.credit_scale, 1)
86
+ || !count(quote.estimated_units) || !count(quote.maximum_units) || quote.estimated_units > quote.maximum_units || !time(quote.expires_at)
87
+ || !object(quantities) || keys(quantities) !== 'work_units' || !count(quantities.work_units, 1)
88
+ || !object(frozen) || frozen.schema !== SCHEMA || frozen.component !== 'evaluation' || frozen.reassessment_id !== value.id
89
+ || frozen.assignment_id !== assignmentId || frozen.source_basis_id !== value.source_basis_id
90
+ || frozen.local_target_compute_charged !== false
91
+ || frozen.evaluation_profile_digest !== value.profile_digest)
92
+ throw unconfirmed('reassessment');
93
+ return {
94
+ id: lower(value.id), assignment_id: assignmentId, source_basis_id: lower(value.source_basis_id),
95
+ basis_id: value.basis_id === null ? null : lower(value.basis_id), request_key: lower(value.request_key),
96
+ state: value.state, created_at: value.created_at, completed_at: value.completed_at,
97
+ profile_changed: value.profile_changed, profile_comparison: value.profile_comparison,
98
+ profile_digest: value.profile_digest, criteria_count: value.criteria_count,
99
+ quote: { ...creditApprovalPolicy(quote), id: lower(quote.id), denomination: quote.denomination, credit_scale: quote.credit_scale, estimated_units: quote.estimated_units,
100
+ maximum_units: quote.maximum_units, expires_at: quote.expires_at, resource_class: quote.resource_class, work_units: quantities.work_units },
101
+ };
102
+ };
103
+ }
104
+ /** Root's exact page envelope for a 25-row page that was asked for. */
105
+ function pageOf(raw, page, row, what) {
106
+ if (!object(raw) || keys(raw) !== PAGE_KEYS || !count(raw.count) || raw.page !== page || raw.page_size !== PAGE
107
+ || (raw.next !== null && typeof raw.next !== 'string') || (raw.previous !== null && typeof raw.previous !== 'string')
108
+ || !Array.isArray(raw.results) || raw.results.length > PAGE || (raw.next !== null) !== (page * PAGE < raw.count))
109
+ throw unconfirmed(what);
110
+ return { count: raw.count, page, next: raw.next, previous: raw.previous, results: raw.results.map(row) };
111
+ }
112
+ function pageNumber(value) {
113
+ const page = value ?? 1;
114
+ if (!count(page, 1))
115
+ throw new CliError('arguments_invalid', 'Use --page with a positive page number.', 2);
116
+ return page;
117
+ }
118
+ /** A drill's reassessments, newest first (25 per page), the reviewing member's and others'. */
119
+ export async function listReassessments(scope, input) {
120
+ const assignmentId = reassessmentId(input.assignmentId, 'assignment id');
121
+ const page = pageNumber(input.page);
122
+ const raw = await api(`${base(scope, assignmentId)}?page=${page}&page_size=${PAGE}`, scoped(scope, input.signal));
123
+ return pageOf(raw, page, reassessmentRow(scope, assignmentId), 'reassessments');
124
+ }
125
+ /** One reassessment by id. */
126
+ export async function getReassessment(scope, input) {
127
+ const assignmentId = reassessmentId(input.assignmentId, 'assignment id');
128
+ const id = reassessmentId(input.reassessmentId, 'reassessment id');
129
+ const row = reassessmentRow(scope, assignmentId)(await api(`${base(scope, assignmentId)}/${id}`, scoped(scope, input.signal)));
130
+ if (row.id !== id)
131
+ throw unconfirmed('reassessment');
132
+ return row;
133
+ }
134
+ /**
135
+ * Review a new evaluation of the drill's retained evidence from `basisId` (its
136
+ * original evaluation basis), under the caller's request key. Root freezes a
137
+ * quote; nothing is reserved or evaluated. The same key returns the same
138
+ * original review, and a different basis under it is refused by root.
139
+ */
140
+ export async function reviewReassessment(scope, input) {
141
+ const assignmentId = reassessmentId(input.assignmentId, 'assignment id');
142
+ const basisId = reassessmentId(input.basisId, 'evaluation basis id');
143
+ const requestKey = reassessmentId(input.requestKey, 'request key');
144
+ const row = reassessmentRow(scope, assignmentId)(await api(base(scope, assignmentId), {
145
+ ...scoped(scope, input.signal), method: 'POST', body: { request_key: requestKey, basis_id: basisId }
146
+ }));
147
+ if (row.request_key !== requestKey || row.source_basis_id !== basisId)
148
+ throw unconfirmed('reassessment');
149
+ return row;
150
+ }
151
+ /** The caller's original review under this key, or null when root has none (which does not prove it will never arrive). */
152
+ export async function recoverReassessment(scope, input) {
153
+ const assignmentId = reassessmentId(input.assignmentId, 'assignment id');
154
+ const requestKey = reassessmentId(input.requestKey, 'request key');
155
+ try {
156
+ const row = reassessmentRow(scope, assignmentId)(await api(`${base(scope, assignmentId)}/requests/${requestKey}`, scoped(scope, input.signal)));
157
+ if (row.request_key !== requestKey)
158
+ throw unconfirmed('reassessment');
159
+ return row;
160
+ }
161
+ catch (error) {
162
+ if (error instanceof CliError && error.httpStatus === 404)
163
+ return null;
164
+ throw error;
165
+ }
166
+ }
167
+ /**
168
+ * Admit a reviewed reassessment with exactly its quote, after the human
169
+ * approved it: root reserves up to that quote and starts the new evaluation.
170
+ * An already admitted one is returned unchanged, so a lost answer is recovered,
171
+ * never charged twice.
172
+ */
173
+ export async function admitReassessment(scope, input) {
174
+ const assignmentId = reassessmentId(input.reassessment.assignment_id, 'assignment id');
175
+ const id = reassessmentId(input.reassessment.id, 'reassessment id');
176
+ const row = reassessmentRow(scope, assignmentId)(await api(`${base(scope, assignmentId)}/${id}/admit`, {
177
+ ...scoped(scope, input.signal), method: 'POST', body: { quote_id: input.reassessment.quote.id, reassess_consent: true, credit_approval: input.creditApproval === true }
178
+ }));
179
+ if (row.id !== id || row.quote.id !== input.reassessment.quote.id || (row.state !== 'evaluating' && row.state !== 'completed')) {
180
+ throw unconfirmed('reassessment');
181
+ }
182
+ return row;
183
+ }
184
+ /** Cancel a reviewed reassessment after the human's approval. Root refuses an admitted one; nothing is undone. */
185
+ export async function cancelReassessment(scope, input) {
186
+ const assignmentId = reassessmentId(input.assignmentId, 'assignment id');
187
+ const id = reassessmentId(input.reassessmentId, 'reassessment id');
188
+ const row = reassessmentRow(scope, assignmentId)(await api(`${base(scope, assignmentId)}/${id}`, {
189
+ ...scoped(scope, input.signal), method: 'DELETE', body: { cancel_consent: true }
190
+ }));
191
+ if (row.id !== id || row.state !== 'cancelled')
192
+ throw unconfirmed('reassessment');
193
+ return row;
194
+ }
195
+ /**
196
+ * One page of a reassessment's own criterion results (25 per page), each on its
197
+ * own scale and never pooled with the original's. Empty until it is admitted,
198
+ * and empty for one that root stopped after admission.
199
+ */
200
+ export async function listReassessmentCriteria(scope, input) {
201
+ const assignmentId = reassessmentId(input.assignmentId, 'assignment id');
202
+ const id = reassessmentId(input.reassessmentId, 'reassessment id');
203
+ const page = pageNumber(input.page);
204
+ const raw = await api(`${base(scope, assignmentId)}/${id}/criteria?page=${page}&page_size=${PAGE}`, scoped(scope, input.signal));
205
+ return pageOf(raw, page, criterionRow, 'reassessment criteria');
206
+ }