@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,22 @@
|
|
|
1
|
+
// Locates and fingerprints the programs cockpit ships in packages/cockpit/libexec/. A step that runs
|
|
2
|
+
// one lists it as a consumed file with this digest, so the executor runs a private snapshot of exactly
|
|
3
|
+
// the bytes hashed here and refuses a program edited or replaced in between. The snapshot runs outside
|
|
4
|
+
// libexec/, so a program launched this way must not require its sibling files.
|
|
5
|
+
import { createHash } from 'node:crypto';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { RefusalError, errorCause } from '../environment/contract.js';
|
|
8
|
+
import { readBoundedFile } from '../bounded-read.js';
|
|
9
|
+
const PROGRAM_MAX_BYTES = 1_048_576;
|
|
10
|
+
export function libexecProgram(name) {
|
|
11
|
+
const path = fileURLToPath(new URL(`../../libexec/${name}`, import.meta.url));
|
|
12
|
+
try {
|
|
13
|
+
const read = readBoundedFile(path, PROGRAM_MAX_BYTES);
|
|
14
|
+
if (read.kind !== 'complete')
|
|
15
|
+
throw new RefusalError(`larger than ${PROGRAM_MAX_BYTES} bytes`);
|
|
16
|
+
return { path, sha256: createHash('sha256').update(read.bytes).digest('hex'), maxBytes: PROGRAM_MAX_BYTES };
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new RefusalError(`cockpit's bundled program ${path} cannot be authenticated (${errorCause(error)}); `
|
|
20
|
+
+ 'cockpit runs only bundled programs whose bytes it hashed — fix: reinstall @b00dea/cockpit', { cause: error });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Stats } from 'node:fs';
|
|
2
|
+
export declare function fileFingerprint(path: string, status: Pick<Stats, 'dev' | 'ino' | 'size' | 'mode' | 'mtimeMs' | 'ctimeMs'>): string;
|
|
3
|
+
export declare function recordVerifiedDigest(fingerprint: string, sha256: string): void;
|
|
4
|
+
export declare function verifiedDigest(fingerprint: string): string | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const MAX_ENTRIES = 64;
|
|
2
|
+
const verified = new Map();
|
|
3
|
+
export function fileFingerprint(path, status) {
|
|
4
|
+
return JSON.stringify([path, status.dev, status.ino, status.size, status.mode, status.mtimeMs, status.ctimeMs]);
|
|
5
|
+
}
|
|
6
|
+
export function recordVerifiedDigest(fingerprint, sha256) {
|
|
7
|
+
if (!/^[a-f0-9]{64}$/.test(sha256))
|
|
8
|
+
throw new TypeError('verified digest must be a SHA-256 hex string');
|
|
9
|
+
verified.delete(fingerprint);
|
|
10
|
+
verified.set(fingerprint, sha256);
|
|
11
|
+
if (verified.size > MAX_ENTRIES)
|
|
12
|
+
verified.delete(verified.keys().next().value);
|
|
13
|
+
}
|
|
14
|
+
export function verifiedDigest(fingerprint) {
|
|
15
|
+
return verified.get(fingerprint);
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** True when `value` has every `required` own enumerable key and no key outside `required` and `optional`. */
|
|
2
|
+
export declare function exactKeys(value: object, required: readonly string[], optional?: readonly string[]): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* The same check over every own key, enumerable or not, refusing symbol keys and accessors. Envelopes a
|
|
5
|
+
* caller hands back are checked this way, so that reading them later invokes nothing the caller planted.
|
|
6
|
+
*/
|
|
7
|
+
export declare function exactOwnKeys(value: object, required: readonly string[]): boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** True when `value` has every `required` own enumerable key and no key outside `required` and `optional`. */
|
|
2
|
+
export function exactKeys(value, required, optional = []) {
|
|
3
|
+
const keys = Object.keys(value);
|
|
4
|
+
return required.every((key) => keys.includes(key)) && keys.every((key) => required.includes(key) || optional.includes(key));
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The same check over every own key, enumerable or not, refusing symbol keys and accessors. Envelopes a
|
|
8
|
+
* caller hands back are checked this way, so that reading them later invokes nothing the caller planted.
|
|
9
|
+
*/
|
|
10
|
+
export function exactOwnKeys(value, required) {
|
|
11
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
12
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
13
|
+
return keys.every((key) => typeof key === 'string' && 'value' in descriptors[key] && required.includes(key))
|
|
14
|
+
&& required.every((key) => keys.includes(key));
|
|
15
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Diagnostic } from './environment/contract.js';
|
|
2
|
+
export type ConfiguredCommand = 'setup' | 'sync' | 'check' | 'confirm' | 'selftest' | 'upgrade' | 'up' | 'sleep' | 'session' | 'down' | 'reset' | 'preflight' | 'doctor' | 'logs' | 'runtime measure' | 'sibling add' | 'sibling remove' | 'stacks' | 'stacks prune' | 'docs check' | 'use' | 'pull';
|
|
3
|
+
export interface FixContext {
|
|
4
|
+
readonly resolvedConfigPath: string | null;
|
|
5
|
+
readonly generatedTargets: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export interface ExecutableFix {
|
|
8
|
+
readonly argv: readonly ['npx', '--no', 'cockpit', 'sync', '--config', string];
|
|
9
|
+
readonly command: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function formatShellCommand(argv: readonly string[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* The runnable spelling of a cockpit command. `operand` (a sibling slug) precedes --config as in
|
|
14
|
+
* the command's usage line; `args` follows it as written, so it may hold `<placeholders>`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function cockpitCommand(command: ConfiguredCommand, options?: Readonly<{
|
|
17
|
+
config?: string;
|
|
18
|
+
operand?: string;
|
|
19
|
+
args?: string;
|
|
20
|
+
}>): string;
|
|
21
|
+
/**
|
|
22
|
+
* The runnable spelling of init, which takes its root operand and --target instead of --config.
|
|
23
|
+
* A root or target the producer does not know prints as a placeholder for the reader to fill in.
|
|
24
|
+
*/
|
|
25
|
+
export declare function initCommand(options?: Readonly<{
|
|
26
|
+
root?: string;
|
|
27
|
+
target?: string;
|
|
28
|
+
args?: string;
|
|
29
|
+
}>): string;
|
|
30
|
+
/** Replaces the configuration placeholder in printed text with the resolved path, shell-quoted. */
|
|
31
|
+
export declare function bindConfigPath(text: string, context?: FixContext): string;
|
|
32
|
+
export declare function admitDiagnosticFix(diagnostic: Diagnostic, context?: FixContext): ExecutableFix | undefined;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { dirname, isAbsolute, normalize } from 'node:path';
|
|
2
|
+
// A printed command has to run as printed. Nothing goes in front of npx: the guard asks before a
|
|
3
|
+
// wrapped command such as `env -u NAME …`, and Codex and OpenCode treat an ask as a denial. Every
|
|
4
|
+
// configured command refuses without --config, so a remedy written where the path is unknown names
|
|
5
|
+
// this placeholder, and bindConfigPath replaces it with the resolved path wherever the command line
|
|
6
|
+
// supplied one.
|
|
7
|
+
const CONFIG_PLACEHOLDER = '<your cockpit.toml>';
|
|
8
|
+
const unsafeControl = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u2028-\u202e\u2066-\u2069]/;
|
|
9
|
+
const plainShellArgument = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
10
|
+
export function formatShellCommand(argv) {
|
|
11
|
+
return argv.map((argument) => plainShellArgument.test(argument)
|
|
12
|
+
? argument
|
|
13
|
+
: `'${argument.replaceAll("'", "'\"'\"'")}'`).join(' ');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The runnable spelling of a cockpit command. `operand` (a sibling slug) precedes --config as in
|
|
17
|
+
* the command's usage line; `args` follows it as written, so it may hold `<placeholders>`.
|
|
18
|
+
*/
|
|
19
|
+
export function cockpitCommand(command, options = {}) {
|
|
20
|
+
const config = options.config === undefined ? CONFIG_PLACEHOLDER : formatShellCommand([options.config]);
|
|
21
|
+
const operand = options.operand === undefined ? '' : ` ${formatShellCommand([options.operand])}`;
|
|
22
|
+
return `npx --no cockpit ${command}${operand} --config ${config}${options.args === undefined ? '' : ` ${options.args}`}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The runnable spelling of init, which takes its root operand and --target instead of --config.
|
|
26
|
+
* A root or target the producer does not know prints as a placeholder for the reader to fill in.
|
|
27
|
+
*/
|
|
28
|
+
export function initCommand(options = {}) {
|
|
29
|
+
const root = options.root === undefined ? '<cockpit root>' : formatShellCommand([options.root]);
|
|
30
|
+
const target = options.target === undefined ? '<target>' : formatShellCommand([options.target]);
|
|
31
|
+
return `npx --no cockpit init ${root} --target ${target}${options.args === undefined ? '' : ` ${options.args}`}`;
|
|
32
|
+
}
|
|
33
|
+
function bindablePath(path) {
|
|
34
|
+
return typeof path === 'string' && isAbsolute(path) && normalize(path) === path && dirname(path) !== path
|
|
35
|
+
&& !unsafeControl.test(path);
|
|
36
|
+
}
|
|
37
|
+
/** Replaces the configuration placeholder in printed text with the resolved path, shell-quoted. */
|
|
38
|
+
export function bindConfigPath(text, context) {
|
|
39
|
+
const path = context?.resolvedConfigPath;
|
|
40
|
+
return bindablePath(path) ? text.replaceAll(`--config ${CONFIG_PLACEHOLDER}`, `--config ${formatShellCommand([path])}`) : text;
|
|
41
|
+
}
|
|
42
|
+
function safeTarget(target) {
|
|
43
|
+
return !unsafeControl.test(target) && !target.includes('\\') && !target.includes(':')
|
|
44
|
+
&& target.split('/').every(part => part !== '' && part !== '.' && part !== '..');
|
|
45
|
+
}
|
|
46
|
+
// The one remedy the catalogue executes. Producers keep it as a string literal so the diagnostic
|
|
47
|
+
// inventory captures it beside its code; the catalogue admits only this exact spelling.
|
|
48
|
+
const GENERATED_DRIFT_FIX = `run ${cockpitCommand('sync')}`;
|
|
49
|
+
export function admitDiagnosticFix(diagnostic, context) {
|
|
50
|
+
if (diagnostic.severity !== 'error' || diagnostic.code !== 'GENERATED_ARTIFACT_DRIFT'
|
|
51
|
+
|| diagnostic.fix !== GENERATED_DRIFT_FIX || !diagnostic.target || !context)
|
|
52
|
+
return undefined;
|
|
53
|
+
const path = context.resolvedConfigPath;
|
|
54
|
+
if (!bindablePath(path) || !safeTarget(diagnostic.target)
|
|
55
|
+
|| !context.generatedTargets.includes(diagnostic.target))
|
|
56
|
+
return undefined;
|
|
57
|
+
const argv = ['npx', '--no', 'cockpit', 'sync', '--config', path];
|
|
58
|
+
const command = formatShellCommand(argv);
|
|
59
|
+
return { argv, command };
|
|
60
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type ReleaseFreshness = Readonly<{
|
|
2
|
+
kind: 'known';
|
|
3
|
+
package: string;
|
|
4
|
+
installedVersion: string;
|
|
5
|
+
latestVersion: string;
|
|
6
|
+
currency: 'same-version' | 'different-version';
|
|
7
|
+
observedAt: string;
|
|
8
|
+
expiresAt: string;
|
|
9
|
+
}> | Readonly<{
|
|
10
|
+
kind: 'unknown';
|
|
11
|
+
reason: string;
|
|
12
|
+
observedAt?: string;
|
|
13
|
+
expiresAt?: string;
|
|
14
|
+
}>;
|
|
15
|
+
export type ReleaseMetadataTransport = (request: Readonly<{
|
|
16
|
+
url: string;
|
|
17
|
+
signal: AbortSignal;
|
|
18
|
+
}>) => Promise<Readonly<{
|
|
19
|
+
status: number;
|
|
20
|
+
body: AsyncIterable<Uint8Array>;
|
|
21
|
+
}>>;
|
|
22
|
+
interface ReleaseDiscoveryInput {
|
|
23
|
+
readonly verb: string;
|
|
24
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
25
|
+
readonly createTransport?: () => ReleaseMetadataTransport;
|
|
26
|
+
readonly now?: () => number;
|
|
27
|
+
}
|
|
28
|
+
export declare function discoverReleaseFreshness(input: ReleaseDiscoveryInput): Promise<ReleaseFreshness>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { get } from 'node:https';
|
|
2
|
+
import { installedPackageMetadata } from './package-metadata.js';
|
|
3
|
+
import { RefusalError, errorCause } from './environment/contract.js';
|
|
4
|
+
const MAX_BYTES = 131_072;
|
|
5
|
+
const TIMEOUT_MS = 2_000;
|
|
6
|
+
const CACHE_MS = 900_000;
|
|
7
|
+
const cache = new WeakMap();
|
|
8
|
+
const createTransport = () => ({ url, signal }) => new Promise((resolve, reject) => {
|
|
9
|
+
const request = get(url, { signal, headers: { accept: 'application/json' } }, response => {
|
|
10
|
+
resolve({ status: response.statusCode ?? 0, body: response });
|
|
11
|
+
});
|
|
12
|
+
request.on('error', reject);
|
|
13
|
+
});
|
|
14
|
+
async function query(factory, now) {
|
|
15
|
+
const observedAt = new Date(now).toISOString();
|
|
16
|
+
const expiresAt = new Date(now + CACHE_MS).toISOString();
|
|
17
|
+
const controller = new AbortController();
|
|
18
|
+
let timer;
|
|
19
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
20
|
+
timer = setTimeout(() => { controller.abort(); reject(new RefusalError('release metadata query timed out')); }, TIMEOUT_MS);
|
|
21
|
+
});
|
|
22
|
+
try {
|
|
23
|
+
const transport = factory();
|
|
24
|
+
const result = await Promise.race([timeout, (async () => {
|
|
25
|
+
const response = await transport({ url: `https://registry.npmjs.org/${encodeURIComponent(installedPackageMetadata.name)}/latest`, signal: controller.signal });
|
|
26
|
+
if (response.status !== 200)
|
|
27
|
+
throw new RefusalError(`release metadata returned HTTP ${response.status}`);
|
|
28
|
+
const chunks = [];
|
|
29
|
+
let size = 0;
|
|
30
|
+
for await (const chunk of response.body) {
|
|
31
|
+
size += chunk.byteLength;
|
|
32
|
+
if (size > MAX_BYTES) {
|
|
33
|
+
controller.abort();
|
|
34
|
+
throw new RefusalError('release metadata exceeded byte limit');
|
|
35
|
+
}
|
|
36
|
+
chunks.push(chunk);
|
|
37
|
+
}
|
|
38
|
+
const value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks)));
|
|
39
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)
|
|
40
|
+
|| !('name' in value) || value.name !== installedPackageMetadata.name || !('version' in value)
|
|
41
|
+
|| typeof value.version !== 'string' || value.version.length > 256
|
|
42
|
+
|| !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(value.version))
|
|
43
|
+
throw new RefusalError('release metadata schema or package identity is invalid');
|
|
44
|
+
return { kind: 'known', package: installedPackageMetadata.name,
|
|
45
|
+
installedVersion: installedPackageMetadata.version, latestVersion: value.version,
|
|
46
|
+
currency: value.version === installedPackageMetadata.version ? 'same-version' : 'different-version', observedAt, expiresAt };
|
|
47
|
+
})()]);
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return { kind: 'unknown', reason: errorCause(error), observedAt, expiresAt };
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
if (timer)
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
controller.abort();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function discoverReleaseFreshness(input) {
|
|
60
|
+
// Admissions precede even cache access: an opted-out caller must not reuse online evidence.
|
|
61
|
+
if (input.env.CI)
|
|
62
|
+
return Promise.resolve({ kind: 'unknown', reason: 'release discovery disabled by CI' });
|
|
63
|
+
if (input.env.NO_UPDATE_NOTIFIER)
|
|
64
|
+
return Promise.resolve({ kind: 'unknown', reason: 'release discovery disabled by NO_UPDATE_NOTIFIER' });
|
|
65
|
+
if (input.verb !== 'doctor')
|
|
66
|
+
return Promise.resolve({ kind: 'unknown', reason: 'release discovery is doctor-only' });
|
|
67
|
+
const factory = input.createTransport ?? createTransport;
|
|
68
|
+
const now = (input.now ?? Date.now)();
|
|
69
|
+
const existing = cache.get(factory);
|
|
70
|
+
if (existing && existing.expiresAt > now)
|
|
71
|
+
return existing.value;
|
|
72
|
+
const value = query(factory, now);
|
|
73
|
+
cache.set(factory, { expiresAt: now + CACHE_MS, value });
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Diagnostic } from '../diagnostics.js';
|
|
2
|
+
import { type PublicationAdapters } from './transaction.js';
|
|
3
|
+
export interface SyncAdoptionInput {
|
|
4
|
+
readonly configPath: string;
|
|
5
|
+
readonly adopt: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
export interface SyncAdoptionOutcome {
|
|
8
|
+
readonly status: number;
|
|
9
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
10
|
+
readonly result: unknown;
|
|
11
|
+
readonly artifact?: string | null;
|
|
12
|
+
readonly destination?: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function runSyncAdoption(input: SyncAdoptionInput, synchronize: (input: Readonly<{
|
|
15
|
+
configPath: string;
|
|
16
|
+
}>) => Promise<SyncAdoptionOutcome>, adapterOverrides?: Partial<PublicationAdapters>): Promise<SyncAdoptionOutcome>;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns `cockpit sync --adopt <path>`: it takes a team's existing harness settings file into cockpit
|
|
3
|
+
* without losing it. The file's bytes move to `cockpit/adopted/<path>`, one `[[surfaces.adopted]]`
|
|
4
|
+
* row records them in cockpit.toml, and the ordinary sync then renders the merge in its place.
|
|
5
|
+
*
|
|
6
|
+
* It decides whether a file may be adopted and records it; the merge rules live in
|
|
7
|
+
* `surfaces/adoption.ts`, the cockpit.toml write in `config/verified-write.ts`, and publication in
|
|
8
|
+
* the sync it hands off to. Filesystem access crosses the authenticated transaction helper rather
|
|
9
|
+
* than introducing another runner. A sync that refuses before writing the merged file is rolled
|
|
10
|
+
* back, so a refused adoption does not silently leave the team's settings moved aside.
|
|
11
|
+
*/
|
|
12
|
+
import { sha256Hex } from '../sha256.js';
|
|
13
|
+
import { canonicalJson } from '../canonical-json.js';
|
|
14
|
+
import { basename, dirname, resolve } from 'node:path';
|
|
15
|
+
import { parse, TomlError } from 'smol-toml';
|
|
16
|
+
import { loadCockpitConfig, STRUCTURED_INPUT_BYTE_LIMIT } from '../config/load.js';
|
|
17
|
+
import { writeVerifiedConfig } from '../config/verified-write.js';
|
|
18
|
+
import { executeProbe } from '../environment-exec/execute.js';
|
|
19
|
+
import { ENVIRONMENT_CODES, errorCause } from '../environment/contract.js';
|
|
20
|
+
import { publicationCockpitId } from '../environment/identity.js';
|
|
21
|
+
import { CockpitConfig, SurfaceAdoption } from '../schema.js';
|
|
22
|
+
import { adoptedCopyPath, inspectAdoptedSettings } from '../surfaces/adoption.js';
|
|
23
|
+
import { ADOPTABLE_SURFACE_PATHS, SURFACE_FILE_MAX_BYTES } from '../surfaces/contract.js';
|
|
24
|
+
import { parseOwnershipManifest } from '../surfaces/ownership.js';
|
|
25
|
+
import { refusalOutcome as refused } from '../refusal.js';
|
|
26
|
+
import { nodeAuthority, readAnchoredEntry, readAnchoredFile, relocateAnchoredFile, restoreAnchoredFile } from './transaction.js';
|
|
27
|
+
const OWNERSHIP_PATH = '.cockpit/generated-environment-ownership.json';
|
|
28
|
+
// A TOML parse error quotes the lines around the failure, and cockpit.toml can hold secrets that must
|
|
29
|
+
// not reach a refusal: name where parsing stopped, never the text there.
|
|
30
|
+
function tomlFailure(error) {
|
|
31
|
+
return error instanceof TomlError ? `TOML error at line ${error.line}, column ${error.column}` : errorCause(error);
|
|
32
|
+
}
|
|
33
|
+
const ADOPT_BY_HAND_FIX = 'move the settings file to cockpit/adopted/<the same path>, add its [[surfaces.adopted]] row to cockpit.toml by hand with the fields the configuration reference lists, then run npx --no cockpit sync --config <your cockpit.toml>';
|
|
34
|
+
function adoptionTable(row) {
|
|
35
|
+
return [
|
|
36
|
+
'[[surfaces.adopted]]',
|
|
37
|
+
`path = ${JSON.stringify(row.path)}`,
|
|
38
|
+
`source = ${JSON.stringify(row.source)}`,
|
|
39
|
+
`sha256 = ${JSON.stringify(row.sha256)}`,
|
|
40
|
+
`adopted_on = ${JSON.stringify(row.adopted_on)}`,
|
|
41
|
+
`provenance = { source = ${JSON.stringify(row.provenance.source)}, observed_on = ${JSON.stringify(row.provenance.observed_on)}, kind = "declared", reason = ${JSON.stringify(row.provenance.reason)} }`,
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
/** Validate one requested path completely before anything moves. */
|
|
45
|
+
async function candidate(root, requested, owned, adopted, node, adapters) {
|
|
46
|
+
if (!ADOPTABLE_SURFACE_PATHS.includes(requested)) {
|
|
47
|
+
return refused('CLI_USAGE_INVALID', `--adopt ${JSON.stringify(requested)} is not an adoptable harness settings file; adoptable: ${ADOPTABLE_SURFACE_PATHS.join(', ')}`, '--adopt');
|
|
48
|
+
}
|
|
49
|
+
const path = requested;
|
|
50
|
+
const destinationPath = adoptedCopyPath(path);
|
|
51
|
+
if (adopted.has(path)) {
|
|
52
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${path} is already adopted from ${destinationPath}. Delete the duplicate ${path} and run npx --no cockpit sync --config <your cockpit.toml>; its settings are kept in ${destinationPath}`, path);
|
|
53
|
+
}
|
|
54
|
+
if (owned.has(path))
|
|
55
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${path} is cockpit's own published output, not a team file; nothing to adopt`, path);
|
|
56
|
+
const target = path;
|
|
57
|
+
const source = await readAnchoredFile(root, target, SURFACE_FILE_MAX_BYTES, node, adapters);
|
|
58
|
+
if (source.kind === 'missing')
|
|
59
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${path} does not exist; there is nothing to adopt`, path);
|
|
60
|
+
if (source.kind !== 'complete') {
|
|
61
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${path} could not be read as one stable regular file no larger than ${SURFACE_FILE_MAX_BYTES} bytes. Replace links, special files, or oversized content with the plain settings file inside the cockpit root, then re-run npx --no cockpit sync --config <your cockpit.toml> --adopt ${path}`, path);
|
|
62
|
+
}
|
|
63
|
+
let text;
|
|
64
|
+
try {
|
|
65
|
+
text = new TextDecoder('utf-8', { fatal: true }).decode(source.bytes);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// undecodable bytes are malformed input the caller refuses.
|
|
69
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${path} is not UTF-8 text`, path);
|
|
70
|
+
}
|
|
71
|
+
const inspected = inspectAdoptedSettings(path, text, path);
|
|
72
|
+
if (inspected.kind !== 'complete')
|
|
73
|
+
return refused(inspected.diagnostic.code, inspected.diagnostic.message, inspected.diagnostic.target);
|
|
74
|
+
const destination = await readAnchoredEntry(root, destinationPath, SURFACE_FILE_MAX_BYTES, node, adapters);
|
|
75
|
+
if (destination.kind === 'invalid')
|
|
76
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${destinationPath} could not be confirmed missing through plain directories inside the cockpit root. Remove links, special files, oversized files, or unstable entries on that path, then re-run npx --no cockpit sync --config <your cockpit.toml> --adopt ${path}`, path);
|
|
77
|
+
if (destination.kind !== 'missing')
|
|
78
|
+
return refused('SURFACE_ADOPTION_REFUSED', `${destinationPath} already exists; move it aside before adopting ${path}`, destinationPath);
|
|
79
|
+
return { path, target, destination: destinationPath, sha256: source.sha256 };
|
|
80
|
+
}
|
|
81
|
+
async function ownedPaths(root, configPath, name, node, adapters) {
|
|
82
|
+
const read = await readAnchoredFile(root, OWNERSHIP_PATH, STRUCTURED_INPUT_BYTE_LIMIT, node, adapters);
|
|
83
|
+
if (read.kind === 'missing')
|
|
84
|
+
return new Set();
|
|
85
|
+
if (read.kind !== 'complete')
|
|
86
|
+
return refused('GENERATED_OWNERSHIP_INVALID', `generated ownership metadata could not be read as one stable regular file no larger than ${STRUCTURED_INPUT_BYTE_LIMIT} bytes. Restore a plain ${OWNERSHIP_PATH} inside the cockpit root or remove the invalid entry, then re-run the command`, OWNERSHIP_PATH);
|
|
87
|
+
let bytes;
|
|
88
|
+
try {
|
|
89
|
+
bytes = new TextDecoder('utf-8', { fatal: true }).decode(read.bytes);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// undecodable bytes are malformed input the caller refuses.
|
|
93
|
+
return refused('GENERATED_OWNERSHIP_INVALID', 'generated ownership metadata is not UTF-8 text, so whether a file is cockpit\'s own cannot be decided', OWNERSHIP_PATH);
|
|
94
|
+
}
|
|
95
|
+
const manifest = parseOwnershipManifest(bytes, { root, cockpitId: publicationCockpitId({ name }), configPath });
|
|
96
|
+
if (manifest.kind !== 'complete')
|
|
97
|
+
return refused('GENERATED_OWNERSHIP_INVALID', 'generated ownership metadata is unreadable, so whether a file is cockpit\'s own cannot be decided', OWNERSHIP_PATH);
|
|
98
|
+
return new Set(manifest.manifest.entries.map(entry => entry.path));
|
|
99
|
+
}
|
|
100
|
+
/** Undo the moves, newest first. Every failure is reported; none is swallowed. */
|
|
101
|
+
async function restoreMoves(root, moved, node, adapters) {
|
|
102
|
+
const failures = [];
|
|
103
|
+
for (const item of [...moved].reverse()) {
|
|
104
|
+
try {
|
|
105
|
+
const restored = await restoreAnchoredFile(root, item.target, item.destination, SURFACE_FILE_MAX_BYTES, item.sha256, node, adapters);
|
|
106
|
+
if (restored.kind !== 'complete')
|
|
107
|
+
failures.push(`${adoptedCopyPath(item.path)} could not be safely moved back to ${item.path}. Preserve both paths; restore the file whose SHA-256 is ${item.sha256} to ${item.path}, then re-run the command`);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
failures.push(`${adoptedCopyPath(item.path)} could not be safely moved back to ${item.path} (${errorCause(error)}). Preserve both paths; restore the file whose SHA-256 is ${item.sha256} to ${item.path}, then re-run the command`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return failures;
|
|
114
|
+
}
|
|
115
|
+
export async function runSyncAdoption(input, synchronize, adapterOverrides = {}) {
|
|
116
|
+
if (input.adopt.length === 0 || new Set(input.adopt).size !== input.adopt.length) {
|
|
117
|
+
return refused('CLI_USAGE_INVALID', 'name each harness settings file to adopt once with --adopt <path>', '--adopt');
|
|
118
|
+
}
|
|
119
|
+
const loaded = await loadCockpitConfig(input.configPath);
|
|
120
|
+
if (loaded.kind !== 'complete')
|
|
121
|
+
return { status: 2, result: null, diagnostics: loaded.diagnostics };
|
|
122
|
+
const configPath = loaded.result.source.path;
|
|
123
|
+
const root = dirname(configPath);
|
|
124
|
+
const config = loaded.result.config;
|
|
125
|
+
const node = await nodeAuthority();
|
|
126
|
+
if (!node)
|
|
127
|
+
return refused('GENERATED_EXECUTABLE_UNAVAILABLE', 'adoption requires an authenticated Node filesystem helper; reinstall cockpit and re-run the command', process.execPath);
|
|
128
|
+
const adapters = { execute: adapterOverrides.execute ?? executeProbe };
|
|
129
|
+
const owned = await ownedPaths(root, configPath, config.cockpit.name, node, adapters);
|
|
130
|
+
if (!(owned instanceof Set))
|
|
131
|
+
return owned;
|
|
132
|
+
const already = new Set(config.surfaces.adopted.map(row => row.path));
|
|
133
|
+
const candidates = [];
|
|
134
|
+
for (const requested of input.adopt) {
|
|
135
|
+
const checked = await candidate(root, requested, owned, already, node, adapters);
|
|
136
|
+
if ('status' in checked)
|
|
137
|
+
return checked;
|
|
138
|
+
candidates.push(checked);
|
|
139
|
+
}
|
|
140
|
+
const original = await readAnchoredFile(root, basename(configPath), STRUCTURED_INPUT_BYTE_LIMIT, node, adapters);
|
|
141
|
+
if (original.kind !== 'complete' || original.sha256 !== loaded.result.source.sha256) {
|
|
142
|
+
return refused(ENVIRONMENT_CODES.CONFIG_CHANGED_DURING_EXECUTION, 'cockpit.toml changed while it was being read; nothing was moved. Re-run the command', configPath);
|
|
143
|
+
}
|
|
144
|
+
const originalText = new TextDecoder('utf-8', { fatal: true }).decode(original.bytes);
|
|
145
|
+
const adoptedOn = new Date().toISOString().slice(0, 10);
|
|
146
|
+
const rows = candidates.map(item => SurfaceAdoption.parse({
|
|
147
|
+
path: item.path, source: adoptedCopyPath(item.path), sha256: item.sha256, adopted_on: adoptedOn,
|
|
148
|
+
provenance: { source: item.path, observed_on: adoptedOn, kind: 'declared', reason: 'the team\'s own harness settings, moved aside by cockpit sync --adopt and merged with cockpit\'s rendering' },
|
|
149
|
+
}));
|
|
150
|
+
const nextText = `${originalText}${originalText.endsWith('\n') ? '' : '\n'}${rows.map(row => `\n${adoptionTable(row)}\n`).join('')}`;
|
|
151
|
+
const expected = { ...config, surfaces: { ...config.surfaces, adopted: [...config.surfaces.adopted, ...rows] } };
|
|
152
|
+
let candidateConfig;
|
|
153
|
+
try {
|
|
154
|
+
candidateConfig = CockpitConfig.safeParse(parse(nextText));
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return refused(ENVIRONMENT_CODES.CONFIG_PARSE_INVALID, `recording the adoption would leave cockpit.toml unparseable (${tomlFailure(error)}); nothing was moved`, configPath, ADOPT_BY_HAND_FIX);
|
|
158
|
+
}
|
|
159
|
+
if (!candidateConfig.success || canonicalJson(candidateConfig.data) !== canonicalJson(expected)) {
|
|
160
|
+
return refused(ENVIRONMENT_CODES.CONFIG_SCHEMA_INVALID, 'recording the adoption would change more than the [[surfaces.adopted]] rows; nothing was moved', configPath, ADOPT_BY_HAND_FIX);
|
|
161
|
+
}
|
|
162
|
+
const moved = [];
|
|
163
|
+
const rollback = async (reason, configState, uncertainty = []) => {
|
|
164
|
+
const failures = await restoreMoves(root, moved, node, adapters);
|
|
165
|
+
let restoreConfig = configState === 'written';
|
|
166
|
+
if (configState === 'unknown') {
|
|
167
|
+
try {
|
|
168
|
+
const current = await readAnchoredFile(root, basename(configPath), STRUCTURED_INPUT_BYTE_LIMIT, node, adapters);
|
|
169
|
+
if (current.kind === 'complete' && current.sha256 === sha256Hex(originalText))
|
|
170
|
+
restoreConfig = false;
|
|
171
|
+
else if (current.kind === 'complete' && current.sha256 === sha256Hex(nextText))
|
|
172
|
+
restoreConfig = true;
|
|
173
|
+
else
|
|
174
|
+
failures.push(`cockpit.toml could not be matched to either the original or adopted configuration. Preserve it and restore the version whose SHA-256 is ${sha256Hex(originalText)} before retrying`);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
failures.push(`cockpit.toml could not be checked after the failed write (${errorCause(error)}). Preserve it and restore the version whose SHA-256 is ${sha256Hex(originalText)} before retrying`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (restoreConfig) {
|
|
181
|
+
const fix = `restore cockpit.toml to SHA-256 ${sha256Hex(originalText)} before retrying`;
|
|
182
|
+
try {
|
|
183
|
+
const restored = await writeVerifiedConfig({
|
|
184
|
+
path: configPath, expectedSha256: sha256Hex(nextText), temporaryTag: 'adopt',
|
|
185
|
+
edit: () => originalText,
|
|
186
|
+
isExactChange: (value) => canonicalJson(value) === canonicalJson(config),
|
|
187
|
+
messages: {
|
|
188
|
+
changedBefore: { message: 'cockpit.toml changed after the adoption was recorded, so its [[surfaces.adopted]] rows were left in place', fix },
|
|
189
|
+
changedDuring: { message: 'cockpit.toml changed while the adoption was being undone, so its [[surfaces.adopted]] rows were left in place', fix },
|
|
190
|
+
invalid: (detail) => ({ message: `undoing the adoption would leave cockpit.toml invalid (${detail})`, fix }),
|
|
191
|
+
notExact: { message: 'undoing the adoption would change more than the [[surfaces.adopted]] rows', fix },
|
|
192
|
+
writtenMismatch: { message: 'cockpit.toml was restored, but re-reading it shows a further change', fix },
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
if (restored.kind !== 'complete')
|
|
196
|
+
failures.push(`${restored.message}; ${restored.fix}`);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
failures.push(`cockpit.toml restoration failed (${errorCause(error)}). Restore cockpit.toml to SHA-256 ${sha256Hex(originalText)} before retrying`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const retained of uncertainty)
|
|
203
|
+
failures.push(`recovery remains indeterminate for ${retained.item.path}. Preserve ${[retained.item.path, ...retained.retainedPaths].join(', ')} until the original inode is confirmed at ${retained.item.path} with SHA-256 ${retained.item.sha256}`);
|
|
204
|
+
const note = failures.length === 0
|
|
205
|
+
? `the adoption was rolled back: ${candidates.map(item => item.path).join(', ')} ${candidates.length === 1 ? 'is' : 'are'} back in place and cockpit.toml is unchanged`
|
|
206
|
+
: `the adoption could not be fully rolled back: ${failures.join('; ')}`;
|
|
207
|
+
return { ...reason, status: reason.status === 0 ? 2 : reason.status, diagnostics: [...reason.diagnostics,
|
|
208
|
+
{ severity: 'error', code: 'SURFACE_ADOPTION_REFUSED', message: note, target: candidates[0].path }] };
|
|
209
|
+
};
|
|
210
|
+
for (const item of candidates) {
|
|
211
|
+
const relocated = await relocateAnchoredFile(root, item.target, item.destination, SURFACE_FILE_MAX_BYTES, item.sha256, node, adapters);
|
|
212
|
+
if (relocated.kind !== 'complete') {
|
|
213
|
+
if (relocated.recovery === 'indeterminate')
|
|
214
|
+
moved.push(item);
|
|
215
|
+
const failure = relocated.failure ? ` Filesystem refusal: ${relocated.failure}.` : '';
|
|
216
|
+
const recoveryFailures = relocated.recoveryFailures?.length ? ` Recovery refusals: ${relocated.recoveryFailures.join(', ')}.` : '';
|
|
217
|
+
return rollback(refused('SURFACE_ADOPTION_REFUSED', relocated.recovery === 'unchanged'
|
|
218
|
+
? `${item.path} or its adopted-copy destination changed while it was being adopted; nothing was moved.${failure}`
|
|
219
|
+
: `${item.path} could not be confirmed after the filesystem helper stopped; recovery was attempted.${failure}${recoveryFailures}`, item.path), 'unchanged', relocated.recovery === 'indeterminate' ? [{ item, retainedPaths: relocated.retainedPaths ?? [] }] : []);
|
|
220
|
+
}
|
|
221
|
+
moved.push(item);
|
|
222
|
+
}
|
|
223
|
+
const rerun = `npx --no cockpit sync --config <your cockpit.toml> ${input.adopt.map(path => `--adopt ${path}`).join(' ')}`;
|
|
224
|
+
let written;
|
|
225
|
+
try {
|
|
226
|
+
written = await writeVerifiedConfig({
|
|
227
|
+
path: configPath, expectedSha256: loaded.result.source.sha256, temporaryTag: 'adopt',
|
|
228
|
+
edit: () => nextText,
|
|
229
|
+
isExactChange: (value) => canonicalJson(value) === canonicalJson(expected),
|
|
230
|
+
messages: {
|
|
231
|
+
changedBefore: { message: 'cockpit.toml changed since it was read', fix: `let the other edit finish, then have a human approve ${rerun} again` },
|
|
232
|
+
changedDuring: { message: 'cockpit.toml changed while the adoption was being recorded', fix: `let the other edit finish, then have a human approve ${rerun} again` },
|
|
233
|
+
invalid: (detail) => ({ message: `recording the adoption would leave cockpit.toml invalid (${detail})`,
|
|
234
|
+
fix: `correct what the message names in cockpit.toml, then have a human approve ${rerun} again` }),
|
|
235
|
+
notExact: { message: 'recording the adoption would change more than the [[surfaces.adopted]] rows', fix: ADOPT_BY_HAND_FIX },
|
|
236
|
+
writtenMismatch: { message: 'the adoption was recorded, but re-reading cockpit.toml shows a further change',
|
|
237
|
+
fix: 'review cockpit.toml for the change you did not make before running npx --no cockpit sync --config <your cockpit.toml>' },
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
return rollback(refused('SURFACE_ADOPTION_REFUSED', `writing cockpit.toml failed (${errorCause(error)}); owned recovery was attempted. Verify cockpit.toml has SHA-256 ${sha256Hex(originalText)} before retrying`, configPath), 'unknown');
|
|
243
|
+
}
|
|
244
|
+
if (written.kind !== 'complete')
|
|
245
|
+
return rollback(refused(written.code, written.message, configPath, written.fix), 'unknown');
|
|
246
|
+
let synced;
|
|
247
|
+
try {
|
|
248
|
+
synced = await synchronize({ configPath });
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
return rollback(refused('SURFACE_ADOPTION_REFUSED', `synchronization failed (${errorCause(error)}); owned recovery was attempted. Inspect ${candidates.map(item => item.path).join(', ')} and cockpit.toml before retrying`, configPath), 'written');
|
|
252
|
+
}
|
|
253
|
+
if (synced.status !== 0) {
|
|
254
|
+
let published;
|
|
255
|
+
try {
|
|
256
|
+
published = await Promise.all(candidates.map(item => readAnchoredEntry(root, item.target, SURFACE_FILE_MAX_BYTES, node, adapters)
|
|
257
|
+
.then(entry => entry.kind !== 'missing')));
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
return rollback(refused('SURFACE_ADOPTION_REFUSED', `published settings could not be checked after synchronization refused (${errorCause(error)}); owned recovery was attempted`, candidates[0].path), 'written');
|
|
261
|
+
}
|
|
262
|
+
// A merged file already on disk is consistent with the recorded adoption; undo only a sync that wrote nothing.
|
|
263
|
+
if (published.every(present => !present))
|
|
264
|
+
return rollback(synced, 'written');
|
|
265
|
+
return synced;
|
|
266
|
+
}
|
|
267
|
+
const result = synced.result !== null && typeof synced.result === 'object' && !Array.isArray(synced.result) ? synced.result : {};
|
|
268
|
+
return { ...synced, result: { ...result, adopted: rows.map(row => ({
|
|
269
|
+
path: row.path, source: resolve(root, row.source), sha256: row.sha256
|
|
270
|
+
})) } };
|
|
271
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Diagnostic } from '../diagnostics.js';
|
|
2
|
+
import { loadOperatorPolicy } from '../environment/operator-application.js';
|
|
3
|
+
import { type SyncAdoptionInput, type SyncAdoptionOutcome } from './adopt.js';
|
|
4
|
+
import { type GeneratedEnvironmentCommandAdapters, type GeneratedEnvironmentCommandInput, type GeneratedEnvironmentCommandOutcome, type GeneratedEnvironmentSyncInput, type GeneratedEnvironmentCurrentness, type GeneratedEnvironmentRepairAuthority, type SelectedBootstrapPublicationAuthority, type SelectedBootstrapSurfaceInput, type SelectedBootstrapResumeInput, type SelectedBootstrapResumeOutcome, type SelectedBootstrapSurfaceOutcome, type GeneratedStaleRemovalApproval, type GeneratedStaleRemovalApprovalRequest } from '../environment/generated-application/shared.js';
|
|
5
|
+
export type { GeneratedEnvironmentCommandAdapters, GeneratedEnvironmentChange, GeneratedEnvironmentCommandInput, GeneratedEnvironmentCommandOutcome, GeneratedEnvironmentSyncInput, GeneratedEnvironmentCurrentness, GeneratedEnvironmentRepairAuthority, SelectedBootstrapPublicationAuthority, SelectedBootstrapSurfaceInput, SelectedBootstrapResumeInput, SelectedBootstrapResumeOutcome, SelectedBootstrapSurfaceOutcome, } from '../environment/generated-application/shared.js';
|
|
6
|
+
export declare function prepareSelectedBootstrapSurface(input: SelectedBootstrapSurfaceInput, adapters?: Partial<GeneratedEnvironmentCommandAdapters>): Promise<SelectedBootstrapSurfaceOutcome>;
|
|
7
|
+
export declare function resumeSelectedBootstrapSurface(input: SelectedBootstrapResumeInput, adapters?: Partial<GeneratedEnvironmentCommandAdapters>): Promise<SelectedBootstrapResumeOutcome>;
|
|
8
|
+
export declare function applySelectedBootstrapSurface(authority: SelectedBootstrapPublicationAuthority): Promise<SelectedBootstrapSurfaceOutcome>;
|
|
9
|
+
export declare function prepareGeneratedEnvironmentCurrentness(input: GeneratedEnvironmentCommandInput, adapters?: Partial<GeneratedEnvironmentCommandAdapters>): Promise<GeneratedEnvironmentCurrentness>;
|
|
10
|
+
export declare function applyGeneratedEnvironmentRepair(authority: GeneratedEnvironmentRepairAuthority, options?: Readonly<{
|
|
11
|
+
dryRun?: boolean;
|
|
12
|
+
}>): Promise<GeneratedEnvironmentCommandOutcome>;
|
|
13
|
+
export declare function syncGeneratedEnvironment(input: GeneratedEnvironmentSyncInput, adapters?: Partial<GeneratedEnvironmentCommandAdapters>): Promise<GeneratedEnvironmentCommandOutcome>;
|
|
14
|
+
export declare function syncTeamGeneratedEnvironment(input: GeneratedEnvironmentSyncInput, adapters?: Partial<GeneratedEnvironmentCommandAdapters>): Promise<GeneratedEnvironmentCommandOutcome>;
|
|
15
|
+
/** `sync --adopt`: record the adoption, then run the ordinary sync that renders the merge. */
|
|
16
|
+
export declare function adoptAndSyncGeneratedEnvironment(input: SyncAdoptionInput): Promise<SyncAdoptionOutcome>;
|
|
17
|
+
export declare function checkGeneratedEnvironment(input: GeneratedEnvironmentCommandInput): Promise<GeneratedEnvironmentCommandOutcome>;
|
|
18
|
+
export interface GeneratedEnvironmentDispatchOutcome {
|
|
19
|
+
readonly artifact?: string | null;
|
|
20
|
+
readonly destination?: string | null;
|
|
21
|
+
readonly status: number;
|
|
22
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
23
|
+
readonly result: unknown;
|
|
24
|
+
}
|
|
25
|
+
export type GeneratedEnvironmentSyncHandlerInput = GeneratedEnvironmentSyncInput & Readonly<{
|
|
26
|
+
authorizeStaleRemoval?: (request: GeneratedStaleRemovalApprovalRequest) => Promise<GeneratedStaleRemovalApproval | undefined>;
|
|
27
|
+
}>;
|
|
28
|
+
type GeneratedEnvironmentSyncHandler = (input: GeneratedEnvironmentSyncHandlerInput) => Promise<GeneratedEnvironmentDispatchOutcome>;
|
|
29
|
+
export interface GeneratedEnvironmentOperatorIo {
|
|
30
|
+
readonly stderr: Pick<NodeJS.WriteStream, 'write'>;
|
|
31
|
+
readonly stdin?: NodeJS.ReadStream;
|
|
32
|
+
readonly confirmStaleRemoval?: (request: GeneratedStaleRemovalApprovalRequest) => Promise<string | undefined>;
|
|
33
|
+
readonly confirmPolicyWeakening?: (request: Readonly<{
|
|
34
|
+
weakened: readonly Readonly<{
|
|
35
|
+
field: string;
|
|
36
|
+
from: string;
|
|
37
|
+
to: string;
|
|
38
|
+
}>[];
|
|
39
|
+
digest: string;
|
|
40
|
+
}>) => Promise<string | undefined>;
|
|
41
|
+
}
|
|
42
|
+
export interface GeneratedEnvironmentOperatorOptions {
|
|
43
|
+
readonly interactive: boolean;
|
|
44
|
+
readonly json: boolean;
|
|
45
|
+
readonly ci: string | undefined;
|
|
46
|
+
}
|
|
47
|
+
export declare function runSyncOperatorCommand(input: GeneratedEnvironmentSyncHandlerInput, options: GeneratedEnvironmentOperatorOptions, io: GeneratedEnvironmentOperatorIo, handler: GeneratedEnvironmentSyncHandler, policy?: typeof loadOperatorPolicy): Promise<GeneratedEnvironmentDispatchOutcome>;
|