antpath 0.2.1 → 0.4.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.
Files changed (110) hide show
  1. package/README.md +54 -40
  2. package/dist/_shared/cleanup-policy.d.ts +8 -0
  3. package/dist/_shared/cleanup-policy.js +24 -0
  4. package/dist/_shared/config.d.ts +47 -0
  5. package/dist/_shared/config.js +150 -0
  6. package/dist/_shared/dev-stack.d.ts +19 -0
  7. package/dist/_shared/dev-stack.js +105 -0
  8. package/dist/_shared/errors.d.ts +8 -0
  9. package/dist/_shared/errors.js +18 -0
  10. package/dist/_shared/http.d.ts +25 -0
  11. package/dist/_shared/http.js +93 -0
  12. package/dist/_shared/index.d.ts +17 -0
  13. package/dist/_shared/index.js +20 -0
  14. package/dist/{providers → _shared}/known-events.d.ts +10 -10
  15. package/dist/{providers → _shared}/known-events.js +9 -9
  16. package/dist/_shared/operations.d.ts +24 -0
  17. package/dist/_shared/operations.js +47 -0
  18. package/dist/_shared/proxy-protocol.d.ts +148 -0
  19. package/dist/_shared/proxy-protocol.js +113 -0
  20. package/dist/_shared/proxy-validation.d.ts +19 -0
  21. package/dist/_shared/proxy-validation.js +51 -0
  22. package/dist/_shared/runtime-types.d.ts +90 -0
  23. package/dist/_shared/runtime-types.js +2 -0
  24. package/dist/{errors.d.ts → _shared/sdk-errors.d.ts} +10 -1
  25. package/dist/{errors.js → _shared/sdk-errors.js} +15 -2
  26. package/dist/{utils/secrets.js → _shared/sdk-secrets.js} +1 -1
  27. package/dist/_shared/secrets.d.ts +7 -0
  28. package/dist/_shared/secrets.js +20 -0
  29. package/dist/_shared/stable.d.ts +16 -0
  30. package/dist/{utils → _shared}/stable.js +14 -0
  31. package/dist/_shared/status.d.ts +8 -0
  32. package/dist/_shared/status.js +46 -0
  33. package/dist/_shared/submission.d.ts +157 -0
  34. package/dist/_shared/submission.js +681 -0
  35. package/dist/{template → _shared/template}/compiler.js +3 -3
  36. package/dist/{template/index.d.ts → _shared/template/helpers.d.ts} +0 -2
  37. package/dist/{template/index.js → _shared/template/helpers.js} +1 -2
  38. package/dist/_shared/template/index.d.ts +4 -0
  39. package/dist/_shared/template/index.js +4 -0
  40. package/dist/_shared/template/mapper.d.ts +11 -0
  41. package/dist/_shared/template/mapper.js +70 -0
  42. package/dist/cli.mjs +1223 -64
  43. package/dist/cli.mjs.sha256 +1 -1
  44. package/dist/client.d.ts +100 -8
  45. package/dist/client.js +193 -30
  46. package/dist/client.js.map +1 -1
  47. package/dist/index.d.ts +16 -10
  48. package/dist/index.js +16 -7
  49. package/dist/index.js.map +1 -1
  50. package/docs/cleanup.md +7 -4
  51. package/docs/credentials.md +10 -12
  52. package/docs/events.md +19 -82
  53. package/docs/outputs.md +15 -4
  54. package/docs/quickstart.md +40 -6
  55. package/docs/release.md +57 -12
  56. package/docs/skills.md +1 -1
  57. package/docs/templates.md +1 -1
  58. package/docs/testing.md +11 -8
  59. package/examples/mcp-static-bearer.ts +12 -9
  60. package/examples/quickstart.ts +6 -6
  61. package/package.json +5 -7
  62. package/dist/credentials.d.ts +0 -3
  63. package/dist/credentials.js +0 -56
  64. package/dist/credentials.js.map +0 -1
  65. package/dist/errors.js.map +0 -1
  66. package/dist/files/downloader.d.ts +0 -3
  67. package/dist/files/downloader.js +0 -43
  68. package/dist/files/downloader.js.map +0 -1
  69. package/dist/platform/client.d.ts +0 -204
  70. package/dist/platform/client.js +0 -203
  71. package/dist/platform/client.js.map +0 -1
  72. package/dist/platform/index.d.ts +0 -1
  73. package/dist/platform/index.js +0 -2
  74. package/dist/platform/index.js.map +0 -1
  75. package/dist/providers/anthropic/provider.d.ts +0 -36
  76. package/dist/providers/anthropic/provider.js +0 -380
  77. package/dist/providers/anthropic/provider.js.map +0 -1
  78. package/dist/providers/known-events.js.map +0 -1
  79. package/dist/providers/types.d.ts +0 -42
  80. package/dist/providers/types.js.map +0 -1
  81. package/dist/run/controller.d.ts +0 -30
  82. package/dist/run/controller.js +0 -314
  83. package/dist/run/controller.js.map +0 -1
  84. package/dist/skills/packager.d.ts +0 -11
  85. package/dist/skills/packager.js +0 -76
  86. package/dist/skills/packager.js.map +0 -1
  87. package/dist/template/compiler.js.map +0 -1
  88. package/dist/template/index.js.map +0 -1
  89. package/dist/template/types.js +0 -2
  90. package/dist/template/types.js.map +0 -1
  91. package/dist/types.d.ts +0 -149
  92. package/dist/types.js +0 -2
  93. package/dist/types.js.map +0 -1
  94. package/dist/utils/events.d.ts +0 -27
  95. package/dist/utils/events.js +0 -120
  96. package/dist/utils/events.js.map +0 -1
  97. package/dist/utils/paths.d.ts +0 -3
  98. package/dist/utils/paths.js +0 -27
  99. package/dist/utils/paths.js.map +0 -1
  100. package/dist/utils/secrets.js.map +0 -1
  101. package/dist/utils/stable.d.ts +0 -2
  102. package/dist/utils/stable.js.map +0 -1
  103. package/references/architecture-decisions.md +0 -473
  104. package/references/implementation-plan.md +0 -452
  105. package/references/research-sources.md +0 -41
  106. package/references/testing-strategy.md +0 -29
  107. /package/dist/{utils/secrets.d.ts → _shared/sdk-secrets.d.ts} +0 -0
  108. /package/dist/{template → _shared/template}/compiler.d.ts +0 -0
  109. /package/dist/{template → _shared/template}/types.d.ts +0 -0
  110. /package/dist/{providers → _shared/template}/types.js +0 -0
