@lightward/mechanic-cli 0.1.8 → 0.1.10

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 (55) hide show
  1. package/README.md +34 -7
  2. package/dist/client.d.ts +2 -1
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +4 -0
  5. package/dist/commands/github/init.d.ts.map +1 -1
  6. package/dist/commands/github/init.js +2 -2
  7. package/dist/commands/globals/delete.d.ts +13 -0
  8. package/dist/commands/globals/delete.d.ts.map +1 -0
  9. package/dist/commands/globals/delete.js +28 -0
  10. package/dist/commands/globals/list.d.ts +10 -0
  11. package/dist/commands/globals/list.d.ts.map +1 -0
  12. package/dist/commands/globals/list.js +39 -0
  13. package/dist/commands/globals/pull.d.ts +11 -0
  14. package/dist/commands/globals/pull.d.ts.map +1 -0
  15. package/dist/commands/globals/pull.js +42 -0
  16. package/dist/commands/globals/push.d.ts +11 -0
  17. package/dist/commands/globals/push.d.ts.map +1 -0
  18. package/dist/commands/globals/push.js +57 -0
  19. package/dist/commands/globals/set.d.ts +13 -0
  20. package/dist/commands/globals/set.d.ts.map +1 -0
  21. package/dist/commands/globals/set.js +26 -0
  22. package/dist/commands/init.d.ts.map +1 -1
  23. package/dist/commands/init.js +1 -0
  24. package/dist/commands/secrets/delete.d.ts +13 -0
  25. package/dist/commands/secrets/delete.d.ts.map +1 -0
  26. package/dist/commands/secrets/delete.js +28 -0
  27. package/dist/commands/secrets/list.d.ts +10 -0
  28. package/dist/commands/secrets/list.d.ts.map +1 -0
  29. package/dist/commands/secrets/list.js +37 -0
  30. package/dist/commands/secrets/set.d.ts +25 -0
  31. package/dist/commands/secrets/set.d.ts.map +1 -0
  32. package/dist/commands/secrets/set.js +91 -0
  33. package/dist/commands/shop/deprecations.d.ts +20 -0
  34. package/dist/commands/shop/deprecations.d.ts.map +1 -0
  35. package/dist/commands/shop/deprecations.js +95 -0
  36. package/dist/commands/tasks/diff.d.ts.map +1 -1
  37. package/dist/commands/tasks/diff.js +4 -3
  38. package/dist/commands/tasks/list.d.ts.map +1 -1
  39. package/dist/commands/tasks/list.js +12 -1
  40. package/dist/commands/tasks/new.d.ts.map +1 -1
  41. package/dist/commands/tasks/new.js +10 -2
  42. package/dist/commands/tasks/push.d.ts +2 -1
  43. package/dist/commands/tasks/push.d.ts.map +1 -1
  44. package/dist/commands/tasks/push.js +43 -20
  45. package/dist/commands/tasks/status.d.ts +22 -4
  46. package/dist/commands/tasks/status.d.ts.map +1 -1
  47. package/dist/commands/tasks/status.js +66 -9
  48. package/dist/config-keys.d.ts +2 -0
  49. package/dist/config-keys.d.ts.map +1 -0
  50. package/dist/config-keys.js +8 -0
  51. package/dist/config.d.ts.map +1 -1
  52. package/dist/config.js +34 -3
  53. package/dist/types.d.ts +24 -0
  54. package/dist/types.d.ts.map +1 -1
  55. package/package.json +10 -3
