@crvouga/dev-fleet 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mise/locks/aws-cdk/2.1146.1/aube-lock.yaml +24 -0
- package/.mise/locks/aws-cdk/2.1146.1/package.json +7 -0
- package/.mise/locks/azure-cli/2.91.0~a837e014/pyproject.toml +5 -0
- package/.mise/locks/azure-cli/2.91.0~a837e014/uv.lock +2794 -0
- package/.mise/locks/gemini/0.66.0~84aac8e6/aube-lock.yaml +123 -0
- package/.mise/locks/gemini/0.66.0~84aac8e6/package.json +12 -0
- package/.mise/locks/npm-devcontainers-cli/0.90.0/aube-lock.yaml +24 -0
- package/.mise/locks/npm-devcontainers-cli/0.90.0/package.json +7 -0
- package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/aube-lock.yaml +1432 -0
- package/.mise/locks/npm-modelcontextprotocol-inspector/2.13.0~4c109bea/package.json +7 -0
- package/.mise/locks/npm-vercel/65.8.0/aube-lock.yaml +3595 -0
- package/.mise/locks/npm-vercel/65.8.0/package.json +7 -0
- package/.mise/locks/npm-wrangler/4.156.0/aube-lock.yaml +895 -0
- package/.mise/locks/npm-wrangler/4.156.0/package.json +7 -0
- package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/aube-lock.yaml +24 -0
- package/.mise/locks/npm-yarnpkg-cli-dist/4.18.1/package.json +7 -0
- package/LICENSE +21 -0
- package/README.md +357 -2
- package/agents/antigravity-proxy.ts +3 -0
- package/agents/audit.md +89 -0
- package/agents/claude-proxy +5 -0
- package/agents/claude-proxy.ts +3 -0
- package/agents/codex-proxy.ts +3 -0
- package/agents/grok-proxy.ts +3 -0
- package/agents/managed-proxy.ts +55 -0
- package/agents/opencode-proxy.ts +3 -0
- package/agents/registry.json +209 -0
- package/agents/registry.schema.json +149 -0
- package/agents/setup.md +158 -0
- package/agents/t3.json +40 -0
- package/ansible/macos/manager.yml +30 -0
- package/ansible/macos/policy.json +9 -0
- package/ansible/monitoring/README.md +215 -0
- package/ansible/monitoring/agent-darwin.yml +198 -0
- package/ansible/monitoring/agent.yml +172 -0
- package/ansible/monitoring/beszel-agent.service +42 -0
- package/ansible/monitoring/compose.yml +74 -0
- package/ansible/monitoring/hub-darwin.yml +102 -0
- package/ansible/monitoring/hub-route-darwin.yml +51 -0
- package/ansible/monitoring/lock.json +16 -0
- package/ansible/net/remote-probe.sh +13 -0
- package/ansible/pyproject.toml +12 -0
- package/ansible/ubuntu/authorize-sudo.sh +51 -0
- package/ansible/ubuntu/baseline.yml +89 -0
- package/ansible/ubuntu/disk-gc.py +336 -0
- package/ansible/ubuntu/disk-guard.py +104 -0
- package/ansible/ubuntu/policy.json +52 -0
- package/ansible/ubuntu/recovery.yml +15 -0
- package/ansible/ubuntu/t3/policy.json +7 -0
- package/ansible/ubuntu/t3-desktop.yml +220 -0
- package/ansible/ubuntu/t3-health.sh +33 -0
- package/ansible/ubuntu/t3-policy.yml +76 -0
- package/ansible/ubuntu/t3-route.yml +28 -0
- package/ansible/ubuntu/tailscale.yml +78 -0
- package/ansible/ubuntu/tasks/credentials.yml +47 -0
- package/ansible/ubuntu/tasks/docker.yml +31 -0
- package/ansible/ubuntu/tasks/packages.yml +56 -0
- package/ansible/ubuntu/tasks/power.yml +51 -0
- package/ansible/ubuntu/tasks/recovery.yml +39 -0
- package/ansible/ubuntu/tasks/resources.yml +312 -0
- package/ansible/ubuntu/tasks/services.yml +31 -0
- package/ansible/ubuntu/tasks/ssh.yml +71 -0
- package/ansible/ubuntu/tasks/user.yml +120 -0
- package/ansible/uv.lock +190 -0
- package/bin/devfleet.mjs +36 -0
- package/bootstrap/bootstrap.ps1 +50 -0
- package/bootstrap/bootstrap.sh +80 -0
- package/bootstrap/devfleet +7 -0
- package/bootstrap/docker-desktop.sh +33 -0
- package/bootstrap/doctor.ts +234 -0
- package/bootstrap/fleet-manager-run.sh +103 -0
- package/bootstrap/fleet-remote-bootstrap.sh +258 -0
- package/bootstrap/global-config.ts +171 -0
- package/bootstrap/install-launcher.sh +10 -0
- package/bootstrap/native-aws.ts +86 -0
- package/bootstrap/native-t3.ts +154 -0
- package/bootstrap/npm.ts +358 -0
- package/bootstrap/release-version.ts +157 -0
- package/bootstrap/setup-status.ts +51 -0
- package/bootstrap/setup.ts +88 -0
- package/bootstrap/shell-path.ts +105 -0
- package/bootstrap/verify-t3-archive.py +49 -0
- package/bootstrap/worker-auth.ts +65 -0
- package/bootstrap/worker-github.ts +47 -0
- package/bootstrap/worker-tools.ts +24 -0
- package/cliproxy/AGENTS.md +11 -0
- package/cliproxy/README.md +269 -0
- package/cliproxy/clients/bootstrap.py +143 -0
- package/cliproxy/clients/launcher.py +57 -0
- package/cliproxy/compose.yaml +90 -0
- package/cliproxy/config.template.yaml +70 -0
- package/cliproxy/docs/cloud-adoption.md +16 -0
- package/cliproxy/docs/deployment.png +0 -0
- package/cliproxy/docs/deployment.svg +109 -0
- package/cliproxy/docs/health-workflow.example.yml +185 -0
- package/cliproxy/docs/migration.md +131 -0
- package/cliproxy/docs/model-health-report.schema.json +364 -0
- package/cliproxy/docs/model-health.md +393 -0
- package/cliproxy/image.lock.json +5 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-backup-check.plist +38 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-backup.plist +48 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-fleet.plist +32 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-gc.plist +38 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-monitor.plist +29 -0
- package/cliproxy/launchd/dev.devfleet.cliproxy-vault-renew.plist +31 -0
- package/cliproxy/models.json +1618 -0
- package/cliproxy/requirements.lock +78 -0
- package/cliproxy/scripts/accounts.py +38 -0
- package/cliproxy/scripts/audit.py +123 -0
- package/cliproxy/scripts/backup +234 -0
- package/cliproxy/scripts/check.py +34 -0
- package/cliproxy/scripts/checkpoint.py +226 -0
- package/cliproxy/scripts/cli.py +64 -0
- package/cliproxy/scripts/cliproxy_host.py +257 -0
- package/cliproxy/scripts/cloud_state.py +150 -0
- package/cliproxy/scripts/container-health +6 -0
- package/cliproxy/scripts/docker +24 -0
- package/cliproxy/scripts/external-health.py +79 -0
- package/cliproxy/scripts/fleet_config.py +43 -0
- package/cliproxy/scripts/fleet_sync.py +274 -0
- package/cliproxy/scripts/initialize +84 -0
- package/cliproxy/scripts/install-dependencies +48 -0
- package/cliproxy/scripts/install.py +406 -0
- package/cliproxy/scripts/model_health.py +16 -0
- package/cliproxy/scripts/modelhealth/__init__.py +5 -0
- package/cliproxy/scripts/modelhealth/checks.py +429 -0
- package/cliproxy/scripts/modelhealth/cli.py +117 -0
- package/cliproxy/scripts/modelhealth/config.py +186 -0
- package/cliproxy/scripts/modelhealth/emulator.py +536 -0
- package/cliproxy/scripts/modelhealth/expect.py +88 -0
- package/cliproxy/scripts/modelhealth/findings.py +183 -0
- package/cliproxy/scripts/modelhealth/protocol.py +330 -0
- package/cliproxy/scripts/modelhealth/redact.py +28 -0
- package/cliproxy/scripts/modelhealth/report.py +150 -0
- package/cliproxy/scripts/modelhealth/runner.py +390 -0
- package/cliproxy/scripts/modelhealth/scenario.py +131 -0
- package/cliproxy/scripts/modelhealth/schema.py +63 -0
- package/cliproxy/scripts/modelhealth/simulate.py +111 -0
- package/cliproxy/scripts/modelhealth/transport.py +213 -0
- package/cliproxy/scripts/monitor +68 -0
- package/cliproxy/scripts/ops +527 -0
- package/cliproxy/scripts/public-endpoint +127 -0
- package/cliproxy/scripts/recover_node.py +177 -0
- package/cliproxy/scripts/restore-verify +60 -0
- package/cliproxy/scripts/retention.py +144 -0
- package/cliproxy/scripts/service-start +7 -0
- package/cliproxy/scripts/validate-config +56 -0
- package/cliproxy/scripts/vault-access.py +57 -0
- package/cliproxy/scripts/vault-backup-login +55 -0
- package/cliproxy/scripts/vault-recovery +56 -0
- package/cliproxy/scripts/vault-renew +30 -0
- package/cliproxy/systemd/cliproxy-backup-check.service +10 -0
- package/cliproxy/systemd/cliproxy-backup-check.timer +8 -0
- package/cliproxy/systemd/cliproxy-backup.service +13 -0
- package/cliproxy/systemd/cliproxy-backup.timer +8 -0
- package/cliproxy/systemd/cliproxy-fleet.service +17 -0
- package/cliproxy/systemd/cliproxy-gc.service +13 -0
- package/cliproxy/systemd/cliproxy-gc.timer +8 -0
- package/cliproxy/systemd/cliproxy-monitor.service +8 -0
- package/cliproxy/systemd/cliproxy-monitor.timer +7 -0
- package/cliproxy/systemd/cliproxy-vault-renew.service +8 -0
- package/cliproxy/systemd/cliproxy-vault-renew.timer +7 -0
- package/cliproxy/vendor/LICENSE +22 -0
- package/cliproxy/vendor/config.upstream.yaml +1349 -0
- package/docs/consumer-setup.md +408 -0
- package/docs/declared.md +89 -0
- package/docs/machine-setup.md +399 -0
- package/docs/operations.md +276 -0
- package/docs/releasing.md +103 -0
- package/docs/state.md +254 -0
- package/docs/topology.md +67 -0
- package/docs/ubuntu-sync.md +351 -0
- package/docs/worker-contract.md +67 -0
- package/examples/fleet.json +100 -0
- package/examples/roster.json +13 -0
- package/llms.txt +35 -0
- package/mise.lock +1521 -0
- package/mise.toml +110 -0
- package/package.json +74 -4
- package/schema/fleet.schema.json +420 -0
- package/schema/roster.schema.json +77 -0
- package/src/agents/account-relay.ts +111 -0
- package/src/agents/accounts.ts +85 -0
- package/src/agents/audit.ts +77 -0
- package/src/agents/cli.ts +13 -0
- package/src/agents/command.ts +204 -0
- package/src/agents/converge.ts +123 -0
- package/src/agents/doctor.ts +107 -0
- package/src/agents/errors.ts +2 -0
- package/src/agents/files.ts +73 -0
- package/src/agents/fleet-verify.ts +165 -0
- package/src/agents/launch.ts +290 -0
- package/src/agents/native-verify.ts +371 -0
- package/src/agents/provider-errors.ts +57 -0
- package/src/agents/registry.ts +61 -0
- package/src/agents/render.ts +110 -0
- package/src/agents/round-trip.ts +192 -0
- package/src/agents/secrets.ts +13 -0
- package/src/agents/toolchain.ts +34 -0
- package/src/agents/verify-cache.ts +103 -0
- package/src/agents/verify.ts +127 -0
- package/src/auth-checks.ts +163 -0
- package/src/cli/agent-guide.ts +129 -0
- package/src/cli/app.ts +122 -0
- package/src/cli/cli.ts +28 -0
- package/src/cli/command-index.ts +57 -0
- package/src/cli/contracts.ts +25 -0
- package/src/cli/fleet-reference.ts +17 -0
- package/src/cli/fleet-state.ts +499 -0
- package/src/cli/fleet-sync-checkout.ts +130 -0
- package/src/cli/fleet-sync-enrollment.ts +140 -0
- package/src/cli/fleet-sync-forward.ts +134 -0
- package/src/cli/fleet-sync-manager.ts +249 -0
- package/src/cli/fleet-sync-monitoring.ts +185 -0
- package/src/cli/fleet-sync-output.ts +317 -0
- package/src/cli/fleet-sync-privilege.ts +27 -0
- package/src/cli/fleet-sync-progress.ts +109 -0
- package/src/cli/fleet-sync-remote.ts +242 -0
- package/src/cli/fleet-sync-report.ts +26 -0
- package/src/cli/fleet-sync-schedule.ts +138 -0
- package/src/cli/fleet-sync-state.ts +86 -0
- package/src/cli/fleet-sync-vault.ts +166 -0
- package/src/cli/fleet-sync.ts +375 -0
- package/src/cli/fleet.ts +165 -0
- package/src/cli/managed-health.ts +219 -0
- package/src/cli/node-deployment.ts +34 -0
- package/src/cli/node-sync.ts +121 -0
- package/src/cli/node-t3.ts +31 -0
- package/src/cli/options.ts +141 -0
- package/src/cli/probe-source.ts +7 -0
- package/src/cli/program.ts +185 -0
- package/src/cli/project.ts +51 -0
- package/src/cli/register-fleet.ts +296 -0
- package/src/cli/registry.ts +185 -0
- package/src/cli/repair-apply.ts +67 -0
- package/src/cli/repair-guard.ts +11 -0
- package/src/cli/repair-inspect.ts +150 -0
- package/src/cli/repair-script.ts +76 -0
- package/src/cli/repair.ts +209 -0
- package/src/cli/roster.ts +105 -0
- package/src/cli/search.ts +35 -0
- package/src/cli/settings.ts +67 -0
- package/src/cli/source-operations.ts +102 -0
- package/src/cli/t3/command.ts +90 -0
- package/src/cli/t3/register.ts +55 -0
- package/src/cli/tailnet.ts +127 -0
- package/src/cli/ui-actions.ts +133 -0
- package/src/cli/ui-controller.ts +113 -0
- package/src/cli/ui-data.ts +106 -0
- package/src/cli/ui-execute.ts +163 -0
- package/src/cli/ui-repairs.ts +34 -0
- package/src/cli/ui-reports.ts +211 -0
- package/src/cli/ui-targets.ts +100 -0
- package/src/cli/ui-terminal.ts +109 -0
- package/src/cli/ui-types.ts +49 -0
- package/src/cli/ui-wizard.ts +101 -0
- package/src/cli/ui.ts +9 -0
- package/src/cli/worker-health-output.ts +37 -0
- package/src/config.ts +186 -0
- package/src/configure.ts +255 -0
- package/src/definition.ts +290 -0
- package/src/diagnostics.ts +92 -0
- package/src/doctor-check.ts +10 -0
- package/src/errors.ts +1 -0
- package/src/fingerprint.ts +120 -0
- package/src/fleet-config.ts +174 -0
- package/src/input-hashes.ts +73 -0
- package/src/machine/local-source.ts +52 -0
- package/src/machine/lock-error.ts +2 -0
- package/src/machine/platform.ts +44 -0
- package/src/machine/source.ts +68 -0
- package/src/machine/state.ts +173 -0
- package/src/machine-health.ts +95 -0
- package/src/managed-source.ts +47 -0
- package/src/manager-failure.ts +48 -0
- package/src/manager-sync.ts +405 -0
- package/src/manager.ts +62 -0
- package/src/monitoring/agent-evidence.ts +146 -0
- package/src/monitoring/apply.ts +183 -0
- package/src/monitoring/beszel.ts +198 -0
- package/src/monitoring/enroll.ts +111 -0
- package/src/monitoring/hub-access.ts +114 -0
- package/src/monitoring/hub-backup.ts +121 -0
- package/src/monitoring/hub-viewer.ts +142 -0
- package/src/monitoring/hub.ts +93 -0
- package/src/monitoring/manager-agent.ts +73 -0
- package/src/monitoring/manager-hub.ts +248 -0
- package/src/monitoring/remote.ts +65 -0
- package/src/network-definition.ts +83 -0
- package/src/node-converge-linux.ts +374 -0
- package/src/node-converge-shared.ts +83 -0
- package/src/node-converge.ts +40 -0
- package/src/onboard.ts +35 -0
- package/src/package-info.ts +45 -0
- package/src/platform/ansible-receipt.ts +128 -0
- package/src/platform/ansible.ts +66 -0
- package/src/platform/darwin.ts +203 -0
- package/src/platform/detect.ts +11 -0
- package/src/platform/fallback.ts +110 -0
- package/src/platform/index.ts +38 -0
- package/src/platform/launchd.ts +98 -0
- package/src/platform/linux.ts +139 -0
- package/src/platform/ps.ts +45 -0
- package/src/platform/resource-verify.ts +132 -0
- package/src/platform/systemd-user.ts +95 -0
- package/src/platform/t3-policy.ts +137 -0
- package/src/platform/t3-route.ts +68 -0
- package/src/platform/t3-service.ts +75 -0
- package/src/platform/types.ts +123 -0
- package/src/platform/ubuntu-audit.ts +66 -0
- package/src/platform/ubuntu-verify.ts +105 -0
- package/src/platform/windows.ts +148 -0
- package/src/power-recovery.ts +55 -0
- package/src/probe.ts +51 -0
- package/src/protocol.ts +119 -0
- package/src/proxy-converge.ts +85 -0
- package/src/remote-bootstrap.ts +210 -0
- package/src/remote-entry.ts +89 -0
- package/src/remote-lock.ts +12 -0
- package/src/repair-catalog.ts +206 -0
- package/src/repair-plan.ts +78 -0
- package/src/repair-runner.ts +84 -0
- package/src/report.ts +71 -0
- package/src/runner.ts +104 -0
- package/src/secrets.ts +169 -0
- package/src/service-auth.ts +115 -0
- package/src/ssh.ts +135 -0
- package/src/state/bucket.ts +208 -0
- package/src/state/check.ts +74 -0
- package/src/state/connection.ts +92 -0
- package/src/state/enrollment.ts +45 -0
- package/src/state/legacy.ts +89 -0
- package/src/state/litestream.ts +143 -0
- package/src/state/operator.ts +20 -0
- package/src/state/paths.ts +40 -0
- package/src/state/roster.ts +62 -0
- package/src/state/store.ts +169 -0
- package/src/state/sync.ts +352 -0
- package/src/sync.ts +104 -0
- package/src/t3/accounts.ts +81 -0
- package/src/t3/desired.ts +165 -0
- package/src/t3/files.ts +81 -0
- package/src/t3/names-check.ts +53 -0
- package/src/t3/names.ts +155 -0
- package/src/t3/plan.ts +82 -0
- package/src/t3/providers.ts +74 -0
- package/src/t3/reconcile.ts +123 -0
- package/src/t3-endpoint.ts +104 -0
- package/src/t3-linked-check.ts +123 -0
- package/src/tailnet-health.ts +231 -0
- package/src/tailnet-matching.ts +37 -0
- package/src/tailscale.ts +141 -0
- package/src/toolchain-checks.ts +108 -0
- package/src/topology.ts +24 -0
- package/src/transport.ts +122 -0
- package/src/types.ts +99 -0
- package/src/vault-config.ts +38 -0
- package/src/worker-access-checks.ts +168 -0
- package/src/worker-capacity.ts +34 -0
- package/src/worker-host-checks.ts +181 -0
- package/src/worker-policy.ts +64 -0
- package/src/worker-readiness.ts +64 -0
- package/src/workstation-checks.ts +29 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Release } from './program';
|
|
2
|
+
|
|
3
|
+
const SAFETY = [
|
|
4
|
+
'No arguments prints help, including on a TTY. --json returns this document. The menu requires --interactive; --json and --non-interactive never prompt.',
|
|
5
|
+
'Diagnostics, onboarding instructions, schema, catalogs, scripts and repair previews are read-only.',
|
|
6
|
+
'fleet-sync, fleet-node-sync, t3-apply and t3-cleanup apply by invocation; --dry-run previews. t3-apply --import ID explicitly adopts ownership. --json never implies a dry run. fleet-node-add and fleet-repair require --apply --yes.',
|
|
7
|
+
'fleet-state alone is read-only; --init, --import, --push and --restore each act on invocation. Bucket credentials come from DEVFLEET_BUCKET_ACCESS_KEY_ID and DEVFLEET_BUCKET_SECRET_ACCESS_KEY or a terminal prompt, never from arguments.',
|
|
8
|
+
'Do not copy credentials, forward SSH agents, bypass host keys, provision infrastructure or execute unreviewed remedies.',
|
|
9
|
+
'A healthy manager does not prove another machine can connect to it. Run fleet-status from each intended manager.',
|
|
10
|
+
'fleet-repair executes only allowlisted owner actions, then reruns diagnostics. Native logins, host trust and resource permissions remain explicit operator steps. Pass the reviewed planHash as --plan-hash to reject a changed plan.',
|
|
11
|
+
'Shared provider keys are fetched through each machine’s existing Vault authorization by workstation tooling. Never copy machine-local login caches.',
|
|
12
|
+
'Use exact npm versions for automation. The application never self-updates.',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const EXAMPLES = [
|
|
16
|
+
'devfleet fleet-node-sync',
|
|
17
|
+
'devfleet fleet-status',
|
|
18
|
+
'devfleet fleet-state --json',
|
|
19
|
+
'devfleet t3-status',
|
|
20
|
+
'devfleet fleet-status --local --workspace /path/to/personal --json',
|
|
21
|
+
'devfleet fleet-status --json --strict --timeout 120000',
|
|
22
|
+
'devfleet fleet-status --tailnet --json',
|
|
23
|
+
'devfleet fleet-status --workers --json',
|
|
24
|
+
'devfleet fleet-node-add --id dev-linux --ssh dev-linux --path /home/dev/workspace --require github,t3,toolchain --json',
|
|
25
|
+
'devfleet fleet-node-add --id dev-linux --ssh dev-linux --path /home/dev/workspace --apply --yes --json',
|
|
26
|
+
'devfleet fleet-status --node dev-linux --json',
|
|
27
|
+
'devfleet fleet-repair --list --json',
|
|
28
|
+
'devfleet fleet-repair --json',
|
|
29
|
+
'devfleet fleet-repair --local --repair workspace --json',
|
|
30
|
+
'devfleet fleet-repair --local --repair workspace --plan-hash <reviewed-sha256> --apply --yes --json',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
/** For an agent working in another project, which is every project that uses
|
|
34
|
+
* dev-fleet: a change to dev-fleet is asked for, never made in place.
|
|
35
|
+
*/
|
|
36
|
+
function support(release: Release) {
|
|
37
|
+
return {
|
|
38
|
+
issues: release.issues ?? null,
|
|
39
|
+
report:
|
|
40
|
+
'A defect in dev-fleet, or something it cannot do yet, is raised as an issue in the dev-fleet repository: one issue per bug or feature request, after searching the open ones. From any other project that is the only way to change dev-fleet. Tell the operator what is blocked and link the issue.',
|
|
41
|
+
never:
|
|
42
|
+
'Do not edit the installed package, a checkout fleet-sync owns or a file dev-fleet manages on a machine: the next install or fleet-sync replaces each of them. Do not clone dev-fleet to patch it, vendor a modified copy, or hide the defect behind a workaround in the project that holds fleet.json.',
|
|
43
|
+
include:
|
|
44
|
+
'devfleet --version, the command and its flags, the error code or the failing check IDs from --json, what happened and what was expected.',
|
|
45
|
+
withhold:
|
|
46
|
+
'The issue tracker is public. Leave out credentials, the fleet configuration, hostnames, accounts, domains, tailnet names, paths under a home directory and raw subprocess output.',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function agentGuide(release: Release) {
|
|
51
|
+
return {
|
|
52
|
+
version: 1,
|
|
53
|
+
name: 'dev-fleet',
|
|
54
|
+
release: release.version,
|
|
55
|
+
releasedAt: release.releasedAt,
|
|
56
|
+
invocation: 'devfleet <command> --json --non-interactive',
|
|
57
|
+
discovery: 'devfleet commands --json',
|
|
58
|
+
setup:
|
|
59
|
+
'Setting up a fleet from a project: llms.txt and docs/consumer-setup.md in this package (node_modules/@crvouga/dev-fleet/), also at https://github.com/crvouga/dev-fleet/blob/main/docs/consumer-setup.md',
|
|
60
|
+
defaultCommand: 'help',
|
|
61
|
+
help: 'devfleet <command> --help',
|
|
62
|
+
interactive:
|
|
63
|
+
'devfleet --interactive (explicit opt-in; TTY required, disabled in CI)',
|
|
64
|
+
groups: {
|
|
65
|
+
'fleet-*':
|
|
66
|
+
'Developer computers: fleet-status, fleet-discover, fleet-sync, fleet-state, fleet-node-sync, fleet-repair, fleet-nodes, fleet-node-add',
|
|
67
|
+
't3-*': 'Declared T3 provider instances: t3-status, t3-apply, t3-cleanup',
|
|
68
|
+
cliproxy: 'The CLI proxy service on the manager; arguments are forwarded',
|
|
69
|
+
},
|
|
70
|
+
configuration: {
|
|
71
|
+
workspace:
|
|
72
|
+
'The published package itself. Run from a checkout (development): --workspace PATH, PERSONAL_WORKSPACE, then the dev-fleet checkout the command is started in',
|
|
73
|
+
roster:
|
|
74
|
+
'--config PATH, PERSONAL_FLEET_CONFIG, closest ancestor .fleet.local.json, then the roster in the fleet state',
|
|
75
|
+
definition:
|
|
76
|
+
'DEVFLEET_CONFIG, then the closest fleet.json in the working directory or above it (the operator’s project), then the configuration fleet-sync last applied from the fleet state (the devfleet CLI on the manager), then the copy fleet-sync installed at ~/.config/dev-fleet/fleet.json',
|
|
77
|
+
state:
|
|
78
|
+
'DEVFLEET_STATE or ~/.local/share/dev-fleet/state: a local copy of the roster, the approved revision and the configuration last applied. The bucket named under "state" in the fleet configuration is the source of truth; its credentials are passed in DEVFLEET_BUCKET_ACCESS_KEY_ID and DEVFLEET_BUCKET_SECRET_ACCESS_KEY, or saved by devfleet fleet-state --init in ~/.config/dev-fleet/bucket.json for unattended runs. devfleet fleet-state --json compares the copies',
|
|
79
|
+
revision:
|
|
80
|
+
'The commit the published package names (devfleet --version). fleet-sync converges every machine to it; --revision SHA selects another',
|
|
81
|
+
},
|
|
82
|
+
output: {
|
|
83
|
+
stdout:
|
|
84
|
+
'Public diagnostics emit one versioned JSON document with --json. cliproxy retains its owner output contract; native agent launch commands stream native output.',
|
|
85
|
+
exitCodes: {
|
|
86
|
+
'0': 'Success or preview',
|
|
87
|
+
'1': 'Failed check or operation; strict also rejects warnings/skips',
|
|
88
|
+
'2': 'Invalid usage or configuration',
|
|
89
|
+
'130': 'Cancelled',
|
|
90
|
+
},
|
|
91
|
+
errors:
|
|
92
|
+
'{version:1,ok:false,code,error}; raw subprocess output and exception details are withheld',
|
|
93
|
+
reports:
|
|
94
|
+
'{version:1,command,ok,generatedAt,nodes:[{node,checks:[{id,status,summary,remedy?}]}],summary,coverage}',
|
|
95
|
+
statuses: ['pass', 'warn', 'fail', 'skip'],
|
|
96
|
+
coverage:
|
|
97
|
+
'Default fleet-status tests the manager and all configured nodes. --local tests only this manager; --tailnet and --workers cover Tailscale computers. A missing roster fails explicitly. T3/VS Code end-to-end checks remain manual.',
|
|
98
|
+
},
|
|
99
|
+
safety: SAFETY,
|
|
100
|
+
support: support(release),
|
|
101
|
+
toolchain:
|
|
102
|
+
'On a fleet machine the global mise configuration belongs to dev-fleet: fleet-sync publishes it, and fleet-status fails tool:global-mise-config when anything replaced it. A project pins its own tools in a project mise.toml (mise install --locked in its checkout) and never publishes a global one.',
|
|
103
|
+
library:
|
|
104
|
+
'None. The package is the devfleet command: it declares no main or exports, and nothing under src/ is a supported import; any release may change it. Ask for a command in an issue instead.',
|
|
105
|
+
fleetSync: {
|
|
106
|
+
command: 'devfleet fleet-sync',
|
|
107
|
+
preview: 'devfleet fleet-sync --dry-run --json',
|
|
108
|
+
approval:
|
|
109
|
+
'Applies on invocation without a prompt; --dry-run previews and changes no machine: on the manager it only checks the release out into dev-fleet’s cache and installs the Bun it pins, never the toolchain, the global mise configuration or shell profiles',
|
|
110
|
+
scope:
|
|
111
|
+
'Whole enrolled Ubuntu fleet over verified SSH; --node filters diagnostics/rollout',
|
|
112
|
+
state:
|
|
113
|
+
'The approved and applied revision are kept in the fleet state and uploaded to its bucket after every run; the report carries the state:replica check',
|
|
114
|
+
readiness:
|
|
115
|
+
'Full Ubuntu acceptance is incomplete and fails closed; do not override it or claim deployment success.',
|
|
116
|
+
},
|
|
117
|
+
reconciliation: {
|
|
118
|
+
plan: 'devfleet t3-apply --dry-run --json',
|
|
119
|
+
apply: 'devfleet t3-apply --plan-hash HASH',
|
|
120
|
+
cleanup: 'devfleet t3-cleanup --dry-run',
|
|
121
|
+
import: 'devfleet t3-apply --import ID',
|
|
122
|
+
ownership:
|
|
123
|
+
'Only declared or explicitly imported T3 instances. Pairing, credentials, threads and unrelated settings are preserved.',
|
|
124
|
+
concurrency:
|
|
125
|
+
'Exclusive personal lock with optimistic external T3 file updates; avoid concurrent Settings edits.',
|
|
126
|
+
},
|
|
127
|
+
examples: EXAMPLES,
|
|
128
|
+
};
|
|
129
|
+
}
|
package/src/cli/app.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { sourceOperation, forwardSourceOperation } from './source-operations';
|
|
2
|
+
import { resolveSettings, type Settings } from './settings';
|
|
3
|
+
import { COMMANDS } from './registry';
|
|
4
|
+
import { execute } from './program';
|
|
5
|
+
import { parseArgs } from 'node:util';
|
|
6
|
+
import { packageInfo } from '../package-info';
|
|
7
|
+
|
|
8
|
+
/** The manifest carries `0.0.0-development` in the repository; the release
|
|
9
|
+
* workflow stamps the tag's version, and the commit, into the package it
|
|
10
|
+
* publishes.
|
|
11
|
+
*/
|
|
12
|
+
const PACKAGE = packageInfo();
|
|
13
|
+
export const VERSION = PACKAGE.version;
|
|
14
|
+
const RELEASE = {
|
|
15
|
+
version: VERSION,
|
|
16
|
+
releasedAt: null,
|
|
17
|
+
revision: PACKAGE.revision,
|
|
18
|
+
issues: PACKAGE.issues,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function wantsInteractive(
|
|
22
|
+
args: string[],
|
|
23
|
+
terminal: boolean,
|
|
24
|
+
ci: boolean
|
|
25
|
+
): boolean {
|
|
26
|
+
if (args.includes('--json') || args.includes('--non-interactive'))
|
|
27
|
+
return false;
|
|
28
|
+
return terminal && !ci && args.includes('--interactive') && contextOnly(args);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function startup(args: string[]) {
|
|
32
|
+
return parseArgs({
|
|
33
|
+
args,
|
|
34
|
+
allowPositionals: true,
|
|
35
|
+
strict: false,
|
|
36
|
+
options: {
|
|
37
|
+
workspace: { type: 'string' },
|
|
38
|
+
config: { type: 'string' },
|
|
39
|
+
interactive: { type: 'boolean' },
|
|
40
|
+
json: { type: 'boolean' },
|
|
41
|
+
'non-interactive': { type: 'boolean' },
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function contextOnly(args: string[]): boolean {
|
|
47
|
+
const parsed = startup(args);
|
|
48
|
+
return (
|
|
49
|
+
parsed.positionals.length === 0 &&
|
|
50
|
+
Object.keys(parsed.values).every((key) =>
|
|
51
|
+
['workspace', 'config', 'interactive'].includes(key)
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function main(args = process.argv.slice(2)): Promise<number> {
|
|
57
|
+
const { values } = startup(args);
|
|
58
|
+
const settings = await resolveSettings({
|
|
59
|
+
...(typeof values.workspace === 'string'
|
|
60
|
+
? { workspace: values.workspace }
|
|
61
|
+
: {}),
|
|
62
|
+
...(typeof values.config === 'string' ? { config: values.config } : {}),
|
|
63
|
+
});
|
|
64
|
+
const forwarded = forwardOwner(args, settings);
|
|
65
|
+
if (forwarded) return forwarded;
|
|
66
|
+
const terminal = interactiveTerminal();
|
|
67
|
+
if (args.includes('--interactive') && !terminal) {
|
|
68
|
+
process.stdout.write(
|
|
69
|
+
`${JSON.stringify({ version: 1, ok: false, code: 'tty_required', error: 'Interactive mode needs a terminal. Use personal commands --json or fleet-status --local --json.' })}\n`
|
|
70
|
+
);
|
|
71
|
+
return 2;
|
|
72
|
+
}
|
|
73
|
+
if (wantsInteractive(args, terminal, Boolean(process.env['CI']))) {
|
|
74
|
+
const { startInteractive } = await import('./ui');
|
|
75
|
+
await startInteractive({
|
|
76
|
+
...settings,
|
|
77
|
+
...RELEASE,
|
|
78
|
+
commands: COMMANDS,
|
|
79
|
+
execute: (command) => execute(command, settings, RELEASE),
|
|
80
|
+
});
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
const outcome = await execute(
|
|
84
|
+
args.filter((arg) => arg !== '--interactive'),
|
|
85
|
+
settings,
|
|
86
|
+
RELEASE
|
|
87
|
+
);
|
|
88
|
+
const text = args.includes('--json')
|
|
89
|
+
? JSON.stringify(outcome.data, null, 2)
|
|
90
|
+
: (outcome.text ?? JSON.stringify(outcome.data, null, 2));
|
|
91
|
+
process.stdout.write(`${text}\n`);
|
|
92
|
+
return outcome.exitCode;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function interactiveTerminal(): boolean {
|
|
96
|
+
return process.stdin.isTTY === true && process.stderr.isTTY === true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function forwardOwner(
|
|
100
|
+
args: string[],
|
|
101
|
+
settings: Settings
|
|
102
|
+
): Promise<number> | undefined {
|
|
103
|
+
const ownerArgs = stripOwnerWorkspace(args);
|
|
104
|
+
if (sourceOperation(ownerArgs))
|
|
105
|
+
return forwardSourceOperation(ownerArgs, settings);
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function stripOwnerWorkspace(args: string[]): string[] {
|
|
110
|
+
const forwarded: string[] = [];
|
|
111
|
+
let child = false;
|
|
112
|
+
for (let index = 0; index < args.length; index++) {
|
|
113
|
+
const arg = args[index]!;
|
|
114
|
+
if (arg === '--') child = true;
|
|
115
|
+
if (!child && arg === '--workspace') {
|
|
116
|
+
index++;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
forwarded.push(arg);
|
|
120
|
+
}
|
|
121
|
+
return forwarded;
|
|
122
|
+
}
|
package/src/cli/cli.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { main } from './app';
|
|
3
|
+
import { useProjectConfig } from './project';
|
|
4
|
+
import { actAsOperator } from '../state/operator';
|
|
5
|
+
import { databasePath } from '../state/paths';
|
|
6
|
+
import { readDocument } from '../state/store';
|
|
7
|
+
|
|
8
|
+
actAsOperator((root) => readDocument(databasePath(root), 'definition'));
|
|
9
|
+
useProjectConfig();
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
process.exitCode = await main();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
const cancelled =
|
|
15
|
+
error instanceof Error &&
|
|
16
|
+
['ExitPromptError', 'AbortPromptError'].includes(error.name);
|
|
17
|
+
process.stdout.write(
|
|
18
|
+
`${JSON.stringify({
|
|
19
|
+
version: 1,
|
|
20
|
+
ok: false,
|
|
21
|
+
code: cancelled ? 'cancelled' : 'operation_failed',
|
|
22
|
+
error: cancelled
|
|
23
|
+
? 'Cancelled; no further actions will run.'
|
|
24
|
+
: 'Command failed. Inspect the local setup; raw errors are withheld to protect credentials.',
|
|
25
|
+
})}\n`
|
|
26
|
+
);
|
|
27
|
+
process.exitCode = cancelled ? 130 : 1;
|
|
28
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SOURCE_OPERATIONS } from './source-operations';
|
|
2
|
+
import { commandCatalog } from './registry';
|
|
3
|
+
import type { CommandSpec } from './contracts';
|
|
4
|
+
|
|
5
|
+
const APPLIES = new Set(['fleet-node-sync', 't3-apply', 't3-cleanup']);
|
|
6
|
+
|
|
7
|
+
/** Additive machine-readable discovery; the registry also drives the menu. */
|
|
8
|
+
export function indexedCommands(search = '', group?: string) {
|
|
9
|
+
return commandCatalog(search, group).map((entry) => ({
|
|
10
|
+
...entry,
|
|
11
|
+
help: `devfleet ${entry.args.join(' ')} --help`,
|
|
12
|
+
execution: execution(entry),
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function execution(entry: CommandSpec) {
|
|
17
|
+
if (Object.hasOwn(SOURCE_OPERATIONS, entry.id))
|
|
18
|
+
return {
|
|
19
|
+
default: 'depends-on-subcommand',
|
|
20
|
+
authorization: 'owner-specific; inspect leaf help before invocation',
|
|
21
|
+
requirements: ['dev-fleet checkout and its toolchain'],
|
|
22
|
+
note: 'Streams the owner protocol. JSON and mutation flags depend on the leaf operation.',
|
|
23
|
+
};
|
|
24
|
+
if (entry.id === 'fleet-sync')
|
|
25
|
+
return {
|
|
26
|
+
default: 'interactive-confirmation-or-action-required',
|
|
27
|
+
authorization: 'interactive-confirmation or --apply --yes',
|
|
28
|
+
preview: 'devfleet fleet-sync --dry-run --json',
|
|
29
|
+
scope:
|
|
30
|
+
'enrolled Ubuntu fleet over verified SSH; manager is not an implicit target',
|
|
31
|
+
note: 'JSON/noninteractive never prompt. Full Ubuntu acceptance is not yet implemented.',
|
|
32
|
+
};
|
|
33
|
+
if (entry.mutation && entry.id.startsWith('fleet-state '))
|
|
34
|
+
return {
|
|
35
|
+
default: 'apply',
|
|
36
|
+
authorization: 'command-invocation',
|
|
37
|
+
preview: 'devfleet fleet-state --json',
|
|
38
|
+
note: 'Each flag is one explicit action on this manager’s fleet state. JSON selects output format; it does not prevent writes.',
|
|
39
|
+
};
|
|
40
|
+
if (APPLIES.has(entry.id))
|
|
41
|
+
return {
|
|
42
|
+
default: 'apply',
|
|
43
|
+
authorization: 'command-invocation',
|
|
44
|
+
preview: `devfleet ${entry.id} --dry-run --json`,
|
|
45
|
+
note:
|
|
46
|
+
entry.id === 't3-apply'
|
|
47
|
+
? '--import ID adopts an existing instance without reconciling. JSON selects output format; it does not prevent writes.'
|
|
48
|
+
: 'JSON selects output format; it does not prevent writes.',
|
|
49
|
+
};
|
|
50
|
+
if (entry.mutation)
|
|
51
|
+
return {
|
|
52
|
+
default: 'preview',
|
|
53
|
+
authorization: '--apply --yes',
|
|
54
|
+
note: 'Supply required options shown by command --help. A preview does not apply changes.',
|
|
55
|
+
};
|
|
56
|
+
return { default: 'read-only', authorization: 'none' };
|
|
57
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface CommandSpec {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
group: string;
|
|
6
|
+
keywords: string[];
|
|
7
|
+
args: string[];
|
|
8
|
+
examples: string[];
|
|
9
|
+
mutation: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CommandOutcome {
|
|
13
|
+
exitCode: number;
|
|
14
|
+
data: unknown;
|
|
15
|
+
text?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface InteractiveOptions {
|
|
19
|
+
version: string;
|
|
20
|
+
releasedAt: string | null;
|
|
21
|
+
workspace: string;
|
|
22
|
+
config: string;
|
|
23
|
+
commands: CommandSpec[];
|
|
24
|
+
execute: (args: string[]) => Promise<CommandOutcome>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Fingerprint, Snapshot } from '../types';
|
|
2
|
+
|
|
3
|
+
declare const PERSONAL_FLEET_REFERENCE: Fingerprint | null | undefined;
|
|
4
|
+
/** Published health carries safe input hashes; it needs no manager checkout or Bun. */
|
|
5
|
+
export function fleetReference(): Snapshot | undefined {
|
|
6
|
+
if (
|
|
7
|
+
typeof PERSONAL_FLEET_REFERENCE === 'undefined' ||
|
|
8
|
+
!PERSONAL_FLEET_REFERENCE?.head
|
|
9
|
+
)
|
|
10
|
+
return undefined;
|
|
11
|
+
return {
|
|
12
|
+
version: 1,
|
|
13
|
+
platform: 'declared-worker-policy',
|
|
14
|
+
fingerprint: PERSONAL_FLEET_REFERENCE,
|
|
15
|
+
checks: [],
|
|
16
|
+
};
|
|
17
|
+
}
|