tracegrove 0.0.0-stage → 0.3.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 (721) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +588 -2
  3. package/conformance/coordination-vectors.json +377 -0
  4. package/dist/adapters/browser/capabilities.d.ts +45 -0
  5. package/dist/adapters/browser/capabilities.js +14 -0
  6. package/dist/adapters/browser/capabilities.js.map +1 -0
  7. package/dist/adapters/browser/driver.d.ts +45 -0
  8. package/dist/adapters/browser/driver.js +295 -0
  9. package/dist/adapters/browser/driver.js.map +1 -0
  10. package/dist/adapters/browser/session.d.ts +21 -0
  11. package/dist/adapters/browser/session.js +87 -0
  12. package/dist/adapters/browser/session.js.map +1 -0
  13. package/dist/adapters/http/capabilities.d.ts +2 -0
  14. package/dist/adapters/http/capabilities.js +21 -0
  15. package/dist/adapters/http/capabilities.js.map +1 -0
  16. package/dist/adapters/http/driver.d.ts +55 -0
  17. package/dist/adapters/http/driver.js +125 -0
  18. package/dist/adapters/http/driver.js.map +1 -0
  19. package/dist/adapters/job/capabilities.d.ts +45 -0
  20. package/dist/adapters/job/capabilities.js +8 -0
  21. package/dist/adapters/job/capabilities.js.map +1 -0
  22. package/dist/adapters/job/driver.d.ts +26 -0
  23. package/dist/adapters/job/driver.js +110 -0
  24. package/dist/adapters/job/driver.js.map +1 -0
  25. package/dist/adapters/job/types.d.ts +9 -0
  26. package/dist/adapters/job/types.js +2 -0
  27. package/dist/adapters/job/types.js.map +1 -0
  28. package/dist/adapters/mcp/capabilities.d.ts +46 -0
  29. package/dist/adapters/mcp/capabilities.js +17 -0
  30. package/dist/adapters/mcp/capabilities.js.map +1 -0
  31. package/dist/adapters/mcp/driver.d.ts +10 -0
  32. package/dist/adapters/mcp/driver.js +83 -0
  33. package/dist/adapters/mcp/driver.js.map +1 -0
  34. package/dist/adapters/poll.d.ts +12 -0
  35. package/dist/adapters/poll.js +31 -0
  36. package/dist/adapters/poll.js.map +1 -0
  37. package/dist/authoring/activity.d.ts +17 -0
  38. package/dist/authoring/activity.js +18 -0
  39. package/dist/authoring/activity.js.map +1 -0
  40. package/dist/authoring/agent.d.ts +70 -0
  41. package/dist/authoring/agent.js +268 -0
  42. package/dist/authoring/agent.js.map +1 -0
  43. package/dist/authoring/appLaunch.d.ts +7 -0
  44. package/dist/authoring/appLaunch.js +32 -0
  45. package/dist/authoring/appLaunch.js.map +1 -0
  46. package/dist/authoring/appLocation.d.ts +2 -0
  47. package/dist/authoring/appLocation.js +5 -0
  48. package/dist/authoring/appLocation.js.map +1 -0
  49. package/dist/authoring/browser.d.ts +15 -0
  50. package/dist/authoring/browser.js +20 -0
  51. package/dist/authoring/browser.js.map +1 -0
  52. package/dist/authoring/compile.d.ts +47 -0
  53. package/dist/authoring/compile.js +508 -0
  54. package/dist/authoring/compile.js.map +1 -0
  55. package/dist/authoring/discover.d.ts +43 -0
  56. package/dist/authoring/discover.js +149 -0
  57. package/dist/authoring/discover.js.map +1 -0
  58. package/dist/authoring/environmentTemplates.d.ts +3 -0
  59. package/dist/authoring/environmentTemplates.js +24 -0
  60. package/dist/authoring/environmentTemplates.js.map +1 -0
  61. package/dist/authoring/heal.d.ts +108 -0
  62. package/dist/authoring/heal.js +723 -0
  63. package/dist/authoring/heal.js.map +1 -0
  64. package/dist/authoring/index.d.ts +14 -0
  65. package/dist/authoring/index.js +15 -0
  66. package/dist/authoring/index.js.map +1 -0
  67. package/dist/authoring/init.d.ts +21 -0
  68. package/dist/authoring/init.js +141 -0
  69. package/dist/authoring/init.js.map +1 -0
  70. package/dist/authoring/localSettings.d.ts +33 -0
  71. package/dist/authoring/localSettings.js +31 -0
  72. package/dist/authoring/localSettings.js.map +1 -0
  73. package/dist/authoring/media.d.ts +10 -0
  74. package/dist/authoring/media.js +37 -0
  75. package/dist/authoring/media.js.map +1 -0
  76. package/dist/authoring/module.d.ts +2 -0
  77. package/dist/authoring/module.js +38 -0
  78. package/dist/authoring/module.js.map +1 -0
  79. package/dist/authoring/run.d.ts +74 -0
  80. package/dist/authoring/run.js +242 -0
  81. package/dist/authoring/run.js.map +1 -0
  82. package/dist/authoring/runSource.d.ts +6 -0
  83. package/dist/authoring/runSource.js +24 -0
  84. package/dist/authoring/runSource.js.map +1 -0
  85. package/dist/authoring/savedRun.d.ts +13 -0
  86. package/dist/authoring/savedRun.js +94 -0
  87. package/dist/authoring/savedRun.js.map +1 -0
  88. package/dist/authoring/schema.d.ts +574 -0
  89. package/dist/authoring/schema.js +147 -0
  90. package/dist/authoring/schema.js.map +1 -0
  91. package/dist/authoring/snapshotSource.d.ts +13 -0
  92. package/dist/authoring/snapshotSource.js +41 -0
  93. package/dist/authoring/snapshotSource.js.map +1 -0
  94. package/dist/authoring/sourceSelection.d.ts +34 -0
  95. package/dist/authoring/sourceSelection.js +13 -0
  96. package/dist/authoring/sourceSelection.js.map +1 -0
  97. package/dist/authoring/sources.d.ts +5 -0
  98. package/dist/authoring/sources.js +65 -0
  99. package/dist/authoring/sources.js.map +1 -0
  100. package/dist/authoring/status.d.ts +48 -0
  101. package/dist/authoring/status.js +100 -0
  102. package/dist/authoring/status.js.map +1 -0
  103. package/dist/authoring/typed.d.ts +6 -0
  104. package/dist/authoring/typed.js +5 -0
  105. package/dist/authoring/typed.js.map +1 -0
  106. package/dist/authoring/ui.d.ts +10 -0
  107. package/dist/authoring/ui.js +486 -0
  108. package/dist/authoring/ui.js.map +1 -0
  109. package/dist/authoring/uiPage.d.ts +1 -0
  110. package/dist/authoring/uiPage.js +358 -0
  111. package/dist/authoring/uiPage.js.map +1 -0
  112. package/dist/authoring/uiSourceControls.d.ts +2 -0
  113. package/dist/authoring/uiSourceControls.js +41 -0
  114. package/dist/authoring/uiSourceControls.js.map +1 -0
  115. package/dist/authoring/verificationSource.d.ts +41 -0
  116. package/dist/authoring/verificationSource.js +46 -0
  117. package/dist/authoring/verificationSource.js.map +1 -0
  118. package/dist/authoring/workspace.d.ts +33 -0
  119. package/dist/authoring/workspace.js +58 -0
  120. package/dist/authoring/workspace.js.map +1 -0
  121. package/dist/cli/arguments.d.ts +288 -0
  122. package/dist/cli/arguments.js +121 -0
  123. package/dist/cli/arguments.js.map +1 -0
  124. package/dist/cli/cleanup.d.ts +18 -0
  125. package/dist/cli/cleanup.js +40 -0
  126. package/dist/cli/cleanup.js.map +1 -0
  127. package/dist/cli/doctor.d.ts +51 -0
  128. package/dist/cli/doctor.js +118 -0
  129. package/dist/cli/doctor.js.map +1 -0
  130. package/dist/cli/errors.d.ts +2 -0
  131. package/dist/cli/errors.js +84 -0
  132. package/dist/cli/errors.js.map +1 -0
  133. package/dist/cli/jsonFile.d.ts +2 -0
  134. package/dist/cli/jsonFile.js +15 -0
  135. package/dist/cli/jsonFile.js.map +1 -0
  136. package/dist/cli/main.d.ts +2 -0
  137. package/dist/cli/main.js +603 -0
  138. package/dist/cli/main.js.map +1 -0
  139. package/dist/cli/render.d.ts +22 -0
  140. package/dist/cli/render.js +150 -0
  141. package/dist/cli/render.js.map +1 -0
  142. package/dist/cli/samples/catalog.d.ts +10 -0
  143. package/dist/cli/samples/catalog.js +3 -0
  144. package/dist/cli/samples/catalog.js.map +1 -0
  145. package/dist/cli/samples/write.d.ts +5 -0
  146. package/dist/cli/samples/write.js +64 -0
  147. package/dist/cli/samples/write.js.map +1 -0
  148. package/dist/cli/source.d.ts +41 -0
  149. package/dist/cli/source.js +59 -0
  150. package/dist/cli/source.js.map +1 -0
  151. package/dist/core/activationDecision.d.ts +153 -0
  152. package/dist/core/activationDecision.js +34 -0
  153. package/dist/core/activationDecision.js.map +1 -0
  154. package/dist/core/artifacts.d.ts +18 -0
  155. package/dist/core/artifacts.js +79 -0
  156. package/dist/core/artifacts.js.map +1 -0
  157. package/dist/core/atomicFiles.d.ts +9 -0
  158. package/dist/core/atomicFiles.js +76 -0
  159. package/dist/core/atomicFiles.js.map +1 -0
  160. package/dist/core/boundedFile.d.ts +2 -0
  161. package/dist/core/boundedFile.js +28 -0
  162. package/dist/core/boundedFile.js.map +1 -0
  163. package/dist/core/bundle.d.ts +77 -0
  164. package/dist/core/bundle.js +375 -0
  165. package/dist/core/bundle.js.map +1 -0
  166. package/dist/core/bundleArchive.d.ts +10 -0
  167. package/dist/core/bundleArchive.js +47 -0
  168. package/dist/core/bundleArchive.js.map +1 -0
  169. package/dist/core/bundleEvidence.d.ts +12 -0
  170. package/dist/core/bundleEvidence.js +169 -0
  171. package/dist/core/bundleEvidence.js.map +1 -0
  172. package/dist/core/bundleExport.d.ts +12 -0
  173. package/dist/core/bundleExport.js +36 -0
  174. package/dist/core/bundleExport.js.map +1 -0
  175. package/dist/core/bundleFiles.d.ts +5 -0
  176. package/dist/core/bundleFiles.js +47 -0
  177. package/dist/core/bundleFiles.js.map +1 -0
  178. package/dist/core/bundlePaths.d.ts +2 -0
  179. package/dist/core/bundlePaths.js +7 -0
  180. package/dist/core/bundlePaths.js.map +1 -0
  181. package/dist/core/bundleSnapshot.d.ts +26 -0
  182. package/dist/core/bundleSnapshot.js +71 -0
  183. package/dist/core/bundleSnapshot.js.map +1 -0
  184. package/dist/core/capabilityBoundary.d.ts +1452 -0
  185. package/dist/core/capabilityBoundary.js +361 -0
  186. package/dist/core/capabilityBoundary.js.map +1 -0
  187. package/dist/core/capabilityLifecycle.d.ts +366 -0
  188. package/dist/core/capabilityLifecycle.js +79 -0
  189. package/dist/core/capabilityLifecycle.js.map +1 -0
  190. package/dist/core/cleanup.d.ts +35 -0
  191. package/dist/core/cleanup.js +71 -0
  192. package/dist/core/cleanup.js.map +1 -0
  193. package/dist/core/cleanupActions.d.ts +5 -0
  194. package/dist/core/cleanupActions.js +15 -0
  195. package/dist/core/cleanupActions.js.map +1 -0
  196. package/dist/core/cleanupAttestation.d.ts +23 -0
  197. package/dist/core/cleanupAttestation.js +57 -0
  198. package/dist/core/cleanupAttestation.js.map +1 -0
  199. package/dist/core/clock.d.ts +4 -0
  200. package/dist/core/clock.js +14 -0
  201. package/dist/core/clock.js.map +1 -0
  202. package/dist/core/compiler.d.ts +19 -0
  203. package/dist/core/compiler.js +200 -0
  204. package/dist/core/compiler.js.map +1 -0
  205. package/dist/core/controller.d.ts +7 -0
  206. package/dist/core/controller.js +132 -0
  207. package/dist/core/controller.js.map +1 -0
  208. package/dist/core/coordination.d.ts +72 -0
  209. package/dist/core/coordination.js +118 -0
  210. package/dist/core/coordination.js.map +1 -0
  211. package/dist/core/corpus.d.ts +60 -0
  212. package/dist/core/corpus.js +216 -0
  213. package/dist/core/corpus.js.map +1 -0
  214. package/dist/core/deadline.d.ts +12 -0
  215. package/dist/core/deadline.js +38 -0
  216. package/dist/core/deadline.js.map +1 -0
  217. package/dist/core/deliveryJournal.d.ts +37 -0
  218. package/dist/core/deliveryJournal.js +85 -0
  219. package/dist/core/deliveryJournal.js.map +1 -0
  220. package/dist/core/environmentPreflight.d.ts +14 -0
  221. package/dist/core/environmentPreflight.js +179 -0
  222. package/dist/core/environmentPreflight.js.map +1 -0
  223. package/dist/core/errors.d.ts +22 -0
  224. package/dist/core/errors.js +29 -0
  225. package/dist/core/errors.js.map +1 -0
  226. package/dist/core/events.d.ts +14 -0
  227. package/dist/core/events.js +37 -0
  228. package/dist/core/events.js.map +1 -0
  229. package/dist/core/executionInspection.d.ts +90 -0
  230. package/dist/core/executionInspection.js +31 -0
  231. package/dist/core/executionInspection.js.map +1 -0
  232. package/dist/core/executionOwnership.d.ts +72 -0
  233. package/dist/core/executionOwnership.js +82 -0
  234. package/dist/core/executionOwnership.js.map +1 -0
  235. package/dist/core/executionPreparation.d.ts +362 -0
  236. package/dist/core/executionPreparation.js +93 -0
  237. package/dist/core/executionPreparation.js.map +1 -0
  238. package/dist/core/executionReadback.d.ts +15 -0
  239. package/dist/core/executionReadback.js +21 -0
  240. package/dist/core/executionReadback.js.map +1 -0
  241. package/dist/core/executor.d.ts +46 -0
  242. package/dist/core/executor.js +616 -0
  243. package/dist/core/executor.js.map +1 -0
  244. package/dist/core/frozenBundle.d.ts +314 -0
  245. package/dist/core/frozenBundle.js +24 -0
  246. package/dist/core/frozenBundle.js.map +1 -0
  247. package/dist/core/fsDurability.d.ts +2 -0
  248. package/dist/core/fsDurability.js +12 -0
  249. package/dist/core/fsDurability.js.map +1 -0
  250. package/dist/core/generators.d.ts +4 -0
  251. package/dist/core/generators.js +71 -0
  252. package/dist/core/generators.js.map +1 -0
  253. package/dist/core/gitSnapshot.d.ts +63 -0
  254. package/dist/core/gitSnapshot.js +55 -0
  255. package/dist/core/gitSnapshot.js.map +1 -0
  256. package/dist/core/gitSources.d.ts +29 -0
  257. package/dist/core/gitSources.js +97 -0
  258. package/dist/core/gitSources.js.map +1 -0
  259. package/dist/core/ledger.d.ts +38 -0
  260. package/dist/core/ledger.js +169 -0
  261. package/dist/core/ledger.js.map +1 -0
  262. package/dist/core/ledgerInspection.d.ts +18 -0
  263. package/dist/core/ledgerInspection.js +66 -0
  264. package/dist/core/ledgerInspection.js.map +1 -0
  265. package/dist/core/ledgerRecords.d.ts +23 -0
  266. package/dist/core/ledgerRecords.js +29 -0
  267. package/dist/core/ledgerRecords.js.map +1 -0
  268. package/dist/core/localActivationState.d.ts +260 -0
  269. package/dist/core/localActivationState.js +49 -0
  270. package/dist/core/localActivationState.js.map +1 -0
  271. package/dist/core/localPromotionState.d.ts +387 -0
  272. package/dist/core/localPromotionState.js +22 -0
  273. package/dist/core/localPromotionState.js.map +1 -0
  274. package/dist/core/localQualificationResults.d.ts +39 -0
  275. package/dist/core/localQualificationResults.js +160 -0
  276. package/dist/core/localQualificationResults.js.map +1 -0
  277. package/dist/core/localReviewStore.d.ts +28 -0
  278. package/dist/core/localReviewStore.js +167 -0
  279. package/dist/core/localReviewStore.js.map +1 -0
  280. package/dist/core/localScenarioActivation.d.ts +6 -0
  281. package/dist/core/localScenarioActivation.js +70 -0
  282. package/dist/core/localScenarioActivation.js.map +1 -0
  283. package/dist/core/localScenarioOwner.d.ts +20 -0
  284. package/dist/core/localScenarioOwner.js +2 -0
  285. package/dist/core/localScenarioOwner.js.map +1 -0
  286. package/dist/core/localScenarioPromotion.d.ts +9 -0
  287. package/dist/core/localScenarioPromotion.js +49 -0
  288. package/dist/core/localScenarioPromotion.js.map +1 -0
  289. package/dist/core/localScenarioState.d.ts +2297 -0
  290. package/dist/core/localScenarioState.js +117 -0
  291. package/dist/core/localScenarioState.js.map +1 -0
  292. package/dist/core/localScenarioStore.d.ts +838 -0
  293. package/dist/core/localScenarioStore.js +218 -0
  294. package/dist/core/localScenarioStore.js.map +1 -0
  295. package/dist/core/localScenarioStructure.d.ts +4 -0
  296. package/dist/core/localScenarioStructure.js +52 -0
  297. package/dist/core/localScenarioStructure.js.map +1 -0
  298. package/dist/core/localStructureState.d.ts +2 -0
  299. package/dist/core/localStructureState.js +22 -0
  300. package/dist/core/localStructureState.js.map +1 -0
  301. package/dist/core/lookup.d.ts +662 -0
  302. package/dist/core/lookup.js +55 -0
  303. package/dist/core/lookup.js.map +1 -0
  304. package/dist/core/ownership.d.ts +3 -0
  305. package/dist/core/ownership.js +24 -0
  306. package/dist/core/ownership.js.map +1 -0
  307. package/dist/core/planInspection.d.ts +108 -0
  308. package/dist/core/planInspection.js +44 -0
  309. package/dist/core/planInspection.js.map +1 -0
  310. package/dist/core/planner.d.ts +14 -0
  311. package/dist/core/planner.js +261 -0
  312. package/dist/core/planner.js.map +1 -0
  313. package/dist/core/qualification.d.ts +26 -0
  314. package/dist/core/qualification.js +58 -0
  315. package/dist/core/qualification.js.map +1 -0
  316. package/dist/core/qualificationBundle.d.ts +6 -0
  317. package/dist/core/qualificationBundle.js +51 -0
  318. package/dist/core/qualificationBundle.js.map +1 -0
  319. package/dist/core/qualificationExecution.d.ts +879 -0
  320. package/dist/core/qualificationExecution.js +54 -0
  321. package/dist/core/qualificationExecution.js.map +1 -0
  322. package/dist/core/recoveryStatus.d.ts +6 -0
  323. package/dist/core/recoveryStatus.js +123 -0
  324. package/dist/core/recoveryStatus.js.map +1 -0
  325. package/dist/core/reducer.d.ts +56 -0
  326. package/dist/core/reducer.js +355 -0
  327. package/dist/core/reducer.js.map +1 -0
  328. package/dist/core/replayAssessment.d.ts +15 -0
  329. package/dist/core/replayAssessment.js +78 -0
  330. package/dist/core/replayAssessment.js.map +1 -0
  331. package/dist/core/replayEvidence.d.ts +7 -0
  332. package/dist/core/replayEvidence.js +58 -0
  333. package/dist/core/replayEvidence.js.map +1 -0
  334. package/dist/core/repositorySelectionEvidence.d.ts +3 -0
  335. package/dist/core/repositorySelectionEvidence.js +58 -0
  336. package/dist/core/repositorySelectionEvidence.js.map +1 -0
  337. package/dist/core/rerun.d.ts +3 -0
  338. package/dist/core/rerun.js +24 -0
  339. package/dist/core/rerun.js.map +1 -0
  340. package/dist/core/resultSink.d.ts +52 -0
  341. package/dist/core/resultSink.js +120 -0
  342. package/dist/core/resultSink.js.map +1 -0
  343. package/dist/core/review.d.ts +22 -0
  344. package/dist/core/review.js +65 -0
  345. package/dist/core/review.js.map +1 -0
  346. package/dist/core/runnerCapabilities.d.ts +22 -0
  347. package/dist/core/runnerCapabilities.js +44 -0
  348. package/dist/core/runnerCapabilities.js.map +1 -0
  349. package/dist/core/scenario.d.ts +32 -0
  350. package/dist/core/scenario.js +119 -0
  351. package/dist/core/scenario.js.map +1 -0
  352. package/dist/core/scenarioActivation.d.ts +16 -0
  353. package/dist/core/scenarioActivation.js +47 -0
  354. package/dist/core/scenarioActivation.js.map +1 -0
  355. package/dist/core/scenarioStructure.d.ts +400 -0
  356. package/dist/core/scenarioStructure.js +72 -0
  357. package/dist/core/scenarioStructure.js.map +1 -0
  358. package/dist/core/snapshotEvidence.d.ts +3 -0
  359. package/dist/core/snapshotEvidence.js +37 -0
  360. package/dist/core/snapshotEvidence.js.map +1 -0
  361. package/dist/core/snapshotRepository.d.ts +48 -0
  362. package/dist/core/snapshotRepository.js +47 -0
  363. package/dist/core/snapshotRepository.js.map +1 -0
  364. package/dist/core/source-analysis.d.ts +18 -0
  365. package/dist/core/source-analysis.js +99 -0
  366. package/dist/core/source-analysis.js.map +1 -0
  367. package/dist/core/source-citation.d.ts +53 -0
  368. package/dist/core/source-citation.js +59 -0
  369. package/dist/core/source-citation.js.map +1 -0
  370. package/dist/core/sourcePromotion.d.ts +929 -0
  371. package/dist/core/sourcePromotion.js +92 -0
  372. package/dist/core/sourcePromotion.js.map +1 -0
  373. package/dist/core/sourceReviewEvidence.d.ts +271 -0
  374. package/dist/core/sourceReviewEvidence.js +24 -0
  375. package/dist/core/sourceReviewEvidence.js.map +1 -0
  376. package/dist/core/targetObservation.d.ts +3 -0
  377. package/dist/core/targetObservation.js +26 -0
  378. package/dist/core/targetObservation.js.map +1 -0
  379. package/dist/hosts/launchTemplates.d.ts +2 -0
  380. package/dist/hosts/launchTemplates.js +5 -0
  381. package/dist/hosts/launchTemplates.js.map +1 -0
  382. package/dist/hosts/local.d.ts +17 -0
  383. package/dist/hosts/local.js +311 -0
  384. package/dist/hosts/local.js.map +1 -0
  385. package/dist/hosts/localSupervisor.d.ts +1 -0
  386. package/dist/hosts/localSupervisor.js +115 -0
  387. package/dist/hosts/localSupervisor.js.map +1 -0
  388. package/dist/hosts/mock.d.ts +4 -0
  389. package/dist/hosts/mock.js +82 -0
  390. package/dist/hosts/mock.js.map +1 -0
  391. package/dist/hosts/pinnedArguments.d.ts +3 -0
  392. package/dist/hosts/pinnedArguments.js +39 -0
  393. package/dist/hosts/pinnedArguments.js.map +1 -0
  394. package/dist/hosts/runtime.d.ts +5 -0
  395. package/dist/hosts/runtime.js +60 -0
  396. package/dist/hosts/runtime.js.map +1 -0
  397. package/dist/hosts/sourceIdentity.d.ts +54 -0
  398. package/dist/hosts/sourceIdentity.js +27 -0
  399. package/dist/hosts/sourceIdentity.js.map +1 -0
  400. package/dist/hosts/types.d.ts +39 -0
  401. package/dist/hosts/types.js +2 -0
  402. package/dist/hosts/types.js.map +1 -0
  403. package/dist/index.d.ts +56 -0
  404. package/dist/index.js +52 -0
  405. package/dist/index.js.map +1 -0
  406. package/dist/integrations/awr/attachment.d.ts +34 -0
  407. package/dist/integrations/awr/attachment.js +120 -0
  408. package/dist/integrations/awr/attachment.js.map +1 -0
  409. package/dist/integrations/awr/attachmentContracts.d.ts +273 -0
  410. package/dist/integrations/awr/attachmentContracts.js +39 -0
  411. package/dist/integrations/awr/attachmentContracts.js.map +1 -0
  412. package/dist/integrations/awr/attachmentHttp.d.ts +9 -0
  413. package/dist/integrations/awr/attachmentHttp.js +19 -0
  414. package/dist/integrations/awr/attachmentHttp.js.map +1 -0
  415. package/dist/integrations/awr/cli.d.ts +7 -0
  416. package/dist/integrations/awr/cli.js +43 -0
  417. package/dist/integrations/awr/cli.js.map +1 -0
  418. package/dist/integrations/awr/contracts.d.ts +54 -0
  419. package/dist/integrations/awr/contracts.js +33 -0
  420. package/dist/integrations/awr/contracts.js.map +1 -0
  421. package/dist/integrations/awr/http.d.ts +8 -0
  422. package/dist/integrations/awr/http.js +23 -0
  423. package/dist/integrations/awr/http.js.map +1 -0
  424. package/dist/integrations/awr/index.d.ts +7 -0
  425. package/dist/integrations/awr/index.js +8 -0
  426. package/dist/integrations/awr/index.js.map +1 -0
  427. package/dist/integrations/awr/jsonHttp.d.ts +15 -0
  428. package/dist/integrations/awr/jsonHttp.js +69 -0
  429. package/dist/integrations/awr/jsonHttp.js.map +1 -0
  430. package/dist/integrations/awr/outbox.d.ts +28 -0
  431. package/dist/integrations/awr/outbox.js +88 -0
  432. package/dist/integrations/awr/outbox.js.map +1 -0
  433. package/dist/integrations/awr/projection.d.ts +4 -0
  434. package/dist/integrations/awr/projection.js +54 -0
  435. package/dist/integrations/awr/projection.js.map +1 -0
  436. package/dist/protocol/canonical.d.ts +41 -0
  437. package/dist/protocol/canonical.js +114 -0
  438. package/dist/protocol/canonical.js.map +1 -0
  439. package/dist/protocol/index.d.ts +9620 -0
  440. package/dist/protocol/index.js +185 -0
  441. package/dist/protocol/index.js.map +1 -0
  442. package/dist/protocol/primitives.d.ts +63 -0
  443. package/dist/protocol/primitives.js +46 -0
  444. package/dist/protocol/primitives.js.map +1 -0
  445. package/dist/protocol/schemas/browser.d.ts +153 -0
  446. package/dist/protocol/schemas/browser.js +29 -0
  447. package/dist/protocol/schemas/browser.js.map +1 -0
  448. package/dist/protocol/schemas/capability.d.ts +2126 -0
  449. package/dist/protocol/schemas/capability.js +165 -0
  450. package/dist/protocol/schemas/capability.js.map +1 -0
  451. package/dist/protocol/schemas/capabilityLifecycle.d.ts +509 -0
  452. package/dist/protocol/schemas/capabilityLifecycle.js +47 -0
  453. package/dist/protocol/schemas/capabilityLifecycle.js.map +1 -0
  454. package/dist/protocol/schemas/cleanup.d.ts +109 -0
  455. package/dist/protocol/schemas/cleanup.js +59 -0
  456. package/dist/protocol/schemas/cleanup.js.map +1 -0
  457. package/dist/protocol/schemas/cli.d.ts +121 -0
  458. package/dist/protocol/schemas/cli.js +24 -0
  459. package/dist/protocol/schemas/cli.js.map +1 -0
  460. package/dist/protocol/schemas/config.d.ts +59 -0
  461. package/dist/protocol/schemas/config.js +32 -0
  462. package/dist/protocol/schemas/config.js.map +1 -0
  463. package/dist/protocol/schemas/corpus.d.ts +36 -0
  464. package/dist/protocol/schemas/corpus.js +10 -0
  465. package/dist/protocol/schemas/corpus.js.map +1 -0
  466. package/dist/protocol/schemas/definitions.d.ts +3409 -0
  467. package/dist/protocol/schemas/definitions.js +431 -0
  468. package/dist/protocol/schemas/definitions.js.map +1 -0
  469. package/dist/protocol/schemas/evidenceProjection.d.ts +146 -0
  470. package/dist/protocol/schemas/evidenceProjection.js +18 -0
  471. package/dist/protocol/schemas/evidenceProjection.js.map +1 -0
  472. package/dist/protocol/schemas/execution.d.ts +3179 -0
  473. package/dist/protocol/schemas/execution.js +500 -0
  474. package/dist/protocol/schemas/execution.js.map +1 -0
  475. package/dist/protocol/schemas/gitSources.d.ts +330 -0
  476. package/dist/protocol/schemas/gitSources.js +32 -0
  477. package/dist/protocol/schemas/gitSources.js.map +1 -0
  478. package/dist/protocol/schemas/mcp.d.ts +24 -0
  479. package/dist/protocol/schemas/mcp.js +16 -0
  480. package/dist/protocol/schemas/mcp.js.map +1 -0
  481. package/dist/protocol/schemas/nativeJob.d.ts +106 -0
  482. package/dist/protocol/schemas/nativeJob.js +16 -0
  483. package/dist/protocol/schemas/nativeJob.js.map +1 -0
  484. package/dist/protocol/schemas/portableEnvironment.d.ts +1256 -0
  485. package/dist/protocol/schemas/portableEnvironment.js +108 -0
  486. package/dist/protocol/schemas/portableEnvironment.js.map +1 -0
  487. package/dist/protocol/schemas/promotion.d.ts +132 -0
  488. package/dist/protocol/schemas/promotion.js +9 -0
  489. package/dist/protocol/schemas/promotion.js.map +1 -0
  490. package/dist/protocol/schemas/protocol.d.ts +146 -0
  491. package/dist/protocol/schemas/protocol.js +25 -0
  492. package/dist/protocol/schemas/protocol.js.map +1 -0
  493. package/dist/protocol/schemas/recoveryStatus.d.ts +88 -0
  494. package/dist/protocol/schemas/recoveryStatus.js +20 -0
  495. package/dist/protocol/schemas/recoveryStatus.js.map +1 -0
  496. package/dist/protocol/schemas/resultSink.d.ts +80 -0
  497. package/dist/protocol/schemas/resultSink.js +14 -0
  498. package/dist/protocol/schemas/resultSink.js.map +1 -0
  499. package/dist/protocol/schemas/review.d.ts +248 -0
  500. package/dist/protocol/schemas/review.js +45 -0
  501. package/dist/protocol/schemas/review.js.map +1 -0
  502. package/dist/protocol/schemas/scenario.d.ts +810 -0
  503. package/dist/protocol/schemas/scenario.js +53 -0
  504. package/dist/protocol/schemas/scenario.js.map +1 -0
  505. package/dist/protocol/schemas/source.d.ts +300 -0
  506. package/dist/protocol/schemas/source.js +25 -0
  507. package/dist/protocol/schemas/source.js.map +1 -0
  508. package/dist/source/git.d.ts +36 -0
  509. package/dist/source/git.js +159 -0
  510. package/dist/source/git.js.map +1 -0
  511. package/dist/source/gitObjectProof.d.ts +12 -0
  512. package/dist/source/gitObjectProof.js +115 -0
  513. package/dist/source/gitObjectProof.js.map +1 -0
  514. package/dist/source/snapshotPaths.d.ts +2 -0
  515. package/dist/source/snapshotPaths.js +24 -0
  516. package/dist/source/snapshotPaths.js.map +1 -0
  517. package/dist/source/snapshotTree.d.ts +15 -0
  518. package/dist/source/snapshotTree.js +79 -0
  519. package/dist/source/snapshotTree.js.map +1 -0
  520. package/docs/architecture.md +126 -0
  521. package/docs/awr-delivery.md +102 -0
  522. package/docs/browser-driver.md +148 -0
  523. package/docs/cleanup-followups.md +74 -0
  524. package/docs/developer-ux.md +315 -0
  525. package/docs/examples/portable-environments/alongside_runner.json +199 -0
  526. package/docs/examples/portable-environments/external_staging.json +183 -0
  527. package/docs/git-object-proof.md +100 -0
  528. package/docs/git-source-resolution.md +133 -0
  529. package/docs/images/ui-run.png +0 -0
  530. package/docs/local-execution-recovery.md +55 -0
  531. package/docs/local-review-store.md +13 -0
  532. package/docs/local-scenario-store.md +91 -0
  533. package/docs/mcp-driver.md +87 -0
  534. package/docs/native-jobs.md +96 -0
  535. package/docs/portable-environments.md +155 -0
  536. package/docs/qualification-registration.md +58 -0
  537. package/docs/qualification-results.md +59 -0
  538. package/docs/replay-assessment.md +17 -0
  539. package/docs/result-sink.md +87 -0
  540. package/docs/scenario-activation.md +54 -0
  541. package/docs/scenario-structure.md +58 -0
  542. package/docs/source-promotion.md +104 -0
  543. package/docs/source-review.md +21 -0
  544. package/docs/verified-bundles.md +175 -0
  545. package/docs/work-report-attachment.md +127 -0
  546. package/package.json +45 -4
  547. package/samples/django-notes/manage.py +8 -0
  548. package/samples/django-notes/notes/__init__.py +0 -0
  549. package/samples/django-notes/notes/auth.py +14 -0
  550. package/samples/django-notes/notes/migrations/0001_initial.py +19 -0
  551. package/samples/django-notes/notes/migrations/__init__.py +0 -0
  552. package/samples/django-notes/notes/models.py +13 -0
  553. package/samples/django-notes/notes/views.py +33 -0
  554. package/samples/django-notes/notesite/__init__.py +0 -0
  555. package/samples/django-notes/notesite/settings.py +17 -0
  556. package/samples/django-notes/notesite/urls.py +9 -0
  557. package/samples/django-notes/requirements.txt +1 -0
  558. package/samples/django-notes/tracegrove/notes/crud.flow.yaml +27 -0
  559. package/samples/django-notes/tracegrove.config.yaml +7 -0
  560. package/samples/fastapi-notes/app/__init__.py +0 -0
  561. package/samples/fastapi-notes/app/main.py +69 -0
  562. package/samples/fastapi-notes/requirements.txt +2 -0
  563. package/samples/fastapi-notes/tracegrove/notes/crud.flow.yaml +27 -0
  564. package/samples/fastapi-notes/tracegrove.config.yaml +8 -0
  565. package/samples/notes-api/app/app.mjs +67 -0
  566. package/samples/notes-api/app/http.mjs +16 -0
  567. package/samples/notes-api/tracegrove/fixtures/existing-note.fixture.yaml +12 -0
  568. package/samples/notes-api/tracegrove/notes/create-read-delete.flow.yaml +35 -0
  569. package/samples/notes-api/tracegrove/notes/list.flow.yaml +25 -0
  570. package/samples/notes-api/tracegrove.config.yaml +15 -0
  571. package/samples/notes-api/verification/actions/notes.registry.yaml +6 -0
  572. package/samples/notes-api/verification/auth/host-issued-owner.yaml +6 -0
  573. package/samples/notes-api/verification/cases/notes.contract.yaml +51 -0
  574. package/samples/notes-api/verification/cases/notes.create.yaml +123 -0
  575. package/samples/notes-api/verification/cases/notes.suite.yaml +5 -0
  576. package/samples/notes-api/verification/components/notes-api-stub.profile.yaml +8 -0
  577. package/samples/notes-api/verification/components/notes-api.profile.yaml +15 -0
  578. package/samples/notes-api/verification/environments/local-notes.yaml +11 -0
  579. package/samples/notes-api/verification/environments/mock-notes.yaml +11 -0
  580. package/samples/notes-api/verification/fidelity/full-live-sandbox.yaml +7 -0
  581. package/samples/notes-api/verification/fidelity/mock-contract.yaml +6 -0
  582. package/samples/notes-api/verification/fixtures/existing-note.payload.yaml +15 -0
  583. package/samples/notes-api/verification/fixtures/existing-note.plan.yaml +9 -0
  584. package/samples/notes-api/verification/fixtures/existing-note.recipe.yaml +29 -0
  585. package/samples/notes-api/verification/hosts/local-process.yaml +27 -0
  586. package/samples/notes-api/verification/hosts/mock-loopback.yaml +14 -0
  587. package/samples/notes-api/verification/mocks/notes.responses.yaml +5 -0
  588. package/samples/notes-api/verification/personas/owner.yaml +16 -0
  589. package/samples/notes-api/verification/policies/no-authoring-inference.yaml +10 -0
  590. package/samples/notes-api/verification/runners/http.yaml +5 -0
  591. package/samples/notes-api/verification/surfaces/http-api.binding.yaml +11 -0
  592. package/samples/notes-api/verification/surfaces/http-api.pack.yaml +7 -0
  593. package/samples/notes-api/verification/workflow.yaml +27 -0
  594. package/samples/notes-browser/tracegrove/notes/browser.flow.yaml +19 -0
  595. package/samples/notes-browser/verification/cases/notes.browser.yaml +63 -0
  596. package/samples/notes-browser/verification/cases/notes.suite.yaml +4 -0
  597. package/samples/notes-browser/verification/runners/http.yaml +5 -0
  598. package/samples/notes-browser/verification/surfaces/http-api.binding.yaml +11 -0
  599. package/samples/notes-browser/verification/surfaces/http-api.pack.yaml +7 -0
  600. package/samples/notes-django/README.md +21 -0
  601. package/samples/notes-django/app/django_app.py +119 -0
  602. package/samples/notes-django/app/requirements.lock +4 -0
  603. package/samples/notes-mcp/app/mcp.mjs +47 -0
  604. package/samples/notes-mcp/tracegrove/notes.flow.yaml +20 -0
  605. package/samples/notes-mcp/tracegrove.config.yaml +13 -0
  606. package/samples/report-jobs/README.md +30 -0
  607. package/samples/report-jobs/app/jobs-api.mjs +65 -0
  608. package/samples/report-jobs/app/native-bridge.mjs +30 -0
  609. package/samples/report-jobs/app/store.mjs +74 -0
  610. package/samples/report-jobs/app/worker.mjs +22 -0
  611. package/samples/report-jobs/tracegrove/fixtures/failed-job.fixture.yaml +12 -0
  612. package/samples/report-jobs/tracegrove/fixtures/held-job.fixture.yaml +12 -0
  613. package/samples/report-jobs/tracegrove/fixtures/success-job.fixture.yaml +12 -0
  614. package/samples/report-jobs/tracegrove/reports/cancellation.flow.yaml +15 -0
  615. package/samples/report-jobs/tracegrove/reports/completion.flow.yaml +31 -0
  616. package/samples/report-jobs/tracegrove/reports/failure.flow.yaml +12 -0
  617. package/samples/report-jobs/tracegrove.config.yaml +10 -0
  618. package/samples/report-native/README.md +11 -0
  619. package/samples/report-native/tracegrove/cancellation.flow.yaml +11 -0
  620. package/samples/report-native/tracegrove/completion.flow.yaml +22 -0
  621. package/samples/report-native/tracegrove/failure.flow.yaml +7 -0
  622. package/samples/report-native/tracegrove.config.yaml +11 -0
  623. package/schema/tracegrove_cli-error_v1.json +156 -0
  624. package/schema/tracegrove_config_v1.json +233 -0
  625. package/schema/tracegrove_fixture_v1.json +297 -0
  626. package/schema/tracegrove_flow_v1.json +960 -0
  627. package/schema/tracegrove_recovery-status_v1.json +234 -0
  628. package/schema/tracegrove_run-video_v1.json +25 -0
  629. package/schema/workflow_action-registry_v1.json +303 -0
  630. package/schema/workflow_auth-recipe_v1.json +146 -0
  631. package/schema/workflow_boundary-observation_v1.json +515 -0
  632. package/schema/workflow_browser-command_v1.json +292 -0
  633. package/schema/workflow_browser-locator_v1.json +74 -0
  634. package/schema/workflow_browser-network-observation_v1.json +48 -0
  635. package/schema/workflow_browser-observation_v1.json +53 -0
  636. package/schema/workflow_budget-reservation_v1.json +150 -0
  637. package/schema/workflow_campaign-result_v1.json +382 -0
  638. package/schema/workflow_capability-artifact-manifest_v1.json +529 -0
  639. package/schema/workflow_capability-descriptor_v1.json +351 -0
  640. package/schema/workflow_capability-lifecycle-checkpoint_v1.json +510 -0
  641. package/schema/workflow_capability-observation_v1.json +1707 -0
  642. package/schema/workflow_capability-operation_v1.json +3212 -0
  643. package/schema/workflow_capability-replay-plan_v1.json +1247 -0
  644. package/schema/workflow_capability-retry-policy_v1.json +39 -0
  645. package/schema/workflow_capability-retry-state_v1.json +242 -0
  646. package/schema/workflow_case_v1.json +4222 -0
  647. package/schema/workflow_change-model_v1.json +614 -0
  648. package/schema/workflow_cleanup-expectation_v1.json +108 -0
  649. package/schema/workflow_cleanup-followup_v1.json +145 -0
  650. package/schema/workflow_component-profile_v1.json +219 -0
  651. package/schema/workflow_config_v1.json +180 -0
  652. package/schema/workflow_corpus_v1.json +172 -0
  653. package/schema/workflow_cost-observation_v1.json +366 -0
  654. package/schema/workflow_credential-lease_v1.json +222 -0
  655. package/schema/workflow_effective-config_v1.json +214 -0
  656. package/schema/workflow_environment-plan_v1.json +445 -0
  657. package/schema/workflow_environment_v1.json +1827 -0
  658. package/schema/workflow_evidence-projection_v1.json +636 -0
  659. package/schema/workflow_execution_v1.json +4086 -0
  660. package/schema/workflow_fidelity-plan_v1.json +512 -0
  661. package/schema/workflow_fidelity-profile_v1.json +396 -0
  662. package/schema/workflow_fixture-manifest_v1.json +918 -0
  663. package/schema/workflow_fixture-plan_v1.json +594 -0
  664. package/schema/workflow_git-source-request_v1.json +124 -0
  665. package/schema/workflow_git-source-resolution_v1.json +660 -0
  666. package/schema/workflow_git-source-snapshot_v1.json +287 -0
  667. package/schema/workflow_host-lease_v1.json +321 -0
  668. package/schema/workflow_host-observation_v1.json +282 -0
  669. package/schema/workflow_host-plan_v1.json +719 -0
  670. package/schema/workflow_identity-attestation_v1.json +412 -0
  671. package/schema/workflow_intelligence-policy_v1.json +153 -0
  672. package/schema/workflow_logical-payload_v1.json +206 -0
  673. package/schema/workflow_mcp-tool-call_v1.json +70 -0
  674. package/schema/workflow_mcp-tool-observation_v1.json +125 -0
  675. package/schema/workflow_mock-responses_v1.json +185 -0
  676. package/schema/workflow_native-job-action_v1.json +123 -0
  677. package/schema/workflow_native-job-observation_v1.json +138 -0
  678. package/schema/workflow_native-job-ready_v1.json +31 -0
  679. package/schema/workflow_native-job-request_v1.json +155 -0
  680. package/schema/workflow_native-job-response_v1.json +125 -0
  681. package/schema/workflow_ownership_v1.json +116 -0
  682. package/schema/workflow_persona_v1.json +499 -0
  683. package/schema/workflow_plan-edit-projection_v1.json +152 -0
  684. package/schema/workflow_plan-review_v1.json +246 -0
  685. package/schema/workflow_portable-environment-intent_v1.json +499 -0
  686. package/schema/workflow_portable-environment-profile_v1.json +1429 -0
  687. package/schema/workflow_portable-preflight_v1.json +2281 -0
  688. package/schema/workflow_qualification-admission_v1.json +467 -0
  689. package/schema/workflow_qualification-intent_v1.json +98 -0
  690. package/schema/workflow_qualification-policy_v1.json +109 -0
  691. package/schema/workflow_qualification-round_v1.json +226 -0
  692. package/schema/workflow_replay-assessment_v1.json +197 -0
  693. package/schema/workflow_replay-finding_v1.json +147 -0
  694. package/schema/workflow_request_v1.json +1567 -0
  695. package/schema/workflow_result-ingest_v1.json +343 -0
  696. package/schema/workflow_revisions_v1.json +334 -0
  697. package/schema/workflow_routing-decision_v1.json +482 -0
  698. package/schema/workflow_runner-capabilities_v1.json +316 -0
  699. package/schema/workflow_runner-profile_v1.json +119 -0
  700. package/schema/workflow_runner-protocol_v1_host.json +382 -0
  701. package/schema/workflow_runner-protocol_v1_plugin.json +491 -0
  702. package/schema/workflow_scenario-activation-intent_v1.json +346 -0
  703. package/schema/workflow_scenario-activation_v1.json +562 -0
  704. package/schema/workflow_scenario-projection_v1.json +221 -0
  705. package/schema/workflow_scenario-promotion_v1.json +455 -0
  706. package/schema/workflow_scenario-replay-assessment_v1.json +696 -0
  707. package/schema/workflow_scenario-revision-token_v1.json +115 -0
  708. package/schema/workflow_scenario-structure_v1.json +368 -0
  709. package/schema/workflow_scenario_v1.json +401 -0
  710. package/schema/workflow_scoped-resource_v1.json +550 -0
  711. package/schema/workflow_seed-recipe_v1.json +724 -0
  712. package/schema/workflow_selection_v1.json +1108 -0
  713. package/schema/workflow_signed-cleanup-followup_v1.json +175 -0
  714. package/schema/workflow_source-plan_v1.json +756 -0
  715. package/schema/workflow_source-selection_v1.json +456 -0
  716. package/schema/workflow_source-validation_v1.json +366 -0
  717. package/schema/workflow_step-event_v1.json +228 -0
  718. package/schema/workflow_stream-transcript_v1.json +1030 -0
  719. package/schema/workflow_suite_v1.json +64 -0
  720. package/schema/workflow_surface-binding_v1.json +411 -0
  721. package/schema/workflow_surface-pack_v1.json +159 -0