package/docs/events.md CHANGED
@@ -4,105 +4,41 @@ title: Events
4
4
 
5
5
  # Events
6
6
 
7
- Claude Managed Agents sessions run autonomously on Anthropic's infrastructure.
8
- They are **non-blocking**: the SDK opens a long-lived SSE stream while the
9
- agent thinks, calls tools, and emits messages on its own schedule. The SDK
10
- cannot intercept a tool call to return a value — `permission_policy` is
11
- `always_allow`. This guide covers the observe-only event surface.
7
+ Claude Managed Agents sessions run autonomously on Anthropic's infrastructure. They are **non-blocking**: the worker polls the provider session while the agent thinks, calls tools, and emits messages on its own schedule, and persists every captured event to the dashboard. The SDK and CLI observe the durable event timeline from the dashboard — there is no in-process tool-approval hook (`permission_policy` is `always_allow`).
12
8
 
13
9
  ## Two ways to consume events
14
10
 
15
11
  ```ts
16
- // Push: register a callback in RunOptions.
17
- const handle = await client.run(template, {
18
- onEvent: async (event) => {
19
- if (event.type === "provider.event") {
20
- // event.event is a ProviderEvent (typed via a type guard below).
21
- }
22
- }
23
- });
24
- await handle.wait();
12
+ // Pull a snapshot of every event captured so far.
13
+ const events = await ref.events();
25
14
  ```
26
15
 
27
16
  ```ts
28
- // Pull: iterate the stream concurrently with handle.wait().
29
- const handle = await client.run(template);
30
- const collect = (async () => {
31
- for await (const event of handle.streamEvents()) {
17
+ // Stream live: yields each event exactly once, stops when the run reaches
18
+ // a terminal status. Backed by polling the dashboard events endpoint.
19
+ for await (const event of ref.stream({ intervalMs: 1000 })) {
20
+ if (event.type === "agent.message") {
32
21
  // ...
33
22
  }
34
- })();
35
- const result = await handle.wait();
36
- await collect;
37
- ```
38
-
39
- Both surfaces observe the same events. They can be used together; every
40
- subscriber sees every event. A subscriber attached after `client.run()`
41
- returns replays the events it missed (including the initial
42
- `sdk.status` emitted while provider resources were being created), then
43
- continues live.
44
-
45
- ## Event shape
46
-
47
- ```ts
48
- type RunEvent =
49
- | { type: "sdk.status"; status: RunStatus; at: string }
50
- | { type: "sdk.message_sent"; index: number; at: string }
51
- | { type: "sdk.cleanup"; ... } // see "Cleanup events" below
52
- | { type: "provider.event"; event: ProviderEvent; at: string };
53
-
54
- interface ProviderEvent {
55
- type: string; // documented Claude event type, e.g. "agent.tool_use"
56
- payload: unknown; // raw provider payload, redacted
57
- receivedAt: string;
58
23
  }
59
24
  ```
