@lightward/mechanic-cli 0.1.12 → 0.1.14

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 (40) hide show
  1. package/README.md +61 -4
  2. package/dist/base-command.d.ts +3 -1
  3. package/dist/base-command.d.ts.map +1 -1
  4. package/dist/base-command.js +10 -2
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +19 -11
  7. package/dist/commands/globals/delete.d.ts +1 -0
  8. package/dist/commands/globals/delete.d.ts.map +1 -1
  9. package/dist/commands/globals/delete.js +4 -1
  10. package/dist/commands/globals/pull.d.ts +1 -0
  11. package/dist/commands/globals/pull.d.ts.map +1 -1
  12. package/dist/commands/globals/pull.js +6 -1
  13. package/dist/commands/globals/push.d.ts +1 -0
  14. package/dist/commands/globals/push.d.ts.map +1 -1
  15. package/dist/commands/globals/push.js +7 -1
  16. package/dist/commands/globals/set.d.ts +1 -0
  17. package/dist/commands/globals/set.d.ts.map +1 -1
  18. package/dist/commands/globals/set.js +6 -1
  19. package/dist/commands/secrets/delete.d.ts +1 -0
  20. package/dist/commands/secrets/delete.d.ts.map +1 -1
  21. package/dist/commands/secrets/delete.js +4 -1
  22. package/dist/commands/secrets/set.d.ts +3 -5
  23. package/dist/commands/secrets/set.d.ts.map +1 -1
  24. package/dist/commands/secrets/set.js +10 -19
  25. package/dist/commands/tasks/preview.d.ts +7 -1
  26. package/dist/commands/tasks/preview.d.ts.map +1 -1
  27. package/dist/commands/tasks/preview.js +58 -3
  28. package/dist/commands/version.d.ts +14 -0
  29. package/dist/commands/version.d.ts.map +1 -0
  30. package/dist/commands/version.js +69 -0
  31. package/dist/errors.d.ts +10 -1
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +14 -1
  34. package/dist/stdin.d.ts +4 -0
  35. package/dist/stdin.d.ts.map +1 -0
  36. package/dist/stdin.js +18 -0
  37. package/dist/update-check.d.ts +3 -0
  38. package/dist/update-check.d.ts.map +1 -1
  39. package/dist/update-check.js +6 -4
  40. package/package.json +1 -1
package/README.md CHANGED
@@ -40,6 +40,12 @@ npm install -g @lightward/mechanic-cli
40
40
 
41
41
  In interactive terminals, Mechanic occasionally checks npm and prints the update command when a newer CLI is available.
42
42
 
43
+ To check your installed CLI version against the latest published version:
44
+
45
+ ```bash
46
+ mechanic version
47
+ ```
48
+
43
49
  ## Quick Start
44
50
 
45
51
  Create an API token in Mechanic:
@@ -116,11 +122,25 @@ mechanic shop status
116
122
  Most commands that editor integrations or agents would call support `--json`.
117
123
  Use JSON output for automation instead of parsing tables or colored text.
118
124
 
125
+ When a `--json` command fails before producing its normal output (auth
126
+ problems, network failures, rate limits), it prints a JSON error envelope to
127
+ stdout instead, with exit codes unchanged:
128
+
129
+ ```json
130
+ { "error": { "message": "Mechanic API rate limit exceeded.", "status": 429, "retry_after_seconds": 7 } }
131
+ ```
132
+
133
+ `status` is present when the Mechanic API rejected the request, and
134
+ `retry_after_seconds` is present when a rate limit response includes
135
+ `Retry-After`. With `--json`, stdout is always a single JSON document: the
136
+ command's normal output, or this error envelope.
137
+
119
138
  ## Commands
120
139
 
121
140
  ```bash
122
141
  mechanic init --shop example.myshopify.com [--token <token>] [--api-base-url <url>] [--app-url <url>] [--force]
123
142
  mechanic help [command]
143
+ mechanic version [--json]
124
144
  mechanic doctor
125
145
  mechanic auth login [--token <token>]
126
146
  mechanic auth logout
@@ -134,7 +154,7 @@ mechanic tasks status [task] [--local] [--json]
134
154
  mechanic tasks pull [--force]
135
155
  mechanic tasks pull <task> [--force]
136
156
  mechanic tasks pull --all [--force]
137
- mechanic tasks preview <task> [--remote] [--verbose] [--json]
157
+ mechanic tasks preview [task] [--stdin] [--remote] [--verbose] [--json]
138
158
  mechanic tasks diff <task> [--exit-code] [--json]
139
159
  mechanic tasks diff --all [--exit-code] [--json]
140
160
  mechanic tasks publish <task> [--force] [--dry-run] [--json]
@@ -233,7 +253,25 @@ current task already in Mechanic instead of your local draft. Add `--verbose`
233
253
  to show event, task run, and action run result details in the terminal. Add
234
254
  `--json` when an agent, script, or CI job needs the raw preview response.
235
255
  Missing Shopify permissions are approved in the Mechanic app after publishing
236
- or enabling the task.
256
+ or enabling the task. Preview exits `0` when the preview passes, `1` when
257
+ sample runs fail, and `2` when the task is invalid.
258
+
259
+ `tasks preview --stdin` reads task JSON from stdin instead of local files, so
260
+ editors and other tools can preview in-memory task content without writing it
261
+ to disk first:
262
+
263
+ ```bash
264
+ cat build/order-tagger.json | mechanic tasks preview order-tagger --stdin
265
+ generate-task | mechanic tasks preview --stdin --json
266
+ ```
267
+
268
+ Pass a task selector alongside `--stdin` to preview the piped content in the
269
+ context of that linked Mechanic task, or omit the selector to preview the
270
+ content as a new unlinked task. `--stdin` trusts the piped content as the
271
+ source of truth, so it skips the stale helper directory check. Previews are
272
+ rate limited per token; tools that preview on every edit should debounce and
273
+ respect `429 Retry-After` responses. With `--json`, a rate limited preview
274
+ prints the JSON error envelope, including `retry_after_seconds`.
237
275
 
238
276
  `tasks publish` sends local task JSON back to Mechanic.
239
277
 
@@ -246,8 +284,8 @@ Mechanic, `.mechanic/links.json`, or local task JSON. New tasks created by
246
284
  they are ready to run.
247
285
 
248
286
  For automation or editor integrations, add `--json` to `tasks list`, `tasks
