ima2-gen 1.1.21 → 1.1.23

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 (214) hide show
  1. package/README.md +44 -7
  2. package/bin/commands/video.js +14 -0
  3. package/bin/ima2.js +14 -4
  4. package/bin/lib/platform.js +34 -5
  5. package/docs/README.ko.md +43 -2
  6. package/lib/agentQueueWorker.js +6 -0
  7. package/lib/agentRuntime.js +3 -2
  8. package/lib/atomicWrite.js +14 -0
  9. package/lib/grokImageAdapter.js +6 -0
  10. package/lib/grokProxyLauncher.js +5 -3
  11. package/lib/grokVideoAdapter.js +1 -1
  12. package/lib/grokVideoPlannerPrompt.js +10 -0
  13. package/lib/inflight.js +1 -1
  14. package/lib/oauthLauncher.js +5 -0
  15. package/lib/videoFrameExtract.js +3 -3
  16. package/package.json +5 -7
  17. package/routes/capabilities.js +13 -0
  18. package/routes/edit.js +2 -1
  19. package/routes/generate.js +32 -6
  20. package/routes/health.js +4 -3
  21. package/routes/multimode.js +2 -1
  22. package/routes/video.js +35 -3
  23. package/server.js +29 -2
  24. package/skills/ima2/SKILL.md +48 -6
  25. package/ui/dist/.vite/manifest.json +12 -12
  26. package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-C21zqdTZ.js} +1 -1
  27. package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-BN-ga1lG.js} +1 -1
  28. package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BbMa4IhI.js} +1 -1
  29. package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DRwBJRDQ.js} +1 -1
  30. package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-Dp85kHCq.js} +2 -2
  31. package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BE8Q8MLD.js} +1 -1
  32. package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-PtH5x0sc.js} +1 -1
  33. package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-FnM9tHI9.js} +2 -2
  34. package/ui/dist/assets/SettingsWorkspace-MARPGyBL.js +1 -0
  35. package/ui/dist/assets/index-BAFI6htx.js +42 -0
  36. package/ui/dist/assets/{index-31uVIdt4.js → index-BSXxr_Bt.js} +1 -1
  37. package/ui/dist/assets/index-DS-ADE7U.css +1 -0
  38. package/ui/dist/index.html +2 -2
  39. package/bin/commands/annotate.ts +0 -119
  40. package/bin/commands/cancel.ts +0 -48
  41. package/bin/commands/canvas-versions.ts +0 -80
  42. package/bin/commands/capabilities.ts +0 -110
  43. package/bin/commands/cardnews.ts +0 -249
  44. package/bin/commands/comfy.ts +0 -54
  45. package/bin/commands/config.ts +0 -186
  46. package/bin/commands/defaults.ts +0 -192
  47. package/bin/commands/doctor.ts +0 -202
  48. package/bin/commands/edit.ts +0 -150
  49. package/bin/commands/gen.ts +0 -214
  50. package/bin/commands/grok.ts +0 -90
  51. package/bin/commands/history.ts +0 -146
  52. package/bin/commands/ls.ts +0 -64
  53. package/bin/commands/metadata.ts +0 -39
  54. package/bin/commands/multimode.ts +0 -196
  55. package/bin/commands/node.ts +0 -166
  56. package/bin/commands/observability.ts +0 -176
  57. package/bin/commands/ping.ts +0 -31
  58. package/bin/commands/prompt-sub/build.ts +0 -101
  59. package/bin/commands/prompt.ts +0 -492
  60. package/bin/commands/ps.ts +0 -81
  61. package/bin/commands/session.ts +0 -266
  62. package/bin/commands/show.ts +0 -72
  63. package/bin/commands/skill.ts +0 -70
  64. package/bin/commands/video.ts +0 -442
  65. package/bin/ima2.ts +0 -430
  66. package/bin/lib/args.ts +0 -92
  67. package/bin/lib/browser-id.ts +0 -16
  68. package/bin/lib/client.ts +0 -122
  69. package/bin/lib/config-store.ts +0 -120
  70. package/bin/lib/destructive-confirm.ts +0 -19
  71. package/bin/lib/doctor-checks.ts +0 -91
  72. package/bin/lib/error-hints.ts +0 -23
  73. package/bin/lib/files.ts +0 -39
  74. package/bin/lib/output.ts +0 -73
  75. package/bin/lib/platform.ts +0 -99
  76. package/bin/lib/recover-output.ts +0 -139
  77. package/bin/lib/sse.ts +0 -73
  78. package/bin/lib/star-prompt.ts +0 -97
  79. package/bin/lib/storage-doctor.ts +0 -39
  80. package/bin/lib/ui-build.ts +0 -85
  81. package/config.ts +0 -354
  82. package/lib/agentCommandParser.ts +0 -69
  83. package/lib/agentGenerationPlanner.ts +0 -273
  84. package/lib/agentQuestionResponder.ts +0 -266
  85. package/lib/agentQueueStore.ts +0 -270
  86. package/lib/agentQueueWorker.ts +0 -89
  87. package/lib/agentRuntime.ts +0 -604
  88. package/lib/agentSettings.ts +0 -72
  89. package/lib/agentStore.ts +0 -422
  90. package/lib/agentStoreRows.ts +0 -136
  91. package/lib/agentTypes.ts +0 -154
  92. package/lib/apiCachePolicy.ts +0 -11
  93. package/lib/assetLifecycle.ts +0 -146
  94. package/lib/canvasVersionStore.ts +0 -223
  95. package/lib/capabilities.ts +0 -126
  96. package/lib/cardNewsGenerator.ts +0 -271
  97. package/lib/cardNewsJobStore.ts +0 -142
  98. package/lib/cardNewsManifestStore.ts +0 -154
  99. package/lib/cardNewsPlanner.ts +0 -236
  100. package/lib/cardNewsPlannerClient.ts +0 -155
  101. package/lib/cardNewsPlannerPrompt.ts +0 -62
  102. package/lib/cardNewsPlannerSchema.ts +0 -321
  103. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  104. package/lib/cardNewsTemplateStore.ts +0 -252
  105. package/lib/codexDetect.ts +0 -71
  106. package/lib/comfyBridge.ts +0 -235
  107. package/lib/composerSnapshot.ts +0 -33
  108. package/lib/configKeys.ts +0 -62
  109. package/lib/db.ts +0 -295
  110. package/lib/errInfo.ts +0 -43
  111. package/lib/errorClassify.ts +0 -100
  112. package/lib/generationCancel.ts +0 -28
  113. package/lib/generationErrors.ts +0 -238
  114. package/lib/grokImageAdapter.ts +0 -513
  115. package/lib/grokMultimodeAdapter.ts +0 -84
  116. package/lib/grokProxyLauncher.ts +0 -153
  117. package/lib/grokRuntime.ts +0 -23
  118. package/lib/grokSizeMapper.ts +0 -71
  119. package/lib/grokVideoAdapter.ts +0 -458
  120. package/lib/grokVideoCanvas.ts +0 -26
  121. package/lib/grokVideoDownload.ts +0 -59
  122. package/lib/grokVideoPlannerPrompt.ts +0 -67
  123. package/lib/historyIndex.ts +0 -51
  124. package/lib/historyList.ts +0 -181
  125. package/lib/imageMetadata.ts +0 -113
  126. package/lib/imageMetadataStore.ts +0 -67
  127. package/lib/imageModels.ts +0 -165
  128. package/lib/inflight.ts +0 -281
  129. package/lib/localImportStore.ts +0 -114
  130. package/lib/logger.ts +0 -161
  131. package/lib/nodeStore.ts +0 -91
  132. package/lib/oauthLauncher.ts +0 -94
  133. package/lib/oauthNormalize.ts +0 -30
  134. package/lib/oauthProxy/errors.ts +0 -128
  135. package/lib/oauthProxy/generators.ts +0 -494
  136. package/lib/oauthProxy/index.ts +0 -28
  137. package/lib/oauthProxy/prompts.ts +0 -123
  138. package/lib/oauthProxy/references.ts +0 -45
  139. package/lib/oauthProxy/runtime.ts +0 -115
  140. package/lib/oauthProxy/streams.ts +0 -232
  141. package/lib/oauthProxy/types.ts +0 -9
  142. package/lib/oauthProxy.ts +0 -3
  143. package/lib/openDirectory.ts +0 -47
  144. package/lib/pngInfo.ts +0 -26
  145. package/lib/promptBuilder/attachments.ts +0 -74
  146. package/lib/promptBuilder/client.ts +0 -130
  147. package/lib/promptBuilder/constants.ts +0 -9
  148. package/lib/promptBuilder/context.ts +0 -36
  149. package/lib/promptBuilder/errors.ts +0 -12
  150. package/lib/promptBuilder/requestSchema.ts +0 -56
  151. package/lib/promptBuilder/responseParser.ts +0 -219
  152. package/lib/promptBuilder/systemPrompt.ts +0 -135
  153. package/lib/promptBuilder/transport.ts +0 -94
  154. package/lib/promptBuilder/types.ts +0 -109
  155. package/lib/promptImport/curatedSources.ts +0 -141
  156. package/lib/promptImport/discoveryRegistry.ts +0 -329
  157. package/lib/promptImport/errors.ts +0 -18
  158. package/lib/promptImport/githubDiscovery.ts +0 -309
  159. package/lib/promptImport/githubFolder.ts +0 -397
  160. package/lib/promptImport/githubSource.ts +0 -257
  161. package/lib/promptImport/gptImageHints.ts +0 -70
  162. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  163. package/lib/promptImport/promptIndex.ts +0 -326
  164. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  165. package/lib/promptImport/types.ts +0 -103
  166. package/lib/promptSafetyPolicy.ts +0 -5
  167. package/lib/providerOptions.ts +0 -56
  168. package/lib/referenceImageCompress.ts +0 -84
  169. package/lib/refs.ts +0 -133
  170. package/lib/requestLogger.ts +0 -49
  171. package/lib/responsesDoctor.ts +0 -456
  172. package/lib/responsesErrors.ts +0 -83
  173. package/lib/responsesFallback.ts +0 -114
  174. package/lib/responsesImageAdapter.ts +0 -466
  175. package/lib/responsesParse.ts +0 -452
  176. package/lib/responsesTools.ts +0 -28
  177. package/lib/runtimeContext.ts +0 -146
  178. package/lib/runtimePorts.ts +0 -105
  179. package/lib/sessionStore.ts +0 -308
  180. package/lib/storageMigration.ts +0 -310
  181. package/lib/styleSheet.ts +0 -139
  182. package/lib/systemTrash.ts +0 -20
  183. package/lib/videoContinuity.ts +0 -180
  184. package/lib/videoFrameExtract.ts +0 -78
  185. package/lib/videoSeriesChain.ts +0 -29
  186. package/lib/visibleTextLanguagePolicy.ts +0 -7
  187. package/routes/agent.ts +0 -308
  188. package/routes/annotations.ts +0 -118
  189. package/routes/canvasVersions.ts +0 -69
  190. package/routes/capabilities.ts +0 -18
  191. package/routes/cardNews.ts +0 -211
  192. package/routes/comfy.ts +0 -43
  193. package/routes/edit.ts +0 -352
  194. package/routes/generate.ts +0 -492
  195. package/routes/grok.ts +0 -24
  196. package/routes/health.ts +0 -123
  197. package/routes/history.ts +0 -221
  198. package/routes/imageImport.ts +0 -37
  199. package/routes/index.ts +0 -52
  200. package/routes/metadata.ts +0 -77
  201. package/routes/multimode.ts +0 -499
  202. package/routes/nodes.ts +0 -578
  203. package/routes/promptBuilder.ts +0 -37
  204. package/routes/promptImport.ts +0 -379
  205. package/routes/prompts.ts +0 -428
  206. package/routes/quota.ts +0 -89
  207. package/routes/sessions.ts +0 -317
  208. package/routes/storage.ts +0 -47
  209. package/routes/video.ts +0 -300
  210. package/routes/videoExtended.ts +0 -284
  211. package/server.ts +0 -293
  212. package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
  213. package/ui/dist/assets/index-CjgnNtgt.css +0 -1
  214. package/ui/dist/assets/index-Da2s4_-5.js +0 -36
