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.
- package/README.md +30 -4
- package/bin/ima2.js +14 -4
- package/bin/lib/platform.js +34 -5
- package/docs/README.ko.md +31 -0
- package/lib/agentQueueWorker.js +6 -0
- package/lib/agentRuntime.js +3 -2
- package/lib/atomicWrite.js +14 -0
- package/lib/grokProxyLauncher.js +5 -3
- package/lib/inflight.js +1 -1
- package/lib/oauthLauncher.js +5 -0
- package/lib/videoFrameExtract.js +3 -3
- package/package.json +5 -7
- package/routes/edit.js +2 -1
- package/routes/generate.js +4 -3
- package/routes/health.js +4 -3
- package/routes/multimode.js +2 -1
- package/routes/video.js +4 -2
- package/server.js +29 -2
- package/ui/dist/.vite/manifest.json +12 -12
- package/ui/dist/assets/{AgentWorkspace-B_hq9CLg.js → AgentWorkspace-COxQ5TjU.js} +1 -1
- package/ui/dist/assets/{CardNewsWorkspace-wD12J7qk.js → CardNewsWorkspace-B0OkcuVz.js} +1 -1
- package/ui/dist/assets/{NodeCanvas-CI_wuPMf.js → NodeCanvas-BSsclEBh.js} +1 -1
- package/ui/dist/assets/{PromptBuilderPanel-CUTujJUV.js → PromptBuilderPanel-DpC9A5Rz.js} +1 -1
- package/ui/dist/assets/{PromptImportDialog-CUi66jPK.js → PromptImportDialog-CVwT0rLd.js} +2 -2
- package/ui/dist/assets/{PromptImportDiscoverySection-Cm3vrjY4.js → PromptImportDiscoverySection-BDCkRCRs.js} +1 -1
- package/ui/dist/assets/{PromptImportFolderSection-DOtWTD9n.js → PromptImportFolderSection-QoKbZD83.js} +1 -1
- package/ui/dist/assets/{PromptLibraryPanel-BMjQegRa.js → PromptLibraryPanel-BhFgeKnY.js} +2 -2
- package/ui/dist/assets/SettingsWorkspace-CfjrlH5R.js +1 -0
- package/ui/dist/assets/index-C-mur7pa.css +1 -0
- package/ui/dist/assets/index-CCP5nUOj.js +42 -0
- package/ui/dist/assets/{index-31uVIdt4.js → index-Cxhzi3bs.js} +1 -1
- package/ui/dist/index.html +2 -2
- package/bin/commands/annotate.ts +0 -119
- package/bin/commands/cancel.ts +0 -48
- package/bin/commands/canvas-versions.ts +0 -80
- package/bin/commands/capabilities.ts +0 -110
- package/bin/commands/cardnews.ts +0 -249
- package/bin/commands/comfy.ts +0 -54
- package/bin/commands/config.ts +0 -186
- package/bin/commands/defaults.ts +0 -192
- package/bin/commands/doctor.ts +0 -202
- package/bin/commands/edit.ts +0 -150
- package/bin/commands/gen.ts +0 -214
- package/bin/commands/grok.ts +0 -90
- package/bin/commands/history.ts +0 -146
- package/bin/commands/ls.ts +0 -64
- package/bin/commands/metadata.ts +0 -39
- package/bin/commands/multimode.ts +0 -196
- package/bin/commands/node.ts +0 -166
- package/bin/commands/observability.ts +0 -176
- package/bin/commands/ping.ts +0 -31
- package/bin/commands/prompt-sub/build.ts +0 -101
- package/bin/commands/prompt.ts +0 -492
- package/bin/commands/ps.ts +0 -81
- package/bin/commands/session.ts +0 -266
- package/bin/commands/show.ts +0 -72
- package/bin/commands/skill.ts +0 -70
- package/bin/commands/video.ts +0 -442
- package/bin/ima2.ts +0 -430
- package/bin/lib/args.ts +0 -92
- package/bin/lib/browser-id.ts +0 -16
- package/bin/lib/client.ts +0 -122
- package/bin/lib/config-store.ts +0 -120
- package/bin/lib/destructive-confirm.ts +0 -19
- package/bin/lib/doctor-checks.ts +0 -91
- package/bin/lib/error-hints.ts +0 -23
- package/bin/lib/files.ts +0 -39
- package/bin/lib/output.ts +0 -73
- package/bin/lib/platform.ts +0 -99
- package/bin/lib/recover-output.ts +0 -139
- package/bin/lib/sse.ts +0 -73
- package/bin/lib/star-prompt.ts +0 -97
- package/bin/lib/storage-doctor.ts +0 -39
- package/bin/lib/ui-build.ts +0 -85
- package/config.ts +0 -354
- package/lib/agentCommandParser.ts +0 -69
- package/lib/agentGenerationPlanner.ts +0 -273
- package/lib/agentQuestionResponder.ts +0 -266
- package/lib/agentQueueStore.ts +0 -270
- package/lib/agentQueueWorker.ts +0 -89
- package/lib/agentRuntime.ts +0 -604
- package/lib/agentSettings.ts +0 -72
- package/lib/agentStore.ts +0 -422
- package/lib/agentStoreRows.ts +0 -136
- package/lib/agentTypes.ts +0 -154
- package/lib/apiCachePolicy.ts +0 -11
- package/lib/assetLifecycle.ts +0 -146
- package/lib/canvasVersionStore.ts +0 -223
- package/lib/capabilities.ts +0 -126
- package/lib/cardNewsGenerator.ts +0 -271
- package/lib/cardNewsJobStore.ts +0 -142
- package/lib/cardNewsManifestStore.ts +0 -154
- package/lib/cardNewsPlanner.ts +0 -236
- package/lib/cardNewsPlannerClient.ts +0 -155
- package/lib/cardNewsPlannerPrompt.ts +0 -62
- package/lib/cardNewsPlannerSchema.ts +0 -321
- package/lib/cardNewsRoleTemplateStore.ts +0 -47
- package/lib/cardNewsTemplateStore.ts +0 -252
- package/lib/codexDetect.ts +0 -71
- package/lib/comfyBridge.ts +0 -235
- package/lib/composerSnapshot.ts +0 -33
- package/lib/configKeys.ts +0 -62
- package/lib/db.ts +0 -295
- package/lib/errInfo.ts +0 -43
- package/lib/errorClassify.ts +0 -100
- package/lib/generationCancel.ts +0 -28
- package/lib/generationErrors.ts +0 -238
- package/lib/grokImageAdapter.ts +0 -513
- package/lib/grokMultimodeAdapter.ts +0 -84
- package/lib/grokProxyLauncher.ts +0 -153
- package/lib/grokRuntime.ts +0 -23
- package/lib/grokSizeMapper.ts +0 -71
- package/lib/grokVideoAdapter.ts +0 -458
- package/lib/grokVideoCanvas.ts +0 -26
- package/lib/grokVideoDownload.ts +0 -59
- package/lib/grokVideoPlannerPrompt.ts +0 -67
- package/lib/historyIndex.ts +0 -51
- package/lib/historyList.ts +0 -181
- package/lib/imageMetadata.ts +0 -113
- package/lib/imageMetadataStore.ts +0 -67
- package/lib/imageModels.ts +0 -165
- package/lib/inflight.ts +0 -281
- package/lib/localImportStore.ts +0 -114
- package/lib/logger.ts +0 -161
- package/lib/nodeStore.ts +0 -91
- package/lib/oauthLauncher.ts +0 -94
- package/lib/oauthNormalize.ts +0 -30
- package/lib/oauthProxy/errors.ts +0 -128
- package/lib/oauthProxy/generators.ts +0 -494
- package/lib/oauthProxy/index.ts +0 -28
- package/lib/oauthProxy/prompts.ts +0 -123
- package/lib/oauthProxy/references.ts +0 -45
- package/lib/oauthProxy/runtime.ts +0 -115
- package/lib/oauthProxy/streams.ts +0 -232
- package/lib/oauthProxy/types.ts +0 -9
- package/lib/oauthProxy.ts +0 -3
- package/lib/openDirectory.ts +0 -47
- package/lib/pngInfo.ts +0 -26
- package/lib/promptBuilder/attachments.ts +0 -74
- package/lib/promptBuilder/client.ts +0 -130
- package/lib/promptBuilder/constants.ts +0 -9
- package/lib/promptBuilder/context.ts +0 -36
- package/lib/promptBuilder/errors.ts +0 -12
- package/lib/promptBuilder/requestSchema.ts +0 -56
- package/lib/promptBuilder/responseParser.ts +0 -219
- package/lib/promptBuilder/systemPrompt.ts +0 -135
- package/lib/promptBuilder/transport.ts +0 -94
- package/lib/promptBuilder/types.ts +0 -109
- package/lib/promptImport/curatedSources.ts +0 -141
- package/lib/promptImport/discoveryRegistry.ts +0 -329
- package/lib/promptImport/errors.ts +0 -18
- package/lib/promptImport/githubDiscovery.ts +0 -309
- package/lib/promptImport/githubFolder.ts +0 -397
- package/lib/promptImport/githubSource.ts +0 -257
- package/lib/promptImport/gptImageHints.ts +0 -70
- package/lib/promptImport/parsePromptCandidates.ts +0 -179
- package/lib/promptImport/promptIndex.ts +0 -326
- package/lib/promptImport/rankPromptCandidates.ts +0 -65
- package/lib/promptImport/types.ts +0 -103
- package/lib/promptSafetyPolicy.ts +0 -5
- package/lib/providerOptions.ts +0 -56
- package/lib/referenceImageCompress.ts +0 -84
- package/lib/refs.ts +0 -133
- package/lib/requestLogger.ts +0 -49
- package/lib/responsesDoctor.ts +0 -456
- package/lib/responsesErrors.ts +0 -83
- package/lib/responsesFallback.ts +0 -114
- package/lib/responsesImageAdapter.ts +0 -466
- package/lib/responsesParse.ts +0 -452
- package/lib/responsesTools.ts +0 -28
- package/lib/runtimeContext.ts +0 -146
- package/lib/runtimePorts.ts +0 -105
- package/lib/sessionStore.ts +0 -308
- package/lib/storageMigration.ts +0 -310
- package/lib/styleSheet.ts +0 -139
- package/lib/systemTrash.ts +0 -20
- package/lib/videoContinuity.ts +0 -180
- package/lib/videoFrameExtract.ts +0 -78
- package/lib/videoSeriesChain.ts +0 -29
- package/lib/visibleTextLanguagePolicy.ts +0 -7
- package/routes/agent.ts +0 -308
- package/routes/annotations.ts +0 -118
- package/routes/canvasVersions.ts +0 -69
- package/routes/capabilities.ts +0 -18
- package/routes/cardNews.ts +0 -211
- package/routes/comfy.ts +0 -43
- package/routes/edit.ts +0 -352
- package/routes/generate.ts +0 -492
- package/routes/grok.ts +0 -24
- package/routes/health.ts +0 -123
- package/routes/history.ts +0 -221
- package/routes/imageImport.ts +0 -37
- package/routes/index.ts +0 -52
- package/routes/metadata.ts +0 -77
- package/routes/multimode.ts +0 -499
- package/routes/nodes.ts +0 -578
- package/routes/promptBuilder.ts +0 -37
- package/routes/promptImport.ts +0 -379
- package/routes/prompts.ts +0 -428
- package/routes/quota.ts +0 -89
- package/routes/sessions.ts +0 -317
- package/routes/storage.ts +0 -47
- package/routes/video.ts +0 -300
- package/routes/videoExtended.ts +0 -284
- package/server.ts +0 -293
- package/ui/dist/assets/SettingsWorkspace-PiaVnsdA.js +0 -1
- package/ui/dist/assets/index-CjgnNtgt.css +0 -1
- package/ui/dist/assets/index-Da2s4_-5.js +0 -36
package/README.md
CHANGED
|
@@ -41,6 +41,27 @@ If `3333` is already occupied, `ima2-gen` binds the next available port and writ
|
|
|
41
41
|
|
|
42
42
|
> **Using npx?** See [docs/NPX_QUICKSTART.md](docs/NPX_QUICKSTART.md) for the `npx ima2-gen serve` workflow.
|
|
43
43
|
|
|
44
|
+
### One-Click Install (no npm required)
|
|
45
|
+
|
|
46
|
+
Don't have Node.js or npm? Use the platform install script — it detects your environment, installs Node LTS if needed, then installs ima2-gen.
|
|
47
|
+
|
|
48
|
+
**macOS:**
|
|
49
|
+
```bash
|
|
50
|
+
curl -fsSL https://lidge-jun.github.io/ima2-gen/install-mac.sh | bash
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Windows (PowerShell):**
|
|
54
|
+
```powershell
|
|
55
|
+
irm https://lidge-jun.github.io/ima2-gen/install-windows.ps1 | iex
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Linux / WSL:**
|
|
59
|
+
```bash
|
|
60
|
+
curl -fsSL https://lidge-jun.github.io/ima2-gen/install-linux.sh | bash
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Each script checks for nvm/fnm/brew/winget, installs Node LTS through the best available method, and handles stale process cleanup automatically.
|
|
64
|
+
|
|
44
65
|
### Setup
|
|
45
66
|
|
|
46
67
|
`ima2 setup` offers four authentication choices:
|
|
@@ -52,10 +73,15 @@ If `3333` is already occupied, `ima2-gen` binds the next available port and writ
|
|
|
52
73
|
|
|
53
74
|
Video generation requires Grok OAuth (option 2 or 3). Run `ima2 grok login` separately if you already have GPT OAuth configured and want to add video support; it defaults to the manual-paste flow.
|
|
54
75
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
### Updating
|
|
77
|
+
|
|
78
|
+
Stop the running server with Ctrl+C, then:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install -g ima2-gen@latest
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Ctrl+C now performs a clean shutdown — closing the database, stopping child processes, and releasing file locks. On older versions (< 1.1.22) or if you see `EBUSY` on Windows, use the install script which handles stale process cleanup automatically.
|
|
59
85
|
|
|
60
86
|
## What It Does
|
|
61
87
|
|
package/bin/ima2.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath } from "url";
|
|
|
6
6
|
import { spawn, execSync } from "child_process";
|
|
7
7
|
import { confirmDestructiveAction } from "./lib/destructive-confirm.js";
|
|
8
8
|
import { doctor } from "./commands/doctor.js";
|
|
9
|
-
import { openUrl, resolveBin } from "./lib/platform.js";
|
|
9
|
+
import { openUrl, resolveBin, killProcessTree } from "./lib/platform.js";
|
|
10
10
|
import { maybePromptGithubStar } from "./lib/star-prompt.js";
|
|
11
11
|
import { ensureFreshUiDist } from "./lib/ui-build.js";
|
|
12
12
|
import { detectCodexAuth } from "../lib/codexDetect.js";
|
|
@@ -197,9 +197,16 @@ async function serve(serveArgs = []) {
|
|
|
197
197
|
env,
|
|
198
198
|
cwd: ROOT,
|
|
199
199
|
});
|
|
200
|
+
child.on("error", (err) => {
|
|
201
|
+
console.error(`[ima2] Failed to start server: ${err.message}`);
|
|
202
|
+
process.exit(1);
|
|
203
|
+
});
|
|
200
204
|
child.on("exit", (code) => process.exit(code));
|
|
201
|
-
process.on("SIGINT", () => child.
|
|
202
|
-
process.on("SIGTERM", () => child.
|
|
205
|
+
process.on("SIGINT", () => killProcessTree(child.pid));
|
|
206
|
+
process.on("SIGTERM", () => killProcessTree(child.pid));
|
|
207
|
+
if (process.platform === "win32") {
|
|
208
|
+
process.on("SIGBREAK", () => killProcessTree(child.pid));
|
|
209
|
+
}
|
|
203
210
|
}
|
|
204
211
|
async function showStatus() {
|
|
205
212
|
const config = loadConfig();
|
|
@@ -335,7 +342,10 @@ switch (command) {
|
|
|
335
342
|
break;
|
|
336
343
|
case "setup":
|
|
337
344
|
case "login":
|
|
338
|
-
setup().then(() => console.log(" Done. Run 'ima2 serve' to start."))
|
|
345
|
+
setup().then(() => console.log(" Done. Run 'ima2 serve' to start.")).catch((e) => {
|
|
346
|
+
console.error(`Setup failed: ${e?.message || e}`);
|
|
347
|
+
process.exit(1);
|
|
348
|
+
});
|
|
339
349
|
break;
|
|
340
350
|
case "status":
|
|
341
351
|
showStatus();
|
package/bin/lib/platform.js
CHANGED
|
@@ -80,20 +80,29 @@ export function openUrl(url) {
|
|
|
80
80
|
* Windows does NOT raise SIGTERM from the OS — SIGINT (Ctrl+C) and SIGBREAK
|
|
81
81
|
* (Ctrl+Break) are the observable signals. We still register SIGTERM so that
|
|
82
82
|
* Node-internal `child.kill("SIGTERM")` calls work in tests.
|
|
83
|
+
*
|
|
84
|
+
* Handlers may return a Promise — they run with a grace period (default 3s)
|
|
85
|
+
* before forceful exit, giving file handles and sockets time to close cleanly.
|
|
83
86
|
*/
|
|
87
|
+
const SHUTDOWN_GRACE_MS = 3_000;
|
|
88
|
+
let shutdownStarted = false;
|
|
84
89
|
export function onShutdown(handler) {
|
|
85
90
|
const signals = isWin
|
|
86
91
|
? ["SIGINT", "SIGTERM", "SIGBREAK"]
|
|
87
92
|
: ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
88
93
|
for (const sig of signals) {
|
|
89
94
|
try {
|
|
90
|
-
process.on(sig, () => {
|
|
95
|
+
process.on(sig, async () => {
|
|
96
|
+
if (shutdownStarted)
|
|
97
|
+
return;
|
|
98
|
+
shutdownStarted = true;
|
|
99
|
+
const forceExit = setTimeout(() => process.exit(0), SHUTDOWN_GRACE_MS);
|
|
100
|
+
forceExit.unref?.();
|
|
91
101
|
try {
|
|
92
|
-
handler(sig);
|
|
93
|
-
}
|
|
94
|
-
finally {
|
|
95
|
-
process.exit(0);
|
|
102
|
+
await handler(sig);
|
|
96
103
|
}
|
|
104
|
+
catch { }
|
|
105
|
+
process.exit(0);
|
|
97
106
|
});
|
|
98
107
|
}
|
|
99
108
|
catch {
|
|
@@ -101,3 +110,23 @@ export function onShutdown(handler) {
|
|
|
101
110
|
}
|
|
102
111
|
}
|
|
103
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Kill an entire process tree. On Windows, child.kill() only kills the
|
|
115
|
+
* immediate process, leaving grandchildren alive and holding file locks.
|
|
116
|
+
* taskkill /T /F kills the whole tree.
|
|
117
|
+
*/
|
|
118
|
+
export function killProcessTree(pid) {
|
|
119
|
+
if (!pid)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
if (isWin) {
|
|
123
|
+
execSync(`taskkill /T /F /PID ${pid}`, { stdio: "ignore" });
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
process.kill(pid, "SIGTERM");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Process already exited
|
|
131
|
+
}
|
|
132
|
+
}
|
package/docs/README.ko.md
CHANGED
|
@@ -30,6 +30,37 @@ ima2 serve
|
|
|
30
30
|
|
|
31
31
|
> **npx로 실행하고 싶다면?** [NPX_QUICKSTART.md](NPX_QUICKSTART.md)를 참고하세요.
|
|
32
32
|
|
|
33
|
+
### 원클릭 설치 (npm 없어도 됩니다)
|
|
34
|
+
|
|
35
|
+
Node.js나 npm이 없어도 플랫폼별 설치 스크립트로 한 번에 설치할 수 있습니다.
|
|
36
|
+
|
|
37
|
+
**macOS:**
|
|
38
|
+
```bash
|
|
39
|
+
curl -fsSL https://lidge-jun.github.io/ima2-gen/install-mac.sh | bash
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Windows (PowerShell):**
|
|
43
|
+
```powershell
|
|
44
|
+
irm https://lidge-jun.github.io/ima2-gen/install-windows.ps1 | iex
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Linux / WSL:**
|
|
48
|
+
```bash
|
|
49
|
+
curl -fsSL https://lidge-jun.github.io/ima2-gen/install-linux.sh | bash
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
각 스크립트가 nvm/fnm/brew/winget을 감지하고, 없으면 Node LTS를 자동 설치한 뒤, ima2-gen을 설치합니다.
|
|
53
|
+
|
|
54
|
+
### 업데이트
|
|
55
|
+
|
|
56
|
+
Ctrl+C로 서버를 종료한 뒤:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install -g ima2-gen@latest
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
v1.1.22부터 Ctrl+C가 DB, 소켓, 자식 프로세스를 깨끗하게 정리합니다. 이전 버전이거나 Windows에서 `EBUSY` 에러가 나면 위의 설치 스크립트를 다시 실행하세요 — 잔여 프로세스를 자동으로 정리합니다.
|
|
63
|
+
|
|
33
64
|
### 설정
|
|
34
65
|
|
|
35
66
|
`ima2 setup`으로 인증 방식을 선택합니다:
|
package/lib/agentQueueWorker.js
CHANGED
|
@@ -18,6 +18,12 @@ export function ensureAgentQueueWorker(ctx) {
|
|
|
18
18
|
workerTimer.unref?.();
|
|
19
19
|
void tickAgentQueueWorker(ctx);
|
|
20
20
|
}
|
|
21
|
+
export function stopAgentQueueWorker() {
|
|
22
|
+
if (workerTimer) {
|
|
23
|
+
clearInterval(workerTimer);
|
|
24
|
+
workerTimer = null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
21
27
|
export async function tickAgentQueueWorker(ctx) {
|
|
22
28
|
if (ticking)
|
|
23
29
|
return;
|
package/lib/agentRuntime.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { atomicWriteJson } from "./atomicWrite.js";
|
|
3
4
|
import { join } from "node:path";
|
|
4
5
|
import { ulid } from "ulid";
|
|
5
6
|
import { embedImageMetadataBestEffort } from "./imageMetadataStore.js";
|
|
@@ -305,7 +306,7 @@ async function persistAgentImage(ctx, sessionId, prompt, format, requestId, resp
|
|
|
305
306
|
const filePath = join(ctx.config.storage.generatedDir, filename);
|
|
306
307
|
await writeFile(filePath, embedded.buffer);
|
|
307
308
|
try {
|
|
308
|
-
await
|
|
309
|
+
await atomicWriteJson(`${filePath}.json`, meta);
|
|
309
310
|
}
|
|
310
311
|
catch (err) {
|
|
311
312
|
await unlink(filePath).catch(() => { });
|
|
@@ -409,7 +410,7 @@ async function persistAgentVideo(ctx, sessionId, prompt, requestId, result) {
|
|
|
409
410
|
const filePath = join(ctx.config.storage.generatedDir, filename);
|
|
410
411
|
await writeFile(filePath, result.videoBuffer);
|
|
411
412
|
try {
|
|
412
|
-
await
|
|
413
|
+
await atomicWriteJson(`${filePath}.json`, meta);
|
|
413
414
|
}
|
|
414
415
|
catch (err) {
|
|
415
416
|
await unlink(filePath).catch(() => { });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { writeFile, rename, unlink } from "node:fs/promises";
|
|
2
|
+
export async function atomicWriteJson(path, data) {
|
|
3
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
4
|
+
await writeFile(tmp, JSON.stringify(data));
|
|
5
|
+
await rename(tmp, path);
|
|
6
|
+
}
|
|
7
|
+
export async function safeWriteSidecar(path, data) {
|
|
8
|
+
try {
|
|
9
|
+
await atomicWriteJson(path, data);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
await unlink(`${path}.${process.pid}.tmp`).catch(() => { });
|
|
13
|
+
}
|
|
14
|
+
}
|
package/lib/grokProxyLauncher.js
CHANGED
|
@@ -66,6 +66,11 @@ export async function startGrokProxy(options = {}) {
|
|
|
66
66
|
});
|
|
67
67
|
currentChild = child;
|
|
68
68
|
authRequired = false;
|
|
69
|
+
child.on("error", (err) => {
|
|
70
|
+
console.error(`[grok] failed to start progrok proxy: ${err.message}`);
|
|
71
|
+
if (currentChild === child)
|
|
72
|
+
currentChild = null;
|
|
73
|
+
});
|
|
69
74
|
child.stdout?.on("data", (d) => {
|
|
70
75
|
const msg = normalizeGrokProxyMessage(d.toString().trim());
|
|
71
76
|
if (!msg)
|
|
@@ -90,9 +95,6 @@ export async function startGrokProxy(options = {}) {
|
|
|
90
95
|
authRequired = true;
|
|
91
96
|
}
|
|
92
97
|
});
|
|
93
|
-
child.on("error", (err) => {
|
|
94
|
-
console.error(`[grok] failed to start progrok proxy: ${err.message}`);
|
|
95
|
-
});
|
|
96
98
|
child.on("exit", (code) => {
|
|
97
99
|
if (currentChild === child)
|
|
98
100
|
currentChild = null;
|
package/lib/inflight.js
CHANGED
|
@@ -113,7 +113,7 @@ export function finishJob(requestId, options = {}) {
|
|
|
113
113
|
abortControllers.delete(requestId);
|
|
114
114
|
reapTerminalJobs();
|
|
115
115
|
}
|
|
116
|
-
function reapTerminalJobs() {
|
|
116
|
+
export function reapTerminalJobs() {
|
|
117
117
|
const now = Date.now();
|
|
118
118
|
for (const [id, j] of terminalJobs) {
|
|
119
119
|
if (now - j.finishedAt > config.inflight.terminalTtlMs)
|
package/lib/oauthLauncher.js
CHANGED
|
@@ -29,6 +29,11 @@ export function startOAuthProxy(options = {}) {
|
|
|
29
29
|
env: { ...process.env },
|
|
30
30
|
});
|
|
31
31
|
currentChild = child;
|
|
32
|
+
child.on("error", (err) => {
|
|
33
|
+
console.error(`[gpt-oauth] failed to start proxy: ${err.message}`);
|
|
34
|
+
if (currentChild === child)
|
|
35
|
+
currentChild = null;
|
|
36
|
+
});
|
|
32
37
|
child.stdout?.on("data", (d) => {
|
|
33
38
|
const msg = d.toString().trim();
|
|
34
39
|
if (!msg)
|
package/lib/videoFrameExtract.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
import { open, readFile, realpath, stat, unlink } from "node:fs/promises";
|
|
4
|
-
import { extname, join, resolve, sep } from "node:path";
|
|
4
|
+
import { extname, isAbsolute, join, resolve, sep } from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
const MAX_LOCAL_VIDEO_BYTES = 100 * 1024 * 1024;
|
|
@@ -12,7 +12,7 @@ function routeError(message, status = 400) {
|
|
|
12
12
|
}
|
|
13
13
|
export async function safeGeneratedFilePath(generatedDir, file, options = {}) {
|
|
14
14
|
const base = resolve(generatedDir);
|
|
15
|
-
const target = file
|
|
15
|
+
const target = isAbsolute(file) ? resolve(file) : resolve(base, file);
|
|
16
16
|
if (target !== base && !target.startsWith(`${base}${sep}`)) {
|
|
17
17
|
throw routeError("invalid file path", 400);
|
|
18
18
|
}
|
|
@@ -54,7 +54,7 @@ export async function assertLocalMp4(path) {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
export async function extractVideoFrame(input, output, position) {
|
|
57
|
-
const options = { timeout: FFMPEG_TIMEOUT_MS, killSignal: "SIGKILL", maxBuffer: 1024 * 1024 };
|
|
57
|
+
const options = { timeout: FFMPEG_TIMEOUT_MS, killSignal: (process.platform === "win32" ? "SIGTERM" : "SIGKILL"), maxBuffer: 1024 * 1024 };
|
|
58
58
|
if (position === "last") {
|
|
59
59
|
await execFileAsync("ffmpeg", ["-y", "-sseof", "-3", "-i", input, "-update", "1", "-q:v", "1", output], options);
|
|
60
60
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ima2-gen",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.22",
|
|
4
4
|
"description": "Local OAuth image generation studio with classic and node workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"setup": "node bin/ima2.js setup",
|
|
21
21
|
"prepack": "npm run ui:build && npm run build:server && npm run build:cli",
|
|
22
22
|
"prepublishOnly": "npm run typecheck && npm run typecheck:tests && npm run test:inventory && npm run ui:build && npm run build:server && npm run build:cli && npm run lint:pkg && npm run test:package-install",
|
|
23
|
-
"lint:pkg": "node -e \"const p=require('./package.json'); const req=['name','version','bin']; for(const k of req){if(!p[k])throw new Error('missing '+k)} const mustInclude=['bin
|
|
23
|
+
"lint:pkg": "node -e \"const p=require('./package.json'); const req=['name','version','bin']; for(const k of req){if(!p[k])throw new Error('missing '+k)} const mustInclude=['bin/**/*.js','lib/**/*.js','routes/**/*.js','skills/','integrations/comfyui/ima2_gen_bridge/__init__.py','integrations/comfyui/ima2_gen_bridge/nodes.py','integrations/comfyui/ima2_gen_bridge/README.md','assets/card-news/templates/','vendor/','server.js','LICENSE']; for(const f of mustInclude){if(!p.files.includes(f))throw new Error('files[] must include '+f)}\"",
|
|
24
24
|
"publish:dry-run": "node scripts/publish-dry-run.mjs",
|
|
25
25
|
"release:patch": "npm version patch && npm publish && git push origin main --tags",
|
|
26
26
|
"release:minor": "npm version minor && npm publish && git push origin main --tags",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"url": "git+https://github.com/lidge-jun/ima2-gen.git"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
|
-
"bin
|
|
47
|
-
"lib
|
|
48
|
-
"routes
|
|
46
|
+
"bin/**/*.js",
|
|
47
|
+
"lib/**/*.js",
|
|
48
|
+
"routes/**/*.js",
|
|
49
49
|
"skills/",
|
|
50
50
|
"integrations/comfyui/ima2_gen_bridge/__init__.py",
|
|
51
51
|
"integrations/comfyui/ima2_gen_bridge/nodes.py",
|
|
@@ -54,8 +54,6 @@
|
|
|
54
54
|
"docs/",
|
|
55
55
|
"vendor/",
|
|
56
56
|
"assets/card-news/templates/",
|
|
57
|
-
"server.ts",
|
|
58
|
-
"config.ts",
|
|
59
57
|
".env.example",
|
|
60
58
|
"README.md",
|
|
61
59
|
"LICENSE",
|
package/routes/edit.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "fs/promises";
|
|
2
|
+
import { safeWriteSidecar } from "../lib/atomicWrite.js";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { randomBytes } from "crypto";
|
|
4
5
|
import { detectImageMimeFromB64 } from "../lib/refs.js";
|
|
@@ -222,7 +223,7 @@ export function registerEditRoutes(app, ctxRaw) {
|
|
|
222
223
|
webSearchCalls,
|
|
223
224
|
webSearchEnabled,
|
|
224
225
|
};
|
|
225
|
-
await
|
|
226
|
+
await safeWriteSidecar(join(ctx.config.storage.generatedDir, filename + ".json"), meta);
|
|
226
227
|
invalidateHistoryIndex();
|
|
227
228
|
finishHttpStatus = 200;
|
|
228
229
|
finishMeta = { filename, imageChars: resultB64.length };
|
package/routes/generate.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2
|
+
import { safeWriteSidecar, atomicWriteJson } from "../lib/atomicWrite.js";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { randomBytes } from "crypto";
|
|
4
5
|
import { detectImageMimeFromB64, summarizeReferencePayload, validateAndNormalizeRefs } from "../lib/refs.js";
|
|
@@ -260,7 +261,7 @@ export function registerGenerateRoutes(app, ctxRaw) {
|
|
|
260
261
|
});
|
|
261
262
|
}
|
|
262
263
|
await writeFile(join(ctx.config.storage.generatedDir, filename), embedded.buffer);
|
|
263
|
-
await
|
|
264
|
+
await safeWriteSidecar(join(ctx.config.storage.generatedDir, filename + ".json"), meta);
|
|
264
265
|
invalidateHistoryIndex();
|
|
265
266
|
images.push({
|
|
266
267
|
image: `data:${resultMime};base64,${r.value.b64}`,
|
|
@@ -346,10 +347,10 @@ export function registerGenerateRoutes(app, ctxRaw) {
|
|
|
346
347
|
const sidecarPath = join(ctx.config.storage.generatedDir, filename + ".json");
|
|
347
348
|
const sidecarMeta = JSON.parse(await readFile(sidecarPath, "utf-8"));
|
|
348
349
|
sidecarMeta.elapsed = elapsed;
|
|
349
|
-
await
|
|
350
|
+
await atomicWriteJson(sidecarPath, sidecarMeta);
|
|
350
351
|
}
|
|
351
352
|
catch {
|
|
352
|
-
/* best-effort
|
|
353
|
+
/* best-effort elapsed patch */
|
|
353
354
|
}
|
|
354
355
|
}));
|
|
355
356
|
const firstRevised = images[0]?.revisedPrompt || null;
|
package/routes/health.js
CHANGED
|
@@ -95,10 +95,11 @@ export function registerHealthRoutes(app, ctxRaw) {
|
|
|
95
95
|
const headers = { Authorization: `Bearer ${ctx.apiKey}`, "Content-Type": "application/json" };
|
|
96
96
|
const start = Math.floor(new Date(new Date().getFullYear(), new Date().getMonth(), 1).getTime() / 1000);
|
|
97
97
|
const end = Math.floor(Date.now() / 1000);
|
|
98
|
+
const billingSignal = AbortSignal.timeout(10_000);
|
|
98
99
|
const [subRes, usageRes, modelsRes] = await Promise.allSettled([
|
|
99
|
-
fetch(`https://api.openai.com/v1/organization/costs?start_time=${start}&end_time=${end}&bucket_width=1d&limit=31`, { headers }),
|
|
100
|
-
fetch("https://api.openai.com/dashboard/billing/credit_grants", { headers }),
|
|
101
|
-
fetch("https://api.openai.com/v1/models", { headers }),
|
|
100
|
+
fetch(`https://api.openai.com/v1/organization/costs?start_time=${start}&end_time=${end}&bucket_width=1d&limit=31`, { headers, signal: billingSignal }),
|
|
101
|
+
fetch("https://api.openai.com/dashboard/billing/credit_grants", { headers, signal: billingSignal }),
|
|
102
|
+
fetch("https://api.openai.com/v1/models", { headers, signal: billingSignal }),
|
|
102
103
|
]);
|
|
103
104
|
const billing = { apiKeySource: ctx.apiKeySource ?? "env" };
|
|
104
105
|
if (subRes.status === "fulfilled" && subRes.value.ok)
|
package/routes/multimode.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "fs/promises";
|
|
2
|
+
import { safeWriteSidecar } from "../lib/atomicWrite.js";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { randomBytes } from "crypto";
|
|
4
5
|
import { detectImageMimeFromB64, summarizeReferencePayload, validateAndNormalizeRefs } from "../lib/refs.js";
|
|
@@ -217,7 +218,7 @@ export function registerMultimodeRoutes(app, ctxRaw) {
|
|
|
217
218
|
version: ctx.packageVersion,
|
|
218
219
|
});
|
|
219
220
|
await writeFile(join(ctx.config.storage.generatedDir, filename), embedded.buffer);
|
|
220
|
-
await
|
|
221
|
+
await safeWriteSidecar(join(ctx.config.storage.generatedDir, filename + ".json"), meta);
|
|
221
222
|
invalidateHistoryIndex();
|
|
222
223
|
const item = {
|
|
223
224
|
image: `data:${resultMime};base64,${image.b64}`,
|
package/routes/video.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
2
|
+
import { atomicWriteJson } from "../lib/atomicWrite.js";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { randomBytes } from "crypto";
|
|
4
5
|
import { startJob, finishJob, registerJobAbortController, isJobCanceled, setJobPhase } from "../lib/inflight.js";
|
|
@@ -26,7 +27,7 @@ export async function saveGeneratedVideoArtifact(ctx, filename, buffer, metadata
|
|
|
26
27
|
const filePath = join(ctx.config.storage.generatedDir, filename);
|
|
27
28
|
await writeFile(filePath, buffer);
|
|
28
29
|
try {
|
|
29
|
-
await
|
|
30
|
+
await atomicWriteJson(`${filePath}.json`, metadata);
|
|
30
31
|
}
|
|
31
32
|
catch (err) {
|
|
32
33
|
await unlink(filePath).catch(() => { });
|
|
@@ -36,8 +37,9 @@ export async function saveGeneratedVideoArtifact(ctx, filename, buffer, metadata
|
|
|
36
37
|
async function resolveSourceImage(ctx, sourceImage, sourceFilename) {
|
|
37
38
|
if (typeof sourceFilename === "string" && sourceFilename) {
|
|
38
39
|
const safe = sourceFilename.replace(/^\/+/, "");
|
|
39
|
-
if (safe.includes(".."))
|
|
40
|
+
if (safe.includes("..") || safe.includes("/") || safe.includes("\\")) {
|
|
40
41
|
throw { status: 400, code: "GROK_VIDEO_INVALID_MODE", message: "invalid source filename" };
|
|
42
|
+
}
|
|
41
43
|
if (/\.mp4$/i.test(safe))
|
|
42
44
|
throw { status: 400, code: "GROK_VIDEO_INVALID_MODE", message: "use continueFromVideo for generated video continuation" };
|
|
43
45
|
const buf = await readFile(join(ctx.config.storage.generatedDir, safe));
|
package/server.js
CHANGED
|
@@ -16,6 +16,10 @@ import { configureApiCachePolicy } from "./lib/apiCachePolicy.js";
|
|
|
16
16
|
import { configureRoutes } from "./routes/index.js";
|
|
17
17
|
import { config } from "./config.js";
|
|
18
18
|
import { getServerPort, listenWithPortFallback } from "./lib/runtimePorts.js";
|
|
19
|
+
import { closeDb } from "./lib/db.js";
|
|
20
|
+
import { stopAgentQueueWorker } from "./lib/agentQueueWorker.js";
|
|
21
|
+
import { reapCardNewsJobs } from "./lib/cardNewsJobStore.js";
|
|
22
|
+
import { reapTerminalJobs } from "./lib/inflight.js";
|
|
19
23
|
import { errInfo } from "./lib/errInfo.js";
|
|
20
24
|
const rootDir = dirname(fileURLToPath(import.meta.url));
|
|
21
25
|
async function loadApiKey() {
|
|
@@ -228,7 +232,9 @@ export async function startServer(overrides = {}) {
|
|
|
228
232
|
},
|
|
229
233
|
})
|
|
230
234
|
: null;
|
|
231
|
-
|
|
235
|
+
let server;
|
|
236
|
+
let reapTimer;
|
|
237
|
+
onShutdown(async () => {
|
|
232
238
|
unadvertise(ctx);
|
|
233
239
|
try {
|
|
234
240
|
oauthChild?.stop?.();
|
|
@@ -246,9 +252,18 @@ export async function startServer(overrides = {}) {
|
|
|
246
252
|
grokChild?.kill?.();
|
|
247
253
|
}
|
|
248
254
|
catch { }
|
|
255
|
+
stopAgentQueueWorker();
|
|
256
|
+
clearInterval(reapTimer);
|
|
257
|
+
await new Promise((resolve) => {
|
|
258
|
+
if (server)
|
|
259
|
+
server.close(() => resolve());
|
|
260
|
+
else
|
|
261
|
+
resolve();
|
|
262
|
+
});
|
|
263
|
+
closeDb();
|
|
249
264
|
});
|
|
250
265
|
process.on("exit", () => unadvertise(ctx));
|
|
251
|
-
|
|
266
|
+
server = await listenWithPortFallback(app, ctx.config.server.port, {
|
|
252
267
|
host: ctx.config.server.host,
|
|
253
268
|
label: "server",
|
|
254
269
|
onFallback: ({ requestedPort, actualPort }) => {
|
|
@@ -272,6 +287,18 @@ export async function startServer(overrides = {}) {
|
|
|
272
287
|
console.error("[server] Failed to start:", err?.message || err);
|
|
273
288
|
process.exit(1);
|
|
274
289
|
});
|
|
290
|
+
reapTimer = setInterval(() => {
|
|
291
|
+
reapTerminalJobs();
|
|
292
|
+
reapCardNewsJobs();
|
|
293
|
+
}, 60_000);
|
|
294
|
+
reapTimer.unref?.();
|
|
295
|
+
process.on("uncaughtException", (err) => {
|
|
296
|
+
console.error("[fatal] uncaughtException:", err);
|
|
297
|
+
process.exit(1);
|
|
298
|
+
});
|
|
299
|
+
process.on("unhandledRejection", (reason) => {
|
|
300
|
+
console.error("[fatal] unhandledRejection:", reason);
|
|
301
|
+
});
|
|
275
302
|
return { app, server, oauthChild, ctx };
|
|
276
303
|
}
|
|
277
304
|
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"index.html": {
|
|
3
|
-
"file": "assets/index-
|
|
3
|
+
"file": "assets/index-CCP5nUOj.js",
|
|
4
4
|
"name": "index",
|
|
5
5
|
"src": "index.html",
|
|
6
6
|
"isEntry": true,
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"src/components/PromptLibraryPanel.tsx"
|
|
17
17
|
],
|
|
18
18
|
"css": [
|
|
19
|
-
"assets/index-
|
|
19
|
+
"assets/index-C-mur7pa.css"
|
|
20
20
|
]
|
|
21
21
|
},
|
|
22
22
|
"src/components/NodeCanvas.tsx": {
|
|
23
|
-
"file": "assets/NodeCanvas-
|
|
23
|
+
"file": "assets/NodeCanvas-BSsclEBh.js",
|
|
24
24
|
"name": "NodeCanvas",
|
|
25
25
|
"src": "src/components/NodeCanvas.tsx",
|
|
26
26
|
"isDynamicEntry": true,
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
]
|
|
33
33
|
},
|
|
34
34
|
"src/components/PromptImportDialog.tsx": {
|
|
35
|
-
"file": "assets/PromptImportDialog-
|
|
35
|
+
"file": "assets/PromptImportDialog-CVwT0rLd.js",
|
|
36
36
|
"name": "PromptImportDialog",
|
|
37
37
|
"src": "src/components/PromptImportDialog.tsx",
|
|
38
38
|
"isDynamicEntry": true,
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
]
|
|
46
46
|
},
|
|
47
47
|
"src/components/PromptImportDiscoverySection.tsx": {
|
|
48
|
-
"file": "assets/PromptImportDiscoverySection-
|
|
48
|
+
"file": "assets/PromptImportDiscoverySection-BDCkRCRs.js",
|
|
49
49
|
"name": "PromptImportDiscoverySection",
|
|
50
50
|
"src": "src/components/PromptImportDiscoverySection.tsx",
|
|
51
51
|
"isDynamicEntry": true,
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
]
|
|
55
55
|
},
|
|
56
56
|
"src/components/PromptImportFolderSection.tsx": {
|
|
57
|
-
"file": "assets/PromptImportFolderSection-
|
|
57
|
+
"file": "assets/PromptImportFolderSection-QoKbZD83.js",
|
|
58
58
|
"name": "PromptImportFolderSection",
|
|
59
59
|
"src": "src/components/PromptImportFolderSection.tsx",
|
|
60
60
|
"isDynamicEntry": true,
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
]
|
|
64
64
|
},
|
|
65
65
|
"src/components/PromptLibraryPanel.tsx": {
|
|
66
|
-
"file": "assets/PromptLibraryPanel-
|
|
66
|
+
"file": "assets/PromptLibraryPanel-BhFgeKnY.js",
|
|
67
67
|
"name": "PromptLibraryPanel",
|
|
68
68
|
"src": "src/components/PromptLibraryPanel.tsx",
|
|
69
69
|
"isDynamicEntry": true,
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
]
|
|
76
76
|
},
|
|
77
77
|
"src/components/SettingsWorkspace.tsx": {
|
|
78
|
-
"file": "assets/SettingsWorkspace-
|
|
78
|
+
"file": "assets/SettingsWorkspace-CfjrlH5R.js",
|
|
79
79
|
"name": "SettingsWorkspace",
|
|
80
80
|
"src": "src/components/SettingsWorkspace.tsx",
|
|
81
81
|
"isDynamicEntry": true,
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
]
|
|
85
85
|
},
|
|
86
86
|
"src/components/agent/AgentWorkspace.tsx": {
|
|
87
|
-
"file": "assets/AgentWorkspace-
|
|
87
|
+
"file": "assets/AgentWorkspace-COxQ5TjU.js",
|
|
88
88
|
"name": "AgentWorkspace",
|
|
89
89
|
"src": "src/components/agent/AgentWorkspace.tsx",
|
|
90
90
|
"isDynamicEntry": true,
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
]
|
|
94
94
|
},
|
|
95
95
|
"src/components/canvas-mode/index.ts": {
|
|
96
|
-
"file": "assets/index-
|
|
96
|
+
"file": "assets/index-Cxhzi3bs.js",
|
|
97
97
|
"name": "index",
|
|
98
98
|
"src": "src/components/canvas-mode/index.ts",
|
|
99
99
|
"isDynamicEntry": true,
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
]
|
|
103
103
|
},
|
|
104
104
|
"src/components/card-news/CardNewsWorkspace.tsx": {
|
|
105
|
-
"file": "assets/CardNewsWorkspace-
|
|
105
|
+
"file": "assets/CardNewsWorkspace-B0OkcuVz.js",
|
|
106
106
|
"name": "CardNewsWorkspace",
|
|
107
107
|
"src": "src/components/card-news/CardNewsWorkspace.tsx",
|
|
108
108
|
"isDynamicEntry": true,
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
]
|
|
112
112
|
},
|
|
113
113
|
"src/components/prompt-builder/PromptBuilderPanel.tsx": {
|
|
114
|
-
"file": "assets/PromptBuilderPanel-
|
|
114
|
+
"file": "assets/PromptBuilderPanel-DpC9A5Rz.js",
|
|
115
115
|
"name": "PromptBuilderPanel",
|
|
116
116
|
"src": "src/components/prompt-builder/PromptBuilderPanel.tsx",
|
|
117
117
|
"isDynamicEntry": true,
|