249
- status`, `tasks diff`, `tasks validate`, `tasks bundle`, `tasks unbundle`,
250
- `tasks publish`, or `shop status`.
287
+ status`, `tasks preview`, `tasks diff`, `tasks validate`, `tasks bundle`,
288
+ `tasks unbundle`, `tasks publish`, or `shop status`.
251
289
 
252
290
  `tasks unbundle` and `tasks bundle` operate on one task at a time. By default,
253
291
  `mechanic tasks unbundle order-tagger` writes to `tasks/order-tagger/`, and
@@ -489,6 +527,15 @@ new globals but refuses to overwrite existing remote globals whose values differ
489
527
  use `mechanic globals push --dry-run` to review the plan, then pass `--force`
490
528
  when the local file should replace those remote values.
491
529
 
530
+ For one-off global changes:
531
+
532
+ ```bash
533
+ mechanic globals list
534
+ mechanic globals set warehouse_id --json '"main"'
535
+ mechanic globals set shipping_rules --json '{"regions":["CA","US"]}'
536
+ mechanic globals delete warehouse_id --force
537
+ ```
538
+
492
539
  Shop secrets are write-only string values. The CLI never creates a secrets file,
493
540
  and task pull, preview, and publish never write secret values into task JSON.
494
541
  Use `mechanic secrets set <key> --from-stdin` or `--value-env <env>` for
@@ -497,6 +544,16 @@ trailing newlines. Secret values are not printed after save. Replacing or
497
544
  deleting a secret can break tasks until they are updated, so existing secret
498
545
  values and secret deletes require `--force`.
499
546
 
547
+ For one-off secret changes:
548
+
549
+ ```bash
550
+ mechanic secrets list
551
+ mechanic secrets set api_token
552
+ printf %s "$API_TOKEN" | mechanic secrets set api_token --from-stdin
553
+ mechanic secrets set api_token --value-env API_TOKEN --force
554
+ mechanic secrets delete api_token --force
555
+ ```
556
+
500
557
  ## Task Sync API
501
558
 
502
559
  This package targets Mechanic's v1 task sync API. The CLI is the recommended
@@ -1,7 +1,9 @@
1
- import { Command } from "@oclif/core";
1
+ import { Command, type Interfaces } from "@oclif/core";
2
2
  import { MechanicClient } from "./client.js";
3
3
  import type { Project } from "./types.js";
