@apicircle/mcp-server 1.0.6 → 1.0.8

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.
@@ -36,10 +36,34 @@ var init_package = __esm({
36
36
  "package.json"() {
37
37
  package_default = {
38
38
  name: "@apicircle/mcp-server",
39
- version: "1.0.6",
39
+ version: "1.0.8",
40
40
  private: false,
41
41
  type: "module",
42
42
  description: "Model Context Protocol server exposing API Circle Studio's workspace as a tool catalog. Used by Claude Desktop, ChatGPT, Cursor, GitHub Copilot, and any other MCP-compatible AI client.",
43
+ keywords: [
44
+ "apicircle",
45
+ "api",
46
+ "api-circle",
47
+ "mcp",
48
+ "mcp-server",
49
+ "model-context-protocol",
50
+ "ai",
51
+ "llm",
52
+ "agent",
53
+ "tool-catalog",
54
+ "claude",
55
+ "claude-desktop",
56
+ "chatgpt",
57
+ "cursor",
58
+ "copilot",
59
+ "continue",
60
+ "cline",
61
+ "zed",
62
+ "windsurf",
63
+ "openapi",
64
+ "postman",
65
+ "api-tools"
66
+ ],
43
67
  license: "SEE LICENSE IN LICENSE",
44
68
  repository: {
45
69
  type: "git",
@@ -595,12 +619,13 @@ var init_workspaceList = __esm({
595
619
  });
596
620
 
597
621
  // src/tools/crud.ts
598
- var import_zod5, import_shared2, HTTP_METHOD, requestCreateTool, requestReadTool, requestUpdateTool, requestDeleteTool, folderCreateTool, folderReadTool, folderUpdateTool, folderDeleteTool, VARIABLE, environmentCreateTool, environmentReadTool, environmentUpdateTool, environmentDeleteTool, environmentSetActiveTool, environmentSetPriorityTool, environmentExportTool, environmentImportTool, PLAN_STEP, planCreateTool, planReadTool, planUpdateTool, planDeleteTool, planAddStepTool, planRemoveStepTool, planReorderStepsTool, PLAN_VARIABLE, planSetVariablesTool, planRunTool, ASSERTION, assertionCreateTool, assertionReadTool, assertionUpdateTool, assertionDeleteTool, workspaceReadTool, workspaceWriteTool;
622
+ var import_zod5, import_shared2, import_core2, HTTP_METHOD, requestCreateTool, requestReadTool, requestUpdateTool, requestDeleteTool, folderCreateTool, folderReadTool, folderUpdateTool, folderDeleteTool, VARIABLE, environmentCreateTool, environmentReadTool, environmentUpdateTool, environmentDeleteTool, environmentSetActiveTool, environmentSetPriorityTool, environmentExportTool, environmentImportTool, PLAN_STEP, planCreateTool, planReadTool, planUpdateTool, planDeleteTool, planAddStepTool, planRemoveStepTool, planReorderStepsTool, PLAN_VARIABLE, planSetVariablesTool, planRunTool, ASSERTION, assertionCreateTool, assertionReadTool, assertionUpdateTool, assertionDeleteTool, workspaceReadTool, workspaceWriteTool;
599
623
  var init_crud = __esm({
600
624
  "src/tools/crud.ts"() {
601
625
  "use strict";
602
626
  import_zod5 = require("zod");
603
627
  import_shared2 = require("@apicircle/shared");
628
+ import_core2 = require("@apicircle/core");
604
629
  HTTP_METHOD = import_zod5.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
605
630
  requestCreateTool = {
606
631
  name: "request.create",
@@ -845,55 +870,136 @@ var init_crud = __esm({
845
870
  };
846
871
  environmentExportTool = {
847
872
  name: "environment.export",
848
- description: "Serialize an environment to a portable JSON string. Encrypted variables drop their value (only `secretKeyId` survives) so the export can be safely pasted elsewhere \u2014 re-attach secrets locally on the receiving side.",
873
+ description: "Serialize an environment to a portable JSON string (envelope v2). Encrypted variables now carry their ciphertext, slot label, and per-slot salt \u2014 the destination decrypts with its local slot value at request-execute time, matching the Git push/pull contract. The plaintext slot value never leaves the device, but the ciphertext does. v1 envelopes (no ciphertext) still parse on import for back-compat.",
849
874
  inputSchema: import_zod5.z.object({ name: import_zod5.z.string() }),
850
875
  async handler(input, ctx) {
851
876
  const state = await ctx.workspace.read();
852
877
  const env = state.synced.environments.items[input.name];
853
878
  if (!env) return { ok: false, error: "environment not found" };
854
879
  const payload = {
855
- apicircleEnvironment: 1,
880
+ apicircleEnvironment: 2,
856
881
  name: env.name,
857
- variables: env.variables.map(
858
- (v) => v.encrypted && v.secretKeyId ? { key: v.key, encrypted: true, secretKeyId: v.secretKeyId } : { key: v.key, value: v.value, encrypted: false }
859
- )
882
+ variables: env.variables.map((v) => {
883
+ if (v.encrypted && v.secretKeyId) {
884
+ const slot = state.synced.secretKeys?.[v.secretKeyId];
885
+ const label = slot?.label ?? v.key;
886
+ const value = typeof v.value === "string" && v.value.startsWith("enc:") ? v.value : "";
887
+ return {
888
+ key: v.key,
889
+ encrypted: true,
890
+ value,
891
+ secretKeyId: v.secretKeyId,
892
+ secret: { label, salt: slot?.salt ?? null }
893
+ };
894
+ }
895
+ return { key: v.key, value: v.value, encrypted: false };
896
+ })
860
897
  };
861
898
  return { ok: true, json: JSON.stringify(payload, null, 2) };
862
899
  }
863
900
  };
864
901
  environmentImportTool = {
865
902
  name: "environment.import",
866
- description: "Import an environment from the JSON shape produced by `environment.export`. When a target with the same name exists, pass `overwrite: true` to replace it, otherwise the import is rejected.",
903
+ description: "Import an environment from the JSON shape produced by `environment.export`. v2 envelopes carry the row ciphertext + per-slot salt, so the destination decrypts at request-execute time with its local slot value (same model as Git push/pull); when no destination slot matches the source's salt, a new slot is minted via `secretKey.upsert` and surfaced in `mintedSlots` so the caller can provide values via `secret.addLocal`. v1 envelopes carry only metadata, so unmatched rows come back as `pendingBindings` for the caller to prompt-and-bind via `secret.addLocal` + `environment.bindSecret`. Pass `overwrite: true` to replace a same-name destination env.",
867
904
  inputSchema: import_zod5.z.object({
868
905
  json: import_zod5.z.string().min(1),
869
906
  overwrite: import_zod5.z.boolean().default(false)
870
907
  }),
871
908
  async handler(input, ctx) {
872
- let parsed;
909
+ let raw;
873
910
  try {
874
- parsed = JSON.parse(input.json);
911
+ raw = JSON.parse(input.json);
875
912
  } catch {
876
913
  return { ok: false, error: "invalid JSON" };
877
914
  }
878
- const obj = parsed;
879
- if (obj.apicircleEnvironment !== 1 || typeof obj.name !== "string" || !Array.isArray(obj.variables)) {
880
- return { ok: false, error: "unsupported export shape" };
915
+ let parsed;
916
+ try {
917
+ parsed = (0, import_core2.parseApicircleEnvironmentDoc)(raw);
918
+ } catch (err) {
919
+ return {
920
+ ok: false,
921
+ error: err instanceof Error ? err.message : "unsupported export shape"
922
+ };
881
923
  }
882
924
  const state = await ctx.workspace.read();
883
- if (state.synced.environments.items[obj.name] && !input.overwrite) {
925
+ if (state.synced.environments.items[parsed.name] && !input.overwrite) {
884
926
  return {
885
927
  ok: false,
886
928
  error: "environment already exists; pass overwrite:true"
887
929
  };
888
930
  }
889
- const env = {
890
- name: obj.name,
891
- variables: obj.variables.map(
892
- (v) => v.encrypted ? { key: v.key, value: "", encrypted: true, secretKeyId: v.secretKeyId } : { key: v.key, value: v.value, encrypted: false }
893
- )
894
- };
931
+ const destSlots = state.synced.secretKeys ?? {};
932
+ const labelToSlotId = /* @__PURE__ */ new Map();
933
+ for (const slot of Object.values(destSlots)) {
934
+ if (!labelToSlotId.has(slot.label)) labelToSlotId.set(slot.label, slot.id);
935
+ }
936
+ const resolvedVariables = [];
937
+ const pendingBindings = [];
938
+ const mintedSlots = [];
939
+ const knownDestIds = new Set(Object.keys(destSlots));
940
+ let hintCursor = 0;
941
+ for (const v of parsed.variables) {
942
+ if (!v.encrypted) {
943
+ resolvedVariables.push(v);
944
+ continue;
945
+ }
946
+ const hint = parsed.encryptedBindingHints[hintCursor];
947
+ hintCursor += 1;
948
+ if (hint && hint.ciphertext && hint.salt) {
949
+ if (hint.originSecretKeyId && destSlots[hint.originSecretKeyId]?.salt === hint.salt) {
950
+ resolvedVariables.push({ ...v, secretKeyId: hint.originSecretKeyId });
951
+ continue;
952
+ }
953
+ const labelMatch = labelToSlotId.get(hint.label);
954
+ if (labelMatch && destSlots[labelMatch]?.salt === hint.salt) {
955
+ resolvedVariables.push({ ...v, secretKeyId: labelMatch });
956
+ continue;
957
+ }
958
+ const mintedId = hint.originSecretKeyId && !knownDestIds.has(hint.originSecretKeyId) ? hint.originSecretKeyId : (0, import_shared2.generateId)();
959
+ knownDestIds.add(mintedId);
960
+ if (!labelToSlotId.has(hint.label)) labelToSlotId.set(hint.label, mintedId);
961
+ mintedSlots.push({
962
+ id: mintedId,
963
+ label: hint.label,
964
+ salt: hint.salt,
965
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
966
+ });
967
+ resolvedVariables.push({ ...v, secretKeyId: mintedId });
968
+ continue;
969
+ }
970
+ if (hint?.originSecretKeyId && destSlots[hint.originSecretKeyId]) {
971
+ resolvedVariables.push({ ...v, secretKeyId: hint.originSecretKeyId });
972
+ continue;
973
+ }
974
+ if (hint?.label) {
975
+ const matchId = labelToSlotId.get(hint.label);
976
+ if (matchId) {
977
+ resolvedVariables.push({ ...v, secretKeyId: matchId });
978
+ continue;
979
+ }
980
+ }
981
+ resolvedVariables.push(v);
982
+ if (hint) {
983
+ pendingBindings.push({
984
+ varKey: hint.varKey,
985
+ label: hint.label,
986
+ labelFromFallback: hint.labelFromFallback
987
+ });
988
+ }
989
+ }
990
+ for (const meta of mintedSlots) {
991
+ await ctx.workspace.apply({ kind: "secretKey.upsert", meta });
992
+ }
993
+ const env = { name: parsed.name, variables: resolvedVariables };
895
994
  const out = await ctx.workspace.apply({ kind: "environment.upsert", environment: env });
896
- return { ok: true, name: env.name, changedIds: out.changedIds };
995
+ return {
996
+ ok: true,
997
+ name: env.name,
998
+ changedIds: out.changedIds,
999
+ pendingBindings,
1000
+ mintedSlots: mintedSlots.map((s) => ({ id: s.id, label: s.label })),
1001
+ warnings: parsed.warnings
1002
+ };
897
1003
  }
898
1004
  };
899
1005
  PLAN_STEP = import_zod5.z.object({
@@ -1226,21 +1332,110 @@ var init_crud = __esm({
1226
1332
  }
1227
1333
  });
1228
1334
 
1335
+ // src/tools/folderExchange.ts
1336
+ var import_zod6, import_core3, folderExportJsonTool, folderImportJsonTool;
1337
+ var init_folderExchange = __esm({
1338
+ "src/tools/folderExchange.ts"() {
1339
+ "use strict";
1340
+ import_zod6 = require("zod");
1341
+ import_core3 = require("@apicircle/core");
1342
+ folderExportJsonTool = {
1343
+ name: "folder.export_json",
1344
+ description: "Export an existing folder (and its subtree) to the API Circle exchange JSON format. Embeds JSON Schema + GraphQL dependencies inline. Auth credentials are redacted by default \u2014 pass `includeCredentialIds` to keep specific fields verbatim (the report from `collectFolderExport` enumerates the available ids).",
1345
+ inputSchema: import_zod6.z.object({
1346
+ folderId: import_zod6.z.string().min(1, "folderId is required"),
1347
+ /**
1348
+ * Subset of credential ids to KEEP in the output. Anything not in
1349
+ * this list (and every detected credential when this is empty)
1350
+ * gets blanked. Use the report-side ids surfaced by the export
1351
+ * report (`<scope>:<ownerId>.<authType>.<field>`).
1352
+ */
1353
+ includeCredentialIds: import_zod6.z.array(import_zod6.z.string()).optional()
1354
+ }),
1355
+ async handler(input, ctx) {
1356
+ const state = await ctx.workspace.read();
1357
+ const collected = (0, import_core3.collectFolderExport)({
1358
+ synced: state.synced,
1359
+ folderId: input.folderId
1360
+ });
1361
+ if (!collected) {
1362
+ return {
1363
+ error: "folder_not_found",
1364
+ message: `No folder with id "${input.folderId}" exists in the active workspace.`
1365
+ };
1366
+ }
1367
+ const includeIds = new Set(input.includeCredentialIds ?? []);
1368
+ const redacted = (0, import_core3.redactFolderExportCredentials)(collected.envelope, includeIds);
1369
+ return {
1370
+ envelope: redacted,
1371
+ json: (0, import_core3.serializeFolderExport)(redacted),
1372
+ filename: (0, import_core3.suggestFolderExportFilename)(redacted),
1373
+ report: collected.report
1374
+ };
1375
+ }
1376
+ };
1377
+ folderImportJsonTool = {
1378
+ name: "folder.import_json",
1379
+ description: "Import an `apicircle.folder/v1` envelope into the active workspace. Folder + request ids are reminted, dependency references are remapped, and JSON Schema / GraphQL definitions that match an existing global asset (by name + content) are reused.",
1380
+ inputSchema: import_zod6.z.object({
1381
+ /** Either a JSON string or the already-parsed envelope object. */
1382
+ json: import_zod6.z.string().min(1).optional(),
1383
+ envelope: import_zod6.z.record(import_zod6.z.unknown()).optional(),
1384
+ parentFolderId: import_zod6.z.string().nullable().optional()
1385
+ }),
1386
+ async handler(input, ctx) {
1387
+ if (!input.json && !input.envelope) {
1388
+ return {
1389
+ error: "invalid_input",
1390
+ message: "Pass either `json` (string) or `envelope` (object)."
1391
+ };
1392
+ }
1393
+ const text = input.json !== void 0 ? input.json : JSON.stringify(input.envelope);
1394
+ let parsed;
1395
+ try {
1396
+ parsed = (0, import_core3.parseApicircleFolderExport)(text);
1397
+ } catch (err) {
1398
+ return {
1399
+ error: "invalid_envelope",
1400
+ message: err instanceof Error ? err.message : String(err)
1401
+ };
1402
+ }
1403
+ const out = await ctx.workspace.apply({
1404
+ kind: "folder.import_apicircle",
1405
+ parsed,
1406
+ parentFolderId: input.parentFolderId ?? null
1407
+ });
1408
+ return {
1409
+ rootFolderId: parsed.rootFolder.id,
1410
+ rootFolderName: parsed.rootFolder.name,
1411
+ counts: {
1412
+ folders: parsed.subfolders.length + 1,
1413
+ requests: parsed.requests.length
1414
+ },
1415
+ filesRequiringReattachment: parsed.dependencies.files.map((f) => f.id),
1416
+ warnings: parsed.warnings,
1417
+ changedIds: out.changedIds
1418
+ };
1419
+ }
1420
+ };
1421
+ }
1422
+ });
1423
+
1229
1424
  // src/tools/history.ts
1230
- var import_zod6, historyListRunsTool, historyGetRunTool, historyDeleteRunTool, historyPurgeTool;
1425
+ var import_zod7, historyListRunsTool, historyGetRunTool, historyDeleteRunTool, historyPurgeTool;
1231
1426
  var init_history = __esm({
1232
1427
  "src/tools/history.ts"() {
1233
1428
  "use strict";
1234
- import_zod6 = require("zod");
1429
+ import_zod7 = require("zod");
1235
1430
  historyListRunsTool = {
1236
1431
  name: "history.list_runs",
1237
1432
  description: "List request-run history rows in reverse-chronological order. Filter by `requestId`, `ok` (success/failure), or `since`/`until` ISO timestamps. `limit` caps the result set; default 100.",
1238
- inputSchema: import_zod6.z.object({
1239
- requestId: import_zod6.z.string().optional(),
1240
- ok: import_zod6.z.boolean().optional(),
1241
- since: import_zod6.z.string().optional(),
1242
- until: import_zod6.z.string().optional(),
1243
- limit: import_zod6.z.number().int().positive().max(500).default(100)
1433
+ inputSchema: import_zod7.z.object({
1434
+ requestId: import_zod7.z.string().optional(),
1435
+ ok: import_zod7.z.boolean().optional(),
1436
+ since: import_zod7.z.string().optional(),
1437
+ until: import_zod7.z.string().optional(),
1438
+ limit: import_zod7.z.number().int().positive().max(500).default(100)
1244
1439
  }),
1245
1440
  async handler(input, ctx) {
1246
1441
  const state = await ctx.workspace.read();
@@ -1274,7 +1469,7 @@ var init_history = __esm({
1274
1469
  historyGetRunTool = {
1275
1470
  name: "history.get_run",
1276
1471
  description: "Fetch a single history row in full (headers, body preview, assertion results).",
1277
- inputSchema: import_zod6.z.object({ id: import_zod6.z.string() }),
1472
+ inputSchema: import_zod7.z.object({ id: import_zod7.z.string() }),
1278
1473
  async handler(input, ctx) {
1279
1474
  const state = await ctx.workspace.read();
1280
1475
  const run = state.local.history.requestRuns.find((r) => r.id === input.id);
@@ -1285,7 +1480,7 @@ var init_history = __esm({
1285
1480
  historyDeleteRunTool = {
1286
1481
  name: "history.delete_run",
1287
1482
  description: "Delete a single request-run row by id.",
1288
- inputSchema: import_zod6.z.object({ id: import_zod6.z.string() }),
1483
+ inputSchema: import_zod7.z.object({ id: import_zod7.z.string() }),
1289
1484
  async handler(input, ctx) {
1290
1485
  const out = await ctx.workspace.apply({ kind: "history.delete_run", runId: input.id });
1291
1486
  return { deleted: out.changedIds.length, changedIds: out.changedIds };
@@ -1294,8 +1489,8 @@ var init_history = __esm({
1294
1489
  historyPurgeTool = {
1295
1490
  name: "history.purge_by_age",
1296
1491
  description: "Drop every request-run + plan-run older than `olderThanDays` days. Pass 0 to clear all history.",
1297
- inputSchema: import_zod6.z.object({
1298
- olderThanDays: import_zod6.z.number().nonnegative()
1492
+ inputSchema: import_zod7.z.object({
1493
+ olderThanDays: import_zod7.z.number().nonnegative()
1299
1494
  }),
1300
1495
  async handler(input, ctx) {
1301
1496
  const olderThanMs = input.olderThanDays * 24 * 60 * 60 * 1e3;
@@ -1307,19 +1502,19 @@ var init_history = __esm({
1307
1502
  });
1308
1503
 
1309
1504
  // src/tools/codebase.ts
1310
- var import_zod7, HTTP_METHODS, codebaseExtractCollectionTool;
1505
+ var import_zod8, HTTP_METHODS, codebaseExtractCollectionTool;
1311
1506
  var init_codebase = __esm({
1312
1507
  "src/tools/codebase.ts"() {
1313
1508
  "use strict";
1314
- import_zod7 = require("zod");
1509
+ import_zod8 = require("zod");
1315
1510
  HTTP_METHODS = ["get", "post", "put", "patch", "delete", "options", "head"];
1316
1511
  codebaseExtractCollectionTool = {
1317
1512
  name: "codebase.extract_collection",
1318
1513
  description: "Scan source code for HTTP route definitions (Express, FastAPI, NestJS, Spring) and return candidate requests for the user to confirm before import.",
1319
- inputSchema: import_zod7.z.object({
1320
- source: import_zod7.z.string().min(1),
1514
+ inputSchema: import_zod8.z.object({
1515
+ source: import_zod8.z.string().min(1),
1321
1516
  /** Hint to limit which framework patterns to apply. Empty = try all. */
1322
- frameworks: import_zod7.z.array(import_zod7.z.enum(["express", "fastapi", "nest", "spring"])).default([])
1517
+ frameworks: import_zod8.z.array(import_zod8.z.enum(["express", "fastapi", "nest", "spring"])).default([])
1323
1518
  }),
1324
1519
  async handler(input) {
1325
1520
  const enabled = new Set(
@@ -1490,22 +1685,22 @@ function patchEndpoint(mock, endpointId, patcher) {
1490
1685
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1491
1686
  };
1492
1687
  }
1493
- var import_zod8, import_shared3, promptCreateEnvironmentTool, promptCreateAssertionTool, promptCreatePlanTool, HTTP_METHOD2, HEADER_OR_QUERY, REQUEST_BODY, PROMPT_AUTH, PROMPT_ASSERTION, ENDPOINT_RESPONSE, VALIDATION_RULE_NL, CONDITION_CLAUSE_NL, RESPONSE_RULE_NL, MULTIPLIER_NL, ENDPOINT_INPUT, promptCreateRequestTool, promptUpdateRequestTool, FOLDER_TREE_NODE, promptCreateFolderTreeTool, promptAddPlanStepsTool, promptSetPlanVariablesTool, promptCreateMockServerTool, promptAddMockEndpointTool, promptSetEndpointValidationRulesTool, promptSetEndpointResponseRulesTool, promptSetEndpointMultipliersTool;
1688
+ var import_zod9, import_shared3, promptCreateEnvironmentTool, promptCreateAssertionTool, promptCreatePlanTool, HTTP_METHOD2, HEADER_OR_QUERY, REQUEST_BODY, PROMPT_AUTH, PROMPT_ASSERTION, ENDPOINT_RESPONSE, VALIDATION_RULE_NL, CONDITION_CLAUSE_NL, RESPONSE_RULE_NL, MULTIPLIER_NL, ENDPOINT_INPUT, promptCreateRequestTool, promptUpdateRequestTool, FOLDER_TREE_NODE, promptCreateFolderTreeTool, promptAddPlanStepsTool, promptSetPlanVariablesTool, promptCreateMockServerTool, promptAddMockEndpointTool, promptSetEndpointValidationRulesTool, promptSetEndpointResponseRulesTool, promptSetEndpointMultipliersTool;
1494
1689
  var init_prompt = __esm({
1495
1690
  "src/tools/prompt.ts"() {
1496
1691
  "use strict";
1497
- import_zod8 = require("zod");
1692
+ import_zod9 = require("zod");
1498
1693
  import_shared3 = require("@apicircle/shared");
1499
1694
  promptCreateEnvironmentTool = {
1500
1695
  name: "prompt.create_environment",
1501
1696
  description: "Create a new environment from an LLM-shaped JSON envelope. The model produces { name, variables: [{ key, value, encrypted }] }; this tool validates and persists it.",
1502
- inputSchema: import_zod8.z.object({
1503
- name: import_zod8.z.string(),
1504
- variables: import_zod8.z.array(
1505
- import_zod8.z.object({
1506
- key: import_zod8.z.string(),
1507
- value: import_zod8.z.string(),
1508
- encrypted: import_zod8.z.boolean().default(false)
1697
+ inputSchema: import_zod9.z.object({
1698
+ name: import_zod9.z.string(),
1699
+ variables: import_zod9.z.array(
1700
+ import_zod9.z.object({
1701
+ key: import_zod9.z.string(),
1702
+ value: import_zod9.z.string(),
1703
+ encrypted: import_zod9.z.boolean().default(false)
1509
1704
  })
1510
1705
  )
1511
1706
  }),
@@ -1518,13 +1713,13 @@ var init_prompt = __esm({
1518
1713
  promptCreateAssertionTool = {
1519
1714
  name: "prompt.create_assertion",
1520
1715
  description: 'Add an assertion to a request from an LLM-shaped JSON envelope. Useful when the user asks "assert that the response status is 200 and body.id matches".',
1521
- inputSchema: import_zod8.z.object({
1522
- requestId: import_zod8.z.string(),
1523
- assertion: import_zod8.z.object({
1524
- kind: import_zod8.z.enum(["status", "header", "json-path", "duration"]),
1525
- op: import_zod8.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1526
- target: import_zod8.z.string().optional(),
1527
- expected: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()])
1716
+ inputSchema: import_zod9.z.object({
1717
+ requestId: import_zod9.z.string(),
1718
+ assertion: import_zod9.z.object({
1719
+ kind: import_zod9.z.enum(["status", "header", "json-path", "duration"]),
1720
+ op: import_zod9.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1721
+ target: import_zod9.z.string().optional(),
1722
+ expected: import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number()])
1528
1723
  })
1529
1724
  }),
1530
1725
  async handler(input, ctx) {
@@ -1543,10 +1738,10 @@ var init_prompt = __esm({
1543
1738
  promptCreatePlanTool = {
1544
1739
  name: "prompt.create_plan",
1545
1740
  description: "Create an execution plan from an LLM-shaped JSON envelope. The model produces { name, stepRequestIds: [...] } and the tool validates that each id exists in the workspace before persisting.",
1546
- inputSchema: import_zod8.z.object({
1547
- name: import_zod8.z.string(),
1548
- stepRequestIds: import_zod8.z.array(import_zod8.z.string()).default([]),
1549
- envPriorityOrder: import_zod8.z.array(import_zod8.z.string()).default([])
1741
+ inputSchema: import_zod9.z.object({
1742
+ name: import_zod9.z.string(),
1743
+ stepRequestIds: import_zod9.z.array(import_zod9.z.string()).default([]),
1744
+ envPriorityOrder: import_zod9.z.array(import_zod9.z.string()).default([])
1550
1745
  }),
1551
1746
  async handler(input, ctx) {
1552
1747
  const state = await ctx.workspace.read();
@@ -1575,51 +1770,51 @@ var init_prompt = __esm({
1575
1770
  return { ok: true, id, changedIds: out.changedIds };
1576
1771
  }
1577
1772
  };
1578
- HTTP_METHOD2 = import_zod8.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
1579
- HEADER_OR_QUERY = import_zod8.z.object({
1580
- key: import_zod8.z.string(),
1581
- value: import_zod8.z.string(),
1582
- enabled: import_zod8.z.boolean().default(true)
1773
+ HTTP_METHOD2 = import_zod9.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
1774
+ HEADER_OR_QUERY = import_zod9.z.object({
1775
+ key: import_zod9.z.string(),
1776
+ value: import_zod9.z.string(),
1777
+ enabled: import_zod9.z.boolean().default(true)
1583
1778
  });
1584
- REQUEST_BODY = import_zod8.z.object({
1585
- type: import_zod8.z.enum(["none", "json", "text", "xml", "graphql", "urlencoded"]).default("none"),
1586
- content: import_zod8.z.string().default(""),
1587
- variables: import_zod8.z.string().optional()
1779
+ REQUEST_BODY = import_zod9.z.object({
1780
+ type: import_zod9.z.enum(["none", "json", "text", "xml", "graphql", "urlencoded"]).default("none"),
1781
+ content: import_zod9.z.string().default(""),
1782
+ variables: import_zod9.z.string().optional()
1588
1783
  });
1589
- PROMPT_AUTH = import_zod8.z.discriminatedUnion("type", [
1590
- import_zod8.z.object({ type: import_zod8.z.literal("none") }),
1591
- import_zod8.z.object({ type: import_zod8.z.literal("inherit") }),
1592
- import_zod8.z.object({ type: import_zod8.z.literal("bearer"), token: import_zod8.z.string().default("") }),
1593
- import_zod8.z.object({
1594
- type: import_zod8.z.literal("basic"),
1595
- username: import_zod8.z.string().default(""),
1596
- password: import_zod8.z.string().default("")
1784
+ PROMPT_AUTH = import_zod9.z.discriminatedUnion("type", [
1785
+ import_zod9.z.object({ type: import_zod9.z.literal("none") }),
1786
+ import_zod9.z.object({ type: import_zod9.z.literal("inherit") }),
1787
+ import_zod9.z.object({ type: import_zod9.z.literal("bearer"), token: import_zod9.z.string().default("") }),
1788
+ import_zod9.z.object({
1789
+ type: import_zod9.z.literal("basic"),
1790
+ username: import_zod9.z.string().default(""),
1791
+ password: import_zod9.z.string().default("")
1597
1792
  }),
1598
- import_zod8.z.object({
1599
- type: import_zod8.z.literal("api-key"),
1600
- key: import_zod8.z.string().default(""),
1601
- value: import_zod8.z.string().default(""),
1602
- addTo: import_zod8.z.enum(["header", "query", "cookie"]).default("header")
1793
+ import_zod9.z.object({
1794
+ type: import_zod9.z.literal("api-key"),
1795
+ key: import_zod9.z.string().default(""),
1796
+ value: import_zod9.z.string().default(""),
1797
+ addTo: import_zod9.z.enum(["header", "query", "cookie"]).default("header")
1603
1798
  }),
1604
- import_zod8.z.object({
1605
- type: import_zod8.z.literal("custom-header"),
1606
- key: import_zod8.z.string().default(""),
1607
- value: import_zod8.z.string().default("")
1799
+ import_zod9.z.object({
1800
+ type: import_zod9.z.literal("custom-header"),
1801
+ key: import_zod9.z.string().default(""),
1802
+ value: import_zod9.z.string().default("")
1608
1803
  })
1609
1804
  ]);
1610
- PROMPT_ASSERTION = import_zod8.z.object({
1611
- kind: import_zod8.z.enum(["status", "header", "json-path", "duration"]),
1612
- op: import_zod8.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1613
- target: import_zod8.z.string().optional(),
1614
- expected: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.number()])
1805
+ PROMPT_ASSERTION = import_zod9.z.object({
1806
+ kind: import_zod9.z.enum(["status", "header", "json-path", "duration"]),
1807
+ op: import_zod9.z.enum(["equals", "not-equals", "contains", "lt", "gt", "matches"]),
1808
+ target: import_zod9.z.string().optional(),
1809
+ expected: import_zod9.z.union([import_zod9.z.string(), import_zod9.z.number()])
1615
1810
  });
1616
- ENDPOINT_RESPONSE = import_zod8.z.object({
1617
- status: import_zod8.z.number().int().min(100).max(599).default(200),
1618
- jsonBody: import_zod8.z.string().default("{}"),
1619
- contentType: import_zod8.z.string().default("application/json")
1811
+ ENDPOINT_RESPONSE = import_zod9.z.object({
1812
+ status: import_zod9.z.number().int().min(100).max(599).default(200),
1813
+ jsonBody: import_zod9.z.string().default("{}"),
1814
+ contentType: import_zod9.z.string().default("application/json")
1620
1815
  });
1621
- VALIDATION_RULE_NL = import_zod8.z.object({
1622
- kind: import_zod8.z.enum([
1816
+ VALIDATION_RULE_NL = import_zod9.z.object({
1817
+ kind: import_zod9.z.enum([
1623
1818
  "header-required",
1624
1819
  "header-equals",
1625
1820
  "header-matches",
@@ -1630,65 +1825,65 @@ var init_prompt = __esm({
1630
1825
  "body-required",
1631
1826
  "content-type-equals"
1632
1827
  ]),
1633
- target: import_zod8.z.string().default(""),
1634
- expected: import_zod8.z.string().optional(),
1635
- message: import_zod8.z.string().optional(),
1636
- enabled: import_zod8.z.boolean().default(true),
1637
- failResponse: import_zod8.z.object({
1638
- status: import_zod8.z.number().int().min(100).max(599).default(400),
1639
- jsonBody: import_zod8.z.string().default('{"error":"validation failed"}')
1828
+ target: import_zod9.z.string().default(""),
1829
+ expected: import_zod9.z.string().optional(),
1830
+ message: import_zod9.z.string().optional(),
1831
+ enabled: import_zod9.z.boolean().default(true),
1832
+ failResponse: import_zod9.z.object({
1833
+ status: import_zod9.z.number().int().min(100).max(599).default(400),
1834
+ jsonBody: import_zod9.z.string().default('{"error":"validation failed"}')
1640
1835
  }).default({})
1641
1836
  });
1642
- CONDITION_CLAUSE_NL = import_zod8.z.object({
1643
- scope: import_zod8.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
1644
- target: import_zod8.z.string(),
1645
- op: import_zod8.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
1646
- value: import_zod8.z.string().optional()
1837
+ CONDITION_CLAUSE_NL = import_zod9.z.object({
1838
+ scope: import_zod9.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
1839
+ target: import_zod9.z.string(),
1840
+ op: import_zod9.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
1841
+ value: import_zod9.z.string().optional()
1647
1842
  });
1648
- RESPONSE_RULE_NL = import_zod8.z.object({
1649
- name: import_zod8.z.string(),
1650
- enabled: import_zod8.z.boolean().default(true),
1651
- when: import_zod8.z.array(CONDITION_CLAUSE_NL).default([]),
1652
- response: import_zod8.z.object({
1653
- status: import_zod8.z.number().int().min(100).max(599).default(200),
1654
- jsonBody: import_zod8.z.string().default("{}")
1843
+ RESPONSE_RULE_NL = import_zod9.z.object({
1844
+ name: import_zod9.z.string(),
1845
+ enabled: import_zod9.z.boolean().default(true),
1846
+ when: import_zod9.z.array(CONDITION_CLAUSE_NL).default([]),
1847
+ response: import_zod9.z.object({
1848
+ status: import_zod9.z.number().int().min(100).max(599).default(200),
1849
+ jsonBody: import_zod9.z.string().default("{}")
1655
1850
  }).default({})
1656
1851
  });
1657
- MULTIPLIER_NL = import_zod8.z.object({
1658
- name: import_zod8.z.string().optional(),
1659
- source: import_zod8.z.object({
1660
- kind: import_zod8.z.enum(["query", "pathParam", "header", "body-json-path"]),
1661
- key: import_zod8.z.string()
1852
+ MULTIPLIER_NL = import_zod9.z.object({
1853
+ name: import_zod9.z.string().optional(),
1854
+ source: import_zod9.z.object({
1855
+ kind: import_zod9.z.enum(["query", "pathParam", "header", "body-json-path"]),
1856
+ key: import_zod9.z.string()
1662
1857
  }),
1663
- targetJsonPath: import_zod8.z.string(),
1664
- defaultCount: import_zod8.z.number().int().nonnegative().default(0),
1665
- min: import_zod8.z.number().int().nonnegative().optional(),
1666
- max: import_zod8.z.number().int().nonnegative().optional()
1858
+ targetJsonPath: import_zod9.z.string(),
1859
+ defaultCount: import_zod9.z.number().int().nonnegative().default(0),
1860
+ min: import_zod9.z.number().int().nonnegative().optional(),
1861
+ max: import_zod9.z.number().int().nonnegative().optional()
1667
1862
  });
1668
- ENDPOINT_INPUT = import_zod8.z.object({
1863
+ ENDPOINT_INPUT = import_zod9.z.object({
1669
1864
  method: HTTP_METHOD2,
1670
- pathPattern: import_zod8.z.string().min(1),
1671
- name: import_zod8.z.string().optional(),
1672
- description: import_zod8.z.string().optional(),
1865
+ pathPattern: import_zod9.z.string().min(1),
1866
+ name: import_zod9.z.string().optional(),
1867
+ description: import_zod9.z.string().optional(),
1673
1868
  response: ENDPOINT_RESPONSE.optional(),
1674
- validationRules: import_zod8.z.array(VALIDATION_RULE_NL).default([]),
1675
- responseRules: import_zod8.z.array(RESPONSE_RULE_NL).default([]),
1676
- multipliers: import_zod8.z.array(MULTIPLIER_NL).default([])
1869
+ validationRules: import_zod9.z.array(VALIDATION_RULE_NL).default([]),
1870
+ responseRules: import_zod9.z.array(RESPONSE_RULE_NL).default([]),
1871
+ multipliers: import_zod9.z.array(MULTIPLIER_NL).default([])
1677
1872
  });
1678
1873
  promptCreateRequestTool = {
1679
1874
  name: "prompt.create_request",
1680
1875
  description: "Create a fully-shaped request from an LLM-shaped JSON envelope: method, url, headers, query params, body, auth, and inline assertions. The model produces a flat object; this tool generates the request id, normalizes auth (defaults to `inherit` so folder auth wins), and persists.",
1681
- inputSchema: import_zod8.z.object({
1682
- name: import_zod8.z.string().default("New request"),
1876
+ inputSchema: import_zod9.z.object({
1877
+ name: import_zod9.z.string().default("New request"),
1683
1878
  method: HTTP_METHOD2.default("GET"),
1684
- url: import_zod8.z.string().default(""),
1685
- folderId: import_zod8.z.string().nullable().optional(),
1686
- headers: import_zod8.z.array(HEADER_OR_QUERY).default([]),
1687
- queryParams: import_zod8.z.array(HEADER_OR_QUERY).default([]),
1688
- pathParams: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
1879
+ url: import_zod9.z.string().default(""),
1880
+ folderId: import_zod9.z.string().nullable().optional(),
1881
+ headers: import_zod9.z.array(HEADER_OR_QUERY).default([]),
1882
+ queryParams: import_zod9.z.array(HEADER_OR_QUERY).default([]),
1883
+ pathParams: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.string()).optional(),
1689
1884
  body: REQUEST_BODY.optional(),
1690
1885
  auth: PROMPT_AUTH.optional(),
1691
- assertions: import_zod8.z.array(PROMPT_ASSERTION).default([])
1886
+ assertions: import_zod9.z.array(PROMPT_ASSERTION).default([])
1692
1887
  }),
1693
1888
  async handler(input, ctx) {
1694
1889
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1718,19 +1913,19 @@ var init_prompt = __esm({
1718
1913
  promptUpdateRequestTool = {
1719
1914
  name: "prompt.update_request",
1720
1915
  description: "Patch an existing request from an LLM-shaped JSON envelope. Provided fields replace the existing values; omitted fields are left untouched. Arrays (headers, queryParams, assertions) are full replacements when supplied. Returns `{ ok: false, error }` when the id does not resolve.",
1721
- inputSchema: import_zod8.z.object({
1722
- id: import_zod8.z.string(),
1723
- patch: import_zod8.z.object({
1724
- name: import_zod8.z.string().optional(),
1916
+ inputSchema: import_zod9.z.object({
1917
+ id: import_zod9.z.string(),
1918
+ patch: import_zod9.z.object({
1919
+ name: import_zod9.z.string().optional(),
1725
1920
  method: HTTP_METHOD2.optional(),
1726
- url: import_zod8.z.string().optional(),
1727
- folderId: import_zod8.z.string().nullable().optional(),
1728
- headers: import_zod8.z.array(HEADER_OR_QUERY).optional(),
1729
- queryParams: import_zod8.z.array(HEADER_OR_QUERY).optional(),
1730
- pathParams: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.string()).optional(),
1921
+ url: import_zod9.z.string().optional(),
1922
+ folderId: import_zod9.z.string().nullable().optional(),
1923
+ headers: import_zod9.z.array(HEADER_OR_QUERY).optional(),
1924
+ queryParams: import_zod9.z.array(HEADER_OR_QUERY).optional(),
1925
+ pathParams: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.string()).optional(),
1731
1926
  body: REQUEST_BODY.optional(),
1732
1927
  auth: PROMPT_AUTH.optional(),
1733
- assertions: import_zod8.z.array(PROMPT_ASSERTION).optional()
1928
+ assertions: import_zod9.z.array(PROMPT_ASSERTION).optional()
1734
1929
  }).strict()
1735
1930
  }),
1736
1931
  async handler(input, ctx) {
@@ -1758,17 +1953,17 @@ var init_prompt = __esm({
1758
1953
  return { ok: true, changedIds: out.changedIds };
1759
1954
  }
1760
1955
  };
1761
- FOLDER_TREE_NODE = import_zod8.z.lazy(
1762
- () => import_zod8.z.object({
1763
- name: import_zod8.z.string(),
1764
- children: import_zod8.z.array(FOLDER_TREE_NODE).optional()
1956
+ FOLDER_TREE_NODE = import_zod9.z.lazy(
1957
+ () => import_zod9.z.object({
1958
+ name: import_zod9.z.string(),
1959
+ children: import_zod9.z.array(FOLDER_TREE_NODE).optional()
1765
1960
  })
1766
1961
  );
1767
1962
  promptCreateFolderTreeTool = {
1768
1963
  name: "prompt.create_folder_tree",
1769
1964
  description: "Create a recursive folder hierarchy from an LLM-shaped JSON envelope. The model produces `{ parentId?, tree: { name, children?: [...] } }` and this tool walks the tree, generating ids and persisting one folder per node. Returns the list of created ids in pre-order.",
1770
- inputSchema: import_zod8.z.object({
1771
- parentId: import_zod8.z.string().nullable().optional(),
1965
+ inputSchema: import_zod9.z.object({
1966
+ parentId: import_zod9.z.string().nullable().optional(),
1772
1967
  tree: FOLDER_TREE_NODE
1773
1968
  }),
1774
1969
  async handler(input, ctx) {
@@ -1794,9 +1989,9 @@ var init_prompt = __esm({
1794
1989
  promptAddPlanStepsTool = {
1795
1990
  name: "prompt.add_plan_steps",
1796
1991
  description: "Append one or more steps to an existing execution plan from an LLM-shaped JSON envelope. The model produces `{ planId, requestIds: [...] }`; each id is validated against the workspace before any step is appended. Order in the input list is preserved.",
1797
- inputSchema: import_zod8.z.object({
1798
- planId: import_zod8.z.string(),
1799
- requestIds: import_zod8.z.array(import_zod8.z.string()).min(1)
1992
+ inputSchema: import_zod9.z.object({
1993
+ planId: import_zod9.z.string(),
1994
+ requestIds: import_zod9.z.array(import_zod9.z.string()).min(1)
1800
1995
  }),
1801
1996
  async handler(input, ctx) {
1802
1997
  const state = await ctx.workspace.read();
@@ -1826,9 +2021,9 @@ var init_prompt = __esm({
1826
2021
  promptSetPlanVariablesTool = {
1827
2022
  name: "prompt.set_plan_variables",
1828
2023
  description: "Replace the plan-scoped variables on an execution plan from an LLM-shaped JSON envelope. The model produces `{ planId, variables: [{ key, value }] }`. Empty array clears all plan variables.",
1829
- inputSchema: import_zod8.z.object({
1830
- planId: import_zod8.z.string(),
1831
- variables: import_zod8.z.array(import_zod8.z.object({ key: import_zod8.z.string(), value: import_zod8.z.string() }))
2024
+ inputSchema: import_zod9.z.object({
2025
+ planId: import_zod9.z.string(),
2026
+ variables: import_zod9.z.array(import_zod9.z.object({ key: import_zod9.z.string(), value: import_zod9.z.string() }))
1832
2027
  }),
1833
2028
  async handler(input, ctx) {
1834
2029
  const state = await ctx.workspace.read();
@@ -1844,10 +2039,10 @@ var init_prompt = __esm({
1844
2039
  promptCreateMockServerTool = {
1845
2040
  name: "prompt.create_mock_server",
1846
2041
  description: "Create a manual-mode mock server with optional inline endpoints from an LLM-shaped JSON envelope. The model produces `{ name, defaultPort?, endpoints: [{ method, pathPattern, name?, response?, validationRules?, responseRules?, multipliers? }] }`; this tool generates ids for the server and every endpoint / rule, then persists in one shot.",
1847
- inputSchema: import_zod8.z.object({
1848
- name: import_zod8.z.string().min(1),
1849
- defaultPort: import_zod8.z.number().int().positive().nullable().optional(),
1850
- endpoints: import_zod8.z.array(ENDPOINT_INPUT).default([])
2042
+ inputSchema: import_zod9.z.object({
2043
+ name: import_zod9.z.string().min(1),
2044
+ defaultPort: import_zod9.z.number().int().positive().nullable().optional(),
2045
+ endpoints: import_zod9.z.array(ENDPOINT_INPUT).default([])
1851
2046
  }),
1852
2047
  async handler(input, ctx) {
1853
2048
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1874,16 +2069,16 @@ var init_prompt = __esm({
1874
2069
  promptAddMockEndpointTool = {
1875
2070
  name: "prompt.add_mock_endpoint",
1876
2071
  description: "Append a new endpoint (with optional inline validation rules, response rules, and multipliers) to an existing mock server from an LLM-shaped JSON envelope. All ids are auto-generated; the existing endpoints stay in place.",
1877
- inputSchema: import_zod8.z.object({
1878
- mockId: import_zod8.z.string(),
2072
+ inputSchema: import_zod9.z.object({
2073
+ mockId: import_zod9.z.string(),
1879
2074
  method: HTTP_METHOD2,
1880
- pathPattern: import_zod8.z.string().min(1),
1881
- name: import_zod8.z.string().optional(),
1882
- description: import_zod8.z.string().optional(),
2075
+ pathPattern: import_zod9.z.string().min(1),
2076
+ name: import_zod9.z.string().optional(),
2077
+ description: import_zod9.z.string().optional(),
1883
2078
  response: ENDPOINT_RESPONSE.optional(),
1884
- validationRules: import_zod8.z.array(VALIDATION_RULE_NL).default([]),
1885
- responseRules: import_zod8.z.array(RESPONSE_RULE_NL).default([]),
1886
- multipliers: import_zod8.z.array(MULTIPLIER_NL).default([])
2079
+ validationRules: import_zod9.z.array(VALIDATION_RULE_NL).default([]),
2080
+ responseRules: import_zod9.z.array(RESPONSE_RULE_NL).default([]),
2081
+ multipliers: import_zod9.z.array(MULTIPLIER_NL).default([])
1887
2082
  }),
1888
2083
  async handler(input, ctx) {
1889
2084
  const state = await ctx.workspace.read();
@@ -1905,10 +2100,10 @@ var init_prompt = __esm({
1905
2100
  promptSetEndpointValidationRulesTool = {
1906
2101
  name: "prompt.set_endpoint_validation_rules",
1907
2102
  description: "Replace an endpoint's validation rules with an LLM-shaped list. Every rule gets a fresh id; the existing rules are dropped. Empty array clears all validation rules.",
1908
- inputSchema: import_zod8.z.object({
1909
- mockId: import_zod8.z.string(),
1910
- endpointId: import_zod8.z.string(),
1911
- rules: import_zod8.z.array(VALIDATION_RULE_NL)
2103
+ inputSchema: import_zod9.z.object({
2104
+ mockId: import_zod9.z.string(),
2105
+ endpointId: import_zod9.z.string(),
2106
+ rules: import_zod9.z.array(VALIDATION_RULE_NL)
1912
2107
  }),
1913
2108
  async handler(input, ctx) {
1914
2109
  const state = await ctx.workspace.read();
@@ -1939,10 +2134,10 @@ var init_prompt = __esm({
1939
2134
  promptSetEndpointResponseRulesTool = {
1940
2135
  name: "prompt.set_endpoint_response_rules",
1941
2136
  description: "Replace an endpoint's conditional response rules with an LLM-shaped list. Rules fire in order, first match wins. Every rule + clause gets a fresh id. Empty array falls back to defaultResponse.",
1942
- inputSchema: import_zod8.z.object({
1943
- mockId: import_zod8.z.string(),
1944
- endpointId: import_zod8.z.string(),
1945
- rules: import_zod8.z.array(RESPONSE_RULE_NL)
2137
+ inputSchema: import_zod9.z.object({
2138
+ mockId: import_zod9.z.string(),
2139
+ endpointId: import_zod9.z.string(),
2140
+ rules: import_zod9.z.array(RESPONSE_RULE_NL)
1946
2141
  }),
1947
2142
  async handler(input, ctx) {
1948
2143
  const state = await ctx.workspace.read();
@@ -1977,10 +2172,10 @@ var init_prompt = __esm({
1977
2172
  promptSetEndpointMultipliersTool = {
1978
2173
  name: "prompt.set_endpoint_multipliers",
1979
2174
  description: "Replace the response multipliers on an endpoint's defaultResponse with an LLM-shaped list. Multipliers expand an array at `targetJsonPath` to a count derived from a request value. Every multiplier gets a fresh id. Empty array clears all multipliers.",
1980
- inputSchema: import_zod8.z.object({
1981
- mockId: import_zod8.z.string(),
1982
- endpointId: import_zod8.z.string(),
1983
- multipliers: import_zod8.z.array(MULTIPLIER_NL)
2175
+ inputSchema: import_zod9.z.object({
2176
+ mockId: import_zod9.z.string(),
2177
+ endpointId: import_zod9.z.string(),
2178
+ multipliers: import_zod9.z.array(MULTIPLIER_NL)
1984
2179
  }),
1985
2180
  async handler(input, ctx) {
1986
2181
  const state = await ctx.workspace.read();
@@ -2072,20 +2267,20 @@ function patchEndpoint2(mock, endpointId, patcher) {
2072
2267
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2073
2268
  };
2074
2269
  }
2075
- var import_zod9, import_shared4, import_mock_server_core2, mockCreateFromOpenApiTool, mockCreateFromPostmanTool, mockCreateFromInsomniaTool, mockImportPostmanMockCollectionTool, mockListTool, mockStartTool, mockStopTool, mockDeleteTool, HTTP_METHOD3, mockCreateManualTool, mockListEndpointsTool, ENDPOINT_RESPONSE2, mockAddEndpointTool, mockUpdateEndpointTool, mockDeleteEndpointTool, VALIDATION_RULE, CONDITION_CLAUSE, RESPONSE_RULE, MULTIPLIER, mockSetValidationRulesTool, mockSetResponseRulesTool, mockSetMultipliersTool;
2270
+ var import_zod10, import_shared4, import_mock_server_core2, mockCreateFromOpenApiTool, mockCreateFromPostmanTool, mockCreateFromInsomniaTool, mockImportPostmanMockCollectionTool, mockListTool, mockStartTool, mockStopTool, mockDeleteTool, HTTP_METHOD3, mockCreateManualTool, mockListEndpointsTool, ENDPOINT_RESPONSE2, mockAddEndpointTool, mockUpdateEndpointTool, mockDeleteEndpointTool, VALIDATION_RULE, CONDITION_CLAUSE, RESPONSE_RULE, MULTIPLIER, mockSetValidationRulesTool, mockSetResponseRulesTool, mockSetMultipliersTool;
2076
2271
  var init_mocks = __esm({
2077
2272
  "src/tools/mocks.ts"() {
2078
2273
  "use strict";
2079
- import_zod9 = require("zod");
2274
+ import_zod10 = require("zod");
2080
2275
  import_shared4 = require("@apicircle/shared");
2081
2276
  import_mock_server_core2 = require("@apicircle/mock-server-core");
2082
2277
  mockCreateFromOpenApiTool = {
2083
2278
  name: "mock.create_from_openapi",
2084
2279
  description: "Create a mock server from an OpenAPI / Swagger spec (YAML or JSON).",
2085
- inputSchema: import_zod9.z.object({
2086
- name: import_zod9.z.string(),
2087
- spec: import_zod9.z.string().min(1),
2088
- format: import_zod9.z.enum(["json", "yaml"]).default("json")
2280
+ inputSchema: import_zod10.z.object({
2281
+ name: import_zod10.z.string(),
2282
+ spec: import_zod10.z.string().min(1),
2283
+ format: import_zod10.z.enum(["json", "yaml"]).default("json")
2089
2284
  }),
2090
2285
  async handler(input, ctx) {
2091
2286
  const { mock, warnings } = await ingestSource(
@@ -2104,7 +2299,7 @@ var init_mocks = __esm({
2104
2299
  mockCreateFromPostmanTool = {
2105
2300
  name: "mock.create_from_postman",
2106
2301
  description: "Create a mock server from a Postman v2/v2.1 collection.",
2107
- inputSchema: import_zod9.z.object({ name: import_zod9.z.string(), collection: import_zod9.z.string().min(1) }),
2302
+ inputSchema: import_zod10.z.object({ name: import_zod10.z.string(), collection: import_zod10.z.string().min(1) }),
2108
2303
  async handler(input, ctx) {
2109
2304
  const { mock, warnings } = await ingestSource(
2110
2305
  { kind: "postman", collection: input.collection },
@@ -2122,7 +2317,7 @@ var init_mocks = __esm({
2122
2317
  mockCreateFromInsomniaTool = {
2123
2318
  name: "mock.create_from_insomnia",
2124
2319
  description: "Create a mock server from an Insomnia v4 export.",
2125
- inputSchema: import_zod9.z.object({ name: import_zod9.z.string(), export: import_zod9.z.string().min(1) }),
2320
+ inputSchema: import_zod10.z.object({ name: import_zod10.z.string(), export: import_zod10.z.string().min(1) }),
2126
2321
  async handler(input, ctx) {
2127
2322
  const { mock, warnings } = await ingestSource(
2128
2323
  { kind: "insomnia", export: input.export },
@@ -2140,7 +2335,7 @@ var init_mocks = __esm({
2140
2335
  mockImportPostmanMockCollectionTool = {
2141
2336
  name: "mock.import_postman_mock_collection",
2142
2337
  description: "Import a Postman Mock Collection (collections previously hosted on Postman's mock service). Same parser as a regular Postman collection but marked as a mock import.",
2143
- inputSchema: import_zod9.z.object({ name: import_zod9.z.string(), collection: import_zod9.z.string().min(1) }),
2338
+ inputSchema: import_zod10.z.object({ name: import_zod10.z.string(), collection: import_zod10.z.string().min(1) }),
2144
2339
  async handler(input, ctx) {
2145
2340
  const { mock, warnings } = await ingestSource(
2146
2341
  { kind: "postman", collection: input.collection },
@@ -2158,7 +2353,7 @@ var init_mocks = __esm({
2158
2353
  mockListTool = {
2159
2354
  name: "mock.list",
2160
2355
  description: "List all mock servers in the workspace plus their runtime status (running / stopped, port).",
2161
- inputSchema: import_zod9.z.object({}),
2356
+ inputSchema: import_zod10.z.object({}),
2162
2357
  async handler(_input, ctx) {
2163
2358
  const state = await ctx.workspace.read();
2164
2359
  const running = await ctx.mock.list();
@@ -2180,9 +2375,9 @@ var init_mocks = __esm({
2180
2375
  mockStartTool = {
2181
2376
  name: "mock.start",
2182
2377
  description: "Start a mock server by id. Returns the bound port. Errors if the mock is already running or the requested port is in use.",
2183
- inputSchema: import_zod9.z.object({
2184
- id: import_zod9.z.string(),
2185
- port: import_zod9.z.number().int().positive().optional()
2378
+ inputSchema: import_zod10.z.object({
2379
+ id: import_zod10.z.string(),
2380
+ port: import_zod10.z.number().int().positive().optional()
2186
2381
  }),
2187
2382
  async handler(input, ctx) {
2188
2383
  const state = await ctx.workspace.read();
@@ -2199,7 +2394,7 @@ var init_mocks = __esm({
2199
2394
  mockStopTool = {
2200
2395
  name: "mock.stop",
2201
2396
  description: "Stop a running mock server by id (no-op if not running).",
2202
- inputSchema: import_zod9.z.object({ id: import_zod9.z.string() }),
2397
+ inputSchema: import_zod10.z.object({ id: import_zod10.z.string() }),
2203
2398
  async handler(input, ctx) {
2204
2399
  try {
2205
2400
  await ctx.mock.stop(input.id);
@@ -2212,7 +2407,7 @@ var init_mocks = __esm({
2212
2407
  mockDeleteTool = {
2213
2408
  name: "mock.delete",
2214
2409
  description: "Delete a mock server definition. Stops it first if it's running.",
2215
- inputSchema: import_zod9.z.object({ id: import_zod9.z.string() }),
2410
+ inputSchema: import_zod10.z.object({ id: import_zod10.z.string() }),
2216
2411
  async handler(input, ctx) {
2217
2412
  try {
2218
2413
  await ctx.mock.stop(input.id);
@@ -2222,13 +2417,13 @@ var init_mocks = __esm({
2222
2417
  return { ok: true, changedIds: out.changedIds };
2223
2418
  }
2224
2419
  };
2225
- HTTP_METHOD3 = import_zod9.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
2420
+ HTTP_METHOD3 = import_zod10.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
2226
2421
  mockCreateManualTool = {
2227
2422
  name: "mock.create_manual",
2228
2423
  description: "Create an empty manual-mode mock server. Use `mock.add_endpoint` afterward to populate it. CORS defaults to off (same-origin only); enable + list explicit origins via `mock.update_cors` if cross-origin access is needed.",
2229
- inputSchema: import_zod9.z.object({
2230
- name: import_zod9.z.string().min(1),
2231
- defaultPort: import_zod9.z.number().int().positive().nullable().optional()
2424
+ inputSchema: import_zod10.z.object({
2425
+ name: import_zod10.z.string().min(1),
2426
+ defaultPort: import_zod10.z.number().int().positive().nullable().optional()
2232
2427
  }),
2233
2428
  async handler(input, ctx) {
2234
2429
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -2251,7 +2446,7 @@ var init_mocks = __esm({
2251
2446
  mockListEndpointsTool = {
2252
2447
  name: "mock.list_endpoints",
2253
2448
  description: "List endpoints for a mock server (id, method, path, name).",
2254
- inputSchema: import_zod9.z.object({ mockId: import_zod9.z.string() }),
2449
+ inputSchema: import_zod10.z.object({ mockId: import_zod10.z.string() }),
2255
2450
  async handler(input, ctx) {
2256
2451
  const state = await ctx.workspace.read();
2257
2452
  const mock = state.synced.mockServers[input.mockId];
@@ -2270,20 +2465,20 @@ var init_mocks = __esm({
2270
2465
  };
2271
2466
  }
2272
2467
  };
2273
- ENDPOINT_RESPONSE2 = import_zod9.z.object({
2274
- status: import_zod9.z.number().int().min(100).max(599).default(200),
2275
- jsonBody: import_zod9.z.string().default("{}"),
2276
- contentType: import_zod9.z.string().default("application/json")
2468
+ ENDPOINT_RESPONSE2 = import_zod10.z.object({
2469
+ status: import_zod10.z.number().int().min(100).max(599).default(200),
2470
+ jsonBody: import_zod10.z.string().default("{}"),
2471
+ contentType: import_zod10.z.string().default("application/json")
2277
2472
  });
2278
2473
  mockAddEndpointTool = {
2279
2474
  name: "mock.add_endpoint",
2280
2475
  description: "Append a new endpoint to a mock server. Defaults to a 200 JSON response of `{}`. Returns the new endpoint id.",
2281
- inputSchema: import_zod9.z.object({
2282
- mockId: import_zod9.z.string(),
2476
+ inputSchema: import_zod10.z.object({
2477
+ mockId: import_zod10.z.string(),
2283
2478
  method: HTTP_METHOD3,
2284
- pathPattern: import_zod9.z.string().min(1),
2285
- name: import_zod9.z.string().optional(),
2286
- description: import_zod9.z.string().optional(),
2479
+ pathPattern: import_zod10.z.string().min(1),
2480
+ name: import_zod10.z.string().optional(),
2481
+ description: import_zod10.z.string().optional(),
2287
2482
  response: ENDPOINT_RESPONSE2.optional()
2288
2483
  }),
2289
2484
  async handler(input, ctx) {
@@ -2306,13 +2501,13 @@ var init_mocks = __esm({
2306
2501
  mockUpdateEndpointTool = {
2307
2502
  name: "mock.update_endpoint",
2308
2503
  description: "Patch fields on a single mock endpoint (method, pathPattern, name, description, defaultResponse status / contentType / json body). Pass only the fields you want to change.",
2309
- inputSchema: import_zod9.z.object({
2310
- mockId: import_zod9.z.string(),
2311
- endpointId: import_zod9.z.string(),
2504
+ inputSchema: import_zod10.z.object({
2505
+ mockId: import_zod10.z.string(),
2506
+ endpointId: import_zod10.z.string(),
2312
2507
  method: HTTP_METHOD3.optional(),
2313
- pathPattern: import_zod9.z.string().optional(),
2314
- name: import_zod9.z.string().optional(),
2315
- description: import_zod9.z.string().optional(),
2508
+ pathPattern: import_zod10.z.string().optional(),
2509
+ name: import_zod10.z.string().optional(),
2510
+ description: import_zod10.z.string().optional(),
2316
2511
  response: ENDPOINT_RESPONSE2.partial().optional()
2317
2512
  }),
2318
2513
  async handler(input, ctx) {
@@ -2353,7 +2548,7 @@ var init_mocks = __esm({
2353
2548
  mockDeleteEndpointTool = {
2354
2549
  name: "mock.delete_endpoint",
2355
2550
  description: "Remove an endpoint from a mock server.",
2356
- inputSchema: import_zod9.z.object({ mockId: import_zod9.z.string(), endpointId: import_zod9.z.string() }),
2551
+ inputSchema: import_zod10.z.object({ mockId: import_zod10.z.string(), endpointId: import_zod10.z.string() }),
2357
2552
  async handler(input, ctx) {
2358
2553
  const state = await ctx.workspace.read();
2359
2554
  const mock = state.synced.mockServers[input.mockId];
@@ -2373,9 +2568,9 @@ var init_mocks = __esm({
2373
2568
  return { ok: true, changedIds: out.changedIds };
2374
2569
  }
2375
2570
  };
2376
- VALIDATION_RULE = import_zod9.z.object({
2377
- id: import_zod9.z.string().optional(),
2378
- kind: import_zod9.z.enum([
2571
+ VALIDATION_RULE = import_zod10.z.object({
2572
+ id: import_zod10.z.string().optional(),
2573
+ kind: import_zod10.z.enum([
2379
2574
  "header-required",
2380
2575
  "header-equals",
2381
2576
  "header-matches",
@@ -2386,51 +2581,51 @@ var init_mocks = __esm({
2386
2581
  "body-required",
2387
2582
  "content-type-equals"
2388
2583
  ]),
2389
- target: import_zod9.z.string().default(""),
2390
- expected: import_zod9.z.string().optional(),
2391
- message: import_zod9.z.string().optional(),
2392
- enabled: import_zod9.z.boolean().default(true),
2393
- failResponse: import_zod9.z.object({
2394
- status: import_zod9.z.number().int().min(100).max(599).default(400),
2395
- jsonBody: import_zod9.z.string().default('{"error":"validation failed"}')
2584
+ target: import_zod10.z.string().default(""),
2585
+ expected: import_zod10.z.string().optional(),
2586
+ message: import_zod10.z.string().optional(),
2587
+ enabled: import_zod10.z.boolean().default(true),
2588
+ failResponse: import_zod10.z.object({
2589
+ status: import_zod10.z.number().int().min(100).max(599).default(400),
2590
+ jsonBody: import_zod10.z.string().default('{"error":"validation failed"}')
2396
2591
  }).default({})
2397
2592
  });
2398
- CONDITION_CLAUSE = import_zod9.z.object({
2399
- id: import_zod9.z.string().optional(),
2400
- scope: import_zod9.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
2401
- target: import_zod9.z.string(),
2402
- op: import_zod9.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
2403
- value: import_zod9.z.string().optional()
2593
+ CONDITION_CLAUSE = import_zod10.z.object({
2594
+ id: import_zod10.z.string().optional(),
2595
+ scope: import_zod10.z.enum(["query", "pathParam", "header", "cookie", "body-json-path"]),
2596
+ target: import_zod10.z.string(),
2597
+ op: import_zod10.z.enum(["equals", "not-equals", "matches", "gt", "lt", "gte", "lte", "present", "absent"]),
2598
+ value: import_zod10.z.string().optional()
2404
2599
  });
2405
- RESPONSE_RULE = import_zod9.z.object({
2406
- id: import_zod9.z.string().optional(),
2407
- name: import_zod9.z.string(),
2408
- enabled: import_zod9.z.boolean().default(true),
2409
- when: import_zod9.z.array(CONDITION_CLAUSE).default([]),
2410
- response: import_zod9.z.object({
2411
- status: import_zod9.z.number().int().min(100).max(599).default(200),
2412
- jsonBody: import_zod9.z.string().default("{}")
2600
+ RESPONSE_RULE = import_zod10.z.object({
2601
+ id: import_zod10.z.string().optional(),
2602
+ name: import_zod10.z.string(),
2603
+ enabled: import_zod10.z.boolean().default(true),
2604
+ when: import_zod10.z.array(CONDITION_CLAUSE).default([]),
2605
+ response: import_zod10.z.object({
2606
+ status: import_zod10.z.number().int().min(100).max(599).default(200),
2607
+ jsonBody: import_zod10.z.string().default("{}")
2413
2608
  }).default({})
2414
2609
  });
2415
- MULTIPLIER = import_zod9.z.object({
2416
- id: import_zod9.z.string().optional(),
2417
- name: import_zod9.z.string().optional(),
2418
- source: import_zod9.z.object({
2419
- kind: import_zod9.z.enum(["query", "pathParam", "header", "body-json-path"]),
2420
- key: import_zod9.z.string()
2610
+ MULTIPLIER = import_zod10.z.object({
2611
+ id: import_zod10.z.string().optional(),
2612
+ name: import_zod10.z.string().optional(),
2613
+ source: import_zod10.z.object({
2614
+ kind: import_zod10.z.enum(["query", "pathParam", "header", "body-json-path"]),
2615
+ key: import_zod10.z.string()
2421
2616
  }),
2422
- targetJsonPath: import_zod9.z.string(),
2423
- defaultCount: import_zod9.z.number().int().nonnegative().default(0),
2424
- min: import_zod9.z.number().int().nonnegative().optional(),
2425
- max: import_zod9.z.number().int().nonnegative().optional()
2617
+ targetJsonPath: import_zod10.z.string(),
2618
+ defaultCount: import_zod10.z.number().int().nonnegative().default(0),
2619
+ min: import_zod10.z.number().int().nonnegative().optional(),
2620
+ max: import_zod10.z.number().int().nonnegative().optional()
2426
2621
  });
2427
2622
  mockSetValidationRulesTool = {
2428
2623
  name: "mock.set_validation_rules",
2429
2624
  description: "Replace an endpoint's validation rules. Rules without an `id` get a fresh one; existing rules can keep theirs to preserve client-side selection state. Empty array clears all rules.",
2430
- inputSchema: import_zod9.z.object({
2431
- mockId: import_zod9.z.string(),
2432
- endpointId: import_zod9.z.string(),
2433
- rules: import_zod9.z.array(VALIDATION_RULE)
2625
+ inputSchema: import_zod10.z.object({
2626
+ mockId: import_zod10.z.string(),
2627
+ endpointId: import_zod10.z.string(),
2628
+ rules: import_zod10.z.array(VALIDATION_RULE)
2434
2629
  }),
2435
2630
  async handler(input, ctx) {
2436
2631
  const state = await ctx.workspace.read();
@@ -2457,10 +2652,10 @@ var init_mocks = __esm({
2457
2652
  mockSetResponseRulesTool = {
2458
2653
  name: "mock.set_response_rules",
2459
2654
  description: "Replace an endpoint's conditional response rules. Rules fire in order; the first whose every clause matches wins. Disabled rules are skipped. Empty array falls back to defaultResponse.",
2460
- inputSchema: import_zod9.z.object({
2461
- mockId: import_zod9.z.string(),
2462
- endpointId: import_zod9.z.string(),
2463
- rules: import_zod9.z.array(RESPONSE_RULE)
2655
+ inputSchema: import_zod10.z.object({
2656
+ mockId: import_zod10.z.string(),
2657
+ endpointId: import_zod10.z.string(),
2658
+ rules: import_zod10.z.array(RESPONSE_RULE)
2464
2659
  }),
2465
2660
  async handler(input, ctx) {
2466
2661
  const state = await ctx.workspace.read();
@@ -2491,10 +2686,10 @@ var init_mocks = __esm({
2491
2686
  mockSetMultipliersTool = {
2492
2687
  name: "mock.set_multipliers",
2493
2688
  description: "Replace the response multipliers on an endpoint's defaultResponse. Multipliers expand an array at `targetJsonPath` to a count derived from a request value. Empty array clears all multipliers.",
2494
- inputSchema: import_zod9.z.object({
2495
- mockId: import_zod9.z.string(),
2496
- endpointId: import_zod9.z.string(),
2497
- multipliers: import_zod9.z.array(MULTIPLIER)
2689
+ inputSchema: import_zod10.z.object({
2690
+ mockId: import_zod10.z.string(),
2691
+ endpointId: import_zod10.z.string(),
2692
+ multipliers: import_zod10.z.array(MULTIPLIER)
2498
2693
  }),
2499
2694
  async handler(input, ctx) {
2500
2695
  const state = await ctx.workspace.read();
@@ -2536,6 +2731,7 @@ var init_registry = __esm({
2536
2731
  init_codegen();
2537
2732
  init_workspaceList();
2538
2733
  init_crud();
2734
+ init_folderExchange();
2539
2735
  init_history();
2540
2736
  init_codebase();
2541
2737
  init_prompt();
@@ -2558,6 +2754,8 @@ var init_registry = __esm({
2558
2754
  folderReadTool,
2559
2755
  folderUpdateTool,
2560
2756
  folderDeleteTool,
2757
+ folderExportJsonTool,
2758
+ folderImportJsonTool,
2561
2759
  environmentCreateTool,
2562
2760
  environmentReadTool,
2563
2761
  environmentUpdateTool,
@@ -2686,11 +2884,11 @@ var init_Workspaces = __esm({
2686
2884
  });
2687
2885
 
2688
2886
  // src/providers/InMemoryWorkspaceProvider.ts
2689
- var import_core2, InMemoryWorkspaceProvider;
2887
+ var import_core4, InMemoryWorkspaceProvider;
2690
2888
  var init_InMemoryWorkspaceProvider = __esm({
2691
2889
  "src/providers/InMemoryWorkspaceProvider.ts"() {
2692
2890
  "use strict";
2693
- import_core2 = require("@apicircle/core");
2891
+ import_core4 = require("@apicircle/core");
2694
2892
  InMemoryWorkspaceProvider = class {
2695
2893
  state;
2696
2894
  constructor(initial) {
@@ -2700,7 +2898,7 @@ var init_InMemoryWorkspaceProvider = __esm({
2700
2898
  return this.state;
2701
2899
  }
2702
2900
  async apply(patch) {
2703
- const out = (0, import_core2.applyMutation)(this.state, patch);
2901
+ const out = (0, import_core4.applyMutation)(this.state, patch);
2704
2902
  this.state = out.next;
2705
2903
  return { state: this.state, changedIds: out.changedIds };
2706
2904
  }
@@ -2720,11 +2918,11 @@ var FileBackedWorkspaceProvider_exports = {};
2720
2918
  __export(FileBackedWorkspaceProvider_exports, {
2721
2919
  FileBackedWorkspaceProvider: () => FileBackedWorkspaceProvider
2722
2920
  });
2723
- var import_core3, import_file_backed, FileBackedWorkspaceProvider;
2921
+ var import_core5, import_file_backed, FileBackedWorkspaceProvider;
2724
2922
  var init_FileBackedWorkspaceProvider = __esm({
2725
2923
  "src/providers/FileBackedWorkspaceProvider.ts"() {
2726
2924
  "use strict";
2727
- import_core3 = require("@apicircle/core");
2925
+ import_core5 = require("@apicircle/core");
2728
2926
  import_file_backed = require("@apicircle/core/workspace/file-backed");
2729
2927
  FileBackedWorkspaceProvider = class {
2730
2928
  constructor(dir) {
@@ -2741,7 +2939,7 @@ var init_FileBackedWorkspaceProvider = __esm({
2741
2939
  async apply(patch) {
2742
2940
  let captured = null;
2743
2941
  await (0, import_file_backed.withWorkspace)(this.dir, async (state) => {
2744
- const result = (0, import_core3.applyMutation)(state, patch);
2942
+ const result = (0, import_core5.applyMutation)(state, patch);
2745
2943
  captured = { state: result.next, changedIds: result.changedIds };
2746
2944
  return { next: result.next };
2747
2945
  });
@@ -2766,24 +2964,65 @@ var MultiWorkspaceProvider_exports = {};
2766
2964
  __export(MultiWorkspaceProvider_exports, {
2767
2965
  MultiWorkspaceProvider: () => MultiWorkspaceProvider
2768
2966
  });
2769
- var import_registry, MultiWorkspaceProvider;
2967
+ var import_registry, LazyActiveWorkspaceProvider, MultiWorkspaceProvider;
2770
2968
  var init_MultiWorkspaceProvider = __esm({
2771
2969
  "src/providers/MultiWorkspaceProvider.ts"() {
2772
2970
  "use strict";
2773
2971
  import_registry = require("@apicircle/core/workspace/registry");
2774
2972
  init_FileBackedWorkspaceProvider();
2775
2973
  init_Workspaces();
2974
+ LazyActiveWorkspaceProvider = class {
2975
+ constructor(registryRoot, onActiveResolved) {
2976
+ this.registryRoot = registryRoot;
2977
+ this.onActiveResolved = onActiveResolved;
2978
+ }
2979
+ registryRoot;
2980
+ onActiveResolved;
2981
+ async resolveActive() {
2982
+ const registry = await (0, import_registry.loadRegistry)(this.registryRoot);
2983
+ const activeId = registry?.activeWorkspaceId ?? null;
2984
+ if (!activeId) {
2985
+ throw new Error(
2986
+ "No active workspace. Open the desktop app at least once, or run `apicircle workspaces create <name>`."
2987
+ );
2988
+ }
2989
+ this.onActiveResolved(activeId);
2990
+ return new FileBackedWorkspaceProvider((0, import_registry.workspaceDirFor)(this.registryRoot, activeId));
2991
+ }
2992
+ async read() {
2993
+ const provider = await this.resolveActive();
2994
+ return provider.read();
2995
+ }
2996
+ async apply(patch) {
2997
+ const provider = await this.resolveActive();
2998
+ return provider.apply(patch);
2999
+ }
3000
+ async write(next) {
3001
+ const provider = await this.resolveActive();
3002
+ return provider.write(next);
3003
+ }
3004
+ };
2776
3005
  MultiWorkspaceProvider = class {
2777
3006
  constructor(registryRoot) {
2778
3007
  this.registryRoot = registryRoot;
3008
+ this.lazyProvider = new LazyActiveWorkspaceProvider(this.registryRoot, (id) => {
3009
+ this.activeWorkspaceId = id;
3010
+ });
2779
3011
  }
2780
3012
  registryRoot;
2781
- active = null;
3013
+ /** Last-known active workspace id. Refreshed every time the lazy
3014
+ * provider resolves; reflects what the most recent operation saw on
3015
+ * disk, not a stale boot-time snapshot. */
2782
3016
  activeWorkspaceId = null;
3017
+ /** The lazy provider tool handlers consume as `ctx.workspace`. Holds a
3018
+ * reference back to this instance so each call updates
3019
+ * `activeWorkspaceId` for `activeId()` callers + diagnostic logs. */
3020
+ lazyProvider;
2783
3021
  /**
2784
- * Hydrate the active provider from disk. Must be called once before the
2785
- * MCP host boots so `ctx.workspace.read()` doesn't race the first
2786
- * registry-load. Returns the registry the boot can log.
3022
+ * Read the registry from disk so the host can log a boot banner. Does
3023
+ * NOT cache a per-id provider — each `activeProvider()` call re-reads
3024
+ * the registry, so a workspace switch in the desktop is picked up by
3025
+ * the next tool call without restarting the MCP server.
2787
3026
  */
2788
3027
  async init() {
2789
3028
  const registry = await (0, import_registry.loadRegistry)(this.registryRoot) ?? {
@@ -2791,22 +3030,18 @@ var init_MultiWorkspaceProvider = __esm({
2791
3030
  activeWorkspaceId: null,
2792
3031
  workspaces: []
2793
3032
  };
2794
- if (registry.activeWorkspaceId) {
2795
- this.activeWorkspaceId = registry.activeWorkspaceId;
2796
- this.active = new FileBackedWorkspaceProvider(
2797
- (0, import_registry.workspaceDirFor)(this.registryRoot, registry.activeWorkspaceId)
2798
- );
2799
- }
3033
+ this.activeWorkspaceId = registry.activeWorkspaceId;
2800
3034
  return registry;
2801
3035
  }
2802
- /** The provider tool handlers see as `ctx.workspace`. */
3036
+ /**
3037
+ * The provider tool handlers see as `ctx.workspace`. Returns a lazy
3038
+ * provider whose `read` / `apply` / `write` calls re-read
3039
+ * `registry.json` so the right active workspace is always targeted
3040
+ * even if the desktop switched workspaces since this MCP process
3041
+ * started.
3042
+ */
2803
3043
  activeProvider() {
2804
- if (!this.active) {
2805
- throw new Error(
2806
- "No active workspace. Open the desktop app at least once, or run `apicircle workspaces create <name>`."
2807
- );
2808
- }
2809
- return this.active;
3044
+ return this.lazyProvider;
2810
3045
  }
2811
3046
  // ─── Workspaces interface ──────────────────────────────────────────────────
2812
3047
  async list() {
@@ -2854,23 +3089,17 @@ var init_MultiWorkspaceProvider = __esm({
2854
3089
  if (!registry || !registry.workspaces.some((w) => w.id === workspaceId)) {
2855
3090
  throw new WorkspaceNotFoundError(workspaceId);
2856
3091
  }
2857
- const next = await (0, import_registry.setActiveWorkspace)(this.registryRoot, workspaceId);
2858
- void next;
3092
+ await (0, import_registry.setActiveWorkspace)(this.registryRoot, workspaceId);
2859
3093
  this.activeWorkspaceId = workspaceId;
2860
- this.active = new FileBackedWorkspaceProvider((0, import_registry.workspaceDirFor)(this.registryRoot, workspaceId));
2861
3094
  }
2862
3095
  /**
2863
3096
  * Idempotent registry write — used by tests / tools that need to
2864
- * persist registry updates that didn't go through `setActive`.
3097
+ * persist registry updates that didn't go through `setActive`. The
3098
+ * lazy active provider picks the new id up on its next operation.
2865
3099
  */
2866
3100
  async writeRegistry(registry) {
2867
3101
  await (0, import_registry.saveRegistry)(this.registryRoot, registry);
2868
3102
  this.activeWorkspaceId = registry.activeWorkspaceId;
2869
- if (registry.activeWorkspaceId) {
2870
- this.active = new FileBackedWorkspaceProvider(
2871
- (0, import_registry.workspaceDirFor)(this.registryRoot, registry.activeWorkspaceId)
2872
- );
2873
- }
2874
3103
  }
2875
3104
  };
2876
3105
  }