@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.
@@ -1,539 +0,0 @@
1
- import { acquireLock, appendAudit, apply, compile, destroy, detectDrift, emptyState, formatPlan, importResource, liveExecutors, liveReaders, loadResources, newRunId, plan, readState, reconcileDrift, removeResources, restoreSnapshot, snapshotState, writeState, } from "@cargo-ai/cdk";
2
- import { getConfig } from "../../config.js";
3
- import { colors, confirm, ExitCodes, failWith, info, outputJson, startSpinner, success, } from "../runHandler.js";
4
- import { registerInitCommand } from "./init.js";
5
- import { registerTypesCommand } from "./types.js";
6
- // `cargo-ai cdk` — declarative deploy of a repo of Cargo resources. The
7
- // engine (load / compile / apply / state) lives in @cargo-ai/cdk; the CLI parses
8
- // args, authenticates, confirms, and prints.
9
- export function registerCdkCommands(program, getApi) {
10
- const cdk = program
11
- .command("cdk")
12
- .description("Cargo CDK — define resources in code and deploy them (plan/deploy)");
13
- // `cdk init` — scaffold a starter project; `cdk types` — generate per-workspace
14
- // TS types (typed connector/model config).
15
- registerInitCommand(cdk);
16
- registerTypesCommand(cdk, getApi);
17
- cdk
18
- .command("plan")
19
- .description("Compile the resource tree and diff against cargo.state.json. Offline — no API calls.")
20
- .option("--dir <path>", "Repo root containing the resource files (default: cwd)")
21
- .option("--json", "Output the raw plan result as JSON")
22
- .action(async (opts) => {
23
- // Run from the repo root so relative code paths (defineWorker/App/File)
24
- // and cargo.state.json resolve against it.
25
- if (opts.dir !== undefined)
26
- process.chdir(opts.dir);
27
- const root = ".";
28
- let result;
29
- try {
30
- result = await plan(root);
31
- }
32
- catch (error) {
33
- failWith(`Failed to load cdk repo: ${message(error)}`, {
34
- code: ExitCodes.InvalidUsage,
35
- });
36
- }
37
- if (opts.json === true)
38
- outputJson(result);
39
- else
40
- process.stdout.write(`${formatPlan(result)}\n`);
41
- if (result.errors.length > 0)
42
- process.exitCode = ExitCodes.GenericError;
43
- });
44
- cdk
45
- .command("deploy")
46
- .description("Deploy the resource tree to Cargo — create/update resources and write cargo.state.json.")
47
- .option("--dir <path>", "Repo root containing the resource files (default: cwd)")
48
- .option("--yes", "Skip the confirmation prompt")
49
- .option("--dry-run", "Show the plan without applying")
50
- .option("--prune", "Delete resources tracked in state but no longer in code")
51
- .option("--refresh", "Re-read live resources first and re-apply any modified out-of-band")
52
- .option("--recreate-deleted", "With --refresh, also restore resources deleted outside the CDK (off by default)")
53
- .option("--force", "Steal the state lock held by another run")
54
- .option("--json", "Output the deploy result as JSON")
55
- .action(async (opts) => {
56
- // Run from the repo root so relative code paths (defineWorker/App/File)
57
- // and cargo.state.json resolve against it.
58
- if (opts.dir !== undefined)
59
- process.chdir(opts.dir);
60
- const root = ".";
61
- const workspaceUuid = await resolveWorkspaceUuid(getApi);
62
- const runId = newRunId();
63
- // Load the resource tree ONCE (loadResources resets the registry, so it
64
- // must not run twice in a process), then reuse the nodes for plan + apply.
65
- let nodes;
66
- try {
67
- nodes = await loadResources(root);
68
- }
69
- catch (error) {
70
- failWith(`Failed to load cdk repo: ${message(error)}`, {
71
- code: ExitCodes.InvalidUsage,
72
- });
73
- }
74
- // Hold the state lock for the whole read→plan→apply sequence (not just
75
- // the apply), so a concurrent run can't rewrite cargo.state.json between
76
- // our read and our write. --dry-run is read-only, so it skips the lock.
77
- if (opts.dryRun !== true) {
78
- try {
79
- acquireLock(root, "deploy", opts.force === true);
80
- }
81
- catch (error) {
82
- failWith(message(error), { code: ExitCodes.GenericError });
83
- }
84
- }
85
- const prior = readState(root);
86
- if (prior !== undefined && prior.workspaceUuid !== workspaceUuid) {
87
- failWith(`cargo.state.json belongs to workspace ${prior.workspaceUuid}, but the selected workspace is ${workspaceUuid}. Refusing to deploy (would orphan resources).`, { code: ExitCodes.InvalidUsage });
88
- }
89
- const baseState = prior ?? emptyState(workspaceUuid);
90
- // Build the authenticated client lazily so a plain `--dry-run` stays
91
- // offline; `--refresh` and the apply both reuse this one instance.
92
- let apiClient;
93
- const api = () => {
94
- if (apiClient === undefined)
95
- apiClient = getApi();
96
- return apiClient;
97
- };
98
- // With --refresh, re-read the live resources and fold out-of-band drift
99
- // into the state before planning: a resource edited in the UI re-applies
100
- // (its code-hash is invalidated) and one deleted externally is recreated.
101
- let state = baseState;
102
- if (opts.refresh === true &&
103
- Object.keys(baseState.resources).length > 0) {
104
- let drift;
105
- try {
106
- drift = await detectDrift(baseState, liveReaders(api()));
107
- }
108
- catch (error) {
109
- failWith(`Refresh failed: ${message(error)}`, {
110
- code: ExitCodes.GenericError,
111
- });
112
- }
113
- const modifiedExternally = drift.filter((d) => d.status === "modified");
114
- const deletedExternally = drift.filter((d) => d.status === "deleted");
115
- const changed = [...modifiedExternally, ...deletedExternally];
116
- if (changed.length === 0) {
117
- info("Refresh: no out-of-band drift.");
118
- }
119
- else {
120
- info(`Refresh found ${String(changed.length)} drifted resource(s):`);
121
- for (const d of modifiedExternally) {
122
- info(` modified externally: ${d.id}`);
123
- }
124
- for (const d of deletedExternally) {
125
- info(` deleted externally: ${d.id}`);
126
- }
127
- // A resource present in code but deleted in the UI is ambiguous —
128
- // an accident to restore, or an intentional removal. Don't silently
129
- // recreate it; force the decision unless --recreate-deleted opts in.
130
- if (deletedExternally.length > 0 && opts.recreateDeleted !== true) {
131
- failWith(`${String(deletedExternally.length)} resource(s) were deleted outside the CDK ` +
132
- `(${deletedExternally.map((d) => d.id).join(", ")}). Re-run with ` +
133
- `--recreate-deleted to restore them, or remove them from your code if ` +
134
- `the deletion was intentional.`, { code: ExitCodes.InvalidUsage });
135
- }
136
- // Modified always re-applies; deleted only reconciles (→ recreate)
137
- // once the user has opted in above.
138
- const effectiveDrift = opts.recreateDeleted === true ? drift : modifiedExternally;
139
- state = reconcileDrift(baseState, effectiveDrift);
140
- }
141
- }
142
- const planResult = compile({ nodes, state });
143
- info(formatPlan(planResult));
144
- if (planResult.errors.length > 0) {
145
- failWith("Plan has errors — fix them before deploying.", {
146
- code: ExitCodes.GenericError,
147
- });
148
- }
149
- const deletes = planResult.plan.filter((e) => e.change === "delete");
150
- const hasApplyWork = planResult.plan.some((e) => e.change === "create" || e.change === "update");
151
- const willPrune = opts.prune === true && deletes.length > 0;
152
- if (opts.dryRun === true) {
153
- // Make the dry run reflect the --prune decision.
154
- if (deletes.length > 0) {
155
- info(willPrune
156
- ? `Would prune ${String(deletes.length)} resource(s): ${deletes.map((e) => e.id).join(", ")}`
157
- : `${String(deletes.length)} resource(s) would be left in place — add --prune to remove them.`);
158
- }
159
- return;
160
- }
161
- if (!hasApplyWork && !willPrune) {
162
- if (deletes.length > 0) {
163
- info(`${String(deletes.length)} resource(s) in state are no longer in code. Re-run with --prune to remove them.`);
164
- }
165
- else {
166
- success("Nothing to deploy — everything is up to date.");
167
- }
168
- return;
169
- }
170
- if (opts.yes !== true) {
171
- const ask = willPrune
172
- ? `Deploy to workspace ${workspaceUuid} and prune ${String(deletes.length)} resource(s)?`
173
- : `Deploy to workspace ${workspaceUuid}?`;
174
- const ok = await confirm(ask);
175
- if (!ok)
176
- failWith("Aborted.", { code: ExitCodes.GenericError });
177
- }
178
- // Snapshot the pre-deploy state so `cdk rollback` can restore it.
179
- snapshotState(root);
180
- // Live progress: a spinner naming the resource currently being applied,
181
- // leaving a ✓ line behind for each completed one. Suppressed for --json
182
- // so machine output on stdout stays clean.
183
- const spinner = opts.json === true ? undefined : startSpinner("Deploying…");
184
- const onProgress = spinner === undefined
185
- ? undefined
186
- : (event) => {
187
- if (event.phase === "start") {
188
- const verb = event.change === "create" ? "Creating" : "Updating";
189
- spinner.update(`${verb} ${colors.bold(event.id)} ${colors.dim(`(${event.index}/${event.total})`)}`);
190
- }
191
- else {
192
- const done = event.change === "create" ? "created" : "updated";
193
- spinner.log(` ${colors.green("✓")} ${event.id} ${colors.dim(done)}`);
194
- }
195
- };
196
- let result;
197
- try {
198
- result = await apply({ nodes, state }, liveExecutors(api()), // throws NotAuthenticated if not logged in
199
- (next) => writeState(root, next), liveReaders(api()), // capture a live fingerprint for drift detection
200
- onProgress);
201
- }
202
- catch (error) {
203
- spinner?.stop();
204
- appendAudit(root, {
205
- runId,
206
- at: new Date().toISOString(),
207
- command: "deploy",
208
- workspaceUuid,
209
- ok: false,
210
- error: message(error),
211
- });
212
- failWith(`Deploy failed: ${message(error)}`, {
213
- code: ExitCodes.GenericError,
214
- extra: {
215
- runId,
216
- hint: "Resources created before the failure were saved to cargo.state.json — fix the error and re-run to continue.",
217
- },
218
- });
219
- }
220
- spinner?.stop();
221
- let pruned = {
222
- removed: [],
223
- released: [],
224
- };
225
- if (willPrune) {
226
- try {
227
- pruned = await removeResources(root, api(), deletes.map((e) => e.id));
228
- }
229
- catch (error) {
230
- appendAudit(root, {
231
- runId,
232
- at: new Date().toISOString(),
233
- command: "deploy",
234
- workspaceUuid,
235
- ok: false,
236
- error: `prune: ${message(error)}`,
237
- });
238
- failWith(`Prune failed: ${message(error)}`, {
239
- code: ExitCodes.GenericError,
240
- extra: { runId },
241
- });
242
- }
243
- }
244
- const created = result.applied.filter((e) => e.change === "create").length;
245
- const updated = result.applied.filter((e) => e.change === "update").length;
246
- appendAudit(root, {
247
- runId,
248
- at: new Date().toISOString(),
249
- command: "deploy",
250
- workspaceUuid,
251
- ok: true,
252
- summary: {
253
- created,
254
- updated,
255
- unchanged: result.skipped.length,
256
- pruned: pruned.removed.length,
257
- released: pruned.released.length,
258
- },
259
- });
260
- if (opts.json === true) {
261
- outputJson({
262
- created,
263
- updated,
264
- skipped: result.skipped.length,
265
- pruned: pruned.removed.length,
266
- released: pruned.released.length,
267
- });
268
- }
269
- else {
270
- success(`${String(created)} created, ${String(updated)} updated, ${String(result.skipped.length)} unchanged.`);
271
- if (pruned.removed.length > 0 || pruned.released.length > 0) {
272
- info(`Pruned ${String(pruned.removed.length)}${pruned.released.length > 0 ? ` (released ${String(pruned.released.length)} adopted)` : ""}.`);
273
- }
274
- else if (deletes.length > 0) {
275
- info(`${String(deletes.length)} resource(s) no longer in code — re-run with --prune to remove them.`);
276
- }
277
- // First deploy: nudge the user to commit state and ignore the lock.
278
- if (prior === undefined) {
279
- info("Wrote cargo.state.json — commit it (it links your code to deployed resources). Add cargo.state.lock to .gitignore.");
280
- }
281
- }
282
- });
283
- cdk
284
- .command("refresh")
285
- .description("Re-read live resources and report drift from the last deploy (read-only).")
286
- .option("--dir <path>", "Repo root (default: cwd)")
287
- .option("--json", "Output the drift report as JSON")
288
- .action(async (opts) => {
289
- if (opts.dir !== undefined)
290
- process.chdir(opts.dir);
291
- const root = ".";
292
- const workspaceUuid = await resolveWorkspaceUuid(getApi);
293
- const state = readState(root);
294
- if (state === undefined || Object.keys(state.resources).length === 0) {
295
- info("No state — nothing to refresh.");
296
- return;
297
- }
298
- // Reading another workspace's state against the selected one would report
299
- // everything as deleted — refuse rather than print misleading drift.
300
- if (state.workspaceUuid !== workspaceUuid) {
301
- failWith(`cargo.state.json belongs to workspace ${state.workspaceUuid}, not the selected ${workspaceUuid}.`, { code: ExitCodes.InvalidUsage });
302
- }
303
- const api = getApi();
304
- let drift;
305
- try {
306
- drift = await detectDrift(state, liveReaders(api));
307
- }
308
- catch (error) {
309
- failWith(`Refresh failed: ${message(error)}`, {
310
- code: ExitCodes.GenericError,
311
- });
312
- }
313
- if (opts.json === true) {
314
- outputJson(drift);
315
- return;
316
- }
317
- const drifted = drift.filter((d) => d.status === "modified" || d.status === "deleted");
318
- if (drifted.length === 0) {
319
- success(`In sync — ${String(drift.length)} resource(s) match the last deploy.`);
320
- return;
321
- }
322
- info(`${String(drifted.length)} resource(s) drifted from code:`);
323
- for (const d of drifted) {
324
- info(` ${d.status === "deleted" ? "deleted externally" : "modified externally"}: ${d.id}`);
325
- }
326
- info("Run 'cdk deploy --refresh' to re-apply code over the drift.");
327
- });
328
- cdk
329
- .command("import")
330
- .argument("<id>", "Code resource id to bind (e.g. agent:sdr)")
331
- .argument("<uuid>", "The live resource's uuid in the workspace")
332
- .description("Bind an existing live resource to a code resource in cargo.state.json.")
333
- .option("--dir <path>", "Repo root (default: cwd)")
334
- .option("--force", "Steal the state lock held by another run")
335
- .option("--json", "Output the result as JSON")
336
- .action(async (id, uuid, opts) => {
337
- if (opts.dir !== undefined)
338
- process.chdir(opts.dir);
339
- const root = ".";
340
- const workspaceUuid = await resolveWorkspaceUuid(getApi);
341
- const api = getApi();
342
- const runId = newRunId();
343
- try {
344
- acquireLock(root, "import", opts.force === true);
345
- }
346
- catch (error) {
347
- failWith(message(error), { code: ExitCodes.GenericError });
348
- }
349
- snapshotState(root); // enable `cdk rollback`
350
- let result;
351
- try {
352
- result = await importResource(root, api, workspaceUuid, id, uuid);
353
- }
354
- catch (error) {
355
- appendAudit(root, {
356
- runId,
357
- at: new Date().toISOString(),
358
- command: "import",
359
- workspaceUuid,
360
- ok: false,
361
- error: message(error),
362
- });
363
- failWith(`Import failed: ${message(error)}`, {
364
- code: ExitCodes.GenericError,
365
- extra: { runId },
366
- });
367
- }
368
- appendAudit(root, {
369
- runId,
370
- at: new Date().toISOString(),
371
- command: "import",
372
- workspaceUuid,
373
- ok: true,
374
- summary: { id, uuid, kind: result.kind },
375
- });
376
- if (opts.json === true)
377
- outputJson(result);
378
- else
379
- success(`Imported ${id} → ${uuid} (${result.kind}).`);
380
- });
381
- cdk
382
- .command("rollback")
383
- .description("Restore cargo.state.json from the snapshot taken before the last deploy/destroy/import.")
384
- .option("--dir <path>", "Repo root (default: cwd)")
385
- .option("--yes", "Skip the confirmation prompt")
386
- .option("--force", "Steal the state lock held by another run")
387
- .action(async (opts) => {
388
- if (opts.dir !== undefined)
389
- process.chdir(opts.dir);
390
- const root = ".";
391
- const workspaceUuid = await resolveWorkspaceUuid(getApi);
392
- const runId = newRunId();
393
- if (opts.yes !== true) {
394
- const ok = await confirm("Restore cargo.state.json from the last snapshot? (restores the state file only — not live resources)");
395
- if (!ok)
396
- failWith("Aborted.", { code: ExitCodes.GenericError });
397
- }
398
- try {
399
- acquireLock(root, "rollback", opts.force === true);
400
- }
401
- catch (error) {
402
- failWith(message(error), { code: ExitCodes.GenericError });
403
- }
404
- if (!restoreSnapshot(root)) {
405
- failWith("No snapshot found (cargo.state.bak.json) — nothing to roll back.", { code: ExitCodes.InvalidUsage });
406
- }
407
- appendAudit(root, {
408
- runId,
409
- at: new Date().toISOString(),
410
- command: "rollback",
411
- workspaceUuid,
412
- ok: true,
413
- });
414
- success("Restored cargo.state.json from the snapshot. Run 'cargo-ai cdk deploy --refresh' to reconcile live resources to it.");
415
- });
416
- cdk
417
- .command("destroy")
418
- .description("Tear down resources recorded in cargo.state.json (deletes by uuid).")
419
- .option("--dir <path>", "Repo root (default: cwd)")
420
- .option("--yes", "Skip the confirmation prompt")
421
- .option("--target <id>", "Only destroy this resource id (e.g. play:welcome)")
422
- .option("--all", "Destroy every state-tracked resource (required for blanket teardown)")
423
- .option("--force", "Steal the state lock held by another run")
424
- .option("--json", "Output the result as JSON")
425
- .action(async (opts) => {
426
- // Run from the repo root so relative code paths (defineWorker/App/File)
427
- // and cargo.state.json resolve against it.
428
- if (opts.dir !== undefined)
429
- process.chdir(opts.dir);
430
- const root = ".";
431
- const api = getApi();
432
- const workspaceUuid = await resolveWorkspaceUuid(getApi);
433
- const runId = newRunId();
434
- // Blanket teardown must be explicit — `--yes` alone can't nuke a whole
435
- // workspace; you must opt in with --target <id> or --all.
436
- if (opts.target === undefined && opts.all !== true) {
437
- failWith("Specify --target <id> to remove one resource, or --all to remove everything in state.", { code: ExitCodes.InvalidUsage });
438
- }
439
- // Lock before reading state so the read→delete sequence is consistent.
440
- try {
441
- acquireLock(root, "destroy", opts.force === true);
442
- }
443
- catch (error) {
444
- failWith(message(error), { code: ExitCodes.GenericError });
445
- }
446
- const state = readState(root);
447
- if (state === undefined || Object.keys(state.resources).length === 0) {
448
- info("Nothing to destroy — no state.");
449
- return;
450
- }
451
- if (state.workspaceUuid !== workspaceUuid) {
452
- failWith(`cargo.state.json belongs to workspace ${state.workspaceUuid}, not the selected ${workspaceUuid}.`, { code: ExitCodes.InvalidUsage });
453
- }
454
- const ids = opts.target !== undefined
455
- ? opts.target in state.resources
456
- ? [opts.target]
457
- : []
458
- : Object.keys(state.resources);
459
- if (ids.length === 0) {
460
- // An explicit --target that matches nothing is a usage error, not a
461
- // success — a scripted `destroy --target X && deploy` must not believe
462
- // X was torn down when the id was simply mistyped.
463
- failWith(`"${String(opts.target)}" is not in state — nothing to destroy. Run \`cargo-ai cdk plan\` to see the tracked ids.`, { code: ExitCodes.InvalidUsage });
464
- }
465
- // Always show exactly what will be deleted, even with --yes.
466
- info(`About to remove ${String(ids.length)} resource(s) from workspace ${workspaceUuid}:`);
467
- for (const id of ids)
468
- info(` - ${id}`);
469
- if (opts.yes !== true) {
470
- const ok = await confirm(`Delete these ${String(ids.length)} resource(s)?`);
471
- if (!ok)
472
- failWith("Aborted.", { code: ExitCodes.GenericError });
473
- }
474
- snapshotState(root); // enable `cdk rollback`
475
- let result;
476
- try {
477
- result = await destroy(root, api, { target: opts.target });
478
- }
479
- catch (error) {
480
- appendAudit(root, {
481
- runId,
482
- at: new Date().toISOString(),
483
- command: "destroy",
484
- workspaceUuid,
485
- ok: false,
486
- error: message(error),
487
- });
488
- failWith(`Destroy failed: ${message(error)}`, {
489
- code: ExitCodes.GenericError,
490
- extra: {
491
- runId,
492
- hint: "Resources removed before the failure are gone and dropped from state — re-run to remove the rest.",
493
- },
494
- });
495
- }
496
- appendAudit(root, {
497
- runId,
498
- at: new Date().toISOString(),
499
- command: "destroy",
500
- workspaceUuid,
501
- ok: true,
502
- summary: {
503
- removed: result.removed.length,
504
- released: result.released.length,
505
- ids: result.removed,
506
- },
507
- });
508
- if (opts.json === true)
509
- outputJson(result);
510
- else {
511
- success(result.removed.length === 0
512
- ? "Nothing removed."
513
- : `Removed ${String(result.removed.length)}: ${result.removed.join(", ")}`);
514
- if (result.released.length > 0) {
515
- info(`Released ${String(result.released.length)} adopted (left in place): ${result.released.join(", ")}`);
516
- }
517
- }
518
- });
519
- }
520
- // Resolve the workspace to operate on. Prefers an explicit `CARGO_WORKSPACE_UUID`
521
- // / credentials-file workspace; otherwise falls back to the workspace the token
522
- // is bound to (the same lookup `cargo-ai whoami` uses), so a workspace-scoped
523
- // token "just works" without setting an env var.
524
- async function resolveWorkspaceUuid(getApi) {
525
- const { workspaceUuid } = getConfig();
526
- if (workspaceUuid !== undefined)
527
- return workspaceUuid;
528
- try {
529
- const { workspace } = await getApi().workspaceManagement.workspace.getCurrent();
530
- return workspace.uuid;
531
- }
532
- catch (error) {
533
- failWith(`No workspace selected and couldn't resolve one from your credentials (${message(error)}). ` +
534
- "Run 'cargo-ai login' or set CARGO_WORKSPACE_UUID.", { code: ExitCodes.NotAuthenticated });
535
- }
536
- }
537
- function message(error) {
538
- return error instanceof Error ? error.message : String(error);
539
- }
@@ -1,3 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerInitCommand(parent: Command): void;
3
- //# sourceMappingURL=init.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/commands/cdk/init.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAyEzD"}
@@ -1,86 +0,0 @@
1
- import { existsSync, readdirSync } from "node:fs";
2
- import { createRequire } from "node:module";
3
- import { basename, dirname, join, relative, resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { ExitCodes, failWith, info, success } from "../runHandler.js";
6
- import { copyDirectory, listTemplates } from "../templateUtils.js";
7
- const require = createRequire(import.meta.url);
8
- // `cargo-ai cdk init <directory> [--template <slug>]` — scaffold a starter CDK
9
- // project by copying one of `@cargo-ai/cdk`'s templates (see `--list-templates`),
10
- // substituting `__APP_NAME__`. Mirrors the hosting app/worker `init` commands.
11
- const TEMPLATE_DESCRIPTIONS = {
12
- blank: "Minimal starter — one connector + model + a workflow-backed tool. Good starting point.",
13
- full: "The full example — every resource type wired into a GTM growth workspace: connectors, models, plays, agents, an MCP server, context, tools, a worker, and a hosted app.",
14
- };
15
- export function registerInitCommand(parent) {
16
- parent
17
- .command("init <directory>")
18
- .description("Scaffold a starter Cargo CDK project locally from a template (ready to plan/deploy).")
19
- .option("--template <slug>", "Template slug (default: blank)", "blank")
20
- .option("--name <name>", "Project name written into package.json")
21
- .option("--list-templates", "Print available templates and exit")
22
- .option("--force", "Write into a non-empty directory")
23
- .action(async (directory, opts) => {
24
- const templatesRoot = findTemplatesRoot();
25
- if (opts.listTemplates === true) {
26
- const slugs = await listTemplates(templatesRoot);
27
- for (const slug of slugs) {
28
- const desc = TEMPLATE_DESCRIPTIONS[slug] ?? "";
29
- info(`${slug}${desc.length > 0 ? ` — ${desc}` : ""}`);
30
- }
31
- return;
32
- }
33
- const templateDir = join(templatesRoot, opts.template);
34
- if (!existsSync(templateDir)) {
35
- const slugs = await listTemplates(templatesRoot);
36
- failWith(`Unknown template "${opts.template}". Available: ${slugs.join(", ")}`, { code: ExitCodes.GenericError });
37
- }
38
- const targetDir = resolve(process.cwd(), directory);
39
- if (existsSync(targetDir) &&
40
- readdirSync(targetDir).length > 0 &&
41
- opts.force !== true) {
42
- failWith(`Directory ${directory} is not empty. Pass --force to scaffold into it anyway.`, { code: ExitCodes.GenericError });
43
- }
44
- const appName = opts.name !== undefined ? opts.name : basename(targetDir);
45
- await copyDirectory(templateDir, targetDir, [
46
- { from: "__APP_NAME__", to: appName },
47
- ]);
48
- success(`Scaffolded ${directory} from the "${opts.template}" template`);
49
- info(``);
50
- info([
51
- `Next steps:`,
52
- ` cd ${relative(process.cwd(), targetDir)}`,
53
- ` npm install`,
54
- ` cargo-ai login # authenticate to your workspace`,
55
- ` cargo-ai cdk types # generate typed connector/model config`,
56
- ` cargo-ai cdk plan # preview the resource tree`,
57
- ` cargo-ai cdk deploy # create it in the workspace`,
58
- ].join("\n"));
59
- });
60
- }
61
- // Templates live in `@cargo-ai/cdk/templates`. Resolve the package entry and walk
62
- // up to the package root that holds `templates/` — works whether the CDK was
63
- // installed from npm or came from the monorepo.
64
- function findTemplatesRoot() {
65
- try {
66
- const entry = require.resolve("@cargo-ai/cdk");
67
- let cursor = dirname(entry);
68
- for (let i = 0; i < 6; i += 1) {
69
- const candidate = join(cursor, "templates");
70
- if (existsSync(candidate))
71
- return candidate;
72
- cursor = dirname(cursor);
73
- }
74
- }
75
- catch {
76
- // Fall through to the monorepo-relative lookup.
77
- }
78
- let cursor = dirname(fileURLToPath(import.meta.url));
79
- for (let i = 0; i < 8; i += 1) {
80
- const candidate = join(cursor, "packages/cdk/templates");
81
- if (existsSync(candidate))
82
- return candidate;
83
- cursor = dirname(cursor);
84
- }
85
- throw new Error("Could not locate @cargo-ai/cdk templates. Make sure @cargo-ai/cdk is installed alongside @cargo-ai/cli.");
86
- }
@@ -1,24 +0,0 @@
1
- /**
2
- * Fixed input shape of every agent node. Matches the SDK's `AgentInput`
3
- * type and the engine's `AiUtils.agentConfig` schema.
4
- */
5
- export declare const AGENT_INPUT_TYPE_SRC: string;
6
- /**
7
- * Print an integration action's JSON Schema config as a TS input type.
8
- * Returns `"Record<string, unknown>"` when the schema is missing or not an
9
- * object schema we can render.
10
- */
11
- export declare function printJsonSchemaInput(schema: unknown): string;
12
- /**
13
- * Like {@link printJsonSchemaInput} but WITHOUT the top-level `Ref<T> | T`
14
- * widening — for CDK connector/model config types, which are plain data (no
15
- * workflow builder Refs). Used by `cargo-ai cdk types`.
16
- */
17
- export declare function printJsonSchemaType(schema: unknown): string;
18
- /**
19
- * Print a tool release's `formFields` as a TS input type. Returns
20
- * `undefined` when the fields can't be interpreted (caller falls back to
21
- * `Record<string, unknown>`).
22
- */
23
- export declare function printFormFieldsInput(formFields: unknown): string | undefined;
24
- //# sourceMappingURL=inputTypes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inputTypes.d.ts","sourceRoot":"","sources":["../../../src/commands/cdk/inputTypes.ts"],"names":[],"mappings":"AAmCA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAE+D,CAAC;AAEjG;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAM5D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAQ3D;AAkMD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAU5E"}