4
4
  export declare abstract class BaseCommand extends Command {
5
+ private wroteJson;
6
+ protected catch(error: Interfaces.CommandError): Promise<unknown>;
5
7
  protected finally(error: Error | undefined): Promise<void>;
6
8
  loadProject(): Promise<Project>;
7
9
  clientForProject(project: Project): Promise<MechanicClient>;
@@ -1 +1 @@
1
- {"version":3,"file":"base-command.d.ts","sourceRoot":"","sources":["../src/base-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAM,MAAM,aAAa,CAAC;AAI1C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAI7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,8BAAsB,WAAY,SAAQ,OAAO;cACtB,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBnE,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAQ3D,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAMnE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAenC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAI1C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI3B,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAIhC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI7B,eAAe,IAAI,MAAM;IAQzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI9B,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAIhD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI;CAgB9B"}
1
+ {"version":3,"file":"base-command.d.ts","sourceRoot":"","sources":["../src/base-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAM,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAI3D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAI7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,8BAAsB,WAAY,SAAQ,OAAO;IAC/C,OAAO,CAAC,SAAS,CAAS;cAED,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;cAQvD,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBnE,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAQ3D,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAMnE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAY/E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI5B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAenC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAI1C,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI3B,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKhC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI7B,eAAe,IAAI,MAAM;IAQzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI9B,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAIhD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI;CAgB9B"}
@@ -4,12 +4,19 @@ import terminalLink from "terminal-link";
4
4
  import { requireToken } from "./auth.js";
5
5
  import { MechanicClient } from "./client.js";
6
6
  import { loadProject, taskAdminUrl } from "./config.js";
7
- import { CliError } from "./errors.js";
7
+ import { CliError, errorJson } from "./errors.js";
8
8
  import { getUpdateNotice, shouldCheckForUpdates } from "./update-check.js";
9
9
  export class BaseCommand extends Command {
10
+ wroteJson = false;
11
+ async catch(error) {
12
+ if (this.argv.includes("--json") && !this.wroteJson) {
13
+ this.outputJson(errorJson(error));
14
+ }
15
+ return super.catch(error);
16
+ }
10
17
  async finally(error) {
11
18
  await super.finally(error);
12
- if (error || !shouldCheckForUpdates(this.argv)) {
19
+ if (error || this.id === "version" || !shouldCheckForUpdates(this.argv)) {
13
20
  return;
14
21
  }
15
22
  const notice = await getUpdateNotice();
@@ -66,6 +73,7 @@ export class BaseCommand extends Command {
66
73
  return this.color("dim", text);
67
74
  }
68
75
  outputJson(value) {
76
+ this.wroteJson = true;
69
77
  this.log(JSON.stringify(value, null, 2));
70
78
  }
71
79
  success(text) {
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,UAAU,EACV,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,UAAU,QAAkD,CAAC;AAE1E,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE;QACL,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAChC,GAAG,IAAI,CAAC;IACT,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;CACH,CAAC;AAwGF,qBAAa,cAAc;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAM7G,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IAgD5E,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAIvC,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI5C,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAMvE,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAItC,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI3C,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAOnE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI3C,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAOlE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1C,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IASxE,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAM3D,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ5E,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAM3H"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,UAAU,EACV,wBAAwB,EACxB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAKpB,eAAO,MAAM,UAAU,QAAkD,CAAC;AAE1E,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,CAAC,EAAE;QACL,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAChC,GAAG,IAAI,CAAC;IACT,SAAS,CAAC,EAAE;QACV,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;CACH,CAAC;AAoHF,qBAAa,cAAc;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAM7G,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IAgD5E,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAIvC,aAAa,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI5C,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAMvE,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAItC,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI3C,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAOnE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI3C,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAOlE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI1C,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IASxE,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAM3D,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ5E,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;CAM3H"}
package/dist/client.js CHANGED
@@ -20,17 +20,25 @@ function parseBody(text) {
20
20
  return { raw: text };
21
21
  }
22
22
  }
23
- function retryDelayMilliseconds(response, attempt) {
23
+ function retryAfterSeconds(response) {
24
24
  const retryAfter = response.headers.get("retry-after");
25
- if (retryAfter) {
26
- const parsedSeconds = Number.parseFloat(retryAfter);
27
- if (Number.isFinite(parsedSeconds) && parsedSeconds >= 0) {
28
- return parsedSeconds * 1000;
29
- }
30
- const parsedDate = Date.parse(retryAfter);
31
- if (Number.isFinite(parsedDate)) {
32
- return Math.max(parsedDate - Date.now(), 0);
33
- }
25
+ if (!retryAfter) {
26
+ return undefined;
27
+ }
28
+ const parsedSeconds = Number.parseFloat(retryAfter);
29
+ if (Number.isFinite(parsedSeconds) && parsedSeconds >= 0) {
30
+ return parsedSeconds;
31
+ }
32
+ const parsedDate = Date.parse(retryAfter);
33
+ if (Number.isFinite(parsedDate)) {
34
+ return Math.max(parsedDate - Date.now(), 0) / 1000;
35
+ }
36
+ return undefined;
37
+ }
38
+ function retryDelayMilliseconds(response, attempt) {
39
+ const seconds = retryAfterSeconds(response);
40
+ if (seconds !== undefined) {
41
+ return seconds * 1000;
34
42
  }
35
43
  return 250 * (2 ** (attempt - 1));
36
44
  }
@@ -131,7 +139,7 @@ export class MechanicClient {
131
139
  await sleep(retryDelayMilliseconds(response, attempt));
132
140
  continue;
133
141
  }
134
- throw new HttpError(apiErrorMessage(response, parsed), response.status, parsed);
142
+ throw new HttpError(apiErrorMessage(response, parsed), response.status, parsed, retryAfterSeconds(response));
135
143
  }
136
144
  throw new HttpError("Request failed", 0, null);
137
145
  }
@@ -2,6 +2,7 @@ import { BaseCommand } from "../../base-command.js";
2
2
  export default class GlobalsDelete extends BaseCommand {
3
3
  static summary: string;
4
4
  static description: string;
5
+ static examples: string[];
5
6
  static args: {
6
7
  key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,OAAgB,OAAO,SAA6B;IACpD,OAAgB,WAAW,SAA2C;IAEtE,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;MAKnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAc3B"}
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,OAAgB,OAAO,SAA6B;IACpD,OAAgB,WAAW,SAA2C;IACtE,OAAgB,QAAQ,WAEtB;IAEF,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;MAKnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAc3B"}
@@ -5,13 +5,16 @@ import { CliError } from "../../errors.js";
5
5
  export default class GlobalsDelete extends BaseCommand {
6
6
  static summary = "Delete one shop global.";
7
7
  static description = "Delete one visible shop-level global.";
8
+ static examples = [
9
+ "$ mechanic globals delete warehouse_id --force",
10
+ ];
8
11
  static args = {
9
12
  key: Args.string({ required: true, description: "Global key, using lower snake-case." }),
10
13
  };
11
14
  static flags = {
12
15
  force: Flags.boolean({
13
16
  char: "f",
14
- description: "Delete without an interactive confirmation.",
17
+ description: "Confirm deleting this global.",
15
18
  }),
16
19
  };
17
20
  async run() {
@@ -2,6 +2,7 @@ import { BaseCommand } from "../../base-command.js";
2
2
  export default class GlobalsPull extends BaseCommand {
3
3
  static summary: string;
4
4
  static description: string;
5
+ static examples: string[];
5
6
  static flags: {
6
7
  out: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
8
  force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/pull.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAOpD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,OAAgB,OAAO,SAAmD;IAC1E,OAAgB,WAAW,SAAiE;IAE5F,OAAgB,KAAK;;;MAQnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0B3B"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/pull.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAOpD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,OAAgB,OAAO,SAAmD;IAC1E,OAAgB,WAAW,SAAiE;IAC5F,OAAgB,QAAQ,WAItB;IAEF,OAAgB,KAAK;;;MAQnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0B3B"}
@@ -8,9 +8,14 @@ const DEFAULT_GLOBALS_FILE = "mechanic.globals.json";
8
8
  export default class GlobalsPull extends BaseCommand {
9
9
  static summary = "Pull shop globals into mechanic.globals.json.";
10
10
  static description = "Pull visible shop-level globals into a repo-safe JSON file.";
11
+ static examples = [
12
+ "$ mechanic globals pull",
13
+ "$ mechanic globals pull --out mechanic.globals.json",
14
+ "$ mechanic globals pull --force",
15
+ ];
11
16
  static flags = {
12
17
  out: Flags.string({
13
- description: "File path to write.",
18
+ description: "File path to write. Defaults to repo-safe mechanic.globals.json.",
14
19
  default: DEFAULT_GLOBALS_FILE,
15
20
  }),
16
21
  force: Flags.boolean({
@@ -2,6 +2,7 @@ import { BaseCommand } from "../../base-command.js";
2
2
  export default class GlobalsPush extends BaseCommand {
3
3
  static summary: string;
4
4
  static description: string;
5
+ static examples: string[];
5
6
  static flags: {
6
7
  file: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
8
  "dry-run": import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/push.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAgBpD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,OAAgB,OAAO,SAA8C;IACrE,OAAgB,WAAW,SAAmI;IAE9J,OAAgB,KAAK;;;;MAYnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA6D3B"}
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/push.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAgBpD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,OAAgB,OAAO,SAA8C;IACrE,OAAgB,WAAW,SAAmI;IAC9J,OAAgB,QAAQ,WAKtB;IAEF,OAAgB,KAAK;;;;MAYnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA6D3B"}
@@ -15,9 +15,15 @@ function ensurePlainObject(value, source) {
15
15
  export default class GlobalsPush extends BaseCommand {
16
16
  static summary = "Push mechanic.globals.json to this shop.";
17
17
  static description = "Push visible shop-level globals from a repo-safe JSON file. This updates listed keys and does not delete missing remote keys.";
18
+ static examples = [
19
+ "$ mechanic globals push --dry-run",
20
+ "$ mechanic globals push",
21
+ "$ mechanic globals push --force",
22
+ "$ mechanic globals push --file mechanic.globals.json --dry-run",
23
+ ];
18
24
  static flags = {
19
25
  file: Flags.string({
20
- description: "Globals JSON file to read.",
26
+ description: "Globals JSON file to read. Missing remote keys are not deleted.",
21
27
  default: DEFAULT_GLOBALS_FILE,
22
28
  }),
23
29
  "dry-run": Flags.boolean({
@@ -2,6 +2,7 @@ import { BaseCommand } from "../../base-command.js";
2
2
  export default class GlobalsSet extends BaseCommand {
3
3
  static summary: string;
4
4
  static description: string;
5
+ static examples: string[];
5
6
  static args: {
6
7
  key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/set.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,OAAgB,OAAO,SAA0B;IACjD,OAAgB,WAAW,SAA6C;IAExE,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;MAKnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAU3B"}
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../src/commands/globals/set.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,OAAgB,OAAO,SAA0B;IACjD,OAAgB,WAAW,SAA6C;IACxE,OAAgB,QAAQ,WAItB;IAEF,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;MAKnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAU3B"}
@@ -5,13 +5,18 @@ import { parseJson } from "../../json.js";
5
5
  export default class GlobalsSet extends BaseCommand {
6
6
  static summary = "Set one shop global.";
7
7
  static description = "Set one visible shop-level JSON global.";
8
+ static examples = [
9
+ "$ mechanic globals set warehouse_id --json '\"main\"'",
10
+ "$ mechanic globals set shipping_rules --json '{\"regions\":[\"CA\",\"US\"]}'",
11
+ "$ mechanic globals set reorder_threshold --json 5",
12
+ ];
8
13
  static args = {
9
14
  key: Args.string({ required: true, description: "Global key, using lower snake-case." }),
10
15
  };
11
16
  static flags = {
12
17
  json: Flags.string({
13
18
  required: true,
14
- description: "JSON value to store.",
19
+ description: "Any valid JSON value. For strings, include JSON quotes, e.g. --json '\"main\"'.",
15
20
  }),
16
21
  };
17
22
  async run() {
@@ -2,6 +2,7 @@ import { BaseCommand } from "../../base-command.js";
2
2
  export default class SecretsDelete extends BaseCommand {
3
3
  static summary: string;
4
4
  static description: string;
5
+ static examples: string[];
5
6
  static args: {
6
7
  key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/secrets/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,OAAgB,OAAO,SAA6B;IACpD,OAAgB,WAAW,SAAqF;IAEhH,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;MAKnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAc3B"}
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/secrets/delete.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,OAAgB,OAAO,SAA6B;IACpD,OAAgB,WAAW,SAAqF;IAChH,OAAgB,QAAQ,WAEtB;IAEF,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;MAKnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAc3B"}
@@ -5,13 +5,16 @@ import { CliError } from "../../errors.js";
5
5
  export default class SecretsDelete extends BaseCommand {
6
6
  static summary = "Delete one shop secret.";
7
7
  static description = "Delete one write-only shop-level secret. Affected tasks may fail until updated.";
8
+ static examples = [
9
+ "$ mechanic secrets delete api_token --force",
10
+ ];
8
11
  static args = {
9
12
  key: Args.string({ required: true, description: "Secret key, using lower snake-case." }),
10
13
  };
11
14
  static flags = {
12
15
  force: Flags.boolean({
13
16
  char: "f",
14
- description: "Delete without an interactive confirmation.",
17
+ description: "Confirm deleting this secret.",
15
18
  }),
16
19
  };
17
20
  async run() {
@@ -1,12 +1,11 @@
1
- import { stdin } from "node:process";
2
1
  import { BaseCommand } from "../../base-command.js";
3
- type SecretStdin = typeof stdin;
4
- export declare function readStdin(input?: SecretStdin): Promise<string>;
5
- export declare function readSecretValueFromStdin(input?: SecretStdin): Promise<string>;
2
+ import { type StdinStream } from "../../stdin.js";
3
+ export declare function readSecretValueFromStdin(input?: StdinStream): Promise<string>;
6
4
  export declare function readSecretValueFromEnv(envName: string, env?: NodeJS.ProcessEnv): string;
7
5
  export default class SecretsSet extends BaseCommand {
8
6
  static summary: string;
9
7
  static description: string;
8
+ static examples: string[];
10
9
  static args: {
11
10
  key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
12
11
  };
@@ -21,5 +20,4 @@ export default class SecretsSet extends BaseCommand {
21
20
  "value-env"?: string;
22
21
  }): Promise<string>;
23
22
  }
24
- export {};
25
23
  //# sourceMappingURL=set.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../src/commands/secrets/set.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,KAAK,WAAW,GAAG,OAAO,KAAK,CAAC;AAEhC,wBAAgB,SAAS,CAAC,KAAK,GAAE,WAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBrE;AAED,wBAAsB,wBAAwB,CAC5C,KAAK,GAAE,WAAmB,GACzB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAYR;AAED,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,OAAgB,OAAO,SAA0B;IACjD,OAAgB,WAAW,SAAwE;IAEnG,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;;MAanB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBpB,WAAW,CAAC,KAAK,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAsB5F"}
1
+ {"version":3,"file":"set.d.ts","sourceRoot":"","sources":["../../../src/commands/secrets/set.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7D,wBAAsB,wBAAwB,CAC5C,KAAK,GAAE,WAAmB,GACzB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAYR;AAED,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,OAAgB,OAAO,SAA0B;IACjD,OAAgB,WAAW,SAAwE;IACnG,OAAgB,QAAQ,WAKtB;IAEF,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;;MAanB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBpB,WAAW,CAAC,KAAK,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CAsB5F"}
@@ -4,24 +4,9 @@ import { promptForHiddenValue } from "../../auth.js";
4
4
  import { BaseCommand } from "../../base-command.js";
5
5
  import { validateConfigKey } from "../../config-keys.js";
6
6
  import { CliError } from "../../errors.js";
7
- export function readStdin(input = stdin) {
8
- if (input.isTTY) {
9
- throw new CliError("Cannot read secret value from stdin while stdin is a TTY. Pipe a value or use --value-env.", 2);
10
- }
11
- return new Promise((resolve, reject) => {
12
- let value = "";
13
- input.setEncoding("utf8");
14
- input.on("data", (chunk) => {
15
- value += chunk;
16
- });
17
- input.on("end", () => {
18
- resolve(value);
19
- });
20
- input.on("error", reject);
21
- });
22
- }
7
+ import { readStdin } from "../../stdin.js";
23
8
  export async function readSecretValueFromStdin(input = stdin) {
24
- const value = await readStdin(input);
9
+ const value = await readStdin("Cannot read secret value from stdin while stdin is a TTY. Pipe a value or use --value-env.", input);
25
10
  if (value.length === 0) {
26
11
  throw new CliError("Secret value cannot be blank.", 2);
27
12
  }
@@ -40,12 +25,18 @@ export function readSecretValueFromEnv(envName, env = process.env) {
40
25
  export default class SecretsSet extends BaseCommand {
41
26
  static summary = "Set one shop secret.";
42
27
  static description = "Set one write-only shop secret. The secret value is never printed.";
28
+ static examples = [
29
+ "$ mechanic secrets set api_token",
30
+ "$ printf %s \"$API_TOKEN\" | mechanic secrets set api_token --from-stdin",
31
+ "$ mechanic secrets set api_token --value-env API_TOKEN",
32
+ "$ mechanic secrets set api_token --value-env API_TOKEN --force",
33
+ ];
43
34
  static args = {
44
35
  key: Args.string({ required: true, description: "Secret key, using lower snake-case." }),
45
36
  };
46
37
  static flags = {
47
38
  "from-stdin": Flags.boolean({
48
- description: "Read the secret value from stdin.",
39
+ description: "Read the secret value from stdin. Preserves exact input, including trailing newlines.",
49
40
  exclusive: ["value-env"],
50
41
  }),
51
42
  force: Flags.boolean({
@@ -53,7 +44,7 @@ export default class SecretsSet extends BaseCommand {
53
44
  description: "Replace the value when this secret key already exists.",
54
45
  }),
55
46
  "value-env": Flags.string({
56
- description: "Read the secret value from the named environment variable.",
47
+ description: "Read the secret value from the named environment variable. Empty values are rejected.",
57
48
  exclusive: ["from-stdin"],
58
49
  }),
59
50
  };
@@ -1,4 +1,5 @@
1
1
  import { BaseCommand } from "../../base-command.js";
2
+ import { type StdinStream } from "../../stdin.js";
2
3
  import type { MechanicClient } from "../../client.js";
3
4
  import type { JsonObject, Project, TaskPreviewResponse } from "../../types.js";
4
5
  type PreviewDiagnostic = NonNullable<TaskPreviewResponse["diagnostics"]>[number];
@@ -11,19 +12,24 @@ type PreparedPreview = {
11
12
  type PreviewRenderOptions = {
12
13
  verbose: boolean;
13
14
  };
15
+ export declare function taskJsonFromStdin(input?: StdinStream): Promise<JsonObject>;
14
16
  export default class TasksPreview extends BaseCommand {
15
17
  static summary: string;
16
18
  static description: string;
19
+ static examples: string[];
17
20
  static args: {
18
- target: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
21
+ target: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
19
22
  };
20
23
  static flags: {
21
24
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
25
  remote: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
+ stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
23
27
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
28
  };
25
29
  run(): Promise<void>;
26
30
  exitForStatus(response: TaskPreviewResponse): void;
31
+ prepareStdinPreview(project: Project, target: string | undefined): Promise<PreparedPreview>;
32
+ taskFromStdin(): Promise<JsonObject>;
27
33
  preparePreview(project: Project, target: string, remote: boolean): Promise<PreparedPreview>;
28
34
  requestPreview(client: MechanicClient, prepared: PreparedPreview, remote: boolean): Promise<TaskPreviewResponse>;
29
35
  renderPreview(project: Project, prepared: PreparedPreview, response: TaskPreviewResponse, options: PreviewRenderOptions): void;
@@ -1 +1 @@
1
- {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/preview.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"preview.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/preview.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,10 @@
1
1
  import { Args, Flags } from "@oclif/core";
2
+ import { stdin } from "node:process";
2
3
  import { BaseCommand } from "../../base-command.js";
3
4
  import { HttpError, CliError } from "../../errors.js";
4
5
  import { pathExists } from "../../fs.js";
6
+ import { parseJson } from "../../json.js";
7
+ import { readStdin } from "../../stdin.js";
5
8
  import { displayTaskPath, readRawTaskFile, resolveTaskSelector, rawTaskFromHelperDir, taskForPush, slugFromTaskFile, unbundledHelperDirForTaskFile, validateTaskForPush, } from "../../tasks.js";
6
9
  function errorBodyAsPreview(body) {
7
10
  if (!body || typeof body !== "object") {
@@ -10,25 +13,49 @@ function errorBodyAsPreview(body) {
10
13
  const candidate = body;
11
14
  return candidate.status === "invalid" ? candidate : null;
12
15
  }
16
+ export async function taskJsonFromStdin(input = stdin) {
17
+ const contents = await readStdin("Cannot read task JSON from stdin while stdin is a TTY. Pipe task JSON or preview a local task file instead.", input);
18
+ if (contents.trim().length === 0) {
19
+ throw new CliError("No task JSON received on stdin.", 2);
20
+ }
21
+ const task = parseJson(contents, "stdin");
22
+ if (!task || typeof task !== "object" || Array.isArray(task)) {
23
+ throw new CliError("stdin must contain a single task JSON object.", 2);
24
+ }
25
+ return task;
26
+ }
13
27
  export default class TasksPreview extends BaseCommand {
14
28
  static summary = "Preview one task with Mechanic sample events.";
15
29
  static description = [
16
30
  "Preview one local task JSON file or helper directory without publishing it.",
17
31
  "The report shows sample event results, action failures, and Shopify permissions detected by the previewed paths.",
32
+ "Use --stdin to preview task JSON piped from an editor or another tool without writing it to disk.",
18
33
  "Use --remote to preview the current task already in Mechanic, or --json for agents, scripts, and CI.",
19
34
  ].join("\n");
35
+ static examples = [
36
+ "$ mechanic tasks preview order-tagger",
37
+ "$ mechanic tasks preview order-tagger --verbose",
38
+ "$ cat build/order-tagger.json | mechanic tasks preview order-tagger --stdin --json",
39
+ "$ generate-task | mechanic tasks preview --stdin --json",
40
+ ];
20
41
  static args = {
21
- target: Args.string({ required: true, description: "Local task slug, task file, helper directory, or linked task ID." }),
42
+ target: Args.string({ description: "Local task slug, task file, helper directory, or linked task ID. Optional with --stdin." }),
22
43
  };
23
44
  static flags = {
24
45
  json: Flags.boolean({ description: "Print the raw preview response as JSON for agents or CI." }),
25
- remote: Flags.boolean({ description: "Preview the current task in Mechanic instead of local content." }),
46
+ remote: Flags.boolean({ description: "Preview the current task in Mechanic instead of local content.", exclusive: ["stdin"] }),
47
+ stdin: Flags.boolean({ description: "Read task JSON from stdin instead of local task files. Pass a target to keep its linked task context.", exclusive: ["remote"] }),
26
48
  verbose: Flags.boolean({ char: "v", description: "Show event, task run, and action run result details." }),
27
49
  };
28
50
  async run() {
29
51
  const { args, flags } = await this.parse(TasksPreview);
52
+ if (!args.target && !flags.stdin) {
53
+ throw new CliError("Provide a task selector, or use --stdin to preview task JSON from stdin.", 2);
54
+ }
30
55
  const project = await this.loadProject();
31
- const prepared = await this.preparePreview(project, args.target, Boolean(flags.remote));
56
+ const prepared = flags.stdin
57
+ ? await this.prepareStdinPreview(project, args.target)
58
+ : await this.preparePreview(project, args.target, Boolean(flags.remote));
32
59
  const client = await this.verifiedClientForProject(project);
33
60
  const response = await this.requestPreview(client, prepared, Boolean(flags.remote));
34
61
  if (flags.json) {
@@ -47,6 +74,34 @@ export default class TasksPreview extends BaseCommand {
47
74
  throw new CliError("Preview found failed runs.", 1);
48
75
  }
49
76
  }
77
+ async prepareStdinPreview(project, target) {
78
+ let label = "stdin";
79
+ let slug;
80
+ let remoteId;
81
+ if (target) {
82
+ const selector = await resolveTaskSelector(project, target, {
83
+ allowHelperDir: true,
84
+ allowRemoteId: true,
85
+ });
86
+ const targetLabel = selector.helperDir
87
+ ? displayTaskPath(project, selector.helperDir)
88
+ : selector.file ? displayTaskPath(project, selector.file) : target;
89
+ label = `stdin (${targetLabel})`;
90
+ slug = selector.slug;
91
+ remoteId = selector.remoteId;
92
+ }
93
+ const task = await this.taskFromStdin();
94
+ this.validateLocalTask(task, label);
95
+ return {
96
+ label,
97
+ slug,
98
+ task: taskForPush(task),
99
+ remoteId,
100
+ };
101
+ }
102
+ async taskFromStdin() {
103
+ return taskJsonFromStdin();
104
+ }
50
105
  async preparePreview(project, target, remote) {
51
106
  const selector = await resolveTaskSelector(project, target, {
52
107
  allowHelperDir: true,
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from "../base-command.js";
2
+ type VersionStatus = "ahead_of_latest" | "unknown" | "update_available" | "up_to_date";
3
+ export default class VersionCommand extends BaseCommand {
4
+ static summary: string;
5
+ static description: string;
6
+ static examples: string[];
7
+ static flags: {
8
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ run(): Promise<void>;
11
+ statusLabel(status: VersionStatus): string;
12
+ }
13
+ export {};
14
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/commands/version.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAQjD,KAAK,aAAa,GAAG,iBAAiB,GAAG,SAAS,GAAG,kBAAkB,GAAG,YAAY,CAAC;AAkBvF,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,WAAW;IACrD,OAAgB,OAAO,SAAsD;IAC7E,OAAgB,WAAW,SAAwF;IACnH,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,KAAK;;MAInB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAgC1B,WAAW,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM;CAY3C"}
@@ -0,0 +1,69 @@
1
+ import { Flags } from "@oclif/core";
2
+ import { BaseCommand } from "../base-command.js";
3
+ import { CURRENT_VERSION, PACKAGE_NAME, fetchLatestPackageVersion, isVersionNewer, } from "../update-check.js";
4
+ function statusFor(latestVersion) {
5
+ if (!latestVersion) {
6
+ return "unknown";
7
+ }
8
+ if (isVersionNewer(latestVersion, CURRENT_VERSION)) {
9
+ return "update_available";
10
+ }
11
+ if (isVersionNewer(CURRENT_VERSION, latestVersion)) {
12
+ return "ahead_of_latest";
13
+ }
14
+ return "up_to_date";
15
+ }
16
+ export default class VersionCommand extends BaseCommand {
17
+ static summary = "Show installed and latest Mechanic CLI versions.";
18
+ static description = "Check the installed Mechanic CLI version against the latest published npm version.";
19
+ static examples = [
20
+ "$ mechanic version",
21
+ "$ mechanic version --json",
22
+ ];
23
+ static flags = {
24
+ json: Flags.boolean({
25
+ description: "Print version status as JSON for agents or scripts.",
26
+ }),
27
+ };
28
+ async run() {
29
+ const { flags } = await this.parse(VersionCommand);
30
+ const latestVersion = await fetchLatestPackageVersion();
31
+ const status = statusFor(latestVersion);
32
+ if (flags.json) {
33
+ this.outputJson({
34
+ package_name: PACKAGE_NAME,
35
+ installed_version: CURRENT_VERSION,
36
+ latest_version: latestVersion,
37
+ status,
38
+ update_available: status === "update_available",
39
+ });
40
+ return;
41
+ }
42
+ this.table([
43
+ ["Version", "Value"],
44
+ ["Installed", CURRENT_VERSION],
45
+ ["Latest", latestVersion || "unknown"],
46
+ ["Status", this.statusLabel(status)],
47
+ ]);
48
+ if (status === "update_available") {
49
+ this.log("");
50
+ this.log(`Update with: ${this.taskName("npm install -g @lightward/mechanic-cli")}`);
51
+ }
52
+ else if (status === "unknown") {
53
+ this.log("");
54
+ this.log(this.muted("Could not check the npm registry. Try again when your network is available."));
55
+ }
56
+ }
57
+ statusLabel(status) {
58
+ switch (status) {
59
+ case "ahead_of_latest":
60
+ return this.color("yellow", "installed version is newer than latest");
61
+ case "unknown":
62
+ return this.color("yellow", "unable to check latest version");
63
+ case "update_available":
64
+ return this.color("yellow", "update available");
65
+ case "up_to_date":
66
+ return this.success("up to date");
67
+ }
68
+ }
69
+ }
package/dist/errors.d.ts CHANGED
@@ -5,6 +5,15 @@ export declare class CliError extends Error {
5
5
  export declare class HttpError extends CliError {
6
6
  readonly status: number;
7
7
  readonly body: unknown;
8
- constructor(message: string, status: number, body: unknown);
8
+ readonly retryAfterSeconds?: number;
9
+ constructor(message: string, status: number, body: unknown, retryAfterSeconds?: number);
9
10
  }
11
+ export type ErrorJson = {
12
+ error: {
13
+ message: string;
14
+ status?: number;
15
+ retry_after_seconds?: number;
16
+ };
17
+ };
18
+ export declare function errorJson(error: unknown): ErrorJson;
10
19
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAI;CAK1C;AAED,qBAAa,SAAU,SAAQ,QAAQ;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;gBAEX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;CAM3D"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAI;CAK1C;AAED,qBAAa,SAAU,SAAQ,QAAQ;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,CAAC,EAAE,MAAM;CAOvF;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;CACH,CAAC;AAEF,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,CAanD"}
package/dist/errors.js CHANGED
@@ -9,10 +9,23 @@ export class CliError extends Error {
9
9
  export class HttpError extends CliError {
10
10
  status;
11
11
  body;
12
- constructor(message, status, body) {
12
+ retryAfterSeconds;
13
+ constructor(message, status, body, retryAfterSeconds) {
13
14
  super(message, status === 409 ? 2 : 1);
14
15
  this.name = "HttpError";
15
16
  this.status = status;
16
17
  this.body = body;
18
+ this.retryAfterSeconds = retryAfterSeconds;
17
19
  }
18
20
  }
21
+ export function errorJson(error) {
22
+ const message = error instanceof Error && error.message ? error.message : String(error);
23
+ const envelope = { error: { message } };
24
+ if (error instanceof HttpError) {
25
+ envelope.error.status = error.status;
26
+ if (error.retryAfterSeconds !== undefined) {
27
+ envelope.error.retry_after_seconds = error.retryAfterSeconds;
28
+ }
29
+ }
30
+ return envelope;
31
+ }
@@ -0,0 +1,4 @@
1
+ import { stdin } from "node:process";
2
+ export type StdinStream = typeof stdin;
3
+ export declare function readStdin(ttyMessage: string, input?: StdinStream): Promise<string>;
4
+ //# sourceMappingURL=stdin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../src/stdin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAGrC,MAAM,MAAM,WAAW,GAAG,OAAO,KAAK,CAAC;AAEvC,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,GAAE,WAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBzF"}
package/dist/stdin.js ADDED
@@ -0,0 +1,18 @@
1
+ import { stdin } from "node:process";
2
+ import { CliError } from "./errors.js";
3
+ export function readStdin(ttyMessage, input = stdin) {
4
+ if (input.isTTY) {
5
+ throw new CliError(ttyMessage, 2);
6
+ }
7
+ return new Promise((resolve, reject) => {
8
+ let value = "";
9
+ input.setEncoding("utf8");
10
+ input.on("data", (chunk) => {
11
+ value += chunk;
12
+ });
13
+ input.on("end", () => {
14
+ resolve(value);
15
+ });
16
+ input.on("error", reject);
17
+ });
18
+ }
@@ -1,3 +1,5 @@
1
+ export declare const PACKAGE_NAME: string;
2
+ export declare const CURRENT_VERSION: string;
1
3
  export type UpdateNotice = {
2
4
  currentVersion: string;
3
5
  latestVersion: string;
@@ -9,6 +11,7 @@ export type UpdateNoticeOptions = {
9
11
  now?: Date;
10
12
  };
11
13
  export declare function isVersionNewer(candidate: string, current: string): boolean;
14
+ export declare function fetchLatestPackageVersion(): Promise<string | null>;
12
15
  export declare function getUpdateNotice(options?: UpdateNoticeOptions): Promise<UpdateNotice | null>;
13
16
  export declare function shouldCheckForUpdates(argv?: string[], env?: NodeJS.ProcessEnv, isTty?: boolean): boolean;
14
17
  //# sourceMappingURL=update-check.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,YAAY,GAAG;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClD,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,CAAC;AAsBF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA+B1E;AA2CD,wBAAsB,eAAe,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA8CrG;AAED,wBAAgB,qBAAqB,CACnC,IAAI,WAAwB,EAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,KAAK,UAAgC,GACpC,OAAO,CAeT"}
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY,QAAgD,CAAC;AAC1E,eAAO,MAAM,eAAe,QAAiC,CAAC;AAiB9D,MAAM,MAAM,YAAY,GAAG;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClD,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,CAAC;AAsBF,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA+B1E;AAYD,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAqBxE;AAUD,wBAAsB,eAAe,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CA8CrG;AAED,wBAAgB,qBAAqB,CACnC,IAAI,WAAwB,EAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,KAAK,UAAgC,GACpC,OAAO,CAmBT"}
@@ -2,8 +2,8 @@ import { createRequire } from "node:module";
2
2
  import { appConfigPath, readJson, writeJson } from "./fs.js";
3
3
  const require = createRequire(import.meta.url);
4
4
  const packageJson = require("../package.json");
5
- const PACKAGE_NAME = packageJson.name || "@lightward/mechanic-cli";
6
- const CURRENT_VERSION = packageJson.version || "0.0.0";
5
+ export const PACKAGE_NAME = packageJson.name || "@lightward/mechanic-cli";
6
+ export const CURRENT_VERSION = packageJson.version || "0.0.0";
7
7
  const NPM_LATEST_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME).replace("%40", "@")}/latest`;
8
8
  const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
9
9
  const NOTIFY_INTERVAL_MS = 24 * 60 * 60 * 1000;
@@ -55,7 +55,7 @@ function millisecondsSince(value, now) {
55
55
  const parsed = Date.parse(value);
56
56
  return Number.isFinite(parsed) ? now.getTime() - parsed : Number.POSITIVE_INFINITY;
57
57
  }
58
- async function fetchLatestPackageVersion() {
58
+ export async function fetchLatestPackageVersion() {
59
59
  const controller = new AbortController();
60
60
  const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
61
61
  try {
@@ -132,5 +132,7 @@ export function shouldCheckForUpdates(argv = process.argv.slice(2), env = proces
132
132
  || env.MECHANIC_UPDATE_CHECK === "0") {
133
133
  return false;
134
134
  }
135
- return !argv.some((arg) => arg === "--json" || arg.startsWith("--json="));
135
+ return !argv.some((arg) => (arg === "version"
136
+ || arg === "--json"
137
+ || arg.startsWith("--json=")));
136
138
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightward/mechanic-cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Develop, preview, diff, and publish Mechanic Shopify automation tasks from local files",
5
5
  "type": "module",
6
6
  "keywords": [