ima2-gen 3.5.3 → 3.6.0

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 (33) hide show
  1. package/bin/lib/mcpJob.js +38 -0
  2. package/docs/migration/runtime-test-inventory.md +3 -1
  3. package/lib/generatePipeline.js +2 -1
  4. package/lib/inflight.js +17 -1
  5. package/lib/multimodePipeline.js +4 -2
  6. package/lib/nodeHelpers.js +9 -3
  7. package/lib/providers/adapters/atlascloud.js +63 -0
  8. package/lib/providers/adapters/index.js +2 -0
  9. package/package.json +2 -2
  10. package/routes/models.js +16 -3
  11. package/routes/video.js +5 -2
  12. package/routes/videoExtended.js +4 -2
  13. package/ui/dist/.vite/manifest.json +35 -35
  14. package/ui/dist/assets/{AgentWorkspace-BZuw_82p.js → AgentWorkspace-Bfe9PqZy.js} +1 -1
  15. package/ui/dist/assets/{AssetGenWorkspace-D-p57I-0.js → AssetGenWorkspace-XbViHOY0.js} +2 -2
  16. package/ui/dist/assets/{AssetsWorkspace-BlVr5Qjq.js → AssetsWorkspace-HemkY-0A.js} +1 -1
  17. package/ui/dist/assets/{CardNewsWorkspace-BPYWHZqh.js → CardNewsWorkspace-Cchcm8ts.js} +1 -1
  18. package/ui/dist/assets/{GenerationRequestLogPanel-CJYn7vCN.js → GenerationRequestLogPanel-CKw9JLH8.js} +1 -1
  19. package/ui/dist/assets/{HomeWorkspace-DbWuQI7B.js → HomeWorkspace-Do6VnjWR.js} +1 -1
  20. package/ui/dist/assets/{KeyingPanel-hK4oc51k.js → KeyingPanel-D79TCHH_.js} +1 -1
  21. package/ui/dist/assets/{NodeCanvas-CO9FzAfn.js → NodeCanvas-BpNgtUxt.js} +1 -1
  22. package/ui/dist/assets/{PromptBuilderPanel-DEPrkXcU.js → PromptBuilderPanel-DHB1sU7O.js} +1 -1
  23. package/ui/dist/assets/{PromptImportDialog-CGxyjU6L.js → PromptImportDialog-qD_tVhN5.js} +2 -2
  24. package/ui/dist/assets/{PromptImportDiscoverySection-C5PY1YV3.js → PromptImportDiscoverySection-51FDzoLN.js} +1 -1
  25. package/ui/dist/assets/{PromptImportFolderSection-DWsWg6nw.js → PromptImportFolderSection-uQNX1sJ_.js} +1 -1
  26. package/ui/dist/assets/{PromptLibraryPanel-BPiKLU-z.js → PromptLibraryPanel-BngHherb.js} +2 -2
  27. package/ui/dist/assets/{SettingsWorkspace-D1gLUIPQ.js → SettingsWorkspace-dpl5CLsg.js} +1 -1
  28. package/ui/dist/assets/{SpriteRecipeWorkspace-vlnp398m.js → SpriteRecipeWorkspace-IpS6TVAF.js} +1 -1
  29. package/ui/dist/assets/{index-DogXlrkz.js → index-BA51BzWd.js} +3 -3
  30. package/ui/dist/assets/{index-znBY56O9.js → index-DoM1FoZ5.js} +14 -14
  31. package/ui/dist/assets/{pptxgen.es-C5xOqzMQ.js → pptxgen.es-DlpIDw00.js} +1 -1
  32. package/ui/dist/assets/{useAgentDialogFocus-C1ZNYO-9.js → useAgentDialogFocus-BOGEpRNF.js} +1 -1
  33. package/ui/dist/index.html +1 -1
package/bin/lib/mcpJob.js CHANGED
@@ -80,6 +80,22 @@ function doneResult(data) {
80
80
  result: { filename: data.filename, url: data.url, meta: data },
81
81
  };
82
82
  }
