@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.
- package/CHANGELOG.md +474 -0
- package/LICENSE +21 -0
- package/README.md +25 -2
- package/bin/cockpit.mjs +33 -0
- package/cockpit.schema.json +2644 -0
- package/dist/autonomy.d.ts +45 -0
- package/dist/autonomy.js +173 -0
- package/dist/bounded-read.d.ts +14 -0
- package/dist/bounded-read.js +42 -0
- package/dist/browser/commands.d.ts +117 -0
- package/dist/browser/commands.js +453 -0
- package/dist/browser/package-paths.d.ts +1 -0
- package/dist/browser/package-paths.js +6 -0
- package/dist/browser/proxy.d.ts +22 -0
- package/dist/browser/proxy.js +37 -0
- package/dist/browser/runtime.d.ts +118 -0
- package/dist/browser/runtime.js +186 -0
- package/dist/browser/surfaces.d.ts +141 -0
- package/dist/browser/surfaces.js +561 -0
- package/dist/browser/ui-gate.d.ts +15 -0
- package/dist/browser/ui-gate.js +18 -0
- package/dist/canonical-json.d.ts +2 -0
- package/dist/canonical-json.js +5 -0
- package/dist/cli-guard.d.ts +5 -0
- package/dist/cli-guard.js +71 -0
- package/dist/cli-main.d.ts +176 -0
- package/dist/cli-main.js +1584 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +16 -0
- package/dist/command-table.d.ts +121 -0
- package/dist/command-table.js +664 -0
- package/dist/config/load.d.ts +183 -0
- package/dist/config/load.js +367 -0
- package/dist/config/sibling-toml.d.ts +48 -0
- package/dist/config/sibling-toml.js +160 -0
- package/dist/config/surface-tools-toml.d.ts +9 -0
- package/dist/config/surface-tools-toml.js +37 -0
- package/dist/config/unconfirmed-toml.d.ts +9 -0
- package/dist/config/unconfirmed-toml.js +29 -0
- package/dist/config/verified-write.d.ts +43 -0
- package/dist/config/verified-write.js +89 -0
- package/dist/diagnostics.d.ts +26 -0
- package/dist/diagnostics.js +344 -0
- package/dist/docs/check.d.ts +16 -0
- package/dist/docs/check.js +197 -0
- package/dist/docs/decision-record.d.ts +34 -0
- package/dist/docs/decision-record.js +135 -0
- package/dist/docs/decisions.d.ts +16 -0
- package/dist/docs/decisions.js +103 -0
- package/dist/docs/markdown.d.ts +36 -0
- package/dist/docs/markdown.js +88 -0
- package/dist/docs/references.d.ts +32 -0
- package/dist/docs/references.js +148 -0
- package/dist/emit.d.ts +22 -0
- package/dist/emit.js +43 -0
- package/dist/entrypoint-kinds.d.ts +3 -0
- package/dist/entrypoint-kinds.js +11 -0
- package/dist/environment/application/confirm.d.ts +35 -0
- package/dist/environment/application/confirm.js +122 -0
- package/dist/environment/application/destructive.d.ts +6 -0
- package/dist/environment/application/destructive.js +429 -0
- package/dist/environment/application/doctor.d.ts +94 -0
- package/dist/environment/application/doctor.js +247 -0
- package/dist/environment/application/guard.d.ts +49 -0
- package/dist/environment/application/guard.js +677 -0
- package/dist/environment/application/health.d.ts +143 -0
- package/dist/environment/application/health.js +385 -0
- package/dist/environment/application/lifecycle-context.d.ts +235 -0
- package/dist/environment/application/lifecycle-context.js +154 -0
- package/dist/environment/application/lifecycle-state.d.ts +25 -0
- package/dist/environment/application/lifecycle-state.js +202 -0
- package/dist/environment/application/lifecycle.d.ts +18 -0
- package/dist/environment/application/lifecycle.js +737 -0
- package/dist/environment/application/logs.d.ts +45 -0
- package/dist/environment/application/logs.js +127 -0
- package/dist/environment/application/services.d.ts +60 -0
- package/dist/environment/application/services.js +89 -0
- package/dist/environment/application/setup.d.ts +129 -0
- package/dist/environment/application/setup.js +741 -0
- package/dist/environment/application/shared.d.ts +11 -0
- package/dist/environment/application/shared.js +61 -0
- package/dist/environment/application/siblings.d.ts +43 -0
- package/dist/environment/application/siblings.js +269 -0
- package/dist/environment/claims.d.ts +389 -0
- package/dist/environment/claims.js +1701 -0
- package/dist/environment/codex-hook-trust.d.ts +11 -0
- package/dist/environment/codex-hook-trust.js +185 -0
- package/dist/environment/compose-environment.d.ts +1 -0
- package/dist/environment/compose-environment.js +6 -0
- package/dist/environment/compose-ownership.d.ts +21 -0
- package/dist/environment/compose-ownership.js +117 -0
- package/dist/environment/compose-topology.d.ts +125 -0
- package/dist/environment/compose-topology.js +490 -0
- package/dist/environment/contract.d.ts +522 -0
- package/dist/environment/contract.js +794 -0
- package/dist/environment/declaration.d.ts +14 -0
- package/dist/environment/declaration.js +39 -0
- package/dist/environment/destructive-composition.d.ts +29 -0
- package/dist/environment/destructive-composition.js +333 -0
- package/dist/environment/docker-daemon.d.ts +30 -0
- package/dist/environment/docker-daemon.js +78 -0
- package/dist/environment/docker-endpoint.d.ts +10 -0
- package/dist/environment/docker-endpoint.js +19 -0
- package/dist/environment/env-schema-observation.d.ts +46 -0
- package/dist/environment/env-schema-observation.js +241 -0
- package/dist/environment/evidence.d.ts +136 -0
- package/dist/environment/evidence.js +437 -0
- package/dist/environment/executable.d.ts +38 -0
- package/dist/environment/executable.js +190 -0
- package/dist/environment/generated-application/authorities.d.ts +5 -0
- package/dist/environment/generated-application/authorities.js +61 -0
- package/dist/environment/generated-application/bootstrap-skill.d.ts +16 -0
- package/dist/environment/generated-application/bootstrap-skill.js +328 -0
- package/dist/environment/generated-application/check.d.ts +13 -0
- package/dist/environment/generated-application/check.js +191 -0
- package/dist/environment/generated-application/custom-surface.d.ts +26 -0
- package/dist/environment/generated-application/custom-surface.js +289 -0
- package/dist/environment/generated-application/prepare.d.ts +29 -0
- package/dist/environment/generated-application/prepare.js +278 -0
- package/dist/environment/generated-application/publication.d.ts +33 -0
- package/dist/environment/generated-application/publication.js +547 -0
- package/dist/environment/generated-application/shared.d.ts +492 -0
- package/dist/environment/generated-application/shared.js +354 -0
- package/dist/environment/generated-application/surface-observation.d.ts +4 -0
- package/dist/environment/generated-application/surface-observation.js +69 -0
- package/dist/environment/generated-application/surface-outputs.d.ts +71 -0
- package/dist/environment/generated-application/surface-outputs.js +400 -0
- package/dist/environment/generated-application/surfaces.d.ts +3 -0
- package/dist/environment/generated-application/surfaces.js +704 -0
- package/dist/environment/generated-application/sync.d.ts +6 -0
- package/dist/environment/generated-application/sync.js +124 -0
- package/dist/environment/git-observation.d.ts +202 -0
- package/dist/environment/git-observation.js +553 -0
- package/dist/environment/health-composition.d.ts +12 -0
- package/dist/environment/health-composition.js +645 -0
- package/dist/environment/host-observation.d.ts +56 -0
- package/dist/environment/host-observation.js +52 -0
- package/dist/environment/identity.d.ts +48 -0
- package/dist/environment/identity.js +85 -0
- package/dist/environment/init-application.d.ts +333 -0
- package/dist/environment/init-application.js +726 -0
- package/dist/environment/install-policy-observation.d.ts +71 -0
- package/dist/environment/install-policy-observation.js +284 -0
- package/dist/environment/install-policy.d.ts +48 -0
- package/dist/environment/install-policy.js +96 -0
- package/dist/environment/instance.d.ts +33 -0
- package/dist/environment/instance.js +122 -0
- package/dist/environment/instruction-pointer.d.ts +19 -0
- package/dist/environment/instruction-pointer.js +144 -0
- package/dist/environment/lifecycle-composition.d.ts +31 -0
- package/dist/environment/lifecycle-composition.js +742 -0
- package/dist/environment/lifecycle-stage.d.ts +120 -0
- package/dist/environment/lifecycle-stage.js +408 -0
- package/dist/environment/lifecycle.d.ts +75 -0
- package/dist/environment/lifecycle.js +354 -0
- package/dist/environment/logs.d.ts +132 -0
- package/dist/environment/logs.js +519 -0
- package/dist/environment/map-limit.d.ts +2 -0
- package/dist/environment/map-limit.js +13 -0
- package/dist/environment/mcp-observation.d.ts +9 -0
- package/dist/environment/mcp-observation.js +46 -0
- package/dist/environment/observations.d.ts +46 -0
- package/dist/environment/observations.js +346 -0
- package/dist/environment/operator-application.d.ts +79 -0
- package/dist/environment/operator-application.js +197 -0
- package/dist/environment/ports.d.ts +182 -0
- package/dist/environment/ports.js +1205 -0
- package/dist/environment/posture-observation.d.ts +68 -0
- package/dist/environment/posture-observation.js +253 -0
- package/dist/environment/presence.d.ts +4 -0
- package/dist/environment/presence.js +26 -0
- package/dist/environment/read-composition.d.ts +32 -0
- package/dist/environment/read-composition.js +397 -0
- package/dist/environment/readiness-composition.d.ts +57 -0
- package/dist/environment/readiness-composition.js +151 -0
- package/dist/environment/reclaim.d.ts +370 -0
- package/dist/environment/reclaim.js +1940 -0
- package/dist/environment/repository-identity.d.ts +13 -0
- package/dist/environment/repository-identity.js +108 -0
- package/dist/environment/runtime-measurement-record.d.ts +38 -0
- package/dist/environment/runtime-measurement-record.js +111 -0
- package/dist/environment/runtime-measurement.d.ts +27 -0
- package/dist/environment/runtime-measurement.js +224 -0
- package/dist/environment/runtime-probe-residue.d.ts +43 -0
- package/dist/environment/runtime-probe-residue.js +148 -0
- package/dist/environment/runtime-probe.d.ts +72 -0
- package/dist/environment/runtime-probe.js +725 -0
- package/dist/environment/runtime.d.ts +551 -0
- package/dist/environment/runtime.js +2405 -0
- package/dist/environment/seed.d.ts +16 -0
- package/dist/environment/seed.js +43 -0
- package/dist/environment/selftest-application.d.ts +86 -0
- package/dist/environment/selftest-application.js +713 -0
- package/dist/environment/sensitive.d.ts +3 -0
- package/dist/environment/sensitive.js +48 -0
- package/dist/environment/served-checkout-grants.d.ts +53 -0
- package/dist/environment/served-checkout-grants.js +182 -0
- package/dist/environment/setup-observation.d.ts +62 -0
- package/dist/environment/setup-observation.js +1473 -0
- package/dist/environment/setup.d.ts +43 -0
- package/dist/environment/setup.js +176 -0
- package/dist/environment/sibling-checkouts.d.ts +119 -0
- package/dist/environment/sibling-checkouts.js +254 -0
- package/dist/environment/sibling-instructions.d.ts +33 -0
- package/dist/environment/sibling-instructions.js +224 -0
- package/dist/environment/sibling-observation.d.ts +27 -0
- package/dist/environment/sibling-observation.js +45 -0
- package/dist/environment/sibling-pull.d.ts +23 -0
- package/dist/environment/sibling-pull.js +95 -0
- package/dist/environment/sibling-registration.d.ts +45 -0
- package/dist/environment/sibling-registration.js +538 -0
- package/dist/environment/stack-inputs.d.ts +18 -0
- package/dist/environment/stack-inputs.js +210 -0
- package/dist/environment/stack-inventory-prune.d.ts +31 -0
- package/dist/environment/stack-inventory-prune.js +129 -0
- package/dist/environment/stack-inventory-report.d.ts +44 -0
- package/dist/environment/stack-inventory-report.js +78 -0
- package/dist/environment/stack-inventory.d.ts +94 -0
- package/dist/environment/stack-inventory.js +418 -0
- package/dist/environment/state.d.ts +410 -0
- package/dist/environment/state.js +2153 -0
- package/dist/environment/templates.d.ts +140 -0
- package/dist/environment/templates.js +685 -0
- package/dist/environment/tool-registration.d.ts +9 -0
- package/dist/environment/tool-registration.js +92 -0
- package/dist/environment/upgrade-application.d.ts +19 -0
- package/dist/environment/upgrade-application.js +175 -0
- package/dist/environment-exec/execute.d.ts +105 -0
- package/dist/environment-exec/execute.js +1179 -0
- package/dist/environment-exec/libexec-program.d.ts +6 -0
- package/dist/environment-exec/libexec-program.js +22 -0
- package/dist/environment-exec/verified-digest.d.ts +4 -0
- package/dist/environment-exec/verified-digest.js +16 -0
- package/dist/exact-keys.d.ts +7 -0
- package/dist/exact-keys.js +15 -0
- package/dist/fix-catalogue.d.ts +32 -0
- package/dist/fix-catalogue.js +60 -0
- package/dist/freshness.d.ts +29 -0
- package/dist/freshness.js +75 -0
- package/dist/generated-environment/adopt.d.ts +16 -0
- package/dist/generated-environment/adopt.js +271 -0
- package/dist/generated-environment/command.d.ts +47 -0
- package/dist/generated-environment/command.js +75 -0
- package/dist/generated-environment/transaction.d.ts +186 -0
- package/dist/generated-environment/transaction.js +1770 -0
- package/dist/grading/evaluate.d.ts +71 -0
- package/dist/grading/evaluate.js +403 -0
- package/dist/grading/grade.d.ts +33 -0
- package/dist/grading/grade.js +57 -0
- package/dist/guards/answer-confirmation.d.ts +41 -0
- package/dist/guards/answer-confirmation.js +109 -0
- package/dist/guards/evaluator.d.ts +130 -0
- package/dist/guards/evaluator.js +1258 -0
- package/dist/guards/harness-adapter.d.ts +17 -0
- package/dist/guards/harness-adapter.js +57 -0
- package/dist/guards/host.d.ts +8 -0
- package/dist/guards/host.js +10 -0
- package/dist/guards/invocation-parser.d.ts +66 -0
- package/dist/guards/invocation-parser.js +595 -0
- package/dist/guards/local-identity.d.ts +44 -0
- package/dist/guards/local-identity.js +129 -0
- package/dist/guards/policy-change.d.ts +43 -0
- package/dist/guards/policy-change.js +159 -0
- package/dist/guards/policy-pin.d.ts +13 -0
- package/dist/guards/policy-pin.js +177 -0
- package/dist/guards/protected-locations.d.ts +62 -0
- package/dist/guards/protected-locations.js +461 -0
- package/dist/guards/read-only.d.ts +37 -0
- package/dist/guards/read-only.js +315 -0
- package/dist/init/command.d.ts +41 -0
- package/dist/init/command.js +330 -0
- package/dist/init/derive.d.ts +53 -0
- package/dist/init/derive.js +819 -0
- package/dist/init/draft.d.ts +140 -0
- package/dist/init/draft.js +1228 -0
- package/dist/init/render.d.ts +47 -0
- package/dist/init/render.js +104 -0
- package/dist/init/scaffold.d.ts +53 -0
- package/dist/init/scaffold.js +121 -0
- package/dist/invocation.d.ts +13 -0
- package/dist/invocation.js +20 -0
- package/dist/package-metadata.d.ts +9 -0
- package/dist/package-metadata.js +19 -0
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.js +88 -0
- package/dist/references/named.d.ts +24 -0
- package/dist/references/named.js +27 -0
- package/dist/refusal.d.ts +15 -0
- package/dist/refusal.js +7 -0
- package/dist/registry-derivation.d.ts +31 -0
- package/dist/registry-derivation.js +32 -0
- package/dist/registry-resolve/command.d.ts +47 -0
- package/dist/registry-resolve/command.js +226 -0
- package/dist/registry-resolve/registry.d.ts +68 -0
- package/dist/registry-resolve/registry.js +292 -0
- package/dist/registry-resolve/render-shell.d.ts +18 -0
- package/dist/registry-resolve/render-shell.js +36 -0
- package/dist/repair.d.ts +29 -0
- package/dist/repair.js +8 -0
- package/dist/repository-path.d.ts +9 -0
- package/dist/repository-path.js +16 -0
- package/dist/schema-json.d.ts +1 -0
- package/dist/schema-json.js +177 -0
- package/dist/schema.d.ts +1289 -0
- package/dist/schema.js +985 -0
- package/dist/setup/command.d.ts +4 -0
- package/dist/setup/command.js +4 -0
- package/dist/sha256.d.ts +1 -0
- package/dist/sha256.js +4 -0
- package/dist/surfaces/adoption.d.ts +41 -0
- package/dist/surfaces/adoption.js +217 -0
- package/dist/surfaces/consumer-instructions.d.ts +20 -0
- package/dist/surfaces/consumer-instructions.js +43 -0
- package/dist/surfaces/contract.d.ts +42 -0
- package/dist/surfaces/contract.js +169 -0
- package/dist/surfaces/core-declarations.d.ts +24 -0
- package/dist/surfaces/core-declarations.js +79 -0
- package/dist/surfaces/development-markers.d.ts +1 -0
- package/dist/surfaces/development-markers.js +18 -0
- package/dist/surfaces/generator-adapter.d.ts +71 -0
- package/dist/surfaces/generator-adapter.js +809 -0
- package/dist/surfaces/harness-registry.d.ts +260 -0
- package/dist/surfaces/harness-registry.js +146 -0
- package/dist/surfaces/mcp.d.ts +145 -0
- package/dist/surfaces/mcp.js +349 -0
- package/dist/surfaces/merge.d.ts +30 -0
- package/dist/surfaces/merge.js +105 -0
- package/dist/surfaces/ownership.d.ts +190 -0
- package/dist/surfaces/ownership.js +795 -0
- package/dist/surfaces/projection.d.ts +136 -0
- package/dist/surfaces/projection.js +716 -0
- package/dist/surfaces/render.d.ts +79 -0
- package/dist/surfaces/render.js +636 -0
- package/dist/surfaces/restrictions.d.ts +130 -0
- package/dist/surfaces/restrictions.js +447 -0
- package/dist/surfaces/selftest.d.ts +162 -0
- package/dist/surfaces/selftest.js +393 -0
- package/dist/surfaces/skill-contract.d.ts +85 -0
- package/dist/surfaces/skill-contract.js +449 -0
- package/dist/surfaces/sync.d.ts +57 -0
- package/dist/surfaces/sync.js +164 -0
- package/dist/team-metadata.d.ts +41 -0
- package/dist/team-metadata.js +513 -0
- package/dist/testing/gates.d.ts +91 -0
- package/dist/testing/gates.js +182 -0
- package/dist/testing/hooks.d.ts +59 -0
- package/dist/testing/hooks.js +139 -0
- package/dist/testing/test-protection.d.ts +34 -0
- package/dist/testing/test-protection.js +137 -0
- package/dist/testing/verdict.d.ts +29 -0
- package/dist/testing/verdict.js +62 -0
- package/dist/testing/weakening.d.ts +15 -0
- package/dist/testing/weakening.js +30 -0
- package/dist/work-orders/application-closure.d.ts +7 -0
- package/dist/work-orders/application-closure.js +76 -0
- package/dist/work-orders/application-context.d.ts +162 -0
- package/dist/work-orders/application-context.js +137 -0
- package/dist/work-orders/application-decisions.d.ts +27 -0
- package/dist/work-orders/application-decisions.js +121 -0
- package/dist/work-orders/application-grading.d.ts +11 -0
- package/dist/work-orders/application-grading.js +212 -0
- package/dist/work-orders/application.d.ts +6 -0
- package/dist/work-orders/application.js +223 -0
- package/dist/work-orders/composition.d.ts +101 -0
- package/dist/work-orders/composition.js +1202 -0
- package/dist/work-orders/contract.d.ts +77 -0
- package/dist/work-orders/contract.js +140 -0
- package/dist/work-orders/decisions.d.ts +23 -0
- package/dist/work-orders/decisions.js +55 -0
- package/dist/work-orders/store.d.ts +207 -0
- package/dist/work-orders/store.js +291 -0
- package/docs/README.md +68 -0
- package/docs/architecture.md +136 -0
- package/docs/capability-matrix.md +58 -0
- package/docs/cli-reference.md +807 -0
- package/docs/command-list.md +62 -0
- package/docs/compose-patterns.md +99 -0
- package/docs/concepts.md +173 -0
- package/docs/configuration-essentials.md +177 -0
- package/docs/configuration-reference.md +636 -0
- package/docs/docs-check.md +76 -0
- package/docs/environment.md +948 -0
- package/docs/extending.md +43 -0
- package/docs/faq.md +113 -0
- package/docs/getting-started.md +692 -0
- package/docs/harness-surfaces.md +500 -0
- package/docs/joining-a-team.md +76 -0
- package/docs/release-policy.md +49 -0
- package/docs/safety-and-autonomy.md +463 -0
- package/docs/troubleshooting.md +382 -0
- package/docs/tutorial.md +171 -0
- package/docs/work-and-browser.md +420 -0
- package/libexec/browser-operation.cjs +270 -0
- package/libexec/fence-marker.cjs +101 -0
- package/libexec/fence-marker.d.cts +24 -0
- package/libexec/fenced-group-runner.cjs +77 -0
- package/libexec/fenced-supervisor.cjs +137 -0
- package/libexec/generated-filesystem.cjs +731 -0
- package/libexec/install-filesystem.cjs +225 -0
- package/libexec/rulesync-generator.NOTICE.md +1112 -0
- package/libexec/rulesync-generator.cjs +743 -0
- package/libexec/surface-generator-worker.cjs +266 -0
- package/libexec/surface-output-reader.cjs +99 -0
- package/libexec/surface-scratch-cleanup.cjs +14 -0
- package/libexec/validate-harness-evidence.d.mts +183 -0
- package/libexec/validate-harness-evidence.mjs +1312 -0
- package/package.json +74 -4
- package/surfaces/README.md +33 -0
- package/surfaces/agents/evaluator.agent.md +76 -0
- package/surfaces/guards/bash-guard.sh +48 -0
- package/surfaces/guards/claude.adapter.json +25 -0
- package/surfaces/guards/codex.adapter.json +24 -0
- package/surfaces/guards/opencode.adapter.json +25 -0
- package/surfaces/references/browser.md +63 -0
- package/surfaces/references/test-data-and-personas.md +84 -0
- package/surfaces/references/testing-tiers.md +11 -0
- package/surfaces/skills/cockpit-browser.skill.md +59 -0
- package/surfaces/skills/cockpit-explain.skill.md +32 -0
- package/surfaces/skills/cockpit-fix.skill.md +37 -0
- package/surfaces/skills/cockpit-setup.skill.md +39 -0
- package/surfaces/skills/cockpit-work.skill.md +34 -0
- package/surfaces/skills/collection.json +5 -0
- package/surfaces/skills/procedures/explain.md +66 -0
- package/surfaces/skills/procedures/fix.md +95 -0
- package/surfaces/skills/procedures/setup.md +452 -0
- package/surfaces/skills/procedures/work.md +134 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { cockpitCommand } from '../../fix-catalogue.js';
|
|
2
|
+
import { proposeGeneratedEnvironmentRepair } from '../../repair.js';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { lstat, realpath } from 'node:fs/promises';
|
|
5
|
+
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { isProxy } from 'node:util/types';
|
|
8
|
+
import { parseDocument } from 'yaml';
|
|
9
|
+
import { observeConfigSource } from '../../config/load.js';
|
|
10
|
+
import { executeProbe } from '../../environment-exec/execute.js';
|
|
11
|
+
import { CORE_EVALUATOR_ASSET as EVALUATOR_ASSET, CORE_SKILL_ASSETS as SKILL_ASSETS } from '../../surfaces/core-declarations.js';
|
|
12
|
+
import { encodeOwnershipManifest, projectGeneratedPathFacts, } from '../../surfaces/ownership.js';
|
|
13
|
+
import { ENVIRONMENT_CODES, errorCause, hasErrorCode } from '../contract.js';
|
|
14
|
+
import { cockpitId, stackId } from '../identity.js';
|
|
15
|
+
import { refusalOutcome as refuse } from '../../refusal.js';
|
|
16
|
+
export const OWNER = 'generated-environment-application';
|
|
17
|
+
export const surfaceObservationDeclarations = Object.freeze([
|
|
18
|
+
{ id: 'harness-surfaces', owner: OWNER, postures: ['environment'], stages: [{ stage: 'bootstrap', disposition: 'required' }, { stage: 'steady', disposition: 'required' }], code: ENVIRONMENT_CODES.HARNESS_SURFACE_UNAVAILABLE, isIssued: isGeneratedApplicationSurfaceObservation, issuedAt: generatedApplicationSurfaceObservationIssuedAt },
|
|
19
|
+
{ id: 'directory-grants', owner: OWNER, postures: ['directory-grants'], stages: [{ stage: 'bootstrap', disposition: 'required' }, { stage: 'steady', disposition: 'required' }], code: ENVIRONMENT_CODES.DIRECTORY_GRANTS_UNAVAILABLE, isIssued: isGeneratedApplicationSurfaceObservation, issuedAt: generatedApplicationSurfaceObservationIssuedAt },
|
|
20
|
+
{ id: 'guide-budget', owner: OWNER, postures: ['environment'], stages: [{ stage: 'bootstrap', disposition: 'required' }, { stage: 'steady', disposition: 'required' }], code: ENVIRONMENT_CODES.GUIDE_CAP_EXCEEDED, isIssued: isGeneratedApplicationSurfaceObservation, issuedAt: generatedApplicationSurfaceObservationIssuedAt },
|
|
21
|
+
{ id: 'skill-budget', owner: OWNER, postures: ['environment'], stages: [{ stage: 'bootstrap', disposition: 'required' }, { stage: 'steady', disposition: 'required' }], code: ENVIRONMENT_CODES.SKILL_BUDGET_UNAVAILABLE, isIssued: isGeneratedApplicationSurfaceObservation, issuedAt: generatedApplicationSurfaceObservationIssuedAt },
|
|
22
|
+
]);
|
|
23
|
+
export const issuedSurfaceObservations = new WeakMap();
|
|
24
|
+
function containedPath(root, candidate) {
|
|
25
|
+
const fromRoot = relative(root, candidate);
|
|
26
|
+
return fromRoot === '' || fromRoot !== '..' && !fromRoot.startsWith(`..${sep}`) && !isAbsolute(fromRoot);
|
|
27
|
+
}
|
|
28
|
+
export function activeClaudeImports(bytes) {
|
|
29
|
+
const imports = [];
|
|
30
|
+
let fence;
|
|
31
|
+
let inComment = false;
|
|
32
|
+
for (const [index, line] of bytes.split(/\r?\n/u).entries()) {
|
|
33
|
+
const trimmed = line.trimStart();
|
|
34
|
+
const marker = /^ {0,3}(?<fence>`{3,}|~{3,})(?<suffix>.*)$/u.exec(line)?.groups;
|
|
35
|
+
if (fence) {
|
|
36
|
+
if (marker?.fence?.[0] === fence.marker && marker.fence.length >= fence.length
|
|
37
|
+
&& marker.suffix?.trim() === '')
|
|
38
|
+
fence = undefined;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (inComment) {
|
|
42
|
+
if (trimmed.includes('-->'))
|
|
43
|
+
inComment = false;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (trimmed.startsWith('<!--')) {
|
|
47
|
+
if (!trimmed.includes('-->'))
|
|
48
|
+
inComment = true;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (marker?.fence && (marker.fence[0] !== '`' || !marker.suffix?.includes('`'))) {
|
|
52
|
+
fence = { marker: marker.fence[0], length: marker.fence.length };
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (line === '@AGENTS.md')
|
|
56
|
+
imports.push(index);
|
|
57
|
+
}
|
|
58
|
+
return imports;
|
|
59
|
+
}
|
|
60
|
+
export async function siblingRootsCurrent(authority) {
|
|
61
|
+
try {
|
|
62
|
+
if (await realpath(authority.declaredRoot) !== authority.canonicalRoot)
|
|
63
|
+
return false;
|
|
64
|
+
const root = await lstat(authority.canonicalRoot);
|
|
65
|
+
if (!root.isDirectory() || root.isSymbolicLink()
|
|
66
|
+
|| root.dev !== authority.rootIdentity.dev || root.ino !== authority.rootIdentity.ino)
|
|
67
|
+
return false;
|
|
68
|
+
for (const sibling of authority.siblings.values()) {
|
|
69
|
+
const canonical = await realpath(sibling.root);
|
|
70
|
+
const status = await lstat(canonical);
|
|
71
|
+
if (canonical !== sibling.root || !containedPath(authority.canonicalRoot, canonical)
|
|
72
|
+
|| !status.isDirectory() || status.isSymbolicLink()
|
|
73
|
+
|| status.dev !== sibling.identity.dev || status.ino !== sibling.identity.ino)
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// a failed re-observation means the root is no longer authenticated; the caller refuses.
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// A teammate's clone of a cockpit has none of its siblings until setup clones them; a sibling
|
|
84
|
+
// setup cannot clone was reported as a bare realpath ENOENT with nothing to do about it.
|
|
85
|
+
function absentSibling(sibling, path, configPath) {
|
|
86
|
+
const setup = cockpitCommand('setup', { config: configPath });
|
|
87
|
+
const fix = sibling.acquire === 'auto' ? `run ${setup}, which clones ${sibling.remote} there, then rerun this command`
|
|
88
|
+
: sibling.acquire === 'manual' ? `clone ${sibling.remote} into ${path}, then rerun this command`
|
|
89
|
+
: `clone or create the repository at ${path}, then rerun this command; cockpit.toml records no remote for it (acquire = "none"), so setup cannot clone it: whoever has the checkout records one with ${cockpitCommand('sibling add', { operand: sibling.slug, config: configPath, args: '--remote <url>' })} and commits cockpit.toml, and every later ${setup} clones it`;
|
|
90
|
+
return {
|
|
91
|
+
kind: 'refusal',
|
|
92
|
+
// A literal, so the diagnostic inventory captures the fix beside the code.
|
|
93
|
+
code: 'SIBLING_MISSING',
|
|
94
|
+
reason: `sibling ${sibling.slug} is declared at ${path}, and nothing is there`,
|
|
95
|
+
target: `sibling:${sibling.slug}`,
|
|
96
|
+
fix,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export async function authenticateSiblingRoots(root, config, configPath) {
|
|
100
|
+
try {
|
|
101
|
+
const declaredRoot = resolve(root, config.cockpit.siblings_root);
|
|
102
|
+
const canonicalRoot = await realpath(declaredRoot);
|
|
103
|
+
const rootStatus = await lstat(canonicalRoot);
|
|
104
|
+
if (!rootStatus.isDirectory() || rootStatus.isSymbolicLink()) {
|
|
105
|
+
return { kind: 'refusal', reason: 'the declared sibling root is not an ordinary directory' };
|
|
106
|
+
}
|
|
107
|
+
const siblings = new Map();
|
|
108
|
+
for (const sibling of config.sibling) {
|
|
109
|
+
const declared = resolve(declaredRoot, sibling.dir);
|
|
110
|
+
if (!containedPath(declaredRoot, declared)) {
|
|
111
|
+
return { kind: 'refusal', reason: `sibling ${sibling.slug} escapes the declared sibling root` };
|
|
112
|
+
}
|
|
113
|
+
const present = await lstat(declared).then(() => true, (error) => {
|
|
114
|
+
if (hasErrorCode(error, 'ENOENT'))
|
|
115
|
+
return false;
|
|
116
|
+
throw error;
|
|
117
|
+
});
|
|
118
|
+
if (!present)
|
|
119
|
+
return absentSibling(sibling, declared, configPath);
|
|
120
|
+
const canonical = await realpath(declared);
|
|
121
|
+
const status = await lstat(canonical);
|
|
122
|
+
if (!containedPath(canonicalRoot, canonical)) {
|
|
123
|
+
return { kind: 'refusal', reason: `sibling ${sibling.slug} resolves outside the declared sibling root` };
|
|
124
|
+
}
|
|
125
|
+
if (!status.isDirectory() || status.isSymbolicLink()) {
|
|
126
|
+
return { kind: 'refusal', reason: `sibling ${sibling.slug} is not an ordinary directory` };
|
|
127
|
+
}
|
|
128
|
+
siblings.set(sibling.slug, { root: canonical, identity: { dev: status.dev, ino: status.ino } });
|
|
129
|
+
}
|
|
130
|
+
return { kind: 'complete', roots: {
|
|
131
|
+
declaredRoot, canonicalRoot, rootIdentity: { dev: rootStatus.dev, ino: rootStatus.ino }, siblings,
|
|
132
|
+
} };
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const reason = errorCause(error);
|
|
136
|
+
return { kind: 'refusal', reason: `could not verify the sibling root (${reason})` };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export const defaultAdapters = { observeSource: observeConfigSource, execute: executeProbe };
|
|
140
|
+
export const OWNERSHIP_PATH = '.cockpit/generated-environment-ownership.json';
|
|
141
|
+
export const SHA256 = /^[a-f0-9]{64}$/;
|
|
142
|
+
export const MAX_OWNERSHIP_BYTES = 1_048_576;
|
|
143
|
+
export const COMPOSE_SOURCE_BYTES = 1_048_576;
|
|
144
|
+
export const MAX_OWNED_FILES = 256;
|
|
145
|
+
export const MAX_EXECUTABLE_BYTES = 536_870_912;
|
|
146
|
+
export const MAX_GENERATED_BYTES = 16_777_216;
|
|
147
|
+
export const MAX_SURFACE_FILE_BYTES = 65_536;
|
|
148
|
+
const MAX_SURFACE_BYTES = 4_194_304;
|
|
149
|
+
export const MAX_HELPER_FRAME_BYTES = 65_536;
|
|
150
|
+
export const HELPER_TIMEOUT_MS = 10_000;
|
|
151
|
+
// The native hook cost workload spawns Git once per ref update, 128 times. On a loaded host that
|
|
152
|
+
// takes seconds (7 s at a load average of 24), so under the helper bound an over-budget hook timed
|
|
153
|
+
// out and was reported as a failed execution instead of being sent to CI.
|
|
154
|
+
export const NATIVE_HOOK_COST_TIMEOUT_MS = 60_000;
|
|
155
|
+
export const SURFACE_ROOT = fileURLToPath(new URL('../../../surfaces', import.meta.url));
|
|
156
|
+
export const RESTRICTION_ASSETS = Object.freeze([
|
|
157
|
+
'guards/bash-guard.sh',
|
|
158
|
+
'guards/claude.adapter.json',
|
|
159
|
+
'guards/codex.adapter.json',
|
|
160
|
+
'guards/opencode.adapter.json',
|
|
161
|
+
]);
|
|
162
|
+
// Shipped beside the setup skill, outside the skill contract: the skill set admits only entry points and the
|
|
163
|
+
// shared procedure, and these are pulled on demand like the browser reference.
|
|
164
|
+
export const REFERENCE_ASSETS = Object.freeze([
|
|
165
|
+
'references/test-data-and-personas.md',
|
|
166
|
+
]);
|
|
167
|
+
export const WORK_ASSETS = Object.freeze([
|
|
168
|
+
'skills/cockpit-browser.skill.md',
|
|
169
|
+
'references/browser.md',
|
|
170
|
+
'references/testing-tiers.md',
|
|
171
|
+
]);
|
|
172
|
+
export const issuedApplicationProjections = new WeakMap();
|
|
173
|
+
export const projectedWorkApplicationAuthorities = new WeakSet();
|
|
174
|
+
export const issuedWorkApplicationAuthorities = new WeakMap();
|
|
175
|
+
export const issuedSelectedBootstrapAuthorities = new WeakMap();
|
|
176
|
+
export const consumedBootstrapStatePublications = new WeakSet();
|
|
177
|
+
export function skillDescription(bytes) {
|
|
178
|
+
const front = /^---\r?\n([\s\S]*?)\r?\n---/.exec(bytes)?.[1];
|
|
179
|
+
if (front === undefined)
|
|
180
|
+
return undefined;
|
|
181
|
+
const description = parseDocument(front).toJS({ maxAliasCount: 0 })?.description;
|
|
182
|
+
return typeof description === 'string' ? description : undefined;
|
|
183
|
+
}
|
|
184
|
+
export const compareCodeUnits = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
185
|
+
export function sha256(value) {
|
|
186
|
+
return createHash('sha256').update(value).digest('hex');
|
|
187
|
+
}
|
|
188
|
+
export function ownRecord(value) {
|
|
189
|
+
try {
|
|
190
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value) || isProxy(value)
|
|
191
|
+
|| ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
192
|
+
return undefined;
|
|
193
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
194
|
+
if (Object.getOwnPropertySymbols(value).length > 0
|
|
195
|
+
|| Object.values(descriptors).some((descriptor) => descriptor.get || descriptor.set || !descriptor.enumerable))
|
|
196
|
+
return undefined;
|
|
197
|
+
return Object.fromEntries(Object.entries(descriptors).map(([key, descriptor]) => [key, descriptor.value]));
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// a guard over caller-supplied values; a throwing accessor or proxy trap is malformed input the caller refuses.
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
export function guideLines(bytes) {
|
|
205
|
+
return bytes.trimEnd().split('\n').length;
|
|
206
|
+
}
|
|
207
|
+
// An overlay pins the digest of the built-in it replaces, so a cockpit upgrade that changes that
|
|
208
|
+
// built-in is reviewed before the override keeps shadowing it.
|
|
209
|
+
function overrideChanged(finding, severity) {
|
|
210
|
+
return {
|
|
211
|
+
severity, code: 'OVERRIDDEN_CORE_CHANGED', target: finding.overlaySource,
|
|
212
|
+
message: `overlay ${finding.name} replaces the built-in ${finding.name} recorded as sha256 ${finding.recordedSha256}, but this cockpit version's built-in is sha256 ${finding.currentSha256}`,
|
|
213
|
+
fix: 'review the new built-in against your override, set the overlay\'s replaces.sha256 to the current digest this message names, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
// Copied sibling guides count toward the cap, so a sibling's own edit can push it over.
|
|
217
|
+
export function guideCapExceeded(cost) {
|
|
218
|
+
return { kind: 'refusal', artifact: null, destination: null, result: null, status: 2,
|
|
219
|
+
diagnostics: [{
|
|
220
|
+
severity: 'error', code: ENVIRONMENT_CODES.GUIDE_CAP_EXCEEDED, target: 'cockpit.guide_cap',
|
|
221
|
+
message: `the instructions ${cost.target} loads at start are ${cost.value} lines, over cockpit.guide_cap ${cost.cap}; the count includes each sibling guide copied into the root AGENTS.md`,
|
|
222
|
+
fix: 'shorten the root or sibling guides, or move conditional guidance into a skill, or raise cockpit.guide_cap in cockpit.toml, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
223
|
+
}] };
|
|
224
|
+
}
|
|
225
|
+
// Codex 0.166.0 dropped the end of a project AGENTS.md past 32 KiB without saying so (measured
|
|
226
|
+
// 2026-11-03), and the copied sibling guides sit at the end of cockpit's region. The team's own text
|
|
227
|
+
// outside the region counts too, so this is the least the file holds.
|
|
228
|
+
export const CODEX_PROJECT_DOC_BYTES = 32_768;
|
|
229
|
+
export function guideBytesExceeded(bytes) {
|
|
230
|
+
return { kind: 'refusal', artifact: null, destination: null, result: null, status: 2,
|
|
231
|
+
diagnostics: [{
|
|
232
|
+
severity: 'error',
|
|
233
|
+
// A literal, so the diagnostic inventory captures the fix beside the code.
|
|
234
|
+
code: 'GUIDE_CAP_EXCEEDED',
|
|
235
|
+
target: 'AGENTS.md',
|
|
236
|
+
message: `cockpit's part of the root AGENTS.md, with the sibling guides it copies, is ${bytes} bytes; Codex drops whatever follows the first 32768 bytes of a project AGENTS.md without saying so`,
|
|
237
|
+
fix: 'shorten the root or sibling guides, or name fewer guides in sibling.guides, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
238
|
+
}] };
|
|
239
|
+
}
|
|
240
|
+
// The projection skips an absent guide, so a misspelled name otherwise copies nothing and says nothing.
|
|
241
|
+
export function siblingGuideMissing(slug, guide, sourcePath) {
|
|
242
|
+
return { kind: 'refusal', artifact: null, destination: null, result: null, status: 2,
|
|
243
|
+
diagnostics: [{
|
|
244
|
+
severity: 'error',
|
|
245
|
+
code: 'SIBLING_GUIDE_MISSING',
|
|
246
|
+
target: `sibling.${slug}.guides`,
|
|
247
|
+
message: `sibling ${slug} declares the guide ${guide}, but ${sourcePath} does not exist, so no harness would load it`,
|
|
248
|
+
fix: 'correct or remove the guide name in that sibling\'s guides list in cockpit.toml, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
249
|
+
}] };
|
|
250
|
+
}
|
|
251
|
+
export function overrideChangedRefusal(finding) {
|
|
252
|
+
return { kind: 'refusal', artifact: null, destination: null, result: null, status: 2,
|
|
253
|
+
diagnostics: [overrideChanged(finding, 'error')] };
|
|
254
|
+
}
|
|
255
|
+
export function complete(action, prepared, dryRun = false, changes = [], staleRemoval) {
|
|
256
|
+
if (!prepared.surfaceSelftest || !prepared.surfaceHealth)
|
|
257
|
+
return refuse('SURFACE_INPUT_INVALID', 'authenticated surface health inputs are missing', 'surfaces');
|
|
258
|
+
const generatedPaths = generatedPathFacts(prepared, dryRun ? 'declared-before-sync' : 'required-after-sync');
|
|
259
|
+
if (generatedPaths.kind !== 'complete')
|
|
260
|
+
return refuse(generatedPaths.diagnostic.code, generatedPaths.diagnostic.message, generatedPaths.diagnostic.target);
|
|
261
|
+
const application = {
|
|
262
|
+
generatedPaths: generatedPaths.facts,
|
|
263
|
+
sourceSha256: prepared.sourceSha256,
|
|
264
|
+
runtimeSha256: prepared.runtimeSha256,
|
|
265
|
+
generation: prepared.generation,
|
|
266
|
+
surfaceSelftest: prepared.surfaceSelftest,
|
|
267
|
+
activeSurfaceOverrides: prepared.activeSurfaceOverrides,
|
|
268
|
+
changedOverrideOriginals: prepared.changedOverrideOriginals,
|
|
269
|
+
inspection: {
|
|
270
|
+
kind: 'passed',
|
|
271
|
+
files: prepared.owned.map(({ path, sha256: digest }) => ({ path, sha256: digest, ownership: 'whole-file' })),
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
issuedApplicationProjections.set(application, Object.freeze({
|
|
275
|
+
root: prepared.root, stackId: prepared.stackId, currentPublication: !dryRun,
|
|
276
|
+
siblingRoots: prepared.siblingRoots,
|
|
277
|
+
node: prepared.node, surfaceSelftest: prepared.surfaceSelftest, surfaceHealth: prepared.surfaceHealth,
|
|
278
|
+
...(!dryRun && prepared.workApplication ? { workApplication: prepared.workApplication } : {}),
|
|
279
|
+
}));
|
|
280
|
+
return {
|
|
281
|
+
kind: 'complete', artifact: null, destination: null,
|
|
282
|
+
diagnostics: [
|
|
283
|
+
// A trust warning is a review prompt for settings being written; repeating it for an
|
|
284
|
+
// unchanged file on every sync and check trained people to ignore it.
|
|
285
|
+
...prepared.warnings.filter(warning => changes.some(change => change.operation === 'write' && change.path === warning.path))
|
|
286
|
+
.map(({ severity, code, target, path, message }) => ({
|
|
287
|
+
severity, code, target: `${target}:${path}`, message,
|
|
288
|
+
})),
|
|
289
|
+
...prepared.unapprovedMcpServers.map(server => ({
|
|
290
|
+
severity: 'warning', code: 'MCP_NOT_APPROVED', target: server.name,
|
|
291
|
+
message: `MCP server ${server.name}, declared in ${server.sources.join(', ')}, has no approval in [mcp.approved] for its current declaration (command, arguments, working directory and environment names for a local server; URL, header references and headers helper for a remote one) (sha256 ${server.sha256}), so every harness keeps it disabled`,
|
|
292
|
+
fix: 'a person reviews its declaration, sets its name to the sha256 in this message under [mcp.approved] in cockpit.toml and runs npx --no cockpit sync --config <your cockpit.toml>; while [autonomy] mcp_approve is person, the default, the guard refuses an agent\'s edit of [mcp]. To keep it off, nothing is needed',
|
|
293
|
+
})),
|
|
294
|
+
...prepared.mcpTransportGaps.map(gap => ({
|
|
295
|
+
severity: 'warning', code: 'MCP_TRANSPORT_UNAVAILABLE', target: gap.name,
|
|
296
|
+
message: `${gap.reason}, so sync writes nothing for it there and the server is unavailable in those tools`,
|
|
297
|
+
fix: 'nothing is needed if the server is not wanted in those tools; otherwise declare it with credentials the tool can carry (an environment reference in headers rather than a headersHelper for OpenCode), or remove those tools from [surfaces] tools, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
298
|
+
})),
|
|
299
|
+
// Real sync and check refuse a changed original; a preview reports it so it can be reviewed.
|
|
300
|
+
...prepared.changedOverrideOriginals.map(finding => overrideChanged(finding, 'warning')),
|
|
301
|
+
],
|
|
302
|
+
status: 0,
|
|
303
|
+
result: {
|
|
304
|
+
action,
|
|
305
|
+
dryRun,
|
|
306
|
+
changes,
|
|
307
|
+
generation: prepared.generation,
|
|
308
|
+
sourceSha256: prepared.sourceSha256,
|
|
309
|
+
paths: [...prepared.owned.map(({ path }) => path), ...prepared.surfaces.map(({ path }) => path)].sort(compareCodeUnits),
|
|
310
|
+
application,
|
|
311
|
+
...(staleRemoval ? { staleRemoval } : {}),
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
export function generatedPathFacts(prepared, applicability) {
|
|
316
|
+
const manifest = encodeOwnershipManifest(prepared).manifest;
|
|
317
|
+
const declarations = [
|
|
318
|
+
...prepared.generated.map(file => ({ producer: 'generated-environment', applicability,
|
|
319
|
+
entry: manifest.entries.find(entry => entry.path === file.path) })),
|
|
320
|
+
...prepared.surfaces.map(file => ({ producer: 'surface-render', applicability,
|
|
321
|
+
entry: manifest.entries.find(entry => entry.path === file.path) })),
|
|
322
|
+
];
|
|
323
|
+
return projectGeneratedPathFacts(manifest, { root: prepared.root, cockpitId: prepared.cockpitId, configPath: prepared.configPath }, declarations);
|
|
324
|
+
}
|
|
325
|
+
function isGeneratedApplicationSurfaceObservation(value) {
|
|
326
|
+
return value !== null && typeof value === 'object' && issuedSurfaceObservations.has(value);
|
|
327
|
+
}
|
|
328
|
+
function generatedApplicationSurfaceObservationIssuedAt(value) {
|
|
329
|
+
return value !== null && typeof value === 'object' ? issuedSurfaceObservations.get(value) : undefined;
|
|
330
|
+
}
|
|
331
|
+
export function confined(root, path) {
|
|
332
|
+
if (typeof path !== 'string' || path.length === 0 || path.includes('\0') || isAbsolute(path))
|
|
333
|
+
return undefined;
|
|
334
|
+
const target = resolve(root, path);
|
|
335
|
+
const offset = relative(root, target);
|
|
336
|
+
return offset !== '' && offset !== '..' && !offset.startsWith(`..${sep}`) && !isAbsolute(offset) ? target : undefined;
|
|
337
|
+
}
|
|
338
|
+
export function sourceIdentity(identity) {
|
|
339
|
+
return JSON.stringify({ root: identity.root, chain: identity.chain, file: identity.file });
|
|
340
|
+
}
|
|
341
|
+
export function readSurfaceAsset(path, read) {
|
|
342
|
+
if (read.kind !== 'complete')
|
|
343
|
+
return undefined;
|
|
344
|
+
try {
|
|
345
|
+
return { path, bytes: new TextDecoder('utf-8', { fatal: true }).decode(read.bytes),
|
|
346
|
+
sha256: read.sha256, identity: read.identity };
|
|
347
|
+
}
|
|
348
|
+
catch { /* undecodable bytes are malformed input the caller refuses. */
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
export function mergedAdapters(overrides) {
|
|
353
|
+
return { ...defaultAdapters, ...overrides };
|
|
354
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type EnvironmentObservation } from '../contract.js';
|
|
2
|
+
import { type GeneratedApplicationProjection } from './shared.js';
|
|
3
|
+
export declare const SURFACE_OBSERVATION_CODES: readonly string[];
|
|
4
|
+
export declare function observeGeneratedApplicationSurfaces(application: GeneratedApplicationProjection): readonly EnvironmentObservation[] | undefined;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { surfaceModelSha256 } from '../../surfaces/render.js';
|
|
2
|
+
import { ENVIRONMENT_CODES, snapshotEnvironmentObservation } from '../contract.js';
|
|
3
|
+
import { stackId } from '../identity.js';
|
|
4
|
+
import { OWNER, issuedApplicationProjections, issuedSurfaceObservations } from './shared.js';
|
|
5
|
+
// The rows only this observation answers; when it cannot be made they report missing evidence.
|
|
6
|
+
export const SURFACE_OBSERVATION_CODES = [ENVIRONMENT_CODES.HARNESS_SURFACE_UNAVAILABLE,
|
|
7
|
+
ENVIRONMENT_CODES.DIRECTORY_GRANTS_UNAVAILABLE, ENVIRONMENT_CODES.GUIDE_CAP_EXCEEDED, ENVIRONMENT_CODES.SKILL_BUDGET_UNAVAILABLE];
|
|
8
|
+
export function observeGeneratedApplicationSurfaces(application) {
|
|
9
|
+
const record = application !== null && typeof application === 'object'
|
|
10
|
+
? issuedApplicationProjections.get(application)
|
|
11
|
+
: undefined;
|
|
12
|
+
if (!record?.currentPublication || record.surfaceSelftest !== application.surfaceSelftest)
|
|
13
|
+
return undefined;
|
|
14
|
+
const grantsSha256 = surfaceModelSha256(record.surfaceHealth.grants);
|
|
15
|
+
const availableGuideCosts = record.surfaceHealth.guideCosts.filter((cost) => cost.status !== 'unavailable');
|
|
16
|
+
if (!grantsSha256 || grantsSha256 !== record.surfaceHealth.nativeGrants.modelSha256
|
|
17
|
+
|| availableGuideCosts.length !== record.surfaceHealth.guideCosts.length
|
|
18
|
+
|| availableGuideCosts.some(cost => cost.status !== 'within_cap'))
|
|
19
|
+
return undefined;
|
|
20
|
+
const guideValue = availableGuideCosts.reduce((maximum, cost) => Math.max(maximum, cost.value), 0);
|
|
21
|
+
const guideCap = availableGuideCosts[0]?.cap;
|
|
22
|
+
if (guideCap === undefined || availableGuideCosts.some(cost => cost.cap !== guideCap))
|
|
23
|
+
return undefined;
|
|
24
|
+
const observedAt = record.surfaceHealth.observedAt;
|
|
25
|
+
const required = (posture) => ({ state: 'required', posture });
|
|
26
|
+
const observations = [
|
|
27
|
+
snapshotEnvironmentObservation({
|
|
28
|
+
code: ENVIRONMENT_CODES.HARNESS_SURFACE_UNAVAILABLE, owner: OWNER, stackId: record.stackId,
|
|
29
|
+
source: `surface-manifest:${record.surfaceSelftest.manifestSha256}`,
|
|
30
|
+
observed: { state: 'available', value: { manifestSha256: record.surfaceSelftest.manifestSha256,
|
|
31
|
+
harnesses: record.surfaceSelftest.configuredHarnesses, entries: record.surfaceSelftest.entries.length }, observedAt },
|
|
32
|
+
expectation: { kind: 'present' }, applicability: required('environment'), freshness: { state: 'current' },
|
|
33
|
+
remedy: 'run npx --no cockpit sync --config <your cockpit.toml>, then rerun npx --no cockpit preflight --config <your cockpit.toml>',
|
|
34
|
+
}),
|
|
35
|
+
snapshotEnvironmentObservation({
|
|
36
|
+
code: ENVIRONMENT_CODES.DIRECTORY_GRANTS_UNAVAILABLE, owner: OWNER, stackId: record.stackId,
|
|
37
|
+
source: `directory-grants:${grantsSha256}`,
|
|
38
|
+
observed: { state: 'available', value: { grants: record.surfaceHealth.grants.length,
|
|
39
|
+
generatedFragments: record.surfaceHealth.nativeGrants.fragments.length, modelSha256: grantsSha256 }, observedAt },
|
|
40
|
+
expectation: { kind: 'present' }, applicability: record.surfaceHealth.grants.length > 0
|
|
41
|
+
? required('directory-grants')
|
|
42
|
+
: { state: 'not-applicable', posture: 'directory-grants', reason: 'the active sibling projection declares no directory grants' },
|
|
43
|
+
freshness: { state: 'current' },
|
|
44
|
+
remedy: 'run npx --no cockpit sync --config <your cockpit.toml>, then rerun npx --no cockpit preflight --config <your cockpit.toml>',
|
|
45
|
+
}),
|
|
46
|
+
snapshotEnvironmentObservation({
|
|
47
|
+
code: ENVIRONMENT_CODES.GUIDE_CAP_EXCEEDED, owner: OWNER, stackId: record.stackId,
|
|
48
|
+
source: `surface-guide-costs:${record.surfaceSelftest.manifestSha256}`,
|
|
49
|
+
observed: { state: 'available', value: guideValue, observedAt }, expectation: { kind: 'maximum', value: guideCap },
|
|
50
|
+
applicability: required('environment'), freshness: { state: 'current' },
|
|
51
|
+
remedy: 'move conditional guidance behind its scoped or pull-loaded surface, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
52
|
+
}),
|
|
53
|
+
snapshotEnvironmentObservation({
|
|
54
|
+
code: ENVIRONMENT_CODES.SKILL_BUDGET_UNAVAILABLE, owner: OWNER, stackId: record.stackId,
|
|
55
|
+
source: `installed-skill-inventory:${record.surfaceHealth.skillInventorySha256}`,
|
|
56
|
+
observed: { state: 'available', value: { coreCollectionSha256: record.surfaceHealth.skillCollectionSha256,
|
|
57
|
+
inventorySha256: record.surfaceHealth.skillInventorySha256, inventory: record.surfaceHealth.skillInventory, skills: record.surfaceHealth.skills,
|
|
58
|
+
costs: record.surfaceHealth.skillCosts.map(({ target, metric, value, cap }) => ({ target, metric, value, cap })) }, observedAt },
|
|
59
|
+
expectation: { kind: 'present' }, applicability: required('environment'), freshness: { state: 'current' },
|
|
60
|
+
remedy: 'move skill procedure text out of always-loaded entry points, then run npx --no cockpit sync --config <your cockpit.toml>',
|
|
61
|
+
}),
|
|
62
|
+
];
|
|
63
|
+
if (!observations.every((observation) => observation !== undefined))
|
|
64
|
+
return undefined;
|
|
65
|
+
const issuedAt = Date.now();
|
|
66
|
+
for (const observation of observations)
|
|
67
|
+
issuedSurfaceObservations.set(observation, issuedAt);
|
|
68
|
+
return observations;
|
|
69
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type SurfaceFeature, type SurfaceSourceFile, type SurfaceTarget } from '../../surfaces/contract.js';
|
|
2
|
+
import { type SurfaceGenerationOutcome } from '../../surfaces/generator-adapter.js';
|
|
3
|
+
import { type McpCollectionOutcome } from '../../surfaces/mcp.js';
|
|
4
|
+
import { type NativeFragmentSet } from '../../surfaces/render.js';
|
|
5
|
+
export declare function expectedSurfaceOutputs(tools: readonly SurfaceTarget[], features: readonly SurfaceFeature[], sources: readonly SurfaceSourceFile[]): Readonly<Partial<Record<SurfaceTarget, readonly string[]>>>;
|
|
6
|
+
export declare function expectedClaudePluginOutputs(features: readonly SurfaceFeature[], sources: readonly SurfaceSourceFile[]): readonly string[];
|
|
7
|
+
export declare function claudePluginManifest(): Readonly<{
|
|
8
|
+
bytes: string;
|
|
9
|
+
sha256: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function alwaysLoadedRule(bytes: string): Readonly<{
|
|
12
|
+
kind: 'complete';
|
|
13
|
+
bytes: string;
|
|
14
|
+
}> | Readonly<{
|
|
15
|
+
kind: 'refusal';
|
|
16
|
+
reason: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function emptyGeneration(): Extract<SurfaceGenerationOutcome, {
|
|
19
|
+
kind: 'complete';
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* OpenCode's native read tool asks its `read` permission with the file path relative to the Git
|
|
23
|
+
* worktree, and its `*` matches across `/`, so each protected path is denied both as written and
|
|
24
|
+
* below any prefix: that covers a cockpit root nested in a larger repository and siblings reached
|
|
25
|
+
* through `../`. Only `*` and `?` are pattern characters there; either one in a path becomes `?`,
|
|
26
|
+
* which over-matches a deny and so stays safe. The plugin's guard routing refuses the same reads,
|
|
27
|
+
* case-folded; these rules still deny the declared spellings when the plugin cannot load.
|
|
28
|
+
*/
|
|
29
|
+
export declare function openCodeReadDenials(siblings: readonly {
|
|
30
|
+
slug: string;
|
|
31
|
+
path: string;
|
|
32
|
+
}[], instances: readonly {
|
|
33
|
+
slug: string;
|
|
34
|
+
path: string;
|
|
35
|
+
}[]): readonly string[];
|
|
36
|
+
/** The machine-local file `sync` writes with a sibling's absolute directory, for OpenCode to read. */
|
|
37
|
+
export declare function openCodeGrantFile(slug: string): string;
|
|
38
|
+
export declare const GUIDE_LOAD_CHARACTERIZATIONS: Readonly<{
|
|
39
|
+
[k: string]: {
|
|
40
|
+
measuredOn: string;
|
|
41
|
+
metric: 'lines';
|
|
42
|
+
scopeSemantics: "conditional" | "full";
|
|
43
|
+
provenance: string;
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
46
|
+
export declare function nativeSources(mcp: Extract<McpCollectionOutcome, {
|
|
47
|
+
kind: 'complete';
|
|
48
|
+
}>, grants: readonly {
|
|
49
|
+
slug: string;
|
|
50
|
+
target: SurfaceTarget;
|
|
51
|
+
path: string;
|
|
52
|
+
}[], siblings: readonly {
|
|
53
|
+
slug: string;
|
|
54
|
+
path: string;
|
|
55
|
+
}[], instances: readonly {
|
|
56
|
+
slug: string;
|
|
57
|
+
path: string;
|
|
58
|
+
}[]): readonly SurfaceSourceFile[];
|
|
59
|
+
export declare function nativeFragmentSet(generated: Extract<SurfaceGenerationOutcome, {
|
|
60
|
+
kind: 'complete';
|
|
61
|
+
}>, model: unknown, paths: Readonly<Partial<Record<SurfaceTarget, string>>>): NativeFragmentSet | undefined;
|
|
62
|
+
export declare function nativeGrantFragmentSet(generated: Extract<SurfaceGenerationOutcome, {
|
|
63
|
+
kind: 'complete';
|
|
64
|
+
}>, grants: readonly Readonly<{
|
|
65
|
+
slug: string;
|
|
66
|
+
target: SurfaceTarget;
|
|
67
|
+
path: string;
|
|
68
|
+
}>[], paths: Readonly<Partial<Record<SurfaceTarget, string>>>, openCodeReads: readonly string[]): NativeFragmentSet | undefined;
|
|
69
|
+
export declare function bindNativeGrantsToMcp(mcp: NativeFragmentSet, grants: NativeFragmentSet): NativeFragmentSet | undefined;
|
|
70
|
+
export declare function nativeMcpPaths(targets: readonly SurfaceTarget[]): Readonly<Partial<Record<SurfaceTarget, string>>>;
|
|
71
|
+
export declare function nativeGrantPaths(targets: readonly SurfaceTarget[]): Readonly<Partial<Record<SurfaceTarget, string>>>;
|