antpath 0.6.2 → 0.8.0
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/dist/_shared/blueprint.d.ts +66 -7
- package/dist/_shared/blueprint.js +53 -8
- package/dist/_shared/operations.d.ts +52 -0
- package/dist/_shared/operations.js +83 -0
- package/dist/_shared/proxy-protocol.d.ts +10 -2
- package/dist/_shared/proxy-protocol.js +3 -2
- package/dist/_shared/runtime-types.d.ts +19 -0
- package/dist/_shared/submission.d.ts +21 -0
- package/dist/_shared/submission.js +102 -4
- package/dist/blueprint.d.ts +15 -6
- package/dist/blueprint.js.map +1 -1
- package/dist/bundle.d.ts +16 -1
- package/dist/bundle.js +32 -0
- package/dist/bundle.js.map +1 -1
- package/dist/cli.mjs +169 -38
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +119 -24
- package/dist/client.js +198 -52
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +203 -31
- package/dist/skill.js +277 -30
- package/dist/skill.js.map +1 -1
- package/docs/credentials.md +34 -0
- package/docs/events.md +7 -0
- package/docs/mcp.md +28 -0
- package/docs/outputs.md +92 -12
- package/docs/quickstart.md +37 -0
- package/docs/skills.md +49 -0
- package/package.json +1 -1
package/dist/blueprint.d.ts
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
import type { JsonValue, PlatformCleanupPolicy,
|
|
1
|
+
import type { JsonValue, PlatformCleanupPolicy, PlatformTemplateEnvironment } from "./_shared/index.js";
|
|
2
2
|
import type { McpServer } from "./mcp-server.js";
|
|
3
|
+
import type { ProxyEndpoint } from "./proxy-endpoint.js";
|
|
3
4
|
import type { Skill } from "./skill.js";
|
|
4
5
|
/**
|
|
5
6
|
* SDK-side blueprint. Mirrors the shared `Blueprint` shape but uses the
|
|
6
|
-
* SDK's `Skill` and `
|
|
7
|
-
* `skills: [rules]
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* SDK's `Skill`, `McpServer`, and `ProxyEndpoint` classes so call sites
|
|
8
|
+
* can write `skills: [rules]`, `mcpServers: [gh]`, and
|
|
9
|
+
* `proxyEndpoints: [stripe]` instead of repeating the underlying wire
|
|
10
|
+
* types. The `submitRun` method normalises these into the wire
|
|
11
|
+
* submission + secrets bag before sending.
|
|
10
12
|
*
|
|
11
13
|
* `Blueprint` is intentionally `Omit<SubmitRunOptions, "secrets" |
|
|
12
14
|
* "idempotencyKey" | "signal">` so it can be embedded as a reusable,
|
|
13
15
|
* credential-free fragment via `defineRun`.
|
|
16
|
+
*
|
|
17
|
+
* Note: Blueprints can legally contain unstaged transient Skills built
|
|
18
|
+
* via `Skill.fromFiles` / `Skill.fromPath`. The transient bytes ride
|
|
19
|
+
* via multipart at `submitRun` time and never persist anywhere —
|
|
20
|
+
* exactly the right shape for a per-run, throwaway skill. Passing a
|
|
21
|
+
* Blueprint through `JSON.stringify`, however, will fail (unstaged
|
|
22
|
+
* Skills are not JSON-serialisable; see `Skill.toJSON`).
|
|
14
23
|
*/
|
|
15
24
|
export interface Blueprint {
|
|
16
25
|
readonly model: string;
|
|
@@ -20,7 +29,7 @@ export interface Blueprint {
|
|
|
20
29
|
readonly mcpServers?: readonly McpServer[];
|
|
21
30
|
readonly environment?: PlatformTemplateEnvironment;
|
|
22
31
|
readonly cleanup?: PlatformCleanupPolicy;
|
|
23
|
-
readonly proxyEndpoints?: readonly
|
|
32
|
+
readonly proxyEndpoints?: readonly ProxyEndpoint[];
|
|
24
33
|
readonly metadata?: Record<string, JsonValue>;
|
|
25
34
|
}
|
|
26
35
|
/**
|
package/dist/blueprint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blueprint.js","sourceRoot":"","sources":["../src/blueprint.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"blueprint.js","sourceRoot":"","sources":["../src/blueprint.ts"],"names":[],"mappings":"AAwCA;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAU,QAAwC;IACzE,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CAAC,MAAe,EAAa,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1D,CAAC"}
|
package/dist/bundle.d.ts
CHANGED
|
@@ -6,7 +6,13 @@
|
|
|
6
6
|
* (`validateSkillBundleEntry`: no `..`, no absolute paths, no Windows
|
|
7
7
|
* backslashes, depth/length limits). The BFF re-canonicalises and
|
|
8
8
|
* recomputes the canonical hash on receipt — SDK-side hashing is NOT
|
|
9
|
-
* part of any contract, so we don't expose one.
|
|
9
|
+
* part of any contract, so we don't expose one for workspace uploads.
|
|
10
|
+
*
|
|
11
|
+
* For transient (per-run) skills the SDK does compute an advisory
|
|
12
|
+
* `sha256` of the canonicalised zip via `hashSkillBundle()` — it travels
|
|
13
|
+
* in the `TransientSkillRef.contentHash` field, is used for retry
|
|
14
|
+
* de-dup and janitor reconciliation, and is recomputed server-side
|
|
15
|
+
* (mismatch → submission rejected).
|
|
10
16
|
*/
|
|
11
17
|
export interface BundledSkill {
|
|
12
18
|
readonly zip: Uint8Array;
|
|
@@ -16,3 +22,12 @@ export interface BundledSkill {
|
|
|
16
22
|
/** Inline files map: path -> contents (UTF-8 string or raw bytes). */
|
|
17
23
|
export type SkillFiles = Readonly<Record<string, string | Uint8Array>>;
|
|
18
24
|
export declare function bundleSkillFiles(files: SkillFiles): BundledSkill;
|
|
25
|
+
/**
|
|
26
|
+
* Compute `sha256:<hex>` of the given canonicalised zip bytes. Used by
|
|
27
|
+
* `Skill.fromFiles` / `Skill.fromPath` to populate the
|
|
28
|
+
* `TransientSkillRef.contentHash` field. The hash is advisory — the BFF
|
|
29
|
+
* recomputes server-side after re-canonicalising the zip; a mismatch is
|
|
30
|
+
* rejected. Web-Crypto-only so the SDK works in Node, edge runtimes,
|
|
31
|
+
* and browsers without polyfills.
|
|
32
|
+
*/
|
|
33
|
+
export declare function hashSkillBundle(zipBytes: Uint8Array): Promise<string>;
|
package/dist/bundle.js
CHANGED
|
@@ -52,4 +52,36 @@ export function bundleSkillFiles(files) {
|
|
|
52
52
|
return { zip, fileCount: entries.length, compressedSize: zip.byteLength };
|
|
53
53
|
}
|
|
54
54
|
const ZIP_EPOCH = new Date(Date.UTC(1980, 0, 1));
|
|
55
|
+
/**
|
|
56
|
+
* Compute `sha256:<hex>` of the given canonicalised zip bytes. Used by
|
|
57
|
+
* `Skill.fromFiles` / `Skill.fromPath` to populate the
|
|
58
|
+
* `TransientSkillRef.contentHash` field. The hash is advisory — the BFF
|
|
59
|
+
* recomputes server-side after re-canonicalising the zip; a mismatch is
|
|
60
|
+
* rejected. Web-Crypto-only so the SDK works in Node, edge runtimes,
|
|
61
|
+
* and browsers without polyfills.
|
|
62
|
+
*/
|
|
63
|
+
export async function hashSkillBundle(zipBytes) {
|
|
64
|
+
const subtle = globalThis.crypto?.subtle;
|
|
65
|
+
if (!subtle) {
|
|
66
|
+
throw new Error("hashSkillBundle: globalThis.crypto.subtle is not available; Node 18+ or a Web-Crypto-capable runtime is required");
|
|
67
|
+
}
|
|
68
|
+
// crypto.subtle.digest expects a BufferSource. Pass a freshly-sliced
|
|
69
|
+
// copy to detach from any external Uint8Array view (Web Crypto rejects
|
|
70
|
+
// non-zero byteOffset SharedArrayBuffer views, and view detach also
|
|
71
|
+
// protects against the caller mutating the input after the digest is
|
|
72
|
+
// computed).
|
|
73
|
+
const view = new Uint8Array(zipBytes.byteLength);
|
|
74
|
+
view.set(zipBytes);
|
|
75
|
+
const digest = await subtle.digest("SHA-256", view.buffer);
|
|
76
|
+
return "sha256:" + bufferToHex(digest);
|
|
77
|
+
}
|
|
78
|
+
function bufferToHex(buffer) {
|
|
79
|
+
const view = new Uint8Array(buffer);
|
|
80
|
+
let out = "";
|
|
81
|
+
for (let i = 0; i < view.length; i++) {
|
|
82
|
+
const byte = view[i];
|
|
83
|
+
out += byte.toString(16).padStart(2, "0");
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
55
87
|
//# sourceMappingURL=bundle.js.map
|
package/dist/bundle.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAiB,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.mjs
CHANGED
|
@@ -6,7 +6,12 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// dist/cli.js
|
|
9
|
-
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
9
|
+
import { readFile as readFile2, writeFile, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
10
|
+
import { resolve as resolvePath4 } from "node:path";
|
|
11
|
+
|
|
12
|
+
// dist/internal.js
|
|
13
|
+
var ANTPATH_INDEX_PATH = "/antpath/index.json";
|
|
14
|
+
var ANTPATH_RUN_TOKEN_PATH = "/antpath/run-token";
|
|
10
15
|
|
|
11
16
|
// ../shared/dist/config.js
|
|
12
17
|
var DEFAULT_CAPS = {
|
|
@@ -54,6 +59,7 @@ var terminalRunStatuses = new Set(TERMINAL_RUN_STATUSES);
|
|
|
54
59
|
|
|
55
60
|
// ../shared/dist/blueprint.js
|
|
56
61
|
var SKILL_ID_PATTERN = /^skl_[A-Za-z0-9_-]{8,128}$/;
|
|
62
|
+
var SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,127}$/;
|
|
57
63
|
var SKILL_BUNDLE_LIMITS = {
|
|
58
64
|
/** Compressed (.zip) ceiling. */
|
|
59
65
|
maxCompressedBytes: 10 * 1024 * 1024,
|
|
@@ -70,7 +76,9 @@ var SKILL_BUNDLE_LIMITS = {
|
|
|
70
76
|
/** Stored directory mode. */
|
|
71
77
|
defaultDirMode: 493
|
|
72
78
|
};
|
|
73
|
-
|
|
79
|
+
var TRANSIENT_SLOT_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
80
|
+
var TRANSIENT_CONTENT_HASH_PATTERN = /^sha256:[0-9a-f]{64}$/;
|
|
81
|
+
function parseSkillRef(input, path, options = {}) {
|
|
74
82
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
75
83
|
throw new Error(`${path} must be a SkillRef object`);
|
|
76
84
|
}
|
|
@@ -113,7 +121,30 @@ function parseSkillRef(input, path) {
|
|
|
113
121
|
...version !== void 0 ? { version } : {}
|
|
114
122
|
};
|
|
115
123
|
}
|
|
116
|
-
|
|
124
|
+
if (kind === "transient") {
|
|
125
|
+
if (options.allowTransient === false) {
|
|
126
|
+
throw new Error(`${path} carries a transient SkillRef, which cannot round-trip through JSON \u2014 transient skills must be supplied at submitRun time with their bytes attached`);
|
|
127
|
+
}
|
|
128
|
+
for (const key of Object.keys(record)) {
|
|
129
|
+
if (key !== "kind" && key !== "slot" && key !== "name" && key !== "contentHash") {
|
|
130
|
+
throw new Error(`${path} contains unexpected field for transient SkillRef: ${key}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const slot = record.slot;
|
|
134
|
+
if (typeof slot !== "string" || !TRANSIENT_SLOT_PATTERN.test(slot)) {
|
|
135
|
+
throw new Error(`${path}.slot must match ${TRANSIENT_SLOT_PATTERN.source}`);
|
|
136
|
+
}
|
|
137
|
+
const name = record.name;
|
|
138
|
+
if (typeof name !== "string" || !SKILL_NAME_PATTERN.test(name)) {
|
|
139
|
+
throw new Error(`${path}.name must match ${SKILL_NAME_PATTERN.source}`);
|
|
140
|
+
}
|
|
141
|
+
const contentHash = record.contentHash;
|
|
142
|
+
if (typeof contentHash !== "string" || !TRANSIENT_CONTENT_HASH_PATTERN.test(contentHash)) {
|
|
143
|
+
throw new Error(`${path}.contentHash must match ${TRANSIENT_CONTENT_HASH_PATTERN.source}`);
|
|
144
|
+
}
|
|
145
|
+
return { kind: "transient", slot, name, contentHash };
|
|
146
|
+
}
|
|
147
|
+
throw new Error(`${path}.kind must be 'workspace', 'provider', or 'transient'`);
|
|
117
148
|
}
|
|
118
149
|
var SkillBundleValidationError = class extends Error {
|
|
119
150
|
constructor(message) {
|
|
@@ -315,7 +346,7 @@ function parseBlueprintSkills(value) {
|
|
|
315
346
|
if (!Array.isArray(value)) {
|
|
316
347
|
throw new Error("Blueprint.skills must be an array");
|
|
317
348
|
}
|
|
318
|
-
return value.map((item, index) => parseSkillRef(item, `Blueprint.skills[${index}]
|
|
349
|
+
return value.map((item, index) => parseSkillRef(item, `Blueprint.skills[${index}]`, { allowTransient: false }));
|
|
319
350
|
}
|
|
320
351
|
function parseBlueprintMcpServers(value) {
|
|
321
352
|
if (value === void 0) {
|
|
@@ -501,6 +532,9 @@ __export(operations_exports, {
|
|
|
501
532
|
createSkillBundle: () => createSkillBundle,
|
|
502
533
|
deleteRun: () => deleteRun,
|
|
503
534
|
deleteSkill: () => deleteSkill,
|
|
535
|
+
downloadRunArchive: () => downloadRunArchive,
|
|
536
|
+
findSkillByHash: () => findSkillByHash,
|
|
537
|
+
findSkillByName: () => findSkillByName,
|
|
504
538
|
getRun: () => getRun,
|
|
505
539
|
getSkill: () => getSkill,
|
|
506
540
|
listOutputs: () => listOutputs,
|
|
@@ -508,6 +542,7 @@ __export(operations_exports, {
|
|
|
508
542
|
listSkills: () => listSkills,
|
|
509
543
|
submitRun: () => submitRun,
|
|
510
544
|
submitRunFlat: () => submitRunFlat,
|
|
545
|
+
submitRunFlatMultipart: () => submitRunFlatMultipart,
|
|
511
546
|
whoami: () => whoami
|
|
512
547
|
});
|
|
513
548
|
async function submitRun(http, request) {
|
|
@@ -540,12 +575,39 @@ async function deleteRun(http, runId) {
|
|
|
540
575
|
async function whoami(http) {
|
|
541
576
|
return http.request("/api/whoami");
|
|
542
577
|
}
|
|
578
|
+
async function downloadRunArchive(http, runId) {
|
|
579
|
+
const { response } = await http.download(`/api/runs/${encodeURIComponent(runId)}/download`);
|
|
580
|
+
return response;
|
|
581
|
+
}
|
|
543
582
|
async function submitRunFlat(http, request) {
|
|
544
583
|
return http.request("/api/runs", {
|
|
545
584
|
method: "POST",
|
|
546
585
|
body: JSON.stringify(request)
|
|
547
586
|
});
|
|
548
587
|
}
|
|
588
|
+
async function submitRunFlatMultipart(http, request, bundles) {
|
|
589
|
+
if (!Array.isArray(bundles) || bundles.length === 0) {
|
|
590
|
+
throw new Error("submitRunFlatMultipart: bundles must be a non-empty array");
|
|
591
|
+
}
|
|
592
|
+
const form = new FormData();
|
|
593
|
+
form.append("submission", new Blob([JSON.stringify(request)], { type: "application/json" }), "submission.json");
|
|
594
|
+
const seen = /* @__PURE__ */ new Set();
|
|
595
|
+
for (const bundle of bundles) {
|
|
596
|
+
if (typeof bundle.slot !== "string" || !bundle.slot) {
|
|
597
|
+
throw new Error("submitRunFlatMultipart: each bundle must have a non-empty slot id");
|
|
598
|
+
}
|
|
599
|
+
if (seen.has(bundle.slot)) {
|
|
600
|
+
throw new Error(`submitRunFlatMultipart: duplicate transient skill slot "${bundle.slot}"`);
|
|
601
|
+
}
|
|
602
|
+
seen.add(bundle.slot);
|
|
603
|
+
const blob = toBlob(bundle.bytes, "application/zip");
|
|
604
|
+
form.append(`skill:${bundle.slot}`, blob, bundle.filename);
|
|
605
|
+
}
|
|
606
|
+
return http.request("/api/runs", {
|
|
607
|
+
method: "POST",
|
|
608
|
+
body: form
|
|
609
|
+
});
|
|
610
|
+
}
|
|
549
611
|
async function createSkillBundle(http, args) {
|
|
550
612
|
const form = new FormData();
|
|
551
613
|
form.append("name", args.name);
|
|
@@ -573,6 +635,18 @@ async function deleteSkill(http, skillId) {
|
|
|
573
635
|
method: "DELETE"
|
|
574
636
|
});
|
|
575
637
|
}
|
|
638
|
+
async function findSkillByHash(http, args) {
|
|
639
|
+
const params = new URLSearchParams({
|
|
640
|
+
name: args.name,
|
|
641
|
+
content_hash: args.contentHash
|
|
642
|
+
});
|
|
643
|
+
const result = await http.request(`/api/skills/by-hash?${params.toString()}`);
|
|
644
|
+
return result.skill ?? null;
|
|
645
|
+
}
|
|
646
|
+
async function findSkillByName(http, name) {
|
|
647
|
+
const skills = await listSkills(http);
|
|
648
|
+
return skills.find((skill) => skill.name === name) ?? null;
|
|
649
|
+
}
|
|
576
650
|
function unwrapSkill(result) {
|
|
577
651
|
if (result && typeof result === "object" && "skill" in result) {
|
|
578
652
|
return result.skill;
|
|
@@ -619,10 +693,6 @@ function validateProxyAuth(endpoints, auth) {
|
|
|
619
693
|
}
|
|
620
694
|
}
|
|
621
695
|
|
|
622
|
-
// dist/internal.js
|
|
623
|
-
var ANTPATH_INDEX_PATH = "/antpath/index.json";
|
|
624
|
-
var ANTPATH_RUN_TOKEN_PATH = "/antpath/run-token";
|
|
625
|
-
|
|
626
696
|
// dist/host/common.js
|
|
627
697
|
var SUCCESS = { code: 0 };
|
|
628
698
|
var USAGE_ERR = { code: 2 };
|
|
@@ -780,6 +850,52 @@ function takeBooleanFlag(rest, flag) {
|
|
|
780
850
|
return { present, remaining };
|
|
781
851
|
}
|
|
782
852
|
|
|
853
|
+
// dist/outputs-sync.js
|
|
854
|
+
async function runOutputsSyncCmd(io2, dirs) {
|
|
855
|
+
if (dirs.length === 0) {
|
|
856
|
+
io2.stderr("usage: antpath outputs sync <dir> [<dir> ...]\n");
|
|
857
|
+
return USAGE_ERR;
|
|
858
|
+
}
|
|
859
|
+
try {
|
|
860
|
+
await io2.readFile(ANTPATH_INDEX_PATH);
|
|
861
|
+
} catch {
|
|
862
|
+
io2.stderr("`antpath outputs sync` is an in-container internal command and cannot run on the host.\n");
|
|
863
|
+
return USAGE_ERR;
|
|
864
|
+
}
|
|
865
|
+
if (!io2.walkDirectory) {
|
|
866
|
+
io2.stderr("antpath outputs sync: walkDirectory IO is not available\n");
|
|
867
|
+
return RUNTIME_ERR;
|
|
868
|
+
}
|
|
869
|
+
let scanned = 0;
|
|
870
|
+
let missing = 0;
|
|
871
|
+
for (const dir of dirs) {
|
|
872
|
+
if (!dir.startsWith("/")) {
|
|
873
|
+
io2.stderr(JSON.stringify({ dir, error: "non_absolute_path", message: "skipping non-absolute output dir" }) + "\n");
|
|
874
|
+
missing++;
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
let entries;
|
|
878
|
+
try {
|
|
879
|
+
entries = await io2.walkDirectory(dir);
|
|
880
|
+
} catch (err2) {
|
|
881
|
+
io2.stderr(JSON.stringify({ dir, error: "walk_failed", message: err2.message ?? "walk failed" }) + "\n");
|
|
882
|
+
missing++;
|
|
883
|
+
continue;
|
|
884
|
+
}
|
|
885
|
+
if (entries === null) {
|
|
886
|
+
io2.stderr(JSON.stringify({ dir, error: "missing_or_unreadable" }) + "\n");
|
|
887
|
+
missing++;
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
890
|
+
for (const entry of entries) {
|
|
891
|
+
io2.stdout(JSON.stringify({ dir, path: entry.path, sizeBytes: entry.sizeBytes }) + "\n");
|
|
892
|
+
scanned++;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
io2.stdout(JSON.stringify({ summary: { dirs: dirs.length, files: scanned, missing } }) + "\n");
|
|
896
|
+
return SUCCESS;
|
|
897
|
+
}
|
|
898
|
+
|
|
783
899
|
// dist/proxy.js
|
|
784
900
|
function parseProxyFlags(rest) {
|
|
785
901
|
let endpointName = null;
|
|
@@ -2594,7 +2710,7 @@ async function runOutputsCmd(io2, argv) {
|
|
|
2594
2710
|
}
|
|
2595
2711
|
|
|
2596
2712
|
// dist/host/download.js
|
|
2597
|
-
import { resolve as resolvePath3
|
|
2713
|
+
import { resolve as resolvePath3 } from "node:path";
|
|
2598
2714
|
async function runDownloadCmd(io2, argv) {
|
|
2599
2715
|
if (await refuseInsideManagedRun(io2, "download"))
|
|
2600
2716
|
return USAGE_ERR;
|
|
@@ -2611,51 +2727,38 @@ async function runDownloadCmd(io2, argv) {
|
|
|
2611
2727
|
return USAGE_ERR;
|
|
2612
2728
|
}
|
|
2613
2729
|
const positional = outFlag.remaining.filter((arg) => !arg.startsWith("--"));
|
|
2614
|
-
if (positional.length !==
|
|
2615
|
-
io2.stderr("usage: antpath download <run-id>
|
|
2730
|
+
if (positional.length !== 1) {
|
|
2731
|
+
io2.stderr("usage: antpath download <run-id> [--out path] [common flags]\n");
|
|
2616
2732
|
return USAGE_ERR;
|
|
2617
2733
|
}
|
|
2618
2734
|
const runId = positional[0];
|
|
2619
|
-
const outputId = positional[1];
|
|
2620
2735
|
const http = makeHttpClient(io2, common.flags);
|
|
2621
|
-
let
|
|
2736
|
+
let response;
|
|
2622
2737
|
try {
|
|
2623
|
-
|
|
2738
|
+
response = await operations_exports.downloadRunArchive(http, runId);
|
|
2624
2739
|
} catch (err2) {
|
|
2625
|
-
return emitJsonError(io2, "
|
|
2740
|
+
return emitJsonError(io2, "download_failed", err2.message ?? "download failed", { runId });
|
|
2626
2741
|
}
|
|
2627
|
-
let
|
|
2742
|
+
let bytes;
|
|
2628
2743
|
try {
|
|
2629
|
-
|
|
2744
|
+
bytes = new Uint8Array(await response.arrayBuffer());
|
|
2630
2745
|
} catch (err2) {
|
|
2631
|
-
return emitJsonError(io2, "download_failed", `download
|
|
2746
|
+
return emitJsonError(io2, "download_failed", `download read failed: ${err2.message}`, { runId });
|
|
2632
2747
|
}
|
|
2633
|
-
|
|
2634
|
-
return emitJsonError(io2, "download_failed", `download HTTP ${response.status}`, { runId, outputId });
|
|
2635
|
-
}
|
|
2636
|
-
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
2637
|
-
const destination = resolveDestination(io2, outFlag.value, outputId, link.url);
|
|
2748
|
+
const destination = resolveDestination(io2, outFlag.value, runId);
|
|
2638
2749
|
try {
|
|
2639
|
-
await io2.writeFile(destination,
|
|
2750
|
+
await io2.writeFile(destination, bytes);
|
|
2640
2751
|
} catch (err2) {
|
|
2641
|
-
return emitJsonError(io2, "write_failed", `failed to write
|
|
2752
|
+
return emitJsonError(io2, "write_failed", `failed to write archive: ${err2.message}`, { destination });
|
|
2642
2753
|
}
|
|
2643
|
-
io2.stdout(JSON.stringify({ runId,
|
|
2754
|
+
io2.stdout(JSON.stringify({ runId, path: destination, bytes: bytes.byteLength }) + "\n");
|
|
2644
2755
|
return SUCCESS;
|
|
2645
2756
|
}
|
|
2646
|
-
function resolveDestination(io2, out,
|
|
2757
|
+
function resolveDestination(io2, out, runId) {
|
|
2647
2758
|
if (out) {
|
|
2648
2759
|
return resolvePath3(io2.cwd(), out);
|
|
2649
2760
|
}
|
|
2650
|
-
|
|
2651
|
-
try {
|
|
2652
|
-
const url = new URL(signedUrl);
|
|
2653
|
-
const tail = basename2(url.pathname);
|
|
2654
|
-
if (tail)
|
|
2655
|
-
fileName = tail;
|
|
2656
|
-
} catch {
|
|
2657
|
-
}
|
|
2658
|
-
return resolvePath3(io2.cwd(), fileName);
|
|
2761
|
+
return resolvePath3(io2.cwd(), `antpath-run-${runId}.zip`);
|
|
2659
2762
|
}
|
|
2660
2763
|
|
|
2661
2764
|
// dist/host/cancel.js
|
|
@@ -2765,6 +2868,9 @@ async function dispatch(io2, args) {
|
|
|
2765
2868
|
case "events":
|
|
2766
2869
|
return runEventsCmd(io2, rest);
|
|
2767
2870
|
case "outputs":
|
|
2871
|
+
if (rest[0] === "sync") {
|
|
2872
|
+
return runOutputsSyncCmd(io2, rest.slice(1));
|
|
2873
|
+
}
|
|
2768
2874
|
return runOutputsCmd(io2, rest);
|
|
2769
2875
|
case "download":
|
|
2770
2876
|
return runDownloadCmd(io2, rest);
|
|
@@ -2814,7 +2920,7 @@ Protocol version: ${manifest.protocolVersion}
|
|
|
2814
2920
|
io2.stdout(" antpath status <run-id> --api-token T\n");
|
|
2815
2921
|
io2.stdout(" antpath events <run-id> [--follow] --api-token T\n");
|
|
2816
2922
|
io2.stdout(" antpath outputs <run-id> --api-token T\n");
|
|
2817
|
-
io2.stdout(" antpath download <run-id>
|
|
2923
|
+
io2.stdout(" antpath download <run-id> [--out path] --api-token T\n");
|
|
2818
2924
|
io2.stdout(" antpath cancel <run-id> --api-token T\n");
|
|
2819
2925
|
io2.stdout(" antpath delete <run-id> --api-token T\n");
|
|
2820
2926
|
io2.stdout(" antpath whoami --api-token T\n");
|
|
@@ -2842,6 +2948,30 @@ Protocol version: ${manifest.protocolVersion}
|
|
|
2842
2948
|
}
|
|
2843
2949
|
|
|
2844
2950
|
// dist/cli.js
|
|
2951
|
+
async function walkDirectory(root) {
|
|
2952
|
+
try {
|
|
2953
|
+
const rootStat = await stat2(root);
|
|
2954
|
+
if (!rootStat.isDirectory())
|
|
2955
|
+
return null;
|
|
2956
|
+
} catch {
|
|
2957
|
+
return null;
|
|
2958
|
+
}
|
|
2959
|
+
const out = [];
|
|
2960
|
+
async function visit(dir) {
|
|
2961
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
2962
|
+
for (const entry of entries) {
|
|
2963
|
+
const full = resolvePath4(dir, entry.name);
|
|
2964
|
+
if (entry.isDirectory()) {
|
|
2965
|
+
await visit(full);
|
|
2966
|
+
} else if (entry.isFile()) {
|
|
2967
|
+
const s = await stat2(full);
|
|
2968
|
+
out.push({ path: full, sizeBytes: s.size });
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
await visit(root);
|
|
2973
|
+
return out;
|
|
2974
|
+
}
|
|
2845
2975
|
var io = {
|
|
2846
2976
|
readFile: (path) => readFile2(path, "utf8"),
|
|
2847
2977
|
writeFile: (path, data) => writeFile(path, data),
|
|
@@ -2850,6 +2980,7 @@ var io = {
|
|
|
2850
2980
|
stderr: (chunk) => process.stderr.write(chunk),
|
|
2851
2981
|
exit: (code) => process.exit(code),
|
|
2852
2982
|
argv: process.argv,
|
|
2853
|
-
cwd: () => process.cwd()
|
|
2983
|
+
cwd: () => process.cwd(),
|
|
2984
|
+
walkDirectory
|
|
2854
2985
|
};
|
|
2855
2986
|
await runCli(io);
|
package/dist/cli.mjs.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
e7ee04a6c02d7ddfef1546abddda3b7031c92b8f21471a1e1cec10478a30fa50 cli.mjs
|