@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,11 @@
|
|
|
1
|
+
import { type EnvironmentCommandOutcome, type EnvironmentDiagnostic, type SourceProvenance } from '../contract.js';
|
|
2
|
+
export declare function exactEnvironment(input: unknown): Readonly<Record<string, string>> | undefined;
|
|
3
|
+
export declare function uniqueDiagnostics(diagnostics: readonly EnvironmentDiagnostic[]): readonly EnvironmentDiagnostic[];
|
|
4
|
+
export declare function sameSource(left: SourceProvenance, right: SourceProvenance): boolean;
|
|
5
|
+
export declare function ownerDiagnostic(code: EnvironmentDiagnostic['code'], message: string, target: string, fix?: string): EnvironmentDiagnostic;
|
|
6
|
+
export declare function shellQuote(value: string): string;
|
|
7
|
+
export declare function confinedPath(root: string, candidate: string): boolean;
|
|
8
|
+
export declare function ownDataValues(value: unknown, required: readonly string[], optional?: readonly string[]): Readonly<Record<string, unknown>> | undefined;
|
|
9
|
+
export declare function lifecycleRefusal(code: EnvironmentDiagnostic['code'], message: string, target: string, fix?: string): Extract<EnvironmentCommandOutcome<never>, {
|
|
10
|
+
kind: 'refusal';
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isAbsolute, relative, sep } from 'node:path';
|
|
2
|
+
import { forwardedRefusal, snapshotJson } from '../contract.js';
|
|
3
|
+
export function exactEnvironment(input) {
|
|
4
|
+
const snapshot = snapshotJson(input);
|
|
5
|
+
if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)
|
|
6
|
+
|| Object.entries(snapshot).some(([name, value]) => name.length === 0 || name.includes('\0')
|
|
7
|
+
|| name.includes('=') || typeof value !== 'string' || value.includes('\0')))
|
|
8
|
+
return undefined;
|
|
9
|
+
return { ...snapshot };
|
|
10
|
+
}
|
|
11
|
+
export function uniqueDiagnostics(diagnostics) {
|
|
12
|
+
const seen = new Set();
|
|
13
|
+
return diagnostics.filter((diagnostic) => {
|
|
14
|
+
const key = JSON.stringify([diagnostic.severity, diagnostic.code, diagnostic.message, diagnostic.target, diagnostic.fix]);
|
|
15
|
+
if (seen.has(key))
|
|
16
|
+
return false;
|
|
17
|
+
seen.add(key);
|
|
18
|
+
return true;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export function sameSource(left, right) {
|
|
22
|
+
return left.path === right.path && left.byteLength === right.byteLength && left.sha256 === right.sha256;
|
|
23
|
+
}
|
|
24
|
+
export function ownerDiagnostic(code, message, target, fix) {
|
|
25
|
+
return { severity: 'error', code, message, target, ...(fix ? { fix } : {}) };
|
|
26
|
+
}
|
|
27
|
+
export function shellQuote(value) {
|
|
28
|
+
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
29
|
+
}
|
|
30
|
+
export function confinedPath(root, candidate) {
|
|
31
|
+
const relation = relative(root, candidate);
|
|
32
|
+
return relation !== '..' && !relation.startsWith(`..${sep}`) && !isAbsolute(relation);
|
|
33
|
+
}
|
|
34
|
+
export function ownDataValues(value, required, optional = []) {
|
|
35
|
+
try {
|
|
36
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
37
|
+
return undefined;
|
|
38
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
39
|
+
const actual = Reflect.ownKeys(descriptors);
|
|
40
|
+
if (actual.some((key) => typeof key !== 'string')
|
|
41
|
+
|| required.some((key) => !descriptors[key])
|
|
42
|
+
|| actual.some((key) => typeof key !== 'string' || (!required.includes(key) && !optional.includes(key)))) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const captured = {};
|
|
46
|
+
for (const key of actual) {
|
|
47
|
+
const descriptor = descriptors[key];
|
|
48
|
+
if (!descriptor || !('value' in descriptor))
|
|
49
|
+
return undefined;
|
|
50
|
+
captured[key] = descriptor.value;
|
|
51
|
+
}
|
|
52
|
+
return captured;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// A throwing accessor or proxy trap makes the input malformed, which the caller refuses.
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function lifecycleRefusal(code, message, target, fix) {
|
|
60
|
+
return forwardedRefusal([ownerDiagnostic(code, message, target, fix)]);
|
|
61
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ExecuteProbeOutcome } from '../../environment-exec/execute.js';
|
|
2
|
+
import { type Diagnostic, type EnvironmentDiagnostic, type ExecutionStep } from '../contract.js';
|
|
3
|
+
import type { LoadedCockpitConfigResult } from './health.js';
|
|
4
|
+
type Execute = (step: ExecutionStep) => Promise<ExecuteProbeOutcome>;
|
|
5
|
+
interface SiblingCommandOutcome {
|
|
6
|
+
readonly status: number;
|
|
7
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
8
|
+
readonly result: unknown;
|
|
9
|
+
readonly artifact?: string | null;
|
|
10
|
+
readonly destination?: null;
|
|
11
|
+
}
|
|
12
|
+
export interface UseCommandInput {
|
|
13
|
+
readonly configPath: string;
|
|
14
|
+
readonly slug: string;
|
|
15
|
+
/** Absolute; absent with `clear`. */
|
|
16
|
+
readonly checkout?: string;
|
|
17
|
+
readonly clear: boolean;
|
|
18
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
19
|
+
}
|
|
20
|
+
export declare function runUse(input: UseCommandInput, dependencies: Readonly<{
|
|
21
|
+
execute: Execute;
|
|
22
|
+
}>): Promise<SiblingCommandOutcome>;
|
|
23
|
+
export interface PullCommandInput {
|
|
24
|
+
readonly configPath: string;
|
|
25
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
26
|
+
}
|
|
27
|
+
export declare function runPull(input: PullCommandInput, dependencies: Readonly<{
|
|
28
|
+
execute: Execute;
|
|
29
|
+
}>): Promise<SiblingCommandOutcome>;
|
|
30
|
+
/**
|
|
31
|
+
* What doctor and preflight report about the served checkouts: each override and where it came
|
|
32
|
+
* from, an override that no longer names a checkout of its sibling, the environment files a worktree
|
|
33
|
+
* lacks, and a running stack whose siblings' dependencies or migrations moved since it came up.
|
|
34
|
+
*/
|
|
35
|
+
export declare function inspectServedSiblings(input: Readonly<{
|
|
36
|
+
configPath: string;
|
|
37
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
38
|
+
/** The configuration the command already loaded; read again from `configPath` when absent. */
|
|
39
|
+
loaded?: LoadedCockpitConfigResult;
|
|
40
|
+
}>, dependencies: Readonly<{
|
|
41
|
+
execute: Execute;
|
|
42
|
+
}>): Promise<readonly EnvironmentDiagnostic[]>;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sequences the commands that choose and refresh the checkouts a stack serves: `use` points a
|
|
3
|
+
* sibling at another checkout of its repository for this cockpit checkout, `pull` fast-forwards
|
|
4
|
+
* every checkout to its upstream, and doctor and preflight read the findings both leave behind.
|
|
5
|
+
* The decisions live in `sibling-checkouts.ts`, `sibling-pull.ts` and `stack-inputs.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import { realpath } from 'node:fs/promises';
|
|
8
|
+
import { dirname } from 'node:path';
|
|
9
|
+
import { loadCockpitConfig } from '../../config/load.js';
|
|
10
|
+
import { cockpitCommand } from '../../fix-catalogue.js';
|
|
11
|
+
import { refusalOutcome } from '../../refusal.js';
|
|
12
|
+
import { mounted } from '../../schema.js';
|
|
13
|
+
import { listedSurfaceTargets } from '../../surfaces/harness-registry.js';
|
|
14
|
+
import { ENVIRONMENT_CODES, errorCause, isMissing } from '../contract.js';
|
|
15
|
+
import { createGitRunner, inspectSiblingCheckout, loadServedSiblings, missingEnvironmentFileDiagnostics, missingEnvironmentFiles, readSiblingCheckouts, SIBLING_CHECKOUTS_PATH, servedSiblings, vanishedServedCheckouts, writeSiblingCheckouts, } from '../sibling-checkouts.js';
|
|
16
|
+
import { fastForwardCheckout } from '../sibling-pull.js';
|
|
17
|
+
import { mapLimit } from '../map-limit.js';
|
|
18
|
+
import { applyAgentGrants, inside, planAgentGrants } from '../served-checkout-grants.js';
|
|
19
|
+
import { staleStackDiagnostics } from '../stack-inputs.js';
|
|
20
|
+
async function gitOrRefusal(env, execute) {
|
|
21
|
+
const git = await createGitRunner(env, execute);
|
|
22
|
+
return 'unavailable' in git
|
|
23
|
+
? refusalOutcome(ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE, `Git is needed to read the checkouts and is unavailable: ${git.unavailable}`, 'git', 'install Git and put it on PATH, then rerun this command')
|
|
24
|
+
: git;
|
|
25
|
+
}
|
|
26
|
+
export async function runUse(input, dependencies) {
|
|
27
|
+
const loaded = await loadCockpitConfig(input.configPath);
|
|
28
|
+
if (loaded.kind !== 'complete')
|
|
29
|
+
return { status: 2, result: null, diagnostics: loaded.diagnostics };
|
|
30
|
+
const configPath = loaded.result.source.path;
|
|
31
|
+
const config = loaded.result.config;
|
|
32
|
+
const root = dirname(configPath);
|
|
33
|
+
const recorded = await readSiblingCheckouts(root);
|
|
34
|
+
if (recorded.kind !== 'complete')
|
|
35
|
+
return { status: 2, result: null, diagnostics: [recorded.diagnostic] };
|
|
36
|
+
const sibling = config.sibling.find(row => row.slug === input.slug);
|
|
37
|
+
// A sibling removed from cockpit.toml can still be forgotten, or doctor would name it forever.
|
|
38
|
+
if (!sibling && input.clear && Object.hasOwn(recorded.checkouts, input.slug)) {
|
|
39
|
+
const { [input.slug]: forgotten, ...others } = recorded.checkouts;
|
|
40
|
+
const grants = await planAgentGrants({ root, slug: input.slug, declared: undefined, served: undefined, targets: [] });
|
|
41
|
+
if (grants.kind !== 'complete')
|
|
42
|
+
return { status: 2, result: null, diagnostics: [grants.diagnostic] };
|
|
43
|
+
const written = await writeSiblingCheckouts(root, others);
|
|
44
|
+
if (written.kind !== 'complete')
|
|
45
|
+
return recordUnwritable(configPath, root, written.message);
|
|
46
|
+
const granted = await applyAgentGrants(root, grants.plan);
|
|
47
|
+
if (granted.kind !== 'complete')
|
|
48
|
+
return { status: 2, result: null, diagnostics: [granted.diagnostic] };
|
|
49
|
+
return { status: 0, diagnostics: [], destination: null, artifact: `Forgot the checkout recorded for ${input.slug}, which cockpit.toml no longer declares.\n`,
|
|
50
|
+
result: { slug: input.slug, overridden: false, previous: forgotten } };
|
|
51
|
+
}
|
|
52
|
+
if (!sibling) {
|
|
53
|
+
return refusalOutcome(ENVIRONMENT_CODES.SIBLING_CHECKOUT_UNKNOWN, `cockpit.toml declares no sibling ${input.slug}; it declares ${config.sibling.map(row => row.slug).join(', ')}`, input.slug, `name a declared sibling, or declare this one with ${cockpitCommand('sibling add', { operand: input.slug, config: configPath })}`);
|
|
54
|
+
}
|
|
55
|
+
const declaredPath = servedSiblings(root, config, {}).get(sibling.slug).declared;
|
|
56
|
+
// Compared with a resolved candidate, so a siblings root reached through a link still matches. A
|
|
57
|
+
// declared checkout not cloned yet stays as declared; one that cannot be resolved is not guessed at.
|
|
58
|
+
let declared = declaredPath;
|
|
59
|
+
try {
|
|
60
|
+
declared = await realpath(declaredPath);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (!isMissing(error))
|
|
64
|
+
return refusalOutcome(ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE, `the declared checkout of sibling ${sibling.slug}, ${declaredPath}, could not be resolved: ${errorCause(error)}`, declaredPath, 'make that directory and every directory above it readable, or correct sibling.dir in cockpit.toml, then run this command again');
|
|
65
|
+
}
|
|
66
|
+
const previous = recorded.checkouts[sibling.slug];
|
|
67
|
+
let served = declared;
|
|
68
|
+
let evidence;
|
|
69
|
+
if (!input.clear) {
|
|
70
|
+
const git = await gitOrRefusal(input.env, dependencies.execute);
|
|
71
|
+
if ('status' in git)
|
|
72
|
+
return git;
|
|
73
|
+
const inspected = await inspectSiblingCheckout({ sibling, declared, candidate: input.checkout, git });
|
|
74
|
+
if (inspected.kind === 'refusal')
|
|
75
|
+
return { status: 2, result: null, diagnostics: [inspected.diagnostic] };
|
|
76
|
+
served = inspected.directory;
|
|
77
|
+
evidence = inspected.evidence;
|
|
78
|
+
}
|
|
79
|
+
const { [sibling.slug]: _cleared, ...others } = recorded.checkouts;
|
|
80
|
+
// Naming the declared checkout is the same as clearing: it is what serves the sibling by default.
|
|
81
|
+
const checkouts = served === declared ? others : { ...others, [sibling.slug]: served };
|
|
82
|
+
// The tools that hold a committed grant for this sibling, as sync writes them.
|
|
83
|
+
const targets = mounted(config, config.environment.profiles).some(row => row.slug === sibling.slug) ? listedSurfaceTargets(config.surfaces.tools) : [];
|
|
84
|
+
const grants = await planAgentGrants({ root, slug: sibling.slug, declared, served, targets });
|
|
85
|
+
if (grants.kind !== 'complete')
|
|
86
|
+
return { status: 2, result: null, diagnostics: [grants.diagnostic] };
|
|
87
|
+
const written = previous === checkouts[sibling.slug] ? { kind: 'complete' } : await writeSiblingCheckouts(root, checkouts);
|
|
88
|
+
if (written.kind !== 'complete')
|
|
89
|
+
return recordUnwritable(configPath, root, written.message);
|
|
90
|
+
const granted = await applyAgentGrants(root, grants.plan);
|
|
91
|
+
if (granted.kind !== 'complete')
|
|
92
|
+
return { status: 2, result: null, diagnostics: [{ ...granted.diagnostic,
|
|
93
|
+
message: `${served} was recorded for sibling ${sibling.slug}, but ${granted.diagnostic.message}` }] };
|
|
94
|
+
const current = servedSiblings(root, config, checkouts);
|
|
95
|
+
const entry = current.get(sibling.slug);
|
|
96
|
+
const diagnostics = [
|
|
97
|
+
...missingEnvironmentFileDiagnostics(entry, entry.overridden ? await missingEnvironmentFiles(entry, sibling) : []),
|
|
98
|
+
// A running stack keeps the checkout it mounted until it is brought down and up again.
|
|
99
|
+
...await staleStackDiagnostics(root, current),
|
|
100
|
+
];
|
|
101
|
+
const covered = inside(served, declared);
|
|
102
|
+
const artifact = [
|
|
103
|
+
entry.overridden ? `Sibling ${sibling.slug} is now served from ${served} (${evidence === 'object-store' ? 'a worktree of' : 'a clone with the same origin as'} ${declared}).`
|
|
104
|
+
: `Sibling ${sibling.slug} is served from its declared checkout ${declared}${previous === undefined ? '' : ` again, no longer from ${previous}`}.`,
|
|
105
|
+
`Recorded for this cockpit checkout only, in ${SIBLING_CHECKOUTS_PATH}; up, the guard, doctor and preflight read it.`,
|
|
106
|
+
...(grants.plan.lines.length > 0 ? [`${served} lies outside ${declared}, which the committed directory grants name:`, ...grants.plan.lines.map(line => ` ${line}`)] : []),
|
|
107
|
+
'',
|
|
108
|
+
].join('\n');
|
|
109
|
+
return { status: 0, diagnostics, destination: null, artifact,
|
|
110
|
+
result: { slug: sibling.slug, declared, served, overridden: entry.overridden, ...(evidence ? { evidence } : {}),
|
|
111
|
+
...(previous === undefined ? {} : { previous }), insideDeclared: covered, ...(grants.plan.report ? { agentGrants: grants.plan.report } : {}) } };
|
|
112
|
+
}
|
|
113
|
+
function recordUnwritable(configPath, root, reason) {
|
|
114
|
+
return refusalOutcome(ENVIRONMENT_CODES.SIBLING_CHECKOUT_RECORD_INVALID, `the sibling checkout record could not be written: ${reason}`, SIBLING_CHECKOUTS_PATH, `run ${cockpitCommand('sync', { config: configPath })} first if ${root}/.cockpit does not exist yet, or make it a plain directory you can write; then run this command again`);
|
|
115
|
+
}
|
|
116
|
+
const PULL_CONCURRENCY = 4;
|
|
117
|
+
export async function runPull(input, dependencies) {
|
|
118
|
+
const loaded = await loadCockpitConfig(input.configPath);
|
|
119
|
+
if (loaded.kind !== 'complete')
|
|
120
|
+
return { status: 2, result: null, diagnostics: loaded.diagnostics };
|
|
121
|
+
const config = loaded.result.config;
|
|
122
|
+
const root = dirname(loaded.result.source.path);
|
|
123
|
+
const served = await loadServedSiblings(root, config);
|
|
124
|
+
if (served.kind !== 'complete')
|
|
125
|
+
return { status: 2, result: null, diagnostics: [served.diagnostic] };
|
|
126
|
+
const git = await gitOrRefusal(input.env, dependencies.execute);
|
|
127
|
+
if ('status' in git)
|
|
128
|
+
return git;
|
|
129
|
+
// The cockpit root first, then each sibling's declared checkout and any checkout `use` put in its
|
|
130
|
+
// place. A sibling that is not a repository (acquire = "none") is expected to have no Git history,
|
|
131
|
+
// and a cockpit root outside Git is doctor's readiness finding, not pull's.
|
|
132
|
+
const targets = [{ label: 'cockpit', path: root, expected: false }];
|
|
133
|
+
for (const sibling of config.sibling) {
|
|
134
|
+
const entry = served.siblings.get(sibling.slug);
|
|
135
|
+
targets.push({ label: sibling.slug, path: entry.declared, expected: sibling.acquire !== 'none' });
|
|
136
|
+
if (entry.overridden)
|
|
137
|
+
targets.push({ label: `${sibling.slug} (served)`, path: entry.served, expected: true });
|
|
138
|
+
}
|
|
139
|
+
// Where Git puts each target's repository: a string, nothing when there is no checkout there, or
|
|
140
|
+
// why a toplevel Git named could not be resolved, which is reported against the target's label.
|
|
141
|
+
const located = await Promise.all(targets.map(async (target) => {
|
|
142
|
+
const output = await git.run(target.path, 'pull:root', ['rev-parse', '--show-toplevel']);
|
|
143
|
+
if (output.kind !== 'complete')
|
|
144
|
+
return undefined;
|
|
145
|
+
try {
|
|
146
|
+
return await realpath(output.stdout);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
return isMissing(error) ? undefined : { unresolved: `its repository at ${output.stdout} could not be resolved: ${errorCause(error)}` };
|
|
150
|
+
}
|
|
151
|
+
}));
|
|
152
|
+
// Two targets in one repository (an in-repo cockpit is its own sibling) move once, under the first one's label.
|
|
153
|
+
const distinct = new Map();
|
|
154
|
+
located.forEach((toplevel, index) => { if (typeof toplevel === 'string' && !distinct.has(toplevel))
|
|
155
|
+
distinct.set(toplevel, targets[index]); });
|
|
156
|
+
const advanced = new Map(await mapLimit([...distinct], PULL_CONCURRENCY, async ([toplevel, target]) => [toplevel, { label: target.label, ...await fastForwardCheckout(git, toplevel) }]));
|
|
157
|
+
const rows = [];
|
|
158
|
+
const diagnostics = [];
|
|
159
|
+
const reported = new Set();
|
|
160
|
+
located.forEach((toplevel, index) => {
|
|
161
|
+
const target = targets[index];
|
|
162
|
+
if (toplevel === undefined) {
|
|
163
|
+
const row = { label: target.label, state: 'skipped', path: target.path, reason: 'there is no Git checkout there',
|
|
164
|
+
fix: `run ${cockpitCommand('setup', { config: loaded.result.source.path })} to clone it`, blocked: target.expected };
|
|
165
|
+
rows.push(row);
|
|
166
|
+
if (row.blocked)
|
|
167
|
+
diagnostics.push(skippedDiagnostic(row));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (typeof toplevel !== 'string') {
|
|
171
|
+
const row = { label: target.label, state: 'skipped', path: target.path, reason: toplevel.unresolved,
|
|
172
|
+
fix: 'make that directory and every directory above it readable, then run pull again', blocked: true };
|
|
173
|
+
rows.push(row);
|
|
174
|
+
diagnostics.push(skippedDiagnostic(row));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (reported.has(toplevel))
|
|
178
|
+
return;
|
|
179
|
+
reported.add(toplevel);
|
|
180
|
+
const row = advanced.get(toplevel);
|
|
181
|
+
rows.push(row);
|
|
182
|
+
if (row.state === 'skipped' && row.blocked)
|
|
183
|
+
diagnostics.push(skippedDiagnostic(row));
|
|
184
|
+
});
|
|
185
|
+
// A pulled lockfile or migration behind a running stack is the next thing to go wrong.
|
|
186
|
+
if (rows.some(row => row.state === 'advanced'))
|
|
187
|
+
diagnostics.push(...await staleStackDiagnostics(root, served.siblings));
|
|
188
|
+
const line = (row) => row.state === 'advanced'
|
|
189
|
+
? `${row.label}: ${row.branch} fast-forwarded ${row.from.slice(0, 12)} -> ${row.to.slice(0, 12)} (${row.commits} commit${row.commits === 1 ? '' : 's'} from ${row.upstream})`
|
|
190
|
+
: row.state === 'current' ? `${row.label}: ${row.branch} is up to date with ${row.upstream}${row.ahead > 0 ? ` (${row.ahead} ahead)` : ''}`
|
|
191
|
+
: `${row.label}: skipped, ${row.reason}`;
|
|
192
|
+
return { status: 0, diagnostics, destination: null, artifact: `${rows.map(line).join('\n')}\n`, result: { repositories: rows } };
|
|
193
|
+
}
|
|
194
|
+
function skippedDiagnostic(row) {
|
|
195
|
+
return {
|
|
196
|
+
severity: 'warning',
|
|
197
|
+
code: 'PULL_SKIPPED',
|
|
198
|
+
message: `${row.label} at ${row.path} was left as it was: ${row.reason}`,
|
|
199
|
+
target: row.path,
|
|
200
|
+
fix: row.fix,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* What doctor and preflight report about the served checkouts: each override and where it came
|
|
205
|
+
* from, an override that no longer names a checkout of its sibling, the environment files a worktree
|
|
206
|
+
* lacks, and a running stack whose siblings' dependencies or migrations moved since it came up.
|
|
207
|
+
*/
|
|
208
|
+
export async function inspectServedSiblings(input, dependencies) {
|
|
209
|
+
try {
|
|
210
|
+
return await servedSiblingFindings(input, dependencies);
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
return [{ severity: 'warning', code: ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE,
|
|
214
|
+
message: `the checkouts serving the siblings could not be inspected: ${errorCause(error)}`, target: SIBLING_CHECKOUTS_PATH,
|
|
215
|
+
fix: 'rerun this command; if it persists, check that the sibling checkouts and .cockpit/local are readable' }];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function servedSiblingFindings(input, dependencies) {
|
|
219
|
+
const loaded = input.loaded ?? await loadCockpitConfig(input.configPath);
|
|
220
|
+
// An unloadable cockpit.toml is reported by the command itself.
|
|
221
|
+
if (loaded.kind !== 'complete')
|
|
222
|
+
return [];
|
|
223
|
+
const config = loaded.result.config;
|
|
224
|
+
const root = dirname(loaded.result.source.path);
|
|
225
|
+
const recorded = await readSiblingCheckouts(root);
|
|
226
|
+
// `up` refuses an unreadable record, so the served-checkouts row fails on it too; this says why.
|
|
227
|
+
if (recorded.kind !== 'complete')
|
|
228
|
+
return [recorded.diagnostic];
|
|
229
|
+
const served = servedSiblings(root, config, recorded.checkouts);
|
|
230
|
+
const findings = [];
|
|
231
|
+
for (const slug of Object.keys(recorded.checkouts).filter(slug => !served.has(slug)))
|
|
232
|
+
findings.push({
|
|
233
|
+
severity: 'warning', code: 'SIBLING_CHECKOUT_UNKNOWN',
|
|
234
|
+
message: `${SIBLING_CHECKOUTS_PATH} names a checkout for ${slug}, which cockpit.toml no longer declares, so nothing serves it`,
|
|
235
|
+
target: SIBLING_CHECKOUTS_PATH,
|
|
236
|
+
fix: `forget it with ${cockpitCommand('use', { operand: slug, args: '--clear' })}`,
|
|
237
|
+
});
|
|
238
|
+
// A directory that is gone is the served-checkouts row's finding, which `up` refuses as well; it is not repeated here.
|
|
239
|
+
const gone = new Set((await vanishedServedCheckouts(served)).map(entry => entry.slug));
|
|
240
|
+
const overridden = [...served.values()].filter(entry => entry.overridden && !gone.has(entry.slug));
|
|
241
|
+
const git = overridden.length === 0 ? undefined : await createGitRunner(input.env, dependencies.execute);
|
|
242
|
+
const perEntry = await Promise.all(overridden.map(async (entry) => {
|
|
243
|
+
const sibling = config.sibling.find(row => row.slug === entry.slug);
|
|
244
|
+
const rows = [{
|
|
245
|
+
severity: 'info', code: 'SIBLING_CHECKOUT_OVERRIDDEN',
|
|
246
|
+
message: `sibling ${entry.slug} is served from ${entry.served}, recorded by use in ${SIBLING_CHECKOUTS_PATH}, instead of its declared checkout ${entry.declared}`,
|
|
247
|
+
target: `sibling:${entry.slug}`,
|
|
248
|
+
fix: `serve the declared checkout again with ${cockpitCommand('use', { operand: entry.slug, args: '--clear' })}`,
|
|
249
|
+
}];
|
|
250
|
+
if (git === undefined)
|
|
251
|
+
return rows;
|
|
252
|
+
if ('unavailable' in git) {
|
|
253
|
+
rows.push({ severity: 'warning', code: ENVIRONMENT_CODES.EVIDENCE_UNAVAILABLE,
|
|
254
|
+
message: `whether ${entry.served} is still a checkout of sibling ${entry.slug} could not be checked: ${git.unavailable}`,
|
|
255
|
+
target: entry.served, fix: 'install Git and put it on PATH, then rerun this command' });
|
|
256
|
+
return rows;
|
|
257
|
+
}
|
|
258
|
+
const inspected = await inspectSiblingCheckout({ sibling, declared: entry.declared, candidate: entry.served, git });
|
|
259
|
+
// `up` does not refuse a checkout of another repository, so these commands report it as a warning.
|
|
260
|
+
if (inspected.kind === 'refusal')
|
|
261
|
+
rows.push({ ...inspected.diagnostic, severity: 'warning' });
|
|
262
|
+
else
|
|
263
|
+
rows.push(...missingEnvironmentFileDiagnostics(entry, await missingEnvironmentFiles(entry, sibling)));
|
|
264
|
+
return rows;
|
|
265
|
+
}));
|
|
266
|
+
findings.push(...perEntry.flat());
|
|
267
|
+
findings.push(...await staleStackDiagnostics(root, served));
|
|
268
|
+
return findings;
|
|
269
|
+
}
|