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,50 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { api } from './auth.js';
3
+ import { CliError } from './http.js';
4
+ import { identifier } from './world-contracts.js';
5
+ import { signRunnerRequest } from './runner-identity.js';
6
+ import { localWorldObservation } from './runner-world-session-protocol.js';
7
+ import { localWorldClaimPath, localWorldClaimTime } from './runner-world-claim.js';
8
+ import { localWorldIdentityMatches, LOCAL_WORLD_IDENTITY_KEYS } from '../../contracts/local-world-native-contracts.js';
9
+ const MAX = 8 * 1024 ** 2;
10
+ const invalid = () => new CliError('local_world_observation_unconfirmed', 'This exact local world observation was not confirmed in cloud history. No target was restarted.');
11
+ const keys = (value, expected) => Object.keys(value).sort().join(',') === [...expected].sort().join(',');
12
+ /** Host-serialized actual native observation, not original status-file bytes
13
+ * or independent attestation. Cloud scans BOTH private matcher sets before
14
+ * retaining exact upload bytes in GCS and recording their owned DB identity.
15
+ * A returned artifact receipt is not execution/cleanup or behavior assessment. */
16
+ export async function retainLocalWorldObservation(owner, configuration, observation, signal) {
17
+ if (configuration.control.schema !== 'firedrill.world-session.v1' || !owner.evidenceUpload)
18
+ throw invalid();
19
+ localWorldObservation(observation, owner, configuration.control);
20
+ const raw = Buffer.from(JSON.stringify(observation));
21
+ try {
22
+ if (!raw.length || raw.length > MAX)
23
+ throw new CliError('local_world_observation_capacity', 'This native observation needs more transfer capacity. No replacement world was started.');
24
+ const digest = createHash('sha256').update(raw).digest('hex'), sent = await localWorldClaimTime(owner, signal);
25
+ const payload = { schema: 'firedrill.local-world-observation-write.v1',
26
+ job_id: owner.job, attempt_id: owner.attempt, lease_id: owner.lease, request_key: owner.request, device_key: owner.device,
27
+ native_session_id: owner.nativeSession, manifest_sha256: configuration.manifest_sha256, session_id: owner.session.session_id,
28
+ input_sha256: owner.session.input_sha256, write_key: randomUUID(), sent_at_ms: sent, size: raw.length,
29
+ sha256: digest, content_base64: raw.toString('base64') };
30
+ const proof = await signRunnerRequest(owner, owner.device, payload, signal);
31
+ const receipt = await api(localWorldClaimPath(owner) + '/world-observations', { actor: owner.owner, workspace: owner.workspace, signal, method: 'POST', body: proof });
32
+ if (!receipt || !localWorldIdentityMatches(receipt, owner, configuration.manifest_sha256)
33
+ || !keys(receipt, [...LOCAL_WORLD_IDENTITY_KEYS.filter(key => key !== 'manifest_sha256'), 'schema', 'session_id', 'lease_id', 'input_sha256', 'manifest_sha256', 'artifact', 'state',
34
+ 'applied', 'server_time', 'provenance', 'target_invocation_observed', 'behavior_assessed'])
35
+ || receipt.schema !== 'firedrill.local-world-observation-receipt.v1' || receipt.session_id !== owner.session.session_id
36
+ || receipt.lease_id !== owner.lease || receipt.input_sha256 !== owner.session.input_sha256
37
+ || receipt.manifest_sha256 !== configuration.manifest_sha256 || receipt.provenance !== 'customer_device'
38
+ || receipt.target_invocation_observed !== false || receipt.behavior_assessed !== false || typeof receipt.applied !== 'boolean'
39
+ || receipt.state !== (observation.status?.state ?? null) || !Number.isFinite(Date.parse(receipt.server_time))
40
+ || !receipt.artifact || !keys(receipt.artifact, ['id', 'size', 'sha256', 'generation'])
41
+ || identifier(receipt.artifact.id) !== receipt.artifact.id || receipt.artifact.sha256 !== digest
42
+ || receipt.artifact.size !== raw.length || typeof receipt.artifact.generation !== 'string'
43
+ || !/^[1-9][0-9]{0,31}$/.test(receipt.artifact.generation))
44
+ throw invalid();
45
+ return receipt;
46
+ }
47
+ finally {
48
+ raw.fill(0); /* JS/HTTP strings are not zeroized memory. */
49
+ }
50
+ }
@@ -0,0 +1,134 @@
1
+ import { CliError } from './http.js';
2
+ import { checkpointResetBaselines } from './world-checkpoint-scopes.js';
3
+ const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
4
+ const exact = (value, names) => Object.keys(value).sort().join(',') === names.sort().join(',');
5
+ const finiteCount = (value) => Number.isSafeInteger(value) && Number(value) >= 0;
6
+ function sameValue(left, right) {
7
+ if (record(left) && record(right))
8
+ return Object.keys(left).length === Object.keys(right).length
9
+ && Object.entries(left).every(([key, value]) => Object.hasOwn(right, key) && sameValue(value, right[key]));
10
+ return left === right;
11
+ }
12
+ const invalid = () => new CliError('local_world_status_invalid', 'The native world status does not match this exact local session.');
13
+ export function nativeFilterReference(value) {
14
+ if (!record(value) || !exact(value, ['schema', 'scope', 'sha256', 'size', 'pattern_count'])
15
+ || value.schema !== 'firedrill.native-filter-reference.v1' || value.scope !== 'native_database_credentials'
16
+ || typeof value.sha256 !== 'string' || !/^[a-f0-9]{64}$/.test(value.sha256)
17
+ || !finiteCount(value.size) || Number(value.size) < 1 || Number(value.size) > 64 * 1024 ** 2
18
+ || !finiteCount(value.pattern_count) || Number(value.pattern_count) > 65536)
19
+ throw invalid();
20
+ }
21
+ /** Native observations, not independent managed attestation or trial scoring. */
22
+ export function localWorldStatus(value, owner, control) {
23
+ if (value === null)
24
+ return; // No startup status is not fabricated failure/cleanup.
25
+ if (record(value) && value.state === 'failed' && exact(value, ['schema', 'session_id', 'operation_id', 'state', 'code',
26
+ 'target_invocation_observed', 'behavior_assessed'])) {
27
+ if (value.schema !== 'firedrill.world-session-status.v7' || value.session_id !== owner.session.session_id
28
+ || value.operation_id !== owner.lease || typeof value.code !== 'string' || !/^[a-z_]{1,64}$/.test(value.code)
29
+ || value.target_invocation_observed !== false || value.behavior_assessed !== false)
30
+ throw invalid();
31
+ return; // The original native fatal diagnostic has no topology/cleanup facts.
32
+ }
33
+ const fields = ['schema', 'session_id', 'operation_id', 'world_id', 'configuration_id', 'configuration_digest', 'bundle_digest',
34
+ 'state', 'code', 'observed_at', 'elapsed_ms', 'completed_command_sequence', 'reset_count', 'native_cleanup_finished',
35
+ 'isolation', 'topology', 'surface_declarations', 'checkpoint', 'native_filters', 'fork', 'dataset', 'target_invocation_observed', 'behavior_assessed'];
36
+ if (record(value) && Object.hasOwn(value, 'lease'))
37
+ fields.push('lease');
38
+ if (record(value) && (Object.hasOwn(value, 'application_checkpoint') || Object.hasOwn(value, 'application_resume')))
39
+ fields.push('application_checkpoint', 'application_resume');
40
+ if (!record(value) || !exact(value, fields) || value.schema !== 'firedrill.world-session-status.v7'
41
+ || value.session_id !== owner.session.session_id || value.operation_id !== owner.lease || value.world_id !== owner.world
42
+ || value.configuration_id !== owner.session.configuration_id || value.configuration_digest !== owner.configurationDigest
43
+ || value.bundle_digest !== control.bundle_digest
44
+ || !['starting', 'active', 'resetting', 'checkpointing', 'stopping', 'stopped', 'failed'].includes(String(value.state))
45
+ || typeof value.code !== 'string' || value.code !== '' && !/^[a-z][a-z0-9_]{0,127}$/.test(value.code)
46
+ || typeof value.observed_at !== 'string' || !Number.isFinite(Date.parse(value.observed_at))
47
+ || !finiteCount(value.elapsed_ms) || !finiteCount(value.completed_command_sequence) || !finiteCount(value.reset_count)
48
+ || typeof value.native_cleanup_finished !== 'boolean' || !record(value.isolation)
49
+ || value.topology !== null && !record(value.topology) || !Array.isArray(value.surface_declarations)
50
+ || value.surface_declarations.some(item => !record(item)) || !record(value.checkpoint)
51
+ || value.target_invocation_observed !== false || value.behavior_assessed !== false)
52
+ throw invalid();
53
+ if (value.lease !== undefined && (!record(value.lease) || !exact(value.lease, ['revision', 'expires_at'])
54
+ || value.lease.revision !== 0 || value.lease.expires_at !== control.expires_at))
55
+ throw invalid();
56
+ if (value.application_checkpoint !== undefined) {
57
+ const declaration = value.application_checkpoint;
58
+ if (!record(declaration) || (declaration.available === false ? !exact(declaration, ['available'])
59
+ : declaration.available !== true || !exact(declaration, ['available', 'driver_digest', 'recipe'])
60
+ || typeof declaration.driver_digest !== 'string' || !/^[a-f0-9]{64}$/.test(declaration.driver_digest) || !record(declaration.recipe)))
61
+ throw invalid();
62
+ const resume = value.application_resume, selected = control.application_checkpoint;
63
+ if (selected === null && resume !== null || selected !== null && value.state === 'active' && resume === null)
64
+ throw invalid();
65
+ if (resume !== null && (!selected || !record(resume) || !exact(resume, ['checkpoint_id', 'checkpoint_session_id', 'sha256', 'driver_digest', 'request_id',
66
+ 'new_execution_id', 'event_watermark', 'applied_at', 'components', 'excluded', 'continuity'])
67
+ || ['checkpoint_id', 'checkpoint_session_id', 'sha256', 'driver_digest', 'event_watermark'].some(key => resume[key] !== selected[key])
68
+ || resume.new_execution_id !== owner.session.session_id || resume.continuity !== 'application_supported_new_process'
69
+ || typeof resume.applied_at !== 'string' || !Number.isFinite(Date.parse(resume.applied_at))
70
+ || Date.parse(resume.applied_at) > Date.parse(value.observed_at)))
71
+ throw invalid();
72
+ }
73
+ if (control.dataset !== null && value.state === 'active' && value.dataset === null)
74
+ throw invalid();
75
+ if (control.initial_checkpoint === null && value.fork !== null
76
+ || control.initial_checkpoint !== null && value.state === 'active' && value.fork === null)
77
+ throw invalid();
78
+ if (value.fork !== null) {
79
+ const proof = value.fork, saved = control.initial_checkpoint;
80
+ if (!saved || !record(proof) || !exact(proof, ['schema', 'session_id', 'checkpoint_id', 'checkpoint_session_id', 'sha256',
81
+ 'schema_sha256', 'clock_mode', 'scope', 'target_state_complete', 'before_source_start', 'applied_at', 'reset_baseline'])
82
+ || proof.schema !== 'firedrill.world-fork-origin.v1' || proof.session_id !== owner.session.session_id
83
+ || ['checkpoint_id', 'checkpoint_session_id', 'sha256', 'schema_sha256', 'clock_mode', 'scope'].some(key => proof[key] !== saved[key])
84
+ || proof.reset_baseline !== checkpointResetBaselines[saved.scope]
85
+ || proof.target_state_complete !== false || proof.before_source_start !== true
86
+ || typeof proof.applied_at !== 'string' || !Number.isFinite(Date.parse(proof.applied_at))
87
+ || Date.parse(proof.applied_at) > Date.parse(value.observed_at))
88
+ throw invalid();
89
+ }
90
+ if (value.dataset !== null) {
91
+ const proof = value.dataset;
92
+ if (control.dataset === null || !record(proof) || !exact(proof, ['schema', 'selection', 'applications', 'latest_worlds', 'scope',
93
+ 'process_memory_included', 'before_source_start', 'real_account_effects'])
94
+ || proof.schema !== 'firedrill.world-dataset-application.v1' || !record(proof.selection)
95
+ || !sameValue(proof.selection, control.dataset)
96
+ || !finiteCount(proof.applications) || Number(proof.applications) < 1
97
+ || !['typed_edits_to_owned_native_postgres_seed', 'typed_edits_to_declared_sqlite_files',
98
+ 'typed_edits_to_owned_postgres_and_declared_sqlite_files'].includes(String(proof.scope))
99
+ || proof.process_memory_included !== false || proof.before_source_start !== (proof.scope === 'typed_edits_to_owned_native_postgres_seed')
100
+ || proof.real_account_effects !== false
101
+ || !Array.isArray(proof.latest_worlds) || proof.latest_worlds.length !== 1
102
+ || proof.latest_worlds.some(row => !record(row) || !exact(row, ['world_index', 'application', 'applied_at', 'affected_rows',
103
+ 'schema_sha256', 'prepared_sha256', 'applied_sha256']) || row.world_index !== 0
104
+ || !finiteCount(row.application) || row.application !== proof.applications
105
+ || !finiteCount(row.affected_rows) || Number(row.affected_rows) > Number(control.dataset.edit_count)
106
+ || typeof row.applied_at !== 'string' || !Number.isFinite(Date.parse(row.applied_at)) || Date.parse(row.applied_at) > Date.parse(value.observed_at)
107
+ || ['schema_sha256', 'prepared_sha256', 'applied_sha256'].some(key => typeof row[key] !== 'string' || !/^[a-f0-9]{64}$/.test(row[key]))))
108
+ throw invalid();
109
+ }
110
+ if (value.native_filters !== null) {
111
+ nativeFilterReference(value.native_filters);
112
+ }
113
+ }
114
+ export function localWorldObservation(value, owner, control) {
115
+ if (value.operation_id !== owner.lease || value.session_id !== owner.session.session_id)
116
+ throw invalid();
117
+ localWorldStatus(value.status, owner, control);
118
+ const launch = value.launch;
119
+ if (launch === null)
120
+ return;
121
+ if (!record(launch) || launch.launch_id !== owner.lease)
122
+ throw invalid();
123
+ if (launch.state === 'claimed' || launch.state === 'running') {
124
+ if (!exact(launch, ['launch_id', 'state', 'process_present']) || typeof launch.process_present !== 'boolean')
125
+ throw invalid();
126
+ }
127
+ else if (launch.state === 'exited') {
128
+ if (!exact(launch, ['launch_id', 'state', 'exit_code']) || !Number.isSafeInteger(launch.exit_code)
129
+ || Number(launch.exit_code) < -128 || Number(launch.exit_code) > 255)
130
+ throw invalid();
131
+ }
132
+ else if (launch.state !== 'launch_failed' || !exact(launch, ['launch_id', 'state']))
133
+ throw invalid();
134
+ }
@@ -0,0 +1,40 @@
1
+ import { api } from './auth.js';
2
+ import { CliError } from './http.js';
3
+ import { savedRecordSelection, savedCollectionsPageMatches, savedRecordsPageMatches, savedRecordDetailMatches } from '../../contracts/saved-record-contracts.js';
4
+ export async function readSavedRecords(prefix, observation, collection, position, options, command, output) {
5
+ if (collection !== undefined && !/^[a-f0-9]{64}$/.test(collection)
6
+ || position !== undefined && (!/^(0|[1-9][0-9]{0,14})$/.test(position) || !Number.isSafeInteger(Number(position)))
7
+ || position !== undefined && (options.page !== undefined || options.search !== undefined)
8
+ || options.page !== undefined && !/^[1-9][0-9]{0,8}$/.test(options.page) || (options.search?.length ?? 0) > 200) {
9
+ throw new CliError('arguments_invalid', 'Use the saved collection key and zero-based record position. --page and --search apply only to lists.', 2);
10
+ }
11
+ const selected = savedRecordSelection(prefix, options.workspace, observation);
12
+ if (!selected)
13
+ throw new CliError('saved_record_selection_invalid', 'Choose a saved capture in the current workspace.', 2);
14
+ const auth = { actor: options.actor, workspace: options.workspace, signal: options.signal, maximumResponseBytes: 16 * 1024 ** 2 };
15
+ const base = `${prefix}/state/collections`, query = `observation=${observation}&page=${options.page ?? '1'}&q=${encodeURIComponent(options.search ?? '')}`;
16
+ const unconfirmed = () => new CliError('state_observation_changed', 'The selected saved records could not be confirmed. Open the capture again.', 2);
17
+ const quote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
18
+ const continuation = (page) => `\nPage ${page.page}; ${page.count.toLocaleString()} matching entries.${page.next
19
+ ? `\nContinue: ${command}${collection ? ' ' + collection : ''} --page ${page.page + 1}${options.search ? ' --search ' + quote(options.search) : ''}${options.json ? ' --json' : ''}` : ''}`;
20
+ if (!collection) {
21
+ const value = await api(`${base}?${query}`, auth);
22
+ if (!savedCollectionsPageMatches(value, selected, options.search))
23
+ throw unconfirmed();
24
+ output('saved_collections', value, (value.results.map(row => `${row.key}\n${row.store ? row.store + ' / ' : ''}${row.name} · ${row.row_count.toLocaleString()} records`).join('\n\n')
25
+ || 'No matching collections in this capture.') + continuation(value));
26
+ return;
27
+ }
28
+ const path = `${base}/${collection}/records`;
29
+ if (position !== undefined) {
30
+ const value = await api(`${path}/${position}?observation=${observation}`, auth);
31
+ if (!savedRecordDetailMatches(value, selected, collection, Number(position)))
32
+ throw unconfirmed();
33
+ output('saved_record', value, JSON.stringify(value, null, 2));
34
+ return;
35
+ }
36
+ const value = await api(`${path}?${query}`, auth);
37
+ if (!savedRecordsPageMatches(value, selected, collection, options.search))
38
+ throw unconfirmed();
39
+ output('saved_records', value, JSON.stringify(value, null, 2) + continuation(value));
40
+ }
@@ -0,0 +1,212 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { createInterface } from 'node:readline/promises';
3
+ import { api } from './auth.js';
4
+ import { CliError } from './http.js';
5
+ import { selectMany, selectOne } from './prompts.js';
6
+ import { requestInput } from './request-input.js';
7
+ import { identifier } from './world-contracts.js';
8
+ import { selectedWorld } from './world-access.js';
9
+ import { preparation } from './world-agent.js';
10
+ const actions = ['create', 'edit', 'duplicate', 'archive', 'restore', 'definition', 'history'];
11
+ const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
12
+ function editableNumbers(value) {
13
+ if (typeof value === 'number' && (!Number.isFinite(value) || Number.isInteger(value) && !Number.isSafeInteger(value)))
14
+ throw new CliError('scenario_number_capacity', 'This definition contains numbers that cannot be safely edited in this terminal. Use an original JSON file with --file; its number literals are sent unchanged.', 2);
15
+ if (Array.isArray(value))
16
+ value.forEach(editableNumbers);
17
+ else if (object(value))
18
+ Object.values(value).forEach(editableNumbers);
19
+ }
20
+ async function line(label, maximum, signal, initial = '', optional = false) {
21
+ const prompt = createInterface({ input: process.stdin, output: process.stderr, terminal: false });
22
+ try {
23
+ const entered = (await prompt.question(`${label}${initial ? ' (blank to keep)' : ''}: `, { signal })).trim();
24
+ const value = entered || initial;
25
+ if ((!optional && !value) || value.length > maximum || /[\u0000-\u001f\u007f-\u009f]/u.test(value))
26
+ throw new CliError('scenario_input_invalid', 'Use text within the field capacity. Use --file for multiline or larger scenario inputs.', 2);
27
+ return value;
28
+ }
29
+ finally {
30
+ prompt.close();
31
+ }
32
+ }
33
+ async function chooseScenario(scope, action, options) {
34
+ const auth = { actor: scope.owner, workspace: scope.workspace, signal: options.signal };
35
+ let page = 1, search = options.search ?? '';
36
+ while (true) {
37
+ const values = await api(`${scope.prefix}/scenarios?${new URLSearchParams({ page: String(page), q: search,
38
+ status: action === 'restore' ? 'archived' : ['history', 'definition'].includes(action) ? 'all' : 'active' })}`, auth);
39
+ const choices = values.results.map(row => ({ value: row.id, label: row.name, detail: `Revision ${row.revision} · ${row.state}` }));
40
+ if (page > 1)
41
+ choices.unshift({ value: 'previous', label: 'Previous page', detail: '' });
42
+ if (values.next)
43
+ choices.push({ value: 'next', label: 'Next page', detail: '' });
44
+ choices.push({ value: 'search', label: 'Search scenarios', detail: search }, { value: 'cancel', label: 'Cancel', detail: '' });
45
+ const selected = await selectOne('Scenario', choices, options.signal);
46
+ if (selected === 'next') {
47
+ page++;
48
+ continue;
49
+ }
50
+ if (selected === 'previous') {
51
+ page--;
52
+ continue;
53
+ }
54
+ if (selected === 'search') {
55
+ search = await line('Find a scenario (blank for all)', 200, options.signal, '', true);
56
+ page = 1;
57
+ continue;
58
+ }
59
+ if (selected === 'cancel')
60
+ throw new CliError('canceled', 'No scenario was changed.', 130);
61
+ return identifier(selected);
62
+ }
63
+ }
64
+ async function participant(signal, current) {
65
+ const original = current ?? null;
66
+ const action = await selectOne('Synthetic user', [...(original ? [{ value: 'keep', label: 'Keep current synthetic user' }] : []),
67
+ { value: 'remove', label: original ? 'Remove synthetic user' : 'No synthetic user' }, { value: 'edit', label: original ? 'Edit synthetic user' : 'Configure a synthetic user' }], signal);
68
+ if (action === 'keep')
69
+ return original;
70
+ if (action === 'remove')
71
+ return null;
72
+ const previous = (field) => original?.[field] ?? '';
73
+ return { ...original, name: await line('Name', 240, signal, previous('name')), personality: await line('Behavior', 4000, signal, previous('personality')),
74
+ communication_style: await line('Communication style', 4000, signal, previous('communication_style')),
75
+ initial_message: await line('Opening message', 4000, signal, previous('initial_message')) };
76
+ }
77
+ async function interactiveDefinition(scope, options, original) {
78
+ const current = await preparation(scope, options.signal);
79
+ if (original && (!original.current || original.world_revision !== current.basis.world_revision || original.definition_locked || !object(original.editor)))
80
+ throw new CliError('scenario_revision_conflict', 'Open the current editable scenario revision before changing it.', 2);
81
+ const definition = { ...(original?.editor ?? {}) };
82
+ editableNumbers(definition);
83
+ const fixture = object(definition.fixture) ? { ...definition.fixture } : {};
84
+ const task = object(fixture.http_task) && fixture.http_task.schema === 'firedrill.http-task.v1';
85
+ let single = task;
86
+ if (!original) {
87
+ const values = await api(`${scope.prefix}/scenarios?page_size=1`, { actor: scope.owner, workspace: scope.workspace, signal: options.signal });
88
+ if (!['conversation', 'browser_chat', 'single_request'].includes(values.invocation_mode ?? '')) {
89
+ const mode = await selectOne('Scenario input', [{ value: 'conversation', label: 'Conversational turns' },
90
+ { value: 'single_request', label: 'One task request' }, { value: 'cancel', label: 'Cancel' }], options.signal);
91
+ if (mode === 'cancel')
92
+ return null;
93
+ single = mode === 'single_request';
94
+ }
95
+ else
96
+ single = values.invocation_mode === 'single_request';
97
+ }
98
+ let title = original?.name ?? '';
99
+ const fields = original ? await selectMany('Fields to change', [
100
+ { value: 'title', label: 'Name' }, { value: 'instruction', label: 'Task and goal' },
101
+ ...(single ? [{ value: 'task', label: 'Task input JSON' }] : [{ value: 'max_turns', label: 'Maximum turns' }, { value: 'persona', label: 'Synthetic user' }]),
102
+ ], options.signal) : ['title', 'instruction', single ? 'task' : 'max_turns', ...(single ? [] : ['persona'])];
103
+ if (!fields.length)
104
+ return null;
105
+ if (fields.includes('title'))
106
+ title = await line('Scenario name', 255, options.signal, title);
107
+ if (fields.includes('instruction'))
108
+ definition.instruction = await line('Task and goal', 16000, options.signal, typeof definition.instruction === 'string' ? definition.instruction : '');
109
+ if (fields.includes('max_turns')) {
110
+ const turns = Number(await line('Maximum turns', 6, options.signal, String(definition.max_turns ?? 10)));
111
+ if (!Number.isSafeInteger(turns) || turns < 1 || turns > 100000)
112
+ throw new CliError('scenario_turns_invalid', 'Use a positive whole number within runtime capacity.', 2);
113
+ definition.max_turns = turns;
114
+ }
115
+ if (fields.includes('persona'))
116
+ definition.persona = await participant(options.signal, definition.persona);
117
+ if (fields.includes('task')) {
118
+ const raw = await line('Task input JSON', 32000, options.signal);
119
+ let body;
120
+ try {
121
+ body = JSON.parse(raw);
122
+ }
123
+ catch {
124
+ throw new CliError('scenario_input_invalid', 'Use a JSON object for task input.', 2);
125
+ }
126
+ if (!object(body))
127
+ throw new CliError('scenario_input_invalid', 'Use a JSON object for task input.', 2);
128
+ editableNumbers(body);
129
+ definition.fixture = { ...fixture, http_task: { schema: 'firedrill.http-task.v1', body } };
130
+ definition.max_turns = 1;
131
+ definition.persona = null;
132
+ }
133
+ return { title, world_revision: current.basis.world_revision, ...(original ? { revision: original.revision } : {}), definition };
134
+ }
135
+ export async function scenarioAuthoring(args, options, output) {
136
+ const action = args[0], interactive = !options.json && !!process.stdin.isTTY && !!process.stderr.isTTY;
137
+ if (!actions.includes(action) || args.length > (action === 'create' ? 1 : 2)
138
+ || options.file && !['create', 'edit'].includes(action) || options.approve && ['history', 'definition'].includes(action)
139
+ || action !== 'history' && options.page !== undefined || (options.search?.length ?? 0) > 200
140
+ || options.search !== undefined && (action === 'create' || Boolean(args[1])))
141
+ throw new CliError('arguments_invalid', 'Use scenarios create, edit, duplicate, archive, restore, definition or history. --file applies to create/edit.', 2);
142
+ const page = options.page ?? '1';
143
+ if (!/^[1-9][0-9]{0,8}$/.test(page))
144
+ throw new CliError('arguments_invalid', 'Choose a positive history page.', 2);
145
+ if (!interactive && action !== 'create' && !args[1])
146
+ throw new CliError('scenario_required', 'Choose a scenario ID and --world.', 2);
147
+ if (!interactive && ['create', 'edit'].includes(action) && !options.file)
148
+ throw new CliError('scenario_file_required', 'Pass --file with the reviewed canonical scenario change.', 2);
149
+ if (!interactive && !['definition', 'history'].includes(action) && !options.approve)
150
+ throw new CliError('approval_required', 'Use --approve-change to save the reviewed scenario change. No agent will run.', 2);
151
+ const scope = await selectedWorld({ ...options, interactive });
152
+ const auth = { actor: scope.owner, workspace: scope.workspace, signal: options.signal };
153
+ const id = action === 'create' ? null : args[1] ? identifier(args[1]) : await chooseScenario(scope, action, options);
154
+ if (action === 'history') {
155
+ const result = await api(`${scope.prefix}/scenarios/${id}/history?page=${page}`, auth);
156
+ output('scenario_history', result, (result.results.map(row => `${row.id}\n${row.name} · Revision ${row.revision}${row.current ? ' (current)' : ''} · ${row.state}`).join('\n\n') || 'No retained revisions.')
157
+ + `\nPage ${result.page}, ${result.count} revisions.${result.next ? ` Continue with --page ${result.page + 1}.` : ''}`);
158
+ return;
159
+ }
160
+ const original = id ? await api(`${scope.prefix}/scenarios/${id}?editor=1`, auth) : undefined;
161
+ if (original && (original.id !== id || original.world_id !== scope.world || !Number.isSafeInteger(original.revision)))
162
+ throw new CliError('scenario_response_invalid', 'The original scenario could not be confirmed. No change was submitted.');
163
+ if (action === 'definition') {
164
+ if (!object(original?.editor))
165
+ throw new CliError('scenario_definition_unavailable', 'The editable definition is not available. Source-comparison definitions remain frozen.', 2);
166
+ editableNumbers(original.editor);
167
+ const value = { title: original.name, world_revision: original.world_revision, revision: original.revision, definition: original.editor };
168
+ output('scenario_definition', value, JSON.stringify(value, null, 2));
169
+ return;
170
+ }
171
+ let body, bodyJson;
172
+ if (['create', 'edit'].includes(action)) {
173
+ // Keep file-authored number literals and nested inputs unchanged on the wire.
174
+ // Parsed values below are used only for the closed envelope/review checks.
175
+ if (options.file)
176
+ bodyJson = await requestInput(options.file, options.signal, 1024 * 1024);
177
+ const value = bodyJson !== undefined ? JSON.parse(bodyJson)
178
+ : await interactiveDefinition(scope, options, original);
179
+ if (value === null) {
180
+ output('scenario_unchanged', { changed: false }, 'No scenario was changed.');
181
+ return;
182
+ }
183
+ if (!object(value) || Object.keys(value).some(key => !['title', 'world_revision', 'revision', 'definition'].includes(key))
184
+ || typeof value.world_revision !== 'number' || !Number.isSafeInteger(value.world_revision) || value.world_revision < 1
185
+ || !object(value.definition) || typeof value.title !== 'string' || !value.title.trim()
186
+ || action === 'create' && value.revision !== undefined && value.revision !== null
187
+ || action === 'edit' && value.revision !== original?.revision)
188
+ throw new CliError('scenario_input_invalid', 'Use title, world_revision, definition and, for editing, the original revision. Export scenarios definition to review the current input.', 2);
189
+ body = value;
190
+ }
191
+ else {
192
+ if (!original?.current || original.definition_locked)
193
+ throw new CliError('scenario_revision_conflict', 'Choose the current editable scenario revision.', 2);
194
+ body = { action, title: action === 'duplicate' ? `${original.name.slice(0, 245)} (copy)` : original.name,
195
+ world_revision: original.world_revision, revision: original.revision };
196
+ }
197
+ output('scenario_review', { action, item_id: id, world_id: scope.world, world_revision: body.world_revision,
198
+ revision: body.revision ?? null, title: body.title }, `${action === 'create' ? 'Create' : action[0].toUpperCase() + action.slice(1)}: ${String(body.title)}\nWorld revision ${body.world_revision}${body.revision ? ` · Scenario revision ${body.revision}` : ''}\nA saved change requires world validation before a future simulation. Existing plans and results are unchanged.`);
199
+ if (!options.approve && !await selectOne('Save this scenario change?', [{ value: false, label: 'Cancel' }, { value: true, label: 'Save change' }], options.signal))
200
+ return;
201
+ const key = randomUUID();
202
+ output('scenario_request', { request_key: key, world_id: scope.world, workspace_id: scope.workspace }, `Recovery: firedrill scenarios request ${key} --world ${scope.world} --workspace ${scope.workspace}\nInspect this original request if its reply is interrupted. Do not repeat the save.`);
203
+ const saved = await api(`${scope.prefix}/scenarios${id ? '/' + id : ''}`, { ...auth, method: 'POST', idempotencyKey: key,
204
+ ...(bodyJson === undefined ? { body } : { bodyJson }) });
205
+ const receipt = await api(`${scope.prefix}/scenario-request?request_key=${key}`, auth);
206
+ if (!saved || typeof saved.id !== 'string' || saved.world_id !== scope.world || !Number.isSafeInteger(saved.revision)
207
+ || receipt.schema !== 'firedrill.scenario-change-receipt.v1' || receipt.actor_id !== scope.owner || receipt.workspace_id !== scope.workspace
208
+ || receipt.world_id !== scope.world || receipt.request_key !== key || receipt.state !== 'accepted' || receipt.resource_available !== true
209
+ || receipt.item_id !== saved.id || receipt.revision !== saved.revision)
210
+ throw new CliError('scenario_response_invalid', 'The original save could not be confirmed. Inspect the printed recovery request. No change was repeated.');
211
+ output('scenario_saved', { request: receipt, scenario: saved }, `${saved.name} · Revision ${saved.revision} · ${saved.state}\n${saved.id}\nScenario saved. No agent was run.`);
212
+ }