ima2-gen 1.1.9 → 1.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 (204) hide show
  1. package/README.md +4 -0
  2. package/bin/commands/annotate.js +5 -3
  3. package/bin/commands/annotate.ts +13 -12
  4. package/bin/commands/cancel.js +5 -2
  5. package/bin/commands/cancel.ts +6 -3
  6. package/bin/commands/canvas-versions.js +4 -4
  7. package/bin/commands/canvas-versions.ts +10 -10
  8. package/bin/commands/cardnews.js +3 -1
  9. package/bin/commands/cardnews.ts +18 -17
  10. package/bin/commands/comfy.js +2 -2
  11. package/bin/commands/comfy.ts +4 -4
  12. package/bin/commands/config.ts +6 -6
  13. package/bin/commands/edit.js +11 -8
  14. package/bin/commands/edit.ts +12 -9
  15. package/bin/commands/gen.js +16 -13
  16. package/bin/commands/gen.ts +20 -17
  17. package/bin/commands/history.js +2 -1
  18. package/bin/commands/history.ts +11 -10
  19. package/bin/commands/ls.js +7 -4
  20. package/bin/commands/ls.ts +13 -10
  21. package/bin/commands/metadata.js +4 -1
  22. package/bin/commands/metadata.ts +5 -2
  23. package/bin/commands/multimode.js +4 -4
  24. package/bin/commands/multimode.ts +5 -6
  25. package/bin/commands/node.js +7 -7
  26. package/bin/commands/node.ts +14 -14
  27. package/bin/commands/observability.js +6 -6
  28. package/bin/commands/observability.ts +20 -20
  29. package/bin/commands/ping.js +4 -2
  30. package/bin/commands/ping.ts +5 -3
  31. package/bin/commands/prompt.js +14 -11
  32. package/bin/commands/prompt.ts +40 -38
  33. package/bin/commands/ps.js +9 -6
  34. package/bin/commands/ps.ts +14 -11
  35. package/bin/commands/session.js +4 -3
  36. package/bin/commands/session.ts +23 -22
  37. package/bin/commands/show.js +5 -2
  38. package/bin/commands/show.ts +8 -5
  39. package/bin/ima2.js +4 -4
  40. package/bin/ima2.ts +6 -6
  41. package/bin/lib/args.ts +20 -1
  42. package/bin/lib/client.ts +20 -7
  43. package/bin/lib/error-hints.ts +3 -3
  44. package/bin/lib/files.ts +8 -8
  45. package/bin/lib/output.js +19 -17
  46. package/bin/lib/output.ts +38 -23
  47. package/bin/lib/platform.js +3 -1
  48. package/bin/lib/platform.ts +9 -7
  49. package/bin/lib/star-prompt.ts +1 -1
  50. package/bin/lib/storage-doctor.ts +3 -2
  51. package/config.js +1 -1
  52. package/config.ts +8 -6
  53. package/docs/migration/runtime-test-inventory.md +135 -0
  54. package/lib/assetLifecycle.ts +8 -8
  55. package/lib/canvasVersionStore.ts +52 -12
  56. package/lib/cardNewsGenerator.js +7 -3
  57. package/lib/cardNewsGenerator.ts +117 -14
  58. package/lib/cardNewsJobStore.ts +47 -12
  59. package/lib/cardNewsManifestStore.js +13 -6
  60. package/lib/cardNewsManifestStore.ts +56 -14
  61. package/lib/cardNewsPlanner.js +11 -9
  62. package/lib/cardNewsPlanner.ts +86 -30
  63. package/lib/cardNewsPlannerClient.js +23 -10
  64. package/lib/cardNewsPlannerClient.ts +58 -17
  65. package/lib/cardNewsPlannerSchema.js +43 -36
  66. package/lib/cardNewsPlannerSchema.ts +120 -58
  67. package/lib/cardNewsTemplateStore.js +20 -35
  68. package/lib/cardNewsTemplateStore.ts +100 -58
  69. package/lib/codexDetect.js +5 -3
  70. package/lib/codexDetect.ts +5 -3
  71. package/lib/comfyBridge.js +3 -1
  72. package/lib/comfyBridge.ts +37 -16
  73. package/lib/db.ts +5 -5
  74. package/lib/errInfo.js +32 -0
  75. package/lib/errInfo.ts +43 -0
  76. package/lib/errorClassify.ts +2 -2
  77. package/lib/generationErrors.ts +37 -11
  78. package/lib/historyList.js +10 -6
  79. package/lib/historyList.ts +17 -13
  80. package/lib/imageMetadata.js +1 -1
  81. package/lib/imageMetadata.ts +8 -8
  82. package/lib/imageMetadataStore.ts +6 -6
  83. package/lib/imageModels.ts +6 -4
  84. package/lib/inflight.js +1 -8
  85. package/lib/inflight.ts +59 -16
  86. package/lib/localImportStore.ts +6 -5
  87. package/lib/logger.js +7 -5
  88. package/lib/logger.ts +34 -23
  89. package/lib/nodeStore.ts +18 -10
  90. package/lib/oauthLauncher.js +2 -2
  91. package/lib/oauthLauncher.ts +7 -6
  92. package/lib/oauthNormalize.ts +1 -1
  93. package/lib/oauthProxy/errors.js +93 -0
  94. package/lib/oauthProxy/errors.ts +128 -0
  95. package/lib/oauthProxy/generators.js +426 -0
  96. package/lib/oauthProxy/generators.ts +494 -0
  97. package/lib/oauthProxy/index.js +8 -0
  98. package/lib/oauthProxy/index.ts +28 -0
  99. package/lib/oauthProxy/prompts.js +84 -0
  100. package/lib/oauthProxy/prompts.ts +108 -0
  101. package/lib/oauthProxy/references.js +32 -0
  102. package/lib/oauthProxy/references.ts +45 -0
  103. package/lib/oauthProxy/runtime.js +101 -0
  104. package/lib/oauthProxy/runtime.ts +115 -0
  105. package/lib/oauthProxy/streams.js +211 -0
  106. package/lib/oauthProxy/streams.ts +232 -0
  107. package/lib/oauthProxy/types.js +6 -0
  108. package/lib/oauthProxy/types.ts +9 -0
  109. package/lib/oauthProxy.js +3 -911
  110. package/lib/oauthProxy.ts +3 -995
  111. package/lib/openDirectory.js +4 -2
  112. package/lib/openDirectory.ts +8 -6
  113. package/lib/pngInfo.ts +2 -2
  114. package/lib/promptImport/curatedSources.ts +4 -2
  115. package/lib/promptImport/discoveryRegistry.js +17 -9
  116. package/lib/promptImport/discoveryRegistry.ts +121 -28
  117. package/lib/promptImport/errors.ts +6 -6
  118. package/lib/promptImport/githubDiscovery.js +13 -7
  119. package/lib/promptImport/githubDiscovery.ts +84 -23
  120. package/lib/promptImport/githubFolder.js +22 -14
  121. package/lib/promptImport/githubFolder.ts +130 -41
  122. package/lib/promptImport/githubSource.js +3 -1
  123. package/lib/promptImport/githubSource.ts +32 -14
  124. package/lib/promptImport/gptImageHints.ts +10 -8
  125. package/lib/promptImport/parsePromptCandidates.js +2 -0
  126. package/lib/promptImport/parsePromptCandidates.ts +43 -17
  127. package/lib/promptImport/promptIndex.js +33 -23
  128. package/lib/promptImport/promptIndex.ts +124 -46
  129. package/lib/promptImport/rankPromptCandidates.js +2 -2
  130. package/lib/promptImport/rankPromptCandidates.ts +22 -6
  131. package/lib/promptImport/types.js +1 -0
  132. package/lib/promptImport/types.ts +103 -0
  133. package/lib/promptSafetyPolicy.js +5 -0
  134. package/lib/promptSafetyPolicy.ts +5 -0
  135. package/lib/providerOptions.ts +3 -2
  136. package/lib/referenceImageCompress.ts +15 -6
  137. package/lib/refs.js +2 -0
  138. package/lib/refs.ts +27 -11
  139. package/lib/requestLogger.ts +4 -3
  140. package/lib/responsesImageAdapter.js +16 -10
  141. package/lib/responsesImageAdapter.ts +109 -31
  142. package/lib/runtimeContext.js +100 -0
  143. package/lib/runtimeContext.ts +131 -0
  144. package/lib/runtimePorts.js +2 -1
  145. package/lib/runtimePorts.ts +28 -16
  146. package/lib/sessionStore.js +7 -5
  147. package/lib/sessionStore.ts +73 -37
  148. package/lib/storageMigration.js +18 -11
  149. package/lib/storageMigration.ts +63 -37
  150. package/lib/styleSheet.js +7 -6
  151. package/lib/styleSheet.ts +34 -23
  152. package/package.json +4 -2
  153. package/routes/annotations.js +9 -4
  154. package/routes/annotations.ts +35 -12
  155. package/routes/canvasVersions.js +8 -3
  156. package/routes/canvasVersions.ts +14 -9
  157. package/routes/cardNews.js +31 -18
  158. package/routes/cardNews.ts +66 -38
  159. package/routes/comfy.js +6 -3
  160. package/routes/comfy.ts +10 -6
  161. package/routes/edit.js +9 -5
  162. package/routes/edit.ts +30 -10
  163. package/routes/generate.js +33 -21
  164. package/routes/generate.ts +43 -29
  165. package/routes/health.js +7 -3
  166. package/routes/health.ts +15 -10
  167. package/routes/history.js +29 -14
  168. package/routes/history.ts +41 -23
  169. package/routes/imageImport.js +6 -2
  170. package/routes/imageImport.ts +9 -5
  171. package/routes/index.js +3 -1
  172. package/routes/index.ts +4 -1
  173. package/routes/metadata.js +9 -4
  174. package/routes/metadata.ts +13 -7
  175. package/routes/multimode.js +17 -11
  176. package/routes/multimode.ts +40 -19
  177. package/routes/nodes.js +30 -20
  178. package/routes/nodes.ts +73 -34
  179. package/routes/promptImport.js +42 -36
  180. package/routes/promptImport.ts +89 -64
  181. package/routes/prompts.js +62 -39
  182. package/routes/prompts.ts +120 -71
  183. package/routes/sessions.js +46 -24
  184. package/routes/sessions.ts +60 -35
  185. package/routes/storage.js +4 -2
  186. package/routes/storage.ts +13 -5
  187. package/server.js +25 -21
  188. package/server.ts +57 -37
  189. package/ui/dist/.vite/manifest.json +11 -10
  190. package/ui/dist/assets/{CardNewsWorkspace-BJOCey7Z.js → CardNewsWorkspace-C9Cpxuxc.js} +1 -1
  191. package/ui/dist/assets/{NodeCanvas-C3dzYNsk.js → NodeCanvas-BllpfcQW.js} +1 -1
  192. package/ui/dist/assets/{PromptImportDialog-Dqu1VpUh.js → PromptImportDialog-D8EMO--u.js} +2 -2
  193. package/ui/dist/assets/{PromptImportDiscoverySection-Dg8T9X0L.js → PromptImportDiscoverySection-BB2FrKuq.js} +1 -1
  194. package/ui/dist/assets/{PromptImportFolderSection-DBaqsFO4.js → PromptImportFolderSection-aVteBUcb.js} +1 -1
  195. package/ui/dist/assets/PromptLibraryPanel-Z-4B8RSs.js +2 -0
  196. package/ui/dist/assets/SettingsWorkspace-DBYdgpPI.js +1 -0
  197. package/ui/dist/assets/index-B2TDuGqy.css +1 -0
  198. package/ui/dist/assets/index-DFlbOIxI.js +25 -0
  199. package/ui/dist/assets/{index-Cvld7dUZ.js → index-Deo5wBiA.js} +1 -1
  200. package/ui/dist/index.html +2 -2
  201. package/ui/dist/assets/PromptLibraryPanel-p5QqR97M.js +0 -2
  202. package/ui/dist/assets/SettingsWorkspace-B5bSAZ6u.js +0 -1
  203. package/ui/dist/assets/index-C9cXwiWE.js +0 -25
  204. package/ui/dist/assets/index-CGMIkZXn.css +0 -1
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # ima2-gen
2
2
 