83
+ /** Human-readable failure text. Non-MCP producers put it in data.error; MCP routes use data.message. */
84
+ function errorMessage(data) {
85
+ if (typeof data.error === "string" && data.error)
86
+ return data.error;
87
+ if (typeof data.message === "string" && data.message)
88
+ return data.message;
89
+ return "MCP job failed";
90
+ }
91
+ /** Defensive code fallback per canonical phase; producers normally supply data.code. */
92
+ function fallbackCode(phase) {
93
+ if (phase === "cancelled")
94
+ return "GENERATION_CANCELED";
95
+ if (phase === "timed_out")
96
+ return "MCP_JOB_TIMEOUT";
97
+ return "MCP_JOB_FAILED";
98
+ }
83
99
  function matchingOutcome(event, opts) {
84
100
  if (event.event === "replay-gap")
85
101
  return { kind: "replay-gap", lastEventId: event.id };
@@ -91,6 +107,28 @@ function matchingOutcome(event, opts) {
91
107
  opts.onProgress?.(data.phase);
92
108
  return null;
93
109
  }
110
+ // #151 stage 2: the canonical envelope is the primary terminal signal. The
111
+ // event-name branches below stay as the fallback for servers that predate it.
112
+ const envelope = asRecord(data.envelope);
113
+ if (envelope && envelope.terminal === true) {
114
+ const phase = String(envelope.phase ?? "");
115
+ if (phase === "completed") {
116
+ // Only a real done event carries filename/url; a non-done event with a
117
+ // completed envelope falls through rather than minting an invalid-event
118
+ // error.
119
+ if (event.event === "done")
120
+ return doneResult(data);
121
+ }
122
+ else {
123
+ const envErr = asRecord(envelope.error);
124
+ return {
125
+ kind: "error",
126
+ error: new McpJobError(typeof envErr?.code === "string" ? envErr.code
127
+ : typeof data.code === "string" ? data.code
128
+ : fallbackCode(phase), errorMessage(data)),
129
+ };
130
+ }
131
+ }
94
132
  if (event.event === "done")
95
133
  return doneResult(data);
96
134
  if (event.event === "error") {
@@ -4,7 +4,7 @@ Generated by `npm run test:inventory` (script: `scripts/classify-tests.mjs`).
4
4
 
5
5
  _Tests considered "runtime-importing" if they import from `../lib/`, `../routes/`, `../bin/`, `../server`, or `../config`._
6
6
 
7
- Total: 362 (runtime: 159, contract: 203)
7
+ Total: 364 (runtime: 161, contract: 203)
8
8
 
9
9
  ## Runtime-importing tests
10
10
  - `tests/agent-mode-auto-planner-contract.test.ts`
@@ -78,6 +78,7 @@ Total: 362 (runtime: 159, contract: 203)
78
78
  - `tests/inflight-persistence.test.ts`
79
79
  - `tests/inflight.test.ts`
80
80
  - `tests/job-envelope-contract.test.ts`
81
+ - `tests/job-envelope-terminal-coverage.test.ts`
81
82
  - `tests/job-idempotency.test.ts`
82
83
  - `tests/job-terminal-status-contract.test.ts`
83
84
  - `tests/local-import-contract.test.ts`
@@ -88,6 +89,7 @@ Total: 362 (runtime: 159, contract: 203)
88
89
  - `tests/mcp-download-retry.test.ts`
89
90
  - `tests/mcp-edit-video.test.ts`
90
91
  - `tests/mcp-generation-integration.test.ts`
92
+ - `tests/mcp-job-envelope-consumer.test.ts`
91
93
  - `tests/mcp-log-secrecy.test.ts`
92
94
  - `tests/mcp-long-job-recovery.test.ts`
93
95
  - `tests/mcp-media-action.test.ts`
@@ -54,7 +54,8 @@ export async function runGeneratePipeline(req, res, ctx) {
54
54
  // generation is the default and never publishes a terminal event.
55
55
  completeIdempotencyKey(idempotencyKey, "error", { ...payload, status });
56
56
  if (asyncMode && res.headersSent) {
57
- publish(requestId, "error", { ...payload, status, requestId });
57
+ // #151 stage 2: terminal failure carries the canonical envelope.
58
+ publishJobEvent(requestId, "error", { ...payload, status, requestId });
58
59
  return;
59
60
  }
60
61
  return res.status(status).json(payload);
package/lib/inflight.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { config } from "../config.js";
2
2
  import { getDb } from "./db.js";
3
3
  import { publish } from "./eventBus.js";
4
+ import { buildEnvelope } from "./jobs/envelope.js";
4
5
  import { logError, logEvent } from "./logger.js";
5
6
  const terminalJobs = new Map(); // requestId -> terminal snapshot, active-only API stays default
6
7
  /**
@@ -144,11 +145,26 @@ export function abortJob(requestId) {
144
145
  aborted = true;
145
146
  }
146
147
  if (active || aborted) {
147
- publish(requestId, "error", {
148
+ // #151 stage 2: the cancel path is a terminal event, so it carries the
149
+ // canonical envelope. Assembled inline rather than via ssePublish because
150
+ // ssePublish imports this module (cycle), and abortJob already knows the
151
+ // inflight phase locally.
152
+ const data = {
148
153
  error: "Generation canceled",
149
154
  code: "GENERATION_CANCELED",
150
155
  status: 499,
151
156
  requestId,
157
+ };
158
+ const inflightPhase = getJobPhase(requestId);
159
+ publish(requestId, "error", data, {
160
+ buildEnvelope: (sequence) => buildEnvelope({
161
+ jobId: requestId,
162
+ requestId,
163
+ sequence,
164
+ event: "error",
165
+ data,
166
+ inflightPhase,
167
+ }),
152
168
  });
153
169
  }
154
170
  finishJob(requestId, {
@@ -69,7 +69,8 @@ async function resolveMultimodeElements(elementIds, references, activeProvider,
69
69
  function dualEmitMultimode(res, requestId, event, data) {
70
70
  if (!res.writableEnded)
71
71
  writeSse(res, event, data);
72
- if (event === "done") {
72
+ if (event === "done" || event === "error") {
73
+ // #151 stage 2: terminal events carry the canonical envelope.
73
74
  publishJobEvent(requestId, event, data);
74
75
  }
75
76
  else {
@@ -77,7 +78,8 @@ function dualEmitMultimode(res, requestId, event, data) {
77
78
  }
78
79
  }
79
80
  function respondMultimodeValidationError(res, requestId, asyncMode, status, payload) {
80
- publish(requestId, "error", payload);
81
+ // #151 stage 2: terminal failure carries the canonical envelope.
82
+ publishJobEvent(requestId, "error", payload);
81
83
  if (asyncMode && !res.headersSent) {
82
84
  return res.status(status).json(payload);
83
85
  }
@@ -1,7 +1,7 @@
1
1
  import { loadNodeB64, loadNodeMeta } from "./nodeStore.js";
2
2
  import { detectImageMimeFromB64 } from "./refs.js";
3
3
  import { writeSse } from "./routeHelpers.js";
4
- import { publish } from "./eventBus.js";
4
+ import { publishJobEvent } from "./ssePublish.js";
5
5
  import { errorEnvelopeFields } from "./errors/envelope.js";
6
6
  export function asUpstream(e) {
7
7
  return (e && typeof e === "object" ? e : {});
@@ -18,8 +18,14 @@ export function writeNodeError(res, status, code, message, parentNodeId, details
18
18
  status,
19
19
  ...payloadDetails,
20
20
  };
21
- if (requestId)
22
- publish(requestId, "error", payload);
21
+ if (requestId) {
22
+ // #151 stage 2: node-mode terminal failure carries the canonical envelope.
23
+ // The bus record flattens code/error to top-level strings because
24
+ // buildEnvelope's errorFromData/resolvePhase read data.code / data.error as
25
+ // strings — the nested shape would stamp every node error "failed" and drop
26
+ // envelope.error (cancel/timeout classification depends on data.code).
27
+ publishJobEvent(requestId, "error", { ...payload, code, error: message });
28
+ }
23
29
  if (res.writableEnded || res.destroyed)
24
30
  return;
25
31
  if (res.headersSent) {
@@ -0,0 +1,63 @@
1
+ import { getProvider } from "../registry.js";
2
+ const LANE_ID = "atlascloud";
3
+ const ERROR_PREFIX = "ATLASCLOUD_";
4
+ /** Status codes worth retrying: transient upstream conditions, not bad input. */
5
+ const RETRYABLE_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);
6
+ function readStatus(error) {
7
+ if (!error || typeof error !== "object")
8
+ return undefined;
9
+ const candidate = error;
10
+ return typeof candidate.status === "number" ? candidate.status
11
+ : typeof candidate.statusCode === "number" ? candidate.statusCode
12
+ : undefined;
13
+ }
14
+ function readCode(error) {
15
+ if (!error || typeof error !== "object")
16
+ return undefined;
17
+ const candidate = error;
18
+ return typeof candidate.code === "string" ? candidate.code : undefined;
19
+ }
20
+ /**
21
+ * Creates an adapter bound to a runtime context.
22
+ *
23
+ * A factory rather than a module-level singleton because the API key is not a
24
+ * process constant: routes/keys.ts updates ctx.atlasCloudApiKey while the
25
+ * server runs, so reading process.env would report the lane as unauthenticated
26
+ * right after the user configured it.
27
+ */
28
+ export function createAtlasCloudAdapter(ctx) {
29
+ return {
30
+ laneId: LANE_ID,
31
+ validateAuth() {
32
+ // Presence only, and note the spelling: the context field is
33
+ // atlasCloudApiKey (capital C) while the lane id is all-lowercase.
34
+ return ctx.atlasCloudApiKey
35
+ ? { ok: true }
36
+ : { ok: false, reason: "Atlas Cloud API key missing" };
37
+ },
38
+ listModels() {
39
+ // Straight from the registry. A hand-written list here is exactly the
40
+ // drift the capability registry was built to remove.
41
+ return getProvider(LANE_ID).models;
42
+ },
43
+ normalizeError(error) {
44
+ const status = readStatus(error);
45
+ const rawCode = readCode(error);
46
+ const message = error instanceof Error ? error.message
47
+ : typeof error === "string" ? error
48
+ : "Atlas Cloud request failed";
49
+ const code = rawCode?.startsWith(ERROR_PREFIX)
50
+ ? rawCode
51
+ : rawCode
52
+ ? `${ERROR_PREFIX}${rawCode}`
53
+ : `${ERROR_PREFIX}UNKNOWN`;
54
+ const retryable = status === undefined ? false : RETRYABLE_STATUSES.has(status);
55
+ return {
56
+ code,
57
+ message,
58
+ ...(status === undefined ? {} : { status }),
59
+ retryable,
60
+ };
61
+ },
62
+ };
63
+ }
@@ -1,6 +1,8 @@
1
+ import { createAtlasCloudAdapter } from "./atlascloud.js";
1
2
  import { createMinimaxAdapter } from "./minimax.js";
2
3
  const ADAPTER_FACTORIES = {
3
4
  minimax: createMinimaxAdapter,
5
+ atlascloud: createAtlasCloudAdapter,
4
6
  };
5
7
  export function getProviderAdapter(ctx, laneId) {
6
8
  const factory = ADAPTER_FACTORIES[laneId];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ima2-gen",
3
- "version": "3.5.3",
3
+ "version": "3.6.0",
4
4
  "packageManager": "npm@11.18.0",
5
5
  "description": "Local-first visual generation runtime and studio for people and coding agents, with reproducible image and video workflows across multiple providers.",
6
6
  "type": "module",
@@ -119,5 +119,5 @@
119
119
  "tsx": "^4.23.12",
120
120
  "typescript": "^5.9.3"
121
121
  },
122
- "gitHead": "ff8f95493fc2e2b5130223e6c63f55043d79fcfe"
122
+ "gitHead": "232bb540a0eb73e570d990d66ebe44be53df3bdf"
123
123
  }
package/routes/models.js CHANGED
@@ -87,11 +87,24 @@ function geminiLane(ctx) {
87
87
  });