@@ -0,0 +1,91 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import { stdin } from "node:process";
3
+ import { promptForHiddenValue } from "../../auth.js";
4
+ import { BaseCommand } from "../../base-command.js";
5
+ import { validateConfigKey } from "../../config-keys.js";
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
+ }
23
+ export async function readSecretValueFromStdin(input = stdin) {
24
+ const value = await readStdin(input);
25
+ if (value.length === 0) {
26
+ throw new CliError("Secret value cannot be blank.", 2);
27
+ }
28
+ return value;
29
+ }
30
+ export function readSecretValueFromEnv(envName, env = process.env) {
31
+ const value = env[envName];
32
+ if (value === undefined) {
33
+ throw new CliError(`Environment variable ${envName} is not set.`, 2);
34
+ }
35
+ if (value.length === 0) {
36
+ throw new CliError(`Environment variable ${envName} is empty.`, 2);
37
+ }
38
+ return value;
39
+ }
40
+ export default class SecretsSet extends BaseCommand {
41
+ static summary = "Set one shop secret.";
42
+ static description = "Set one write-only shop secret. The secret value is never printed.";
43
+ static args = {
44
+ key: Args.string({ required: true, description: "Secret key, using lower snake-case." }),
45
+ };
46
+ static flags = {
47
+ "from-stdin": Flags.boolean({
48
+ description: "Read the secret value from stdin.",
49
+ exclusive: ["value-env"],
50
+ }),
51
+ force: Flags.boolean({
52
+ char: "f",
53
+ description: "Replace the value when this secret key already exists.",
54
+ }),
55
+ "value-env": Flags.string({
56
+ description: "Read the secret value from the named environment variable.",
57
+ exclusive: ["from-stdin"],
58
+ }),
59
+ };
60
+ async run() {
61
+ const { args, flags } = await this.parse(SecretsSet);
62
+ const key = validateConfigKey(args.key);
63
+ const project = await this.loadProject();
64
+ const client = await this.verifiedClientForProject(project);
65
+ const existing = (await client.listSecrets()).secrets?.some((secret) => secret.key === key);
66
+ if (existing && !flags.force) {
67
+ throw new CliError(`Secret ${key} already exists. Re-run with --force to replace its value.`, 2);
68
+ }
69
+ const value = await this.secretValue(flags);
70
+ await client.setSecret(key, value);
71
+ this.log(`${this.success(existing ? "Replaced" : "Set")} secret ${this.taskName(key)}`);
72
+ }
73
+ async secretValue(flags) {
74
+ if (flags["from-stdin"]) {
75
+ return readSecretValueFromStdin();
76
+ }
77
+ if (flags["value-env"]) {
78
+ return readSecretValueFromEnv(flags["value-env"]);
79
+ }
80
+ const value = await promptForHiddenValue({
81
+ blankMessage: "Secret value cannot be blank.",
82
+ missingInputMessage: "Provide a secret value with --from-stdin or --value-env.",
83
+ prompt: "Secret value: ",
84
+ trim: false,
85
+ });
86
+ if (value === null) {
87
+ throw new CliError("Secret value cannot be blank.", 2);
88
+ }
89
+ return value;
90
+ }
91
+ }
@@ -0,0 +1,20 @@
1
+ import { BaseCommand } from "../../base-command.js";
2
+ import type { Project, ShopDeprecationsResponse } from "../../types.js";
3
+ type ShopDeprecation = ShopDeprecationsResponse["deprecations"][number];
4
+ export default class ShopDeprecations extends BaseCommand {
5
+ static summary: string;
6
+ static description: string;
7
+ static args: {
8
+ task: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
9
+ };
10
+ static flags: {
11
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ };
13
+ run(): Promise<void>;
14
+ taskIdForSelector(project: Project, input: string): Promise<string>;
15
+ deprecationsTable(response: ShopDeprecationsResponse): string[][];
16
+ deprecationCountSummary(response: ShopDeprecationsResponse): string;
17
+ requestSummary(deprecation: ShopDeprecation): string;
18
+ }
19
+ export {};
20
+ //# sourceMappingURL=deprecations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deprecations.d.ts","sourceRoot":"","sources":["../../../src/commands/shop/deprecations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,KAAK,EAAE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAExE,KAAK,eAAe,GAAG,wBAAwB,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAUxE,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,WAAW;IACvD,OAAgB,OAAO,SAA6D;IACpF,OAAgB,WAAW,SAAqH;IAEhJ,OAAgB,IAAI;;MAKlB;IAEF,OAAgB,KAAK;;MAInB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAyCpB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzE,iBAAiB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,EAAE,EAAE;IAcjE,uBAAuB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM;IAOnE,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM;CAcrD"}
@@ -0,0 +1,95 @@
1
+ import { Args, Flags } from "@oclif/core";
2
+ import { BaseCommand } from "../../base-command.js";
3
+ import { CliError } from "../../errors.js";
4
+ import { resolveTaskSelector } from "../../tasks.js";
5
+ function formatCount(value) {
6
+ return typeof value === "number" ? value.toLocaleString() : "--";
7
+ }
8
+ function formatValue(value) {
9
+ return value && value.trim() ? value : "--";
10
+ }
11
+ export default class ShopDeprecations extends BaseCommand {
12
+ static summary = "Show unresolved Shopify API deprecations for this shop.";
13
+ static description = "Show unresolved Shopify API deprecations reported by this shop's tasks, optionally filtered to one linked task.";
14
+ static args = {
15
+ task: Args.string({
16
+ description: "Optional task selector, linked task ID, local slug, task JSON file, or helper directory.",
17
+ required: false,
18
+ }),
19
+ };
20
+ static flags = {
21
+ json: Flags.boolean({
22
+ description: "Print deprecations as JSON for agents, scripts, or editor integrations.",
23
+ }),
24
+ };
25
+ async run() {
26
+ const { args, flags } = await this.parse(ShopDeprecations);
27
+ const project = await this.loadProject();
28
+ const client = await this.verifiedClientForProject(project);
29
+ const taskId = args.task ? await this.taskIdForSelector(project, args.task) : undefined;
30
+ const response = await client.getShopDeprecations(taskId);
31
+ if (flags.json) {
32
+ this.outputJson(response);
33
+ return;
34
+ }
35
+ this.log(`${this.accent("Shop")} ${response.shop.shopify_domain}`);
36
+ if (taskId) {
37
+ this.log(`${this.accent("Task")} ${this.taskId(project, taskId)}`);
38
+ }
39
+ if (response.deprecations.length === 0) {
40
+ this.log("");
41
+ this.log(this.success("No unresolved Shopify API deprecations."));
42
+ return;
43
+ }
44
+ this.log(`${this.accent("Deprecations")} ${this.deprecationCountSummary(response)}`);
45
+ if (response.truncated) {
46
+ const limit = typeof response.limit === "number" ? response.limit.toLocaleString() : response.deprecations.length.toLocaleString();
47
+ this.log(this.color("yellow", `Showing the first ${limit} unresolved deprecations. Filter with "mechanic shop deprecations <task>" for one task.`));
48
+ }
49
+ this.log("");
50
+ this.table(this.deprecationsTable(response));
51
+ this.log("");
52
+ this.log(this.accent("Details"));
53
+ response.deprecations.forEach((deprecation, index) => {
54
+ this.log(`${index + 1}. ${this.taskName(deprecation.task_name || deprecation.task_id)}`);
55
+ this.log(` ${this.muted("Request")} ${this.requestSummary(deprecation)}`);
56
+ this.log(` ${this.muted("Reason")} ${formatValue(deprecation.reason)}`);
57
+ });
58
+ }
59
+ async taskIdForSelector(project, input) {
60
+ const selector = await resolveTaskSelector(project, input, { allowHelperDir: true, allowRemoteId: true });
61
+ if (!selector.remoteId) {
62
+ throw new CliError(`${input} is not linked to a remote Mechanic task. Pull or publish it first.`, 2);
63
+ }
64
+ return selector.remoteId;
65
+ }
66
+ deprecationsTable(response) {
67
+ return [
68
+ ["#", "Task", "Task API", "Request API", "Last seen", "Count"],
69
+ ...response.deprecations.map((deprecation, index) => [
70
+ String(index + 1),
71
+ this.taskName(deprecation.task_name || deprecation.task_id),
72
+ formatValue(deprecation.task_shopify_api_version),
73
+ formatValue(deprecation.shopify_api_version),
74
+ this.muted(formatValue(deprecation.last_occurrence_at)),
75
+ formatCount(deprecation.occurrences_count),
76
+ ]),
77
+ ];
78
+ }
79
+ deprecationCountSummary(response) {
80
+ const shown = response.deprecations.length;
81
+ const total = typeof response.total_count === "number" ? response.total_count : shown;
82
+ return `${shown.toLocaleString()}/${total.toLocaleString()} shown`;
83
+ }
84
+ requestSummary(deprecation) {
85
+ const method = formatValue(deprecation.request_method);
86
+ const path = formatValue(deprecation.request_path);
87
+ if (method === "--") {
88
+ return path;
89
+ }
90
+ if (path === "--") {
91
+ return method;
92
+ }
93
+ return `${method} ${path}`;
94
+ }
95
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/diff.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAapD,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,WAAW;IAChD,OAAgB,OAAO,SAA2D;IAClF,OAAgB,WAAW,SAA6G;IAExI,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;;MAMnB;IAEF,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IA2BzB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAuI3B"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/diff.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAapD,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,WAAW;IAChD,OAAgB,OAAO,SAA2D;IAClF,OAAgB,WAAW,SAA6G;IAExI,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;;MAMnB;IAEF,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IA2BzB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAwI3B"}
@@ -51,6 +51,7 @@ export default class TasksDiff extends BaseCommand {
51
51
  const relativeFile = displayTaskPath(project, file);
52
52
  if (!link) {
53
53
  hasUnlinkedTasks = true;
54
+ const message = `No remote task is linked yet. Run "mechanic tasks publish ${slug} --dry-run" to review the disabled create plan.`;
54
55
  results.push({
55
56
  file: relativeFile,
56
57
  slug,
@@ -59,9 +60,9 @@ export default class TasksDiff extends BaseCommand {
59
60
  remote_changed: false,
60
61
  field_differences: false,
61
62
  diff: null,
62
- message: "Task is not linked to a remote task.",
63
+ message,
63
64
  });
64
- differences.push(`# ${relativeFile}\nTask is not linked to a remote task.`);
65
+ differences.push(`# ${relativeFile}\n${message}`);
65
66
  continue;
66
67
  }
67
68
  const localTask = taskForPush(await readTaskFile(file));
@@ -134,7 +135,7 @@ export default class TasksDiff extends BaseCommand {
134
135
  summary = "Remote changes found.";
135
136
  }
136
137
  else if (!hasFieldDifferences && hasUnlinkedTasks) {
137
- summary = "Unlinked tasks found.";
138
+ summary = "No remote task linked yet.";
138
139
  }
139
140
  this.log(summary);
140
141
  if (flags["exit-code"]) {
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGpD,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,WAAW;IAChD,OAAgB,OAAO,SAAkD;IACzE,OAAgB,WAAW,SAAsF;IAEjH,OAAgB,KAAK;;;MAQnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAgD3B"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAcpD,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,WAAW;IAChD,OAAgB,OAAO,SAAkD;IACzE,OAAgB,WAAW,SAAsF;IAEjH,OAAgB,KAAK;;;MAQnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAoD3B"}
@@ -1,6 +1,13 @@
1
1
  import { Flags } from "@oclif/core";
2
2
  import { BaseCommand } from "../../base-command.js";
3
3
  import { slugForRemoteId } from "../../config.js";
4
+ function taskShopifyApiVersion(envelope) {
5
+ if (typeof envelope.shopify_api_version === "string" && envelope.shopify_api_version.trim()) {
6
+ return envelope.shopify_api_version;
7
+ }
8
+ const version = envelope.task?.shopify_api_version;
9
+ return typeof version === "string" && version.trim() ? version : null;
10
+ }
4
11
  export default class TasksList extends BaseCommand {
5
12
  static summary = "List remote tasks without changing anything.";
6
13
  static description = "List remote Mechanic tasks without pulling, publishing, or changing local files.";
@@ -28,6 +35,7 @@ export default class TasksList extends BaseCommand {
28
35
  id: envelope.id,
29
36
  name: typeof envelope.task?.name === "string" ? envelope.task.name : "",
30
37
  updated_at: envelope.updated_at || null,
38
+ shopify_api_version: taskShopifyApiVersion(envelope),
31
39
  content_hash: envelope.content_hash || null,
32
40
  linked: Boolean(link),
33
41
  slug: slug || null,
@@ -37,13 +45,16 @@ export default class TasksList extends BaseCommand {
37
45
  });
38
46
  return;
39
47
  }
40
- const rows = flags.verbose ? [["Name", "File", "Updated", "ID", "Hash"]] : [["Name", "File", "Updated", "ID"]];
48
+ const rows = flags.verbose
49
+ ? [["Name", "File", "API version", "Updated", "ID", "Hash"]]
50
+ : [["Name", "File", "API version", "Updated", "ID"]];
41
51
  for (const envelope of response.tasks || []) {
42
52
  const slug = slugForRemoteId(project, envelope.id);
43
53
  const link = slug ? project.links.tasks[slug] : null;
44
54
  const row = [
45
55
  this.taskName(String(envelope.task?.name || "")),
46
56
  link ? this.taskName(link.file || `${project.tasksDirName}/${slug}.json`) : this.muted("--"),
57
+ taskShopifyApiVersion(envelope) || this.muted("--"),
47
58
  this.muted(envelope.updated_at || ""),
48
59
  this.taskId(project, envelope.id),
49
60
  ];
@@ -1 +1 @@
1
- {"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/new.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAwCpD,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,WAAW;IAC/C,OAAgB,OAAO,SAAoC;IAC3D,OAAgB,WAAW,SAAiJ;IAC5K,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;MAGnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA0CZ,kBAAkB;CA2BjC"}
1
+ {"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/new.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAyCpD,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,WAAW;IAC/C,OAAgB,OAAO,SAAoC;IAC3D,OAAgB,WAAW,SAAiJ;IAC5K,OAAgB,QAAQ,WAGtB;IAEF,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;MAGnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA0CZ,kBAAkB;CAoCjC"}
@@ -1,6 +1,7 @@
1
1
  import { Args, Flags } from "@oclif/core";
2
2
  import path from "node:path";
3
3
  import { BaseCommand } from "../../base-command.js";
4
+ import { linkForSlug } from "../../config.js";
4
5
  import { CliError } from "../../errors.js";
5
6
  import { pathExists } from "../../fs.js";
6
7
  import { displayTaskPath, taskPath, taskSlug, unbundleTask, writeTaskFilePath } from "../../tasks.js";
@@ -59,7 +60,7 @@ export default class TasksNew extends BaseCommand {
59
60
  const name = taskNameFromInput(requestedName);
60
61
  const filePath = taskPath(project, slug);
61
62
  const helperDir = filePath.replace(/\.json$/i, "");
62
- await this.checkExistingPaths(project, filePath, helperDir, Boolean(flags.force));
63
+ await this.checkExistingPaths(project, slug, filePath, helperDir, Boolean(flags.force));
63
64
  await writeTaskFilePath(filePath, starterTask(name));
64
65
  await unbundleTask(filePath, helperDir);
65
66
  const fileDisplay = displayTaskPath(project, filePath);
@@ -83,7 +84,14 @@ export default class TasksNew extends BaseCommand {
83
84
  this.log(` mechanic tasks bundle ${this.taskName(slug)}`);
84
85
  this.log(` mechanic tasks publish ${this.taskName(slug)}`);
85
86
  }
86
- async checkExistingPaths(project, filePath, helperDir, force) {
87
+ async checkExistingPaths(project, slug, filePath, helperDir, force) {
88
+ const link = linkForSlug(project, slug);
89
+ if (link) {
90
+ throw new CliError([
91
+ `${slug} is already linked to a Mechanic task.`,
92
+ `Run "mechanic tasks pull ${link.remote_id}" to refresh it, or choose another name for a new task.`,
93
+ ].join("\n"), 2);
94
+ }
87
95
  if (force) {
88
96
  return;
89
97
  }
@@ -18,6 +18,7 @@ type PushRow = {
18
18
  task_id: string | null;
19
19
  content_hash: string | null;
20
20
  details: string;
21
+ enabled?: boolean | null;
21
22
  url?: string;
22
23
  };
23
24
  type CreateCollision = {
@@ -55,7 +56,7 @@ export default class TasksPush extends BaseCommand {
55
56
  rows: PushRow[];
56
57
  }>;
57
58
  pushRowsToTable(project: Project, statusHeader: string, rows: PushRow[], label: (status: string) => string): string[][];
58
- printCreatedTaskLinks(rows: PushRow[]): void;
59
+ printPublishedTaskLinks(rows: PushRow[]): void;
59
60
  planLabel(plan: string): string;
60
61
  }
61
62
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/push.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/push.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,25 @@ function createTaskIdempotencyKey(shopDomain, slug) {
18
18
  hex.slice(20, 32),
19
19
  ].join("-");
20
20
  }
21
+ function remoteTaskEnabled(envelope) {
22
+ if (typeof envelope.enabled === "boolean") {
23
+ return envelope.enabled;
24
+ }
25
+ if (typeof envelope.task.enabled === "boolean") {
26
+ return envelope.task.enabled;
27
+ }
28
+ return null;
29
+ }
30
+ function remoteTaskStateDetail(envelope) {
31
+ const enabled = remoteTaskEnabled(envelope);
32
+ if (enabled === true) {
33
+ return "currently enabled";
34
+ }
35
+ if (enabled === false) {
36
+ return "currently disabled";
37
+ }
38
+ return "";
39
+ }
21
40
  export default class TasksPush extends BaseCommand {
22
41
  static hidden = true;
23
42
  static summary = "Publish one local task, or use --all to publish every local task.";
@@ -68,7 +87,7 @@ export default class TasksPush extends BaseCommand {
68
87
  return;
69
88
  }
70
89
  this.table(this.pushRowsToTable(project, "Action", rows, (status) => this.actionLabel(status)));
71
- this.printCreatedTaskLinks(rows);
90
+ this.printPublishedTaskLinks(rows);
72
91
  }
73
92
  async publishTasks(project, preparation, force) {
74
93
  const client = await this.verifiedClientForProject(project);
@@ -91,22 +110,25 @@ export default class TasksPush extends BaseCommand {
91
110
  task_id: created.id,
92
111
  content_hash: created.content_hash,
93
112
  details: "created disabled; enable in Mechanic",
113
+ enabled: remoteTaskEnabled(created),
94
114
  url: taskAdminUrl(project, created.id),
95
115
  });
96
116
  continue;
97
117
  }
98
- if (!force) {
99
- const remote = remoteBySlug.get(slug) || await client.getTask(link.remote_id);
100
- if (stableStringify(task) === stableStringify(taskForPush(remote.task))) {
101
- rows.push({
102
- file: relativeFile,
103
- status: "skipped",
104
- task_id: remote.id,
105
- content_hash: remote.content_hash,
106
- details: "",
107
- });
108
- continue;
109
- }
118
+ const remote = force
119
+ ? await client.getTask(link.remote_id)
120
+ : remoteBySlug.get(slug) || await client.getTask(link.remote_id);
121
+ if (stableStringify(task) === stableStringify(taskForPush(remote.task))) {
122
+ rows.push({
123
+ file: relativeFile,
124
+ status: "skipped",
125
+ task_id: remote.id,
126
+ content_hash: remote.content_hash,
127
+ details: remoteTaskStateDetail(remote),
128
+ enabled: remoteTaskEnabled(remote),
129
+ url: taskAdminUrl(project, remote.id),
130
+ });
131
+ continue;
110
132
  }
111
133
  const updated = await client.updateTask(link.remote_id, {
112
134
  task,
@@ -120,7 +142,8 @@ export default class TasksPush extends BaseCommand {
120
142
  status: force ? "forced" : "updated",
121
143
  task_id: updated.id,
122
144
  content_hash: updated.content_hash,
123
- details: "",
145
+ details: remoteTaskStateDetail(updated),
146
+ enabled: remoteTaskEnabled(updated),
124
147
  url: taskAdminUrl(project, updated.id),
125
148
  });
126
149
  }
@@ -326,7 +349,7 @@ export default class TasksPush extends BaseCommand {
326
349
  status: "conflict",
327
350
  task_id: remote.id,
328
351
  content_hash: remote.content_hash,
329
- details: remoteChangedSinceLastPullDetails(),
352
+ details: remoteChangedSinceLastPullMessage(relativeFile, remote.id, localChangedSinceLastSync(link, task)),
330
353
  });
331
354
  continue;
332
355
  }
@@ -356,14 +379,14 @@ export default class TasksPush extends BaseCommand {
356
379
  ]),
357
380
  ];
358
381
  }
