@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,44 @@
1
+ import { type EnvironmentDiagnostic } from './environment/contract.js';
2
+ import type { CockpitConfig, Decider, WorkGrading } from './schema.js';
3
+ export type WorkGate = 'accept' | 'amend' | 'answer' | 'signoff';
4
+ export type AutonomyDecision = 'sync' | 'stale_delete' | 'reset' | 'mcp_approve';
5
+ export interface EffectivePolicy {
6
+ readonly grading: WorkGrading;
7
+ readonly gates: Readonly<Record<WorkGate, Decider>>;
8
+ readonly autonomy: Readonly<Record<AutonomyDecision, Decider>>;
9
+ }
10
+ export declare const GATE_DEFAULTS: Readonly<Record<WorkGate, Decider>>;
11
+ export declare const AUTONOMY_DEFAULTS: Readonly<Record<AutonomyDecision, Decider>>;
12
+ export declare function effectivePolicy(config: Readonly<{
13
+ work: Readonly<Pick<CockpitConfig['work'], 'grading'> & {
14
+ gates: Readonly<CockpitConfig['work']['gates']>;
15
+ }>;
16
+ autonomy: Readonly<CockpitConfig['autonomy']>;
17
+ }>): EffectivePolicy;
18
+ /** cockpit detects CI from the CI variable, as every hosted runner sets it; an agent can set it too. */
19
+ export declare function runningInCi(env: Readonly<Record<string, string | undefined>>): boolean;
20
+ /**
21
+ * Whether this run may pass the decision without a person. A `person` decision is never passed here:
22
+ * its caller asks for the typed digest. A `ci` decision passes only under CI, where a protected
23
+ * environment's reviewers are the human gate; locally that is best-effort, as an agent can set CI too.
24
+ */
25
+ export declare function decide(decider: Decider, env: Readonly<Record<string, string | undefined>>): 'proceed' | 'person' | 'ci-only';
26
+ export interface PolicyWeakening {
27
+ readonly field: string;
28
+ readonly from: string;
29
+ readonly to: string;
30
+ }
31
+ /** Every field `current` sets weaker than `recorded`, named as cockpit.toml spells it. */
32
+ export declare function policyWeakening(recorded: EffectivePolicy, current: EffectivePolicy): readonly PolicyWeakening[];
33
+ /** The error `check` reports while cockpit.toml sits weaker than the recorded policy; sync would refuse the same change. */
34
+ export declare function policyWeakeningDiagnostic(weakened: readonly PolicyWeakening[]): EnvironmentDiagnostic;
35
+ /** The digest a person types to accept exactly these weakenings of exactly this recorded policy. */
36
+ export declare function weakeningDigest(recorded: EffectivePolicy, current: EffectivePolicy): string;
37
+ /** The policy the last sync recorded, or undefined before the first; an unreadable record refuses. */
38
+ export declare function readRecordedPolicy(root: string): Promise<EffectivePolicy | undefined>;
39
+ export declare function writeRecordedPolicy(root: string, policy: EffectivePolicy): Promise<void>;
40
+ /**
41
+ * The cockpit.toml tables the guard keeps an agent from editing, as parsed values to compare, or
42
+ * undefined when the text is not TOML. [mcp] is pinned only while a person approves MCP servers.
43
+ */
44
+ export declare function pinnedPolicyTables(text: string): Readonly<Record<string, unknown>> | undefined;
@@ -0,0 +1,156 @@
1
+ // Owns the autonomy policy: who may pass each decision point cockpit gates, as cockpit.toml's [work]
2
+ // and [autonomy] tables declare it, what an unset field means, which change weakens it, and the
3
+ // record of the policy the last sync accepted. Every command that gates a decision asks `decide`
4
+ // here, so a field cannot mean one thing to sync and another to the guard.
5
+ import { createHash, randomUUID } from 'node:crypto';
6
+ import { mkdir, open, rename, rm } from 'node:fs/promises';
7
+ import { dirname, join } from 'node:path';
8
+ import { isDeepStrictEqual } from 'node:util';
9
+ import { parse as parseToml, TomlError } from 'smol-toml';
10
+ import { readBoundedFile } from './bounded-read.js';
11
+ import { hasErrorCode, RefusalError } from './environment/contract.js';
12
+ // The owner's defaults: an agent runs cockpit end to end except where stack data is lost or a process
13
+ // would start outside the guard, and a team opts into person or CI gates field by field. A sibling's
14
+ // MCP source is an ordinary file an agent writes, and a harness starts an enabled server outside every
15
+ // guard boundary, so an agent approving MCP servers could run any command it wrote there.
16
+ export const GATE_DEFAULTS = Object.freeze({ accept: 'agent', amend: 'agent', answer: 'agent', signoff: 'agent' });
17
+ export const AUTONOMY_DEFAULTS = Object.freeze({ sync: 'agent', stale_delete: 'agent', reset: 'person', mcp_approve: 'person' });
18
+ export function effectivePolicy(config) {
19
+ const pick = (declared, defaults) => Object.fromEntries(Object.entries(defaults).map(([key, value]) => [key, declared[key] ?? value]));
20
+ return {
21
+ grading: config.work.grading,
22
+ gates: pick(config.work.gates, GATE_DEFAULTS),
23
+ autonomy: pick({ sync: config.autonomy.sync, stale_delete: config.autonomy.stale_delete,
24
+ reset: config.autonomy.reset, mcp_approve: config.autonomy.mcp_approve }, AUTONOMY_DEFAULTS),
25
+ };
26
+ }
27
+ /** cockpit detects CI from the CI variable, as every hosted runner sets it; an agent can set it too. */
28
+ export function runningInCi(env) {
29
+ return typeof env.CI === 'string' && env.CI.length > 0 && env.CI !== 'false' && env.CI !== '0';
30
+ }
31
+ /**
32
+ * Whether this run may pass the decision without a person. A `person` decision is never passed here:
33
+ * its caller asks for the typed digest. A `ci` decision passes only under CI, where a protected
34
+ * environment's reviewers are the human gate; locally that is best-effort, as an agent can set CI too.
35
+ */
36
+ export function decide(decider, env) {
37
+ if (decider === 'agent')
38
+ return 'proceed';
39
+ if (decider === 'person')
40
+ return 'person';
41
+ return runningInCi(env) ? 'proceed' : 'ci-only';
42
+ }
43
+ // Stronger is later: an agent decision is the weakest, CI behind reviewers the strongest.
44
+ const DECIDER_RANK = Object.freeze({ agent: 0, person: 1, ci: 2 });
45
+ const GRADING_RANK = Object.freeze({ self: 0, checks: 1, independent: 2 });
46
+ /** Every field `current` sets weaker than `recorded`, named as cockpit.toml spells it. */
47
+ export function policyWeakening(recorded, current) {
48
+ const rows = [];
49
+ if (GRADING_RANK[current.grading] < GRADING_RANK[recorded.grading])
50
+ rows.push({ field: 'work.grading', from: recorded.grading, to: current.grading });
51
+ for (const [table, field] of [['gates', 'work.gates'], ['autonomy', 'autonomy']]) {
52
+ for (const [key, was] of Object.entries(recorded[table])) {
53
+ const now = current[table][key];
54
+ if (DECIDER_RANK[now] < DECIDER_RANK[was])
55
+ rows.push({ field: `${field}.${key}`, from: was, to: now });
56
+ }
57
+ }
58
+ return rows;
59
+ }
60
+ /** The error `check` reports while cockpit.toml sits weaker than the recorded policy; sync would refuse the same change. */
61
+ export function policyWeakeningDiagnostic(weakened) {
62
+ const shown = weakened.map(row => `${row.field}: ${row.from} -> ${row.to}`).join('; ');
63
+ return { severity: 'error', target: 'autonomy',
64
+ code: 'POLICY_WEAKENING_UNCONFIRMED',
65
+ message: `cockpit.toml weakens the policy the last sync recorded (${shown})`,
66
+ fix: 'a person runs npx --no cockpit sync --config <your cockpit.toml> --interactive in a terminal outside CI, reads the weakening it shows and types its digest, or the change is reverted' };
67
+ }
68
+ /** The digest a person types to accept exactly these weakenings of exactly this recorded policy. */
69
+ export function weakeningDigest(recorded, current) {
70
+ return createHash('sha256').update(JSON.stringify({ recorded, current })).digest('hex');
71
+ }
72
+ // Written only by cockpit: the guard protects `.cockpit/policy.json` as a control, so the policy an
73
+ // agent's edit would weaken still stands until a person accepts the weakening at sync.
74
+ const POLICY_RECORD_PATH = '.cockpit/policy.json';
75
+ const RECORD_FORMAT = 'cockpit-policy/v1';
76
+ function validPolicy(value) {
77
+ const row = value;
78
+ const deciders = (table, keys) => typeof table === 'object' && table !== null && !Array.isArray(table)
79
+ && Object.keys(table).sort().join() === [...keys].sort().join()
80
+ && Object.values(table).every(entry => Object.hasOwn(DECIDER_RANK, entry));
81
+ return typeof value === 'object' && value !== null && Object.keys(value).sort().join() === 'autonomy,gates,grading'
82
+ && Object.hasOwn(GRADING_RANK, row.grading) && deciders(row.gates, Object.keys(GATE_DEFAULTS)) && deciders(row.autonomy, Object.keys(AUTONOMY_DEFAULTS));
83
+ }
84
+ /** The policy the last sync recorded, or undefined before the first; an unreadable record refuses. */
85
+ export async function readRecordedPolicy(root) {
86
+ const path = join(root, POLICY_RECORD_PATH);
87
+ const unusable = `${POLICY_RECORD_PATH} is not a regular file of at most 64 KiB; restore it with git restore -- ${POLICY_RECORD_PATH}`;
88
+ let read;
89
+ try {
90
+ read = readBoundedFile(path, 65_536);
91
+ }
92
+ catch (error) {
93
+ if (hasErrorCode(error, 'ENOENT'))
94
+ return undefined;
95
+ if (hasErrorCode(error, 'ELOOP', 'EISDIR', 'EIO'))
96
+ throw new RefusalError(unusable);
97
+ throw error;
98
+ }
99
+ if (read.kind === 'too-large')
100
+ throw new RefusalError(unusable);
101
+ const bytes = read.bytes;
102
+ let parsed;
103
+ try {
104
+ parsed = JSON.parse(bytes.toString('utf8'));
105
+ }
106
+ catch (error) {
107
+ if (!(error instanceof SyntaxError))
108
+ throw error;
109
+ throw new RefusalError(`${POLICY_RECORD_PATH} is not JSON; restore it with git restore -- ${POLICY_RECORD_PATH}`);
110
+ }
111
+ const record = parsed;
112
+ if (record?.format !== RECORD_FORMAT || !validPolicy(record.policy)) {
113
+ throw new RefusalError(`${POLICY_RECORD_PATH} is not a ${RECORD_FORMAT} record; restore it with git restore -- ${POLICY_RECORD_PATH}`);
114
+ }
115
+ return record.policy;
116
+ }
117
+ export async function writeRecordedPolicy(root, policy) {
118
+ const path = join(root, POLICY_RECORD_PATH);
119
+ if (isDeepStrictEqual(await readRecordedPolicy(root), policy))
120
+ return;
121
+ await mkdir(dirname(path), { recursive: true });
122
+ const staged = `${path}.${randomUUID()}.tmp`;
123
+ const handle = await open(staged, 'wx', 0o644);
124
+ try {
125
+ await handle.writeFile(`${JSON.stringify({ format: RECORD_FORMAT, policy }, null, 2)}\n`);
126
+ await handle.sync();
127
+ }
128
+ finally {
129
+ await handle.close();
130
+ }
131
+ try {
132
+ await rename(staged, path);
133
+ }
134
+ catch (error) {
135
+ await rm(staged, { force: true });
136
+ throw error;
137
+ }
138
+ }
139
+ /**
140
+ * The cockpit.toml tables the guard keeps an agent from editing, as parsed values to compare, or
141
+ * undefined when the text is not TOML. [mcp] is pinned only while a person approves MCP servers.
142
+ */
143
+ export function pinnedPolicyTables(text) {
144
+ let parsed;
145
+ try {
146
+ parsed = parseToml(text);
147
+ }
148
+ catch (error) {
149
+ if (error instanceof TomlError)
150
+ return undefined;
151
+ throw error;
152
+ }
153
+ const autonomy = parsed.autonomy;
154
+ const mcpByAgent = (autonomy?.mcp_approve ?? AUTONOMY_DEFAULTS.mcp_approve) === 'agent';
155
+ return { work: parsed.work, autonomy: parsed.autonomy, ...(mcpByAgent ? {} : { mcp: parsed.mcp }) };
156
+ }
@@ -0,0 +1,14 @@
1
+ export type BoundedRead = Readonly<{
2
+ kind: 'complete';
3
+ bytes: Buffer;
4
+ }> | Readonly<{
5
+ kind: 'too-large';
6
+ }>;
7
+ /**
8
+ * Reads a whole regular file without following a symbolic link at its last component and without
9
+ * blocking on a FIFO, so an agent-writable path cannot redirect or stall the read. A file larger
10
+ * than maxBytes is `too-large`. One that is not regular is refused with code EISDIR; one whose
11
+ * identity, size or times change while it is read, or whose name stops naming the opened file, with
12
+ * code EIO. Open errors such as ENOENT or ELOOP propagate.
13
+ */
14
+ export declare function readBoundedFile(path: string, maxBytes: number): BoundedRead;
@@ -0,0 +1,42 @@
1
+ import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from 'node:fs';
2
+ import { RefusalError } from './environment/contract.js';
3
+ function sameFile(left, right) {
4
+ return left.dev === right.dev && left.ino === right.ino && left.size === right.size
5
+ && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
6
+ }
7
+ /**
8
+ * Reads a whole regular file without following a symbolic link at its last component and without
9
+ * blocking on a FIFO, so an agent-writable path cannot redirect or stall the read. A file larger
10
+ * than maxBytes is `too-large`. One that is not regular is refused with code EISDIR; one whose
11
+ * identity, size or times change while it is read, or whose name stops naming the opened file, with
12
+ * code EIO. Open errors such as ENOENT or ELOOP propagate.
13
+ */
14
+ export function readBoundedFile(path, maxBytes) {
15
+ const descriptor = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
16
+ try {
17
+ const opened = fstatSync(descriptor);
18
+ if (!opened.isFile())
19
+ throw Object.assign(new RefusalError(`${path} is not a regular file`), { code: 'EISDIR' });
20
+ if (opened.size > maxBytes)
21
+ return { kind: 'too-large' };
22
+ // One byte past the observed size shows a file that grew while it was read.
23
+ const buffer = Buffer.alloc(opened.size + 1);
24
+ let length = 0;
25
+ while (length < buffer.length) {
26
+ const read = readSync(descriptor, buffer, length, buffer.length - length, null);
27
+ if (read === 0)
28
+ break;
29
+ length += read;
30
+ }
31
+ if (length > maxBytes)
32
+ return { kind: 'too-large' };
33
+ const named = lstatSync(path);
34
+ if (length !== opened.size || !sameFile(opened, fstatSync(descriptor)) || named.isSymbolicLink() || !sameFile(opened, named)) {
35
+ throw Object.assign(new RefusalError(`${path} changed while it was read`), { code: 'EIO' });
36
+ }
37
+ return { kind: 'complete', bytes: buffer.subarray(0, length) };
38
+ }
39
+ finally {
40
+ closeSync(descriptor);
41
+ }
42
+ }
@@ -0,0 +1,62 @@
1
+ import { type HolderId, type StackId } from '../environment/contract.js';
2
+ import { type StateNamespace } from '../environment/state.js';
3
+ import { type BrowserRuntimeProjection } from './runtime.js';
4
+ import { type BrowserProjectClient } from './surfaces.js';
5
+ export type BrowserCommandKind = 'drive' | 'screenshot';
6
+ export interface BrowserRouteDeclaration {
7
+ readonly name: string;
8
+ readonly path: string;
9
+ }
10
+ export interface BrowserRoutePolicy {
11
+ readonly origin: string;
12
+ readonly surfaces: readonly Readonly<{
13
+ name: string;
14
+ url: string;
15
+ }>[];
16
+ }
17
+ export interface BrowserCommandInput {
18
+ readonly runtime: BrowserRuntimeProjection;
19
+ readonly client: BrowserProjectClient;
20
+ readonly policy: BrowserRoutePolicy;
21
+ readonly kind: BrowserCommandKind;
22
+ readonly role?: string;
23
+ readonly state?: Readonly<{
24
+ namespace: StateNamespace;
25
+ stackId: StackId;
26
+ ownerId: HolderId;
27
+ }>;
28
+ }
29
+ export interface BrowserCommandSurfaceReceipt {
30
+ readonly name: string;
31
+ readonly url: string;
32
+ readonly screenshot?: Readonly<{
33
+ path: string;
34
+ sha256: string;
35
+ byteLength: number;
36
+ }>;
37
+ }
38
+ export interface BrowserCommandReceipt {
39
+ readonly kind: BrowserCommandKind;
40
+ readonly activation: 'application';
41
+ readonly authentication: Readonly<{
42
+ posture: 'bypassed' | 'none';
43
+ } | {
44
+ posture: 'real';
45
+ role: string;
46
+ policy: 'serialized' | 'per-worker';
47
+ }>;
48
+ readonly surfaces: readonly Readonly<BrowserCommandSurfaceReceipt>[];
49
+ }
50
+ export type BrowserCommandResult = Readonly<{
51
+ kind: 'complete';
52
+ receipt: BrowserCommandReceipt;
53
+ }> | Readonly<{
54
+ kind: 'refusal';
55
+ reason: string;
56
+ }>;
57
+ export declare function issueBrowserRoutePolicy(runtime: BrowserRuntimeProjection, input: Readonly<{
58
+ origin: string;
59
+ routes: readonly BrowserRouteDeclaration[];
60
+ }>): BrowserRoutePolicy;
61
+ export declare function isIssuedBrowserCommandReceipt(value: unknown): value is BrowserCommandReceipt;
62
+ export declare function executeBrowserCommand(value: BrowserCommandInput): Promise<BrowserCommandResult>;