@b00dea/cockpit 0.0.0-bootstrap.0 → 0.1.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 (363) hide show
  1. package/CHANGELOG.md +375 -0
  2. package/LICENSE +21 -0
  3. package/README.md +21 -1
  4. package/bin/cockpit.mjs +33 -0
  5. package/cockpit.schema.json +2574 -0
  6. package/dist/autonomy.d.ts +44 -0
  7. package/dist/autonomy.js +156 -0
  8. package/dist/bounded-read.d.ts +14 -0
  9. package/dist/bounded-read.js +42 -0
  10. package/dist/browser/commands.d.ts +62 -0
  11. package/dist/browser/commands.js +349 -0
  12. package/dist/browser/package-paths.d.ts +1 -0
  13. package/dist/browser/package-paths.js +6 -0
  14. package/dist/browser/proxy.d.ts +22 -0
  15. package/dist/browser/proxy.js +37 -0
  16. package/dist/browser/runtime.d.ts +117 -0
  17. package/dist/browser/runtime.js +183 -0
  18. package/dist/browser/surfaces.d.ts +141 -0
  19. package/dist/browser/surfaces.js +556 -0
  20. package/dist/browser/ui-gate.d.ts +15 -0
  21. package/dist/browser/ui-gate.js +18 -0
  22. package/dist/cli-guard.d.ts +5 -0
  23. package/dist/cli-guard.js +71 -0
  24. package/dist/cli-main.d.ts +139 -0
  25. package/dist/cli-main.js +1405 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.js +16 -0
  28. package/dist/command-table.d.ts +113 -0
  29. package/dist/command-table.js +512 -0
  30. package/dist/config/load.d.ts +171 -0
  31. package/dist/config/load.js +345 -0
  32. package/dist/config/sibling-toml.d.ts +48 -0
  33. package/dist/config/sibling-toml.js +160 -0
  34. package/dist/config/surface-tools-toml.d.ts +9 -0
  35. package/dist/config/surface-tools-toml.js +37 -0
  36. package/dist/config/verified-write.d.ts +43 -0
  37. package/dist/config/verified-write.js +89 -0
  38. package/dist/diagnostics.d.ts +26 -0
  39. package/dist/diagnostics.js +335 -0
  40. package/dist/emit.d.ts +22 -0
  41. package/dist/emit.js +43 -0
  42. package/dist/entrypoint-kinds.d.ts +3 -0
  43. package/dist/entrypoint-kinds.js +11 -0
  44. package/dist/environment/application/destructive.d.ts +6 -0
  45. package/dist/environment/application/destructive.js +425 -0
  46. package/dist/environment/application/doctor.d.ts +89 -0
  47. package/dist/environment/application/doctor.js +235 -0
  48. package/dist/environment/application/guard.d.ts +43 -0
  49. package/dist/environment/application/guard.js +622 -0
  50. package/dist/environment/application/health.d.ts +134 -0
  51. package/dist/environment/application/health.js +379 -0
  52. package/dist/environment/application/lifecycle-context.d.ts +228 -0
  53. package/dist/environment/application/lifecycle-context.js +154 -0
  54. package/dist/environment/application/lifecycle-state.d.ts +25 -0
  55. package/dist/environment/application/lifecycle-state.js +201 -0
  56. package/dist/environment/application/lifecycle.d.ts +17 -0
  57. package/dist/environment/application/lifecycle.js +729 -0
  58. package/dist/environment/application/logs.d.ts +45 -0
  59. package/dist/environment/application/logs.js +127 -0
  60. package/dist/environment/application/setup.d.ts +129 -0
  61. package/dist/environment/application/setup.js +741 -0
  62. package/dist/environment/application/shared.d.ts +11 -0
  63. package/dist/environment/application/shared.js +61 -0
  64. package/dist/environment/claims.d.ts +389 -0
  65. package/dist/environment/claims.js +1709 -0
  66. package/dist/environment/codex-hook-trust.d.ts +11 -0
  67. package/dist/environment/codex-hook-trust.js +185 -0
  68. package/dist/environment/compose-environment.d.ts +1 -0
  69. package/dist/environment/compose-environment.js +6 -0
  70. package/dist/environment/compose-ownership.d.ts +21 -0
  71. package/dist/environment/compose-ownership.js +117 -0
  72. package/dist/environment/compose-topology.d.ts +117 -0
  73. package/dist/environment/compose-topology.js +413 -0
  74. package/dist/environment/contract.d.ts +489 -0
  75. package/dist/environment/contract.js +761 -0
  76. package/dist/environment/declaration.d.ts +14 -0
  77. package/dist/environment/declaration.js +39 -0
  78. package/dist/environment/destructive-composition.d.ts +29 -0
  79. package/dist/environment/destructive-composition.js +333 -0
  80. package/dist/environment/docker-daemon.d.ts +30 -0
  81. package/dist/environment/docker-daemon.js +78 -0
  82. package/dist/environment/docker-endpoint.d.ts +10 -0
  83. package/dist/environment/docker-endpoint.js +19 -0
  84. package/dist/environment/env-schema-observation.d.ts +46 -0
  85. package/dist/environment/env-schema-observation.js +241 -0
  86. package/dist/environment/evidence.d.ts +136 -0
  87. package/dist/environment/evidence.js +437 -0
  88. package/dist/environment/executable.d.ts +26 -0
  89. package/dist/environment/executable.js +167 -0
  90. package/dist/environment/generated-application/authorities.d.ts +5 -0
  91. package/dist/environment/generated-application/authorities.js +61 -0
  92. package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
  93. package/dist/environment/generated-application/bootstrap-skill.js +328 -0
  94. package/dist/environment/generated-application/check.d.ts +13 -0
  95. package/dist/environment/generated-application/check.js +189 -0
  96. package/dist/environment/generated-application/custom-surface.d.ts +26 -0
  97. package/dist/environment/generated-application/custom-surface.js +289 -0
  98. package/dist/environment/generated-application/prepare.d.ts +29 -0
  99. package/dist/environment/generated-application/prepare.js +276 -0
  100. package/dist/environment/generated-application/publication.d.ts +33 -0
  101. package/dist/environment/generated-application/publication.js +547 -0
  102. package/dist/environment/generated-application/shared.d.ts +484 -0
  103. package/dist/environment/generated-application/shared.js +349 -0
  104. package/dist/environment/generated-application/surface-observation.d.ts +4 -0
  105. package/dist/environment/generated-application/surface-observation.js +69 -0
  106. package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
  107. package/dist/environment/generated-application/surface-outputs.js +389 -0
  108. package/dist/environment/generated-application/surfaces.d.ts +3 -0
  109. package/dist/environment/generated-application/surfaces.js +699 -0
  110. package/dist/environment/generated-application/sync.d.ts +6 -0
  111. package/dist/environment/generated-application/sync.js +109 -0
  112. package/dist/environment/git-observation.d.ts +183 -0
  113. package/dist/environment/git-observation.js +544 -0
  114. package/dist/environment/health-composition.d.ts +11 -0
  115. package/dist/environment/health-composition.js +628 -0
  116. package/dist/environment/host-observation.d.ts +56 -0
  117. package/dist/environment/host-observation.js +52 -0
  118. package/dist/environment/identity.d.ts +48 -0
  119. package/dist/environment/identity.js +85 -0
  120. package/dist/environment/init-application.d.ts +308 -0
  121. package/dist/environment/init-application.js +697 -0
  122. package/dist/environment/install-policy-observation.d.ts +71 -0
  123. package/dist/environment/install-policy-observation.js +284 -0
  124. package/dist/environment/install-policy.d.ts +48 -0
  125. package/dist/environment/install-policy.js +96 -0
  126. package/dist/environment/instance.d.ts +33 -0
  127. package/dist/environment/instance.js +122 -0
  128. package/dist/environment/instruction-pointer.d.ts +19 -0
  129. package/dist/environment/instruction-pointer.js +144 -0
  130. package/dist/environment/lifecycle-composition.d.ts +29 -0
  131. package/dist/environment/lifecycle-composition.js +675 -0
  132. package/dist/environment/lifecycle-stage.d.ts +115 -0
  133. package/dist/environment/lifecycle-stage.js +398 -0
  134. package/dist/environment/lifecycle.d.ts +75 -0
  135. package/dist/environment/lifecycle.js +354 -0
  136. package/dist/environment/logs.d.ts +132 -0
  137. package/dist/environment/logs.js +519 -0
  138. package/dist/environment/observations.d.ts +46 -0
  139. package/dist/environment/observations.js +344 -0
  140. package/dist/environment/operator-application.d.ts +50 -0
  141. package/dist/environment/operator-application.js +155 -0
  142. package/dist/environment/ports.d.ts +182 -0
  143. package/dist/environment/ports.js +1205 -0
  144. package/dist/environment/posture-observation.d.ts +68 -0
  145. package/dist/environment/posture-observation.js +253 -0
  146. package/dist/environment/read-composition.d.ts +27 -0
  147. package/dist/environment/read-composition.js +352 -0
  148. package/dist/environment/readiness-composition.d.ts +38 -0
  149. package/dist/environment/readiness-composition.js +130 -0
  150. package/dist/environment/reclaim.d.ts +333 -0
  151. package/dist/environment/reclaim.js +1835 -0
  152. package/dist/environment/repository-identity.d.ts +13 -0
  153. package/dist/environment/repository-identity.js +108 -0
  154. package/dist/environment/runtime-measurement-record.d.ts +38 -0
  155. package/dist/environment/runtime-measurement-record.js +111 -0
  156. package/dist/environment/runtime-measurement.d.ts +27 -0
  157. package/dist/environment/runtime-measurement.js +224 -0
  158. package/dist/environment/runtime-probe-residue.d.ts +43 -0
  159. package/dist/environment/runtime-probe-residue.js +148 -0
  160. package/dist/environment/runtime-probe.d.ts +72 -0
  161. package/dist/environment/runtime-probe.js +725 -0
  162. package/dist/environment/runtime.d.ts +505 -0
  163. package/dist/environment/runtime.js +2335 -0
  164. package/dist/environment/seed.d.ts +16 -0
  165. package/dist/environment/seed.js +43 -0
  166. package/dist/environment/selftest-application.d.ts +86 -0
  167. package/dist/environment/selftest-application.js +713 -0
  168. package/dist/environment/sensitive.d.ts +3 -0
  169. package/dist/environment/sensitive.js +48 -0
  170. package/dist/environment/setup-observation.d.ts +62 -0
  171. package/dist/environment/setup-observation.js +1473 -0
  172. package/dist/environment/setup.d.ts +43 -0
  173. package/dist/environment/setup.js +176 -0
  174. package/dist/environment/sibling-instructions.d.ts +33 -0
  175. package/dist/environment/sibling-instructions.js +224 -0
  176. package/dist/environment/sibling-registration.d.ts +45 -0
  177. package/dist/environment/sibling-registration.js +538 -0
  178. package/dist/environment/state.d.ts +371 -0
  179. package/dist/environment/state.js +2013 -0
  180. package/dist/environment/templates.d.ts +140 -0
  181. package/dist/environment/templates.js +685 -0
  182. package/dist/environment/tool-registration.d.ts +9 -0
  183. package/dist/environment/tool-registration.js +96 -0
  184. package/dist/environment/upgrade-application.d.ts +19 -0
  185. package/dist/environment/upgrade-application.js +175 -0
  186. package/dist/environment-exec/execute.d.ts +102 -0
  187. package/dist/environment-exec/execute.js +1175 -0
  188. package/dist/environment-exec/libexec-program.d.ts +6 -0
  189. package/dist/environment-exec/libexec-program.js +22 -0
  190. package/dist/environment-exec/verified-digest.d.ts +4 -0
  191. package/dist/environment-exec/verified-digest.js +16 -0
  192. package/dist/exact-keys.d.ts +7 -0
  193. package/dist/exact-keys.js +15 -0
  194. package/dist/fix-catalogue.d.ts +32 -0
  195. package/dist/fix-catalogue.js +60 -0
  196. package/dist/freshness.d.ts +29 -0
  197. package/dist/freshness.js +75 -0
  198. package/dist/generated-environment/adopt.d.ts +16 -0
  199. package/dist/generated-environment/adopt.js +275 -0
  200. package/dist/generated-environment/command.d.ts +47 -0
  201. package/dist/generated-environment/command.js +75 -0
  202. package/dist/generated-environment/transaction.d.ts +186 -0
  203. package/dist/generated-environment/transaction.js +1770 -0
  204. package/dist/grading/evaluate.d.ts +71 -0
  205. package/dist/grading/evaluate.js +403 -0
  206. package/dist/grading/grade.d.ts +33 -0
  207. package/dist/grading/grade.js +57 -0
  208. package/dist/guards/evaluator.d.ts +113 -0
  209. package/dist/guards/evaluator.js +1226 -0
  210. package/dist/guards/harness-adapter.d.ts +17 -0
  211. package/dist/guards/harness-adapter.js +57 -0
  212. package/dist/guards/host.d.ts +8 -0
  213. package/dist/guards/host.js +10 -0
  214. package/dist/guards/invocation-parser.d.ts +66 -0
  215. package/dist/guards/invocation-parser.js +595 -0
  216. package/dist/guards/local-identity.d.ts +40 -0
  217. package/dist/guards/local-identity.js +123 -0
  218. package/dist/guards/policy-pin.d.ts +13 -0
  219. package/dist/guards/policy-pin.js +175 -0
  220. package/dist/guards/protected-locations.d.ts +62 -0
  221. package/dist/guards/protected-locations.js +461 -0
  222. package/dist/guards/read-only.d.ts +37 -0
  223. package/dist/guards/read-only.js +315 -0
  224. package/dist/init/command.d.ts +40 -0
  225. package/dist/init/command.js +310 -0
  226. package/dist/init/derive.d.ts +51 -0
  227. package/dist/init/derive.js +715 -0
  228. package/dist/init/draft.d.ts +138 -0
  229. package/dist/init/draft.js +1205 -0
  230. package/dist/init/render.d.ts +35 -0
  231. package/dist/init/render.js +82 -0
  232. package/dist/init/scaffold.d.ts +53 -0
  233. package/dist/init/scaffold.js +121 -0
  234. package/dist/invocation.d.ts +13 -0
  235. package/dist/invocation.js +20 -0
  236. package/dist/package-metadata.d.ts +9 -0
  237. package/dist/package-metadata.js +19 -0
  238. package/dist/readiness.d.ts +53 -0
  239. package/dist/readiness.js +88 -0
  240. package/dist/references/named.d.ts +24 -0
  241. package/dist/references/named.js +27 -0
  242. package/dist/refusal.d.ts +15 -0
  243. package/dist/refusal.js +7 -0
  244. package/dist/registry-derivation.d.ts +31 -0
  245. package/dist/registry-derivation.js +32 -0
  246. package/dist/registry-resolve/command.d.ts +47 -0
  247. package/dist/registry-resolve/command.js +226 -0
  248. package/dist/registry-resolve/registry.d.ts +68 -0
  249. package/dist/registry-resolve/registry.js +292 -0
  250. package/dist/registry-resolve/render-shell.d.ts +18 -0
  251. package/dist/registry-resolve/render-shell.js +36 -0
  252. package/dist/repair.d.ts +29 -0
  253. package/dist/repair.js +8 -0
  254. package/dist/schema-json.d.ts +1 -0
  255. package/dist/schema-json.js +177 -0
  256. package/dist/schema.d.ts +1322 -0
  257. package/dist/schema.js +934 -0
  258. package/dist/setup/command.d.ts +4 -0
  259. package/dist/setup/command.js +4 -0
  260. package/dist/sha256.d.ts +1 -0
  261. package/dist/sha256.js +4 -0
  262. package/dist/surfaces/adoption.d.ts +41 -0
  263. package/dist/surfaces/adoption.js +217 -0
  264. package/dist/surfaces/consumer-instructions.d.ts +20 -0
  265. package/dist/surfaces/consumer-instructions.js +43 -0
  266. package/dist/surfaces/contract.d.ts +42 -0
  267. package/dist/surfaces/contract.js +169 -0
  268. package/dist/surfaces/core-declarations.d.ts +24 -0
  269. package/dist/surfaces/core-declarations.js +79 -0
  270. package/dist/surfaces/development-markers.d.ts +1 -0
  271. package/dist/surfaces/development-markers.js +18 -0
  272. package/dist/surfaces/generator-adapter.d.ts +71 -0
  273. package/dist/surfaces/generator-adapter.js +809 -0
  274. package/dist/surfaces/harness-registry.d.ts +180 -0
  275. package/dist/surfaces/harness-registry.js +117 -0
  276. package/dist/surfaces/mcp.d.ts +95 -0
  277. package/dist/surfaces/mcp.js +186 -0
  278. package/dist/surfaces/merge.d.ts +30 -0
  279. package/dist/surfaces/merge.js +105 -0
  280. package/dist/surfaces/ownership.d.ts +190 -0
  281. package/dist/surfaces/ownership.js +795 -0
  282. package/dist/surfaces/projection.d.ts +136 -0
  283. package/dist/surfaces/projection.js +681 -0
  284. package/dist/surfaces/render.d.ts +118 -0
  285. package/dist/surfaces/render.js +633 -0
  286. package/dist/surfaces/restrictions.d.ts +130 -0
  287. package/dist/surfaces/restrictions.js +447 -0
  288. package/dist/surfaces/selftest.d.ts +162 -0
  289. package/dist/surfaces/selftest.js +393 -0
  290. package/dist/surfaces/skill-contract.d.ts +85 -0
  291. package/dist/surfaces/skill-contract.js +449 -0
  292. package/dist/surfaces/sync.d.ts +57 -0
  293. package/dist/surfaces/sync.js +164 -0
  294. package/dist/team-metadata.d.ts +41 -0
  295. package/dist/team-metadata.js +512 -0
  296. package/dist/testing/gates.d.ts +91 -0
  297. package/dist/testing/gates.js +182 -0
  298. package/dist/testing/hooks.d.ts +59 -0
  299. package/dist/testing/hooks.js +139 -0
  300. package/dist/testing/verdict.d.ts +29 -0
  301. package/dist/testing/verdict.js +62 -0
  302. package/dist/work-orders/application.d.ts +99 -0
  303. package/dist/work-orders/application.js +383 -0
  304. package/dist/work-orders/composition.d.ts +124 -0
  305. package/dist/work-orders/composition.js +1010 -0
  306. package/dist/work-orders/contract.d.ts +61 -0
  307. package/dist/work-orders/contract.js +122 -0
  308. package/dist/work-orders/store.d.ts +158 -0
  309. package/dist/work-orders/store.js +197 -0
  310. package/docs/README.md +65 -0
  311. package/docs/architecture.md +136 -0
  312. package/docs/capability-matrix.md +50 -0
  313. package/docs/cli-reference.md +599 -0
  314. package/docs/command-list.md +51 -0
  315. package/docs/compose-patterns.md +99 -0
  316. package/docs/concepts.md +171 -0
  317. package/docs/configuration-essentials.md +172 -0
  318. package/docs/configuration-reference.md +621 -0
  319. package/docs/environment.md +760 -0
  320. package/docs/extending.md +43 -0
  321. package/docs/faq.md +111 -0
  322. package/docs/getting-started.md +608 -0
  323. package/docs/harness-surfaces.md +433 -0
  324. package/docs/joining-a-team.md +76 -0
  325. package/docs/release-policy.md +49 -0
  326. package/docs/safety-and-autonomy.md +419 -0
  327. package/docs/troubleshooting.md +361 -0
  328. package/docs/tutorial.md +170 -0
  329. package/docs/work-and-browser.md +254 -0
  330. package/libexec/browser-operation.cjs +186 -0
  331. package/libexec/fence-marker.cjs +101 -0
  332. package/libexec/fence-marker.d.cts +24 -0
  333. package/libexec/fenced-group-runner.cjs +77 -0
  334. package/libexec/fenced-supervisor.cjs +137 -0
  335. package/libexec/generated-filesystem.cjs +731 -0
  336. package/libexec/install-filesystem.cjs +225 -0
  337. package/libexec/rulesync-generator.NOTICE.md +1112 -0
  338. package/libexec/rulesync-generator.cjs +743 -0
  339. package/libexec/surface-generator-worker.cjs +266 -0
  340. package/libexec/surface-output-reader.cjs +99 -0
  341. package/libexec/surface-scratch-cleanup.cjs +14 -0
  342. package/libexec/validate-harness-evidence.d.mts +183 -0
  343. package/libexec/validate-harness-evidence.mjs +1312 -0
  344. package/package.json +76 -1
  345. package/surfaces/README.md +33 -0
  346. package/surfaces/agents/evaluator.agent.md +76 -0
  347. package/surfaces/guards/bash-guard.sh +48 -0
  348. package/surfaces/guards/claude.adapter.json +25 -0
  349. package/surfaces/guards/codex.adapter.json +24 -0
  350. package/surfaces/guards/opencode.adapter.json +25 -0
  351. package/surfaces/references/browser.md +63 -0
  352. package/surfaces/references/test-data-and-personas.md +84 -0
  353. package/surfaces/references/testing-tiers.md +11 -0
  354. package/surfaces/skills/cockpit-browser.skill.md +54 -0
  355. package/surfaces/skills/cockpit-explain.skill.md +32 -0
  356. package/surfaces/skills/cockpit-fix.skill.md +37 -0
  357. package/surfaces/skills/cockpit-setup.skill.md +39 -0
  358. package/surfaces/skills/cockpit-work.skill.md +34 -0
  359. package/surfaces/skills/collection.json +5 -0
  360. package/surfaces/skills/procedures/explain.md +61 -0
  361. package/surfaces/skills/procedures/fix.md +81 -0
  362. package/surfaces/skills/procedures/setup.md +379 -0
  363. package/surfaces/skills/procedures/work.md +105 -0
