@cargo-ai/cdk 1.0.7 → 1.0.9

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.
Files changed (40) hide show
  1. package/README.md +0 -43
  2. package/build/src/cli/auth.d.ts.map +1 -1
  3. package/build/src/cli/auth.js +16 -12
  4. package/build/src/cli/commands/deploy.d.ts.map +1 -1
  5. package/build/src/cli/commands/deploy.js +81 -107
  6. package/build/src/cli/commands/from.d.ts.map +1 -1
  7. package/build/src/cli/commands/from.js +18 -8
  8. package/build/src/cli/commands/init.d.ts.map +1 -1
  9. package/build/src/cli/commands/init.js +13 -8
  10. package/build/src/cli/commands/inputTypes.d.ts +8 -0
  11. package/build/src/cli/commands/inputTypes.d.ts.map +1 -1
  12. package/build/src/cli/commands/inputTypes.js +117 -13
  13. package/build/src/cli/commands/types.d.ts.map +1 -1
  14. package/build/src/cli/commands/types.js +32 -13
  15. package/build/src/cli/io.js +2 -2
  16. package/build/src/cli/version.d.ts.map +1 -1
  17. package/build/src/cli/version.js +10 -6
  18. package/build/src/deploy/apply.d.ts.map +1 -1
  19. package/build/src/deploy/apply.js +37 -30
  20. package/build/src/deploy/compile.d.ts.map +1 -1
  21. package/build/src/deploy/compile.js +7 -5
  22. package/build/src/deploy/destroy.d.ts.map +1 -1
  23. package/build/src/deploy/destroy.js +24 -14
  24. package/build/src/deploy/executors.live.d.ts.map +1 -1
  25. package/build/src/deploy/executors.live.js +202 -173
  26. package/build/src/deploy/import.js +2 -2
  27. package/build/src/deploy/index.js +1 -1
  28. package/build/src/deploy/lock.d.ts.map +1 -1
  29. package/build/src/deploy/lock.js +13 -10
  30. package/build/src/deploy/readers.live.d.ts.map +1 -1
  31. package/build/src/deploy/readers.live.js +27 -15
  32. package/build/src/deploy/refresh.d.ts.map +1 -1
  33. package/build/src/deploy/refresh.js +20 -18
  34. package/build/src/refs.d.ts.map +1 -1
  35. package/build/src/refs.js +5 -1
  36. package/build/src/resources/actions.d.ts +1 -1
  37. package/build/src/resources/actions.d.ts.map +1 -1
  38. package/build/src/resources/actions.js +3 -2
  39. package/build/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +3 -3
package/README.md CHANGED
@@ -168,49 +168,6 @@ There is one context repo per workspace, so this is a singleton. On deploy it
168
168
  writes each changed file into the repo via the runtime — **additive**: files
169
169
  added elsewhere (the UI, other tooling) are left in place.
170
170
 
