omp-fabric 1.25.34 → 1.26.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 (52) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +1 -0
  3. package/dist/chunks/{chunk-HOKJTRI4.js → chunk-3OQKG7H6.js} +3 -3
  4. package/dist/chunks/{chunk-JWC7B67Z.js → chunk-66H3QSMR.js} +62 -1
  5. package/dist/chunks/chunk-66H3QSMR.js.map +7 -0
  6. package/dist/chunks/{chunk-UKB5RJDP.js → chunk-BEFZRH76.js} +61 -1
  7. package/dist/chunks/{chunk-UKB5RJDP.js.map → chunk-BEFZRH76.js.map} +2 -2
  8. package/dist/chunks/{chunk-TRM76YFF.js → chunk-CEDP5WMR.js} +11 -3
  9. package/dist/chunks/chunk-CEDP5WMR.js.map +7 -0
  10. package/dist/chunks/{chunk-2C5YN36Y.js → chunk-GFUWAUL2.js} +15 -1
  11. package/dist/chunks/chunk-GFUWAUL2.js.map +7 -0
  12. package/dist/chunks/{chunk-5CW2S6EB.js → chunk-Q2LRXHPR.js} +2 -2
  13. package/dist/chunks/{chunk-3FCNSDDD.js → chunk-TGIT2F2G.js} +3 -3
  14. package/dist/chunks/{chunk-OLFP7R5J.js → chunk-Z3KAY6S7.js} +2 -2
  15. package/dist/compaction/hook.js +1 -1
  16. package/dist/config.d.ts +11 -0
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/core/session-context.d.ts.map +1 -1
  19. package/dist/core/system-guidance.d.ts.map +1 -1
  20. package/dist/fabric-runtime-state.d.ts.map +1 -1
  21. package/dist/fabric-runtime-state.js +797 -139
  22. package/dist/fabric-runtime-state.js.map +4 -4
  23. package/dist/index.js +6 -6
  24. package/dist/index.js.map +2 -2
  25. package/dist/providers/image-provider.d.ts +37 -0
  26. package/dist/providers/image-provider.d.ts.map +1 -0
  27. package/dist/residency/host.js +5 -5
  28. package/dist/residency/omp-entry.js +5 -5
  29. package/dist/runtime/core-override-guest-types.js +1 -1
  30. package/dist/runtime/guest-types.d.ts +1 -1
  31. package/dist/runtime/guest-types.d.ts.map +1 -1
  32. package/dist/runtime/guest-types.js +1 -1
  33. package/dist/runtime/node-process-runtime.js +1 -1
  34. package/dist/runtime/quickjs-runtime.d.ts +1 -1
  35. package/dist/runtime/quickjs-runtime.d.ts.map +1 -1
  36. package/dist/runtime/quickjs-runtime.js +1 -1
  37. package/dist/ui/settings.d.ts +1 -1
  38. package/dist/ui/settings.d.ts.map +1 -1
  39. package/dist/ui/settings.js +126 -11
  40. package/dist/ui/settings.js.map +3 -3
  41. package/docs/architecture.md +1 -1
  42. package/docs/certification.md +1 -1
  43. package/docs/configuration.md +13 -1
  44. package/docs/image.md +79 -0
  45. package/package.json +8 -8
  46. package/dist/chunks/chunk-2C5YN36Y.js.map +0 -7
  47. package/dist/chunks/chunk-JWC7B67Z.js.map +0 -7
  48. package/dist/chunks/chunk-TRM76YFF.js.map +0 -7
  49. /package/dist/chunks/{chunk-HOKJTRI4.js.map → chunk-3OQKG7H6.js.map} +0 -0
  50. /package/dist/chunks/{chunk-5CW2S6EB.js.map → chunk-Q2LRXHPR.js.map} +0 -0
  51. /package/dist/chunks/{chunk-3FCNSDDD.js.map → chunk-TGIT2F2G.js.map} +0 -0
  52. /package/dist/chunks/{chunk-OLFP7R5J.js.map → chunk-Z3KAY6S7.js.map} +0 -0
@@ -33,7 +33,7 @@ import {
33
33
  repairFabricGuestCode,
34
34
  resolveFabricIdentity,
35
35
  runFabricHandoffAtBoundary
36
- } from "./chunks/chunk-OLFP7R5J.js";
36
+ } from "./chunks/chunk-Z3KAY6S7.js";
37
37
  import "./chunks/chunk-7VIQNUPS.js";
38
38
  import {
39
39
  AgentTranscriptReader,
@@ -97,7 +97,7 @@ import {
97
97
  resolveAgentCwd,
98
98
  resolveOmpBinary,
99
99
  validateAgentCwdRequest
100
- } from "./chunks/chunk-HOKJTRI4.js";
100
+ } from "./chunks/chunk-3OQKG7H6.js";
101
101
  import "./chunks/chunk-VPPIJRNZ.js";
