@cardelli/ambit 0.3.4 → 0.3.5

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/README.md CHANGED
@@ -211,6 +211,61 @@ Shows detailed status for a specific app: machines, Flycast IPs, and the backing
211
211
  | `--org <org>` | Fly.io organization slug |
212
212
  | `--json` | Machine-readable JSON output |
213
213
 
214
+ ### `ambit secrets list|set|unset|deploy <app>.<network>`
215
+
216
+ Manage secrets for workload apps. Secrets are encrypted environment variables provided to the app at runtime.
217
+
218
+ #### `ambit secrets list <app>.<network>`
219
+
220
+ Lists secret names and digests (not values) for an app.
221
+
222
+ #### `ambit secrets set <app>.<network> KEY=VALUE ...`
223
+
224
+ Sets one or more secrets. Positional `KEY=VALUE` pairs and `--env` can be combined — positional args take precedence.
225
+
226
+ | Flag | Description |
227
+ | ----------------- | -------------------------------------------- |
228
+ | `--env <file>` | Load secrets from an env file |
229
+ | `--stage` | Stage secrets without deploying |
230
+ | `--org <org>` | Fly.io organization slug |
231
+ | `--json` | Machine-readable JSON output |
232
+
233
+ #### `ambit secrets unset <app>.<network> KEY ...`
234
+
235
+ Removes one or more secrets by name.
236
+
237
+ | Flag | Description |
238
+ | ----------------- | -------------------------------------------- |
239
+ | `--stage` | Stage removal without deploying |
240
+ | `--org <org>` | Fly.io organization slug |
241
+ | `--json` | Machine-readable JSON output |
242
+
243
+ #### `ambit secrets deploy <app>.<network>`
244
+
245
+ Deploys staged secrets (from `set --stage` or `unset --stage`).
246
+
247
+ | Flag | Description |
248
+ | ----------------- | -------------------------------------------- |
249
+ | `--org <org>` | Fly.io organization slug |
250
+ | `--json` | Machine-readable JSON output |
251
+
252
+ ### `ambit logs <app>.<network>`
253
+
254
+ Streams logs for a workload app. By default, logs are streamed continuously. Use `--no-tail` to fetch only buffered logs. Pipe through `less` for scrollable output:
255
+
256
+ ```bash
257
+ npx @cardelli/ambit logs my-app.lab | less +F -R # stream with scroll (Ctrl+C to scroll, F to resume)
258
+ npx @cardelli/ambit logs my-app.lab --no-tail | less -R # scroll buffered logs
259
+ ```
260
+
261
+ | Flag | Description |
262
+ | -------------------- | -------------------------------------------- |
263
+ | `-r`, `--region <r>` | Filter by region |
264
+ | `--machine <id>` | Filter by machine ID |
265
+ | `-n`, `--no-tail` | Only fetch buffered logs (no streaming) |
266
+ | `--org <org>` | Fly.io organization slug |
267
+ | `--json` | JSON output |
268
+
214
269
  ### `ambit destroy network <name>`
215
270
 
216
271
  Tears down a network: destroys the router, cleans up DNS, removes the Tailscale device, and automatically removes the router's tag from your Tailscale ACL policy (tagOwners and autoApprovers). If there are workload apps still on the network, ambit warns you before proceeding.
