@cargo-ai/cdk 1.0.11 → 1.0.12
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/build/src/cli/commands/deploy.d.ts.map +1 -1
- package/build/src/cli/commands/deploy.js +105 -1
- package/build/src/deploy/executors.live.d.ts.map +1 -1
- package/build/src/deploy/executors.live.js +56 -2
- package/build/src/deploy/import.d.ts +12 -0
- package/build/src/deploy/import.d.ts.map +1 -1
- package/build/src/deploy/import.js +79 -9
- package/build/src/deploy/index.d.ts +2 -0
- package/build/src/deploy/index.d.ts.map +1 -1
- package/build/src/deploy/index.js +1 -0
- package/build/src/deploy/pull/enumerate.d.ts +8 -0
- package/build/src/deploy/pull/enumerate.d.ts.map +1 -0
- package/build/src/deploy/pull/enumerate.js +258 -0
- package/build/src/deploy/pull/index.d.ts +28 -0
- package/build/src/deploy/pull/index.d.ts.map +1 -0
- package/build/src/deploy/pull/index.js +152 -0
- package/build/src/deploy/pull/ir.d.ts +45 -0
- package/build/src/deploy/pull/ir.d.ts.map +1 -0
- package/build/src/deploy/pull/ir.js +72 -0
- package/build/src/deploy/pull/mappers.d.ts +10 -0
- package/build/src/deploy/pull/mappers.d.ts.map +1 -0
- package/build/src/deploy/pull/mappers.js +689 -0
- package/build/src/deploy/pull/print.d.ts +9 -0
- package/build/src/deploy/pull/print.d.ts.map +1 -0
- package/build/src/deploy/pull/print.js +59 -0
- package/build/src/deploy/pull/resolve.d.ts +24 -0
- package/build/src/deploy/pull/resolve.d.ts.map +1 -0
- package/build/src/deploy/pull/resolve.js +113 -0
- package/build/src/deploy/pull/untar.d.ts +6 -0
- package/build/src/deploy/pull/untar.d.ts.map +1 -0
- package/build/src/deploy/pull/untar.js +84 -0
- package/build/src/deploy/readers.live.d.ts +3 -0
- package/build/src/deploy/readers.live.d.ts.map +1 -1
- package/build/src/deploy/readers.live.js +12 -6
- package/build/src/index.d.ts +3 -3
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +1 -1
- package/build/src/refs.d.ts +7 -1
- package/build/src/refs.d.ts.map +1 -1
- package/build/src/refs.js +10 -0
- package/build/src/resources/customIntegration.d.ts +3 -2
- package/build/src/resources/customIntegration.d.ts.map +1 -1
- package/build/src/resources/model.d.ts +56 -8
- package/build/src/resources/model.d.ts.map +1 -1
- package/build/src/resources/model.js +48 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -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;
|
|
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;AA+CzC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAuuBN"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { acquireLock, appendAudit, apply, compile, destroy, detectDrift, emptyState, formatPlan, importResource, liveExecutors, liveReaders, loadResources, newRunId, plan, readState, reconcileDrift, removeResources, restoreSnapshot, snapshotState, writeState, } from "../../deploy/index.js";
|
|
1
|
+
import { acquireLock, appendAudit, apply, compile, destroy, detectDrift, emptyState, formatPlan, importResource, liveExecutors, liveReaders, loadResources, newRunId, plan, pull, readState, reconcileDrift, removeResources, restoreSnapshot, SKIP_REASONS, snapshotState, SUPPORTED_KINDS, writeState, } from "../../deploy/index.js";
|
|
2
2
|
import { getConfig } from "../auth.js";
|
|
3
3
|
import { colors, confirm, ExitCodes, failWith, info, outputJson, startSpinner, success, } from "../io.js";
|
|
4
4
|
// `plan / deploy / refresh / import / rollback / destroy` — the reconcile
|
|
@@ -301,6 +301,110 @@ export function registerDeployCommands(parent, getApi) {
|
|
|
301
301
|
else
|
|
302
302
|
success(`Imported ${id} → ${uuid} (${result.kind}).`);
|
|
303
303
|
});
|
|
304
|
+
parent
|
|
305
|
+
.command("pull")
|
|
306
|
+
.description("Generate define* source from a live workspace and adopt it into " +
|
|
307
|
+
"cargo.state.json (so the next deploy is a no-op, not a duplicate-create).")
|
|
308
|
+
.option("--dir <path>", "Repo root to write into (default: cwd)")
|
|
309
|
+
.option("--types <kinds>", `Comma-separated kinds to pull (default: all supported — ${SUPPORTED_KINDS.join(", ")})`)
|
|
310
|
+
.option("--dry-run", "Print what would be generated without writing or adopting")
|
|
311
|
+
.option("--no-adopt", "Write files but skip state adoption (leaves a repo whose deploy would duplicate — advanced)")
|
|
312
|
+
.option("--force", "Steal the state lock held by another run")
|
|
313
|
+
.option("--json", "Output the result as JSON")
|
|
314
|
+
.action(async (opts) => {
|
|
315
|
+
if (opts.dir !== undefined)
|
|
316
|
+
process.chdir(opts.dir);
|
|
317
|
+
const root = ".";
|
|
318
|
+
let kinds;
|
|
319
|
+
if (opts.types !== undefined) {
|
|
320
|
+
const requested = opts.types.split(",").map((k) => k.trim());
|
|
321
|
+
const unknown = requested.filter((k) => !SUPPORTED_KINDS.includes(k));
|
|
322
|
+
if (unknown.length > 0) {
|
|
323
|
+
failWith(`Unsupported --types: ${unknown.join(", ")}. Supported: ${SUPPORTED_KINDS.join(", ")}.`, { code: ExitCodes.InvalidUsage });
|
|
324
|
+
}
|
|
325
|
+
kinds = requested;
|
|
326
|
+
}
|
|
327
|
+
const workspaceUuid = await resolveWorkspaceUuid(getApi);
|
|
328
|
+
const api = getApi();
|
|
329
|
+
const runId = newRunId();
|
|
330
|
+
if (opts.dryRun !== true) {
|
|
331
|
+
try {
|
|
332
|
+
acquireLock(root, "pull", opts.force === true);
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
failWith(message(error), { code: ExitCodes.GenericError });
|
|
336
|
+
}
|
|
337
|
+
snapshotState(root); // enable `cdk rollback`
|
|
338
|
+
}
|
|
339
|
+
let result;
|
|
340
|
+
try {
|
|
341
|
+
result = await pull(root, api, workspaceUuid, {
|
|
342
|
+
kinds,
|
|
343
|
+
dryRun: opts.dryRun === true,
|
|
344
|
+
noAdopt: opts.adopt === false,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
appendAudit(root, {
|
|
349
|
+
runId,
|
|
350
|
+
at: new Date().toISOString(),
|
|
351
|
+
command: "pull",
|
|
352
|
+
workspaceUuid,
|
|
353
|
+
ok: false,
|
|
354
|
+
error: message(error),
|
|
355
|
+
});
|
|
356
|
+
failWith(`Pull failed: ${message(error)}`, {
|
|
357
|
+
code: ExitCodes.GenericError,
|
|
358
|
+
extra: { runId },
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
appendAudit(root, {
|
|
362
|
+
runId,
|
|
363
|
+
at: new Date().toISOString(),
|
|
364
|
+
command: "pull",
|
|
365
|
+
workspaceUuid,
|
|
366
|
+
ok: true,
|
|
367
|
+
summary: {
|
|
368
|
+
files: result.files.length,
|
|
369
|
+
adopted: result.adopted,
|
|
370
|
+
counts: result.counts,
|
|
371
|
+
skipped: result.skipped,
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
if (opts.json === true) {
|
|
375
|
+
// Binary assets would JSON.stringify as one numeric key per byte —
|
|
376
|
+
// report their path + size instead of the content.
|
|
377
|
+
outputJson({
|
|
378
|
+
...result,
|
|
379
|
+
files: result.files.map((file) => "source" in file
|
|
380
|
+
? file
|
|
381
|
+
: { path: file.path, byteLength: file.bytes.byteLength }),
|
|
382
|
+
});
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const summary = Object.entries(result.counts)
|
|
386
|
+
.map(([kind, n]) => `${String(n)} ${kind}`)
|
|
387
|
+
.join(", ");
|
|
388
|
+
const skipped = Object.entries(result.skipped)
|
|
389
|
+
.map(([kind, n]) => {
|
|
390
|
+
const reason = SKIP_REASONS[kind];
|
|
391
|
+
return `${String(n)} ${kind}${reason === undefined ? "" : ` (${reason})`}`;
|
|
392
|
+
})
|
|
393
|
+
.join(", ");
|
|
394
|
+
if (skipped.length > 0) {
|
|
395
|
+
info(`Skipped: ${skipped}.`);
|
|
396
|
+
}
|
|
397
|
+
if (result.envNames.length > 0) {
|
|
398
|
+
info(`${String(result.envNames.length)} env var(s) hold masked secrets` +
|
|
399
|
+
`${opts.dryRun === true ? "" : " (see .env.example)"}: ${result.envNames.join(", ")}.`);
|
|
400
|
+
}
|
|
401
|
+
if (opts.dryRun === true) {
|
|
402
|
+
success(`Would generate ${String(result.files.length)} file(s): ${summary || "nothing"}.`);
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
success(`Generated ${String(result.files.length)} file(s) (${summary || "nothing"}); adopted ${String(result.adopted)} into state.`);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
304
408
|
parent
|
|
305
409
|
.command("rollback")
|
|
306
410
|
.description("Restore cargo.state.json from the snapshot taken before the last deploy/destroy/import.")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executors.live.d.ts","sourceRoot":"","sources":["../../../src/deploy/executors.live.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAIzC,OAAO,KAAK,EAAE,SAAS,EAAW,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"executors.live.d.ts","sourceRoot":"","sources":["../../../src/deploy/executors.live.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAIzC,OAAO,KAAK,EAAE,SAAS,EAAW,MAAM,YAAY,CAAC;AAiPrD,wBAAgB,aAAa,CAAC,GAAG,EAAE,GAAG,GAAG,SAAS,CAgsBjD"}
|
|
@@ -182,6 +182,22 @@ async function readContextFile(api, path) {
|
|
|
182
182
|
return undefined; // new file — read 404s
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
|
+
// Does every field the code declares match the live value? Keys the code omits
|
|
186
|
+
// (server-filled defaults like `columnsUsed`) are not compared, mirroring the
|
|
187
|
+
// "include iff defined" rule — so an omitted optional never forces an update.
|
|
188
|
+
function declaredMatchesLive(declared, live) {
|
|
189
|
+
if (Array.isArray(declared)) {
|
|
190
|
+
return (Array.isArray(live) &&
|
|
191
|
+
declared.length === live.length &&
|
|
192
|
+
declared.every((item, i) => declaredMatchesLive(item, live[i])));
|
|
193
|
+
}
|
|
194
|
+
if (typeof declared === "object" && declared !== null) {
|
|
195
|
+
if (typeof live !== "object" || live === null)
|
|
196
|
+
return false;
|
|
197
|
+
return Object.entries(declared).every(([key, value]) => value === undefined || declaredMatchesLive(value, live[key]));
|
|
198
|
+
}
|
|
199
|
+
return declared === live;
|
|
200
|
+
}
|
|
185
201
|
export function liveExecutors(api) {
|
|
186
202
|
// Resolve the dataset uuid auto-created alongside a connector — needed when a
|
|
187
203
|
// connector is ADOPTED (create returns it directly; list/adopt does not).
|
|
@@ -193,6 +209,31 @@ export function liveExecutors(api) {
|
|
|
193
209
|
}
|
|
194
210
|
return match.uuid;
|
|
195
211
|
}
|
|
212
|
+
// Make a model's live additional columns match the declared list: create
|
|
213
|
+
// missing, update changed, remove undeclared. Only runs when the spec declares
|
|
214
|
+
// `additionalColumns` — an omitted field leaves live columns untouched.
|
|
215
|
+
// `liveColumns` skips the model fetch when the caller already knows them
|
|
216
|
+
// (a just-created model has none).
|
|
217
|
+
async function reconcileAdditionalColumns(modelUuid, declared, liveColumns) {
|
|
218
|
+
const live = liveColumns !== undefined
|
|
219
|
+
? liveColumns
|
|
220
|
+
: (await api.storage.model.get(modelUuid)).model.additionalColumns;
|
|
221
|
+
const liveBySlug = new Map(live.map((column) => [column.slug, column]));
|
|
222
|
+
for (const column of declared) {
|
|
223
|
+
const live = liveBySlug.get(column.slug);
|
|
224
|
+
if (live === undefined) {
|
|
225
|
+
await api.storage.column.create({ modelUuid, column });
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
liveBySlug.delete(column.slug);
|
|
229
|
+
if (!declaredMatchesLive(column, live)) {
|
|
230
|
+
await api.storage.column.update({ modelUuid, column });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
for (const slug of liveBySlug.keys()) {
|
|
234
|
+
await api.storage.column.remove({ modelUuid, columnSlug: slug });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
196
237
|
return {
|
|
197
238
|
async connector(spec, prior) {
|
|
198
239
|
const slug = str(spec["slug"]);
|
|
@@ -270,7 +311,13 @@ export function liveExecutors(api) {
|
|
|
270
311
|
// `undefined` when the spec omits it, so the source's default (integration
|
|
271
312
|
// mapping for connector models) is preserved.
|
|
272
313
|
const unification = spec["unification"];
|
|
314
|
+
// Columns are reconciled BEFORE the unification update on every path, so a
|
|
315
|
+
// unification can reference a just-declared additional column.
|
|
316
|
+
const additionalColumns = spec["additionalColumns"];
|
|
273
317
|
if (prior !== undefined) {
|
|
318
|
+
if (additionalColumns !== undefined) {
|
|
319
|
+
await reconcileAdditionalColumns(prior.uuid, additionalColumns);
|
|
320
|
+
}
|
|
274
321
|
// No extractorSlug — a model's extractor is immutable post-create
|
|
275
322
|
// (it's not part of UpdateModelPayload).
|
|
276
323
|
await api.storage.model.update({
|
|
@@ -294,8 +341,12 @@ export function liveExecutors(api) {
|
|
|
294
341
|
if (found === undefined) {
|
|
295
342
|
throw new Error(`model "${slug}" reported to exist but was not found`);
|
|
296
343
|
}
|
|
297
|
-
// Adopted an existing model — apply the declared
|
|
298
|
-
// skips it), then release on destroy rather than
|
|
344
|
+
// Adopted an existing model — reconcile columns and apply the declared
|
|
345
|
+
// unification (create skips it), then release on destroy rather than
|
|
346
|
+
// delete.
|
|
347
|
+
if (additionalColumns !== undefined) {
|
|
348
|
+
await reconcileAdditionalColumns(found.uuid, additionalColumns);
|
|
349
|
+
}
|
|
299
350
|
if (unification !== undefined) {
|
|
300
351
|
await api.storage.model.update({ uuid: found.uuid, unification });
|
|
301
352
|
}
|
|
@@ -311,6 +362,9 @@ export function liveExecutors(api) {
|
|
|
311
362
|
schedule,
|
|
312
363
|
folderUuid: optStr(spec["folderUuid"]),
|
|
313
364
|
});
|
|
365
|
+
if (additionalColumns !== undefined) {
|
|
366
|
+
await reconcileAdditionalColumns(created.model.uuid, additionalColumns, []);
|
|
367
|
+
}
|
|
314
368
|
// CreateModelPayload has no unification field, so a declared unification
|
|
315
369
|
// is applied with a follow-up update once the model exists.
|
|
316
370
|
if (unification !== undefined) {
|
|
@@ -10,4 +10,16 @@ export type ImportResult = {
|
|
|
10
10
|
* the live resource is reachable, then writes/overwrites its state entry.
|
|
11
11
|
*/
|
|
12
12
|
export declare function importResource(root: string, api: Api, workspaceUuid: string, id: string, uuid: string, nodes?: readonly ResourceNode[]): Promise<ImportResult>;
|
|
13
|
+
export type AdoptTarget = {
|
|
14
|
+
id: string;
|
|
15
|
+
uuid: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Batch import for `cdk pull` adoption: the same per-resource contract as
|
|
19
|
+
* importResource, but the graph is compiled once, the workspace listings
|
|
20
|
+
* importOutputs consults are fetched at most once, resources are processed
|
|
21
|
+
* concurrently, and the state file is written once at the end — so adoption is
|
|
22
|
+
* atomic (a mid-batch failure commits nothing) instead of N read/fsync cycles.
|
|
23
|
+
*/
|
|
24
|
+
export declare function adoptResources(root: string, api: Api, workspaceUuid: string, targets: readonly AdoptTarget[], nodes: readonly ResourceNode[]): Promise<number>;
|
|
13
25
|
//# sourceMappingURL=import.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/deploy/import.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM7D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../src/deploy/import.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM7D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC,CAAC;AAmFF;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,MAAM,EACrB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EAGZ,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,GAC9B,OAAO,CAAC,YAAY,CAAC,CAuBvB;AAsCD,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAiBvD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,GAAG,EACR,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,KAAK,EAAE,SAAS,YAAY,EAAE,GAC7B,OAAO,CAAC,MAAM,CAAC,CAyBjB"}
|
|
@@ -10,26 +10,53 @@ import { compile } from "./compile.js";
|
|
|
10
10
|
import { loadResources } from "./load.js";
|
|
11
11
|
import { liveReaders } from "./readers.live.js";
|
|
12
12
|
import { emptyState, readState, writeState } from "./state.js";
|
|
13
|
+
function workspaceListings(api) {
|
|
14
|
+
const cache = {};
|
|
15
|
+
const lazy = (key, fetch) => {
|
|
16
|
+
return () => {
|
|
17
|
+
const hit = cache[key];
|
|
18
|
+
if (hit !== undefined)
|
|
19
|
+
return hit;
|
|
20
|
+
const miss = fetch();
|
|
21
|
+
cache[key] = miss;
|
|
22
|
+
return miss;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
datasets: lazy("datasets", async () => {
|
|
27
|
+
const { datasets } = await api.storage.dataset.all();
|
|
28
|
+
return datasets;
|
|
29
|
+
}),
|
|
30
|
+
plays: lazy("plays", async () => {
|
|
31
|
+
const { plays } = await api.orchestration.play.list();
|
|
32
|
+
return plays;
|
|
33
|
+
}),
|
|
34
|
+
tools: lazy("tools", async () => {
|
|
35
|
+
const { tools } = await api.orchestration.tool.all();
|
|
36
|
+
return tools;
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
13
40
|
// Reconstruct the outputs an apply would have produced for this kind, so tokens
|
|
14
41
|
// its dependents reference (connector.datasetUuid, tool/play.workflowUuid,
|
|
15
42
|
// worker/app.url) still resolve.
|
|
16
|
-
async function importOutputs(api, kind, uuid) {
|
|
43
|
+
async function importOutputs(api, kind, uuid, listings) {
|
|
17
44
|
const outputs = { uuid };
|
|
18
45
|
if (kind === "connector") {
|
|
19
|
-
const
|
|
46
|
+
const datasets = await listings.datasets();
|
|
20
47
|
const match = datasets.find((d) => d["kind"] === "connector" && d["connectorUuid"] === uuid);
|
|
21
48
|
if (match !== undefined)
|
|
22
49
|
outputs["datasetUuid"] = match["uuid"];
|
|
23
50
|
}
|
|
24
51
|
else if (kind === "play") {
|
|
25
|
-
const
|
|
52
|
+
const plays = await listings.plays();
|
|
26
53
|
const play = plays.find((p) => p["uuid"] === uuid);
|
|
27
54
|
const wf = play === undefined ? undefined : play["workflowUuid"];
|
|
28
55
|
if (typeof wf === "string")
|
|
29
56
|
outputs["workflowUuid"] = wf;
|
|
30
57
|
}
|
|
31
58
|
else if (kind === "tool") {
|
|
32
|
-
const
|
|
59
|
+
const tools = await listings.tools();
|
|
33
60
|
const tool = tools.find((t) => t["uuid"] === uuid);
|
|
34
61
|
const wf = tool === undefined ? undefined : tool["workflowUuid"];
|
|
35
62
|
if (typeof wf === "string")
|
|
@@ -64,11 +91,20 @@ nodes) {
|
|
|
64
91
|
throw new Error(`no resource "${id}" found in code — import targets a code resource id like "agent:sdr".`);
|
|
65
92
|
}
|
|
66
93
|
const kind = entry.kind;
|
|
67
|
-
const
|
|
94
|
+
const stateEntry = await buildStateEntry(api, kind, uuid, entry.hash, workspaceListings(api));
|
|
95
|
+
const state = readValidatedState(root, workspaceUuid);
|
|
96
|
+
state.resources[id] = stateEntry;
|
|
97
|
+
writeState(root, state);
|
|
98
|
+
return { kind, outputs: stateEntry.outputs };
|
|
99
|
+
}
|
|
100
|
+
// Outputs + adopted marker + live existence check + drift baseline — the
|
|
101
|
+
// per-resource half of an import, shared by importResource and adoptResources.
|
|
102
|
+
async function buildStateEntry(api, kind, uuid, hash, listings) {
|
|
103
|
+
const outputs = await importOutputs(api, kind, uuid, listings);
|
|
68
104
|
// Imported resources are treated as adopted: a later `destroy` releases them
|
|
69
105
|
// (drops from state) rather than deleting infra the CDK didn't create.
|
|
70
106
|
outputs["adopted"] = "true";
|
|
71
|
-
const stateEntry = { hash
|
|
107
|
+
const stateEntry = { hash, uuid, outputs };
|
|
72
108
|
// Confirm it's actually there (and capture a drift baseline).
|
|
73
109
|
const live = await liveReaders(api)[kind](stateEntry);
|
|
74
110
|
if (live.exists === false) {
|
|
@@ -76,12 +112,46 @@ nodes) {
|
|
|
76
112
|
}
|
|
77
113
|
if (live.fingerprint !== undefined)
|
|
78
114
|
stateEntry.live = live.fingerprint;
|
|
115
|
+
return stateEntry;
|
|
116
|
+
}
|
|
117
|
+
function readValidatedState(root, workspaceUuid) {
|
|
79
118
|
const prior = readState(root);
|
|
80
|
-
const state = prior !== undefined ? prior : emptyState(workspaceUuid);
|
|
81
119
|
if (prior !== undefined && prior.workspaceUuid !== workspaceUuid) {
|
|
82
120
|
throw new Error(`cargo.state.json belongs to workspace ${prior.workspaceUuid}, not the selected ${workspaceUuid}.`);
|
|
83
121
|
}
|
|
84
|
-
|
|
122
|
+
return prior !== undefined ? prior : emptyState(workspaceUuid);
|
|
123
|
+
}
|
|
124
|
+
// Concurrency-capped map — adoption fans out 1-3 API calls per resource, so a
|
|
125
|
+
// full-workspace pull stays polite to the backend.
|
|
126
|
+
async function inChunks(items, size, fn) {
|
|
127
|
+
const out = [];
|
|
128
|
+
for (let index = 0; index < items.length; index += size) {
|
|
129
|
+
const chunk = items.slice(index, index + size);
|
|
130
|
+
out.push(...(await Promise.all(chunk.map(fn))));
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Batch import for `cdk pull` adoption: the same per-resource contract as
|
|
136
|
+
* importResource, but the graph is compiled once, the workspace listings
|
|
137
|
+
* importOutputs consults are fetched at most once, resources are processed
|
|
138
|
+
* concurrently, and the state file is written once at the end — so adoption is
|
|
139
|
+
* atomic (a mid-batch failure commits nothing) instead of N read/fsync cycles.
|
|
140
|
+
*/
|
|
141
|
+
export async function adoptResources(root, api, workspaceUuid, targets, nodes) {
|
|
142
|
+
const plan = new Map(compile({ nodes }).plan.map((entry) => [entry.id, entry]));
|
|
143
|
+
const listings = workspaceListings(api);
|
|
144
|
+
const entries = await inChunks(targets, 8, async ({ id, uuid }) => {
|
|
145
|
+
const entry = plan.get(id);
|
|
146
|
+
if (entry === undefined) {
|
|
147
|
+
throw new Error(`no resource "${id}" found in the generated code.`);
|
|
148
|
+
}
|
|
149
|
+
const stateEntry = await buildStateEntry(api, entry.kind, uuid, entry.hash, listings);
|
|
150
|
+
return [id, stateEntry];
|
|
151
|
+
});
|
|
152
|
+
const state = readValidatedState(root, workspaceUuid);
|
|
153
|
+
for (const [id, stateEntry] of entries)
|
|
154
|
+
state.resources[id] = stateEntry;
|
|
85
155
|
writeState(root, state);
|
|
86
|
-
return
|
|
156
|
+
return entries.length;
|
|
87
157
|
}
|
|
@@ -15,6 +15,8 @@ export { loadResources } from "./load.js";
|
|
|
15
15
|
export type { Lock } from "./lock.js";
|
|
16
16
|
export { acquireLock } from "./lock.js";
|
|
17
17
|
export { formatPlan } from "./plan.js";
|
|
18
|
+
export type { PullOptions, PullResult } from "./pull/index.js";
|
|
19
|
+
export { pull, SKIP_REASONS, SUPPORTED_KINDS } from "./pull/index.js";
|
|
18
20
|
export { liveReaders } from "./readers.live.js";
|
|
19
21
|
export type { DriftEntry, DriftStatus, LiveRead, LiveReader, LiveReaders, } from "./refresh.js";
|
|
20
22
|
export { detectDrift, fingerprint, reconcileDrift } from "./refresh.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/deploy/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAIvE,YAAY,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACT,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,KAAK,EACL,UAAU,EACV,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EACL,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAG/D;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,MAAM,CAC1B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/deploy/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAIvE,YAAY,EACV,aAAa,EACb,WAAW,EACX,SAAS,EACT,OAAO,GACR,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EACV,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,KAAK,EACL,UAAU,EACV,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EACL,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAG/D;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,MAAM,CAC1B,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,SAAS,GACnB,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
|
|
@@ -13,6 +13,7 @@ export { importResource } from "./import.js";
|
|
|
13
13
|
export { loadResources } from "./load.js";
|
|
14
14
|
export { acquireLock } from "./lock.js";
|
|
15
15
|
export { formatPlan } from "./plan.js";
|
|
16
|
+
export { pull, SKIP_REASONS, SUPPORTED_KINDS } from "./pull/index.js";
|
|
16
17
|
export { liveReaders } from "./readers.live.js";
|
|
17
18
|
export { detectDrift, fingerprint, reconcileDrift } from "./refresh.js";
|
|
18
19
|
export { emptyState, readState, restoreSnapshot, snapshotState, writeState, } from "./state.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Api } from "@cargo-ai/api";
|
|
2
|
+
import type { ResourceKind } from "../../core.js";
|
|
3
|
+
export type EnumeratedRow = {
|
|
4
|
+
readonly kind: ResourceKind;
|
|
5
|
+
readonly row: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
export declare function enumerateWorkspace(api: Api, kinds: readonly ResourceKind[]): Promise<EnumeratedRow[]>;
|
|
8
|
+
//# sourceMappingURL=enumerate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enumerate.d.ts","sourceRoot":"","sources":["../../../../src/deploy/pull/enumerate.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAKlD,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAI5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC,CAAC;AAqCF,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,SAAS,YAAY,EAAE,GAC7B,OAAO,CAAC,aAAa,EAAE,CAAC,CAkQ1B"}
|