171
- ### Unification
172
-
173
- A model can declare how it feeds Cargo's unified `Account` / `Contact` /
174
- `AccountEvent` / `ContactEvent` models. A connector model defaults to its
175
- integration's built-in mapping (`{ source: "integration" }`), so you only pass
176
- `unification` to override it or to unify a model the integration doesn't map on
177
- its own. A `custom` unification maps columns to shared references (`domain`,
178
- `email`, `linkedinId`, …) and can link a child to its parent by pointing at
179
- another model handle:
180
-
181
- ```ts
182
- import { defineModel } from "@cargo-ai/cdk";
183
-
184
- export const accounts = defineModel("accounts", {
185
- dataset: warehouse,
186
- extractSlug: "runQuery",
187
- unification: {
188
- source: "custom",
189
- type: "account",
190
- uniqueColumns: [{ slug: "website", reference: "domain" }],
191
- },
192
- });
193
-
194
- export const contacts = defineModel("contacts", {
195
- dataset: warehouse,
196
- extractSlug: "runQuery",
197
- unification: {
198
- source: "custom",
199
- type: "contact",
200
- uniqueColumns: [{ slug: "work_email", reference: "workEmail" }],
201
- // link each contact to its unified account — pass the model handle, not a uuid
202
- parent: { kind: "model", columnSlug: "account_id", parent: accounts },
203
- },
204
- });
205
- ```
206
-
207
- Unification isn't part of the create call, so the CDK applies it with a
208
- follow-up update once the model exists — including models the deploy adopts.
209
- Passing a parent handle makes the child depend on the parent, so the parent is
210
- created first and its uuid is injected. See
211
- [Unification](https://docs.getcargo.ai/models/unification) for the reference and
212
- priority rules.
213
-
214
171
  ## Commands
215
172
 
216
173
  In a scaffolded project, the everyday commands are `npm run` scripts:
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/cli/auth.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,GAAG,EAAkC,MAAM,eAAe,CAAC;AAuBzE,MAAM,MAAM,MAAM,GAAG;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAYF,wBAAgB,SAAS,IAAI,MAAM,CAoBlC;AA4DD,wBAAgB,MAAM,IAAI,GAAG,CAS5B"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/cli/auth.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,GAAG,EAAkC,MAAM,eAAe,CAAC;AAuBzE,MAAM,MAAM,MAAM,GAAG;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAYF,wBAAgB,SAAS,IAAI,MAAM,CAqBlC;AAgED,wBAAgB,MAAM,IAAI,GAAG,CAS5B"}
@@ -13,7 +13,7 @@ const ORIGIN = { name: "cargo-cdk", version: packageVersion() };
13
13
  const DEFAULT_BASE_URL = "https://api.getcargo.io";
14
14
  const CREDENTIALS_FILE = join(homedir(), ".config", "cargo-ai", "credentials.json");