@@ -0,0 +1,358 @@
1
+ /**
2
+ * The single page served by `tracegrove ui`, in the Grove design: a bonsai of scenarios (trunk,
3
+ * branches, step twigs), pruning as a reversible rename, live progress from real run and agent
4
+ * events, self-healing with reviewable diffs and undo, a command palette (Cmd/Ctrl+K) and keyboard
5
+ * navigation.
6
+ * No build step and no framework; every string reaches the DOM through textContent.
7
+ */
8
+ import { SOURCE_CONTROLS_JS } from "./uiSourceControls.js";
9
+ export const UI_HTML = String.raw `<!doctype html>
10
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
11
+ <title>tracegrove</title>
12
+ <link rel="preconnect" href="https://fonts.googleapis.com">
13
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
14
+ <style>
15
+ :root{--stone:#F4F4F1;--paper:#FFFFFF;--line:#E2E2DC;--line2:#CFCFC8;--sel:#E6E7E1;--ink:#1A1C1A;--ink2:#3E423D;--ink3:#5E625C;--muted:#6B6F68;
16
+ --trunk:#3C4A3E;--twig:#A9B0A6;--moss:#2F5D3A;--moss-bg:#E9F0E8;--verm:#B8410E;--verm-bg:#FBE9E0;--verm-ink:#8A2E08;--ochre:#9A6A1F;--ochre-bg:#FBF1E4;--ochre-ink:#5B3A0A;
17
+ --indigo:#4A5C94;--indigo-bg:#EAEDF6;--forest:#1F3524;--on-forest:#F4F4F1;--bar:#F0F0EB;--code:#F4F4F1;
18
+ --sans:'Instrument Sans',ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif;--mono:'JetBrains Mono',ui-monospace,SFMono-Regular,Menlo,monospace}
19
+ @media (prefers-color-scheme:dark){:root{--stone:#121412;--paper:#1A1D1A;--line:#2A2E2A;--line2:#3A3F3A;--sel:#262A26;--ink:#E8E9E4;--ink2:#C9CCC4;--ink3:#A3A79F;--muted:#8F938B;
20
+ --trunk:#8FA38F;--twig:#55605A;--moss:#7FC39A;--moss-bg:#1D2E22;--verm:#F08A66;--verm-bg:#3A2219;--verm-ink:#F6B59C;--ochre:#E2B45C;--ochre-bg:#352A17;--ochre-ink:#EBCB8E;
21
+ --indigo:#9AAEE8;--indigo-bg:#1F2538;--forest:#CFE3D3;--on-forest:#121412;--bar:#232723;--code:#141714}}
22
+ *{box-sizing:border-box}html,body{margin:0;background:var(--stone);color:var(--ink);font:15px/22px var(--sans)}
23
+ button{font:inherit;color:inherit;cursor:pointer}button:disabled{cursor:not-allowed;opacity:.5}
24
+ :focus-visible{outline:2px solid var(--moss);outline-offset:2px;border-radius:6px}
25
+ a{color:var(--moss)}code,pre,.mono{font-family:var(--mono)}
26
+ header{display:flex;flex-wrap:wrap;align-items:center;gap:12px 32px;min-height:64px;padding:12px 32px;border-bottom:1px solid var(--line)}
27
+ .brand{display:flex;align-items:center;gap:8px;font-weight:600;font-size:17px;letter-spacing:-.01em}
28
+ nav{display:flex;flex-wrap:wrap;gap:4px}
29
+ nav button{display:inline-flex;align-items:center;min-height:36px;padding:0 12px;border:0;border-radius:8px;background:none;color:var(--ink3)}
30
+ nav button[aria-current=page]{background:var(--sel);color:var(--ink);font-weight:500}
31
+ .ctx{margin-left:auto;font:13px/18px var(--mono);color:var(--ink3);overflow-wrap:anywhere}
32
+ .page{max-width:1376px;margin:0 auto;padding:28px 32px 48px}
33
+ .label{font:500 11px/16px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
34
+ .rulehead{display:flex;align-items:center;gap:12px;margin-bottom:10px;flex-wrap:wrap}.rulehead .rule{flex:1;height:1px;background:var(--line);min-width:40px}
35
+ .card{background:var(--paper);border:1px solid var(--line);border-radius:12px;padding:20px}
36
+ .recording{margin-top:20px}.recording video{display:block;width:100%;max-height:360px;aspect-ratio:16/9;object-fit:contain;margin:10px 0;background:var(--ink)}
37
+ .cols{display:flex;flex-wrap:wrap;gap:24px;align-items:flex-start}.grow{flex:999 1 560px;min-width:0}.side{flex:1 1 340px;min-width:0;display:flex;flex-direction:column;gap:16px}
38
+ h1{font-size:28px;line-height:34px;font-weight:500;letter-spacing:-.015em;margin:0;max-width:30ch}h2{font-size:17px;line-height:24px;font-weight:600;margin:0}
39
+ .muted{color:var(--ink3)}.small{font-size:13px;line-height:18px}
40
+ .btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:44px;padding:0 18px;border-radius:8px;border:0;background:var(--forest);color:var(--on-forest);font-weight:500;white-space:nowrap}
41
+ .btn.ghost{background:var(--paper);color:var(--ink);border:1px solid var(--line2);font-weight:400}.btn.sm{min-height:36px;padding:0 12px;font-size:14px}
42
+ input,select,textarea{font:inherit;color:var(--ink);background:var(--paper);border:1px solid var(--line2);border-radius:8px;padding:0 12px;min-height:44px;max-width:100%}
43
+ textarea{padding:12px;resize:vertical;min-height:88px;width:100%}
44
+ .row{display:flex;gap:12px;align-items:center;flex-wrap:wrap}
45
+ .stats{display:flex;flex-wrap:wrap;gap:12px 40px;margin-top:20px}.stats b{font-size:22px;font-weight:500;margin-right:6px}
46
+ .pill{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border-radius:6px;font-size:12px;line-height:16px;font-weight:500}
47
+ .p-pass{background:var(--moss-bg);color:var(--moss)}.p-fail{background:var(--verm-bg);color:var(--verm-ink)}.p-warn{background:var(--ochre-bg);color:var(--ochre-ink)}.p-info{background:var(--indigo-bg);color:var(--indigo)}.p-none{background:var(--sel);color:var(--ink3)}
48
+ .state{font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}
49
+ .c-pass{color:var(--moss)}.c-fail{color:var(--verm)}.c-warn{color:var(--ochre)}.c-none{color:var(--muted)}
50
+ .dot{width:12px;height:12px;border-radius:50%;flex:none}.dot.pass{background:var(--moss)}.dot.fail{background:var(--paper);border:3px solid var(--verm)}.dot.warn{background:var(--paper);border:3px solid var(--ochre)}
51
+ .dot.none{border:1.5px solid var(--ink3)}.dot.pruned{border:1.5px dashed var(--muted)}.dot.s{width:8px;height:8px;border-width:0}.dot.s.fail{background:var(--verm)}.dot.s.warn{background:var(--ochre)}.dot.s.none{background:var(--twig)}
52
+ .tree{border-left:1.5px solid var(--trunk);margin-left:10px}
53
+ .br{display:flex;align-items:stretch;padding:3px 0}.twig{width:22px;flex:none;display:flex;align-items:center}.twig i{display:block;width:100%;border-top:1.5px solid var(--trunk)}.twig.cut i{border-top-style:dashed;border-color:var(--twig)}
54
+ .node{flex:1;min-width:0;display:flex;align-items:center;gap:14px;padding:10px 14px;border-radius:10px;border:1px solid transparent;background:none;min-height:44px;text-align:left}
55
+ .node:hover{background:var(--paper)}.node[aria-expanded=true]{background:var(--paper);border-color:var(--line2)}
56
+ .node .body{display:flex;flex-direction:column;min-width:0;flex:1}.node .id{font:13px/18px var(--mono)}
57
+ .pips{display:flex;gap:3px;flex:none}.pips i{width:8px;height:14px;border-radius:2px;background:var(--twig)}.pips i.pass{background:var(--moss)}.pips i.fail{background:var(--verm)}.pips i.warn{background:var(--ochre)}
58
+ .time{font:12px/16px var(--mono);color:var(--ink3);width:56px;text-align:right;flex:none}
59
+ .twigs{border-left:1px solid var(--twig);margin:4px 0 8px 44px}.twigs .twig{width:18px}.twigs .twig i{border-top:1px solid var(--twig)}
60
+ .step{flex:1;min-width:0;display:grid;grid-template-columns:8px minmax(120px,1.1fr) minmax(120px,1fr) minmax(60px,.8fr) 60px 48px;align-items:center;gap:12px;padding:8px 12px;border-radius:8px;border:0;background:none;min-height:40px;text-align:left}
61
+ .step:hover{background:var(--sel)}.step[aria-pressed=true]{background:var(--sel)}
62
+ .step .req{font:12px/16px var(--mono);color:var(--ink3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
63
+ .bar{height:10px;position:relative;background:var(--bar);border-radius:3px}.bar i{position:absolute;top:0;bottom:0;border-radius:3px;background:var(--trunk);min-width:3px}.bar i.fail{background:var(--verm)}
64
+ .ms,.res{font:12px/16px var(--mono);text-align:right}
65
+ .fix{display:flex;flex-direction:column;gap:4px;text-align:left;padding:12px 14px;border-radius:10px;border:1px solid var(--line);background:var(--paper)}
66
+ .fix:hover,.fix[aria-pressed=true]{border-color:var(--twig)}
67
+ .obs{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px;margin:12px 0}.obs>div{min-width:0;overflow-wrap:anywhere;padding:10px 12px;border-radius:8px;background:var(--stone)}.obs .bad{background:var(--verm-bg)}.obs .good{background:var(--moss-bg)}
68
+ .obs-long{grid-template-columns:minmax(0,1fr)}.obs .mono{white-space:pre-wrap}
69
+ pre{font:12px/1.6 var(--mono);background:var(--code);border-radius:8px;padding:12px 14px;overflow-x:auto;margin:0;white-space:pre-wrap;overflow-wrap:anywhere}
70
+ .think{display:inline-flex;gap:5px;align-items:center}.think i{width:7px;height:7px;border-radius:50%;background:var(--moss);animation:pulse 1.2s ease-in-out infinite}
71
+ .think i:nth-child(2){animation-delay:.18s}.think i:nth-child(3){animation-delay:.36s}
72
+ .growing .dot{animation:breathe 1.6s ease-in-out infinite}
73
+ @keyframes pulse{0%,100%{opacity:.25;transform:scale(.75)}50%{opacity:1;transform:scale(1)}}@keyframes breathe{0%,100%{box-shadow:0 0 0 0 transparent}50%{box-shadow:0 0 0 5px var(--moss-bg)}}
74
+ .fade{animation:fade .24s ease-out both}@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
75
+ @media (prefers-reduced-motion:reduce){.think i,.growing .dot,.fade,.live .dot{animation:none}}
76
+ .phases{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}.phases li{display:flex;gap:10px;align-items:center}.phases .ok{color:var(--moss);width:12px}.phases .wait{color:var(--muted);width:12px}
77
+ .src{display:flex;flex-direction:column;gap:4px}.src button{display:flex;align-items:center;gap:10px;min-height:40px;padding:0 12px;border-radius:8px;border:1px solid transparent;background:none;text-align:left;font:13px/18px var(--mono)}
78
+ .src button[aria-pressed=true]{background:var(--paper);border-color:var(--line2)}.src button:hover{background:var(--paper)}
79
+ .route{display:grid;grid-template-columns:8px minmax(160px,1.4fr) minmax(120px,1fr) auto;gap:12px;align-items:center;padding:8px 12px;border-radius:8px;min-height:44px}.route:hover{background:var(--paper)}
80
+ .grid{border-collapse:separate;border-spacing:0}.grid th,.grid td{padding:8px 10px;text-align:center;border-bottom:1px solid var(--line)}.grid th:first-child,.grid td:first-child{text-align:left;position:sticky;left:0;background:var(--stone)}
81
+ .cell{width:28px;height:28px;border-radius:8px;border:1px solid transparent;background:none;display:inline-flex;align-items:center;justify-content:center}.cell:hover{border-color:var(--twig);background:var(--paper)}
82
+ .scroll{overflow-x:auto}.seg{display:flex;flex-wrap:wrap;gap:8px}.seg button{flex:1 1 160px;text-align:left;padding:12px 14px;border-radius:10px;border:1px solid var(--line2);background:var(--paper);display:flex;flex-direction:column;gap:2px}
83
+ .seg button[aria-pressed=true]{border-color:var(--moss);box-shadow:inset 0 0 0 1px var(--moss)}
84
+ table.kv{border-collapse:collapse;width:100%}table.kv th,table.kv td{text-align:left;padding:8px 0;border-bottom:1px solid var(--line);vertical-align:top}table.kv th{width:38%;padding-right:12px;font-weight:500;color:var(--ink3)}
85
+ .toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);display:flex;align-items:center;gap:14px;background:var(--forest);color:var(--on-forest);padding:10px 16px;border-radius:10px;font-size:14px;z-index:30;max-width:92vw}
86
+ .toast .act{background:none;border:0;color:var(--on-forest);text-decoration:underline;font-weight:600;min-height:28px;padding:0}
87
+ .pal-back{position:fixed;inset:0;background:rgba(18,20,18,.34);display:flex;align-items:flex-start;justify-content:center;padding-top:12vh;z-index:20}
88
+ .pal{width:min(640px,92vw);background:var(--paper);border:1px solid var(--line2);border-radius:14px;box-shadow:0 24px 60px rgba(0,0,0,.2);overflow:hidden}
89
+ .pal input{width:100%;border:0;border-bottom:1px solid var(--line);border-radius:0;min-height:54px;font-size:16px;padding:0 18px;outline:none}
90
+ .pal ul{list-style:none;margin:0;padding:6px;max-height:52vh;overflow:auto}.pal li{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:8px;cursor:pointer;min-height:44px}
91
+ .pal li[aria-selected=true]{background:var(--sel)}.pal .grp{font:500 11px/16px var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--muted);width:76px;flex:none}.pal .hint{margin-left:auto;color:var(--muted);font-size:13px}
92
+ .pal .foot{display:flex;gap:16px;padding:8px 14px;border-top:1px solid var(--line);color:var(--muted);font-size:12px;flex-wrap:wrap}
93
+ kbd{font:500 11px/16px var(--mono);border:1px solid var(--line2);border-bottom-width:2px;border-radius:5px;padding:1px 6px;color:var(--ink3);background:var(--stone)}
94
+ .kbtn{display:inline-flex;gap:8px;align-items:center;min-height:36px;padding:0 10px;border:1px solid var(--line2);border-radius:8px;background:var(--paper);color:var(--ink3);font-size:13px}
95
+ .log{max-height:280px;overflow:auto;font:12px/1.6 var(--mono);background:var(--code);border-radius:8px;padding:10px 12px;margin-top:12px}.log div{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--ink3)}.log div:last-child{color:var(--ink)}
96
+ .diff{font:12px/1.6 var(--mono);background:var(--code);border-radius:8px;padding:8px 0;overflow-x:auto;margin-top:8px}.diff div{padding:0 12px;white-space:pre}.diff .add{background:var(--moss-bg);color:var(--moss)}.diff .del{background:var(--verm-bg);color:var(--verm-ink)}.diff .ctx{color:var(--ink3)}
97
+ .finding{display:flex;flex-direction:column;gap:6px;padding:14px 16px;border-radius:10px;border:1px solid var(--line);background:var(--paper)}
98
+ .step.live,.node.live{box-shadow:inset 3px 0 0 var(--moss);background:var(--paper)}.live .dot{animation:breathe 1.1s ease-in-out infinite}
99
+ .keys{display:grid;grid-template-columns:auto 1fr;gap:10px 16px;align-items:center;margin-top:12px}
100
+ @media (max-width:720px){header{padding:12px 16px}.page{padding:20px 16px 40px}.ctx{margin-left:0;width:100%}h1{font-size:23px;line-height:30px}
101
+ .step{grid-template-columns:8px 1fr 48px;}.step .req,.step .bar,.step .ms{display:none}.route{grid-template-columns:8px 1fr auto}.route .where{display:none}.obs{grid-template-columns:minmax(0,1fr)}}
102
+ </style></head><body>
103
+ <header><span class="brand"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true" style="color:var(--moss)"><path d="M12 21V11"/><path d="M12 14c-3 0-5-2-6-4"/><path d="M12 11c2.5 0 4.5-1.5 5.5-3.5"/><circle cx="6" cy="9" r="2.2"/><circle cx="17.8" cy="7.2" r="2.2"/><circle cx="12" cy="6" r="2.6"/><path d="M8 21h8"/></svg>tracegrove</span>
104
+ <nav id="tabs" aria-label="Sections"></nav><span class="ctx" id="ctx"></span><button class="kbtn" id="palbtn" type="button" aria-label="Open the command palette" aria-keyshortcuts="Control+K Meta+K">Commands <kbd>⌘K</kbd></button></header>
105
+ <div class="page" id="main"></div>
106
+ <script>
107
+ const TOKEN='__TOKEN__';const START_BRANCH=__BRANCH__;const DEFAULT_MODELS=__DEFAULT_MODELS__;
108
+ const TABS=['Run','Discover','Heal','History','Settings'];
109
+ let tab=START_BRANCH?'Discover':'Run';let state=null;
110
+ const ui={run:null,runName:null,sel:null,step:null,running:false,activeRunId:null,cancelling:false,disc:null,source:START_BRANCH||'',draft:null,agent:null,agentPhase:-1,videoTimes:{},live:null,heal:null,heals:[],healing:false,healError:null};
111
+ function h(tag,attrs,...kids){const el=document.createElement(tag);for(const[k,v]of Object.entries(attrs||{})){if(k==='on')for(const[e,f]of Object.entries(v))el.addEventListener(e,f);else if(v!==null&&v!==undefined&&v!==false)el.setAttribute(k,v===true?'':v)}for(const kid of kids.flat()){if(kid===null||kid===undefined||kid===false)continue;el.append(kid instanceof Node?kid:document.createTextNode(String(kid)))}return el}
112
+ async function api(path,body){const r=await fetch(path,body?{method:'POST',headers:{'content-type':'application/json','x-tracegrove-token':TOKEN},body:JSON.stringify(body)}:{});const j=await r.json();if(!r.ok)throw j;return j}
113
+ function toast(text,action){for(const old of document.querySelectorAll('.toast'))old.remove();const t=h('div',{class:'toast fade',role:'status'},h('span',{},text),
114
+ action?h('button',{class:'act',on:{click:async()=>{t.remove();await action.run()}}},action.label):null);document.body.append(t);setTimeout(()=>t.remove(),action?7000:2800)}
115
+ function blocked(e){return h('div',{class:'card fade'},h('div',{class:'row'},h('span',{class:'pill p-fail'},'blocked'),h('h2',{},'Fix this first')),
116
+ ...(e.reasons||[{code:'error',detail:e.error||String(e),action:''}]).map(r=>h('div',{style:'margin-top:12px'},h('div',{class:'mono small'},r.code),h('div',{},r.detail),r.action?h('div',{class:'muted small'},'Fix: '+r.action):null)))}
117
+ const OUT={passed:'pass',assertion_failed:'fail',failed:'fail',completed:'pass',blocked:'warn',inconclusive:'warn',infrastructure_failed:'warn',cancelled:'warn',skipped:'none'};
118
+ const LABEL={pass:'held',fail:'failed',warn:'blocked',none:'not run',pruned:'pruned'};
119
+ const kind=o=>OUT[o]||'none';
120
+ const secs=ms=>ms==null?'':ms<1000?ms+' ms':(ms/1000).toFixed(1)+' s';
121
+ const ago=iso=>{const d=(Date.now()-new Date(iso).getTime())/1000;return d<60?'just now':d<3600?Math.round(d/60)+' min ago':d<86400?Math.round(d/3600)+' h ago':new Date(iso).toLocaleDateString()};
122
+ function header(){document.getElementById('tabs').replaceChildren(...TABS.map(t=>h('button',{'aria-current':t===tab?'page':'false',on:{click:()=>{tab=t;render()}}},t)));
123
+ const g=state?state.git:null;const last=state&&state.runs[0];
124
+ document.getElementById('ctx').textContent=state?[state.config?state.config.project:state.dir.split('/').pop(),g&&g.isRepo?(g.current||'detached'):null,last?'last run '+ago(last.startedAt):'never run'].filter(Boolean).join(' · '):''}
125
+ async function load(){state=await api('/api/overview');try{ui.heals=await api('/api/heals')}catch{ui.heals=[]}if(!ui.heal&&ui.heals.length)ui.heal=ui.heals[0];ui.activeRunId=state.activeRunId;ui.cancelling=state.cancelling;if(state.running){ui.running=ui.running||'Verification is running';watchRun()}if(state.runs.length&&(!ui.runName||!state.runs.some(r=>r.name===ui.runName))){ui.runName=state.runs[0].name;ui.run=null}if(ui.runName&&!ui.run){try{ui.run=await api('/api/runs/'+encodeURIComponent(ui.runName))}catch{ui.run=null}}render()}
126
+ function page(...nodes){document.getElementById('main').replaceChildren(...nodes.flat().filter(n=>n!==null&&n!==undefined&&n!==false))}
127
+
128
+ ${SOURCE_CONTROLS_JS}
129
+ /* ---------- Run: the bonsai ---------- */
130
+ function scenarios(){const run=ui.run;
131
+ // Saved observations belong to their recorded steps, never today's flow or array position.
132
+ if(run)return(run.cases||[]).map(c=>({id:c.caseId,title:c.title,file:c.file,reportedFile:c.reportedFile,reportedTitle:c.reportedTitle,fixtures:[],state:kind(c.outcome),ms:c.durationMs,failure:c.failure,
133
+ steps:c.steps.map(r=>({id:r.id,name:r.name,reportedName:r.reportedName,method:r.method,path:r.path,as:null,expect:null,expectation:'Checks recorded for this run',result:kind(r.result),status:r.status,observedText:r.observedText,ms:r.durationMs,reason:r.reason}))}));
134
+ const live=state.flows.map(f=>({id:f.caseId,title:f.title,file:f.file,fixtures:f.fixtures,state:'none',ms:null,failure:null,
135
+ steps:f.steps.map(s=>({id:s.id,name:s.name,method:s.method,path:s.path,as:s.as,expect:s.expectStatus,expectation:s.expectation,result:'none',status:null,observedText:null,ms:null,reason:null}))}));
136
+ const cut=(state.pruned||[]).map(p=>({id:p.file.replace(/^.*\//,'').replace(/\.flow\.(?:ya?ml|ts)\.pruned$/,''),title:p.title,file:p.file,state:'pruned',steps:[],fixtures:[]}));
137
+ return live.concat(cut)}
138
+ function runTab(){
139
+ if(!state.hasConfig&&!ui.run)return[h('div',{class:'card fade',style:'max-width:640px'},h('span',{class:'label'},'Plant the first tree'),h('h1',{style:'margin:8px 0 12px'},'No tracegrove.config.yaml in this folder yet.'),
140
+ h('p',{class:'muted'},'Init detects FastAPI, Django or Node, writes a config and one example flow, and tells you the test-mode auth line to add.'),h('button',{class:'btn',on:{click:async()=>{try{await api('/api/init',{});toast('Config and example flow written');await load()}catch(e){page(blocked(e))}}}},'Initialize'))];
141
+ if(state.compileError&&!state.flows.length&&!ui.run)return[sourceBanner(),blocked(state.compileError)];
142
+ const sc=scenarios();const run=ui.run;const ran=sc.filter(s=>s.state!=='none'&&s.state!=='pruned');const held=ran.filter(s=>s.state==='pass').length;
143
+ const allSteps=run?(run.cases||[]).flatMap(s=>s.steps):[];const stepsHeld=allSteps.filter(s=>kind(s.result)==='pass').length;
144
+ if(ui.sel===null){const f=sc.find(s=>s.state==='fail');ui.sel=f?f.id:(sc[0]||{}).id;ui.step=f?Math.max(0,f.steps.findIndex(x=>x.result==='fail')):0}
145
+ const headline=!run?'Nothing has run yet. Run the grove to see which scenarios hold.':run.bundleVerified===false?'Evidence could not be verified for this run.':run.outcome==='passed'?'Every scenario held on this run.':held+' of '+ran.length+' scenarios held. '+(ran.length-held)+' need'+(ran.length-held===1?'s':'')+' a look.';
146
+ const pick=h('select',{'aria-label':'Run',on:{change:async e=>{ui.runName=e.target.value;ui.run=null;ui.sel=null;await load()}}},state.runs.map(r=>h('option',{value:r.name,selected:r.name===ui.runName},ago(r.startedAt)+' · '+LABEL[kind(r.outcome)]+' · '+r.totals.passed+'/'+(r.totals.passed+r.totals.failed+r.totals.other))));
147
+ const hero=h('section',{style:'margin-bottom:28px'},h('div',{class:'row',style:'justify-content:space-between;align-items:flex-start'},
148
+ h('div',{},h('span',{class:'label'},run?'Run '+run.runDir.split('/').pop():state.flows.length+' scenarios planted'),h('h1',{style:'margin-top:6px'},headline)),
149
+ h('div',{class:'row'},state.runs.length?pick:null,ui.running?h('div',{class:'row'},h('span',{class:'row muted'},h('span',{class:'think'},h('i'),h('i'),h('i')),h('span',{id:'run-activity',role:'status','aria-live':'polite'},ui.running)),ui.activeRunId?h('button',{class:'btn ghost',disabled:ui.cancelling,on:{click:cancelRun}},ui.cancelling?'Waiting for run to settle':'Cancel run'):null):
150
+ [ui.sel&&sc.length>1?h('button',{class:'btn ghost',disabled:!!state.compileError||!state.flows.some(f=>f.caseId===ui.sel),on:{click:()=>runNow(ui.sel)}},'Run this scenario'):null,h('button',{class:'btn',disabled:!state.hasConfig||!!state.compileError,on:{click:()=>runNow('')}},'Run all')])),
151
+ run?h('div',{class:'stats'},h('div',{},h('b',{},held+' / '+ran.length),h('span',{class:'muted'},'scenarios held')),h('div',{},h('b',{},stepsHeld+' / '+allSteps.length),h('span',{class:'muted'},'steps held')),
152
+ h('div',{},h('b',{},secs(new Date(run.finishedAt)-new Date(run.startedAt))),h('span',{class:'muted'},'wall time')),
153
+ h('div',{},h('b',{class:run.bundleVerified?'c-pass':'c-warn'},run.bundleVerified?'✓':'–'),h('span',{class:'muted'},run.savedEvidence?(run.savedEvidence.status==='verified'?'saved evidence freshly verified':'saved evidence '+run.savedEvidence.status):(run.bundleVerified?'evidence verified at run completion':'bundle not verified')))):null,
154
+ run?h('p',{class:'small muted',role:'note'},'Showing recorded scenarios and steps. Rerun and Run all use the current configuration.'+(state.sourceDigest==null?' Current application source could not be resolved.':run.sourceDigest!==state.sourceDigest?' Application source differs from this recorded run.':'')):null,
155
+ run&&run.savedEvidence?h('p',{class:'small muted','aria-label':'Saved evidence status'},run.savedEvidence.message):null,
156
+ state.compileError?h('div',{style:'margin-top:16px'},blocked(state.compileError)):null,ui.error?h('div',{style:'margin-top:16px'},blocked(ui.error)):null);
157
+ const tree=h('section',{class:'grow','aria-label':'Scenario tree'},h('div',{class:'rulehead'},h('span',{class:'label'},'Scenarios'),h('span',{class:'rule'}),h('span',{class:'small muted'},'step · interaction · time on the run clock · status')),
158
+ h('div',{class:'tree'+(ui.running?' growing':'')},sc.map(s=>branch(s))));
159
+ const side=h('div',{class:'side'},fixes(sc,run),detail(sc));
160
+ return[sourceBanner(),hero,h('div',{class:'cols'},tree,side)]}
161
+ function branch(s){const open=ui.sel===s.id&&s.steps.length>0;const cut=s.state==='pruned';const total=s.steps.reduce((a,x)=>a+(x.ms||0),0)||1;let at=0;
162
+ return h('div',{class:'fade'},h('div',{class:'br'},h('span',{class:'twig'+(cut?' cut':'')},h('i')),
163
+ h('button',{class:'node','data-case':s.id,'data-steps':s.steps.map(x=>x.id).join(' '),'aria-expanded':open?'true':'false',on:{click:()=>{ui.sel=s.id;ui.step=Math.max(0,s.steps.findIndex(x=>x.result==='fail'));render()}}},
164
+ h('span',{class:'dot '+s.state,'aria-hidden':'true'}),
165
+ h('span',{class:'body'},h('span',{class:'row',style:'gap:4px 12px'},h('span',{class:'id',style:cut?'color:var(--muted)':''},s.id),h('span',{class:'state c-'+(cut?'none':s.state)},LABEL[s.state])),
166
+ h('span',{style:cut?'color:var(--ink3)':''},s.title),s.reportedTitle&&s.reportedTitle!==s.title?h('span',{class:'small muted'},'Saved title (unsealed): '+s.reportedTitle):null,s.fixtures.length?h('span',{class:'small muted'},'given '+s.fixtures.join(', ')):null),
167
+ h('span',{class:'pips','aria-label':s.steps.filter(x=>x.result==='pass').length+' of '+s.steps.length+' steps held'},s.steps.map(x=>h('i',{class:x.result}))),
168
+ h('span',{class:'time'},secs(s.ms)))),
169
+ open?h('div',{class:'twigs fade'},s.steps.map((x,j)=>{const left=at/total*100;at+=x.ms||0;return h('div',{class:'br'},h('span',{class:'twig'},h('i')),
170
+ h('button',{class:'step','data-step':x.id,'aria-pressed':ui.step===j?'true':'false',on:{click:()=>{ui.step=j;render()}}},h('span',{class:'dot s '+x.result,'aria-hidden':'true'}),h('span',{},x.name,x.reportedName&&x.reportedName!==x.name?h('small',{class:'muted'},' · saved name (unsealed): '+x.reportedName):null),h('span',{class:'req'},x.method+' '+x.path),
171
+ h('span',{class:'bar','aria-hidden':'true'},x.ms!=null?h('i',{class:x.result==='fail'?'fail':'',style:'left:'+left.toFixed(1)+'%;width:'+((x.ms||0)/total*100).toFixed(1)+'%'}):null),
172
+ h('span',{class:'ms muted'},x.ms!=null?x.ms+' ms':''),h('span',{class:'res c-'+x.result},x.status!=null?x.status:x.result==='none'?'–':LABEL[x.result])))})):null)}
173
+ function fixes(sc,run){const items=[];for(const s of sc)if(s.state==='fail'||s.state==='warn')items.push({s,title:s.failure?s.failure.message:'Did not complete',where:s.failure?'step "'+s.failure.step+'"':s.file});
174
+ if(run&&run.bundleVerified===false)items.push({s:null,title:run.savedEvidence?run.savedEvidence.message:'Exported evidence failed verification',where:'Preserve this run and inspect its evidence before relying on the historical result.'});
175
+ for(const b of (run&&run.blockers)||[])items.push({s:null,title:b.code+': '+b.detail,where:b.action});
176
+ return h('section',{'aria-label':'Needs a fix'},h('div',{class:'rulehead'},h('h2',{},'Needs a fix'),h('span',{class:'rule'}),h('span',{class:'small muted'},items.length?items.length+' open':''),
177
+ items.length&&!ui.running?h('button',{class:'btn sm',title:'Fix setup and drifted tests, prove each fix by re-running; product bugs are reported, never hidden (h)',on:{click:()=>startHeal(false)}},'Heal'):null),
178
+ items.length?h('div',{style:'display:flex;flex-direction:column;gap:8px'},items.map(it=>h('button',{class:'fix','aria-pressed':it.s&&ui.sel===it.s.id?'true':'false',on:{click:()=>{if(!it.s)return;ui.sel=it.s.id;ui.step=Math.max(0,it.s.steps.findIndex(x=>x.result!=='pass'));render()}}},
179
+ h('span',{class:'row',style:'gap:8px'},h('span',{class:'pill '+(it.s&&it.s.state==='fail'?'p-fail':'p-warn')},it.s&&it.s.state==='fail'?'failed':'blocked'),h('span',{class:'mono small'},it.s?it.s.id:'run')),h('span',{},it.title),h('span',{class:'small muted'},it.where)))):
180
+ h('p',{class:'muted'},run?'Nothing. Every scenario that ran held.':'Run the grove and failures land here, ordered as they occurred.'))}
181
+ function recording(s){const c=ui.run&&(ui.run.cases||[]).find(c=>c.caseId===s.id);const v=c&&(c.videos||[]).find(v=>v.mediaType==='video/webm'&&/^[a-f0-9]{64}$/.test(v.digest));if(!v||!ui.runName)return null;
182
+ const status=h('p',{class:'small muted',role:'status'},'Checking the recording evidence…');
183
+ if(ui.run.bundleVerified===false)return h('section',{class:'recording','aria-label':'Browser recording'},h('h2',{},'Browser recording'),h('p',{role:'alert'},'Recording unavailable: this run’s evidence failed verification.'));
184
+ const key=ui.runName+':'+v.digest;
185
+ const player=h('video',{controls:true,playsinline:true,preload:'metadata','aria-label':'Browser recording for '+s.id,src:'/api/runs/'+encodeURIComponent(ui.runName)+'/media/'+v.digest+'?case='+encodeURIComponent(s.id),
186
+ on:{loadedmetadata:()=>{const at=ui.videoTimes[key];if(Number.isFinite(at)&&at>0)player.currentTime=Math.min(at,Number.isFinite(player.duration)?player.duration:at);status.textContent='Recording loaded from verified evidence.'},timeupdate:()=>{ui.videoTimes[key]=player.currentTime},error:()=>{status.textContent='Recording unavailable or its evidence failed verification.'}}});
187
+ return h('section',{class:'recording','aria-label':'Browser recording'},h('h2',{},'Browser recording'),player,status)}
188
+ function detail(sc){const s=sc.find(x=>x.id===ui.sel);if(!s)return null;const x=s.steps[ui.step];const current=state.flows.find(f=>f.caseId===s.id);
189
+ if(!x)return h('aside',{class:'card fade'},h('span',{class:'label'},s.id),h('h2',{style:'margin:6px 0'},s.title),h('p',{class:'muted'},s.state==='pruned'?'Pruned: the file is kept as '+s.file+' and the compiler skips it.':'No steps.'),
190
+ s.state==='pruned'?h('button',{class:'btn ghost',on:{click:()=>prune(s.file.replace(/\.pruned$/,''),true)}},'Graft back'):null);
191
+ const bad=x.result==='fail';
192
+ return h('aside',{class:'card fade','aria-label':'Step detail'},h('span',{class:'label'},s.id+' › step '+(ui.step+1)+' of '+s.steps.length),h('h2',{style:'margin:6px 0 2px'},x.name),
193
+ x.reportedName&&x.reportedName!==x.name?h('p',{class:'small muted'},'Saved name (unsealed): '+x.reportedName):null,
194
+ h('p',{class:'mono small muted',style:'margin:0'},[x.method&&x.path?x.method+' '+x.path:null,x.as?'as '+x.as:null,x.ms!=null?x.ms+' ms':null].filter(Boolean).join(' · ')),
195
+
196
+ h('div',{class:'obs'+(x.observedText&&x.observedText.length>120?' obs-long':'')},h('div',{},h('div',{class:'label'},'expected'),h('div',{class:'mono'},x.expectation||(x.expect!=null?'Status '+x.expect:'Step completes'))),h('div',{class:bad?'bad':x.result==='pass'?'good':''},h('div',{class:'label'},'observed'),h('div',{class:'mono'},x.observedText!=null?x.observedText:x.status!=null?x.status:x.result==='none'?'not run':LABEL[x.result]))),
197
+ s.failure?h('pre',{},'Recorded case failure at '+s.failure.step+': '+s.failure.message+(s.failure.observed?'\n'+s.failure.observed:'')):x.reason?h('p',{class:'small muted'},x.reason):h('p',{class:'small muted'},x.result==='pass'?'Step completed. See the recorded case outcome and checks.':'Run the scenario to observe this step.'),
198
+ recording(s),
199
+ h('div',{class:'row',style:'margin-top:16px'},h('span',{class:'mono small muted',style:'flex:1;overflow-wrap:anywhere'},s.reportedFile?'Saved flow (unsealed): '+s.reportedFile:s.file),
200
+ current?h('button',{class:'btn ghost sm',on:{click:()=>prune(current.file,false)}},ui.run?'Prune current flow':'Prune'):null,h('button',{class:'btn sm',disabled:!current||!!ui.running||!!state.compileError,on:{click:()=>runNow(s.id)}},s.state==='none'?'Run':'Rerun')))}
201
+ let runWatch=null;
202
+ function stopRunWatch(){if(runWatch!==null)clearInterval(runWatch);runWatch=null}
203
+ /* Live progress comes from real run and agent events (/api/live), never from timers. */
204
+ function paintLive(){const l=ui.live;if(!l)return;const a=l.run;
205
+ const el=document.getElementById('run-activity');if(el&&a.status==='running')el.textContent=a.label;
206
+ for(const n of document.querySelectorAll('[data-step]'))n.classList.toggle('live',a.status==='running'&&!!a.stepId&&n.getAttribute('data-step')===a.stepId);
207
+ for(const n of document.querySelectorAll('[data-steps]'))n.classList.toggle('live',a.status==='running'&&!!a.stepId&&n.getAttribute('data-steps').split(' ').includes(a.stepId));
208
+ const log=document.getElementById('agent-log');if(log){const lines=l.agent.lines.length?l.agent.lines:['Waiting for the agent to start'];if(log.childElementCount!==lines.length||log.lastChild.textContent!==lines[lines.length-1]){const stick=log.scrollTop+log.clientHeight>=log.scrollHeight-8;log.replaceChildren(...lines.map(x=>h('div',{},x)));if(stick)log.scrollTop=log.scrollHeight}}
209
+ const hp=document.getElementById('heal-phase');if(hp&&l.heal.status==='running')hp.textContent=l.heal.phase+(l.heal.detail?' · '+l.heal.detail:'')}
210
+ function watchRun(){if(runWatch!==null)return;let polling=false;runWatch=setInterval(async()=>{if(polling)return;polling=true;try{const [l,c]=await Promise.all([api('/api/live'),api('/api/run-control')]);const changed=ui.activeRunId!==c.runId||ui.cancelling!==c.cancelling;ui.activeRunId=c.runId;ui.cancelling=c.cancelling;ui.live=l;if(changed)render();const a=l.run;if(ui.running&&a.status==='running')ui.running=a.label;paintLive();
211
+ if(ui.running&&!ui.healing&&ui.agentPhase<0&&(a.status==='finished'||a.status==='failed')){stopRunWatch();ui.running=false;ui.runName=null;ui.run=null;await load()}}catch{}finally{polling=false}},400)}
212
+ async function cancelRun(){const runId=ui.activeRunId;if(!runId||ui.cancelling)return;ui.cancelling=true;render();try{const r=await api('/api/cancel',{runId});toast((r.operation==='heal'?'Heal':r.operation==='draft'?'Draft':'Run')+' settled: '+r.outcome+'; inspect saved records')}catch(e){ui.error=e;render()}}
213
+ async function runNow(grep){if(state.compileError){ui.error=state.compileError;render();return}if(ui.running)return;ui.running='Compiling flows and starting the app';render();watchRun();
214
+ ui.error=null;try{const r=await api('/api/test',{grep});ui.runName=r.runDir.split('/').pop();ui.run=r;ui.sel=null;toast(r.outcome==='passed'?'Every scenario held':'Run finished: '+r.totals.passed+' held, '+(r.totals.failed+r.totals.other)+' need a look',r.outcome==='passed'?null:{label:'Heal',run:()=>startHeal(false)})}catch(e){ui.error=e}finally{stopRunWatch();ui.running=false;ui.activeRunId=null;ui.cancelling=false}await load()}
215
+ async function prune(file,graft){try{await api('/api/prune',{file,graft});toast(graft?'Grafted back':'Pruned '+file.split('/').pop(),{label:'Undo',run:()=>prune(file,!graft)});ui.sel=null;await load()}catch(e){toast(e.error||'Could not '+(graft?'graft':'prune'))}}
216
+
217
+ /* ---------- Discover: source, reachability, intent ---------- */
218
+ function discoverTab(){const g=state.git;const a=state.agent.settings;const name=a.provider==='claude'?'Claude':a.provider==='codex'?'Codex':null;const available=!!(name&&state.agent.detected[a.provider]);
219
+ const sources=[{v:'',label:'working tree',note:'uncommitted files included'}].concat(g.branches.map(b=>({v:b,label:b,note:b===g.current?'checked out':b===g.base?'base':''})));
220
+ const src=h('section',{class:'side',style:'flex:1 1 260px;max-width:340px'},h('div',{},h('span',{class:'label'},'Source'),h('div',{class:'src',style:'margin-top:10px'},
221
+ (g.isRepo?sources:sources.slice(0,1)).map(s=>h('button',{'aria-pressed':ui.source===s.v?'true':'false',on:{click:()=>{ui.source=s.v;scan()}}},h('span',{class:'dot s '+(ui.source===s.v?'pass':'none')}),h('span',{style:'flex:1;min-width:0;display:flex;flex-direction:column;padding:6px 0'},h('span',{style:'overflow-wrap:anywhere'},s.label),s.note?h('span',{class:'small muted',style:'font-family:var(--sans)'},s.note):null)))),
222
+ g.isRepo?h('p',{class:'small muted'},'A branch shows routes in files it changed against '+(g.base||'the default branch')+' first.'):h('p',{class:'small muted'},'Not a git repo, so only the working tree.')));
223
+ const d=ui.disc;
224
+ const reach=h('section',{class:'grow'},h('div',{class:'rulehead'},h('span',{class:'label'},'Static routes'),h('span',{class:'rule'}),d?h('span',{class:'small muted'},d.routes.length+' recognized routes · '+d.uncovered+' without a flow'+(d.branch&&d.base?' · '+d.changedFiles.length+' files changed':'')):null),
225
+ h('p',{class:'small muted'},'Partial static inventory for FastAPI, Django and Express. Other routes may be missing; this is not execution coverage.'),
226
+ !d?h('p',{class:'row muted'},h('span',{class:'think'},h('i'),h('i'),h('i')),'Scanning routes'):d.routes.length?h('div',{},d.routes.map(r=>routeRow(r))):h('p',{class:'muted'},'No supported routes recognized. Other routing styles, including Next.js, are not scanned.'),
227
+ ui.draft?draftCard():null);
228
+ const intent=h('section',{class:'side',style:'flex:1 1 340px'},h('div',{class:'card'},h('span',{class:'label'},'Intent'),h('h2',{style:'margin:6px 0 4px'},'What should be true after this change?'),
229
+ h('p',{id:'agent-readiness',class:'small muted',style:'margin:0 0 12px'},name?(available?name+' ('+(a.model||'CLI default')+') reads the code, writes flows into tracegrove/discovered/, and tracegrove checks them before you see them.':name+' is not installed. Choose an installed provider in Settings, or None for templates. Executable detection does not establish sign-in.'):'Choose an installed provider in Settings, or use route templates without an agent.'),
230
+ h('textarea',{id:'intent',placeholder:'After Alice revokes a share, Bob can no longer read the note.','aria-label':'Intent'},ui.intent||''),
231
+ h('div',{class:'row',style:'margin-top:12px'},h('button',{class:'btn','aria-describedby':'agent-readiness',disabled:!available||ui.agentPhase>=0,on:{click:agentDraft}},name?'Draft with '+name:'Draft'),h('button',{class:'btn ghost',on:{click:()=>{tab='Settings';render()}}},'Settings')),
232
+ ui.agentPhase>=0?h('div',{class:'fade'},h('p',{class:'row small muted',style:'margin:14px 0 0'},h('span',{class:'think'},h('i'),h('i'),h('i')),name+' is working; tracegrove checks every file it writes'),
233
+ h('div',{class:'log',id:'agent-log','aria-live':'polite'},(ui.live&&ui.live.agent.task==='draft'&&ui.live.agent.lines.length?ui.live.agent.lines:['Waiting for the agent to start']).map(x=>h('div',{},x)))):null,
234
+ ui.agent?agentResult():null));
235
+ return[h('div',{class:'cols'},src,reach,intent)]}
236
+ function routeRow(r){const covered=r.coveredBy.length>0;return h('div',{class:'route fade'},h('span',{class:'dot s '+(covered?'pass':'fail'),'aria-hidden':'true'}),
237
+ h('span',{style:'min-width:0'},h('span',{class:'mono small'},r.method+' '+r.path),r.changed?h('span',{class:'pill p-warn',style:'margin-left:8px'},'changed'):null,h('div',{class:'small '+(covered?'muted':'c-fail')},covered?r.coveredBy.join(', '):'no matching flow')),
238
+ h('span',{class:'where mono small muted',style:'overflow-wrap:anywhere'},r.file+':'+r.line),covered?h('span'):h('button',{class:'btn ghost sm',on:{click:()=>draftOne(r)}},'Draft'))}
239
+ function draftCard(){const d=ui.draft;return h('div',{class:'card fade',style:'margin-top:16px'},h('span',{class:'label'},'Draft'),h('h2',{class:'mono',style:'font-size:14px;margin:6px 0 12px'},'discovered/'+d.file),h('pre',{},d.yaml),
240
+ h('div',{class:'row',style:'margin-top:12px'},h('button',{class:'btn',on:{click:async()=>{try{const s=await api('/api/draft',{method:d.route.method,path:d.route.path,save:true});ui.draft=null;toast('Saved '+s.saved.split('/').slice(-3).join('/')+'. Fill the TODOs.');await load();scan()}catch(e){toast(e.error||'Could not save')}}}},'Plant it'),h('button',{class:'btn ghost',on:{click:()=>{ui.draft=null;render()}}},'Discard')))}
241
+ async function draftOne(r){try{const d=await api('/api/draft',{method:r.method,path:r.path});ui.draft={...d,route:r};render()}catch(e){toast(e.error||'Could not draft')}}
242
+ async function scan(){ui.scanning=true;ui.disc=null;ui.draft=null;render();try{ui.disc=await api('/api/discover?branch='+encodeURIComponent(ui.source||''))}catch(e){ui.scanning=false;page(blocked(e));return}ui.scanning=false;if(tab==='Discover')render()}
243
+ async function agentDraft(){const box=document.getElementById('intent');if(box)ui.intent=box.value;ui.agent=null;ui.agentPhase=0;ui.live=null;render();watchRun();
244
+ try{ui.agent=await api('/api/agent-draft',{intent:ui.intent||'',branch:ui.source})}catch(e){ui.agent={error:e}}finally{ui.agentPhase=-1;stopRunWatch()}await load();if(ui.disc)scan();
245
+ if(ui.agent&&ui.agent.agent)toast(ui.agent.agent.files.length+' flow file(s) drafted'+(ui.agent.check.ok?' and checked':'; check found issues'))}
246
+ function agentResult(){const r=ui.agent;if(r.error)return h('div',{style:'margin-top:16px'},blocked(r.error));const c=r.check;const ok=c.ok&&r.agent.exitCode===0;
247
+ return h('div',{class:'fade',style:'margin-top:16px'},h('div',{class:'row',style:'gap:8px'},h('span',{class:'pill '+(ok?'p-pass':'p-fail')},ok?'checked':'needs fixes'),h('span',{class:'small muted'},r.agent.files.length+' flow file(s) from '+r.agent.provider+(r.agent.model?' · '+r.agent.model:''))),
248
+ r.agent.files.length?h('div',{style:'margin-top:8px'},r.agent.files.map(f=>h('div',{class:'row',style:'justify-content:space-between;padding:6px 0;border-bottom:1px solid var(--line)'},h('span',{class:'mono small',style:'overflow-wrap:anywhere'},f),h('button',{class:'btn ghost sm',on:{click:()=>prune(f,false)}},'Prune')))):null,
249
+ c.ok?null:c.issues.map(x=>h('p',{class:'small'},h('span',{class:'c-fail'},x.detail),h('br'),h('span',{class:'muted'},'Fix: '+x.action))),
250
+ r.agent.output?h('details',{style:'margin-top:8px'},h('summary',{class:'small muted'},'What the agent said'),h('pre',{style:'margin-top:8px'},r.agent.output)):null,
251
+ ok&&r.agent.files.length?h('button',{class:'btn',style:'margin-top:12px',disabled:!!ui.running,on:{click:()=>{tab='Run';ui.sel=null;render();runNow('discovered')}}},'Run the new scenarios'):null)}
252
+
253
+ /* ---------- History: one case or the whole set ---------- */
254
+ function historyTab(){const runs=state.runs.slice(0,24);if(!runs.length)return[h('div',{class:'card'},h('h2',{},'No runs yet'),h('p',{class:'muted'},'Every run is kept under .tracegrove/runs/ with its evidence bundle.'))];
255
+ const ids=[...new Set(state.flows.map(f=>f.caseId).concat(runs.flatMap(r=>r.cases.map(c=>c.caseId))))];
256
+ const open=async(name,id)=>{ui.runName=name;ui.run=null;ui.sel=id||null;tab='Run';await load()};
257
+ return[h('div',{class:'rulehead'},h('span',{class:'label'},'History'),h('span',{class:'rule'}),h('span',{class:'small muted'},'newest first · a column is one run of the set · a row is one scenario across runs')),
258
+ h('div',{class:'card scroll',style:'padding:8px 12px'},h('table',{class:'grid'},h('thead',{},h('tr',{},h('th',{class:'label',style:'text-align:left'},'Scenario'),runs.map(r=>h('th',{},h('button',{class:'cell',title:r.name+' · '+r.outcome,on:{click:()=>open(r.name)}},h('span',{class:'dot '+kind(r.outcome)})),h('div',{class:'mono',style:'font-size:11px;color:var(--muted)'},ago(r.startedAt).replace(' ago','')))))),
259
+ h('tbody',{},ids.map(id=>h('tr',{},h('td',{class:'mono small'},id),runs.map(r=>{const c=r.cases.find(x=>x.caseId===id);return h('td',{},c?h('button',{class:'cell',title:id+' · '+c.outcome+' · '+secs(c.durationMs),on:{click:()=>open(r.name,id)}},h('span',{class:'dot s '+kind(c.outcome)})):h('span',{class:'muted'},'·'))}))))))]}
260
+
261
+ /* ---------- Settings ---------- */
262
+ function settingsTab(){const a=state.agent;const s=a.settings;const det=a.detected;let provider=s.provider;
263
+ const model=h('input',{id:'model','aria-label':'Model',value:s.source.model==='default'?'':(s.model||''),placeholder:DEFAULT_MODELS[s.provider]||'No agent selected',style:'flex:1;min-width:200px'});
264
+ const opt=(v,title,note,ok)=>h('button',{'aria-pressed':provider===v?'true':'false',on:{click:e=>{provider=v;model.value='';model.placeholder=DEFAULT_MODELS[v]||'No agent selected';for(const b of e.currentTarget.parentNode.children)b.setAttribute('aria-pressed',b===e.currentTarget?'true':'false')}}},h('b',{style:'font-weight:500'},title),h('span',{class:'small '+(ok?'c-pass':'muted')},note));
265
+ const cfg=state.config;
266
+ return[sourceSettings(),h('div',{class:'cols'},h('section',{class:'grow card'},h('span',{class:'label'},'Agent under the hood'),h('h2',{style:'margin:6px 0 4px'},'Who drafts and repairs your flows'),
267
+ h('p',{class:'small muted',style:'margin:0 0 16px'},'Saved to .tracegrove/settings.json for you alone. agent: in tracegrove.config.yaml sets the team default; --agent and --model on the CLI override both.'),
268
+ h('div',{class:'seg'},opt('claude','Claude Code',det.claude?'installed · '+DEFAULT_MODELS.claude:'not installed',!!det.claude),opt('codex','Codex',det.codex?'installed · '+DEFAULT_MODELS.codex:'not installed',!!det.codex),opt('none','None','discovery and templates only',false)),
269
+ h('div',{class:'row',style:'margin-top:16px'},model,h('button',{class:'btn',on:{click:async()=>{try{state.agent=await api('/api/settings',{agent:{provider,model:model.value}});toast('Saved');render()}catch(e){toast(e.reasons?e.reasons[0].detail:e.error)}}}},'Save')),
270
+ h('p',{class:'small muted',style:'margin-top:12px'},'In effect: ',h('span',{class:'mono'},s.provider+' · '+(s.model||'CLI default')),' (provider from '+s.source.provider+', model from '+s.source.model+').'),
271
+ (!det.claude||!det.codex)?h('p',{class:'small muted'},(!det.claude?'Claude Code: npm i -g @anthropic-ai/claude-code. ':'')+(!det.codex?'Codex: npm i -g @openai/codex.':'')):null),
272
+ h('section',{class:'side card'},h('span',{class:'label'},'Project'),cfg?h('table',{class:'kv'},h('tbody',{},
273
+ h('tr',{},h('th',{},'Name'),h('td',{},cfg.project)),h('tr',{},h('th',{},'Adapter'),h('td',{class:'mono small'},cfg.app.adapter+' '+(cfg.app.entry||cfg.app.run||''))),
274
+ h('tr',{},h('th',{},'Health'),h('td',{class:'mono small'},cfg.app.health)),h('tr',{},h('th',{},'Personas'),h('td',{class:'small'},Object.entries(cfg.personas).map(([k,v],i)=>(i?', ':'')+k+' → '+v.subject+(i===0?' (default)':'')).join(''))),
275
+ h('tr',{},h('th',{},'Flows'),h('td',{class:'mono small'},cfg.testDir+'/ · '+state.flows.length+' live, '+(state.pruned||[]).length+' pruned')),
276
+ h('tr',{},h('th',{},'Source digest'),h('td',{class:'mono small'},state.sourceDigest?state.sourceDigest.slice(0,16)+' · '+state.sourceFiles+' files':'–')))):h('p',{class:'muted'},'No config yet. Initialize from the Run tab.'),
277
+ h('p',{class:'small muted mono',style:'overflow-wrap:anywhere'},state.dir)))]}
278
+
279
+ /* ---------- Heal: diagnose, repair, prove, undo ---------- */
280
+ const KIND={setup:['setup','p-warn'],authoring:['authoring','p-warn'],test_drift:['test drift','p-info'],product_bug:['product bug','p-fail'],assertion:['failing','p-fail'],evidence:['evidence','p-warn'],infrastructure:['infrastructure','p-warn']};
281
+ const HEAL_TITLE={cancelled:'Heal cancelled',healthy:'Nothing to heal. Every scenario holds.',healed:'Healed. Every fix was proven by a re-run.',partly_healed:'Partly healed. Some findings still need you.',product_bugs:'Found product bugs. The tests stay red on purpose.',needs_human:'Needs you. Nothing was safe to fix automatically.'};
282
+ function diffView(text){return h('div',{class:'diff'},text.split('\n').slice(2).map(l=>h('div',{class:l[0]==='+'?'add':l[0]==='-'?'del':'ctx'},l||' ')))}
283
+ function healTab(){const r=ui.heal;const a=state.agent.settings;const name=a.provider==='claude'?'Claude Code':a.provider==='codex'?'Codex':null;const installed=name&&state.agent.detected[a.provider];
284
+ const hero=h('section',{style:'margin-bottom:24px'},h('div',{class:'row',style:'justify-content:space-between;align-items:flex-start'},
285
+ h('div',{style:'max-width:760px'},h('span',{class:'label'},'Self-healing'),h('h1',{style:'margin-top:6px'},ui.healing?'Healing the grove':r?HEAL_TITLE[r.outcome]:'Fix what broke, prove it, keep only what holds.'),
286
+ h('p',{class:'muted',style:'margin:8px 0 0'},'Setup mistakes are fixed in the config. Failing checks go to '+(installed?name+' ('+(a.model||'default')+')':'the agent')+', which must call each one test drift or a product bug. Drift is repaired and re-run; bugs are reported and the test stays red. Inspect the saved diff: agent judgments do not prove intended product behavior. Undo skips files changed afterward.')),
287
+ ui.healing?(ui.activeRunId?h('button',{class:'btn ghost',disabled:ui.cancelling,on:{click:cancelRun}},ui.cancelling?'Waiting for heal to settle':'Cancel heal'):null):h('div',{class:'row'},h('button',{class:'btn ghost',on:{click:()=>startHeal(true)}},'Preview'),h('button',{class:'btn',on:{click:()=>startHeal(false)}},'Heal now'))),
288
+ ui.healing?h('div',{class:'card fade',style:'margin-top:18px'},h('p',{class:'row',style:'margin:0'},h('span',{class:'think'},h('i'),h('i'),h('i')),h('span',{id:'heal-phase',role:'status','aria-live':'polite'},ui.live&&ui.live.heal.status==='running'?ui.live.heal.phase+(ui.live.heal.detail?' · '+ui.live.heal.detail:''):'Starting')),
289
+ h('div',{class:'log',id:'agent-log','aria-label':'What the agent is doing'},(ui.live&&ui.live.agent.task==='heal'&&ui.live.agent.lines.length?ui.live.agent.lines:['The agent joins only if a check fails after setup is sound']).map(x=>h('div',{},x)))):null,
290
+ !installed&&!ui.healing?h('p',{class:'small muted'},'No agent available: setup fixes still run. ',h('button',{class:'btn ghost sm',on:{click:()=>{tab='Settings';render()}}},'Choose an agent')):null,
291
+ ui.healError?h('div',{style:'margin-top:16px'},blocked(ui.healError)):null);
292
+ if(!r||ui.healing)return[hero,pastHeals()];
293
+ const kept=r.changes.filter(c=>c.status==='kept');const other=r.changes.filter(c=>c.status!=='kept');const b=r.before.totals,af=r.after.totals;
294
+ const findings=h('section',{class:'grow'},h('div',{class:'rulehead'},h('span',{class:'label'},'Findings'),h('span',{class:'rule'}),h('span',{class:'small muted'},r.findings.length+' · '+r.id)),
295
+ r.findings.length?h('div',{style:'display:flex;flex-direction:column;gap:8px'},r.findings.map(f=>{const k=KIND[f.kind]||[f.kind,'p-none'];return h('div',{class:'finding fade'},
296
+ h('div',{class:'row',style:'gap:8px'},h('span',{class:'pill '+(f.status==='fixed'?'p-pass':k[1])},f.status==='fixed'?'fixed':k[0]),h('span',{class:'mono small'},f.caseId||f.file||'project'),f.step?h('span',{class:'small muted'},'· '+f.step):null),
297
+ h('span',{},f.detail.split('\n')[0]),h('span',{class:'small muted'},f.status==='fixed'?'Fixed and verified.':f.fix),
298
+ f.caseId?h('div',{class:'row'},h('button',{class:'btn ghost sm',on:{click:()=>{tab='Run';ui.sel=f.caseId;ui.step=null;render()}}},'Open scenario')):null)})):h('p',{class:'muted'},'Nothing to fix.'));
299
+ const changes=h('div',{class:'side'},h('section',{class:'card'},h('div',{class:'rulehead'},h('h2',{},'Kept changes'),h('span',{class:'rule'}),kept.length?h('button',{class:'btn ghost sm',on:{click:()=>undoHeal(r.id)}},'Undo all'):null),
300
+ kept.length?kept.map(c=>h('div',{style:'margin-top:10px'},h('div',{class:'row',style:'gap:8px'},h('span',{class:'pill p-pass'},c.by),h('span',{class:'mono small',style:'overflow-wrap:anywhere'},c.file)),h('div',{class:'small muted',style:'margin-top:4px'},c.reason+(c.note?' · '+c.note:'')),diffView(c.diff))):h('p',{class:'muted small'},'No file was changed.'),
301
+ b&&af?h('p',{class:'small muted',style:'margin-top:14px'},'Before: '+b.passed+' passed, '+b.failed+' failed, '+b.other+' other. After: '+af.passed+' passed, '+af.failed+' failed, '+af.other+' other.'):null),
302
+ other.length?h('details',{class:'card'},h('summary',{class:'small'},other.length+' tried and not kept'),other.map(c=>h('div',{style:'margin-top:10px'},h('div',{class:'row',style:'gap:8px'},h('span',{class:'pill p-none'},c.status),h('span',{class:'mono small'},c.file)),h('div',{class:'small muted'},c.note||c.reason),diffView(c.diff)))):null,
303
+ r.agent?h('details',{class:'card'},h('summary',{class:'small'},'What '+r.agent.provider+(r.agent.model?' ('+r.agent.model+')':'')+' concluded'),r.agent.verdicts.map(v=>h('p',{class:'small'},h('b',{class:'mono',style:'font-weight:500'},v.caseId),': '+v.verdict.replace('_',' ')+'. '+v.reason)),r.agent.summary?h('pre',{style:'margin-top:8px'},r.agent.summary):null):null,
304
+ r.next.length?h('section',{class:'card'},h('span',{class:'label'},'Next'),r.next.map(n=>h('div',{style:'margin-top:8px'},h('code',{class:'small'},n.command),h('div',{class:'small muted'},n.why)))):null);
305
+ return[hero,h('div',{class:'cols'},findings,changes),pastHeals()]}
306
+ function pastHeals(){const list=ui.heals.filter(x=>!ui.heal||x.id!==ui.heal.id);if(!list.length)return null;
307
+ return h('section',{style:'margin-top:28px'},h('div',{class:'rulehead'},h('span',{class:'label'},'Earlier heals'),h('span',{class:'rule'})),
308
+ list.slice(0,8).map(x=>h('div',{class:'route'},h('span',{class:'dot s '+(x.outcome==='healed'||x.outcome==='healthy'?'pass':x.outcome==='product_bugs'?'fail':'warn')}),h('span',{},HEAL_TITLE[x.outcome]),h('span',{class:'where mono small muted'},x.id),h('button',{class:'btn ghost sm',on:{click:()=>{ui.heal=x;render()}}},'Open'))))}
309
+ async function startHeal(dryRun){if(ui.healing||ui.running)return;tab='Heal';ui.healing=true;ui.healError=null;ui.running='Healing';ui.live=null;render();watchRun();
310
+ try{ui.heal=await api('/api/heal',{dryRun});const kept=ui.heal.changes.filter(c=>c.status==='kept').length;
311
+ const bugs=ui.heal.findings.filter(f=>f.kind==='product_bug').length;
312
+ toast(dryRun?'Preview ready: nothing was changed':(kept?kept+' verified fix'+(kept===1?'':'es')+' kept':'No file changed')+(bugs?'; '+bugs+' product bug'+(bugs===1?'':'s')+' reported':''),kept&&!dryRun?{label:'Undo',run:()=>undoHeal(ui.heal.id)}:null)}
313
+ catch(e){ui.healError=e}finally{ui.healing=false;ui.running=false;stopRunWatch()}ui.runName=null;ui.run=null;await load()}
314
+ async function undoHeal(id){try{const r=await api('/api/heal/undo',{id});toast(r.restored.length?'Restored '+r.restored.join(', '):r.skipped.length?r.skipped[0].file+': '+r.skipped[0].why:'Nothing to restore');ui.runName=null;ui.run=null;await load()}catch(e){toast(e.reasons?e.reasons[0].detail:e.error||'Could not undo')}}
315
+
316
+ /* ---------- Command palette and keyboard ---------- */
317
+ function commands(){const list=[];const add=(grp,label,run,hint)=>list.push({grp,label,run,hint:hint||''});
318
+ add('Run','Run all scenarios',()=>{tab='Run';render();runNow('')},'R');
319
+ if(ui.sel)add('Run','Rerun '+ui.sel,()=>{tab='Run';render();runNow(ui.sel)},'r');
320
+ add('Heal','Heal now',()=>startHeal(false),'h');add('Heal','Preview a heal (changes nothing)',()=>startHeal(true));
321
+ if(ui.heal&&ui.heal.changes.some(c=>c.status==='kept'))add('Heal','Undo heal '+ui.heal.id,()=>undoHeal(ui.heal.id));
322
+ if(state&&state.agent.settings.provider!=='none')add('Agent','Draft flows for uncovered routes',()=>{tab='Discover';render();agentDraft()});
323
+ for(const t of TABS)add('Go','Open '+t,()=>{tab=t;render()},String(TABS.indexOf(t)+1));
324
+ for(const f of (state?state.flows:[]))add('Scenario',f.caseId,()=>{tab='Run';ui.sel=f.caseId;ui.step=null;render()},f.title);
325
+ if(state&&state.git.isRepo)for(const b of state.git.branches)add('Branch','Discover on '+b,()=>{tab='Discover';ui.source=b;render();scan()});
326
+ for(const f of (state?state.flows:[]))add('Prune','Prune '+f.caseId,()=>prune(f.file,false));
327
+ add('Help','Keyboard shortcuts',shortcuts,'?');return list}
328
+ function fuzzy(q,text){q=q.toLowerCase();text=text.toLowerCase();if(!q)return 1;if(text.includes(q))return 3-text.indexOf(q)/1000;let i=0;for(const ch of text)if(ch===q[i])i++;return i===q.length?1:0}
329
+ let palette=null;
330
+ function closeOverlay(){if(palette){palette.remove();palette=null}}
331
+ function openPalette(){closeOverlay();const all=commands();let sel=0;let shown=all;
332
+ const input=h('input',{type:'text',placeholder:'Type a command, a scenario or a branch','aria-label':'Command',role:'combobox','aria-expanded':'true','aria-controls':'pal-list',autocomplete:'off'});
333
+ const list=h('ul',{id:'pal-list',role:'listbox'});
334
+ const draw=()=>{list.replaceChildren(...shown.slice(0,60).map((c,i)=>h('li',{role:'option','aria-selected':i===sel?'true':'false',on:{mousemove:()=>{if(sel!==i){sel=i;draw()}},click:()=>pick(i)}},h('span',{class:'grp'},c.grp),h('span',{},c.label),c.hint?h('span',{class:'hint'},c.hint):null)));const on=list.children[sel];if(on)on.scrollIntoView({block:'nearest'})};
335
+ const pick=i=>{const c=shown[i];closeOverlay();if(c)c.run()};
336
+ input.addEventListener('input',()=>{const q=input.value.trim();shown=all.map(c=>({c,s:Math.max(fuzzy(q,c.label),fuzzy(q,c.grp+' '+c.label)*.9)})).filter(x=>x.s>0).sort((a,b)=>b.s-a.s).map(x=>x.c);sel=0;draw()});
337
+ input.addEventListener('keydown',e=>{if(e.key==='ArrowDown'){e.preventDefault();sel=Math.min(sel+1,shown.length-1);draw()}else if(e.key==='ArrowUp'){e.preventDefault();sel=Math.max(sel-1,0);draw()}else if(e.key==='Enter'){e.preventDefault();pick(sel)}else if(e.key==='Escape'){closeOverlay()}});
338
+ palette=h('div',{class:'pal-back',on:{click:e=>{if(e.target===palette)closeOverlay()}}},h('div',{class:'pal fade',role:'dialog','aria-modal':'true','aria-label':'Command palette'},input,list,
339
+ h('div',{class:'foot'},h('span',{},h('kbd',{},'↑↓'),' move'),h('span',{},h('kbd',{},'↵'),' run'),h('span',{},h('kbd',{},'esc'),' close'),h('span',{},h('kbd',{},'?'),' shortcuts'))));
340
+ document.body.append(palette);draw();input.focus()}
341
+ function shortcuts(){closeOverlay();const keys=[['⌘K / Ctrl K','command palette'],['j / k','next / previous scenario'],['↵','open the selected scenario'],['r','rerun the selected scenario'],['R','run all'],['h','heal'],['1 to 5','switch tab'],['?','this list'],['esc','close']];
342
+ palette=h('div',{class:'pal-back',on:{click:e=>{if(e.target===palette)closeOverlay()}}},h('div',{class:'pal fade card',role:'dialog','aria-modal':'true','aria-label':'Keyboard shortcuts',style:'padding:20px'},h('h2',{},'Keyboard'),
343
+ h('div',{class:'keys'},keys.flatMap(([k,v])=>[h('kbd',{},k),h('span',{class:'small'},v)]))));document.body.append(palette)}
344
+ function moveSel(d){if(tab!=='Run'||!state)return;const sc=scenarios();if(!sc.length)return;const i=sc.findIndex(s=>s.id===ui.sel);const n=sc[Math.max(0,Math.min(sc.length-1,(i<0?0:i+d)))];ui.sel=n.id;ui.step=Math.max(0,n.steps.findIndex(x=>x.result==='fail'));render();
345
+ const el=document.querySelector('[data-case="'+CSS.escape(n.id)+'"]');if(el){el.focus({preventScroll:true});el.scrollIntoView({block:'nearest'})}}
346
+ document.addEventListener('keydown',e=>{const typing=/^(INPUT|TEXTAREA|SELECT)$/.test(document.activeElement&&document.activeElement.tagName||'');
347
+ if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==='k'){e.preventDefault();palette?closeOverlay():openPalette();return}
348
+ if(e.key==='Escape'&&palette){closeOverlay();return}
349
+ if(typing||palette||e.metaKey||e.ctrlKey||e.altKey)return;
350
+ if(e.key==='/'){e.preventDefault();openPalette()}else if(e.key==='?'){shortcuts()}else if(e.key==='j'){moveSel(1)}else if(e.key==='k'){moveSel(-1)}
351
+ else if(e.key==='r'&&ui.sel&&!ui.running){tab='Run';runNow(ui.sel)}else if(e.key==='R'&&!ui.running){tab='Run';runNow('')}else if(e.key==='h'&&!ui.running){startHeal(false)}
352
+ else if(/^[1-5]$/.test(e.key)){tab=TABS[Number(e.key)-1];render()}});
353
+ document.getElementById('palbtn').addEventListener('click',openPalette);
354
+
355
+ function render(){header();if(!state)return;const views={Run:runTab,Discover:discoverTab,Heal:healTab,History:historyTab,Settings:settingsTab};page(views[tab]());if(tab==='Discover'&&!ui.disc&&!ui.scanning)scan()}
356
+ load().catch(e=>page(blocked(e)));
357
+ </script></body></html>`;
358
+ //# sourceMappingURL=uiPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiPage.js","sourceRoot":"","sources":["../../src/authoring/uiPage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuH/B,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAqOI,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** Grove source controls share the existing DOM helpers; no HTML interpolation of local paths. */
2
+ export declare const SOURCE_CONTROLS_JS: string;
@@ -0,0 +1,41 @@
1
+ /** Grove source controls share the existing DOM helpers; no HTML interpolation of local paths. */
2
+ export const SOURCE_CONTROLS_JS = String.raw `
3
+ function sourceDescription(binding){
4
+ if(!binding)return 'Input could not be established.';
5
+ if(binding.kind==='working_tree')return 'Working tree · file hashes captured for each run';
6
+ return 'Local snapshot · commit '+binding.commit+' · '+binding.files+' files · '+binding.bytes+' bytes · '+binding.ref.digest.hex;
7
+ }
8
+ function sourceBanner(){const source=state.verificationSource;
9
+ return h('section',{class:'card',style:'margin-bottom:20px;overflow-wrap:anywhere','aria-label':'Verification input'},
10
+ h('div',{class:'row'},h('b',{},'Next run input'),h('span',{class:'small muted'},source.status==='blocked'?'Blocked — review selection':sourceDescription(source.binding)),
11
+ h('button',{class:'btn ghost',on:{click:()=>{tab='Settings';render()}}},'Change input')),
12
+ ui.run?h('p',{class:'small muted'},'Recorded run request: '+(ui.run.sourceChecked?sourceDescription(ui.run.sourceBinding):'Unavailable — saved evidence could not establish the input.')):null);
13
+ }
14
+ function sourceSettings(){
15
+ const source=state.verificationSource;let candidate=null;let busy=false;
16
+ const status=h('div',{id:'source-status',role:'status','aria-live':'polite',tabindex:'-1',style:'overflow-wrap:anywhere'});
17
+ const path=h('input',{id:'snapshot-path',value:source.selection.kind==='snapshot'?source.selection.path:'',placeholder:'Path to snapshot.json',style:'width:100%;min-width:0'});
18
+ const apply=h('button',{class:'btn',disabled:true,on:{click:()=>save(candidate.selection)}},'Use this snapshot');
19
+ const check=h('button',{class:'btn ghost',on:{click:async()=>{
20
+ if(busy)return;busy=true;candidate=null;apply.disabled=true;check.disabled=true;path.disabled=true;working.disabled=true;status.textContent='Checking snapshot bytes…';
21
+ try{candidate=await api('/api/source/preview',{path:path.value});status.textContent=sourceDescription(candidate.binding);apply.disabled=false}
22
+ catch(e){status.replaceChildren(blocked(e))}finally{busy=false;check.disabled=false;path.disabled=false;working.disabled=false;status.focus()}
23
+ }}},'Check snapshot');
24
+ path.addEventListener('input',()=>{candidate=null;apply.disabled=true;status.textContent='Check this path before selecting it.'});
25
+ const working=h('button',{class:'btn ghost',on:{click:()=>save({kind:'working_tree'})}},'Use working tree');
26
+ async function save(selection){if(busy||!selection)return;busy=true;apply.disabled=true;check.disabled=true;working.disabled=true;path.disabled=true;
27
+ try{await api('/api/source',{source:selection});await load();const next=document.getElementById('source-status');if(next){next.textContent='Verification input saved.';next.focus()}toast('Verification input saved')}
28
+ catch(e){status.replaceChildren(blocked(e));status.focus()}
29
+ finally{busy=false;check.disabled=false;working.disabled=false;path.disabled=false;candidate=null;apply.disabled=true}
30
+ }
31
+ return h('section',{class:'card',style:'margin-bottom:24px;overflow-wrap:anywhere'},h('span',{class:'label'},'Verification input'),
32
+ h('h2',{style:'margin:6px 0'},'Choose what the next run launches'),
33
+ h('p',{class:'small muted'},sourceDescription(source.binding)),source.error?blocked(source.error):null,
34
+ h('p',{class:'small muted'},'Keep one set of scenarios here. Select application files from your working tree or a materialized snapshot. This local preference leaves the team config unchanged.'),
35
+ h('label',{for:'snapshot-path'},'Snapshot manifest'),path,
36
+ h('div',{class:'row',style:'margin-top:12px'},check,apply,working),status,
37
+ h('p',{class:'small muted'},'Checking launches nothing. Saving pins the exact manifest; changed bytes block the next run. These are local content checks, not remote or deployed revision attestations. Dependencies and environment remain external.'),
38
+ h('p',{class:'small muted'},'The Discover branch selector only scans routes; it does not change verification input.'));
39
+ }
40
+ `;
41
+ //# sourceMappingURL=uiSourceControls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiSourceControls.js","sourceRoot":"","sources":["../../src/authoring/uiSourceControls.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsC3C,CAAC"}
@@ -0,0 +1,41 @@
1
+ import type { GitSourceSnapshot } from '../protocol/index.ts';
2
+ import type { AuthoringConfig } from './schema.ts';
3
+ import { SnapshotSource } from './snapshotSource.ts';
4
+ import { VerificationSourceBinding, VerificationSourceSelection } from './sourceSelection.ts';
5
+ export declare function describeSnapshot(snapshot: GitSourceSnapshot): VerificationSourceBinding;
6
+ export declare function savedVerificationSource(root: string): VerificationSourceSelection;
7
+ export declare function resolveVerificationSource(root: string, override?: string): SnapshotSource | null;
8
+ /** Read-only candidate validation; no compile output, runtime probe, or application starts. */
9
+ export declare function previewVerificationSource(root: string, path: string, config: AuthoringConfig): {
10
+ selection: {
11
+ kind: "working_tree";
12
+ } | {
13
+ kind: "snapshot";
14
+ path: string;
15
+ ref: {
16
+ id: string;
17
+ revision: string;
18
+ digest: {
19
+ algorithm: "sha256";
20
+ hex: string;
21
+ };
22
+ };
23
+ };
24
+ binding: {
25
+ kind: "working_tree";
26
+ } | {
27
+ kind: "snapshot";
28
+ ref: {
29
+ id: string;
30
+ revision: string;
31
+ digest: {
32
+ algorithm: "sha256";
33
+ hex: string;
34
+ };
35
+ };
36
+ commit: string;
37
+ files: number;
38
+ bytes: number;
39
+ };
40
+ };
41
+ export declare function saveVerificationSource(root: string, input: unknown, config: AuthoringConfig): void;
@@ -0,0 +1,46 @@
1
+ import { relative, resolve, sep } from 'node:path';
2
+ import { localScope } from "../core/corpus.js";
3
+ import { Blocked } from "../core/errors.js";
4
+ import { sameRef } from "../protocol/canonical.js";
5
+ import { pinnedArguments } from "../hosts/pinnedArguments.js";
6
+ import { SnapshotSource } from "./snapshotSource.js";
7
+ import { readLocalSettings, writeLocalSettings } from "./localSettings.js";
8
+ import { applicationCwd } from "./appLocation.js";
9
+ import { VerificationSourceBinding, VerificationSourceSelection } from "./sourceSelection.js";
10
+ import { applicationLaunch } from "./appLaunch.js";
11
+ export function describeSnapshot(snapshot) {
12
+ return { kind: 'snapshot', ref: snapshot.ref, commit: snapshot.commit, files: snapshot.files.length, bytes: snapshot.files.reduce((sum, file) => sum + file.bytes, 0) };
13
+ }
14
+ export function savedVerificationSource(root) {
15
+ return readLocalSettings(root).verification?.source ?? { kind: 'working_tree' };
16
+ }
17
+ export function resolveVerificationSource(root, override) {
18
+ const selected = override === undefined ? savedVerificationSource(root) : null;
19
+ const path = override ?? (selected?.kind === 'snapshot' ? selected.path : null);
20
+ if (path === null)
21
+ return null;
22
+ const source = new SnapshotSource(resolve(root, path), localScope());
23
+ if (selected?.kind === 'snapshot' && !sameRef(source.snapshot.ref, selected.ref))
24
+ throw new Blocked([{ code: 'source_selection_changed', detail: 'The selected manifest has changed since it was saved', action: 'review and select the snapshot again in Settings' }]);
25
+ return source;
26
+ }
27
+ /** Read-only candidate validation; no compile output, runtime probe, or application starts. */
28
+ export function previewVerificationSource(root, path, config) {
29
+ const absolute = resolve(root, path);
30
+ const source = new SnapshotSource(absolute, localScope());
31
+ const cwd = applicationCwd(config.app, resolve(source.root, config.app.root));
32
+ source.bind(cwd, root);
33
+ const launch = applicationLaunch(config, root, resolve(source.root, config.app.root));
34
+ pinnedArguments(launch.args.map(arg => arg.replaceAll('{port}', '1')), cwd, source.root, source.snapshot, config.app.adapter === 'node' ? 'node' : 'python');
35
+ return { selection: VerificationSourceSelection.parse({ kind: 'snapshot', path: relative(root, absolute).split(sep).join('/') || '.', ref: source.snapshot.ref }), binding: describeSnapshot(source.snapshot) };
36
+ }
37
+ export function saveVerificationSource(root, input, config) {
38
+ const selected = VerificationSourceSelection.parse(input);
39
+ if (selected.kind === 'snapshot') {
40
+ const candidate = previewVerificationSource(root, selected.path, config);
41
+ if (candidate.selection.kind !== 'snapshot' || !sameRef(candidate.selection.ref, selected.ref))
42
+ throw new Blocked([{ code: 'source_selection_changed', detail: 'Snapshot changed after preview', action: 'check the snapshot again before saving' }]);
43
+ }
44
+ writeLocalSettings(root, { ...readLocalSettings(root), verification: { source: selected } });
45
+ }
46
+ //# sourceMappingURL=verificationSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verificationSource.js","sourceRoot":"","sources":["../../src/authoring/verificationSource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,UAAU,gBAAgB,CAAC,QAA2B;IAC1D,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;AAC1K,CAAC;AACD,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,MAAM,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AAClF,CAAC;AACD,MAAM,UAAU,yBAAyB,CAAC,IAAY,EAAE,QAAiB;IACvE,MAAM,QAAQ,GAAG,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/E,MAAM,IAAI,GAAG,QAAQ,IAAI,CAAC,QAAQ,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAChF,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IACrE,IAAI,QAAQ,EAAE,IAAI,KAAK,UAAU,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,EAAE,sDAAsD,EAAE,MAAM,EAAE,kDAAkD,EAAE,CAAC,CAAC,CAAC;IACxQ,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,yBAAyB,CAAC,IAAY,EAAE,IAAY,EAAE,MAAuB;IAC3F,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAAC,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACtF,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7J,OAAO,EAAE,SAAS,EAAE,2BAA2B,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;AAClN,CAAC;AACD,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,KAAc,EAAE,MAAuB;IAC1F,MAAM,QAAQ,GAAG,2BAA2B,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1D,IAAI,QAAQ,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,yBAAyB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzE,IAAI,SAAS,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,EAAE,gCAAgC,EAAE,MAAM,EAAE,wCAAwC,EAAE,CAAC,CAAC,CAAC;IACxP,CAAC;IACD,kBAAkB,CAAC,IAAI,EAAE,EAAE,GAAG,iBAAiB,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC/F,CAAC"}