60
25
 
61
- All events pass through the SDK's secret redaction before reaching any
62
- subscriber, so payloads do not contain the Anthropic key or MCP credentials
63
- that were supplied to `client.run()`.
26
+ The CLI mirrors the same surface:
64
27
 
65
- ## Drain-before-`wait()` guarantee
66
-
67
- By the time `await handle.wait()` resolves, every `onEvent` invocation
68
- triggered by events emitted before the terminal `sdk.status` has itself
69
- resolved or rejected. Async handlers are invoked serially in event order on
70
- a single per-listener promise chain, so callers can persist events in order
71
- without their own queue.
72
-
73
- The same drain applies to handlers that throw — both modes (warn-only and
74
- abort-on-error, see below) wait for the offending invocation to settle
75
- before resolving.
76
-
77
- ## Error semantics
78
-
79
- Default: a handler that throws (or returns a rejecting promise) is logged
80
- via the SDK's configured `logger` at `warn`. The run continues, and the
81
- final result is unaffected.
82
-
83
- Opt-in: `onEventAbortOnError: true` upgrades the **first** pre-terminal
84
- handler error into a `RunStateError` that fails the run. Once terminal
85
- status has been reached, listener errors are always logged only — they
86
- never mutate the result, and they cannot trigger recursion when the
87
- terminal `sdk.status: failed` event itself causes another error.
28
+ ```bash
29
+ antpath events <run-id> --api-token … --workspace … --dashboard-url … # snapshot
30
+ antpath events <run-id> --follow --api-token --workspace --dashboard-url … # stream until terminal
31
+ ```
88
32
 
89
- `RunStateError.message` and its `cause` field pass through the same
90
- redaction layer used for events.
33
+ Both surfaces observe the same events. A subscriber attached after `submitRun()` returns replays the events it missed, then continues live.
91
34
 
92
- ## Cleanup events
35
+ ## Event shape
93
36
 
94
- `sdk.cleanup` events are part of the `RunEvent` union, but they are
95
- emitted by `handle.cleanup()` after `handle.wait()` has already resolved.
96
- By that time the event bus has been closed; subscribers attached during
97
- the run do **not** see them. Inspect cleanup outcomes via the
98
- `CleanupResult.operations` array returned by `cleanup()` instead.
37
+ Events are typed as the discriminated `RunEvent` union — agent messages, tool uses, tool results, session status transitions, sdk lifecycle events, span events. The dashboard records the raw provider payload **after** secret redaction and structural sanitization, so the bytes you see in `event.payload` never contain the Anthropic key, MCP credentials, or proxy bearer that were supplied to `submitRun`.
99
38
 
100
39
  ## Typed helpers
101
40
 
102
- `packages/sdk/src/providers/known-events.ts` exports conservative type
103
- guards that narrow `ProviderEvent.type` to documented Claude event strings.
104
- They do **not** assert payload field shapes — the raw provider payload
105
- stays `unknown` until callers parse it themselves.
41
+ The package exports conservative type guards that narrow events to documented Claude event types:
106
42
 
107
43
  ```ts
108
44
  import {
@@ -125,5 +61,6 @@ import {
125
61
  } from "antpath";
126
62
  ```
127
63
 
