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.
- package/dist/_shared/blueprint.d.ts +70 -2
- package/dist/_shared/blueprint.js +38 -3
- package/dist/_shared/operations.d.ts +85 -10
- package/dist/_shared/operations.js +148 -12
- package/dist/_shared/run-unit.js +4 -0
- package/dist/_shared/runtime-types.d.ts +47 -0
- package/dist/_shared/submission.d.ts +3 -1
- package/dist/_shared/submission.js +103 -0
- package/dist/agents-md.d.ts +90 -0
- package/dist/agents-md.js +171 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/asset-upload.d.ts +85 -0
- package/dist/asset-upload.js +124 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/bundle.js +3 -1
- package/dist/bundle.js.map +1 -1
- package/dist/cli.mjs +114 -4
- package/dist/cli.mjs.sha256 +1 -1
- package/dist/client.d.ts +98 -5
- package/dist/client.js +207 -19
- package/dist/client.js.map +1 -1
- package/dist/file.d.ts +117 -0
- package/dist/file.js +287 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +7 -3
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/skill.d.ts +29 -0
- package/dist/skill.js +38 -1
- package/dist/skill.js.map +1 -1
- package/docs/skills.md +76 -24
- package/package.json +3 -2
|
@@ -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
|
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;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,
|
|
1
|
+
{"version":3,"file":"bundle.js","sourceRoot":"","sources":["../src/bundle.ts"],"names":[],"mappings":"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"}
|