15
15
  function loadCredentials() {
16
- if (!existsSync(CREDENTIALS_FILE))
16
+ if (existsSync(CREDENTIALS_FILE) === false)
17
17
  return undefined;
18
18
  try {
19
19
  return JSON.parse(readFileSync(CREDENTIALS_FILE, "utf-8"));
@@ -24,21 +24,31 @@ function loadCredentials() {
24
24
  }
25
25
  // Resolve token / baseUrl / workspace, preferring env over the credentials file.
26
26
  export function getConfig() {
27
- const credentials = loadCredentials();
27
+ const loaded = loadCredentials();
28
+ const credentials = loaded === undefined ? {} : loaded;
28
29
  const envToken = process.env["CARGO_API_TOKEN"];
29
- const accessToken = envToken !== undefined ? envToken : credentials?.accessToken;
30
+ const accessToken = envToken !== undefined ? envToken : credentials.accessToken;
30
31
  const envUrl = process.env["CARGO_BASE_URL"];
31
32
  const baseUrl = envUrl !== undefined
32
33
  ? envUrl
33
- : credentials?.baseUrl !== undefined
34
+ : credentials.baseUrl !== undefined
34
35
  ? credentials.baseUrl
35
36
  : DEFAULT_BASE_URL;
36
37
  const envUuid = process.env["CARGO_WORKSPACE_UUID"];
37
- const workspaceUuid = envUuid !== undefined ? envUuid : credentials?.workspaceUuid;
38
+ const workspaceUuid = envUuid !== undefined ? envUuid : credentials.workspaceUuid;
38
39
  return { accessToken, baseUrl, workspaceUuid };
39
40
  }
40
41
  // Tunnel through an HTTP/HTTPS proxy when one is configured via the standard env
41
42
  // vars (honoring NO_PROXY); returns undefined otherwise so egress stays direct.
43
+ // The URL's hostname, or "" if it doesn't parse (used only for NO_PROXY matching).
44
+ function safeHostname(url) {
45
+ try {
46
+ return new URL(url).hostname;
47
+ }
48
+ catch {
49
+ return "";
50
+ }
51
+ }
42
52
  function getProxyTransport(targetUrl) {
43
53
  const getEnv = (...names) => {
44
54
  for (const name of names) {
@@ -52,13 +62,7 @@ function getProxyTransport(targetUrl) {
52
62
  if (noProxy === "*")
53
63
  return undefined;
54
64
  if (noProxy !== undefined) {
55
- let hostname = "";
56
- try {
57
- hostname = new URL(targetUrl).hostname;
58
- }
59
- catch {
60
- hostname = "";
61
- }
65
+ const hostname = safeHostname(targetUrl);
62
66
  const bypass = noProxy
63
67
  .split(",")
64
68
  .map((e) => e.trim())
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0CzC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA0oBN"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CzC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA2lBN"}
@@ -17,15 +17,9 @@ export function registerDeployCommands(parent, getApi) {
17
17
  if (opts.dir !== undefined)
18
18
  process.chdir(opts.dir);
19
19
  const root = ".";
20
- let result;
21
- try {
22
- result = await plan(root);
23
- }
24
- catch (error) {
25
- failWith(`Failed to load cdk repo: ${message(error)}`, {
26
- code: ExitCodes.InvalidUsage,
27
- });
28
- }
20
+ const result = await runOrFail(() => plan(root), (error) => failWith(`Failed to load cdk repo: ${message(error)}`, {
21
+ code: ExitCodes.InvalidUsage,
22
+ }));
29
23
  if (opts.json === true)
30
24
  outputJson(result);
31
25
  else
@@ -54,15 +48,9 @@ export function registerDeployCommands(parent, getApi) {
54
48
  const runId = newRunId();
55
49
  // Load the resource tree ONCE (loadResources resets the registry, so it
56
50
  // must not run twice in a process), then reuse the nodes for plan + apply.
57
- let nodes;
58
- try {
59
- nodes = await loadResources(root);
60
- }
61
- catch (error) {
62
- failWith(`Failed to load cdk repo: ${message(error)}`, {
63
- code: ExitCodes.InvalidUsage,
64
- });
65
- }
51
+ const nodes = await runOrFail(() => loadResources(root), (error) => failWith(`Failed to load cdk repo: ${message(error)}`, {
52
+ code: ExitCodes.InvalidUsage,
53
+ }));
66
54
  // Hold the state lock for the whole read→plan→apply sequence (not just
67
55
  // the apply), so a concurrent run can't rewrite cargo.state.json between
68
56
  // our read and our write. --dry-run is read-only, so it skips the lock.
@@ -78,7 +66,7 @@ export function registerDeployCommands(parent, getApi) {
78
66
  if (prior !== undefined && prior.workspaceUuid !== workspaceUuid) {
79
67
  failWith(`cargo.state.json belongs to workspace ${prior.workspaceUuid}, but the selected workspace is ${workspaceUuid}. Refusing to deploy (would orphan resources).`, { code: ExitCodes.InvalidUsage });
80
68
  }
81
- const baseState = prior ?? emptyState(workspaceUuid);
69
+ const baseState = prior !== undefined ? prior : emptyState(workspaceUuid);
82
70
  // Build the authenticated client lazily so a plain `--dry-run` stays
83
71
  // offline; `--refresh` and the apply both reuse this one instance.
84
72
  let apiClient;
@@ -90,47 +78,9 @@ export function registerDeployCommands(parent, getApi) {
90
78
  // With --refresh, re-read the live resources and fold out-of-band drift
91
79
  // into the state before planning: a resource edited in the UI re-applies
92
80
  // (its code-hash is invalidated) and one deleted externally is recreated.
93
- let state = baseState;
94
- if (opts.refresh === true &&
95
- Object.keys(baseState.resources).length > 0) {
96
- let drift;
97
- try {
98
- drift = await detectDrift(baseState, liveReaders(api()));
99
- }
100
- catch (error) {
101
- failWith(`Refresh failed: ${message(error)}`, {
102
- code: ExitCodes.GenericError,
103
- });
104
- }
105
- const modifiedExternally = drift.filter((d) => d.status === "modified");
106
- const deletedExternally = drift.filter((d) => d.status === "deleted");
107
- const changed = [...modifiedExternally, ...deletedExternally];
108
- if (changed.length === 0) {
109
- info("Refresh: no out-of-band drift.");
110
- }
111
- else {
112
- info(`Refresh found ${String(changed.length)} drifted resource(s):`);
113
- for (const d of modifiedExternally) {
114
- info(` modified externally: ${d.id}`);
115
- }
116
- for (const d of deletedExternally) {
117
- info(` deleted externally: ${d.id}`);
118
- }
119
- // A resource present in code but deleted in the UI is ambiguous —
120
- // an accident to restore, or an intentional removal. Don't silently
121
- // recreate it; force the decision unless --recreate-deleted opts in.
122
- if (deletedExternally.length > 0 && opts.recreateDeleted !== true) {
123
- failWith(`${String(deletedExternally.length)} resource(s) were deleted outside the CDK ` +
124
- `(${deletedExternally.map((d) => d.id).join(", ")}). Re-run with ` +
125
- `--recreate-deleted to restore them, or remove them from your code if ` +
126
- `the deletion was intentional.`, { code: ExitCodes.InvalidUsage });
127
- }
128
- // Modified always re-applies; deleted only reconciles (→ recreate)
129
- // once the user has opted in above.
130
- const effectiveDrift = opts.recreateDeleted === true ? drift : modifiedExternally;
131
- state = reconcileDrift(baseState, effectiveDrift);
132
- }
133
- }
81
+ const state = opts.refresh === true && Object.keys(baseState.resources).length > 0
82
+ ? await refreshedState(baseState, opts, api)
83
+ : baseState;
134
84
  const planResult = compile({ nodes, state });
135
85
  info(formatPlan(planResult));
136
86
  if (planResult.errors.length > 0) {
@@ -150,7 +100,7 @@ export function registerDeployCommands(parent, getApi) {
150
100
  }
151
101
  return;
152
102
  }
153
- if (!hasApplyWork && !willPrune) {
103
+ if (hasApplyWork === false && willPrune === false) {
154
104
  if (deletes.length > 0) {
155
105
  info(`${String(deletes.length)} resource(s) in state are no longer in code. Re-run with --prune to remove them.`);
156
106
  }
@@ -164,7 +114,7 @@ export function registerDeployCommands(parent, getApi) {
164
114
  ? `Deploy to workspace ${workspaceUuid} and prune ${String(deletes.length)} resource(s)?`
165
115
  : `Deploy to workspace ${workspaceUuid}?`;
166
116
  const ok = await confirm(ask);
167
- if (!ok)
117
+ if (ok === false)
168
118
  failWith("Aborted.", { code: ExitCodes.GenericError });
169
119
  }
170
120
  // Snapshot the pre-deploy state so `cdk rollback` can restore it.
@@ -185,14 +135,11 @@ export function registerDeployCommands(parent, getApi) {
185
135
  spinner.log(` ${colors.green("✓")} ${event.id} ${colors.dim(done)}`);
186
136
  }
187
137
  };
188
- let result;
189
- try {
190
- result = await apply({ nodes, state }, liveExecutors(api()), // throws NotAuthenticated if not logged in
191
- (next) => writeState(root, next), liveReaders(api()), // capture a live fingerprint for drift detection
192
- onProgress);
193
- }
194
- catch (error) {
195
- spinner?.stop();
138
+ const result = await runOrFail(() => apply({ nodes, state }, liveExecutors(api()), // throws NotAuthenticated if not logged in
139
+ (next) => writeState(root, next), liveReaders(api()), // capture a live fingerprint for drift detection
140
+ onProgress), (error) => {
141
+ if (spinner !== undefined)
142
+ spinner.stop();
196
143
  appendAudit(root, {
197
144
  runId,
198
145
  at: new Date().toISOString(),
@@ -208,17 +155,11 @@ export function registerDeployCommands(parent, getApi) {
208
155
  hint: "Resources created before the failure were saved to cargo.state.json — fix the error and re-run to continue.",
209
156
  },
210
157
  });
211
- }
212
- spinner?.stop();
213
- let pruned = {
214
- removed: [],
215
- released: [],
216
- };
217
- if (willPrune) {
218
- try {
219
- pruned = await removeResources(root, api(), deletes.map((e) => e.id));
220
- }
221
- catch (error) {
158
+ });
159
+ if (spinner !== undefined)
160
+ spinner.stop();
161
+ const pruned = willPrune
162
+ ? await runOrFail(() => removeResources(root, api(), deletes.map((e) => e.id)), (error) => {
222
163
  appendAudit(root, {
223
164
  runId,
224
165
  at: new Date().toISOString(),
@@ -231,8 +172,8 @@ export function registerDeployCommands(parent, getApi) {
231
172
  code: ExitCodes.GenericError,
232
173
  extra: { runId },
233
174
  });
234
- }
235
- }
175
+ })
176
+ : { removed: [], released: [] };
236
177
  const created = result.applied.filter((e) => e.change === "create").length;
237
178
  const updated = result.applied.filter((e) => e.change === "update").length;
238
179
  appendAudit(root, {
@@ -293,15 +234,9 @@ export function registerDeployCommands(parent, getApi) {
293
234
  failWith(`cargo.state.json belongs to workspace ${state.workspaceUuid}, not the selected ${workspaceUuid}.`, { code: ExitCodes.InvalidUsage });
294
235
  }
295
236
  const api = getApi();
296
- let drift;
297
- try {
298
- drift = await detectDrift(state, liveReaders(api));
299
- }
300
- catch (error) {
301
- failWith(`Refresh failed: ${message(error)}`, {
302
- code: ExitCodes.GenericError,
303
- });
304
- }
237
+ const drift = await runOrFail(() => detectDrift(state, liveReaders(api)), (error) => failWith(`Refresh failed: ${message(error)}`, {
238
+ code: ExitCodes.GenericError,
239
+ }));
305
240
  if (opts.json === true) {
306
241
  outputJson(drift);
307
242
  return;
@@ -339,11 +274,7 @@ export function registerDeployCommands(parent, getApi) {
339
274
  failWith(message(error), { code: ExitCodes.GenericError });
340
275
  }
341
276
  snapshotState(root); // enable `cdk rollback`
342
- let result;
343
- try {
344
- result = await importResource(root, api, workspaceUuid, id, uuid);
345
- }
346
- catch (error) {
277
+ const result = await runOrFail(() => importResource(root, api, workspaceUuid, id, uuid), (error) => {
347
278
  appendAudit(root, {
348
279
  runId,
349
280
  at: new Date().toISOString(),
@@ -356,7 +287,7 @@ export function registerDeployCommands(parent, getApi) {
356
287
  code: ExitCodes.GenericError,
357
288
  extra: { runId },
358
289
  });
359
- }
290
+ });
360
291
  appendAudit(root, {
361
292
  runId,
362
293
  at: new Date().toISOString(),
@@ -384,7 +315,7 @@ export function registerDeployCommands(parent, getApi) {
384
315
  const runId = newRunId();
385
316
  if (opts.yes !== true) {
386
317
  const ok = await confirm("Restore cargo.state.json from the last snapshot? (restores the state file only — not live resources)");
387
- if (!ok)
318
+ if (ok === false)
388
319
  failWith("Aborted.", { code: ExitCodes.GenericError });
389
320
  }
390
321
  try {
@@ -393,7 +324,7 @@ export function registerDeployCommands(parent, getApi) {
393
324
  catch (error) {
394
325
  failWith(message(error), { code: ExitCodes.GenericError });
395
326
  }
396
- if (!restoreSnapshot(root)) {
327
+ if (restoreSnapshot(root) === false) {
397
328
  failWith("No snapshot found (cargo.state.bak.json) — nothing to roll back.", { code: ExitCodes.InvalidUsage });
398
329
  }
399
330
  appendAudit(root, {
@@ -460,15 +391,11 @@ export function registerDeployCommands(parent, getApi) {
460
391
  info(` - ${id}`);
461
392
  if (opts.yes !== true) {
462
393
  const ok = await confirm(`Delete these ${String(ids.length)} resource(s)?`);
463
- if (!ok)
394
+ if (ok === false)
464
395
  failWith("Aborted.", { code: ExitCodes.GenericError });
465
396
  }
466
397
  snapshotState(root); // enable `cdk rollback`
467
- let result;
468
- try {
469
- result = await destroy(root, api, { target: opts.target });
470
- }
471
- catch (error) {
398
+ const result = await runOrFail(() => destroy(root, api, { target: opts.target }), (error) => {
472
399
  appendAudit(root, {
473
400
  runId,
474
401
  at: new Date().toISOString(),
@@ -484,7 +411,7 @@ export function registerDeployCommands(parent, getApi) {
484
411
  hint: "Resources removed before the failure are gone and dropped from state — re-run to remove the rest.",
485
412
  },
486
413
  });
487
- }
414
+ });
488
415
  appendAudit(root, {
489
416
  runId,
490
417
  at: new Date().toISOString(),
@@ -526,6 +453,53 @@ async function resolveWorkspaceUuid(getApi) {
526
453
  "Run 'cargo-ai login' or set CARGO_WORKSPACE_UUID.", { code: ExitCodes.NotAuthenticated });
527
454
  }
528
455
  }
456
+ // Await `op`, routing any failure through `onError` (which never returns —
457
+ // it exits via `failWith`) so the successful result can bind to a `const`
458
+ // instead of a reassigned `let` captured out of a try/catch.
459
+ async function runOrFail(op, onError) {
460
+ try {
461
+ return await op();
462
+ }
463
+ catch (error) {
464
+ onError(error);
465
+ }
466
+ }
467
+ // --refresh: re-read the live resources and fold out-of-band drift into the
468
+ // state before planning. Returns the state to plan against — `baseState`
469
+ // unchanged when there is no actionable drift. Callers gate this behind the
470
+ // refresh flag and a non-empty state.
471
+ async function refreshedState(baseState, opts, api) {
472
+ const drift = await runOrFail(() => detectDrift(baseState, liveReaders(api())), (error) => failWith(`Refresh failed: ${message(error)}`, {
473
+ code: ExitCodes.GenericError,
474
+ }));
475
+ const modifiedExternally = drift.filter((d) => d.status === "modified");
476
+ const deletedExternally = drift.filter((d) => d.status === "deleted");
477
+ const changed = [...modifiedExternally, ...deletedExternally];
478
+ if (changed.length === 0) {
479
+ info("Refresh: no out-of-band drift.");
480
+ return baseState;
481
+ }
482
+ info(`Refresh found ${String(changed.length)} drifted resource(s):`);
483
+ for (const d of modifiedExternally) {
484
+ info(` modified externally: ${d.id}`);
485
+ }
486
+ for (const d of deletedExternally) {
487
+ info(` deleted externally: ${d.id}`);
488
+ }
489
+ // A resource present in code but deleted in the UI is ambiguous — an accident
490
+ // to restore, or an intentional removal. Don't silently recreate it; force the
491
+ // decision unless --recreate-deleted opts in.
492
+ if (deletedExternally.length > 0 && opts.recreateDeleted !== true) {
493
+ failWith(`${String(deletedExternally.length)} resource(s) were deleted outside the CDK ` +
494
+ `(${deletedExternally.map((d) => d.id).join(", ")}). Re-run with ` +
495
+ `--recreate-deleted to restore them, or remove them from your code if ` +
496
+ `the deletion was intentional.`, { code: ExitCodes.InvalidUsage });
497
+ }
498
+ // Modified always re-applies; deleted only reconciles (→ recreate) once the
499
+ // user has opted in above.
500
+ const effectiveDrift = opts.recreateDeleted === true ? drift : modifiedExternally;
501
+ return reconcileDrift(baseState, effectiveDrift);
502
+ }
529
503
  function message(error) {
530
504
  return error instanceof Error ? error.message : String(error);
531
505
  }
@@ -1 +1 @@
1
- {"version":3,"file":"from.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/from.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAIF,mFAAmF;AACnF,wBAAgB,0BAA0B,CACxC,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,MAAM,GACZ,IAAI,CAeN;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAW3E;AA0BD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAqD7D;AAED,QAAA,MAAM,cAAc;;;;;iBAKlB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAEvD,4EAA4E;AAC5E,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAoCvC;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,OAAO,EAAE,MAAM,GACd,QAAQ,CAkBV;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA8BxD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAsDpB"}
1
+ {"version":3,"file":"from.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/from.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAIF,mFAAmF;AACnF,wBAAgB,0BAA0B,CACxC,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,MAAM,GACZ,IAAI,CAeN;AAED,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAW3E;AA0BD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAwD7D;AAED,QAAA,MAAM,cAAc;;;;;iBAKlB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE9D,eAAO,MAAM,iBAAiB,wBAAwB,CAAC;AAqCvD,4EAA4E;AAC5E,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAavC;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,QAAQ,EAAE,gBAAgB,GAAG,SAAS,EACtC,OAAO,EAAE,MAAM,GACd,QAAQ,CAkBV;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,OAAO,EACZ,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA8BxD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE;IAChD,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAsDpB"}
@@ -102,7 +102,8 @@ export function parseFromRef(raw) {
102
102
  if (owner === undefined || repoRaw === undefined)
103
103
  return undefined;
104
104
  const repo = repoRaw.replace(/\.git$/, "");
105
- if (!SEGMENT_PATTERN.test(owner) || !SEGMENT_PATTERN.test(repo)) {
105
+ if (SEGMENT_PATTERN.test(owner) === false ||
106
+ SEGMENT_PATTERN.test(repo) === false) {
106
107
  return undefined;
107
108
  }
108
109
  // A tree URL pins its ref in the path: owner/repo/tree/<ref>/<sub/path>.
@@ -139,12 +140,11 @@ const manifestSchema = z.object({
139
140
  .default({}),
140
141
  });
141
142
  export const MANIFEST_FILENAME = "cargo.scaffold.json";
142
- /** Read and validate `cargo.scaffold.json` at the repo root, if present. */
143
- export async function readManifest(repoDir) {
144
- const manifestPath = join(repoDir, MANIFEST_FILENAME);
145
- let raw;
143
+ // Read the manifest file's raw contents; undefined when it doesn't exist
144
+ // (ENOENT), rethrowing any other read error.
145
+ async function readManifestFile(manifestPath) {
146
146
  try {
147
- raw = await fs.readFile(manifestPath, "utf-8");
147
+ return await fs.readFile(manifestPath, "utf-8");
148
148
  }
149
149
  catch (error) {
150
150
  if (error !== null &&
@@ -156,14 +156,24 @@ export async function readManifest(repoDir) {
156
156
  const message = error instanceof Error ? error.message : String(error);
157
157
  throw new Error(`Could not read ${MANIFEST_FILENAME} in the source repo: ${message}`);
158
158
  }
159
- let json;
159
+ }
160
+ // Parse the manifest text, turning a JSON syntax error into a clear message.
161
+ function parseManifestJson(raw) {
160
162
  try {
161
- json = JSON.parse(raw);
163
+ return JSON.parse(raw);
162
164
  }
163
165
  catch (error) {
164
166
  const message = error instanceof Error ? error.message : String(error);
165
167
  throw new Error(`Invalid ${MANIFEST_FILENAME} in the source repo: ${message}`);
166
168
  }
169
+ }
170
+ /** Read and validate `cargo.scaffold.json` at the repo root, if present. */
171
+ export async function readManifest(repoDir) {
172
+ const manifestPath = join(repoDir, MANIFEST_FILENAME);
173
+ const raw = await readManifestFile(manifestPath);
174
+ if (raw === undefined)
175
+ return undefined;
176
+ const json = parseManifestJson(raw);
167
177
  const parsed = manifestSchema.safeParse(json);
168
178
  if (parsed.success === false) {
169
179
  throw new Error(`Invalid ${MANIFEST_FILENAME} in the source repo: ${z.prettifyError(parsed.error)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAmBjD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAoGzD"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAU,MAAM,WAAW,CAAC;AAmBjD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAqGzD"}
@@ -31,7 +31,8 @@ export function registerInitCommand(parent) {
31
31
  if (opts.listTemplates === true) {
32
32
  const slugs = await listTemplates(templatesRoot);
33
33
  for (const slug of slugs) {
34
- const desc = TEMPLATE_DESCRIPTIONS[slug] ?? "";
34
+ const described = TEMPLATE_DESCRIPTIONS[slug];
35
+ const desc = described === undefined ? "" : described;
35
36
  info(`${slug}${desc.length > 0 ? ` — ${desc}` : ""}`);
36
37
  }
37
38
  return;
@@ -54,7 +55,7 @@ export function registerInitCommand(parent) {
54
55
  }
55
56
  else {
56
57
  const templateDir = join(templatesRoot, opts.template);
57
- if (!existsSync(templateDir)) {
58
+ if (existsSync(templateDir) === false) {
58
59
  const slugs = await listTemplates(templatesRoot);
59
60
  failWith(`Unknown template "${opts.template}". Available: ${slugs.join(", ")}`, { code: ExitCodes.GenericError });
60
61
  }
@@ -81,15 +82,19 @@ export function registerInitCommand(parent) {
81
82
  // unrelated `templates/` dir along the way). Works both from the monorepo build
82
83
  // output and an installed `node_modules/@cargo-ai/cdk`.
83
84
  function findTemplatesRoot() {
84
- let cursor = dirname(fileURLToPath(import.meta.url));
85
- for (let i = 0; i < 8; i += 1) {
85
+ const start = dirname(fileURLToPath(import.meta.url));
86
+ for (const cursor of ancestorDirs(start, 8)) {
86
87
  const candidate = join(cursor, "templates");
87
88
  if (existsSync(join(candidate, "blank")))
88
89
  return candidate;
89
- const parent = dirname(cursor);
90
- if (parent === cursor)
91
- break;
92
- cursor = parent;
93
90
  }
94
91
  throw new Error("Could not locate the @cargo-ai/cdk templates directory. Reinstall @cargo-ai/cdk if this persists.");
95
92
  }
93
+ // The directory chain from `start` walking up to `max` levels, stopping at the
94
+ // filesystem root — so a marker file/dir can be located independent of build depth.
95
+ function ancestorDirs(start, max) {
96
+ const parent = dirname(start);
97
+ if (max <= 1 || parent === start)
98
+ return [start];
99
+ return [start, ...ancestorDirs(parent, max - 1)];
100
+ }
@@ -15,6 +15,14 @@ export declare function printJsonSchemaInput(schema: unknown): string;
15
15
  * workflow builder Refs). Used by `cargo-ai cdk types`.
16
16
  */
17
17
  export declare function printJsonSchemaType(schema: unknown): string;
18
+ /**
19
+ * Print an integration action's static output JSON Schema as a plain TS type —
20
+ * no `Ref<T> | T` widening and no `EncryptionRef`. Returns `undefined` when
21
+ * the schema is missing or too loose to be useful; the caller falls back to
22
+ * `any`, which stays usable everywhere a nested `Ref<Record<string, unknown>>`
23
+ * would not.
24
+ */
25
+ export declare function printJsonSchemaOutput(schema: unknown): string | undefined;
18
26
  /**
19
27
  * Print a tool release's `formFields` as a TS input type. Returns
20
28
  * `undefined` when the fields can't be interpreted (caller falls back to
@@ -1 +1 @@
1
- {"version":3,"file":"inputTypes.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/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"}
1
+ {"version":3,"file":"inputTypes.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/inputTypes.ts"],"names":[],"mappings":"AAqCA;;;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;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQzE;AAmUD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAU5E"}