@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
@@ -1,340 +0,0 @@
1
- // =============================================================================
2
- // Destroy Command - Destroy Networks or Apps
3
- // =============================================================================
4
- import * as dntShim from "../../../_dnt.shims.js";
5
- import { parseArgs } from "../../../deps/jsr.io/@std/cli/1.0.28/mod.js";
6
- import { bold, confirm } from "../../../lib/cli.js";
7
- import { createOutput } from "../../../lib/output.js";
8
- 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 { findRouterApp, findWorkloadApp, listWorkloadAppsOnNetwork, } from "../../discovery.js";
13
- import { resolveOrg } from "../../resolve.js";
14
- import { assertNotRouter } from "../../guard.js";
15
- // =============================================================================
16
- // Top-Level Help
17
- // =============================================================================
18
- const showDestroyHelp = () => {
19
- console.log(`
20
- ${bold("ambit destroy")} - Destroy Networks or Apps
21
-
22
- ${bold("USAGE")}
23
- ambit destroy network <name> [options]
24
- ambit destroy app <app>.<network> [options]
25
-
26
- ${bold("SUBCOMMANDS")}
27
- network Tear down a router, clean up DNS and tailnet device
28
- app Destroy a workload app on a network
29
-
30
- ${bold("OPTIONS")}
31
- --help Show help for a subcommand
32
-
33
- ${bold("EXAMPLES")}
34
- ambit destroy network browsers
35
- ambit destroy app my-app.browsers
36
- ambit destroy app my-app --network browsers
37
-
38
- Run 'ambit destroy network --help' or 'ambit destroy app --help' for details.
39
- `);
40
- };
41
- // =============================================================================
42
- // Destroy Network
43
- // =============================================================================
44
- const destroyNetwork = async (argv) => {
45
- const args = parseArgs(argv, {
46
- string: ["network", "org"],
47
- boolean: ["help", "yes", "json"],
48
- alias: { y: "yes" },
49
- });
50
- if (args.help) {
51
- console.log(`
52
- ${bold("ambit destroy network")} - Tear Down Router
53
-
54
- ${bold("USAGE")}
55
- ambit destroy network <name> [--org <org>] [--yes] [--json]
56
-
57
- ${bold("OPTIONS")}
58
- --org <org> Fly.io organization slug
59
- -y, --yes Skip confirmation prompts
60
- --json Output as JSON
61
-
62
- ${bold("EXAMPLES")}
63
- ambit destroy network browsers
64
- ambit destroy network browsers --org my-org --yes
65
- `);
66
- return;
67
- }
68
- const out = createOutput(args.json);
69
- // Accept network as positional or --network flag (backward compat)
70
- const network = (typeof args._[0] === "string" ? args._[0] : undefined) || args.network;
71
- if (!network) {
72
- return out.die("Network name required. Usage: ambit destroy network <name>");
73
- }
74
- // ===========================================================================
75
- // Prerequisites
76
- // ===========================================================================
77
- const { tailscaleKey } = await checkDependencies(out);
78
- const fly = createFlyProvider();
79
- await fly.ensureAuth({ interactive: !args.json });
80
- const tailscale = createTailscaleProvider("-", tailscaleKey);
81
- const org = await resolveOrg(fly, args, out);
82
- // ===========================================================================
83
- // Discover Router
84
- // ===========================================================================
85
- const spinner = out.spinner("Discovering Router");
86
- const app = await findRouterApp(fly, org, network);
87
- if (!app) {
88
- spinner.fail("Router Not Found");
89
- return out.die(`No Router Found for Network '${network}'`);
90
- }
91
- spinner.success(`Found Router: ${app.appName}`);
92
- let tsDevice = null;
93
- try {
94
- tsDevice = await tailscale.getDeviceByHostname(app.appName);
95
- }
96
- catch {
97
- /* device may not exist */
98
- }
99
- const tag = tsDevice?.tags?.[0] ?? null;
100
- // ===========================================================================
101
- // Check for Workload Apps on This Network
102
- // ===========================================================================
103
- const workloadApps = await listWorkloadAppsOnNetwork(fly, org, network);
104
- // ===========================================================================
105
- // Confirm
106
- // ===========================================================================
107
- out.blank()
108
- .header("ambit Destroy Network")
109
- .blank()
110
- .text(` Network: ${network}`)
111
- .text(` Router App: ${app.appName}`)
112
- .text(` Tag: ${tag ?? "unknown"}`)
113
- .blank();
114
- if (workloadApps.length > 0) {
115
- out.warn(`${workloadApps.length} workload app(s) still on network '${network}':`);
116
- for (const wa of workloadApps) {
117
- out.text(` - ${wa.appName}`);
118
- }
119
- out.blank();
120
- out.dim("These apps will lose connectivity when the router is destroyed.");
121
- out.dim(`Consider destroying them first with: ambit destroy app <name>.${network}`);
122
- out.blank();
123
- }
124
- if (!args.yes && !args.json) {
125
- const confirmed = await confirm("Destroy this router?");
126
- if (!confirmed) {
127
- out.text("Cancelled.");
128
- return;
129
- }
130
- out.blank();
131
- }
132
- // ===========================================================================
133
- // Tear Down
134
- // ===========================================================================
135
- const dnsSpinner = out.spinner("Clearing Split DNS");
136
- try {
137
- await tailscale.clearSplitDns(network);
138
- dnsSpinner.success("Split DNS Cleared");
139
- }
140
- catch {
141
- dnsSpinner.fail("Split DNS Already Cleared");
142
- }
143
- const deviceSpinner = out.spinner("Removing Tailscale Device");
144
- try {
145
- const device = await tailscale.getDeviceByHostname(app.appName);
146
- if (device) {
147
- await tailscale.deleteDevice(device.id);
148
- deviceSpinner.success("Tailscale Device Removed");
149
- }
150
- else {
151
- deviceSpinner.success("Tailscale Device Not Found (Already Removed)");
152
- }
153
- }
154
- catch {
155
- deviceSpinner.fail("Could Not Remove Tailscale Device");
156
- }
157
- const appSpinner = out.spinner("Destroying Fly App");
158
- try {
159
- await fly.deleteApp(app.appName);
160
- appSpinner.success("Fly App Destroyed");
161
- }
162
- catch {
163
- appSpinner.fail("Could Not Destroy Fly App");
164
- }
165
- // ===========================================================================
166
- // Done
167
- // ===========================================================================
168
- out.done({
169
- destroyed: true,
170
- appName: app.appName,
171
- workloadAppsWarned: workloadApps.length,
172
- });
173
- out.ok("Router Destroyed");
174
- if (tag) {
175
- out.blank()
176
- .dim("If you added ACL policy entries for this router, remember to remove:")
177
- .dim(` tagOwners: ${tag}`)
178
- .dim(` autoApprovers: routes for ${tag}`)
179
- .dim(` acls: rules referencing ${tag}`)
180
- .blank();
181
- }
182
- else {
183
- out.blank()
184
- .dim("If you added ACL policy entries for this router, remember to remove")
185
- .dim("the associated tag from tagOwners, autoApprovers, and acls.")
186
- .blank();
187
- }
188
- out.print();
189
- };
190
- // =============================================================================
191
- // Destroy App
192
- // =============================================================================
193
- const destroyApp = async (argv) => {
194
- const args = parseArgs(argv, {
195
- string: ["network", "org"],
196
- boolean: ["help", "yes", "json"],
197
- alias: { y: "yes" },
198
- });
199
- if (args.help) {
200
- console.log(`
201
- ${bold("ambit destroy app")} - Destroy a Workload App
202
-
203
- ${bold("USAGE")}
204
- ambit destroy app <app>.<network> [--org <org>] [--yes] [--json]
205
- ambit destroy app <app> --network <name> [--org <org>] [--yes] [--json]
206
-
207
- ${bold("OPTIONS")}
208
- --network <name> Target network (if not using dot syntax)
209
- --org <org> Fly.io organization slug
210
- -y, --yes Skip confirmation prompts
211
- --json Output as JSON
212
-
213
- ${bold("EXAMPLES")}
214
- ambit destroy app my-app.browsers
215
- ambit destroy app my-app --network browsers --yes
216
- `);
217
- return;
218
- }
219
- const out = createOutput(args.json);
220
- // ===========================================================================
221
- // Parse App & Network
222
- // ===========================================================================
223
- const appArg = args._[0];
224
- if (!appArg || typeof appArg !== "string") {
225
- return out.die("Missing app name. Usage: ambit destroy app <app>.<network>");
226
- }
227
- let app;
228
- let network;
229
- if (appArg.includes(".")) {
230
- const parts = appArg.split(".");
231
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
232
- return out.die(`'${appArg}' should have exactly one dot, like my-app.my-network`);
233
- }
234
- if (args.network) {
235
- return out.die(`Network is already part of the name ('${appArg}'), --network is not needed`);
236
- }
237
- app = parts[0];
238
- network = parts[1];
239
- }
240
- else {
241
- app = appArg;
242
- if (!args.network) {
243
- return out.die(`Missing network. Use: ambit destroy app ${app}.<network>`);
244
- }
245
- network = args.network;
246
- }
247
- try {
248
- assertNotRouter(app);
249
- }
250
- catch (e) {
251
- return out.die(e instanceof Error ? e.message : String(e));
252
- }
253
- // ===========================================================================
254
- // Prerequisites
255
- // ===========================================================================
256
- const { tailscaleKey: _tailscaleKey } = await checkDependencies(out);
257
- const fly = createFlyProvider();
258
- await fly.ensureAuth({ interactive: !args.json });
259
- const org = await resolveOrg(fly, args, out);
260
- // ===========================================================================
261
- // Discover App
262
- // ===========================================================================
263
- const spinner = out.spinner("Discovering App");
264
- const workloadApp = await findWorkloadApp(fly, org, app, network);
265
- if (!workloadApp) {
266
- spinner.fail("App Not Found");
267
- // Check if app exists on a different network
268
- const anyApp = await findWorkloadApp(fly, org, app);
269
- if (anyApp) {
270
- return out.die(`App '${app}' exists on network '${anyApp.network}', not '${network}'`);
271
- }
272
- return out.die(`No app '${app}' found on network '${network}'`);
273
- }
274
- spinner.success(`Found App: ${workloadApp.appName} (network: ${workloadApp.network})`);
275
- // ===========================================================================
276
- // Confirm
277
- // ===========================================================================
278
- out.blank()
279
- .header("ambit Destroy App")
280
- .blank()
281
- .text(` App: ${workloadApp.appName}`)
282
- .text(` Network: ${workloadApp.network}`)
283
- .blank();
284
- if (!args.yes && !args.json) {
285
- const confirmed = await confirm(`Destroy app '${app}' on network '${network}'?`);
286
- if (!confirmed) {
287
- out.text("Cancelled.");
288
- return;
289
- }
290
- out.blank();
291
- }
292
- // ===========================================================================
293
- // Destroy
294
- // ===========================================================================
295
- const appSpinner = out.spinner("Destroying Fly App");
296
- try {
297
- await fly.deleteApp(app);
298
- appSpinner.success("Fly App Destroyed");
299
- }
300
- catch {
301
- appSpinner.fail("Could Not Destroy Fly App");
302
- }
303
- // ===========================================================================
304
- // Done
305
- // ===========================================================================
306
- out.done({ destroyed: true, appName: app, network });
307
- out.ok("App Destroyed");
308
- out.blank();
309
- out.print();
310
- };
311
- // =============================================================================
312
- // Dispatcher
313
- // =============================================================================
314
- const destroy = async (argv) => {
315
- const subcommand = typeof argv[0] === "string" ? argv[0] : undefined;
316
- if (subcommand === "network") {
317
- return destroyNetwork(argv.slice(1));
318
- }
319
- if (subcommand === "app") {
320
- return destroyApp(argv.slice(1));
321
- }
322
- // Handle --help at the top level
323
- const args = parseArgs(argv, { boolean: ["help"] });
324
- if (args.help) {
325
- showDestroyHelp();
326
- return;
327
- }
328
- // No valid subcommand
329
- showDestroyHelp();
330
- dntShim.Deno.exit(1);
331
- };
332
- // =============================================================================
333
- // Register Command
334
- // =============================================================================
335
- registerCommand({
336
- name: "destroy",
337
- description: "Destroy a network (router) or a workload app",
338
- usage: "ambit destroy network|app <name> [options]",
339
- run: destroy,
340
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/commands/doctor.ts"],"names":[],"mappings":""}
@@ -1,141 +0,0 @@
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 { createOutput } from "../../../lib/output.js";
7
- import { runCommand } from "../../../lib/command.js";
8
- import { registerCommand } from "../mod.js";
9
- import { createFlyProvider } from "../../providers/fly.js";
10
- import { createTailscaleProvider, isAcceptRoutesEnabled, isTailscaleInstalled, } from "../../providers/tailscale.js";
11
- import { checkDependencies } from "../../credentials.js";
12
- import { findRouterApp, getRouterMachineInfo, getRouterTailscaleInfo, listRouterApps, } from "../../discovery.js";
13
- import { resolveOrg } from "../../resolve.js";
14
- // =============================================================================
15
- // Doctor Command
16
- // =============================================================================
17
- const doctor = async (argv) => {
18
- const args = parseArgs(argv, {
19
- string: ["network", "org"],
20
- boolean: ["help", "json"],
21
- });
22
- if (args.help) {
23
- console.log(`
24
- ${bold("ambit doctor")} - Verify Environment and Infrastructure Health
25
-
26
- ${bold("USAGE")}
27
- ambit doctor [--network <name>] [--org <org>] [--json]
28
-
29
- ${bold("OPTIONS")}
30
- --network <name> Check a specific router (otherwise checks all)
31
- --org <org> Fly.io organization slug
32
- --json Output as JSON
33
-
34
- ${bold("CHECKS")}
35
- - Tailscale CLI installed and connected
36
- - Accept-routes enabled
37
- - Router(s) created and running
38
- - Router(s) visible in tailnet
39
- `);
40
- return;
41
- }
42
- const out = createOutput(args.json);
43
- out.blank().header("ambit Doctor").blank();
44
- const results = [];
45
- const report = (name, ok, hint) => {
46
- results.push({ name, ok, hint });
47
- if (ok) {
48
- out.ok(name);
49
- }
50
- else {
51
- out.err(name);
52
- if (hint)
53
- out.dim(` ${hint}`);
54
- }
55
- };
56
- // =========================================================================
57
- // Prerequisites
58
- // =========================================================================
59
- const { tailscaleKey } = await checkDependencies(out);
60
- const fly = createFlyProvider();
61
- await fly.ensureAuth({ interactive: !args.json });
62
- const tailscale = createTailscaleProvider("-", tailscaleKey);
63
- const org = await resolveOrg(fly, args, out);
64
- // =========================================================================
65
- // Local Checks
66
- // =========================================================================
67
- report("Tailscale Installed", await isTailscaleInstalled(), "Install from https://tailscale.com/download");
68
- const tsStatus = await runCommand(["tailscale", "status", "--json"]);
69
- let tsConnected = false;
70
- if (tsStatus.success) {
71
- try {
72
- const parsed = JSON.parse(tsStatus.stdout);
73
- tsConnected = parsed.BackendState === "Running";
74
- }
75
- catch { /* ignore */ }
76
- }
77
- report("Tailscale Connected", tsConnected, "Run: tailscale up");
78
- report("Accept Routes Enabled", await isAcceptRoutesEnabled(), "Run: sudo tailscale set --accept-routes");
79
- // =========================================================================
80
- // Router Checks
81
- // =========================================================================
82
- if (args.network) {
83
- const app = await findRouterApp(fly, org, args.network);
84
- report(`Router Exists (${args.network})`, app !== null, `Create with: ambit create ${args.network}`);
85
- const machine = app ? await getRouterMachineInfo(fly, app.appName) : null;
86
- report(`Router Running (${args.network})`, machine?.state === "started", machine ? `Machine state: ${machine.state}` : "No machine found");
87
- const ts = app
88
- ? await getRouterTailscaleInfo(tailscale, app.appName)
89
- : null;
90
- report(`Router in Tailnet (${args.network})`, ts !== null, "Router may still be starting, or check router logs");
91
- }
92
- else {
93
- const routerApps = await listRouterApps(fly, org);
94
- if (routerApps.length === 0) {
95
- report("Routers Discovered", false, "Run: ambit create <network>");
96
- }
97
- else {
98
- let runningCount = 0;
99
- let inTailnetCount = 0;
100
- for (const app of routerApps) {
101
- const machine = await getRouterMachineInfo(fly, app.appName);
102
- if (machine?.state === "started")
103
- runningCount++;
104
- const ts = await getRouterTailscaleInfo(tailscale, app.appName);
105
- if (ts)
106
- inTailnetCount++;
107
- }
108
- report("Routers Discovered", runningCount > 0, `${routerApps.length} Router(s): ${runningCount} Running, ${inTailnetCount} In Tailnet`);
109
- }
110
- }
111
- // =========================================================================
112
- // Summary
113
- // =========================================================================
114
- const issues = results.filter((r) => !r.ok).length;
115
- if (issues === 0) {
116
- out.done({ checks: results });
117
- }
118
- else {
119
- out.fail(`${issues} Issue${issues > 1 ? "s" : ""} Found`, {
120
- checks: results,
121
- });
122
- }
123
- out.blank();
124
- if (issues === 0) {
125
- out.text("All Checks Passed.");
126
- }
127
- else {
128
- out.text(`${issues} Issue${issues > 1 ? "s" : ""} Found.`);
129
- }
130
- out.blank();
131
- out.print();
132
- };
133
- // =============================================================================
134
- // Register Command
135
- // =============================================================================
136
- registerCommand({
137
- name: "doctor",
138
- description: "Check that Tailscale and the router are working correctly",
139
- usage: "ambit doctor [--network <name>] [--org <org>] [--json]",
140
- run: doctor,
141
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../src/src/cli/commands/status.ts"],"names":[],"mappings":""}
@@ -1,152 +0,0 @@
1
- // =============================================================================
2
- // Status Command - Show Router Status
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";
8
- 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 { findRouterApp, getRouterMachineInfo, getRouterTailscaleInfo, listRouterApps, } from "../../discovery.js";
13
- import { resolveOrg } from "../../resolve.js";
14
- // =============================================================================
15
- // Status Command
16
- // =============================================================================
17
- const status = async (argv) => {
18
- const args = parseArgs(argv, {
19
- string: ["network", "org"],
20
- boolean: ["help", "json"],
21
- });
22
- if (args.help) {
23
- console.log(`
24
- ${bold("ambit status")} - Show Router Status
25
-
26
- ${bold("USAGE")}
27
- ambit status [--network <name>] [--org <org>] [--json]
28
-
29
- ${bold("OPTIONS")}
30
- --network <name> Show detailed status for a specific network
31
- --org <org> Fly.io organization slug
32
- --json Output as JSON
33
-
34
- ${bold("EXAMPLES")}
35
- ambit status Show summary of all routers
36
- ambit status --network browsers Show detailed status for one router
37
- `);
38
- return;
39
- }
40
- // =========================================================================
41
- // Prerequisites
42
- // =========================================================================
43
- const { tailscaleKey } = await checkDependencies(createOutput(args.json));
44
- const fly = createFlyProvider();
45
- await fly.ensureAuth({ interactive: !args.json });
46
- const tailscale = createTailscaleProvider("-", tailscaleKey);
47
- // =========================================================================
48
- // Status
49
- // =========================================================================
50
- if (args.network) {
51
- await showNetworkStatus(fly, tailscale, args);
52
- }
53
- else {
54
- await showAllStatus(fly, tailscale, args);
55
- }
56
- };
57
- // =============================================================================
58
- // Single Router Detailed View
59
- // =============================================================================
60
- const showNetworkStatus = async (fly, tailscale, args) => {
61
- const out = createOutput(args.json);
62
- const org = await resolveOrg(fly, args, out);
63
- const app = await findRouterApp(fly, org, args.network);
64
- if (!app) {
65
- return out.die(`No Router Found for Network '${args.network}'`);
66
- }
67
- const machine = await getRouterMachineInfo(fly, app.appName);
68
- const ts = await getRouterTailscaleInfo(tailscale, app.appName);
69
- const tag = ts?.tags?.[0] ?? null;
70
- out.blank()
71
- .header("ambit Status")
72
- .blank()
73
- .text(` Network: ${bold(app.network)}`)
74
- .text(` TLD: *.${app.network}`)
75
- .text(` Tag: ${tag ?? "unknown"}`)
76
- .blank()
77
- .text(` Router App: ${app.appName}`)
78
- .text(` Region: ${machine?.region ?? "unknown"}`)
79
- .text(` Machine State: ${machine?.state ?? "unknown"}`)
80
- .text(` Private IP: ${machine?.privateIp ?? "unknown"}`)
81
- .text(` SOCKS Proxy: ${machine?.privateIp ? `socks5://[${machine.privateIp}]:1080` : "unknown"}`);
82
- if (machine?.subnet) {
83
- out.text(` Subnet: ${machine.subnet}`);
84
- }
85
- out.blank();
86
- if (ts) {
87
- out.text(` Tailscale IP: ${ts.ip}`)
88
- .text(` Online: ${ts.online ? "yes" : "no"}`);
89
- }
90
- else {
91
- out.text(" Tailscale: Not Found in Tailnet");
92
- }
93
- out.blank();
94
- out.done({
95
- network: app.network,
96
- router: app,
97
- machine,
98
- tag,
99
- tailscale: ts,
100
- });
101
- out.print();
102
- };
103
- // =============================================================================
104
- // Summary Table of All Routers
105
- // =============================================================================
106
- const showAllStatus = async (fly, tailscale, args) => {
107
- const out = createOutput(args.json);
108
- const org = await resolveOrg(fly, args, out);
109
- const spinner = out.spinner("Discovering Routers");
110
- const routerApps = await listRouterApps(fly, org);
111
- spinner.success(`Found ${routerApps.length} Router${routerApps.length !== 1 ? "s" : ""}`);
112
- if (routerApps.length === 0) {
113
- out.blank()
114
- .text("No Routers Found.")
115
- .dim(" Create one with: ambit create <network>")
116
- .blank();
117
- out.done({ routers: [] });
118
- out.print();
119
- return;
120
- }
121
- const routers = [];
122
- for (const app of routerApps) {
123
- const machine = await getRouterMachineInfo(fly, app.appName);
124
- const ts = await getRouterTailscaleInfo(tailscale, app.appName);
125
- routers.push({ ...app, machine, tailscale: ts });
126
- }
127
- out.blank().header("Router Status").blank();
128
- const rows = routers.map((r) => {
129
- const tsStatus = r.tailscale
130
- ? r.tailscale.online ? "online" : "offline"
131
- : "not found";
132
- return [r.network, r.appName, r.machine?.state ?? "unknown", tsStatus];
133
- });
134
- const table = new Table()
135
- .header(["Network", "App", "State", "Tailscale"])
136
- .body(rows)
137
- .indent(2)
138
- .padding(2);
139
- out.text(table.toString());
140
- out.blank();
141
- out.done({ routers });
142
- out.print();
143
- };
144
- // =============================================================================
145
- // Register Command
146
- // =============================================================================
147
- registerCommand({
148
- name: "status",
149
- description: "Show router status, network, and tailnet info",
150
- usage: "ambit status [--network <name>] [--org <org>] [--json]",
151
- run: status,
152
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../../src/src/cli/mod.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAQD,eAAO,MAAM,eAAe,GAAI,SAAS,OAAO,KAAG,IAElD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,OAAO,GAAG,SAEnD,CAAC;AAEF,eAAO,MAAM,cAAc,QAAO,OAAO,EAExC,CAAC;AAQF,eAAO,MAAM,QAAQ,QAAO,IA6B3B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAMF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAuCzD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/src/credentials.ts"],"names":[],"mappings":"AAGA,OAAO,sBAAsB,CAAC;AAqB9B,MAAM,WAAW,eAAe;IAC9B,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAQD,eAAO,MAAM,2BAA2B,QAAO,eA0B9C,CAAC;AAMF,eAAO,MAAM,kBAAkB,QAAO,eAgBrC,CAAC;AAMF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,GAC5B,KAAK;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAAC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAA;CAAE,KAC1D,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,CAyBlC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/src/discovery.ts"],"names":[],"mappings":"AAcA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAOlE,qDAAqD;AACrD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,2CAA2C;AAC3C,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAaD,wDAAwD;AACxD,eAAO,MAAM,cAAc,GACzB,KAAK,WAAW,EAChB,KAAK,MAAM,KACV,OAAO,CAAC,SAAS,EAAE,CAcrB,CAAC;AAEF,kDAAkD;AAClD,eAAO,MAAM,aAAa,GACxB,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,KACd,OAAO,CAAC,SAAS,GAAG,IAAI,CAG1B,CAAC;AAMF,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,uEAAuE;AACvE,eAAO,MAAM,yBAAyB,GACpC,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,KACd,OAAO,CAAC,WAAW,EAAE,CAcvB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,eAAe,GAC1B,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,SAAS,MAAM,EACf,UAAU,MAAM,KACf,OAAO,CAAC,WAAW,GAAG,IAAI,CAmB5B,CAAC;AAMF,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,GAC/B,KAAK,WAAW,EAChB,SAAS,MAAM,KACd,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAclC,CAAC;AAMF,yEAAyE;AACzE,eAAO,MAAM,sBAAsB,GACjC,WAAW,iBAAiB,EAC5B,SAAS,MAAM,KACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAcpC,CAAC"}