@openagentpack/sdk 0.3.1 → 0.4.0-beta-2472720-20260827

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  toSessionEvent
3
- } from "./chunk-GAAU67HX.js";
3
+ } from "./chunk-6PDVAFLK.js";
4
4
  import {
5
5
  defaultFileUploadPurpose,
6
6
  enrichProviderFileInfo
@@ -58,10 +58,10 @@ var BaseApiClient = class {
58
58
  if (this.isConflict(res.status, body)) throw new ConflictError(res.status, body, this.errorPrefix);
59
59
  throw new ApiError(res.status, body, this.errorPrefix);
60
60
  }
61
- async post(path, body) {
61
+ async post(path, body, options) {
62
62
  const res = await resolveFetch()(`${this.baseUrl}${path}`, {
63
63
  method: "POST",
64
- headers: this.headers(),
64
+ headers: { ...this.headers(), ...options?.headers },
65
65
  body: JSON.stringify(body)
66
66
  });
67
67
  await this.throwIfError(res);
@@ -395,6 +395,24 @@ function skillNameFromFiles(files) {
395
395
  return match?.[1]?.replace(/^["']|["']$/g, "") || void 0;
396
396
  }
397
397
 
398
+ // src/internal/providers/deployment-conflict.ts
399
+ var DeploymentCreateConflictError = class extends ConflictError {
400
+ constructor(conflict, preparedFiles) {
401
+ super(conflict.statusCode, conflict.responseBody, "Deployment create");
402
+ this.preparedFiles = preparedFiles;
403
+ this.name = conflict.name;
404
+ this.message = conflict.message;
405
+ this.stack = conflict.stack;
406
+ }
407
+ preparedFiles;
408
+ };
409
+ function preserveDeploymentFilesOnConflict(error, preparedFiles) {
410
+ if (error instanceof ConflictError && preparedFiles.size > 0) {
411
+ throw new DeploymentCreateConflictError(error, preparedFiles);
412
+ }
413
+ throw error;
414
+ }
415
+
398
416
  // src/internal/providers/memory-api.ts
399
417
  function query(path, values) {
400
418
  const params = new URLSearchParams();
@@ -610,6 +628,13 @@ async function listSessionEventsPaged(client, sessionId, options, toEvent, confi
610
628
  const params = new URLSearchParams();
611
629
  if (options?.limit) params.set("limit", String(options.limit));
612
630
  if (options?.order) params.set("order", options.order);
631
+ if (config?.forwardTypes !== false) {
632
+ for (const type of options?.types ?? []) params.append("types", type);
633
+ }
634
+ if (options?.created_at_gt) params.set("created_at[gt]", options.created_at_gt);
635
+ if (options?.created_at_gte) params.set("created_at[gte]", options.created_at_gte);
636
+ if (options?.created_at_lt) params.set("created_at[lt]", options.created_at_lt);
637
+ if (options?.created_at_lte) params.set("created_at[lte]", options.created_at_lte);
613
638
  const pageCursor = options?.page_token ?? options?.page;
614
639
  if (pageCursor) params.set("page", pageCursor);
615
640
  if (config?.forwardAfterId && options?.after_id) params.set("after_id", options.after_id);
@@ -776,7 +801,8 @@ function toCloudAgent(raw) {
776
801
  workspace_id: raw.workspace_id,
777
802
  created_at: raw.created_at,
778
803
  updated_at: raw.updated_at,
779
- archived_at: raw.archived_at ?? null
804
+ archived_at: raw.archived_at ?? null,
805
+ attributes: raw
780
806
  };
781
807
  }
782
808
  function toCloudEnvironment(raw) {
@@ -792,7 +818,8 @@ function toCloudEnvironment(raw) {
792
818
  workspace_id: raw.workspace_id,
793
819
  created_at: raw.created_at,
794
820
  updated_at: raw.updated_at,
795
- archived_at: raw.archived_at ?? null
821
+ archived_at: raw.archived_at ?? null,
822
+ attributes: raw
796
823
  };
797
824
  }
798
825
  function toCloudVault(raw) {
@@ -803,7 +830,8 @@ function toCloudVault(raw) {
803
830
  type: raw.type,
804
831
  created_at: raw.created_at ?? null,
805
832
  updated_at: raw.updated_at ?? null,
806
- archived_at: raw.archived_at ?? null
833
+ archived_at: raw.archived_at ?? null,
834
+ attributes: raw
807
835
  };
808
836
  }
809
837
  function toRestFileInfo(res) {
@@ -815,7 +843,9 @@ function toRestFileInfo(res) {
815
843
  created_at: res.created_at,
816
844
  downloadable: res.downloadable,
817
845
  status: res.status,
818
- purpose: res.purpose
846
+ purpose: res.purpose,
847
+ scope: res.scope,
848
+ attributes: res
819
849
  };
820
850
  }
821
851
  function toRestSkillInfo(res) {
@@ -828,7 +858,8 @@ function toRestSkillInfo(res) {
828
858
  status: "active",
829
859
  latest_version: res.latest_version,
830
860
  created_at: res.created_at,
831
- updated_at: res.updated_at
861
+ updated_at: res.updated_at,
862
+ attributes: res
832
863
  };
833
864
  }
834
865
 
@@ -1220,7 +1251,7 @@ function mapAgent(name, decl, refs, version, projectName) {
1220
1251
  }
1221
1252
  }
1222
1253
  const body = {
1223
- name,
1254
+ name: decl.name ?? name,
1224
1255
  model: modelValue,
1225
1256
  system: decl.instructions
1226
1257
  };
@@ -1736,11 +1767,15 @@ var ClaudeAdapter = class _ClaudeAdapter {
1736
1767
  async createDeployment(name, decl, refs, basePath) {
1737
1768
  const uploaded = await this.uploadDeploymentFiles(decl, basePath);
1738
1769
  const body = mapDeployment(name, decl, refs, this.projectName, uploaded);
1739
- const res = await this.client.post("/deployments", body);
1740
- return toRemoteResource(res);
1770
+ try {
1771
+ const res = await this.client.post("/deployments", body);
1772
+ return toRemoteResource(res);
1773
+ } catch (error) {
1774
+ preserveDeploymentFilesOnConflict(error, uploaded);
1775
+ }
1741
1776
  }
1742
- async updateDeployment(id, name, decl, refs, basePath) {
1743
- const uploaded = await this.uploadDeploymentFiles(decl, basePath);
1777
+ async updateDeployment(id, name, decl, refs, basePath, preparedFiles) {
1778
+ const uploaded = preparedFiles ? new Map(preparedFiles) : await this.uploadDeploymentFiles(decl, basePath);
1744
1779
  const current = await this.client.get(`/deployments/${id}`);
1745
1780
  if (current.schedule && !decl.schedule) {
1746
1781
  throw new UserError(
@@ -2013,12 +2048,23 @@ function normalizeToolNameForQoder(name) {
2013
2048
  function normalizeToolNameFromQoder(name) {
2014
2049
  return name.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
2015
2050
  }
2051
+ function normalizeEnvironmentPackages(value) {
2052
+ if (!value || typeof value !== "object") return void 0;
2053
+ const raw = value;
2054
+ const packages = {};
2055
+ for (const key of ["apt", "npm", "pip"]) {
2056
+ if (Array.isArray(raw[key]) && raw[key].length > 0) packages[key] = raw[key];
2057
+ }
2058
+ return Object.keys(packages).length > 0 ? packages : void 0;
2059
+ }
2016
2060
  function mapEnvironment2(name, decl, projectName) {
2017
2061
  const envType = decl.config.type ?? "cloud";
2018
2062
  const config = { type: envType };
2019
2063
  if (decl.config.networking) config.networking = decl.config.networking;
2020
2064
  else if (envType === "cloud") config.networking = { type: "unrestricted" };
2021
- if (decl.config.packages) config.packages = decl.config.packages;
2065
+ const packages = normalizeEnvironmentPackages(decl.config.packages);
2066
+ if (packages) config.packages = packages;
2067
+ if (decl.config.setup_script !== void 0) config.setup_script = decl.config.setup_script;
2022
2068
  return {
2023
2069
  name,
2024
2070
  description: decl.description ?? "",
@@ -2026,6 +2072,13 @@ function mapEnvironment2(name, decl, projectName) {
2026
2072
  metadata: injectMetadata(decl.metadata, projectName, name)
2027
2073
  };
2028
2074
  }
2075
+ function mapForwardEnvironment(name, decl, projectName) {
2076
+ const body = mapEnvironment2(name, decl, projectName);
2077
+ const config = { ...body.config };
2078
+ delete config.networking;
2079
+ body.config = config;
2080
+ return body;
2081
+ }
2029
2082
  function mapVault(name, decl, projectName) {
2030
2083
  const body = { display_name: decl.display_name };
2031
2084
  if (projectName) body.metadata = injectMetadata(decl.metadata, projectName, name);
@@ -2099,7 +2152,8 @@ function envToDecl2(raw) {
2099
2152
  config: {
2100
2153
  type: config.type ?? "cloud",
2101
2154
  networking: config.networking,
2102
- packages: config.packages
2155
+ packages: normalizeEnvironmentPackages(config.packages),
2156
+ setup_script: config.setup_script
2103
2157
  },
2104
2158
  metadata: stripAgentsMetadata(raw.metadata)
2105
2159
  });
@@ -2142,6 +2196,7 @@ function agentToDecl2(raw) {
2142
2196
  }));
2143
2197
  }
2144
2198
  return compactDeep({
2199
+ name: raw.name,
2145
2200
  description: raw.description,
2146
2201
  model: raw.model,
2147
2202
  instructions: raw.system,
@@ -2266,7 +2321,7 @@ function mapAgent2(name, decl, refs, version, projectName) {
2266
2321
  model = typeof qoderModel === "string" ? qoderModel : qoderModel.id;
2267
2322
  }
2268
2323
  const body = {
2269
- name,
2324
+ name: decl.name ?? name,
2270
2325
  model,
2271
2326
  system: decl.instructions
2272
2327
  };
@@ -2339,9 +2394,12 @@ function mapForwardTemplate(name, decl, refs, projectName) {
2339
2394
  environment_id: refs.environment_id,
2340
2395
  vault_ids: refs.vault_ids
2341
2396
  };
2397
+ body.files = Object.fromEntries((refs.file_ids ?? []).map((id) => [id, { enabled: true }]));
2342
2398
  if (refs.tunnel_id) body.tunnel_id = refs.tunnel_id;
2343
2399
  if (projectName) body.metadata = injectMetadata(decl.metadata, projectName, name);
2344
2400
  else body.metadata = decl.metadata ?? {};
2401
+ if (decl.environment_variables) body.environment_variables = decl.environment_variables;
2402
+ if (decl.managed_tool_config) body.managed_tool_config = decl.managed_tool_config;
2345
2403
  if (decl.tools) {
2346
2404
  body.tools = [
2347
2405
  {
@@ -2482,6 +2540,9 @@ function mapSession2(bindings) {
2482
2540
  if (bindings.tunnel_id) body.tunnel_id = bindings.tunnel_id;
2483
2541
  if (bindings.title) body.title = bindings.title;
2484
2542
  if (bindings.metadata) body.metadata = bindings.metadata;
2543
+ if (bindings.environment_variables) {
2544
+ body.environment_variables = Object.entries(bindings.environment_variables).map(([key, value]) => `${key}=${value}`).join(";");
2545
+ }
2485
2546
  if (bindings.vault_ids.length) body.vault_ids = bindings.vault_ids;
2486
2547
  const resources = [];
2487
2548
  for (const id of bindings.memory_store_ids) resources.push({ type: "memory_store", memory_store_id: id });
@@ -2527,6 +2588,7 @@ var QoderAdapter = class _QoderAdapter {
2527
2588
  client;
2528
2589
  memoryApi;
2529
2590
  forwardClient;
2591
+ forwardMemoryApi;
2530
2592
  projectName;
2531
2593
  forwardSessionIds = /* @__PURE__ */ new Set();
2532
2594
  constructor(apiKey, gateway, projectName, forwardGateway) {
@@ -2548,6 +2610,19 @@ var QoderAdapter = class _QoderAdapter {
2548
2610
  apiKey,
2549
2611
  gateway: forwardGateway ?? deriveForwardGateway(gateway)
2550
2612
  });
2613
+ this.forwardMemoryApi = new ProviderMemoryApi(this.forwardClient, {
2614
+ pathStyle: "relative",
2615
+ cursorParam: "after_id",
2616
+ updatePrecondition: "content_sha256",
2617
+ prefixParam: "prefix",
2618
+ versionsSegment: "versions",
2619
+ storeMetadataMode: "merge_patch",
2620
+ supportsView: false,
2621
+ supportsMemoryMetadata: true,
2622
+ supportsPathUpdate: false,
2623
+ supportsDeletePrecondition: false,
2624
+ supportsIncludeArchived: true
2625
+ });
2551
2626
  this.projectName = projectName ?? "";
2552
2627
  }
2553
2628
  async validate() {
@@ -2562,7 +2637,7 @@ var QoderAdapter = class _QoderAdapter {
2562
2637
  file: "/files",
2563
2638
  deployment: "/deployments"
2564
2639
  };
2565
- async findResource(type, name, id) {
2640
+ async findResource(type, name, id, mode) {
2566
2641
  if (type === "template") {
2567
2642
  const raw2 = await locateRemote(this.forwardClient, "/templates", name, id, (item) => item.status !== "archived");
2568
2643
  return raw2 ? toRemoteResource(raw2) : null;
@@ -2582,7 +2657,14 @@ var QoderAdapter = class _QoderAdapter {
2582
2657
  const raw2 = await locateRemote(this.forwardClient, "/channels", name, id, () => true);
2583
2658
  return raw2 ? toRemoteResource(raw2) : null;
2584
2659
  }
2585
- const raw = await locateRemote(this.client, _QoderAdapter.ENDPOINT_MAP[type], name, id, notArchived);
2660
+ if (type === "environment" && id && mode === "auto") {
2661
+ const managed = await locateRemote(this.client, "/environments", name, id, notArchived);
2662
+ if (managed) return toRemoteResource(managed);
2663
+ const forward = await locateRemote(this.forwardClient, "/environments", name, id, notArchived);
2664
+ return forward ? toRemoteResource(forward) : null;
2665
+ }
2666
+ const client = mode === "forward" && (type === "environment" || type === "skill" || type === "vault" || type === "memory_store" || type === "file") ? this.forwardClient : this.client;
2667
+ const raw = await locateRemote(client, _QoderAdapter.ENDPOINT_MAP[type], name, id, notArchived);
2586
2668
  return raw ? toRemoteResource(raw) : null;
2587
2669
  }
2588
2670
  async listAgents(filter) {
@@ -2691,14 +2773,10 @@ var QoderAdapter = class _QoderAdapter {
2691
2773
  }
2692
2774
  normalizeRemote(type, raw) {
2693
2775
  if (type === "environment") {
2694
- const config = raw.config ?? {};
2776
+ const normalized = envToDecl2(raw);
2695
2777
  return compactDeep({
2696
2778
  description: raw.description,
2697
- config: {
2698
- type: config.type ?? "cloud",
2699
- networking: config.networking,
2700
- packages: config.packages
2701
- },
2779
+ config: normalized.config,
2702
2780
  metadata: stripAgentsMetadata(raw.metadata)
2703
2781
  });
2704
2782
  }
@@ -2730,18 +2808,24 @@ var QoderAdapter = class _QoderAdapter {
2730
2808
  }
2731
2809
  if (type === "channel") {
2732
2810
  const channelConfig = raw.channel_config ?? {};
2733
- return compactDeep({
2734
- identity_id: raw.identity_id,
2735
- template_id: raw.template_id,
2811
+ const mode = raw.identity_resolution?.mode ?? "fixed";
2812
+ const normalized = {
2813
+ identity_resolution: { mode },
2736
2814
  channel_type: raw.channel_type,
2737
2815
  name: raw.name,
2738
2816
  enabled: raw.enabled,
2739
2817
  channel_config: {
2740
2818
  response_options: channelConfig.response_options ?? {}
2741
2819
  }
2742
- });
2820
+ };
2821
+ if (mode === "fixed") {
2822
+ normalized.identity_id = raw.identity_id;
2823
+ normalized.template_id = raw.template_id;
2824
+ }
2825
+ return compactDeep(normalized);
2743
2826
  }
2744
2827
  return compactDeep({
2828
+ name: raw.name,
2745
2829
  description: raw.description,
2746
2830
  model: normalizeModel(raw.model),
2747
2831
  instructions: raw.system,
@@ -2750,17 +2834,41 @@ var QoderAdapter = class _QoderAdapter {
2750
2834
  metadata: stripAgentsMetadata(raw.metadata)
2751
2835
  });
2752
2836
  }
2753
- async createEnvironment(name, decl) {
2754
- const body = mapEnvironment2(name, decl, this.projectName);
2755
- const res = await this.client.post("/environments", body);
2837
+ async createEnvironment(name, decl, mode = "managed") {
2838
+ const body = mode === "forward" ? mapForwardEnvironment(name, decl, this.projectName) : mapEnvironment2(name, decl, this.projectName);
2839
+ const res = await (mode === "forward" ? this.forwardClient : this.client).post("/environments", body);
2756
2840
  return toRemoteResource(res);
2757
2841
  }
2758
- async updateEnvironment(id, name, decl) {
2759
- const body = mapEnvironment2(name, decl, this.projectName);
2760
- const res = await this.client.put(`/environments/${id}`, body);
2842
+ async updateEnvironment(id, name, decl, mode = "managed") {
2843
+ const body = mode === "forward" ? mapForwardEnvironment(name, decl, this.projectName) : mapEnvironment2(name, decl, this.projectName);
2844
+ const client = mode === "forward" ? this.forwardClient : this.client;
2845
+ const current = await client.get(`/environments/${id}`);
2846
+ const currentMetadata = current.metadata ?? {};
2847
+ const metadata = { ...body.metadata ?? {} };
2848
+ for (const key of Object.keys(currentMetadata)) {
2849
+ if (!key.startsWith("agents.") && !(key in metadata)) metadata[key] = null;
2850
+ }
2851
+ body.metadata = metadata;
2852
+ const res = await client.post(`/environments/${id}`, body);
2761
2853
  return toRemoteResource(res);
2762
2854
  }
2763
- async deleteEnvironment(id, cascade = false) {
2855
+ async deleteEnvironment(id, cascade = false, mode = "managed") {
2856
+ if (mode === "forward") {
2857
+ try {
2858
+ await this.forwardClient.delete(`/environments/${id}`);
2859
+ return;
2860
+ } catch (err) {
2861
+ const isConflict = err instanceof ApiError && (err.statusCode === 409 || err.responseBody.includes("in use"));
2862
+ if (!isConflict) throw err;
2863
+ if (!cascade) {
2864
+ throw new UserError(
2865
+ `Environment ${id} is referenced by one or more Forward sessions. Use --cascade to archive the environment.`
2866
+ );
2867
+ }
2868
+ await this.forwardClient.post(`/environments/${id}/archive`, {});
2869
+ return;
2870
+ }
2871
+ }
2764
2872
  try {
2765
2873
  await this.client.delete(`/environments/${id}`);
2766
2874
  return;
@@ -2787,17 +2895,18 @@ var QoderAdapter = class _QoderAdapter {
2787
2895
  await this.client.post(`/environments/${id}/archive`, {});
2788
2896
  }
2789
2897
  }
2790
- async createVault(name, decl) {
2898
+ async createVault(name, decl, mode = "managed") {
2899
+ const client = mode === "forward" ? this.forwardClient : this.client;
2791
2900
  const body = mapVault(name, decl, this.projectName);
2792
- const res = await this.client.post("/vaults", body);
2901
+ const res = await client.post("/vaults", body);
2793
2902
  const vaultId = res.id;
2794
2903
  for (const cred of decl.credentials ?? []) {
2795
- await this.client.post(`/vaults/${vaultId}/credentials`, mapCredential(cred));
2904
+ await client.post(`/vaults/${vaultId}/credentials`, mapCredential(cred));
2796
2905
  }
2797
2906
  return toRemoteResource(res);
2798
2907
  }
2799
- async deleteVault(id) {
2800
- await this.client.delete(`/vaults/${id}`);
2908
+ async deleteVault(id, mode = "managed") {
2909
+ await (mode === "forward" ? this.forwardClient : this.client).delete(`/vaults/${id}`);
2801
2910
  }
2802
2911
  async exportResources(type) {
2803
2912
  return exportRemoteResources(this.client, type, {
@@ -2808,17 +2917,24 @@ var QoderAdapter = class _QoderAdapter {
2808
2917
  agentToDecl: agentToDecl2
2809
2918
  });
2810
2919
  }
2811
- async createSkill(name, decl, files) {
2920
+ async createSkill(name, decl, files, mode = "managed") {
2812
2921
  const formData = await buildSkillFormData(name, decl, files);
2813
- const res = await this.client.postFormData("/skills", formData);
2922
+ const res = await (mode === "forward" ? this.forwardClient : this.client).postFormData(
2923
+ "/skills",
2924
+ formData
2925
+ );
2814
2926
  return toRemoteResource(res);
2815
2927
  }
2816
- async updateSkill(id, name, decl, files) {
2817
- await this.client.delete(`/skills/${id}`);
2818
- return this.createSkill(name, decl, files);
2928
+ async updateSkill(id, name, decl, files, mode = "managed") {
2929
+ const client = mode === "forward" ? this.forwardClient : this.client;
2930
+ const packageName = skillNameFromFiles(files) ?? name;
2931
+ const formData = await buildSkillFormData(packageName, decl, files, "files", false, true);
2932
+ await client.postFormData(`/skills/${id}/versions`, formData);
2933
+ const current = await client.get(`/skills/${id}`);
2934
+ return toRemoteResource(current);
2819
2935
  }
2820
- async deleteSkill(id) {
2821
- await this.client.delete(`/skills/${id}`);
2936
+ async deleteSkill(id, mode = "managed") {
2937
+ await (mode === "forward" ? this.forwardClient : this.client).delete(`/skills/${id}`);
2822
2938
  }
2823
2939
  async createAgent(name, decl, refs) {
2824
2940
  const body = mapAgent2(name, decl, refs, void 0, this.projectName);
@@ -2835,21 +2951,89 @@ var QoderAdapter = class _QoderAdapter {
2835
2951
  await this.client.delete(`/agents/${id}`);
2836
2952
  }
2837
2953
  async createTemplate(name, decl, refs) {
2838
- await this.registerForwardVaults(refs.vault_ids);
2839
2954
  const body = mapForwardTemplate(name, decl, refs, this.projectName);
2840
2955
  const res = await this.forwardClient.post("/templates", body);
2956
+ await this.reconcileForwardMemoryMounts(res.id, refs);
2841
2957
  return toRemoteResource(res);
2842
2958
  }
2843
2959
  async updateTemplate(id, name, decl, refs) {
2844
- await this.registerForwardVaults(refs.vault_ids);
2845
2960
  const body = mapForwardTemplate(name, decl, refs, this.projectName);
2846
2961
  if (!refs.tunnel_id) body.tunnel_id = null;
2847
2962
  const res = await this.forwardClient.post(`/templates/${id}`, body);
2963
+ await this.reconcileForwardMemoryMounts(id, refs);
2848
2964
  return toRemoteResource(res);
2849
2965
  }
2850
- async archiveTemplate(id) {
2966
+ async archiveTemplate(id, ownedMemoryStoreIds = []) {
2967
+ const owned = new Set(ownedMemoryStoreIds);
2968
+ if (owned.size > 0) {
2969
+ for (const identity of await this.forwardClient.getAllPaged("/identities")) {
2970
+ if (typeof identity.id !== "string") continue;
2971
+ const path = `/identities/${identity.id}/templates/${id}/memory_stores`;
2972
+ try {
2973
+ const mounts = await this.forwardClient.get(path);
2974
+ for (const mount of mounts.data ?? []) {
2975
+ const storeId = mount.memory_store_id;
2976
+ if (mount.system_managed !== true && typeof storeId === "string" && owned.has(storeId)) {
2977
+ await this.forwardClient.delete(`${path}/${storeId}`);
2978
+ }
2979
+ }
2980
+ } catch (error) {
2981
+ if (!ApiError.isNotFound(error)) throw error;
2982
+ }
2983
+ }
2984
+ }
2851
2985
  await this.forwardClient.post(`/templates/${id}/archive`, {});
2852
2986
  }
2987
+ async reconcileForwardMemoryMounts(templateId, refs) {
2988
+ if (refs.memory_store_ids === void 0) return;
2989
+ const desired = new Set(refs.memory_store_ids ?? []);
2990
+ if (!refs.identity_id) {
2991
+ if (desired.size > 0) throw new UserError("Qoder Forward Memory Store mounts require an Identity.");
2992
+ return;
2993
+ }
2994
+ const path = `/identities/${refs.identity_id}/templates/${templateId}/memory_stores`;
2995
+ const current = await this.forwardClient.get(path);
2996
+ const explicit = (current.data ?? []).filter((mount) => mount.system_managed !== true);
2997
+ const owned = new Set(refs.owned_memory_store_ids ?? refs.memory_store_ids ?? []);
2998
+ for (const mount of explicit) {
2999
+ const storeId = mount.memory_store_id;
3000
+ if (typeof storeId === "string" && owned.has(storeId) && !desired.has(storeId)) {
3001
+ await this.forwardClient.delete(`${path}/${storeId}`);
3002
+ }
3003
+ }
3004
+ const mounted = new Set(
3005
+ explicit.map((mount) => mount.memory_store_id).filter((id) => typeof id === "string")
3006
+ );
3007
+ for (const memoryStoreId of desired) {
3008
+ if (!mounted.has(memoryStoreId)) await this.forwardClient.post(path, { memory_store_id: memoryStoreId });
3009
+ }
3010
+ }
3011
+ async reconcileDefaultMemoryStore(identityId, templateId, desired) {
3012
+ const storeId = await this.findDefaultMemoryStoreId(identityId, templateId);
3013
+ if (!storeId) return { status: "pending" };
3014
+ const current = await this.forwardClient.get(`/memory_stores/${storeId}`);
3015
+ const descriptionChanged = desired.description !== void 0 && current.description !== desired.description;
3016
+ if (current.name === desired.name && !descriptionChanged) {
3017
+ return { status: "unchanged", memory_store_id: storeId };
3018
+ }
3019
+ await this.forwardClient.post(`/memory_stores/${storeId}`, {
3020
+ name: desired.name,
3021
+ ...desired.description !== void 0 ? { description: desired.description } : {}
3022
+ });
3023
+ return { status: "updated", memory_store_id: storeId };
3024
+ }
3025
+ async findDefaultMemoryStoreId(identityId, templateId) {
3026
+ const mounts = await this.forwardClient.get(
3027
+ `/identities/${identityId}/templates/${templateId}/memory_stores`
3028
+ );
3029
+ const writableDefault = (mounts.data ?? []).find(
3030
+ (mount) => mount.system_managed === true && mount.access === "read_write"
3031
+ );
3032
+ return typeof writableDefault?.memory_store_id === "string" ? writableDefault.memory_store_id : null;
3033
+ }
3034
+ async deleteDefaultMemoryStore(id) {
3035
+ await this.client.delete(`/memory_stores/${id}`);
3036
+ }
2853
3037
  async createIdentity(name, decl) {
2854
3038
  if (decl.identity_id) return { id: decl.identity_id, type: "identity" };
2855
3039
  const res = await this.forwardClient.post("/identities", {
@@ -2886,12 +3070,14 @@ var QoderAdapter = class _QoderAdapter {
2886
3070
  }
2887
3071
  async updateChannel(id, name, decl, refs) {
2888
3072
  const current = await this.forwardClient.get(`/channels/${id}`);
2889
- if (current.channel_type !== decl.type) {
3073
+ const currentMode = current.identity_resolution?.mode ?? "fixed";
3074
+ if (current.channel_type !== decl.type || currentMode !== (decl.mode ?? "fixed")) {
2890
3075
  await this.deleteChannel(id);
2891
3076
  return this.createChannel(name, decl, refs);
2892
3077
  }
2893
3078
  const body = this.mapChannel(name, decl, refs);
2894
3079
  delete body.channel_type;
3080
+ delete body.identity_resolution;
2895
3081
  const res = await this.forwardClient.post(`/channels/${id}`, body);
2896
3082
  return toRemoteResource(res);
2897
3083
  }
@@ -2899,9 +3085,8 @@ var QoderAdapter = class _QoderAdapter {
2899
3085
  await this.forwardClient.delete(`/channels/${id}`);
2900
3086
  }
2901
3087
  mapChannel(name, decl, refs) {
2902
- return {
2903
- identity_id: refs.identity_id,
2904
- template_id: refs.agent_id,
3088
+ const mode = decl.mode ?? "fixed";
3089
+ const body = {
2905
3090
  channel_type: decl.type,
2906
3091
  name: decl.name ?? name,
2907
3092
  enabled: decl.enabled ?? true,
@@ -2914,22 +3099,27 @@ var QoderAdapter = class _QoderAdapter {
2914
3099
  }
2915
3100
  }
2916
3101
  };
2917
- }
2918
- async registerForwardVaults(vaultIds) {
2919
- for (const id of vaultIds) {
2920
- await this.forwardClient.post("/resources/registry", {
2921
- type: "vault",
2922
- resource: { id }
2923
- });
3102
+ if (mode === "pairing") {
3103
+ body.identity_resolution = { mode: "pairing" };
3104
+ } else {
3105
+ body.identity_id = refs.identity_id;
3106
+ body.template_id = refs.agent_id;
2924
3107
  }
3108
+ return body;
2925
3109
  }
2926
- async createMemoryStore(name, decl) {
3110
+ async createMemoryStore(name, decl, mode = "managed") {
2927
3111
  const body = mapMemoryStore2(name, decl);
2928
- const res = await this.client.post("/memory_stores", body);
3112
+ const client = mode === "forward" ? this.forwardClient : this.client;
3113
+ const memoryApi = mode === "forward" ? this.forwardMemoryApi : this.memoryApi;
3114
+ const res = await client.post(
3115
+ "/memory_stores",
3116
+ body,
3117
+ mode === "forward" ? { headers: { "Idempotency-Key": crypto.randomUUID() } } : void 0
3118
+ );
2929
3119
  const storeId = res.id;
2930
3120
  try {
2931
3121
  for (const entry of decl.entries ?? []) {
2932
- await this.memoryApi.createMemory(storeId, { content: entry.content, path: entry.key });
3122
+ await memoryApi.createMemory(storeId, { content: entry.content, path: entry.key });
2933
3123
  }
2934
3124
  } catch (error) {
2935
3125
  await this.client.delete(`/memory_stores/${storeId}`).catch(() => void 0);
@@ -2937,7 +3127,7 @@ var QoderAdapter = class _QoderAdapter {
2937
3127
  }
2938
3128
  return toRemoteResource(res);
2939
3129
  }
2940
- async deleteMemoryStore(id) {
3130
+ async deleteMemoryStore(id, _mode = "managed") {
2941
3131
  await this.client.delete(`/memory_stores/${id}`);
2942
3132
  }
2943
3133
  listMemoryStores(options) {
@@ -2946,23 +3136,23 @@ var QoderAdapter = class _QoderAdapter {
2946
3136
  getMemoryStore(id) {
2947
3137
  return this.memoryApi.getStore(id);
2948
3138
  }
2949
- updateMemoryStore(id, input) {
2950
- return this.memoryApi.updateStore(id, input);
3139
+ updateMemoryStore(id, input, mode = "managed") {
3140
+ return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).updateStore(id, input);
2951
3141
  }
2952
3142
  archiveMemoryStore(id) {
2953
3143
  return this.memoryApi.archiveStore(id);
2954
3144
  }
2955
- createMemory(storeId, input) {
2956
- return this.memoryApi.createMemory(storeId, input);
3145
+ createMemory(storeId, input, mode = "managed") {
3146
+ return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).createMemory(storeId, input);
2957
3147
  }
2958
- listMemories(storeId, options) {
2959
- return this.memoryApi.listMemories(storeId, options);
3148
+ listMemories(storeId, options, mode = "managed") {
3149
+ return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).listMemories(storeId, options);
2960
3150
  }
2961
3151
  getMemory(storeId, memoryId) {
2962
3152
  return this.memoryApi.getMemory(storeId, memoryId);
2963
3153
  }
2964
- updateMemory(storeId, memoryId, input) {
2965
- return this.memoryApi.updateMemory(storeId, memoryId, input);
3154
+ updateMemory(storeId, memoryId, input, mode = "managed") {
3155
+ return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).updateMemory(storeId, memoryId, input);
2966
3156
  }
2967
3157
  deleteMemory(storeId, memoryId, expected) {
2968
3158
  return this.memoryApi.deleteMemory(storeId, memoryId, expected);
@@ -2979,11 +3169,15 @@ var QoderAdapter = class _QoderAdapter {
2979
3169
  async createDeployment(name, decl, refs, basePath) {
2980
3170
  const uploaded = await this.uploadDeploymentFiles(decl, basePath);
2981
3171
  const body = mapDeployment2(name, decl, refs, this.projectName, uploaded);
2982
- const res = await this.client.post("/deployments", body);
2983
- return toRemoteResource(res);
3172
+ try {
3173
+ const res = await this.client.post("/deployments", body);
3174
+ return toRemoteResource(res);
3175
+ } catch (error) {
3176
+ preserveDeploymentFilesOnConflict(error, uploaded);
3177
+ }
2984
3178
  }
2985
- async updateDeployment(id, name, decl, refs, basePath) {
2986
- const uploaded = await this.uploadDeploymentFiles(decl, basePath);
3179
+ async updateDeployment(id, name, decl, refs, basePath, preparedFiles) {
3180
+ const uploaded = preparedFiles ? new Map(preparedFiles) : await this.uploadDeploymentFiles(decl, basePath);
2987
3181
  const current = await this.client.get(`/deployments/${id}`);
2988
3182
  if (current.schedule && !decl.schedule) {
2989
3183
  throw new UserError(
@@ -3091,6 +3285,9 @@ var QoderAdapter = class _QoderAdapter {
3091
3285
  };
3092
3286
  if (bindings.title) body2.title = bindings.title;
3093
3287
  if (bindings.metadata) body2.metadata = bindings.metadata;
3288
+ if (bindings.environment_variables) {
3289
+ body2.config = { environment_variables: bindings.environment_variables };
3290
+ }
3094
3291
  if (bindings.files?.length) {
3095
3292
  body2.resources = bindings.files.map((file) => ({
3096
3293
  type: "file",
@@ -3244,30 +3441,42 @@ var QoderAdapter = class _QoderAdapter {
3244
3441
  return res.data;
3245
3442
  }
3246
3443
  // --- Files ---
3247
- async uploadFile(filePath, options) {
3444
+ async uploadFile(filePath, options, mode = "managed") {
3445
+ if (mode === "forward" && options?.purpose && !["user_upload", "session_resource"].includes(options.purpose)) {
3446
+ throw new UserError(
3447
+ `Qoder Forward File purpose must be 'user_upload' or 'session_resource', got '${options.purpose}'.`
3448
+ );
3449
+ }
3248
3450
  const resolved = resolve2(filePath);
3249
3451
  const content = readFileSync2(resolved);
3250
3452
  const fileName = options?.name ?? basename2(resolved);
3251
- return this.uploadFileContent(new Uint8Array(content), fileName, {
3252
- purpose: options?.purpose
3253
- });
3453
+ const formData = buildFileFormData(new Uint8Array(content), fileName, { purpose: options?.purpose });
3454
+ const res = await (mode === "forward" ? this.forwardClient : this.client).postFormData(
3455
+ "/files",
3456
+ formData
3457
+ );
3458
+ return toRestFileInfo(res);
3254
3459
  }
3255
3460
  async uploadFileContent(content, filename, options) {
3256
- const formData = new FormData();
3257
- const bytes = new Uint8Array(content);
3258
- formData.append(
3259
- "file",
3260
- options?.mimeType ? new File([bytes], filename, { type: options.mimeType }) : new File([bytes], filename)
3261
- );
3262
- if (filename) formData.append("name", filename);
3263
- if (options?.purpose) formData.append("purpose", options.purpose);
3461
+ const formData = buildFileFormData(content, filename, options);
3264
3462
  const res = await this.client.postFormData("/files", formData);
3265
3463
  return toRestFileInfo(res);
3266
3464
  }
3267
- async deleteFile(id) {
3268
- await this.client.delete(`/files/${id}`);
3465
+ async deleteFile(id, mode = "managed") {
3466
+ await (mode === "forward" ? this.forwardClient : this.client).delete(`/files/${id}`);
3269
3467
  }
3270
3468
  };
3469
+ function buildFileFormData(content, filename, options) {
3470
+ const formData = new FormData();
3471
+ const bytes = new Uint8Array(content);
3472
+ formData.append(
3473
+ "file",
3474
+ options?.mimeType ? new File([bytes], filename, { type: options.mimeType }) : new File([bytes], filename)
3475
+ );
3476
+ if (filename) formData.append("name", filename);
3477
+ if (options?.purpose) formData.append("purpose", options.purpose);
3478
+ return formData;
3479
+ }
3271
3480
  function toSessionInfo2(res) {
3272
3481
  return buildSessionInfo(res, (r) => r.memory_store_ids ?? []);
3273
3482
  }
@@ -3317,22 +3526,24 @@ function normalizeQoderMcpServers(value) {
3317
3526
  });
3318
3527
  });
3319
3528
  }
3320
- async function buildSkillFormData(name, decl, files) {
3529
+ async function buildSkillFormData(name, decl, files, fileField = "file", includeCreateFields = true, prefixTopLevelDirectory = false) {
3321
3530
  const zip = new JSZip2();
3322
3531
  for (const f of files) {
3323
- zip.file(f.relativePath, f.content);
3532
+ zip.file(prefixTopLevelDirectory ? `${name}/${f.relativePath}` : f.relativePath, f.content);
3324
3533
  }
3325
3534
  const zipContent = await zip.generateAsync({ type: "uint8array" });
3326
3535
  const formData = new FormData();
3327
3536
  formData.append(
3328
- "file",
3537
+ fileField,
3329
3538
  new File([new Uint8Array(zipContent)], `${name}.zip`, {
3330
3539
  type: "application/zip"
3331
3540
  })
3332
3541
  );
3333
- formData.append("name", name);
3334
- formData.append("type", "custom");
3335
- if (decl.description) formData.append("description", decl.description);
3542
+ if (includeCreateFields) {
3543
+ formData.append("name", name);
3544
+ formData.append("type", "custom");
3545
+ if (decl.description) formData.append("description", decl.description);
3546
+ }
3336
3547
  return formData;
3337
3548
  }
3338
3549
 
@@ -3447,7 +3658,7 @@ function mapVault2(name, decl, projectName) {
3447
3658
  }
3448
3659
  function mapCredential2(cred) {
3449
3660
  if (cred.type === "environment_variable") {
3450
- return {
3661
+ const body2 = {
3451
3662
  auth: {
3452
3663
  type: "environment_variable",
3453
3664
  secret_name: cred.secret_name,
@@ -3456,8 +3667,10 @@ function mapCredential2(cred) {
3456
3667
  },
3457
3668
  display_name: cred.name
3458
3669
  };
3670
+ if (cred.metadata) body2.metadata = cred.metadata;
3671
+ return body2;
3459
3672
  }
3460
- return {
3673
+ const body = {
3461
3674
  auth: {
3462
3675
  type: cred.type,
3463
3676
  token: cred.access_token,
@@ -3465,6 +3678,8 @@ function mapCredential2(cred) {
3465
3678
  },
3466
3679
  display_name: cred.name
3467
3680
  };
3681
+ if (cred.metadata) body.metadata = cred.metadata;
3682
+ return body;
3468
3683
  }
3469
3684
  function credToDecl3(raw, vaultName) {
3470
3685
  const auth = raw.auth ?? {};
@@ -3474,6 +3689,7 @@ function credToDecl3(raw, vaultName) {
3474
3689
  return {
3475
3690
  name,
3476
3691
  type: "static_bearer",
3692
+ metadata: stripAgentsMetadata(raw.metadata),
3477
3693
  mcp_server_url: auth.mcp_server_url ?? "",
3478
3694
  access_token: placeholder
3479
3695
  };
@@ -3482,6 +3698,7 @@ function credToDecl3(raw, vaultName) {
3482
3698
  return {
3483
3699
  name,
3484
3700
  type: "environment_variable",
3701
+ metadata: stripAgentsMetadata(raw.metadata),
3485
3702
  secret_name: auth.secret_name ?? name,
3486
3703
  secret_value: placeholder,
3487
3704
  networking: networking ?? { type: "unrestricted" }
@@ -3549,6 +3766,7 @@ function agentToDecl3(raw) {
3549
3766
  const model = raw.model;
3550
3767
  const modelValue = typeof model === "object" && model ? model.id : model;
3551
3768
  return compactDeep({
3769
+ name: raw.name,
3552
3770
  description: raw.description,
3553
3771
  model: modelValue,
3554
3772
  instructions: raw.system,
@@ -3568,7 +3786,7 @@ function mapAgent3(name, decl, refs, version, projectName, skillVersions) {
3568
3786
  modelId = typeof bailianModel === "string" ? bailianModel : bailianModel.id;
3569
3787
  }
3570
3788
  const body = {
3571
- name,
3789
+ name: decl.name ?? name,
3572
3790
  model: { id: modelId },
3573
3791
  system: decl.instructions
3574
3792
  };
@@ -3581,7 +3799,9 @@ function mapAgent3(name, decl, refs, version, projectName, skillVersions) {
3581
3799
  }
3582
3800
  const BAILIAN_BUILTINS = /* @__PURE__ */ new Set(["bash", "read", "write", "edit", "glob", "grep", "download_file"]);
3583
3801
  if (decl.tools) {
3584
- const toolConfigs = resolveBuiltinTools(decl.tools, { supportedWireNames: BAILIAN_BUILTINS }).map((tool) => ({
3802
+ const toolConfigs = resolveBuiltinTools(decl.tools, {
3803
+ supportedWireNames: BAILIAN_BUILTINS
3804
+ }).map((tool) => ({
3585
3805
  name: tool.wireName,
3586
3806
  enabled: true
3587
3807
  }));
@@ -3655,30 +3875,60 @@ function mapSession3(bindings) {
3655
3875
  if (bindings.memory_store_ids.length) body.memory_store_ids = bindings.memory_store_ids;
3656
3876
  return body;
3657
3877
  }
3658
- function mapDeploymentToSession(decl, refs, fileIds) {
3878
+ function mapDeployment3(name, decl, refs, projectName, uploadedFiles) {
3879
+ const agent = { id: refs.agent_id };
3880
+ if (refs.agent_version !== void 0) agent.version = refs.agent_version;
3659
3881
  const body = {
3660
- agent: refs.agent_id,
3661
- environment_id: refs.environment_id
3882
+ name: decl.name ?? name,
3883
+ agent,
3884
+ environment_id: refs.environment_id,
3885
+ initial_events: mapMessageEvents(decl.initial_events)
3662
3886
  };
3663
- if (decl.description) body.title = decl.description;
3664
- if (fileIds.length) {
3665
- const fileResources = (decl.resources ?? []).filter((r) => r.type === "file");
3666
- body.resources = fileIds.map((id, index) => {
3667
- const entry = { type: "file", file_id: id };
3668
- const mountPath = fileResources[index]?.mount_path;
3669
- if (mountPath) entry.mount_path = mountPath;
3670
- return entry;
3671
- });
3887
+ if (decl.description) body.description = decl.description;
3888
+ if (refs.vault_ids.length) body.vault_ids = refs.vault_ids;
3889
+ const resources = mapDeploymentResources3(decl, uploadedFiles);
3890
+ if (resources.length) body.resources = resources;
3891
+ if (decl.schedule) {
3892
+ body.schedule = {
3893
+ type: "cron",
3894
+ expression: decl.schedule.expression,
3895
+ timezone: decl.schedule.timezone
3896
+ };
3897
+ }
3898
+ if (projectName) {
3899
+ body.metadata = injectMetadata(decl.metadata, projectName, name);
3900
+ } else if (decl.metadata) {
3901
+ body.metadata = decl.metadata;
3672
3902
  }
3673
3903
  return body;
3674
3904
  }
3675
- function mapInitialEvents2(events) {
3676
- const input = events.filter((e) => e.type === "user.message" || e.type === "system.message").map((e) => ({
3905
+ function mapDeploymentUpdate3(name, decl, refs, projectName, uploadedFiles, existingMetadata) {
3906
+ const body = mapDeployment3(name, decl, refs, projectName, uploadedFiles);
3907
+ body.description = decl.description ?? "";
3908
+ body.vault_ids = refs.vault_ids;
3909
+ body.resources = mapDeploymentResources3(decl, uploadedFiles);
3910
+ if (!decl.schedule) body.schedule = null;
3911
+ if (!projectName && !decl.metadata && existingMetadata) body.metadata = existingMetadata;
3912
+ return body;
3913
+ }
3914
+ function mapDeploymentResources3(decl, uploadedFiles) {
3915
+ const resources = [];
3916
+ for (const resource of decl.resources ?? []) {
3917
+ if (resource.type !== "file") continue;
3918
+ const fileId = resource.file_id ?? (resource.source ? uploadedFiles?.get(resource.source) : void 0);
3919
+ if (!fileId) continue;
3920
+ const entry = { type: "file", file_id: fileId };
3921
+ if (resource.mount_path) entry.mount_path = resolveSandboxMountPath("bailian", resource.mount_path);
3922
+ resources.push(entry);
3923
+ }
3924
+ return resources;
3925
+ }
3926
+ function mapMessageEvents(events) {
3927
+ return events.filter((event) => event.type === "user.message" || event.type === "system.message").map((event) => ({
3677
3928
  role: "user",
3678
3929
  type: "message",
3679
- content: [{ type: "text", text: e.content }]
3930
+ content: [{ type: "text", text: event.content }]
3680
3931
  }));
3681
- return { input };
3682
3932
  }
3683
3933
  function mapSendMessage3(text) {
3684
3934
  return {
@@ -3710,7 +3960,8 @@ var BailianAdapter = class _BailianAdapter {
3710
3960
  agent: "/agents",
3711
3961
  skill: "/skills",
3712
3962
  vault: "/vaults",
3713
- file: "/files"
3963
+ file: "/files",
3964
+ deployment: "/deployments"
3714
3965
  };
3715
3966
  async findResource(type, name, id) {
3716
3967
  const accept = type === "agent" ? (r) => !isArchivedAgent(r) : void 0;
@@ -3766,6 +4017,7 @@ var BailianAdapter = class _BailianAdapter {
3766
4017
  });
3767
4018
  }
3768
4019
  return compactDeep({
4020
+ name: raw.name,
3769
4021
  description: raw.description,
3770
4022
  model: normalizeBailianModel(raw.model),
3771
4023
  instructions: raw.system,
@@ -3797,6 +4049,18 @@ var BailianAdapter = class _BailianAdapter {
3797
4049
  async deleteEnvironment(id) {
3798
4050
  await this.client.delete(`/environments/${id}`);
3799
4051
  }
4052
+ async listEnvironmentResources(options) {
4053
+ const params = cursorParams(options);
4054
+ if (options?.include_archived !== void 0) {
4055
+ params.set("include_archived", String(options.include_archived));
4056
+ }
4057
+ const res = await this.client.get(withQuery("/environments", params));
4058
+ return cursorPage(res, toCloudEnvironment);
4059
+ }
4060
+ async getRemoteEnvironment(id) {
4061
+ const res = await this.client.get(`/environments/${id}`);
4062
+ return toCloudEnvironment(res);
4063
+ }
3800
4064
  // --- Agent ---
3801
4065
  async createAgent(name, decl, refs) {
3802
4066
  const skillVersions = await this.fetchSkillVersions(refs);
@@ -3845,6 +4109,25 @@ var BailianAdapter = class _BailianAdapter {
3845
4109
  async deleteAgent(id) {
3846
4110
  await this.client.post(`/agents/${id}/archive`, {});
3847
4111
  }
4112
+ async listAgentResources(options) {
4113
+ const params = cursorParams(options);
4114
+ if (options?.include_archived !== void 0) {
4115
+ params.set("include_archived", String(options.include_archived));
4116
+ }
4117
+ const res = await this.client.get(withQuery("/agents", params));
4118
+ return cursorPage(res, toCloudAgent);
4119
+ }
4120
+ async getRemoteAgent(id, version) {
4121
+ const params = new URLSearchParams();
4122
+ if (version !== void 0) params.set("version", String(version));
4123
+ const res = await this.client.get(withQuery(`/agents/${id}`, params));
4124
+ return toCloudAgent(res);
4125
+ }
4126
+ async listAgentVersions(id, options) {
4127
+ const params = cursorParams(options);
4128
+ const res = await this.client.get(withQuery(`/agents/${id}/versions`, params));
4129
+ return cursorPage(res, toCloudAgent);
4130
+ }
3848
4131
  // --- Skill (2-step: Files API → Skills API) ---
3849
4132
  async createSkill(name, decl, files) {
3850
4133
  const fileId = await this.uploadSkillZip(name, decl, files);
@@ -3943,10 +4226,31 @@ var BailianAdapter = class _BailianAdapter {
3943
4226
  const all = await this.client.getAllPaged(path);
3944
4227
  return all.map(toBailianSkillInfo);
3945
4228
  }
4229
+ async listSkillResources(options) {
4230
+ const params = cursorParams(options);
4231
+ if (options?.source === "official") params.set("source", "official");
4232
+ if (options?.source === "custom") params.set("source", "customer");
4233
+ const res = await this.client.get(withQuery("/skills", params));
4234
+ return cursorPage(res, toBailianSkillInfo);
4235
+ }
3946
4236
  async getSkillInfo(id) {
3947
4237
  const res = await this.client.get(`/skills/${id}`);
3948
4238
  return toBailianSkillInfo(res);
3949
4239
  }
4240
+ async listSkillVersions(id, options) {
4241
+ const params = cursorParams(options);
4242
+ const res = await this.client.get(withQuery(`/skills/${id}/versions`, params));
4243
+ return cursorPage(res, toSkillVersionInfo);
4244
+ }
4245
+ async getSkillVersion(id, version) {
4246
+ const res = await this.client.get(`/skills/${id}/versions/${encodeURIComponent(version)}`);
4247
+ return toSkillVersionInfo(res);
4248
+ }
4249
+ async getSkillDownloadInfo(id, version) {
4250
+ return await this.client.get(
4251
+ `/skills/${id}/versions/${encodeURIComponent(version)}/content`
4252
+ );
4253
+ }
3950
4254
  // Non-blocking create: file already uploaded → POST /skills with retry for residual OSS
3951
4255
  // replication lag (postSkillWithRetry covers SKILL_FILE_NOT_FOUND for a few seconds), and return
3952
4256
  // the initial status WITHOUT waiting for the security scan. Callers MUST ensure the file has
@@ -3976,7 +4280,7 @@ var BailianAdapter = class _BailianAdapter {
3976
4280
  }
3977
4281
  async waitForFileReady(fileId) {
3978
4282
  const start = Date.now();
3979
- let delay2 = FILE_SCAN_BACKOFF.initial;
4283
+ let delay3 = FILE_SCAN_BACKOFF.initial;
3980
4284
  let logged = false;
3981
4285
  while (true) {
3982
4286
  const detail = await this.client.get(`/files/${fileId}`);
@@ -3995,8 +4299,8 @@ var BailianAdapter = class _BailianAdapter {
3995
4299
  );
3996
4300
  return;
3997
4301
  }
3998
- await new Promise((r) => setTimeout(r, delay2));
3999
- delay2 = Math.min(delay2 * FILE_SCAN_BACKOFF.factor, FILE_SCAN_BACKOFF.max);
4302
+ await new Promise((r) => setTimeout(r, delay3));
4303
+ delay3 = Math.min(delay3 * FILE_SCAN_BACKOFF.factor, FILE_SCAN_BACKOFF.max);
4000
4304
  }
4001
4305
  }
4002
4306
  // --- Vault (Vaults API) ---
@@ -4018,6 +4322,18 @@ var BailianAdapter = class _BailianAdapter {
4018
4322
  const all = await this.client.getAllPaged("/vaults");
4019
4323
  return all.map(toCloudVault);
4020
4324
  }
4325
+ async listVaultResources(options) {
4326
+ const params = cursorParams(options);
4327
+ if (options?.include_archived !== void 0) {
4328
+ params.set("include_archived", String(options.include_archived));
4329
+ }
4330
+ const res = await this.client.get(withQuery("/vaults", params));
4331
+ return cursorPage(res, toCloudVault);
4332
+ }
4333
+ async getRemoteVault(id) {
4334
+ const res = await this.client.get(`/vaults/${id}`);
4335
+ return toCloudVault(res);
4336
+ }
4021
4337
  async getVault(id) {
4022
4338
  return await this.client.get(`/vaults/${id}`);
4023
4339
  }
@@ -4039,7 +4355,21 @@ var BailianAdapter = class _BailianAdapter {
4039
4355
  }
4040
4356
  async listCredentials(vaultId) {
4041
4357
  const all = await this.client.getAllPaged(`/vaults/${vaultId}/credentials`);
4042
- return all.map(toRemoteResource);
4358
+ return all.map((raw) => {
4359
+ const auth = raw.auth ?? {};
4360
+ const networking = auth.networking;
4361
+ const metadata = raw.metadata;
4362
+ return {
4363
+ id: raw.id,
4364
+ display_name: raw.display_name ?? raw.id,
4365
+ auth_type: auth.type ?? "",
4366
+ secret_name: auth.secret_name,
4367
+ networking_type: networking?.type,
4368
+ metadata: metadata ? Object.fromEntries(
4369
+ Object.entries(metadata).filter((entry) => typeof entry[1] === "string")
4370
+ ) : void 0
4371
+ };
4372
+ });
4043
4373
  }
4044
4374
  async getCredential(vaultId, credentialId) {
4045
4375
  return await this.client.get(`/vaults/${vaultId}/credentials/${credentialId}`);
@@ -4055,46 +4385,116 @@ var BailianAdapter = class _BailianAdapter {
4055
4385
  async deleteCredential(vaultId, credentialId) {
4056
4386
  await this.client.delete(`/vaults/${vaultId}/credentials/${credentialId}`);
4057
4387
  }
4058
- // --- Deployment (emulated) ---
4059
- async createDeployment(_name, _decl, _refs, _basePath) {
4060
- return { id: null, type: "deployment" };
4388
+ // --- Deployment ---
4389
+ async createDeployment(name, decl, refs, basePath) {
4390
+ const uploaded = await this.uploadDeploymentFiles(decl, basePath);
4391
+ const body = mapDeployment3(name, decl, refs, this.projectName, uploaded);
4392
+ try {
4393
+ const res = await this.client.post("/deployments", body);
4394
+ return toRemoteResource(res);
4395
+ } catch (error) {
4396
+ preserveDeploymentFilesOnConflict(error, uploaded);
4397
+ }
4061
4398
  }
4062
- async updateDeployment(_id, _name, _decl, _refs, _basePath) {
4063
- return { id: null, type: "deployment" };
4399
+ async updateDeployment(id, name, decl, refs, basePath, preparedFiles) {
4400
+ if (!id) return this.createDeployment(name, decl, refs, basePath);
4401
+ const current = await this.client.get(`/deployments/${id}`);
4402
+ const uploaded = preparedFiles ? new Map(preparedFiles) : await this.uploadDeploymentFiles(decl, basePath);
4403
+ const body = mapDeploymentUpdate3(
4404
+ name,
4405
+ decl,
4406
+ refs,
4407
+ this.projectName,
4408
+ uploaded,
4409
+ current.metadata
4410
+ );
4411
+ const res = await this.client.post(`/deployments/${id}`, body);
4412
+ return toRemoteResource(res);
4064
4413
  }
4065
- async deleteDeployment(_id) {
4414
+ async deleteDeployment(id) {
4415
+ await this.client.post(`/deployments/${id}/archive`, {});
4066
4416
  }
4067
4417
  async runDeployment(ctx) {
4068
- const fileIds = [];
4069
- for (const r of ctx.decl.resources ?? []) {
4070
- if (r.type === "file") {
4071
- if (r.file_id) {
4072
- fileIds.push(r.file_id);
4073
- } else if (r.source) {
4074
- fileIds.push(await this.uploadSessionFile(r.source, ctx.basePath));
4075
- }
4076
- }
4077
- }
4078
- const body = mapDeploymentToSession(ctx.decl, ctx.refs, fileIds);
4079
- const sessionRes = await this.client.post("/sessions", body);
4080
- const sessionId = sessionRes.id;
4081
- const eventsBody = mapInitialEvents2(ctx.decl.initial_events);
4082
- const input = eventsBody.input;
4083
- if (input.length) {
4084
- await this.client.post(`/sessions/${sessionId}/events`, eventsBody);
4418
+ if (!ctx.id) {
4419
+ throw new UserError(`Deployment '${ctx.name}' has no remote id; run \`agents apply\` first.`);
4085
4420
  }
4086
- return { session_id: sessionId };
4421
+ const res = await this.client.post(`/deployments/${ctx.id}/run`, {});
4422
+ return toDeploymentRunResult(res);
4087
4423
  }
4088
4424
  async getDeployment(ctx) {
4089
- const plan = mapDeploymentToSession(ctx.decl, ctx.refs, []);
4090
- return {
4091
- id: ctx.id,
4092
- status: "emulated (local)",
4093
- schedule: ctx.decl.schedule,
4094
- attributes: { materialization_plan: plan }
4095
- };
4096
- }
4097
- async uploadSessionFile(source, basePath) {
4425
+ if (!ctx.id) {
4426
+ throw new UserError(`Deployment '${ctx.name}' has no remote id; run \`agents apply\` first.`);
4427
+ }
4428
+ const res = await this.client.get(`/deployments/${ctx.id}`);
4429
+ return toDeploymentInfo3(res);
4430
+ }
4431
+ async listDeployments(filter) {
4432
+ const params = new URLSearchParams();
4433
+ if (filter?.agent_id) params.set("agent_id", filter.agent_id);
4434
+ if (filter?.keyword) params.set("keyword", filter.keyword);
4435
+ if (filter?.status) params.set("status", filter.status);
4436
+ if (filter?.include_archived) params.set("include_archived", "true");
4437
+ if (filter?.limit) params.set("limit", String(filter.limit));
4438
+ if (filter?.page) params.set("page", filter.page);
4439
+ if (filter?.created_at_gte) params.set("created_at[gte]", filter.created_at_gte);
4440
+ if (filter?.created_at_lte) params.set("created_at[lte]", filter.created_at_lte);
4441
+ const query2 = params.toString();
4442
+ const res = await this.client.get(`/deployments${query2 ? `?${query2}` : ""}`);
4443
+ const nextPage = res.next_page ?? void 0;
4444
+ return {
4445
+ deployments: (res.data ?? []).map(toDeploymentInfo3),
4446
+ has_more: nextPage != null,
4447
+ next_page: nextPage
4448
+ };
4449
+ }
4450
+ async getDeploymentById(id) {
4451
+ const res = await this.client.get(`/deployments/${id}`);
4452
+ return toDeploymentInfo3(res);
4453
+ }
4454
+ async runDeploymentById(id) {
4455
+ const res = await this.client.post(`/deployments/${id}/run`, {});
4456
+ return toDeploymentRunResult(res);
4457
+ }
4458
+ async pauseDeploymentById(id) {
4459
+ const res = await this.client.post(`/deployments/${id}/pause`, {});
4460
+ return toDeploymentInfo3(res);
4461
+ }
4462
+ async unpauseDeploymentById(id) {
4463
+ const res = await this.client.post(`/deployments/${id}/unpause`, {});
4464
+ return toDeploymentInfo3(res);
4465
+ }
4466
+ async listDeploymentRuns(deploymentId, options) {
4467
+ const res = await this.client.get(
4468
+ withQuery(`/deployments/${deploymentId}/runs`, cursorParams(options))
4469
+ );
4470
+ return cursorPage(res, toDeploymentRunInfo);
4471
+ }
4472
+ async getDeploymentRun(runId) {
4473
+ const res = await this.client.get(`/deployment_runs/${runId}`);
4474
+ return toDeploymentRunInfo(res);
4475
+ }
4476
+ async pauseDeployment(ctx) {
4477
+ return this.setDeploymentPaused(ctx, true);
4478
+ }
4479
+ async unpauseDeployment(ctx) {
4480
+ return this.setDeploymentPaused(ctx, false);
4481
+ }
4482
+ async setDeploymentPaused(ctx, paused) {
4483
+ if (!ctx.id) throw new UserError(`Deployment '${ctx.name}' has no remote id; run \`agents apply\` first.`);
4484
+ const action = paused ? "pause" : "unpause";
4485
+ const res = await this.client.post(`/deployments/${ctx.id}/${action}`, {});
4486
+ return toDeploymentInfo3(res);
4487
+ }
4488
+ async uploadDeploymentFiles(decl, basePath) {
4489
+ const uploaded = /* @__PURE__ */ new Map();
4490
+ for (const resource of decl.resources ?? []) {
4491
+ if (resource.type === "file" && !resource.file_id && resource.source && !uploaded.has(resource.source)) {
4492
+ uploaded.set(resource.source, await this.uploadDeploymentFile(resource.source, basePath));
4493
+ }
4494
+ }
4495
+ return uploaded;
4496
+ }
4497
+ async uploadDeploymentFile(source, basePath) {
4098
4498
  const fullPath = resolve3(dirname3(basePath), source);
4099
4499
  const content = readFileSync3(fullPath);
4100
4500
  const formData = new FormData();
@@ -4127,6 +4527,9 @@ var BailianAdapter = class _BailianAdapter {
4127
4527
  async listSessions(filter) {
4128
4528
  const params = new URLSearchParams();
4129
4529
  if (filter?.agent_id) params.set("agent_id", filter.agent_id);
4530
+ for (const status of filter?.statuses ?? []) params.append("statuses[]", status);
4531
+ if (filter?.created_at_gte) params.set("created_at[gte]", filter.created_at_gte);
4532
+ if (filter?.created_at_lte) params.set("created_at[lte]", filter.created_at_lte);
4130
4533
  if (filter?.limit) params.set("limit", String(filter.limit));
4131
4534
  if (filter?.page) params.set("page", filter.page);
4132
4535
  const qs = params.toString();
@@ -4143,6 +4546,15 @@ var BailianAdapter = class _BailianAdapter {
4143
4546
  const res = await this.client.get(`/sessions/${id}`);
4144
4547
  return toSessionInfo3(res);
4145
4548
  }
4549
+ async updateSession(id, input) {
4550
+ const res = await this.client.post(`/sessions/${id}`, input);
4551
+ if (!res.agent || !res.environment_id) return this.getSession(id);
4552
+ return toSessionInfo3(res);
4553
+ }
4554
+ async archiveSession(id) {
4555
+ const res = await this.client.post(`/sessions/${id}/archive`, {});
4556
+ return toSessionInfo3(res);
4557
+ }
4146
4558
  async deleteSession(id) {
4147
4559
  await this.client.delete(`/sessions/${id}`);
4148
4560
  }
@@ -4151,13 +4563,20 @@ var BailianAdapter = class _BailianAdapter {
4151
4563
  const res = await this.client.post(`/sessions/${sessionId}/events`, body);
4152
4564
  return extractCreatedEventId(res);
4153
4565
  }
4566
+ async sendSessionEvents(sessionId, events) {
4567
+ const res = await this.client.post(`/sessions/${sessionId}/events`, { input: events });
4568
+ return {
4569
+ event_ids: extractCreatedEventIds(res),
4570
+ attributes: res
4571
+ };
4572
+ }
4154
4573
  async *streamSessionEvents(sessionId, _options) {
4155
4574
  for await (const raw of this.client.sse(`/sessions/${sessionId}/events/stream`)) {
4156
4575
  yield toSessionEvent(raw);
4157
4576
  }
4158
4577
  }
4159
4578
  async listSessionEvents(sessionId, options) {
4160
- return listSessionEventsPaged(this.client, sessionId, options, toSessionEvent);
4579
+ return listSessionEventsPaged(this.client, sessionId, options, toSessionEvent, { forwardTypes: false });
4161
4580
  }
4162
4581
  // --- Files ---
4163
4582
  async uploadFile(filePath, options) {
@@ -4183,6 +4602,15 @@ var BailianAdapter = class _BailianAdapter {
4183
4602
  const all = await this.client.getAllPaged("/files");
4184
4603
  return all.map(toRestFileInfo);
4185
4604
  }
4605
+ async listFileResources(options) {
4606
+ const params = cursorParams(options);
4607
+ if (options?.scope_id) params.set("scope_id", options.scope_id);
4608
+ const res = await this.client.get(withQuery("/files", params));
4609
+ return cursorPage(res, toRestFileInfo);
4610
+ }
4611
+ async downloadFileContent(id) {
4612
+ return new Uint8Array(await this.client.getBuffer(`/files/${id}/content`));
4613
+ }
4186
4614
  async deleteFile(id) {
4187
4615
  await this.client.delete(`/files/${id}`);
4188
4616
  }
@@ -4190,6 +4618,19 @@ var BailianAdapter = class _BailianAdapter {
4190
4618
  function isArchivedAgent(raw) {
4191
4619
  return typeof raw.archived_at === "string" && raw.archived_at.trim().length > 0;
4192
4620
  }
4621
+ function toDeploymentInfo3(res) {
4622
+ const schedule = res.schedule;
4623
+ return {
4624
+ id: res.id ?? null,
4625
+ status: res.status ?? "unknown",
4626
+ paused_reason: res.paused_reason ?? void 0,
4627
+ schedule: schedule ? {
4628
+ expression: schedule.expression,
4629
+ timezone: schedule.timezone
4630
+ } : void 0,
4631
+ attributes: res
4632
+ };
4633
+ }
4193
4634
  function toSessionInfo3(res) {
4194
4635
  return buildSessionInfo(res, () => []);
4195
4636
  }
@@ -4204,9 +4645,77 @@ function toBailianSkillInfo(res) {
4204
4645
  status: skillStatusFromString(res.status),
4205
4646
  latest_version: res.latest_version,
4206
4647
  created_at: res.created_at,
4207
- updated_at: res.updated_at
4648
+ updated_at: res.updated_at,
4649
+ attributes: res
4650
+ };
4651
+ }
4652
+ function cursorParams(options) {
4653
+ const params = new URLSearchParams();
4654
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
4655
+ if (options?.page) params.set("page", options.page);
4656
+ return params;
4657
+ }
4658
+ function withQuery(path, params) {
4659
+ const query2 = params.toString();
4660
+ return query2 ? `${path}?${query2}` : path;
4661
+ }
4662
+ function cursorPage(res, mapper) {
4663
+ const nextPage = res.next_page ?? void 0;
4664
+ return {
4665
+ data: (res.data ?? []).map(mapper),
4666
+ has_more: res.has_more ?? nextPage !== void 0,
4667
+ next_page: nextPage
4668
+ };
4669
+ }
4670
+ function toSkillVersionInfo(res) {
4671
+ return {
4672
+ id: res.id,
4673
+ skill_id: res.skill_id ?? "",
4674
+ type: res.type ?? "skill_version",
4675
+ name: res.name,
4676
+ description: res.description,
4677
+ version: res.version ?? "",
4678
+ status: res.status,
4679
+ created_at: res.created_at,
4680
+ updated_at: res.updated_at,
4681
+ additional_properties: res.additional_properties,
4682
+ attributes: res
4683
+ };
4684
+ }
4685
+ function toDeploymentRunResult(res) {
4686
+ return {
4687
+ run_id: res.id,
4688
+ session_id: res.session_id ?? null,
4689
+ error: res.error ?? void 0
4690
+ };
4691
+ }
4692
+ function toDeploymentRunInfo(res) {
4693
+ return {
4694
+ id: res.id ?? "",
4695
+ deployment_id: res.deployment_id,
4696
+ session_id: res.session_id ?? void 0,
4697
+ status: res.status,
4698
+ error: res.error ?? void 0,
4699
+ created_at: res.created_at,
4700
+ updated_at: res.updated_at,
4701
+ attributes: res
4208
4702
  };
4209
4703
  }
4704
+ function extractCreatedEventIds(res) {
4705
+ const ids = /* @__PURE__ */ new Set();
4706
+ const topLevel = extractCreatedEventId(res);
4707
+ if (topLevel) ids.add(topLevel);
4708
+ for (const key of ["data", "events"]) {
4709
+ const items = res[key];
4710
+ if (!Array.isArray(items)) continue;
4711
+ for (const item of items) {
4712
+ if (!item || typeof item !== "object") continue;
4713
+ const id = item.id;
4714
+ if (typeof id === "string") ids.add(id);
4715
+ }
4716
+ }
4717
+ return Array.from(ids);
4718
+ }
4210
4719
  function normalizeBailianModel(value) {
4211
4720
  if (value && typeof value === "object" && "id" in value) {
4212
4721
  return value.id;
@@ -4286,9 +4795,8 @@ var BAILIAN_CAPABILITIES = {
4286
4795
  remediation: "deploy agents independently and orchestrate via MCP"
4287
4796
  },
4288
4797
  deployment: {
4289
- tier: "emulated",
4290
- reason: "no deployment primitive on Bailian; expanded into a session at run time",
4291
- remediation: "scheduling and outcome rubrics are not enforced server-side \u2014 use external cron/CI for always-on or scheduled runs"
4798
+ tier: "native",
4799
+ reason: "deployments API with cron schedules, manual runs, pause/unpause and archive"
4292
4800
  },
4293
4801
  session: { tier: "native", reason: "sessions API" },
4294
4802
  identity: { tier: "unsupported", reason: "no mapped Identity primitive on Bailian" },
@@ -4533,7 +5041,7 @@ function mapAgent4(name, decl, refs, version, projectName) {
4533
5041
  if (!arkModel) throw new UserError(`No Ark model specified for agent '${name}'`);
4534
5042
  const modelValue = typeof arkModel === "string" ? { id: arkModel } : { id: arkModel.id };
4535
5043
  const body = {
4536
- name,
5044
+ name: decl.name ?? name,
4537
5045
  model: modelValue,
4538
5046
  system: decl.instructions
4539
5047
  };
@@ -4590,7 +5098,7 @@ function mapAgent4(name, decl, refs, version, projectName) {
4590
5098
  }
4591
5099
  return body;
4592
5100
  }
4593
- function mapDeploymentToSession2(decl, refs, fileIds) {
5101
+ function mapDeploymentToSession(decl, refs, fileIds) {
4594
5102
  const body = {
4595
5103
  agent: refs.agent_id,
4596
5104
  environment_id: refs.environment_id
@@ -4953,7 +5461,7 @@ var ArkAdapter = class _ArkAdapter {
4953
5461
  }
4954
5462
  }
4955
5463
  }
4956
- const body = mapDeploymentToSession2(ctx.decl, ctx.refs, fileIds);
5464
+ const body = mapDeploymentToSession(ctx.decl, ctx.refs, fileIds);
4957
5465
  const sessionRes = await this.client.post("/sessions", body);
4958
5466
  const sessionId = sessionRes.id;
4959
5467
  const events = ctx.decl.initial_events.filter((e) => e.type === "user.message" || e.type === "system.message").map((e) => ({
@@ -4966,7 +5474,7 @@ var ArkAdapter = class _ArkAdapter {
4966
5474
  return { session_id: sessionId };
4967
5475
  }
4968
5476
  async getDeployment(ctx) {
4969
- const plan = mapDeploymentToSession2(ctx.decl, ctx.refs, []);
5477
+ const plan = mapDeploymentToSession(ctx.decl, ctx.refs, []);
4970
5478
  return {
4971
5479
  id: ctx.id,
4972
5480
  status: "emulated (local)",
@@ -5239,6 +5747,9 @@ var packagesSchema = z5.object({
5239
5747
  gem: z5.array(z5.string()).optional(),
5240
5748
  go: z5.array(z5.string()).optional()
5241
5749
  });
5750
+ var setupScriptSchema = z5.string().refine((value) => new TextEncoder().encode(value).byteLength <= 64 * 1024, {
5751
+ message: "setup_script must not exceed 65536 UTF-8 bytes"
5752
+ });
5242
5753
  var environmentSchema = z5.object({
5243
5754
  name: z5.string().optional(),
5244
5755
  description: z5.string().optional(),
@@ -5248,7 +5759,8 @@ var environmentSchema = z5.object({
5248
5759
  config: z5.object({
5249
5760
  type: z5.enum(["cloud", "self_hosted"]),
5250
5761
  networking: networkingSchema.optional(),
5251
- packages: packagesSchema.optional()
5762
+ packages: packagesSchema.optional(),
5763
+ setup_script: setupScriptSchema.optional()
5252
5764
  }),
5253
5765
  metadata: z5.record(z5.string(), z5.string()).optional()
5254
5766
  });
@@ -5263,6 +5775,7 @@ var coerceString = z5.union([z5.string(), z5.number()]).transform(String);
5263
5775
  var staticBearerCredentialSchema = z5.object({
5264
5776
  name: z5.string(),
5265
5777
  type: z5.literal("static_bearer"),
5778
+ metadata: z5.record(z5.string(), z5.string()).optional(),
5266
5779
  mcp_server_url: z5.string(),
5267
5780
  access_token: coerceString,
5268
5781
  protocol: z5.enum(["sse", "streamable_http"]).optional()
@@ -5270,6 +5783,7 @@ var staticBearerCredentialSchema = z5.object({
5270
5783
  var environmentVariableCredentialSchema = z5.object({
5271
5784
  name: z5.string(),
5272
5785
  type: z5.literal("environment_variable"),
5786
+ metadata: z5.record(z5.string(), z5.string()).optional(),
5273
5787
  secret_name: z5.string(),
5274
5788
  secret_value: coerceString,
5275
5789
  networking: z5.object({ type: z5.enum(["unrestricted", "limited"]) }).optional()
@@ -5412,6 +5926,9 @@ var agentSkillRefSchema = z5.object({
5412
5926
  var agentDeliverySchema = z5.object({
5413
5927
  type: z5.enum(["managed", "forward"])
5414
5928
  });
5929
+ var managedToolConfigSchema = z5.object({
5930
+ enabled_tools: z5.array(z5.string().min(1))
5931
+ });
5415
5932
  var sessionGithubRepoResourceSchema = z5.object({
5416
5933
  type: z5.literal("github_repository"),
5417
5934
  url: z5.string().url(),
@@ -5433,18 +5950,27 @@ var agentSchema = z5.object({
5433
5950
  mcp_servers: z5.array(mcpServerSchema).optional(),
5434
5951
  skills: z5.array(z5.union([z5.string(), agentSkillRefSchema])).optional(),
5435
5952
  vault: z5.string().optional(),
5953
+ files: z5.array(z5.string()).optional(),
5436
5954
  memory_stores: z5.array(z5.string()).optional(),
5955
+ default_memory_store: z5.object({
5956
+ name: z5.string().trim().min(1).max(255),
5957
+ description: z5.string().max(1024).optional(),
5958
+ delete_on_destroy: z5.boolean().optional().default(false)
5959
+ }).optional(),
5437
5960
  resources: z5.array(sessionGithubRepoResourceSchema).optional(),
5438
5961
  multiagent: multiagentSchema.optional(),
5439
5962
  metadata: z5.record(z5.string(), z5.string()).optional(),
5963
+ environment_variables: z5.record(z5.string().min(1), z5.string()).optional(),
5964
+ managed_tool_config: managedToolConfigSchema.optional(),
5440
5965
  delivery: z5.record(z5.string(), agentDeliverySchema).optional()
5441
5966
  });
5442
5967
  var channelSchema = z5.object({
5443
5968
  provider: z5.string().optional(),
5444
- agent: z5.string().min(1),
5969
+ agent: z5.string().min(1).optional(),
5445
5970
  identity: z5.string().min(1).optional(),
5446
5971
  type: z5.string().min(1),
5447
5972
  name: z5.string().trim().min(1).optional(),
5973
+ mode: z5.enum(["fixed", "pairing"]).optional().default("fixed"),
5448
5974
  enabled: z5.boolean().optional(),
5449
5975
  credentials: z5.record(z5.string(), coerceString).optional(),
5450
5976
  options: z5.record(z5.string(), z5.unknown()).optional()
@@ -5491,6 +6017,7 @@ var scheduleSchema = z5.object({
5491
6017
  timezone: z5.string()
5492
6018
  });
5493
6019
  var deploymentSchema = z5.object({
6020
+ name: z5.string().optional(),
5494
6021
  agent: z5.string(),
5495
6022
  agent_version: z5.number().int().optional(),
5496
6023
  environment: z5.string().optional(),
@@ -5683,14 +6210,29 @@ async function computeResourceHash(address, config, basePath, state) {
5683
6210
  if (!decl) return "";
5684
6211
  if (address.type === "skill") {
5685
6212
  const skillDecl = decl;
6213
+ const apiMode = resolveQoderApiMode(address.type, address.name, address.provider, config);
5686
6214
  if (basePath) {
5687
6215
  const fileHash = computeSkillContentHash(skillDecl.source, basePath);
5688
- return contentHash({ decl, fileHash });
6216
+ return contentHash({ decl, fileHash, apiMode });
5689
6217
  }
6218
+ return contentHash({ decl, apiMode });
6219
+ }
6220
+ if (address.type === "environment" || address.type === "vault" || address.type === "memory_store") {
6221
+ return contentHash({ decl, apiMode: resolveQoderApiMode(address.type, address.name, address.provider, config) });
6222
+ }
6223
+ if (address.type === "file" && basePath) {
6224
+ const fileDecl = decl;
6225
+ const fileHash = computeLocalFileContentHash(fileDecl.source, basePath);
6226
+ return contentHash({
6227
+ decl,
6228
+ fileHash,
6229
+ apiMode: resolveQoderApiMode("file", address.name, address.provider, config)
6230
+ });
5690
6231
  }
5691
6232
  if (address.type === "deployment") {
5692
6233
  const refs = resolveDeploymentReferenceIds(decl, config, address.provider, state);
5693
- if (refs) return contentHash({ decl, refs });
6234
+ const sourceHashes = basePath ? computeDeploymentSourceHashes(decl, basePath) : void 0;
6235
+ if (refs || sourceHashes) return contentHash({ decl, refs, sourceHashes });
5694
6236
  }
5695
6237
  if (address.type === "template") {
5696
6238
  const refs = resolveTemplateReferenceIds(decl, config, address.provider, state);
@@ -5707,7 +6249,28 @@ async function computeResourceHash(address, config, basePath, state) {
5707
6249
  }
5708
6250
  return contentHash(decl);
5709
6251
  }
6252
+ function resolveQoderApiMode(type, name, provider, config) {
6253
+ if (provider !== "qoder") return void 0;
6254
+ if (type === "environment" && config.environments?.[name]?.environment_id) return "auto";
6255
+ for (const agent of Object.values(config.agents ?? {})) {
6256
+ if (agent.provider && agent.provider !== provider) continue;
6257
+ const referenced = type === "environment" ? agent.environment === name : type === "skill" ? agent.skills?.some(
6258
+ (skill) => typeof skill === "string" ? skill === name : skill.type === "custom" && skill.skill_id === name
6259
+ ) : type === "vault" ? agent.vault === name : type === "memory_store" ? agent.memory_stores?.includes(name) : agent.files?.includes(name);
6260
+ if (referenced && agent.delivery?.qoder?.type === "forward") return "forward";
6261
+ }
6262
+ return "managed";
6263
+ }
6264
+ function computeReplacementFingerprint(address, config) {
6265
+ if (address.type !== "channel") return void 0;
6266
+ const decl = config.channels?.[address.name];
6267
+ if (!decl) return void 0;
6268
+ return contentHash({ channel_type: decl.type, mode: decl.mode ?? "fixed", credentials: decl.credentials ?? {} });
6269
+ }
5710
6270
  function resolveChannelReferenceIds(decl, config, provider, state) {
6271
+ if (decl.mode === "pairing" || !decl.agent) {
6272
+ return { mode: "pairing" };
6273
+ }
5711
6274
  const agent = config.agents?.[decl.agent];
5712
6275
  const agentType = agent?.delivery?.[provider]?.type === "forward" ? "template" : "agent";
5713
6276
  const identity = decl.identity ?? config.defaults?.identity;
@@ -5730,7 +6293,14 @@ function resolveTemplateReferenceIds(decl, config, provider, state) {
5730
6293
  environment_id: environment?.environment_id ?? (decl.environment ? state?.getResource({ type: "environment", name: decl.environment, provider })?.remote_id ?? void 0 : void 0),
5731
6294
  tunnel_id: tunnel?.tunnel_id,
5732
6295
  vault_ids: decl.vault ? [state?.getResource({ type: "vault", name: decl.vault, provider })?.remote_id ?? decl.vault] : [],
5733
- skill_ids: skillIds
6296
+ skill_ids: skillIds,
6297
+ memory_store_ids: (decl.memory_stores ?? []).map(
6298
+ (memoryStore) => state?.getResource({ type: "memory_store", name: memoryStore, provider })?.remote_id ?? memoryStore
6299
+ ),
6300
+ file_ids: (decl.files ?? []).map(
6301
+ (file) => state?.getResource({ type: "file", name: file, provider })?.remote_id ?? file
6302
+ ),
6303
+ identity_id: decl.memory_stores?.length && config.defaults?.identity ? state?.getResource({ type: "identity", name: config.defaults.identity, provider })?.remote_id : void 0
5734
6304
  };
5735
6305
  }
5736
6306
  function resolveDeploymentReferenceIds(decl, config, provider, state) {
@@ -5745,6 +6315,23 @@ function resolveDeploymentReferenceIds(decl, config, provider, state) {
5745
6315
  function getDeclaration(address, config) {
5746
6316
  return getResourceDeclaration(address, config);
5747
6317
  }
6318
+ function computeDeploymentSourceHashes(decl, basePath) {
6319
+ const sources = [
6320
+ ...new Set(
6321
+ (decl.resources ?? []).flatMap(
6322
+ (resource) => resource.type === "file" && !resource.file_id && resource.source ? [resource.source] : []
6323
+ )
6324
+ )
6325
+ ];
6326
+ if (sources.length === 0) return void 0;
6327
+ return Object.fromEntries(sources.map((source) => [source, computeLocalFileContentHash(source, basePath)]));
6328
+ }
6329
+ function computeLocalFileContentHash(source, basePath) {
6330
+ const fullPath = resolve9(dirname8(basePath), source);
6331
+ const stat = statSync2(fullPath, { throwIfNoEntry: false });
6332
+ if (!stat?.isFile()) return "";
6333
+ return contentHash(readFileSync6(fullPath).toString("base64"));
6334
+ }
5748
6335
  function computeSkillContentHash(source, basePath) {
5749
6336
  const fullPath = resolve9(dirname8(basePath), source);
5750
6337
  const stat = statSync2(fullPath, { throwIfNoEntry: false });
@@ -5893,11 +6480,21 @@ function resolveTemplateRefs(agentName, config, provider, state) {
5893
6480
  const environment = config.environments?.[agent.environment];
5894
6481
  if (!environment) throw new UserError(`Environment '${agent.environment}' is not defined in config.`);
5895
6482
  const agentRefs = resolveAgentRefs(agentName, config, provider, state);
6483
+ const memoryStoreIds = (agent.memory_stores ?? []).map(
6484
+ (memoryStore) => requireRef(state, { type: "memory_store", name: memoryStore, provider })
6485
+ );
6486
+ const identityName = config.defaults?.identity;
5896
6487
  return {
5897
6488
  ...agentRefs,
5898
6489
  environment_id: environment.environment_id ?? requireRef(state, { type: "environment", name: agent.environment, provider }),
5899
6490
  ...agent.tunnel ? { tunnel_id: resolveTunnelIdFromConfig(config, agent.tunnel, provider) } : {},
5900
- vault_ids: agent.vault ? [requireRef(state, { type: "vault", name: agent.vault, provider })] : []
6491
+ vault_ids: agent.vault ? [requireRef(state, { type: "vault", name: agent.vault, provider })] : [],
6492
+ file_ids: (agent.files ?? []).map((file) => requireRef(state, { type: "file", name: file, provider })),
6493
+ memory_store_ids: memoryStoreIds,
6494
+ owned_memory_store_ids: state.listResources().filter(
6495
+ (resource) => resource.address.provider === provider && resource.address.type === "memory_store" && resource.api_mode === "forward" && typeof resource.remote_id === "string"
6496
+ ).map((resource) => resource.remote_id),
6497
+ ...identityName ? { identity_id: requireRef(state, { type: "identity", name: identityName, provider }) } : {}
5901
6498
  };
5902
6499
  }
5903
6500
  function resolveDeploymentRefs(deploymentName, config, provider, state) {
@@ -5959,6 +6556,12 @@ function resolveDeploymentRefs(deploymentName, config, provider, state) {
5959
6556
  function resolveChannelRefs(channelName, config, provider, state) {
5960
6557
  const channel = config.channels?.[channelName];
5961
6558
  if (!channel) throw new UserError(`Channel '${channelName}' not found in config`);
6559
+ if (channel.mode === "pairing") {
6560
+ return {};
6561
+ }
6562
+ if (!channel.agent) {
6563
+ throw new UserError(`Channel '${channelName}' is fixed mode and must declare agent`);
6564
+ }
5962
6565
  const agent = config.agents?.[channel.agent];
5963
6566
  if (!agent) throw new UserError(`Channel '${channelName}' references unknown agent '${channel.agent}'`);
5964
6567
  const agentType = agent.delivery?.[provider]?.type === "forward" ? "template" : "agent";
@@ -5982,8 +6585,61 @@ function resolveTunnelIdFromConfig(config, tunnelName, provider) {
5982
6585
  }
5983
6586
 
5984
6587
  // src/internal/executor/skill-resolver.ts
6588
+ import { dirname as dirname9 } from "path";
6589
+
6590
+ // src/internal/core/skill-source.ts
5985
6591
  import { readFileSync as readFileSync7, statSync as statSync3 } from "fs";
5986
- import { dirname as dirname9, resolve as resolve10 } from "path";
6592
+ import { basename as basename6, resolve as resolve10 } from "path";
6593
+ import { parse } from "yaml";
6594
+ async function inspectSkillSource(source, options = {}) {
6595
+ if (/^https?:\/\//i.test(source)) {
6596
+ throw new UserError("Skill source inspection only accepts a local directory, zip, or SKILL.md file.");
6597
+ }
6598
+ const sourcePath = resolve10(options.basePath ?? process.cwd(), source);
6599
+ const sourceStat = statSync3(sourcePath, { throwIfNoEntry: false });
6600
+ if (!sourceStat) throw new UserError(`Skill source not found: ${source}`);
6601
+ let files;
6602
+ if (sourceStat.isDirectory()) {
6603
+ files = collectFiles(sourcePath, "");
6604
+ } else if (sourceStat.isFile() && sourcePath.toLowerCase().endsWith(".zip")) {
6605
+ files = await extractSkillZipFiles(readFileSync7(sourcePath));
6606
+ } else if (sourceStat.isFile() && basename6(sourcePath).toLowerCase() === "skill.md") {
6607
+ files = [{ relativePath: "SKILL.md", content: readFileSync7(sourcePath) }];
6608
+ } else {
6609
+ throw new UserError("Skill source must be a directory, .zip archive, or SKILL.md file.");
6610
+ }
6611
+ const normalizedFiles = normalizeSkillRoot(files);
6612
+ const manifest = normalizedFiles.find((file) => file.relativePath === "SKILL.md");
6613
+ const name = parseSkillManifestName(manifest.content);
6614
+ return { name, sourcePath, files: normalizedFiles };
6615
+ }
6616
+ function normalizeSkillRoot(files) {
6617
+ if (files.some((file) => file.relativePath === "SKILL.md")) return files;
6618
+ const manifests = files.filter((file) => file.relativePath.endsWith("/SKILL.md"));
6619
+ if (manifests.length === 0) throw new UserError("Skill source does not contain SKILL.md.");
6620
+ if (manifests.length > 1) {
6621
+ throw new UserError("Skill source contains multiple SKILL.md files and has no unambiguous root.");
6622
+ }
6623
+ const prefix = manifests[0].relativePath.slice(0, -"SKILL.md".length);
6624
+ return files.filter((file) => file.relativePath.startsWith(prefix)).map((file) => ({ ...file, relativePath: file.relativePath.slice(prefix.length) }));
6625
+ }
6626
+ function parseSkillManifestName(content) {
6627
+ const text = content.toString("utf8");
6628
+ const frontmatter = text.match(/^---\s*\r?\n([\s\S]*?)\r?\n---(?:\s*\r?\n|$)/);
6629
+ if (!frontmatter) throw new UserError("SKILL.md must start with YAML frontmatter containing a name.");
6630
+ let manifest;
6631
+ try {
6632
+ manifest = parse(frontmatter[1]);
6633
+ } catch (error) {
6634
+ throw new UserError(`Invalid SKILL.md frontmatter: ${error instanceof Error ? error.message : String(error)}`);
6635
+ }
6636
+ const rawName = manifest && typeof manifest === "object" ? manifest.name : void 0;
6637
+ const name = typeof rawName === "string" ? rawName.trim() : "";
6638
+ if (!name) throw new UserError("SKILL.md frontmatter must contain a non-empty name.");
6639
+ return name;
6640
+ }
6641
+
6642
+ // src/internal/executor/skill-resolver.ts
5987
6643
  async function resolveSkillFiles(decl, ctx) {
5988
6644
  if (/^https?:\/\//i.test(decl.source)) {
5989
6645
  const res = await resolveFetch()(decl.source);
@@ -5991,19 +6647,7 @@ async function resolveSkillFiles(decl, ctx) {
5991
6647
  return extractSkillZipFiles(Buffer.from(await res.arrayBuffer()));
5992
6648
  }
5993
6649
  if (!ctx.configPath) return [];
5994
- const sourcePath = resolve10(dirname9(ctx.configPath), decl.source);
5995
- const stat = statSync3(sourcePath, { throwIfNoEntry: false });
5996
- if (stat?.isDirectory()) {
5997
- return collectFiles(sourcePath, "");
5998
- }
5999
- if (stat?.isFile()) {
6000
- if (sourcePath.endsWith(".zip")) {
6001
- return extractSkillZipFiles(readFileSync7(sourcePath));
6002
- }
6003
- const content = readFileSync7(sourcePath);
6004
- return [{ relativePath: "SKILL.md", content }];
6005
- }
6006
- return [];
6650
+ return (await inspectSkillSource(decl.source, { basePath: dirname9(ctx.configPath) })).files;
6007
6651
  }
6008
6652
 
6009
6653
  // src/internal/executor/executor.ts
@@ -6081,6 +6725,7 @@ async function executePlan(plan, ctx, options = {}) {
6081
6725
  await runWithConcurrency(level, concurrency, runAction);
6082
6726
  await ctx.state.save();
6083
6727
  }
6728
+ await reconcileDefaultMemoryStores(ctx, new Set(plan.actions.map((action) => action.address.provider)));
6084
6729
  for (const action of deletions) {
6085
6730
  await runAction(action);
6086
6731
  await ctx.state.save();
@@ -6091,6 +6736,41 @@ async function executePlan(plan, ctx, options = {}) {
6091
6736
  partial: results.some((r) => r.status === "failed")
6092
6737
  };
6093
6738
  }
6739
+ async function reconcileDefaultMemoryStores(ctx, plannedProviders) {
6740
+ const identityName = ctx.config.defaults?.identity;
6741
+ for (const [agentName, agent] of Object.entries(ctx.config.agents ?? {})) {
6742
+ const desired = agent.default_memory_store;
6743
+ if (!desired || agent.delivery?.qoder?.type !== "forward") continue;
6744
+ const providerName = "qoder";
6745
+ if (agent.provider && agent.provider !== providerName || !plannedProviders.has(providerName)) continue;
6746
+ const provider = ctx.providers.get(providerName);
6747
+ if (!provider?.reconcileDefaultMemoryStore || !identityName) continue;
6748
+ const identityId = ctx.state.getResource({
6749
+ type: "identity",
6750
+ name: identityName,
6751
+ provider: providerName
6752
+ })?.remote_id;
6753
+ const templateId = ctx.state.getResource({ type: "template", name: agentName, provider: providerName })?.remote_id;
6754
+ if (!identityId || !templateId) continue;
6755
+ const result = await provider.reconcileDefaultMemoryStore(identityId, templateId, desired);
6756
+ const resource = { type: "template", name: agentName, provider: providerName };
6757
+ if (result.status === "pending") {
6758
+ emitRuntimeFeedback(ctx.onFeedback, {
6759
+ type: "provider_wait",
6760
+ level: "warning",
6761
+ resource,
6762
+ message: `default memory store for template.${agentName} is pending \u2014 create the first Forward Session, then run apply again`
6763
+ });
6764
+ } else if (result.status === "updated") {
6765
+ emitRuntimeFeedback(ctx.onFeedback, {
6766
+ type: "resource_action_success",
6767
+ level: "success",
6768
+ resource,
6769
+ message: `updated default memory store for template.${agentName} to "${desired.name}"`
6770
+ });
6771
+ }
6772
+ }
6773
+ }
6094
6774
  async function runWithConcurrency(items, limit, worker) {
6095
6775
  if (items.length === 0) return;
6096
6776
  let cursor = 0;
@@ -6157,8 +6837,8 @@ async function executeAction(action, provider, ctx) {
6157
6837
  resource: action.address,
6158
6838
  message: `update ${action.address.type}.${action.address.name} (${action.address.provider}) \u2014 not found remotely, recreating`
6159
6839
  });
6160
- ctx.state.removeResource(action.address);
6161
- return executeActionInner({ ...action, action: "create" }, provider, ctx);
6840
+ ctx.state.removeResource(action.previousAddress ?? action.address);
6841
+ return executeActionInner({ ...action, action: "create", previousAddress: void 0 }, provider, ctx);
6162
6842
  }
6163
6843
  }
6164
6844
  async function executeActionInner(action, provider, ctx) {
@@ -6169,6 +6849,7 @@ async function executeActionInner(action, provider, ctx) {
6169
6849
  const existing = ctx.state.getResource(address);
6170
6850
  if (!existing) return false;
6171
6851
  const id = existing.remote_id;
6852
+ const apiMode2 = existing.api_mode;
6172
6853
  if (type === "environment" || type === "identity") {
6173
6854
  const externalReference = type === "environment" ? ctx.config.environments?.[name]?.environment_id : ctx.config.identities?.[name]?.identity_id;
6174
6855
  if (existing.externally_managed || externalReference) {
@@ -6180,13 +6861,13 @@ async function executeActionInner(action, provider, ctx) {
6180
6861
  try {
6181
6862
  switch (type) {
6182
6863
  case "environment":
6183
- await provider.deleteEnvironment(id);
6864
+ await provider.deleteEnvironment(id, false, apiMode2);
6184
6865
  break;
6185
6866
  case "vault":
6186
- await provider.deleteVault(id);
6867
+ await provider.deleteVault(id, apiMode2);
6187
6868
  break;
6188
6869
  case "skill":
6189
- await provider.deleteSkill(id);
6870
+ await provider.deleteSkill(id, apiMode2);
6190
6871
  break;
6191
6872
  case "agent":
6192
6873
  await provider.deleteAgent(id);
@@ -6194,17 +6875,17 @@ async function executeActionInner(action, provider, ctx) {
6194
6875
  case "template":
6195
6876
  if (!provider.archiveTemplate)
6196
6877
  throw new UserError(`Provider '${address.provider}' does not support templates`);
6197
- await provider.archiveTemplate(id);
6878
+ await provider.archiveTemplate(id, ownedForwardMemoryStoreIds(ctx, address.provider));
6198
6879
  break;
6199
6880
  case "memory_store":
6200
6881
  if (!provider.deleteMemoryStore) throw memoryStoreUnsupported(address.provider);
6201
- await provider.deleteMemoryStore(id);
6882
+ await provider.deleteMemoryStore(id, apiMode2);
6202
6883
  break;
6203
6884
  case "deployment":
6204
6885
  await provider.deleteDeployment(id);
6205
6886
  break;
6206
6887
  case "file":
6207
- await provider.deleteFile(id);
6888
+ await provider.deleteFile(id, apiMode2);
6208
6889
  break;
6209
6890
  case "identity":
6210
6891
  if (!provider.deleteIdentity)
@@ -6231,7 +6912,11 @@ async function executeActionInner(action, provider, ctx) {
6231
6912
  return false;
6232
6913
  }
6233
6914
  const isUpdate = action.action === "update";
6234
- const existingId = isUpdate ? ctx.state.getResource(address)?.remote_id : void 0;
6915
+ const priorAddress = action.previousAddress ?? address;
6916
+ const existingId = isUpdate ? ctx.state.getResource(priorAddress)?.remote_id : void 0;
6917
+ const apiMode = resolveResourceApiMode(type, name, address.provider, ctx.config);
6918
+ const priorApiMode = ctx.state.getResource(priorAddress)?.api_mode ?? (address.provider === "qoder" ? "managed" : void 0);
6919
+ const apiModeChanged = isUpdate && apiMode !== void 0 && priorApiMode !== apiMode;
6235
6920
  let result;
6236
6921
  switch (type) {
6237
6922
  case "environment": {
@@ -6246,6 +6931,17 @@ async function executeActionInner(action, provider, ctx) {
6246
6931
  resource: action.address,
6247
6932
  message: `${action.action} ${action.address.type}.${action.address.name} (${action.address.provider}) \u2014 external reference, no remote mutation`
6248
6933
  });
6934
+ } else if (apiModeChanged) {
6935
+ try {
6936
+ result = await provider.createEnvironment(remoteName, decl, apiMode);
6937
+ } catch (err) {
6938
+ result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
6939
+ mode: apiMode,
6940
+ onExisting: (existing) => provider.updateEnvironment(existing.id, remoteName, decl, apiMode)
6941
+ });
6942
+ adopted = true;
6943
+ }
6944
+ if (existingId) await provider.deleteEnvironment(existingId, false, priorApiMode);
6249
6945
  } else if (isUpdate) {
6250
6946
  const prior = ctx.state.getResource(address);
6251
6947
  if (prior?.externally_managed) {
@@ -6253,13 +6949,14 @@ async function executeActionInner(action, provider, ctx) {
6253
6949
  `environment.${name} is recorded as an external reference (${prior.remote_id ?? "unknown id"}); refusing to modify it remotely. Restore 'environment_id' to keep it as a reference, or release it first with 'agents state rm environment.${name}' (then 'agents state import' to adopt it as a managed resource).`
6254
6950
  );
6255
6951
  }
6256
- result = await provider.updateEnvironment(existingId, remoteName, decl);
6952
+ result = await provider.updateEnvironment(existingId, remoteName, decl, apiMode);
6257
6953
  } else {
6258
6954
  try {
6259
- result = await provider.createEnvironment(remoteName, decl);
6955
+ result = await provider.createEnvironment(remoteName, decl, apiMode);
6260
6956
  } catch (err) {
6261
6957
  result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
6262
- onExisting: (existing) => provider.updateEnvironment(existing.id, remoteName, decl)
6958
+ mode: apiMode,
6959
+ onExisting: (existing) => provider.updateEnvironment(existing.id, remoteName, decl, apiMode)
6263
6960
  });
6264
6961
  adopted = true;
6265
6962
  }
@@ -6268,22 +6965,26 @@ async function executeActionInner(action, provider, ctx) {
6268
6965
  }
6269
6966
  case "vault": {
6270
6967
  const decl = ctx.config.vaults[name];
6271
- if (isUpdate) {
6968
+ if (apiModeChanged) {
6969
+ result = await provider.createVault(name, decl, apiMode);
6970
+ if (existingId) await provider.deleteVault(existingId, priorApiMode).catch(() => void 0);
6971
+ } else if (isUpdate) {
6272
6972
  try {
6273
- result = await provider.createVault(name, decl);
6274
- await provider.deleteVault(existingId);
6973
+ result = await provider.createVault(name, decl, apiMode);
6974
+ await provider.deleteVault(existingId, apiMode);
6275
6975
  } catch {
6276
- await provider.deleteVault(existingId);
6277
- result = await provider.createVault(name, decl);
6976
+ await provider.deleteVault(existingId, apiMode);
6977
+ result = await provider.createVault(name, decl, apiMode);
6278
6978
  }
6279
6979
  } else {
6280
6980
  try {
6281
- result = await provider.createVault(name, decl);
6981
+ result = await provider.createVault(name, decl, apiMode);
6282
6982
  } catch (err) {
6283
6983
  result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
6984
+ mode: apiMode,
6284
6985
  onExisting: async (existing) => {
6285
- await provider.deleteVault(existing.id);
6286
- return provider.createVault(name, decl);
6986
+ await provider.deleteVault(existing.id, apiMode);
6987
+ return provider.createVault(name, decl, apiMode);
6287
6988
  }
6288
6989
  });
6289
6990
  adopted = true;
@@ -6307,12 +7008,15 @@ async function executeActionInner(action, provider, ctx) {
6307
7008
  }
6308
7009
  const remoteName = decl.name ?? name;
6309
7010
  const files = await resolveSkillFiles(decl, ctx);
6310
- if (isUpdate) {
6311
- result = await provider.updateSkill(existingId, remoteName, decl, files);
7011
+ if (apiModeChanged) {
7012
+ result = await provider.createSkill(remoteName, decl, files, apiMode);
7013
+ if (existingId) await provider.deleteSkill(existingId, priorApiMode).catch(() => void 0);
7014
+ } else if (isUpdate) {
7015
+ result = await provider.updateSkill(existingId, remoteName, decl, files, apiMode);
6312
7016
  } else {
6313
7017
  const manifestName = skillNameFromFiles(files);
6314
7018
  const searchNames = manifestName && manifestName !== remoteName ? [remoteName, manifestName] : [remoteName];
6315
- const existing = await findExistingByNames(provider, "skill", searchNames);
7019
+ const existing = await findExistingByNames(provider, "skill", searchNames, apiMode);
6316
7020
  if (existing) {
6317
7021
  result = existing.resource;
6318
7022
  emitRuntimeFeedback(ctx.onFeedback, {
@@ -6324,9 +7028,10 @@ async function executeActionInner(action, provider, ctx) {
6324
7028
  adopted = true;
6325
7029
  } else {
6326
7030
  try {
6327
- result = await provider.createSkill(remoteName, decl, files);
7031
+ result = await provider.createSkill(remoteName, decl, files, apiMode);
6328
7032
  } catch (err) {
6329
7033
  result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
7034
+ mode: apiMode,
6330
7035
  searchNames,
6331
7036
  onExisting: async (existing2) => existing2
6332
7037
  });
@@ -6345,15 +7050,19 @@ async function executeActionInner(action, provider, ctx) {
6345
7050
  throw memoryStoreUnsupported(address.provider);
6346
7051
  }
6347
7052
  const reconcile = async (storeId) => {
6348
- const store = await provider.updateMemoryStore(storeId, {
6349
- name,
6350
- description: decl.description,
6351
- metadata: decl.metadata ?? {}
6352
- });
7053
+ const store = await provider.updateMemoryStore(
7054
+ storeId,
7055
+ {
7056
+ name,
7057
+ description: decl.description,
7058
+ metadata: decl.metadata ?? {}
7059
+ },
7060
+ apiMode
7061
+ );
6353
7062
  const current = /* @__PURE__ */ new Map();
6354
7063
  let cursor;
6355
7064
  do {
6356
- const page2 = await provider.listMemories(storeId, { limit: 100, cursor, view: "basic" });
7065
+ const page2 = await provider.listMemories(storeId, { limit: 100, cursor, view: "basic" }, apiMode);
6357
7066
  for (const memory of page2.data) {
6358
7067
  if (memory.type === "memory") current.set(memory.path, memory);
6359
7068
  }
@@ -6363,24 +7072,33 @@ async function executeActionInner(action, provider, ctx) {
6363
7072
  const existing = current.get(entry.key.replace(/^\/+/, ""));
6364
7073
  if (existing) {
6365
7074
  if (existing.content_sha256 !== sha256(entry.content)) {
6366
- await provider.updateMemory(storeId, existing.id, {
6367
- content: entry.content,
6368
- expected_content_sha256: existing.content_sha256
6369
- });
7075
+ await provider.updateMemory(
7076
+ storeId,
7077
+ existing.id,
7078
+ {
7079
+ content: entry.content,
7080
+ expected_content_sha256: existing.content_sha256
7081
+ },
7082
+ apiMode
7083
+ );
6370
7084
  }
6371
7085
  } else {
6372
- await provider.createMemory(storeId, { path: entry.key, content: entry.content });
7086
+ await provider.createMemory(storeId, { path: entry.key, content: entry.content }, apiMode);
6373
7087
  }
6374
7088
  }
6375
7089
  return store;
6376
7090
  };
6377
- if (isUpdate) {
7091
+ if (apiModeChanged) {
7092
+ result = await createMemoryStore2(name, decl, apiMode);
7093
+ if (existingId) await deleteMemoryStore2(existingId, priorApiMode).catch(() => void 0);
7094
+ } else if (isUpdate) {
6378
7095
  result = await reconcile(existingId);
6379
7096
  } else {
6380
7097
  try {
6381
- result = await createMemoryStore2(name, decl);
7098
+ result = await createMemoryStore2(name, decl, apiMode);
6382
7099
  } catch (err) {
6383
7100
  result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
7101
+ mode: apiMode,
6384
7102
  onExisting: async (existing) => reconcile(existing.id)
6385
7103
  });
6386
7104
  adopted = true;
@@ -6489,16 +7207,36 @@ async function executeActionInner(action, provider, ctx) {
6489
7207
  case "deployment": {
6490
7208
  const decl = ctx.config.deployments[name];
6491
7209
  const refs = resolveDeploymentRefs(name, ctx.config, address.provider, ctx.state);
6492
- if (isUpdate) {
6493
- result = await provider.updateDeployment(existingId, name, decl, refs, ctx.configPath ?? "");
6494
- } else {
7210
+ const hasLocalFileSources = decl.resources?.some(
7211
+ (resource) => resource.type === "file" && !resource.file_id && Boolean(resource.source)
7212
+ );
7213
+ const materializeDeployment = async () => {
6495
7214
  try {
6496
- result = await provider.createDeployment(name, decl, refs, ctx.configPath ?? "");
7215
+ return await provider.createDeployment(name, decl, refs, ctx.configPath ?? "");
6497
7216
  } catch (err) {
6498
- result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
6499
- onExisting: (existing) => provider.updateDeployment(existing.id, name, decl, refs, ctx.configPath ?? "")
7217
+ const preparedFiles = err instanceof DeploymentCreateConflictError ? err.preparedFiles : void 0;
7218
+ const existing = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
7219
+ onExisting: (existing2) => provider.updateDeployment(existing2.id, name, decl, refs, ctx.configPath ?? "", preparedFiles)
7220
+ });
7221
+ adopted = true;
7222
+ return existing;
7223
+ }
7224
+ };
7225
+ if (isUpdate && existingId) {
7226
+ result = await provider.updateDeployment(existingId, name, decl, refs, ctx.configPath ?? "");
7227
+ } else {
7228
+ const existing = hasLocalFileSources ? await findExistingByNames(provider, "deployment", [name]) : null;
7229
+ if (existing) {
7230
+ result = await provider.updateDeployment(existing.resource.id, name, decl, refs, ctx.configPath ?? "");
7231
+ emitRuntimeFeedback(ctx.onFeedback, {
7232
+ type: "resource_adopted",
7233
+ level: "info",
7234
+ resource: address,
7235
+ message: `adopt deployment.${name} (${address.provider}) \u2014 already existed remotely as "${existing.name}"`
6500
7236
  });
6501
7237
  adopted = true;
7238
+ } else {
7239
+ result = await materializeDeployment();
6502
7240
  }
6503
7241
  }
6504
7242
  break;
@@ -6510,15 +7248,12 @@ async function executeActionInner(action, provider, ctx) {
6510
7248
  const oldId = ctx.state.getResource(address)?.remote_id;
6511
7249
  if (oldId) {
6512
7250
  try {
6513
- await provider.deleteFile(oldId);
7251
+ await provider.deleteFile(oldId, priorApiMode);
6514
7252
  } catch {
6515
7253
  }
6516
7254
  }
6517
7255
  }
6518
- const info = await provider.uploadFile(filePath, {
6519
- name: decl.name,
6520
- purpose: decl.purpose
6521
- });
7256
+ const info = await provider.uploadFile(filePath, { name: decl.name, purpose: decl.purpose }, apiMode);
6522
7257
  result = { id: info.id, type: "file" };
6523
7258
  break;
6524
7259
  }
@@ -6534,11 +7269,12 @@ async function executeActionInner(action, provider, ctx) {
6534
7269
  remoteHash = contentHash(remote.comparable);
6535
7270
  remoteSnapshot = remote.snapshot ?? remote.comparable;
6536
7271
  }
6537
- const priorResource = ctx.state.getResource(address);
7272
+ const priorResource = ctx.state.getResource(priorAddress);
6538
7273
  ctx.state.setResource({
6539
7274
  address,
6540
7275
  remote_id: result.id,
6541
7276
  externally_managed: priorResource?.externally_managed || type === "environment" && ctx.config.environments?.[name]?.environment_id || type === "identity" && ctx.config.identities?.[name]?.identity_id ? true : void 0,
7277
+ api_mode: apiMode,
6542
7278
  version: result.version,
6543
7279
  content_hash: hash,
6544
7280
  desired_hash: hash,
@@ -6546,14 +7282,44 @@ async function executeActionInner(action, provider, ctx) {
6546
7282
  desired_readiness_baseline: buildReadinessBaseline(getResourceDeclaration(address, ctx.config)),
6547
7283
  remote_hash: remoteHash,
6548
7284
  remote_snapshot: remoteSnapshot,
7285
+ replacement_fingerprint: computeReplacementFingerprint(address, ctx.config),
6549
7286
  drift_paths: [],
6550
7287
  drift_status: remoteHash ? "in_sync" : void 0
6551
7288
  });
7289
+ if (action.previousAddress) ctx.state.removeResource(action.previousAddress);
6552
7290
  return adopted;
6553
7291
  }
6554
- async function findExistingByNames(provider, type, names) {
7292
+ function ownedForwardMemoryStoreIds(ctx, provider) {
7293
+ return ctx.state.listResources().filter(
7294
+ (resource) => resource.address.provider === provider && resource.address.type === "memory_store" && resource.api_mode === "forward" && typeof resource.remote_id === "string"
7295
+ ).map((resource) => resource.remote_id);
7296
+ }
7297
+ function resolveResourceApiMode(type, name, provider, config) {
7298
+ if (provider !== "qoder" || type !== "environment" && type !== "skill" && type !== "vault" && type !== "memory_store" && type !== "file") {
7299
+ return void 0;
7300
+ }
7301
+ if (type === "environment" && config.environments?.[name]?.environment_id) return "auto";
7302
+ let managed = false;
7303
+ let forward = false;
7304
+ for (const agent of Object.values(config.agents ?? {})) {
7305
+ if (agent.provider && agent.provider !== provider) continue;
7306
+ const referenced = type === "environment" ? agent.environment === name : type === "skill" ? agent.skills?.some(
7307
+ (skill) => typeof skill === "string" ? skill === name : skill.type === "custom" && skill.skill_id === name
7308
+ ) : type === "vault" ? agent.vault === name : type === "memory_store" ? agent.memory_stores?.includes(name) : agent.files?.includes(name);
7309
+ if (!referenced) continue;
7310
+ if (agent.delivery?.qoder?.type === "forward") forward = true;
7311
+ else managed = true;
7312
+ }
7313
+ if (managed && forward) {
7314
+ throw new UserError(
7315
+ `Qoder ${type}.${name} is referenced by both Managed and Forward agents; declare separate resources for each API domain.`
7316
+ );
7317
+ }
7318
+ return forward ? "forward" : "managed";
7319
+ }
7320
+ async function findExistingByNames(provider, type, names, mode) {
6555
7321
  for (const candidate of names) {
6556
- const found = await provider.findResource(type, candidate);
7322
+ const found = await provider.findResource(type, candidate, void 0, mode);
6557
7323
  if (found && found.id !== null) return { resource: found, name: candidate };
6558
7324
  }
6559
7325
  return null;
@@ -6561,7 +7327,7 @@ async function findExistingByNames(provider, type, names) {
6561
7327
  async function adoptOnConflict(err, address, provider, onFeedback, opts) {
6562
7328
  if (!(err instanceof ConflictError)) throw err;
6563
7329
  const candidates = opts.searchNames?.length ? opts.searchNames : [address.name];
6564
- const existing = await findExistingByNames(provider, address.type, candidates);
7330
+ const existing = await findExistingByNames(provider, address.type, candidates, opts.mode);
6565
7331
  if (!existing) throw nameReservedError(err, address, candidates.join('" / "'));
6566
7332
  emitRuntimeFeedback(onFeedback, {
6567
7333
  type: "resource_adopted",
@@ -6573,68 +7339,303 @@ async function adoptOnConflict(err, address, provider, onFeedback, opts) {
6573
7339
  }
6574
7340
  function nameReservedError(err, address, searchName) {
6575
7341
  const detail = err instanceof ApiError ? err.message : String(err);
7342
+ if (address.type === "channel" && err instanceof ApiError && err.responseBody.includes("CHANNEL_CREDENTIAL_CONFLICT")) {
7343
+ return new UserError(
7344
+ `${address.provider} rejected channel.${address.name} because its credentials are already used by another Channel. Keep the existing Channel address so it can be updated in place, remove the old Channel first, or use a different credential set. (${detail})`
7345
+ );
7346
+ }
6576
7347
  return new UserError(
6577
7348
  `${address.provider} reported ${address.type} "${searchName}" already exists, but it could not be found remotely to adopt. This usually means it was recently deleted and the provider still reserves the name. Wait for the provider to release the name, or use a different name for ${address.type}.${address.name}. (${detail})`
6578
7349
  );
6579
7350
  }
6580
7351
 
6581
- // src/internal/diagnostics/diagnostics.ts
6582
- var DiagnosticCollector = class {
6583
- items = [];
6584
- error(code, message, resource) {
6585
- this.items.push({ severity: "error", code, message, resource });
6586
- }
6587
- warning(code, message, resource) {
6588
- this.items.push({ severity: "warning", code, message, resource });
6589
- }
6590
- info(code, message, resource) {
6591
- this.items.push({ severity: "info", code, message, resource });
6592
- }
6593
- hasErrors() {
6594
- return this.items.some((d) => d.severity === "error");
6595
- }
6596
- getAll() {
6597
- return [...this.items];
6598
- }
6599
- format() {
6600
- if (this.items.length === 0) return "";
6601
- const lines = [];
6602
- for (const d of this.items) {
6603
- const icon = severityIcon(d.severity);
6604
- const addr = d.resource ? ` ${d.resource.type}.${d.resource.name} (${d.resource.provider})` : "";
6605
- lines.push(`${icon} ${d.code}`);
6606
- if (addr) lines.push(` Resource:${addr}`);
6607
- lines.push(` ${d.message}`);
6608
- lines.push("");
6609
- }
6610
- return lines.join("\n");
6611
- }
6612
- };
6613
- function severityIcon(s) {
6614
- switch (s) {
6615
- case "error":
6616
- return "\u2717";
6617
- case "warning":
6618
- return "\u26A0";
6619
- case "info":
6620
- return "\u2139";
6621
- }
7352
+ // src/internal/core/agent-materialization.ts
7353
+ function resolveAgentMaterialization(provider, agent) {
7354
+ const mode = agent.delivery?.[provider]?.type ?? "managed";
7355
+ if (mode === "managed") return { resourceType: "agent", mode };
7356
+ return { resourceType: "template", mode };
6622
7357
  }
6623
7358
 
6624
- // src/internal/validation/bailian.ts
6625
- function findMissingBailianMcpToolConfigs(config, providerName = "bailian") {
6626
- if (providerName !== "bailian") return [];
6627
- const missing = [];
6628
- for (const [agentName, agent] of Object.entries(config.agents ?? {})) {
6629
- if (!agentTargetsProvider(config, agent.provider, providerName)) continue;
6630
- const configuredToolServers = new Set((agent.tools?.mcp ?? []).map((tool) => tool.mcp_server_name));
6631
- for (const server of agent.mcp_servers ?? []) {
6632
- if (!configuredToolServers.has(server.name)) {
6633
- missing.push({ agentName, serverName: server.name });
6634
- }
7359
+ // src/internal/graph/dependency.ts
7360
+ function collectDependencyClosure(graph, roots) {
7361
+ const selected = /* @__PURE__ */ new Map();
7362
+ function visit(address) {
7363
+ const key = addressKey(address);
7364
+ if (selected.has(key)) return;
7365
+ selected.set(key, graph.nodes.get(key) ?? address);
7366
+ for (const dependencyKey of graph.edges.get(key) ?? []) {
7367
+ const dependency = graph.nodes.get(dependencyKey);
7368
+ if (dependency) visit(dependency);
6635
7369
  }
6636
7370
  }
6637
- return missing;
7371
+ for (const root of roots) visit(root);
7372
+ return [...selected.values()];
7373
+ }
7374
+ function buildDependencyGraph(config, targetProviders) {
7375
+ const nodes = /* @__PURE__ */ new Map();
7376
+ const edges = /* @__PURE__ */ new Map();
7377
+ function addNode(addr) {
7378
+ const key = addressKey(addr);
7379
+ nodes.set(key, addr);
7380
+ if (!edges.has(key)) edges.set(key, /* @__PURE__ */ new Set());
7381
+ }
7382
+ function addEdge(from, to) {
7383
+ const fromKey = addressKey(from);
7384
+ const toKey = addressKey(to);
7385
+ edges.get(fromKey)?.add(toKey);
7386
+ }
7387
+ for (const provider of targetProviders) {
7388
+ const def = getProvider(provider);
7389
+ const caps = def?.capabilities;
7390
+ if (config.environments) {
7391
+ for (const name of Object.keys(config.environments)) {
7392
+ const decl = config.environments[name];
7393
+ if (decl.provider && decl.provider !== provider) continue;
7394
+ addNode({ type: "environment", name, provider });
7395
+ }
7396
+ }
7397
+ if (config.memory_stores) {
7398
+ for (const name of Object.keys(config.memory_stores)) {
7399
+ const decl = config.memory_stores[name];
7400
+ if (decl.provider && decl.provider !== provider) continue;
7401
+ if (!isSupported(caps, "memory_store")) continue;
7402
+ addNode({ type: "memory_store", name, provider });
7403
+ }
7404
+ }
7405
+ if (config.vaults) {
7406
+ for (const name of Object.keys(config.vaults)) {
7407
+ const decl = config.vaults[name];
7408
+ if (decl.provider && decl.provider !== provider) continue;
7409
+ addNode({ type: "vault", name, provider });
7410
+ }
7411
+ }
7412
+ if (config.skills) {
7413
+ for (const name of Object.keys(config.skills)) {
7414
+ const decl = config.skills[name];
7415
+ if (decl.provider && decl.provider !== provider) continue;
7416
+ addNode({ type: "skill", name, provider });
7417
+ }
7418
+ }
7419
+ if (config.files) {
7420
+ for (const name of Object.keys(config.files)) {
7421
+ const decl = config.files[name];
7422
+ if (decl.provider && decl.provider !== provider) continue;
7423
+ addNode({ type: "file", name, provider });
7424
+ }
7425
+ }
7426
+ if (config.identities && isSupported(caps, "identity")) {
7427
+ for (const name of Object.keys(config.identities)) {
7428
+ const decl = config.identities[name];
7429
+ if (decl.provider && decl.provider !== provider) continue;
7430
+ addNode({ type: "identity", name, provider });
7431
+ }
7432
+ }
7433
+ if (config.agents) {
7434
+ for (const name of Object.keys(config.agents)) {
7435
+ const decl = config.agents[name];
7436
+ if (decl.provider && decl.provider !== provider) continue;
7437
+ const materialization = resolveAgentMaterialization(provider, decl);
7438
+ const agentAddr = { type: materialization.resourceType, name, provider };
7439
+ addNode(agentAddr);
7440
+ if ((decl.default_memory_store || decl.memory_stores?.length) && materialization.resourceType === "template") {
7441
+ const identityName = config.defaults?.identity;
7442
+ if (identityName) {
7443
+ const identityAddr = { type: "identity", name: identityName, provider };
7444
+ if (nodes.has(addressKey(identityAddr))) addEdge(agentAddr, identityAddr);
7445
+ }
7446
+ }
7447
+ if (decl.environment && config.environments?.[decl.environment]) {
7448
+ const envAddr = {
7449
+ type: "environment",
7450
+ name: decl.environment,
7451
+ provider
7452
+ };
7453
+ if (nodes.has(addressKey(envAddr))) {
7454
+ addEdge(agentAddr, envAddr);
7455
+ }
7456
+ }
7457
+ if (decl.skills) {
7458
+ for (const skillRef of decl.skills) {
7459
+ if (typeof skillRef !== "string") continue;
7460
+ const skillName = skillRef;
7461
+ const skillAddr = { type: "skill", name: skillName, provider };
7462
+ if (nodes.has(addressKey(skillAddr))) {
7463
+ addEdge(agentAddr, skillAddr);
7464
+ }
7465
+ }
7466
+ }
7467
+ if (decl.vault) {
7468
+ const vaultAddr = { type: "vault", name: decl.vault, provider };
7469
+ if (nodes.has(addressKey(vaultAddr))) {
7470
+ addEdge(agentAddr, vaultAddr);
7471
+ }
7472
+ }
7473
+ if (decl.files) {
7474
+ for (const fileName of decl.files) {
7475
+ const fileAddr = { type: "file", name: fileName, provider };
7476
+ if (nodes.has(addressKey(fileAddr))) addEdge(agentAddr, fileAddr);
7477
+ }
7478
+ }
7479
+ if (decl.memory_stores) {
7480
+ for (const msName of decl.memory_stores) {
7481
+ const msAddr = {
7482
+ type: "memory_store",
7483
+ name: msName,
7484
+ provider
7485
+ };
7486
+ if (nodes.has(addressKey(msAddr))) {
7487
+ addEdge(agentAddr, msAddr);
7488
+ }
7489
+ }
7490
+ }
7491
+ if (decl.multiagent && isSupported(caps, "multiagent")) {
7492
+ for (const subName of decl.multiagent.agents) {
7493
+ const subDecl = config.agents[subName];
7494
+ const subType = subDecl ? resolveAgentMaterialization(provider, subDecl).resourceType : "agent";
7495
+ const subAddr = { type: subType, name: subName, provider };
7496
+ addEdge(agentAddr, subAddr);
7497
+ }
7498
+ }
7499
+ }
7500
+ }
7501
+ if (config.deployments) {
7502
+ for (const name of Object.keys(config.deployments)) {
7503
+ const decl = config.deployments[name];
7504
+ if (decl.provider && decl.provider !== provider) continue;
7505
+ const depAddr = { type: "deployment", name, provider };
7506
+ addNode(depAddr);
7507
+ const agentDecl = config.agents?.[decl.agent];
7508
+ const agentType = agentDecl ? resolveAgentMaterialization(provider, agentDecl).resourceType : "agent";
7509
+ const agentAddr = { type: agentType, name: decl.agent, provider };
7510
+ if (nodes.has(addressKey(agentAddr))) addEdge(depAddr, agentAddr);
7511
+ if (decl.environment) {
7512
+ const envAddr = { type: "environment", name: decl.environment, provider };
7513
+ if (nodes.has(addressKey(envAddr))) addEdge(depAddr, envAddr);
7514
+ }
7515
+ if (decl.vaults) {
7516
+ for (const vName of decl.vaults) {
7517
+ const vAddr = { type: "vault", name: vName, provider };
7518
+ if (nodes.has(addressKey(vAddr))) addEdge(depAddr, vAddr);
7519
+ }
7520
+ }
7521
+ if (decl.memory_stores) {
7522
+ for (const msName of decl.memory_stores) {
7523
+ const msAddr = { type: "memory_store", name: msName, provider };
7524
+ if (nodes.has(addressKey(msAddr))) addEdge(depAddr, msAddr);
7525
+ }
7526
+ }
7527
+ if (decl.resources) {
7528
+ for (const r of decl.resources) {
7529
+ if (r.type === "memory_store") {
7530
+ const msAddr = { type: "memory_store", name: r.memory_store, provider };
7531
+ if (nodes.has(addressKey(msAddr))) addEdge(depAddr, msAddr);
7532
+ }
7533
+ }
7534
+ }
7535
+ }
7536
+ }
7537
+ if (config.channels && isSupported(caps, "channel")) {
7538
+ for (const name of Object.keys(config.channels)) {
7539
+ const decl = config.channels[name];
7540
+ if (decl.provider && decl.provider !== provider) continue;
7541
+ const channelAddr = { type: "channel", name, provider };
7542
+ addNode(channelAddr);
7543
+ if (decl.mode === "pairing" || !decl.agent) continue;
7544
+ const agentDecl = config.agents?.[decl.agent];
7545
+ const agentType = agentDecl ? resolveAgentMaterialization(provider, agentDecl).resourceType : "agent";
7546
+ const agentAddr = { type: agentType, name: decl.agent, provider };
7547
+ if (nodes.has(addressKey(agentAddr))) addEdge(channelAddr, agentAddr);
7548
+ const identityName = decl.identity ?? config.defaults?.identity;
7549
+ if (identityName) {
7550
+ const identityAddr = { type: "identity", name: identityName, provider };
7551
+ if (nodes.has(addressKey(identityAddr))) addEdge(channelAddr, identityAddr);
7552
+ }
7553
+ }
7554
+ }
7555
+ }
7556
+ return { nodes, edges };
7557
+ }
7558
+ function topologicalSort(graph) {
7559
+ const visited = /* @__PURE__ */ new Set();
7560
+ const sorted = [];
7561
+ const visiting = /* @__PURE__ */ new Set();
7562
+ function visit(key) {
7563
+ if (visited.has(key)) return;
7564
+ if (visiting.has(key)) {
7565
+ throw new UserError(`Circular dependency detected involving: ${key}`);
7566
+ }
7567
+ visiting.add(key);
7568
+ const deps = graph.edges.get(key) ?? /* @__PURE__ */ new Set();
7569
+ for (const dep of deps) {
7570
+ visit(dep);
7571
+ }
7572
+ visiting.delete(key);
7573
+ visited.add(key);
7574
+ sorted.push(graph.nodes.get(key));
7575
+ }
7576
+ for (const key of graph.nodes.keys()) {
7577
+ visit(key);
7578
+ }
7579
+ return sorted;
7580
+ }
7581
+
7582
+ // src/internal/diagnostics/diagnostics.ts
7583
+ var DiagnosticCollector = class {
7584
+ items = [];
7585
+ error(code, message, resource) {
7586
+ this.items.push({ severity: "error", code, message, resource });
7587
+ }
7588
+ warning(code, message, resource) {
7589
+ this.items.push({ severity: "warning", code, message, resource });
7590
+ }
7591
+ info(code, message, resource) {
7592
+ this.items.push({ severity: "info", code, message, resource });
7593
+ }
7594
+ hasErrors() {
7595
+ return this.items.some((d) => d.severity === "error");
7596
+ }
7597
+ getAll() {
7598
+ return [...this.items];
7599
+ }
7600
+ format() {
7601
+ if (this.items.length === 0) return "";
7602
+ const lines = [];
7603
+ for (const d of this.items) {
7604
+ const icon = severityIcon(d.severity);
7605
+ const addr = d.resource ? ` ${d.resource.type}.${d.resource.name} (${d.resource.provider})` : "";
7606
+ lines.push(`${icon} ${d.code}`);
7607
+ if (addr) lines.push(` Resource:${addr}`);
7608
+ lines.push(` ${d.message}`);
7609
+ lines.push("");
7610
+ }
7611
+ return lines.join("\n");
7612
+ }
7613
+ };
7614
+ function severityIcon(s) {
7615
+ switch (s) {
7616
+ case "error":
7617
+ return "\u2717";
7618
+ case "warning":
7619
+ return "\u26A0";
7620
+ case "info":
7621
+ return "\u2139";
7622
+ }
7623
+ }
7624
+
7625
+ // src/internal/validation/bailian.ts
7626
+ function findMissingBailianMcpToolConfigs(config, providerName = "bailian") {
7627
+ if (providerName !== "bailian") return [];
7628
+ const missing = [];
7629
+ for (const [agentName, agent] of Object.entries(config.agents ?? {})) {
7630
+ if (!agentTargetsProvider(config, agent.provider, providerName)) continue;
7631
+ const configuredToolServers = new Set((agent.tools?.mcp ?? []).map((tool) => tool.mcp_server_name));
7632
+ for (const server of agent.mcp_servers ?? []) {
7633
+ if (!configuredToolServers.has(server.name)) {
7634
+ missing.push({ agentName, serverName: server.name });
7635
+ }
7636
+ }
7637
+ }
7638
+ return missing;
6638
7639
  }
6639
7640
  function agentTargetsProvider(config, agentProvider, providerName) {
6640
7641
  if (agentProvider) return agentProvider === providerName;
@@ -6671,6 +7672,7 @@ function collectReferenceDiagnostics(config, diagnostics) {
6671
7672
  const skillNames = new Set(Object.keys(config.skills ?? {}));
6672
7673
  const vaultNames = new Set(Object.keys(config.vaults ?? {}));
6673
7674
  const memoryNames = new Set(Object.keys(config.memory_stores ?? {}));
7675
+ const fileNames = new Set(Object.keys(config.files ?? {}));
6674
7676
  const agentNames = new Set(Object.keys(config.agents ?? {}));
6675
7677
  const identityNames = new Set(Object.keys(config.identities ?? {}));
6676
7678
  if (config.defaults?.identity && !identityNames.has(config.defaults.identity)) {
@@ -6698,6 +7700,11 @@ function collectReferenceDiagnostics(config, diagnostics) {
6698
7700
  if (agent.vault && !vaultNames.has(agent.vault)) {
6699
7701
  diagnostics.error("config.agent.vault.unknown", `agent.${name}: references unknown vault '${agent.vault}'`);
6700
7702
  }
7703
+ for (const file of agent.files ?? []) {
7704
+ if (!fileNames.has(file)) {
7705
+ diagnostics.error("config.agent.file.unknown", `agent.${name}: references unknown file '${file}'`);
7706
+ }
7707
+ }
6701
7708
  for (const memory of agent.memory_stores ?? []) {
6702
7709
  if (!memoryNames.has(memory)) {
6703
7710
  diagnostics.error(
@@ -6729,7 +7736,10 @@ function collectReferenceDiagnostics(config, diagnostics) {
6729
7736
  }
6730
7737
  }
6731
7738
  for (const [name, channel] of Object.entries(config.channels ?? {})) {
6732
- if (!agentNames.has(channel.agent)) {
7739
+ if (channel.mode === "pairing") continue;
7740
+ if (!channel.agent) {
7741
+ diagnostics.error("config.channel.agent.required", `channel.${name}: fixed-mode channels require agent`);
7742
+ } else if (!agentNames.has(channel.agent)) {
6733
7743
  diagnostics.error("config.channel.agent.unknown", `channel.${name}: references unknown agent '${channel.agent}'`);
6734
7744
  }
6735
7745
  const identity = channel.identity ?? config.defaults?.identity;
@@ -6757,6 +7767,37 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6757
7767
  continue;
6758
7768
  }
6759
7769
  const caps = def.capabilities;
7770
+ for (const [name, environment] of Object.entries(config.environments ?? {})) {
7771
+ if (environment.provider && environment.provider !== providerName) continue;
7772
+ if (environment.environment_id) continue;
7773
+ const address = { type: "environment", name, provider: providerName };
7774
+ if (environment.config.setup_script !== void 0 && providerName !== "qoder") {
7775
+ diagnostics.error(
7776
+ `${providerName}.environment.setup_script.unsupported`,
7777
+ `environment.${name}: provider '${providerName}' does not support setup_script; remove it or pin this environment to qoder.`,
7778
+ address
7779
+ );
7780
+ }
7781
+ if (providerName === "qoder") {
7782
+ if (environment.config.type === "self_hosted" && (environment.config.networking !== void 0 || environment.config.packages !== void 0)) {
7783
+ diagnostics.error(
7784
+ "qoder.environment.self_hosted.config.unsupported",
7785
+ `environment.${name}: Qoder self_hosted environments accept only config.type and config.setup_script; remove networking and packages.`,
7786
+ address
7787
+ );
7788
+ }
7789
+ const unsupported = ["cargo", "gem", "go"].filter(
7790
+ (key) => (environment.config.packages?.[key]?.length ?? 0) > 0
7791
+ );
7792
+ if (unsupported.length > 0) {
7793
+ diagnostics.error(
7794
+ "qoder.environment.packages.unsupported",
7795
+ `environment.${name}: Qoder accepts only apt, npm, and pip package declarations; remove ${unsupported.join(", ")} or install them from setup_script.`,
7796
+ address
7797
+ );
7798
+ }
7799
+ }
7800
+ }
6760
7801
  for (const [name, identity] of Object.entries(config.identities ?? {})) {
6761
7802
  if (identity.provider && identity.provider !== providerName) continue;
6762
7803
  if (!isSupported(caps, "identity")) {
@@ -6778,29 +7819,31 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6778
7819
  continue;
6779
7820
  }
6780
7821
  if (providerName === "qoder") {
6781
- const agent = config.agents?.[channel.agent];
6782
- if (agent?.provider && agent.provider !== providerName) {
6783
- diagnostics.error(
6784
- "config.channel.agent.provider_mismatch",
6785
- `channel.${name}: agent '${channel.agent}' is pinned to provider '${agent.provider}'.`,
6786
- { type: "channel", name, provider: providerName }
6787
- );
6788
- }
6789
- const identityName = channel.identity ?? config.defaults?.identity;
6790
- const identity = identityName ? config.identities?.[identityName] : void 0;
6791
- if (identity?.provider && identity.provider !== providerName) {
6792
- diagnostics.error(
6793
- "config.channel.identity.provider_mismatch",
6794
- `channel.${name}: identity '${identityName}' is pinned to provider '${identity.provider}'.`,
6795
- { type: "channel", name, provider: providerName }
6796
- );
6797
- }
6798
- if (agent && agent.delivery?.qoder?.type !== "forward") {
6799
- diagnostics.error(
6800
- "qoder.channel.forward_template.required",
6801
- `channel.${name}: Qoder Channels require agent '${channel.agent}' to use delivery.qoder.type: forward.`,
6802
- { type: "channel", name, provider: providerName }
6803
- );
7822
+ if (channel.mode !== "pairing" && channel.agent) {
7823
+ const agent = config.agents?.[channel.agent];
7824
+ if (agent?.provider && agent.provider !== providerName) {
7825
+ diagnostics.error(
7826
+ "config.channel.agent.provider_mismatch",
7827
+ `channel.${name}: agent '${channel.agent}' is pinned to provider '${agent.provider}'.`,
7828
+ { type: "channel", name, provider: providerName }
7829
+ );
7830
+ }
7831
+ const identityName = channel.identity ?? config.defaults?.identity;
7832
+ const identity = identityName ? config.identities?.[identityName] : void 0;
7833
+ if (identity?.provider && identity.provider !== providerName) {
7834
+ diagnostics.error(
7835
+ "config.channel.identity.provider_mismatch",
7836
+ `channel.${name}: identity '${identityName}' is pinned to provider '${identity.provider}'.`,
7837
+ { type: "channel", name, provider: providerName }
7838
+ );
7839
+ }
7840
+ if (agent && agent.delivery?.qoder?.type !== "forward") {
7841
+ diagnostics.error(
7842
+ "qoder.channel.forward_template.required",
7843
+ `channel.${name}: Qoder Channels require agent '${channel.agent}' to use delivery.qoder.type: forward.`,
7844
+ { type: "channel", name, provider: providerName }
7845
+ );
7846
+ }
6804
7847
  }
6805
7848
  const requiredCredentials = {
6806
7849
  dingtalk: ["client_id", "client_secret"],
@@ -6831,6 +7874,46 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6831
7874
  }
6832
7875
  }
6833
7876
  }
7877
+ if (providerName === "qoder") {
7878
+ const domains = /* @__PURE__ */ new Map();
7879
+ for (const agent of Object.values(config.agents ?? {})) {
7880
+ if (agent.provider && agent.provider !== providerName) continue;
7881
+ const mode = agent.delivery?.qoder?.type === "forward" ? "forward" : "managed";
7882
+ const refs = [
7883
+ ...agent.environment && !config.environments?.[agent.environment]?.environment_id ? [`environment:${agent.environment}`] : [],
7884
+ ...(agent.skills ?? []).flatMap(
7885
+ (skill) => typeof skill === "string" ? [`skill:${skill}`] : skill.type === "custom" ? [`skill:${skill.skill_id}`] : []
7886
+ ),
7887
+ ...agent.vault ? [`vault:${agent.vault}`] : [],
7888
+ ...(agent.memory_stores ?? []).map((store) => `memory_store:${store}`),
7889
+ ...(agent.files ?? []).map((file) => `file:${file}`)
7890
+ ];
7891
+ for (const ref of refs) {
7892
+ const modes = domains.get(ref) ?? /* @__PURE__ */ new Set();
7893
+ modes.add(mode);
7894
+ domains.set(ref, modes);
7895
+ }
7896
+ }
7897
+ for (const [ref, modes] of domains) {
7898
+ if (modes.size < 2) continue;
7899
+ const [type, name] = ref.split(":");
7900
+ diagnostics.error(
7901
+ `qoder.${type}.delivery_domain.conflict`,
7902
+ `${type}.${name}: referenced by both Managed and Forward agents; declare separate resources because Qoder uses different API domains.`,
7903
+ { type, name, provider: providerName }
7904
+ );
7905
+ }
7906
+ }
7907
+ for (const [name, agent] of Object.entries(config.agents ?? {})) {
7908
+ if (agent.provider && agent.provider !== providerName) continue;
7909
+ if (agent.files?.length && (providerName !== "qoder" || agent.delivery?.qoder?.type !== "forward")) {
7910
+ diagnostics.error(
7911
+ "config.agent.files.unsupported",
7912
+ `agent.${name}: files are supported only by Qoder Forward Templates.`,
7913
+ { type: resolveAgentMaterialization(providerName, agent).resourceType, name, provider: providerName }
7914
+ );
7915
+ }
7916
+ }
6834
7917
  for (const [name, agent] of Object.entries(config.agents ?? {})) {
6835
7918
  if (agent.provider && agent.provider !== providerName) continue;
6836
7919
  const delivery = agent.delivery?.[providerName]?.type ?? "managed";
@@ -6871,6 +7954,44 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6871
7954
  address
6872
7955
  );
6873
7956
  }
7957
+ if (delivery !== "forward" && agent.managed_tool_config) {
7958
+ diagnostics.error(
7959
+ `${providerName}.agent.managed_tool_config.forward_required`,
7960
+ `agent.${name}: managed_tool_config applies to Forward Templates; set delivery.${providerName}.type: forward or remove it.`,
7961
+ address
7962
+ );
7963
+ }
7964
+ if (agent.default_memory_store) {
7965
+ if (providerName !== "qoder" || delivery !== "forward") {
7966
+ diagnostics.error(
7967
+ `${providerName}.agent.default_memory_store.forward_required`,
7968
+ `agent.${name}: default_memory_store is supported only by Qoder Forward delivery.`,
7969
+ address
7970
+ );
7971
+ } else if (!config.defaults?.identity) {
7972
+ diagnostics.error(
7973
+ "qoder.template.default_memory_store.identity.required",
7974
+ `agent.${name}: default_memory_store requires defaults.identity to select the owning Forward Identity.`,
7975
+ { type: "template", name, provider: providerName }
7976
+ );
7977
+ } else {
7978
+ const identity = config.identities?.[config.defaults.identity];
7979
+ if (identity?.provider && identity.provider !== providerName) {
7980
+ diagnostics.error(
7981
+ "qoder.template.default_memory_store.identity.provider_mismatch",
7982
+ `agent.${name}: defaults.identity '${config.defaults.identity}' is pinned to provider '${identity.provider}'.`,
7983
+ { type: "template", name, provider: providerName }
7984
+ );
7985
+ }
7986
+ if (agent.default_memory_store.delete_on_destroy && identity?.identity_id) {
7987
+ diagnostics.error(
7988
+ "qoder.template.default_memory_store.delete.external_identity",
7989
+ `agent.${name}: delete_on_destroy requires an OpenCMA-managed Identity because an external Identity keeps the default Memory Store mounted.`,
7990
+ { type: "template", name, provider: providerName }
7991
+ );
7992
+ }
7993
+ }
7994
+ }
6874
7995
  if (delivery === "forward" && !isSupported(caps, "template")) {
6875
7996
  diagnostics.error(
6876
7997
  `${providerName}.agent.delivery.forward.unsupported`,
@@ -6886,10 +8007,10 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6886
8007
  { type: "template", name, provider: providerName }
6887
8008
  );
6888
8009
  }
6889
- if (agent.memory_stores?.length) {
8010
+ if (agent.memory_stores?.length && !config.defaults?.identity) {
6890
8011
  diagnostics.error(
6891
- "qoder.template.memory_store.unsupported",
6892
- `agent.${name}: memory_stores are not yet supported by Qoder Forward Template delivery.`,
8012
+ "qoder.template.memory_store.identity.required",
8013
+ `agent.${name}: Forward memory_stores require defaults.identity for the Identity/Template mount.`,
6893
8014
  { type: "template", name, provider: providerName }
6894
8015
  );
6895
8016
  }
@@ -6923,6 +8044,68 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6923
8044
  }
6924
8045
  }
6925
8046
  }
8047
+ if (providerName === "bailian") {
8048
+ for (const [name, deployment] of Object.entries(config.deployments ?? {})) {
8049
+ if (deployment.provider && deployment.provider !== providerName) continue;
8050
+ const addr = {
8051
+ type: "deployment",
8052
+ name,
8053
+ provider: providerName
8054
+ };
8055
+ if (deployment.initial_events?.some((event) => event.type === "user.define_outcome")) {
8056
+ diagnostics.warning(
8057
+ `${providerName}.deployment.define_outcome_unsupported`,
8058
+ "Outcome rubrics (user.define_outcome) are dropped from the Bailian deployment payload; the run executes without rubric grading.",
8059
+ addr
8060
+ );
8061
+ }
8062
+ if (!deployment.initial_events?.some((event) => event.type === "user.message" || event.type === "system.message")) {
8063
+ diagnostics.error(
8064
+ `${providerName}.deployment.initial_events.message_required`,
8065
+ `deployment.${name}: Bailian requires at least one user.message or system.message initial event; user.define_outcome events are dropped.`,
8066
+ addr
8067
+ );
8068
+ }
8069
+ if (deployment.resources?.some((resource) => resource.type === "github_repository")) {
8070
+ diagnostics.warning(
8071
+ `${providerName}.deployment.github_repository_unsupported`,
8072
+ "Bailian deployment resources accept files only; github_repository resources are dropped. Clone the repository inside the session instead.",
8073
+ addr
8074
+ );
8075
+ }
8076
+ const mountPrefix = providerMountPrefix(providerName);
8077
+ const normalizedMountPaths = /* @__PURE__ */ new Set();
8078
+ for (const resource of deployment.resources ?? []) {
8079
+ if (resource.type !== "file") continue;
8080
+ if (!resource.mount_path?.trim()) {
8081
+ diagnostics.error(
8082
+ `${providerName}.deployment.file.mount_path.required`,
8083
+ `deployment.${name}: Bailian file resources require mount_path.`,
8084
+ addr
8085
+ );
8086
+ continue;
8087
+ }
8088
+ if (mountPrefix && resource.mount_path.startsWith("/") && resource.mount_path !== mountPrefix && !resource.mount_path.startsWith(`${mountPrefix}/`)) {
8089
+ diagnostics.error(
8090
+ `${providerName}.deployment.file.mount_path.invalid`,
8091
+ `deployment.${name}: Bailian file mount_path must start with '${mountPrefix}/'.`,
8092
+ addr
8093
+ );
8094
+ continue;
8095
+ }
8096
+ const normalizedMountPath = resolveSandboxMountPath(providerName, resource.mount_path);
8097
+ if (normalizedMountPaths.has(normalizedMountPath)) {
8098
+ diagnostics.error(
8099
+ `${providerName}.deployment.file.mount_path.duplicate`,
8100
+ `deployment.${name}: Bailian file mount_path '${normalizedMountPath}' is duplicated after normalization.`,
8101
+ addr
8102
+ );
8103
+ } else {
8104
+ normalizedMountPaths.add(normalizedMountPath);
8105
+ }
8106
+ }
8107
+ }
8108
+ }
6926
8109
  if (providerName !== "qoder") {
6927
8110
  for (const [name, env] of Object.entries(config.environments ?? {})) {
6928
8111
  if (env.environment_id) continue;
@@ -6935,6 +8118,20 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6935
8118
  }
6936
8119
  }
6937
8120
  for (const [name, agent] of Object.entries(config.agents ?? {})) {
8121
+ if (agent.environment_variables && (!agent.provider || agent.provider === providerName)) {
8122
+ diagnostics.error(
8123
+ `${providerName}.agent.environment_variables.unsupported`,
8124
+ `agent.${name}: environment_variables is supported only by Qoder; remove it or pin this agent to qoder.`,
8125
+ { type: "agent", name, provider: providerName }
8126
+ );
8127
+ }
8128
+ if (agent.managed_tool_config && (!agent.provider || agent.provider === providerName)) {
8129
+ diagnostics.error(
8130
+ `${providerName}.agent.managed_tool_config.unsupported`,
8131
+ `agent.${name}: managed_tool_config is supported only by Qoder; remove it or pin this agent to qoder.`,
8132
+ { type: "agent", name, provider: providerName }
8133
+ );
8134
+ }
6938
8135
  if (agent.tunnel && (!agent.provider || agent.provider === providerName)) {
6939
8136
  diagnostics.error(
6940
8137
  `${providerName}.agent.tunnel.unsupported`,
@@ -6995,7 +8192,11 @@ function collectProviderCapabilities(config, providers, diagnostics) {
6995
8192
  if (config.deployments && caps.deployment.tier === "emulated") {
6996
8193
  for (const [name, dep] of Object.entries(config.deployments)) {
6997
8194
  if (dep.provider && dep.provider !== providerName) continue;
6998
- const addr = { type: "deployment", name, provider: providerName };
8195
+ const addr = {
8196
+ type: "deployment",
8197
+ name,
8198
+ provider: providerName
8199
+ };
6999
8200
  if (dep.schedule) {
7000
8201
  diagnostics.warning(
7001
8202
  `${providerName}.deployment.schedule_unsupported`,
@@ -7014,238 +8215,39 @@ function collectProviderCapabilities(config, providers, diagnostics) {
7014
8215
  diagnostics.warning(
7015
8216
  `${providerName}.deployment.github_repository_unsupported`,
7016
8217
  "github_repository resources are not provisioned on this provider; clone the repository inside the session instead.",
7017
- addr
7018
- );
7019
- }
7020
- if (dep.resources?.some((r) => r.type === "memory_store" && (r.access === "read_only" || r.instructions))) {
7021
- diagnostics.warning(
7022
- `${providerName}.deployment.memory_store_options_unsupported`,
7023
- "Per-resource memory_store access/instructions are not honored on this provider; the store is attached with default access.",
7024
- addr
7025
- );
7026
- }
7027
- }
7028
- }
7029
- }
7030
- }
7031
-
7032
- // src/internal/core/agent-materialization.ts
7033
- function resolveAgentMaterialization(provider, agent) {
7034
- const mode = agent.delivery?.[provider]?.type ?? "managed";
7035
- if (mode === "managed") return { resourceType: "agent", mode };
7036
- return { resourceType: "template", mode };
7037
- }
7038
-
7039
- // src/internal/graph/dependency.ts
7040
- function buildDependencyGraph(config, targetProviders) {
7041
- const nodes = /* @__PURE__ */ new Map();
7042
- const edges = /* @__PURE__ */ new Map();
7043
- function addNode(addr) {
7044
- const key = addressKey(addr);
7045
- nodes.set(key, addr);
7046
- if (!edges.has(key)) edges.set(key, /* @__PURE__ */ new Set());
7047
- }
7048
- function addEdge(from, to) {
7049
- const fromKey = addressKey(from);
7050
- const toKey = addressKey(to);
7051
- edges.get(fromKey)?.add(toKey);
7052
- }
7053
- for (const provider of targetProviders) {
7054
- const def = getProvider(provider);
7055
- const caps = def?.capabilities;
7056
- if (config.environments) {
7057
- for (const name of Object.keys(config.environments)) {
7058
- const decl = config.environments[name];
7059
- if (decl.provider && decl.provider !== provider) continue;
7060
- addNode({ type: "environment", name, provider });
7061
- }
7062
- }
7063
- if (config.memory_stores) {
7064
- for (const name of Object.keys(config.memory_stores)) {
7065
- const decl = config.memory_stores[name];
7066
- if (decl.provider && decl.provider !== provider) continue;
7067
- if (!isSupported(caps, "memory_store")) continue;
7068
- addNode({ type: "memory_store", name, provider });
7069
- }
7070
- }
7071
- if (config.vaults) {
7072
- for (const name of Object.keys(config.vaults)) {
7073
- const decl = config.vaults[name];
7074
- if (decl.provider && decl.provider !== provider) continue;
7075
- addNode({ type: "vault", name, provider });
7076
- }
7077
- }
7078
- if (config.skills) {
7079
- for (const name of Object.keys(config.skills)) {
7080
- const decl = config.skills[name];
7081
- if (decl.provider && decl.provider !== provider) continue;
7082
- addNode({ type: "skill", name, provider });
7083
- }
7084
- }
7085
- if (config.files) {
7086
- for (const name of Object.keys(config.files)) {
7087
- const decl = config.files[name];
7088
- if (decl.provider && decl.provider !== provider) continue;
7089
- addNode({ type: "file", name, provider });
7090
- }
7091
- }
7092
- if (config.identities && isSupported(caps, "identity")) {
7093
- for (const name of Object.keys(config.identities)) {
7094
- const decl = config.identities[name];
7095
- if (decl.provider && decl.provider !== provider) continue;
7096
- addNode({ type: "identity", name, provider });
7097
- }
7098
- }
7099
- if (config.agents) {
7100
- for (const name of Object.keys(config.agents)) {
7101
- const decl = config.agents[name];
7102
- if (decl.provider && decl.provider !== provider) continue;
7103
- const materialization = resolveAgentMaterialization(provider, decl);
7104
- const agentAddr = { type: materialization.resourceType, name, provider };
7105
- addNode(agentAddr);
7106
- if (decl.environment && config.environments?.[decl.environment]) {
7107
- const envAddr = {
7108
- type: "environment",
7109
- name: decl.environment,
7110
- provider
7111
- };
7112
- if (nodes.has(addressKey(envAddr))) {
7113
- addEdge(agentAddr, envAddr);
7114
- }
7115
- }
7116
- if (decl.skills) {
7117
- for (const skillRef of decl.skills) {
7118
- if (typeof skillRef !== "string") continue;
7119
- const skillName = skillRef;
7120
- const skillAddr = { type: "skill", name: skillName, provider };
7121
- if (nodes.has(addressKey(skillAddr))) {
7122
- addEdge(agentAddr, skillAddr);
7123
- }
7124
- }
7125
- }
7126
- if (decl.vault) {
7127
- const vaultAddr = { type: "vault", name: decl.vault, provider };
7128
- if (nodes.has(addressKey(vaultAddr))) {
7129
- addEdge(agentAddr, vaultAddr);
7130
- }
7131
- }
7132
- if (decl.memory_stores) {
7133
- for (const msName of decl.memory_stores) {
7134
- const msAddr = {
7135
- type: "memory_store",
7136
- name: msName,
7137
- provider
7138
- };
7139
- if (nodes.has(addressKey(msAddr))) {
7140
- addEdge(agentAddr, msAddr);
7141
- }
7142
- }
7143
- }
7144
- if (decl.multiagent && isSupported(caps, "multiagent")) {
7145
- for (const subName of decl.multiagent.agents) {
7146
- const subDecl = config.agents[subName];
7147
- const subType = subDecl ? resolveAgentMaterialization(provider, subDecl).resourceType : "agent";
7148
- const subAddr = { type: subType, name: subName, provider };
7149
- addEdge(agentAddr, subAddr);
7150
- }
7151
- }
7152
- }
7153
- }
7154
- if (config.deployments) {
7155
- for (const name of Object.keys(config.deployments)) {
7156
- const decl = config.deployments[name];
7157
- if (decl.provider && decl.provider !== provider) continue;
7158
- const depAddr = { type: "deployment", name, provider };
7159
- addNode(depAddr);
7160
- const agentDecl = config.agents?.[decl.agent];
7161
- const agentType = agentDecl ? resolveAgentMaterialization(provider, agentDecl).resourceType : "agent";
7162
- const agentAddr = { type: agentType, name: decl.agent, provider };
7163
- if (nodes.has(addressKey(agentAddr))) addEdge(depAddr, agentAddr);
7164
- if (decl.environment) {
7165
- const envAddr = { type: "environment", name: decl.environment, provider };
7166
- if (nodes.has(addressKey(envAddr))) addEdge(depAddr, envAddr);
7167
- }
7168
- if (decl.vaults) {
7169
- for (const vName of decl.vaults) {
7170
- const vAddr = { type: "vault", name: vName, provider };
7171
- if (nodes.has(addressKey(vAddr))) addEdge(depAddr, vAddr);
7172
- }
7173
- }
7174
- if (decl.memory_stores) {
7175
- for (const msName of decl.memory_stores) {
7176
- const msAddr = { type: "memory_store", name: msName, provider };
7177
- if (nodes.has(addressKey(msAddr))) addEdge(depAddr, msAddr);
7178
- }
7179
- }
7180
- if (decl.resources) {
7181
- for (const r of decl.resources) {
7182
- if (r.type === "memory_store") {
7183
- const msAddr = { type: "memory_store", name: r.memory_store, provider };
7184
- if (nodes.has(addressKey(msAddr))) addEdge(depAddr, msAddr);
7185
- }
7186
- }
8218
+ addr
8219
+ );
7187
8220
  }
7188
- }
7189
- }
7190
- if (config.channels && isSupported(caps, "channel")) {
7191
- for (const name of Object.keys(config.channels)) {
7192
- const decl = config.channels[name];
7193
- if (decl.provider && decl.provider !== provider) continue;
7194
- const channelAddr = { type: "channel", name, provider };
7195
- addNode(channelAddr);
7196
- const agentDecl = config.agents?.[decl.agent];
7197
- const agentType = agentDecl ? resolveAgentMaterialization(provider, agentDecl).resourceType : "agent";
7198
- const agentAddr = { type: agentType, name: decl.agent, provider };
7199
- if (nodes.has(addressKey(agentAddr))) addEdge(channelAddr, agentAddr);
7200
- const identityName = decl.identity ?? config.defaults?.identity;
7201
- if (identityName) {
7202
- const identityAddr = { type: "identity", name: identityName, provider };
7203
- if (nodes.has(addressKey(identityAddr))) addEdge(channelAddr, identityAddr);
8221
+ if (dep.resources?.some((r) => r.type === "memory_store" && (r.access === "read_only" || r.instructions))) {
8222
+ diagnostics.warning(
8223
+ `${providerName}.deployment.memory_store_options_unsupported`,
8224
+ "Per-resource memory_store access/instructions are not honored on this provider; the store is attached with default access.",
8225
+ addr
8226
+ );
7204
8227
  }
7205
8228
  }
7206
8229
  }
7207
8230
  }
7208
- return { nodes, edges };
7209
- }
7210
- function topologicalSort(graph) {
7211
- const visited = /* @__PURE__ */ new Set();
7212
- const sorted = [];
7213
- const visiting = /* @__PURE__ */ new Set();
7214
- function visit(key) {
7215
- if (visited.has(key)) return;
7216
- if (visiting.has(key)) {
7217
- throw new UserError(`Circular dependency detected involving: ${key}`);
7218
- }
7219
- visiting.add(key);
7220
- const deps = graph.edges.get(key) ?? /* @__PURE__ */ new Set();
7221
- for (const dep of deps) {
7222
- visit(dep);
7223
- }
7224
- visiting.delete(key);
7225
- visited.add(key);
7226
- sorted.push(graph.nodes.get(key));
7227
- }
7228
- for (const key of graph.nodes.keys()) {
7229
- visit(key);
7230
- }
7231
- return sorted;
7232
8231
  }
7233
8232
 
7234
8233
  // src/internal/planner/planner.ts
7235
8234
  async function buildPlan(config, state, options = {}) {
8235
+ const scopedConfig = options.resourceAddresses ? selectProjectConfig(config, options.resourceAddresses) : config;
8236
+ const resourceKeys = options.resourceAddresses ? new Set(options.resourceAddresses.map(addressKey)) : void 0;
8237
+ const scopedState = resourceKeys ? { ...state, resources: state.resources.filter((resource) => resourceKeys.has(addressKey(resource.address))) } : state;
7236
8238
  const diagnostics = new DiagnosticCollector();
7237
8239
  const actions = [];
7238
- const targetProviders = options.providers ?? resolveTargetProviders(config);
7239
- collectReferenceDiagnostics(config, diagnostics);
7240
- collectProviderCapabilities(config, targetProviders, diagnostics);
7241
- const graph = buildDependencyGraph(config, targetProviders);
8240
+ const targetProviders = options.providers ?? resolveTargetProviders(scopedConfig);
8241
+ collectReferenceDiagnostics(scopedConfig, diagnostics);
8242
+ collectProviderCapabilities(scopedConfig, targetProviders, diagnostics);
8243
+ const graph = buildDependencyGraph(scopedConfig, targetProviders);
7242
8244
  const sorted = topologicalSort(graph);
7243
8245
  const stateIndex = /* @__PURE__ */ new Map();
7244
- for (const res of state.resources) {
8246
+ for (const res of scopedState.resources) {
7245
8247
  stateIndex.set(addressKey(res.address), res);
7246
8248
  }
7247
8249
  const remoteIdLookup = /* @__PURE__ */ new Map();
7248
- for (const res of state.resources) {
8250
+ for (const res of scopedState.resources) {
7249
8251
  remoteIdLookup.set(addressKey(res.address), res);
7250
8252
  }
7251
8253
  const hashStateLookup = { getResource: (addr) => remoteIdLookup.get(addressKey(addr)) };
@@ -7254,6 +8256,7 @@ async function buildPlan(config, state, options = {}) {
7254
8256
  const desiredHash = await computeResourceHash(address, config, options.configPath, hashStateLookup);
7255
8257
  const existing = stateIndex.get(key);
7256
8258
  const deps = getDependencies(address, graph);
8259
+ const needsNativeDeploymentMaterialization = address.type === "deployment" && existing?.remote_id === null && getProvider(address.provider)?.capabilities.deployment.tier === "native";
7257
8260
  if (address.type === "environment" && existing) {
7258
8261
  const envDecl = config.environments?.[address.name];
7259
8262
  if (existing.externally_managed && envDecl && !envDecl.environment_id) {
@@ -7305,6 +8308,17 @@ async function buildPlan(config, state, options = {}) {
7305
8308
  after: { content_hash: desiredHash },
7306
8309
  dependencies: deps
7307
8310
  });
8311
+ } else if (needsNativeDeploymentMaterialization) {
8312
+ actions.push({
8313
+ action: "update",
8314
+ address,
8315
+ driftKind: "none",
8316
+ readinessImpact: "blocking",
8317
+ reason: "Materialize legacy state as a native deployment",
8318
+ before: { content_hash: existing.desired_hash ?? existing.content_hash },
8319
+ after: { content_hash: desiredHash },
8320
+ dependencies: deps
8321
+ });
7308
8322
  } else if ((existing.desired_hash ?? existing.content_hash) !== desiredHash && existing.drift_status === "drifted") {
7309
8323
  const changedPaths = collectChangedPaths(address, config, existing, true);
7310
8324
  actions.push({
@@ -7377,8 +8391,106 @@ async function buildPlan(config, state, options = {}) {
7377
8391
  dependencies: replacement ? [replacement] : []
7378
8392
  });
7379
8393
  }
8394
+ coalesceChannelRenames(actions, scopedConfig, scopedState);
7380
8395
  return { actions, diagnostics: diagnostics.getAll() };
7381
8396
  }
8397
+ function selectProjectConfig(config, addresses) {
8398
+ const providers = new Set(addresses.map((address) => address.provider));
8399
+ const namesByType = /* @__PURE__ */ new Map();
8400
+ for (const address of addresses) {
8401
+ const names = namesByType.get(address.type) ?? /* @__PURE__ */ new Set();
8402
+ names.add(address.name);
8403
+ namesByType.set(address.type, names);
8404
+ }
8405
+ const pick = (record, names) => {
8406
+ if (!record || !names?.size) return void 0;
8407
+ const selected = Object.fromEntries(Object.entries(record).filter(([name]) => names.has(name)));
8408
+ return Object.keys(selected).length > 0 ? selected : void 0;
8409
+ };
8410
+ const agentNames = /* @__PURE__ */ new Set([...namesByType.get("agent") ?? [], ...namesByType.get("template") ?? []]);
8411
+ const selectedAgents = pick(config.agents, agentNames);
8412
+ const tunnelNames = /* @__PURE__ */ new Set();
8413
+ for (const agent of Object.values(selectedAgents ?? {})) {
8414
+ if (agent.tunnel) tunnelNames.add(agent.tunnel);
8415
+ }
8416
+ for (const deployment of Object.values(pick(config.deployments, namesByType.get("deployment")) ?? {})) {
8417
+ if (deployment.tunnel) tunnelNames.add(deployment.tunnel);
8418
+ }
8419
+ const identityNames = namesByType.get("identity");
8420
+ const selectedProviders = Object.fromEntries(
8421
+ Object.entries(config.providers).filter(([providerName]) => providers.has(providerName))
8422
+ );
8423
+ const defaultProvider = providers.size === 1 ? [...providers][0] : config.defaults?.provider;
8424
+ const defaultIdentity = config.defaults?.identity && identityNames?.has(config.defaults.identity) ? config.defaults.identity : void 0;
8425
+ return {
8426
+ ...config,
8427
+ providers: selectedProviders,
8428
+ defaults: defaultProvider || defaultIdentity ? { provider: defaultProvider, identity: defaultIdentity } : void 0,
8429
+ environments: pick(config.environments, namesByType.get("environment")),
8430
+ tunnels: pick(config.tunnels, tunnelNames),
8431
+ vaults: pick(config.vaults, namesByType.get("vault")),
8432
+ memory_stores: pick(config.memory_stores, namesByType.get("memory_store")),
8433
+ skills: pick(config.skills, namesByType.get("skill")),
8434
+ files: pick(config.files, namesByType.get("file")),
8435
+ identities: pick(config.identities, identityNames),
8436
+ agents: selectedAgents,
8437
+ channels: pick(config.channels, namesByType.get("channel")),
8438
+ deployments: pick(config.deployments, namesByType.get("deployment"))
8439
+ };
8440
+ }
8441
+ function coalesceChannelRenames(actions, config, state) {
8442
+ const creates = actions.filter((action) => action.action === "create" && action.address.type === "channel");
8443
+ const deletes = actions.filter((action) => action.action === "delete" && action.address.type === "channel");
8444
+ const stateByAddress = new Map(state.resources.map((resource) => [addressKey(resource.address), resource]));
8445
+ const matchedDeletes = /* @__PURE__ */ new Set();
8446
+ for (const create of creates) {
8447
+ const desiredType = config.channels?.[create.address.name]?.type;
8448
+ if (!desiredType) continue;
8449
+ const desiredFingerprint = computeReplacementFingerprint(create.address, config);
8450
+ const candidates = deletes.filter((deletion2) => {
8451
+ if (matchedDeletes.has(deletion2) || deletion2.address.provider !== create.address.provider) return false;
8452
+ const prior2 = stateByAddress.get(addressKey(deletion2.address));
8453
+ const snapshot = prior2?.remote_snapshot;
8454
+ if (snapshot?.channel_type !== desiredType) return false;
8455
+ return !prior2?.replacement_fingerprint || prior2.replacement_fingerprint === desiredFingerprint;
8456
+ });
8457
+ if (candidates.length !== 1) continue;
8458
+ const deletion = candidates[0];
8459
+ const prior = stateByAddress.get(addressKey(deletion.address));
8460
+ const competingCreates = creates.filter(
8461
+ (candidate) => candidate !== create && candidate.address.provider === create.address.provider && config.channels?.[candidate.address.name]?.type === desiredType && (!prior?.replacement_fingerprint || computeReplacementFingerprint(candidate.address, config) === prior.replacement_fingerprint)
8462
+ );
8463
+ if (competingCreates.length > 0) continue;
8464
+ create.action = "update";
8465
+ create.previousAddress = deletion.address;
8466
+ create.before = deletion.before;
8467
+ create.driftKind = "local";
8468
+ create.reason = `Channel key renamed from '${deletion.address.name}' (remote resource retained)`;
8469
+ protectRenamedChannelDependencies(actions, stateByAddress, deletion, create);
8470
+ matchedDeletes.add(deletion);
8471
+ }
8472
+ for (let index = actions.length - 1; index >= 0; index--) {
8473
+ if (matchedDeletes.has(actions[index])) actions.splice(index, 1);
8474
+ }
8475
+ }
8476
+ function protectRenamedChannelDependencies(actions, stateByAddress, deletion, replacement) {
8477
+ const prior = stateByAddress.get(addressKey(deletion.address));
8478
+ const snapshot = prior?.remote_snapshot;
8479
+ const referencedIds = new Set(
8480
+ [snapshot?.identity_id, snapshot?.template_id].filter((id) => typeof id === "string")
8481
+ );
8482
+ if (referencedIds.size === 0) return;
8483
+ for (const action of actions) {
8484
+ if (action.action !== "delete" || action.address.type !== "identity" && action.address.type !== "template" || action.address.provider !== replacement.address.provider) {
8485
+ continue;
8486
+ }
8487
+ const dependency = stateByAddress.get(addressKey(action.address));
8488
+ if (!dependency?.remote_id || !referencedIds.has(dependency.remote_id)) continue;
8489
+ if (!action.dependencies.some((address) => addressKey(address) === addressKey(replacement.address))) {
8490
+ action.dependencies.push(replacement.address);
8491
+ }
8492
+ }
8493
+ }
7382
8494
  function deliveryReplacementAddress(address, graph) {
7383
8495
  if (address.type !== "agent" && address.type !== "template") return void 0;
7384
8496
  const replacementType = address.type === "agent" ? "template" : "agent";
@@ -7405,6 +8517,9 @@ async function refreshState(state, providers, options = {}) {
7405
8517
  const errors = [];
7406
8518
  let dirty = false;
7407
8519
  for (const res of resources) {
8520
+ if (options.resourceKeys && !options.resourceKeys.has(addressKey(res.address))) {
8521
+ continue;
8522
+ }
7408
8523
  if (options.targetProviders && !options.targetProviders.includes(res.address.provider)) {
7409
8524
  continue;
7410
8525
  }
@@ -7467,7 +8582,7 @@ async function refreshState(state, providers, options = {}) {
7467
8582
  dirty = true;
7468
8583
  continue;
7469
8584
  }
7470
- const remote = await provider.findResource(res.address.type, res.address.name, res.remote_id);
8585
+ const remote = await provider.findResource(res.address.type, res.address.name, res.remote_id, res.api_mode);
7471
8586
  if (!remote) {
7472
8587
  if (!options.quiet) {
7473
8588
  emitRuntimeFeedback(options.onFeedback, {
@@ -7518,12 +8633,19 @@ async function refreshState(state, providers, options = {}) {
7518
8633
  }
7519
8634
 
7520
8635
  // src/internal/core/resource-runtime.ts
8636
+ async function planProjectWithStateBackend(input, options = {}) {
8637
+ return readProjectRuntime(input, (ctx) => planProjectContext(ctx, options));
8638
+ }
7521
8639
  async function syncProjectResourcesWithStateBackend(input, options = {}) {
7522
8640
  return writeProjectRuntime(input, async (ctx) => {
7523
8641
  const planned = await planProjectContext(ctx, options);
7524
8642
  if (options.refreshOnly) {
7525
8643
  return { planned };
7526
8644
  }
8645
+ if (options.mode === "create-only") {
8646
+ const errorDiagnostic = planned.plan.diagnostics.find((diagnostic) => diagnostic.severity === "error");
8647
+ if (errorDiagnostic) throw new UserError(errorDiagnostic.message);
8648
+ }
7527
8649
  return {
7528
8650
  planned,
7529
8651
  execution: await executePlannedProject(planned, {
@@ -7591,25 +8713,98 @@ async function importResource(ctx, address, remoteId, options = {}) {
7591
8713
  return resource;
7592
8714
  }
7593
8715
  async function planProjectContext(ctx, options = {}) {
7594
- const targetProviders = resolveTargetProviders2(options.provider);
8716
+ if (options.mode === "create-only" && !options.scope) {
8717
+ throw new UserError("Resource create-only mode requires an explicit resource scope.");
8718
+ }
8719
+ let targetProviders = resolveTargetProviders2(options.provider);
8720
+ if (!targetProviders && options.scope) {
8721
+ targetProviders = [...new Set(options.scope.roots.map((root) => root.provider))];
8722
+ }
8723
+ const selectedAddresses = options.scope ? resolvePlanScope(ctx, targetProviders ?? [], options.scope) : void 0;
8724
+ const resourceKeys = selectedAddresses ? new Set(selectedAddresses.map(addressKey)) : void 0;
7595
8725
  const refreshResult = options.refresh !== false && ctx.state.listResources().length > 0 ? await refreshState(ctx.state, ctx.providers, {
7596
8726
  targetProviders,
8727
+ resourceKeys,
7597
8728
  config: ctx.config,
7598
8729
  quiet: options.quiet ?? true,
7599
8730
  onFeedback: options.onFeedback
7600
8731
  }) : void 0;
7601
- const plan = await buildPlan(ctx.config, ctx.state.getStateFile(), {
8732
+ let plan = await buildPlan(ctx.config, ctx.state.getStateFile(), {
7602
8733
  providers: targetProviders,
7603
- configPath: ctx.configPath
8734
+ configPath: ctx.configPath,
8735
+ resourceAddresses: selectedAddresses
7604
8736
  });
8737
+ if (options.mode === "create-only" && options.scope) {
8738
+ plan = enforceCreateOnlyPlan(plan, options.scope, toResourceRefreshResult(refreshResult));
8739
+ }
7605
8740
  return {
7606
8741
  executionContext: ctx,
7607
8742
  plan,
7608
8743
  refreshResult: toResourceRefreshResult(refreshResult),
7609
8744
  targetProviders,
7610
- destructiveActions: selectDestructive(plan.actions)
8745
+ destructiveActions: selectDestructive(plan.actions),
8746
+ selectedAddresses,
8747
+ mode: options.mode
8748
+ };
8749
+ }
8750
+ function enforceCreateOnlyPlan(plan, scope, refreshResult) {
8751
+ const reasons = [];
8752
+ const rootKeys = new Set(scope.roots.map(addressKey));
8753
+ const refreshError = refreshResult?.errors[0];
8754
+ if (refreshError) {
8755
+ reasons.push(
8756
+ `Cannot verify scoped dependencies because refresh failed for ${addressKey(refreshError.resource.address)}: ${refreshError.error}`
8757
+ );
8758
+ }
8759
+ for (const root of scope.roots) {
8760
+ const rootKey = addressKey(root);
8761
+ const rootAction = plan.actions.find((action) => addressKey(action.address) === rootKey);
8762
+ if (!rootAction) {
8763
+ reasons.push(`Scoped plan did not contain target resource ${rootKey}.`);
8764
+ } else if (rootAction.action !== "create") {
8765
+ reasons.push(`Target resource ${rootKey} must be new, but the scoped plan requires '${rootAction.action}'.`);
8766
+ }
8767
+ }
8768
+ const dependencyChanges = plan.actions.filter(
8769
+ (action) => !rootKeys.has(addressKey(action.address)) && action.action !== "no-op"
8770
+ );
8771
+ if (dependencyChanges.length > 0) {
8772
+ const labels = dependencyChanges.map((action) => `${addressKey(action.address)} (${action.action})`).join(", ");
8773
+ reasons.push(`Create-only requires every scoped dependency to be up-to-date. Reconcile first: ${labels}.`);
8774
+ }
8775
+ if (reasons.length === 0) return plan;
8776
+ return {
8777
+ ...plan,
8778
+ diagnostics: [
8779
+ ...plan.diagnostics,
8780
+ {
8781
+ severity: "error",
8782
+ code: "resource.create_only.blocked",
8783
+ message: reasons.join(" "),
8784
+ resource: scope.roots[0]
8785
+ }
8786
+ ]
7611
8787
  };
7612
8788
  }
8789
+ function resolvePlanScope(ctx, targetProviders, scope) {
8790
+ if (scope.roots.length === 0) {
8791
+ throw new UserError("Resource plan scope requires at least one root address.");
8792
+ }
8793
+ for (const root of scope.roots) {
8794
+ if (!targetProviders.includes(root.provider)) {
8795
+ throw new UserError(
8796
+ `Scoped resource ${addressKey(root)} is outside the selected provider set: ${targetProviders.join(", ")}.`
8797
+ );
8798
+ }
8799
+ }
8800
+ const graph = buildDependencyGraph(ctx.config, targetProviders);
8801
+ for (const root of scope.roots) {
8802
+ if (!graph.nodes.has(addressKey(root))) {
8803
+ throw new UserError(`Scoped resource ${addressKey(root)} is not declared in the project config.`);
8804
+ }
8805
+ }
8806
+ return scope.includeDependencies === false ? [...scope.roots] : collectDependencyClosure(graph, scope.roots);
8807
+ }
7613
8808
  async function executePlannedProject(planned, options = {}) {
7614
8809
  const decision = await decideDestructive(planned.destructiveActions, {
7615
8810
  policy: options.policy,
@@ -7653,13 +8848,6 @@ async function decideDestructive(destructiveActions, options = {}) {
7653
8848
  return "blocked";
7654
8849
  }
7655
8850
  }
7656
- function replaceResourcePlan(planned, plan) {
7657
- return {
7658
- ...planned,
7659
- plan,
7660
- destructiveActions: selectDestructive(plan.actions)
7661
- };
7662
- }
7663
8851
  function toResourceRefreshResult(result) {
7664
8852
  if (!result) return void 0;
7665
8853
  return {
@@ -8008,6 +9196,354 @@ function buildDeploymentContext(ctx, name, provider) {
8008
9196
  };
8009
9197
  }
8010
9198
 
9199
+ // src/internal/core/managed-api-runtime.ts
9200
+ function resolveAdapter(ctx, provider) {
9201
+ if (provider) return getRuntimeProvider(ctx, provider);
9202
+ const configured = Array.from(ctx.providers.keys());
9203
+ if (configured.length === 1) return getRuntimeProvider(ctx, configured[0]);
9204
+ throw new UserError("Multiple providers configured. Use --provider to specify one.");
9205
+ }
9206
+ function requiredMethod(value, provider, operation) {
9207
+ if (value) return value;
9208
+ throw new UserError(`Provider '${provider}' does not support ${operation}.`);
9209
+ }
9210
+ async function listRemoteAgents(ctx, options = {}) {
9211
+ const adapter2 = resolveAdapter(ctx, options.provider);
9212
+ const method2 = requiredMethod(adapter2.listAgentResources, adapter2.name, "agent listing");
9213
+ return method2.call(adapter2, options);
9214
+ }
9215
+ async function getRemoteAgent(ctx, id, options = {}) {
9216
+ const adapter2 = resolveAdapter(ctx, options.provider);
9217
+ const method2 = requiredMethod(adapter2.getRemoteAgent, adapter2.name, "agent lookup");
9218
+ return method2.call(adapter2, id, options.version);
9219
+ }
9220
+ async function listRemoteAgentVersions(ctx, id, options = {}) {
9221
+ const adapter2 = resolveAdapter(ctx, options.provider);
9222
+ const method2 = requiredMethod(adapter2.listAgentVersions, adapter2.name, "agent version listing");
9223
+ return method2.call(adapter2, id, options);
9224
+ }
9225
+ async function listRemoteEnvironments(ctx, options = {}) {
9226
+ const adapter2 = resolveAdapter(ctx, options.provider);
9227
+ const method2 = requiredMethod(adapter2.listEnvironmentResources, adapter2.name, "environment listing");
9228
+ return method2.call(adapter2, options);
9229
+ }
9230
+ async function getRemoteEnvironment(ctx, id, options = {}) {
9231
+ const adapter2 = resolveAdapter(ctx, options.provider);
9232
+ const method2 = requiredMethod(adapter2.getRemoteEnvironment, adapter2.name, "environment lookup");
9233
+ return method2.call(adapter2, id);
9234
+ }
9235
+ async function listRemoteVaults(ctx, options = {}) {
9236
+ const adapter2 = resolveAdapter(ctx, options.provider);
9237
+ const method2 = requiredMethod(adapter2.listVaultResources, adapter2.name, "vault listing");
9238
+ return method2.call(adapter2, options);
9239
+ }
9240
+ async function getRemoteVault(ctx, id, options = {}) {
9241
+ const adapter2 = resolveAdapter(ctx, options.provider);
9242
+ const method2 = requiredMethod(adapter2.getRemoteVault, adapter2.name, "vault lookup");
9243
+ return method2.call(adapter2, id);
9244
+ }
9245
+ async function listRemoteSkills(ctx, options = {}) {
9246
+ const adapter2 = resolveAdapter(ctx, options.provider);
9247
+ const method2 = requiredMethod(adapter2.listSkillResources, adapter2.name, "skill listing");
9248
+ return method2.call(adapter2, options);
9249
+ }
9250
+ async function getRemoteSkill(ctx, id, options = {}) {
9251
+ const adapter2 = resolveAdapter(ctx, options.provider);
9252
+ const method2 = requiredMethod(adapter2.getSkillInfo, adapter2.name, "skill lookup");
9253
+ return method2.call(adapter2, id);
9254
+ }
9255
+ async function listRemoteSkillVersions(ctx, id, options = {}) {
9256
+ const adapter2 = resolveAdapter(ctx, options.provider);
9257
+ const method2 = requiredMethod(adapter2.listSkillVersions, adapter2.name, "skill version listing");
9258
+ return method2.call(adapter2, id, options);
9259
+ }
9260
+ async function getRemoteSkillVersion(ctx, id, version, options = {}) {
9261
+ const adapter2 = resolveAdapter(ctx, options.provider);
9262
+ const method2 = requiredMethod(adapter2.getSkillVersion, adapter2.name, "skill version lookup");
9263
+ return method2.call(adapter2, id, version);
9264
+ }
9265
+ async function getRemoteSkillDownloadInfo(ctx, id, version, options = {}) {
9266
+ const adapter2 = resolveAdapter(ctx, options.provider);
9267
+ const method2 = requiredMethod(adapter2.getSkillDownloadInfo, adapter2.name, "skill version download");
9268
+ return method2.call(adapter2, id, version);
9269
+ }
9270
+ async function downloadRemoteSkill(ctx, id, version, options = {}) {
9271
+ const info = await getRemoteSkillDownloadInfo(ctx, id, version, options);
9272
+ const response = await resolveFetch()(info.file_url, { method: "GET" });
9273
+ if (!response.ok) {
9274
+ throw new ApiError(response.status, await response.text(), "Skill download failed");
9275
+ }
9276
+ return new Uint8Array(await response.arrayBuffer());
9277
+ }
9278
+ async function listRemoteFiles(ctx, options = {}) {
9279
+ const adapter2 = resolveAdapter(ctx, options.provider);
9280
+ const method2 = requiredMethod(adapter2.listFileResources, adapter2.name, "file listing");
9281
+ return method2.call(adapter2, options);
9282
+ }
9283
+ async function downloadRemoteFile(ctx, id, options = {}) {
9284
+ const adapter2 = resolveAdapter(ctx, options.provider);
9285
+ const method2 = requiredMethod(adapter2.downloadFileContent, adapter2.name, "file content download");
9286
+ return method2.call(adapter2, id);
9287
+ }
9288
+ async function updateRemoteSession(ctx, id, input, options = {}) {
9289
+ const adapter2 = resolveAdapter(ctx, options.provider);
9290
+ const method2 = requiredMethod(adapter2.updateSession, adapter2.name, "session update");
9291
+ return method2.call(adapter2, id, input);
9292
+ }
9293
+ async function archiveRemoteSession(ctx, id, options = {}) {
9294
+ const adapter2 = resolveAdapter(ctx, options.provider);
9295
+ const method2 = requiredMethod(adapter2.archiveSession, adapter2.name, "session archive");
9296
+ return method2.call(adapter2, id);
9297
+ }
9298
+ async function sendRemoteSessionEvents(ctx, id, events, options = {}) {
9299
+ const adapter2 = resolveAdapter(ctx, options.provider);
9300
+ const method2 = requiredMethod(adapter2.sendSessionEvents, adapter2.name, "generic session event sending");
9301
+ return method2.call(adapter2, id, events);
9302
+ }
9303
+ async function listRemoteDeployments(ctx, options = {}) {
9304
+ const adapter2 = resolveAdapter(ctx, options.provider);
9305
+ const method2 = requiredMethod(adapter2.listDeployments, adapter2.name, "deployment listing");
9306
+ return method2.call(adapter2, options);
9307
+ }
9308
+ async function getRemoteDeployment(ctx, id, options = {}) {
9309
+ const adapter2 = resolveAdapter(ctx, options.provider);
9310
+ const method2 = requiredMethod(adapter2.getDeploymentById, adapter2.name, "deployment lookup");
9311
+ return method2.call(adapter2, id);
9312
+ }
9313
+ async function runRemoteDeployment(ctx, id, options = {}) {
9314
+ const adapter2 = resolveAdapter(ctx, options.provider);
9315
+ const method2 = requiredMethod(adapter2.runDeploymentById, adapter2.name, "deployment run");
9316
+ return method2.call(adapter2, id);
9317
+ }
9318
+ async function setRemoteDeploymentPaused(ctx, id, paused, options = {}) {
9319
+ const adapter2 = resolveAdapter(ctx, options.provider);
9320
+ const method2 = paused ? adapter2.pauseDeploymentById : adapter2.unpauseDeploymentById;
9321
+ return requiredMethod(method2, adapter2.name, `${paused ? "pausing" : "unpausing"} deployments`).call(adapter2, id);
9322
+ }
9323
+ async function listRemoteDeploymentRuns(ctx, deploymentId, options = {}) {
9324
+ const adapter2 = resolveAdapter(ctx, options.provider);
9325
+ const method2 = requiredMethod(adapter2.listDeploymentRuns, adapter2.name, "deployment run listing");
9326
+ return method2.call(adapter2, deploymentId, options);
9327
+ }
9328
+ async function getRemoteDeploymentRun(ctx, runId, options = {}) {
9329
+ const adapter2 = resolveAdapter(ctx, options.provider);
9330
+ const method2 = requiredMethod(adapter2.getDeploymentRun, adapter2.name, "deployment run lookup");
9331
+ return method2.call(adapter2, runId);
9332
+ }
9333
+ var API_KEY = { supported: true, auth: "api_key" };
9334
+ var CLIENT_SEARCH = {
9335
+ supported: true,
9336
+ auth: "api_key",
9337
+ reason: "Client-side filtering over the corresponding list API."
9338
+ };
9339
+ var UNSUPPORTED_MODEL = {
9340
+ supported: false,
9341
+ auth: null,
9342
+ reason: "The public Managed Agents API does not expose a model catalog endpoint."
9343
+ };
9344
+ var UNSUPPORTED_THREAD = {
9345
+ supported: false,
9346
+ auth: null,
9347
+ reason: "Managed Agents exposes child-thread ids and lifecycle events through Session Events, but no independent Thread resource API."
9348
+ };
9349
+ var UNSUPPORTED_OAUTH = {
9350
+ supported: false,
9351
+ auth: null,
9352
+ reason: "The public Managed Agents data plane does not expose MCP OAuth login."
9353
+ };
9354
+ var BAILIAN_OPERATIONS = {
9355
+ "agent.create": { ...API_KEY, reason: "YAML declaration plus scoped create-only apply." },
9356
+ "agent.list": API_KEY,
9357
+ "agent.get": API_KEY,
9358
+ "agent.search": CLIENT_SEARCH,
9359
+ "agent.versions": API_KEY,
9360
+ "environment.create": { ...API_KEY, reason: "YAML declaration plus scoped create-only apply." },
9361
+ "environment.list": API_KEY,
9362
+ "environment.get": API_KEY,
9363
+ "environment.search": CLIENT_SEARCH,
9364
+ "skill.create": { ...API_KEY, reason: "YAML declaration plus scoped create-only apply." },
9365
+ "skill.list": API_KEY,
9366
+ "skill.get": API_KEY,
9367
+ "skill.search": CLIENT_SEARCH,
9368
+ "skill.versions": API_KEY,
9369
+ "skill.download": API_KEY,
9370
+ "vault.create": { ...API_KEY, reason: "YAML declaration plus scoped create-only apply." },
9371
+ "vault.credential.create": { ...API_KEY, reason: "YAML declaration plus scoped Vault transaction." },
9372
+ "vault.list": API_KEY,
9373
+ "vault.get": API_KEY,
9374
+ "vault.search": CLIENT_SEARCH,
9375
+ "deployment.create": { ...API_KEY, reason: "YAML declaration plus scoped create-only apply." },
9376
+ "deployment.list": API_KEY,
9377
+ "deployment.get": API_KEY,
9378
+ "deployment.search": { ...API_KEY, reason: "Maps to the server-side keyword parameter." },
9379
+ "deployment.runs.list": API_KEY,
9380
+ "deployment.runs.get": API_KEY,
9381
+ "deployment.run": API_KEY,
9382
+ "deployment.pause": API_KEY,
9383
+ "deployment.unpause": API_KEY,
9384
+ "session.create": API_KEY,
9385
+ "session.list": API_KEY,
9386
+ "session.get": API_KEY,
9387
+ "session.search": CLIENT_SEARCH,
9388
+ "session.update": API_KEY,
9389
+ "session.archive": API_KEY,
9390
+ "session.delete": API_KEY,
9391
+ "session.run": { ...API_KEY, reason: "Client composition of session create and event send/stream." },
9392
+ "session.event.send": API_KEY,
9393
+ "session.event.list": API_KEY,
9394
+ "session.event.stream": API_KEY,
9395
+ "session.debug": { ...API_KEY, reason: "Client-side aggregation of supported read APIs." },
9396
+ "session.export": { ...API_KEY, reason: "Client-side export of supported read APIs." },
9397
+ "file.upload": API_KEY,
9398
+ "file.list": API_KEY,
9399
+ "file.get": API_KEY,
9400
+ "file.search": CLIENT_SEARCH,
9401
+ "file.download": API_KEY,
9402
+ "file.delete": API_KEY,
9403
+ "model.list": UNSUPPORTED_MODEL,
9404
+ "model.search": UNSUPPORTED_MODEL,
9405
+ "session_thread.list": UNSUPPORTED_THREAD,
9406
+ "session_thread.get": UNSUPPORTED_THREAD,
9407
+ "session_thread.archive": UNSUPPORTED_THREAD,
9408
+ "session_thread.events": UNSUPPORTED_THREAD,
9409
+ "mcp.oauth_login": UNSUPPORTED_OAUTH
9410
+ };
9411
+ function getManagedAgentProviderCapabilities(provider) {
9412
+ if (provider === "bailian") {
9413
+ return { provider, operations: { ...BAILIAN_OPERATIONS } };
9414
+ }
9415
+ return {
9416
+ provider,
9417
+ operations: {
9418
+ "managed_agent.api": {
9419
+ supported: false,
9420
+ auth: null,
9421
+ reason: "The operation-level API command surface is currently implemented for Bailian only."
9422
+ }
9423
+ }
9424
+ };
9425
+ }
9426
+
9427
+ // src/internal/core/vault-credential-runtime.ts
9428
+ async function planVaultCredentialCreate(ctx, vaultName, credentialName, options = {}) {
9429
+ const prepared = await prepareVaultCredentialCreate(ctx, vaultName, credentialName, options);
9430
+ return {
9431
+ provider: prepared.provider,
9432
+ vault: vaultName,
9433
+ vaultRemoteId: prepared.vaultState.remote_id,
9434
+ credential: credentialName,
9435
+ remoteChecked: prepared.remoteChecked,
9436
+ reuseRemote: Boolean(prepared.remoteCredential),
9437
+ remoteCredentialId: prepared.remoteCredential?.id
9438
+ };
9439
+ }
9440
+ async function planVaultCredentialCreateWithStateBackend(input, vaultName, credentialName, options = {}) {
9441
+ return readProjectRuntime(input, (ctx) => planVaultCredentialCreate(ctx, vaultName, credentialName, options));
9442
+ }
9443
+ async function createVaultCredential(ctx, vaultName, credentialName, options = {}) {
9444
+ if (options.checkRemote === false) {
9445
+ throw new UserError("Vault Credential create requires the remote duplicate check.");
9446
+ }
9447
+ const prepared = await prepareVaultCredentialCreate(ctx, vaultName, credentialName, options);
9448
+ const remote = prepared.remoteCredential ?? await prepared.adapter.createCredential(prepared.vaultState.remote_id, prepared.credential);
9449
+ if (!remote.id) throw new UserError("Credential create returned no remote id.");
9450
+ const address = { type: "vault", name: vaultName, provider: prepared.provider };
9451
+ const desiredHash = await computeResourceHash(address, ctx.config, ctx.configPath, ctx.state);
9452
+ ctx.state.setResource({
9453
+ ...prepared.vaultState,
9454
+ content_hash: desiredHash,
9455
+ desired_hash: desiredHash,
9456
+ drift_paths: [],
9457
+ drift_status: "unchecked"
9458
+ });
9459
+ await ctx.state.save();
9460
+ return {
9461
+ provider: prepared.provider,
9462
+ vault: vaultName,
9463
+ vaultRemoteId: prepared.vaultState.remote_id,
9464
+ credential: credentialName,
9465
+ remoteChecked: prepared.remoteChecked,
9466
+ credentialId: remote.id,
9467
+ reuseRemote: Boolean(prepared.remoteCredential),
9468
+ remoteCredentialId: prepared.remoteCredential?.id,
9469
+ adopted: Boolean(prepared.remoteCredential)
9470
+ };
9471
+ }
9472
+ async function createVaultCredentialWithStateBackend(input, vaultName, credentialName, options = {}) {
9473
+ return writeProjectRuntime(input, (ctx) => createVaultCredential(ctx, vaultName, credentialName, options));
9474
+ }
9475
+ async function prepareVaultCredentialCreate(ctx, vaultName, credentialName, options) {
9476
+ const vault = ctx.config.vaults?.[vaultName];
9477
+ if (!vault) throw new UserError(`Vault '${vaultName}' is not declared in the project config.`);
9478
+ const provider = resolveVaultProvider(ctx, vault.provider, options.provider);
9479
+ const credential = vault.credentials.at(-1);
9480
+ if (!credential || credential.name !== credentialName) {
9481
+ throw new UserError(`Credential '${credentialName}' must be the final newly appended entry in vault.${vaultName}.`);
9482
+ }
9483
+ if (vault.credentials.slice(0, -1).some((entry) => entry.name === credentialName)) {
9484
+ throw new UserError(`Vault '${vaultName}' already declares a credential named '${credentialName}'.`);
9485
+ }
9486
+ const address = { type: "vault", name: vaultName, provider };
9487
+ const priorConfig = structuredClone(ctx.config);
9488
+ priorConfig.vaults[vaultName] = {
9489
+ ...priorConfig.vaults[vaultName],
9490
+ credentials: priorConfig.vaults[vaultName].credentials.slice(0, -1)
9491
+ };
9492
+ const priorPlan = await planProjectContext(
9493
+ { ...ctx, config: priorConfig },
9494
+ {
9495
+ provider,
9496
+ scope: { roots: [address] },
9497
+ refresh: options.refresh,
9498
+ quiet: options.quiet ?? true
9499
+ }
9500
+ );
9501
+ const refreshError = priorPlan.refreshResult?.errors[0];
9502
+ if (refreshError) {
9503
+ throw new UserError(`Cannot verify vault.${vaultName} because refresh failed: ${refreshError.error}`);
9504
+ }
9505
+ const errorDiagnostic = priorPlan.plan.diagnostics.find((diagnostic) => diagnostic.severity === "error");
9506
+ if (errorDiagnostic) throw new UserError(errorDiagnostic.message);
9507
+ const vaultAction = priorPlan.plan.actions.find(
9508
+ (action) => action.address.type === "vault" && action.address.name === vaultName
9509
+ );
9510
+ if (vaultAction?.action !== "no-op") {
9511
+ throw new UserError(
9512
+ `vault.${vaultName} must be tracked and up-to-date before adding a credential; current action is '${vaultAction?.action ?? "missing"}'.`
9513
+ );
9514
+ }
9515
+ const vaultState = ctx.state.getResource(address);
9516
+ if (!vaultState?.remote_id) throw new UserError(`vault.${vaultName} has no tracked remote id.`);
9517
+ const adapter2 = getRuntimeProvider(ctx, provider);
9518
+ if (!adapter2.createCredential || !adapter2.listCredentials) {
9519
+ throw new UserError(`Provider '${provider}' does not support scoped Vault Credential create.`);
9520
+ }
9521
+ const remoteChecked = options.checkRemote !== false;
9522
+ const sameName = remoteChecked ? (await adapter2.listCredentials(vaultState.remote_id)).filter(
9523
+ (remoteCredential) => remoteCredential.display_name === credentialName
9524
+ ) : [];
9525
+ const exact = sameName.find((remoteCredential) => credentialMatches(remoteCredential, credential));
9526
+ if (sameName.length > 0 && !exact) {
9527
+ throw new UserError(`Vault '${vaultName}' already has a different remote credential named '${credentialName}'.`);
9528
+ }
9529
+ return { provider, credential, vaultState, adapter: adapter2, remoteChecked, remoteCredential: exact };
9530
+ }
9531
+ function resolveVaultProvider(ctx, declaredProvider, requestedProvider) {
9532
+ if (requestedProvider && declaredProvider && requestedProvider !== declaredProvider) {
9533
+ throw new UserError(
9534
+ `Vault provider '${declaredProvider}' does not match requested provider '${requestedProvider}'.`
9535
+ );
9536
+ }
9537
+ const provider = requestedProvider ?? declaredProvider ?? ctx.config.defaults?.provider;
9538
+ if (provider && provider !== "all") return provider;
9539
+ const configured = [...ctx.providers.keys()];
9540
+ if (configured.length === 1) return configured[0];
9541
+ throw new UserError("Cannot infer one provider for Vault Credential create.");
9542
+ }
9543
+ function credentialMatches(remote, desired) {
9544
+ return remote.auth_type === desired.type && remote.secret_name === desired.secret_name && (remote.networking_type ?? "unrestricted") === (desired.networking?.type ?? "unrestricted");
9545
+ }
9546
+
8011
9547
  // src/internal/core/destroy-runtime.ts
8012
9548
  var destroyOrder = {
8013
9549
  deployment: 0,
@@ -8025,12 +9561,64 @@ function planDestroyProjectContext(ctx) {
8025
9561
  const resources = [...ctx.state.listResources()].sort(
8026
9562
  (a, b) => (destroyOrder[a.address.type] ?? 99) - (destroyOrder[b.address.type] ?? 99)
8027
9563
  );
8028
- return { resources, executionContext: ctx };
9564
+ const identityName = ctx.config.defaults?.identity;
9565
+ const defaultMemoryStores = [];
9566
+ for (const [agentName, agent] of Object.entries(ctx.config.agents ?? {})) {
9567
+ if (!agent.default_memory_store || agent.delivery?.qoder?.type !== "forward") continue;
9568
+ if (agent.provider && agent.provider !== "qoder") continue;
9569
+ const identityId = identityName ? ctx.state.getResource({ type: "identity", name: identityName, provider: "qoder" })?.remote_id ?? null : null;
9570
+ const templateId = ctx.state.getResource({ type: "template", name: agentName, provider: "qoder" })?.remote_id ?? null;
9571
+ if (!identityId && !templateId) continue;
9572
+ defaultMemoryStores.push({
9573
+ agentName,
9574
+ provider: "qoder",
9575
+ identityId,
9576
+ templateId,
9577
+ deleteOnDestroy: agent.default_memory_store.delete_on_destroy ?? false
9578
+ });
9579
+ }
9580
+ for (const pending of ctx.state.getStateFile().pending_default_memory_store_cleanups ?? []) {
9581
+ const existing = defaultMemoryStores.find(
9582
+ (item) => item.agentName === pending.agent_name && item.provider === pending.provider
9583
+ );
9584
+ if (existing) {
9585
+ existing.memoryStoreId = pending.remote_id;
9586
+ existing.deleteOnDestroy = true;
9587
+ } else {
9588
+ defaultMemoryStores.push({
9589
+ agentName: pending.agent_name,
9590
+ provider: pending.provider,
9591
+ identityId: pending.identity_id ?? null,
9592
+ templateId: pending.template_id ?? null,
9593
+ deleteOnDestroy: true,
9594
+ memoryStoreId: pending.remote_id
9595
+ });
9596
+ }
9597
+ }
9598
+ return { resources, defaultMemoryStores, executionContext: ctx };
8029
9599
  }
8030
9600
  async function destroyPlannedProjectResources(planned, options = {}) {
8031
9601
  const results = [];
8032
- let stateChanged = false;
9602
+ const capturedDefaults = await captureDefaultMemoryStores(planned);
8033
9603
  const ctx = planned.executionContext;
9604
+ if (capturedDefaults.some((item) => item.error)) {
9605
+ const defaultMemoryStoreResults2 = capturedDefaults.map(preflightFailureResult);
9606
+ for (const resource of planned.resources) {
9607
+ const result = {
9608
+ resource,
9609
+ status: "blocked",
9610
+ reason: "skipped",
9611
+ error: "Destroy aborted because the default Memory Store preflight failed."
9612
+ };
9613
+ results.push(result);
9614
+ options.onResourceResult?.(result);
9615
+ }
9616
+ return { ...planned, results, defaultMemoryStoreResults: defaultMemoryStoreResults2, destroyed: 0, partial: true };
9617
+ }
9618
+ if (await persistCapturedDefaultMemoryStores(ctx, capturedDefaults)) {
9619
+ await ctx.state.save();
9620
+ }
9621
+ let stateChanged = false;
8034
9622
  for (const resource of planned.resources) {
8035
9623
  options.onResourceStart?.(resource);
8036
9624
  const result = await destroyOneResource(ctx, resource, options);
@@ -8041,14 +9629,171 @@ async function destroyPlannedProjectResources(planned, options = {}) {
8041
9629
  if (stateChanged) {
8042
9630
  await ctx.state.save();
8043
9631
  }
9632
+ const defaultMemoryStoreResults = await finalizeDefaultMemoryStores(planned, capturedDefaults, options);
9633
+ if (recordFailedDefaultMemoryStoreCleanups(ctx, defaultMemoryStoreResults)) {
9634
+ await ctx.state.save();
9635
+ }
9636
+ if (clearCompletedDefaultMemoryStoreCleanups(ctx, defaultMemoryStoreResults)) {
9637
+ await ctx.state.save();
9638
+ }
8044
9639
  const destroyed = results.filter((result) => result.status === "success").length;
8045
9640
  return {
8046
9641
  ...planned,
8047
9642
  results,
9643
+ defaultMemoryStoreResults,
8048
9644
  destroyed,
8049
- partial: destroyed !== planned.resources.length
9645
+ partial: destroyed !== planned.resources.length || defaultMemoryStoreResults.some((result) => result.status === "failed")
9646
+ };
9647
+ }
9648
+ async function persistCapturedDefaultMemoryStores(ctx, captured) {
9649
+ const state = ctx.state.getStateFile();
9650
+ if (!state.pending_default_memory_store_cleanups) state.pending_default_memory_store_cleanups = [];
9651
+ const pending = state.pending_default_memory_store_cleanups;
9652
+ let changed = false;
9653
+ for (const item of captured) {
9654
+ if (!item.plan.deleteOnDestroy || !item.memoryStoreId) continue;
9655
+ if (pending.some((entry) => entry.provider === item.plan.provider && entry.remote_id === item.memoryStoreId))
9656
+ continue;
9657
+ pending.push({
9658
+ agent_name: item.plan.agentName,
9659
+ provider: item.plan.provider,
9660
+ remote_id: item.memoryStoreId,
9661
+ ...item.plan.identityId ? { identity_id: item.plan.identityId } : {},
9662
+ ...item.plan.templateId ? { template_id: item.plan.templateId } : {}
9663
+ });
9664
+ changed = true;
9665
+ }
9666
+ return changed;
9667
+ }
9668
+ function clearCompletedDefaultMemoryStoreCleanups(ctx, results) {
9669
+ const state = ctx.state.getStateFile();
9670
+ const completedIds = new Set(
9671
+ results.filter((item) => item.status === "deleted" || item.status === "already_gone").map((item) => item.memoryStoreId).filter((id) => Boolean(id))
9672
+ );
9673
+ if (completedIds.size === 0 || !state.pending_default_memory_store_cleanups?.length) return false;
9674
+ const remaining = state.pending_default_memory_store_cleanups.filter((item) => !completedIds.has(item.remote_id));
9675
+ if (remaining.length === state.pending_default_memory_store_cleanups.length) return false;
9676
+ state.pending_default_memory_store_cleanups = remaining;
9677
+ return true;
9678
+ }
9679
+ function recordFailedDefaultMemoryStoreCleanups(ctx, results) {
9680
+ const pending = ctx.state.getStateFile().pending_default_memory_store_cleanups;
9681
+ if (!pending?.length) return false;
9682
+ let changed = false;
9683
+ for (const result of results) {
9684
+ if (result.status !== "failed" || !result.memoryStoreId) continue;
9685
+ const entry = pending.find((item) => item.remote_id === result.memoryStoreId);
9686
+ if (entry && entry.last_error !== result.error) {
9687
+ entry.last_error = result.error;
9688
+ changed = true;
9689
+ }
9690
+ }
9691
+ return changed;
9692
+ }
9693
+ function preflightFailureResult(item) {
9694
+ if (!item.plan.deleteOnDestroy) return { ...item.plan, status: "retained" };
9695
+ return {
9696
+ ...item.plan,
9697
+ status: "failed",
9698
+ ...item.memoryStoreId ? { memoryStoreId: item.memoryStoreId } : {},
9699
+ error: item.error ?? "Destroy aborted because another default Memory Store preflight failed."
8050
9700
  };
8051
9701
  }
9702
+ async function captureDefaultMemoryStores(planned) {
9703
+ return Promise.all(
9704
+ planned.defaultMemoryStores.map(async (item) => {
9705
+ if (!item.deleteOnDestroy) return { plan: item };
9706
+ if (item.memoryStoreId) return { plan: item, memoryStoreId: item.memoryStoreId };
9707
+ if (!item.identityId || !item.templateId) {
9708
+ return { plan: item, error: "Cannot resolve the Identity and Template before destroy." };
9709
+ }
9710
+ try {
9711
+ const provider = getRuntimeProvider(planned.executionContext, item.provider);
9712
+ if (!provider.findDefaultMemoryStoreId || !provider.deleteDefaultMemoryStore) {
9713
+ return { plan: item, error: `Provider '${item.provider}' cannot delete a default memory store.` };
9714
+ }
9715
+ const memoryStoreId = await provider.findDefaultMemoryStoreId(item.identityId, item.templateId);
9716
+ return { plan: item, ...memoryStoreId ? { memoryStoreId } : {} };
9717
+ } catch (error) {
9718
+ return { plan: item, error: error instanceof Error ? error.message : String(error) };
9719
+ }
9720
+ })
9721
+ );
9722
+ }
9723
+ async function finalizeDefaultMemoryStores(planned, captured, options) {
9724
+ const output = [];
9725
+ for (const item of captured) {
9726
+ if (!item.plan.deleteOnDestroy) {
9727
+ output.push({ ...item.plan, status: "retained" });
9728
+ continue;
9729
+ }
9730
+ if (item.error) {
9731
+ output.push({ ...item.plan, status: "failed", error: item.error });
9732
+ continue;
9733
+ }
9734
+ if (!item.memoryStoreId) {
9735
+ output.push({ ...item.plan, status: "already_gone" });
9736
+ continue;
9737
+ }
9738
+ try {
9739
+ const provider = getRuntimeProvider(planned.executionContext, item.plan.provider);
9740
+ await deleteDefaultMemoryStoreWithArchiveFallback(
9741
+ provider,
9742
+ item.memoryStoreId,
9743
+ options.defaultMemoryStoreRetryDelaysMs ?? [1e3, 2e3, 4e3, 8e3]
9744
+ );
9745
+ output.push({ ...item.plan, status: "deleted", memoryStoreId: item.memoryStoreId });
9746
+ } catch (error) {
9747
+ if (ApiError.isNotFound(error)) {
9748
+ output.push({ ...item.plan, status: "already_gone", memoryStoreId: item.memoryStoreId });
9749
+ } else {
9750
+ output.push({
9751
+ ...item.plan,
9752
+ status: "failed",
9753
+ memoryStoreId: item.memoryStoreId,
9754
+ error: error instanceof Error ? error.message : String(error)
9755
+ });
9756
+ }
9757
+ }
9758
+ }
9759
+ return output;
9760
+ }
9761
+ async function deleteDefaultMemoryStoreWithArchiveFallback(provider, memoryStoreId, retryDelaysMs) {
9762
+ try {
9763
+ await retryDefaultMemoryStoreOperation(() => provider.deleteDefaultMemoryStore(memoryStoreId), retryDelaysMs);
9764
+ } catch (error) {
9765
+ if (isAlreadyArchivedConflict(error) && provider.deleteMemoryStore) {
9766
+ await retryDefaultMemoryStoreOperation(() => provider.deleteMemoryStore(memoryStoreId), retryDelaysMs);
9767
+ return;
9768
+ }
9769
+ if (!isStillMountedConflict(error) || !provider.archiveMemoryStore || !provider.deleteMemoryStore) throw error;
9770
+ await retryDefaultMemoryStoreOperation(() => provider.archiveMemoryStore(memoryStoreId), retryDelaysMs);
9771
+ await retryDefaultMemoryStoreOperation(() => provider.deleteMemoryStore(memoryStoreId), retryDelaysMs);
9772
+ }
9773
+ }
9774
+ async function retryDefaultMemoryStoreOperation(operation, delaysMs) {
9775
+ for (let attempt = 0; ; attempt++) {
9776
+ try {
9777
+ await operation();
9778
+ return;
9779
+ } catch (error) {
9780
+ if (!isRetryableDefaultMemoryStoreError(error) || attempt >= delaysMs.length) throw error;
9781
+ await delay(delaysMs[attempt]);
9782
+ }
9783
+ }
9784
+ }
9785
+ function isRetryableDefaultMemoryStoreError(error) {
9786
+ return error instanceof ApiError && (isStillMountedConflict(error) || isAlreadyArchivedConflict(error) || error.statusCode === 429 || [500, 502, 503].includes(error.statusCode));
9787
+ }
9788
+ function isStillMountedConflict(error) {
9789
+ return error instanceof ApiError && error.statusCode === 409 && error.responseBody.includes("still mounted");
9790
+ }
9791
+ function isAlreadyArchivedConflict(error) {
9792
+ return error instanceof ApiError && error.statusCode === 409 && error.responseBody.toLowerCase().includes("already archived");
9793
+ }
9794
+ function delay(ms) {
9795
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
9796
+ }
8052
9797
  async function destroyOneResource(ctx, resource, options) {
8053
9798
  if (isExternalReference(ctx, resource)) {
8054
9799
  ctx.state.removeResource(resource.address);
@@ -8069,8 +9814,18 @@ async function destroyOneResource(ctx, resource, options) {
8069
9814
  ctx.state.removeResource(resource.address);
8070
9815
  return successResult(resource, "destroyed");
8071
9816
  }
9817
+ const apiMode = resource.api_mode === "auto" ? void 0 : resource.api_mode;
8072
9818
  try {
8073
- await deleteRemoteResource(provider, resource.address.type, resource.remote_id, options.cascade);
9819
+ await deleteRemoteResource(
9820
+ provider,
9821
+ resource.address.type,
9822
+ resource.remote_id,
9823
+ options.cascade,
9824
+ apiMode,
9825
+ ctx.state.listResources().filter(
9826
+ (candidate) => candidate.address.provider === resource.address.provider && candidate.address.type === "memory_store" && candidate.api_mode === "forward" && typeof candidate.remote_id === "string"
9827
+ ).map((candidate) => candidate.remote_id)
9828
+ );
8074
9829
  ctx.state.removeResource(resource.address);
8075
9830
  emitRuntimeFeedback(options.onFeedback, {
8076
9831
  type: "resource_action_success",
@@ -8099,7 +9854,7 @@ async function destroyOneResource(ctx, resource, options) {
8099
9854
  };
8100
9855
  if (await options.onCascadeRequired?.(blocked)) {
8101
9856
  try {
8102
- await provider.deleteEnvironment(resource.remote_id, true);
9857
+ await provider.deleteEnvironment(resource.remote_id, true, apiMode);
8103
9858
  ctx.state.removeResource(resource.address);
8104
9859
  return {
8105
9860
  ...successResult(resource, "destroyed"),
@@ -8135,29 +9890,29 @@ function failureResult(resource, error) {
8135
9890
  error: error instanceof Error ? error.message : String(error)
8136
9891
  };
8137
9892
  }
8138
- async function deleteRemoteResource(provider, type, id, cascade) {
9893
+ async function deleteRemoteResource(provider, type, id, cascade, mode, ownedMemoryStoreIds = []) {
8139
9894
  switch (type) {
8140
9895
  case "agent":
8141
9896
  await provider.deleteAgent(id);
8142
9897
  return;
8143
9898
  case "template":
8144
9899
  if (!provider.archiveTemplate) throw new UserError(`Provider does not support templates`);
8145
- await provider.archiveTemplate(id);
9900
+ await provider.archiveTemplate(id, ownedMemoryStoreIds);
8146
9901
  return;
8147
9902
  case "skill":
8148
- await provider.deleteSkill(id);
9903
+ await provider.deleteSkill(id, mode);
8149
9904
  return;
8150
9905
  case "memory_store":
8151
9906
  if (!provider.deleteMemoryStore) {
8152
9907
  throw new UserError(`Provider does not support memory stores`);
8153
9908
  }
8154
- await provider.deleteMemoryStore(id);
9909
+ await provider.deleteMemoryStore(id, mode);
8155
9910
  return;
8156
9911
  case "vault":
8157
- await provider.deleteVault(id);
9912
+ await provider.deleteVault(id, mode);
8158
9913
  return;
8159
9914
  case "environment":
8160
- await provider.deleteEnvironment(id, cascade);
9915
+ await provider.deleteEnvironment(id, cascade, mode);
8161
9916
  return;
8162
9917
  case "deployment":
8163
9918
  await provider.deleteDeployment(id);
@@ -8171,7 +9926,7 @@ async function deleteRemoteResource(provider, type, id, cascade) {
8171
9926
  await provider.deleteChannel(id);
8172
9927
  return;
8173
9928
  case "file":
8174
- await provider.deleteFile(id);
9929
+ await provider.deleteFile(id, mode);
8175
9930
  return;
8176
9931
  }
8177
9932
  }
@@ -8331,6 +10086,7 @@ function buildAgentDecl(base, input) {
8331
10086
  });
8332
10087
  const agent = {
8333
10088
  ...base ?? {},
10089
+ name: input.name ?? base?.name,
8334
10090
  description: input.description ?? base?.description,
8335
10091
  model,
8336
10092
  instructions: input.instructions ?? base?.instructions ?? "",
@@ -8374,6 +10130,10 @@ function buildSessionBindings(agentName, config, provider, state, options = {})
8374
10130
  throw new UserError(`Agent '${agentName}' not found in config. Available agents: ${available || "(none)"}`);
8375
10131
  }
8376
10132
  const sessionResources = options.resources ?? agent.resources;
10133
+ const environmentVariables = options.environmentVariables ?? agent.environment_variables;
10134
+ if (environmentVariables && provider !== "qoder") {
10135
+ throw new UserError("Session environment variables are supported only by Qoder.");
10136
+ }
8377
10137
  const providerFeatures = getProvider(provider)?.features;
8378
10138
  for (const resource of sessionResources ?? []) {
8379
10139
  if (!providerFeatures?.session_resources.includes(resource.type)) {
@@ -8402,7 +10162,8 @@ function buildSessionBindings(agentName, config, provider, state, options = {})
8402
10162
  identity_id: identityId,
8403
10163
  files: (options.files ?? []).map((file) => ({ file_id: file.fileId, mount_path: file.mountPath })),
8404
10164
  title: options.title,
8405
- metadata: options.metadata
10165
+ metadata: options.metadata,
10166
+ environment_variables: environmentVariables
8406
10167
  };
8407
10168
  }
8408
10169
  const agentId = requireRef(state, { type: "agent", name: agentName, provider });
@@ -8447,7 +10208,8 @@ function buildSessionBindings(agentName, config, provider, state, options = {})
8447
10208
  files: (options.files ?? []).map((f) => ({ file_id: f.fileId, mount_path: f.mountPath })),
8448
10209
  resources: sessionResources,
8449
10210
  title: options.title,
8450
- metadata: options.metadata
10211
+ metadata: options.metadata,
10212
+ environment_variables: environmentVariables
8451
10213
  };
8452
10214
  }
8453
10215
  function resolveTunnelId(agent, config, options, provider) {
@@ -8561,28 +10323,36 @@ async function listAgentsWithReadiness(ctx, options = {}) {
8561
10323
  }
8562
10324
  async function planAgentResources(ctx, agentId, options = {}) {
8563
10325
  const agent = getAgent(ctx, agentId);
10326
+ const rootAddress = collectAgentAddresses(ctx.config, agent.agentName, agent.provider)[0];
8564
10327
  const planned = await planProjectContext(ctx, {
8565
10328
  provider: agent.provider,
10329
+ scope: { roots: [rootAddress] },
10330
+ mode: options.mode,
8566
10331
  refresh: options.refresh,
8567
10332
  quiet: options.quiet ?? true
8568
10333
  });
8569
- const actions = filterAgentActions(ctx, agent, planned.plan);
10334
+ const actions = planned.plan.actions;
10335
+ const diagnostics = planned.plan.diagnostics;
8570
10336
  return {
8571
10337
  agentId,
8572
10338
  provider: agent.provider,
8573
10339
  actions,
8574
- diagnostics: filterAgentDiagnostics(ctx, agent, planned.plan),
10340
+ diagnostics,
8575
10341
  destructiveActions: selectDestructive(actions),
8576
10342
  planned
8577
10343
  };
8578
10344
  }
10345
+ async function planAgentResourcesWithStateBackend(input, agentId, options = {}) {
10346
+ return readProjectRuntime(input, (ctx) => planAgentResources(ctx, agentId, options));
10347
+ }
8579
10348
  async function syncAgentResources(ctx, agentId, options = {}) {
8580
10349
  return runAgentSync(ctx, agentId, options);
8581
10350
  }
8582
10351
  async function runAgentSync(ctx, agentId, options) {
8583
10352
  const fullPlan = await planAgentResources(ctx, agentId, {
8584
10353
  refresh: options.refresh,
8585
- quiet: options.quiet
10354
+ quiet: options.quiet,
10355
+ mode: options.mode
8586
10356
  });
8587
10357
  const actions = fullPlan.actions;
8588
10358
  const destructiveActions = fullPlan.destructiveActions;
@@ -8616,11 +10386,7 @@ async function runAgentSync(ctx, agentId, options) {
8616
10386
  };
8617
10387
  }
8618
10388
  try {
8619
- const scopedPlan = {
8620
- diagnostics: fullPlan.diagnostics,
8621
- actions: scopePlanActions(fullPlan.planned.plan, actions)
8622
- };
8623
- const execution = await executePlannedProject(replaceResourcePlan(fullPlan.planned, scopedPlan), {
10389
+ const execution = await executePlannedProject(fullPlan.planned, {
8624
10390
  policy: "force"
8625
10391
  });
8626
10392
  const results = toAgentSyncResults(execution);
@@ -8724,29 +10490,6 @@ function getAgentReadinessFromPlan(ctx, agentId, plan) {
8724
10490
  plannedActions: relevantActions
8725
10491
  };
8726
10492
  }
8727
- function filterAgentActions(ctx, agent, plan) {
8728
- const relevantKeys = agentAddressKeys(ctx, agent);
8729
- return plan.actions.filter(
8730
- (action) => relevantKeys.has(addressKey(action.address)) || action.dependencies.some((dependency) => relevantKeys.has(addressKey(dependency)))
8731
- );
8732
- }
8733
- function filterAgentDiagnostics(ctx, agent, plan) {
8734
- const relevantKeys = agentAddressKeys(ctx, agent);
8735
- return plan.diagnostics.filter(
8736
- (diagnostic) => !diagnostic.resource || relevantKeys.has(addressKey(diagnostic.resource))
8737
- );
8738
- }
8739
- function agentAddressKeys(ctx, agent) {
8740
- return new Set(collectAgentAddresses(ctx.config, agent.agentName, agent.provider).map(addressKey));
8741
- }
8742
- function scopePlanActions(fullPlan, agentActions) {
8743
- const allowedKeys = new Set(agentActions.filter((action) => action.action !== "no-op").map(actionKey));
8744
- return fullPlan.actions.filter((action) => action.action === "no-op" || allowedKeys.has(actionKey(action)));
8745
- }
8746
- function actionKey(action) {
8747
- const address = action.address;
8748
- return `${action.action}:${address.provider}:${address.type}:${address.name}`;
8749
- }
8750
10493
  function isNonBlockingAgentDrift(action) {
8751
10494
  if (action.action === "no-op") return true;
8752
10495
  return action.readinessImpact === "non_blocking";
@@ -8758,33 +10501,13 @@ function collectAgentAddresses(config, agentName, provider) {
8758
10501
  }
8759
10502
  const resolvedProvider = provider ?? resolveSessionProvider(agentName, config, void 0);
8760
10503
  const materialization = resolveAgentMaterialization(resolvedProvider, agent);
8761
- const addresses = [
8762
- { type: materialization.resourceType, name: agentName, provider: resolvedProvider }
8763
- ];
8764
- if (agent.environment) {
8765
- addresses.push({
8766
- type: "environment",
8767
- name: agent.environment,
8768
- provider: resolvedProvider
8769
- });
8770
- }
8771
- if (agent.vault) {
8772
- addresses.push({ type: "vault", name: agent.vault, provider: resolvedProvider });
8773
- }
8774
- for (const name of agent.memory_stores ?? []) {
8775
- addresses.push({ type: "memory_store", name, provider: resolvedProvider });
8776
- }
8777
- for (const skill of agent.skills ?? []) {
8778
- if (typeof skill === "string") {
8779
- addresses.push({ type: "skill", name: skill, provider: resolvedProvider });
8780
- }
8781
- }
8782
- for (const subAgent of agent.multiagent?.agents ?? []) {
8783
- const subDecl = config.agents?.[subAgent];
8784
- const subType = subDecl ? resolveAgentMaterialization(resolvedProvider, subDecl).resourceType : "agent";
8785
- addresses.push({ type: subType, name: subAgent, provider: resolvedProvider });
8786
- }
8787
- return addresses;
10504
+ const rootAddress = {
10505
+ type: materialization.resourceType,
10506
+ name: agentName,
10507
+ provider: resolvedProvider
10508
+ };
10509
+ const graph = buildDependencyGraph(config, [resolvedProvider]);
10510
+ return collectDependencyClosure(graph, [rootAddress]);
8788
10511
  }
8789
10512
  function toAgentDefinition(config, agentName, agent) {
8790
10513
  return {
@@ -8848,7 +10571,8 @@ async function createSessionForAgent(ctx, options = {}) {
8848
10571
  files: options.files,
8849
10572
  resources: options.resources,
8850
10573
  title: options.title,
8851
- metadata: options.metadata
10574
+ metadata: options.metadata,
10575
+ environmentVariables: options.environmentVariables
8852
10576
  });
8853
10577
  const session = await adapter2.createSession(bindings);
8854
10578
  return { agentName, provider, session };
@@ -8867,7 +10591,8 @@ async function startSessionRun(ctx, prompt, options = {}) {
8867
10591
  files: options.files,
8868
10592
  resources: options.resources,
8869
10593
  title: options.title,
8870
- metadata: options.metadata
10594
+ metadata: options.metadata,
10595
+ environmentVariables: options.environmentVariables
8871
10596
  });
8872
10597
  const session = await adapter2.createSession(bindings);
8873
10598
  return {
@@ -8928,7 +10653,7 @@ async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
8928
10653
  terminalStatus = terminalEvent.status;
8929
10654
  break;
8930
10655
  }
8931
- await delay(currentIntervalMs);
10656
+ await delay2(currentIntervalMs);
8932
10657
  currentIntervalMs = Math.min(currentIntervalMs * 2, maxPollIntervalMs);
8933
10658
  }
8934
10659
  } else {
@@ -8939,7 +10664,7 @@ async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
8939
10664
  terminalStatus = session.status;
8940
10665
  break;
8941
10666
  }
8942
- await delay(currentIntervalMs);
10667
+ await delay2(currentIntervalMs);
8943
10668
  currentIntervalMs = Math.min(currentIntervalMs * 2, maxPollIntervalMs);
8944
10669
  }
8945
10670
  result = await adapter2.listSessionEvents(sessionId, { limit: 100 });
@@ -9009,12 +10734,20 @@ async function listSessionEvents(ctx, sessionId, options = {}) {
9009
10734
  const listOptions = {};
9010
10735
  if (options.limit !== void 0) listOptions.limit = options.limit;
9011
10736
  if (options.order !== void 0) listOptions.order = options.order;
10737
+ if (options.types !== void 0) listOptions.types = options.types;
10738
+ if (options.created_at_gt !== void 0) listOptions.created_at_gt = options.created_at_gt;
10739
+ if (options.created_at_gte !== void 0) listOptions.created_at_gte = options.created_at_gte;
10740
+ if (options.created_at_lt !== void 0) listOptions.created_at_lt = options.created_at_lt;
10741
+ if (options.created_at_lte !== void 0) listOptions.created_at_lte = options.created_at_lte;
9012
10742
  const pageToken = options.page_token ?? options.page;
9013
10743
  if (pageToken !== void 0) listOptions.page_token = pageToken;
9014
- return resolveDirectAdapter(ctx, options.provider).listSessionEvents(
10744
+ const result = await resolveDirectAdapter(ctx, options.provider).listSessionEvents(
9015
10745
  sessionId,
9016
10746
  Object.keys(listOptions).length > 0 ? listOptions : void 0
9017
10747
  );
10748
+ if (!options.types || options.types.length === 0) return result;
10749
+ const allowedTypes = new Set(options.types);
10750
+ return { ...result, events: result.events.filter((event) => allowedTypes.has(event.raw_type)) };
9018
10751
  }
9019
10752
  async function uploadFile(ctx, content, filename, options = {}) {
9020
10753
  const adapter2 = resolveDirectAdapter(ctx, options.provider);
@@ -9064,12 +10797,89 @@ async function deleteSkill(ctx, id, options = {}) {
9064
10797
  await resolveDirectAdapter(ctx, options.provider).deleteSkill(id);
9065
10798
  }
9066
10799
  function streamSessionEvents(ctx, sessionId, options = {}) {
10800
+ const adapter2 = resolveDirectAdapter(ctx, options.provider);
10801
+ if (options.after_id && !adapter2.eventResume) {
10802
+ return replaySessionEventsByPolling(adapter2, sessionId, options.after_id);
10803
+ }
9067
10804
  const streamOptions = {};
9068
10805
  if (options.after_id !== void 0) streamOptions.after_id = options.after_id;
9069
- return resolveDirectAdapter(ctx, options.provider).streamSessionEvents(
9070
- sessionId,
9071
- Object.keys(streamOptions).length > 0 ? streamOptions : void 0
9072
- );
10806
+ return adapter2.streamSessionEvents(sessionId, Object.keys(streamOptions).length > 0 ? streamOptions : void 0);
10807
+ }
10808
+ async function* replaySessionEventsByPolling(adapter2, sessionId, afterId) {
10809
+ const history = await listAllSessionEventHistory(adapter2, sessionId);
10810
+ const markerIndex = history.findIndex((event) => event.id === afterId);
10811
+ if (markerIndex < 0) {
10812
+ throw new UserError(`Session event '${afterId}' was not found; list session events and choose a valid event id.`);
10813
+ }
10814
+ const knownEventKeys = new Set(history.slice(0, markerIndex + 1).map(sessionEventKey));
10815
+ for (const event of history.slice(markerIndex + 1)) {
10816
+ const eventKey = sessionEventKey(event);
10817
+ if (knownEventKeys.has(eventKey)) continue;
10818
+ knownEventKeys.add(eventKey);
10819
+ yield event;
10820
+ if (event.type === "status" && isTerminalSessionStatus(event.status)) return;
10821
+ }
10822
+ while (true) {
10823
+ const newEvents = await listNewSessionEvents(adapter2, sessionId, knownEventKeys);
10824
+ for (const event of newEvents) {
10825
+ const eventKey = sessionEventKey(event);
10826
+ if (knownEventKeys.has(eventKey)) continue;
10827
+ knownEventKeys.add(eventKey);
10828
+ yield event;
10829
+ if (event.type === "status" && isTerminalSessionStatus(event.status)) return;
10830
+ }
10831
+ const session = await adapter2.getSession(sessionId);
10832
+ if (isTerminalSessionStatus(session.status)) return;
10833
+ await delay2(DEFAULT_POLL_INTERVAL_MS);
10834
+ }
10835
+ }
10836
+ async function listAllSessionEventHistory(adapter2, sessionId) {
10837
+ const events = [];
10838
+ const seenPageTokens = /* @__PURE__ */ new Set();
10839
+ let pageToken;
10840
+ while (true) {
10841
+ const result = await adapter2.listSessionEvents(sessionId, {
10842
+ limit: 100,
10843
+ order: "asc",
10844
+ ...pageToken ? { page_token: pageToken } : {}
10845
+ });
10846
+ events.push(...result.events);
10847
+ if (!result.next_page) return events;
10848
+ if (seenPageTokens.has(result.next_page)) {
10849
+ throw new UserError("Session event pagination returned a repeated cursor.");
10850
+ }
10851
+ seenPageTokens.add(result.next_page);
10852
+ pageToken = result.next_page;
10853
+ }
10854
+ }
10855
+ async function listNewSessionEvents(adapter2, sessionId, knownEventKeys) {
10856
+ const descendingEvents = [];
10857
+ const seenPageTokens = /* @__PURE__ */ new Set();
10858
+ let pageToken;
10859
+ while (true) {
10860
+ const result = await adapter2.listSessionEvents(sessionId, {
10861
+ limit: 100,
10862
+ order: "desc",
10863
+ ...pageToken ? { page_token: pageToken } : {}
10864
+ });
10865
+ let reachedKnownEvent = false;
10866
+ for (const event of result.events) {
10867
+ if (knownEventKeys.has(sessionEventKey(event))) {
10868
+ reachedKnownEvent = true;
10869
+ break;
10870
+ }
10871
+ descendingEvents.push(event);
10872
+ }
10873
+ if (reachedKnownEvent || !result.next_page) return descendingEvents.reverse();
10874
+ if (seenPageTokens.has(result.next_page)) {
10875
+ throw new UserError("Session event pagination returned a repeated cursor.");
10876
+ }
10877
+ seenPageTokens.add(result.next_page);
10878
+ pageToken = result.next_page;
10879
+ }
10880
+ }
10881
+ function sessionEventKey(event) {
10882
+ return event.id ?? `raw:${event.raw_type}:${JSON.stringify(event.raw)}`;
9073
10883
  }
9074
10884
  function resolveDirectAdapter(ctx, overrideProvider) {
9075
10885
  if (overrideProvider) return getRuntimeProvider(ctx, overrideProvider);
@@ -9106,7 +10916,7 @@ async function* streamWithResume(adapter2, sessionId, message) {
9106
10916
  }
9107
10917
  }
9108
10918
  if (!reachedTerminal) {
9109
- await delay(reconnectIntervalMs);
10919
+ await delay2(reconnectIntervalMs);
9110
10920
  reconnectIntervalMs = Math.min(reconnectIntervalMs * 2, DEFAULT_POLL_INTERVAL_MS);
9111
10921
  }
9112
10922
  }
@@ -9134,7 +10944,7 @@ function assertNotTimedOut(start, timeoutMs) {
9134
10944
  throw new UserError(`Session did not complete within the timeout (${Math.floor(timeoutMs / 1e3)} seconds).`);
9135
10945
  }
9136
10946
  }
9137
- function delay(ms) {
10947
+ function delay2(ms) {
9138
10948
  return new Promise((resolve13) => setTimeout(resolve13, ms));
9139
10949
  }
9140
10950
 
@@ -9320,6 +11130,7 @@ var StateManager = class _StateManager {
9320
11130
  address: r.address,
9321
11131
  remote_id: r.remote_id,
9322
11132
  externally_managed: r.externally_managed === true ? true : void 0,
11133
+ api_mode: r.api_mode === "forward" ? "forward" : r.api_mode === "managed" ? "managed" : void 0,
9323
11134
  version: r.version,
9324
11135
  content_hash: r.content_hash ?? r.desired_hash ?? "",
9325
11136
  desired_hash: r.desired_hash ?? r.content_hash ?? "",
@@ -9327,10 +11138,15 @@ var StateManager = class _StateManager {
9327
11138
  desired_readiness_baseline: r.desired_readiness_baseline,
9328
11139
  remote_hash: r.remote_hash,
9329
11140
  remote_snapshot: r.remote_snapshot,
11141
+ replacement_fingerprint: r.replacement_fingerprint,
9330
11142
  drift_paths: r.drift_paths,
9331
11143
  drift_status: r.drift_status
9332
11144
  }));
9333
- return new _StateManager({ resources }, path);
11145
+ const pending = Array.isArray(data.pending_default_memory_store_cleanups) ? data.pending_default_memory_store_cleanups : void 0;
11146
+ return new _StateManager(
11147
+ { resources, ...pending ? { pending_default_memory_store_cleanups: pending } : {} },
11148
+ path
11149
+ );
9334
11150
  } catch (err) {
9335
11151
  if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
9336
11152
  return _StateManager.initialize(path);
@@ -9528,6 +11344,8 @@ var PlanReadinessImpactSchema = z6.enum(["none", "non_blocking", "blocking"]);
9528
11344
  var PlannedActionSchema = z6.object({
9529
11345
  action: ActionTypeSchema,
9530
11346
  address: ResourceAddressSchema,
11347
+ /** Existing state address to retain when this action is an inferred logical rename. */
11348
+ previousAddress: ResourceAddressSchema.optional(),
9531
11349
  reason: z6.string(),
9532
11350
  driftKind: DriftKindSchema.optional(),
9533
11351
  readinessImpact: PlanReadinessImpactSchema.optional(),
@@ -9593,7 +11411,8 @@ var CloudAgentSchema = z6.object({
9593
11411
  workspace_id: z6.string().optional(),
9594
11412
  created_at: z6.string().optional(),
9595
11413
  updated_at: z6.string().optional(),
9596
- archived_at: z6.string().nullish()
11414
+ archived_at: z6.string().nullish(),
11415
+ attributes: z6.record(z6.string(), z6.unknown()).optional()
9597
11416
  });
9598
11417
  var ListCloudAgentsResponseSchema = z6.object({
9599
11418
  agents: z6.array(CloudAgentSchema)
@@ -9610,7 +11429,8 @@ var CloudEnvironmentSchema = z6.object({
9610
11429
  workspace_id: z6.string().optional(),
9611
11430
  created_at: z6.string().optional(),
9612
11431
  updated_at: z6.string().optional(),
9613
- archived_at: z6.string().nullish()
11432
+ archived_at: z6.string().nullish(),
11433
+ attributes: z6.record(z6.string(), z6.unknown()).optional()
9614
11434
  });
9615
11435
  var ListCloudEnvironmentsResponseSchema = z6.object({
9616
11436
  environments: z6.array(CloudEnvironmentSchema)
@@ -9622,7 +11442,8 @@ var CloudVaultSchema = z6.object({
9622
11442
  type: z6.string().optional(),
9623
11443
  created_at: z6.string().nullish(),
9624
11444
  updated_at: z6.string().nullish(),
9625
- archived_at: z6.string().nullish()
11445
+ archived_at: z6.string().nullish(),
11446
+ attributes: z6.record(z6.string(), z6.unknown()).optional()
9626
11447
  });
9627
11448
  var ListCloudVaultsResponseSchema = z6.object({
9628
11449
  vaults: z6.array(CloudVaultSchema)
@@ -9802,6 +11623,7 @@ export {
9802
11623
  applyProviderConfigToEnv,
9803
11624
  archiveCloudAgent,
9804
11625
  archiveMemoryStore,
11626
+ archiveRemoteSession,
9805
11627
  areRuntimeCredentialsReady,
9806
11628
  batchCreateMemories,
9807
11629
  bootstrapRuntimeCredentials,
@@ -9815,6 +11637,8 @@ export {
9815
11637
  createProjectRuntime,
9816
11638
  createSessionForAgent,
9817
11639
  createSkillFromFileId,
11640
+ createVaultCredential,
11641
+ createVaultCredentialWithStateBackend,
9818
11642
  decideDestructive,
9819
11643
  deleteCloudEnvironment,
9820
11644
  deleteCloudVault,
@@ -9824,6 +11648,8 @@ export {
9824
11648
  deleteSession,
9825
11649
  deleteSkill,
9826
11650
  destroyPlannedProjectResources,
11651
+ downloadRemoteFile,
11652
+ downloadRemoteSkill,
9827
11653
  executePlannedProject,
9828
11654
  extractSkillZipFiles,
9829
11655
  getAgent,
@@ -9831,13 +11657,23 @@ export {
9831
11657
  getDeploymentRuntimeProviderForContext,
9832
11658
  getFileDownloadUrl,
9833
11659
  getFileInfo,
11660
+ getManagedAgentProviderCapabilities,
9834
11661
  getMemory,
9835
11662
  getMemoryProviderCapabilities,
9836
11663
  getMemoryStore,
9837
11664
  getMemoryVersion,
11665
+ getRemoteAgent,
11666
+ getRemoteDeployment,
11667
+ getRemoteDeploymentRun,
11668
+ getRemoteEnvironment,
11669
+ getRemoteSkill,
11670
+ getRemoteSkillDownloadInfo,
11671
+ getRemoteSkillVersion,
11672
+ getRemoteVault,
9838
11673
  getSession,
9839
11674
  getSkillInfo,
9840
11675
  importResource,
11676
+ inspectSkillSource,
9841
11677
  isTerminalSessionStatus,
9842
11678
  listAgentsWithReadiness,
9843
11679
  listCloudAgents,
@@ -9850,7 +11686,16 @@ export {
9850
11686
  listMemoryVersions,
9851
11687
  listProviderModelsForContext,
9852
11688
  listProviderNames,
11689
+ listRemoteAgentVersions,
11690
+ listRemoteAgents,
11691
+ listRemoteDeploymentRuns,
11692
+ listRemoteDeployments,
9853
11693
  listRemoteDeploymentsForContext,
11694
+ listRemoteEnvironments,
11695
+ listRemoteFiles,
11696
+ listRemoteSkillVersions,
11697
+ listRemoteSkills,
11698
+ listRemoteVaults,
9854
11699
  listSessionEvents,
9855
11700
  listSessionSummaries,
9856
11701
  listSkills,
@@ -9860,8 +11705,13 @@ export {
9860
11705
  migrateConfig,
9861
11706
  parseStateAddress,
9862
11707
  pauseDeploymentForContext,
11708
+ planAgentResources,
11709
+ planAgentResourcesWithStateBackend,
9863
11710
  planDestroyProjectContext,
9864
11711
  planProjectContext,
11712
+ planProjectWithStateBackend,
11713
+ planVaultCredentialCreate,
11714
+ planVaultCredentialCreateWithStateBackend,
9865
11715
  prepareInitialSessionPrompt,
9866
11716
  preparePromptForProvider,
9867
11717
  prependFileHint,
@@ -9877,9 +11727,12 @@ export {
9877
11727
  resolveSyncProvider,
9878
11728
  rewriteFileMentions,
9879
11729
  runDeploymentForContext,
11730
+ runRemoteDeployment,
11731
+ sendRemoteSessionEvents,
9880
11732
  sendSessionMessagePolling,
9881
11733
  sendSessionMessageStreaming,
9882
11734
  setDefaultFetch,
11735
+ setRemoteDeploymentPaused,
9883
11736
  startSessionRun,
9884
11737
  startSessionRunPolling,
9885
11738
  streamSessionEvents,
@@ -9889,6 +11742,7 @@ export {
9889
11742
  syncProviderResourcesFromEnv,
9890
11743
  updateMemory,
9891
11744
  updateMemoryStore,
11745
+ updateRemoteSession,
9892
11746
  uploadFile,
9893
11747
  validateProjectConfig,
9894
11748
  writeProjectRuntime