agent-army 0.1.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.
Files changed (80) hide show
  1. package/README.md +162 -0
  2. package/dist/adapters/api-adapter.d.ts +76 -0
  3. package/dist/adapters/api-adapter.js +251 -0
  4. package/dist/adapters/api-adapter.js.map +1 -0
  5. package/dist/adapters/cli-adapter.d.ts +15 -0
  6. package/dist/adapters/cli-adapter.js +207 -0
  7. package/dist/adapters/cli-adapter.js.map +1 -0
  8. package/dist/adapters/index.d.ts +22 -0
  9. package/dist/adapters/index.js +32 -0
  10. package/dist/adapters/index.js.map +1 -0
  11. package/dist/adapters/types.d.ts +135 -0
  12. package/dist/adapters/types.js +14 -0
  13. package/dist/adapters/types.js.map +1 -0
  14. package/dist/bin.d.ts +8 -0
  15. package/dist/bin.js +83 -0
  16. package/dist/bin.js.map +1 -0
  17. package/dist/commands/deploy.d.ts +7 -0
  18. package/dist/commands/deploy.js +13 -0
  19. package/dist/commands/deploy.js.map +1 -0
  20. package/dist/commands/destroy.d.ts +7 -0
  21. package/dist/commands/destroy.js +13 -0
  22. package/dist/commands/destroy.js.map +1 -0
  23. package/dist/commands/init.d.ts +9 -0
  24. package/dist/commands/init.js +538 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/list.d.ts +8 -0
  27. package/dist/commands/list.js +42 -0
  28. package/dist/commands/list.js.map +1 -0
  29. package/dist/commands/ssh.d.ts +9 -0
  30. package/dist/commands/ssh.js +101 -0
  31. package/dist/commands/ssh.js.map +1 -0
  32. package/dist/commands/status.d.ts +7 -0
  33. package/dist/commands/status.js +13 -0
  34. package/dist/commands/status.js.map +1 -0
  35. package/dist/commands/validate.d.ts +7 -0
  36. package/dist/commands/validate.js +13 -0
  37. package/dist/commands/validate.js.map +1 -0
  38. package/dist/lib/config.d.ts +66 -0
  39. package/dist/lib/config.js +239 -0
  40. package/dist/lib/config.js.map +1 -0
  41. package/dist/lib/constants.d.ts +147 -0
  42. package/dist/lib/constants.js +307 -0
  43. package/dist/lib/constants.js.map +1 -0
  44. package/dist/lib/exec.d.ts +22 -0
  45. package/dist/lib/exec.js +60 -0
  46. package/dist/lib/exec.js.map +1 -0
  47. package/dist/lib/prerequisites.d.ts +8 -0
  48. package/dist/lib/prerequisites.js +124 -0
  49. package/dist/lib/prerequisites.js.map +1 -0
  50. package/dist/lib/process.d.ts +18 -0
  51. package/dist/lib/process.js +37 -0
  52. package/dist/lib/process.js.map +1 -0
  53. package/dist/lib/pulumi.d.ts +39 -0
  54. package/dist/lib/pulumi.js +87 -0
  55. package/dist/lib/pulumi.js.map +1 -0
  56. package/dist/lib/tailscale.d.ts +24 -0
  57. package/dist/lib/tailscale.js +71 -0
  58. package/dist/lib/tailscale.js.map +1 -0
  59. package/dist/lib/ui.d.ts +27 -0
  60. package/dist/lib/ui.js +89 -0
  61. package/dist/lib/ui.js.map +1 -0
  62. package/dist/tools/deploy.d.ts +16 -0
  63. package/dist/tools/deploy.js +133 -0
  64. package/dist/tools/deploy.js.map +1 -0
  65. package/dist/tools/destroy.d.ts +16 -0
  66. package/dist/tools/destroy.js +186 -0
  67. package/dist/tools/destroy.js.map +1 -0
  68. package/dist/tools/index.d.ts +17 -0
  69. package/dist/tools/index.js +28 -0
  70. package/dist/tools/index.js.map +1 -0
  71. package/dist/tools/status.d.ts +16 -0
  72. package/dist/tools/status.js +213 -0
  73. package/dist/tools/status.js.map +1 -0
  74. package/dist/tools/validate.d.ts +16 -0
  75. package/dist/tools/validate.js +215 -0
  76. package/dist/tools/validate.js.map +1 -0
  77. package/dist/types.d.ts +50 -0
  78. package/dist/types.js +6 -0
  79. package/dist/types.js.map +1 -0
  80. package/package.json +32 -0
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /**
3
+ * Destroy Tool — Tear down resources with safety confirmations
4
+ *
5
+ * Platform-agnostic implementation using RuntimeAdapter.
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.destroyTool = void 0;
12
+ const config_1 = require("../lib/config");
13
+ const constants_1 = require("../lib/constants");
14
+ const picocolors_1 = __importDefault(require("picocolors"));
15
+ /**
16
+ * Format agent list for display
17
+ */
18
+ function formatAgentList(agents) {
19
+ return agents
20
+ .map((a) => {
21
+ const type = a.preset ? `preset:${a.preset}` : "custom";
22
+ return ` ${picocolors_1.default.bold(a.displayName)} (${a.role}) [${type}]`;
23
+ })
24
+ .join("\n");
25
+ }
26
+ /**
27
+ * Get Pulumi config value
28
+ */
29
+ function getConfig(exec, key) {
30
+ const result = exec.capture("pulumi", ["config", "get", key]);
31
+ return result.exitCode === 0 ? result.stdout.trim() : null;
32
+ }
33
+ /**
34
+ * List all devices on a tailnet via the Tailscale API.
35
+ */
36
+ function listTailscaleDevices(exec, apiKey, tailnet) {
37
+ const result = exec.capture("curl", [
38
+ "-sf",
39
+ "-H", `Authorization: Bearer ${apiKey}`,
40
+ `https://api.tailscale.com/api/v2/tailnet/${tailnet}/devices?fields=default`,
41
+ ]);
42
+ if (result.exitCode !== 0)
43
+ return null;
44
+ try {
45
+ const data = JSON.parse(result.stdout);
46
+ if (!data.devices || !Array.isArray(data.devices))
47
+ return null;
48
+ return data.devices.map((d) => ({
49
+ id: d.id,
50
+ name: d.name ?? "",
51
+ hostname: d.hostname ?? "",
52
+ }));
53
+ }
54
+ catch (err) {
55
+ console.warn(`[destroy] Failed to parse Tailscale API response: ${err instanceof Error ? err.message : String(err)}`);
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * Delete a single Tailscale device by ID.
61
+ */
62
+ function deleteTailscaleDevice(exec, apiKey, deviceId) {
63
+ const result = exec.capture("curl", [
64
+ "-sf",
65
+ "-X", "DELETE",
66
+ "-H", `Authorization: Bearer ${apiKey}`,
67
+ `https://api.tailscale.com/api/v2/device/${deviceId}`,
68
+ ]);
69
+ return result.exitCode === 0;
70
+ }
71
+ /**
72
+ * Destroy tool implementation
73
+ */
74
+ const destroyTool = async (runtime, options) => {
75
+ const { ui, exec } = runtime;
76
+ ui.intro("Agent Army");
77
+ // Resolve config name and load manifest
78
+ let configName;
79
+ try {
80
+ configName = (0, config_1.resolveConfigName)(options.config);
81
+ }
82
+ catch (err) {
83
+ ui.log.error(err.message);
84
+ process.exit(1);
85
+ }
86
+ const manifest = (0, config_1.loadManifest)(configName);
87
+ if (!manifest) {
88
+ ui.log.error(`Config '${configName}' could not be loaded.`);
89
+ process.exit(1);
90
+ }
91
+ // Select/create stack
92
+ const selectResult = exec.capture("pulumi", ["stack", "select", manifest.stackName]);
93
+ if (selectResult.exitCode !== 0) {
94
+ const initResult = exec.capture("pulumi", ["stack", "init", manifest.stackName]);
95
+ if (initResult.exitCode !== 0) {
96
+ ui.log.error(`Could not select Pulumi stack "${manifest.stackName}".`);
97
+ process.exit(1);
98
+ }
99
+ }
100
+ // Show what will be destroyed (provider-aware)
101
+ const manifestProvider = manifest.provider ?? "aws";
102
+ const resourceLabel = manifestProvider === "hetzner" ? "Hetzner servers" : "EC2 instances";
103
+ const infraLabel = manifestProvider === "hetzner" ? "Firewall rules" : "VPC, subnet, and security group";
104
+ ui.note([
105
+ `Stack: ${manifest.stackName}`,
106
+ `Region: ${manifest.region}`,
107
+ ``,
108
+ `Agents (${manifest.agents.length}):`,
109
+ formatAgentList(manifest.agents),
110
+ ``,
111
+ `This will PERMANENTLY DESTROY:`,
112
+ ` - ${manifest.agents.length} ${resourceLabel}`,
113
+ ` - All workspace data on those instances`,
114
+ ` - ${infraLabel}`,
115
+ ` - Tailscale device registrations`,
116
+ ].join("\n"), "Destruction Plan");
117
+ // Confirm
118
+ if (!options.yes) {
119
+ const typedName = await ui.text({
120
+ message: `Type the stack name to confirm: "${manifest.stackName}"`,
121
+ validate: (val) => {
122
+ if (val !== manifest.stackName)
123
+ return `Must type "${manifest.stackName}" to confirm`;
124
+ return undefined;
125
+ },
126
+ });
127
+ const confirmed = await ui.confirm({
128
+ message: "Are you ABSOLUTELY sure?",
129
+ initialValue: false,
130
+ });
131
+ if (!confirmed) {
132
+ ui.cancel("Destruction cancelled.");
133
+ }
134
+ }
135
+ // Sync manifest to project root so the Pulumi program can read it
136
+ (0, config_1.syncManifestToProject)(configName);
137
+ // Destroy infrastructure
138
+ ui.log.step("Running pulumi destroy...");
139
+ console.log();
140
+ const exitCode = await exec.stream("pulumi", ["destroy", "--yes"]);
141
+ console.log();
142
+ if (exitCode !== 0) {
143
+ ui.log.error("Destruction failed. Check the output above for details.");
144
+ process.exit(1);
145
+ }
146
+ // Clean up Tailscale devices after infrastructure is destroyed
147
+ const tailnetDnsName = getConfig(exec, "tailnetDnsName");
148
+ const tailscaleApiKey = getConfig(exec, "tailscaleApiKey");
149
+ if (tailnetDnsName && tailscaleApiKey) {
150
+ const spinner = ui.spinner("Removing agents from Tailscale...");
151
+ const apiFailed = [];
152
+ const tailnet = tailnetDnsName;
153
+ const devices = listTailscaleDevices(exec, tailscaleApiKey, tailnet);
154
+ if (devices) {
155
+ for (const agent of manifest.agents) {
156
+ const tsHost = (0, constants_1.tailscaleHostname)(manifest.stackName, agent.name);
157
+ const device = devices.find((d) => d.hostname === tsHost || d.name.startsWith(`${tsHost}.`));
158
+ if (device) {
159
+ const deleted = deleteTailscaleDevice(exec, tailscaleApiKey, device.id);
160
+ if (!deleted)
161
+ apiFailed.push(agent.name);
162
+ }
163
+ }
164
+ if (apiFailed.length === 0) {
165
+ spinner.stop("Tailscale devices cleaned up");
166
+ }
167
+ else {
168
+ spinner.stop("Some Tailscale devices could not be removed");
169
+ ui.log.warn(`Could not remove: ${apiFailed.join(", ")}. Remove manually from https://login.tailscale.com/admin/machines`);
170
+ }
171
+ }
172
+ else {
173
+ spinner.stop("Could not list Tailscale devices");
174
+ ui.log.warn("Manual cleanup may be needed at https://login.tailscale.com/admin/machines");
175
+ }
176
+ }
177
+ else if (tailnetDnsName && !tailscaleApiKey) {
178
+ ui.log.warn("No Tailscale API key configured - devices must be removed manually.");
179
+ console.log(" Remove devices at: https://login.tailscale.com/admin/machines");
180
+ console.log(" Tip: Set a Tailscale API key (`agent-army init`) for automatic cleanup.");
181
+ }
182
+ ui.log.success(`Stack "${manifest.stackName}" has been destroyed.`);
183
+ ui.outro("Done!");
184
+ };
185
+ exports.destroyTool = destroyTool;
186
+ //# sourceMappingURL=destroy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"destroy.js","sourceRoot":"","sources":["../../tools/destroy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Tools Module
3
+ *
4
+ * Platform-agnostic tool implementations using the RuntimeAdapter pattern.
5
+ * Each tool is a ToolImplementation that can run with any adapter.
6
+ *
7
+ * @example
8
+ * import { deployTool, createCLIAdapter } from './tools';
9
+ *
10
+ * // Run with CLI adapter
11
+ * await deployTool(createCLIAdapter(), { yes: false });
12
+ */
13
+ export { deployTool, type DeployOptions } from "./deploy";
14
+ export { statusTool, type StatusOptions } from "./status";
15
+ export { validateTool, type ValidateOptions } from "./validate";
16
+ export { destroyTool, type DestroyOptions } from "./destroy";
17
+ export { type RuntimeAdapter, type ToolImplementation, type ToolDefinition, createCLIAdapter, } from "../adapters";
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Tools Module
4
+ *
5
+ * Platform-agnostic tool implementations using the RuntimeAdapter pattern.
6
+ * Each tool is a ToolImplementation that can run with any adapter.
7
+ *
8
+ * @example
9
+ * import { deployTool, createCLIAdapter } from './tools';
10
+ *
11
+ * // Run with CLI adapter
12
+ * await deployTool(createCLIAdapter(), { yes: false });
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createCLIAdapter = exports.destroyTool = exports.validateTool = exports.statusTool = exports.deployTool = void 0;
16
+ // Export all tools
17
+ var deploy_1 = require("./deploy");
18
+ Object.defineProperty(exports, "deployTool", { enumerable: true, get: function () { return deploy_1.deployTool; } });
19
+ var status_1 = require("./status");
20
+ Object.defineProperty(exports, "statusTool", { enumerable: true, get: function () { return status_1.statusTool; } });
21
+ var validate_1 = require("./validate");
22
+ Object.defineProperty(exports, "validateTool", { enumerable: true, get: function () { return validate_1.validateTool; } });
23
+ var destroy_1 = require("./destroy");
24
+ Object.defineProperty(exports, "destroyTool", { enumerable: true, get: function () { return destroy_1.destroyTool; } });
25
+ // Re-export adapter types and factory for convenience
26
+ var adapters_1 = require("../adapters");
27
+ Object.defineProperty(exports, "createCLIAdapter", { enumerable: true, get: function () { return adapters_1.createCLIAdapter; } });
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../tools/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAEH,mBAAmB;AACnB,mCAA0D;AAAjD,oGAAA,UAAU,OAAA;AACnB,mCAA0D;AAAjD,oGAAA,UAAU,OAAA;AACnB,uCAAgE;AAAvD,wGAAA,YAAY,OAAA;AACrB,qCAA6D;AAApD,sGAAA,WAAW,OAAA;AAEpB,sDAAsD;AACtD,wCAKqB;AADnB,4GAAA,gBAAgB,OAAA"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Status Tool — Show agent statuses from stack outputs
3
+ *
4
+ * Platform-agnostic implementation using RuntimeAdapter.
5
+ */
6
+ import type { ToolImplementation } from "../adapters";
7
+ export interface StatusOptions {
8
+ /** Output as JSON */
9
+ json?: boolean;
10
+ /** Config name (auto-detected if only one) */
11
+ config?: string;
12
+ }
13
+ /**
14
+ * Status tool implementation
15
+ */
16
+ export declare const statusTool: ToolImplementation<StatusOptions>;
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+ /**
3
+ * Status Tool — Show agent statuses from stack outputs
4
+ *
5
+ * Platform-agnostic implementation using RuntimeAdapter.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.statusTool = void 0;
9
+ const config_1 = require("../lib/config");
10
+ const constants_1 = require("../lib/constants");
11
+ /**
12
+ * SSH options for non-interactive connections
13
+ */
14
+ const SSH_OPTS = [
15
+ "-o", "StrictHostKeyChecking=no",
16
+ "-o", "UserKnownHostsFile=/dev/null",
17
+ "-o", "BatchMode=yes",
18
+ ];
19
+ /**
20
+ * Fetch Claude Code version via SSH (best effort, returns "—" on failure)
21
+ */
22
+ function getClaudeCodeVersion(exec, host, timeout = 5) {
23
+ const result = exec.capture("ssh", [
24
+ "-o", `ConnectTimeout=${timeout}`,
25
+ ...SSH_OPTS,
26
+ `${constants_1.SSH_USER}@${host}`,
27
+ `"/home/${constants_1.SSH_USER}/.local/bin/claude --version 2>/dev/null || echo ''"`,
28
+ ]);
29
+ if (result.exitCode === 0 && result.stdout?.trim()) {
30
+ return result.stdout.trim();
31
+ }
32
+ return "—";
33
+ }
34
+ /**
35
+ * Fetch GitHub CLI version via SSH (best effort, returns "—" on failure)
36
+ */
37
+ function getGhVersion(exec, host, timeout = 5) {
38
+ const result = exec.capture("ssh", [
39
+ "-o", `ConnectTimeout=${timeout}`,
40
+ ...SSH_OPTS,
41
+ `${constants_1.SSH_USER}@${host}`,
42
+ `"gh --version 2>/dev/null | head -n1 | awk '{print \\$3}' || echo ''"`,
43
+ ]);
44
+ if (result.exitCode === 0 && result.stdout?.trim()) {
45
+ return result.stdout.trim();
46
+ }
47
+ return "—";
48
+ }
49
+ /**
50
+ * Fetch GitHub CLI auth status via SSH (best effort, returns "✓" or "—")
51
+ */
52
+ function getGhAuthStatus(exec, host, timeout = 5) {
53
+ const result = exec.capture("ssh", [
54
+ "-o", `ConnectTimeout=${timeout}`,
55
+ ...SSH_OPTS,
56
+ `${constants_1.SSH_USER}@${host}`,
57
+ `"gh auth status 2>&1 >/dev/null && echo 'OK' || echo 'no'"`,
58
+ ]);
59
+ if (result.exitCode === 0 && result.stdout?.trim() === "OK") {
60
+ return "✓";
61
+ }
62
+ return "—";
63
+ }
64
+ /**
65
+ * Get Pulumi config value
66
+ */
67
+ function getConfig(exec, key) {
68
+ const result = exec.capture("pulumi", ["config", "get", key]);
69
+ return result.exitCode === 0 ? result.stdout.trim() : null;
70
+ }
71
+ /**
72
+ * Get stack outputs
73
+ */
74
+ function getStackOutputs(exec, showSecrets = false) {
75
+ const args = ["stack", "output", "--json"];
76
+ if (showSecrets)
77
+ args.push("--show-secrets");
78
+ const result = exec.capture("pulumi", args);
79
+ if (result.exitCode !== 0)
80
+ return null;
81
+ try {
82
+ return JSON.parse(result.stdout);
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ /**
89
+ * Status tool implementation
90
+ */
91
+ const statusTool = async (runtime, options) => {
92
+ const { ui, exec } = runtime;
93
+ if (!options.json) {
94
+ ui.intro("Agent Army");
95
+ }
96
+ // Resolve config name and load manifest
97
+ let configName;
98
+ try {
99
+ configName = (0, config_1.resolveConfigName)(options.config);
100
+ }
101
+ catch (err) {
102
+ ui.log.error(err.message);
103
+ process.exit(1);
104
+ }
105
+ const manifest = (0, config_1.loadManifest)(configName);
106
+ if (!manifest) {
107
+ ui.log.error(`Config '${configName}' could not be loaded.`);
108
+ process.exit(1);
109
+ }
110
+ // Select/create stack
111
+ const selectResult = exec.capture("pulumi", ["stack", "select", manifest.stackName]);
112
+ if (selectResult.exitCode !== 0) {
113
+ const initResult = exec.capture("pulumi", ["stack", "init", manifest.stackName]);
114
+ if (initResult.exitCode !== 0) {
115
+ if (!options.json) {
116
+ ui.log.error(initResult.stderr || selectResult.stderr);
117
+ ui.log.error(`Could not select Pulumi stack "${manifest.stackName}".`);
118
+ }
119
+ process.exit(1);
120
+ }
121
+ }
122
+ // Get outputs
123
+ const outputs = getStackOutputs(exec, true);
124
+ if (!outputs) {
125
+ ui.log.error("Could not fetch stack outputs. Has the stack been deployed?");
126
+ process.exit(1);
127
+ }
128
+ // Get tailnet DNS name for SSH connections
129
+ const tailnetDnsName = getConfig(exec, "tailnetDnsName");
130
+ // Build status data with Claude Code and GitHub CLI versions (fetched via SSH)
131
+ const statusData = manifest.agents.map((agent) => {
132
+ let claudeCodeVersion = "—";
133
+ let ghVersion = "—";
134
+ let ghAuth = "—";
135
+ if (tailnetDnsName) {
136
+ const tsHost = (0, constants_1.tailscaleHostname)(manifest.stackName, agent.name);
137
+ const host = `${tsHost}.${tailnetDnsName}`;
138
+ claudeCodeVersion = getClaudeCodeVersion(exec, host);
139
+ ghVersion = getGhVersion(exec, host);
140
+ if (ghVersion !== "—") {
141
+ ghAuth = getGhAuthStatus(exec, host);
142
+ }
143
+ }
144
+ return {
145
+ name: agent.displayName,
146
+ role: agent.role,
147
+ instanceId: outputs[`${agent.role}InstanceId`] ?? "—",
148
+ publicIp: outputs[`${agent.role}PublicIp`] ?? "—",
149
+ tailscaleUrl: outputs[`${agent.role}TailscaleUrl`] ?? "—",
150
+ claudeCodeVersion,
151
+ ghVersion,
152
+ ghAuth,
153
+ };
154
+ });
155
+ // JSON output
156
+ if (options.json) {
157
+ console.log(JSON.stringify(statusData, null, 2));
158
+ return;
159
+ }
160
+ // Table output
161
+ ui.log.step(`Stack: ${manifest.stackName} | Region: ${manifest.region}`);
162
+ console.log();
163
+ // Header
164
+ const nameW = 12;
165
+ const roleW = 10;
166
+ const idW = 22;
167
+ const ipW = 16;
168
+ const claudeW = 16;
169
+ const ghW = 8;
170
+ const authW = 6;
171
+ const header = [
172
+ "Agent".padEnd(nameW),
173
+ "Role".padEnd(roleW),
174
+ "Instance ID".padEnd(idW),
175
+ "Public IP".padEnd(ipW),
176
+ "Claude Code".padEnd(claudeW),
177
+ "gh".padEnd(ghW),
178
+ "Auth".padEnd(authW),
179
+ ].join(" ");
180
+ const separator = [
181
+ "─".repeat(nameW),
182
+ "─".repeat(roleW),
183
+ "─".repeat(idW),
184
+ "─".repeat(ipW),
185
+ "─".repeat(claudeW),
186
+ "─".repeat(ghW),
187
+ "─".repeat(authW),
188
+ ].join(" ");
189
+ console.log(` ${header}`);
190
+ console.log(` ${separator}`);
191
+ for (const s of statusData) {
192
+ const row = [
193
+ s.name.padEnd(nameW),
194
+ s.role.padEnd(roleW),
195
+ s.instanceId.padEnd(idW),
196
+ s.publicIp.padEnd(ipW),
197
+ s.claudeCodeVersion.padEnd(claudeW),
198
+ s.ghVersion.padEnd(ghW),
199
+ s.ghAuth.padEnd(authW),
200
+ ].join(" ");
201
+ console.log(` ${row}`);
202
+ }
203
+ console.log();
204
+ // Show Tailscale URLs
205
+ const urlLines = statusData
206
+ .filter((s) => s.tailscaleUrl !== "—")
207
+ .map((s) => ` ${s.name}: ${s.tailscaleUrl}`);
208
+ if (urlLines.length > 0) {
209
+ ui.note(urlLines.join("\n"), "Tailscale URLs");
210
+ }
211
+ };
212
+ exports.statusTool = statusTool;
213
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../tools/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Validate Tool — Health check agents via Tailscale SSH
3
+ *
4
+ * Platform-agnostic implementation using RuntimeAdapter.
5
+ */
6
+ import type { ToolImplementation } from "../adapters";
7
+ export interface ValidateOptions {
8
+ /** SSH timeout in seconds */
9
+ timeout?: string;
10
+ /** Config name (auto-detected if only one) */
11
+ config?: string;
12
+ }
13
+ /**
14
+ * Validate tool implementation
15
+ */
16
+ export declare const validateTool: ToolImplementation<ValidateOptions>;