@b00dea/cockpit 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (426) hide show
  1. package/CHANGELOG.md +474 -0
  2. package/LICENSE +21 -0
  3. package/README.md +25 -2
  4. package/bin/cockpit.mjs +33 -0
  5. package/cockpit.schema.json +2644 -0
  6. package/dist/autonomy.d.ts +45 -0
  7. package/dist/autonomy.js +173 -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 +117 -0
  11. package/dist/browser/commands.js +453 -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 +118 -0
  17. package/dist/browser/runtime.js +186 -0
  18. package/dist/browser/surfaces.d.ts +141 -0
  19. package/dist/browser/surfaces.js +561 -0
  20. package/dist/browser/ui-gate.d.ts +15 -0
  21. package/dist/browser/ui-gate.js +18 -0
  22. package/dist/canonical-json.d.ts +2 -0
  23. package/dist/canonical-json.js +5 -0
  24. package/dist/cli-guard.d.ts +5 -0
  25. package/dist/cli-guard.js +71 -0
  26. package/dist/cli-main.d.ts +176 -0
  27. package/dist/cli-main.js +1584 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.js +16 -0
  30. package/dist/command-table.d.ts +121 -0
  31. package/dist/command-table.js +664 -0
  32. package/dist/config/load.d.ts +183 -0
  33. package/dist/config/load.js +367 -0
  34. package/dist/config/sibling-toml.d.ts +48 -0
  35. package/dist/config/sibling-toml.js +160 -0
  36. package/dist/config/surface-tools-toml.d.ts +9 -0
  37. package/dist/config/surface-tools-toml.js +37 -0
  38. package/dist/config/unconfirmed-toml.d.ts +9 -0
  39. package/dist/config/unconfirmed-toml.js +29 -0
  40. package/dist/config/verified-write.d.ts +43 -0
  41. package/dist/config/verified-write.js +89 -0
  42. package/dist/diagnostics.d.ts +26 -0
  43. package/dist/diagnostics.js +344 -0
  44. package/dist/docs/check.d.ts +16 -0
  45. package/dist/docs/check.js +197 -0
  46. package/dist/docs/decision-record.d.ts +34 -0
  47. package/dist/docs/decision-record.js +135 -0
  48. package/dist/docs/decisions.d.ts +16 -0
  49. package/dist/docs/decisions.js +103 -0
  50. package/dist/docs/markdown.d.ts +36 -0
  51. package/dist/docs/markdown.js +88 -0
  52. package/dist/docs/references.d.ts +32 -0
  53. package/dist/docs/references.js +148 -0
  54. package/dist/emit.d.ts +22 -0
  55. package/dist/emit.js +43 -0
  56. package/dist/entrypoint-kinds.d.ts +3 -0
  57. package/dist/entrypoint-kinds.js +11 -0
  58. package/dist/environment/application/confirm.d.ts +35 -0
  59. package/dist/environment/application/confirm.js +122 -0
  60. package/dist/environment/application/destructive.d.ts +6 -0
  61. package/dist/environment/application/destructive.js +429 -0
  62. package/dist/environment/application/doctor.d.ts +94 -0
  63. package/dist/environment/application/doctor.js +247 -0
  64. package/dist/environment/application/guard.d.ts +49 -0
  65. package/dist/environment/application/guard.js +677 -0
  66. package/dist/environment/application/health.d.ts +143 -0
  67. package/dist/environment/application/health.js +385 -0
  68. package/dist/environment/application/lifecycle-context.d.ts +235 -0
  69. package/dist/environment/application/lifecycle-context.js +154 -0
  70. package/dist/environment/application/lifecycle-state.d.ts +25 -0
  71. package/dist/environment/application/lifecycle-state.js +202 -0
  72. package/dist/environment/application/lifecycle.d.ts +18 -0
  73. package/dist/environment/application/lifecycle.js +737 -0
  74. package/dist/environment/application/logs.d.ts +45 -0
  75. package/dist/environment/application/logs.js +127 -0
  76. package/dist/environment/application/services.d.ts +60 -0
  77. package/dist/environment/application/services.js +89 -0
  78. package/dist/environment/application/setup.d.ts +129 -0
  79. package/dist/environment/application/setup.js +741 -0
  80. package/dist/environment/application/shared.d.ts +11 -0
  81. package/dist/environment/application/shared.js +61 -0
  82. package/dist/environment/application/siblings.d.ts +43 -0
  83. package/dist/environment/application/siblings.js +269 -0
  84. package/dist/environment/claims.d.ts +389 -0
  85. package/dist/environment/claims.js +1701 -0
  86. package/dist/environment/codex-hook-trust.d.ts +11 -0
  87. package/dist/environment/codex-hook-trust.js +185 -0
  88. package/dist/environment/compose-environment.d.ts +1 -0
  89. package/dist/environment/compose-environment.js +6 -0
  90. package/dist/environment/compose-ownership.d.ts +21 -0
  91. package/dist/environment/compose-ownership.js +117 -0
  92. package/dist/environment/compose-topology.d.ts +125 -0
  93. package/dist/environment/compose-topology.js +490 -0
  94. package/dist/environment/contract.d.ts +522 -0
  95. package/dist/environment/contract.js +794 -0
  96. package/dist/environment/declaration.d.ts +14 -0
  97. package/dist/environment/declaration.js +39 -0
  98. package/dist/environment/destructive-composition.d.ts +29 -0
  99. package/dist/environment/destructive-composition.js +333 -0
  100. package/dist/environment/docker-daemon.d.ts +30 -0
  101. package/dist/environment/docker-daemon.js +78 -0
  102. package/dist/environment/docker-endpoint.d.ts +10 -0
  103. package/dist/environment/docker-endpoint.js +19 -0
  104. package/dist/environment/env-schema-observation.d.ts +46 -0
  105. package/dist/environment/env-schema-observation.js +241 -0
  106. package/dist/environment/evidence.d.ts +136 -0
  107. package/dist/environment/evidence.js +437 -0
  108. package/dist/environment/executable.d.ts +38 -0
  109. package/dist/environment/executable.js +190 -0
  110. package/dist/environment/generated-application/authorities.d.ts +5 -0
  111. package/dist/environment/generated-application/authorities.js +61 -0
  112. package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
  113. package/dist/environment/generated-application/bootstrap-skill.js +328 -0
  114. package/dist/environment/generated-application/check.d.ts +13 -0
  115. package/dist/environment/generated-application/check.js +191 -0
  116. package/dist/environment/generated-application/custom-surface.d.ts +26 -0
  117. package/dist/environment/generated-application/custom-surface.js +289 -0
  118. package/dist/environment/generated-application/prepare.d.ts +29 -0
  119. package/dist/environment/generated-application/prepare.js +278 -0
  120. package/dist/environment/generated-application/publication.d.ts +33 -0
  121. package/dist/environment/generated-application/publication.js +547 -0
  122. package/dist/environment/generated-application/shared.d.ts +492 -0
  123. package/dist/environment/generated-application/shared.js +354 -0
  124. package/dist/environment/generated-application/surface-observation.d.ts +4 -0
  125. package/dist/environment/generated-application/surface-observation.js +69 -0
  126. package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
  127. package/dist/environment/generated-application/surface-outputs.js +400 -0
  128. package/dist/environment/generated-application/surfaces.d.ts +3 -0
  129. package/dist/environment/generated-application/surfaces.js +704 -0
  130. package/dist/environment/generated-application/sync.d.ts +6 -0
  131. package/dist/environment/generated-application/sync.js +124 -0
  132. package/dist/environment/git-observation.d.ts +202 -0
  133. package/dist/environment/git-observation.js +553 -0
  134. package/dist/environment/health-composition.d.ts +12 -0
  135. package/dist/environment/health-composition.js +645 -0
  136. package/dist/environment/host-observation.d.ts +56 -0
  137. package/dist/environment/host-observation.js +52 -0
  138. package/dist/environment/identity.d.ts +48 -0
  139. package/dist/environment/identity.js +85 -0
  140. package/dist/environment/init-application.d.ts +333 -0
  141. package/dist/environment/init-application.js +726 -0
  142. package/dist/environment/install-policy-observation.d.ts +71 -0
  143. package/dist/environment/install-policy-observation.js +284 -0
  144. package/dist/environment/install-policy.d.ts +48 -0
  145. package/dist/environment/install-policy.js +96 -0
  146. package/dist/environment/instance.d.ts +33 -0
  147. package/dist/environment/instance.js +122 -0
  148. package/dist/environment/instruction-pointer.d.ts +19 -0
  149. package/dist/environment/instruction-pointer.js +144 -0
  150. package/dist/environment/lifecycle-composition.d.ts +31 -0
  151. package/dist/environment/lifecycle-composition.js +742 -0
  152. package/dist/environment/lifecycle-stage.d.ts +120 -0
  153. package/dist/environment/lifecycle-stage.js +408 -0
  154. package/dist/environment/lifecycle.d.ts +75 -0
  155. package/dist/environment/lifecycle.js +354 -0
  156. package/dist/environment/logs.d.ts +132 -0
  157. package/dist/environment/logs.js +519 -0
  158. package/dist/environment/map-limit.d.ts +2 -0
  159. package/dist/environment/map-limit.js +13 -0
  160. package/dist/environment/mcp-observation.d.ts +9 -0
  161. package/dist/environment/mcp-observation.js +46 -0
  162. package/dist/environment/observations.d.ts +46 -0
  163. package/dist/environment/observations.js +346 -0
  164. package/dist/environment/operator-application.d.ts +79 -0
  165. package/dist/environment/operator-application.js +197 -0
  166. package/dist/environment/ports.d.ts +182 -0
  167. package/dist/environment/ports.js +1205 -0
  168. package/dist/environment/posture-observation.d.ts +68 -0
  169. package/dist/environment/posture-observation.js +253 -0
  170. package/dist/environment/presence.d.ts +4 -0
  171. package/dist/environment/presence.js +26 -0
  172. package/dist/environment/read-composition.d.ts +32 -0
  173. package/dist/environment/read-composition.js +397 -0
  174. package/dist/environment/readiness-composition.d.ts +57 -0
  175. package/dist/environment/readiness-composition.js +151 -0
  176. package/dist/environment/reclaim.d.ts +370 -0
  177. package/dist/environment/reclaim.js +1940 -0
  178. package/dist/environment/repository-identity.d.ts +13 -0
  179. package/dist/environment/repository-identity.js +108 -0
  180. package/dist/environment/runtime-measurement-record.d.ts +38 -0
  181. package/dist/environment/runtime-measurement-record.js +111 -0
  182. package/dist/environment/runtime-measurement.d.ts +27 -0
  183. package/dist/environment/runtime-measurement.js +224 -0
  184. package/dist/environment/runtime-probe-residue.d.ts +43 -0
  185. package/dist/environment/runtime-probe-residue.js +148 -0
  186. package/dist/environment/runtime-probe.d.ts +72 -0
  187. package/dist/environment/runtime-probe.js +725 -0
  188. package/dist/environment/runtime.d.ts +551 -0
  189. package/dist/environment/runtime.js +2405 -0
  190. package/dist/environment/seed.d.ts +16 -0
  191. package/dist/environment/seed.js +43 -0
  192. package/dist/environment/selftest-application.d.ts +86 -0
  193. package/dist/environment/selftest-application.js +713 -0
  194. package/dist/environment/sensitive.d.ts +3 -0
  195. package/dist/environment/sensitive.js +48 -0
  196. package/dist/environment/served-checkout-grants.d.ts +53 -0
  197. package/dist/environment/served-checkout-grants.js +182 -0
  198. package/dist/environment/setup-observation.d.ts +62 -0
  199. package/dist/environment/setup-observation.js +1473 -0
  200. package/dist/environment/setup.d.ts +43 -0
  201. package/dist/environment/setup.js +176 -0
  202. package/dist/environment/sibling-checkouts.d.ts +119 -0
  203. package/dist/environment/sibling-checkouts.js +254 -0
  204. package/dist/environment/sibling-instructions.d.ts +33 -0
  205. package/dist/environment/sibling-instructions.js +224 -0
  206. package/dist/environment/sibling-observation.d.ts +27 -0
  207. package/dist/environment/sibling-observation.js +45 -0
  208. package/dist/environment/sibling-pull.d.ts +23 -0
  209. package/dist/environment/sibling-pull.js +95 -0
  210. package/dist/environment/sibling-registration.d.ts +45 -0
  211. package/dist/environment/sibling-registration.js +538 -0
  212. package/dist/environment/stack-inputs.d.ts +18 -0
  213. package/dist/environment/stack-inputs.js +210 -0
  214. package/dist/environment/stack-inventory-prune.d.ts +31 -0
  215. package/dist/environment/stack-inventory-prune.js +129 -0
  216. package/dist/environment/stack-inventory-report.d.ts +44 -0
  217. package/dist/environment/stack-inventory-report.js +78 -0
  218. package/dist/environment/stack-inventory.d.ts +94 -0
  219. package/dist/environment/stack-inventory.js +418 -0
  220. package/dist/environment/state.d.ts +410 -0
  221. package/dist/environment/state.js +2153 -0
  222. package/dist/environment/templates.d.ts +140 -0
  223. package/dist/environment/templates.js +685 -0
  224. package/dist/environment/tool-registration.d.ts +9 -0
  225. package/dist/environment/tool-registration.js +92 -0
  226. package/dist/environment/upgrade-application.d.ts +19 -0
  227. package/dist/environment/upgrade-application.js +175 -0
  228. package/dist/environment-exec/execute.d.ts +105 -0
  229. package/dist/environment-exec/execute.js +1179 -0
  230. package/dist/environment-exec/libexec-program.d.ts +6 -0
  231. package/dist/environment-exec/libexec-program.js +22 -0
  232. package/dist/environment-exec/verified-digest.d.ts +4 -0
  233. package/dist/environment-exec/verified-digest.js +16 -0
  234. package/dist/exact-keys.d.ts +7 -0
  235. package/dist/exact-keys.js +15 -0
  236. package/dist/fix-catalogue.d.ts +32 -0
  237. package/dist/fix-catalogue.js +60 -0
  238. package/dist/freshness.d.ts +29 -0
  239. package/dist/freshness.js +75 -0
  240. package/dist/generated-environment/adopt.d.ts +16 -0
  241. package/dist/generated-environment/adopt.js +271 -0
  242. package/dist/generated-environment/command.d.ts +47 -0
  243. package/dist/generated-environment/command.js +75 -0
  244. package/dist/generated-environment/transaction.d.ts +186 -0
  245. package/dist/generated-environment/transaction.js +1770 -0
  246. package/dist/grading/evaluate.d.ts +71 -0
  247. package/dist/grading/evaluate.js +403 -0
  248. package/dist/grading/grade.d.ts +33 -0
  249. package/dist/grading/grade.js +57 -0
  250. package/dist/guards/answer-confirmation.d.ts +41 -0
  251. package/dist/guards/answer-confirmation.js +109 -0
  252. package/dist/guards/evaluator.d.ts +130 -0
  253. package/dist/guards/evaluator.js +1258 -0
  254. package/dist/guards/harness-adapter.d.ts +17 -0
  255. package/dist/guards/harness-adapter.js +57 -0
  256. package/dist/guards/host.d.ts +8 -0
  257. package/dist/guards/host.js +10 -0
  258. package/dist/guards/invocation-parser.d.ts +66 -0
  259. package/dist/guards/invocation-parser.js +595 -0
  260. package/dist/guards/local-identity.d.ts +44 -0
  261. package/dist/guards/local-identity.js +129 -0
  262. package/dist/guards/policy-change.d.ts +43 -0
  263. package/dist/guards/policy-change.js +159 -0
  264. package/dist/guards/policy-pin.d.ts +13 -0
  265. package/dist/guards/policy-pin.js +177 -0
  266. package/dist/guards/protected-locations.d.ts +62 -0
  267. package/dist/guards/protected-locations.js +461 -0
  268. package/dist/guards/read-only.d.ts +37 -0
  269. package/dist/guards/read-only.js +315 -0
  270. package/dist/init/command.d.ts +41 -0
  271. package/dist/init/command.js +330 -0
  272. package/dist/init/derive.d.ts +53 -0
  273. package/dist/init/derive.js +819 -0
  274. package/dist/init/draft.d.ts +140 -0
  275. package/dist/init/draft.js +1228 -0
  276. package/dist/init/render.d.ts +47 -0
  277. package/dist/init/render.js +104 -0
  278. package/dist/init/scaffold.d.ts +53 -0
  279. package/dist/init/scaffold.js +121 -0
  280. package/dist/invocation.d.ts +13 -0
  281. package/dist/invocation.js +20 -0
  282. package/dist/package-metadata.d.ts +9 -0
  283. package/dist/package-metadata.js +19 -0
  284. package/dist/readiness.d.ts +53 -0
  285. package/dist/readiness.js +88 -0
  286. package/dist/references/named.d.ts +24 -0
  287. package/dist/references/named.js +27 -0
  288. package/dist/refusal.d.ts +15 -0
  289. package/dist/refusal.js +7 -0
  290. package/dist/registry-derivation.d.ts +31 -0
  291. package/dist/registry-derivation.js +32 -0
  292. package/dist/registry-resolve/command.d.ts +47 -0
  293. package/dist/registry-resolve/command.js +226 -0
  294. package/dist/registry-resolve/registry.d.ts +68 -0
  295. package/dist/registry-resolve/registry.js +292 -0
  296. package/dist/registry-resolve/render-shell.d.ts +18 -0
  297. package/dist/registry-resolve/render-shell.js +36 -0
  298. package/dist/repair.d.ts +29 -0
  299. package/dist/repair.js +8 -0
  300. package/dist/repository-path.d.ts +9 -0
  301. package/dist/repository-path.js +16 -0
  302. package/dist/schema-json.d.ts +1 -0
  303. package/dist/schema-json.js +177 -0
  304. package/dist/schema.d.ts +1289 -0
  305. package/dist/schema.js +985 -0
  306. package/dist/setup/command.d.ts +4 -0
  307. package/dist/setup/command.js +4 -0
  308. package/dist/sha256.d.ts +1 -0
  309. package/dist/sha256.js +4 -0
  310. package/dist/surfaces/adoption.d.ts +41 -0
  311. package/dist/surfaces/adoption.js +217 -0
  312. package/dist/surfaces/consumer-instructions.d.ts +20 -0
  313. package/dist/surfaces/consumer-instructions.js +43 -0
  314. package/dist/surfaces/contract.d.ts +42 -0
  315. package/dist/surfaces/contract.js +169 -0
  316. package/dist/surfaces/core-declarations.d.ts +24 -0
  317. package/dist/surfaces/core-declarations.js +79 -0
  318. package/dist/surfaces/development-markers.d.ts +1 -0
  319. package/dist/surfaces/development-markers.js +18 -0
  320. package/dist/surfaces/generator-adapter.d.ts +71 -0
  321. package/dist/surfaces/generator-adapter.js +809 -0
  322. package/dist/surfaces/harness-registry.d.ts +260 -0
  323. package/dist/surfaces/harness-registry.js +146 -0
  324. package/dist/surfaces/mcp.d.ts +145 -0
  325. package/dist/surfaces/mcp.js +349 -0
  326. package/dist/surfaces/merge.d.ts +30 -0
  327. package/dist/surfaces/merge.js +105 -0
  328. package/dist/surfaces/ownership.d.ts +190 -0
  329. package/dist/surfaces/ownership.js +795 -0
  330. package/dist/surfaces/projection.d.ts +136 -0
  331. package/dist/surfaces/projection.js +716 -0
  332. package/dist/surfaces/render.d.ts +79 -0
  333. package/dist/surfaces/render.js +636 -0
  334. package/dist/surfaces/restrictions.d.ts +130 -0
  335. package/dist/surfaces/restrictions.js +447 -0
  336. package/dist/surfaces/selftest.d.ts +162 -0
  337. package/dist/surfaces/selftest.js +393 -0
  338. package/dist/surfaces/skill-contract.d.ts +85 -0
  339. package/dist/surfaces/skill-contract.js +449 -0
  340. package/dist/surfaces/sync.d.ts +57 -0
  341. package/dist/surfaces/sync.js +164 -0
  342. package/dist/team-metadata.d.ts +41 -0
  343. package/dist/team-metadata.js +513 -0
  344. package/dist/testing/gates.d.ts +91 -0
  345. package/dist/testing/gates.js +182 -0
  346. package/dist/testing/hooks.d.ts +59 -0
  347. package/dist/testing/hooks.js +139 -0
  348. package/dist/testing/test-protection.d.ts +34 -0
  349. package/dist/testing/test-protection.js +137 -0
  350. package/dist/testing/verdict.d.ts +29 -0
  351. package/dist/testing/verdict.js +62 -0
  352. package/dist/testing/weakening.d.ts +15 -0
  353. package/dist/testing/weakening.js +30 -0
  354. package/dist/work-orders/application-closure.d.ts +7 -0
  355. package/dist/work-orders/application-closure.js +76 -0
  356. package/dist/work-orders/application-context.d.ts +162 -0
  357. package/dist/work-orders/application-context.js +137 -0
  358. package/dist/work-orders/application-decisions.d.ts +27 -0
  359. package/dist/work-orders/application-decisions.js +121 -0
  360. package/dist/work-orders/application-grading.d.ts +11 -0
  361. package/dist/work-orders/application-grading.js +212 -0
  362. package/dist/work-orders/application.d.ts +6 -0
  363. package/dist/work-orders/application.js +223 -0
  364. package/dist/work-orders/composition.d.ts +101 -0
  365. package/dist/work-orders/composition.js +1202 -0
  366. package/dist/work-orders/contract.d.ts +77 -0
  367. package/dist/work-orders/contract.js +140 -0
  368. package/dist/work-orders/decisions.d.ts +23 -0
  369. package/dist/work-orders/decisions.js +55 -0
  370. package/dist/work-orders/store.d.ts +207 -0
  371. package/dist/work-orders/store.js +291 -0
  372. package/docs/README.md +68 -0
  373. package/docs/architecture.md +136 -0
  374. package/docs/capability-matrix.md +58 -0
  375. package/docs/cli-reference.md +807 -0
  376. package/docs/command-list.md +62 -0
  377. package/docs/compose-patterns.md +99 -0
  378. package/docs/concepts.md +173 -0
  379. package/docs/configuration-essentials.md +177 -0
  380. package/docs/configuration-reference.md +636 -0
  381. package/docs/docs-check.md +76 -0
  382. package/docs/environment.md +948 -0
  383. package/docs/extending.md +43 -0
  384. package/docs/faq.md +113 -0
  385. package/docs/getting-started.md +692 -0
  386. package/docs/harness-surfaces.md +500 -0
  387. package/docs/joining-a-team.md +76 -0
  388. package/docs/release-policy.md +49 -0
  389. package/docs/safety-and-autonomy.md +463 -0
  390. package/docs/troubleshooting.md +382 -0
  391. package/docs/tutorial.md +171 -0
  392. package/docs/work-and-browser.md +420 -0
  393. package/libexec/browser-operation.cjs +270 -0
  394. package/libexec/fence-marker.cjs +101 -0
  395. package/libexec/fence-marker.d.cts +24 -0
  396. package/libexec/fenced-group-runner.cjs +77 -0
  397. package/libexec/fenced-supervisor.cjs +137 -0
  398. package/libexec/generated-filesystem.cjs +731 -0
  399. package/libexec/install-filesystem.cjs +225 -0
  400. package/libexec/rulesync-generator.NOTICE.md +1112 -0
  401. package/libexec/rulesync-generator.cjs +743 -0
  402. package/libexec/surface-generator-worker.cjs +266 -0
  403. package/libexec/surface-output-reader.cjs +99 -0
  404. package/libexec/surface-scratch-cleanup.cjs +14 -0
  405. package/libexec/validate-harness-evidence.d.mts +183 -0
  406. package/libexec/validate-harness-evidence.mjs +1312 -0
  407. package/package.json +74 -4
  408. package/surfaces/README.md +33 -0
  409. package/surfaces/agents/evaluator.agent.md +76 -0
  410. package/surfaces/guards/bash-guard.sh +48 -0
  411. package/surfaces/guards/claude.adapter.json +25 -0
  412. package/surfaces/guards/codex.adapter.json +24 -0
  413. package/surfaces/guards/opencode.adapter.json +25 -0
  414. package/surfaces/references/browser.md +63 -0
  415. package/surfaces/references/test-data-and-personas.md +84 -0
  416. package/surfaces/references/testing-tiers.md +11 -0
  417. package/surfaces/skills/cockpit-browser.skill.md +59 -0
  418. package/surfaces/skills/cockpit-explain.skill.md +32 -0
  419. package/surfaces/skills/cockpit-fix.skill.md +37 -0
  420. package/surfaces/skills/cockpit-setup.skill.md +39 -0
  421. package/surfaces/skills/cockpit-work.skill.md +34 -0
  422. package/surfaces/skills/collection.json +5 -0
  423. package/surfaces/skills/procedures/explain.md +66 -0
  424. package/surfaces/skills/procedures/fix.md +95 -0
  425. package/surfaces/skills/procedures/setup.md +452 -0
  426. package/surfaces/skills/procedures/work.md +134 -0
