antpath 0.9.2 → 0.10.7

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,5 +1,6 @@
1
1
  import { authShapeHeaderName, PROXY_ALLOWED_METHODS, PROXY_RESPONSE_MODES } from "./proxy-protocol.js";
2
2
  import { parseMcpServerRef, parseSkillRef } from "./blueprint.js";
3
+ import { TRANSIENT_CONTENT_HASH_PATTERN, TRANSIENT_SLOT_PATTERN } from "./blueprint.js";
3
4
  const SECRETS_KEY = "secrets";
4
5
  /**
5
6
  * Default caps for a proxy endpoint when the submission doesn't specify
@@ -753,6 +754,8 @@ function parseFlatSubmission(input) {
753
754
  "system",
754
755
  "prompt",
755
756
  "skills",
757
+ "agentsMd",
758
+ "files",
756
759
  "mcpServers",
757
760
  "environment",
758
761
  "metadata",
@@ -767,6 +770,8 @@ function parseFlatSubmission(input) {
767
770
  const system = optionalString(value.system, "submission.system");
768
771
  const prompt = parseFlatPrompt(value.prompt);
769
772
  const skills = parseFlatSkills(value.skills);
773
+ const agentsMd = parseFlatAgentsMd(value.agentsMd);
774
+ const files = parseFlatFiles(value.files);
770
775
  const mcpServers = parseFlatMcpServers(value.mcpServers);
771
776
  const environment = parseTemplateEnvironment(value.environment);
772
777
  const metadata = optionalJsonRecord(value.metadata, "submission.metadata");
@@ -776,6 +781,8 @@ function parseFlatSubmission(input) {
776
781
  ...(system ? { system } : {}),
777
782
  prompt,
778
783
  skills,
784
+ agentsMd,
785
+ files,
779
786
  mcpServers,
780
787
  ...(environment ? { environment } : {}),
781
788
  ...(metadata ? { metadata } : {}),
@@ -911,6 +918,102 @@ function parseFlatSkills(input) {
911
918
  return ref;
912
919
  });
913
920
  }
921
+ // Validation shared between AgentsMd and File refs since the wire
922
+ // shape of an inline-supplied ref is identical (slot, name,
923
+ // contentHash). The discriminator (`kind`) differs by call site.
924
+ const WORKSPACE_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$/;
925
+ function parseTransientWireFields(raw, path) {
926
+ const slot = raw.slot;
927
+ if (typeof slot !== "string" || !TRANSIENT_SLOT_PATTERN.test(slot)) {
928
+ throw new Error(`${path}.slot must match ${TRANSIENT_SLOT_PATTERN.source}`);
929
+ }
930
+ const name = raw.name;
931
+ if (typeof name !== "string" || !WORKSPACE_NAME_PATTERN.test(name)) {
932
+ throw new Error(`${path}.name must match ${WORKSPACE_NAME_PATTERN.source}`);
933
+ }
934
+ const contentHash = raw.contentHash;
935
+ if (typeof contentHash !== "string" || !TRANSIENT_CONTENT_HASH_PATTERN.test(contentHash)) {
936
+ throw new Error(`${path}.contentHash must match ${TRANSIENT_CONTENT_HASH_PATTERN.source}`);
937
+ }
938
+ return { slot, name, contentHash };
939
+ }
940
+ function parseFlatAgentsMd(input) {
941
+ if (input === undefined)
942
+ return [];
943
+ if (!Array.isArray(input)) {
944
+ throw new Error("submission.agentsMd must be an array of AgentsMdRef objects");
945
+ }
946
+ const seenWorkspace = new Set();
947
+ const seenTransientSlot = new Set();
948
+ return input.map((item, index) => {
949
+ const path = `submission.agentsMd[${index}]`;
950
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
951
+ throw new Error(`${path} must be an AgentsMdRef object`);
952
+ }
953
+ const raw = item;
954
+ if (raw.kind === "workspace_agentsmd") {
955
+ if (typeof raw.id !== "string" || raw.id.length === 0) {
956
+ throw new Error(`${path}.id must be a non-empty string`);
957
+ }
958
+ if (seenWorkspace.has(raw.id)) {
959
+ throw new Error(`submission.agentsMd duplicate workspace id: ${raw.id}`);
960
+ }
961
+ seenWorkspace.add(raw.id);
962
+ return { kind: "workspace_agentsmd", id: raw.id };
963
+ }
964
+ if (raw.kind === "transient_agentsmd") {
965
+ const fields = parseTransientWireFields(raw, path);
966
+ if (seenTransientSlot.has(fields.slot)) {
967
+ throw new Error(`submission.agentsMd duplicate transient slot: ${fields.slot}`);
968
+ }
969
+ seenTransientSlot.add(fields.slot);
970
+ return { kind: "transient_agentsmd", ...fields };
971
+ }
972
+ throw new Error(`${path}.kind must be 'workspace_agentsmd' or 'transient_agentsmd' (got ${JSON.stringify(raw.kind)})`);
973
+ });
974
+ }
975
+ function parseFlatFiles(input) {
976
+ if (input === undefined)
977
+ return [];
978
+ if (!Array.isArray(input)) {
979
+ throw new Error("submission.files must be an array of FileRef objects");
980
+ }
981
+ const seenWorkspace = new Set();
982
+ const seenTransientSlot = new Set();
983
+ return input.map((item, index) => {
984
+ const path = `submission.files[${index}]`;
985
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
986
+ throw new Error(`${path} must be a FileRef object`);
987
+ }
988
+ const raw = item;
989
+ if (raw.kind === "workspace_file") {
990
+ if (typeof raw.id !== "string" || raw.id.length === 0) {
991
+ throw new Error(`${path}.id must be a non-empty string`);
992
+ }
993
+ if (seenWorkspace.has(raw.id)) {
994
+ throw new Error(`submission.files duplicate workspace id: ${raw.id}`);
995
+ }
996
+ seenWorkspace.add(raw.id);
997
+ return { kind: "workspace_file", id: raw.id };
998
+ }
999
+ if (raw.kind === "transient_file") {
1000
+ const fields = parseTransientWireFields(raw, path);
1001
+ if (seenTransientSlot.has(fields.slot)) {
1002
+ throw new Error(`submission.files duplicate transient slot: ${fields.slot}`);
1003
+ }
1004
+ seenTransientSlot.add(fields.slot);
1005
+ const mountPath = raw.mountPath;
1006
+ if (mountPath !== undefined) {
1007
+ if (typeof mountPath !== "string" || !mountPath.startsWith("/") || mountPath.length === 0) {
1008
+ throw new Error(`${path}.mountPath must be a non-empty absolute path starting with '/'`);
1009
+ }
1010
+ return { kind: "transient_file", ...fields, mountPath };
1011
+ }
1012
+ return { kind: "transient_file", ...fields };
1013
+ }
1014
+ throw new Error(`${path}.kind must be 'workspace_file' or 'transient_file' (got ${JSON.stringify(raw.kind)})`);
1015
+ });
1016
+ }
914
1017
  function parseFlatMcpServers(input) {
915
1018
  if (input === undefined) {
916
1019
  return [];
@@ -0,0 +1,90 @@
1
+ import type { AgentsMdRef } from "./_shared/index.js";
2
+ /**
3
+ * The second of the three agent-context concepts (see
4
+ * `references/agent-context-uploads.md`). An `AgentsMd` instance
5
+ * carries the bytes of a single markdown file that antpath will
6
+ * deliver to the agent as the **first user turn** of the session —
7
+ * matching Claude Code's CLAUDE.md behaviour.
8
+ *
9
+ * Three usage modes mirror `Skill`:
10
+ *
11
+ * - **Workspace** — `AgentsMd.fromId("amd_…")`. Persistent, reused
12
+ * across runs.
13
+ * - **Workspace via explicit upload** —
14
+ * `await AgentsMd.fromContent("…", { name }).upload(client)`.
15
+ * Returns a workspace-backed instance; the original is consumed.
16
+ * - **Inline per-run** — `await AgentsMd.fromContent("…", { name })`
17
+ * passed directly to `submitRun({ agentsMd: [...] })`. The BFF
18
+ * ingests it as a per-run-artifact workspace file with an
19
+ * auto-suffixed name (mirrors `Skill`'s inline behaviour).
20
+ *
21
+ * The single canonical filename inside the zip is always `AGENTS.md`
22
+ * so the canonical hash is a pure function of the markdown content —
23
+ * dedup via `uploadIfChanged` works on bytes alone.
24
+ */
25
+ export declare class AgentsMd {
26
+ #private;
27
+ constructor(ref: AgentsMdRef, content?: string, contentHash?: string);
28
+ get ref(): AgentsMdRef;
29
+ /** True for `AgentsMd.fromId(...)` and instances returned by `.upload(...)`. */
30
+ get isWorkspace(): boolean;
31
+ /** True only while the inline AgentsMd still carries bytes and has not been consumed. */
32
+ get isUnstaged(): boolean;
33
+ get isConsumed(): boolean;
34
+ /**
35
+ * Reference an existing workspace `amd_*` row. Does NOT validate
36
+ * existence — that check happens on the next `submitRun`, where the
37
+ * BFF rejects unknown / soft-deleted ids before inserting the run.
38
+ */
39
+ static fromId(id: string): AgentsMd;
40
+ /**
41
+ * Build an inline AgentsMd from a markdown string. `name` becomes
42
+ * the workspace name (per-run-artifact auto-suffixes it at ingest).
43
+ */
44
+ static fromContent(content: string, args: {
45
+ readonly name: string;
46
+ }): Promise<AgentsMd>;
47
+ /**
48
+ * Read a local markdown file and build an inline AgentsMd. Path
49
+ * may point at AGENTS.md, CLAUDE.md, or any markdown file — the
50
+ * filename inside the zip is always normalised to AGENTS.md so
51
+ * the canonical hash is pure.
52
+ */
53
+ static fromPath(path: string, args?: {
54
+ readonly name?: string;
55
+ }): Promise<AgentsMd>;
56
+ /**
57
+ * Persist this inline AgentsMd as a workspace row and return a new
58
+ * workspace-backed instance. The original is marked consumed.
59
+ */
60
+ upload(client: AgentsMdUploader): Promise<AgentsMd>;
61
+ /**
62
+ * Internal: yield the inline content + hash so client.submitRun
63
+ * can build the `agentsmd:<slot>` multipart part. Not part of the
64
+ * public API.
65
+ */
66
+ _takeUnstagedContent(): {
67
+ name: string;
68
+ content: string;
69
+ contentHash: string;
70
+ } | undefined;
71
+ toJSON(): AgentsMdRef;
72
+ }
73
+ export interface AgentsMdRecord {
74
+ readonly id: string;
75
+ readonly name: string;
76
+ readonly hash: string | null;
77
+ readonly sizeBytes: number | null;
78
+ }
79
+ export interface AgentsMdUploader {
80
+ readonly _uploadAgentsMd?: (args: {
81
+ readonly name: string;
82
+ readonly content: string;
83
+ }) => Promise<AgentsMdRecord>;
84
+ readonly agentsMd?: {
85
+ readonly _uploadAgentsMd?: (args: {
86
+ readonly name: string;
87
+ readonly content: string;
88
+ }) => Promise<AgentsMdRecord>;
89
+ };
90
+ }
@@ -0,0 +1,171 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { hashSkillBundle } from "./bundle.js";
3
+ import { strToU8, zipSync } from "fflate";
4
+ /**
5
+ * The second of the three agent-context concepts (see
6
+ * `references/agent-context-uploads.md`). An `AgentsMd` instance
7
+ * carries the bytes of a single markdown file that antpath will
8
+ * deliver to the agent as the **first user turn** of the session —
9
+ * matching Claude Code's CLAUDE.md behaviour.
10
+ *
11
+ * Three usage modes mirror `Skill`:
12
+ *
13
+ * - **Workspace** — `AgentsMd.fromId("amd_…")`. Persistent, reused
14
+ * across runs.
15
+ * - **Workspace via explicit upload** —
16
+ * `await AgentsMd.fromContent("…", { name }).upload(client)`.
17
+ * Returns a workspace-backed instance; the original is consumed.
18
+ * - **Inline per-run** — `await AgentsMd.fromContent("…", { name })`
19
+ * passed directly to `submitRun({ agentsMd: [...] })`. The BFF
20
+ * ingests it as a per-run-artifact workspace file with an
21
+ * auto-suffixed name (mirrors `Skill`'s inline behaviour).
22
+ *
23
+ * The single canonical filename inside the zip is always `AGENTS.md`
24
+ * so the canonical hash is a pure function of the markdown content —
25
+ * dedup via `uploadIfChanged` works on bytes alone.
26
+ */
27
+ export class AgentsMd {
28
+ #ref;
29
+ #content;
30
+ #contentHash;
31
+ #consumed = false;
32
+ constructor(ref, content, contentHash) {
33
+ this.#ref = ref;
34
+ this.#content = content;
35
+ this.#contentHash = contentHash;
36
+ }
37
+ get ref() {
38
+ return this.#ref;
39
+ }
40
+ /** True for `AgentsMd.fromId(...)` and instances returned by `.upload(...)`. */
41
+ get isWorkspace() {
42
+ return this.#ref.kind === "workspace_agentsmd";
43
+ }
44
+ /** True only while the inline AgentsMd still carries bytes and has not been consumed. */
45
+ get isUnstaged() {
46
+ return (this.#ref.kind === "transient_agentsmd" &&
47
+ this.#ref.slot === UNSTAGED_SLOT &&
48
+ !this.#consumed &&
49
+ this.#content !== undefined);
50
+ }
51
+ get isConsumed() {
52
+ return this.#consumed;
53
+ }
54
+ /**
55
+ * Reference an existing workspace `amd_*` row. Does NOT validate
56
+ * existence — that check happens on the next `submitRun`, where the
57
+ * BFF rejects unknown / soft-deleted ids before inserting the run.
58
+ */
59
+ static fromId(id) {
60
+ if (typeof id !== "string" || id.length === 0) {
61
+ throw new Error("AgentsMd.fromId: id is required");
62
+ }
63
+ return new AgentsMd({ kind: "workspace_agentsmd", id });
64
+ }
65
+ /**
66
+ * Build an inline AgentsMd from a markdown string. `name` becomes
67
+ * the workspace name (per-run-artifact auto-suffixes it at ingest).
68
+ */
69
+ static async fromContent(content, args) {
70
+ if (typeof content !== "string" || content.length === 0) {
71
+ throw new Error("AgentsMd.fromContent: content must be a non-empty string");
72
+ }
73
+ if (!args || typeof args.name !== "string" || !WORKSPACE_NAME_RE.test(args.name)) {
74
+ throw new Error(`AgentsMd.fromContent: name must match ${WORKSPACE_NAME_RE.source}`);
75
+ }
76
+ const zip = zipSync({ "AGENTS.md": [strToU8(content), { mtime: ZIP_EPOCH }] }, { level: 6 });
77
+ const contentHash = await hashSkillBundle(zip);
78
+ const ref = {
79
+ kind: "transient_agentsmd",
80
+ slot: UNSTAGED_SLOT,
81
+ name: args.name,
82
+ contentHash
83
+ };
84
+ return new AgentsMd(ref, content, contentHash);
85
+ }
86
+ /**
87
+ * Read a local markdown file and build an inline AgentsMd. Path
88
+ * may point at AGENTS.md, CLAUDE.md, or any markdown file — the
89
+ * filename inside the zip is always normalised to AGENTS.md so
90
+ * the canonical hash is pure.
91
+ */
92
+ static async fromPath(path, args) {
93
+ const buffer = await readFile(path, "utf8");
94
+ const inferredName = args?.name ?? inferNameFromPath(path);
95
+ return AgentsMd.fromContent(buffer, { name: inferredName });
96
+ }
97
+ /**
98
+ * Persist this inline AgentsMd as a workspace row and return a new
99
+ * workspace-backed instance. The original is marked consumed.
100
+ */
101
+ async upload(client) {
102
+ if (this.#consumed) {
103
+ throw new Error(consumedMessage());
104
+ }
105
+ if (this.#ref.kind !== "transient_agentsmd" || this.#content === undefined) {
106
+ throw new Error("AgentsMd.upload: only inline (unstaged) instances can be uploaded");
107
+ }
108
+ const uploader = resolveUploader(client);
109
+ const record = await uploader({ name: this.#ref.name, content: this.#content });
110
+ this.#consumed = true;
111
+ return new AgentsMd({ kind: "workspace_agentsmd", id: record.id });
112
+ }
113
+ /**
114
+ * Internal: yield the inline content + hash so client.submitRun
115
+ * can build the `agentsmd:<slot>` multipart part. Not part of the
116
+ * public API.
117
+ */
118
+ _takeUnstagedContent() {
119
+ if (this.#consumed) {
120
+ throw new Error(consumedMessage());
121
+ }
122
+ if (!this.isUnstaged)
123
+ return undefined;
124
+ if (this.#ref.kind !== "transient_agentsmd" || this.#content === undefined || this.#contentHash === undefined) {
125
+ return undefined;
126
+ }
127
+ return {
128
+ name: this.#ref.name,
129
+ content: this.#content,
130
+ contentHash: this.#contentHash
131
+ };
132
+ }
133
+ toJSON() {
134
+ if (this.#consumed)
135
+ throw new Error(consumedMessage());
136
+ if (this.isUnstaged) {
137
+ throw new Error("Cannot JSON-serialise an inline AgentsMd — the content is not in the JSON. " +
138
+ "Persist via agentsMd.upload(client) and serialise the returned workspace instance, " +
139
+ "or pass the inline AgentsMd directly to submitRun without serialising.");
140
+ }
141
+ return this.#ref;
142
+ }
143
+ }
144
+ const UNSTAGED_SLOT = "(unstaged)";
145
+ const ZIP_EPOCH = new Date(Date.UTC(1980, 0, 1));
146
+ const WORKSPACE_NAME_RE = /^[a-z0-9][a-z0-9-]{0,62}[a-z0-9]$/;
147
+ function resolveUploader(client) {
148
+ const direct = client._uploadAgentsMd;
149
+ if (typeof direct === "function")
150
+ return direct.bind(client);
151
+ const nested = client.agentsMd?._uploadAgentsMd;
152
+ if (typeof nested === "function")
153
+ return nested.bind(client.agentsMd);
154
+ throw new Error("AgentsMd.upload: client argument does not expose an upload entry point — " +
155
+ "pass the AntpathClient instance or its `client.agentsMd`");
156
+ }
157
+ function consumedMessage() {
158
+ return ("this AgentsMd was already uploaded via agentsMd.upload(client); use the returned instance " +
159
+ "or AgentsMd.fromId(record.id) for subsequent runs");
160
+ }
161
+ function inferNameFromPath(path) {
162
+ // Use the basename minus extension, lowercased and normalised to
163
+ // match the workspace-name regex. Falls back to a timestamp slug.
164
+ const base = path.replace(/\\/g, "/").split("/").at(-1) ?? "";
165
+ const stem = base.replace(/\.[^.]+$/, "").toLowerCase();
166
+ const slug = stem.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
167
+ if (slug && WORKSPACE_NAME_RE.test(slug))
168
+ return slug;
169
+ return `agentsmd-${Date.now().toString(36)}`;
170
+ }
171
+ //# sourceMappingURL=agents-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../src/agents-md.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Phase C: Chunked upload protocol for large assets.
3
+ *
4
+ * Two upload strategies:
5
+ *
6
+ * - **small** (≤ 6 MiB): existing single-request multipart POST to
7
+ * `/api/skills` or `/api/files`. No change to the existing path.
8
+ * - **chunked** (> 6 MiB): three-step TUS resumable upload:
9
+ * 1. `POST /api/assets/upload-init` — BFF mints a pending row +
10
+ * returns TUS URL + short-lived token.
11
+ * 2. Drive `tus-js-client` with `chunkSize: 6 MiB` against the
12
+ * Supabase TUS endpoint.
13
+ * 3. `POST /api/assets/finalize` — BFF verifies sha256 of the
14
+ * assembled bytes and transitions the row pending → ready.
15
+ *
16
+ * The threshold (6 MiB) matches the Supabase TUS requirement exactly:
17
+ * their endpoint requires chunk sizes of exactly 6 MiB for all chunks
18
+ * except the final one.
19
+ *
20
+ * `AgentsMd.upload` is NOT wired through chunked — a single markdown
21
+ * file will never exceed 6 MiB. Only `Skill.upload` and `File.upload`
22
+ * use the strategy chooser.
23
+ */
24
+ /** Exact threshold in bytes: 6 MiB. */
25
+ export declare const CHUNKED_UPLOAD_THRESHOLD_BYTES: number;
26
+ /** Exact chunk size: 6 MiB. Supabase TUS requires this exactly. */
27
+ export declare const TUS_CHUNK_SIZE: number;
28
+ /**
29
+ * Choose the upload strategy based on bundle size.
30
+ *
31
+ * - `<= 6 MiB` → `"small"` — existing single-request multipart POST.
32
+ * - `> 6 MiB` → `"chunked"` — three-step TUS resumable upload.
33
+ *
34
+ * The boundary is inclusive at 6 MiB: a bundle of exactly 6,291,456 bytes
35
+ * takes the small path; one byte more takes the chunked path.
36
+ */
37
+ export declare function chooseUploadStrategy(sizeBytes: number): "small" | "chunked";
38
+ /**
39
+ * Arguments for `uploadChunked`. The caller provides the bundle bytes,
40
+ * the TUS URL, the token, and the advisory hash that was computed
41
+ * before the upload session was opened (so the finalize endpoint can
42
+ * verify integrity without re-downloading).
43
+ */
44
+ export interface UploadChunkedArgs {
45
+ /** The raw bytes to upload (canonical zip). */
46
+ readonly bundle: Uint8Array;
47
+ /** The TUS endpoint URL returned by the BFF's upload-init endpoint. */
48
+ readonly tusUrl: string;
49
+ /**
50
+ * Short-lived token returned by upload-init. Placed in the
51
+ * `Authorization` header of every TUS request so Supabase
52
+ * Storage accepts the upload.
53
+ */
54
+ readonly tusToken: string;
55
+ /**
56
+ * Additional per-upload headers returned by the BFF (e.g.
57
+ * `x-upsert`, `content-type`). These travel verbatim on every TUS
58
+ * PATCH request.
59
+ */
60
+ readonly uploadHeaders?: Readonly<Record<string, string>>;
61
+ /**
62
+ * Advisory `sha256:<hex>` hash of the bundle bytes. Verified
63
+ * BEFORE any bytes are pushed to the TUS endpoint — a mismatch
64
+ * throws early so we never PATCH bytes that don't match what was
65
+ * declared to the BFF during init.
66
+ */
67
+ readonly hash: string;
68
+ }
69
+ /**
70
+ * Drive `tus-js-client` to upload `bundle` in 6 MiB chunks.
71
+ *
72
+ * Pre-upload steps:
73
+ * 1. Verify `sha256(bundle) === args.hash`. Throws if they don't match.
74
+ *
75
+ * Upload:
76
+ * 2. Build a `tus.Upload` with `chunkSize: TUS_CHUNK_SIZE`, the
77
+ * supplied auth header, and the extra headers the BFF returned.
78
+ * 3. Await the upload completion via a Promise wrapper around the
79
+ * `onSuccess` / `onError` callbacks.
80
+ *
81
+ * The function does NOT call the BFF finalize endpoint — that is the
82
+ * caller's responsibility (so the caller can attach extra metadata like
83
+ * `assetId`, `kind`, etc.).
84
+ */
85
+ export declare function uploadChunked(args: UploadChunkedArgs): Promise<void>;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Phase C: Chunked upload protocol for large assets.
3
+ *
4
+ * Two upload strategies:
5
+ *
6
+ * - **small** (≤ 6 MiB): existing single-request multipart POST to
7
+ * `/api/skills` or `/api/files`. No change to the existing path.
8
+ * - **chunked** (> 6 MiB): three-step TUS resumable upload:
9
+ * 1. `POST /api/assets/upload-init` — BFF mints a pending row +
10
+ * returns TUS URL + short-lived token.
11
+ * 2. Drive `tus-js-client` with `chunkSize: 6 MiB` against the
12
+ * Supabase TUS endpoint.
13
+ * 3. `POST /api/assets/finalize` — BFF verifies sha256 of the
14
+ * assembled bytes and transitions the row pending → ready.
15
+ *
16
+ * The threshold (6 MiB) matches the Supabase TUS requirement exactly:
17
+ * their endpoint requires chunk sizes of exactly 6 MiB for all chunks
18
+ * except the final one.
19
+ *
20
+ * `AgentsMd.upload` is NOT wired through chunked — a single markdown
21
+ * file will never exceed 6 MiB. Only `Skill.upload` and `File.upload`
22
+ * use the strategy chooser.
23
+ */
24
+ import * as tus from "tus-js-client";
25
+ /** Exact threshold in bytes: 6 MiB. */
26
+ export const CHUNKED_UPLOAD_THRESHOLD_BYTES = 6 * 1024 * 1024;
27
+ /** Exact chunk size: 6 MiB. Supabase TUS requires this exactly. */
28
+ export const TUS_CHUNK_SIZE = 6 * 1024 * 1024;
29
+ /**
30
+ * Choose the upload strategy based on bundle size.
31
+ *
32
+ * - `<= 6 MiB` → `"small"` — existing single-request multipart POST.
33
+ * - `> 6 MiB` → `"chunked"` — three-step TUS resumable upload.
34
+ *
35
+ * The boundary is inclusive at 6 MiB: a bundle of exactly 6,291,456 bytes
36
+ * takes the small path; one byte more takes the chunked path.
37
+ */
38
+ export function chooseUploadStrategy(sizeBytes) {
39
+ return sizeBytes <= CHUNKED_UPLOAD_THRESHOLD_BYTES ? "small" : "chunked";
40
+ }
41
+ /**
42
+ * Drive `tus-js-client` to upload `bundle` in 6 MiB chunks.
43
+ *
44
+ * Pre-upload steps:
45
+ * 1. Verify `sha256(bundle) === args.hash`. Throws if they don't match.
46
+ *
47
+ * Upload:
48
+ * 2. Build a `tus.Upload` with `chunkSize: TUS_CHUNK_SIZE`, the
49
+ * supplied auth header, and the extra headers the BFF returned.
50
+ * 3. Await the upload completion via a Promise wrapper around the
51
+ * `onSuccess` / `onError` callbacks.
52
+ *
53
+ * The function does NOT call the BFF finalize endpoint — that is the
54
+ * caller's responsibility (so the caller can attach extra metadata like
55
+ * `assetId`, `kind`, etc.).
56
+ */
57
+ export async function uploadChunked(args) {
58
+ // ── 1. Pre-upload hash verification ────────────────────────────────────
59
+ const recomputed = await computeSha256Hex(args.bundle);
60
+ const expected = args.hash.startsWith("sha256:")
61
+ ? args.hash.slice("sha256:".length)
62
+ : args.hash;
63
+ if (recomputed !== expected) {
64
+ throw new Error(`uploadChunked: bundle hash mismatch — computed sha256:${recomputed} ` +
65
+ `but init-session declared ${args.hash}. Bytes do not match the advisory hash; ` +
66
+ `aborting to avoid uploading corrupted data.`);
67
+ }
68
+ // ── 2. Build tus.Upload and drive the upload ────────────────────────────
69
+ await new Promise((resolve, reject) => {
70
+ const headers = {
71
+ Authorization: `Bearer ${args.tusToken}`,
72
+ ...(args.uploadHeaders ?? {})
73
+ };
74
+ // tus-js-client accepts a Buffer in Node environments.
75
+ const file = Buffer.from(args.bundle.buffer, args.bundle.byteOffset, args.bundle.byteLength);
76
+ const upload = new tus.Upload(file, {
77
+ endpoint: args.tusUrl,
78
+ chunkSize: TUS_CHUNK_SIZE,
79
+ headers,
80
+ // Do not retry automatically — the caller (Skill.upload / File.upload)
81
+ // owns retry semantics. retryDelays: null means "fail fast on error".
82
+ retryDelays: null,
83
+ // Disable fingerprint-based resumption — we don't persist state
84
+ // across process restarts in Phase C (scoped out per plan).
85
+ storeFingerprintForResuming: false,
86
+ onSuccess() {
87
+ resolve();
88
+ },
89
+ onError(err) {
90
+ reject(err);
91
+ }
92
+ });
93
+ upload.start();
94
+ });
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Internal helpers
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Compute SHA-256 over `bytes` and return the lowercase hex digest.
101
+ * Uses Web Crypto when available (Node 18+ / browser), falls back to
102
+ * nothing — the SDK already requires Web Crypto for `hashSkillBundle`.
103
+ */
104
+ async function computeSha256Hex(bytes) {
105
+ const subtle = globalThis.crypto?.subtle;
106
+ if (!subtle) {
107
+ throw new Error("uploadChunked: globalThis.crypto.subtle is not available; " +
108
+ "Node 18+ or a Web-Crypto-capable runtime is required");
109
+ }
110
+ const copy = new Uint8Array(bytes.byteLength);
111
+ copy.set(bytes);
112
+ const digest = await subtle.digest("SHA-256", copy.buffer);
113
+ return bufferToHex(digest);
114
+ }
115
+ function bufferToHex(buffer) {
116
+ const view = new Uint8Array(buffer);
117
+ let out = "";
118
+ for (let i = 0; i < view.length; i++) {
119
+ const byte = view[i];
120
+ out += byte.toString(16).padStart(2, "0");
121
+ }
122
+ return out;
123
+ }
124
+ //# sourceMappingURL=asset-upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-upload.js","sourceRoot":"","sources":["../src/asset-upload.ts"],"names":[],"mappings":"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"}
package/dist/bundle.js CHANGED
@@ -34,7 +34,9 @@ export function bundleSkillFiles(files) {
34
34
  collected.set(entry.path, bytes);
35
35
  }
36
36
  if (!hasSkillMd) {
37
- throw new Error('Skill bundle must contain a "SKILL.md" file at the root');
37
+ throw new Error('Skill bundle must contain a "SKILL.md" file at the root. ' +
38
+ "If you want to upload an instructions file or generic agent context, " +
39
+ "use AgentsMd.fromPath / File.fromPath instead.");
38
40
  }
39
41
  // Sort entries and pin every mtime to the epoch so the byte output is
40
42
  // identical across machines and re-runs (the BFF re-canonicalises and
@@ -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;AAwBhF,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;AAK/B,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,mBAAmB,CAAC,QAAQ,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CAAC,wBAAwB,mBAAmB,CAAC,QAAQ,oBAAoB,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7G,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;IAChD,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAE1B,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,OAAO,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC9E,IAAI,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,eAAe,OAAO,kCAAkC,CAAC,CAAC;QAC5E,CAAC;QACD,MAAM,KAAK,GAAG,wBAAwB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;QAClF,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;QACD,iBAAiB,IAAI,KAAK,CAAC,UAAU,CAAC;QACtC,IAAI,iBAAiB,GAAG,mBAAmB,CAAC,oBAAoB,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CACb,4CAA4C,mBAAmB,CAAC,oBAAoB,QAAQ,CAC7F,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED,sEAAsE;IACtE,sEAAsE;IACtE,qEAAqE;IACrE,sDAAsD;IACtD,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjG,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,IAAI,GAAG,CAAC,UAAU,GAAG,mBAAmB,CAAC,kBAAkB,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,0CAA0C,mBAAmB,CAAC,kBAAkB,eAAe,GAAG,CAAC,UAAU,GAAG,CACjH,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAoB;IACxD,MAAM,MAAM,GAAI,UAAqD,CAAC,MAAM,EAAE,MAAM,CAAC;IACrF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,kHAAkH,CACnH,CAAC;IACJ,CAAC;IACD,qEAAqE;IACrE,uEAAuE;IACvE,oEAAoE;IACpE,qEAAqE;IACrE,aAAa;IACb,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACnB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3D,OAAO,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;QAC/B,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}