128
- The official list of event types is maintained at
129
- [`platform.claude.com/docs/en/managed-agents/events-and-streaming`](https://platform.claude.com/docs/en/managed-agents/events-and-streaming).
64
+ They narrow only the discriminant payload field shapes stay `unknown` until callers parse them.
65
+
66
+ The official list of event types is maintained at [`platform.claude.com/docs/en/managed-agents/events-and-streaming`](https://platform.claude.com/docs/en/managed-agents/events-and-streaming).
package/docs/outputs.md CHANGED
@@ -4,13 +4,24 @@ title: Outputs
4
4
 
5
5
  # Outputs
6
6
 
7
- `downloadOutputs()` downloads all session-scoped provider files by default.
7
+ Every run captures provider session-scoped files into private Supabase Storage. List and download them through whichever surface is convenient.
8
8
 
9
- `/antpath/outputs` is a recommended convention, not a provider default. Templates may instruct agents to write important artifacts there, but MVP output download still uses session-scoped files.
9
+ ```ts
10
+ const outputs = await ref.outputs(); // OutputSummary[]
11
+ const { url } = await client.createOutputLink(ref.runId, outputs[0].id);
12
+ ```
13
+
14
+ ```bash
15
+ antpath outputs list <run-id> --api-token … --workspace … --dashboard-url …
16
+ antpath outputs download <run-id> <output-id> --out ./dir \
17
+ --api-token … --workspace … --dashboard-url …
18
+ ```
19
+
20
+ `/antpath/outputs` is a recommended convention, not a provider default. Templates may instruct agents to write important artifacts there, but every session-scoped provider file is captured unconditionally (bounded only by the workspace storage cap; skipped files are recorded as `output_capture_failures`).
10
21
 
11
22
  Safety rules:
12
23
 
13
24
  - filenames are sanitized;
14
25
  - downloads stay within the requested local directory;
15
- - max file count and max total bytes are enforced;
16
- - manifests contain provider file IDs, local paths, names, and sizes only.
26
+ - signed download links are short-lived;
27
+ - manifests contain provider file IDs, local paths, names, and sizes only — never file bytes.
@@ -4,10 +4,44 @@ title: antpath quickstart
4
4
 
5
5
  # Quickstart
6
6
 
7
- 1. Put `ANTHROPIC_API_KEY` in `.env.local`.
8
- 2. Define a secret-free Template in TypeScript.
9
- 3. Create `AntpathClient`.
10
- 4. Run the Template.
11
- 5. Wait, download files, then call `cleanup()`.
7
+ 1. Get an antpath SDK API token (`ant_…`).
8
+ 2. Define a secret-free Template in TypeScript (or JSON / a `.mjs` default export).
9
+ 3. Create `AntpathClient` — the workspace is derived server-side from the token.
10
+ 4. Submit the run with an inline `secrets` bundle. Wait for terminal status. Fetch outputs.
12
11
 
13
- See `README.md` for a minimal example.
12
+ ```ts
13
+ import { AntpathClient, defineTemplate, string } from "antpath";
14
+
15
+ const client = new AntpathClient({
16
+ apiToken: process.env.ANTPATH_API_TOKEN!
17
+ // baseUrl defaults to https://antpath.ai — set it for self-hosted deployments.
18
+ });
19
+
20
+ const template = defineTemplate({
21
+ name: "hello",
22
+ model: "claude-haiku-4-5",
23
+ messages: ["Write a short answer about {{topic}}."],
24
+ variables: { topic: string() }
25
+ });
26
+
27
+ const ref = await client.submitRun(template, {
28
+ variables: { topic: "agent-first SDK design" },
29
+ secrets: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } }
30
+ });
31
+
32
+ const run = await ref.wait();
33
+ console.log(run.status);
34
+ console.log(await ref.outputs());
35
+ ```
36
+
37
+ Or from the shell:
38
+
39
+ ```bash
40
+ antpath run ./template.json \
41
+ --api-token "$ANTPATH_API_TOKEN" \
42
+ --anthropic-api-key "$ANTHROPIC_API_KEY" \
43
+ --var topic="agent-first SDK design" \
44
+ --follow
45
+ ```
46
+
47
+ Both surfaces hit the same dashboard BFF and operate on the same durable run records — pick whichever is most convenient.
package/docs/release.md CHANGED
@@ -4,19 +4,64 @@ title: Release
4
4
 
5
5
  # Release
6
6
 
7
- CI runs on pull requests and pushes to `main`.
7
+ Releasing is **atomic** and **driven by `packages/sdk/package.json#version`**: bump the SDK version on `main` and the publish pipeline carries that exact version through npm → git tag → GitHub Release in one job. Any push to `main` that does not bump the version is a publish no-op.
8
8
 
9
- Publishing runs when a GitHub release is published, or when the publish workflow is manually dispatched.
9
+ ## How to ship a release
10
10
 
11
- Repository setup required:
11
+ 1. On a branch, bump `packages/sdk/package.json#version` to the next semver. Land any companion code/doc changes in the same PR.
12
+ 2. Merge into `main` (or push directly if you have the right). The pre-push hook (see [Local guard rails](#local-guard-rails)) refuses the push if the local version still matches what's on npm or has already been git-tagged.
13
+ 3. CI (`.github/workflows/ci.yml`) runs the `version-gate` job on every PR and direct push to `main`. It diffs against the base ref using [`scripts/check-version-drift.mjs --strict`](../../scripts/check-version-drift.mjs) and fails fast if anything under `packages/{sdk,cli,shared}/src/` or the listed exact paths changed without a fresh version. **`--strict` treats unreachable npm as a hard failure** so we never publish on top of an existing version.
14
+ 4. After merge, the `Publish package` workflow (`.github/workflows/publish.yml`) is triggered automatically on push to `main` and decides whether to ship.
12
15
 
13
- 1. Create or reserve the `antpath` package on npm.
14
- 2. Add a Trusted Publisher for this GitHub repository.
15
- 3. Set **Organization or user** to `weilueluo`.
16
- 4. Set **Repository** to `antpath`.
17
- 5. Set **Workflow filename** to `publish.yml`.
18
- 6. Leave **Environment name** empty unless the workflow uses a matching GitHub Actions environment.
19
- 7. Update `packages/sdk/package.json` version before publishing a release.
20
- 8. Publish a GitHub release for that version.
16
+ You don't tag locally and you don't open a GitHub Release manually — the workflow does both. If the workflow ends red after a successful `npm publish`, the npm version is the source of truth and a human can tag/release retroactively.
21
17
 
22
- The publish workflow uses GitHub OIDC through `id-token: write`; it does not require an npm token secret. It runs type-checks, tests, build, then publishes the `antpath` SDK workspace with provenance.
18
+ ## Publish pipeline
19
+
20
+ The workflow has three jobs, in this order:
21
+
22
+ 1. **`decide`** — compares the local `packages/sdk/package.json#version` with `npm view antpath@latest version`.
23
+ - If they match → output `proceed=false` and the rest of the pipeline no-ops. Documentation-only commits, refactors that ride along with a previous version, and any other non-publishable change pass through cleanly.
24
+ - If they differ → `proceed=true`, with the local version flowing forward as the canonical `v<version>` for tagging and release notes.
25
+ 2. **`publish`** (gated on `proceed=true`) — single linear job:
26
+ - `pnpm install --frozen-lockfile`, `pnpm lint`, `pnpm test`, `pnpm build`.
27
+ - `pnpm --filter antpath pack` into `$RUNNER_TEMP`.
28
+ - **Pre-publish user-tests gate**: runs `apps/user-tests` `user-test:offline` against the packed tarball. A broken artifact (missing `bin`, broken shebang, leaked workspace dep, ESM-only contract violation, …) never reaches npm.
29
+ - **Final freshness check**: `npm view antpath@${VERSION} version` — guards the rare race where someone else publishes the same version between `decide` and here.
30
+ - `pnpm publish --provenance --no-git-checks` from `packages/sdk`. Auth is GitHub OIDC via `id-token: write` plus npm Trusted Publishers — there is no `NPM_TOKEN` secret.
31
+ - `git tag -a v${VERSION}` signed as the canonical commit identity, then `git push origin v${VERSION}`.
32
+ - `gh release create v${VERSION} --generate-notes`.
33
+ 3. **`user-tests-post-publish`** (matrix `ubuntu-latest, windows-latest`) — waits for registry visibility with `scripts/wait-for-npm.mjs antpath <version>` (catches the "metadata says yes but CDN tarball 404s" case), then runs `user-test:offline` against the published version on both runners.
34
+
35
+ Atomicity boundary: **publish + tag + GitHub Release happen in the same job**. Until that job goes green, the release is not done — even if `npm publish` already succeeded. Post-publish user-tests are a follow-on signal, not part of the atomic act.
36
+
37
+ ## What ships in the tarball
38
+
39
+ The published tarball is **self-contained**. It declares **zero `@antpath/*` runtime dependencies** and is installable from a clean `npm install antpath` with no workspace access:
40
+
41
+ - `@antpath/shared` lives in `packages/sdk/package.json#devDependencies` only. At build time, [`packages/sdk/scripts/inline-shared.mjs`](../scripts/inline-shared.mjs) copies `packages/shared/dist/**` (minus the test-only `testing/` directory and sourcemaps) into `packages/sdk/dist/_shared/` and rewrites `from "@antpath/shared"` to `from "./_shared/index.js"` across the SDK dist tree. A sanity check at the end of that script refuses to finish if any bare `@antpath/shared` specifier survives.
42
+ - `@antpath/cli` is bundled at build time by [`packages/sdk/scripts/bundle-cli.mjs`](../scripts/bundle-cli.mjs) into a single `dist/cli.mjs`, which is the `bin: antpath` entry in `packages/sdk/package.json`.
43
+ - This invariant is mechanically enforced by `apps/user-tests/test/offline/install.test.ts` ("declares no @antpath/* runtime dependencies") — the pre-publish gate fails before npm if any workspace dep leaks back into `dependencies`/`peerDependencies`/`optionalDependencies`.
44
+
45
+ ## Local guard rails
46
+
47
+ Every contributor who pushes is expected to install the tracked pre-push hook from the repo root once:
48
+
49
+ ```text
50
+ pnpm hooks:install
51
+ ```
52
+
53
+ The hook runs lint, tests, build, an SDK pack dry-run, and `check-version-drift.mjs` (advisory mode — unreachable npm is a warning so offline development still works). It catches "I bumped a runtime file but forgot to bump the version" or "the new version is already on npm" before the push leaves the laptop.
54
+
55
+ ## Repository setup (one-time)
56
+
57
+ 1. Reserve `antpath` on npm.
58
+ 2. Add a Trusted Publisher for this repository (`npmjs.com` → *Settings* → *Publishing access*):
59
+ - **Organization or user**: `weilueluo`
60
+ - **Repository**: `antpath`
61
+ - **Workflow filename**: `publish.yml`
62
+ - **Environment name**: leave empty.
63
+ 3. No `NPM_TOKEN` secret is required — OIDC handles auth.
64
+
65
+ ## Rollback
66
+
67
+ There is no "unpublish" path: npm prevents reuse of a published version, and a bad release is fixed by publishing a higher version. If the atomic publish job dies between `npm publish` and `gh release create`, retag manually (`git tag -a v<version>`, push, `gh release create`); npm is already truthful.
package/docs/skills.md CHANGED
@@ -15,4 +15,4 @@ Local directories are packaged as zip files and mounted under `/antpath/skills/`
15
15
 
16
16
  Inline skills are uploaded as markdown files and mounted under `/antpath/skills/` unless overridden.
17
17
 
18
- The platform also mounts the `antpath` CLI at `/antpath/antpath` and a per-run manifest at `/antpath/index.json` on **every** run. Skills can invoke the managed HTTP proxy via `node /antpath/antpath proxy …` — see `credentials.md` for the policy/auth model.
18
+ The platform also mounts the `antpath` CLI at `/antpath/antpath` and a per-run manifest at `/antpath/index.json` on **every** run. Skills can invoke the managed HTTP proxy via `/antpath/antpath proxy …` — see `credentials.md` for the policy/auth model.
package/docs/templates.md CHANGED
@@ -21,4 +21,4 @@ Allowed Template content:
21
21
 
22
22
  Variables use `{{name}}` and are resolved before provider calls. Use `\{{name}}` for a literal placeholder.
23
23
 
24
- Secrets must not appear in Templates. Pass credentials through `run({ credentials })`.
24
+ Secrets must not appear in Templates. Pass credentials through `submitRun(template, { secrets, proxyEndpointAuth })` (SDK) or the equivalent host-mode flags (`--anthropic-api-key`, `--mcp-secret`, `--proxy-auth`).
package/docs/testing.md CHANGED
@@ -6,21 +6,24 @@ title: Testing
6
6
 
7
7
  antpath uses test-first development.
8
8
 
9
- Commands:
9
+ Workspace-wide commands:
10
10
 
11
11
  ```text
12
- npm run test:unit
13
- npm run test:unit:recorded
14
- npm run test:e2e:live
12
+ pnpm test # unit, all packages, deterministic
13
+ pnpm test:unit:recorded # unit + replayed provider fixtures
14
+ pnpm test:integration # live external systems (Supabase + dashboard) — no skip flags
15
+ pnpm test:e2e:live # full top-to-bottom flows against live services
16
+ pnpm test:user # offline assertions on the published antpath package
17
+ pnpm test:user:live # live assertions on the published antpath package
15
18
  ```
16
19
 
17
- Unit tests are deterministic and may use fakes or sanitized recorded snapshots. Live tests run when `npm run test:e2e:live` is invoked with `.env.local` containing `ANTHROPIC_API_KEY`.
20
+ Unit tests are deterministic and may use fakes or sanitized recorded snapshots. Integration tests run live external systems without any skip flag; if credentials are missing they fail loudly. Live e2e and user-live tests require `.env.local` (or runner-provided env) to include `ANTHROPIC_API_KEY` and any other live target vars; see `references/environment-variables.md`.
18
21
 
19
- Recorded API fixtures are created with:
22
+ Recorded provider fixtures are produced with:
20
23
 
21
24
  ```text
22
- npm run fixtures:record:anthropic
23
- npm run fixtures:sanitize
25
+ pnpm --filter antpath run fixtures:record:anthropic
26
+ pnpm --filter antpath run fixtures:sanitize
24
27
  ```
25
28
 
26
29
  Raw fixtures and secret-shaped fixture files are ignored.
@@ -1,7 +1,7 @@
1
1
  import { AntpathClient, defineTemplate, requiredStaticBearer } from "antpath";
2
2
 
3
3
  const client = new AntpathClient({
4
- anthropicApiKey: process.env.ANTHROPIC_API_KEY
4
+ apiToken: process.env.ANTPATH_API_TOKEN!
5
5
  });
6
6
 
7
7
  const template = defineTemplate({
@@ -17,14 +17,17 @@ const template = defineTemplate({
17
17
  }
18
18
  });
19
19
 
20
- const handle = await client.run(template, {
21
- credentials: {
22
- example: {
23
- type: "static_bearer",
24
- token: process.env.EXAMPLE_MCP_TOKEN ?? ""
25
- }
20
+ const ref = await client.submitRun(template, {
21
+ secrets: {
22
+ anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! },
23
+ mcpServers: [
24
+ {
25
+ name: "example",
26
+ url: "https://mcp.example.com/mcp",
27
+ headers: { Authorization: `Bearer ${process.env.EXAMPLE_MCP_TOKEN ?? ""}` }
28
+ }
29
+ ]
26
30
  }
27
31
  });
28
32
 
29
- await handle.wait();
30
- await handle.cleanup();
33
+ await ref.wait();
@@ -1,7 +1,7 @@
1
1
  import { AntpathClient, defineTemplate, string } from "antpath";
2
2
 
3
3
  const client = new AntpathClient({
4
- anthropicApiKey: process.env.ANTHROPIC_API_KEY
4
+ apiToken: process.env.ANTPATH_API_TOKEN!
5
5
  });
6
6
 
7
7
  const template = defineTemplate({
@@ -14,10 +14,10 @@ const template = defineTemplate({
14
14
  }
15
15
  });
16
16
 
17
- const handle = await client.run(template, {
18
- variables: { topic: "test-first SDK design" }
17
+ const ref = await client.submitRun(template, {
18
+ variables: { topic: "agent-first SDK design" },
19
+ secrets: { anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! } }
19
20
  });
20
21
 
21
- const result = await handle.wait();
22
- console.log(result.status);
23
- await handle.cleanup();
22
+ const run = await ref.wait();
23
+ console.log(run.status);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antpath",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "TypeScript SDK for running autonomous Claude Managed Agents sessions.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,18 +22,16 @@
22
22
  "dist",
23
23
  "README.md",
24
24
  "docs",
25
- "examples",
26
- "references"
25
+ "examples"
27
26
  ],
28
- "dependencies": {
29
- "eventsource-parser": "3.0.6",
30
- "fflate": "0.8.2"
27
+ "devDependencies": {
28
+ "@antpath/shared": "0.1.0"
31
29
  },
32
30
  "engines": {
33
31
  "node": ">=20"
34
32
  },
35
33
  "scripts": {
36
- "build": "pnpm --filter @antpath/cli run build && tsc -p tsconfig.build.json && node ./scripts/bundle-cli.mjs",
34
+ "build": "pnpm --filter @antpath/cli run build && pnpm --filter @antpath/shared run build && tsc -p tsconfig.build.json && node ./scripts/bundle-cli.mjs && node ./scripts/inline-shared.mjs",
37
35
  "lint": "tsc --noEmit",
38
36
  "test": "vitest run test/unit",
39
37
  "test:unit": "vitest run test/unit",
@@ -1,3 +0,0 @@
1
- import type { CredentialInput } from "./types.js";
2
- import type { ResolvedTemplate } from "./template/compiler.js";
3
- export declare function validateCredentials(template: ResolvedTemplate, credentials?: Record<string, CredentialInput>): void;
@@ -1,56 +0,0 @@
1
- import { CredentialValidationError } from "./errors.js";
2
- export function validateCredentials(template, credentials = {}) {
3
- for (const [key, requirement] of Object.entries(template.credentialRequirements)) {
4
- const credential = credentials[key];
5
- if (credential === undefined) {
6
- throw new CredentialValidationError(`Missing credential for MCP server '${key}'`);
7
- }
8
- if (!isRecord(credential)) {
9
- throw new CredentialValidationError(`Credential for MCP server '${key}' must be an object`);
10
- }
11
- if (credential.type !== requirement.type) {
12
- throw new CredentialValidationError(`Credential for MCP server '${key}' must be '${requirement.type}'`);
13
- }
14
- validateCredentialValue(key, credential);
15
- }
16
- for (const key of Object.keys(credentials)) {
17
- if (!template.credentialRequirements[key]) {
18
- throw new CredentialValidationError(`Credential provided for unknown MCP server '${key}'`);
19
- }
20
- }
21
- }
22
- function validateCredentialValue(key, credential) {
23
- if (!isRecord(credential)) {
24
- throw new CredentialValidationError(`Credential for MCP server '${key}' must be an object`);
25
- }
26
- if (credential.type === "static_bearer") {
27
- assertAllowedFields(key, credential, ["type", "token"]);
28
- if (typeof credential.token !== "string" || credential.token.length === 0) {
29
- throw new CredentialValidationError(`Static bearer credential for '${key}' requires token`);
30
- }
31
- return;
32
- }
33
- if (credential.type === "oauth_access_token") {
34
- assertAllowedFields(key, credential, ["type", "accessToken", "expiresAt"]);
35
- if (typeof credential.accessToken !== "string" || credential.accessToken.length === 0) {
36
- throw new CredentialValidationError(`OAuth credential for '${key}' requires accessToken`);
37
- }
38
- if (credential.expiresAt !== undefined && (typeof credential.expiresAt !== "string" || credential.expiresAt.length === 0)) {
39
- throw new CredentialValidationError(`OAuth credential for '${key}' has invalid expiresAt`);
40
- }
41
- return;
42
- }
43
- throw new CredentialValidationError(`Credential for MCP server '${key}' has unsupported type`);
44
- }
45
- function assertAllowedFields(key, credential, allowed) {
46
- const allowedSet = new Set(allowed);
47
- for (const field of Object.keys(credential)) {
48
- if (!allowedSet.has(field)) {
49
- throw new CredentialValidationError(`Credential for MCP server '${key}' contains unsupported field '${field}'`);
50
- }
51
- }
52
- }
53
- function isRecord(input) {
54
- return typeof input === "object" && input !== null && !Array.isArray(input);
55
- }
56
- //# sourceMappingURL=credentials.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AASnD,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAAmB;IACvB,OAAO,CAAW;IAE3B,YAAY,IAAsB,EAAE,OAAe,EAAE,OAAiB;QACpE,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC5E,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,YAAY;IACvD,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,kBAAkB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;CACF;AAED,MAAM,OAAO,yBAA0B,SAAQ,YAAY;IACzD,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,oBAAoB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,YAAY;IACpC,MAAM,CAAqB;IAEpC,YAAY,OAAe,EAAE,UAAkD,EAAE;QAC/E,KAAK,CAAC,gBAAgB,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,YAAY;IAC7C,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,iBAAiB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,YAAY;IAC5C,YAAY,OAAe,EAAE,OAAiB;QAC5C,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -1,3 +0,0 @@
1
- import type { DownloadOutputsOptions, DownloadOutputsResult } from "../types.js";
2
- import type { ManagedAgentProvider } from "../providers/types.js";
3
- export declare function downloadOutputs(provider: ManagedAgentProvider, sessionId: string, options: DownloadOutputsOptions): Promise<DownloadOutputsResult>;
@@ -1,43 +0,0 @@
1
- import { writeFileSafe } from "../utils/paths.js";
2
- const DEFAULT_MAX_FILES = 100;
3
- const DEFAULT_MAX_BYTES = 250 * 1024 * 1024;
4
- export async function downloadOutputs(provider, sessionId, options) {
5
- const files = filterFiles(await provider.listFiles(sessionId), options);
6
- if (files.length > (options.maxFiles ?? DEFAULT_MAX_FILES)) {
7
- throw new Error(`Refusing to download ${files.length} files; maxFiles exceeded`);
8
- }
9
- const totalBytes = files.reduce((sum, file) => sum + (file.sizeBytes ?? 0), 0);
10
- if (totalBytes > (options.maxTotalBytes ?? DEFAULT_MAX_BYTES)) {
11
- throw new Error(`Refusing to download ${totalBytes} bytes; maxTotalBytes exceeded`);
12
- }
13
- const manifest = { directory: options.directory, files: [] };
14
- let downloadedBytes = 0;
15
- for (const file of files) {
16
- const content = await provider.downloadFile(file.id);
17
- if (file.sizeBytes !== undefined && content.byteLength !== file.sizeBytes) {
18
- throw new Error(`Downloaded byte size for ${file.id} did not match provider metadata`);
19
- }
20
- downloadedBytes += content.byteLength;
21
- if (downloadedBytes > (options.maxTotalBytes ?? DEFAULT_MAX_BYTES)) {
22
- throw new Error(`Downloaded outputs exceeded maxTotalBytes`);
23
- }
24
- const localPath = await writeFileSafe(options.directory, file.filename, content);
25
- const entry = {
26
- providerFileId: file.id,
27
- filename: file.filename,
28
- localPath
29
- };
30
- manifest.files.push(file.sizeBytes === undefined ? entry : { ...entry, sizeBytes: file.sizeBytes });
31
- }
32
- return { manifest };
33
- }
34
- function filterFiles(files, options) {
35
- if (!options.include) {
36
- return files;
37
- }
38
- if (options.include instanceof RegExp) {
39
- return files.filter((file) => options.include instanceof RegExp && options.include.test(file.filename));
40
- }
41
- return files.filter(options.include);
42
- }
43
- //# sourceMappingURL=downloader.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"downloader.js","sourceRoot":"","sources":["../../src/files/downloader.ts"],"names":[],"mappings":"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"}