@cargo-ai/cdk 1.0.3 → 1.0.4
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 +64 -35
- package/build/src/cli/auth.d.ts +9 -0
- package/build/src/cli/auth.d.ts.map +1 -0
- package/build/src/cli/auth.js +100 -0
- package/build/src/cli/bin.d.ts +3 -0
- package/build/src/cli/bin.d.ts.map +1 -0
- package/build/src/cli/bin.js +9 -0
- package/build/src/cli/commands/deploy.d.ts +4 -0
- package/build/src/cli/commands/deploy.d.ts.map +1 -0
- package/build/src/cli/commands/deploy.js +531 -0
- package/build/src/cli/commands/index.d.ts +4 -0
- package/build/src/cli/commands/index.d.ts.map +1 -0
- package/build/src/cli/commands/index.js +11 -0
- package/build/src/cli/commands/init.d.ts +3 -0
- package/build/src/cli/commands/init.d.ts.map +1 -0
- package/build/src/cli/commands/init.js +76 -0
- package/build/src/cli/commands/inputTypes.d.ts +24 -0
- package/build/src/cli/commands/inputTypes.d.ts.map +1 -0
- package/build/src/cli/commands/inputTypes.js +273 -0
- package/build/src/cli/commands/templates.d.ts +6 -0
- package/build/src/cli/commands/templates.d.ts.map +1 -0
- package/build/src/cli/commands/templates.js +33 -0
- package/build/src/cli/commands/types.d.ts +4 -0
- package/build/src/cli/commands/types.d.ts.map +1 -0
- package/build/src/cli/commands/types.js +385 -0
- package/build/src/cli/deployCommands.d.ts +4 -0
- package/build/src/cli/deployCommands.d.ts.map +1 -0
- package/build/src/cli/deployCommands.js +531 -0
- package/build/src/cli/index.d.ts +4 -0
- package/build/src/cli/index.d.ts.map +1 -0
- package/build/src/cli/index.js +20 -0
- package/build/src/cli/initCommand.d.ts +3 -0
- package/build/src/cli/initCommand.d.ts.map +1 -0
- package/build/src/cli/initCommand.js +76 -0
- package/build/src/cli/inputTypes.d.ts +24 -0
- package/build/src/cli/inputTypes.d.ts.map +1 -0
- package/build/src/cli/inputTypes.js +273 -0
- package/build/src/cli/io.d.ts +38 -0
- package/build/src/cli/io.d.ts.map +1 -0
- package/build/src/cli/io.js +226 -0
- package/build/src/cli/templates.d.ts +6 -0
- package/build/src/cli/templates.d.ts.map +1 -0
- package/build/src/cli/templates.js +34 -0
- package/build/src/cli/typesCommand.d.ts +4 -0
- package/build/src/cli/typesCommand.d.ts.map +1 -0
- package/build/src/cli/typesCommand.js +385 -0
- package/build/src/cli/version.d.ts +2 -0
- package/build/src/cli/version.d.ts.map +1 -0
- package/build/src/cli/version.js +25 -0
- package/build/src/deploy/executors.live.d.ts.map +1 -1
- package/build/src/deploy/executors.live.js +15 -3
- package/build/src/resources/bundle.d.ts +4 -2
- package/build/src/resources/bundle.d.ts.map +1 -1
- package/build/src/resources/bundle.js +11 -2
- package/build/src/resources/connector.d.ts.map +1 -1
- package/build/src/resources/connector.js +3 -2
- package/build/src/resources/worker.d.ts.map +1 -1
- package/build/src/resources/worker.js +14 -7
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -4
- package/templates/blank/package.json +3 -3
- package/templates/full/README.md +21 -20
- package/templates/full/apps/dashboard/index.html +1 -1
- package/templates/full/apps/dashboard/package.json +18 -3
- package/templates/full/apps/dashboard/src/App.tsx +57 -0
- package/templates/full/apps/dashboard/src/index.css +4 -0
- package/templates/full/apps/dashboard/src/main.tsx +13 -7
- package/templates/full/apps/dashboard/tailwind.config.ts +13 -0
- package/templates/full/apps/dashboard/tsconfig.json +10 -3
- package/templates/full/apps/dashboard/vite.config.ts +22 -0
- package/templates/full/package.json +3 -3
- package/templates/full/workers/webhook/package.json +12 -1
- package/templates/full/workers/webhook/src/index.ts +53 -0
- package/templates/full/workers/webhook/tsconfig.json +14 -0
- package/templates/full/workers/webhook.ts +9 -7
- package/templates/full/apps/dashboard/package-lock.json +0 -1080
- package/templates/full/workers/webhook/index.js +0 -12
- package/templates/full/workers/webhook/package-lock.json +0 -12
|
@@ -0,0 +1,273 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const ExitCodes: {
|
|
2
|
+
readonly Success: 0;
|
|
3
|
+
readonly GenericError: 1;
|
|
4
|
+
readonly InvalidUsage: 2;
|
|
5
|
+
readonly NotAuthenticated: 3;
|
|
6
|
+
readonly PermissionDenied: 4;
|
|
7
|
+
readonly NotFound: 5;
|
|
8
|
+
};
|
|
9
|
+
export type ExitCode = (typeof ExitCodes)[keyof typeof ExitCodes];
|
|
10
|
+
export declare const colors: {
|
|
11
|
+
red: (s: string) => string;
|
|
12
|
+
green: (s: string) => string;
|
|
13
|
+
yellow: (s: string) => string;
|
|
14
|
+
cyan: (s: string) => string;
|
|
15
|
+
dim: (s: string) => string;
|
|
16
|
+
bold: (s: string) => string;
|
|
17
|
+
};
|
|
18
|
+
export declare function outputJson(value: unknown): void;
|
|
19
|
+
export declare function info(message: string): void;
|
|
20
|
+
export declare function success(message: string): void;
|
|
21
|
+
export declare function confirm(question: string): Promise<boolean>;
|
|
22
|
+
type FailWithOpts = {
|
|
23
|
+
code?: ExitCode;
|
|
24
|
+
extra?: Record<string, unknown>;
|
|
25
|
+
};
|
|
26
|
+
export declare function failWith(message: string, opts?: FailWithOpts): never;
|
|
27
|
+
export type Spinner = {
|
|
28
|
+
update: (message: string) => void;
|
|
29
|
+
log: (line: string) => void;
|
|
30
|
+
stop: () => void;
|
|
31
|
+
};
|
|
32
|
+
export declare function startSpinner(message: string): Spinner;
|
|
33
|
+
type HandleApiCallOpts = {
|
|
34
|
+
spinner?: string | false;
|
|
35
|
+
};
|
|
36
|
+
export declare function handleApiCall<T>(fn: () => Promise<T>, opts?: HandleApiCallOpts): Promise<T>;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../../src/cli/io.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,SAAS;;;;;;;CAOZ,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAclE,eAAO,MAAM,MAAM;aACR,MAAM,KAAG,MAAM;eACb,MAAM,KAAG,MAAM;gBACd,MAAM,KAAG,MAAM;cACjB,MAAM,KAAG,MAAM;aAChB,MAAM,KAAG,MAAM;cACd,MAAM,KAAG,MAAM;CAC1B,CAAC;AAEF,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAM/C;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAID,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhE;AAED,KAAK,YAAY,GAAG;IAClB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,KAAK,CAyBpE;AAKD,MAAM,MAAM,OAAO,GAAG;IAEpB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAGlC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CA6CrD;AAED,KAAK,iBAAiB,GAAG;IACvB,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B,CAAC;AAOF,wBAAsB,aAAa,CAAC,CAAC,EACnC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,CAAC,CAAC,CAiDZ"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// Terminal I/O helpers (colors, info/success, confirm, failWith, a spinner, and
|
|
2
|
+
// API-error formatting) — a self-contained copy of the CLI's presentation helpers
|
|
3
|
+
// so the command layer ships with @cargo-ai/cdk and needn't reach into the CLI.
|
|
4
|
+
import { determineIfIsFetcherError } from "@cargo-ai/api";
|
|
5
|
+
export const ExitCodes = {
|
|
6
|
+
Success: 0,
|
|
7
|
+
GenericError: 1,
|
|
8
|
+
InvalidUsage: 2,
|
|
9
|
+
NotAuthenticated: 3,
|
|
10
|
+
PermissionDenied: 4,
|
|
11
|
+
NotFound: 5,
|
|
12
|
+
};
|
|
13
|
+
const useColor = process.stderr.isTTY === true &&
|
|
14
|
+
process.env["NO_COLOR"] === undefined &&
|
|
15
|
+
process.env["CI"] !== "true";
|
|
16
|
+
const colorize = (text, code) => {
|
|
17
|
+
if (useColor !== true) {
|
|
18
|
+
return text;
|
|
19
|
+
}
|
|
20
|
+
return `\x1B[${code}m${text}\x1B[0m`;
|
|
21
|
+
};
|
|
22
|
+
export const colors = {
|
|
23
|
+
red: (s) => colorize(s, "31"),
|
|
24
|
+
green: (s) => colorize(s, "32"),
|
|
25
|
+
yellow: (s) => colorize(s, "33"),
|
|
26
|
+
cyan: (s) => colorize(s, "36"),
|
|
27
|
+
dim: (s) => colorize(s, "2"),
|
|
28
|
+
bold: (s) => colorize(s, "1"),
|
|
29
|
+
};
|
|
30
|
+
export function outputJson(value) {
|
|
31
|
+
if (process.stdout.isTTY === true) {
|
|
32
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
36
|
+
}
|
|
37
|
+
export function info(message) {
|
|
38
|
+
process.stderr.write(`${message}\n`);
|
|
39
|
+
}
|
|
40
|
+
export function success(message) {
|
|
41
|
+
process.stderr.write(`${colors.green("✓")} ${message}\n`);
|
|
42
|
+
}
|
|
43
|
+
// Ask a yes/no question on stderr (stdout stays reserved for JSON). Resolves
|
|
44
|
+
// false on a non-TTY stdin (callers should require an explicit --yes there).
|
|
45
|
+
export async function confirm(question) {
|
|
46
|
+
if (process.stdin.isTTY !== true)
|
|
47
|
+
return false;
|
|
48
|
+
const { createInterface } = await import("node:readline/promises");
|
|
49
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
50
|
+
try {
|
|
51
|
+
const answer = await rl.question(`${question} [y/N] `);
|
|
52
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
rl.close();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function failWith(message, opts) {
|
|
59
|
+
const code = opts !== undefined && opts.code !== undefined
|
|
60
|
+
? opts.code
|
|
61
|
+
: ExitCodes.GenericError;
|
|
62
|
+
const extra = opts !== undefined ? opts.extra : undefined;
|
|
63
|
+
if (process.stderr.isTTY === true) {
|
|
64
|
+
process.stderr.write(`${colors.red("✗")} ${message}\n`);
|
|
65
|
+
if (extra !== undefined) {
|
|
66
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
67
|
+
const valueStr = typeof value === "string" ? value : JSON.stringify(value);
|
|
68
|
+
process.stderr.write(` ${colors.dim(`${key}:`)} ${valueStr}\n`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const payload = { error: message };
|
|
74
|
+
if (extra !== undefined) {
|
|
75
|
+
Object.assign(payload, extra);
|
|
76
|
+
}
|
|
77
|
+
process.stderr.write(`${JSON.stringify(payload)}\n`);
|
|
78
|
+
}
|
|
79
|
+
process.exit(code);
|
|
80
|
+
}
|
|
81
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
82
|
+
const SPINNER_INTERVAL_MS = 80;
|
|
83
|
+
export function startSpinner(message) {
|
|
84
|
+
if (process.stderr.isTTY !== true) {
|
|
85
|
+
// Non-TTY (CI, piped): no animation — just emit each line so progress is
|
|
86
|
+
// still visible in logs.
|
|
87
|
+
process.stderr.write(`${message}\n`);
|
|
88
|
+
return {
|
|
89
|
+
update: (m) => process.stderr.write(`${m}\n`),
|
|
90
|
+
log: (line) => process.stderr.write(`${line}\n`),
|
|
91
|
+
stop: () => undefined,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
process.stderr.write("\x1B[?25l");
|
|
95
|
+
let current = message;
|
|
96
|
+
let frame = 0;
|
|
97
|
+
const render = () => {
|
|
98
|
+
const ch = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
|
|
99
|
+
if (ch !== undefined) {
|
|
100
|
+
// \x1B[K clears any stale characters when the message shrinks.
|
|
101
|
+
process.stderr.write(`\r\x1B[K${colors.cyan(ch)} ${colors.dim(current)}`);
|
|
102
|
+
}
|
|
103
|
+
frame += 1;
|
|
104
|
+
};
|
|
105
|
+
const id = setInterval(render, SPINNER_INTERVAL_MS);
|
|
106
|
+
let stopped = false;
|
|
107
|
+
return {
|
|
108
|
+
update: (m) => {
|
|
109
|
+
current = m;
|
|
110
|
+
},
|
|
111
|
+
log: (line) => {
|
|
112
|
+
// Wipe the spinner line, drop a permanent line, let the next frame redraw
|
|
113
|
+
// the spinner beneath it.
|
|
114
|
+
process.stderr.write(`\r\x1B[K${line}\n`);
|
|
115
|
+
},
|
|
116
|
+
stop: () => {
|
|
117
|
+
if (stopped) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
stopped = true;
|
|
121
|
+
clearInterval(id);
|
|
122
|
+
process.stderr.write("\r\x1B[K\x1B[?25h");
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const SPINNER_DELAY_MS = 200;
|
|
127
|
+
const DEFAULT_SPINNER_MESSAGE = "Loading...";
|
|
128
|
+
// Run an API call, surfacing a delayed spinner and turning FetcherErrors into a
|
|
129
|
+
// clean `failWith` with the right exit code. Used by `cdk types`.
|
|
130
|
+
export async function handleApiCall(fn, opts) {
|
|
131
|
+
const spinnerMessage = opts !== undefined && opts.spinner === false
|
|
132
|
+
? undefined
|
|
133
|
+
: opts !== undefined && typeof opts.spinner === "string"
|
|
134
|
+
? opts.spinner
|
|
135
|
+
: DEFAULT_SPINNER_MESSAGE;
|
|
136
|
+
let spinner;
|
|
137
|
+
let startTimer;
|
|
138
|
+
if (spinnerMessage !== undefined) {
|
|
139
|
+
startTimer = setTimeout(() => {
|
|
140
|
+
spinner = startSpinner(spinnerMessage);
|
|
141
|
+
}, SPINNER_DELAY_MS);
|
|
142
|
+
}
|
|
143
|
+
const stopAll = () => {
|
|
144
|
+
if (startTimer !== undefined) {
|
|
145
|
+
clearTimeout(startTimer);
|
|
146
|
+
}
|
|
147
|
+
if (spinner !== undefined) {
|
|
148
|
+
spinner.stop();
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
try {
|
|
152
|
+
const result = await fn();
|
|
153
|
+
stopAll();
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
stopAll();
|
|
158
|
+
if (determineIfIsFetcherError(error)) {
|
|
159
|
+
const parsedError = error;
|
|
160
|
+
const status = parsedError.status;
|
|
161
|
+
const body = parsedError.body !== undefined ? parsedError.body : String(error);
|
|
162
|
+
const { message, code } = describeApiError(status, body);
|
|
163
|
+
failWith(message, {
|
|
164
|
+
code,
|
|
165
|
+
extra: { status: status !== undefined ? status : "unknown", body },
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function describeApiError(status, body) {
|
|
172
|
+
const detail = extractApiErrorDetail(body);
|
|
173
|
+
const detailSuffix = detail !== undefined ? `: ${detail}` : "";
|
|
174
|
+
if (status === 401) {
|
|
175
|
+
return {
|
|
176
|
+
message: `Not authenticated${detailSuffix}. Run \`cargo-ai login\` to refresh credentials.`,
|
|
177
|
+
code: ExitCodes.NotAuthenticated,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
if (status === 403) {
|
|
181
|
+
return {
|
|
182
|
+
message: `Permission denied${detailSuffix}. Check your workspace permissions or selected workspace UUID.`,
|
|
183
|
+
code: ExitCodes.PermissionDenied,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (status === 404) {
|
|
187
|
+
return {
|
|
188
|
+
message: `Not found${detailSuffix}. Verify the UUID(s) you passed.`,
|
|
189
|
+
code: ExitCodes.NotFound,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (status === 429) {
|
|
193
|
+
return {
|
|
194
|
+
message: `Rate limited${detailSuffix}. Retry in a moment.`,
|
|
195
|
+
code: ExitCodes.GenericError,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (status !== undefined && status >= 500) {
|
|
199
|
+
return {
|
|
200
|
+
message: `Server error (${String(status)})${detailSuffix}. Retry shortly or check status.getcargo.io.`,
|
|
201
|
+
code: ExitCodes.GenericError,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
message: `API error (${status !== undefined ? String(status) : "unknown"})${detailSuffix}`,
|
|
206
|
+
code: ExitCodes.GenericError,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function extractApiErrorDetail(body) {
|
|
210
|
+
if (typeof body === "string" && body.length > 0) {
|
|
211
|
+
return body;
|
|
212
|
+
}
|
|
213
|
+
if (body !== null && typeof body === "object") {
|
|
214
|
+
const record = body;
|
|
215
|
+
if (typeof record["message"] === "string") {
|
|
216
|
+
return record["message"];
|
|
217
|
+
}
|
|
218
|
+
if (typeof record["reason"] === "string") {
|
|
219
|
+
return record["reason"];
|
|
220
|
+
}
|
|
221
|
+
if (typeof record["error"] === "string") {
|
|
222
|
+
return record["error"];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/cli/templates.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,aAAa,SAAgB,MAAM,KAAG,QAAQ,MAAM,EAAE,CAUlE,CAAC;AAEF,eAAO,MAAM,aAAa,QACnB,MAAM,QACL,MAAM,UACJ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,KACrC,QAAQ,IAAI,CAmBd,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Template scaffolding for `cdk init` — list the template directories under
|
|
2
|
+
// `@cargo-ai/cdk/templates` and copy one into a target directory, substituting
|
|
3
|
+
// `__APP_NAME__`. (A self-contained copy of the CLI's templateUtils so the
|
|
4
|
+
// command layer ships with the package.)
|
|
5
|
+
import { promises as fs } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
export const listTemplates = async (root) => {
|
|
8
|
+
try {
|
|
9
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
10
|
+
return entries
|
|
11
|
+
.filter((entry) => entry.isDirectory() === true)
|
|
12
|
+
.map((entry) => entry.name)
|
|
13
|
+
.filter((name) => name.startsWith("_") === false);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export const copyDirectory = async (src, dest, rename) => {
|
|
20
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
21
|
+
await fs.mkdir(dest, { recursive: true });
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const srcPath = path.join(src, entry.name);
|
|
24
|
+
const destPath = path.join(dest, entry.name);
|
|
25
|
+
if (entry.isDirectory() === true) {
|
|
26
|
+
await copyDirectory(srcPath, destPath, rename);
|
|
27
|
+
}
|
|
28
|
+
else if (entry.isFile() === true) {
|
|
29
|
+
const raw = await fs.readFile(srcPath, "utf-8");
|
|
30
|
+
const replaced = rename.reduce((current, { from, to }) => current.split(from).join(to), raw);
|
|
31
|
+
await fs.writeFile(destPath, replaced, "utf-8");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typesCommand.d.ts","sourceRoot":"","sources":["../../../src/cli/typesCommand.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2FzC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CA8D7E"}
|