firedrill-run 2.2.5 → 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,306 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { lstat, open } from 'node:fs/promises';
4
+ import { basename, resolve } from 'node:path';
5
+ import { createInterface } from 'node:readline/promises';
6
+ import { Readable } from 'node:stream';
7
+ import { api } from './auth.js';
8
+ import { CliError } from './http.js';
9
+ import { selectOne, terminalText } from './prompts.js';
10
+ import { identifier } from './world-contracts.js';
11
+ import { selectedWorkspace } from './world-access.js';
12
+ import { toolInstanceCommand } from './tool-instances.js';
13
+ import { exportToolCommand } from './tool-command-export.js';
14
+ import { toolDataCommand } from './tool-data.js';
15
+ import { toolLifecycleCommand } from './tool-lifecycle.js';
16
+ import { toolRecordsCommand } from './tool-records.js';
17
+ import { toolDatasetCommand } from './tool-datasets.js';
18
+ import { toolGroupCommand } from './tool-groups.js';
19
+ import { toolGroupStateCommand } from './tool-group-state.js';
20
+ import { toolCatalogCommand } from './tool-catalog.js';
21
+ import { toolRuntimeCommand } from './tool-runtime.js';
22
+ import { packageReads } from './tool-package-reads.js';
23
+ import { toolContributionCommand } from './tool-contributions.js';
24
+ import { nativeToolsCommand } from './simple/native-tools.js';
25
+ import { packageRead, toolVersionMatches, toolPackageMatches, toolPackageUploadDestination } from './tool-package-contracts.js';
26
+ const isInteractive = (options) => !options.json && Boolean(process.stdin.isTTY && process.stderr.isTTY);
27
+ const key = (value) => identifier(value);
28
+ const serviceKey = (value) => {
29
+ if (!/^[a-z][a-z0-9_-]{0,79}$/.test(value))
30
+ throw new CliError('arguments_invalid', 'Choose a service key from tools services.', 2);
31
+ return value;
32
+ };
33
+ function receiptText(row) {
34
+ const saved = row.implementation_id ? `\nSaved version: ${row.implementation_id}` : '';
35
+ return `Package request ${row.request_key}: ${row.state}.${saved}${row.problem ? '\n' + row.problem : ''}`
36
+ + (row.state === 'uploading' && row.can_upload ? `\nResume this original with tools upload ${row.request_key} --file <same-package.zip> --approve-tool-upload. No replacement request is needed.` : '')
37
+ + (row.state === 'inspected' ? '\nPackage inspected. No tool instance or agent was started.' : '');
38
+ }
39
+ async function chosenFile(options) {
40
+ if (options.file)
41
+ return options.file;
42
+ if (!isInteractive(options))
43
+ throw new CliError('tool_package_file_required', 'Use --file <tool-package.zip>. No file was read or uploaded.', 2);
44
+ const prompt = createInterface({ input: process.stdin, output: process.stderr, terminal: false });
45
+ try {
46
+ const path = (await prompt.question('Tool package ZIP path: ', { signal: options.signal })).trim();
47
+ if (!path || /[\u0000-\u001f\u007f]/.test(path))
48
+ throw new CliError('tool_package_file_required', 'Choose a regular ZIP file.', 2);
49
+ return path;
50
+ }
51
+ finally {
52
+ prompt.close();
53
+ }
54
+ }
55
+ async function archive(path, maximum, signal) {
56
+ if (!path.toLowerCase().endsWith('.zip'))
57
+ throw new CliError('tool_package_file_invalid', 'Choose a ZIP tool package.', 2);
58
+ const before = await lstat(resolve(path));
59
+ if (!before.isFile() || before.isSymbolicLink() || !Number.isSafeInteger(before.size) || before.size < 1 || before.size > maximum) {
60
+ throw new CliError('tool_package_file_invalid', 'Choose a regular ZIP within the configured upload capacity.', 2);
61
+ }
62
+ const file = await open(resolve(path), constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
63
+ try {
64
+ const held = await file.stat();
65
+ if (held.ino !== before.ino || held.dev !== before.dev || held.size !== before.size || held.mtimeMs !== before.mtimeMs)
66
+ throw new Error();
67
+ const digest = createHash('sha256');
68
+ for await (const chunk of file.createReadStream({ autoClose: false })) {
69
+ signal.throwIfAborted();
70
+ digest.update(chunk);
71
+ }
72
+ const after = await file.stat();
73
+ if (after.size !== held.size || after.mtimeMs !== held.mtimeMs || after.ctimeMs !== held.ctimeMs)
74
+ throw new Error();
75
+ return { file, stat: held, sha256: digest.digest('hex'), size: held.size };
76
+ }
77
+ catch {
78
+ await file.close();
79
+ throw new CliError('tool_package_file_changed', 'The selected package changed. No file was transferred.', 2);
80
+ }
81
+ }
82
+ export async function toolsCommand(args, options, output) {
83
+ let action = args[0];
84
+ if (options.category !== undefined && action !== 'catalog')
85
+ throw new CliError('arguments_invalid', 'Use --category only with tools catalog.', 2);
86
+ if (options.usageQuote !== undefined && !['start', 'add', 'reset', 'restore', 'fork', 'resume', 'extend'].includes(action))
87
+ throw new CliError('arguments_invalid', 'Use --usage-quote only for a single tool start, saved-data replacement or runtime extension. Group starts carry one quote per member in their input file.', 2);
88
+ if (options.state !== undefined && action !== 'instances')
89
+ throw new CliError('arguments_invalid', 'Use --state only with tools instances.', 2);
90
+ if (!['dataset-export', 'download'].includes(action) && (options.into !== undefined || options.approveDownload !== undefined))
91
+ throw new CliError('arguments_invalid', 'Use --into and --approve-download only with tools download or tools dataset-export.', 2);
92
+ if (action !== 'activity' && [options.before, options.after, options.anchor, options.outcome].some(one => one !== undefined)) {
93
+ throw new CliError('arguments_invalid', 'Use activity positions and outcome filters only with tools activity.', 2);
94
+ }
95
+ if (options.importStatus !== undefined && (action !== 'requests' || !['all', 'uploading', 'inspecting', 'inspected', 'rejected', 'withdrawn'].includes(options.importStatus))) {
96
+ throw new CliError('arguments_invalid', 'Use tools requests --import-status all|uploading|inspecting|inspected|rejected|withdrawn.', 2);
97
+ }
98
+ if (['contribute', 'contributions', 'contribution', 'contribution-withdraw'].includes(action))
99
+ return toolContributionCommand(args, options, output);
100
+ if (action === 'download')
101
+ return exportToolCommand(args, options, output);
102
+ if (['quote', 'extension-quote', 'extend', 'extensions', 'extension-status'].includes(action))
103
+ return toolRuntimeCommand(args, options, output);
104
+ if (['group-state', 'group-state-members', 'group-state-status', 'group-state-quote', 'capture-group', 'reset-group', 'fork-group'].includes(action))
105
+ return toolGroupStateCommand(args, options, output);
106
+ if (['catalog', 'catalog-categories', 'catalog-show', 'catalog-operations', 'catalog-operation', 'add', 'save', 'catalog-setups', 'catalog-status', 'catalog-withdraw'].includes(action))
107
+ return toolCatalogCommand(args, options, output);
108
+ if (action === 'start' && args.length === 1)
109
+ return toolGroupCommand(args, options, output);
110
+ if (['setups', 'setup', 'setup-members', 'setup-status', 'start-many', 'stop-setup'].includes(action))
111
+ return toolGroupCommand(args, options, output);
112
+ if (['start', 'start-status', 'stop', 'remove', 'removal', 'remove-status', 'connect', 'connections', 'connection-request', 'disconnect', 'open'].includes(action))
113
+ return toolLifecycleCommand(args, options, output);
114
+ if (['checkpoint', 'reset', 'restore', 'fork', 'resume', 'transitions', 'transition', 'checkpoint-status'].includes(action))
115
+ return toolDataCommand(args, options, output);
116
+ if (['instances', 'removed', 'instance', 'call', 'activity', 'result', 'checkpoints'].includes(action))
117
+ return toolInstanceCommand(args, options, output);
118
+ if (action === 'data')
119
+ return toolRecordsCommand(args, options, output);
120
+ if (['datasets', 'dataset', 'dataset-document', 'dataset-export', 'dataset-request', 'dataset-save', 'dataset-withdraw'].includes(action))
121
+ return toolDatasetCommand(args, options, output);
122
+ if (!action && isInteractive(options))
123
+ action = await selectOne('Tools', [
124
+ { value: 'start', label: 'Start tools', detail: 'Choose saved tools to run in the cloud for a set time' },
125
+ { value: 'sessions', label: 'Tool sessions', detail: 'Inspect, connect to or stop running tools' },
126
+ { value: 'catalog', label: 'Browse the tool catalog' },
127
+ { value: 'versions', label: 'Browse saved versions' }, { value: 'import', label: 'Import a tool package' },
128
+ { value: 'instances', label: 'Inspect tool instances' },
129
+ { value: 'download', label: 'Download retained operation content' },
130
+ { value: 'setups', label: 'Inspect tool setups' },
131
+ { value: 'remove', label: 'Remove an instance' }, { value: 'removed', label: 'Inspect removed instances' },
132
+ ], options.signal);
133
+ if (!action || ['catalog', 'add'].includes(action))
134
+ return toolCatalogCommand([action ?? 'catalog'], options, output);
135
+ if (['start-many', 'setups'].includes(action))
136
+ return toolGroupCommand([action], options, output);
137
+ if (['instances', 'removed'].includes(action))
138
+ return toolInstanceCommand([action], options, output);
139
+ if (action === 'download')
140
+ return exportToolCommand([action], options, output);
141
+ if (action === 'remove')
142
+ return toolLifecycleCommand(['remove'], options, output);
143
+ // Hosted tool sessions replace the older managed setup start.
144
+ if (action === 'start' || action === 'sessions')
145
+ return nativeToolsCommand([action], { json: options.json, workspace: options.workspace,
146
+ openBrowser: options.openBrowser, signal: options.signal }, output);
147
+ if (!['versions', 'list', 'requests', 'show', 'services', 'operations', 'operation', 'import', 'upload', 'status', 'complete', 'withdraw', 'revoke'].includes(action)
148
+ || args.length > (action === 'operation' ? 4 : 2)
149
+ || ['versions', 'list', 'requests', 'import'].includes(action) && args.length > 1
150
+ || !['versions', 'list', 'requests', 'services', 'operations'].includes(action) && (options.page !== undefined || options.search !== undefined)
151
+ || !['import', 'upload'].includes(action) && (options.file !== undefined || options.upload)
152
+ || action !== 'import' && options.request !== undefined
153
+ || !['withdraw', 'revoke'].includes(action) && options.change
154
+ || options.seconds !== undefined || action !== 'operations' && options.service !== undefined) {
155
+ throw new CliError('arguments_invalid', 'Use tools catalog, versions, show <version>, services <version>, operations <version> --service <key>, operation <version> <service> <name>, import, upload|status|complete|withdraw <request>, or revoke <version>.', 2);
156
+ }
157
+ if (options.page !== undefined && !/^[1-9][0-9]{0,8}$/.test(options.page) || (options.search?.length ?? 0) > 200) {
158
+ throw new CliError('arguments_invalid', 'Use a positive page and a search up to 200 characters.', 2);
159
+ }
160
+ const scope = await selectedWorkspace({ ...options, interactive: isInteractive(options) });
161
+ const auth = { actor: scope.owner, workspace: scope.workspace, signal: options.signal };
162
+ const prefix = `/api/workspaces/${scope.workspace}/tools`;
163
+ const reads = packageReads(scope, options.signal), owner = { workspace: scope.workspace, actor: scope.owner };
164
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
165
+ const continuation = (page, command) => `\nPage ${page.page}; ${page.count} items.${page.next ? `\nNext: tools ${command} --workspace ${scope.workspace} --page ${page.page + 1}${options.search ? ` --search ${quote(terminalText(options.search))}` : ''}` : ''}`;
166
+ if (action === 'requests') {
167
+ const page = await reads.requests(Number(options.page ?? 1), options.search ?? '', options.importStatus ?? 'all');
168
+ output('tool_package_requests', page, (page.results.map(receiptText).join('\n\n') || 'No tool package requests in this workspace.')
169
+ + continuation(page, `requests${options.importStatus ? ` --import-status ${options.importStatus}` : ''}`));
170
+ return;
171
+ }
172
+ if (action === 'versions' || action === 'list') {
173
+ const page = await reads.versions(Number(options.page ?? 1), options.search ?? '');
174
+ output('tool_catalog', page, (page.results.map(row => `${row.id} ${terminalText(row.name)} ${terminalText(row.version)} · ${row.state}\n${row.operation_count ?? 'Unrecorded'} declared operations`).join('\n\n') || 'No saved tool packages in this workspace.')
175
+ + continuation(page, 'versions'));
176
+ return;
177
+ }
178
+ if (action === 'show' || action === 'services' || action === 'operations' || action === 'operation' || action === 'revoke') {
179
+ const version = identifier(args[1] ?? '');
180
+ const original = await reads.version(version);
181
+ if (action === 'show') {
182
+ const row = original;
183
+ output('tool_implementation', row, `${row.name} ${row.version} · ${row.state}\n`
184
+ + `${row.service_count} services · ${row.operation_count} declared operations\nUse firedrill tools services ${version} to browse services.`
185
+ + '\nPackage information only. No instance was started.');
186
+ }
187
+ else if (action === 'services') {
188
+ const page = await reads.services(original, Number(options.page ?? 1), options.search ?? '');
189
+ output('tool_services', page, (page.results.map(one => `${one.key}: ${terminalText(one.name)} · ${one.operation_count} declared operations`).join('\n') || 'No matching services.')
190
+ + continuation(page, `services ${version}`));
191
+ }
192
+ else if (action === 'revoke') {
193
+ const approved = options.change || isInteractive(options) && await selectOne('Revoke this saved tool version?', [{ value: false, label: 'Cancel' }, { value: true, label: 'Revoke version', detail: 'Prevents new use. Saved history is not deleted.' }], options.signal);
194
+ if (!approved)
195
+ throw new CliError('tool_change_consent_required', 'No version was revoked. Use --approve-tool-change for automation.', 2);
196
+ const row = await api(`${prefix}/implementations/${version}`, { ...auth, method: 'DELETE' });
197
+ packageRead(row, toolVersionMatches(row, scope.workspace, version) && row.contract_digest === original.contract_digest && row.state === 'revoked');
198
+ const observed = await reads.version(version);
199
+ packageRead(observed, observed.contract_digest === original.contract_digest && observed.state === 'revoked');
200
+ output('tool_implementation', observed, `${terminalText(observed.name)} ${terminalText(observed.version)} · ${observed.state}`);
201
+ }
202
+ else {
203
+ const service = serviceKey(action === 'operation' ? args[2] ?? '' : options.service ?? '');
204
+ await reads.service(original, service);
205
+ if (action === 'operation') {
206
+ const operation = args[3] ?? '';
207
+ if (!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(operation))
208
+ throw new CliError('arguments_invalid', 'Choose an operation name from tools operations.', 2);
209
+ const row = await reads.operation(original, service, operation);
210
+ output('tool_operation', row, JSON.stringify(row, null, 2));
211
+ }
212
+ else {
213
+ const page = await reads.operations(original, service, Number(options.page ?? 1), options.search ?? '');
214
+ output('tool_operations', page, (page.results.map(one => `${terminalText(one.name)} · ${one.effect} · ${one.transport.kind}\n${terminalText(one.description)}`
215
+ + (one.mcp_aliases?.length ? `\nMCP names: ${one.mcp_aliases.map(terminalText).join(', ')}` : '')).join('\n\n') || 'No matching operations.')
216
+ + continuation(page, `operations ${version} --service ${service}`));
217
+ }
218
+ }
219
+ return;
220
+ }
221
+ if (['status', 'complete', 'withdraw'].includes(action)) {
222
+ const request = key(args[1] ?? '');
223
+ const original = await reads.request(request);
224
+ if (action === 'withdraw' && !(options.change || isInteractive(options) && await selectOne('Withdraw this package upload?', [{ value: false, label: 'Keep upload' }, { value: true, label: 'Withdraw upload' }], options.signal))) {
225
+ throw new CliError('tool_change_consent_required', 'No request was withdrawn. Use --approve-tool-change for automation.', 2);
226
+ }
227
+ let row = original;
228
+ if (action !== 'status') {
229
+ const accepted = await api(`${prefix}/package-requests/${request}${action === 'complete' ? '/complete' : ''}`, { ...auth, ...(action === 'complete' ? { method: 'POST', body: {} } : { method: 'DELETE' }) });
230
+ packageRead(accepted, toolPackageMatches(accepted, owner, { key: request, id: original.id, input: original }));
231
+ row = await reads.request(request, { id: original.id, input: original });
232
+ }
233
+ output('tool_package_request', row, receiptText(row));
234
+ return;
235
+ }
236
+ const path = await chosenFile(options);
237
+ const consent = options.upload || isInteractive(options) && await selectOne('Upload this tool package to the selected workspace?', [{ value: false, label: 'Keep file local' }, { value: true, label: 'Upload package', detail: 'Include service code and synthetic data only. Never credentials or customer data.' }], options.signal);
238
+ if (!consent)
239
+ throw new CliError('tool_upload_consent_required', 'No package was uploaded. Use --approve-tool-upload for explicit automated transfer.', 2);
240
+ const capacity = await reads.versions();
241
+ const maximum = capacity.package_capacity.upload_bytes;
242
+ if (!Number.isSafeInteger(maximum) || !maximum || maximum < 1)
243
+ throw new CliError('tool_capacity_unavailable', 'Upload capacity is unavailable. No file was transferred.');
244
+ const request = key(action === 'upload' ? args[1] ?? '' : options.request ?? randomUUID());
245
+ const chosen = await archive(path, maximum, options.signal);
246
+ const requestPath = `${prefix}/package-requests/${request}`;
247
+ try {
248
+ output('tool_upload_intent', { request_key: request, workspace_id: scope.workspace, sha256: chosen.sha256, size: chosen.size }, `Tool package request: ${request}\nIf interrupted, inspect tools status ${request}, then tools complete ${request}. Do not create a replacement request.`);
249
+ const input = { filename: basename(path), size: chosen.size, sha256: chosen.sha256, upload_consent: true };
250
+ let row;
251
+ if (action === 'upload')
252
+ row = await reads.request(request, { input });
253
+ else {
254
+ try {
255
+ const accepted = await api(`${prefix}/package-requests`, { ...auth, method: 'POST', idempotencyKey: request, body: input });
256
+ packageRead(accepted, toolPackageMatches(accepted, owner, { key: request, input }));
257
+ row = await reads.request(request, { id: accepted.id, input });
258
+ }
259
+ catch {
260
+ try {
261
+ row = await reads.request(request, { input });
262
+ }
263
+ catch {
264
+ throw new CliError('tool_package_acceptance_unconfirmed', `Import acceptance is unconfirmed. No replacement was submitted. Inspect tools status ${request} --workspace ${scope.workspace}.`);
265
+ }
266
+ }
267
+ }
268
+ if (row.state === 'uploading' || row.state === 'inspecting') {
269
+ // Observe the original object before any transfer. A completed original
270
+ // is consumed, never re-uploaded. A definite missing object remains on
271
+ // this exact request; an uncertain observation stops here.
272
+ const observed = await api(requestPath + '/complete', { ...auth, method: 'POST', body: {} });
273
+ packageRead(observed, toolPackageMatches(observed, owner, { key: request, id: row.id, input }));
274
+ row = await reads.request(request, { id: row.id, input });
275
+ }
276
+ if (row.state !== 'uploading' || !row.can_upload) {
277
+ output('tool_package_request', row, receiptText(row));
278
+ return;
279
+ }
280
+ const access = await api(requestPath + '/upload-access', { ...auth, method: 'POST', body: {} });
281
+ const destination = toolPackageUploadDestination(access, owner, row);
282
+ const current = await chosen.file.stat();
283
+ if (current.size !== chosen.stat.size || current.mtimeMs !== chosen.stat.mtimeMs || current.ctimeMs !== chosen.stat.ctimeMs) {
284
+ throw new CliError('tool_package_file_changed', 'The package changed after its checksum was captured. Nothing was transferred.');
285
+ }
286
+ let response;
287
+ try {
288
+ response = await fetch(destination, { method: 'PUT', headers: { ...access.headers, 'Content-Length': String(chosen.size) },
289
+ body: Readable.toWeb(chosen.file.createReadStream({ autoClose: false, start: 0 })), duplex: 'half', redirect: 'error', credentials: 'omit',
290
+ signal: AbortSignal.any([options.signal, AbortSignal.timeout(12 * 60 * 1000)]) });
291
+ await response.body?.cancel();
292
+ }
293
+ catch {
294
+ throw new CliError('tool_upload_uncertain', `The upload reply is unknown. Use tools complete ${request}; no file upload is retried automatically.`);
295
+ }
296
+ if (![200, 201, 412].includes(response.status))
297
+ throw new CliError('tool_upload_uncertain', `Upload not confirmed. Inspect tools status ${request} before another transfer.`);
298
+ const receipt = await api(requestPath + '/complete', { ...auth, method: 'POST', body: {} });
299
+ packageRead(receipt, toolPackageMatches(receipt, owner, { key: request, id: row.id, input }));
300
+ const observed = await reads.request(request, { id: row.id, input });
301
+ output('tool_package_request', observed, receiptText(observed));
302
+ }
303
+ finally {
304
+ await chosen.file.close();
305
+ }
306
+ }
@@ -0,0 +1,93 @@
1
+ import { workspaceLink } from './browser-links.js';
2
+ import { api } from './auth.js';
3
+ import { CliError } from './http.js';
4
+ import { selectOne } from './prompts.js';
5
+ import { identifier } from './world-contracts.js';
6
+ const label = (row) => row.observation_source === 'target_http_json' ? `HTTP ${row.http_status}`
7
+ : row.observation_source === 'target_mcp' ? row.outcome === 'succeeded' ? 'MCP response' : 'MCP error'
8
+ : row.outcome === 'succeeded' ? 'Reported success' : row.outcome === 'refused' ? 'Refused' : 'Reported error';
9
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
10
+ export function validateActionOptions(options) {
11
+ if (options.page !== undefined && !/^[1-9][0-9]{0,8}$/.test(options.page)
12
+ || (options.search?.length ?? 0) > 200 || /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/.test(options.search ?? '')
13
+ || options.status !== undefined && !['succeeded', 'failed', 'refused'].includes(options.status))
14
+ throw new CliError('arguments_invalid', 'Use a positive page, search up to 200 characters and --status succeeded|failed|refused for action lists.', 2);
15
+ if (options.serviceRequest !== undefined)
16
+ identifier(options.serviceRequest);
17
+ }
18
+ async function inspect(path, id, scope, options, output) {
19
+ const selected = identifier(id);
20
+ const row = await api(`${path}/actions/${selected}`, { actor: scope.owner, workspace: scope.workspace,
21
+ signal: options.signal, maximumResponseBytes: 16 * 1024 ** 2 });
22
+ if (row.id !== selected)
23
+ throw new CliError('trial_action_unavailable', 'This retained action could not be confirmed.');
24
+ output(row, [`${row.name}: ${label(row)}`,
25
+ ...(row.observation_source === 'target_http_json' ? ['Observed mapped HTTP request and response, not a behavior score.'] : []),
26
+ ...(row.observation_source === 'target_mcp' ? ['Observed MCP tools/call arguments and matching result. Protocol success is not a behavior score or proof of state changes.'] : []),
27
+ ...(row.observation_source === 'synthetic_handler' ? ['Returned by the simulated handler, not proof of a state mutation or business correctness.'] : []),
28
+ ...(row.observation_source === 'operation_policy' ? ['Firedrill refused this operation before running its handler.'] : []),
29
+ ...(row.observation_source === 'source_reported' ? ['Reported by the agent, not independent proof of tool execution or state changes. The timestamp is when the report was observed.'] : []),
30
+ row.observation_source === 'target_http_json' ? 'Request body' : 'Arguments', JSON.stringify(row.arguments, null, 2),
31
+ 'Response', JSON.stringify(row.result, null, 2), ...(row.error ? ['Recorded error', row.error] : []),
32
+ ...(row.request_path ? [workspaceLink(scope.workspace, row.request_path)] : [])].join('\n'));
33
+ }
34
+ export async function trialActions(path, scope, interactive, options, output, supplied) {
35
+ validateActionOptions(options);
36
+ if (supplied) {
37
+ if (options.page !== undefined || options.search !== undefined || options.status !== undefined || options.serviceRequest !== undefined)
38
+ throw new CliError('arguments_invalid', 'Use filters with an action list, not one selected action.', 2);
39
+ await inspect(path, supplied, scope, options, output);
40
+ return;
41
+ }
42
+ let page = Number(options.page ?? 1);
43
+ let receipt = options.serviceRequest === undefined ? undefined : identifier(options.serviceRequest);
44
+ const parts = path.split('/');
45
+ const command = `firedrill report ${identifier(parts.at(-3))} drill ${identifier(parts.at(-1))} actions --workspace ${scope.workspace}`;
46
+ while (true) {
47
+ const params = new URLSearchParams({ page: String(page), q: options.search ?? '', status: options.status ?? '' });
48
+ if (receipt)
49
+ params.set('service_request', receipt);
50
+ const data = await api(`${path}/actions?${params}`, { actor: scope.owner, workspace: scope.workspace, signal: options.signal });
51
+ if (receipt && data.service_request?.id !== receipt)
52
+ throw new CliError('service_receipt_unavailable', 'The selected receipt filter could not be confirmed. No unfiltered history was substituted.');
53
+ const continuation = command + (receipt ? ` --service-request ${receipt}` : '')
54
+ + (options.search ? ' --search ' + quote(options.search) : '') + (options.status ? ' --status ' + options.status : '');
55
+ output(data, [...(data.service_request ? [`Captured actions for ${data.service_request.operation}`,
56
+ data.service_request.capture_supported ? 'Matched to this original request and response, not proof of which state changes it caused.'
57
+ : 'Payload capture is not available for this connection or response. Inspect its receipt and drill evidence separately.'] : []),
58
+ ...data.results.map(row => `${row.name}: ${label(row)}\n${row.id}`), ...(!data.count ? ['No matching retained actions.'] : []),
59
+ `Page ${data.page}; ${data.count.toLocaleString()} retained actions.`,
60
+ ...(data.next ? [`Continue: ${continuation} --page ${page + 1}`] : []), 'HTTP and MCP response outcomes are not behavior scores.'].join('\n\n'));
61
+ if (!interactive)
62
+ return;
63
+ const choices = data.results.map(row => ({
64
+ value: { kind: 'action', id: row.id }, label: row.name, detail: label(row)
65
+ }));
66
+ if (page > 1)
67
+ choices.push({ value: { kind: 'previous' }, label: 'Previous page' });
68
+ if (data.next)
69
+ choices.push({ value: { kind: 'next' }, label: 'Next page' });
70
+ if (receipt)
71
+ choices.push({ value: { kind: 'all' }, label: 'View all drill actions' });
72
+ choices.push({ value: { kind: 'done' }, label: 'Done' });
73
+ const selected = await selectOne('Recorded action', choices, options.signal);
74
+ if (selected.kind === 'done')
75
+ return;
76
+ if (selected.kind === 'previous') {
77
+ page -= 1;
78
+ continue;
79
+ }
80
+ if (selected.kind === 'next') {
81
+ page += 1;
82
+ continue;
83
+ }
84
+ if (selected.kind === 'all') {
85
+ receipt = undefined;
86
+ page = 1;
87
+ continue;
88
+ }
89
+ if (selected.kind !== 'action')
90
+ throw new CliError('selection_invalid', 'Choose a retained action.', 2);
91
+ await inspect(path, selected.id, scope, options, output);
92
+ }
93
+ }
@@ -0,0 +1,133 @@
1
+ import { api } from './auth.js';
2
+ import { CliError } from './http.js';
3
+ import { selectOne } from './prompts.js';
4
+ import { identifier } from './world-contracts.js';
5
+ import { checkpointLabel, observedCellValue } from '../../contracts/trial-state-contracts.js';
6
+ const uuid = /^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/;
7
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
8
+ export function validateCheckpointReport(args, options) {
9
+ if (args.length > 4 || options.status !== undefined || options.evidenceKind !== undefined || options.checkpoint !== undefined
10
+ || args[1] && !uuid.test(args[1]) || args[2] && args[2] !== 'mutations' && !/^[a-f0-9]{64}$/.test(args[2])
11
+ || args[2] === 'mutations' && args[3] !== undefined || args[3] && !uuid.test(args[3])
12
+ || options.page !== undefined && !/^[1-9][0-9]{0,8}$/.test(options.page)
13
+ || (options.search?.length ?? 0) > 200 || /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/.test(options.search ?? '')
14
+ || !args[1] && options.search !== undefined || args[3] && (options.page !== undefined || options.search !== undefined))
15
+ throw new CliError('arguments_invalid', 'Use state checkpoints [checkpoint-id [collection-key [record-id]]], or state checkpoints <checkpoint-id> mutations. --page pages lists; --search filters collections or records.', 2);
16
+ }
17
+ function shown(cell) {
18
+ const value = observedCellValue(cell), text = typeof value === 'string' ? value : JSON.stringify(value) ?? '';
19
+ return text.slice(0, 600) + (text.length > 600 || 'truncated' in cell && cell.truncated ? '…' : '');
20
+ }
21
+ async function selection(prompt, choices, page, next, signal) {
22
+ if (page > 1)
23
+ choices.push({ value: 'previous', label: 'Previous page', detail: '' });
24
+ if (next)
25
+ choices.push({ value: 'next', label: 'Next page', detail: '' });
26
+ choices.push({ value: 'done', label: 'Done', detail: '' });
27
+ return selectOne(prompt, choices, signal);
28
+ }
29
+ export async function checkpointReport(args, path, command, scope, interactive, options, output) {
30
+ validateCheckpointReport(args, options);
31
+ const auth = { actor: scope.owner, workspace: scope.workspace, signal: options.signal };
32
+ const prefix = `${path}/state-comparisons/checkpoints`, json = options.json ? ' --json' : '';
33
+ let selected = args[1], collection = args[2], page = Number(options.page ?? 1);
34
+ if (!selected) {
35
+ while (true) {
36
+ const data = await api(`${prefix}?page=${page}`, auth);
37
+ output(data, [...data.results.map(row => `${checkpointLabel(row)}\n${row.captured_at ?? 'Time not retained'}; ${row.status}; ${row.id}\nInspect: ${command} checkpoints ${row.id} --workspace ${scope.workspace}`),
38
+ ...(!data.count ? ['No public state checkpoints have been retained.'] : []),
39
+ `Page ${data.page}; ${data.count.toLocaleString()} observed boundaries. Controlled SQL state only, not agent memory, a score or a restorable world.`,
40
+ ...(data.next ? [`Continue: ${command} checkpoints --workspace ${scope.workspace} --page ${page + 1}${json}`] : [])].join('\n\n'));
41
+ if (!interactive || !data.count)
42
+ return;
43
+ const value = await selection('State checkpoint', data.results.map(row => ({ value: row.id, label: checkpointLabel(row), detail: row.status })), page, data.next, options.signal);
44
+ if (value === 'done')
45
+ return;
46
+ if (value === 'previous' || value === 'next') {
47
+ page += value === 'next' ? 1 : -1;
48
+ continue;
49
+ }
50
+ selected = identifier(value);
51
+ page = 1;
52
+ break;
53
+ }
54
+ }
55
+ const original = await api(`${prefix}/${identifier(selected)}`, auth);
56
+ if (original.id !== selected)
57
+ throw new CliError('trial_state_changed', 'The original checkpoint could not be confirmed. Reopen the drill.');
58
+ if (collection === 'mutations') {
59
+ const term = options.search ?? '', search = term ? ' --search ' + quote(term) : '';
60
+ while (true) {
61
+ const data = await api(`${prefix}/${selected}/mutations?${new URLSearchParams({ page: String(page), q: term })}`, auth);
62
+ const key = (value) => value === null ? 'Not present' : Object.entries(value).map(([name, cell]) => `${name}: ${shown(cell)}`).join('; ');
63
+ output({ checkpoint: original, ...data }, [checkpointLabel(original), 'Actual committed row writes. They may cancel in the net diff; native transaction identity is scoped to this isolated attempt.',
64
+ ...(data.producer_origin === 'customer_device' ? ['Device-reported receipts, not independently attested managed execution.'] : []),
65
+ ...data.results.map(row => `${row.collection}: native transaction ${row.transaction}\nOperation request: ${row.request_id}\nPrevious key: ${key(row.key)}\nFollowing key: ${key(row.after_key)}`),
66
+ ...(!data.count ? ['No matching committed write receipts.'] : []), `Page ${data.page}; ${data.count.toLocaleString()} retained row writes.`,
67
+ ...(data.next ? [`Continue: ${command} checkpoints ${selected} mutations --workspace ${scope.workspace} --page ${page + 1}${search}${json}`] : [])].join('\n\n'));
68
+ if (!interactive)
69
+ return;
70
+ const value = await selection('Committed write receipts', [], page, data.next, options.signal);
71
+ if (value === 'done')
72
+ return;
73
+ page += value === 'next' ? 1 : -1;
74
+ }
75
+ }
76
+ if (original.status !== 'observed') {
77
+ output(original, `${checkpointLabel(original)}: state unavailable (${original.reason ?? 'not observed'}). No empty state is inferred.`);
78
+ return;
79
+ }
80
+ const coverage = original.omitted_checkpoints || original.omitted_cause_references
81
+ ? [`Observation budget: ${original.omitted_checkpoints} intermediate boundaries and ${original.omitted_cause_references} cause references omitted. Missing state is not inferred.`] : [];
82
+ const term = options.search ?? '', search = term ? ' --search ' + quote(term) : '';
83
+ if (!collection) {
84
+ while (true) {
85
+ const data = await api(`${prefix}/${selected}/collections?${new URLSearchParams({ page: String(page), q: term })}`, auth);
86
+ output({ checkpoint: original, ...data }, [checkpointLabel(original), ...coverage,
87
+ ...(original.kind === 'operation_committed' ? [`Committed write receipts: ${command} checkpoints ${selected} mutations --workspace ${scope.workspace}`] : []),
88
+ ...data.results.map(row => `${row.name}: ${row.row_count.toLocaleString()} records; ${row.column_count} fields\n${row.key}\nRead: ${command} checkpoints ${selected} ${row.key} --workspace ${scope.workspace}`),
89
+ ...(!data.count ? ['No matching observed collections.'] : []), `Page ${data.page}; ${data.count.toLocaleString()} collections.`,
90
+ ...(data.next ? [`Continue: ${command} checkpoints ${selected} --workspace ${scope.workspace} --page ${page + 1}${search}${json}`] : [])].join('\n\n'));
91
+ if (!interactive || !data.count)
92
+ return;
93
+ const value = await selection('Observed collection', data.results.map(row => ({ value: row.key, label: row.name, detail: `${row.row_count} records` })), page, data.next, options.signal);
94
+ if (value === 'done')
95
+ return;
96
+ if (value === 'previous' || value === 'next') {
97
+ page += value === 'next' ? 1 : -1;
98
+ continue;
99
+ }
100
+ collection = value;
101
+ page = 1;
102
+ break;
103
+ }
104
+ }
105
+ const records = `${prefix}/${selected}/collections/${collection}/records`;
106
+ const showRecord = async (record) => {
107
+ const value = await api(`${records}/${identifier(record)}`, { ...auth, maximumResponseBytes: 16 * 1024 ** 2 });
108
+ if (value.id !== record)
109
+ throw new CliError('trial_state_changed', 'The original state record could not be confirmed. Reopen the checkpoint.');
110
+ output(value, [`Record ${(value.position + 1).toLocaleString()}`, ...Object.entries(value.cells).slice(0, 40).map(([name, cell]) => `${name}: ${shown(cell)}`),
111
+ ...(Object.keys(value.cells).length > 40 ? ['Display shortened. Use --json for the complete retained record.'] : [])].join('\n'));
112
+ };
113
+ if (args[3]) {
114
+ await showRecord(args[3]);
115
+ return;
116
+ }
117
+ while (true) {
118
+ const data = await api(`${records}?${new URLSearchParams({ page: String(page), q: term })}`, auth);
119
+ output({ checkpoint: original, ...data }, [...data.results.map(row => `Record ${(row.position + 1).toLocaleString()}: ${Object.entries(row.cells).slice(0, 3).map(([name, cell]) => `${name}: ${shown(cell)}`).join('; ')}\nRead: ${command} checkpoints ${selected} ${collection} ${row.id} --workspace ${scope.workspace}`),
120
+ ...(!data.count ? ['No matching observed records.'] : []), `Page ${data.page}; ${data.count.toLocaleString()} records. Directory values are previews.`,
121
+ ...(data.next ? [`Continue: ${command} checkpoints ${selected} ${collection} --workspace ${scope.workspace} --page ${page + 1}${search}${json}`] : [])].join('\n\n'));
122
+ if (!interactive || !data.count)
123
+ return;
124
+ const value = await selection('Observed record', data.results.map(row => ({ value: row.id, label: `Record ${row.position + 1}`, detail: row.id })), page, data.next, options.signal);
125
+ if (value === 'done')
126
+ return;
127
+ if (value === 'previous' || value === 'next') {
128
+ page += value === 'next' ? 1 : -1;
129
+ continue;
130
+ }
131
+ await showRecord(value);
132
+ }
133
+ }
@@ -0,0 +1,70 @@
1
+ import { api } from './auth.js';
2
+ import { CliError } from './http.js';
3
+ import { selectOne } from './prompts.js';
4
+ import { identifier } from './world-contracts.js';
5
+ const outcomes = { met: 'Met', unmet: 'Unmet', unassessed: 'Not assessed' };
6
+ const kinds = { objective: 'Objective check', semantic: 'Judged check', both: 'Objective and judged check', unknown: 'Check definition unavailable' };
7
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
8
+ export function validateCheckOptions(options) {
9
+ if (options.page !== undefined && !/^[1-9][0-9]{0,8}$/.test(options.page)
10
+ || (options.search?.length ?? 0) > 200 || /[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/.test(options.search ?? '')
11
+ || options.status !== undefined && !Object.hasOwn(outcomes, options.status)
12
+ || options.evidenceKind !== undefined && !Object.hasOwn(kinds, options.evidenceKind))
13
+ throw new CliError('arguments_invalid', 'Use a positive page, search up to 200 characters, --status met|unmet|unassessed and --kind objective|semantic|both|unknown for recorded check lists.', 2);
14
+ }
15
+ async function inspect(path, position, scope, options, output) {
16
+ if (!/^[1-9][0-9]{0,8}$/.test(position))
17
+ throw new CliError('arguments_invalid', 'Choose the original positive check position from this drill.', 2);
18
+ const row = await api(`${path}/checks/${position}`, { actor: scope.owner, workspace: scope.workspace,
19
+ signal: options.signal, maximumResponseBytes: 16 * 1024 ** 2 });
20
+ if (row.position !== Number(position))
21
+ throw new CliError('trial_check_unavailable', 'The selected original check could not be confirmed.');
22
+ output(row, [`${row.name}: ${outcomes[row.outcome]}`, kinds[row.kind], ...(row.reason === null ? [] : [row.reason])].join('\n'));
23
+ }
24
+ export async function trialRecordedChecks(path, scope, interactive, options, output, supplied) {
25
+ validateCheckOptions(options);
26
+ if (supplied) {
27
+ if (options.page !== undefined || options.search !== undefined || options.status !== undefined || options.evidenceKind !== undefined)
28
+ throw new CliError('arguments_invalid', 'Use filters with the recorded check list, not one selected check.', 2);
29
+ await inspect(path, supplied, scope, options, output);
30
+ return;
31
+ }
32
+ let page = Number(options.page ?? 1);
33
+ const parts = path.split('/');
34
+ const command = `firedrill report ${identifier(parts.at(-3))} drill ${identifier(parts.at(-1))} checks --workspace ${scope.workspace}`;
35
+ while (true) {
36
+ const params = new URLSearchParams({ page: String(page), q: options.search ?? '', status: options.status ?? '', kind: options.evidenceKind ?? '' });
37
+ const data = await api(`${path}/checks?${params}`, { actor: scope.owner, workspace: scope.workspace, signal: options.signal });
38
+ const continuation = command + (options.search ? ' --search ' + quote(options.search) : '')
39
+ + (options.status ? ' --status ' + options.status : '') + (options.evidenceKind ? ' --kind ' + options.evidenceKind : '') + (options.json ? ' --json' : '');
40
+ output(data, [...data.results.map(row => `${row.position}. ${row.name}: ${outcomes[row.outcome]}\n${kinds[row.kind]}${row.reason_excerpt === null ? '' : '\n' + row.reason_excerpt}${row.reason_truncated ? `\nRead full explanation: ${command.split(' --workspace')[0]} ${row.position} --workspace ${scope.workspace}` : ''}`),
41
+ ...(!data.count ? [!data.recorded_checks.result_retained ? 'The original result is not available.'
42
+ : options.search || options.status || options.evidenceKind ? 'No recorded checks match these filters.' : 'No checks were included in this result.'] : []),
43
+ `Page ${data.page}; ${data.count.toLocaleString()} matching recorded checks.`,
44
+ ...(data.next ? [`Continue: ${continuation} --page ${page + 1}`] : [])].join('\n\n'));
45
+ if (!interactive)
46
+ return;
47
+ const choices = data.results.map(row => ({
48
+ value: { kind: 'check', position: row.position }, label: row.name, detail: `${outcomes[row.outcome]}; ${kinds[row.kind]}`
49
+ }));
50
+ if (page > 1)
51
+ choices.push({ value: { kind: 'previous' }, label: 'Previous page' });
52
+ if (data.next)
53
+ choices.push({ value: { kind: 'next' }, label: 'Next page' });
54
+ choices.push({ value: { kind: 'done' }, label: 'Done' });
55
+ const selected = await selectOne('Recorded check', choices, options.signal);
56
+ if (selected.kind === 'done')
57
+ return;
58
+ if (selected.kind === 'previous') {
59
+ page -= 1;
60
+ continue;
61
+ }
62
+ if (selected.kind === 'next') {
63
+ page += 1;
64
+ continue;
65
+ }
66
+ if (selected.kind !== 'check')
67
+ throw new CliError('selection_invalid', 'Choose a retained check.', 2);
68
+ await inspect(path, String(selected.position), scope, options, output);
69
+ }
70
+ }