3
+ <p align="center">
4
+ <img src="assets/logo.png" alt="ima2-gen logo" width="240">
5
+ </p>
6
+
3
7
  [![npm version](https://img.shields.io/npm/v/ima2-gen)](https://www.npmjs.com/package/ima2-gen)
4
8
  [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org/)
5
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
@@ -31,6 +31,8 @@ async function getServer(args) {
31
31
  async function resolveBody(value) {
32
32
  if (!value)
33
33
  return null;
34
+ if (typeof value !== "string")
35
+ return null;
34
36
  let text;
35
37
  if (value === "-")
36
38
  text = await readStdin();
@@ -72,7 +74,7 @@ async function getSub(argv) {
72
74
  const browserId = getCliBrowserId();
73
75
  const resp = await request(server.base, `/api/annotations/${encodeURIComponent(filename)}`, {
74
76
  headers: { "X-Ima2-Browser-Id": browserId },
75
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
77
+ }).catch((e) => { const err = e; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
76
78
  json(resp);
77
79
  }
78
80
  async function setSub(argv) {
@@ -89,7 +91,7 @@ async function setSub(argv) {
89
91
  method: "PUT",
90
92
  body,
91
93
  headers: { "X-Ima2-Browser-Id": browserId },
92
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
94
+ }).catch((e) => { const err = e; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
93
95
  if (args.json) {
94
96
  json(resp);
95
97
  return;
@@ -116,7 +118,7 @@ async function rmSub(argv) {
116
118
  await request(server.base, `/api/annotations/${encodeURIComponent(filename)}`, {
117
119
  method: "DELETE",
118
120
  headers: { "X-Ima2-Browser-Id": browserId },
119
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
121
+ }).catch((e) => { const err = e; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
120
122
  out(color.green("✓ deleted"));
121
123
  }
122
124
  const SUB = {
@@ -1,5 +1,5 @@
1
1
  import { readFile } from "fs/promises";
2
- import { parseArgs } from "../lib/args.js";
2
+ import { parseArgs, type ParsedArgs } from "../lib/args.js";
3
3
  import { resolveServer, request } from "../lib/client.js";
4
4
  import { readStdin } from "../lib/files.js";
5
5
  import { out, die, color, json, exitCodeForError } from "../lib/output.js";
@@ -22,14 +22,15 @@ const FLAGS = {
22
22
  help: { short: "h", type: "boolean" },
23
23
  };
24
24
 
25
- async function getServer(args) {
25
+ async function getServer(args: ParsedArgs) {
26
26
  try { return await resolveServer({ serverFlag: args.server }); }
27
27
  catch (e: any) { die(exitCodeForError(e), e.message); throw e; }
28
28
  }
29
29
 
30
- async function resolveBody(value): Promise<any> {
30
+ async function resolveBody(value: unknown): Promise<any> {
31
31
  if (!value) return null;
32
- let text;
32
+ if (typeof value !== "string") return null;
33
+ let text: string;
33
34
  if (value === "-") text = await readStdin();
34
35
  else if (value.startsWith("@")) text = await readFile(value.slice(1), "utf-8");
35
36
  else text = value;
@@ -41,7 +42,7 @@ async function readLine(): Promise<string> {
41
42
  return new Promise((resolve) => {
42
43
  let buf = "";
43
44
  process.stdin.setEncoding("utf-8");
44
- const onData = (chunk) => {
45
+ const onData = (chunk: Buffer | string) => {
45
46
  buf += chunk;
46
47
  const nl = buf.indexOf("\n");
47
48
  if (nl !== -1) {
@@ -55,7 +56,7 @@ async function readLine(): Promise<string> {
55
56
  });
56
57
  }
57
58
 
58
- async function getSub(argv) {
59
+ async function getSub(argv: string[]) {
59
60
  const args = parseArgs(argv, { flags: FLAGS });
60
61
  const filename = args.positional[0];
61
62
  if (!filename) die(2, "filename required");
@@ -63,11 +64,11 @@ async function getSub(argv) {
63
64
  const browserId = getCliBrowserId();
64
65
  const resp = await request(server.base, `/api/annotations/${encodeURIComponent(filename)}`, {
65
66
  headers: { "X-Ima2-Browser-Id": browserId },
66
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
67
+ }).catch((e: unknown) => { const err = e as { message?: string; code?: string }; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
67
68
  json(resp);
68
69
  }
69
70
 
70
- async function setSub(argv) {
71
+ async function setSub(argv: string[]) {
71
72
  const args = parseArgs(argv, { flags: FLAGS });
72
73
  const filename = args.positional[0];
73
74
  if (!filename) die(2, "filename required");
@@ -79,12 +80,12 @@ async function setSub(argv) {
79
80
  method: "PUT",
80
81
  body,
81
82
  headers: { "X-Ima2-Browser-Id": browserId },
82
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
83
+ }).catch((e: unknown) => { const err = e as { message?: string; code?: string }; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
83
84
  if (args.json) { json(resp); return; }
84
85
  out(color.green("✓ annotation saved"));
85
86
  }
86
87
 
87
- async function rmSub(argv) {
88
+ async function rmSub(argv: string[]) {
88
89
  const args = parseArgs(argv, { flags: FLAGS });
89
90
  const filename = args.positional[0];
90
91
  if (!filename) die(2, "filename required");
@@ -99,7 +100,7 @@ async function rmSub(argv) {
99
100
  await request(server.base, `/api/annotations/${encodeURIComponent(filename)}`, {
100
101
  method: "DELETE",
101
102
  headers: { "X-Ima2-Browser-Id": browserId },
102
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
103
+ }).catch((e: unknown) => { const err = e as { message?: string; code?: string }; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
103
104
  out(color.green("✓ deleted"));
104
105
  }
105
106
 
@@ -109,7 +110,7 @@ const SUB: Record<string, (argv: any[]) => Promise<void>> = {
109
110
  rm: rmSub,
110
111
  };
111
112
 
112
- export default async function annotateCmd(argv) {
113
+ export default async function annotateCmd(argv: string[]) {
113
114
  const sub = argv[0];
114
115
  if (!sub || sub === "--help" || sub === "-h") { out(HELP); return; }
115
116
  const handler = SUB[sub];
@@ -1,6 +1,7 @@
1
1
  import { parseArgs } from "../lib/args.js";
2
2
  import { resolveServer, request } from "../lib/client.js";
3
3
  import { out, die, dieWithError, color, json } from "../lib/output.js";
4
+ import { errInfo } from "../../lib/errInfo.js";
4
5
  const SPEC = {
5
6
  flags: {
6
7
  json: { type: "boolean" },
@@ -27,8 +28,9 @@ export default async function cancelCmd(argv) {
27
28
  server = await resolveServer({ serverFlag: args.server });
28
29
  }
29
30
  catch (e) {
31
+ const err = errInfo(e);
30
32
  if (args.json)
31
- json({ ok: false, requestId, error: e.message, code: e.code, status: e.status });
33
+ json({ ok: false, requestId, error: err.message, code: err.code, status: err.status });
32
34
  dieWithError(e);
33
35
  }
34
36
  try {
@@ -38,8 +40,9 @@ export default async function cancelCmd(argv) {
38
40
  });
39
41
  }
40
42
  catch (e) {
43
+ const err = errInfo(e);
41
44
  if (args.json)
42
- json({ ok: false, requestId, error: e.message, code: e.code, status: e.status });
45
+ json({ ok: false, requestId, error: err.message, code: err.code, status: err.status });
43
46
  dieWithError(e);
44
47
  }
45
48
  if (args.json)
@@ -2,6 +2,7 @@ import { parseArgs } from "../lib/args.js";
2
2
  import { resolveServer, request } from "../lib/client.js";
3
3
  import { out, die, dieWithError, color, json } from "../lib/output.js";
4
4
 
5
+ import { errInfo } from "../../lib/errInfo.js";
5
6
  const SPEC = {
6
7
  flags: {
7
8
  json: { type: "boolean" },
@@ -16,7 +17,7 @@ const HELP = `
16
17
  Mark an in-flight job as canceled in the local ima2 server registry.
17
18
  `;
18
19
 
19
- export default async function cancelCmd(argv) {
20
+ export default async function cancelCmd(argv: string[]) {
20
21
  const args = parseArgs(argv, SPEC);
21
22
  if (args.help) { out(HELP); return; }
22
23
 
@@ -26,7 +27,8 @@ export default async function cancelCmd(argv) {
26
27
  let server;
27
28
  try { server = await resolveServer({ serverFlag: args.server }); }
28
29
  catch (e) {
29
- if (args.json) json({ ok: false, requestId, error: e.message, code: e.code, status: e.status });
30
+ const err = errInfo(e);
31
+ if (args.json) json({ ok: false, requestId, error: err.message, code: err.code, status: err.status });
30
32
  dieWithError(e);
31
33
  }
32
34
 
@@ -36,7 +38,8 @@ export default async function cancelCmd(argv) {
36
38
  timeoutMs: 30_000,
37
39
  });
38
40
  } catch (e) {
39
- if (args.json) json({ ok: false, requestId, error: e.message, code: e.code, status: e.status });
41
+ const err = errInfo(e);
42
+ if (args.json) json({ ok: false, requestId, error: err.message, code: err.code, status: err.status });
40
43
  dieWithError(e);
41
44
  }
42
45
 
@@ -31,9 +31,9 @@ async function getServer(args) {
31
31
  function buildHeaders(args) {
32
32
  const h = { "Content-Type": "image/png" };
33
33
  if (args.source)
34
- h["X-Ima2-Canvas-Source-Filename"] = args.source;
34
+ h["X-Ima2-Canvas-Source-Filename"] = String(args.source);
35
35
  if (args.prompt)
36
- h["X-Ima2-Canvas-Prompt"] = args.prompt;
36
+ h["X-Ima2-Canvas-Prompt"] = String(args.prompt);
37
37
  return h;
38
38
  }
39
39
  async function saveSub(argv) {
@@ -48,7 +48,7 @@ async function saveSub(argv) {
48
48
  body: buf,
49
49
  raw: true,
50
50
  headers: buildHeaders(args),
51
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
51
+ }).catch((e) => { const err = e; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
52
52
  if (args.json) {
53
53
  json(resp);
54
54
  return;
@@ -67,7 +67,7 @@ async function updateSub(argv) {
67
67
  body: buf,
68
68
  raw: true,
69
69
  headers: buildHeaders(args),
70
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
70
+ }).catch((e) => { const err = e; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
71
71
  if (args.json) {
72
72
  json(resp);
73
73
  return;
@@ -1,5 +1,5 @@
1
1
  import { readFile } from "fs/promises";
2
- import { parseArgs } from "../lib/args.js";
2
+ import { parseArgs, type ParsedArgs } from "../lib/args.js";
3
3
  import { resolveServer, request } from "../lib/client.js";
4
4
  import { out, die, color, json, exitCodeForError } from "../lib/output.js";
5
5
 
@@ -22,19 +22,19 @@ const FLAGS = {
22
22
  help: { short: "h", type: "boolean" },
23
23
  };
24
24
 
25
- async function getServer(args) {
25
+ async function getServer(args: ParsedArgs) {
26
26
  try { return await resolveServer({ serverFlag: args.server }); }
27
27
  catch (e: any) { die(exitCodeForError(e), e.message); throw e; }
28
28
  }
29
29
 
30
- function buildHeaders(args) {
30
+ function buildHeaders(args: ParsedArgs) {
31
31
  const h: Record<string, string> = { "Content-Type": "image/png" };
32
- if (args.source) h["X-Ima2-Canvas-Source-Filename"] = args.source;
33
- if (args.prompt) h["X-Ima2-Canvas-Prompt"] = args.prompt;
32
+ if (args.source) h["X-Ima2-Canvas-Source-Filename"] = String(args.source);
33
+ if (args.prompt) h["X-Ima2-Canvas-Prompt"] = String(args.prompt);
34
34
  return h;
35
35
  }
36
36
 
37
- async function saveSub(argv) {
37
+ async function saveSub(argv: string[]) {
38
38
  const args = parseArgs(argv, { flags: FLAGS });
39
39
  const file = args.positional[0];
40
40
  if (!file) die(2, "image file required");
@@ -45,12 +45,12 @@ async function saveSub(argv) {
45
45
  body: buf,
46
46
  raw: true,
47
47
  headers: buildHeaders(args),
48
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
48
+ }).catch((e: unknown) => { const err = e as { message?: string; code?: string }; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
49
49
  if (args.json) { json(resp); return; }
50
50
  out(color.green("✓ saved canvas version"));
51
51
  }
52
52
 
53
- async function updateSub(argv) {
53
+ async function updateSub(argv: string[]) {
54
54
  const args = parseArgs(argv, { flags: FLAGS });
55
55
  const [filename, file] = args.positional;
56
56
  if (!filename || !file) die(2, "usage: canvas-versions update <filename> <imagefile>");
@@ -61,7 +61,7 @@ async function updateSub(argv) {
61
61
  body: buf,
62
62
  raw: true,
63
63
  headers: buildHeaders(args),
64
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
64
+ }).catch((e: unknown) => { const err = e as { message?: string; code?: string }; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
65
65
  if (args.json) { json(resp); return; }
66
66
  out(color.green("✓ updated"));
67
67
  }
@@ -71,7 +71,7 @@ const SUB: Record<string, (argv: any[]) => Promise<void>> = {
71
71
  update: updateSub,
72
72
  };
73
73
 
74
- export default async function canvasVersionsCmd(argv) {
74
+ export default async function canvasVersionsCmd(argv: string[]) {
75
75
  const sub = argv[0];
76
76
  if (!sub || sub === "--help" || sub === "-h") { out(HELP); return; }
77
77
  const handler = SUB[sub];
@@ -51,6 +51,8 @@ async function getServer(args) {
51
51
  function parseData(raw) {
52
52
  if (!raw)
53
53
  return {};
54
+ if (typeof raw !== "string")
55
+ return {};
54
56
  try {
55
57
  return JSON.parse(raw);
56
58
  }
@@ -201,7 +203,7 @@ async function jobRetrySub(argv) {
201
203
  const server = await getServer(args);
202
204
  const body = {};
203
205
  if (args.cards)
204
- body.cardIds = args.cards.split(",").map((s) => s.trim()).filter(Boolean);
206
+ body.cardIds = String(args.cards).split(",").map((s) => s.trim()).filter(Boolean);
205
207
  const resp = await request(server.base, `/api/cardnews/jobs/${encodeURIComponent(jobId)}/retry`, { method: "POST", body })
206
208
  .catch((e) => die(exitCodeForError(e), e.message));
207
209
  if (args.json) {
@@ -1,4 +1,4 @@
1
- import { parseArgs } from "../lib/args.js";
1
+ import { parseArgs, type ParsedArgs } from "../lib/args.js";
2
2
  import { resolveServer, request } from "../lib/client.js";
3
3
  import { out, die, color, json, exitCodeForError } from "../lib/output.js";
4
4
  import { config as runtimeConfig } from "../../config.js";
@@ -43,18 +43,19 @@ function ensureCardNewsEnabled() {
43
43
  }
44
44
  }
45
45
 
46
- async function getServer(args) {
46
+ async function getServer(args: ParsedArgs) {
47
47
  try { return await resolveServer({ serverFlag: args.server }); }
48
48
  catch (e: any) { die(exitCodeForError(e), e.message); throw e; }
49
49
  }
50
50
 
51
- function parseData(raw: string | undefined): any {
51
+ function parseData(raw: unknown): any {
52
52
  if (!raw) return {};
53
+ if (typeof raw !== "string") return {};
53
54
  try { return JSON.parse(raw); }
54
55
  catch { die(2, `--data must be valid JSON`); }
55
56
  }
56
57
 
57
- async function templatesSub(argv) {
58
+ async function templatesSub(argv: string[]) {
58
59
  const args = parseArgs(argv, { flags: FLAGS });
59
60
  if (args.help) { out(HELP); return; }
60
61
  ensureCardNewsEnabled();
@@ -72,7 +73,7 @@ async function templatesSub(argv) {
72
73
  out(JSON.stringify(roleTemplates, null, 2));
73
74
  }
74
75
 
75
- async function templatePreviewSub(argv) {
76
+ async function templatePreviewSub(argv: string[]) {
76
77
  const args = parseArgs(argv, { flags: FLAGS });
77
78
  const templateId = args.positional[0];
78
79
  if (!templateId) die(2, "templateId required");
@@ -84,7 +85,7 @@ async function templatePreviewSub(argv) {
84
85
  out(JSON.stringify(resp, null, 2));
85
86
  }
86
87
 
87
- async function setsSub(argv) {
88
+ async function setsSub(argv: string[]) {
88
89
  const args = parseArgs(argv, { flags: FLAGS });
89
90
  ensureCardNewsEnabled();
90
91
  const server = await getServer(args);
@@ -94,7 +95,7 @@ async function setsSub(argv) {
94
95
  out(JSON.stringify(resp, null, 2));
95
96
  }
96
97
 
97
- async function setShowSub(argv) {
98
+ async function setShowSub(argv: string[]) {
98
99
  const args = parseArgs(argv, { flags: FLAGS });
99
100
  const setId = args.positional[0];
100
101
  if (!setId) die(2, "setId required");
@@ -106,7 +107,7 @@ async function setShowSub(argv) {
106
107
  out(JSON.stringify(resp, null, 2));
107
108
  }
108
109
 
109
- async function setManifestSub(argv) {
110
+ async function setManifestSub(argv: string[]) {
110
111
  const args = parseArgs(argv, { flags: FLAGS });
111
112
  const setId = args.positional[0];
112
113
  if (!setId) die(2, "setId required");
@@ -118,7 +119,7 @@ async function setManifestSub(argv) {
118
119
  out(JSON.stringify(resp, null, 2));
119
120
  }
120
121
 
121
- async function draftSub(argv) {
122
+ async function draftSub(argv: string[]) {
122
123
  const args = parseArgs(argv, { flags: FLAGS });
123
124
  ensureCardNewsEnabled();
124
125
  const server = await getServer(args);
@@ -129,7 +130,7 @@ async function draftSub(argv) {
129
130
  out(JSON.stringify(resp, null, 2));
130
131
  }
131
132
 
132
- async function generateSub(argv) {
133
+ async function generateSub(argv: string[]) {
133
134
  const args = parseArgs(argv, { flags: FLAGS });
134
135
  ensureCardNewsEnabled();
135
136
  const server = await getServer(args);
@@ -140,7 +141,7 @@ async function generateSub(argv) {
140
141
  out(JSON.stringify(resp, null, 2));
141
142
  }
142
143
 
143
- async function jobCreateSub(argv) {
144
+ async function jobCreateSub(argv: string[]) {
144
145
  const args = parseArgs(argv, { flags: FLAGS });
145
146
  ensureCardNewsEnabled();
146
147
  const server = await getServer(args);
@@ -151,7 +152,7 @@ async function jobCreateSub(argv) {
151
152
  out(JSON.stringify(resp, null, 2));
152
153
  }
153
154
 
154
- async function jobShowSub(argv) {
155
+ async function jobShowSub(argv: string[]) {
155
156
  const args = parseArgs(argv, { flags: FLAGS });
156
157
  const jobId = args.positional[0];
157
158
  if (!jobId) die(2, "jobId required");
@@ -163,14 +164,14 @@ async function jobShowSub(argv) {
163
164
  out(JSON.stringify(resp, null, 2));
164
165
  }
165
166
 
166
- async function jobRetrySub(argv) {
167
+ async function jobRetrySub(argv: string[]) {
167
168
  const args = parseArgs(argv, { flags: FLAGS });
168
169
  const jobId = args.positional[0];
169
170
  if (!jobId) die(2, "jobId required");
170
171
  ensureCardNewsEnabled();
171
172
  const server = await getServer(args);
172
173
  const body: any = {};
173
- if (args.cards) body.cardIds = args.cards.split(",").map((s) => s.trim()).filter(Boolean);
174
+ if (args.cards) body.cardIds = String(args.cards).split(",").map((s: string) => s.trim()).filter(Boolean);
174
175
  const resp = await request(server.base, `/api/cardnews/jobs/${encodeURIComponent(jobId)}/retry`, { method: "POST", body })
175
176
  .catch((e) => die(exitCodeForError(e), e.message));
176
177
  if (args.json) { json(resp); return; }
@@ -178,7 +179,7 @@ async function jobRetrySub(argv) {
178
179
  if (resp && typeof resp === "object" && Object.keys(resp).length > 0) out(JSON.stringify(resp, null, 2));
179
180
  }
180
181
 
181
- async function cardRegenerateSub(argv) {
182
+ async function cardRegenerateSub(argv: string[]) {
182
183
  const args = parseArgs(argv, { flags: FLAGS });
183
184
  const cardId = args.positional[0];
184
185
  if (!cardId) die(2, "cardId required");
@@ -192,7 +193,7 @@ async function cardRegenerateSub(argv) {
192
193
  if (resp && typeof resp === "object" && Object.keys(resp).length > 0) out(JSON.stringify(resp, null, 2));
193
194
  }
194
195
 
195
- async function exportSub(argv) {
196
+ async function exportSub(argv: string[]) {
196
197
  const args = parseArgs(argv, { flags: FLAGS });
197
198
  ensureCardNewsEnabled();
198
199
  const server = await getServer(args);
@@ -206,7 +207,7 @@ async function exportSub(argv) {
206
207
 
207
208
  type Sub = (argv: any[]) => Promise<void>;
208
209
 
209
- export default async function cardnewsCmd(argv) {
210
+ export default async function cardnewsCmd(argv: string[]) {
210
211
  const sub = argv[0];
211
212
  if (!sub || sub === "--help" || sub === "-h") { out(HELP); return; }
212
213
 
@@ -31,8 +31,8 @@ async function exportSub(argv) {
31
31
  const resp = await request(server.base, "/api/comfy/export-image", {
32
32
  method: "POST",
33
33
  body: { filename },
34
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
35
- const target = args.out || `${filename}.workflow.json`;
34
+ }).catch((e) => { const err = e; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
35
+ const target = String(args.out || `${filename}.workflow.json`);
36
36
  if (!args.force) {
37
37
  try {
38
38
  await access(target);
@@ -18,7 +18,7 @@ const FLAGS = {
18
18
  help: { short: "h", type: "boolean" },
19
19
  };
20
20
 
21
- async function exportSub(argv) {
21
+ async function exportSub(argv: string[]) {
22
22
  const args = parseArgs(argv, { flags: FLAGS });
23
23
  const filename = args.positional[0];
24
24
  if (!filename) die(2, "filename required");
@@ -28,8 +28,8 @@ async function exportSub(argv) {
28
28
  const resp: any = await request(server.base, "/api/comfy/export-image", {
29
29
  method: "POST",
30
30
  body: { filename },
31
- }).catch((e) => die(exitCodeForError(e), `${e.message}${e.code ? ` (${e.code})` : ""}`));
32
- const target = args.out || `${filename}.workflow.json`;
31
+ }).catch((e: unknown) => { const err = e as { message?: string; code?: string }; die(exitCodeForError(e), `${err.message}${err.code ? ` (${err.code})` : ""}`); });
32
+ const target = String(args.out || `${filename}.workflow.json`);
33
33
  if (!args.force) {
34
34
  try {
35
35
  await access(target);
@@ -45,7 +45,7 @@ const SUB: Record<string, (argv: any[]) => Promise<void>> = {
45
45
  export: exportSub,
46
46
  };
47
47
 
48
- export default async function comfyCmd(argv) {
48
+ export default async function comfyCmd(argv: string[]) {
49
49
  const sub = argv[0];
50
50
  if (!sub || sub === "--help" || sub === "-h") { out(HELP); return; }
51
51
  const handler = SUB[sub];
@@ -156,11 +156,11 @@ function displayPath(p: string): string {
156
156
  return home && p.startsWith(home) ? p.replace(home, "~") : p;
157
157
  }
158
158
 
159
- async function pathSub(_argv) {
159
+ async function pathSub(_argv: string[]) {
160
160
  out(CONFIG_FILE);
161
161
  }
162
162
 
163
- async function lsSub(argv) {
163
+ async function lsSub(argv: string[]) {
164
164
  const args = parseArgs(argv, { flags: FLAGS });
165
165
  if (args.effective) {
166
166
  const eff = buildEffectiveConfig();
@@ -173,7 +173,7 @@ async function lsSub(argv) {
173
173
  }
174
174
  }
175
175
 
176
- async function getSub(argv) {
176
+ async function getSub(argv: string[]) {
177
177
  const args = parseArgs(argv, { flags: FLAGS });
178
178
  const key = args.positional[0];
179
179
  if (!key) die(2, "key required. Usage: config get <dotted.key>");
@@ -188,7 +188,7 @@ async function getSub(argv) {
188
188
  }
189
189
  }
190
190
 
191
- async function setSub(argv) {
191
+ async function setSub(argv: string[]) {
192
192
  const args = parseArgs(argv, { flags: FLAGS });
193
193
  const [key, rawValue] = args.positional;
194
194
  if (!key || rawValue === undefined) die(2, "usage: config set <key> <value>");
@@ -227,7 +227,7 @@ async function setSub(argv) {
227
227
  out(color.dim("note: server must be restarted to pick up config changes (run `ima2 serve`)"));
228
228
  }
229
229
 
230
- async function rmSub(argv) {
230
+ async function rmSub(argv: string[]) {
231
231
  const args = parseArgs(argv, { flags: FLAGS });
232
232
  const key = args.positional[0];
233
233
  if (!key) die(2, "key required. Usage: config rm <key>");
@@ -256,7 +256,7 @@ const SUB: Record<string, Sub> = {
256
256
  rm: rmSub,
257
257
  };
258
258
 
259
- export default async function configCmd(argv) {
259
+ export default async function configCmd(argv: string[]) {
260
260
  const sub = argv[0];
261
261
  if (!sub || sub === "--help" || sub === "-h") { out(HELP); return; }
262
262
  const handler = SUB[sub];
@@ -3,6 +3,7 @@ import { resolveServer, request } from "../lib/client.js";
3
3
  import { fileToDataUri, dataUriToFile, defaultOutName } from "../lib/files.js";
4
4
  import { out, die, dieWithError, color, json } from "../lib/output.js";
5
5
  import { config } from "../../config.js";
6
+ import { errInfo } from "../../lib/errInfo.js";
6
7
  const VALID_MODES = new Set(["auto", "direct"]);
7
8
  const VALID_MODERATION = new Set(["auto", "low"]);
8
9
  const KNOWN_IMAGE_MODELS = new Set(["gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark"]);
@@ -54,15 +55,15 @@ export default async function editCmd(argv) {
54
55
  die(2, "input image path required");
55
56
  if (!args.prompt)
56
57
  die(2, "--prompt is required");
57
- if (!VALID_MODES.has(args.mode))
58
+ if (!VALID_MODES.has(String(args.mode)))
58
59
  die(2, "--mode must be one of: auto, direct");
59
- if (!VALID_MODERATION.has(args.moderation))
60
+ if (!VALID_MODERATION.has(String(args.moderation)))
60
61
  die(2, "--moderation must be one of: auto, low");
61
- if (args.model && !KNOWN_IMAGE_MODELS.has(args.model)) {
62
+ if (args.model && !KNOWN_IMAGE_MODELS.has(String(args.model))) {
62
63
  die(2, "--model must be one of: gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex-spark");
63
64
  }
64
65
  const VALID_REASONING = new Set(["none", "low", "medium", "high", "xhigh"]);
65
- if (args["reasoning-effort"] && !VALID_REASONING.has(args["reasoning-effort"])) {
66
+ if (args["reasoning-effort"] && !VALID_REASONING.has(String(args["reasoning-effort"]))) {
66
67
  die(2, "--reasoning-effort must be one of: none, low, medium, high, xhigh");
67
68
  }
68
69
  if (args["web-search"] && args["no-web-search"]) {
@@ -73,13 +74,14 @@ export default async function editCmd(argv) {
73
74
  server = await resolveServer({ serverFlag: args.server });
74
75
  }
75
76
  catch (e) {
77
+ const err = errInfo(e);
76
78
  if (args.json)
77
- json({ ok: false, error: e.message, code: e.code, status: e.status });
79
+ json({ ok: false, error: err.message, code: err.code, status: err.status });
78
80
  dieWithError(e);
79
81
  }
80
82
  const imageDataUri = await fileToDataUri(input);
81
83
  const imageB64 = imageDataUri.split(",")[1];
82
- const timeoutMs = (parseInt(args.timeout) || 180) * 1000;
84
+ const timeoutMs = (parseInt(String(args.timeout)) || 180) * 1000;
83
85
  let resp;
84
86
  try {
85
87
  const editBody = {
@@ -105,15 +107,16 @@ export default async function editCmd(argv) {
105
107
  });
106
108
  }
107
109
  catch (e) {
110
+ const err = errInfo(e);
108
111
  if (args.json)
109
- json({ ok: false, error: e.message, code: e.code });
112
+ json({ ok: false, error: err.message, code: err.code });
110
113
  dieWithError(e);
111
114
  }
112
115
  const image = resp.image;
113
116
  if (!image)
114
117
  die(1, "server returned no image");
115
118
  const target = args.out || `${config.storage.generatedDir}/${defaultOutName(0, 1)}`;
116
- await dataUriToFile(image, target);
119
+ await dataUriToFile(image, String(target));
117
120
  if (args.json) {
118
121
  json({ ok: true, path: target, requestId: resp.requestId, elapsed: resp.elapsed });
119
122
  }