@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,185 @@
|
|
|
1
|
+
import { SOURCE_OPERATIONS } from './source-operations';
|
|
2
|
+
import type { CommandSpec } from './contracts';
|
|
3
|
+
import { searchCommands } from './search';
|
|
4
|
+
|
|
5
|
+
type Entry = [
|
|
6
|
+
id: string,
|
|
7
|
+
title: string,
|
|
8
|
+
description: string,
|
|
9
|
+
keywords: string[],
|
|
10
|
+
mutation?: boolean,
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
function group(name: string, entries: Entry[]): CommandSpec[] {
|
|
14
|
+
return entries.map(([id, title, description, keywords, mutation]) => ({
|
|
15
|
+
id,
|
|
16
|
+
title,
|
|
17
|
+
description,
|
|
18
|
+
group: name,
|
|
19
|
+
keywords,
|
|
20
|
+
args: id.split(' '),
|
|
21
|
+
examples: [`devfleet ${id} --json`],
|
|
22
|
+
mutation: mutation === true,
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** One flat, prefixed command surface shared by help, the palette and agents. */
|
|
27
|
+
export const COMMANDS: CommandSpec[] = [
|
|
28
|
+
...group('Fleet', [
|
|
29
|
+
[
|
|
30
|
+
'fleet-status',
|
|
31
|
+
'Check this computer and registered nodes',
|
|
32
|
+
'Read-only SSH, authentication, T3, VS Code and dependency checks for this manager and every roster node. --tailnet covers every visible Tailscale computer; --workers audits the canonical worker fleet.',
|
|
33
|
+
['health', 'doctor', 'ssh', 'auth', 'github', 'vscode', 't3', 'diagnose'],
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
'fleet-status --local',
|
|
37
|
+
'Check this computer only',
|
|
38
|
+
'Diagnose this process context without a roster or remote connections.',
|
|
39
|
+
['local', 'manager', 'health'],
|
|
40
|
+
],
|
|
41
|
+
[
|
|
42
|
+
'fleet-status --tailnet',
|
|
43
|
+
'Check all Tailscale computers',
|
|
44
|
+
'Discover every visible non-mobile Tailscale computer, then test reachability, pinned tools, configuration and service logins. Offline, unregistered and unverified computers fail coverage.',
|
|
45
|
+
['tailscale', 'tailnet', 'all', 'versions', 'codex', 'claude', 'login'],
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
'fleet-status --workers',
|
|
49
|
+
'Check the canonical worker fleet',
|
|
50
|
+
'Read-only canonical worker readiness, dependencies, services and authentication; lists every remaining gap.',
|
|
51
|
+
['workers', 'readiness', 'health', 'canonical'],
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
'fleet-discover',
|
|
55
|
+
'Discover Tailscale computers',
|
|
56
|
+
'List all computers visible to this Tailscale account, including offline devices. Excludes iOS, Android and tvOS; never writes a roster.',
|
|
57
|
+
['tailscale', 'tailnet', 'computers', 'machines'],
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
'fleet-sync',
|
|
61
|
+
'Synchronize the enrolled Ubuntu fleet',
|
|
62
|
+
'Manager push to all enrolled Ubuntu nodes at one approved revision over verified SSH: the commit the dev-fleet package was published from, with the fleet.json of the project it is run from. Interactive confirmation or --apply --yes. Readiness is verified separately.',
|
|
63
|
+
['ubuntu', 'enrollment', 'converge', 'sync'],
|
|
64
|
+
true,
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
'fleet-state',
|
|
68
|
+
'Check the fleet state and its bucket',
|
|
69
|
+
'Read-only: where the fleet configuration, the roster and the approved revision are kept on this manager, and whether the bucket holds the same version. --example prints a fleet.json to start a project from; --export prints the configuration fleet-sync last applied; --import PATH stores one.',
|
|
70
|
+
['state', 'bucket', 's3', 'backup', 'litestream', 'configuration'],
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
'fleet-state --init',
|
|
74
|
+
'Connect the bucket and restore or seed the fleet state',
|
|
75
|
+
'Restore the fleet state from the bucket fleet.json names under "state" (or the one given with --bucket/--endpoint or --directory), or seed an empty bucket from this machine, and save the bucket and its credentials on this machine for runs it starts by itself. Credentials come from the environment or a terminal prompt.',
|
|
76
|
+
['state', 'bucket', 's3', 'setup', 'restore', 'new manager'],
|
|
77
|
+
true,
|
|
78
|
+
],
|
|
79
|
+
[
|
|
80
|
+
'fleet-state --push',
|
|
81
|
+
'Upload fleet state changes to the bucket',
|
|
82
|
+
'Upload changes this manager made while the bucket was unreachable. Refuses when the bucket has changed since.',
|
|
83
|
+
['state', 'bucket', 'upload', 'replicate'],
|
|
84
|
+
true,
|
|
85
|
+
],
|
|
86
|
+
[
|
|
87
|
+
'fleet-state --restore',
|
|
88
|
+
'Replace the local fleet state with the bucket’s',
|
|
89
|
+
'Discard this manager’s copy of the fleet state and download the bucket’s version. Needs --yes when this machine has changes the bucket does not hold.',
|
|
90
|
+
['state', 'bucket', 'restore', 'recover', 'disposable'],
|
|
91
|
+
true,
|
|
92
|
+
],
|
|
93
|
+
[
|
|
94
|
+
'fleet-node-sync',
|
|
95
|
+
'Sync this node',
|
|
96
|
+
'Reconcile locked tools, the personal launcher, Codex proxy profile and owned T3 instances on this machine. Applies by default; --dry-run previews.',
|
|
97
|
+
['node', 'sync', 'proxy', 'tools'],
|
|
98
|
+
true,
|
|
99
|
+
],
|
|
100
|
+
[
|
|
101
|
+
'fleet-repair',
|
|
102
|
+
'Repair tools and configuration',
|
|
103
|
+
'Inspect visible Tailscale computers and preview owner-managed repairs. --apply --yes executes eligible tools/config repairs and reruns diagnostics. Logins and host trust remain explicit operator steps.',
|
|
104
|
+
['fix', 'repair', 'sync', 'setup', 'versions', 'config', 'login'],
|
|
105
|
+
true,
|
|
106
|
+
],
|
|
107
|
+
[
|
|
108
|
+
'fleet-repair --list',
|
|
109
|
+
'Explore repairs and login commands',
|
|
110
|
+
'List existing tool owners, automated repairs, native per-machine login commands and shared Vault access guidance. No roster or credentials required.',
|
|
111
|
+
['fix', 'repair', 'login', 'credentials', 'vault', 'catalog'],
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
'fleet-nodes',
|
|
115
|
+
'Explore fleet nodes',
|
|
116
|
+
'List and validate registered developer computers without contacting them. --onboard adds per-node setup instructions; --schema prints the roster JSON schema.',
|
|
117
|
+
['roster', 'list', 'machines', 'validate', 'schema'],
|
|
118
|
+
],
|
|
119
|
+
[
|
|
120
|
+
'fleet-nodes --onboard',
|
|
121
|
+
'Explore onboarding instructions',
|
|
122
|
+
'Get per-node SSH templates, VS Code guidance, authentication steps and safe verification commands.',
|
|
123
|
+
['setup', 'guide', 'instructions', 'vscode', 'connect'],
|
|
124
|
+
],
|
|
125
|
+
[
|
|
126
|
+
'fleet-nodes --schema',
|
|
127
|
+
'Explore the fleet JSON schema',
|
|
128
|
+
'Read the versioned roster schema for editors and agents.',
|
|
129
|
+
['agent', 'config', 'json', 'schema'],
|
|
130
|
+
],
|
|
131
|
+
[
|
|
132
|
+
'fleet-node-add',
|
|
133
|
+
'Register a developer computer',
|
|
134
|
+
'Preview or explicitly save an existing SSH alias, checkout path and per-machine capabilities. No SSH or cloud setup.',
|
|
135
|
+
['onboarding', 'register', 'new', 'setup', 'add'],
|
|
136
|
+
true,
|
|
137
|
+
],
|
|
138
|
+
]),
|
|
139
|
+
...group('T3', [
|
|
140
|
+
[
|
|
141
|
+
't3-status',
|
|
142
|
+
'Check T3 configuration drift',
|
|
143
|
+
'Compare declared T3 provider instances with the configuration on this machine; exit 1 on drift.',
|
|
144
|
+
['t3', 'drift', 'status'],
|
|
145
|
+
],
|
|
146
|
+
[
|
|
147
|
+
't3-apply',
|
|
148
|
+
'Reconcile T3 provider instances',
|
|
149
|
+
'Create and update declared instances and remove previously owned instances absent from the definition. --dry-run plans; --plan-hash rejects stale plans; --import ID adopts an existing instance.',
|
|
150
|
+
['t3', 'apply', 'plan', 'import', 'reconcile'],
|
|
151
|
+
true,
|
|
152
|
+
],
|
|
153
|
+
[
|
|
154
|
+
't3-cleanup',
|
|
155
|
+
'Remove owned T3 instances',
|
|
156
|
+
'Remove only provider instances recorded in personal ownership state. --dry-run previews.',
|
|
157
|
+
['t3', 'cleanup', 'remove'],
|
|
158
|
+
true,
|
|
159
|
+
],
|
|
160
|
+
]),
|
|
161
|
+
...group(
|
|
162
|
+
'Services',
|
|
163
|
+
Object.entries(SOURCE_OPERATIONS).map(([id, operation]) => [
|
|
164
|
+
id,
|
|
165
|
+
operation.title,
|
|
166
|
+
`${operation.description} Inspect devfleet ${id} help.`,
|
|
167
|
+
operation.keywords,
|
|
168
|
+
operation.mutation,
|
|
169
|
+
])
|
|
170
|
+
),
|
|
171
|
+
...group('Reference', [
|
|
172
|
+
[
|
|
173
|
+
'commands',
|
|
174
|
+
'Explore the command catalog and agent contract',
|
|
175
|
+
'Search the command index; the JSON document also carries the agent usage/safety contract, release metadata and exit codes.',
|
|
176
|
+
['search', 'help', 'llm', 'agent', 'api', 'index'],
|
|
177
|
+
],
|
|
178
|
+
]),
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
export function commandCatalog(search = '', group?: string): CommandSpec[] {
|
|
182
|
+
return searchCommands(COMMANDS, search).filter(
|
|
183
|
+
(command) => !group || command.group.toLowerCase() === group.toLowerCase()
|
|
184
|
+
);
|
|
185
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { automaticRepairs } from '../repair-plan';
|
|
2
|
+
import { mapBounded } from '../report';
|
|
3
|
+
import { repairWorkspace } from '../repair-runner';
|
|
4
|
+
import { inspectRemote } from '../transport';
|
|
5
|
+
import { timeout } from './options';
|
|
6
|
+
import type { AutomatedRepair } from '../repair-catalog';
|
|
7
|
+
import type { RepairTarget, RepairStep } from '../repair-plan';
|
|
8
|
+
import type { NodeReport } from '../types';
|
|
9
|
+
import type { CliOptions } from './options';
|
|
10
|
+
import type { FleetServices } from './fleet';
|
|
11
|
+
|
|
12
|
+
export async function applyRepairs(
|
|
13
|
+
targets: RepairTarget[],
|
|
14
|
+
steps: RepairStep[],
|
|
15
|
+
options: CliOptions,
|
|
16
|
+
services: FleetServices
|
|
17
|
+
): Promise<NodeReport[]> {
|
|
18
|
+
let source: Promise<string> | undefined;
|
|
19
|
+
return mapBounded(
|
|
20
|
+
targets,
|
|
21
|
+
async (target) => {
|
|
22
|
+
const actions = automaticRepairs(steps, target.name);
|
|
23
|
+
const checks: NodeReport['checks'] = [];
|
|
24
|
+
for (const step of actions) {
|
|
25
|
+
try {
|
|
26
|
+
if (!target.fingerprint)
|
|
27
|
+
throw new Error('No verified checkout fingerprint');
|
|
28
|
+
const repairs = [step.id as AutomatedRepair];
|
|
29
|
+
const result = target.node
|
|
30
|
+
? (
|
|
31
|
+
await inspectRemote(
|
|
32
|
+
target.node,
|
|
33
|
+
{
|
|
34
|
+
action: 'repair',
|
|
35
|
+
repairs,
|
|
36
|
+
expected: target.fingerprint,
|
|
37
|
+
source: await (source ??= Promise.resolve().then(
|
|
38
|
+
services.source
|
|
39
|
+
)),
|
|
40
|
+
timeoutMs: timeout(options),
|
|
41
|
+
},
|
|
42
|
+
services.run
|
|
43
|
+
)
|
|
44
|
+
).checks
|
|
45
|
+
: await repairWorkspace(
|
|
46
|
+
target.root,
|
|
47
|
+
repairs,
|
|
48
|
+
services.run,
|
|
49
|
+
target.fingerprint
|
|
50
|
+
);
|
|
51
|
+
checks.push(...result);
|
|
52
|
+
if (result.some((check) => check.status !== 'pass')) break;
|
|
53
|
+
} catch {
|
|
54
|
+
checks.push({
|
|
55
|
+
id: 'repair:operation',
|
|
56
|
+
status: 'fail',
|
|
57
|
+
summary:
|
|
58
|
+
'Repair could not be prepared or completed. Later actions on this computer were stopped; inspect partial changes locally. Raw errors are withheld.',
|
|
59
|
+
});
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return { node: target.name, checks };
|
|
64
|
+
},
|
|
65
|
+
1
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import type { RepairStep, RepairTarget } from '../repair-plan';
|
|
3
|
+
|
|
4
|
+
export function repairPlanHash(
|
|
5
|
+
steps: RepairStep[],
|
|
6
|
+
targets: RepairTarget[]
|
|
7
|
+
): string {
|
|
8
|
+
return createHash('sha256')
|
|
9
|
+
.update(JSON.stringify({ steps, targets }))
|
|
10
|
+
.digest('hex');
|
|
11
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { selectNodes } from '../config';
|
|
2
|
+
import { probe } from '../probe';
|
|
3
|
+
import { mapBounded } from '../report';
|
|
4
|
+
import { discoverTailnet } from '../tailscale';
|
|
5
|
+
import {
|
|
6
|
+
HEALTH_CAPABILITIES,
|
|
7
|
+
tailnetHealth,
|
|
8
|
+
uniqueMapping,
|
|
9
|
+
} from '../tailnet-health';
|
|
10
|
+
import { matchComputers } from '../tailnet-matching';
|
|
11
|
+
import { inspectRemote } from '../transport';
|
|
12
|
+
import { FleetUsageError } from '../errors';
|
|
13
|
+
import { readRoster } from './roster';
|
|
14
|
+
import { capabilities, timeout } from './options';
|
|
15
|
+
import type { NodeReport, FleetConfig } from '../types';
|
|
16
|
+
import type { RepairTarget } from '../repair-plan';
|
|
17
|
+
import type { FleetServices } from './fleet';
|
|
18
|
+
import type { CliOptions } from './options';
|
|
19
|
+
import type { Settings } from './settings';
|
|
20
|
+
|
|
21
|
+
export interface RepairInspection {
|
|
22
|
+
reports: NodeReport[];
|
|
23
|
+
targets: RepairTarget[];
|
|
24
|
+
coverage: { scope: string; limitation: string };
|
|
25
|
+
}
|
|
26
|
+
export async function inspectRepair(
|
|
27
|
+
options: CliOptions,
|
|
28
|
+
settings: Settings,
|
|
29
|
+
services: FleetServices
|
|
30
|
+
): Promise<RepairInspection> {
|
|
31
|
+
if (options.local) return inspectLocal(settings, services, options);
|
|
32
|
+
const roster = await readRoster(settings.config);
|
|
33
|
+
if (options.node?.length) return inspectSelected(options, roster, services);
|
|
34
|
+
return inspectTailnet(options, settings, roster, services);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function inspectLocal(
|
|
38
|
+
settings: Settings,
|
|
39
|
+
services: FleetServices,
|
|
40
|
+
options: CliOptions
|
|
41
|
+
): Promise<RepairInspection> {
|
|
42
|
+
const snapshot = await probe(
|
|
43
|
+
settings.workspace,
|
|
44
|
+
options.require === undefined
|
|
45
|
+
? HEALTH_CAPABILITIES
|
|
46
|
+
: capabilities(options.require),
|
|
47
|
+
services.run
|
|
48
|
+
);
|
|
49
|
+
return {
|
|
50
|
+
reports: [{ node: 'local', snapshot, checks: snapshot.checks }],
|
|
51
|
+
targets: [
|
|
52
|
+
{
|
|
53
|
+
name: 'local',
|
|
54
|
+
root: settings.workspace,
|
|
55
|
+
fingerprint: snapshot.fingerprint,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
coverage: {
|
|
59
|
+
scope: 'local',
|
|
60
|
+
limitation: 'Only this process context was tested.',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function inspectSelected(
|
|
66
|
+
options: CliOptions,
|
|
67
|
+
roster: FleetConfig | null,
|
|
68
|
+
services: FleetServices
|
|
69
|
+
): Promise<RepairInspection> {
|
|
70
|
+
if (!roster)
|
|
71
|
+
throw new FleetUsageError(
|
|
72
|
+
'Register real SSH aliases and checkout paths before selecting remote repairs.'
|
|
73
|
+
);
|
|
74
|
+
const nodes = selectNodes(roster, options.node ?? []);
|
|
75
|
+
const source = await services.source();
|
|
76
|
+
const reports = await mapBounded(nodes, (node) =>
|
|
77
|
+
inspectRemote(
|
|
78
|
+
node,
|
|
79
|
+
{ action: 'probe', source, timeoutMs: timeout(options) },
|
|
80
|
+
services.run
|
|
81
|
+
)
|
|
82
|
+
);
|
|
83
|
+
return {
|
|
84
|
+
reports,
|
|
85
|
+
targets: nodes.map((node) =>
|
|
86
|
+
attachFingerprint({ name: node.id, root: node.workspace, node }, reports)
|
|
87
|
+
),
|
|
88
|
+
coverage: {
|
|
89
|
+
scope: 'selected',
|
|
90
|
+
limitation:
|
|
91
|
+
'Only selected roster computers were tested; other devices are unverified.',
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function inspectTailnet(
|
|
97
|
+
options: CliOptions,
|
|
98
|
+
settings: Settings,
|
|
99
|
+
roster: FleetConfig | null,
|
|
100
|
+
services: FleetServices
|
|
101
|
+
): Promise<RepairInspection> {
|
|
102
|
+
const tailnet = await discoverTailnet(services.run);
|
|
103
|
+
const reports = await tailnetHealth(
|
|
104
|
+
tailnet,
|
|
105
|
+
roster?.nodes ?? [],
|
|
106
|
+
{
|
|
107
|
+
root: settings.workspace,
|
|
108
|
+
timeoutMs: timeout(options),
|
|
109
|
+
source: services.source,
|
|
110
|
+
},
|
|
111
|
+
services.run
|
|
112
|
+
);
|
|
113
|
+
const matches = await matchComputers(
|
|
114
|
+
roster?.nodes ?? [],
|
|
115
|
+
tailnet.computers,
|
|
116
|
+
services.run
|
|
117
|
+
);
|
|
118
|
+
const targets: RepairTarget[] = [];
|
|
119
|
+
for (const peer of tailnet.computers) {
|
|
120
|
+
if (peer.self) targets.push({ name: peer.dns, root: settings.workspace });
|
|
121
|
+
else if (peer.online && uniqueMapping(matches.get(peer.id)!, matches)) {
|
|
122
|
+
const node = matches.get(peer.id)![0]!;
|
|
123
|
+
targets.push({ name: peer.dns, root: node.workspace, node });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!tailnet.computers.some((peer) => peer.self))
|
|
127
|
+
targets.push({ name: 'manager', root: settings.workspace });
|
|
128
|
+
return {
|
|
129
|
+
reports,
|
|
130
|
+
targets: targets.map((target) => attachFingerprint(target, reports)),
|
|
131
|
+
coverage: {
|
|
132
|
+
scope: 'tailscale-visible-computers',
|
|
133
|
+
limitation:
|
|
134
|
+
'Only devices visible to this Tailscale account/ACLs. Offline, unregistered or ambiguous computers cannot be repaired. No credentials, host keys or resources are cloned.',
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function attachFingerprint(
|
|
140
|
+
target: RepairTarget,
|
|
141
|
+
reports: NodeReport[]
|
|
142
|
+
): RepairTarget {
|
|
143
|
+
const snapshot = reports.find(
|
|
144
|
+
(report) => report.node === target.name
|
|
145
|
+
)?.snapshot;
|
|
146
|
+
return {
|
|
147
|
+
...target,
|
|
148
|
+
...(snapshot ? { fingerprint: snapshot.fingerprint } : {}),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { automaticRepairs } from '../repair-plan';
|
|
2
|
+
import { recipe } from '../repair-catalog';
|
|
3
|
+
import { shellQuote, sshArgs } from '../ssh';
|
|
4
|
+
import type { RepairTarget, RepairStep } from '../repair-plan';
|
|
5
|
+
|
|
6
|
+
export function targetCommand(
|
|
7
|
+
target: RepairTarget,
|
|
8
|
+
commands: string[][]
|
|
9
|
+
): string {
|
|
10
|
+
const command = `cd -- ${shellQuote(target.root)} && ${commands.map((args) => args.map(shellQuote).join(' ')).join(' && ')}`;
|
|
11
|
+
if (!target.node) return command;
|
|
12
|
+
return [
|
|
13
|
+
...sshArgs(target.node)
|
|
14
|
+
.map((arg) => (arg === '-T' ? '-t' : arg))
|
|
15
|
+
.map(shellQuote),
|
|
16
|
+
shellQuote(command),
|
|
17
|
+
].join(' ');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Generates a reviewable operator script. It is never written or executed by this command. */
|
|
21
|
+
export function repairScript(
|
|
22
|
+
steps: RepairStep[],
|
|
23
|
+
targets: RepairTarget[]
|
|
24
|
+
): string {
|
|
25
|
+
const lines = [
|
|
26
|
+
'#!/bin/sh',
|
|
27
|
+
'set -eu',
|
|
28
|
+
'# Generated repair plan. Review before running in your own terminal.',
|
|
29
|
+
'# Automated steps use existing owners. Native login commands below are commented and require operator approval.',
|
|
30
|
+
'# POSIX shell required; Windows operators can use the personal commands directly.',
|
|
31
|
+
];
|
|
32
|
+
for (const target of targets) {
|
|
33
|
+
const actions = automaticRepairs(steps, target.name);
|
|
34
|
+
if (!actions.length) continue;
|
|
35
|
+
const commands = actions.flatMap((step) =>
|
|
36
|
+
step.id === 'workspace'
|
|
37
|
+
? [
|
|
38
|
+
[
|
|
39
|
+
'bun',
|
|
40
|
+
'src/cli/cli.ts',
|
|
41
|
+
'fleet-repair',
|
|
42
|
+
'--local',
|
|
43
|
+
'--repair',
|
|
44
|
+
'workspace',
|
|
45
|
+
'--apply',
|
|
46
|
+
'--yes',
|
|
47
|
+
'--json',
|
|
48
|
+
],
|
|
49
|
+
]
|
|
50
|
+
: recipe(step.id).commands
|
|
51
|
+
);
|
|
52
|
+
lines.push('', targetCommand(target, commands));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
for (const step of steps.filter(
|
|
56
|
+
(entry) => !entry.automatic || !entry.eligible
|
|
57
|
+
)) {
|
|
58
|
+
lines.push(
|
|
59
|
+
'',
|
|
60
|
+
`# ${comment(step.node)} / ${comment(step.title)}`,
|
|
61
|
+
`# ${comment(step.action)}`
|
|
62
|
+
);
|
|
63
|
+
const target = targets.find((entry) => entry.name === step.node);
|
|
64
|
+
if (target && step.eligible && step.commands.length)
|
|
65
|
+
lines.push(`# ${targetCommand(target, step.commands)}`);
|
|
66
|
+
else for (const next of step.next) lines.push(`# ${comment(next)}`);
|
|
67
|
+
}
|
|
68
|
+
lines.push(
|
|
69
|
+
'',
|
|
70
|
+
'# Re-run devfleet fleet-status --tailnet --json for fresh whole-tailnet coverage.'
|
|
71
|
+
);
|
|
72
|
+
return `${lines.join('\n')}\n`;
|
|
73
|
+
}
|
|
74
|
+
function comment(value: string): string {
|
|
75
|
+
return value.replace(/[\r\n\x00-\x1f\x7f]/g, ' ');
|
|
76
|
+
}
|