359
- printCreatedTaskLinks(rows) {
360
- const createdRows = rows.filter((row) => row.status === "created" && row.url);
361
- if (createdRows.length === 0) {
382
+ printPublishedTaskLinks(rows) {
383
+ const publishedRows = rows.filter((row) => ["created", "updated", "forced"].includes(row.status) && row.url);
384
+ if (publishedRows.length === 0) {
362
385
  return;
363
386
  }
364
387
  this.log("");
365
- this.log(this.accent(createdRows.length === 1 ? "Open created task:" : "Open created tasks:"));
366
- for (const row of createdRows) {
388
+ this.log(this.accent(publishedRows.length === 1 ? "Open task:" : "Open published tasks:"));
389
+ for (const row of publishedRows) {
367
390
  this.log(` ${this.taskName(row.file)} ${this.taskName(row.url || "")}`);
368
391
  }
369
392
  }
@@ -7,6 +7,25 @@ type HelperStatus = {
7
7
  blocked: boolean;
8
8
  details?: string;
9
9
  };
10
+ type TaskStatusResult = {
11
+ file: string;
12
+ slug: string;
13
+ link: {
14
+ linked: boolean;
15
+ remote_id: string | null;
16
+ };
17
+ local: HelperStatus;
18
+ remote: {
19
+ label: string;
20
+ details?: string;
21
+ task_id?: string;
22
+ task_name?: string;
23
+ updated_at?: string | null;
24
+ enabled?: boolean | null;
25
+ url?: string;
26
+ } | null;
27
+ details: string[];
28
+ };
10
29
  export default class TasksStatus extends BaseCommand {
11
30
  static summary: string;
12
31
  static description: string;
@@ -19,12 +38,11 @@ export default class TasksStatus extends BaseCommand {
19
38
  };
20
39
  run(): Promise<void>;
21
40
  helperStatus(project: Project, file: string, task: JsonObject): Promise<HelperStatus>;
22
- remoteStatus(client: MechanicClient | null, task: JsonObject, link: ReturnType<typeof linkForSlug>): Promise<{
23
- label: string;
24
- details?: string;
25
- }>;
41
+ remoteStatus(project: Project, client: MechanicClient | null, task: JsonObject, link: ReturnType<typeof linkForSlug>, relativeFile: string): Promise<TaskStatusResult["remote"]>;
42
+ printSingleTaskInfo(project: Project, statuses: TaskStatusResult[], checkRemote: boolean): void;
26
43
  localLabel(label: string): string;
27
44
  remoteLabel(label: string): string;
45
+ enabledLabel(enabled: boolean | null | undefined): string;
28
46
  }
29
47
  export {};
30
48
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/status.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAe9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAE1D,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAuBF,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,OAAgB,OAAO,SAAwE;IAC/F,OAAgB,WAAW,SAA+Q;IAE1S,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;MAOnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAsHpB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IA4BrF,YAAY,CAChB,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,GACnC,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAsB/C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAejC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAgBnC"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/tasks/status.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAgB,MAAM,iBAAiB,CAAC;AAgB5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAgB,MAAM,gBAAgB,CAAC;AAExE,KAAK,YAAY,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE;QACJ,MAAM,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,CAAC;IACF,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QACzB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AA0BF,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW;IAClD,OAAgB,OAAO,SAAwE;IAC/F,OAAgB,WAAW,SAA+Q;IAE1S,OAAgB,IAAI;;MAElB;IAEF,OAAgB,KAAK;;;MAOnB;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAuHpB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IA4BrF,YAAY,CAChB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,cAAc,GAAG,IAAI,EAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,EACpC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAiCtC,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,EAAE,WAAW,EAAE,OAAO,GAAG,IAAI;IAwB/F,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAejC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAmBlC,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM;CAW1D"}