88
88
  }
89
89
  function atlasCloudLane(ctx) {
90
- const state = ctx.atlasCloudApiKey
90
+ // #150 phase 2: Atlas Cloud is the second lane behind ProviderAdapterV1.
91
+ // The adapter owns auth state and the model list; the DTO projection stays
92
+ // here, so /api/models keeps its exact shape.
93
+ const adapter = getProviderAdapter(ctx, "atlascloud");
94
+ if (!adapter) {
95
+ const fallback = ctx.atlasCloudApiKey
96
+ ? { status: "ready" }
97
+ : { status: "key-missing", reason: "Atlas Cloud API key missing" };
98
+ return lane(fallback, { image: ATLASCLOUD_TEXT_TO_IMAGE_MODEL }, {
99
+ image: entries(deriveModels("atlascloud", "image")), video: [],
100
+ });
101
+ }
102
+ const auth = adapter.validateAuth();
103
+ const state = auth.ok
91
104
  ? { status: "ready" }
92
- : { status: "key-missing", reason: "Atlas Cloud API key missing" };
105
+ : { status: "key-missing", reason: auth.reason ?? "Atlas Cloud API key missing" };
93
106
  return lane(state, { image: ATLASCLOUD_TEXT_TO_IMAGE_MODEL }, {
94
- image: entries(deriveModels("atlascloud", "image")), video: [],
107
+ image: entries(adapter.listModels().map((model) => model.id)), video: [],
95
108
  });
96
109
  }