@@ -0,0 +1,61 @@
1
+ import { z } from 'zod';
2
+ export declare const WORK_ORDER_ID: RegExp;
3
+ declare const Check: z.ZodUnion<readonly [z.ZodObject<{
4
+ gate: z.ZodString;
5
+ select: z.ZodOptional<z.ZodString>;
6
+ }, z.core.$strict>, z.ZodArray<z.ZodString>]>;
7
+ export type WorkOrderCheck = z.infer<typeof Check>;
8
+ export declare const WorkOrderFrontMatter: z.ZodObject<{
9
+ id: z.ZodString;
10
+ objective: z.ZodString;
11
+ scope: z.ZodArray<z.ZodString>;
12
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString>>;
13
+ gates: z.ZodDefault<z.ZodArray<z.ZodString>>;
14
+ criteria: z.ZodArray<z.ZodObject<{
15
+ id: z.ZodString;
16
+ text: z.ZodString;
17
+ check: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
18
+ gate: z.ZodString;
19
+ select: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strict>, z.ZodArray<z.ZodString>]>>;
21
+ source: z.ZodOptional<z.ZodString>;
22
+ }, z.core.$strict>>;
23
+ non_goals: z.ZodDefault<z.ZodArray<z.ZodString>>;
24
+ }, z.core.$strict>;
25
+ export type WorkOrder = z.infer<typeof WorkOrderFrontMatter>;
26
+ export type WorkOrderCriterion = WorkOrder['criteria'][number];
27
+ export type ParsedFile<T> = Readonly<{
28
+ ok: true;
29
+ value: T;
30
+ }> | Readonly<{
31
+ ok: false;
32
+ problems: readonly string[];
33
+ }>;
34
+ /** Parses `workorders/<id>.md`; the id the file declares must be the name it is stored under. */
35
+ export declare function parseWorkOrder(bytes: Uint8Array, fileId: string): ParsedFile<WorkOrder>;
36
+ /** The quick-path file `cockpit grade --criteria` reads: front-matter with criteria, and optionally scope and gates. */
37
+ export declare const CriteriaFile: z.ZodObject<{
38
+ criteria: z.ZodArray<z.ZodObject<{
39
+ id: z.ZodString;
40
+ text: z.ZodString;
41
+ check: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
42
+ gate: z.ZodString;
43
+ select: z.ZodOptional<z.ZodString>;
44
+ }, z.core.$strict>, z.ZodArray<z.ZodString>]>>;
45
+ source: z.ZodOptional<z.ZodString>;
46
+ }, z.core.$strict>>;
47
+ scope: z.ZodDefault<z.ZodArray<z.ZodString>>;
48
+ gates: z.ZodDefault<z.ZodArray<z.ZodString>>;
49
+ objective: z.ZodOptional<z.ZodString>;
50
+ }, z.core.$strict>;
51
+ export declare function parseCriteriaFile(bytes: Uint8Array): ParsedFile<z.infer<typeof CriteriaFile>>;
52
+ /** The digest an acceptance binds: the contract, each cited source's bytes, and the base commits. */
53
+ export declare function workOrderDigest(order: WorkOrder, sources: Readonly<Record<string, string>>, base: Readonly<Record<string, string>>): string;
54
+ /**
55
+ * The accepted criteria a changed contract removes or rewrites. Adding a criterion strengthens an
56
+ * order; dropping one, or changing what one says or how it is checked, weakens it, and that is never
57
+ * an agent's decision.
58
+ */
59
+ export declare function criteriaWeakening(accepted: WorkOrder, changed: WorkOrder): readonly string[];
60
+ export declare function scopeMatches(scope: readonly string[], path: string): boolean;
61
+ export {};
@@ -0,0 +1,122 @@
1
+ // Owns the work-order file: `workorders/<id>.md`, whose YAML front-matter is the whole contract an
2
+ // order is accepted, checked and graded against, and whose Markdown body is free notes cockpit never
3
+ // reads. One schema validates the front-matter; the digest binds it with the bytes of every source a
4
+ // criterion cites and the commit each repository stood at when the order was accepted.
5
+ import { createHash } from 'node:crypto';
6
+ import { parseDocument } from 'yaml';
7
+ import { z } from 'zod';
8
+ // One inert word, never a path or an option: the CLI, the guard and the store each admit it before it names a file.
9
+ export const WORK_ORDER_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
10
+ const WORK_ORDER_LIMITS = Object.freeze({ bytes: 65_536, criteria: 12, scope: 64, textBytes: 2_048, arguments: 32, argumentBytes: 2_048 });
11
+ const PRINTABLE = /^[^\x00-\x08\x0b-\x1f\x7f]*$/;
12
+ const text = z.string().trim().min(1).refine(value => Buffer.byteLength(value) <= WORK_ORDER_LIMITS.textBytes && PRINTABLE.test(value), `at most ${WORK_ORDER_LIMITS.textBytes} bytes without control characters`);
13
+ // `path` in the cockpit's own repository, or `<sibling slug>:path` in a sibling; never absolute or climbing.
14
+ const REPOSITORY_PATH = /^(?:[a-z0-9][a-z0-9-]{0,63}:)?(?![/])(?!.*(?:^|[/:])\.\.(?:\/|$))[A-Za-z0-9._@+\-/*?]+$/;
15
+ const repositoryPath = z.string().max(1_024).regex(REPOSITORY_PATH, 'a relative path, optionally <sibling slug>:path, without .. or a leading /');
16
+ const sourcePath = repositoryPath.refine(value => !/[*?]/.test(value), 'a source names one file, without wildcards');
17
+ const argument = z.string().min(1).refine(value => Buffer.byteLength(value) <= WORK_ORDER_LIMITS.argumentBytes && !/[\x00-\x1f\x7f]/.test(value), 'a bounded argument without control characters');
18
+ const GateCheck = z.object({
19
+ gate: z.string().regex(/^[a-z][a-z0-9-]{0,63}$/, 'a declared [testing] gate id'),
20
+ // A selected value that starts with `-` would reach the product's tool as an option of its own.
21
+ select: z.string().max(4_096).regex(/^(?:spec|file|test|route):[^-]/, 'spec|file|test|route:<value>').optional(),
22
+ }).strict();
23
+ const Check = z.union([GateCheck, z.array(argument).min(1).max(WORK_ORDER_LIMITS.arguments)]);
24
+ const Criterion = z.object({
25
+ id: z.string().regex(/^[A-Za-z][A-Za-z0-9_-]{0,31}$/, 'a short identifier such as AC1'),
26
+ text,
27
+ check: Check.optional(),
28
+ source: sourcePath.optional(),
29
+ }).strict();
30
+ const Criteria = z.array(Criterion).min(1).max(WORK_ORDER_LIMITS.criteria)
31
+ .refine(rows => new Set(rows.map(row => row.id)).size === rows.length, 'each criterion id is used once');
32
+ export const WorkOrderFrontMatter = z.object({
33
+ id: z.string().regex(WORK_ORDER_ID, 'letters, digits, dot, underscore or hyphen, at most 128'),
34
+ objective: text,
35
+ scope: z.array(repositoryPath).min(1).max(WORK_ORDER_LIMITS.scope).describe('Paths and globs the work may change.'),
36
+ depends_on: z.array(z.string().regex(WORK_ORDER_ID)).max(32).default([]),
37
+ gates: z.array(z.string().regex(/^[a-z][a-z0-9-]{0,63}$/)).max(16).default([]).describe('Declared [testing] gates that must pass at work check.'),
38
+ criteria: Criteria,
39
+ non_goals: z.array(text).max(32).default([]),
40
+ }).strict();
41
+ function frontMatter(bytes) {
42
+ if (bytes.byteLength > WORK_ORDER_LIMITS.bytes)
43
+ return { ok: false, problems: [`the file exceeds ${WORK_ORDER_LIMITS.bytes} bytes`] };
44
+ let source;
45
+ try {
46
+ source = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
47
+ }
48
+ catch (error) {
49
+ if (!(error instanceof TypeError))
50
+ throw error;
51
+ return { ok: false, problems: ['the file is not UTF-8'] };
52
+ }
53
+ const lines = source.replace(/^/, '').split(/\r?\n/);
54
+ const end = lines.indexOf('---', 1);
55
+ if (lines[0] !== '---' || end < 0)
56
+ return { ok: false, problems: ['the file must start with YAML front-matter between two --- lines'] };
57
+ const document = parseDocument(lines.slice(1, end).join('\n'), { uniqueKeys: true, prettyErrors: false });
58
+ if (document.errors.length)
59
+ return { ok: false, problems: document.errors.map(error => `front-matter is not YAML: ${error.message.split('\n')[0]}`) };
60
+ return { ok: true, value: document.toJS({ maxAliasCount: 0 }) };
61
+ }
62
+ function issues(error) {
63
+ return error.issues.map(issue => `${issue.path.length ? issue.path.join('.') : 'front-matter'}: ${issue.message}`);
64
+ }
65
+ /** Parses `workorders/<id>.md`; the id the file declares must be the name it is stored under. */
66
+ export function parseWorkOrder(bytes, fileId) {
67
+ const read = frontMatter(bytes);
68
+ if (!read.ok)
69
+ return read;
70
+ const parsed = WorkOrderFrontMatter.safeParse(read.value);
71
+ if (!parsed.success)
72
+ return { ok: false, problems: issues(parsed.error) };
73
+ if (parsed.data.id !== fileId)
74
+ return { ok: false, problems: [`id: the file workorders/${fileId}.md declares id ${parsed.data.id}; they must match`] };
75
+ if (parsed.data.depends_on.includes(parsed.data.id))
76
+ return { ok: false, problems: ['depends_on: an order cannot depend on itself'] };
77
+ return { ok: true, value: parsed.data };
78
+ }
79
+ /** The quick-path file `cockpit grade --criteria` reads: front-matter with criteria, and optionally scope and gates. */
80
+ export const CriteriaFile = z.object({ criteria: Criteria, scope: z.array(repositoryPath).max(WORK_ORDER_LIMITS.scope).default([]),
81
+ gates: z.array(z.string().regex(/^[a-z][a-z0-9-]{0,63}$/)).max(16).default([]), objective: text.optional() }).strict();
82
+ export function parseCriteriaFile(bytes) {
83
+ const read = frontMatter(bytes);
84
+ if (!read.ok)
85
+ return read;
86
+ const parsed = CriteriaFile.safeParse(read.value);
87
+ return parsed.success ? { ok: true, value: parsed.data } : { ok: false, problems: issues(parsed.error) };
88
+ }
89
+ function canonical(value) {
90
+ if (Array.isArray(value))
91
+ return value.map(canonical);
92
+ if (value === null || typeof value !== 'object')
93
+ return value;
94
+ return Object.fromEntries(Object.keys(value).sort().map(key => [key, canonical(value[key])]));
95
+ }
96
+ /** The digest an acceptance binds: the contract, each cited source's bytes, and the base commits. */
97
+ export function workOrderDigest(order, sources, base) {
98
+ return createHash('sha256').update(JSON.stringify(canonical({ order, sources, base }))).digest('hex');
99
+ }
100
+ /**
101
+ * The accepted criteria a changed contract removes or rewrites. Adding a criterion strengthens an
102
+ * order; dropping one, or changing what one says or how it is checked, weakens it, and that is never
103
+ * an agent's decision.
104
+ */
105
+ export function criteriaWeakening(accepted, changed) {
106
+ return accepted.criteria.flatMap(before => {
107
+ const after = changed.criteria.find(row => row.id === before.id);
108
+ if (!after)
109
+ return [`${before.id} is removed`];
110
+ return JSON.stringify(canonical(after)) === JSON.stringify(canonical(before)) ? [] : [`${before.id} is rewritten`];
111
+ });
112
+ }
113
+ // `**` crosses directories, `*` and `?` stay within one; a plain entry also covers what is below it.
114
+ export function scopeMatches(scope, path) {
115
+ return scope.some(entry => {
116
+ if (!/[*?]/.test(entry))
117
+ return path === entry || path.startsWith(`${entry.replace(/\/$/, '')}/`);
118
+ const pattern = entry.split(/(\*\*\/?|\*|\?)/).map(part => part === '**' || part === '**/' ? '(?:.*/)?' + (part === '**' ? '.*' : '')
119
+ : part === '*' ? '[^/]*' : part === '?' ? '[^/]' : part.replace(/[.+^${}()|[\]\\]/g, '\\$&')).join('');
120
+ return new RegExp(`^${pattern}$`).test(path);
121
+ });
122
+ }
@@ -0,0 +1,158 @@
1
+ import { z } from 'zod';
2
+ export declare const WORK_RECORD_DIRECTORY = ".cockpit/work-orders";
3
+ declare const CheckResult: z.ZodObject<{
4
+ criterion: z.ZodString;
5
+ kind: z.ZodEnum<{
6
+ argv: "argv";
7
+ gate: "gate";
8
+ }>;
9
+ passed: z.ZodBoolean;
10
+ outcome: z.ZodString;
11
+ output: z.ZodString;
12
+ }, z.core.$strict>;
13
+ export type CheckResult = z.infer<typeof CheckResult>;
14
+ export declare const WorkRecord: z.ZodObject<{
15
+ format: z.ZodLiteral<"cockpit-work-order/v1">;
16
+ id: z.ZodString;
17
+ state: z.ZodEnum<{
18
+ abandoned: "abandoned";
19
+ accepted: "accepted";
20
+ checked: "checked";
21
+ done: "done";
22
+ graded: "graded";
23
+ partial: "partial";
24
+ }>;
25
+ accepted: z.ZodObject<{
26
+ at: z.ZodString;
27
+ by: z.ZodEnum<{
28
+ agent: "agent";
29
+ ci: "ci";
30
+ person: "person";
31
+ }>;
32
+ digest: z.ZodString;
33
+ order: z.ZodObject<{
34
+ id: z.ZodString;
35
+ objective: z.ZodString;
36
+ scope: z.ZodArray<z.ZodString>;
37
+ depends_on: z.ZodDefault<z.ZodArray<z.ZodString>>;
38
+ gates: z.ZodDefault<z.ZodArray<z.ZodString>>;
39
+ criteria: z.ZodArray<z.ZodObject<{
40
+ id: z.ZodString;
41
+ text: z.ZodString;
42
+ check: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
43
+ gate: z.ZodString;
44
+ select: z.ZodOptional<z.ZodString>;
45
+ }, z.core.$strict>, z.ZodArray<z.ZodString>]>>;
46
+ source: z.ZodOptional<z.ZodString>;
47
+ }, z.core.$strict>>;
48
+ non_goals: z.ZodDefault<z.ZodArray<z.ZodString>>;
49
+ }, z.core.$strict>;
50
+ sources: z.ZodRecord<z.ZodString, z.ZodString>;
51
+ base: z.ZodRecord<z.ZodString, z.ZodString>;
52
+ }, z.core.$strict>;
53
+ amendments: z.ZodArray<z.ZodObject<{
54
+ at: z.ZodString;
55
+ by: z.ZodEnum<{
56
+ agent: "agent";
57
+ ci: "ci";
58
+ person: "person";
59
+ }>;
60
+ from: z.ZodString;
61
+ to: z.ZodString;
62
+ weakened: z.ZodArray<z.ZodString>;
63
+ }, z.core.$strict>>;
64
+ attempts: z.ZodNumber;
65
+ checks: z.ZodOptional<z.ZodObject<{
66
+ at: z.ZodString;
67
+ digest: z.ZodString;
68
+ results: z.ZodArray<z.ZodObject<{
69
+ criterion: z.ZodString;
70
+ kind: z.ZodEnum<{
71
+ argv: "argv";
72
+ gate: "gate";
73
+ }>;
74
+ passed: z.ZodBoolean;
75
+ outcome: z.ZodString;
76
+ output: z.ZodString;
77
+ }, z.core.$strict>>;
78
+ }, z.core.$strict>>;
79
+ grade: z.ZodOptional<z.ZodObject<{
80
+ at: z.ZodString;
81
+ digest: z.ZodString;
82
+ mode: z.ZodEnum<{
83
+ checks: "checks";
84
+ independent: "independent";
85
+ self: "self";
86
+ }>;
87
+ passed: z.ZodBoolean;
88
+ criteria: z.ZodArray<z.ZodObject<{
89
+ id: z.ZodString;
90
+ verdict: z.ZodEnum<{
91
+ met: "met";
92
+ unclear: "unclear";
93
+ unmet: "unmet";
94
+ }>;
95
+ note: z.ZodString;
96
+ }, z.core.$strict>>;
97
+ outOfScope: z.ZodArray<z.ZodString>;
98
+ evaluator: z.ZodOptional<z.ZodObject<{
99
+ tool: z.ZodString;
100
+ fallbacks: z.ZodArray<z.ZodObject<{
101
+ tool: z.ZodString;
102
+ code: z.ZodString;
103
+ message: z.ZodString;
104
+ }, z.core.$strict>>;
105
+ }, z.core.$strict>>;
106
+ note: z.ZodOptional<z.ZodString>;
107
+ }, z.core.$strict>>;
108
+ notes: z.ZodArray<z.ZodObject<{
109
+ at: z.ZodString;
110
+ by: z.ZodEnum<{
111
+ agent: "agent";
112
+ ci: "ci";
113
+ person: "person";
114
+ }>;
115
+ kind: z.ZodEnum<{
116
+ answer: "answer";
117
+ note: "note";
118
+ question: "question";
119
+ }>;
120
+ text: z.ZodString;
121
+ answers: z.ZodOptional<z.ZodNumber>;
122
+ }, z.core.$strict>>;
123
+ closure: z.ZodOptional<z.ZodObject<{
124
+ at: z.ZodString;
125
+ by: z.ZodEnum<{
126
+ agent: "agent";
127
+ ci: "ci";
128
+ person: "person";
129
+ }>;
130
+ how: z.ZodEnum<{
131
+ abandoned: "abandoned";
132
+ "checks-passed": "checks-passed";
133
+ graded: "graded";
134
+ partial: "partial";
135
+ "self-reported": "self-reported";
136
+ }>;
137
+ note: z.ZodOptional<z.ZodString>;
138
+ }, z.core.$strict>>;
139
+ }, z.core.$strict>;
140
+ export type WorkRecord = z.infer<typeof WorkRecord>;
141
+ /** Keeps the end of a command's output, where a runner prints its summary, within the record's bound. */
142
+ export declare function outputTail(value: string): string;
143
+ export interface WorkStore {
144
+ readonly read: (id: string) => Promise<WorkRecord | undefined>;
145
+ readonly list: () => Promise<readonly WorkRecord[]>;
146
+ /** Runs `change` holding the order's lock; it returns the next record, or undefined to write nothing. */
147
+ readonly update: <T>(id: string, change: (current: WorkRecord | undefined) => Promise<{
148
+ record?: WorkRecord;
149
+ value: T;
150
+ }>) => Promise<T>;
151
+ readonly recover: (id: string, apply: boolean) => Promise<Readonly<{
152
+ id: string;
153
+ lock: 'none' | 'live' | 'unknown' | 'dead' | 'removed';
154
+ holder?: string;
155
+ }>>;
156
+ }
157
+ export declare function createWorkStore(root: string): WorkStore;
158
+ export {};
@@ -0,0 +1,197 @@
1
+ // Owns the record cockpit keeps of each work order, `.cockpit/work-orders/<id>.json`: what was
2
+ // accepted and by whom, the checks cockpit ran, the grade, notes and questions, and how the order
3
+ // closed. Records are committed so the `work verify` CI job can read them, and only cockpit writes
4
+ // them: the guard denies an agent's write below `.cockpit/work-orders/`, because an unkeyed record
5
+ // an agent wrote there would read as cockpit's own. A write holds the order's lock file, which a
6
+ // crashed writer leaves behind until `work recover --apply` removes it.
7
+ import { randomUUID } from 'node:crypto';
8
+ import { lstat, mkdir, open, readFile, readdir, rename, rm } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { z } from 'zod';
11
+ import { isProcessGone, observeProcessStart, processHost } from '../environment/claims.js';
12
+ import { hasErrorCode, RefusalError } from '../environment/contract.js';
13
+ import { executeProbe } from '../environment-exec/execute.js';
14
+ import { DECIDERS, WORK_GRADING } from '../schema.js';
15
+ import { WORK_ORDER_ID, WorkOrderFrontMatter } from './contract.js';
16
+ export const WORK_RECORD_DIRECTORY = '.cockpit/work-orders';
17
+ const RECORD_LIMIT_BYTES = 1_048_576;
18
+ const OUTPUT_TAIL_BYTES = 4_096;
19
+ const at = z.string().datetime();
20
+ const by = z.enum(DECIDERS);
21
+ const note = z.string().min(1).max(4_096);
22
+ const CheckResult = z.object({
23
+ criterion: z.string().max(64),
24
+ kind: z.enum(['argv', 'gate']),
25
+ passed: z.boolean(),
26
+ // How the check ended: an exit status, a gate verdict, or why it could not run.
27
+ outcome: z.string().max(256),
28
+ output: z.string().max(OUTPUT_TAIL_BYTES * 2),
29
+ }).strict();
30
+ const Verdict = z.object({ id: z.string().max(64), verdict: z.enum(['met', 'unmet', 'unclear']), note: z.string().max(4_096) }).strict();
31
+ const Grade = z.object({
32
+ at, digest: z.string().length(64), mode: z.enum(WORK_GRADING), passed: z.boolean(),
33
+ criteria: z.array(Verdict).max(64), outOfScope: z.array(z.string().max(1_100)).max(512),
34
+ // Which evaluator answered and those passed over on the way; absent when no evaluator ran.
35
+ evaluator: z.object({ tool: z.string().max(64), fallbacks: z.array(z.object({ tool: z.string().max(64), code: z.string().max(64), message: z.string().max(8_192) }).strict()).max(8) }).strict().optional(),
36
+ note: note.optional(),
37
+ }).strict();
38
+ export const WorkRecord = z.object({
39
+ format: z.literal('cockpit-work-order/v1'),
40
+ id: z.string().regex(WORK_ORDER_ID),
41
+ state: z.enum(['accepted', 'checked', 'graded', 'done', 'partial', 'abandoned']),
42
+ accepted: z.object({
43
+ at, by, digest: z.string().length(64),
44
+ // The accepted contract, so a later amendment can be compared criterion by criterion.
45
+ order: WorkOrderFrontMatter,
46
+ sources: z.record(z.string(), z.string().length(64)),
47
+ base: z.record(z.string(), z.string().regex(/^[a-f0-9]{40,64}$/)),
48
+ }).strict(),
49
+ amendments: z.array(z.object({ at, by, from: z.string().length(64), to: z.string().length(64), weakened: z.array(z.string()).max(64) }).strict()).max(256),
50
+ attempts: z.number().int().min(0),
51
+ checks: z.object({ at, digest: z.string().length(64), results: z.array(CheckResult).max(64) }).strict().optional(),
52
+ grade: Grade.optional(),
53
+ notes: z.array(z.object({ at, by: z.enum(['agent', 'person', 'ci']), kind: z.enum(['note', 'question', 'answer']), text: note,
54
+ answers: z.number().int().min(1).optional() }).strict()).max(1_024),
55
+ closure: z.object({ at, by, how: z.enum(['graded', 'checks-passed', 'self-reported', 'partial', 'abandoned']), note: note.optional() }).strict().optional(),
56
+ }).strict();
57
+ /** Keeps the end of a command's output, where a runner prints its summary, within the record's bound. */
58
+ export function outputTail(value) {
59
+ const bytes = Buffer.from(value);
60
+ return bytes.byteLength <= OUTPUT_TAIL_BYTES ? value : `[...]${bytes.subarray(bytes.byteLength - OUTPUT_TAIL_BYTES).toString('utf8')}`;
61
+ }
62
+ // A lock names its holder as pid@start, so a reused pid never keeps a dead writer's lock alive.
63
+ const holder = async () => {
64
+ const observed = await observeProcessStart(process.pid, processHost(executeProbe));
65
+ return observed.state === 'present' ? `${process.pid}@${observed.start}` : `${process.pid}`;
66
+ };
67
+ export function createWorkStore(root) {
68
+ const directory = join(root, WORK_RECORD_DIRECTORY);
69
+ const pathOf = (id, suffix) => {
70
+ if (!WORK_ORDER_ID.test(id))
71
+ throw new RefusalError(`work order id ${JSON.stringify(id)} is not an id`);
72
+ return join(directory, `${id}${suffix}`);
73
+ };
74
+ const read = async (id) => {
75
+ const path = pathOf(id, '.json');
76
+ let bytes;
77
+ try {
78
+ const status = await lstat(path);
79
+ if (!status.isFile() || status.size > RECORD_LIMIT_BYTES)
80
+ throw new RefusalError(`${WORK_RECORD_DIRECTORY}/${id}.json is not a regular file of at most 1 MiB`);
81
+ bytes = await readFile(path);
82
+ }
83
+ catch (error) {
84
+ if (hasErrorCode(error, 'ENOENT'))
85
+ return undefined;
86
+ throw error;
87
+ }
88
+ let value;
89
+ try {
90
+ value = JSON.parse(bytes.toString('utf8'));
91
+ }
92
+ catch (error) {
93
+ if (!(error instanceof SyntaxError))
94
+ throw error;
95
+ value = undefined;
96
+ }
97
+ const parsed = WorkRecord.safeParse(value);
98
+ if (!parsed.success || parsed.data.id !== id) {
99
+ throw new RefusalError(`${WORK_RECORD_DIRECTORY}/${id}.json is not a cockpit work-order record; restore it with git restore -- ${WORK_RECORD_DIRECTORY}/${id}.json`);
100
+ }
101
+ return parsed.data;
102
+ };
103
+ const lock = async (id) => {
104
+ await mkdir(directory, { recursive: true });
105
+ const path = pathOf(id, '.lock');
106
+ const recorded = await holder();
107
+ try {
108
+ const handle = await open(path, 'wx', 0o644);
109
+ try {
110
+ await handle.writeFile(`${recorded}\n`);
111
+ }
112
+ finally {
113
+ await handle.close();
114
+ }
115
+ }
116
+ catch (error) {
117
+ if (!hasErrorCode(error, 'EEXIST'))
118
+ throw error;
119
+ throw new RefusalError(`work order ${id} is locked by another cockpit command (${WORK_RECORD_DIRECTORY}/${id}.lock); wait for it, or if it crashed run npx --no cockpit work recover --config <your cockpit.toml> --work-order ${id} --apply`);
120
+ }
121
+ return async () => { await rm(path, { force: true }); };
122
+ };
123
+ const write = async (record) => {
124
+ const checked = WorkRecord.parse(record);
125
+ const bytes = `${JSON.stringify(checked, null, 2)}\n`;
126
+ if (Buffer.byteLength(bytes) > RECORD_LIMIT_BYTES)
127
+ throw new RefusalError(`the ${record.id} record would exceed 1 MiB`);
128
+ const path = pathOf(record.id, '.json');
129
+ const staged = `${path}.${randomUUID()}.tmp`;
130
+ const handle = await open(staged, 'wx', 0o644);
131
+ try {
132
+ await handle.writeFile(bytes);
133
+ await handle.sync();
134
+ }
135
+ finally {
136
+ await handle.close();
137
+ }
138
+ try {
139
+ await rename(staged, path);
140
+ }
141
+ catch (error) {
142
+ await rm(staged, { force: true });
143
+ throw error;
144
+ }
145
+ };
146
+ const store = {
147
+ read,
148
+ list: async () => {
149
+ let names;
150
+ try {
151
+ names = await readdir(directory);
152
+ }
153
+ catch (error) {
154
+ if (hasErrorCode(error, 'ENOENT'))
155
+ return [];
156
+ throw error;
157
+ }
158
+ const ids = names.filter(name => name.endsWith('.json')).map(name => name.slice(0, -'.json'.length)).filter(id => WORK_ORDER_ID.test(id)).sort();
159
+ return Promise.all(ids.map(async (id) => (await read(id))));
160
+ },
161
+ update: async (id, change) => {
162
+ const release = await lock(id);
163
+ try {
164
+ const result = await change(await read(id));
165
+ if (result.record)
166
+ await write(result.record);
167
+ return result.value;
168
+ }
169
+ finally {
170
+ await release();
171
+ }
172
+ },
173
+ recover: async (id, apply) => {
174
+ const path = pathOf(id, '.lock');
175
+ let text;
176
+ try {
177
+ text = await readFile(path, 'utf8');
178
+ }
179
+ catch (error) {
180
+ if (hasErrorCode(error, 'ENOENT'))
181
+ return { id, lock: 'none' };
182
+ throw error;
183
+ }
184
+ const recorded = text.trim();
185
+ const [pidText, start] = recorded.split('@', 2);
186
+ const observed = await observeProcessStart(Number(pidText), processHost(executeProbe));
187
+ // A lock whose writer is still running, or cannot be shown gone, is never removed: the write it guards may be in progress.
188
+ if (!isProcessGone(start, observed))
189
+ return { id, lock: observed.state === 'unknown' ? 'unknown' : 'live', holder: recorded };
190
+ if (!apply)
191
+ return { id, lock: 'dead', holder: recorded };
192
+ await rm(path, { force: true });
193
+ return { id, lock: 'removed', holder: recorded };
194
+ },
195
+ };
196
+ return store;
197
+ }
package/docs/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Cockpit documentation
2
+
3
+ cockpit is the local environment coding agents work from: every repository of the product in reach,
4
+ the product running on the checkouts they edit, the same instructions, skills and guard in every agent
5
+ tool from one `cockpit.toml`, and work orders checked against criteria you set and graded the way you choose. The instructions and
6
+ guard need only Git and Node.js; the stack and grading switch on when configured. New here: read [Getting started](getting-started.md)
7
+ chapter 1, which needs one repository and no Docker.
8
+
9
+ This index lists every page for people using cockpit on their own products, grouped by what you
10
+ are trying to do. To work on cockpit itself, start with [CONTRIBUTING.md](https://github.com/b0dea/cockpit/blob/main/CONTRIBUTING.md); the
11
+ contributor pages live separately under docs/contributing/.
12
+
13
+ ## Learn
14
+
15
+ - [Tutorial](tutorial.md): run the Compose-first example end to end.
16
+ - [Getting started](getting-started.md): one repository, one tool and no Docker first, then more
17
+ repositories and a Compose stack; includes the guide and safety contract for an AI agent setting
18
+ cockpit up.
19
+ - [Concepts](concepts.md): the glossary and the terms diagnostics use.
20
+ - [FAQ](faq.md): short answers, including when not to use cockpit.
21
+
22
+ ## Guides
23
+
24
+ - [Joining a team's cockpit](joining-a-team.md): install and verify a cockpit from a fresh clone.
25
+ - [Environment lifecycle](environment.md): setup, bring-up, health, logs, reset and seeding.
26
+ - [Compose patterns](compose-patterns.md): vendor stubs, TLS and data restore in plain Compose.
27
+ - [Harness surfaces](harness-surfaces.md): what `sync` writes for each agent tool, and overlays.
28
+ - [Extending cockpit](extending.md): supported extension points, what an upgrade replaces and the build-beside pattern.
29
+ - [Safety and autonomy](safety-and-autonomy.md): what guards allow, ask about and deny.
30
+ - [Work and browser workflows](work-and-browser.md): work orders, grading, browser checks and
31
+ test tiers.
32
+
33
+ ## Reference
34
+
35
+ The command list, CLI reference, configuration reference and capability matrix are generated from
36
+ the source and change with it. Troubleshooting combines hand-written recovery guidance with a
37
+ generated diagnostic index.
38
+
39
+ - [Configuration essentials](configuration-essentials.md): the tables a typical `cockpit.toml`
40
+ sets, each linked to its full reference entry.
41
+ - [Command list](command-list.md)
42
+ - [CLI reference](cli-reference.md)
43
+ - [Configuration reference](configuration-reference.md)
44
+ - [Capability matrix](capability-matrix.md)
45
+ - [Troubleshooting](troubleshooting.md): hand-written remedies followed by the generated table
46
+ of codes with a fixed remedy.
47
+
48
+ ## Examples
49
+
50
+ Each example is a cockpit you can copy and run; its README gives the exact commands.
51
+
52
+ - [examples/minimal](https://github.com/b0dea/cockpit/blob/main/examples/minimal/README.md): one service, one port and one health check
53
+ in a plain `compose.yml`, for a running stack.
54
+ - [examples/compose-first](https://github.com/b0dea/cockpit/blob/main/examples/compose-first/README.md): a cockpit that keeps its own
55
+ `compose.yml`.
56
+ - [examples/docs-only](https://github.com/b0dea/cockpit/blob/main/examples/docs-only/README.md): no environment, for a repository of
57
+ documents or a product not yet built.
58
+ - [examples/extended](https://github.com/b0dea/cockpit/blob/main/examples/extended/README.md): a custom Compose service and
59
+ product-specific checks kept beside cockpit.
60
+
61
+ ## Background
62
+
63
+ - [Architecture and design](architecture.md): why cockpit is shaped this way, non-goals, and
64
+ extension seams.
65
+ - [Release policy](release-policy.md): supported runtimes, deprecation and migration.