102
102
  import {
103
103
  executeFile,
@@ -107,7 +107,7 @@ import {
107
107
  import "./chunks/chunk-CT2AJ2UI.js";
108
108
  import {
109
109
  checkedHandoffCompaction
110
- } from "./chunks/chunk-5CW2S6EB.js";
110
+ } from "./chunks/chunk-Q2LRXHPR.js";
111
111
  import {
112
112
  DEFAULT_FABRIC_CONFIG,
113
113
  FUZZY_RESOLUTION_MARKERS,
@@ -117,7 +117,7 @@ import {
117
117
  resolveAgentDir,
118
118
  resolveAvailableOmpModel,
119
119
  resolveFabricModel
120
- } from "./chunks/chunk-JWC7B67Z.js";
120
+ } from "./chunks/chunk-66H3QSMR.js";
121
121
  import {
122
122
  FABRIC_ACTOR_HOST_EVENTS,
123
123
  isFabricActorHostEvent,
@@ -157,7 +157,7 @@ import {
157
157
  import {
158
158
  estimateTokens,
159
159
  fabricExecTitleHintCached
160
- } from "./chunks/chunk-TRM76YFF.js";
160
+ } from "./chunks/chunk-CEDP5WMR.js";
161
161
  import "./chunks/chunk-3J7BKUNG.js";
162
162
  import {
163
163
  MAX_COMPACTION_INSTRUCTIONS_CHARS,
@@ -182,7 +182,7 @@ import {
182
182
  } from "./chunks/chunk-ATTYOQSI.js";
183
183
 
184
184
  // src/fabric-runtime-state.ts
185
- import path19 from "node:path";
185
+ import path20 from "node:path";
186
186
  import { fileURLToPath as fileURLToPath2 } from "node:url";
187
187
 
188
188
  // src/actors/global-registry.ts
@@ -2235,10 +2235,10 @@ var FabricComponentSupervisor = class {
2235
2235
  adjacent.set(edge.from, targets);
2236
2236
  }
2237
2237
  const cycles = /* @__PURE__ */ new Map();
2238
- const visit = (node, path20, positions) => {
2238
+ const visit = (node, path21, positions) => {
2239
2239
  const position = positions.get(node);
2240
2240
  if (position !== void 0) {
2241
- const cycle = path20.slice(position);
2241
+ const cycle = path21.slice(position);
2242
2242
  const rotations = cycle.map((_, index) => [
2243
2243
  ...cycle.slice(index),
2244
2244
  ...cycle.slice(0, index)
@@ -2248,10 +2248,10 @@ var FabricComponentSupervisor = class {
2248
2248
  cycles.set(canonical.join("\0"), canonical);
2249
2249
  return;
2250
2250
  }
2251
- if (path20.length > this.#components.size) return;
2252
- const nextPositions = new Map(positions).set(node, path20.length);
2251
+ if (path21.length > this.#components.size) return;
2252
+ const nextPositions = new Map(positions).set(node, path21.length);
2253
2253
  for (const target of adjacent.get(node) ?? []) {
2254
- visit(target, [...path20, node], nextPositions);
2254
+ visit(target, [...path21, node], nextPositions);
2255
2255
  }
2256
2256
  };
2257
2257
  for (const id of this.#components.keys()) visit(id, [], /* @__PURE__ */ new Map());
@@ -7060,9 +7060,9 @@ var CapturedToolsProvider = class {
7060
7060
  #allowedTools = readChildToolAllowlist();
7061
7061
  async list(request, _context) {
7062
7062
  const query = request.query?.trim().toLowerCase();
7063
- const descriptors8 = this.catalog.list().filter((entry) => !this.#allowedTools || this.#allowedTools.has(entry.name)).map(descriptorFrom);
7064
- if (!query) return descriptors8;
7065
- return descriptors8.filter(
7063
+ const descriptors9 = this.catalog.list().filter((entry) => !this.#allowedTools || this.#allowedTools.has(entry.name)).map(descriptorFrom);
7064
+ if (!query) return descriptors9;
7065
+ return descriptors9.filter(
7066
7066
  (descriptor) => `${descriptor.name} ${descriptor.description} ${descriptor.namespace ?? ""}`.toLowerCase().includes(query)
7067
7067
  );
7068
7068
  }
@@ -8498,6 +8498,650 @@ var CodemapProvider = class {
8498
8498
  }
8499
8499
  };
8500
8500
 
8501
+ // src/providers/image-provider.ts
8502
+ import { mkdir, readFile as readFile2, writeFile } from "node:fs/promises";
8503
+ import os from "node:os";
8504
+ import path10 from "node:path";
8505
+ var IMAGE_MODEL_API = /image|imagen|dall-e|flux|stable-diffusion|sdxl|seedream|kolors|wanx|cogview|recraft|ideogram|midjourney|horde|banana/i;
8506
+ var generateSchema = {
8507
+ type: "object",
8508
+ additionalProperties: false,
8509
+ required: ["prompt"],
8510
+ properties: {
8511
+ prompt: { type: "string", description: "Full image description; the only required argument." },
8512
+ model: {
8513
+ type: "string",
8514
+ description: 'Optional provider/id to try first, e.g. "sub2api-agy/gemini-3.1-flash-image". Falls back to the configured chain.'
8515
+ },
8516
+ aspectRatio: {
8517
+ type: "string",
8518
+ description: "Aspect ratio forwarded as aspect_ratio or imageConfig.aspectRatio, e.g. 1:1, 16:9, 9:16."
8519
+ },
8520
+ size: {
8521
+ type: "string",
8522
+ enum: ["1024x1024", "1536x1024", "1024x1536"],
8523
+ description: "Pixel size for gateways that accept an images-API size field."
8524
+ },
8525
+ count: { type: "number", description: "Images to request from one model; only the images API honours more than one." },
8526
+ saveTo: { type: "string", description: "Absolute or cwd-relative file path for a single image." }
8527
+ }
8528
+ };
8529
+ var editSchema = {
8530
+ type: "object",
8531
+ additionalProperties: false,
8532
+ required: ["prompt", "images"],
8533
+ properties: {
8534
+ prompt: { type: "string", description: "What to change in the source images." },
8535
+ images: {
8536
+ type: "array",
8537
+ minItems: 1,
8538
+ description: "Source images as file paths or data URLs.",
8539
+ items: { type: "string" }
8540
+ },
8541
+ model: { type: "string", description: "Optional provider/id to try first." },
8542
+ aspectRatio: { type: "string", description: "Aspect ratio forwarded to the backend." },
8543
+ size: {
8544
+ type: "string",
8545
+ enum: ["1024x1024", "1536x1024", "1024x1536"],
8546
+ description: "Pixel size for gateways that accept an images-API size field."
8547
+ },
8548
+ saveTo: { type: "string", description: "Absolute or cwd-relative file path for a single image." }
8549
+ }
8550
+ };
8551
+ var modelsSchema = { type: "object", additionalProperties: false, properties: {} };
8552
+ var descriptors2 = [
8553
+ {
8554
+ name: "generate",
8555
+ description: "Generate an image from a prompt. Tries each configured model in priority order and returns the first success with its path, bytes, model, and dialect. Returns { ok: false, reason, failures } instead of throwing when every model fails.",
8556
+ inputSchema: generateSchema,
8557
+ risk: "network"
8558
+ },
8559
+ {
8560
+ name: "edit",
8561
+ description: "Edit existing images with a prompt. Tries each configured model in priority order and returns the first success or { ok: false, reason, failures }. Source images travel in the shape each dialect expects: input_references or image/images for the images API, image_url parts for chat, input_image for responses, inlineData for gemini.",
8562
+ inputSchema: editSchema,
8563
+ risk: "network"
8564
+ },
8565
+ {
8566
+ name: "models",
8567
+ description: "Show the resolved priority chain: each entry's provider, model id, api, inferred or overridden dialect, and whether credentials resolve. No network call.",
8568
+ inputSchema: modelsSchema,
8569
+ risk: "read"
8570
+ }
8571
+ ];
8572
+ var splitModelSelector = (selector) => {
8573
+ const trimmed = selector.trim();
8574
+ const separator = trimmed.indexOf("/");
8575
+ if (separator <= 0 || separator === trimmed.length - 1) return void 0;
8576
+ return { provider: trimmed.slice(0, separator), id: trimmed.slice(separator + 1) };
8577
+ };
8578
+ var inferImageDialect = (api, modelId) => {
8579
+ if (api === "openai-images" || api === "openrouter-images") return "images";
8580
+ if (api === "google-generative-ai") return "gemini";
8581
+ if (api === "openai-responses" || api === "openai-codex-responses") {
8582
+ return IMAGE_MODEL_API.test(modelId) ? "images" : "responses";
8583
+ }
8584
+ return "chat";
8585
+ };
8586
+ var GPT_IMAGE_FAMILY = /gpt-image|chatgpt-image/i;
8587
+ var mimeFromMagic = (bytes) => {
8588
+ if (bytes.length > 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
8589
+ if (bytes.length > 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return "image/png";
8590
+ if (bytes.length > 6 && bytes.subarray(0, 3).toString("latin1") === "GIF") return "image/gif";
8591
+ if (bytes.length > 12 && bytes.subarray(0, 4).toString("latin1") === "RIFF" && bytes.subarray(8, 12).toString("latin1") === "WEBP") {
8592
+ return "image/webp";
8593
+ }
8594
+ return void 0;
8595
+ };
8596
+ var extensionForMime = (mimeType) => {
8597
+ if (mimeType === "image/jpeg") return "jpg";
8598
+ if (mimeType === "image/webp") return "webp";
8599
+ if (mimeType === "image/gif") return "gif";
8600
+ return "png";
8601
+ };
8602
+ var MAGIC_SNIFF_BASE64_CHARS = 64;
8603
+ var decodeImage = (value) => {
8604
+ if (typeof value !== "string" || value.length === 0) return void 0;
8605
+ let base64 = value;
8606
+ if (value.startsWith("data:")) {
8607
+ const comma = value.indexOf(",");
8608
+ if (comma < 0) return void 0;
8609
+ base64 = value.slice(comma + 1);
8610
+ }
8611
+ const head = Buffer.from(base64.slice(0, MAGIC_SNIFF_BASE64_CHARS), "base64");
8612
+ if (head.length < 16) return void 0;
8613
+ const mimeType = mimeFromMagic(head);
8614
+ if (mimeType === void 0) return void 0;
8615
+ return { data: base64, mimeType };
8616
+ };
8617
+ var collectFromUrlList = (value) => {
8618
+ if (!Array.isArray(value)) return [];
8619
+ const images = [];
8620
+ for (const entry of value) {
8621
+ if (typeof entry === "string") {
8622
+ const decoded2 = decodeImage(entry);
8623
+ if (decoded2) images.push(decoded2);
8624
+ continue;
8625
+ }
8626
+ if (typeof entry !== "object" || entry === null) continue;
8627
+ const record2 = entry;
8628
+ const nested = record2.image_url;
8629
+ const url = typeof nested === "string" ? nested : typeof nested === "object" && nested !== null ? nested.url : record2.url;
8630
+ const decoded = decodeImage(url);
8631
+ if (decoded) images.push(decoded);
8632
+ }
8633
+ return images;
8634
+ };
8635
+ var DATA_URL_PATTERN = /data:(image\/[a-z+]+);base64,([A-Za-z0-9+/=]+)/gi;
8636
+ var parseImagesApiPayload = (payload) => {
8637
+ const data = payload?.data;
8638
+ if (!Array.isArray(data)) return [];
8639
+ const images = [];
8640
+ for (const entry of data) {
8641
+ if (typeof entry !== "object" || entry === null) continue;
8642
+ const record2 = entry;
8643
+ const decoded = decodeImage(record2.b64_json) ?? decodeImage(record2.url);
8644
+ if (decoded) images.push(decoded);
8645
+ }
8646
+ return images;
8647
+ };
8648
+ var parseResponsesPayload = (payload) => {
8649
+ const output = payload?.output;
8650
+ if (!Array.isArray(output)) return [];
8651
+ const images = [];
8652
+ for (const entry of output) {
8653
+ if (typeof entry !== "object" || entry === null) continue;
8654
+ const record2 = entry;
8655
+ if (record2.type !== "image_generation_call") continue;
8656
+ const decoded = decodeImage(record2.result);
8657
+ if (decoded) images.push(decoded);
8658
+ }
8659
+ return images;
8660
+ };
8661
+ var parseChatPayload = (payload) => {
8662
+ const choices = payload?.choices;
8663
+ if (!Array.isArray(choices) || choices.length === 0) return [];
8664
+ const message2 = choices[0]?.message;
8665
+ if (!message2) return [];
8666
+ const direct = collectFromUrlList(message2.images);
8667
+ if (direct.length > 0) return direct;
8668
+ const content = message2.content;
8669
+ const text = typeof content === "string" ? content : Array.isArray(content) ? content.map(
8670
+ (part) => typeof part === "object" && part !== null && typeof part.text === "string" ? String(part.text) : ""
8671
+ ).join("\n") : "";
8672
+ const images = [];
8673
+ for (const match of text.matchAll(DATA_URL_PATTERN)) {
8674
+ const decoded = decodeImage(match[0]);
8675
+ if (decoded) images.push(decoded);
8676
+ }
8677
+ if (images.length > 0) return images;
8678
+ return collectFromUrlList(
8679
+ Array.isArray(content) ? content.filter(
8680
+ (part) => typeof part === "object" && part !== null && part.type === "image_url"
8681
+ ) : []
8682
+ );
8683
+ };
8684
+ var parseGeminiPayload = (payload) => {
8685
+ const candidates = payload?.candidates;
8686
+ if (!Array.isArray(candidates)) return [];
8687
+ const images = [];
8688
+ for (const candidate of candidates) {
8689
+ const parts = candidate?.content?.parts;
8690
+ if (!Array.isArray(parts)) continue;
8691
+ for (const part of parts) {
8692
+ if (typeof part !== "object" || part === null) continue;
8693
+ const inline = part.inlineData ?? part.inline_data;
8694
+ if (typeof inline !== "object" || inline === null) continue;
8695
+ const record2 = inline;
8696
+ const decoded = decodeImage(record2.data);
8697
+ if (decoded) images.push(decoded);
8698
+ }
8699
+ }
8700
+ return images;
8701
+ };
8702
+ var joinUrl = (baseUrl, suffix) => `${baseUrl.replace(/\/+$/, "")}${suffix.startsWith("/") ? suffix : "/" + suffix}`;
8703
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8704
+ var MAX_RESPONSE_BYTES = 96 * 1024 * 1024;
8705
+ var postJson = async (env, url, body, extraHeaders = {}) => {
8706
+ const response = await env.fetchImpl(url, {
8707
+ method: "POST",
8708
+ headers: { ...env.headers, "Content-Type": "application/json", ...extraHeaders },
8709
+ body: JSON.stringify(body),
8710
+ ...env.signal ? { signal: env.signal } : {}
8711
+ });
8712
+ const declared = Number(response.headers.get("content-length") ?? "");
8713
+ if (Number.isFinite(declared) && declared > MAX_RESPONSE_BYTES) {
8714
+ throw Object.assign(new Error(`${url} declared ${declared} bytes, over the ${MAX_RESPONSE_BYTES} ceiling`), {
8715
+ status: 413
8716
+ });
8717
+ }
8718
+ const text = await response.text();
8719
+ if (!response.ok) {
8720
+ throw Object.assign(new Error(`${url} returned ${response.status}: ${text.slice(0, 400)}`), {
8721
+ status: response.status
8722
+ });
8723
+ }
8724
+ const contentType = response.headers.get("content-type") ?? "";
8725
+ if (contentType.includes("text/event-stream")) {
8726
+ return { payload: parseSsePayload(text), status: response.status, contentType };
8727
+ }
8728
+ try {
8729
+ return { payload: JSON.parse(text), status: response.status, contentType };
8730
+ } catch {
8731
+ throw new Error(`${url} returned non-JSON: ${text.slice(0, 200)}`);
8732
+ }
8733
+ };
8734
+ var parseSsePayload = (text) => {
8735
+ let last;
8736
+ for (const line of text.split("\n")) {
8737
+ if (!line.startsWith("data:")) continue;
8738
+ const data = line.slice(5).trim();
8739
+ if (data.length === 0 || data === "[DONE]") continue;
8740
+ let event;
8741
+ try {
8742
+ event = JSON.parse(data);
8743
+ } catch {
8744
+ continue;
8745
+ }
8746
+ if (!isRecord3(event)) continue;
8747
+ const nested = event.response;
8748
+ if (isRecord3(nested) && Array.isArray(nested.output)) {
8749
+ last = nested;
8750
+ continue;
8751
+ }
8752
+ if (Array.isArray(event.output)) last = event;
8753
+ }
8754
+ if (last === void 0) throw new Error("event stream carried no response payload");
8755
+ return last;
8756
+ };
8757
+ var dataUrl = (image) => `data:${image.mimeType};base64,${image.data}`;
8758
+ var requestImages = async (env, model, options) => {
8759
+ const openrouter = model.api === "openrouter-images";
8760
+ const body = { model: model.id, prompt: options.prompt, n: options.count };
8761
+ if (!model.gptImage) body.response_format = "b64_json";
8762
+ if (options.size !== void 0) {
8763
+ if (openrouter) body.image_size = options.size;
8764
+ else body.size = options.size;
8765
+ }
8766
+ if (options.aspectRatio !== void 0) body.aspect_ratio = options.aspectRatio;
8767
+ const references = options.inputImages.map((image) => ({ type: "image_url", url: dataUrl(image) }));
8768
+ if (options.inputImages.length === 0) {
8769
+ const url2 = joinUrl(env.baseUrl, openrouter ? "/images" : "/images/generations");
8770
+ const { payload } = await postJson(env, url2, body);
8771
+ return parseImagesApiPayload(payload);
8772
+ }
8773
+ if (model.provider === "openai") {
8774
+ const form = new FormData();
8775
+ form.set("model", model.id);
8776
+ form.set("prompt", options.prompt);
8777
+ form.set("n", String(options.count));
8778
+ if (!model.gptImage) form.set("response_format", "b64_json");
8779
+ if (options.size !== void 0) form.set("size", options.size);
8780
+ for (const image of options.inputImages) {
8781
+ form.append("image", new File([Buffer.from(image.data, "base64")], "image", { type: image.mimeType }));
8782
+ }
8783
+ const response = await env.fetchImpl(joinUrl(env.baseUrl, "/images/edits"), {
8784
+ method: "POST",
8785
+ headers: env.headers,
8786
+ body: form,
8787
+ ...env.signal ? { signal: env.signal } : {}
8788
+ });
8789
+ const text = await response.text();
8790
+ if (!response.ok) {
8791
+ throw Object.assign(new Error(`images edit returned ${response.status}: ${text.slice(0, 400)}`), {
8792
+ status: response.status
8793
+ });
8794
+ }
8795
+ return parseImagesApiPayload(JSON.parse(text));
8796
+ }
8797
+ if (model.xai) {
8798
+ body.image = references[0];
8799
+ if (references.length > 1) body.images = references;
8800
+ } else {
8801
+ body.input_references = references;
8802
+ }
8803
+ const url = joinUrl(env.baseUrl, openrouter ? "/images" : "/images/edits");
8804
+ try {
8805
+ const { payload } = await postJson(env, url, body);
8806
+ return parseImagesApiPayload(payload);
8807
+ } catch (error) {
8808
+ if (error.status !== 404) throw error;
8809
+ const { payload } = await postJson(env, joinUrl(env.baseUrl, "/images/generations"), body);
8810
+ return parseImagesApiPayload(payload);
8811
+ }
8812
+ };
8813
+ var requestResponses = async (env, model, options) => {
8814
+ const content = [{ type: "input_text", text: options.prompt }];
8815
+ for (const image of options.inputImages) {
8816
+ content.push({ type: "input_image", image_url: dataUrl(image) });
8817
+ }
8818
+ const body = {
8819
+ model: model.id,
8820
+ input: [{ role: "user", content }],
8821
+ tools: [{ type: "image_generation" }],
8822
+ tool_choice: { type: "image_generation" },
8823
+ store: false
8824
+ };
8825
+ const url = model.codex ? joinUrl(env.baseUrl, "/codex/responses") : joinUrl(env.baseUrl, "/responses");
8826
+ if (model.codex) body.stream = true;
8827
+ const { payload } = await postJson(env, url, body, model.codex ? { Accept: "text/event-stream" } : {});
8828
+ const status = payload?.status;
8829
+ const images = parseResponsesPayload(payload);
8830
+ if (images.length === 0 && status === "failed") {
8831
+ const error = payload?.error;
8832
+ throw new Error(
8833
+ `responses backend reported status=failed${error ? `: ${JSON.stringify(error).slice(0, 200)}` : ""}`
8834
+ );
8835
+ }
8836
+ return images;
8837
+ };
8838
+ var requestChat = async (env, model, options) => {
8839
+ const content = [{ type: "text", text: options.prompt }];
8840
+ for (const image of options.inputImages) {
8841
+ content.push({ type: "image_url", image_url: { url: `data:${image.mimeType};base64,${image.data}` } });
8842
+ }
8843
+ const body = {
8844
+ model: model.id,
8845
+ messages: [{ role: "user", content }],
8846
+ modalities: ["image", "text"]
8847
+ };
8848
+ const { payload } = await postJson(env, joinUrl(env.baseUrl, "/chat/completions"), body);
8849
+ return parseChatPayload(payload);
8850
+ };
8851
+ var requestGemini = async (env, model, options) => {
8852
+ const parts = [{ text: options.prompt }];
8853
+ for (const image of options.inputImages) {
8854
+ parts.push({ inlineData: { mimeType: image.mimeType, data: image.data } });
8855
+ }
8856
+ const imageConfig = {};
8857
+ if (options.aspectRatio !== void 0) imageConfig.aspectRatio = options.aspectRatio;
8858
+ if (options.size !== void 0) imageConfig.imageSize = options.size;
8859
+ const body = {
8860
+ contents: [{ role: "user", parts }],
8861
+ generationConfig: {
8862
+ responseModalities: ["IMAGE"],
8863
+ candidateCount: 1,
8864
+ ...Object.keys(imageConfig).length > 0 ? { imageConfig } : {}
8865
+ }
8866
+ };
8867
+ const base = env.baseUrl.replace(/\/+$/, "");
8868
+ const root = /\/v1beta\d*$/.test(base) ? base : `${base}/v1beta`;
8869
+ const { payload } = await postJson(env, `${root}/models/${model.id}:generateContent`, body);
8870
+ return parseGeminiPayload(payload);
8871
+ };
8872
+ var geminiHeaders = (apiKey) => ({ "x-goog-api-key": apiKey });
8873
+ var callDialect = (dialect, env, model, options) => {
8874
+ switch (dialect) {
8875
+ case "images":
8876
+ return requestImages(env, model, options);
8877
+ case "responses":
8878
+ return requestResponses(env, model, options);
8879
+ case "chat":
8880
+ return requestChat(env, model, options);
8881
+ case "gemini":
8882
+ return requestGemini(env, model, options);
8883
+ }
8884
+ };
8885
+ var readSourceImage = async (source, cwd) => {
8886
+ if (source.startsWith("data:")) {
8887
+ const decoded = decodeImage(source);
8888
+ if (!decoded) throw new Error(`image source is not a usable data URL: ${source.slice(0, 40)}`);
8889
+ return decoded;
8890
+ }
8891
+ const resolved = path10.isAbsolute(source) ? source : path10.resolve(cwd, source);
8892
+ const bytes = await readFile2(resolved);
8893
+ const mimeType = mimeFromMagic(bytes);
8894
+ if (!mimeType) throw new Error(`unsupported or missing image file: ${resolved}`);
8895
+ return { data: bytes.toString("base64"), mimeType };
8896
+ };
8897
+ var transient = (error) => {
8898
+ const status = error?.status;
8899
+ if (typeof status === "number") return status >= 500 || status === 408 || status === 409 || status === 429;
8900
+ return true;
8901
+ };
8902
+ var describeError = (error) => error instanceof Error ? error.message : String(error);
8903
+ var ImageProvider = class {
8904
+ constructor(config, options = {}) {
8905
+ this.config = config;
8906
+ this.options = options;
8907
+ }
8908
+ name = "image";
8909
+ description = "Image generation and editing across a configurable priority chain of image models";
8910
+ async list(request, _context) {
8911
+ const query = request.query?.toLowerCase();
8912
+ if (!query) return descriptors2;
8913
+ return descriptors2.filter(
8914
+ (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
8915
+ );
8916
+ }
8917
+ async describe(actionName, _context) {
8918
+ return descriptors2.find((descriptor) => descriptor.name === actionName);
8919
+ }
8920
+ async invoke(actionName, args, context) {
8921
+ switch (actionName) {
8922
+ case "generate":
8923
+ return this.run("generate", args, context);
8924
+ case "edit":
8925
+ return this.run("edit", args, context);
8926
+ case "models":
8927
+ return this.chain(context);
8928
+ default:
8929
+ throw new Error(`Unknown image action: ${actionName}`);
8930
+ }
8931
+ }
8932
+ registry(context) {
8933
+ const registry = context.extensionContext.modelRegistry;
8934
+ if (!registry) throw new Error("image provider needs a model registry on the extension context");
8935
+ return registry;
8936
+ }
8937
+ resolveModel(registry, selector) {
8938
+ const parsed = splitModelSelector(selector);
8939
+ if (!parsed) return void 0;
8940
+ const found = registry.find(parsed.provider, parsed.id);
8941
+ if (!isRecord3(found)) return void 0;
8942
+ const api = typeof found.api === "string" ? found.api : "";
8943
+ const baseUrl = typeof found.baseUrl === "string" ? found.baseUrl : "";
8944
+ if (api.length === 0 || baseUrl.length === 0) return void 0;
8945
+ return {
8946
+ provider: parsed.provider,
8947
+ id: parsed.id,
8948
+ api,
8949
+ baseUrl,
8950
+ gptImage: GPT_IMAGE_FAMILY.test(parsed.id),
8951
+ codex: api === "openai-codex-responses",
8952
+ xai: parsed.provider === "xai" || parsed.provider === "xai-oauth" || parsed.provider.startsWith("xai-")
8953
+ };
8954
+ }
8955
+ dialectFor(model) {
8956
+ const override = this.config().dialects[`${model.provider}/${model.id}`];
8957
+ return override ?? inferImageDialect(model.api, model.id);
8958
+ }
8959
+ chainSelectors(args) {
8960
+ const preferred = typeof args.model === "string" ? args.model.trim() : "";
8961
+ const configured = this.config().models;
8962
+ const selectors = preferred.length > 0 ? [preferred, ...configured] : [...configured];
8963
+ const seen = /* @__PURE__ */ new Set();
8964
+ return selectors.filter((selector) => {
8965
+ if (seen.has(selector)) return false;
8966
+ seen.add(selector);
8967
+ return true;
8968
+ });
8969
+ }
8970
+ async chain(context) {
8971
+ const registry = this.registry(context);
8972
+ const sessionId = context.extensionContext.sessionManager.getSessionId() ?? void 0;
8973
+ const entries = [];
8974
+ for (const selector of this.config().models) {
8975
+ const model = this.resolveModel(registry, selector);
8976
+ if (!model) {
8977
+ entries.push({ selector, resolved: false, reason: "no matching model in the registry" });
8978
+ continue;
8979
+ }
8980
+ let credentials = false;
8981
+ try {
8982
+ const apiKey = await registry.getApiKey(model, sessionId);
8983
+ credentials = typeof apiKey === "string" && apiKey.length > 0;
8984
+ } catch {
8985
+ credentials = false;
8986
+ }
8987
+ entries.push({
8988
+ selector,
8989
+ resolved: true,
8990
+ provider: model.provider,
8991
+ id: model.id,
8992
+ api: model.api,
8993
+ baseUrl: model.baseUrl,
8994
+ dialect: this.dialectFor(model),
8995
+ credentials
8996
+ });
8997
+ }
8998
+ return {
8999
+ enabled: this.config().enabled,
9000
+ timeoutMs: this.config().timeoutMs,
9001
+ retries: this.config().retries,
9002
+ outputDir: this.config().outputDir || os.tmpdir(),
9003
+ models: entries
9004
+ };
9005
+ }
9006
+ async run(action, args, context) {
9007
+ const config = this.config();
9008
+ if (!config.enabled) {
9009
+ return { ok: false, reason: "image provider is disabled (image.enabled=false)" };
9010
+ }
9011
+ const prompt = typeof args.prompt === "string" ? args.prompt.trim() : "";
9012
+ if (prompt.length === 0) return { ok: false, reason: "prompt must be a non-empty string" };
9013
+ const selectors = this.chainSelectors(args);
9014
+ if (selectors.length === 0) {
9015
+ return { ok: false, reason: "no image models configured (image.models is empty)" };
9016
+ }
9017
+ const count = typeof args.count === "number" && Number.isFinite(args.count) && args.count > 0 ? Math.min(Math.floor(args.count), 4) : 1;
9018
+ const aspectRatio = typeof args.aspectRatio === "string" ? args.aspectRatio : void 0;
9019
+ const size = typeof args.size === "string" ? args.size : void 0;
9020
+ const saveTo = typeof args.saveTo === "string" && args.saveTo.trim().length > 0 ? args.saveTo.trim() : void 0;
9021
+ const sources = action === "edit" ? Array.isArray(args.images) ? args.images.filter((entry) => typeof entry === "string") : [] : [];
9022
+ if (action === "edit" && sources.length === 0) {
9023
+ return { ok: false, reason: "edit needs at least one image path or data URL" };
9024
+ }
9025
+ let inputImages = [];
9026
+ try {
9027
+ inputImages = await Promise.all(sources.map((source) => readSourceImage(source, context.cwd)));
9028
+ } catch (error) {
9029
+ return { ok: false, reason: describeError(error) };
9030
+ }
9031
+ const registry = this.registry(context);
9032
+ const sessionId = context.extensionContext.sessionManager.getSessionId() ?? void 0;
9033
+ const fetchImpl = this.options.fetchImpl ?? fetch;
9034
+ const now = this.options.now ?? Date.now;
9035
+ const started = now();
9036
+ const failures = [];
9037
+ const attemptsPerModel = Math.max(1, Math.min(config.retries + 1, 5));
9038
+ for (const selector of selectors) {
9039
+ const model = this.resolveModel(registry, selector);
9040
+ if (!model) {
9041
+ failures.push({ model: selector, dialect: "images", error: "no matching model in the registry" });
9042
+ continue;
9043
+ }
9044
+ const dialect = this.dialectFor(model);
9045
+ let apiKey;
9046
+ let extraHeaders = {};
9047
+ try {
9048
+ apiKey = await registry.getApiKey(model, sessionId);
9049
+ extraHeaders = await registry.resolveModelHeaders?.(model, context.signal) ?? {};
9050
+ } catch (error) {
9051
+ failures.push({ model: selector, dialect, error: `credential lookup failed: ${describeError(error)}` });
9052
+ continue;
9053
+ }
9054
+ if (typeof apiKey !== "string" || apiKey.length === 0) {
9055
+ failures.push({ model: selector, dialect, error: "no credential for this model" });
9056
+ continue;
9057
+ }
9058
+ const authHeaders = model.api === "google-generative-ai" ? geminiHeaders(apiKey) : { Authorization: `Bearer ${apiKey}` };
9059
+ for (let attempt = 1; attempt <= attemptsPerModel; attempt += 1) {
9060
+ context.signal?.throwIfAborted();
9061
+ const signals = [AbortSignal.timeout(config.timeoutMs)];
9062
+ if (context.signal) signals.push(context.signal);
9063
+ const env = {
9064
+ baseUrl: model.baseUrl,
9065
+ apiKey,
9066
+ headers: { ...authHeaders, ...extraHeaders },
9067
+ signal: AbortSignal.any(signals),
9068
+ fetchImpl
9069
+ };
9070
+ try {
9071
+ const images = await callDialect(dialect, env, model, {
9072
+ prompt,
9073
+ aspectRatio,
9074
+ size,
9075
+ count,
9076
+ inputImages,
9077
+ signal: env.signal
9078
+ });
9079
+ if (images.length === 0) throw new Error("backend returned no image data");
9080
+ let written;
9081
+ try {
9082
+ written = await this.write(images, saveTo, context.cwd);
9083
+ } catch (error) {
9084
+ return {
9085
+ ok: false,
9086
+ reason: `${model.provider}/${model.id} returned ${images.length} image(s) but the write failed: ${describeError(error)}`,
9087
+ model: `${model.provider}/${model.id}`,
9088
+ dialect,
9089
+ failures,
9090
+ elapsedMs: Math.max(0, now() - started)
9091
+ };
9092
+ }
9093
+ context.attachMedia?.(
9094
+ written.map((entry) => ({ type: "image", data: entry.data, mimeType: entry.mimeType })),
9095
+ `Generated ${written.length} image(s) with ${model.provider}/${model.id} (${dialect}):
9096
+ ${written.map((entry) => ` ${entry.path} (${entry.bytes} bytes)`).join("\n")}`
9097
+ );
9098
+ return {
9099
+ ok: true,
9100
+ model: `${model.provider}/${model.id}`,
9101
+ dialect,
9102
+ images: written.map((entry) => ({ path: entry.path, bytes: entry.bytes, mimeType: entry.mimeType })),
9103
+ attempts: attempt,
9104
+ elapsedMs: Math.max(0, now() - started),
9105
+ failures
9106
+ };
9107
+ } catch (error) {
9108
+ const status = error?.status;
9109
+ failures.push({
9110
+ model: `${model.provider}/${model.id}`,
9111
+ dialect,
9112
+ error: describeError(error),
9113
+ ...typeof status === "number" ? { status } : {}
9114
+ });
9115
+ if (context.signal?.aborted) throw error;
9116
+ if (attempt < attemptsPerModel && transient(error)) continue;
9117
+ break;
9118
+ }
9119
+ }
9120
+ }
9121
+ return {
9122
+ ok: false,
9123
+ reason: `every configured image model failed (${failures.length} attempt${failures.length === 1 ? "" : "s"})`,
9124
+ failures,
9125
+ elapsedMs: Math.max(0, now() - started)
9126
+ };
9127
+ }
9128
+ async write(images, saveTo, cwd) {
9129
+ const configured = this.config().outputDir;
9130
+ const directory = configured.length > 0 ? path10.isAbsolute(configured) ? configured : path10.resolve(cwd, configured) : os.tmpdir();
9131
+ await mkdir(directory, { recursive: true, mode: 448 });
9132
+ const written = [];
9133
+ for (const [index, image] of images.entries()) {
9134
+ const extension = extensionForMime(image.mimeType);
9135
+ const target = saveTo !== void 0 && images.length === 1 ? path10.isAbsolute(saveTo) ? saveTo : path10.resolve(cwd, saveTo) : path10.join(directory, `fabric-image-${Date.now()}-${index}.${extension}`);
9136
+ await mkdir(path10.dirname(target), { recursive: true, mode: 448 });
9137
+ const bytes = Buffer.from(image.data, "base64");
9138
+ await writeFile(target, bytes, { mode: 384 });
9139
+ written.push({ path: target, bytes: bytes.length, mimeType: image.mimeType, data: image.data });
9140
+ }
9141
+ return written;
9142
+ }
9143
+ };
9144
+
8501
9145
  // src/providers/judgment-provider.ts
8502
9146
  import { Type as Type2 } from "@oh-my-pi/pi-coding-agent/extensibility/legacy-typebox";
8503
9147
  import { validateJsonSchemaValue as validateJsonSchemaValue2 } from "@oh-my-pi/pi-ai/utils/schema";
@@ -8510,7 +9154,7 @@ var askSchema = Type2.Object({
8510
9154
  })
8511
9155
  }, { additionalProperties: false });
8512
9156
  var statsSchema = Type2.Object({}, { additionalProperties: false });
8513
- var descriptors2 = [
9157
+ var descriptors3 = [
8514
9158
  {
8515
9159
  name: "ask",
8516
9160
  description: "Answer typed questions about one state with calibrated probabilities: choice (one label plus its distribution), bool (probability of yes), score (weighted position on ordered levels). Questions asked about the same state within the coalesce window travel as one backend request. Returns { ok: false, reason } instead of throwing when no backend is configured, the budget refuses, or the request fails.",
@@ -8524,8 +9168,8 @@ var descriptors2 = [
8524
9168
  risk: "read"
8525
9169
  }
8526
9170
  ];
8527
- var normalizeJudgmentArgs = actionArgNormalizer(() => descriptors2);
8528
- var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
9171
+ var normalizeJudgmentArgs = actionArgNormalizer(() => descriptors3);
9172
+ var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8529
9173
  var instructionsOf = (id, value) => {
8530
9174
  if (typeof value !== "string" || value.length === 0) {
8531
9175
  throw new Error(`judgment.ask question "${id}" needs non-empty string instructions`);
@@ -8534,7 +9178,7 @@ var instructionsOf = (id, value) => {
8534
9178
  };
8535
9179
  var parseChoice = (id, value) => {
8536
9180
  const instructions = instructionsOf(id, value.instructions);
8537
- if (!isRecord3(value.criteria)) {
9181
+ if (!isRecord4(value.criteria)) {
8538
9182
  throw new Error(`judgment.ask choice question "${id}" needs criteria: { label: rubric | null }`);
8539
9183
  }
8540
9184
  const criteria = {};
@@ -8553,7 +9197,7 @@ var parseChoice = (id, value) => {
8553
9197
  var parseBool = (id, value) => {
8554
9198
  const instructions = instructionsOf(id, value.instructions);
8555
9199
  if (value.criteria === void 0) return { type: "noul", instructions };
8556
- if (!isRecord3(value.criteria)) {
9200
+ if (!isRecord4(value.criteria)) {
8557
9201
  throw new Error(`judgment.ask bool question "${id}" criteria must be { true?: string, false?: string }`);
8558
9202
  }
8559
9203
  const criteria = {};
@@ -8580,7 +9224,7 @@ var parseScore = (id, value) => {
8580
9224
  return { type: "score", instructions, criteria: [lowest, second, ...rest] };
8581
9225
  };
8582
9226
  var parseQuestion = (id, value) => {
8583
- if (!isRecord3(value)) throw new Error(`judgment.ask question "${id}" must be an object`);
9227
+ if (!isRecord4(value)) throw new Error(`judgment.ask question "${id}" must be an object`);
8584
9228
  switch (value.type) {
8585
9229
  case "choice":
8586
9230
  return parseChoice(id, value);
@@ -8597,7 +9241,7 @@ var parseState = (value) => {
8597
9241
  if (value.length === 0) throw new Error("judgment.ask state must not be empty");
8598
9242
  return value;
8599
9243
  }
8600
- if (Array.isArray(value) || isRecord3(value)) return value;
9244
+ if (Array.isArray(value) || isRecord4(value)) return value;
8601
9245
  throw new Error("judgment.ask state must be a string, a JSON object, or a JSON array");
8602
9246
  };
8603
9247
  var checked2 = (action, schema, args) => {
@@ -8616,12 +9260,12 @@ var JudgmentProvider = class {
8616
9260
  description = "Typed judgments over one state: calibrated choice, bool, and score answers batched into one backend request";
8617
9261
  async list(request, _context) {
8618
9262
  const query = request.query?.toLowerCase();
8619
- return query ? descriptors2.filter(
9263
+ return query ? descriptors3.filter(
8620
9264
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
8621
- ) : descriptors2;
9265
+ ) : descriptors3;
8622
9266
  }
8623
9267
  async describe(actionName, _context) {
8624
- return descriptors2.find((descriptor) => descriptor.name === actionName);
9268
+ return descriptors3.find((descriptor) => descriptor.name === actionName);
8625
9269
  }
8626
9270
  prepareArguments(actionName, args) {
8627
9271
  return normalizeJudgmentArgs(actionName, args);
@@ -8933,7 +9577,7 @@ var emptySchema = {
8933
9577
  properties: {},
8934
9578
  additionalProperties: false
8935
9579
  };
8936
- var descriptors3 = [
9580
+ var descriptors4 = [
8937
9581
  {
8938
9582
  name: "request",
8939
9583
  description: "Request an advisory compaction of the host session's context at the next safe boundary (agent_end). The host commits it only between turns, never mid-turn. A new request replaces any pending one.",
@@ -8956,7 +9600,7 @@ var descriptors3 = [
8956
9600
  risk: "write"
8957
9601
  }
8958
9602
  ];
8959
- var normalizeCompactArgs = actionArgNormalizer(() => descriptors3);
9603
+ var normalizeCompactArgs = actionArgNormalizer(() => descriptors4);
8960
9604
  var CompactProvider = class {
8961
9605
  constructor(controller) {
8962
9606
  this.controller = controller;
@@ -8965,12 +9609,12 @@ var CompactProvider = class {
8965
9609
  description = "Programmatic, advisory-then-committed context compaction for the host OMP session";
8966
9610
  async list(request, _context) {
8967
9611
  const query = request.query?.toLowerCase();
8968
- return query ? descriptors3.filter(
9612
+ return query ? descriptors4.filter(
8969
9613
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
8970
- ) : descriptors3;
9614
+ ) : descriptors4;
8971
9615
  }
8972
9616
  async describe(actionName, _context) {
8973
- return descriptors3.find((descriptor) => descriptor.name === actionName);
9617
+ return descriptors4.find((descriptor) => descriptor.name === actionName);
8974
9618
  }
8975
9619
  prepareArguments(actionName, args) {
8976
9620
  return normalizeCompactArgs(actionName, args);
@@ -9010,7 +9654,7 @@ var CompactProvider = class {
9010
9654
  };
9011
9655
 
9012
9656
  // src/providers/components-provider.ts
9013
- var descriptors4 = [
9657
+ var descriptors5 = [
9014
9658
  {
9015
9659
  name: "list",
9016
9660
  description: "List registered component definitions and configured component instances.",
@@ -9057,13 +9701,13 @@ var ComponentsProvider = class {
9057
9701
  description = "Supervised component lifecycle, exact capability dependencies, effect cleanup, and reload diagnostics.";
9058
9702
  async list(request, _context) {
9059
9703
  const query = request.query?.normalize("NFKC").trim().toLowerCase();
9060
- const filtered = query ? descriptors4.filter(
9704
+ const filtered = query ? descriptors5.filter(
9061
9705
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
9062
- ) : descriptors4;
9706
+ ) : descriptors5;
9063
9707
  return filtered.slice(0, Math.max(1, Math.min(request.limit ?? 100, 100)));
9064
9708
  }
9065
9709
  async describe(actionName, _context) {
9066
- return descriptors4.find((descriptor) => descriptor.name === actionName);
9710
+ return descriptors5.find((descriptor) => descriptor.name === actionName);
9067
9711
  }
9068
9712
  async invoke(actionName, args, _context) {
9069
9713
  switch (actionName) {
@@ -9097,37 +9741,37 @@ var ComponentsProvider = class {
9097
9741
  // src/providers/mcp-descriptor-cache.ts
9098
9742
  import fs5 from "node:fs/promises";
9099
9743
  import fsSync from "node:fs";
9100
- import os from "node:os";
9101
- import path10 from "node:path";
9744
+ import os2 from "node:os";
9745
+ import path11 from "node:path";
9102
9746
  var MCP_DESCRIPTOR_CACHE_VERSION = 1;
9103
9747
  var homeDir = () => {
9104
9748
  const home = process.env.HOME;
9105
- return home && home.trim().length > 0 ? home : os.homedir();
9749
+ return home && home.trim().length > 0 ? home : os2.homedir();
9106
9750
  };
9107
9751
  var expandHome = (input) => {
9108
9752
  if (!input.startsWith("~")) return input;
9109
9753
  const home = homeDir();
9110
9754
  if (input === "~") return home;
9111
9755
  if (input.startsWith("~/") || input.startsWith("~\\")) {
9112
- return path10.join(home, input.slice(2));
9756
+ return path11.join(home, input.slice(2));
9113
9757
  }
9114
9758
  return input;
9115
9759
  };
9116
- var legacyMcporterDir = () => path10.join(homeDir(), ".mcporter");
9760
+ var legacyMcporterDir = () => path11.join(homeDir(), ".mcporter");
9117
9761
  var mcporterConfigDir = () => {
9118
9762
  const raw = process.env.XDG_CONFIG_HOME;
9119
9763
  if (raw && raw.trim().length > 0) {
9120
9764
  const resolved = expandHome(raw.trim());
9121
- if (path10.isAbsolute(resolved)) return path10.join(resolved, "mcporter");
9765
+ if (path11.isAbsolute(resolved)) return path11.join(resolved, "mcporter");
9122
9766
  }
9123
9767
  return legacyMcporterDir();
9124
9768
  };
9125
9769
  var mcporterConfigCandidates = () => {
9126
9770
  const base = mcporterConfigDir();
9127
- const candidates = [path10.join(base, "mcporter.json"), path10.join(base, "mcporter.jsonc")];
9771
+ const candidates = [path11.join(base, "mcporter.json"), path11.join(base, "mcporter.jsonc")];
9128
9772
  const legacy = legacyMcporterDir();
9129
9773
  if (base !== legacy) {
9130
- candidates.push(path10.join(legacy, "mcporter.json"), path10.join(legacy, "mcporter.jsonc"));
9774
+ candidates.push(path11.join(legacy, "mcporter.json"), path11.join(legacy, "mcporter.jsonc"));
9131
9775
  }
9132
9776
  return candidates;
9133
9777
  };
@@ -9142,12 +9786,12 @@ var pathExists = (filePath) => {
9142
9786
  var mcpConfigLayerPaths = (rootDir, configPath) => {
9143
9787
  const explicitRaw = configPath ?? process.env.MCPORTER_CONFIG;
9144
9788
  if (explicitRaw && explicitRaw.trim().length > 0) {
9145
- return [path10.resolve(expandHome(explicitRaw.trim()))];
9789
+ return [path11.resolve(expandHome(explicitRaw.trim()))];
9146
9790
  }
9147
9791
  const paths = [];
9148
9792
  const home = mcporterConfigCandidates().find(pathExists);
9149
9793
  if (home) paths.push(home);
9150
- const projectPath = path10.resolve(rootDir, "config", "mcporter.json");
9794
+ const projectPath = path11.resolve(rootDir, "config", "mcporter.json");
9151
9795
  if (pathExists(projectPath)) paths.push(projectPath);
9152
9796
  return paths;
9153
9797
  };
@@ -9169,11 +9813,11 @@ var sameConfigLayers = (left, right) => left.length === right.length && left.eve
9169
9813
  return other !== void 0 && layer.path === other.path && layer.size === other.size && Math.abs(layer.mtimeMs - other.mtimeMs) <= 1;
9170
9814
  });
9171
9815
  var hashServerDefinition = (definition) => stableJsonHash(definition);
9172
- var isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
9816
+ var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
9173
9817
  var parseCachedServer = (value) => {
9174
- if (!isRecord4(value)) return void 0;
9818
+ if (!isRecord5(value)) return void 0;
9175
9819
  const tools = Array.isArray(value.tools) ? value.tools.filter(
9176
- (tool) => isRecord4(tool) && typeof tool.name === "string"
9820
+ (tool) => isRecord5(tool) && typeof tool.name === "string"
9177
9821
  ) : void 0;
9178
9822
  if (typeof value.definitionHash !== "string" || tools === void 0) return void 0;
9179
9823
  return {
@@ -9186,10 +9830,10 @@ var parseCachedServer = (value) => {
9186
9830
  };
9187
9831
  };
9188
9832
  var parseCacheFile = (value) => {
9189
- if (!isRecord4(value) || value.version !== MCP_DESCRIPTOR_CACHE_VERSION) return void 0;
9190
- if (!Array.isArray(value.layers) || !isRecord4(value.servers)) return void 0;
9833
+ if (!isRecord5(value) || value.version !== MCP_DESCRIPTOR_CACHE_VERSION) return void 0;
9834
+ if (!Array.isArray(value.layers) || !isRecord5(value.servers)) return void 0;
9191
9835
  const layers = value.layers.filter(
9192
- (layer) => isRecord4(layer) && typeof layer.path === "string" && typeof layer.mtimeMs === "number" && typeof layer.size === "number"
9836
+ (layer) => isRecord5(layer) && typeof layer.path === "string" && typeof layer.mtimeMs === "number" && typeof layer.size === "number"
9193
9837
  );
9194
9838
  return {
9195
9839
  version: MCP_DESCRIPTOR_CACHE_VERSION,
@@ -9198,8 +9842,8 @@ var parseCacheFile = (value) => {
9198
9842
  servers: value.servers
9199
9843
  };
9200
9844
  };
9201
- var projectMcpCachePath = (projectRoot) => path10.join(projectRoot, ".omp", "fabric", "mcp-cache.json");
9202
- var globalMcpCachePath = (agentDir) => path10.join(agentDir, "fabric", "mcp-descriptors.json");
9845
+ var projectMcpCachePath = (projectRoot) => path11.join(projectRoot, ".omp", "fabric", "mcp-cache.json");
9846
+ var globalMcpCachePath = (agentDir) => path11.join(agentDir, "fabric", "mcp-descriptors.json");
9203
9847
  var tempCounter = 0;
9204
9848
  var McpDescriptorCacheStore = class {
9205
9849
  constructor(filePath) {
@@ -9216,9 +9860,9 @@ var McpDescriptorCacheStore = class {
9216
9860
  // Atomic-ish write: temp file then rename, so a concurrent reader either
9217
9861
  // sees the previous cache or the next one, never a torn document.
9218
9862
  async save(file) {
9219
- const directory = path10.dirname(this.filePath);
9863
+ const directory = path11.dirname(this.filePath);
9220
9864
  await fs5.mkdir(directory, { recursive: true });
9221
- const tempPath = path10.join(
9865
+ const tempPath = path11.join(
9222
9866
  directory,
9223
9867
  `.mcp-cache-${process.pid}-${Date.now()}-${tempCounter++}.tmp`
9224
9868
  );
@@ -9233,7 +9877,7 @@ var McpDescriptorCacheStore = class {
9233
9877
  };
9234
9878
 
9235
9879
  // src/providers/mcp-provider.ts
9236
- import path11 from "node:path";
9880
+ import path12 from "node:path";
9237
9881
  var TOOL_METADATA_TTL_MS = 6e4;
9238
9882
  var REVALIDATE_CONCURRENCY = 3;
9239
9883
  var REVALIDATE_SERVER_TIMEOUT_MS = 2e4;
@@ -9394,9 +10038,9 @@ var McpProvider = class {
9394
10038
  this.#kickRevalidation();
9395
10039
  if (!request.namespace) await this.#awaitColdEnumeration(context.signal);
9396
10040
  const query = request.query?.toLowerCase();
9397
- const filterQuery = (descriptors8) => query ? descriptors8.filter(
10041
+ const filterQuery = (descriptors9) => query ? descriptors9.filter(
9398
10042
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
9399
- ) : descriptors8;
10043
+ ) : descriptors9;
9400
10044
  if (request.namespace) {
9401
10045
  const server = await this.#resolveKnownServer(request.namespace);
9402
10046
  if (!server) return [];
@@ -9551,11 +10195,11 @@ var McpProvider = class {
9551
10195
  // Provider-fidelity descriptors for everything currently known, cached or
9552
10196
  // ephemeral.
9553
10197
  sliceDescriptors() {
9554
- const descriptors8 = [];
10198
+ const descriptors9 = [];
9555
10199
  for (const [server, entry] of this.#servers) {
9556
- for (const tool of entry.tools) descriptors8.push(this.#toolDescriptor(server, tool));
10200
+ for (const tool of entry.tools) descriptors9.push(this.#toolDescriptor(server, tool));
9557
10201
  }
9558
- return descriptors8;
10202
+ return descriptors9;
9559
10203
  }
9560
10204
  // Test/ops hook: await hydration and any in-flight background revalidation,
9561
10205
  // then flush pending persistence and notifications.
@@ -9957,7 +10601,7 @@ var McpProvider = class {
9957
10601
  kind: "stdio",
9958
10602
  command: args.command,
9959
10603
  args: commandArgs,
9960
- cwd: path11.resolve(this.cwd, typeof args.cwd === "string" ? args.cwd : ".")
10604
+ cwd: path12.resolve(this.cwd, typeof args.cwd === "string" ? args.cwd : ".")
9961
10605
  },
9962
10606
  ...env ? { env } : {}
9963
10607
  };
@@ -10022,13 +10666,13 @@ var McpProvider = class {
10022
10666
  return tools.map((tool) => this.#toolDescriptor(server, tool));
10023
10667
  })
10024
10668
  );
10025
- const descriptors8 = settled.flatMap(
10669
+ const descriptors9 = settled.flatMap(
10026
10670
  (entry) => entry.status === "fulfilled" ? entry.value : []
10027
10671
  );
10028
10672
  const query = request.query?.toLowerCase();
10029
- const filtered = query ? descriptors8.filter(
10673
+ const filtered = query ? descriptors9.filter(
10030
10674
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
10031
- ) : descriptors8;
10675
+ ) : descriptors9;
10032
10676
  return request.namespace ? filtered : [...managementDescriptors, ...filtered];
10033
10677
  }
10034
10678
  async #describeLegacy(actionName, _context) {
@@ -10100,7 +10744,7 @@ var assertReadableStateKey = (key) => {
10100
10744
  throw new Error(`Fabric mesh key is private host state: ${key}`);
10101
10745
  }
10102
10746
  };
10103
- var descriptors5 = [
10747
+ var descriptors6 = [
10104
10748
  {
10105
10749
  name: "self",
10106
10750
  description: "Return this Fabric participant's mesh identity",
@@ -10227,7 +10871,7 @@ var descriptors5 = [
10227
10871
  namespace: "coordination"
10228
10872
  }
10229
10873
  ];
10230
- var normalizeMeshArgs = actionArgNormalizer(() => descriptors5);
10874
+ var normalizeMeshArgs = actionArgNormalizer(() => descriptors6);
10231
10875
  var MeshProvider = class {
10232
10876
  constructor(store, identity, participants) {
10233
10877
  this.store = store;
@@ -10238,12 +10882,12 @@ var MeshProvider = class {
10238
10882
  description = "Durable topics and compare-and-swap shared state for emergent agent coordination";
10239
10883
  async list(request, _context) {
10240
10884
  const query = request.query?.toLowerCase();
10241
- return query ? descriptors5.filter(
10885
+ return query ? descriptors6.filter(
10242
10886
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
10243
- ) : descriptors5;
10887
+ ) : descriptors6;
10244
10888
  }
10245
10889
  async describe(actionName, _context) {
10246
- return descriptors5.find((descriptor) => descriptor.name === actionName);
10890
+ return descriptors6.find((descriptor) => descriptor.name === actionName);
10247
10891
  }
10248
10892
  prepareArguments(actionName, args) {
10249
10893
  return normalizeMeshArgs(actionName, args);
@@ -10337,7 +10981,7 @@ var MeshProvider = class {
10337
10981
  // src/providers/omp-tools-provider.ts
10338
10982
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, statSync as statSync4, writeFileSync as writeFileSync2 } from "node:fs";
10339
10983
  import { AsyncLocalStorage } from "node:async_hooks";
10340
- import path14 from "node:path";
10984
+ import path15 from "node:path";
10341
10985
  import { randomUUID as randomUUID3 } from "node:crypto";
10342
10986
  import { BashTool } from "@oh-my-pi/pi-coding-agent/tools/bash";
10343
10987
  import { EditTool } from "@oh-my-pi/pi-coding-agent/edit";
@@ -10356,7 +11000,7 @@ import {
10356
11000
 
10357
11001
  // src/agents/bash-worktree-add.ts
10358
11002
  import fs6 from "node:fs";
10359
- import path12 from "node:path";
11003
+ import path13 from "node:path";
10360
11004
  var BARE_SAFE = /^[A-Za-z0-9_./:@%+=,-]+$/;
10361
11005
  var parseGitWorktreeAdd = (command) => {
10362
11006
  const trimmed = command.trim();
@@ -10419,8 +11063,8 @@ var tryExecuteGitWorktreeAdd = async (args, sessionCwd) => {
10419
11063
  if (typeof command !== "string") return void 0;
10420
11064
  const parsed = parseGitWorktreeAdd(command);
10421
11065
  if (!parsed) return void 0;
10422
- const gitCwd = parsed.gitCwd ? path12.resolve(sessionCwd, parsed.gitCwd) : typeof args.cwd === "string" ? args.cwd : sessionCwd;
10423
- const dest = path12.resolve(gitCwd, parsed.dest);
11066
+ const gitCwd = parsed.gitCwd ? path13.resolve(sessionCwd, parsed.gitCwd) : typeof args.cwd === "string" ? args.cwd : sessionCwd;
11067
+ const dest = path13.resolve(gitCwd, parsed.dest);
10424
11068
  let gitRoot;
10425
11069
  try {
10426
11070
  const root = await executeFile("git", ["rev-parse", "--show-toplevel"], {
@@ -10449,7 +11093,7 @@ var tryExecuteGitWorktreeAdd = async (args, sessionCwd) => {
10449
11093
 
10450
11094
  // src/providers/omp-bash-cwd.ts
10451
11095
  import { accessSync, constants, statSync as statSync3 } from "node:fs";
10452
- import path13 from "node:path";
11096
+ import path14 from "node:path";
10453
11097
  import { createBashToolDefinition } from "@oh-my-pi/pi-coding-agent/extensibility/legacy-pi-coding-agent-shim";
10454
11098
  import { Type as Type4 } from "@oh-my-pi/pi-coding-agent/extensibility/legacy-typebox";
10455
11099
  var OMP_BASH_CWD_KEY = "cwd";
@@ -10459,7 +11103,7 @@ var resolveOmpShellCwd = (toolName, sessionCwd, requested) => {
10459
11103
  `Invalid omp.${toolName} cwd ${JSON.stringify(requested)}: path must be a non-empty string`
10460
11104
  );
10461
11105
  }
10462
- const resolved = path13.isAbsolute(requested) ? path13.resolve(requested) : path13.resolve(sessionCwd, requested);
11106
+ const resolved = path14.isAbsolute(requested) ? path14.resolve(requested) : path14.resolve(sessionCwd, requested);
10463
11107
  try {
10464
11108
  if (!statSync3(resolved).isDirectory()) throw new Error("path is not a directory");
10465
11109
  accessSync(resolved, constants.R_OK | constants.X_OK);
@@ -10481,23 +11125,23 @@ var resolveShellCwdArgument = (toolName, sessionCwd, args) => Object.hasOwn(args
10481
11125
  } : args;
10482
11126
  var CWD_DESCRIPTION = "Execution directory for this command; relative paths resolve from the session cwd.";
10483
11127
  var CWD_PROPERTY = Type4.Optional(Type4.String({ description: CWD_DESCRIPTION }));
10484
- var isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
11128
+ var isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
10485
11129
  var SHELL_FIELD_DESCRIPTIONS = {
10486
11130
  command: "command to execute",
10487
11131
  [OMP_BASH_CWD_KEY]: CWD_DESCRIPTION,
10488
11132
  pty: "run in pty mode"
10489
11133
  };
10490
11134
  var schemaDocument2 = (schema) => {
10491
- if (isRecord5(schema)) return schema;
11135
+ if (isRecord6(schema)) return schema;
10492
11136
  if (typeof schema !== "function" || !("toJsonSchema" in schema)) return void 0;
10493
11137
  const toJsonSchema = schema.toJsonSchema;
10494
11138
  if (typeof toJsonSchema !== "function") return void 0;
10495
11139
  const document = toJsonSchema.call(schema);
10496
- return isRecord5(document) ? document : void 0;
11140
+ return isRecord6(document) ? document : void 0;
10497
11141
  };
10498
11142
  var withShellCwdSchema = (schema) => {
10499
11143
  const document = schemaDocument2(schema);
10500
- if (!document || !isRecord5(document.properties)) return schema;
11144
+ if (!document || !isRecord6(document.properties)) return schema;
10501
11145
  const properties = { ...document.properties };
10502
11146
  let changed = false;
10503
11147
  const cwdSchema = Object.hasOwn(properties, OMP_BASH_CWD_KEY) ? void 0 : schemaDocument2(CWD_PROPERTY);
@@ -10507,7 +11151,7 @@ var withShellCwdSchema = (schema) => {
10507
11151
  }
10508
11152
  for (const [field, description] of Object.entries(SHELL_FIELD_DESCRIPTIONS)) {
10509
11153
  const property = properties[field];
10510
- if (!isRecord5(property) || typeof property.description === "string") continue;
11154
+ if (!isRecord6(property) || typeof property.description === "string") continue;
10511
11155
  properties[field] = { ...property, description };
10512
11156
  changed = true;
10513
11157
  }
@@ -10544,23 +11188,23 @@ var BashCwdDefinitions = class extends ShellCwdDefinitions {
10544
11188
  // src/providers/write-preview.ts
10545
11189
  import { homedir } from "node:os";
10546
11190
  import { dirname, isAbsolute, resolve, win32 } from "node:path";
10547
- import { mkdir, readFile as readFile2, stat, writeFile } from "node:fs/promises";
11191
+ import { mkdir as mkdir2, readFile as readFile3, stat, writeFile as writeFile2 } from "node:fs/promises";
10548
11192
  import { Type as Type5 } from "@oh-my-pi/pi-coding-agent/extensibility/legacy-typebox";
10549
11193
  import { WriteTool } from "@oh-my-pi/pi-coding-agent/tools/write";
10550
11194
  var mutationQueues = /* @__PURE__ */ new Map();
10551
- var withFileMutationQueue = async (path20, operation) => {
10552
- const previous = mutationQueues.get(path20) ?? Promise.resolve();
11195
+ var withFileMutationQueue = async (path21, operation) => {
11196
+ const previous = mutationQueues.get(path21) ?? Promise.resolve();
10553
11197
  let release;
10554
11198
  const current = new Promise((resolve2) => {
10555
11199
  release = resolve2;
10556
11200
  });
10557
- mutationQueues.set(path20, current);
11201
+ mutationQueues.set(path21, current);
10558
11202
  await previous;
10559
11203
  try {
10560
11204
  return await operation();
10561
11205
  } finally {
10562
11206
  release();
10563
- if (mutationQueues.get(path20) === current) mutationQueues.delete(path20);
11207
+ if (mutationQueues.get(path21) === current) mutationQueues.delete(path21);
10564
11208
  }
10565
11209
  };
10566
11210
  var URI_LIKE_WRITE_TARGET_RE = /^([a-z][a-z0-9+.-]*):\/{1,2}/i;
@@ -10605,7 +11249,7 @@ var readExistingFileForPreview = async (filePath, cwd, nextContent) => {
10605
11249
  return skipped("previous file too large", fileStat.size, true);
10606
11250
  }
10607
11251
  try {
10608
- const content = await readFile2(absolutePath, "utf8");
11252
+ const content = await readFile3(absolutePath, "utf8");
10609
11253
  const bytes = Buffer.byteLength(content, "utf8");
10610
11254
  return bytes > MAX_WRITE_DIFF_BYTES ? skipped("previous file too large", bytes, true) : { kind: "content", content };
10611
11255
  } catch {
@@ -10623,11 +11267,11 @@ var createPreviewWriteToolDefinition = (cwd, session) => {
10623
11267
  return {
10624
11268
  ...original,
10625
11269
  async execute(_toolCallId, params, signal) {
10626
- const { path: path20, content } = params;
10627
- if (isUriLikeWriteTarget(path20)) {
11270
+ const { path: path21, content } = params;
11271
+ if (isUriLikeWriteTarget(path21)) {
10628
11272
  if (session === void 0) {
10629
11273
  throw new Error(
10630
- `Refusing to write '${path20}': URI-like targets need a host session to resolve. Prefix the path with './' to create a literal file by that name.`
11274
+ `Refusing to write '${path21}': URI-like targets need a host session to resolve. Prefix the path with './' to create a literal file by that name.`
10631
11275
  );
10632
11276
  }
10633
11277
  return await new WriteTool(session).execute(
@@ -10639,23 +11283,23 @@ var createPreviewWriteToolDefinition = (cwd, session) => {
10639
11283
  { signal }
10640
11284
  );
10641
11285
  }
10642
- const absolutePath = resolvePreviewPath(path20, cwd);
11286
+ const absolutePath = resolvePreviewPath(path21, cwd);
10643
11287
  return withFileMutationQueue(absolutePath, async () => {
10644
11288
  const throwIfAborted2 = () => {
10645
11289
  if (signal?.aborted) throw new Error("Operation aborted");
10646
11290
  };
10647
11291
  throwIfAborted2();
10648
- const before = await readExistingFileForPreview(path20, cwd, content);
11292
+ const before = await readExistingFileForPreview(path21, cwd, content);
10649
11293
  throwIfAborted2();
10650
- await mkdir(dirname(absolutePath), { recursive: true });
11294
+ await mkdir2(dirname(absolutePath), { recursive: true });
10651
11295
  throwIfAborted2();
10652
- await writeFile(absolutePath, content, "utf8");
11296
+ await writeFile2(absolutePath, content, "utf8");
10653
11297
  throwIfAborted2();
10654
11298
  return {
10655
11299
  content: [
10656
11300
  {
10657
11301
  type: "text",
10658
- text: `Successfully wrote ${Buffer.byteLength(content, "utf8")} bytes to ${path20}`
11302
+ text: `Successfully wrote ${Buffer.byteLength(content, "utf8")} bytes to ${path21}`
10659
11303
  }
10660
11304
  ],
10661
11305
  details: { codePreviewBeforeWrite: before }
@@ -10782,7 +11426,7 @@ var createNativeSession = (cwd, {
10782
11426
  try {
10783
11427
  mkdirSync2(artifacts.root, { recursive: true, mode: 448 });
10784
11428
  const id = randomUUID3();
10785
- const artifactPath = path14.join(artifacts.root, `${toolType}-${id}.log`);
11429
+ const artifactPath = path15.join(artifacts.root, `${toolType}-${id}.log`);
10786
11430
  writeFileSync2(artifactPath, "", { mode: 384 });
10787
11431
  artifacts.paths.set(id, artifactPath);
10788
11432
  artifactAllocations.getStore()?.push(artifactPath);
@@ -10950,7 +11594,7 @@ var normalizeEditArguments = (args, replaceAll, cwd) => {
10950
11594
  ...replaceAll || record2.all === true || record2.replace_all === true ? { replace_all: true } : {}
10951
11595
  };
10952
11596
  });
10953
- const resolvedPath = path14.resolve(cwd, filePath.startsWith("@") ? filePath.slice(1) : filePath);
11597
+ const resolvedPath = path15.resolve(cwd, filePath.startsWith("@") ? filePath.slice(1) : filePath);
10954
11598
  const current = readFileSync2(resolvedPath, "utf8");
10955
11599
  if (current.length > MAX_REPLACE_ALL_FILE_CHARS) {
10956
11600
  throw new Error(`omp.edit refuses files over ${MAX_REPLACE_ALL_FILE_CHARS} characters`);
@@ -11425,10 +12069,10 @@ var OmpToolsProvider = class _OmpToolsProvider {
11425
12069
  }
11426
12070
  async list(request, _context) {
11427
12071
  const query = request.query?.toLowerCase();
11428
- const descriptors8 = await Promise.all(
12072
+ const descriptors9 = await Promise.all(
11429
12073
  OMP_GUEST_TOOL_NAMES.map((name) => this.describe(name, _context))
11430
12074
  );
11431
- return descriptors8.filter((descriptor) => descriptor !== void 0).filter(
12075
+ return descriptors9.filter((descriptor) => descriptor !== void 0).filter(
11432
12076
  (descriptor) => query ? `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query) : true
11433
12077
  );
11434
12078
  }
@@ -11834,7 +12478,7 @@ var OmpToolsProvider = class _OmpToolsProvider {
11834
12478
  import { spawn } from "node:child_process";
11835
12479
  import { createHash as createHash3, randomBytes, randomUUID as randomUUID4 } from "node:crypto";
11836
12480
  import fs8 from "node:fs";
11837
- import path16 from "node:path";
12481
+ import path17 from "node:path";
11838
12482
 
11839
12483
  // src/schema/types.ts
11840
12484
  var stateBinding = (head) => head ? { transitionId: head.transitionId, version: head.version, to: head.to } : null;
@@ -11843,7 +12487,7 @@ var stateBinding = (head) => head ? { transitionId: head.transitionId, version:
11843
12487
  import { execFileSync } from "node:child_process";
11844
12488
  import { createHash as createHash2 } from "node:crypto";
11845
12489
  import fs7 from "node:fs";
11846
- import path15 from "node:path";
12490
+ import path16 from "node:path";
11847
12491
  var SNAPSHOT_MAX_FILES = 2e4;
11848
12492
  var SNAPSHOT_MAX_BYTES = 512 * 1024 * 1024;
11849
12493
  var FALLBACK_SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([
@@ -11861,10 +12505,10 @@ var git = (cwd, args) => execFileSync("git", ["-C", cwd, ...args], {
11861
12505
  stdio: ["ignore", "pipe", "ignore"]
11862
12506
  });
11863
12507
  var nulPaths = (buffer) => buffer.toString("utf8").split("\0").filter((item) => item.length > 0);
11864
- var normalizeRelative = (value) => value.split(path15.sep).join("/");
12508
+ var normalizeRelative = (value) => value.split(path16.sep).join("/");
11865
12509
  var isInside = (root, candidate) => {
11866
- const relative = path15.relative(root, candidate);
11867
- return relative === "" || !path15.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path15.sep}`);
12510
+ const relative = path16.relative(root, candidate);
12511
+ return relative === "" || !path16.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path16.sep}`);
11868
12512
  };
11869
12513
  var excluded = (absolute, exclusions) => exclusions.some((root) => isInside(root, absolute));
11870
12514
  var entryDigest = (absolute) => {
@@ -11890,12 +12534,12 @@ var buildSnapshot = (cwd, paths, metadata, exclusions) => {
11890
12534
  let bytes = 0;
11891
12535
  const unique = [...new Set(paths)].sort((left, right) => left.localeCompare(right));
11892
12536
  for (const relativeInput of unique) {
11893
- const absolute = path15.resolve(cwd, relativeInput);
12537
+ const absolute = path16.resolve(cwd, relativeInput);
11894
12538
  if (!isInside(cwd, absolute) || excluded(absolute, exclusions)) continue;
11895
12539
  if (Object.keys(entries).length >= SNAPSHOT_MAX_FILES) {
11896
12540
  throw new Error(`Schema workspace snapshot exceeds ${SNAPSHOT_MAX_FILES} files`);
11897
12541
  }
11898
- const relative = normalizeRelative(path15.relative(cwd, absolute));
12542
+ const relative = normalizeRelative(path16.relative(cwd, absolute));
11899
12543
  const entry = entryDigest(absolute);
11900
12544
  bytes += entry.bytes;
11901
12545
  if (bytes > SNAPSHOT_MAX_BYTES) {
@@ -11924,9 +12568,9 @@ var fallbackPaths = (cwd, exclusions) => {
11924
12568
  const entries = fs7.readdirSync(directory, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
11925
12569
  for (const entry of entries) {
11926
12570
  if (FALLBACK_SKIPPED_DIRECTORIES.has(entry.name)) continue;
11927
- const absolute = path15.join(directory, entry.name);
12571
+ const absolute = path16.join(directory, entry.name);
11928
12572
  if (excluded(absolute, exclusions)) continue;
11929
- const relative = normalizeRelative(path15.relative(cwd, absolute));
12573
+ const relative = normalizeRelative(path16.relative(cwd, absolute));
11930
12574
  if (entry.isDirectory()) visit(absolute);
11931
12575
  else paths.push(relative);
11932
12576
  if (paths.length > SNAPSHOT_MAX_FILES) {
@@ -11940,7 +12584,7 @@ var fallbackPaths = (cwd, exclusions) => {
11940
12584
  var snapshotWorkspace = (cwdInput, excludedRoots = []) => {
11941
12585
  const cwd = fs7.realpathSync(cwdInput);
11942
12586
  const exclusions = excludedRoots.map((root) => {
11943
- const absolute = path15.resolve(root);
12587
+ const absolute = path16.resolve(root);
11944
12588
  try {
11945
12589
  return fs7.realpathSync(absolute);
11946
12590
  } catch {
@@ -11978,18 +12622,18 @@ var snapshotWorkspace = (cwdInput, excludedRoots = []) => {
11978
12622
  );
11979
12623
  };
11980
12624
  var resolveWorkspaceFile = (cwdInput, requestedPath, options) => {
11981
- if (!requestedPath.trim() || path15.isAbsolute(requestedPath)) {
12625
+ if (!requestedPath.trim() || path16.isAbsolute(requestedPath)) {
11982
12626
  throw new Error(`Schema paths must be non-empty project-relative paths: ${requestedPath}`);
11983
12627
  }
11984
12628
  const cwd = fs7.realpathSync(cwdInput);
11985
- const absolute = path15.resolve(cwd, requestedPath);
12629
+ const absolute = path16.resolve(cwd, requestedPath);
11986
12630
  if (!isInside(cwd, absolute) || absolute === cwd) {
11987
12631
  throw new Error(`Schema path escapes the project workspace: ${requestedPath}`);
11988
12632
  }
11989
- const relativeParts = path15.relative(cwd, absolute).split(path15.sep);
12633
+ const relativeParts = path16.relative(cwd, absolute).split(path16.sep);
11990
12634
  let cursor = cwd;
11991
12635
  for (let index = 0; index < relativeParts.length; index++) {
11992
- cursor = path15.join(cursor, relativeParts[index]);
12636
+ cursor = path16.join(cursor, relativeParts[index]);
11993
12637
  let stat2;
11994
12638
  try {
11995
12639
  stat2 = fs7.lstatSync(cursor);
@@ -11998,9 +12642,9 @@ var resolveWorkspaceFile = (cwdInput, requestedPath, options) => {
11998
12642
  if (index !== relativeParts.length - 1 || !options.allowAbsent) {
11999
12643
  throw new Error(`Schema path does not exist: ${requestedPath}`);
12000
12644
  }
12001
- const parentReal = fs7.realpathSync(path15.dirname(cursor));
12645
+ const parentReal = fs7.realpathSync(path16.dirname(cursor));
12002
12646
  if (!isInside(cwd, parentReal)) throw new Error(`Schema path parent escapes the workspace: ${requestedPath}`);
12003
- return { absolute, relative: normalizeRelative(path15.relative(cwd, absolute)), exists: false };
12647
+ return { absolute, relative: normalizeRelative(path16.relative(cwd, absolute)), exists: false };
12004
12648
  }
12005
12649
  throw error;
12006
12650
  }
@@ -12012,7 +12656,7 @@ var resolveWorkspaceFile = (cwdInput, requestedPath, options) => {
12012
12656
  throw new Error(`Schema transaction paths must name regular files: ${requestedPath}`);
12013
12657
  }
12014
12658
  }
12015
- return { absolute, relative: normalizeRelative(path15.relative(cwd, absolute)), exists: true };
12659
+ return { absolute, relative: normalizeRelative(path16.relative(cwd, absolute)), exists: true };
12016
12660
  };
12017
12661
  var sha256File = (absolute) => `sha256:${digest(fs7.readFileSync(absolute))}`;
12018
12662
 
@@ -12063,8 +12707,8 @@ var SchemaController = class {
12063
12707
  this.identity = identity;
12064
12708
  this.state = state;
12065
12709
  this.cwd = fs8.realpathSync(cwd);
12066
- this.#journalRoot = path16.join(mesh.root, "schema-transactions");
12067
- this.#lockPath = path16.join(this.#journalRoot, ".commit.lock");
12710
+ this.#journalRoot = path17.join(mesh.root, "schema-transactions");
12711
+ this.#lockPath = path17.join(this.#journalRoot, ".commit.lock");
12068
12712
  this.#recoverJournals();
12069
12713
  }
12070
12714
  #activeHypotheses = /* @__PURE__ */ new Map();
@@ -12263,7 +12907,7 @@ var SchemaController = class {
12263
12907
  this.#assertPayloadBound(input);
12264
12908
  const release = this.#acquireCommitLock();
12265
12909
  const transactionId = randomUUID4();
12266
- const journalPath = path16.join(this.#journalRoot, `${transactionId}.json`);
12910
+ const journalPath = path17.join(this.#journalRoot, `${transactionId}.json`);
12267
12911
  let journal;
12268
12912
  let consumed = false;
12269
12913
  let committed = false;
@@ -12744,7 +13388,7 @@ ${Date.now()}
12744
13388
  }
12745
13389
  for (const name of fs8.readdirSync(this.#journalRoot)) {
12746
13390
  if (!name.endsWith(".json")) continue;
12747
- const filePath = path16.join(this.#journalRoot, name);
13391
+ const filePath = path17.join(this.#journalRoot, name);
12748
13392
  try {
12749
13393
  const journal = JSON.parse(fs8.readFileSync(filePath, "utf8"));
12750
13394
  if (journal.format !== 1 || journal.status !== "applying" || !Array.isArray(journal.before)) continue;
@@ -12864,7 +13508,7 @@ var operationSchema = {
12864
13508
  }
12865
13509
  ]
12866
13510
  };
12867
- var descriptors6 = [
13511
+ var descriptors7 = [
12868
13512
  {
12869
13513
  name: "status",
12870
13514
  description: "Read the fixed session Schema mode, transaction bounds, generation, and invocation hypotheses",
@@ -12934,7 +13578,7 @@ var descriptors6 = [
12934
13578
  namespace: "schema"
12935
13579
  }
12936
13580
  ];
12937
- var normalizeSchemaArgs = actionArgNormalizer(() => descriptors6);
13581
+ var normalizeSchemaArgs = actionArgNormalizer(() => descriptors7);
12938
13582
  var SchemaProvider = class {
12939
13583
  constructor(controller) {
12940
13584
  this.controller = controller;
@@ -12943,12 +13587,12 @@ var SchemaProvider = class {
12943
13587
  description = "Host-owned, opt-in Schema verification and bounded local-file transaction control plane";
12944
13588
  async list(request, _context) {
12945
13589
  const query = request.query?.toLowerCase();
12946
- return query ? descriptors6.filter(
13590
+ return query ? descriptors7.filter(
12947
13591
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
12948
- ) : descriptors6;
13592
+ ) : descriptors7;
12949
13593
  }
12950
13594
  async describe(actionName, _context) {
12951
- return descriptors6.find((descriptor) => descriptor.name === actionName);
13595
+ return descriptors7.find((descriptor) => descriptor.name === actionName);
12952
13596
  }
12953
13597
  prepareArguments(actionName, args) {
12954
13598
  return normalizeSchemaArgs(actionName, args);
@@ -12998,11 +13642,11 @@ var SchemaProvider = class {
12998
13642
 
12999
13643
  // src/state/store.ts
13000
13644
  import { createHash as createHash5 } from "node:crypto";
13001
- import path18 from "node:path";
13645
+ import path19 from "node:path";
13002
13646
 
13003
13647
  // src/state/complexity.ts
13004
13648
  import fs9 from "node:fs";
13005
- import path17 from "node:path";
13649
+ import path18 from "node:path";
13006
13650
  var isWordStart = (character) => character !== void 0 && (character >= "a" && character <= "z" || character >= "A" && character <= "Z" || character === "_" || character === "$");
13007
13651
  var isWordPart = (character) => isWordStart(character) || character !== void 0 && character >= "0" && character <= "9";
13008
13652
  var regularExpressionPrefixWords = /* @__PURE__ */ new Set([
@@ -13234,7 +13878,7 @@ var languageComplexities = [
13234
13878
  typeScriptJavaScriptComplexity
13235
13879
  ];
13236
13880
  var complexityForFile = (file, languages = languageComplexities) => {
13237
- const extension = path17.extname(file).toLowerCase();
13881
+ const extension = path18.extname(file).toLowerCase();
13238
13882
  return languages.find((language) => language.extensions.includes(extension));
13239
13883
  };
13240
13884
  var countFileComplexity = (file) => {
@@ -14125,7 +14769,7 @@ var StateStore = class {
14125
14769
  const files = [];
14126
14770
  let netDelta = 0;
14127
14771
  for (const file of this.normalizeComplexityFiles(requestedFiles, input.cwd)) {
14128
- const measured = countFileComplexity(path18.resolve(input.cwd, file));
14772
+ const measured = countFileComplexity(path19.resolve(input.cwd, file));
14129
14773
  if (!measured) {
14130
14774
  files.push({ file, supported: false });
14131
14775
  continue;
@@ -14152,7 +14796,7 @@ var StateStore = class {
14152
14796
  const updates = [];
14153
14797
  let netDelta = 0;
14154
14798
  for (const file of this.normalizeComplexityFiles(files, cwd)) {
14155
- const measured = countFileComplexity(path18.resolve(cwd, file));
14799
+ const measured = countFileComplexity(path19.resolve(cwd, file));
14156
14800
  if (!measured) {
14157
14801
  deltas.push({ file, supported: false });
14158
14802
  continue;
@@ -14202,11 +14846,11 @@ var StateStore = class {
14202
14846
  const normalized = /* @__PURE__ */ new Set();
14203
14847
  for (const file of files) {
14204
14848
  if (!file.trim()) continue;
14205
- const relative = path18.relative(cwd, path18.resolve(cwd, file));
14206
- if (relative === ".." || relative.startsWith(`..${path18.sep}`) || path18.isAbsolute(relative)) {
14849
+ const relative = path19.relative(cwd, path19.resolve(cwd, file));
14850
+ if (relative === ".." || relative.startsWith(`..${path19.sep}`) || path19.isAbsolute(relative)) {
14207
14851
  throw new Error(`State complexity file must be inside the project cwd: ${file}`);
14208
14852
  }
14209
- normalized.add(relative.split(path18.sep).join("/"));
14853
+ normalized.add(relative.split(path19.sep).join("/"));
14210
14854
  }
14211
14855
  return [...normalized];
14212
14856
  }
@@ -14648,7 +15292,7 @@ var checkGoalSchema = {
14648
15292
  additionalProperties: false
14649
15293
  };
14650
15294
  var emptySchema3 = { type: "object", properties: {}, additionalProperties: false };
14651
- var descriptors7 = [
15295
+ var descriptors8 = [
14652
15296
  {
14653
15297
  name: "transition",
14654
15298
  description: "Append a labeled, validated state transition and compare-and-swap advance the head",
@@ -14699,7 +15343,7 @@ var descriptors7 = [
14699
15343
  namespace: "state"
14700
15344
  }
14701
15345
  ];
14702
- var normalizeStateArgs = actionArgNormalizer(() => descriptors7);
15346
+ var normalizeStateArgs = actionArgNormalizer(() => descriptors8);
14703
15347
  var StateProvider = class {
14704
15348
  name = "state";
14705
15349
  description = "Schema-style labeled transition layer: an append-only timeline of validated transitions with a compare-and-swap head and evidence-based certification over mesh storage";
@@ -14714,12 +15358,12 @@ var StateProvider = class {
14714
15358
  }
14715
15359
  async list(request, _context) {
14716
15360
  const query = request.query?.toLowerCase();
14717
- return query ? descriptors7.filter(
15361
+ return query ? descriptors8.filter(
14718
15362
  (descriptor) => `${descriptor.name} ${descriptor.description}`.toLowerCase().includes(query)
14719
- ) : descriptors7;
15363
+ ) : descriptors8;
14720
15364
  }
14721
15365
  async describe(actionName, _context) {
14722
- return descriptors7.find((descriptor) => descriptor.name === actionName);
15366
+ return descriptors8.find((descriptor) => descriptor.name === actionName);
14723
15367
  }
14724
15368
  prepareArguments(actionName, args) {
14725
15369
  return normalizeStateArgs(actionName, args);
@@ -15227,7 +15871,7 @@ var FabricRuntimeState = class {
15227
15871
  const projectRoot = process.env.OMP_FABRIC_PROJECT_ROOT ?? context.cwd;
15228
15872
  await ensureFabricStateExclude(projectRoot).catch(() => void 0);
15229
15873
  const configuredMeshRoot = this.#config.mesh.root;
15230
- const meshRoot = process.env.OMP_FABRIC_MESH_ROOT ?? (configuredMeshRoot ? path19.resolve(projectRoot, configuredMeshRoot) : path19.join(projectRoot, ".omp", "fabric", "mesh"));
15874
+ const meshRoot = process.env.OMP_FABRIC_MESH_ROOT ?? (configuredMeshRoot ? path20.resolve(projectRoot, configuredMeshRoot) : path20.join(projectRoot, ".omp", "fabric", "mesh"));
15231
15875
  this.#mesh = new MeshStore(
15232
15876
  meshRoot,
15233
15877
  this.#config.mesh.maxEventBytes,
@@ -15323,6 +15967,19 @@ var FabricRuntimeState = class {
15323
15967
  'disabled by configuration (judgment.enabled=false); set "judgment": { "enabled": true } in .omp/fabric.json or the agent fabric.json to enable judgment.* actions'
15324
15968
  );
15325
15969
  }
15970
+ if (this.#config.image.enabled) {
15971
+ const imageConfig = () => this.#config?.image ?? DEFAULT_FABRIC_CONFIG.image;
15972
+ await installBuiltin(createProviderComponent({
15973
+ provider: "image",
15974
+ description: "Image generation and editing across a configured priority chain",
15975
+ create: () => new ImageProvider(imageConfig)
15976
+ }));
15977
+ } else {
15978
+ this.#registry.markUnavailable(
15979
+ "image",
15980
+ 'disabled by configuration (image.enabled=false); set "image": { "enabled": true } in .omp/fabric.json or the agent fabric.json to enable image.* actions'
15981
+ );
15982
+ }
15326
15983
  const agentConfig = enforceSchema ? { ...this.#config.agents, enabled: false } : this.#config.agents;
15327
15984
  const modelsConfig = this.#config.models;
15328
15985
  const visibleOmpModels = () => {
@@ -15421,8 +16078,8 @@ var FabricRuntimeState = class {
15421
16078
  };
15422
16079
  const lineageAlive = (rootId) => this.#participants?.get(rootId) !== void 0;
15423
16080
  const actorRoots = {
15424
- project: path19.join(meshRoot, "actors"),
15425
- session: path19.join(meshRoot, "actors", fabricSessionId)
16081
+ project: path20.join(meshRoot, "actors"),
16082
+ session: path20.join(meshRoot, "actors", fabricSessionId)
15426
16083
  };
15427
16084
  const acquireActorCapabilityView = (requirements, signal) => this.#registry.acquireCapabilityView(requirements, {
15428
16085
  cwd: context.cwd,
@@ -15626,6 +16283,7 @@ ${escapeXmlText(text)}
15626
16283
  "compact",
15627
16284
  ...this.#config.codemap.enabled ? ["codemap"] : [],
15628
16285
  ...this.#config.judgment.enabled ? ["judgment"] : [],
16286
+ ...this.#config.image.enabled ? ["image"] : [],
15629
16287
  "agents",
15630
16288
  ...this.#config.memory.enabled ? ["memory"] : []
15631
16289
  ]);