@cardelli/ambit 0.1.4 → 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.
Files changed (141) hide show
  1. package/esm/cli/commands/create/index.d.ts +2 -0
  2. package/esm/cli/commands/create/index.d.ts.map +1 -0
  3. package/esm/cli/commands/create/index.js +292 -0
  4. package/esm/cli/commands/create/machine.d.ts +33 -0
  5. package/esm/cli/commands/create/machine.d.ts.map +1 -0
  6. package/esm/cli/commands/create/machine.js +162 -0
  7. package/esm/cli/commands/deploy/index.d.ts +2 -0
  8. package/esm/cli/commands/deploy/index.d.ts.map +1 -0
  9. package/esm/cli/commands/deploy/index.js +290 -0
  10. package/esm/cli/commands/deploy/machine.d.ts +52 -0
  11. package/esm/cli/commands/deploy/machine.d.ts.map +1 -0
  12. package/esm/cli/commands/deploy/machine.js +116 -0
  13. package/esm/cli/commands/deploy/modes.d.ts +18 -0
  14. package/esm/cli/commands/deploy/modes.d.ts.map +1 -0
  15. package/esm/cli/commands/deploy/modes.js +152 -0
  16. package/esm/cli/commands/destroy/app.d.ts +2 -0
  17. package/esm/cli/commands/destroy/app.d.ts.map +1 -0
  18. package/esm/cli/commands/destroy/app.js +173 -0
  19. package/esm/cli/commands/destroy/index.d.ts +2 -0
  20. package/esm/cli/commands/destroy/index.d.ts.map +1 -0
  21. package/esm/cli/commands/destroy/index.js +63 -0
  22. package/esm/cli/commands/destroy/network.d.ts +2 -0
  23. package/esm/cli/commands/destroy/network.d.ts.map +1 -0
  24. package/esm/cli/commands/destroy/network.js +210 -0
  25. package/esm/cli/commands/doctor.d.ts.map +1 -0
  26. package/esm/cli/commands/doctor.js +295 -0
  27. package/esm/{src/cli → cli}/commands/list.d.ts.map +1 -1
  28. package/esm/{src/cli → cli}/commands/list.js +39 -54
  29. package/esm/cli/commands/status.d.ts.map +1 -0
  30. package/esm/cli/commands/status.js +331 -0
  31. package/esm/cli/mod.d.ts.map +1 -0
  32. package/esm/{src/cli → cli}/mod.js +4 -4
  33. package/esm/deno.d.ts +4 -18
  34. package/esm/deno.js +5 -19
  35. package/esm/deps/jsr.io/@std/path/1.1.4/constants.d.ts +1 -1
  36. package/esm/deps/jsr.io/@zod/zod/4.3.6/src/v4/core/json-schema-generator.d.ts +1 -1
  37. package/esm/lib/args.d.ts +11 -0
  38. package/esm/lib/args.d.ts.map +1 -0
  39. package/esm/lib/args.js +28 -0
  40. package/esm/lib/cli.d.ts +0 -2
  41. package/esm/lib/cli.d.ts.map +1 -1
  42. package/esm/lib/cli.js +41 -27
  43. package/esm/lib/command.d.ts +21 -49
  44. package/esm/lib/command.d.ts.map +1 -1
  45. package/esm/lib/command.js +55 -95
  46. package/esm/lib/machine.d.ts +11 -0
  47. package/esm/lib/machine.d.ts.map +1 -0
  48. package/esm/lib/machine.js +15 -0
  49. package/esm/lib/output.d.ts +3 -2
  50. package/esm/lib/output.d.ts.map +1 -1
  51. package/esm/lib/output.js +25 -11
  52. package/esm/lib/result.d.ts +18 -7
  53. package/esm/lib/result.d.ts.map +1 -1
  54. package/esm/lib/result.js +46 -1
  55. package/esm/main.d.ts +6 -6
  56. package/esm/main.d.ts.map +1 -1
  57. package/esm/main.js +7 -9
  58. package/esm/providers/fly.d.ts +81 -0
  59. package/esm/providers/fly.d.ts.map +1 -0
  60. package/esm/providers/fly.js +372 -0
  61. package/esm/providers/tailscale.d.ts +31 -0
  62. package/esm/providers/tailscale.d.ts.map +1 -0
  63. package/esm/providers/tailscale.js +150 -0
  64. package/esm/{src/schemas → schemas}/fly.d.ts +1 -11
  65. package/esm/schemas/fly.d.ts.map +1 -0
  66. package/esm/{src/schemas → schemas}/fly.js +14 -56
  67. package/esm/{src/schemas → schemas}/tailscale.d.ts +1 -2
  68. package/esm/schemas/tailscale.d.ts.map +1 -0
  69. package/esm/{src/schemas → schemas}/tailscale.js +2 -3
  70. package/esm/src/{docker/router → router}/Dockerfile +0 -11
  71. package/esm/src/router/start.sh +101 -0
  72. package/esm/util/constants.d.ts +13 -0
  73. package/esm/util/constants.d.ts.map +1 -0
  74. package/esm/util/constants.js +34 -0
  75. package/esm/{src → util}/credentials.d.ts +0 -1
  76. package/esm/util/credentials.d.ts.map +1 -0
  77. package/esm/{src → util}/credentials.js +3 -5
  78. package/esm/{src → util}/discovery.d.ts +20 -4
  79. package/esm/util/discovery.d.ts.map +1 -0
  80. package/esm/{src → util}/discovery.js +38 -15
  81. package/esm/util/fly-transforms.d.ts +27 -0
  82. package/esm/util/fly-transforms.d.ts.map +1 -0
  83. package/esm/util/fly-transforms.js +87 -0
  84. package/esm/{src → util}/guard.d.ts +1 -2
  85. package/esm/util/guard.d.ts.map +1 -0
  86. package/esm/{src → util}/guard.js +27 -27
  87. package/esm/util/naming.d.ts +5 -0
  88. package/esm/util/naming.d.ts.map +1 -0
  89. package/esm/util/naming.js +12 -0
  90. package/esm/{src → util}/resolve.d.ts +2 -3
  91. package/esm/util/resolve.d.ts.map +1 -0
  92. package/esm/{src → util}/resolve.js +1 -2
  93. package/esm/util/session.d.ts +16 -0
  94. package/esm/util/session.d.ts.map +1 -0
  95. package/esm/util/session.js +19 -0
  96. package/esm/util/tailscale-local.d.ts +13 -0
  97. package/esm/util/tailscale-local.d.ts.map +1 -0
  98. package/esm/util/tailscale-local.js +63 -0
  99. package/esm/{src → util}/template.d.ts +2 -4
  100. package/esm/util/template.d.ts.map +1 -0
  101. package/esm/{src → util}/template.js +14 -17
  102. package/package.json +1 -43
  103. package/esm/lib/paths.d.ts +0 -3
  104. package/esm/lib/paths.d.ts.map +0 -1
  105. package/esm/lib/paths.js +0 -5
  106. package/esm/src/cli/commands/create.d.ts +0 -2
  107. package/esm/src/cli/commands/create.d.ts.map +0 -1
  108. package/esm/src/cli/commands/create.js +0 -294
  109. package/esm/src/cli/commands/deploy.d.ts +0 -2
  110. package/esm/src/cli/commands/deploy.d.ts.map +0 -1
  111. package/esm/src/cli/commands/deploy.js +0 -426
  112. package/esm/src/cli/commands/destroy.d.ts +0 -2
  113. package/esm/src/cli/commands/destroy.d.ts.map +0 -1
  114. package/esm/src/cli/commands/destroy.js +0 -340
  115. package/esm/src/cli/commands/doctor.d.ts.map +0 -1
  116. package/esm/src/cli/commands/doctor.js +0 -141
  117. package/esm/src/cli/commands/status.d.ts.map +0 -1
  118. package/esm/src/cli/commands/status.js +0 -152
  119. package/esm/src/cli/mod.d.ts.map +0 -1
  120. package/esm/src/credentials.d.ts.map +0 -1
  121. package/esm/src/discovery.d.ts.map +0 -1
  122. package/esm/src/docker/router/start.sh +0 -146
  123. package/esm/src/guard.d.ts.map +0 -1
  124. package/esm/src/providers/fly.d.ts +0 -70
  125. package/esm/src/providers/fly.d.ts.map +0 -1
  126. package/esm/src/providers/fly.js +0 -411
  127. package/esm/src/providers/tailscale.d.ts +0 -31
  128. package/esm/src/providers/tailscale.d.ts.map +0 -1
  129. package/esm/src/providers/tailscale.js +0 -195
  130. package/esm/src/resolve.d.ts.map +0 -1
  131. package/esm/src/schemas/config.d.ts +0 -5
  132. package/esm/src/schemas/config.d.ts.map +0 -1
  133. package/esm/src/schemas/config.js +0 -22
  134. package/esm/src/schemas/fly.d.ts.map +0 -1
  135. package/esm/src/schemas/tailscale.d.ts.map +0 -1
  136. package/esm/src/template.d.ts.map +0 -1
  137. /package/esm/{src/cli → cli}/commands/doctor.d.ts +0 -0
  138. /package/esm/{src/cli → cli}/commands/list.d.ts +0 -0
  139. /package/esm/{src/cli → cli}/commands/status.d.ts +0 -0
  140. /package/esm/{src/cli → cli}/mod.d.ts +0 -0
  141. /package/esm/src/{docker/router → router}/fly.toml +0 -0