@@ -169,7 +169,7 @@ const stageDeploy = async (out, fly, tailscale, opts) => {
169
169
  // =============================================================================
170
170
  // Stage 4: Summary
171
171
  // =============================================================================
172
- const stageSummary = async (out, fly, tailscale, ctx, opts) => {
172
+ const stageSummary = async (out, _fly, tailscale, ctx, opts) => {
173
173
  const policy = await tailscale.acl.getPolicy();
174
174
  const hasAutoApprover = isAutoApproverConfigured(policy, opts.tag);
175
175
  out.done({
@@ -1,4 +1,4 @@
1
- import { type Output } from "../../../lib/output.js";
1
+ import type { Output } from "../../../lib/output.js";
2
2
  import { Result } from "../../../lib/result.js";
3
3
  import { type FlyProvider } from "../../../providers/fly.js";
4
4
  import type { TailscaleProvider } from "../../../providers/tailscale.js";
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/create/machine.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAQhD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAW7E,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAOrE,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,UAAU,CAAC;AAMf,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACxD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAcD,eAAO,MAAM,aAAa,GACxB,KAAK,MAAM,CAAC,YAAY,CAAC,EACzB,YAAY,WAAW,SAMxB,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,KACb,OAAO,CAAC,WAAW,CA4BrB,CAAC;AAMF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,WAAW,EAClB,KAAK,SAAS,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CA6K7B,CAAC"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/create/machine.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAQhD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAW7E,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAOrE,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,eAAe,GACf,gBAAgB,GAChB,eAAe,GACf,eAAe,GACf,UAAU,CAAC;AAMf,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACxD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAcD,eAAO,MAAM,aAAa,GACxB,KAAK,MAAM,CAAC,YAAY,CAAC,EACzB,YAAY,WAAW,SAMxB,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,KACb,OAAO,CAAC,WAAW,CA4BrB,CAAC;AAMF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,WAAW,EAClB,KAAK,SAAS,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CA+K7B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type Output } from "../../../lib/output.js";
1
+ import type { Output } from "../../../lib/output.js";
2
2
  import { Result } from "../../../lib/result.js";
3
3
  import { type FlyProvider, type SafeDeployOptions } from "../../../providers/fly.js";
4
4
  import type { DeployConfig } from "./modes.js";
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/machine.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,OAAO,GACP,UAAU,CAAC;AAMf,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE;QACL,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,SAAS,EAAE;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,iBAAiB,CAAC;IACjC,KAAK,CAAC,EAAE;QACN,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAaD,eAAO,MAAM,mBAAmB,GAC9B,KAAK,MAAM,CAAC,YAAY,CAAC,EACzB,YAAY,WAAW,SAMxB,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,KACb,OAAO,CAAC,WAAW,CAMrB,CAAC;AAMF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,WAAW,EAClB,KAAK,SAAS,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CA6G7B,CAAC"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/machine.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,MAAM,MAAM,WAAW,GACnB,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,OAAO,GACP,UAAU,CAAC;AAMf,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE;QACL,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,SAAS,EAAE;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,WAAW,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,iBAAiB,CAAC;IACjC,KAAK,CAAC,EAAE;QACN,mBAAmB,EAAE,MAAM,CAAC;QAC5B,aAAa,EAAE,MAAM,CAAC;QACtB,mBAAmB,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAaD,eAAO,MAAM,mBAAmB,GAC9B,KAAK,MAAM,CAAC,YAAY,CAAC,EACzB,YAAY,WAAW,SAMxB,CAAC;AAMF,eAAO,MAAM,aAAa,GACxB,KAAK,SAAS,KACb,OAAO,CAAC,WAAW,CAMrB,CAAC;AAMF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,WAAW,EAClB,KAAK,SAAS,KACb,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CA6G7B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { createOutput } from "../../../lib/output.js";
1
+ import type { createOutput } from "../../../lib/output.js";
2
2
  /** Resolved deploy configuration — the output of mode-specific validation. */
3
3
  export interface DeployConfig {
4
4
  image?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/modes.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQtD,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoCD,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,aAAa,MAAM,EACnB,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,YAAY,GAAG,IAmBjB,CAAC;AAMF,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,GAC5B,gBAAgB,MAAM,GAAG,SAAS,EAClC,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAqC7B,CAAC;AAMF,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAyE7B,CAAC"}
1
+ {"version":3,"file":"modes.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/modes.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ3D,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoCD,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,aAAa,MAAM,EACnB,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,YAAY,GAAG,IAmBjB,CAAC;AAMF,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,GAC5B,gBAAgB,MAAM,GAAG,SAAS,EAClC,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAqC7B,CAAC;AAMF,4DAA4D;AAC5D,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,KACnC,OAAO,CAAC,YAAY,GAAG,IAAI,CAyE7B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/list/apps.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,QAAQ,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAqE3D,CAAC"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/list/apps.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,QAAQ,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAqE3D,CAAC"}
@@ -6,7 +6,7 @@ import { Table } from "../../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
6
6
  import { bold } from "../../../lib/cli.js";
7
7
  import { checkArgs } from "../../../lib/args.js";
8
8
  import { createOutput } from "../../../lib/output.js";
9
- import { findRouterApp, listWorkloadAppsOnNetwork, } from "../../../util/discovery.js";
9
+ import { findRouterApp, listWorkloadAppsOnNetwork } from "../../../util/discovery.js";
10
10
  import { initSession } from "../../../util/session.js";
11
11
  // =============================================================================
12
12
  // List Apps Command
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/logs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,142 @@
1
+ // =============================================================================
2
+ // Logs Command - Stream Logs for Workload Apps
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 { streamCommand } from "../../lib/command.js";
9
+ import { registerCommand } from "../mod.js";
10
+ import { findWorkloadApp } from "../../util/discovery.js";
11
+ import { initSession } from "../../util/session.js";
12
+ import { StreamTable } from "../../lib/table.js";
13
+ // =============================================================================
14
+ // Log Table
15
+ // =============================================================================
16
+ const logTable = new StreamTable([
17
+ { name: "Timestamp", width: 19 },
18
+ { name: "Region", width: 6 },
19
+ { name: "Level", width: 5 },
20
+ { name: "Message", width: 0 },
21
+ ]);
22
+ const formatTimestamp = (ts) => {
23
+ return ts.replace("T", " ").replace(/\.\d+Z$/, "");
24
+ };
25
+ // =============================================================================
26
+ // Logs Command
27
+ // =============================================================================
28
+ const logs = async (argv) => {
29
+ const opts = {
30
+ string: ["org", "region", "machine"],
31
+ boolean: ["help", "json", "no-tail"],
32
+ alias: { r: "region", n: "no-tail" },
33
+ };
34
+ const args = parseArgs(argv, opts);
35
+ checkArgs(args, opts, "ambit logs", 1);
36
+ if (args.help) {
37
+ console.log(`
38
+ ${bold("ambit logs")} - Stream Logs for a Workload App
39
+
40
+ ${bold("USAGE")}
41
+ ambit logs <app>.<network> [options]
42
+
43
+ ${bold("OPTIONS")}
44
+ --org <org> Fly.io organization slug
45
+ -r, --region <r> Filter by region
46
+ --machine <id> Filter by machine ID
47
+ -n, --no-tail Only fetch buffered logs (no streaming)
48
+ --json JSON output
49
+
50
+ ${bold("EXAMPLES")}
51
+ ambit logs my-app.browsers
52
+ ambit logs my-app.browsers | less +F -R
53
+ ambit logs my-app.browsers --no-tail | less -R
54
+ ambit logs my-app.browsers --region iad --json
55
+ `);
56
+ return;
57
+ }
58
+ const out = createOutput(args.json);
59
+ const appArg = args._[0];
60
+ if (!appArg || typeof appArg !== "string") {
61
+ return out.die("Missing App Name. Usage: ambit logs <app>.<network>");
62
+ }
63
+ if (!appArg.includes(".")) {
64
+ return out.die(`Missing Network. Use: ambit logs ${appArg}.<network>`);
65
+ }
66
+ const parts = appArg.split(".");
67
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
68
+ return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
69
+ }
70
+ const app = parts[0];
71
+ const network = parts[1];
72
+ const { fly, org } = await initSession(out, {
73
+ json: args.json,
74
+ org: args.org,
75
+ });
76
+ const workload = await findWorkloadApp(fly, org, app, network);
77
+ if (!workload) {
78
+ return out.die(`App '${app}' Not Found on Network '${network}'`);
79
+ }
80
+ // Always request JSON from fly so we can parse and format
81
+ const flyArgs = ["fly", "logs", "-a", workload.appName, "--json"];
82
+ if (args["no-tail"])
83
+ flyArgs.push("--no-tail");
84
+ if (args.region)
85
+ flyArgs.push("--region", args.region);
86
+ if (args.machine)
87
+ flyArgs.push("--machine", args.machine);
88
+ const stream = streamCommand(flyArgs);
89
+ out.blank();
90
+ out.text(logTable.header());
91
+ out.text(logTable.separator());
92
+ // fly logs --json emits pretty-printed multi-line JSON objects.
93
+ // Accumulate lines and parse when brace depth returns to zero.
94
+ let buf = [];
95
+ let depth = 0;
96
+ for await (const line of stream.lines) {
97
+ const trimmed = line.trim();
98
+ if (!trimmed)
99
+ continue;
100
+ for (const ch of trimmed) {
101
+ if (ch === "{")
102
+ depth++;
103
+ else if (ch === "}")
104
+ depth--;
105
+ }
106
+ buf.push(trimmed);
107
+ if (depth === 0 && buf.length > 0) {
108
+ const block = buf.join("");
109
+ buf = [];
110
+ try {
111
+ const entry = JSON.parse(block);
112
+ if (out.isJson()) {
113
+ console.log(JSON.stringify(entry));
114
+ }
115
+ else {
116
+ out.text(logTable.row([
117
+ formatTimestamp(entry.timestamp ?? ""),
118
+ entry.region ?? "",
119
+ entry.level ?? "",
120
+ entry.message ?? "",
121
+ ]));
122
+ }
123
+ }
124
+ catch {
125
+ out.dim(` ${block}`);
126
+ }
127
+ }
128
+ }
129
+ const result = await stream.done;
130
+ if (!result.ok && result.stderr) {
131
+ out.err(result.stderr.trim());
132
+ }
133
+ };
134
+ // =============================================================================
135
+ // Register Command
136
+ // =============================================================================
137
+ registerCommand({
138
+ name: "logs",
139
+ description: "Stream logs for a workload app",
140
+ usage: "ambit logs <app>.<network> [--region <r>] [--no-tail] [--json]",
141
+ run: logs,
142
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=secrets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/secrets.ts"],"names":[],"mappings":""}
@@ -0,0 +1,302 @@
1
+ // =============================================================================
2
+ // Secrets Command - Manage Secrets for Workload 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 { Table } from "../../deps/jsr.io/@cliffy/table/1.0.0/mod.js";
7
+ import { bold } from "../../lib/cli.js";
8
+ import { checkArgs } from "../../lib/args.js";
9
+ import { createOutput } from "../../lib/output.js";
10
+ import { registerCommand } from "../mod.js";
11
+ import { findWorkloadApp } from "../../util/discovery.js";
12
+ import { initSession } from "../../util/session.js";
13
+ // =============================================================================
14
+ // Shared Helpers
15
+ // =============================================================================
16
+ const resolveAppTarget = (out, appArg, command) => {
17
+ if (!appArg || typeof appArg !== "string") {
18
+ return out.die(`Missing App Name. Usage: ${command} <app>.<network>`);
19
+ }
20
+ if (!appArg.includes(".")) {
21
+ return out.die(`Missing Network. Use: ${command} ${appArg}.<network>`);
22
+ }
23
+ const parts = appArg.split(".");
24
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
25
+ return out.die(`'${appArg}' Should Have Exactly One Dot, Like my-app.my-network`);
26
+ }
27
+ return { app: parts[0], network: parts[1] };
28
+ };
29
+ const resolveFlyAppName = async (out, fly, org, app, network) => {
30
+ const workload = await findWorkloadApp(fly, org, app, network);
31
+ if (!workload) {
32
+ return out.die(`App '${app}' Not Found on Network '${network}'`);
33
+ }
34
+ return workload.appName;
35
+ };
36
+ // =============================================================================
37
+ // Secrets List
38
+ // =============================================================================
39
+ const secretsList = async (argv) => {
40
+ const opts = { string: ["org"], boolean: ["help", "json"] };
41
+ const args = parseArgs(argv, opts);
42
+ checkArgs(args, opts, "ambit secrets list", 1);
43
+ if (args.help) {
44
+ console.log(`
45
+ ${bold("ambit secrets list")} - List Secrets for an App
46
+
47
+ ${bold("USAGE")}
48
+ ambit secrets list <app>.<network> [--org <org>] [--json]
49
+
50
+ ${bold("OPTIONS")}
51
+ --org <org> Fly.io organization slug
52
+ --json Output as JSON
53
+
54
+ ${bold("EXAMPLES")}
55
+ ambit secrets list my-app.browsers
56
+ ambit secrets list my-app.browsers --json
57
+ `);
58
+ return;
59
+ }
60
+ const out = createOutput(args.json);
61
+ const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets list");
62
+ const { fly, org } = await initSession(out, {
63
+ json: args.json,
64
+ org: args.org,
65
+ });
66
+ const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
67
+ const secrets = await fly.secrets.list(flyAppName);
68
+ if (secrets.length === 0) {
69
+ out.blank()
70
+ .text(`No Secrets Found for ${app}.${network}.`)
71
+ .blank();
72
+ }
73
+ else {
74
+ out.blank().header(`Secrets for ${app}.${network}`).blank();
75
+ const table = new Table()
76
+ .header(["Name", "Digest"])
77
+ .body(secrets.map((s) => [s.name, s.digest]))
78
+ .indent(2)
79
+ .padding(2);
80
+ out.text(table.toString());
81
+ out.blank();
82
+ }
83
+ out.done({ app, network, flyAppName, secrets });
84
+ out.print();
85
+ };
86
+ // =============================================================================
87
+ // Secrets Set
88
+ // =============================================================================
89
+ const secretsSet = async (argv) => {
90
+ const opts = {
91
+ string: ["org", "env"],
92
+ boolean: ["help", "json", "stage"],
93
+ };
94
+ const args = parseArgs(argv, opts);
95
+ checkArgs(args, opts, "ambit secrets set", Infinity);
96
+ if (args.help) {
97
+ console.log(`
98
+ ${bold("ambit secrets set")} - Set Secrets for an App
99
+
100
+ ${bold("USAGE")}
101
+ ambit secrets set <app>.<network> KEY=VALUE ... [--org <org>] [--stage] [--json]
102
+ ambit secrets set <app>.<network> --env <file> [--org <org>] [--stage] [--json]
103
+
104
+ ${bold("OPTIONS")}
105
+ --env <file> Load secrets from an env file (KEY=VALUE per line)
106
+ --org <org> Fly.io organization slug
107
+ --stage Stage secrets without deploying
108
+ --json Output as JSON
109
+
110
+ ${bold("EXAMPLES")}
111
+ ambit secrets set my-app.browsers API_KEY=abc123
112
+ ambit secrets set my-app.browsers KEY1=val1 KEY2=val2 --stage
113
+ ambit secrets set my-app.browsers --env .env
114
+ `);
115
+ return;
116
+ }
117
+ const out = createOutput(args.json);
118
+ const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets set");
119
+ const secretsObj = {};
120
+ // Load from env file if provided
121
+ if (args.env) {
122
+ let content;
123
+ try {
124
+ content = await dntShim.Deno.readTextFile(args.env);
125
+ }
126
+ catch {
127
+ return out.die(`Failed to Read Env File: ${args.env}`);
128
+ }
129
+ for (const line of content.split("\n")) {
130
+ const trimmed = line.trim();
131
+ if (!trimmed || trimmed.startsWith("#"))
132
+ continue;
133
+ const eq = trimmed.indexOf("=");
134
+ if (eq === -1)
135
+ continue;
136
+ secretsObj[trimmed.slice(0, eq)] = trimmed.slice(eq + 1);
137
+ }
138
+ }
139
+ // Load from positional KEY=VALUE args
140
+ const pairs = args._.slice(1).map(String);
141
+ for (const pair of pairs) {
142
+ const eq = pair.indexOf("=");
143
+ if (eq === -1) {
144
+ return out.die(`Invalid Format: '${pair}'. Expected KEY=VALUE`);
145
+ }
146
+ secretsObj[pair.slice(0, eq)] = pair.slice(eq + 1);
147
+ }
148
+ if (Object.keys(secretsObj).length === 0) {
149
+ return out.die("No Secrets Provided. Use KEY=VALUE args or --env <file>");
150
+ }
151
+ const { fly, org } = await initSession(out, {
152
+ json: args.json,
153
+ org: args.org,
154
+ });
155
+ const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
156
+ await out.spin(args.stage ? "Staging Secrets" : "Setting Secrets", () => fly.secrets.set(flyAppName, secretsObj, { stage: args.stage }));
157
+ out.done({ app, network, flyAppName });
158
+ out.print();
159
+ };
160
+ // =============================================================================
161
+ // Secrets Unset
162
+ // =============================================================================
163
+ const secretsUnset = async (argv) => {
164
+ const opts = {
165
+ string: ["org"],
166
+ boolean: ["help", "json", "stage"],
167
+ };
168
+ const args = parseArgs(argv, opts);
169
+ checkArgs(args, opts, "ambit secrets unset", Infinity);
170
+ if (args.help) {
171
+ console.log(`
172
+ ${bold("ambit secrets unset")} - Remove Secrets from an App
173
+
174
+ ${bold("USAGE")}
175
+ ambit secrets unset <app>.<network> KEY ... [--org <org>] [--stage] [--json]
176
+
177
+ ${bold("OPTIONS")}
178
+ --org <org> Fly.io organization slug
179
+ --stage Stage removal without deploying
180
+ --json Output as JSON
181
+
182
+ ${bold("EXAMPLES")}
183
+ ambit secrets unset my-app.browsers API_KEY
184
+ ambit secrets unset my-app.browsers KEY1 KEY2 --stage
185
+ `);
186
+ return;
187
+ }
188
+ const out = createOutput(args.json);
189
+ const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets unset");
190
+ const keys = args._.slice(1).map(String);
191
+ if (keys.length === 0) {
192
+ return out.die("No Secret Names Provided. Usage: ambit secrets unset <app>.<network> KEY ...");
193
+ }
194
+ const { fly, org } = await initSession(out, {
195
+ json: args.json,
196
+ org: args.org,
197
+ });
198
+ const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
199
+ await out.spin(args.stage ? "Staging Secrets Removal" : "Removing Secrets", () => fly.secrets.unset(flyAppName, keys, { stage: args.stage }));
200
+ out.done({ app, network, flyAppName });
201
+ out.print();
202
+ };
203
+ // =============================================================================
204
+ // Secrets Deploy
205
+ // =============================================================================
206
+ const secretsDeploy = async (argv) => {
207
+ const opts = { string: ["org"], boolean: ["help", "json"] };
208
+ const args = parseArgs(argv, opts);
209
+ checkArgs(args, opts, "ambit secrets deploy", 1);
210
+ if (args.help) {
211
+ console.log(`
212
+ ${bold("ambit secrets deploy")} - Deploy Staged Secrets
213
+
214
+ ${bold("USAGE")}
215
+ ambit secrets deploy <app>.<network> [--org <org>] [--json]
216
+
217
+ ${bold("OPTIONS")}
218
+ --org <org> Fly.io organization slug
219
+ --json Output as JSON
220
+
221
+ ${bold("EXAMPLES")}
222
+ ambit secrets deploy my-app.browsers
223
+ `);
224
+ return;
225
+ }
226
+ const out = createOutput(args.json);
227
+ const { app, network } = resolveAppTarget(out, args._[0], "ambit secrets deploy");
228
+ const { fly, org } = await initSession(out, {
229
+ json: args.json,
230
+ org: args.org,
231
+ });
232
+ const flyAppName = await resolveFlyAppName(out, fly, org, app, network);
233
+ await out.spin("Deploying Secrets", () => fly.secrets.deploy(flyAppName));
234
+ out.done({ app, network, flyAppName });
235
+ out.print();
236
+ };
237
+ // =============================================================================
238
+ // Top-Level Help
239
+ // =============================================================================
240
+ const showSecretsHelp = () => {
241
+ console.log(`
242
+ ${bold("ambit secrets")} - Manage Secrets for Workload Apps
243
+
244
+ ${bold("USAGE")}
245
+ ambit secrets list <app>.<network> [options]
246
+ ambit secrets set <app>.<network> KEY=VALUE ... [options]
247
+ ambit secrets unset <app>.<network> KEY ... [options]
248
+ ambit secrets deploy <app>.<network> [options]
249
+
250
+ ${bold("SUBCOMMANDS")}
251
+ list List secret names and digests
252
+ set Set one or more secrets
253
+ unset Remove one or more secrets
254
+ deploy Deploy staged secrets
255
+
256
+ ${bold("OPTIONS")}
257
+ --org <org> Fly.io organization slug
258
+ --stage Stage changes without deploying (set/unset only)
259
+ --json Output as JSON
260
+
261
+ ${bold("EXAMPLES")}
262
+ ambit secrets list my-app.browsers
263
+ ambit secrets set my-app.browsers API_KEY=abc123
264
+ ambit secrets unset my-app.browsers API_KEY
265
+ ambit secrets deploy my-app.browsers
266
+
267
+ Run 'ambit secrets <subcommand> --help' for details.
268
+ `);
269
+ };
270
+ // =============================================================================
271
+ // Dispatcher
272
+ // =============================================================================
273
+ const secrets = async (argv) => {
274
+ const subcommand = typeof argv[0] === "string" ? argv[0] : undefined;
275
+ if (subcommand === "list" || subcommand === "ls") {
276
+ return secretsList(argv.slice(1));
277
+ }
278
+ if (subcommand === "set")
279
+ return secretsSet(argv.slice(1));
280
+ if (subcommand === "unset")
281
+ return secretsUnset(argv.slice(1));
282
+ if (subcommand === "deploy")
283
+ return secretsDeploy(argv.slice(1));
284
+ const opts = { boolean: ["help"] };
285
+ const args = parseArgs(argv, opts);
286
+ checkArgs(args, opts, "ambit secrets", 0);
287
+ if (args.help) {
288
+ showSecretsHelp();
289
+ return;
290
+ }
291
+ showSecretsHelp();
292
+ dntShim.Deno.exit(1);
293
+ };
294
+ // =============================================================================
295
+ // Register Command
296
+ // =============================================================================
297
+ registerCommand({
298
+ name: "secrets",
299
+ description: "Manage secrets for workload apps",
300
+ usage: "ambit secrets list|set|unset|deploy <app>.<network> [options]",
301
+ run: secrets,
302
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../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,IA+B3B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAMF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAuCzD,CAAC"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../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,IAiC3B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAMF,eAAO,MAAM,MAAM,GAAU,MAAM,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAuCzD,CAAC"}
package/esm/cli/mod.js CHANGED
@@ -35,6 +35,8 @@ ${bold("COMMANDS")}
35
35
  share Grant a Tailscale group access to a network via ACL rules
36
36
  list List all discovered routers across networks
37
37
  status Show router status, network, and tailnet info
38
+ secrets Manage secrets for workload apps
39
+ logs Stream logs for a workload app
38
40
  destroy Destroy a network (router) or a workload app
39
41
  doctor Check that Tailscale and the router are working correctly
40
42
 
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "@cardelli/ambit",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Deploy apps to the cloud that only you and your AI agents can reach",
5
5
  "license": "MIT",
6
6
  "tasks": {
@@ -23,4 +23,13 @@ export declare class CmdResult {
23
23
  export declare const runCommand: (args: string[], options?: RunOptions) => Promise<CmdResult>;
24
24
  /** Run and parse stdout as JSON. */
25
25
  export declare const runJson: <T>(args: string[], options?: RunOptions) => Promise<Result<T>>;
26
+ export interface StreamHandle {
27
+ lines: AsyncIterable<string>;
28
+ done: Promise<CmdResult>;
29
+ }
30
+ /**
31
+ * Spawn a command and stream stdout line-by-line via an async iterable.
32
+ * Use `done` to check the exit code after the stream ends.
33
+ */
34
+ export declare const streamCommand: (args: string[], options?: Omit<RunOptions, "interactive">) => StreamHandle;
26
35
  //# sourceMappingURL=command.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lib/command.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMrC,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAMD,qBAAa,SAAS;IAIlB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IALzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;gBAGV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;IAKzB,iDAAiD;IACjD,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;IAapB,8BAA8B;IAC9B,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF;AAMD;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,SAAS,CAyCnB,CAAC;AAMF,oCAAoC;AACpC,eAAO,MAAM,OAAO,GAAI,CAAC,EACvB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAuD,CAAC"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/lib/command.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAMrC,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAMD,qBAAa,SAAS;IAIlB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IALzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;gBAGV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM;IAKzB,iDAAiD;IACjD,IAAI,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;IAapB,8BAA8B;IAC9B,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF;AAMD;;;GAGG;AACH,eAAO,MAAM,UAAU,GACrB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,SAAS,CAyCnB,CAAC;AAMF,oCAAoC;AACpC,eAAO,MAAM,OAAO,GAAI,CAAC,EACvB,MAAM,MAAM,EAAE,EACd,UAAU,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAuD,CAAC;AAM5E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,MAAM,EAAE,EACd,UAAU,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,KACxC,YA+BF,CAAC"}
@@ -2,6 +2,8 @@
2
2
  // Shell Command Helpers
3
3
  // =============================================================================
4
4
  import { spawn } from "node:child_process";
5
+ import { createInterface } from "node:readline";
6
+ import process from "node:process";
5
7
  import { Result } from "./result.js";
6
8
  // =============================================================================
7
9
  // Command Result
@@ -82,3 +84,33 @@ export const runCommand = (args, options) => {
82
84
  // =============================================================================
83
85
  /** Run and parse stdout as JSON. */
84
86
  export const runJson = (args, options) => runCommand(args, options).then((r) => r.json());
87
+ /**
88
+ * Spawn a command and stream stdout line-by-line via an async iterable.
89
+ * Use `done` to check the exit code after the stream ends.
90
+ */
91
+ export const streamCommand = (args, options) => {
92
+ const [cmd, ...cmdArgs] = args;
93
+ const child = spawn(cmd, cmdArgs, {
94
+ cwd: options?.cwd,
95
+ env: options?.env ? { ...process.env, ...options.env } : undefined,
96
+ stdio: [
97
+ options?.stdin === "inherit" ? "inherit" : "ignore",
98
+ "pipe",
99
+ "pipe",
100
+ ],
101
+ });
102
+ child.stdout.setEncoding("utf8");
103
+ child.stderr.setEncoding("utf8");
104
+ const rl = createInterface({ input: child.stdout });
105
+ const stderr = [];
106
+ child.stderr.on("data", (chunk) => stderr.push(chunk));
107
+ const done = new Promise((resolve) => {
108
+ child.on("error", (error) => {
109
+ resolve(new CmdResult(-1, "", error.message));
110
+ });
111
+ child.on("close", (code) => {
112
+ resolve(new CmdResult(code ?? 1, "", stderr.join("")));
113
+ });
114
+ });
115
+ return { lines: rl, done };
116
+ };
@@ -0,0 +1,23 @@
1
+ export interface Column {
2
+ name: string;
3
+ width: number;
4
+ }
5
+ export interface StreamTableOptions {
6
+ indent?: number;
7
+ padding?: number;
8
+ }
9
+ export declare class StreamTable {
10
+ private columns;
11
+ private indent;
12
+ private padding;
13
+ constructor(columns: Column[], opts?: StreamTableOptions);
14
+ /** Render the header row (bold column names). */
15
+ header(): string;
16
+ /** Render a separator line under the header. */
17
+ separator(): string;
18
+ /** Render a single data row. */
19
+ row(values: string[]): string;
20
+ private effectiveWidth;
21
+ private pad;
22
+ }
23
+ //# sourceMappingURL=table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../src/lib/table.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,kBAAkB;IAMxD,iDAAiD;IACjD,MAAM,IAAI,MAAM;IAMhB,gDAAgD;IAChD,SAAS,IAAI,MAAM;IAWnB,gCAAgC;IAChC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM;IAU7B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,GAAG;CAMZ"}
@@ -0,0 +1,64 @@
1
+ // =============================================================================
2
+ // StreamTable - Fixed-Width Column Formatter for Streaming Output
3
+ // =============================================================================
4
+ //
5
+ // Unlike @cliffy/table which needs all rows upfront to calculate widths,
6
+ // StreamTable uses fixed column widths so rows can be rendered one at a time.
7
+ // Each method returns a string — pass it to out.text() for JSON mode guard.
8
+ //
9
+ // =============================================================================
10
+ import { bold, dim } from "./cli.js";
11
+ // =============================================================================
12
+ // StreamTable
13
+ // =============================================================================
14
+ export class StreamTable {
15
+ columns;
16
+ indent;
17
+ padding;
18
+ constructor(columns, opts) {
19
+ this.columns = columns;
20
+ this.indent = " ".repeat(opts?.indent ?? 2);
21
+ this.padding = " ".repeat(opts?.padding ?? 2);
22
+ }
23
+ /** Render the header row (bold column names). */
24
+ header() {
25
+ return this.indent + this.columns
26
+ .map((col, i) => bold(this.pad(col.name, col.width, i)))
27
+ .join(this.padding);
28
+ }
29
+ /** Render a separator line under the header. */
30
+ separator() {
31
+ return this.indent + dim(this.columns
32
+ .map((col, i) => {
33
+ const w = this.effectiveWidth(col.width, i);
34
+ return w > 0 ? "─".repeat(w) : "─".repeat(col.name.length);
35
+ })
36
+ .join(this.padding));
37
+ }
38
+ /** Render a single data row. */
39
+ row(values) {
40
+ return this.indent + this.columns
41
+ .map((col, i) => this.pad(values[i] ?? "", col.width, i))
42
+ .join(this.padding);
43
+ }
44
+ // ===========================================================================
45
+ // Internal
46
+ // ===========================================================================
47
+ effectiveWidth(width, index) {
48
+ // width=0 on last column means unbounded
49
+ if (width === 0 && index === this.columns.length - 1)
50
+ return 0;
51
+ // width=0 on non-last column falls back to header name length
52
+ if (width === 0)
53
+ return this.columns[index].name.length;
54
+ return width;
55
+ }
56
+ pad(value, width, index) {
57
+ const w = this.effectiveWidth(width, index);
58
+ if (w === 0)
59
+ return value; // unbounded last column
60
+ if (value.length > w)
61
+ return value.slice(0, w - 1) + "…";
62
+ return value.padEnd(w);
63
+ }
64
+ }
package/esm/main.d.ts CHANGED
@@ -7,4 +7,6 @@ import "./cli/commands/list/index.js";
7
7
  import "./cli/commands/status/index.js";
8
8
  import "./cli/commands/destroy/index.js";
9
9
  import "./cli/commands/doctor.js";
10
+ import "./cli/commands/secrets.js";
11
+ import "./cli/commands/logs.js";
10
12
  //# sourceMappingURL=main.d.ts.map
package/esm/main.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC;AAkC7B,OAAO,gCAAgC,CAAC;AACxC,OAAO,gCAAgC,CAAC;AACxC,OAAO,yBAAyB,CAAC;AACjC,OAAO,8BAA8B,CAAC;AACtC,OAAO,gCAAgC,CAAC;AACxC,OAAO,iCAAiC,CAAC;AACzC,OAAO,0BAA0B,CAAC"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,qBAAqB,CAAC;AAoC7B,OAAO,gCAAgC,CAAC;AACxC,OAAO,gCAAgC,CAAC;AACxC,OAAO,yBAAyB,CAAC;AACjC,OAAO,8BAA8B,CAAC;AACtC,OAAO,gCAAgC,CAAC;AACxC,OAAO,iCAAiC,CAAC;AACzC,OAAO,0BAA0B,CAAC;AAClC,OAAO,2BAA2B,CAAC;AACnC,OAAO,wBAAwB,CAAC"}
package/esm/main.js CHANGED
@@ -14,6 +14,8 @@ import * as dntShim from "./_dnt.shims.js";
14
14
  // deploy Deploy an app safely on a custom private network
15
15
  // share Grant a group access to a network via Tailscale ACL rules
16
16
  // status Show router status, network, and tailnet info
17
+ // secrets Manage secrets for workload apps
18
+ // logs Stream logs for a workload app
17
19
  // destroy Destroy a network (router) or a workload app
18
20
  // doctor Check that Tailscale and the router are working correctly
19
21
  //
@@ -37,6 +39,8 @@ import "./cli/commands/list/index.js";
37
39
  import "./cli/commands/status/index.js";
38
40
  import "./cli/commands/destroy/index.js";
39
41
  import "./cli/commands/doctor.js";
42
+ import "./cli/commands/secrets.js";
43
+ import "./cli/commands/logs.js";
40
44
  // =============================================================================
41
45
  // Main
42
46
  // =============================================================================
@@ -57,9 +57,17 @@ export interface FlyProvider {
57
57
  destroy(app: string, machineId: string): Promise<void>;
58
58
  };
59
59
  secrets: {
60
+ list(app: string): Promise<Array<{
61
+ name: string;
62
+ digest: string;
63
+ }>>;
60
64
  set(app: string, secrets: Record<string, string>, opts?: {
61
65
  stage?: boolean;
62
66
  }): Promise<void>;
67
+ unset(app: string, keys: string[], opts?: {
68
+ stage?: boolean;
69
+ }): Promise<void>;
70
+ deploy(app: string): Promise<void>;
63
71
  };
64
72
  ips: {
65
73
  list(app: string): Promise<FlyIp[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../src/providers/fly.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../src/providers/fly.ts"],"names":[],"mappings":"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"}
@@ -246,6 +246,10 @@ export const createFlyProvider = () => {
246
246
  },
247
247
  },
248
248
  secrets: {
249
+ async list(app) {
250
+ const result = await runJson(["fly", "secrets", "list", "-a", app, "--json"]);
251
+ return result.unwrapOr([]);
252
+ },
249
253
  async set(app, secrets, opts) {
250
254
  const pairs = Object.entries(secrets)
251
255
  .filter(([_, v]) => v !== undefined && v !== "")
@@ -261,6 +265,30 @@ export const createFlyProvider = () => {
261
265
  return die("Failed to Set Secrets");
262
266
  }
263
267
  },
268
+ async unset(app, keys, opts) {
269
+ if (keys.length === 0)
270
+ return;
271
+ const args = ["fly", "secrets", "unset", ...keys, "-a", app];
272
+ if (opts?.stage) {
273
+ args.push("--stage");
274
+ }
275
+ const result = await runCommand(args);
276
+ if (!result.ok) {
277
+ return die("Failed to Unset Secrets");
278
+ }
279
+ },
280
+ async deploy(app) {
281
+ const result = await runCommand([
282
+ "fly",
283
+ "secrets",
284
+ "deploy",
285
+ "-a",
286
+ app,
287
+ ]);
288
+ if (!result.ok) {
289
+ return die("Failed to Deploy Secrets");
290
+ }
291
+ },
264
292
  },
265
293
  ips: {
266
294
  async list(app) {
@@ -1,5 +1,4 @@
1
- import type { FlyMachine } from "../schemas/fly.js";
2
- import { type FlyMachineGuestSchema } from "../schemas/fly.js";
1
+ import type { FlyMachine, FlyMachineGuestSchema } from "../schemas/fly.js";
3
2
  import type { z } from "../deps/jsr.io/@zod/zod/4.3.6/src/index.js";
4
3
  /**
5
4
  * Map Fly machine state to internal state.
@@ -1 +1 @@
1
- {"version":3,"file":"fly-transforms.d.ts","sourceRoot":"","sources":["../../src/util/fly-transforms.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,4CAA4C,CAAC;AAMpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,MAAM,KACf,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,QAiBtC,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,KAC5C,eAAe,GAAG,eAAe,GAAG,eAOtC,CAAC;AAMF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,6DAA6D;AAC7D,eAAO,MAAM,WAAW,GAAI,KAAK,UAAU,EAAE,KAAG,aAAa,EAQ5D,CAAC;AAMF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,aAAa,GACxB,MAAM,WAAW,KAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CASlC,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,MAOnD,CAAC;AAMF,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,KAAG,MAKjD,CAAC"}
1
+ {"version":3,"file":"fly-transforms.d.ts","sourceRoot":"","sources":["../../src/util/fly-transforms.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,4CAA4C,CAAC;AAMpE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,MAAM,KACf,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,QAiBtC,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,KAC5C,eAAe,GAAG,eAAe,GAAG,eAOtC,CAAC;AAMF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,6DAA6D;AAC7D,eAAO,MAAM,WAAW,GAAI,KAAK,UAAU,EAAE,KAAG,aAAa,EAQ5D,CAAC;AAMF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,eAAO,MAAM,aAAa,GACxB,MAAM,WAAW,KAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CASlC,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,KAAG,MAOnD,CAAC;AAMF,eAAO,MAAM,aAAa,GAAI,WAAW,MAAM,KAAG,MAKjD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/util/resolve.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,KAAK,WAAW,EAChB,MAAM;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,EACtC,KAAK,MAAM,CAAC,GAAG,CAAC,KACf,OAAO,CAAC,MAAM,CA6BhB,CAAC"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/util/resolve.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,KAAK,WAAW,EAChB,MAAM;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,EAEtC,KAAK,MAAM,CAAC,GAAG,CAAC,KACf,OAAO,CAAC,MAAM,CA6BhB,CAAC"}
@@ -8,7 +8,9 @@ import { prompt } from "../lib/cli.js";
8
8
  /**
9
9
  * Resolve Fly.io organization: --org flag → single org auto-select → prompt.
10
10
  */
11
- export const resolveOrg = async (fly, args, out) => {
11
+ export const resolveOrg = async (fly, args,
12
+ // deno-lint-ignore no-explicit-any
13
+ out) => {
12
14
  if (args.org)
13
15
  return args.org;
14
16
  if (args.json) {
@@ -24,7 +24,7 @@ import { Result } from "../lib/result.js";
24
24
  /** Shorthand for returning a typed fetch error. */
25
25
  const fail = (message) => Result.err(message);
26
26
  /** Format a template reference for display. */
27
- const formatRef = (ref) => {
27
+ const _formatRef = (ref) => {
28
28
  const base = ref.path === "."
29
29
  ? `${ref.owner}/${ref.repo}`
30
30
  : `${ref.owner}/${ref.repo}/${ref.path}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardelli/ambit",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "description": "Deploy apps to the cloud that only you and your AI agents can reach",
5
5
  "license": "MIT",
6
6
  "scripts": {},