firedrill-run 2.2.5 → 3.0.1

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 +176 -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 +506 -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 +1627 -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 +96 -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,302 @@
1
+ export const WORKOS_ORIGIN = 'https://api.workos.com';
2
+ function safeRequestId(value) {
3
+ return typeof value === 'string' && (/^[a-f0-9]{32}$/.test(value)
4
+ || /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(value)) ? value : null;
5
+ }
6
+ export class CliError extends Error {
7
+ code;
8
+ exitCode;
9
+ httpStatus;
10
+ requestId;
11
+ constructor(code, message, exitCode = 1, httpStatus = null, requestId = null) {
12
+ super(message);
13
+ this.code = code;
14
+ this.exitCode = exitCode;
15
+ this.httpStatus = httpStatus;
16
+ this.requestId = safeRequestId(requestId);
17
+ }
18
+ }
19
+ /**
20
+ * Root's release gate refused this request (`release_capability_unavailable`).
21
+ * Root checks for a retained original before its gate, so the refusal proves no
22
+ * original exists under that key: the write is definitely not accepted, never
23
+ * "uncertain", and a read-back would only hide the real reason.
24
+ */
25
+ export function releaseClosed(error) {
26
+ return error instanceof CliError && error.code === 'release_capability_unavailable';
27
+ }
28
+ function platformOrigins() {
29
+ const profile = process.env.FIREDRILL_PLATFORM;
30
+ const api = process.env.FIREDRILL_LOCAL_API_ORIGIN;
31
+ const app = process.env.FIREDRILL_LOCAL_APP_ORIGIN;
32
+ const local = process.env.FIREDRILL_LOCAL_PLATFORM;
33
+ const hasLocalConfiguration = api !== undefined || app !== undefined || local !== undefined;
34
+ if (profile !== undefined) {
35
+ if (profile !== 'sim-dev' || hasLocalConfiguration) {
36
+ throw new CliError('platform_configuration_invalid', 'Use FIREDRILL_PLATFORM=sim-dev for the isolated hosted development platform, without FIREDRILL_LOCAL_PLATFORM, FIREDRILL_LOCAL_API_ORIGIN or FIREDRILL_LOCAL_APP_ORIGIN. Unset all platform variables to select the public platform. Unknown or mixed profiles are refused.', 2);
37
+ }
38
+ return { api: 'https://api.sim-dev.firedrill.run', app: 'https://app.sim-dev.firedrill.run' };
39
+ }
40
+ if (!hasLocalConfiguration)
41
+ return { api: 'https://api.firedrill.run', app: 'https://app.firedrill.run' };
42
+ const valid = (raw) => {
43
+ if (!raw)
44
+ return false;
45
+ try {
46
+ const value = new URL(raw);
47
+ return value.origin === raw && value.protocol === 'http:'
48
+ && ['127.0.0.1', 'localhost', '[::1]'].includes(value.hostname) && !!value.port
49
+ && !value.username && !value.password && !value.search && !value.hash && value.pathname === '/';
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ };
55
+ if (local !== '1' || !valid(api) || !valid(app))
56
+ throw new CliError('local_platform_configuration_invalid', 'Local development requires explicit paired loopback API and app origins. Public, private-network and arbitrary cloud destination overrides are not allowed.', 2);
57
+ return { api: api, app: app };
58
+ }
59
+ // Resolve before credentials or requests can be used. Hosted development has
60
+ // fixed HTTPS origins; the separate explicit localhost lane accepts loopback
61
+ // only. There is no arbitrary service URL or production fallback for a profile.
62
+ const origins = platformOrigins();
63
+ export const API_ORIGIN = origins.api;
64
+ export const APP_ORIGIN = origins.app;
65
+ export async function jsonRequest(url, init = {}, maximumBytes = 2 * 1024 * 1024) {
66
+ if (!Number.isSafeInteger(maximumBytes) || maximumBytes < 1 || maximumBytes > 16 * 1024 * 1024) {
67
+ throw new CliError('response_capacity_invalid', 'The response capacity is not supported.');
68
+ }
69
+ if (![API_ORIGIN, WORKOS_ORIGIN].includes(url.origin) || url.username || url.password || url.hash) {
70
+ throw new CliError('destination_refused', 'The request destination is not allowed.');
71
+ }
72
+ let response;
73
+ try {
74
+ response = await fetch(url, { ...init, redirect: 'error', credentials: 'omit',
75
+ signal: init.signal ? AbortSignal.any([init.signal, AbortSignal.timeout(25000)]) : AbortSignal.timeout(25000) });
76
+ }
77
+ catch {
78
+ throw new CliError('connection_uncertain', 'The response was not received. No pending operation is retried automatically.');
79
+ }
80
+ const reader = response.body?.getReader();
81
+ if (!reader)
82
+ throw new CliError('response_unavailable', 'The service response is unavailable.');
83
+ let size = 0;
84
+ const chunks = [];
85
+ try {
86
+ while (true) {
87
+ const part = await reader.read();
88
+ if (part.done)
89
+ break;
90
+ size += part.value.length;
91
+ if (size > maximumBytes)
92
+ throw new Error();
93
+ chunks.push(part.value);
94
+ }
95
+ const retryAfter = response.headers.get('Retry-After');
96
+ const retryAfterMs = retryAfter === null ? undefined : /^\d+$/.test(retryAfter)
97
+ ? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now();
98
+ return { status: response.status, body: JSON.parse(Buffer.concat(chunks).toString('utf8')),
99
+ ...(retryAfterMs !== undefined && Number.isFinite(retryAfterMs) && retryAfterMs >= 0 ? { retryAfterMs } : {}) };
100
+ }
101
+ catch {
102
+ throw new CliError('response_unavailable', 'The service response could not be read safely.');
103
+ }
104
+ finally {
105
+ await reader.cancel().catch(() => undefined);
106
+ reader.releaseLock();
107
+ }
108
+ }
109
+ export function endpoint(path) {
110
+ const url = new URL(path, API_ORIGIN);
111
+ if (!path.startsWith('/api/') || path.includes('\\') || url.origin !== API_ORIGIN || url.hash || url.username || url.password) {
112
+ throw new CliError('destination_refused', 'Choose a supported Firedrill operation.');
113
+ }
114
+ return url;
115
+ }
116
+ export function responseError(body, status) {
117
+ const error = body && typeof body === 'object' ? body.error : null;
118
+ const code = error && typeof error === 'object' ? error.code : null;
119
+ const requestId = error && typeof error === 'object' ? safeRequestId(error.request_id) : null;
120
+ const guidance = {
121
+ tool_package_upload_unconfirmed: 'The original upload could not be confirmed. Keep its request key and use tools complete <key> before any transfer. Do not create a replacement.',
122
+ tool_package_upload_integrity: 'The stored original file does not match its declared size. Preserve the request for review; do not overwrite it.',
123
+ tool_package_inspection_pending: 'The original inspection is still active or needs reconciliation. Use tools status <key>, then tools complete <key> when it is no longer active. Do not create a replacement.',
124
+ dependency_decision_invalid: 'Use the exact original decision metadata and digest. Catalog/generated choices need explicit coverage acknowledgement; continuation keeps its original catalog cursor. Do not include credentials.',
125
+ dependency_decision_access_required: 'Use the original requester with current access to this workspace. Accepted decision history does not grant permission for a new connection change.',
126
+ dependency_decision_unavailable: 'The original decision history cannot be confirmed. Keep its preparation ID and digest, then use connections preparation-decision to read it. Do not replace an uncertain decision or restart an active adoption.',
127
+ simulation_capture_policy_changed: 'The workspace browser capture preference changed. Refresh simulation setup before saving a new plan. No agent was run.',
128
+ desktop_capture_consent_required: 'This desktop input adapter needs explicit private-screen recording consent. Review a new simulation plan and use --record-desktop --acknowledge-desktop-screen-content only if authorized.',
129
+ agent_driver_input_required: 'Review the current agent input adapter and save a new simulation plan. Use --approve-agent-input only for explicitly authorized input.',
130
+ agent_execution_identity_changed: 'The prepared agent input adapter changed. Inspect the current world and its execution requirements before saving a new plan. No replacement adapter was selected.',
131
+ membership_discovery_running: 'Workspace access is already being refreshed. Use firedrill workspace list to see available workspaces.',
132
+ membership_discovery_request_invalid: 'Use the original workspace refresh request key.',
133
+ workspace_discovery_pending: 'Workspace access is still being checked. Use firedrill workspace list, then select an available workspace.',
134
+ vault_write_pending: 'Secure storage has not confirmed the original save. Use firedrill vault request <key> or vault resume <key>; do not create a replacement request.',
135
+ vault_rotation_pending: 'An original replacement is already pending. Inspect pending Vault values and recover that request before another rotation.',
136
+ vault_request_invalid: 'Use the original Vault request UUID. No value or replacement was saved.',
137
+ vault_request_not_received: 'This Vault request is not confirmed. Continue its exact saved metadata and original value, not a new key.',
138
+ vault_value_required: 'Re-enter the exact original value using hidden input, or pipe its exact UTF-8 bytes with --value-stdin. Never put it in command arguments.',
139
+ vault_rotation_conflict: 'Read the current value version and approve revoking old grants after its replacement is saved. Existing mappings are never changed automatically.',
140
+ vault_revision_changed: 'The expiry changed. Read the current Vault entry before submitting a reviewed edit.',
141
+ vault_expiry_invalid: 'Choose a future ISO expiry date including its timezone, or no expiry. Expired values cannot be reactivated.',
142
+ trial_dependency_evidence_invalid: 'This saved service receipt could not be confirmed. Inspect other retained drill evidence or contact support. No request was repeated.',
143
+ report_request_capacity: 'This service activity page exceeds inline processing capacity. Narrow its search or page selection, or contact support. No connection or operation was repeated.',
144
+ report_record_capacity: 'This record exceeds inline report capacity. Inspect its retained evidence file in the drill Files view. No content or score was substituted.',
145
+ report_record_unavailable: 'The retained record could not be opened safely. Inspect its original evidence file in the drill Files view.',
146
+ report_read_capacity: 'This report took too long to load. Narrow its filters or repeat the same read. No simulation or assessment was restarted.',
147
+ report_read_unavailable: 'This report is temporarily unavailable. Try the same read again later.',
148
+ recommendation_consent_required: 'Review the selected proposals and frozen context. Use --approve-assessment only to authorize that priority assessment.',
149
+ recommendation_context_changed: 'The world or selected proposal context changed. Inspect the saved world and its current proposals before a new request.',
150
+ recommendation_selection_changed: 'Some selected proposals are no longer pending. Inspect current proposals before creating another priority request.',
151
+ recommendation_context_unavailable: 'The original priority context is no longer retained or readable. No replacement evidence or new score was substituted.',
152
+ recommendation_request_withdrawn: 'This exact unaccepted priority request was canceled. It cannot start a later assessment.',
153
+ recommendation_access_revoked: 'Permission to assess these proposals changed. No new target run was started.',
154
+ assessment_context_capacity: 'Use a more focused retained evidence selection or contact support about evaluator processing capacity. No score was invented.',
155
+ assessment_private_input: 'Sensitive context could not be shared for assessment. Keep credentials in Vault; no substitute score was created.',
156
+ assessment_reply_unconfirmed: 'The original evaluator reply is unconfirmed. Inspect its saved report or check original saved replies; do not request a new evaluation just to recover the reply.',
157
+ assessment_configuration_required: 'The evaluator is not configured for this deployment. Saved results remain readable. Contact support.',
158
+ configuration_capacity: 'This world needs more configuration capacity. Contact support. No partial configuration or replacement run was saved.',
159
+ report_export_capacity: 'Use narrower drill filters or contact support about report export capacity. No partial report was published.',
160
+ report_export_inputs_changed: 'The export or some of its original evidence is unavailable. Inspect the report and create a current export if needed.',
161
+ report_export_access_ended: 'Export permission ended. Inspect the saved request using an authorized account.',
162
+ report_export_request_invalid: 'Use the original export request ID with unchanged drill filters.',
163
+ tool_access_configuration_required: 'Tool connections are not configured for this deployment. No new instance or connection was allocated. Contact support.',
164
+ tool_access_invalid: 'Choose explicit supported operations, protocols and duration. Use tools connect for the guided flow.',
165
+ tool_start_consent_required: 'Choose a saved tool version and approve its isolated setup. No instance was requested.',
166
+ tool_stop_consent_required: 'Approve stopping this exact instance. Existing history remains available.',
167
+ tool_instance_duration_invalid: 'Choose a duration within configured compute capacity, or omit --seconds to use the current default.',
168
+ tool_instance_input_unavailable: 'This exact tool version or saved input is unavailable. Inspect tools show before requesting another setup.',
169
+ tool_instance_not_ready: 'Wait for a current tool observation. Inspect firedrill tools instance <id>; no replacement instance was started.',
170
+ tool_command_pending: 'Read the original request with firedrill tools result <instance> <request>. Do not create another request.',
171
+ tool_previous_effect_unknown: 'An earlier operation has an uncertain effect. Inspect a declared read-only operation or stop this instance.',
172
+ tool_arguments_invalid: 'Arguments did not match the declared operation. Inspect firedrill tools operation before a new request.',
173
+ tool_arguments_private_value: 'Remove real credentials from synthetic tool arguments. Use Vault for real-account connections.',
174
+ tool_data_consent_required: 'Approve sending the selected arguments to this managed synthetic tool, or cancel.',
175
+ tool_operation_transport_unavailable: 'This instance operation does not have a supported execution transport yet. No call was submitted.',
176
+ tool_records_unavailable: 'The saved record pages are unavailable or expired. Choose another checkpoint with tools checkpoints. No live state was read.',
177
+ tool_records_not_applicable: 'This tool declares no persistent records. Use tools checkpoints to inspect its startup and closing records.',
178
+ tool_state_not_applicable: 'This tool declares no persistent data to checkpoint. Its startup and closing records remain in tools checkpoints.',
179
+ tool_records_integrity: 'The saved record bytes could not be confirmed. No replacement data was substituted. Inspect another saved capture or contact support.',
180
+ tool_dataset_base_unavailable: 'Choose a retained checkpoint with record pages using tools checkpoints. No tool state was changed.',
181
+ tool_dataset_version_conflict: 'Read tools datasets and choose the latest version before a new revision. Do not reuse a pending save request for different edits.',
182
+ tool_dataset_edits_invalid: 'Review captured collection keys, row positions and typed column values. Save only synthetic data, not real credentials.',
183
+ tool_dataset_unavailable: 'This dataset or its original checkpoint is withdrawn, expired or unavailable. No substitute was used.',
184
+ tool_dataset_integrity: 'The exact saved dataset bytes could not be confirmed. Contact support; do not replace an uncertain save automatically.',
185
+ tool_dataset_save_pending: 'Read tools dataset-request using the original request ID. Do not submit a new save request.',
186
+ tool_dataset_invalid: 'The original dataset and checkpoint could not be confirmed. No substitute data or replacement instance was used.',
187
+ tool_dataset_apply_failed: 'The dataset could not be applied under this tool database’s native rules. Review values, generated columns and relationships before a new setup.',
188
+ world_dataset_base_unavailable: 'Choose retained synthetic starting data in this world. No live account or running world was changed.',
189
+ world_dataset_version_conflict: 'Read firedrill datasets and choose the latest version before a new revision. Keep pending save requests unchanged.',
190
+ world_dataset_edits_invalid: 'Review captured collection keys, original row positions and typed column values. Save synthetic data only.',
191
+ world_dataset_private_key: 'This record has a redacted private primary key. Choose another record; hidden values cannot be restored.',
192
+ world_dataset_unavailable: 'The dataset or its original starting data is withdrawn, expired or unavailable. No substitute was used.',
193
+ world_dataset_integrity: 'The exact saved bytes could not be confirmed. Contact support; do not replace an uncertain save automatically.',
194
+ world_dataset_save_pending: 'Read datasets request with the original request ID. Do not submit another save request.',
195
+ state_search_capacity: 'Use a search of up to 200 characters.',
196
+ world_not_authored: 'Prepare this world before validating startup. Inspect its current state with firedrill worlds <id>.',
197
+ validation_active: 'Startup validation is already in progress. Inspect the saved world or its original setup request.',
198
+ world_execution_not_ready: 'Startup or selected connection checks are incomplete. New simulations use firedrill plan, apply and run.',
199
+ release_capability_unavailable: 'This action is not available in this release. Retained history, reports, cancellation, cleanup and original-request recovery stay available; new simulations use firedrill plan, apply and run.',
200
+ native_setup_withdrawn: 'This exact setup request was withdrawn. Review the current world before creating a new request.',
201
+ native_setup_resource_unavailable: 'The original setup was accepted but is no longer available. This request cannot create a replacement.',
202
+ local_campaign_permission_changed: 'The saved local permission changed. Review the original device, source and world configuration.',
203
+ local_grant_basis_changed: 'The source or configuration changed. Reopen local execution setup for the current world before approving or claiming work.',
204
+ source_set_component_unavailable: 'An original repository capture is unavailable. Review the connected source set; no replacement repository or file was selected.',
205
+ local_source_basis_invalid: 'Read the current local execution offer and use its exact source basis when inspecting repository roots.',
206
+ local_execution_access_removed: 'Local execution permission ended or changed. No replacement target was started.',
207
+ local_job_already_claimed: 'This job already has an ownership request. Inspect that original claim; it was not taken over.',
208
+ world_session_input_unavailable: 'Review startup checks for this exact source and configuration. Local manual sessions need completed validation on the same approved device and runtime. No replacement was started.',
209
+ world_session_inputs_changed: 'The source or configuration changed. Review the current world and original opening request before another action.',
210
+ world_session_exists: 'Inspect firedrill sessions. Close or reconcile the original session before opening another.',
211
+ world_session_bindings_changed: 'Repeat startup checks for this exact source and configuration before opening another world session. No replacement connection was used.',
212
+ world_session_operation_not_allowed: 'Choose a declared operation and its admitted connection using firedrill sessions call. No arbitrary endpoint or live fallback is available.',
213
+ world_session_observation_unavailable: 'Wait for a current session observation. Inspect sessions show before submitting another request.',
214
+ world_session_request_pending: 'A preceding command is being reconciled. Inspect sessions requests and recover its original key rather than repeating it.',
215
+ world_session_request_unknown: 'A prior result is uncertain. Inspect declared read-only operations or close the session. Do not repeat a possible effect.',
216
+ world_session_mcp_arguments_invalid: 'Use an MCP JSON argument object matching the selected operation. Inspect its declared inputs before a new request.',
217
+ world_session_request_capacity: 'This request exceeds current transport capacity. Reduce its body or headers before creating a new intent.',
218
+ service_directory_changed: 'The service evidence changed while reading this page. Reload its operation choices before submitting.',
219
+ world_session_request_withdrawn: 'This original opening was withdrawn. It cannot create or restart a session.',
220
+ native_tool_renewal_not_live: 'Only a running tool session can be extended, before it ends or is stopped. Nothing was reserved or extended.',
221
+ native_tool_renewal_owner_unavailable: 'The shared pool holding these tools cannot take an extension right now. Nothing was reserved or extended; check the session, then continue with the same request key.',
222
+ native_tool_renewal_scope_changed: 'The session changed since this renewal was reviewed (its tools, end time or pricing). Nothing was reserved or extended. Close this review and start a new renewal.',
223
+ native_tool_renewal_conflict: 'That request key or estimate belongs to a different renewal. Nothing was changed; read the original by its key.',
224
+ native_tool_renewal_limit: 'This tool session has reached its renewal limit. Start a new tool session instead.',
225
+ native_tool_renewal_duration_invalid: 'Use --seconds from 60 to 31536000 (one year).',
226
+ native_library_grant_invalid: 'Choose another workspace of this organization and read or use access. Nothing was shared or changed.',
227
+ native_library_grant_exists: 'That workspace already has an active grant for this version. List grants with firedrill library grants <version-id>; revoke it first to change its access.',
228
+ native_library_parameters_invalid: 'Use the version\'s declared parameters only, with values of the declared type and bounds and no credentials, and declare parameters only on allowed content fields. Nothing was saved.',
229
+ native_library_reference_unavailable: 'A library version is no longer available to this workspace: it was unshared, archived, replaced or is not usable here. Reference a current version you can use.',
230
+ native_library_filter_invalid: 'Use each supported filter once, within its bounds.',
231
+ native_standalone_duration_unavailable: 'That is longer than the maximum tool session lifetime allowed here. Choose a shorter length; nothing was reserved.',
232
+ native_reassessment_unavailable: 'This reassessment cannot continue in its current state or under this account. Its original evaluation must be finished and retained; only its reviewing member can approve or cancel it. Read the original status with firedrill report <campaign> drill <drill> reassessments before taking another action.',
233
+ native_reassessment_limit: 'This drill has reached its reassessment limit (64). Read its existing reassessments with firedrill report <campaign> drill <drill> reassessments.',
234
+ native_reassessment_original_pending: 'The original evaluation still has unfinished or unconfirmed criteria. Wait for its retained results before requesting a separate assessment. Nothing was reserved.',
235
+ billing_quote_expired: 'This estimate expired before approval. Recover the original request and review its current state before requesting a new estimate.',
236
+ native_evaluation_report_unavailable: 'The retained evaluation report is not available for this request. Read the original drill status before requesting another assessment.',
237
+ native_reassessment_quote_changed: 'That estimate is not this reassessment\'s current one. Nothing was reserved; continue with the same request key to see its estimate.',
238
+ native_reassessment_review_changed: 'The original evidence or the evaluator changed since this reassessment was reviewed. Nothing was reserved or evaluated. Cancel this review and start a new reassessment.',
239
+ native_reassessment_already_admitted: 'This reassessment was already approved, so it cannot be cancelled; nothing was undone. Read its results instead.',
240
+ native_reassessment_input_invalid: 'The reassessment request was not in the expected form. Nothing was reserved or changed; update the CLI and try again with the same request key.',
241
+ native_reassessment_consent_required: 'Approval is required. After the human approves this exact estimate, rerun with --usage-quote <quote-id> --approve-assessment.',
242
+ world_session_duration_invalid: 'Choose --seconds within the current runtime capacity, or omit it to use the returned default.',
243
+ local_world_session_duration_unavailable: 'Choose a shorter --seconds duration or renew the original device permission in your terminal. No local session was queued.',
244
+ local_world_session_access_removed: 'Review the original device’s world_session permission with evidence upload. The source, actor or configuration changed.',
245
+ world_session_real_consent_required: 'Approve real operations and shared state for this exact session. In automation use sessions open --approve-real-session --acknowledge-shared-state; --run is separate.',
246
+ world_session_real_owner_required: 'Only the member who approved real-account access can change this session. Open your own reviewed session instead.',
247
+ local_dataset_consent_required: 'Approve downloading this saved starting-data version to the selected local device. --run and Vault permission do not approve data downloads.',
248
+ local_dataset_consent_invalid: 'Use --share-dataset-with-device only with a saved dataset and local execution.',
249
+ local_checkpoint_consent_required: 'Approve downloading this exact saved checkpoint to the session’s original local device. --run does not approve a checkpoint download.',
250
+ local_checkpoint_consent_invalid: 'Use --share-checkpoint-with-device only with checkpoint restore or a separate local checkpoint opening.',
251
+ local_checkpoint_input_unavailable: 'The original local restore input changed or expired. Inspect checkpoint activity; do not repeat an uncertain restore.',
252
+ local_world_session_capacity: 'Choose CPU capacity supported by the current local manual runtime. No permission was granted.',
253
+ configuration_conflict: 'Configuration changed. Review the current world before creating another setup request.',
254
+ configuration_request_conflict: 'This request ID belongs to different configuration inputs. Inspect the exact saved request.',
255
+ configuration_request_withdrawn: 'This configuration request was withdrawn. It cannot change settings.',
256
+ real_binding_mapping_required: 'Keep real connection mappings at Runtime. The connection supplies its endpoint; credentials use secret saved values.',
257
+ real_binding_mapping_conflict: 'This variable has another phase or use. Review Configuration before selecting it for this connection.',
258
+ real_binding_variable_conflict: 'Use distinct endpoint and credential variables for model and service connections.',
259
+ real_binding_protocol_unsupported: 'This service needs a protocol-specific adapter before a real connection can be saved.',
260
+ real_binding_routes_required: 'Review the declared HTTP routes or Streamable HTTP MCP tools and input schemas for this connection.',
261
+ real_mcp_session_invalid: 'The real MCP session changed or could not be confirmed. Inspect its original request history before starting another session.',
262
+ real_mcp_catalog_required: 'Read tools/list on the connected MCP server before calling a reviewed tool.',
263
+ real_binding_address_mismatch: 'Use the address matching the reviewed operation paths. When the source expects an MCP endpoint, include its complete path.',
264
+ real_effect_consent_required: 'Review the selected real-account operations and explicitly authorize writes or unclassified effects if included.',
265
+ real_effect_review_required: 'Inspect firedrill real-operations. An administrator must review the real account before acknowledging an uncertain request. No operation was repeated.',
266
+ real_effect_review_conflict: 'This outcome was reviewed using another request. Read its current history; do not create a replacement operation.',
267
+ real_effect_review_unnecessary: 'This request already has a recorded transport outcome. Open its real-account history.',
268
+ real_effect_dispatch_pending: 'The original dispatch window is still open. Inspect the recorded review-available time before acknowledging the outcome.',
269
+ admin_required: 'An administrator is required for this action. History remains available if your account may read it.',
270
+ simulation_plan_conflict: 'Another tab changed the plan. Review the saved setup request and current selection.',
271
+ assessment_consent_required: 'Approve sharing selected drill evidence for assessment, or run without saved criteria.',
272
+ agent_change_stale: 'The original source, approval or evidence changed. Inspect the saved source change before proposing a current replacement.',
273
+ agent_change_source_unavailable: 'The baseline source snapshot is no longer available. It was not substituted with another revision.',
274
+ agent_change_approval_required: 'Source access needs explicit scoped approval by an active workspace writer. Only the approving user can continue drafting.',
275
+ agent_change_draft_required: 'Inspect a completed source diff before saving a separate candidate.',
276
+ agent_change_review_required: 'The reviewed draft or source scope changed. Inspect the current source change before accepting it.',
277
+ agent_change_retry_unavailable: 'This candidate has no failed save to retry. Inspect its current saved status instead.',
278
+ agent_change_conversation_required: 'This world has no saved preparation context for drafting. No source access was granted.',
279
+ agent_change_candidate_required: 'Save the reviewed candidate first. Source download does not create or run a candidate.',
280
+ agent_change_candidate_unavailable: 'The exact candidate source is unavailable. No different source revision was downloaded.',
281
+ agent_change_capacity: 'Select fewer source files for this focused change request.',
282
+ simulation_balance_insufficient: 'Open Billing to add credits or apply an event code. No extra run was admitted.',
283
+ billing_funding_pending: 'Funding did not finish. Inspect the saved simulation request, then continue that same request or cancel it before starting another. No operation was retried automatically.',
284
+ billing_adjustment_pending: 'A payment adjustment needs review before new simulations can start. Existing reports remain available. No extra run was admitted.',
285
+ billing_configuration_required: 'Payment setup is not available. Existing reports and usage remain accessible. No replacement payment was requested.',
286
+ billing_offer_unavailable: 'This offer is not available for the current organization. Inspect firedrill billing options or manage the existing subscription.',
287
+ billing_purchase_pending: 'Another subscription request is pending. Inspect firedrill billing purchases before creating another one.',
288
+ billing_idempotency_conflict: 'This request key belongs to different billing inputs or another actor. Recover the original request; do not change its offer.',
289
+ billing_response_unconfirmed: 'The payment link or response is not confirmed. Recover the original billing request rather than starting another purchase.',
290
+ promotion_configuration_required: 'Event-code redemption is not configured. Keep the code private and contact support.',
291
+ promotion_unavailable: 'This code is unavailable or not eligible for this account. No new allocation was confirmed.',
292
+ promotion_already_claimed: 'This event allocation was already claimed for this person or organization. Inspect billing balance and usage.',
293
+ promotion_idempotency_conflict: 'This request was used for another code or actor. Recover the original claim before making a different request.',
294
+ promotion_rate_limited: 'Too many event-code attempts. Wait a minute before trying again; keep the original request key.',
295
+ };
296
+ // Never echo provider bodies, arbitrary error text, authorization headers or
297
+ // source/target values through the terminal's catch handler.
298
+ return new CliError(typeof code === 'string' && /^[a-z_]{1,64}$/.test(code) ? code : 'request_failed', typeof code === 'string' && Object.hasOwn(guidance, code) ? guidance[code]
299
+ : code === 'native_account_changed' || code === 'native_workspace_changed' ? 'The terminal account or workspace changed. Reopen this world to continue.'
300
+ : status === 401 ? 'Sign in with firedrill login.' : status === 403 ? 'This account does not have access to that action.'
301
+ : status === 404 ? 'The requested item was not found in this workspace.' : 'The request was not accepted. Check its saved status before trying again.', status === 401 ? 2 : status === 403 ? 3 : 1, status, requestId);
302
+ }
@@ -0,0 +1,38 @@
1
+ import { CliError } from './http.js';
2
+ import { policyMatches } from './local-container-policy.js';
3
+ /** Exact selected boundary, before start and again during final observation. */
4
+ export function requireContainerBoundary(row, policy, expected) {
5
+ const host = row?.HostConfig, configuration = row?.Config;
6
+ const tmpfs = host?.Tmpfs;
7
+ if (!host || !configuration || host.Privileged || host.NetworkMode !== 'none' || host.IpcMode !== 'private'
8
+ || host.PidMode || host.UTSMode || host.UsernsMode === 'host' || host.CgroupnsMode !== 'private'
9
+ || host.ReadonlyRootfs !== true || host.Init === true || host.AutoRemove === true
10
+ || host.PublishAllPorts || Object.keys(host.PortBindings ?? {}).length
11
+ || (host.Binds?.length ?? 0) || (host.Devices?.length ?? 0) || (host.DeviceRequests?.length ?? 0)
12
+ || (host.VolumesFrom?.length ?? 0) || (host.Links?.length ?? 0) || (host.ExtraHosts?.length ?? 0)
13
+ || configuration.Volumes && Object.keys(configuration.Volumes).length
14
+ || !Array.isArray(host.CapDrop) || host.CapDrop.length !== 1 || !['ALL', 'CAP_ALL'].includes(host.CapDrop[0])
15
+ || !Array.isArray(host.CapAdd) || host.CapAdd.length !== 2
16
+ || host.CapAdd.map((name) => name.replace(/^CAP_/, '')).sort().join(',') !== 'SETGID,SETUID'
17
+ || configuration.Image !== expected.image || configuration.User !== '2000:2000' || configuration.Tty !== false
18
+ || configuration.OpenStdin !== expected.interactive || configuration.StdinOnce === true
19
+ || configuration.Entrypoint?.length !== 1 || configuration.Entrypoint[0] !== '/opt/firedrill/bin/python'
20
+ || JSON.stringify(configuration.Cmd) !== JSON.stringify(expected.arguments)
21
+ || !tmpfs || Object.keys(tmpfs).sort().join(',') !== Object.keys(expected.tmpfs).sort().join(',')
22
+ || Object.entries(expected.tmpfs).some(([path, options]) => tmpfs[path] !== options)
23
+ || !Array.isArray(row.Mounts) || row.Mounts.some((mount) => mount.Type !== 'tmpfs' || !Object.hasOwn(tmpfs, mount.Destination))
24
+ || host.RestartPolicy?.Name !== 'no' || host.PidsLimit !== 256 || host.LogConfig?.Type !== 'none'
25
+ || host.Memory !== expected.memoryBytes || host.MemorySwap !== expected.memoryBytes || host.NanoCpus !== expected.nanoCpus
26
+ || !policyMatches(row, policy)) {
27
+ throw new CliError('container_boundary_mismatch', 'The container does not match the approved isolation. No weaker runtime was selected.');
28
+ }
29
+ }
30
+ export function boundaryArguments(value, policy) {
31
+ return ['--user', '2000:2000', '--network', 'none', '--ipc', 'private', '--cgroupns', 'private', '--read-only',
32
+ '--cap-drop', 'ALL', '--cap-add', 'SETUID', '--cap-add', 'SETGID', '--pids-limit', '256',
33
+ '--cpus', String(value.nanoCpus / 10 ** 9), '--memory', String(value.memoryBytes), '--memory-swap', String(value.memoryBytes),
34
+ ...policy.options.flatMap(option => ['--security-opt', option]), '--init=false', '--restart', 'no', '--log-driver', 'none',
35
+ ...(value.interactive ? ['--interactive'] : []),
36
+ ...Object.entries(value.tmpfs).flatMap(([path, options]) => ['--tmpfs', path + ':' + options]),
37
+ '--entrypoint', '/opt/firedrill/bin/python', value.image, ...value.arguments];
38
+ }
@@ -0,0 +1,201 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { lstat, mkdir, open } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { privateDirectory } from './credentials.js';
6
+ import { CliError } from './http.js';
7
+ // Original local-engine policy, not Docker's default profile or a downloaded
8
+ // policy. The outer container still has no parent SYS_ADMIN/NET_ADMIN and no
9
+ // host mounts/network. The retained guest enforces NEW inner namespaces and
10
+ // drops capabilities/identities before any target/generated code is invoked.
11
+ const CALLS = `accept accept4 access alarm arch_prctl bind brk capget capset chdir chmod chown chown32
12
+ clock_getres clock_getres_time64 clock_gettime clock_gettime64 clock_nanosleep clock_nanosleep_time64
13
+ clone close close_range connect copy_file_range creat dup dup2 dup3 epoll_create epoll_create1 epoll_ctl
14
+ epoll_pwait epoll_pwait2 epoll_wait eventfd eventfd2 execve execveat exit exit_group faccessat faccessat2
15
+ fadvise64 fallocate fchdir fchmod fchmodat fchmodat2 fchown fchown32 fchownat fcntl fcntl64 fdatasync
16
+ fgetxattr flistxattr flock fork fremovexattr fsetxattr fstat fstat64 fstatfs fstatfs64 fsync ftruncate ftruncate64
17
+ futex futex_time64 futex_waitv getcpu getcwd getdents getdents64 getegid getegid32 geteuid geteuid32
18
+ getgid getgid32 getgroups getgroups32 getitimer getpeername getpgid getpgrp getpid getppid getpriority
19
+ getrandom getresgid getresgid32 getresuid getresuid32 getrlimit get_robust_list getrusage getsid getsockname
20
+ getsockopt gettid gettimeofday getuid getuid32 getxattr inotify_add_watch inotify_init inotify_init1
21
+ inotify_rm_watch ioctl ipc kill landlock_add_rule landlock_create_ruleset landlock_restrict_self
22
+ lchown lchown32 lgetxattr link linkat listen listxattr llistxattr lremovexattr lseek lsetxattr lstat lstat64
23
+ madvise membarrier memfd_create mincore mkdir mkdirat mlock mlock2 mlockall mmap mmap2 mprotect
24
+ mq_getsetattr mq_notify mq_open mq_timedreceive mq_timedreceive_time64 mq_timedsend mq_timedsend_time64
25
+ mq_unlink mremap msgctl msgget msgrcv msgsnd msync munlock munlockall munmap nanosleep newfstatat
26
+ open openat openat2 pause pipe pipe2 poll ppoll ppoll_time64 prctl pread64 preadv preadv2 prlimit64
27
+ pselect6 pselect6_time64 pwrite64 pwritev pwritev2 read readahead readlink readlinkat readv recvfrom
28
+ recvmmsg recvmmsg_time64 recvmsg removexattr rename renameat renameat2 restart_syscall rmdir rseq
29
+ rt_sigaction rt_sigpending rt_sigprocmask rt_sigqueueinfo rt_sigreturn rt_sigsuspend rt_sigtimedwait
30
+ rt_sigtimedwait_time64 rt_tgsigqueueinfo sched_getaffinity sched_getattr sched_getparam sched_get_priority_max
31
+ sched_get_priority_min sched_getscheduler sched_rr_get_interval sched_rr_get_interval_time64 sched_setaffinity
32
+ sched_setattr sched_setparam sched_setscheduler sched_yield seccomp select semctl semget semop semtimedop
33
+ semtimedop_time64 sendfile sendfile64 sendmmsg sendmsg sendto setfsgid setfsgid32 setfsuid setfsuid32
34
+ setgid setgid32 setgroups setgroups32 setitimer setpgid setpriority setregid setregid32 setresgid setresgid32
35
+ setresuid setresuid32 setreuid setreuid32 setrlimit set_robust_list setsid setsockopt set_tid_address setuid
36
+ setuid32 setxattr shmat shmctl shmdt shmget shutdown sigaltstack signalfd signalfd4 splice stat stat64
37
+ statfs statfs64 statx symlink symlinkat sync sync_file_range syncfs sysinfo tee tgkill time timer_create
38
+ timer_delete timer_getoverrun timer_gettime timer_gettime64 timer_settime timer_settime64 timerfd_create
39
+ timerfd_gettime timerfd_gettime64 timerfd_settime timerfd_settime64 times tkill truncate truncate64 umask
40
+ uname unlink unlinkat utime utimensat utimensat_time64 utimes vfork vmsplice wait4 waitid waitpid write writev`;
41
+ // Privileged namespace operations are still kernel-gated to the NEW user
42
+ // namespace. Only mount/IPC setns is admitted for the fixed root entry's private
43
+ // role descriptors. Kernel ownership/capability checks still apply. Host user/
44
+ // PID/network namespace joins, time/keyring/BPF/module/perf/ptrace/handle/device/
45
+ // uring operations remain absent, not broadly allowed.
46
+ function seccomp(arch) {
47
+ const args = (index, value, valueTwo) => ({ index, value, ...(valueTwo === undefined
48
+ ? { op: 'SCMP_CMP_EQ' } : { op: 'SCMP_CMP_MASKED_EQ', valueTwo }) });
49
+ const allow = (names, arguments_ = []) => ({ names, action: 'SCMP_ACT_ALLOW', ...(arguments_.length ? { args: arguments_ } : {}) });
50
+ const sockets = [1, 2, 10].flatMap(family => (family === 1 ? [1, 2, 5] : [1, 2]).map(kind => allow(['socket'], [args(0, family), args(1, 15, kind)])));
51
+ sockets.push(...[2, 3].map(kind => allow(['socket'], [args(0, 16), args(1, 15, kind), args(2, 0)])));
52
+ const namespaceFlags = 0x10000000 | 0x00020000 | 0x20000000 | 0x08000000 | 0x40000000 | 0x00000200;
53
+ return JSON.stringify({ defaultAction: 'SCMP_ACT_ERRNO', defaultErrnoRet: 1,
54
+ architectures: [arch === 'amd64' ? 'SCMP_ARCH_X86_64' : 'SCMP_ARCH_AARCH64'], syscalls: [
55
+ allow(CALLS.trim().split(/\s+/).sort()),
56
+ // clone3's pointer-based flags cannot be argument-filtered. libc can use
57
+ // its ordinary clone fallback; no unrestricted clone3 exception.
58
+ { names: ['clone3'], action: 'SCMP_ACT_ERRNO', errnoRet: 38 },
59
+ // util-linux --kill-child opens its parent handle with flags0 before
60
+ // polling it. Keep that lifetime guard without admitting getfd/signals.
61
+ allow(['pidfd_open'], [args(1, 0)]),
62
+ allow(['unshare'], [args(0, (0xffffffff ^ namespaceFlags) >>> 0, 0)]),
63
+ ...[0x00020000, 0x08000000].map(kind => allow(['setns'], [args(1, kind)])),
64
+ allow(['mount', 'umount2']),
65
+ allow(['personality'], [args(0, 0)]),
66
+ allow(['personality'], [args(0, 0xffffffff)]),
67
+ ...sockets,
68
+ ...[1, 2, 5].map(kind => allow(['socketpair'], [args(0, 1), args(1, 15, kind)])),
69
+ ] }) + '\n';
70
+ }
71
+ // This named profile is selected only when the daemon advertises AppArmor.
72
+ // It does not replace docker-default, restart a daemon, disable another LSM or
73
+ // grant parent-namespace capabilities. A host administrator loads it separately.
74
+ const APPARMOR_TEMPLATE = `abi <abi/4.0>,
75
+ profile @PROFILE@ flags=(attach_disconnected,mediate_deleted) {
76
+ file,
77
+ userns create,
78
+ capability setuid,
79
+ capability setgid,
80
+ capability setpcap,
81
+ capability chown,
82
+ capability dac_override,
83
+ capability dac_read_search,
84
+ capability fowner,
85
+ capability fsetid,
86
+ capability kill,
87
+ capability sys_admin,
88
+ capability net_admin,
89
+ capability net_bind_service,
90
+ network unix,
91
+ network inet stream,
92
+ network inet dgram,
93
+ network inet6 stream,
94
+ network inet6 dgram,
95
+ network netlink raw,
96
+ network netlink dgram,
97
+ signal (send, receive) peer=@PROFILE@,
98
+ signal (receive) peer=unconfined,
99
+ ptrace (readby) peer=unconfined,
100
+ mount options=(rprivate) -> /,
101
+ mount fstype=proc -> /proc/,
102
+ mount fstype=tmpfs -> /tmp/,
103
+ mount fstype=tmpfs -> /var/tmp/,
104
+ mount fstype=tmpfs -> /dev/shm/,
105
+ mount fstype=tmpfs -> /work/,
106
+ mount fstype=tmpfs -> /home/,
107
+ mount fstype=mqueue -> /dev/mqueue/,
108
+ umount /proc/,
109
+ deny /sys/** wklx,
110
+ deny /proc/sys/** wklx,
111
+ deny /proc/sysrq-trigger rwklx,
112
+ deny /proc/kcore rwklx,
113
+ deny /proc/kallsyms rwklx,
114
+ deny /proc/*/mem rwklx,
115
+ deny /proc/*/attr/** wklx,
116
+ }
117
+ `;
118
+ const sha256 = (value) => createHash('sha256').update(value).digest('hex');
119
+ const APPARMOR_NAME = 'firedrill-local-' + sha256(APPARMOR_TEMPLATE).slice(0, 24);
120
+ async function retain(directory, name, body) {
121
+ const path = join(directory, name);
122
+ try {
123
+ const file = await open(path, 'wx', 0o600);
124
+ try {
125
+ await file.writeFile(body);
126
+ await file.sync();
127
+ }
128
+ finally {
129
+ await file.close();
130
+ }
131
+ }
132
+ catch (error) {
133
+ if (error.code !== 'EEXIST')
134
+ throw error;
135
+ }
136
+ const before = await lstat(path);
137
+ if (!before.isFile() || before.isSymbolicLink() || before.mode & 0o077 || before.size !== Buffer.byteLength(body)
138
+ || process.getuid && before.uid !== process.getuid())
139
+ throw new CliError('local_policy_storage_unsafe', 'The local policy file is not private or changed. It was not replaced.');
140
+ const file = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
141
+ try {
142
+ const actual = await file.stat();
143
+ if (actual.ino !== before.ino || actual.dev !== before.dev || await file.readFile('utf8') !== body) {
144
+ throw new CliError('local_policy_storage_unsafe', 'The local policy bytes changed. No container was started.');
145
+ }
146
+ }
147
+ finally {
148
+ await file.close();
149
+ }
150
+ return path;
151
+ }
152
+ export async function containerPolicy(arch, securityOptions) {
153
+ if (!Array.isArray(securityOptions) || securityOptions.some(value => typeof value !== 'string')
154
+ || !securityOptions.some(value => /^name=seccomp(?:,|$)/.test(value))) {
155
+ throw new CliError('local_seccomp_required', 'The local Docker Engine must provide seccomp enforcement. No weaker runtime was selected.', 2);
156
+ }
157
+ const directory = join(await privateDirectory(), 'container-policy');
158
+ await mkdir(directory, { mode: 0o700 }).catch(error => { if (error.code !== 'EEXIST')
159
+ throw error; });
160
+ const value = await lstat(directory);
161
+ if (!value.isDirectory() || value.isSymbolicLink() || value.mode & 0o077 || process.getuid && value.uid !== process.getuid()) {
162
+ throw new CliError('local_policy_storage_unsafe', 'Use private policy storage owned by this OS user.');
163
+ }
164
+ const body = seccomp(arch), hash = sha256(body);
165
+ const path = await retain(directory, hash + '.seccomp.json', body);
166
+ const apparmorBody = APPARMOR_TEMPLATE.replaceAll('@PROFILE@', APPARMOR_NAME);
167
+ const apparmorPath = await retain(directory, APPARMOR_NAME + '.apparmor', apparmorBody);
168
+ const requiredApparmor = securityOptions.some(item => /^name=apparmor(?:,|$)/.test(item));
169
+ return { schema: 'firedrill.local-security.v1', arch, seccomp: { path, sha256: hash, body },
170
+ apparmor: { name: APPARMOR_NAME, path: apparmorPath, sha256: sha256(apparmorBody) }, requiredApparmor,
171
+ options: ['seccomp=' + path, ...(requiredApparmor ? ['apparmor=' + APPARMOR_NAME] : [])] };
172
+ }
173
+ export function policyMatches(row, policy) {
174
+ const options = row.HostConfig?.SecurityOpt;
175
+ if (!Array.isArray(options) || options.length !== policy.options.length || options.some(value => typeof value !== 'string'))
176
+ return false;
177
+ const profiles = options.filter((value) => value.startsWith('seccomp='));
178
+ if (profiles.length !== 1 || (policy.requiredApparmor ? row.AppArmorProfile !== policy.apparmor.name
179
+ || !options.includes('apparmor=' + policy.apparmor.name) : Boolean(row.AppArmorProfile)))
180
+ return false;
181
+ try {
182
+ const actual = JSON.parse(profiles[0].slice('seccomp='.length));
183
+ const expected = JSON.parse(policy.seccomp.body);
184
+ // All authored numeric fields are exact uint32 values. Key order is not
185
+ // authority; every scalar, syscall, condition and array order must match.
186
+ const canonical = (value) => {
187
+ if (Array.isArray(value))
188
+ return '[' + value.map(canonical).join(',') + ']';
189
+ if (value && typeof value === 'object')
190
+ return '{' + Object.keys(value).sort().map(key => JSON.stringify(key) + ':' + canonical(value[key])).join(',') + '}';
191
+ const encoded = JSON.stringify(value);
192
+ if (encoded === undefined)
193
+ throw new Error('invalid_policy');
194
+ return encoded;
195
+ };
196
+ return canonical(actual) === canonical(expected);
197
+ }
198
+ catch {
199
+ return false;
200
+ }
201
+ }