ima2-gen 1.1.21 → 1.1.22

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 (208) hide show
  1. package/README.md +30 -4
  2. package/bin/ima2.js +14 -4
  3. package/bin/lib/platform.js +34 -5
  4. package/docs/README.ko.md +31 -0
  5. package/lib/agentQueueWorker.js +6 -0
  6. package/lib/agentRuntime.js +3 -2
  7. package/lib/atomicWrite.js +14 -0
  8. package/lib/grokProxyLauncher.js +5 -3
  9. package/lib/inflight.js +1 -1
  10. package/lib/oauthLauncher.js +5 -0
  11. package/lib/videoFrameExtract.js +3 -3
  12. package/package.json +5 -7
  13. package/routes/edit.js +2 -1
  14. package/routes/generate.js +4 -3
  15. package/routes/health.js +4 -3
  16. package/routes/multimode.js +2 -1
  17. package/routes/video.js +4 -2
  18. package/server.js +29 -2
  19. package/ui/dist/.vite/manifest.json +12 -12
  20. package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-COxQ5TjU.js} +1 -1
  21. package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-B0OkcuVz.js} +1 -1
  22. package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BSsclEBh.js} +1 -1
  23. package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DpC9A5Rz.js} +1 -1
  24. package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-CVwT0rLd.js} +2 -2
  25. package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BDCkRCRs.js} +1 -1
  26. package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-QoKbZD83.js} +1 -1
  27. package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-BhFgeKnY.js} +2 -2
  28. package/ui/dist/assets/SettingsWorkspace-CfjrlH5R.js +1 -0
  29. package/ui/dist/assets/index-C-mur7pa.css +1 -0
  30. package/ui/dist/assets/index-CCP5nUOj.js +42 -0
  31. package/ui/dist/assets/{index-31uVIdt4.js → index-Cxhzi3bs.js} +1 -1
  32. package/ui/dist/index.html +2 -2
  33. package/bin/commands/annotate.ts +0 -119
  34. package/bin/commands/cancel.ts +0 -48
  35. package/bin/commands/canvas-versions.ts +0 -80
  36. package/bin/commands/capabilities.ts +0 -110
  37. package/bin/commands/cardnews.ts +0 -249
  38. package/bin/commands/comfy.ts +0 -54
  39. package/bin/commands/config.ts +0 -186
  40. package/bin/commands/defaults.ts +0 -192
  41. package/bin/commands/doctor.ts +0 -202
  42. package/bin/commands/edit.ts +0 -150
  43. package/bin/commands/gen.ts +0 -214
  44. package/bin/commands/grok.ts +0 -90
  45. package/bin/commands/history.ts +0 -146
  46. package/bin/commands/ls.ts +0 -64
  47. package/bin/commands/metadata.ts +0 -39
  48. package/bin/commands/multimode.ts +0 -196
  49. package/bin/commands/node.ts +0 -166
  50. package/bin/commands/observability.ts +0 -176
  51. package/bin/commands/ping.ts +0 -31
  52. package/bin/commands/prompt-sub/build.ts +0 -101
  53. package/bin/commands/prompt.ts +0 -492
  54. package/bin/commands/ps.ts +0 -81
  55. package/bin/commands/session.ts +0 -266
  56. package/bin/commands/show.ts +0 -72
  57. package/bin/commands/skill.ts +0 -70
  58. package/bin/commands/video.ts +0 -442
  59. package/bin/ima2.ts +0 -430
  60. package/bin/lib/args.ts +0 -92
  61. package/bin/lib/browser-id.ts +0 -16
  62. package/bin/lib/client.ts +0 -122
  63. package/bin/lib/config-store.ts +0 -120
  64. package/bin/lib/destructive-confirm.ts +0 -19
  65. package/bin/lib/doctor-checks.ts +0 -91
  66. package/bin/lib/error-hints.ts +0 -23
  67. package/bin/lib/files.ts +0 -39
  68. package/bin/lib/output.ts +0 -73
  69. package/bin/lib/platform.ts +0 -99
  70. package/bin/lib/recover-output.ts +0 -139
  71. package/bin/lib/sse.ts +0 -73
  72. package/bin/lib/star-prompt.ts +0 -97
  73. package/bin/lib/storage-doctor.ts +0 -39
  74. package/bin/lib/ui-build.ts +0 -85
  75. package/config.ts +0 -354
  76. package/lib/agentCommandParser.ts +0 -69
  77. package/lib/agentGenerationPlanner.ts +0 -273
  78. package/lib/agentQuestionResponder.ts +0 -266
  79. package/lib/agentQueueStore.ts +0 -270
  80. package/lib/agentQueueWorker.ts +0 -89
  81. package/lib/agentRuntime.ts +0 -604
  82. package/lib/agentSettings.ts +0 -72
  83. package/lib/agentStore.ts +0 -422
  84. package/lib/agentStoreRows.ts +0 -136
  85. package/lib/agentTypes.ts +0 -154
  86. package/lib/apiCachePolicy.ts +0 -11
  87. package/lib/assetLifecycle.ts +0 -146
  88. package/lib/canvasVersionStore.ts +0 -223
  89. package/lib/capabilities.ts +0 -126
  90. package/lib/cardNewsGenerator.ts +0 -271
  91. package/lib/cardNewsJobStore.ts +0 -142
  92. package/lib/cardNewsManifestStore.ts +0 -154
  93. package/lib/cardNewsPlanner.ts +0 -236
  94. package/lib/cardNewsPlannerClient.ts +0 -155
  95. package/lib/cardNewsPlannerPrompt.ts +0 -62
  96. package/lib/cardNewsPlannerSchema.ts +0 -321
  97. package/lib/cardNewsRoleTemplateStore.ts +0 -47
  98. package/lib/cardNewsTemplateStore.ts +0 -252
  99. package/lib/codexDetect.ts +0 -71
  100. package/lib/comfyBridge.ts +0 -235
  101. package/lib/composerSnapshot.ts +0 -33
  102. package/lib/configKeys.ts +0 -62
  103. package/lib/db.ts +0 -295
  104. package/lib/errInfo.ts +0 -43
  105. package/lib/errorClassify.ts +0 -100
  106. package/lib/generationCancel.ts +0 -28
  107. package/lib/generationErrors.ts +0 -238
  108. package/lib/grokImageAdapter.ts +0 -513
  109. package/lib/grokMultimodeAdapter.ts +0 -84
  110. package/lib/grokProxyLauncher.ts +0 -153
  111. package/lib/grokRuntime.ts +0 -23
  112. package/lib/grokSizeMapper.ts +0 -71
  113. package/lib/grokVideoAdapter.ts +0 -458
  114. package/lib/grokVideoCanvas.ts +0 -26
  115. package/lib/grokVideoDownload.ts +0 -59
  116. package/lib/grokVideoPlannerPrompt.ts +0 -67
  117. package/lib/historyIndex.ts +0 -51
  118. package/lib/historyList.ts +0 -181
  119. package/lib/imageMetadata.ts +0 -113
  120. package/lib/imageMetadataStore.ts +0 -67
  121. package/lib/imageModels.ts +0 -165
  122. package/lib/inflight.ts +0 -281
  123. package/lib/localImportStore.ts +0 -114
  124. package/lib/logger.ts +0 -161
  125. package/lib/nodeStore.ts +0 -91
  126. package/lib/oauthLauncher.ts +0 -94
  127. package/lib/oauthNormalize.ts +0 -30
  128. package/lib/oauthProxy/errors.ts +0 -128
  129. package/lib/oauthProxy/generators.ts +0 -494
  130. package/lib/oauthProxy/index.ts +0 -28
  131. package/lib/oauthProxy/prompts.ts +0 -123
  132. package/lib/oauthProxy/references.ts +0 -45
  133. package/lib/oauthProxy/runtime.ts +0 -115
  134. package/lib/oauthProxy/streams.ts +0 -232
  135. package/lib/oauthProxy/types.ts +0 -9
  136. package/lib/oauthProxy.ts +0 -3
  137. package/lib/openDirectory.ts +0 -47
  138. package/lib/pngInfo.ts +0 -26
  139. package/lib/promptBuilder/attachments.ts +0 -74
  140. package/lib/promptBuilder/client.ts +0 -130
  141. package/lib/promptBuilder/constants.ts +0 -9
  142. package/lib/promptBuilder/context.ts +0 -36
  143. package/lib/promptBuilder/errors.ts +0 -12
  144. package/lib/promptBuilder/requestSchema.ts +0 -56
  145. package/lib/promptBuilder/responseParser.ts +0 -219
  146. package/lib/promptBuilder/systemPrompt.ts +0 -135
  147. package/lib/promptBuilder/transport.ts +0 -94
  148. package/lib/promptBuilder/types.ts +0 -109
  149. package/lib/promptImport/curatedSources.ts +0 -141
  150. package/lib/promptImport/discoveryRegistry.ts +0 -329
  151. package/lib/promptImport/errors.ts +0 -18
  152. package/lib/promptImport/githubDiscovery.ts +0 -309
  153. package/lib/promptImport/githubFolder.ts +0 -397
  154. package/lib/promptImport/githubSource.ts +0 -257
  155. package/lib/promptImport/gptImageHints.ts +0 -70
  156. package/lib/promptImport/parsePromptCandidates.ts +0 -179
  157. package/lib/promptImport/promptIndex.ts +0 -326
  158. package/lib/promptImport/rankPromptCandidates.ts +0 -65
  159. package/lib/promptImport/types.ts +0 -103
  160. package/lib/promptSafetyPolicy.ts +0 -5
  161. package/lib/providerOptions.ts +0 -56
  162. package/lib/referenceImageCompress.ts +0 -84
  163. package/lib/refs.ts +0 -133
  164. package/lib/requestLogger.ts +0 -49
  165. package/lib/responsesDoctor.ts +0 -456
  166. package/lib/responsesErrors.ts +0 -83
  167. package/lib/responsesFallback.ts +0 -114
  168. package/lib/responsesImageAdapter.ts +0 -466
  169. package/lib/responsesParse.ts +0 -452
  170. package/lib/responsesTools.ts +0 -28
  171. package/lib/runtimeContext.ts +0 -146
  172. package/lib/runtimePorts.ts +0 -105
  173. package/lib/sessionStore.ts +0 -308
  174. package/lib/storageMigration.ts +0 -310
  175. package/lib/styleSheet.ts +0 -139
  176. package/lib/systemTrash.ts +0 -20
  177. package/lib/videoContinuity.ts +0 -180
  178. package/lib/videoFrameExtract.ts +0 -78
  179. package/lib/videoSeriesChain.ts +0 -29
  180. package/lib/visibleTextLanguagePolicy.ts +0 -7
  181. package/routes/agent.ts +0 -308
  182. package/routes/annotations.ts +0 -118
  183. package/routes/canvasVersions.ts +0 -69
  184. package/routes/capabilities.ts +0 -18
  185. package/routes/cardNews.ts +0 -211
  186. package/routes/comfy.ts +0 -43
  187. package/routes/edit.ts +0 -352
  188. package/routes/generate.ts +0 -492
  189. package/routes/grok.ts +0 -24
  190. package/routes/health.ts +0 -123
  191. package/routes/history.ts +0 -221
  192. package/routes/imageImport.ts +0 -37
  193. package/routes/index.ts +0 -52
  194. package/routes/metadata.ts +0 -77
  195. package/routes/multimode.ts +0 -499
  196. package/routes/nodes.ts +0 -578
  197. package/routes/promptBuilder.ts +0 -37
  198. package/routes/promptImport.ts +0 -379
  199. package/routes/prompts.ts +0 -428
  200. package/routes/quota.ts +0 -89
  201. package/routes/sessions.ts +0 -317
  202. package/routes/storage.ts +0 -47
  203. package/routes/video.ts +0 -300
  204. package/routes/videoExtended.ts +0 -284
  205. package/server.ts +0 -293
  206. package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
  207. package/ui/dist/assets/index-CjgnNtgt.css +0 -1
  208. 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
- }