97
110
  function minimaxLane(ctx) {
package/routes/video.js CHANGED
@@ -38,7 +38,9 @@ function sendSse(res, event, data) {
38
38
  function dualEmitVideo(res, requestId, event, data) {
39
39
  if (!res.writableEnded)
40
40
  sendSse(res, event, data);
41
- if (event === "done") {
41
+ if (event === "done" || event === "error") {
42
+ // #151 stage 2: terminal events (done AND error) carry the canonical
43
+ // envelope. Stream events (progress/phase/partial) stay on raw publish.
42
44
  publishJobEvent(requestId, event, data);
43
45
  }
44
46
  else {
@@ -124,7 +126,8 @@ export function registerVideoRoutes(app, ctxRaw) {
124
126
  finishHttpStatus = httpStatus;
125
127
  finishErrorCode = code;
126
128
  const payload = { error, code, status: httpStatus, requestId, ...extra };
127
- publish(requestId, "error", payload);
129
+ // #151 stage 2: terminal failure carries the canonical envelope.
130
+ publishJobEvent(requestId, "error", payload);
128
131
  if (asyncMode && !res.headersSent) {
129
132
  return res.status(httpStatus).json(payload);
130
133
  }
@@ -248,7 +248,8 @@ export function registerVideoExtendedRoutes(app, ctxRaw, dependencies = {}) {
248
248
  const status = info.status ?? 500;
249
249
  const code = info.code ?? "VIDEO_EXTEND_FAILED";
250
250
  const payload = { requestId, error: info.message, code, status, ...retryableData(error), ...errorEnvelopeFields(error) };
251
- publish(requestId, "error", payload);
251
+ // #151 stage 2: terminal failure carries the canonical envelope.
252
+ publishJobEvent(requestId, "error", payload);
252
253
  finishJob(requestId, { status: "error", httpStatus: status, errorCode: code, meta: { stage: "preflight" } });
253
254
  if (!res.headersSent)
254
255
  res.status(status).json(payload);
@@ -369,7 +370,8 @@ export function registerVideoExtendedRoutes(app, ctxRaw, dependencies = {}) {
369
370
  catch (error) {
370
371
  if (!isJobCanceled(requestId)) {
371
372
  const info = errInfo(error);
372
- publish(requestId, "error", { requestId, error: info.message, code: info.code ?? "VIDEO_EXTEND_FAILED", status: info.status ?? 500, ...retryableData(error), ...errorEnvelopeFields(error) });
373
+ // #151 stage 2: terminal failure carries the canonical envelope.
374
+ publishJobEvent(requestId, "error", { requestId, error: info.message, code: info.code ?? "VIDEO_EXTEND_FAILED", status: info.status ?? 500, ...retryableData(error), ...errorEnvelopeFields(error) });
373
375
  finishJob(requestId, { status: "error", httpStatus: info.status ?? 500, errorCode: info.code ?? "VIDEO_EXTEND_FAILED", meta: { stage } });
374
376
  }
375
377
  }
@@ -1,11 +1,15 @@
1
1
  {
2
- "_AssetGenWorkspace-D-p57I-0.js": {
3
- "file": "assets/AssetGenWorkspace-D-p57I-0.js",
2
+ "_AssetGenWorkspace-Dkr80l12.css": {
3
+ "file": "assets/AssetGenWorkspace-Dkr80l12.css",
4
+ "src": "_AssetGenWorkspace-Dkr80l12.css"
5
+ },
6
+ "_AssetGenWorkspace-XbViHOY0.js": {
7
+ "file": "assets/AssetGenWorkspace-XbViHOY0.js",
4
8
  "name": "AssetGenWorkspace",
5
9
  "isDynamicEntry": true,
6
10
  "imports": [
7
11
  "index.html",
8
- "_KeyingPanel-hK4oc51k.js"
12
+ "_KeyingPanel-D79TCHH_.js"
9
13
  ],
10
14
  "dynamicImports": [
11
15
  "src/components/assetgen/SpriteRecipeWorkspace.tsx"
@@ -14,16 +18,12 @@
14
18
  "assets/AssetGenWorkspace-Dkr80l12.css"
15
19
  ]
16
20
  },
17
- "_AssetGenWorkspace-Dkr80l12.css": {
18
- "file": "assets/AssetGenWorkspace-Dkr80l12.css",
19
- "src": "_AssetGenWorkspace-Dkr80l12.css"
20
- },
21
- "_KeyingPanel-hK4oc51k.js": {
22
- "file": "assets/KeyingPanel-hK4oc51k.js",
21
+ "_KeyingPanel-D79TCHH_.js": {
22
+ "file": "assets/KeyingPanel-D79TCHH_.js",
23
23
  "name": "KeyingPanel",
24
24
  "imports": [
25
25
  "index.html",
26
- "_useAgentDialogFocus-C1ZNYO-9.js"
26
+ "_useAgentDialogFocus-BOGEpRNF.js"
27
27
  ]
28
28
  },
29
29
  "__vite-browser-external": {
@@ -32,15 +32,15 @@
32
32
  "src": "__vite-browser-external",
33
33
  "isDynamicEntry": true
34
34
  },
35
- "_useAgentDialogFocus-C1ZNYO-9.js": {
36
- "file": "assets/useAgentDialogFocus-C1ZNYO-9.js",
35
+ "_useAgentDialogFocus-BOGEpRNF.js": {
36
+ "file": "assets/useAgentDialogFocus-BOGEpRNF.js",
37
37
  "name": "useAgentDialogFocus",
38
38
  "imports": [
39
39
  "index.html"
40
40
  ]
41
41
  },
42
42
  "index.html": {
43
- "file": "assets/index-znBY56O9.js",
43
+ "file": "assets/index-DoM1FoZ5.js",
44
44
  "name": "index",
45
45
  "src": "index.html",
46
46
  "isEntry": true,
@@ -55,7 +55,7 @@
55
55
  "src/components/card-news/CardNewsWorkspace.tsx",
56
56
  "src/components/agent/AgentWorkspace.tsx",
57
57
  "src/components/assets/AssetsWorkspace.tsx",
58
- "_AssetGenWorkspace-D-p57I-0.js",
58
+ "_AssetGenWorkspace-XbViHOY0.js",
59
59
  "src/components/home/HomeWorkspace.tsx",
60
60
  "src/components/PromptLibraryPanel.tsx"
61
61
  ],
@@ -64,7 +64,7 @@
64
64
  ]
65
65
  },
66
66
  "node_modules/pptxgenjs/dist/pptxgen.es.js": {
67
- "file": "assets/pptxgen.es-C5xOqzMQ.js",
67
+ "file": "assets/pptxgen.es-DlpIDw00.js",
68
68
  "name": "pptxgen.es",
69
69
  "src": "node_modules/pptxgenjs/dist/pptxgen.es.js",
70
70
  "isDynamicEntry": true,
@@ -78,7 +78,7 @@
78
78
  ]
79
79
  },
80
80
  "src/components/GenerationRequestLogPanel.tsx": {
81
- "file": "assets/GenerationRequestLogPanel-CJYn7vCN.js",
81
+ "file": "assets/GenerationRequestLogPanel-CKw9JLH8.js",
82
82
  "name": "GenerationRequestLogPanel",
83
83
  "src": "src/components/GenerationRequestLogPanel.tsx",
84
84
  "isDynamicEntry": true,
@@ -87,7 +87,7 @@
87
87
  ]
88
88
  },
89
89
  "src/components/NodeCanvas.tsx": {
90
- "file": "assets/NodeCanvas-CO9FzAfn.js",
90
+ "file": "assets/NodeCanvas-BpNgtUxt.js",
91
91
  "name": "NodeCanvas",
92
92
  "src": "src/components/NodeCanvas.tsx",
93
93
  "isDynamicEntry": true,
@@ -99,7 +99,7 @@
99
99
  ]
100
100
  },
101
101
  "src/components/PromptImportDialog.tsx": {
102
- "file": "assets/PromptImportDialog-CGxyjU6L.js",
102
+ "file": "assets/PromptImportDialog-qD_tVhN5.js",
103
103
  "name": "PromptImportDialog",
104
104
  "src": "src/components/PromptImportDialog.tsx",
105
105
  "isDynamicEntry": true,
@@ -112,7 +112,7 @@
112
112
  ]
113
113
  },
114
114
  "src/components/PromptImportDiscoverySection.tsx": {
115
- "file": "assets/PromptImportDiscoverySection-C5PY1YV3.js",
115
+ "file": "assets/PromptImportDiscoverySection-51FDzoLN.js",
116
116
  "name": "PromptImportDiscoverySection",
117
117
  "src": "src/components/PromptImportDiscoverySection.tsx",
118
118
  "isDynamicEntry": true,
@@ -121,7 +121,7 @@
121
121
  ]
122
122
  },
123
123
  "src/components/PromptImportFolderSection.tsx": {
124
- "file": "assets/PromptImportFolderSection-DWsWg6nw.js",
124
+ "file": "assets/PromptImportFolderSection-uQNX1sJ_.js",
125
125
  "name": "PromptImportFolderSection",
126
126
  "src": "src/components/PromptImportFolderSection.tsx",
127
127
  "isDynamicEntry": true,
@@ -130,7 +130,7 @@
130
130
  ]
131
131
  },
132
132
  "src/components/PromptLibraryPanel.tsx": {
133
- "file": "assets/PromptLibraryPanel-BPiKLU-z.js",
133
+ "file": "assets/PromptLibraryPanel-BngHherb.js",
134
134
  "name": "PromptLibraryPanel",
135
135
  "src": "src/components/PromptLibraryPanel.tsx",
136
136
  "isDynamicEntry": true,
@@ -142,7 +142,7 @@
142
142
  ]
143
143
  },
144
144
  "src/components/SettingsWorkspace.tsx": {
145
- "file": "assets/SettingsWorkspace-D1gLUIPQ.js",
145
+ "file": "assets/SettingsWorkspace-dpl5CLsg.js",
146
146
  "name": "SettingsWorkspace",
147
147
  "src": "src/components/SettingsWorkspace.tsx",
148
148
  "isDynamicEntry": true,
@@ -151,43 +151,43 @@
151
151
  ]
152
152
  },
153
153
  "src/components/agent/AgentWorkspace.tsx": {
154
- "file": "assets/AgentWorkspace-BZuw_82p.js",
154
+ "file": "assets/AgentWorkspace-Bfe9PqZy.js",
155
155
  "name": "AgentWorkspace",
156
156
  "src": "src/components/agent/AgentWorkspace.tsx",
157
157
  "isDynamicEntry": true,
158
158
  "imports": [
159
159
  "index.html",
160
- "_useAgentDialogFocus-C1ZNYO-9.js"
160
+ "_useAgentDialogFocus-BOGEpRNF.js"
161
161
  ]
162
162
  },
163
163
  "src/components/assetgen/SpriteRecipeWorkspace.tsx": {
164
- "file": "assets/SpriteRecipeWorkspace-vlnp398m.js",
164
+ "file": "assets/SpriteRecipeWorkspace-IpS6TVAF.js",
165
165
  "name": "SpriteRecipeWorkspace",
166
166
  "src": "src/components/assetgen/SpriteRecipeWorkspace.tsx",
167
167
  "isDynamicEntry": true,
168
168
  "imports": [
169
169
  "index.html",
170
- "_AssetGenWorkspace-D-p57I-0.js",
171
- "_KeyingPanel-hK4oc51k.js",
172
- "_useAgentDialogFocus-C1ZNYO-9.js"
170
+ "_AssetGenWorkspace-XbViHOY0.js",
171
+ "_KeyingPanel-D79TCHH_.js",
172
+ "_useAgentDialogFocus-BOGEpRNF.js"
173
173
  ]
174
174
  },
175
175
  "src/components/assets/AssetsWorkspace.tsx": {
176
- "file": "assets/AssetsWorkspace-BlVr5Qjq.js",
176
+ "file": "assets/AssetsWorkspace-HemkY-0A.js",
177
177
  "name": "AssetsWorkspace",
178
178
  "src": "src/components/assets/AssetsWorkspace.tsx",
179
179
  "isDynamicEntry": true,
180
180
  "imports": [
181
181
  "index.html",
182
- "_KeyingPanel-hK4oc51k.js",
183
- "_useAgentDialogFocus-C1ZNYO-9.js"
182
+ "_KeyingPanel-D79TCHH_.js",
183
+ "_useAgentDialogFocus-BOGEpRNF.js"
184
184
  ],
185
185
  "css": [
186
186
  "assets/AssetsWorkspace-BkUjPPKU.css"
187
187
  ]
188
188
  },
189
189
  "src/components/canvas-mode/index.ts": {
190
- "file": "assets/index-DogXlrkz.js",
190
+ "file": "assets/index-BA51BzWd.js",
191
191
  "name": "index",
192
192
  "src": "src/components/canvas-mode/index.ts",
193
193
  "isDynamicEntry": true,
@@ -199,7 +199,7 @@
199
199
  ]
200
200
  },
201
201
  "src/components/card-news/CardNewsWorkspace.tsx": {
202
- "file": "assets/CardNewsWorkspace-BPYWHZqh.js",
202
+ "file": "assets/CardNewsWorkspace-Cchcm8ts.js",
203
203
  "name": "CardNewsWorkspace",
204
204
  "src": "src/components/card-news/CardNewsWorkspace.tsx",
205
205
  "isDynamicEntry": true,
@@ -208,7 +208,7 @@
208
208
  ]
209
209
  },
210
210
  "src/components/home/HomeWorkspace.tsx": {
211
- "file": "assets/HomeWorkspace-DbWuQI7B.js",
211
+ "file": "assets/HomeWorkspace-Do6VnjWR.js",
212
212
  "name": "HomeWorkspace",
213
213
  "src": "src/components/home/HomeWorkspace.tsx",
214
214
  "isDynamicEntry": true,
@@ -217,7 +217,7 @@
217
217
  ]
218
218
  },
219
219
  "src/components/prompt-builder/PromptBuilderPanel.tsx": {
220
- "file": "assets/PromptBuilderPanel-DEPrkXcU.js",
220
+ "file": "assets/PromptBuilderPanel-DHB1sU7O.js",
221
221
  "name": "PromptBuilderPanel",
222
222
  "src": "src/components/prompt-builder/PromptBuilderPanel.tsx",
223
223
  "isDynamicEntry": true,