@cargo-ai/cli 1.0.26 → 1.0.28
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 +1 -1
- package/build/commands/hosting/app.js +1 -1
- package/build/commands/hosting/deployment.d.ts.map +1 -1
- package/build/commands/hosting/deployment.js +22 -0
- package/build/commands/hosting/worker.d.ts.map +1 -1
- package/build/commands/hosting/worker.js +12 -5
- package/build/index.js +4 -2
- package/package.json +4 -4
- package/build/commands/cdk/index.d.ts +0 -4
- package/build/commands/cdk/index.d.ts.map +0 -1
- package/build/commands/cdk/index.js +0 -539
- package/build/commands/cdk/init.d.ts +0 -3
- package/build/commands/cdk/init.d.ts.map +0 -1
- package/build/commands/cdk/init.js +0 -86
- package/build/commands/cdk/inputTypes.d.ts +0 -24
- package/build/commands/cdk/inputTypes.d.ts.map +0 -1
- package/build/commands/cdk/inputTypes.js +0 -273
- package/build/commands/cdk/types.d.ts +0 -4
- package/build/commands/cdk/types.d.ts.map +0 -1
- package/build/commands/cdk/types.js +0 -385
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
// TypeScript input-type printers for `cargo-ai workflow sync` codegen.
|
|
2
|
-
//
|
|
3
|
-
// Three sources of truth, three printers:
|
|
4
|
-
// - Integration actions expose their config as JSON Schema on
|
|
5
|
-
// `connection.integration.list` (`action.config.schema`).
|
|
6
|
-
// - Workspace tools expose their input as `formFields` on the tool
|
|
7
|
-
// workflow's deployed release (`orchestration.release.getDeployed`).
|
|
8
|
-
// - Agent nodes accept a single global shape (`{ prompt, output? }`) —
|
|
9
|
-
// the engine validates every agent node against `AiUtils.agentConfig`.
|
|
10
|
-
//
|
|
11
|
-
// All printers run in "input mode": each top-level property is widened to
|
|
12
|
-
// `Ref<T> | T` so callers can pass either a builder Ref or a literal.
|
|
13
|
-
// Anything unrecognized falls back to `unknown` — codegen must never abort
|
|
14
|
-
// on a schema edge case.
|
|
15
|
-
//
|
|
16
|
-
// Mirrors `packages/workflow-sdk/scripts/lib/jsonSchemaToTs.ts` (which is a
|
|
17
|
-
// build-time-only script the CLI can't import).
|
|
18
|
-
/**
|
|
19
|
-
* Fixed input shape of every agent node. Matches the SDK's `AgentInput`
|
|
20
|
-
* type and the engine's `AiUtils.agentConfig` schema.
|
|
21
|
-
*/
|
|
22
|
-
export const AGENT_INPUT_TYPE_SRC = `{ prompt: Ref<string> | string; ` +
|
|
23
|
-
`output?: { type: "default" | "text" | "jsonSchema"; jsonSchema?: Record<string, unknown> } }`;
|
|
24
|
-
/**
|
|
25
|
-
* Print an integration action's JSON Schema config as a TS input type.
|
|
26
|
-
* Returns `"Record<string, unknown>"` when the schema is missing or not an
|
|
27
|
-
* object schema we can render.
|
|
28
|
-
*/
|
|
29
|
-
export function printJsonSchemaInput(schema) {
|
|
30
|
-
if (schema === null || typeof schema !== "object") {
|
|
31
|
-
return "Record<string, unknown>";
|
|
32
|
-
}
|
|
33
|
-
const printed = printSchema(schema, true, false);
|
|
34
|
-
return printed === "unknown" ? "Record<string, unknown>" : printed;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Like {@link printJsonSchemaInput} but WITHOUT the top-level `Ref<T> | T`
|
|
38
|
-
* widening — for CDK connector/model config types, which are plain data (no
|
|
39
|
-
* workflow builder Refs). Used by `cargo-ai cdk types`.
|
|
40
|
-
*/
|
|
41
|
-
export function printJsonSchemaType(schema) {
|
|
42
|
-
if (schema === null || typeof schema !== "object") {
|
|
43
|
-
return "Record<string, unknown>";
|
|
44
|
-
}
|
|
45
|
-
// encRef=true: print `EncryptionRef` at encryption-typed fields so only those
|
|
46
|
-
// accept a `secret()`.
|
|
47
|
-
const printed = printSchema(schema, false, true);
|
|
48
|
-
return printed === "unknown" ? "Record<string, unknown>" : printed;
|
|
49
|
-
}
|
|
50
|
-
// The platform's shared `encryption` schema definition: an object with a `type`
|
|
51
|
-
// const/enum of "encryption" plus `isEncrypted` and `value`. In CDK config types
|
|
52
|
-
// these positions become `EncryptionRef` (see printObject).
|
|
53
|
-
function isEncryptionSchema(schema) {
|
|
54
|
-
const props = schema.properties;
|
|
55
|
-
if (props === undefined)
|
|
56
|
-
return false;
|
|
57
|
-
const typeProp = props["type"];
|
|
58
|
-
if (typeProp === undefined)
|
|
59
|
-
return false;
|
|
60
|
-
const isEnc = typeProp.const === "encryption" ||
|
|
61
|
-
(Array.isArray(typeProp.enum) &&
|
|
62
|
-
typeProp.enum.length === 1 &&
|
|
63
|
-
typeProp.enum[0] === "encryption");
|
|
64
|
-
return (isEnc && props["isEncrypted"] !== undefined && props["value"] !== undefined);
|
|
65
|
-
}
|
|
66
|
-
function printSchema(schema, topLevel, encRef) {
|
|
67
|
-
if (Array.isArray(schema.type)) {
|
|
68
|
-
return uniqueUnion(schema.type.map((t) => printPrimitive(t, schema, false, encRef)));
|
|
69
|
-
}
|
|
70
|
-
if (schema.enum !== undefined && schema.enum.length > 0) {
|
|
71
|
-
return schema.enum.map((v) => JSON.stringify(v)).join(" | ");
|
|
72
|
-
}
|
|
73
|
-
if (schema.const !== undefined) {
|
|
74
|
-
return JSON.stringify(schema.const);
|
|
75
|
-
}
|
|
76
|
-
if (schema.oneOf !== undefined && schema.oneOf.length > 0) {
|
|
77
|
-
return uniqueUnion(schema.oneOf.map((s) => printSchema(s, false, encRef)));
|
|
78
|
-
}
|
|
79
|
-
if (schema.anyOf !== undefined && schema.anyOf.length > 0) {
|
|
80
|
-
return uniqueUnion(schema.anyOf.map((s) => printSchema(s, false, encRef)));
|
|
81
|
-
}
|
|
82
|
-
if (schema.allOf !== undefined && schema.allOf.length > 0) {
|
|
83
|
-
// Connectors model "pick an auth method, then its fields" as an object with
|
|
84
|
-
// a discriminant property plus `allOf: [{ if, then, else }]`. Expand that to
|
|
85
|
-
// a discriminated union (e.g. HubSpot → `{ method: "privateApp"; … } | { …
|
|
86
|
-
// "oauth"; … }`); otherwise fall back to rendering the head.
|
|
87
|
-
const conditional = printConditionalObject(schema, topLevel, encRef);
|
|
88
|
-
if (conditional !== undefined)
|
|
89
|
-
return conditional;
|
|
90
|
-
return printSchema(schema.allOf[0], topLevel, encRef);
|
|
91
|
-
}
|
|
92
|
-
if (typeof schema.type !== "string")
|
|
93
|
-
return "unknown";
|
|
94
|
-
return printPrimitive(schema.type, schema, topLevel, encRef);
|
|
95
|
-
}
|
|
96
|
-
function printPrimitive(type, schema, topLevel, encRef) {
|
|
97
|
-
switch (type) {
|
|
98
|
-
case "string":
|
|
99
|
-
return "string";
|
|
100
|
-
case "number":
|
|
101
|
-
case "integer":
|
|
102
|
-
return "number";
|
|
103
|
-
case "boolean":
|
|
104
|
-
return "boolean";
|
|
105
|
-
case "null":
|
|
106
|
-
return "null";
|
|
107
|
-
case "array":
|
|
108
|
-
return printArray(schema, encRef);
|
|
109
|
-
case "object":
|
|
110
|
-
return printObject(schema, topLevel, encRef);
|
|
111
|
-
default:
|
|
112
|
-
return "unknown";
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
// Expand the connector "discriminant + allOf[{ if, then, else }]" pattern into a
|
|
116
|
-
// discriminated union. Returns undefined when the schema isn't that shape (the
|
|
117
|
-
// caller then falls back to rendering the allOf head).
|
|
118
|
-
function printConditionalObject(schema, topLevel, encRef) {
|
|
119
|
-
const props = schema.properties;
|
|
120
|
-
if (props === undefined || schema.allOf === undefined)
|
|
121
|
-
return undefined;
|
|
122
|
-
const block = schema.allOf.find((a) => a.if !== undefined);
|
|
123
|
-
if (block === undefined || block.if?.properties === undefined)
|
|
124
|
-
return undefined;
|
|
125
|
-
// The discriminant: the single property the `if` tests, and its `const` value.
|
|
126
|
-
const ifEntries = Object.entries(block.if.properties);
|
|
127
|
-
if (ifEntries.length !== 1)
|
|
128
|
-
return undefined;
|
|
129
|
-
const [discKey, discCond] = ifEntries[0];
|
|
130
|
-
const thenValue = discCond.const;
|
|
131
|
-
if (thenValue === undefined)
|
|
132
|
-
return undefined;
|
|
133
|
-
// All the discriminant's allowed values, from its own oneOf/enum consts.
|
|
134
|
-
const discSchema = props[discKey];
|
|
135
|
-
const values = discriminantValues(discSchema);
|
|
136
|
-
if (values.length === 0)
|
|
137
|
-
return undefined;
|
|
138
|
-
const baseRequired = Array.isArray(schema.required) ? schema.required : [];
|
|
139
|
-
const branches = values.map((value) => {
|
|
140
|
-
const isThen = value === thenValue;
|
|
141
|
-
const extra = isThen ? block.then : block.else;
|
|
142
|
-
const branchProps = {
|
|
143
|
-
...props,
|
|
144
|
-
[discKey]: { const: value },
|
|
145
|
-
};
|
|
146
|
-
if (extra?.properties !== undefined) {
|
|
147
|
-
Object.assign(branchProps, extra.properties);
|
|
148
|
-
}
|
|
149
|
-
const required = new Set(baseRequired);
|
|
150
|
-
if (Array.isArray(extra?.required)) {
|
|
151
|
-
for (const r of extra.required)
|
|
152
|
-
required.add(r);
|
|
153
|
-
}
|
|
154
|
-
return printSchema({ type: "object", properties: branchProps, required: [...required] }, topLevel, encRef);
|
|
155
|
-
});
|
|
156
|
-
return uniqueUnion(branches);
|
|
157
|
-
}
|
|
158
|
-
function discriminantValues(schema) {
|
|
159
|
-
if (schema === undefined)
|
|
160
|
-
return [];
|
|
161
|
-
if (schema.const !== undefined)
|
|
162
|
-
return [schema.const];
|
|
163
|
-
if (Array.isArray(schema.enum))
|
|
164
|
-
return schema.enum;
|
|
165
|
-
const variants = schema.oneOf ?? schema.anyOf;
|
|
166
|
-
if (Array.isArray(variants)) {
|
|
167
|
-
const consts = variants.map((v) => v.const).filter((v) => v !== undefined);
|
|
168
|
-
if (consts.length > 0)
|
|
169
|
-
return consts;
|
|
170
|
-
}
|
|
171
|
-
return [];
|
|
172
|
-
}
|
|
173
|
-
function printArray(schema, encRef) {
|
|
174
|
-
if (schema.items === undefined)
|
|
175
|
-
return "unknown[]";
|
|
176
|
-
if (Array.isArray(schema.items)) {
|
|
177
|
-
return `[${schema.items.map((s) => printSchema(s, false, encRef)).join(", ")}]`;
|
|
178
|
-
}
|
|
179
|
-
return `Array<${printSchema(schema.items, false, encRef)}>`;
|
|
180
|
-
}
|
|
181
|
-
function printObject(schema, topLevel, encRef) {
|
|
182
|
-
// An encryption-typed field becomes `EncryptionRef` (which accepts `secret()`)
|
|
183
|
-
// — but only in CDK config mode; workflow input types print it structurally.
|
|
184
|
-
if (encRef && isEncryptionSchema(schema))
|
|
185
|
-
return "EncryptionRef";
|
|
186
|
-
const props = schema.properties;
|
|
187
|
-
if (props === undefined) {
|
|
188
|
-
if (typeof schema.additionalProperties === "object" &&
|
|
189
|
-
schema.additionalProperties !== null) {
|
|
190
|
-
return `Record<string, ${printSchema(schema.additionalProperties, false, encRef)}>`;
|
|
191
|
-
}
|
|
192
|
-
return "Record<string, unknown>";
|
|
193
|
-
}
|
|
194
|
-
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
195
|
-
const fields = [];
|
|
196
|
-
for (const [key, child] of Object.entries(props)) {
|
|
197
|
-
const inner = printSchema(child, false, encRef);
|
|
198
|
-
// Only top-level properties are Ref-widened; nested values are plain.
|
|
199
|
-
const value = topLevel ? `Ref<${inner}> | ${inner}` : inner;
|
|
200
|
-
const opt = required.has(key) ? "" : "?";
|
|
201
|
-
fields.push(`${tsKey(key)}${opt}: ${value}`);
|
|
202
|
-
}
|
|
203
|
-
if (fields.length === 0)
|
|
204
|
-
return "Record<string, never>";
|
|
205
|
-
return `{ ${fields.join("; ")} }`;
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Print a tool release's `formFields` as a TS input type. Returns
|
|
209
|
-
* `undefined` when the fields can't be interpreted (caller falls back to
|
|
210
|
-
* `Record<string, unknown>`).
|
|
211
|
-
*/
|
|
212
|
-
export function printFormFieldsInput(formFields) {
|
|
213
|
-
if (!Array.isArray(formFields))
|
|
214
|
-
return undefined;
|
|
215
|
-
const fields = formFields.filter(isFormFieldLike);
|
|
216
|
-
if (fields.length === 0)
|
|
217
|
-
return "Record<string, never>";
|
|
218
|
-
const rendered = fields.map((f) => {
|
|
219
|
-
const inner = formFieldToTs(f);
|
|
220
|
-
const opt = f.isRequired === true ? "" : "?";
|
|
221
|
-
return `${tsKey(f.slug)}${opt}: Ref<${inner}> | ${inner}`;
|
|
222
|
-
});
|
|
223
|
-
return `{ ${rendered.join("; ")} }`;
|
|
224
|
-
}
|
|
225
|
-
function isFormFieldLike(value) {
|
|
226
|
-
if (value === null || typeof value !== "object")
|
|
227
|
-
return false;
|
|
228
|
-
const v = value;
|
|
229
|
-
return typeof v["slug"] === "string" && typeof v["kind"] === "string";
|
|
230
|
-
}
|
|
231
|
-
function formFieldToTs(field) {
|
|
232
|
-
switch (field.kind) {
|
|
233
|
-
case "string":
|
|
234
|
-
case "date":
|
|
235
|
-
return "string";
|
|
236
|
-
case "number":
|
|
237
|
-
return "number";
|
|
238
|
-
case "boolean":
|
|
239
|
-
return "boolean";
|
|
240
|
-
case "enum": {
|
|
241
|
-
const values = Array.isArray(field.enum)
|
|
242
|
-
? field.enum.filter((v) => typeof v === "string")
|
|
243
|
-
: [];
|
|
244
|
-
if (values.length === 0)
|
|
245
|
-
return "string";
|
|
246
|
-
return values.map((v) => JSON.stringify(v)).join(" | ");
|
|
247
|
-
}
|
|
248
|
-
case "array": {
|
|
249
|
-
const nested = Array.isArray(field.fields)
|
|
250
|
-
? field.fields.filter(isFormFieldLike)
|
|
251
|
-
: [];
|
|
252
|
-
if (nested.length === 0)
|
|
253
|
-
return "unknown[]";
|
|
254
|
-
const inner = nested
|
|
255
|
-
.map((f) => {
|
|
256
|
-
const opt = f.isRequired === true ? "" : "?";
|
|
257
|
-
return `${tsKey(f.slug)}${opt}: ${formFieldToTs(f)}`;
|
|
258
|
-
})
|
|
259
|
-
.join("; ");
|
|
260
|
-
return `Array<{ ${inner} }>`;
|
|
261
|
-
}
|
|
262
|
-
case "any":
|
|
263
|
-
default:
|
|
264
|
-
return "unknown";
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
function uniqueUnion(parts) {
|
|
268
|
-
const dedup = Array.from(new Set(parts));
|
|
269
|
-
return dedup.length === 1 ? dedup[0] : dedup.join(" | ");
|
|
270
|
-
}
|
|
271
|
-
function tsKey(key) {
|
|
272
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
|
|
273
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/commands/cdk/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AA0FxC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CA8D7E"}
|
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { handleApiCall, info, success } from "../runHandler.js";
|
|
4
|
-
import { printJsonSchemaInput, printJsonSchemaType } from "./inputTypes.js";
|
|
5
|
-
// Composite natives surfaced via dedicated SDK syntax / scope helpers —
|
|
6
|
-
// excluded so we don't double-register them. Mirrors the codegen exclusion
|
|
7
|
-
// list in `packages/workflow-sdk/scripts/generateNativeIntegration.ts`
|
|
8
|
-
// (everything in the `logic` category gets dedicated syntax instead of
|
|
9
|
-
// going through `native.<slug>`).
|
|
10
|
-
const COMPOSITE_NATIVE = new Set([
|
|
11
|
-
"start",
|
|
12
|
-
"end",
|
|
13
|
-
"agent",
|
|
14
|
-
"balance",
|
|
15
|
-
"branch",
|
|
16
|
-
"delay",
|
|
17
|
-
"filter",
|
|
18
|
-
"group",
|
|
19
|
-
"humanReview",
|
|
20
|
-
"memory",
|
|
21
|
-
"split",
|
|
22
|
-
"switch",
|
|
23
|
-
"tool",
|
|
24
|
-
"variables",
|
|
25
|
-
]);
|
|
26
|
-
// Native actions the SDK already ships typed declarations + registrations
|
|
27
|
-
// for (platform-level, identical in every workspace) — skipped so the
|
|
28
|
-
// synced `.d.ts` doesn't redeclare `Native` properties with conflicting
|
|
29
|
-
// (looser) types. Source of truth lives in
|
|
30
|
-
// `packages/workflow-sdk/src/native/manifest.generated.ts`.
|
|
31
|
-
const BUNDLED_NATIVE = new Set([
|
|
32
|
-
"note",
|
|
33
|
-
"python",
|
|
34
|
-
"scoring",
|
|
35
|
-
"script",
|
|
36
|
-
]);
|
|
37
|
-
export function registerTypesCommand(parent, getApi) {
|
|
38
|
-
parent
|
|
39
|
-
.command("types")
|
|
40
|
-
.description("Generate per-workspace TypeScript types for the Cargo CDK — typed defineConnector/defineModel config + integration actions in workflow bodies")
|
|
41
|
-
.option("--dir <path>", "Repo root the generated files are written into (default: cwd)")
|
|
42
|
-
.option("--out <dir>", "Output subdirectory for generated files (default: .cargo-ai)", ".cargo-ai")
|
|
43
|
-
.action(async (opts) => {
|
|
44
|
-
const api = getApi();
|
|
45
|
-
// Match the other `cdk` commands: `--dir` selects the repo root, and the
|
|
46
|
-
// generated `.cargo-ai` lands there (not wherever the CLI happens to run).
|
|
47
|
-
if (opts.dir !== undefined)
|
|
48
|
-
process.chdir(opts.dir);
|
|
49
|
-
const baseDir = process.cwd();
|
|
50
|
-
const outDir = resolve(baseDir, opts.out);
|
|
51
|
-
info(`Fetching workspace surface…`);
|
|
52
|
-
const payload = await fetchWorkspaceSurface(api);
|
|
53
|
-
mkdirSync(outDir, { recursive: true });
|
|
54
|
-
const typesPath = resolve(outDir, "cargo-types.d.ts");
|
|
55
|
-
writeFileSync(typesPath, renderTypes(payload));
|
|
56
|
-
success(`Wrote ${relativeToBase(baseDir, typesPath)}`);
|
|
57
|
-
const eagerPath = resolve(outDir, "cargo-register.ts");
|
|
58
|
-
writeFileSync(eagerPath, renderEagerRegistration(payload));
|
|
59
|
-
success(`Wrote ${relativeToBase(baseDir, eagerPath)}`);
|
|
60
|
-
info(``);
|
|
61
|
-
info([
|
|
62
|
-
`Next steps:`,
|
|
63
|
-
` 1. Add "${relativeToBase(baseDir, outDir)}/**/*.d.ts" to your tsconfig`,
|
|
64
|
-
` include so the types are picked up (a bare dot-dir path is ignored by`,
|
|
65
|
-
` TypeScript). Enables typed defineConnector/defineModel config.`,
|
|
66
|
-
` 2. To also type integration actions inside workflow bodies, add`,
|
|
67
|
-
` \`import "./${relativeToBase(baseDir, eagerPath).replace(/\.ts$/, ".js")}";\``,
|
|
68
|
-
` to your entry file so the workspace's integrations register at runtime.`,
|
|
69
|
-
].join("\n"));
|
|
70
|
-
info(``);
|
|
71
|
-
const extractorCount = payload.extractorConfigs.reduce((n, e) => n + e.extractors.length, 0);
|
|
72
|
-
info(`Typed ${String(payload.connectorConfigs.length)} connector config(s), ${String(extractorCount)} extractor config(s), ${String(payload.integrations.length)} integration(s), ${String(payload.native.length)} native action(s).`);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
async function fetchWorkspaceSurface(api) {
|
|
76
|
-
const integrationsResult = await handleApiCall(() => api.connection.integration.list({}));
|
|
77
|
-
const nativeIntegrationResult = await handleApiCall(() => api.connection.nativeIntegration.get());
|
|
78
|
-
const rawIntegrations = integrationsResult.integrations;
|
|
79
|
-
const integrations = collectIntegrations(rawIntegrations);
|
|
80
|
-
const native = collectNative(nativeIntegrationResult.nativeIntegration.actions);
|
|
81
|
-
const connectorConfigs = collectConnectorConfigs(rawIntegrations);
|
|
82
|
-
const extractorConfigs = collectExtractorConfigs(rawIntegrations);
|
|
83
|
-
return { integrations, native, connectorConfigs, extractorConfigs };
|
|
84
|
-
}
|
|
85
|
-
// integrationSlug → connector config type. Skips integrations whose schema
|
|
86
|
-
// prints as a bare record (no typing gained — the builder already falls back to
|
|
87
|
-
// that), keeping the generated file to connectors that actually add types.
|
|
88
|
-
function collectConnectorConfigs(integrations) {
|
|
89
|
-
const out = [];
|
|
90
|
-
for (const integration of integrations) {
|
|
91
|
-
const schema = integration.connector?.config?.schema;
|
|
92
|
-
if (schema === undefined)
|
|
93
|
-
continue;
|
|
94
|
-
const typeSrc = printJsonSchemaType(schema);
|
|
95
|
-
if (typeSrc === "Record<string, unknown>")
|
|
96
|
-
continue;
|
|
97
|
-
out.push({
|
|
98
|
-
slug: integration.slug,
|
|
99
|
-
name: trimOrUndefined(integration.name),
|
|
100
|
-
typeSrc,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
out.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
104
|
-
return out;
|
|
105
|
-
}
|
|
106
|
-
// integrationSlug → its extractors' config types. Skips extractors whose schema
|
|
107
|
-
// prints as a bare record, and integrations left with none.
|
|
108
|
-
function collectExtractorConfigs(integrations) {
|
|
109
|
-
const out = [];
|
|
110
|
-
for (const integration of integrations) {
|
|
111
|
-
const extractors = [];
|
|
112
|
-
for (const [slug, extractor] of Object.entries(integration.extractors ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
|
|
113
|
-
const schema = extractor.config?.schema;
|
|
114
|
-
if (schema === undefined)
|
|
115
|
-
continue;
|
|
116
|
-
const typeSrc = printJsonSchemaType(schema);
|
|
117
|
-
if (typeSrc === "Record<string, unknown>")
|
|
118
|
-
continue;
|
|
119
|
-
extractors.push({ slug, typeSrc });
|
|
120
|
-
}
|
|
121
|
-
if (extractors.length === 0)
|
|
122
|
-
continue;
|
|
123
|
-
out.push({ integrationSlug: integration.slug, extractors });
|
|
124
|
-
}
|
|
125
|
-
out.sort((a, b) => a.integrationSlug.localeCompare(b.integrationSlug));
|
|
126
|
-
return out;
|
|
127
|
-
}
|
|
128
|
-
function collectIntegrations(integrations) {
|
|
129
|
-
const out = [];
|
|
130
|
-
for (const integration of integrations) {
|
|
131
|
-
const actionEntries = Object.entries(integration.actions ?? {}).sort(([a], [b]) => a.localeCompare(b));
|
|
132
|
-
if (actionEntries.length === 0)
|
|
133
|
-
continue;
|
|
134
|
-
const actions = actionEntries.map(([slug, raw]) => {
|
|
135
|
-
const meta = raw;
|
|
136
|
-
return {
|
|
137
|
-
slug,
|
|
138
|
-
name: trimOrUndefined(meta.name),
|
|
139
|
-
description: trimOrUndefined(meta.description),
|
|
140
|
-
inputTypeSrc: printJsonSchemaInput(meta.config?.schema),
|
|
141
|
-
};
|
|
142
|
-
});
|
|
143
|
-
out.push({
|
|
144
|
-
slug: integration.slug,
|
|
145
|
-
name: trimOrUndefined(integration.name),
|
|
146
|
-
description: trimOrUndefined(integration.description),
|
|
147
|
-
actions,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
out.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
151
|
-
return out;
|
|
152
|
-
}
|
|
153
|
-
function collectNative(actions) {
|
|
154
|
-
const out = [];
|
|
155
|
-
for (const [slug, meta] of Object.entries(actions)) {
|
|
156
|
-
if (COMPOSITE_NATIVE.has(slug))
|
|
157
|
-
continue;
|
|
158
|
-
if (BUNDLED_NATIVE.has(slug))
|
|
159
|
-
continue;
|
|
160
|
-
const name = meta.name.length > 0 ? meta.name : slug;
|
|
161
|
-
out.push({
|
|
162
|
-
slug,
|
|
163
|
-
name,
|
|
164
|
-
description: trimOrUndefined(meta.description),
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
out.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
168
|
-
return out;
|
|
169
|
-
}
|
|
170
|
-
function trimOrUndefined(value) {
|
|
171
|
-
if (typeof value !== "string")
|
|
172
|
-
return undefined;
|
|
173
|
-
const trimmed = value.trim();
|
|
174
|
-
return trimmed.length > 0 ? trimmed : undefined;
|
|
175
|
-
}
|
|
176
|
-
const GENERATED_AT = new Date().toISOString();
|
|
177
|
-
const HEADER = `// THIS FILE IS GENERATED by \`cargo-ai cdk types\`. Do not edit by hand.
|
|
178
|
-
// Re-run the command to refresh after adding/removing workspace integrations
|
|
179
|
-
// or connectors.
|
|
180
|
-
// Last regenerated: ${GENERATED_AT}
|
|
181
|
-
|
|
182
|
-
`;
|
|
183
|
-
function renderTypes(payload) {
|
|
184
|
-
const blocks = [];
|
|
185
|
-
// ── @cargo-ai/cdk — typed define* config (connector + extractor schemas) ──
|
|
186
|
-
const cdkLines = [];
|
|
187
|
-
if (payload.connectorConfigs.length > 0) {
|
|
188
|
-
cdkLines.push(` interface ConnectorConfigs {`);
|
|
189
|
-
for (const c of payload.connectorConfigs) {
|
|
190
|
-
const doc = formatJsDoc({ name: c.name ?? c.slug, updatedAt: GENERATED_AT }, " ");
|
|
191
|
-
if (doc !== "")
|
|
192
|
-
cdkLines.push(doc.trimEnd());
|
|
193
|
-
cdkLines.push(` ${jsonKey(c.slug)}: ${c.typeSrc};`);
|
|
194
|
-
}
|
|
195
|
-
cdkLines.push(` }`);
|
|
196
|
-
}
|
|
197
|
-
if (payload.extractorConfigs.length > 0) {
|
|
198
|
-
cdkLines.push(` interface ExtractorConfigs {`);
|
|
199
|
-
for (const e of payload.extractorConfigs) {
|
|
200
|
-
cdkLines.push(` ${jsonKey(e.integrationSlug)}: {`);
|
|
201
|
-
for (const x of e.extractors) {
|
|
202
|
-
cdkLines.push(` ${jsonKey(x.slug)}: ${x.typeSrc};`);
|
|
203
|
-
}
|
|
204
|
-
cdkLines.push(` };`);
|
|
205
|
-
}
|
|
206
|
-
cdkLines.push(` }`);
|
|
207
|
-
}
|
|
208
|
-
if (cdkLines.length > 0) {
|
|
209
|
-
blocks.push([`declare module "@cargo-ai/cdk" {`, ...cdkLines, `}`].join("\n"));
|
|
210
|
-
}
|
|
211
|
-
// ── @cargo-ai/workflow-sdk — integration actions + natives (workflow bodies) ──
|
|
212
|
-
const wfLines = [];
|
|
213
|
-
if (payload.integrations.length > 0) {
|
|
214
|
-
wfLines.push(` interface Integrations {`);
|
|
215
|
-
for (const c of payload.integrations) {
|
|
216
|
-
const intDoc = formatJsDoc({
|
|
217
|
-
name: c.name ?? c.slug,
|
|
218
|
-
description: c.description,
|
|
219
|
-
updatedAt: GENERATED_AT,
|
|
220
|
-
}, " ");
|
|
221
|
-
if (intDoc !== "")
|
|
222
|
-
wfLines.push(intDoc.trimEnd());
|
|
223
|
-
wfLines.push(` ${jsonKey(c.slug)}: {`);
|
|
224
|
-
for (const action of c.actions) {
|
|
225
|
-
const actionDoc = formatJsDoc({
|
|
226
|
-
name: action.name,
|
|
227
|
-
description: action.description,
|
|
228
|
-
category: c.slug,
|
|
229
|
-
updatedAt: GENERATED_AT,
|
|
230
|
-
}, " ");
|
|
231
|
-
if (actionDoc !== "")
|
|
232
|
-
wfLines.push(actionDoc.trimEnd());
|
|
233
|
-
wfLines.push(` ${jsonKey(action.slug)}: IntegrationAction<${action.inputTypeSrc}, Record<string, unknown>>;`);
|
|
234
|
-
}
|
|
235
|
-
wfLines.push(` };`);
|
|
236
|
-
}
|
|
237
|
-
wfLines.push(` }`);
|
|
238
|
-
}
|
|
239
|
-
if (payload.native.length > 0) {
|
|
240
|
-
wfLines.push(` interface Native {`);
|
|
241
|
-
for (const n of payload.native) {
|
|
242
|
-
const doc = formatJsDoc({ name: n.name, description: n.description, updatedAt: GENERATED_AT }, " ");
|
|
243
|
-
if (doc !== "")
|
|
244
|
-
wfLines.push(doc.trimEnd());
|
|
245
|
-
wfLines.push(` ${jsonKey(n.slug)}: NativeAction<Record<string, unknown>, Record<string, unknown>>;`);
|
|
246
|
-
}
|
|
247
|
-
wfLines.push(` }`);
|
|
248
|
-
}
|
|
249
|
-
// The workflow-sdk augmentation needs its builder types imported; `Ref` only
|
|
250
|
-
// when a typed action input references it.
|
|
251
|
-
const preamble = [];
|
|
252
|
-
// The cdk augmentation references `EncryptionRef` at encryption-typed fields.
|
|
253
|
-
if (cdkLines.some((l) => l.includes("EncryptionRef"))) {
|
|
254
|
-
preamble.push(`import type { EncryptionRef } from "@cargo-ai/cdk";`);
|
|
255
|
-
}
|
|
256
|
-
if (wfLines.length > 0) {
|
|
257
|
-
const wfBody = wfLines.join("\n");
|
|
258
|
-
const imports = [
|
|
259
|
-
"IntegrationAction",
|
|
260
|
-
"NativeAction",
|
|
261
|
-
...(wfBody.includes("Ref<") ? ["Ref"] : []),
|
|
262
|
-
];
|
|
263
|
-
preamble.push([
|
|
264
|
-
`import type {`,
|
|
265
|
-
...imports.map((name) => ` ${name},`),
|
|
266
|
-
`} from "@cargo-ai/workflow-sdk";`,
|
|
267
|
-
].join("\n"));
|
|
268
|
-
blocks.push([`declare module "@cargo-ai/workflow-sdk" {`, wfBody, `}`].join("\n"));
|
|
269
|
-
}
|
|
270
|
-
// `declare module` only *augments* an existing module when this file is itself
|
|
271
|
-
// a module. The workflow-sdk import makes it one; when only the cdk block is
|
|
272
|
-
// emitted there's no import, so force module mode with an empty export.
|
|
273
|
-
if (preamble.length === 0)
|
|
274
|
-
preamble.push(`export {};`);
|
|
275
|
-
return `${HEADER.trim()}\n\n${[...preamble, ...blocks].join("\n\n")}\n`;
|
|
276
|
-
}
|
|
277
|
-
function renderEagerRegistration(payload) {
|
|
278
|
-
const lines = [];
|
|
279
|
-
lines.push(HEADER.trim());
|
|
280
|
-
const imports = [];
|
|
281
|
-
if (payload.integrations.length > 0)
|
|
282
|
-
imports.push("registerIntegration");
|
|
283
|
-
if (payload.native.length > 0)
|
|
284
|
-
imports.push("registerNative");
|
|
285
|
-
if (imports.length === 0) {
|
|
286
|
-
lines.push(``);
|
|
287
|
-
lines.push(`// Workspace surface is empty (no custom integrations / natives).`);
|
|
288
|
-
lines.push(``);
|
|
289
|
-
return lines.join("\n");
|
|
290
|
-
}
|
|
291
|
-
lines.push(`import { ${imports.join(", ")} } from "@cargo-ai/workflow-sdk";`);
|
|
292
|
-
lines.push(``);
|
|
293
|
-
for (const c of payload.integrations) {
|
|
294
|
-
lines.push(`registerIntegration(${JSON.stringify(c.slug)}, {`);
|
|
295
|
-
for (const action of c.actions) {
|
|
296
|
-
const displayName = action.name !== undefined && action.name.length > 0
|
|
297
|
-
? action.name
|
|
298
|
-
: `${capitalize(c.slug)} ${humanize(action.slug)}`;
|
|
299
|
-
lines.push(` ${jsonKey(action.slug)}: { name: ${JSON.stringify(displayName)} },`);
|
|
300
|
-
}
|
|
301
|
-
lines.push(`});`);
|
|
302
|
-
}
|
|
303
|
-
for (const n of payload.native) {
|
|
304
|
-
lines.push(`registerNative(${JSON.stringify(n.slug)}, ${JSON.stringify(n.name)});`);
|
|
305
|
-
}
|
|
306
|
-
lines.push(``);
|
|
307
|
-
return lines.join("\n");
|
|
308
|
-
}
|
|
309
|
-
function jsonKey(key) {
|
|
310
|
-
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key) ? key : JSON.stringify(key);
|
|
311
|
-
}
|
|
312
|
-
// Render a JSDoc block above a generated declaration so editors surface the
|
|
313
|
-
// entry's metadata on hover. Returns "" when there's nothing to document.
|
|
314
|
-
function formatJsDoc(doc, indent) {
|
|
315
|
-
const body = [];
|
|
316
|
-
if (doc.name !== undefined && doc.name.trim().length > 0) {
|
|
317
|
-
body.push(doc.name.trim());
|
|
318
|
-
}
|
|
319
|
-
if (doc.description !== undefined && doc.description.trim().length > 0) {
|
|
320
|
-
if (body.length > 0)
|
|
321
|
-
body.push("");
|
|
322
|
-
for (const line of doc.description.split("\n")) {
|
|
323
|
-
body.push(line.trimEnd());
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const tags = [];
|
|
327
|
-
if (doc.category !== undefined) {
|
|
328
|
-
const cats = Array.isArray(doc.category)
|
|
329
|
-
? doc.category.join(", ")
|
|
330
|
-
: String(doc.category);
|
|
331
|
-
if (cats.trim().length > 0) {
|
|
332
|
-
tags.push(`@category ${cats}`);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
if (doc.author !== undefined && doc.author.trim().length > 0) {
|
|
336
|
-
tags.push(`@author ${doc.author.trim()}`);
|
|
337
|
-
}
|
|
338
|
-
if (doc.version !== undefined && String(doc.version).length > 0) {
|
|
339
|
-
tags.push(`@version ${String(doc.version)}`);
|
|
340
|
-
}
|
|
341
|
-
if (doc.updatedAt !== undefined && doc.updatedAt !== null) {
|
|
342
|
-
const date = doc.updatedAt instanceof Date ? doc.updatedAt : new Date(doc.updatedAt);
|
|
343
|
-
if (!Number.isNaN(date.getTime())) {
|
|
344
|
-
tags.push(`@updated ${date.toISOString().slice(0, 10)}`);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
if (doc.see !== undefined && doc.see.trim().length > 0) {
|
|
348
|
-
tags.push(`@see ${doc.see.trim()}`);
|
|
349
|
-
}
|
|
350
|
-
if (body.length > 0 && tags.length > 0) {
|
|
351
|
-
body.push("");
|
|
352
|
-
}
|
|
353
|
-
body.push(...tags);
|
|
354
|
-
if (body.length === 0)
|
|
355
|
-
return "";
|
|
356
|
-
const out = [`${indent}/**`];
|
|
357
|
-
for (const line of body) {
|
|
358
|
-
const safe = line.replace(/\*\//g, "*\\/");
|
|
359
|
-
out.push(safe.length > 0 ? `${indent} * ${safe}` : `${indent} *`);
|
|
360
|
-
}
|
|
361
|
-
out.push(`${indent} */`);
|
|
362
|
-
return `${out.join("\n")}\n`;
|
|
363
|
-
}
|
|
364
|
-
function capitalize(s) {
|
|
365
|
-
if (s.length === 0)
|
|
366
|
-
return s;
|
|
367
|
-
const first = s[0];
|
|
368
|
-
if (first === undefined)
|
|
369
|
-
return s;
|
|
370
|
-
return first.toUpperCase() + s.slice(1);
|
|
371
|
-
}
|
|
372
|
-
function humanize(slug) {
|
|
373
|
-
return slug
|
|
374
|
-
.replace(/([A-Z])/g, " $1")
|
|
375
|
-
.replace(/[_-]+/g, " ")
|
|
376
|
-
.trim()
|
|
377
|
-
.toLowerCase();
|
|
378
|
-
}
|
|
379
|
-
function relativeToBase(base, path) {
|
|
380
|
-
if (path.startsWith(base)) {
|
|
381
|
-
const rel = path.slice(base.length);
|
|
382
|
-
return rel.startsWith("/") ? rel.slice(1) : rel;
|
|
383
|
-
}
|
|
384
|
-
return path;
|
|
385
|
-
}
|