@@ -1,235 +0,0 @@
1
- import { constants as fsConstants } from "node:fs";
2
- import { access, readFile, realpath, stat } from "node:fs/promises";
3
- import { basename, extname, isAbsolute, join, relative } from "node:path";
4
-
5
- export const COMFY_ERROR = {
6
- URL_NOT_LOCAL: "COMFY_URL_NOT_LOCAL",
7
- IMAGE_INVALID: "COMFY_IMAGE_INVALID",
8
- IMAGE_NOT_FOUND: "COMFY_IMAGE_NOT_FOUND",
9
- UPLOAD_FAILED: "COMFY_UPLOAD_FAILED",
10
- };
11
-
12
- const LOCAL_HOSTS = new Set(["127.0.0.1", "localhost", "[::1]"]);
13
-
14
- class ComfyBridgeError extends Error {
15
- code: string;
16
- status: number;
17
- constructor(code: string, message: string, status: number) {
18
- super(message);
19
- this.name = "ComfyBridgeError";
20
- this.code = code;
21
- this.status = status;
22
- }
23
- }
24
-
25
- function bridgeError(code: string, message: string, status: number) {
26
- return new ComfyBridgeError(code, message, status);
27
- }
28
-
29
- export function isComfyBridgeError(error: unknown): error is ComfyBridgeError {
30
- return error instanceof ComfyBridgeError;
31
- }
32
-
33
- export function normalizeComfyOrigin(rawUrl: unknown): string {
34
- if (typeof rawUrl !== "string" || !rawUrl.trim()) {
35
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL is not configured.", 400);
36
- }
37
- const trimmed = rawUrl.trim();
38
- const rawHost = trimmed.match(/^http:\/\/(?:[^@/]+@)?(\[[^\]]+\]|[^/:?#]+)/i)?.[1] ?? "";
39
- if (
40
- rawHost === "localhost." ||
41
- /^\d+$/.test(rawHost) ||
42
- /^0x/i.test(rawHost) ||
43
- /^0[0-9]+/.test(rawHost) ||
44
- (/^[0-9.]+$/.test(rawHost) && rawHost.split(".").length !== 4) ||
45
- rawHost.split(".").some((part) => part.length > 1 && part.startsWith("0"))
46
- ) {
47
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL is not local.", 400);
48
- }
49
- let url;
50
- try {
51
- url = new URL(trimmed);
52
- } catch {
53
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL is invalid.", 400);
54
- }
55
- if (url.protocol !== "http:") {
56
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL must use HTTP.", 400);
57
- }
58
- if (url.username || url.password || !url.port) {
59
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL is not local.", 400);
60
- }
61
- if (!LOCAL_HOSTS.has(url.hostname)) {
62
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL is not local.", 400);
63
- }
64
- if (url.pathname !== "/" || url.search || url.hash) {
65
- throw bridgeError(COMFY_ERROR.URL_NOT_LOCAL, "ComfyUI URL must be an origin.", 400);
66
- }
67
- return url.origin;
68
- }
69
-
70
- function hasEncodedSeparator(filename: string): boolean {
71
- try {
72
- const decoded = decodeURIComponent(filename);
73
- return decoded.includes("/") || decoded.includes("\\");
74
- } catch {
75
- return true;
76
- }
77
- }
78
-
79
- function validateFilename(filename: unknown): string {
80
- if (typeof filename !== "string" || !filename.trim()) {
81
- throw bridgeError(COMFY_ERROR.IMAGE_INVALID, "A generated filename is required.", 400);
82
- }
83
- if (
84
- isAbsolute(filename) ||
85
- filename !== basename(filename) ||
86
- filename.includes("/") ||
87
- filename.includes("\\") ||
88
- filename.includes("..") ||
89
- /^[a-z][a-z0-9+.-]*:/i.test(filename) ||
90
- hasEncodedSeparator(filename)
91
- ) {
92
- throw bridgeError(COMFY_ERROR.IMAGE_INVALID, "Generated filename is invalid.", 400);
93
- }
94
- return filename;
95
- }
96
-
97
- function isInsideDirectory(parent: string, candidate: string): boolean {
98
- const rel = relative(parent, candidate);
99
- return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
100
- }
101
-
102
- interface ImageType { ext: string; mime: string; }
103
-
104
- function sniffImage(buffer: Buffer): ImageType {
105
- if (
106
- buffer.length >= 8 &&
107
- buffer[0] === 0x89 &&
108
- buffer[1] === 0x50 &&
109
- buffer[2] === 0x4e &&
110
- buffer[3] === 0x47 &&
111
- buffer[4] === 0x0d &&
112
- buffer[5] === 0x0a &&
113
- buffer[6] === 0x1a &&
114
- buffer[7] === 0x0a
115
- ) {
116
- return { ext: "png", mime: "image/png" };
117
- }
118
- if (buffer.length >= 3 && buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
119
- return { ext: "jpg", mime: "image/jpeg" };
120
- }
121
- if (
122
- buffer.length >= 12 &&
123
- buffer.subarray(0, 4).toString("ascii") === "RIFF" &&
124
- buffer.subarray(8, 12).toString("ascii") === "WEBP"
125
- ) {
126
- return { ext: "webp", mime: "image/webp" };
127
- }
128
- throw bridgeError(COMFY_ERROR.IMAGE_INVALID, "Generated file is not a supported image.", 400);
129
- }
130
-
131
- function sanitizeBaseName(filename: string): string {
132
- const raw = basename(filename, extname(filename));
133
- const safe = raw.replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "");
134
- return safe || "image";
135
- }
136
-
137
- interface ComfyCtx {
138
- config: {
139
- storage: { generatedDir: string };
140
- comfy: { defaultUrl: string; uploadTimeoutMs: number; maxUploadBytes: number };
141
- };
142
- }
143
-
144
- interface GeneratedImage {
145
- buffer: Buffer;
146
- imageType: ImageType;
147
- sourceFilename: string;
148
- uploadFilename: string;
149
- }
150
-
151
- async function readGeneratedImage(ctx: ComfyCtx, filename: unknown): Promise<GeneratedImage> {
152
- const safeFilename = validateFilename(filename);
153
- const generatedDir = await realpath(ctx.config.storage.generatedDir);
154
- const candidatePath = join(ctx.config.storage.generatedDir, safeFilename);
155
- try {
156
- await access(candidatePath, fsConstants.F_OK);
157
- } catch {
158
- throw bridgeError(COMFY_ERROR.IMAGE_NOT_FOUND, "Generated image was not found.", 404);
159
- }
160
- let candidateReal;
161
- try {
162
- candidateReal = await realpath(candidatePath);
163
- } catch {
164
- throw bridgeError(COMFY_ERROR.IMAGE_NOT_FOUND, "Generated image was not found.", 404);
165
- }
166
- if (!isInsideDirectory(generatedDir, candidateReal)) {
167
- throw bridgeError(COMFY_ERROR.IMAGE_INVALID, "Generated filename is invalid.", 400);
168
- }
169
- const info = await stat(candidateReal);
170
- if (!info.isFile()) {
171
- throw bridgeError(COMFY_ERROR.IMAGE_INVALID, "Generated filename is invalid.", 400);
172
- }
173
- if (info.size > ctx.config.comfy.maxUploadBytes) {
174
- throw bridgeError(COMFY_ERROR.IMAGE_INVALID, "Generated image is too large.", 400);
175
- }
176
- const buffer = await readFile(candidateReal);
177
- const imageType = sniffImage(buffer);
178
- return {
179
- buffer,
180
- imageType,
181
- sourceFilename: safeFilename,
182
- uploadFilename: `ima2_${Date.now()}_${sanitizeBaseName(safeFilename)}.${imageType.ext}`,
183
- };
184
- }
185
-
186
- async function postToComfy(origin: string, image: GeneratedImage, timeoutMs: number, fetchImpl: typeof fetch = fetch): Promise<string> {
187
- const controller = new AbortController();
188
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
189
- try {
190
- const form = new FormData();
191
- form.append("image", new Blob([new Uint8Array(image.buffer)], { type: image.imageType.mime }), image.uploadFilename);
192
- form.append("type", "input");
193
- const res = await fetchImpl(`${origin}/upload/image`, {
194
- method: "POST",
195
- body: form,
196
- redirect: "manual",
197
- signal: controller.signal,
198
- });
199
- if (res.status >= 300 && res.status < 400) {
200
- throw bridgeError(COMFY_ERROR.UPLOAD_FAILED, "Could not upload image to ComfyUI.", 502);
201
- }
202
- if (!res.ok) {
203
- throw bridgeError(COMFY_ERROR.UPLOAD_FAILED, "Could not upload image to ComfyUI.", 502);
204
- }
205
- const data = await res.json().catch(() => null) as { name?: unknown } | null;
206
- if (!data || typeof data.name !== "string" || !data.name.trim()) {
207
- throw bridgeError(COMFY_ERROR.UPLOAD_FAILED, "Could not upload image to ComfyUI.", 502);
208
- }
209
- return data.name;
210
- } catch (error) {
211
- if (isComfyBridgeError(error)) throw error;
212
- throw bridgeError(COMFY_ERROR.UPLOAD_FAILED, "Could not upload image to ComfyUI.", 502);
213
- } finally {
214
- clearTimeout(timeout);
215
- }
216
- }
217
-
218
- interface ExportInput { filename: unknown; }
219
- interface ExportOptions { comfyUrl?: string; fetchImpl?: (input: any, init?: any) => Promise<any>; }
220
-
221
- export async function exportImageToComfy(ctx: ComfyCtx, input: ExportInput, options: ExportOptions = {}) {
222
- const origin = normalizeComfyOrigin(options.comfyUrl ?? ctx.config.comfy.defaultUrl);
223
- const image = await readGeneratedImage(ctx, input.filename);
224
- const uploadedFilename = await postToComfy(
225
- origin,
226
- image,
227
- ctx.config.comfy.uploadTimeoutMs,
228
- options.fetchImpl,
229
- );
230
- return {
231
- ok: true,
232
- sourceFilename: image.sourceFilename,
233
- uploadedFilename,
234
- };
235
- }
@@ -1,33 +0,0 @@
1
- export type ComposerInsertedPromptSnapshot = {
2
- id: string;
3
- name: string;
4
- text: string;
5
- placement: "before" | "after";
6
- };
7
-
8
- export function normalizeComposerPrompt(value: unknown): string | null {
9
- return typeof value === "string" ? value : null;
10
- }
11
-
12
- export function normalizeComposerInsertedPrompts(
13
- value: unknown,
14
- ): ComposerInsertedPromptSnapshot[] {
15
- if (!Array.isArray(value)) return [];
16
- return value.flatMap((entry) => {
17
- if (!entry || typeof entry !== "object") return [];
18
- const item = entry as Record<string, unknown>;
19
- if (
20
- typeof item.id !== "string" ||
21
- typeof item.name !== "string" ||
22
- typeof item.text !== "string"
23
- ) {
24
- return [];
25
- }
26
- return [{
27
- id: item.id,
28
- name: item.name,
29
- text: item.text,
30
- placement: item.placement === "after" ? "after" : "before",
31
- }];
32
- });
33
- }
package/lib/configKeys.ts DELETED
@@ -1,62 +0,0 @@
1
- export const AUTH_CONFIG_KEYS = new Set(["provider", "apiKey"]);
2
-
3
- export const WRITABLE_CONFIG_KEYS = new Set([
4
- "imageModels.default",
5
- "imageModels.reasoningEffort",
6
- "apiProvider.defaultImageModel",
7
- "apiProvider.defaultReasoningEffort",
8
- "log.level",
9
- "features.cardNews",
10
- "cardNewsPlanner.enabled",
11
- "cardNewsPlanner.model",
12
- "cardNewsPlanner.timeoutMs",
13
- "cardNewsPlanner.deterministicFallback",
14
- "grokProvider.plannerModel",
15
- "grokProvider.plannerTimeoutMs",
16
- "grokProvider.defaultImageModel",
17
- "comfy.defaultUrl",
18
- "comfy.uploadTimeoutMs",
19
- "comfy.maxUploadBytes",
20
- "storage.generatedDir",
21
- "storage.generatedDirName",
22
- "server.port",
23
- "server.host",
24
- "server.bodyLimit",
25
- "oauth.proxyPort",
26
- "oauth.statusTimeoutMs",
27
- "oauth.restartDelayMs",
28
- "limits.maxRefCount",
29
- "limits.maxParallel",
30
- "history.defaultPageSize",
31
- "history.maxPageCap",
32
- ]);
33
-
34
- export const KEY_TO_ENV: Record<string, string> = {
35
- "imageModels.default": "IMA2_IMAGE_MODEL_DEFAULT",
36
- "imageModels.reasoningEffort": "IMA2_REASONING_EFFORT",
37
- "apiProvider.defaultImageModel": "IMA2_API_IMAGE_MODEL_DEFAULT",
38
- "apiProvider.defaultReasoningEffort": "IMA2_API_REASONING_EFFORT",
39
- "log.level": "IMA2_LOG_LEVEL",
40
- "features.cardNews": "IMA2_CARD_NEWS",
41
- "server.port": "IMA2_PORT",
42
- "server.host": "IMA2_HOST",
43
- "server.bodyLimit": "IMA2_BODY_LIMIT",
44
- "oauth.proxyPort": "IMA2_OAUTH_PROXY_PORT",
45
- "storage.generatedDir": "IMA2_GENERATED_DIR",
46
- "cardNewsPlanner.enabled": "IMA2_CARD_NEWS_PLANNER",
47
- "cardNewsPlanner.model": "IMA2_CARD_NEWS_PLANNER_MODEL",
48
- "cardNewsPlanner.timeoutMs": "IMA2_CARD_NEWS_PLANNER_TIMEOUT_MS",
49
- "grokProvider.plannerModel": "IMA2_GROK_PLANNER_MODEL",
50
- "grokProvider.plannerTimeoutMs": "IMA2_GROK_PLANNER_TIMEOUT_MS",
51
- "grokProvider.defaultImageModel": "IMA2_GROK_IMAGE_MODEL_DEFAULT",
52
- "limits.maxParallel": "IMA2_MAX_PARALLEL",
53
- "limits.maxRefCount": "IMA2_MAX_REF_COUNT",
54
- "history.defaultPageSize": "IMA2_HISTORY_PAGE_SIZE",
55
- };
56
-
57
- const REDACT_PATTERN = /token|secret|apikey|password/i;
58
- const ALWAYS_REDACT = new Set(["provider", "apiKey", "oauth.token", "oauth.refreshToken"]);
59
-
60
- export function isSensitiveConfigKey(key: string): boolean {
61
- return ALWAYS_REDACT.has(key) || REDACT_PATTERN.test(key);
62
- }
package/lib/db.ts DELETED
@@ -1,295 +0,0 @@
1
- import Database from "better-sqlite3";
2
- import { mkdirSync, existsSync } from "fs";
3
- import { dirname } from "path";
4
- import { config } from "../config.js";
5
-
6
- let db: Database.Database | null = null;
7
-
8
- export function getDbPath() {
9
- return config.storage.dbPath;
10
- }
11
-
12
- export function getDb() {
13
- if (db) return db;
14
- const dbPath = getDbPath();
15
- const dir = dirname(dbPath);
16
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
17
-
18
- db = new Database(dbPath);
19
- db.pragma("journal_mode = WAL");
20
- db.pragma("foreign_keys = ON");
21
- migrate(db);
22
- return db;
23
- }
24
-
25
- function migrate(database: Database.Database) {
26
- database.exec(`
27
- CREATE TABLE IF NOT EXISTS _meta (
28
- key TEXT PRIMARY KEY,
29
- value TEXT NOT NULL
30
- );
31
-
32
- CREATE TABLE IF NOT EXISTS sessions (
33
- id TEXT PRIMARY KEY,
34
- title TEXT NOT NULL DEFAULT 'Untitled',
35
- created_at INTEGER NOT NULL,
36
- updated_at INTEGER NOT NULL,
37
- graph_version INTEGER NOT NULL DEFAULT 0
38
- );
39
-
40
- CREATE TABLE IF NOT EXISTS nodes (
41
- session_id TEXT NOT NULL,
42
- id TEXT NOT NULL,
43
- x REAL NOT NULL DEFAULT 0,
44
- y REAL NOT NULL DEFAULT 0,
45
- data TEXT NOT NULL DEFAULT '{}',
46
- PRIMARY KEY (session_id, id),
47
- FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
48
- );
49
-
50
- CREATE TABLE IF NOT EXISTS edges (
51
- session_id TEXT NOT NULL,
52
- id TEXT NOT NULL,
53
- source TEXT NOT NULL,
54
- target TEXT NOT NULL,
55
- data TEXT NOT NULL DEFAULT '{}',
56
- PRIMARY KEY (session_id, id),
57
- FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
58
- );
59
-
60
- CREATE INDEX IF NOT EXISTS idx_nodes_session ON nodes(session_id);
61
- CREATE INDEX IF NOT EXISTS idx_edges_session ON edges(session_id);
62
-
63
- CREATE TABLE IF NOT EXISTS inflight (
64
- request_id TEXT PRIMARY KEY,
65
- kind TEXT NOT NULL,
66
- prompt TEXT NOT NULL DEFAULT '',
67
- meta TEXT NOT NULL DEFAULT '{}',
68
- session_id TEXT,
69
- parent_node_id TEXT,
70
- client_node_id TEXT,
71
- started_at INTEGER NOT NULL,
72
- phase TEXT NOT NULL DEFAULT 'queued',
73
- phase_at INTEGER NOT NULL
74
- );
75
-
76
- CREATE INDEX IF NOT EXISTS idx_inflight_started ON inflight(started_at);
77
- CREATE INDEX IF NOT EXISTS idx_inflight_kind ON inflight(kind);
78
- CREATE INDEX IF NOT EXISTS idx_inflight_session ON inflight(session_id);
79
-
80
- CREATE TABLE IF NOT EXISTS agent_sessions (
81
- id TEXT PRIMARY KEY,
82
- title TEXT NOT NULL DEFAULT 'New Agent',
83
- codex_thread_id TEXT,
84
- last_turn_id TEXT,
85
- current_image_id TEXT,
86
- compacted INTEGER NOT NULL DEFAULT 0,
87
- web_search_enabled INTEGER NOT NULL DEFAULT 1,
88
- generation_settings TEXT NOT NULL DEFAULT '{}',
89
- style_locks TEXT NOT NULL DEFAULT '[]',
90
- subject_locks TEXT NOT NULL DEFAULT '[]',
91
- created_at INTEGER NOT NULL,
92
- updated_at INTEGER NOT NULL
93
- );
94
-
95
- CREATE TABLE IF NOT EXISTS agent_turns (
96
- id TEXT PRIMARY KEY,
97
- session_id TEXT NOT NULL,
98
- role TEXT NOT NULL,
99
- text TEXT NOT NULL DEFAULT '',
100
- status TEXT NOT NULL DEFAULT 'complete',
101
- image_ids TEXT NOT NULL DEFAULT '[]',
102
- web_finding_ids TEXT NOT NULL DEFAULT '[]',
103
- raw TEXT NOT NULL DEFAULT '{}',
104
- created_at INTEGER NOT NULL,
105
- FOREIGN KEY (session_id) REFERENCES agent_sessions(id) ON DELETE CASCADE
106
- );
107
-
108
- CREATE TABLE IF NOT EXISTS agent_images (
109
- id TEXT PRIMARY KEY,
110
- session_id TEXT NOT NULL,
111
- filename TEXT NOT NULL,
112
- url TEXT NOT NULL,
113
- thumb_url TEXT,
114
- prompt TEXT,
115
- revised_prompt TEXT,
116
- width INTEGER,
117
- height INTEGER,
118
- created_at INTEGER NOT NULL,
119
- FOREIGN KEY (session_id) REFERENCES agent_sessions(id) ON DELETE CASCADE
120
- );
121
-
122
- CREATE TABLE IF NOT EXISTS agent_references (
123
- id TEXT PRIMARY KEY,
124
- session_id TEXT NOT NULL,
125
- role TEXT NOT NULL DEFAULT 'source',
126
- image_id TEXT,
127
- filename TEXT,
128
- url TEXT,
129
- prompt TEXT,
130
- created_at INTEGER NOT NULL,
131
- FOREIGN KEY (session_id) REFERENCES agent_sessions(id) ON DELETE CASCADE
132
- );
133
-
134
- CREATE TABLE IF NOT EXISTS agent_web_findings (
135
- id TEXT PRIMARY KEY,
136
- session_id TEXT NOT NULL,
137
- query TEXT NOT NULL DEFAULT '',
138
- url TEXT,
139
- title TEXT,
140
- snippet TEXT,
141
- created_at INTEGER NOT NULL,
142
- FOREIGN KEY (session_id) REFERENCES agent_sessions(id) ON DELETE CASCADE
143
- );
144
-
145
- CREATE TABLE IF NOT EXISTS agent_queue_items (
146
- id TEXT PRIMARY KEY,
147
- session_id TEXT NOT NULL,
148
- request_id TEXT NOT NULL,
149
- prompt TEXT NOT NULL DEFAULT '',
150
- options TEXT NOT NULL DEFAULT '{}',
151
- tool_plan TEXT NOT NULL DEFAULT '{}',
152
- status TEXT NOT NULL DEFAULT 'queued',
153
- position INTEGER NOT NULL DEFAULT 0,
154
- result_image_ids TEXT NOT NULL DEFAULT '[]',
155
- error_code TEXT,
156
- error_message TEXT,
157
- created_at INTEGER NOT NULL,
158
- started_at INTEGER,
159
- finished_at INTEGER,
160
- FOREIGN KEY (session_id) REFERENCES agent_sessions(id) ON DELETE CASCADE
161
- );
162
-
163
- CREATE INDEX IF NOT EXISTS idx_agent_sessions_updated
164
- ON agent_sessions(updated_at);
165
- CREATE INDEX IF NOT EXISTS idx_agent_turns_session
166
- ON agent_turns(session_id, created_at);
167
- CREATE INDEX IF NOT EXISTS idx_agent_images_session
168
- ON agent_images(session_id, created_at);
169
- CREATE INDEX IF NOT EXISTS idx_agent_web_findings_session
170
- ON agent_web_findings(session_id, created_at);
171
- CREATE INDEX IF NOT EXISTS idx_agent_queue_session
172
- ON agent_queue_items(session_id, status, created_at);
173
- CREATE INDEX IF NOT EXISTS idx_agent_queue_status
174
- ON agent_queue_items(status, created_at);
175
- `);
176
-
177
- const sessionColumns = (database
178
- .prepare("PRAGMA table_info(sessions)")
179
- .all() as Array<{ name: string }>)
180
- .map((row) => row.name);
181
- if (!sessionColumns.includes("graph_version")) {
182
- database.exec(
183
- "ALTER TABLE sessions ADD COLUMN graph_version INTEGER NOT NULL DEFAULT 0",
184
- );
185
- }
186
- if (!sessionColumns.includes("style_sheet")) {
187
- database.exec("ALTER TABLE sessions ADD COLUMN style_sheet TEXT");
188
- }
189
- if (!sessionColumns.includes("style_sheet_enabled")) {
190
- database.exec(
191
- "ALTER TABLE sessions ADD COLUMN style_sheet_enabled INTEGER NOT NULL DEFAULT 0",
192
- );
193
- }
194
-
195
- const agentSessionColumns = (database
196
- .prepare("PRAGMA table_info(agent_sessions)")
197
- .all() as Array<{ name: string }>)
198
- .map((row) => row.name);
199
- if (!agentSessionColumns.includes("generation_settings")) {
200
- database.exec("ALTER TABLE agent_sessions ADD COLUMN generation_settings TEXT NOT NULL DEFAULT '{}'");
201
- }
202
-
203
- const agentQueueColumns = (database
204
- .prepare("PRAGMA table_info(agent_queue_items)")
205
- .all() as Array<{ name: string }>)
206
- .map((row) => row.name);
207
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "request_id", "TEXT NOT NULL DEFAULT ''");
208
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "options", "TEXT NOT NULL DEFAULT '{}'");
209
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "tool_plan", "TEXT NOT NULL DEFAULT '{}'");
210
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "position", "INTEGER NOT NULL DEFAULT 0");
211
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "result_image_ids", "TEXT NOT NULL DEFAULT '[]'");
212
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "error_code", "TEXT");
213
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "error_message", "TEXT");
214
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "started_at", "INTEGER");
215
- addColumnIfMissing(database, agentQueueColumns, "agent_queue_items", "finished_at", "INTEGER");
216
-
217
- // ── Prompt Library (schema v4) ──
218
- database.exec(`
219
- CREATE TABLE IF NOT EXISTS prompt_folders (
220
- id TEXT PRIMARY KEY,
221
- parent_id TEXT NOT NULL,
222
- name TEXT NOT NULL COLLATE NOCASE,
223
- created_at INTEGER NOT NULL DEFAULT (unixepoch()),
224
- updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
225
- UNIQUE(parent_id, name)
226
- );
227
-
228
- CREATE TABLE IF NOT EXISTS prompts (
229
- id TEXT PRIMARY KEY,
230
- folder_id TEXT NOT NULL DEFAULT '__root__',
231
- name TEXT NOT NULL,
232
- text TEXT NOT NULL,
233
- tags TEXT,
234
- mode TEXT,
235
- is_favorite INTEGER NOT NULL DEFAULT 0,
236
- favorited_at INTEGER,
237
- created_at INTEGER NOT NULL DEFAULT (unixepoch()),
238
- updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
239
- FOREIGN KEY (folder_id) REFERENCES prompt_folders(id) ON DELETE SET DEFAULT
240
- );
241
-
242
- CREATE TABLE IF NOT EXISTS gallery_favorites (
243
- id TEXT PRIMARY KEY,
244
- browser_id TEXT NOT NULL,
245
- filename TEXT NOT NULL,
246
- favorited_at INTEGER NOT NULL DEFAULT (unixepoch()),
247
- UNIQUE(browser_id, filename)
248
- );
249
-
250
- CREATE TABLE IF NOT EXISTS image_annotations (
251
- id TEXT PRIMARY KEY,
252
- browser_id TEXT NOT NULL,
253
- filename TEXT NOT NULL,
254
- payload TEXT NOT NULL,
255
- schema_version INTEGER NOT NULL DEFAULT 1,
256
- created_at INTEGER NOT NULL DEFAULT (unixepoch()),
257
- updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
258
- UNIQUE(browser_id, filename)
259
- );
260
-
261
- CREATE INDEX IF NOT EXISTS idx_image_annotations_filename
262
- ON image_annotations(filename);
263
-
264
- INSERT OR IGNORE INTO prompt_folders (id, parent_id, name) VALUES
265
- ('__root__', '__root__', '__root__'),
266
- ('__trash__', '__root__', '__trash__');
267
- `);
268
-
269
- const row = database.prepare("SELECT value FROM _meta WHERE key = 'schema_version'").get() as { value?: string } | undefined;
270
- if (!row) {
271
- database.prepare("INSERT INTO _meta (key, value) VALUES ('schema_version', '5')").run();
272
- } else if (row.value !== "5") {
273
- database
274
- .prepare("UPDATE _meta SET value = '5' WHERE key = 'schema_version'")
275
- .run();
276
- }
277
- }
278
-
279
- function addColumnIfMissing(
280
- database: Database.Database,
281
- columns: readonly string[],
282
- table: string,
283
- name: string,
284
- definition: string,
285
- ) {
286
- if (columns.includes(name)) return;
287
- database.exec(`ALTER TABLE ${table} ADD COLUMN ${name} ${definition}`);
288
- }
289
-
290
- export function closeDb() {
291
- if (db) {
292
- db.close();
293
- db = null;
294
- }
295
- }
package/lib/errInfo.ts DELETED
@@ -1,43 +0,0 @@
1
- export interface ErrInfo {
2
- message: string;
3
- code: string | undefined;
4
- status: number | undefined;
5
- name: string | undefined;
6
- cause: unknown;
7
- stack: string | undefined;
8
- raw: unknown;
9
- }
10
-
11
- /** Narrow an unknown thrown value to a stable info shape. */
12
- export function errInfo(e: unknown): ErrInfo {
13
- if (e instanceof Error) {
14
- const anyE = e as Error & { code?: unknown; status?: unknown; cause?: unknown };
15
- return {
16
- message: e.message,
17
- code: typeof anyE.code === "string" ? anyE.code : undefined,
18
- status: typeof anyE.status === "number" ? anyE.status : undefined,
19
- name: e.name,
20
- cause: anyE.cause,
21
- stack: e.stack,
22
- raw: e,
23
- };
24
- }
25
- if (e && typeof e === "object") {
26
- const o = e as Record<string, unknown>;
27
- return {
28
- message: typeof o.message === "string" ? o.message : String(e),
29
- code: typeof o.code === "string" ? o.code : undefined,
30
- status: typeof o.status === "number" ? o.status : undefined,
31
- name: typeof o.name === "string" ? o.name : undefined,
32
- cause: o.cause,
33
- stack: typeof o.stack === "string" ? o.stack : undefined,
34
- raw: e,
35
- };
36
- }
37
- return { message: String(e), code: undefined, status: undefined, name: undefined, cause: undefined, stack: undefined, raw: e };
38
- }
39
-
40
- /** Handy for `throw e instanceof Error ? e : asError(e)`. */
41
- export function asError(e: unknown): Error {
42
- return e instanceof Error ? e : new Error(typeof e === "string" ? e : JSON.stringify(e));
43
- }