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