@@ -0,0 +1,449 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { parseDocument, visit } from 'yaml';
3
+ import { commandSpelling, commands } from '../command-table.js';
4
+ import { stripDevelopmentMarkers } from './development-markers.js';
5
+ import { snapshotGeneratedJson, snapshotJson } from '../environment/contract.js';
6
+ import { RULESYNC_VERSION, generateSurfaceBatch, } from './generator-adapter.js';
7
+ import { SURFACE_TARGETS, SURFACE_OUTPUT_MAX_FILES, bundleSurfaceFiles, surfaceSourcesMatchFeature, } from './contract.js';
8
+ import { GUARD_SURFACE_TARGETS, harnessFact } from './harness-registry.js';
9
+ import { exactKeys } from '../exact-keys.js';
10
+ /** The skill `cockpit init` installs first; init and the reference renderer both address it by this name. */
11
+ export const SHIPPED_SETUP_SKILL = 'cockpit-setup';
12
+ const inspectedSkillResults = new WeakMap();
13
+ const inspectedBootstrapOutputs = new WeakSet();
14
+ export function isInspectedBootstrapOutputs(value) {
15
+ return typeof value === 'object' && value !== null && inspectedBootstrapOutputs.has(value);
16
+ }
17
+ const DESCRIPTION_MAX_BYTES = 512;
18
+ const ENTRY_POINT_MAX_LINES = 32;
19
+ const INSTALLED_SET_CAP_MAX_BYTES = 65_536;
20
+ const NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
21
+ const COMMAND = /`cockpit\s+([a-z][a-z-]*)(?:\s+([a-z][a-z-]*))?/g;
22
+ const INLINE_NUMBERED_STEP = /^\s*\d+[.)]\s+/m;
23
+ const INLINE_FENCE = /^\s*```/m;
24
+ const COPIED_DECISION_LOGIC = /(?:\bparse\w*\s+(?:the\s+)?(?:registry|cockpit\.toml)|\bTOML\.parse\b|^\s*\[[a-z][a-z0-9_.-]*\]\s*$|\|\s*(?:tier|mount|data mode|verdict)\s*\|)/im;
25
+ const MISLEADING_COMPLETION = /\b(?:report|declare|claim)\w*\s+(?:the\s+)?(?:work\s+)?(?:complete|successful|green)\s+without\b/i;
26
+ const ALLOWED_COMMANDS = new Set(commands.map(command => command.name));
27
+ const TARGET_PATH_PREFIX = Object.freeze(Object.fromEntries(SURFACE_TARGETS.map(target => [target, harnessFact(target).outputs.skills])));
28
+ function object(value) {
29
+ return value !== undefined && value !== null && typeof value === 'object' && !Array.isArray(value);
30
+ }
31
+ function strings(value) {
32
+ return Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'string' && item.length > 0)
33
+ && new Set(value).size === value.length ? value : undefined;
34
+ }
35
+ function refusal(code, message, target) {
36
+ return {
37
+ kind: 'refusal',
38
+ status: 2,
39
+ diagnostics: [{ severity: 'error', code, message, ...(target ? { target } : {}) }],
40
+ files: [],
41
+ };
42
+ }
43
+ const PROCEDURE_ASSET = /^skills\/procedures\/[a-z0-9][a-z0-9-]*\.md$/;
44
+ function authenticatedAsset(value, path) {
45
+ return object(value) && exactKeys(value, ['path', 'bytes', 'sha256']) && typeof value.path === 'string'
46
+ && (typeof path === 'string' ? value.path === path : path.test(value.path))
47
+ && typeof value.bytes === 'string' && Buffer.byteLength(value.bytes) <= 65_536
48
+ && typeof value.sha256 === 'string' && createHash('sha256').update(value.bytes).digest('hex') === value.sha256;
49
+ }
50
+ function captureInput(input) {
51
+ const captured = snapshotJson(input);
52
+ if (!object(captured) || !exactKeys(captured, ['sources', 'collection', 'procedures', 'tools',
53
+ ...(Object.hasOwn(captured, 'declaredExtensions') ? ['declaredExtensions'] : [])]) || !Array.isArray(captured.sources)
54
+ || !Array.isArray(captured.tools) || captured.tools.length === 0 || new Set(captured.tools).size !== captured.tools.length
55
+ || !captured.tools.every(tool => SURFACE_TARGETS.includes(tool))
56
+ || !authenticatedAsset(captured.collection, 'skills/collection.json')
57
+ || !Array.isArray(captured.procedures) || captured.procedures.length === 0 || captured.procedures.length > 16
58
+ || !captured.procedures.every(procedure => authenticatedAsset(procedure, PROCEDURE_ASSET))
59
+ || new Set(captured.procedures.map(procedure => procedure.path)).size !== captured.procedures.length)
60
+ return undefined;
61
+ let authority;
62
+ try {
63
+ authority = snapshotJson(JSON.parse(captured.collection.bytes));
64
+ const json = parseDocument(captured.collection.bytes, { uniqueKeys: true });
65
+ if (json.errors.length > 0 || json.warnings.length > 0)
66
+ return undefined;
67
+ }
68
+ catch { /* unparseable input is malformed; the caller refuses it. */
69
+ return undefined;
70
+ }
71
+ if (!object(authority) || !exactKeys(authority, ['skills', 'metric', 'caps'])
72
+ || !Array.isArray(authority.skills) || !sameStrings(authority.skills, ['cockpit-setup', 'cockpit-explain', 'cockpit-fix', 'cockpit-work']) || authority.metric !== 'frontmatter_bytes'
73
+ || !object(authority.caps) || !exactKeys(authority.caps, SURFACE_TARGETS))
74
+ return undefined;
75
+ const caps = authority.caps;
76
+ const shippedSkills = authority.skills;
77
+ if (SURFACE_TARGETS.some(target => !Number.isSafeInteger(caps[target]) || Number(caps[target]) < 1
78
+ || Number(caps[target]) > INSTALLED_SET_CAP_MAX_BYTES))
79
+ return undefined;
80
+ const declaredExtensions = Object.hasOwn(captured, 'declaredExtensions') ? captured.declaredExtensions : [];
81
+ if (!Array.isArray(declaredExtensions) || declaredExtensions.length > SURFACE_OUTPUT_MAX_FILES
82
+ || declaredExtensions.some((name, index) => typeof name !== 'string' || name.length > 128 || !NAME.test(name)
83
+ || shippedSkills.includes(name) || index > 0 && String(declaredExtensions[index - 1]) >= name))
84
+ return undefined;
85
+ if (!surfaceSourcesMatchFeature(captured.sources, 'skills'))
86
+ return undefined;
87
+ if (!captured.procedures.every(procedure => pulledProcedure(procedure.bytes)))
88
+ return undefined;
89
+ return { ...captured, declaredExtensions, authority };
90
+ }
91
+ /** A procedure is read on demand and uncapped, and says something. */
92
+ function pulledProcedure(bytes) {
93
+ const parsed = parseEntryPoint(bytes);
94
+ return !!parsed && exactKeys(parsed.frontmatter, ['loading', 'budget']) && parsed.frontmatter.loading === 'pull'
95
+ && parsed.frontmatter.budget === 'uncapped' && parsed.body.length > 0;
96
+ }
97
+ function captureRenderedInput(input) {
98
+ // Rendered output carries every target's copy of each procedure, so it outgrows the generic
99
+ // JSON limit with one extra skill; bundleSurfaceFiles below enforces the real output cap.
100
+ const captured = snapshotGeneratedJson(input);
101
+ if (!object(captured) || !exactKeys(captured, ['sources', 'collection', 'procedures', 'generated', 'targets',
102
+ ...(Object.hasOwn(captured, 'declaredExtensions') ? ['declaredExtensions'] : [])]))
103
+ return undefined;
104
+ const targets = Array.isArray(captured.targets) && captured.targets.length > 0
105
+ && captured.targets.every(target => SURFACE_TARGETS.includes(target))
106
+ && new Set(captured.targets).size === captured.targets.length
107
+ ? SURFACE_TARGETS.filter(target => captured.targets.includes(target)) : undefined;
108
+ if (!targets)
109
+ return undefined;
110
+ const base = captureInput({ sources: captured.sources, tools: targets, collection: captured.collection, procedures: captured.procedures,
111
+ ...(Object.hasOwn(captured, 'declaredExtensions') ? { declaredExtensions: captured.declaredExtensions } : {}) });
112
+ const generated = captured.generated;
113
+ if (!base || !object(generated) || !exactKeys(generated, ['kind', 'status', 'diagnostics', 'mechanism', 'files', 'warnings'])
114
+ || generated.kind !== 'complete' || generated.status !== 0 || !Array.isArray(generated.diagnostics) || generated.diagnostics.length !== 0
115
+ || !object(generated.mechanism) || !exactKeys(generated.mechanism, ['package', 'version', 'role'])
116
+ || generated.mechanism.package !== 'rulesync' || generated.mechanism.version !== RULESYNC_VERSION || generated.mechanism.role !== 'spelling'
117
+ || !Array.isArray(generated.files) || !Array.isArray(generated.warnings)
118
+ || !generated.warnings.every((warning) => object(warning)
119
+ && exactKeys(warning, ['severity', 'code', 'target', 'path', 'message']) && warning.severity === 'warning'
120
+ && warning.code === 'SURFACE_GENERATOR_TRUST_WARNING' && SURFACE_TARGETS.includes(warning.target)
121
+ && warning.path === '.claude/settings.json' && typeof warning.message === 'string' && warning.message.length > 0)
122
+ || !bundleSurfaceFiles(generated.files))
123
+ return undefined;
124
+ return { ...base, generated, targets };
125
+ }
126
+ function parseEntryPoint(bytes) {
127
+ if (!bytes.startsWith('---\n'))
128
+ return undefined;
129
+ const end = bytes.indexOf('\n---\n', 4);
130
+ if (end < 0)
131
+ return undefined;
132
+ const rawFrontmatter = bytes.slice(4, end);
133
+ const document = parseDocument(rawFrontmatter, { uniqueKeys: true });
134
+ if (document.errors.length > 0 || document.warnings.length > 0)
135
+ return undefined;
136
+ let hasAlias = false;
137
+ visit(document, { Alias: () => { hasAlias = true; return visit.BREAK; } });
138
+ if (hasAlias)
139
+ return undefined;
140
+ const frontmatter = snapshotJson(document.toJS({ maxAliasCount: 0 }));
141
+ if (!object(frontmatter))
142
+ return undefined;
143
+ return { frontmatter, body: bytes.slice(end + 5).trim(), rawFrontmatter };
144
+ }
145
+ function targetEquivalences(value) {
146
+ if (!object(value) || !exactKeys(value, GUARD_SURFACE_TARGETS))
147
+ return undefined;
148
+ const claudecode = strings(value.claudecode);
149
+ const codexcli = strings(value.codexcli);
150
+ const opencode = strings(value.opencode);
151
+ if (!claudecode || !codexcli || !opencode)
152
+ return undefined;
153
+ return { claudecode, codexcli, opencode };
154
+ }
155
+ function sameStrings(value, expected) {
156
+ return Array.isArray(value) && value.length === expected.length
157
+ && value.every((item, index) => item === expected[index]);
158
+ }
159
+ function targetToolsMatch(frontmatter, equivalences) {
160
+ const claude = frontmatter.claudecode;
161
+ const opencode = frontmatter.opencode;
162
+ const codex = frontmatter.codexcli;
163
+ if (!object(claude) || !exactKeys(claude, ['allowed-tools']) || !sameStrings(claude['allowed-tools'], equivalences.claudecode)
164
+ || !object(opencode) || !exactKeys(opencode, ['allowed-tools']) || !sameStrings(opencode['allowed-tools'], equivalences.opencode)
165
+ || !object(codex) || !exactKeys(codex, ['dependencies']))
166
+ return false;
167
+ const dependencies = codex.dependencies;
168
+ if (!object(dependencies) || !exactKeys(dependencies, ['tools']) || !Array.isArray(dependencies.tools)
169
+ || dependencies.tools.length !== 1 || !object(dependencies.tools[0]))
170
+ return false;
171
+ const executable = dependencies.tools[0];
172
+ return exactKeys(executable, ['type', 'value', 'description']) && executable.type === 'executable'
173
+ && executable.value === 'cockpit' && typeof executable.description === 'string' && executable.description.length > 0;
174
+ }
175
+ function declaration(source, renderedTools) {
176
+ const parsed = parseEntryPoint(source.bytes);
177
+ if (!parsed)
178
+ return refusal('SKILL_FRONTMATTER_INVALID', 'skill frontmatter is missing, malformed, aliased, duplicated, or unbounded', source.path);
179
+ const { frontmatter, body } = parsed;
180
+ if (!exactKeys(frontmatter, ['name', 'description', 'targets', 'cockpit', 'claudecode', 'codexcli', 'opencode'])) {
181
+ return refusal('SKILL_FRONTMATTER_INVALID', 'skill frontmatter contains an unexpected or missing field', source.path);
182
+ }
183
+ const contract = frontmatter.cockpit;
184
+ if (!object(contract) || !exactKeys(contract, [
185
+ 'commands', 'changes', 'entry-point-lines', 'non-goals', 'procedure', 'review', 'tool-equivalences', 'tools',
186
+ ]))
187
+ return refusal('SKILL_CONTRACT_INVALID', 'cockpit skill metadata is incomplete', source.path);
188
+ if (typeof frontmatter.name !== 'string' || !NAME.test(frontmatter.name)
189
+ || typeof frontmatter.description !== 'string' || !frontmatter.description.startsWith('Use when ')
190
+ || Buffer.byteLength(frontmatter.description) > DESCRIPTION_MAX_BYTES
191
+ || !Array.isArray(frontmatter.targets) || frontmatter.targets.length !== 1 || frontmatter.targets[0] !== '*') {
192
+ return refusal('SKILL_IDENTITY_INVALID', 'skill name, trigger description, or targets are invalid', source.path);
193
+ }
194
+ const tools = strings(contract.tools);
195
+ const declaredCommands = strings(contract.commands);
196
+ const changes = strings(contract.changes);
197
+ const nonGoals = strings(contract['non-goals']);
198
+ const equivalences = targetEquivalences(contract['tool-equivalences']);
199
+ const review = contract.review;
200
+ const entryPointLines = contract['entry-point-lines'];
201
+ if (!tools || !declaredCommands || !changes || !nonGoals || !equivalences || typeof contract.procedure !== 'string'
202
+ || !/^procedures\/[a-z0-9][a-z0-9-]*\.md$/.test(contract.procedure)
203
+ || !Number.isSafeInteger(entryPointLines) || Number(entryPointLines) < 1 || Number(entryPointLines) > ENTRY_POINT_MAX_LINES
204
+ || !object(review) || !exactKeys(review, ['mechanical', 'judgment'])
205
+ || typeof review.mechanical !== 'string' || review.mechanical.length === 0
206
+ || review.judgment !== 'accepted' && review.judgment !== 'pending') {
207
+ return refusal('SKILL_CONTRACT_INVALID', 'skill tools, effects, procedure, review, or line cap are invalid', source.path);
208
+ }
209
+ if (!targetToolsMatch(frontmatter, equivalences)) {
210
+ return refusal('SKILL_TOOL_EQUIVALENCE_MISSING', 'skill native tool declarations do not match its equivalence contract', source.path);
211
+ }
212
+ const actualLines = body.length === 0 ? 0 : body.split(/\r?\n/).length;
213
+ if (actualLines === 0 || actualLines > Number(entryPointLines) || INLINE_NUMBERED_STEP.test(body) || INLINE_FENCE.test(body)) {
214
+ return refusal('SKILL_ENTRY_POINT_EXCEEDED', 'skill entry point exceeds its declared line cap or embeds a procedure', source.path);
215
+ }
216
+ if (COPIED_DECISION_LOGIC.test(body) || MISLEADING_COMPLETION.test(body)) {
217
+ return refusal('SKILL_DECISION_LOGIC_EMBEDDED', 'skill entry point copies decision logic or makes an unauthenticated completion claim', source.path);
218
+ }
219
+ if (declaredCommands.some(command => !ALLOWED_COMMANDS.has(command))) {
220
+ return refusal('SKILL_COMMAND_UNDECLARED', 'skill declares a command that is not in the cockpit command table', source.path);
221
+ }
222
+ const invoked = [...body.matchAll(COMMAND)].map(match => commandSpelling(match.slice(1).filter(word => word !== undefined)).name ?? match[1]);
223
+ if (invoked.some(command => !declaredCommands.includes(command) || !ALLOWED_COMMANDS.has(command))) {
224
+ return refusal('SKILL_COMMAND_UNDECLARED', 'skill invokes an undeclared cockpit command', source.path);
225
+ }
226
+ if (body.includes('{{')) {
227
+ return refusal('SKILL_TOOL_EQUIVALENCE_MISSING', 'skill entry point still holds an unrendered placeholder', source.path);
228
+ }
229
+ // An entry point names the shell tool of the harnesses the cockpit renders for, and only those.
230
+ for (const target of GUARD_SURFACE_TARGETS.filter(guard => renderedTools.includes(guard))) {
231
+ if (!equivalences[target].every(tool => body.includes(`\`${tool}\``))) {
232
+ return refusal('SKILL_TOOL_EQUIVALENCE_MISSING', `skill entry point omits the ${target} tool equivalence`, source.path);
233
+ }
234
+ }
235
+ return { name: frontmatter.name, procedure: contract.procedure, cap: Number(entryPointLines) };
236
+ }
237
+ function expectedOutputs(skills, sources) {
238
+ const paths = Object.fromEntries(SURFACE_TARGETS.map(target => [target, []]));
239
+ for (const target of SURFACE_TARGETS)
240
+ paths[target] = sources.flatMap(source => {
241
+ const match = /^skills\/([^/]+)\/(.+)$/.exec(source.path);
242
+ if (!match || !skills.some(skill => skill.name === match[1]))
243
+ return [];
244
+ const output = [`${TARGET_PATH_PREFIX[target]}/${match[1]}/${match[2]}`];
245
+ if (target === 'codexcli' && match[2] === 'SKILL.md')
246
+ output.push(`${TARGET_PATH_PREFIX[target]}/${match[1]}/agents/openai.yaml`);
247
+ return output;
248
+ });
249
+ return paths;
250
+ }
251
+ function generatedDiagnostic(kind, status, item) {
252
+ const diagnostics = [{ severity: 'error', code: item.code,
253
+ message: item.message, ...(item.target ? { target: item.target } : {}) }];
254
+ return kind === 'refusal' && status === 2
255
+ ? { kind, status, diagnostics, files: [] }
256
+ : { kind: 'unavailable', status: 3, diagnostics, files: [] };
257
+ }
258
+ function renderedFrontmatterBytes(file) {
259
+ if (!file.path.endsWith('/SKILL.md'))
260
+ return 0;
261
+ const parsed = parseEntryPoint(file.bytes);
262
+ return parsed ? Buffer.byteLength(parsed.rawFrontmatter) : undefined;
263
+ }
264
+ function admitDeclarations(captured) {
265
+ const entrySources = captured.sources.filter(source => source.path.endsWith('/SKILL.md'));
266
+ const declarations = [];
267
+ for (const source of entrySources) {
268
+ const admitted = declaration(source, captured.tools);
269
+ if ('kind' in admitted)
270
+ return admitted;
271
+ if (declarations.some(skill => skill.name === admitted.name) || source.path !== `skills/${admitted.name}/SKILL.md`) {
272
+ return refusal('SKILL_NAME_DUPLICATE', 'skill names must be unique and match their source directory', source.path);
273
+ }
274
+ const procedurePath = `skills/${admitted.name}/${admitted.procedure}`;
275
+ const procedure = captured.sources.find(candidate => candidate.path === procedurePath);
276
+ const extension = captured.declaredExtensions.includes(admitted.name);
277
+ // A shipped skill's procedure is exactly the packaged file its entry point names.
278
+ const packaged = captured.procedures.find(candidate => candidate.path === `skills/${admitted.procedure}`);
279
+ if (!procedure || (extension ? !pulledProcedure(procedure.bytes) : procedure.bytes !== packaged?.bytes)) {
280
+ return refusal('SKILL_PROCEDURE_MISSING', 'skill procedure is missing or empty', procedurePath);
281
+ }
282
+ declarations.push(admitted);
283
+ }
284
+ if (!sameStrings(declarations.map(skill => skill.name).sort(), [...captured.authority.skills, ...captured.declaredExtensions].sort())) {
285
+ return refusal('SKILL_INPUT_INVALID', 'skill set does not match the declared collection inventory');
286
+ }
287
+ const permittedPaths = new Set(declarations.flatMap(skill => [
288
+ `skills/${skill.name}/SKILL.md`, `skills/${skill.name}/${skill.procedure}`,
289
+ ]));
290
+ if (captured.sources.length !== permittedPaths.size || captured.sources.some(source => !permittedPaths.has(source.path))) {
291
+ return refusal('SKILL_INPUT_INVALID', 'skill sources do not exactly match the declared entry points and procedures');
292
+ }
293
+ return declarations;
294
+ }
295
+ function inspectRendered(captured, declarations, files, targets) {
296
+ const expected = expectedOutputs(declarations, captured.sources);
297
+ if (files.some(file => !targets.includes(file.target) && file.path.startsWith(`${TARGET_PATH_PREFIX[file.target]}/`))) {
298
+ return refusal('SKILL_RENDER_INVENTORY_INVALID', 'rendered skills include a tool that is not listed');
299
+ }
300
+ for (const target of targets) {
301
+ const prefix = `${TARGET_PATH_PREFIX[target]}/`;
302
+ const actual = files.filter(file => file.target === target && file.path.startsWith(prefix)).map(file => file.path).sort();
303
+ if (actual.length !== expected[target].length || actual.some((path, index) => path !== [...expected[target]].sort()[index])) {
304
+ return refusal('SKILL_RENDER_INVENTORY_INVALID', 'rendered skill inventory does not exactly match the admitted neutral sources', target);
305
+ }
306
+ }
307
+ const costs = [];
308
+ for (const target of targets) {
309
+ let value = 0;
310
+ for (const file of files.filter(candidate => candidate.target === target && candidate.path.startsWith(`${TARGET_PATH_PREFIX[target]}/`))) {
311
+ const bytes = renderedFrontmatterBytes(file);
312
+ if (bytes === undefined)
313
+ return refusal('SKILL_RENDER_INVALID', 'rendered skill frontmatter is malformed', `${target}:${file.path}`);
314
+ value += bytes;
315
+ }
316
+ const cap = captured.authority.caps[target];
317
+ const status = value > cap ? 'exceeded' : 'within_cap';
318
+ costs.push({ target, metric: 'frontmatter_bytes', value, cap, status });
319
+ if (status === 'exceeded')
320
+ return refusal('SKILL_STANDING_COST_EXCEEDED', `rendered ${target} installed skill set exceeds its standing-cost cap`, target);
321
+ }
322
+ const collection = {
323
+ source: { path: captured.collection.path, sha256: captured.collection.sha256 },
324
+ skills: [...captured.authority.skills], metric: captured.authority.metric,
325
+ caps: { ...captured.authority.caps },
326
+ procedures: captured.procedures.map(procedure => ({ path: procedure.path, sha256: procedure.sha256,
327
+ loading: 'pull', budget: 'uncapped' })),
328
+ entrypoints: declarations.map(skill => ({ path: `skills/${skill.name}/SKILL.md`,
329
+ cap: skill.cap, metric: 'lines', displacement: captured.declaredExtensions.includes(skill.name)
330
+ ? `skills/${skill.name}/${skill.procedure}` : `skills/${skill.procedure}` })),
331
+ };
332
+ const result = {
333
+ kind: 'complete',
334
+ status: 0,
335
+ diagnostics: [],
336
+ skills: declarations.map(skill => skill.name).sort(),
337
+ costs,
338
+ collection,
339
+ files,
340
+ };
341
+ inspectedSkillResults.set(result, Object.freeze(Object.fromEntries(targets.map(target => [
342
+ target, [...expected[target]].sort(),
343
+ ]))));
344
+ return result;
345
+ }
346
+ export function extendInspectedSkillStandingCosts(result, additionalFiles) {
347
+ if (result.kind !== 'complete' || !inspectedSkillResults.has(result)) {
348
+ return refusal('SKILL_PROJECTION_INVALID', 'skill standing-cost extension requires the exact issued inspection result');
349
+ }
350
+ const captured = snapshotJson(additionalFiles);
351
+ if (!Array.isArray(captured) || (captured.length > 0
352
+ && !bundleSurfaceFiles(captured))) {
353
+ return refusal('SKILL_RENDER_INVALID', 'additional rendered skill files are malformed or unbounded');
354
+ }
355
+ const files = captured;
356
+ const additions = new Map(SURFACE_TARGETS.map(target => [target, 0]));
357
+ const additionalSkills = new Set();
358
+ const targetSkills = new Set();
359
+ for (const file of files) {
360
+ const prefix = `${TARGET_PATH_PREFIX[file.target]}/`;
361
+ const match = file.path.startsWith(prefix) ? /^([^/]+)\/SKILL\.md$/.exec(file.path.slice(prefix.length)) : null;
362
+ const parsed = parseEntryPoint(file.bytes);
363
+ const name = parsed?.frontmatter.name;
364
+ if (!match || !parsed || parsed.body.length === 0 || typeof name !== 'string' || !NAME.test(name) || name !== match[1]) {
365
+ return refusal('SKILL_RENDER_INVALID', 'additional rendered skill frontmatter or path is invalid', `${file.target}:${file.path}`);
366
+ }
367
+ if (result.skills.includes(name)) {
368
+ return refusal('SKILL_NAME_DUPLICATE', 'additional rendered skill duplicates the admitted collection inventory', `${file.target}:${file.path}`);
369
+ }
370
+ const targetSkill = `${file.target}\0${name}`;
371
+ if (targetSkills.has(targetSkill)) {
372
+ return refusal('SKILL_NAME_DUPLICATE', 'additional rendered skill names must be unique per target', `${file.target}:${file.path}`);
373
+ }
374
+ targetSkills.add(targetSkill);
375
+ additionalSkills.add(name);
376
+ additions.set(file.target, additions.get(file.target) + Buffer.byteLength(parsed.rawFrontmatter));
377
+ }
378
+ const costs = result.costs.map(cost => {
379
+ const value = cost.value + additions.get(cost.target);
380
+ return { ...cost, value, status: value > cost.cap ? 'exceeded' : 'within_cap' };
381
+ });
382
+ const exceeded = costs.find(cost => cost.status === 'exceeded');
383
+ if (exceeded)
384
+ return refusal('SKILL_STANDING_COST_EXCEEDED', `rendered ${exceeded.target} installed skill set exceeds its standing-cost cap`, exceeded.target);
385
+ const inventory = [...result.files, ...files].filter(file => file.path.endsWith('/SKILL.md'))
386
+ .map(({ target, path, sha256 }) => ({ target, path, sha256 }))
387
+ .sort((left, right) => {
388
+ const leftKey = `${left.target}\0${left.path}`;
389
+ const rightKey = `${right.target}\0${right.path}`;
390
+ return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
391
+ });
392
+ return {
393
+ kind: 'complete', status: 0, diagnostics: [],
394
+ skills: [...result.skills, ...additionalSkills].sort(),
395
+ costs,
396
+ inventorySha256: createHash('sha256').update(JSON.stringify(inventory)).digest('hex'),
397
+ };
398
+ }
399
+ export function projectInspectedSkillOutputs(result, targets, skill) {
400
+ const expected = typeof result === 'object' && result !== null ? inspectedSkillResults.get(result) : undefined;
401
+ if (!expected || result.kind !== 'complete' || skill !== SHIPPED_SETUP_SKILL || targets.length === 0
402
+ || new Set(targets).size !== targets.length || targets.some(target => !SURFACE_TARGETS.includes(target) || !expected[target])) {
403
+ return refusal('SKILL_PROJECTION_INVALID', 'skill output projection requires the exact issued inspection result and distinct targets');
404
+ }
405
+ const files = [];
406
+ for (const target of targets) {
407
+ const prefix = `${TARGET_PATH_PREFIX[target]}/${skill}/`;
408
+ const paths = expected[target].filter(path => path.startsWith(prefix)).sort();
409
+ const targetFiles = result.files.filter(file => file.target === target && paths.includes(file.path))
410
+ .sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
411
+ if (targetFiles.length !== paths.length || targetFiles.some((file, index) => file.path !== paths[index]
412
+ || createHash('sha256').update(file.bytes).digest('hex') !== file.sha256)) {
413
+ return refusal('SKILL_PROJECTION_INVALID', 'inspected skill output set is incomplete or changed', target);
414
+ }
415
+ // These bytes land in the consumer's checkout, and the first sync adopts them as already owned, so
416
+ // they must be exactly what the full render publishes there: without its development markers.
417
+ files.push(...targetFiles.map(file => {
418
+ const bytes = stripDevelopmentMarkers(file.bytes);
419
+ return bytes === file.bytes ? file : { ...file, bytes, sha256: createHash('sha256').update(bytes).digest('hex') };
420
+ }));
421
+ }
422
+ const projection = { kind: 'complete', target: targets[0], skill, files };
423
+ inspectedBootstrapOutputs.add(projection);
424
+ return projection;
425
+ }
426
+ export async function inspectSkillSet(input) {
427
+ const captured = captureInput(input);
428
+ if (!captured)
429
+ return refusal('SKILL_INPUT_INVALID', 'skill contract input is invalid');
430
+ const declarations = admitDeclarations(captured);
431
+ if (!Array.isArray(declarations))
432
+ return declarations;
433
+ const generated = await generateSurfaceBatch({
434
+ targets: SURFACE_TARGETS,
435
+ features: ['skills'],
436
+ sources: captured.sources,
437
+ expectedOutputs: expectedOutputs(declarations, captured.sources),
438
+ });
439
+ if (generated.kind !== 'complete')
440
+ return generatedDiagnostic(generated.kind, generated.status, generated.diagnostics[0]);
441
+ return inspectRendered(captured, declarations, generated.files, SURFACE_TARGETS);
442
+ }
443
+ export async function inspectRenderedSkillSet(input) {
444
+ const captured = captureRenderedInput(input);
445
+ if (!captured)
446
+ return refusal('SKILL_INPUT_INVALID', 'rendered skill contract input is invalid');
447
+ const declarations = admitDeclarations(captured);
448
+ return Array.isArray(declarations) ? inspectRendered(captured, declarations, captured.generated.files, captured.targets) : declarations;
449
+ }
@@ -0,0 +1,57 @@
1
+ import { type SurfaceDesiredEntry, type SurfaceDiagnostic, type SurfacePriorOwnedEntry } from './ownership.js';
2
+ export type SurfaceObservedEntry = Readonly<{
3
+ path: string;
4
+ kind: 'missing';
5
+ }> | Readonly<{
6
+ path: string;
7
+ kind: 'file';
8
+ bytes: string;
9
+ sha256: string;
10
+ identity: string;
11
+ }> | Readonly<{
12
+ path: string;
13
+ kind: 'symlink';
14
+ target: string;
15
+ identity: string;
16
+ }> | Readonly<{
17
+ path: string;
18
+ kind: 'other';
19
+ identity: string;
20
+ }>;
21
+ export type SurfaceChange = Readonly<{
22
+ kind: 'write';
23
+ path: string;
24
+ desired: SurfaceDesiredEntry;
25
+ postimage?: string;
26
+ preimage?: Readonly<{
27
+ identity: string;
28
+ sha256?: string;
29
+ }>;
30
+ }> | Readonly<{
31
+ kind: 'remove';
32
+ path: string;
33
+ priorOwned: SurfacePriorOwnedEntry;
34
+ postimage?: string;
35
+ preimage?: Readonly<{
36
+ identity: string;
37
+ sha256?: string;
38
+ }>;
39
+ }> | Readonly<{
40
+ kind: 'already-absent';
41
+ path: string;
42
+ priorOwned: SurfacePriorOwnedEntry;
43
+ }>;
44
+ export type SurfaceChangePlanResult = Readonly<{
45
+ kind: 'complete';
46
+ actions: readonly SurfaceChange[];
47
+ }> | Readonly<{
48
+ kind: 'refusal';
49
+ diagnostic: SurfaceDiagnostic;
50
+ }>;
51
+ export interface SurfaceChangeInput {
52
+ readonly configuredHarnesses: readonly string[];
53
+ readonly desired: readonly SurfaceDesiredEntry[];
54
+ readonly priorOwned: readonly SurfacePriorOwnedEntry[];
55
+ readonly observed: readonly SurfaceObservedEntry[];
56
+ }
57
+ export declare function planSurfaceChanges(input: unknown): SurfaceChangePlanResult;