@lunnoa/client 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -28,16 +28,21 @@ var LunnoaApiError = class extends Error {
28
28
  method;
29
29
  /** Path of the failed request (without the base URL). */
30
30
  path;
31
+ /** Present on definition-sync 409s when the server sends the current revision. */
32
+ currentRevision;
31
33
  constructor(args) {
32
34
  const detail = extractMessage(args.body);
35
+ const currentRevision = extractCurrentRevision(args.body);
36
+ const shown = [detail, currentRevision ? `currentRevision: ${currentRevision}` : void 0].filter(Boolean).join(" ");
33
37
  super(
34
- `Lunnoa API request failed: ${args.method} ${args.path} \u2192 ${args.status}${detail ? ` (${detail})` : ""}`
38
+ `Lunnoa API request failed: ${args.method} ${args.path} \u2192 ${args.status}${shown ? ` (${shown})` : ""}`
35
39
  );
36
40
  this.name = "LunnoaApiError";
37
41
  this.status = args.status;
38
42
  this.body = args.body;
39
43
  this.method = args.method;
40
44
  this.path = args.path;
45
+ this.currentRevision = currentRevision;
41
46
  }
42
47
  /** True for 401 responses (missing, revoked, or expired credential). */
43
48
  get isUnauthorized() {
@@ -56,6 +61,11 @@ var LunnoaApiError = class extends Error {
56
61
  return this.status === 429;
57
62
  }
58
63
  };
64
+ function extractCurrentRevision(body) {
65
+ if (!body || typeof body !== "object") return void 0;
66
+ const revision = body.currentRevision;
67
+ return typeof revision === "string" ? revision : void 0;
68
+ }
59
69
  function extractMessage(body) {
60
70
  if (body && typeof body === "object") {
61
71
  const record = body;
@@ -532,6 +542,139 @@ var ActionsResource = class {
532
542
  }
533
543
  };
534
544
 
545
+ // src/define/files.ts
546
+ var STEP_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
547
+ function hasFileAgentSignals(record) {
548
+ if (record.instructions && typeof record.instructions === "object") return true;
549
+ if (record.settings && typeof record.settings === "object") return true;
550
+ if ("workflows" in record || "agents" in record || "knowledge" in record || "variables" in record || "objects" in record || "objectTypes" in record || "mcpServers" in record || "a2aAgents" in record) {
551
+ return true;
552
+ }
553
+ return Array.isArray(record.tools) && record.tools.some(
554
+ (tool) => tool && typeof tool === "object" && !("kind" in tool) && !("use" in tool)
555
+ );
556
+ }
557
+ function isAgentFileInput(config) {
558
+ if (!config || typeof config !== "object") return false;
559
+ return hasFileAgentSignals(config);
560
+ }
561
+ function isAgentFileShape(config) {
562
+ if (!config || typeof config !== "object") return false;
563
+ return hasFileAgentSignals(config);
564
+ }
565
+ function acceptAgentFile(config) {
566
+ const slug = config.slug?.trim();
567
+ if (!slug) throw new Error("defineAgent requires slug");
568
+ const instructions = config.instructions;
569
+ const fileRef = instructions && typeof instructions === "object" && typeof instructions.file === "string" && instructions.file.trim().length > 0;
570
+ if (typeof instructions !== "string" && !fileRef) {
571
+ throw new Error("defineAgent requires instructions");
572
+ }
573
+ const copy = { ...config };
574
+ delete copy.$schema;
575
+ delete copy.kind;
576
+ return { ...copy, kind: "agent", slug, instructions };
577
+ }
578
+ function assertStepKeys(steps, seen) {
579
+ for (const step of steps ?? []) {
580
+ if (!step?.use?.id?.trim()) {
581
+ throw new Error("workflow step requires use.id");
582
+ }
583
+ if (step.key !== void 0) {
584
+ if (!STEP_KEY_PATTERN.test(step.key) || step.key === "trigger") {
585
+ throw new Error(
586
+ `Step key "${step.key}" must start with a letter, use letters, digits, - or _, and not be "trigger".`
587
+ );
588
+ }
589
+ if (seen.has(step.key)) {
590
+ throw new Error(`Step key "${step.key}" is used twice.`);
591
+ }
592
+ seen.add(step.key);
593
+ }
594
+ for (const path of step.paths ?? []) {
595
+ assertStepKeys(path.steps ?? [], seen);
596
+ }
597
+ }
598
+ }
599
+ function acceptWorkflowStepsFile(config) {
600
+ const slug = config.slug?.trim();
601
+ if (!slug) throw new Error("defineWorkflow requires slug");
602
+ if (!config.steps?.length) {
603
+ throw new Error("defineWorkflow requires at least one step");
604
+ }
605
+ if (config.trigger && !config.trigger.id?.trim()) {
606
+ throw new Error("defineWorkflow trigger requires id");
607
+ }
608
+ assertStepKeys(config.steps, /* @__PURE__ */ new Set());
609
+ const copy = { ...config };
610
+ delete copy.$schema;
611
+ delete copy.kind;
612
+ return {
613
+ ...copy,
614
+ kind: "workflow",
615
+ format: "steps",
616
+ slug
617
+ };
618
+ }
619
+ function acceptWorkflowGraphFile(config) {
620
+ const slug = config.slug?.trim();
621
+ if (!slug) throw new Error("defineWorkflow requires slug");
622
+ if (!Array.isArray(config.nodes) || config.nodes.length === 0) {
623
+ throw new Error("defineWorkflow graph requires nodes");
624
+ }
625
+ const keys = /* @__PURE__ */ new Set();
626
+ let triggers = 0;
627
+ for (const node of config.nodes) {
628
+ if (!node?.key || typeof node.key !== "string") {
629
+ throw new Error("graph node requires key");
630
+ }
631
+ if (!STEP_KEY_PATTERN.test(node.key)) {
632
+ throw new Error(
633
+ `Node key "${node.key}" must start with a letter, use letters, digits, - or _, and not be empty.`
634
+ );
635
+ }
636
+ if (keys.has(node.key)) {
637
+ throw new Error(`Node key "${node.key}" is used twice.`);
638
+ }
639
+ keys.add(node.key);
640
+ if (node.nodeType === "trigger") triggers += 1;
641
+ }
642
+ if (triggers !== 1) {
643
+ throw new Error("defineWorkflow graph requires exactly one trigger");
644
+ }
645
+ for (const edge of config.edges ?? []) {
646
+ if (!keys.has(edge?.source) || !keys.has(edge?.target)) {
647
+ throw new Error(
648
+ `Edge from "${edge?.source ?? ""}" to "${edge?.target ?? ""}" references an unknown key.`
649
+ );
650
+ }
651
+ }
652
+ const copy = { ...config };
653
+ delete copy.$schema;
654
+ delete copy.kind;
655
+ return {
656
+ ...copy,
657
+ kind: "workflow",
658
+ format: "graph",
659
+ slug,
660
+ edges: config.edges ?? []
661
+ };
662
+ }
663
+ function isWorkflowGraphInput(config) {
664
+ return !!config && typeof config === "object" && config.format === "graph";
665
+ }
666
+ function isWorkflowStepsFile(config) {
667
+ if (!config || typeof config !== "object") return false;
668
+ const record = config;
669
+ if (record.format === "steps") return true;
670
+ if (record.trigger && typeof record.trigger === "object" && record.trigger.kind !== "trigger" && typeof record.trigger.id === "string") {
671
+ return true;
672
+ }
673
+ return Array.isArray(record.steps) && record.steps.some(
674
+ (step) => step && typeof step === "object" && step.use && step.use?.kind !== "action"
675
+ );
676
+ }
677
+
535
678
  // src/define/index.ts
536
679
  var DEFINE_KINDS = {
537
680
  connection: "connection",
@@ -601,7 +744,7 @@ function defineTrigger(config) {
601
744
  }
602
745
  var MANUAL_TRIGGER_ID = "flow-control_trigger_manual";
603
746
  var TRIGGER_KEY = "trigger";
604
- var STEP_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/;
747
+ var STEP_KEY_PATTERN2 = /^[A-Za-z][A-Za-z0-9_-]*$/;
605
748
  var STEP_REF_PATTERN = /={{step:([^}]*)}}/g;
606
749
  function refString(key, path) {
607
750
  const parts = [key, ...path.map(String)];
@@ -641,7 +784,7 @@ var SINGLE_REF_PATTERN = /^={{step:[^}]*}}$/;
641
784
  function collectKeys(steps, seen) {
642
785
  for (const step of steps) {
643
786
  if (step.key !== void 0) {
644
- if (!STEP_KEY_PATTERN.test(step.key) || step.key === TRIGGER_KEY) {
787
+ if (!STEP_KEY_PATTERN2.test(step.key) || step.key === TRIGGER_KEY) {
645
788
  throw new Error(
646
789
  `Step key "${step.key}" must start with a letter, use letters, digits, - or _, and not be "${TRIGGER_KEY}".`
647
790
  );
@@ -725,29 +868,43 @@ function assertStepRefs(config) {
725
868
  checkChain(config.steps, /* @__PURE__ */ new Set([TRIGGER_KEY]));
726
869
  }
727
870
  function defineWorkflow(config) {
728
- if (!config.slug?.trim()) {
871
+ const record = config;
872
+ if (isWorkflowGraphInput(config) || Array.isArray(record.nodes) && !Array.isArray(record.steps)) {
873
+ return acceptWorkflowGraphFile(config);
874
+ }
875
+ if (isWorkflowStepsFile(config)) {
876
+ return acceptWorkflowStepsFile(config);
877
+ }
878
+ const authored = { ...config };
879
+ delete authored.$schema;
880
+ if (!authored.slug?.trim()) {
729
881
  throw new Error("defineWorkflow requires slug");
730
882
  }
731
- if (!config.steps?.length) {
883
+ if (!authored.steps?.length) {
732
884
  throw new Error("defineWorkflow requires at least one step");
733
885
  }
734
- if (config.trigger) {
735
- assertTriggerConfig(config.trigger);
886
+ if (authored.trigger) {
887
+ assertTriggerConfig(authored.trigger);
736
888
  }
737
- assertStepRefs(config);
738
- return { kind: DEFINE_KINDS.workflow, ...config };
889
+ assertStepRefs(authored);
890
+ return { kind: DEFINE_KINDS.workflow, ...authored };
739
891
  }
740
892
  function defineAgent(config) {
741
- if (!config.slug?.trim()) {
893
+ if (isAgentFileInput(config)) {
894
+ return acceptAgentFile(config);
895
+ }
896
+ const authored = { ...config };
897
+ delete authored.$schema;
898
+ if (!authored.slug?.trim()) {
742
899
  throw new Error("defineAgent requires slug");
743
900
  }
744
- if (!config.model?.trim()) {
901
+ if (!authored.model?.trim()) {
745
902
  throw new Error("defineAgent requires model");
746
903
  }
747
- if (config.instructions == null) {
904
+ if (authored.instructions == null) {
748
905
  throw new Error("defineAgent requires instructions");
749
906
  }
750
- return { kind: DEFINE_KINDS.agent, ...config };
907
+ return { kind: DEFINE_KINDS.agent, ...authored };
751
908
  }
752
909
  function defineEntityType(config) {
753
910
  if (!config.slug?.trim()) {
@@ -862,10 +1019,24 @@ function unwrapTool(tool) {
862
1019
  }
863
1020
  return tool;
864
1021
  }
1022
+ function syncFields(options) {
1023
+ return {
1024
+ ...options?.baseRevision ? { baseRevision: options.baseRevision } : {},
1025
+ ...options?.force ? { force: true } : {}
1026
+ };
1027
+ }
1028
+ function idsOf(links) {
1029
+ if (!links) return void 0;
1030
+ return links.map((link) => link.id);
1031
+ }
865
1032
  function agentDefinitionToUpsert(def, options) {
1033
+ if (isAgentFileShape(def)) {
1034
+ return fileAgentToUpsert(def, options);
1035
+ }
866
1036
  const tools = [];
867
1037
  const workflowIds = [...options?.workflowIds ?? []];
868
- for (const tool of def.tools ?? []) {
1038
+ const authored = def;
1039
+ for (const tool of authored.tools ?? []) {
869
1040
  const unwrapped = unwrapTool(tool);
870
1041
  if (unwrapped.kind === DEFINE_KINDS.workflow) {
871
1042
  continue;
@@ -881,17 +1052,65 @@ function agentDefinitionToUpsert(def, options) {
881
1052
  });
882
1053
  }
883
1054
  }
1055
+ return {
1056
+ slug: authored.slug,
1057
+ name: authored.name,
1058
+ description: authored.description,
1059
+ instructions: authored.instructions,
1060
+ model: authored.model,
1061
+ aiConnectionId: authored.aiConnection?.id,
1062
+ connectionIds: authored.connections?.map((c) => c.id).filter((id) => Boolean(id)),
1063
+ workflowIds: workflowIds.length ? workflowIds : void 0,
1064
+ tools,
1065
+ codeSource: options?.codeSource ?? "generated",
1066
+ ...syncFields(options)
1067
+ };
1068
+ }
1069
+ function fileAgentToUpsert(def, options) {
1070
+ if (typeof def.instructions !== "string") {
1071
+ throw new Error(
1072
+ "Agent instructions are still a file reference. The CLI resolves these before push."
1073
+ );
1074
+ }
1075
+ const tools = [];
1076
+ for (const tool of def.tools ?? []) {
1077
+ const action = {
1078
+ kind: DEFINE_KINDS.action,
1079
+ id: tool.id,
1080
+ appId: tool.appId,
1081
+ connection: tool.connection?.id ? { kind: DEFINE_KINDS.connection, id: tool.connection.id } : void 0
1082
+ };
1083
+ tools.push({
1084
+ key: tool.key,
1085
+ appId: resolveActionAppId(action),
1086
+ actionId: resolveActionId(action),
1087
+ connectionId: tool.connection?.id,
1088
+ name: tool.name,
1089
+ description: tool.description,
1090
+ input: tool.input
1091
+ });
1092
+ }
884
1093
  return {
885
1094
  slug: def.slug,
886
1095
  name: def.name,
887
- description: def.description,
1096
+ // A file is the whole definition. Omitted description and model are empty.
1097
+ description: def.description ?? null,
888
1098
  instructions: def.instructions,
889
- model: def.model,
1099
+ model: def.model ?? null,
890
1100
  aiConnectionId: def.aiConnection?.id,
891
- connectionIds: def.connections?.map((c) => c.id).filter((id) => Boolean(id)),
892
- workflowIds: workflowIds.length ? workflowIds : void 0,
893
- tools,
894
- managedByCode: true
1101
+ ...def.settings ? { settings: def.settings } : {},
1102
+ ...def.tools ? { tools } : {},
1103
+ ...def.workflows ? { workflows: def.workflows } : {},
1104
+ ...def.agents ? { agents: def.agents } : {},
1105
+ ...def.connections ? { connectionIds: idsOf(def.connections) } : {},
1106
+ ...def.knowledge ? { knowledgeIds: idsOf(def.knowledge) } : {},
1107
+ ...def.variables ? { variableIds: idsOf(def.variables) } : {},
1108
+ ...def.objects ? { objectIds: idsOf(def.objects) } : {},
1109
+ ...def.objectTypes ? { objectTypeIds: idsOf(def.objectTypes) } : {},
1110
+ ...def.mcpServers ? { mcpServers: def.mcpServers } : {},
1111
+ ...def.a2aAgents ? { a2aAgentIds: idsOf(def.a2aAgents) } : {},
1112
+ codeSource: "synced",
1113
+ ...syncFields(options)
895
1114
  };
896
1115
  }
897
1116
  var AgentsResource = class {
@@ -911,15 +1130,22 @@ var AgentsResource = class {
911
1130
  query: serializeListQuery(options)
912
1131
  });
913
1132
  }
1133
+ /** Exported definition for `lunnoa/agents/<slug>.json`. */
1134
+ getDefinition(slug) {
1135
+ return this.http.get(
1136
+ `/api/agents/slug/${encodeURIComponent(slug)}/definition`
1137
+ );
1138
+ }
914
1139
  /**
915
1140
  * Upsert an agent by slug inside the workspace on the API key.
916
1141
  * Prefer the CLI (`npx @lunnoa/client agents deploy`) for happy-path deploy.
917
1142
  */
918
1143
  upsertBySlug(body, options) {
919
1144
  const payload = "kind" in body && body.kind === "agent" ? agentDefinitionToUpsert(body, options) : body;
920
- return this.http.post("/api/agents/upsert", {
921
- body: payload
922
- });
1145
+ return this.http.post(
1146
+ "/api/agents/upsert",
1147
+ { body: payload }
1148
+ );
923
1149
  }
924
1150
  };
925
1151
 
@@ -2043,6 +2269,11 @@ function stepFromDefinition(step) {
2043
2269
  }
2044
2270
  function normalizeStartRunInput(input) {
2045
2271
  if (isWorkflowDefinition(input)) {
2272
+ if ("format" in input && input.format === "graph") {
2273
+ throw new Error(
2274
+ "runs.start runs straight lines only. Push the graph workflow, then execute it."
2275
+ );
2276
+ }
2046
2277
  return {
2047
2278
  steps: input.steps.map(stepFromDefinition),
2048
2279
  name: input.name ?? input.slug
@@ -2234,6 +2465,18 @@ var WorkflowAppsResource = class {
2234
2465
  }
2235
2466
  };
2236
2467
 
2468
+ // src/resources/code-sync.ts
2469
+ var CodeSyncResource = class {
2470
+ constructor(http) {
2471
+ this.http = http;
2472
+ }
2473
+ http;
2474
+ /** Workspace id and whether synced resources are locked in the UI. */
2475
+ context() {
2476
+ return this.http.get("/api/code-sync/context");
2477
+ }
2478
+ };
2479
+
2237
2480
  // src/resources/workflows.ts
2238
2481
  function triggerToUpsertInput(trigger) {
2239
2482
  return {
@@ -2246,8 +2489,38 @@ function triggerToUpsertInput(trigger) {
2246
2489
  ...trigger.description ? { description: trigger.description } : {}
2247
2490
  };
2248
2491
  }
2492
+ function asAction(use) {
2493
+ if (use && typeof use === "object" && "kind" in use && use.kind === DEFINE_KINDS.action) {
2494
+ return use;
2495
+ }
2496
+ const fileUse = use;
2497
+ return {
2498
+ kind: DEFINE_KINDS.action,
2499
+ id: fileUse.id,
2500
+ appId: fileUse.appId,
2501
+ connection: fileUse.connection?.id ? { kind: DEFINE_KINDS.connection, id: fileUse.connection.id } : void 0
2502
+ };
2503
+ }
2504
+ function asTrigger(trigger) {
2505
+ if ("kind" in trigger && trigger.kind === DEFINE_KINDS.trigger) {
2506
+ return trigger;
2507
+ }
2508
+ const fileTrigger = trigger;
2509
+ return {
2510
+ kind: DEFINE_KINDS.trigger,
2511
+ id: fileTrigger.id,
2512
+ appId: fileTrigger.appId,
2513
+ connection: fileTrigger.connection?.id ? { kind: DEFINE_KINDS.connection, id: fileTrigger.connection.id } : void 0,
2514
+ input: fileTrigger.input,
2515
+ inputs: fileTrigger.inputs,
2516
+ name: fileTrigger.name,
2517
+ description: fileTrigger.description
2518
+ };
2519
+ }
2249
2520
  function stepToUpsertInput(step) {
2250
- const use = step.use;
2521
+ const use = asAction(step.use);
2522
+ const retry = "retrySettings" in step ? step.retrySettings : void 0;
2523
+ const continueOnFailure = "continueOnFailure" in step ? step.continueOnFailure : void 0;
2251
2524
  return {
2252
2525
  ...step.key ? { key: step.key } : {},
2253
2526
  appId: resolveActionAppId(use),
@@ -2258,25 +2531,60 @@ function stepToUpsertInput(step) {
2258
2531
  ...step.input ?? {}
2259
2532
  },
2260
2533
  name: step.name ?? use.name,
2261
- description: use.description,
2534
+ description: step.description ?? use.description,
2535
+ ...retry ? { retrySettings: retry } : {},
2536
+ ...continueOnFailure ? { continueOnFailure } : {},
2262
2537
  ...step.paths?.length ? {
2263
2538
  paths: step.paths.map((path) => ({
2264
2539
  label: path.label,
2265
2540
  ...path.when ? { when: path.when } : {},
2266
- steps: path.steps.map(stepToUpsertInput)
2541
+ steps: path.steps.map(
2542
+ (nested) => stepToUpsertInput(nested)
2543
+ )
2267
2544
  }))
2268
2545
  } : {}
2269
2546
  };
2270
2547
  }
2271
- function workflowDefinitionToUpsert(def) {
2548
+ function syncFields2(options) {
2272
2549
  return {
2273
- slug: def.slug,
2274
- name: def.name,
2275
- description: def.description,
2276
- isActive: def.isActive,
2277
- ...def.trigger ? { trigger: triggerToUpsertInput(def.trigger) } : {},
2278
- managedByCode: true,
2279
- steps: def.steps.map(stepToUpsertInput)
2550
+ ...options?.baseRevision ? { baseRevision: options.baseRevision } : {},
2551
+ ...options?.force ? { force: true } : {}
2552
+ };
2553
+ }
2554
+ function workflowDefinitionToUpsert(def, options) {
2555
+ if ("format" in def && def.format === "graph") {
2556
+ return {
2557
+ slug: def.slug,
2558
+ name: def.name,
2559
+ // A file is the whole definition: an omitted description is empty, not "leave it".
2560
+ description: def.description ?? null,
2561
+ codeSource: "synced",
2562
+ graph: { nodes: def.nodes, edges: def.edges ?? [] },
2563
+ ...syncFields2(options)
2564
+ };
2565
+ }
2566
+ if ("format" in def && def.format === "steps") {
2567
+ const file = def;
2568
+ return {
2569
+ slug: file.slug,
2570
+ name: file.name,
2571
+ description: file.description ?? null,
2572
+ ...file.trigger ? { trigger: triggerToUpsertInput(asTrigger(file.trigger)) } : {},
2573
+ codeSource: "synced",
2574
+ steps: file.steps.map((step) => stepToUpsertInput(step)),
2575
+ ...syncFields2(options)
2576
+ };
2577
+ }
2578
+ const authored = def;
2579
+ return {
2580
+ slug: authored.slug,
2581
+ name: authored.name,
2582
+ description: authored.description,
2583
+ isActive: authored.isActive,
2584
+ ...authored.trigger ? { trigger: triggerToUpsertInput(authored.trigger) } : {},
2585
+ codeSource: options?.codeSource ?? "generated",
2586
+ ...syncFields2(options),
2587
+ steps: authored.steps.map((step) => stepToUpsertInput(step))
2280
2588
  };
2281
2589
  }
2282
2590
  var WorkflowsResource = class {
@@ -2301,15 +2609,22 @@ var WorkflowsResource = class {
2301
2609
  query: serializeListQuery(options)
2302
2610
  });
2303
2611
  }
2612
+ /** Exported definition for `lunnoa/workflows/<slug>.json`. */
2613
+ getDefinition(slug) {
2614
+ return this.http.get(
2615
+ `/api/workflows/slug/${encodeURIComponent(slug)}/definition`
2616
+ );
2617
+ }
2304
2618
  /**
2305
2619
  * Upsert a workflow by slug inside the workspace on the API key.
2306
2620
  * Prefer the CLI (`npx @lunnoa/client workflows deploy`) for happy-path deploy.
2307
2621
  */
2308
- upsertBySlug(body) {
2309
- const payload = "kind" in body && body.kind === "workflow" ? workflowDefinitionToUpsert(body) : body;
2310
- return this.http.post("/api/workflows/upsert", {
2311
- body: payload
2312
- });
2622
+ upsertBySlug(body, options) {
2623
+ const payload = "kind" in body && body.kind === "workflow" ? workflowDefinitionToUpsert(body, options) : body;
2624
+ return this.http.post(
2625
+ "/api/workflows/upsert",
2626
+ { body: payload }
2627
+ );
2313
2628
  }
2314
2629
  /**
2315
2630
  * Starts a new execution of the workflow with the given trigger inputs.
@@ -2375,6 +2690,8 @@ var LunnoaClient = class {
2375
2690
  aiConnections;
2376
2691
  workflowApps;
2377
2692
  discovery;
2693
+ /** Workspace id for the definitions lock, and the code-sync lock flag. */
2694
+ codeSync;
2378
2695
  constructor(options) {
2379
2696
  this.http = new HttpClient(options);
2380
2697
  this.auth = new AuthResource(this.http, this.http.tokenStore);
@@ -2398,6 +2715,7 @@ var LunnoaClient = class {
2398
2715
  this.connections = new ConnectionsResource(this.http);
2399
2716
  this.aiConnections = new AiConnectionsResource(this.http);
2400
2717
  this.discovery = new DiscoveryResource(this.http);
2718
+ this.codeSync = new CodeSyncResource(this.http);
2401
2719
  }
2402
2720
  };
2403
2721
 
@@ -2481,6 +2799,7 @@ exports.AgentsResource = AgentsResource;
2481
2799
  exports.AiConnectionsResource = AiConnectionsResource;
2482
2800
  exports.ApprovalsResource = ApprovalsResource;
2483
2801
  exports.AuthResource = AuthResource;
2802
+ exports.CodeSyncResource = CodeSyncResource;
2484
2803
  exports.ConnectionsResource = ConnectionsResource;
2485
2804
  exports.DEFINE_KINDS = DEFINE_KINDS;
2486
2805
  exports.DiscoveryResource = DiscoveryResource;
@@ -2517,6 +2836,7 @@ exports.defineEntityType = defineEntityType;
2517
2836
  exports.defineTrigger = defineTrigger;
2518
2837
  exports.defineWorkflow = defineWorkflow;
2519
2838
  exports.entityTypeDefinitionToUpsert = entityTypeDefinitionToUpsert;
2839
+ exports.isAgentFileShape = isAgentFileShape;
2520
2840
  exports.isBrowserEnvironment = isBrowserEnvironment;
2521
2841
  exports.isLoginRequires2FA = isLoginRequires2FA;
2522
2842
  exports.iterateOffset = iterateOffset;