@@ -0,0 +1,295 @@
1
+ // =============================================================================
2
+ // Doctor Command - Verify Environment and Infrastructure Health
3
+ // =============================================================================
4
+ import { parseArgs } from "../../deps/jsr.io/@std/cli/1.0.28/mod.js";
5
+ import { bold } from "../../lib/cli.js";
6
+ import { checkArgs } from "../../lib/args.js";
7
+ import { createOutput } from "../../lib/output.js";
8
+ import { runCommand } from "../../lib/command.js";
9
+ import { registerCommand } from "../mod.js";
10
+ import { isAcceptRoutesEnabled, isTailscaleInstalled, } from "../../util/tailscale-local.js";
11
+ import { findRouterApp, findWorkloadApp, getRouterMachineInfo, getRouterTailscaleInfo, listRouterApps, } from "../../util/discovery.js";
12
+ import { initSession } from "../../util/session.js";
13
+ // =============================================================================
14
+ // Reporter
15
+ // =============================================================================
16
+ const makeReporter = (results, out) => (name, ok, hint) => {
17
+ results.push({ name, ok, hint });
18
+ if (ok) {
19
+ out.ok(name);
20
+ }
21
+ else {
22
+ out.err(name);
23
+ if (hint)
24
+ out.dim(` ${hint}`);
25
+ }
26
+ };
27
+ // =============================================================================
28
+ // Stage 1: Local Checks
29
+ // =============================================================================
30
+ const stageLocalChecks = async (report) => {
31
+ report("Tailscale Installed", await isTailscaleInstalled(), "Install from https://tailscale.com/download");
32
+ const tsStatus = await runCommand(["tailscale", "status", "--json"]);
33
+ let tsConnected = false;
34
+ if (tsStatus.ok) {
35
+ try {
36
+ const parsed = JSON.parse(tsStatus.stdout);
37
+ tsConnected = parsed.BackendState === "Running";
38
+ }
39
+ catch { /* ignore */ }
40
+ }
41
+ report("Tailscale Connected", tsConnected, "Run: tailscale up");
42
+ report("Accept Routes Enabled", await isAcceptRoutesEnabled(), "Run: sudo tailscale set --accept-routes");
43
+ };
44
+ // =============================================================================
45
+ // Router Health Helper (shared by network and app stages)
46
+ // =============================================================================
47
+ const checkRouter = async (fly, tailscale, report, app) => {
48
+ const { network } = app;
49
+ report(`Router Exists (${network})`, true);
50
+ const machine = await getRouterMachineInfo(fly, app.appName);
51
+ report(`Router Running (${network})`, machine?.state === "started", machine ? `Machine State: ${machine.state}` : "No Machine Found");
52
+ const ts = await getRouterTailscaleInfo(tailscale, app.appName);
53
+ report(`Router in Tailnet (${network})`, ts !== null, "Router May Still Be Starting, or Check Router Logs");
54
+ if (ts) {
55
+ const device = await tailscale.devices.getByHostname(app.appName);
56
+ if (device) {
57
+ const routes = await tailscale.routes.get(device.id);
58
+ if (routes && routes.unapproved.length > 0) {
59
+ await tailscale.routes.approve(device.id, routes.advertised);
60
+ report(`Routes Approved (${network})`, true, `Approved: ${routes.unapproved.join(", ")}`);
61
+ }
62
+ else if (routes && routes.advertised.length > 0) {
63
+ report(`Routes Approved (${network})`, true);
64
+ }
65
+ else {
66
+ report(`Routes Approved (${network})`, false, "No Routes Advertised — Router May Need Restart");
67
+ }
68
+ }
69
+ }
70
+ };
71
+ // =============================================================================
72
+ // Stage 3a: Network Checks
73
+ // =============================================================================
74
+ const stageNetworkChecks = async (fly, tailscale, org, report, network) => {
75
+ if (network) {
76
+ const app = await findRouterApp(fly, org, network);
77
+ if (!app) {
78
+ report(`Router Exists (${network})`, false, `Create with: ambit create ${network}`);
79
+ }
80
+ else {
81
+ await checkRouter(fly, tailscale, report, app);
82
+ }
83
+ }
84
+ else {
85
+ const routerApps = await listRouterApps(fly, org);
86
+ if (routerApps.length === 0) {
87
+ report("Routers Discovered", false, "Run: ambit create <network>");
88
+ }
89
+ else {
90
+ for (const app of routerApps) {
91
+ await checkRouter(fly, tailscale, report, app);
92
+ }
93
+ }
94
+ }
95
+ };
96
+ // =============================================================================
97
+ // Stage 3b: App Checks
98
+ // =============================================================================
99
+ const stageAppChecks = async (fly, tailscale, org, report, app, network) => {
100
+ const workload = await findWorkloadApp(fly, org, app, network);
101
+ if (!workload) {
102
+ report(`App Exists (${app}.${network})`, false, `Deploy with: ambit deploy ${app}.${network}`);
103
+ return;
104
+ }
105
+ report(`App Exists (${app}.${network})`, true);
106
+ const machines = await fly.machines.list(workload.appName);
107
+ const started = machines.find((m) => m.state === "started");
108
+ report(`App Running (${app}.${network})`, started !== undefined, machines.length > 0
109
+ ? `Machine State: ${machines[0].state}`
110
+ : "No Machines Found");
111
+ const router = await findRouterApp(fly, org, network);
112
+ if (!router) {
113
+ report(`Router Exists (${network})`, false, `Create with: ambit create ${network}`);
114
+ }
115
+ else {
116
+ await checkRouter(fly, tailscale, report, router);
117
+ }
118
+ };
119
+ // =============================================================================
120
+ // Stage 4: Summary
121
+ // =============================================================================
122
+ const stageSummary = (out, results) => {
123
+ const issues = results.filter((r) => !r.ok).length;
124
+ if (issues === 0) {
125
+ out.done({ checks: results });
126
+ }
127
+ else {
128
+ out.fail(`${issues} Issue${issues > 1 ? "s" : ""} Found`, {
129
+ checks: results,
130
+ });
131
+ }
132
+ out.blank();
133
+ out.text(issues === 0 ? "All Checks Passed." : `${issues} Issue${issues > 1 ? "s" : ""} Found.`);
134
+ out.blank();
135
+ out.print();
136
+ };
137
+ // =============================================================================
138
+ // Doctor Network
139
+ // =============================================================================
140
+ const doctorNetwork = async (argv) => {
141
+ const opts = { string: ["network", "org"], boolean: ["help", "json"] };
142
+ const args = parseArgs(argv, opts);
143
+ checkArgs(args, opts, "ambit doctor network");
144
+ if (args.help) {
145
+ console.log(`
146
+ ${bold("ambit doctor network")} - Check Router Health
147
+
148
+ ${bold("USAGE")}
149
+ ambit doctor network [<name>] [--org <org>] [--json]
150
+ ambit doctor [--network <name>] [--org <org>] [--json]
151
+
152
+ ${bold("OPTIONS")}
153
+ <name> Router network to check (checks all if omitted)
154
+ --network <name> Alias for positional <name>
155
+ --org <org> Fly.io organization slug
156
+ --json Output as JSON
157
+
158
+ ${bold("CHECKS")}
159
+ - Tailscale CLI installed and connected
160
+ - Accept-routes enabled
161
+ - Router created and running
162
+ - Router visible in tailnet
163
+ - Subnet routes approved
164
+ `);
165
+ return;
166
+ }
167
+ const out = createOutput(args.json);
168
+ out.blank().header("ambit Doctor: Network").blank();
169
+ const results = [];
170
+ const report = makeReporter(results, out);
171
+ const network = (typeof args._[0] === "string" ? args._[0] : undefined) || args.network;
172
+ const { fly, tailscale, org } = await initSession(out, {
173
+ json: args.json,
174
+ org: args.org,
175
+ });
176
+ await stageLocalChecks(report);
177
+ await stageNetworkChecks(fly, tailscale, org, report, network);
178
+ stageSummary(out, results);
179
+ };
180
+ // =============================================================================
181
+ // Doctor App
182
+ // =============================================================================
183
+ const doctorApp = async (argv) => {
184
+ const opts = { string: ["network", "org"], boolean: ["help", "json"] };
185
+ const args = parseArgs(argv, opts);
186
+ checkArgs(args, opts, "ambit doctor app");
187
+ if (args.help) {
188
+ console.log(`
189
+ ${bold("ambit doctor app")} - Check App Health
190
+
191
+ ${bold("USAGE")}
192
+ ambit doctor app <app>.<network> [--org <org>] [--json]
193
+ ambit doctor app <app> --network <name> [--org <org>] [--json]
194
+
195
+ ${bold("OPTIONS")}
196
+ --network <name> Target network (if not using dot syntax)
197
+ --org <org> Fly.io organization slug
198
+ --json Output as JSON
199
+
200
+ ${bold("CHECKS")}
201
+ - Tailscale CLI installed and connected
202
+ - Accept-routes enabled
203
+ - App deployed and running
204
+ - Router exists and is healthy
205
+ - Subnet routes approved
206
+ `);
207
+ return;
208
+ }
209
+ const out = createOutput(args.json);
210
+ const appArg = args._[0];
211
+ if (!appArg || typeof appArg !== "string") {
212
+ return out.die("Missing App Name. Usage: ambit doctor app <app>.<network>");
213
+ }
214
+ let app;
215
+ let network;
216
+ if (appArg.includes(".")) {
217
+ const parts = appArg.split(".");
218
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
219
+ return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
220
+ }
221
+ app = parts[0];
222
+ network = parts[1];
223
+ }
224
+ else {
225
+ app = appArg;
226
+ if (!args.network) {
227
+ return out.die(`Missing Network. Use: ambit doctor app ${app}.<network>`);
228
+ }
229
+ network = args.network;
230
+ }
231
+ out.blank().header(`ambit Doctor: App ${app}.${network}`).blank();
232
+ const results = [];
233
+ const report = makeReporter(results, out);
234
+ const { fly, tailscale, org } = await initSession(out, {
235
+ json: args.json,
236
+ org: args.org,
237
+ });
238
+ await stageLocalChecks(report);
239
+ await stageAppChecks(fly, tailscale, org, report, app, network);
240
+ stageSummary(out, results);
241
+ };
242
+ // =============================================================================
243
+ // Top-Level Help
244
+ // =============================================================================
245
+ const showDoctorHelp = () => {
246
+ console.log(`
247
+ ${bold("ambit doctor")} - Verify Environment and Infrastructure Health
248
+
249
+ ${bold("USAGE")}
250
+ ambit doctor [options]
251
+ ambit doctor network [<name>] [options]
252
+ ambit doctor app <app>.<network> [options]
253
+
254
+ ${bold("SUBCOMMANDS")}
255
+ network Check router(s) health — default when no subcommand given
256
+ app Check a specific app's health
257
+
258
+ ${bold("OPTIONS")}
259
+ --org <org> Fly.io organization slug
260
+ --json Output as JSON
261
+
262
+ ${bold("EXAMPLES")}
263
+ ambit doctor
264
+ ambit doctor network
265
+ ambit doctor network browsers
266
+ ambit doctor app my-app.browsers
267
+
268
+ Run 'ambit doctor network --help' or 'ambit doctor app --help' for details.
269
+ `);
270
+ };
271
+ // =============================================================================
272
+ // Dispatcher
273
+ // =============================================================================
274
+ const doctor = async (argv) => {
275
+ const subcommand = typeof argv[0] === "string" ? argv[0] : undefined;
276
+ if (subcommand === "network")
277
+ return doctorNetwork(argv.slice(1));
278
+ if (subcommand === "app")
279
+ return doctorApp(argv.slice(1));
280
+ const args = parseArgs(argv, { boolean: ["help"] });
281
+ if (args.help) {
282
+ showDoctorHelp();
283
+ return;
284
+ }
285
+ return doctorNetwork(argv);
286
+ };
287
+ // =============================================================================
288
+ // Register Command
289
+ // =============================================================================
290
+ registerCommand({
291
+ name: "doctor",
292
+ description: "Check that Tailscale and the router are working correctly",
293
+ usage: "ambit doctor [network|app] [<name>] [--org <org>] [--json]",
294
+ run: doctor,
295
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/commands/list.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":""}
@@ -1,53 +1,19 @@
1
1
  // =============================================================================
2
2
  // List Command - List All Discovered Routers
3
3
  // =============================================================================
4
- import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
5
- import { Table } from "../../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
6
- import { bold } from "../../../lib/cli.js";
7
- import { createOutput } from "../../../lib/output.js";
4
+ import { parseArgs } from "../../deps/jsr.io/@std/cli/1.0.28/mod.js";
5
+ import { Table } from "../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
6
+ import { bold } from "../../lib/cli.js";
7
+ import { checkArgs } from "../../lib/args.js";
8
+ import { createOutput } from "../../lib/output.js";
8
9
  import { registerCommand } from "../mod.js";
9
- import { createFlyProvider } from "../../providers/fly.js";
10
- import { createTailscaleProvider } from "../../providers/tailscale.js";
11
- import { checkDependencies } from "../../credentials.js";
12
- import { getRouterMachineInfo, getRouterTailscaleInfo, listRouterApps, } from "../../discovery.js";
13
- import { resolveOrg } from "../../resolve.js";
10
+ import { discoverRouters, } from "../../util/discovery.js";
11
+ import { initSession } from "../../util/session.js";
14
12
  // =============================================================================
15
- // List Command
13
+ // Stage: Render
16
14
  // =============================================================================
17
- const list = async (argv) => {
18
- const args = parseArgs(argv, {
19
- string: ["org"],
20
- boolean: ["help", "json"],
21
- });
22
- if (args.help) {
23
- console.log(`
24
- ${bold("ambit list")} - List All Discovered Routers
25
-
26
- ${bold("USAGE")}
27
- ambit list [--org <org>] [--json]
28
-
29
- ${bold("OPTIONS")}
30
- --org <org> Fly.io organization slug
31
- --json Output as JSON
32
- `);
33
- return;
34
- }
35
- const out = createOutput(args.json);
36
- // =========================================================================
37
- // Prerequisites
38
- // =========================================================================
39
- const { tailscaleKey } = await checkDependencies(out);
40
- const fly = createFlyProvider();
41
- await fly.ensureAuth({ interactive: !args.json });
42
- const tailscale = createTailscaleProvider("-", tailscaleKey);
43
- const org = await resolveOrg(fly, args, out);
44
- // =========================================================================
45
- // Discover Routers
46
- // =========================================================================
47
- const spinner = out.spinner("Discovering Routers");
48
- const routerApps = await listRouterApps(fly, org);
49
- spinner.success(`Found ${routerApps.length} Router${routerApps.length !== 1 ? "s" : ""}`);
50
- if (routerApps.length === 0) {
15
+ const stageRender = (out, routers) => {
16
+ if (routers.length === 0) {
51
17
  out.blank()
52
18
  .text("No Routers Found.")
53
19
  .dim(" Create one with: ambit create <network>")
@@ -56,19 +22,10 @@ ${bold("OPTIONS")}
56
22
  out.print();
57
23
  return;
58
24
  }
59
- const routers = [];
60
- for (const app of routerApps) {
61
- const machine = await getRouterMachineInfo(fly, app.appName);
62
- const ts = await getRouterTailscaleInfo(tailscale, app.appName);
63
- routers.push({ ...app, machine, tailscale: ts });
64
- }
65
- // =========================================================================
66
- // Render
67
- // =========================================================================
68
25
  out.blank().header("Routers").blank();
69
26
  const rows = routers.map((r) => {
70
27
  const tsStatus = r.tailscale
71
- ? r.tailscale.online ? "online" : "offline"
28
+ ? (r.tailscale.online ? "online" : "offline")
72
29
  : "not found";
73
30
  const tag = r.tailscale?.tags?.[0] ?? "unknown";
74
31
  return [
@@ -91,6 +48,34 @@ ${bold("OPTIONS")}
91
48
  out.print();
92
49
  };
93
50
  // =============================================================================
51
+ // List Command
52
+ // =============================================================================
53
+ const list = async (argv) => {
54
+ const opts = { string: ["org"], boolean: ["help", "json"] };
55
+ const args = parseArgs(argv, opts);
56
+ checkArgs(args, opts, "ambit list");
57
+ if (args.help) {
58
+ console.log(`
59
+ ${bold("ambit list")} - List All Discovered Routers
60
+
61
+ ${bold("USAGE")}
62
+ ambit list [--org <org>] [--json]
63
+
64
+ ${bold("OPTIONS")}
65
+ --org <org> Fly.io organization slug
66
+ --json Output as JSON
67
+ `);
68
+ return;
69
+ }
70
+ const out = createOutput(args.json);
71
+ const { fly, tailscale, org } = await initSession(out, {
72
+ json: args.json,
73
+ org: args.org,
74
+ });
75
+ const routers = await discoverRouters(out, fly, tailscale, org);
76
+ stageRender(out, routers);
77
+ };
78
+ // =============================================================================
94
79
  // Register Command
95
80
  // =============================================================================
96
81
  registerCommand({
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":""}