foldrun 0.8.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/providers.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Providers, by name
2
2
 
3
+ ## Your account's own model key
4
+
5
+ The simplest way to bring a key: **Settings → Model provider**, or
6
+ `foldrun account model set <provider> --key <api key>`, or
7
+ `PUT /api/account/model`. Pick a name from the table below (or `custom`
8
+ with a base URL and a format), paste an **API key**, and every step in
9
+ every workspace runs on it. No `provider:` block is needed; one written in
10
+ an agent, a workspace or the account's AGENTS.md still wins over it.
11
+
12
+ The key is stored in the account's vault, encrypted under the account's own
13
+ key, as `FOLDRUN_MODEL_PROVIDER`, `FOLDRUN_MODEL_API_KEY` and, for a custom
14
+ endpoint, `FOLDRUN_MODEL_BASE_URL` and `FOLDRUN_MODEL_FORMAT`. The dashboard
15
+ and the API show only its last four characters.
16
+
17
+ **On a hosted platform every account brings its own key.** The platform's
18
+ own model credential is for the operator's accounts
19
+ (`FOLDRUN_PLATFORM_KEY_ACCOUNTS`); a step in any other account with no key
20
+ of its own is refused before it starts — "no model key: …" on the run — and
21
+ an eval's judge or "draft with AI" says the same. A **Claude login token**
22
+ (`sk-ant-oat…`, from `claude setup-token`) is refused as a customer's key:
23
+ Anthropic's terms do not let a third-party product run its customers on
24
+ claude.ai logins. Use an API key from the provider.
25
+
26
+ Tokens on your own key are billed by your provider, not by the platform
27
+ ([budgets and billing](budgets-and-billing.md)).
28
+
3
29
  What `provider: { name: … }` resolves to. Mirrors `foldrun-core/src/providers.ts`,
4
30
  checked against each provider's own documentation on 2026-09-02 and again on
5
31
  2026-09-06; the table below is what the runtime believes, and
@@ -178,6 +204,8 @@ what would be checked; `POST` forces one, for the minute after rotating a
178
204
  key. From the terminal, `foldrun account providers` prints the same table
179
205
  (✓, ✗ with the verdict, or · for never checked) and `--check` forces one;
180
206
  a dead key is a non-zero exit, so a deploy script can refuse to continue.
207
+ In the dashboard, Settings → Model provider shows the same check per
208
+ provider, with **Check now** (editor and above, since it spends a request).
181
209
 
182
210
  ## When a provider says no, the run says why
183
211
 
package/docs/runs.md CHANGED
@@ -87,7 +87,11 @@ run until a person decides. Three doors open it, and the trace says which:
87
87
  - **the emailed link** — the notification carries approve and reject links
88
88
  when the install has a public URL;
89
89
  - **an external event** — a `wait: event` step is released by a POST to the
90
- run's event URL, and what was posted reaches the next step.
90
+ run's event URL, and what was posted reaches the next step. A person can
91
+ release it the same way from the run page (or `approve` with a `payload`):
92
+ the payload reaches the step just the same, and the trace names them, not
93
+ "an external event". The approvers and self-approval rules below are for
94
+ gates that ask a person; a `wait: event` release asks for `run:start`.
91
95
 
92
96
  The answer typed at an `ask:` gate reaches the next step's prompt, so "GO,
93
97
  but skip the third one" is an instruction the publisher reads.
@@ -155,7 +159,8 @@ flow, a time window, or an explicit list of ids. It is the tool for the
155
159
  morning when one broken thing failed seventy runs. A call naming no filter is
156
160
  refused rather than treated as everything, `dryRun: true` shows what would be
157
161
  touched, and each run is its own outcome so one that cannot be stopped does
158
- not abort the rest.
162
+ not abort the rest. On the runs pages, tick runs and choose **Stop** or
163
+ **Rerun**: the bar makes this call, once per workspace in the selection.
159
164
 
160
165
  **Re-run from a group** (`from: N`) starts a new run at group N with the
161
166
  earlier groups recorded as skipped, not invented — the step reads what earlier
package/docs/security.md CHANGED
@@ -134,6 +134,20 @@ name only — for the owner and admins to read or export. Support can view an
134
134
  account only [read-only, for thirty minutes, with a reason the customer
135
135
  reads](team-and-access#support-access).
136
136
 
137
+ ## Your terminal
138
+
139
+ The CLI prints what a platform sends it — agents' replies, logs, files,
140
+ release notes, errors — and a terminal obeys escape sequences hidden in
141
+ text: it can move the cursor and overwrite a line, clear the screen, retitle
142
+ the window, write your clipboard, or show a link that goes somewhere else.
143
+ So nothing the CLI prints carries them. The only ones that get through are
144
+ the CLI's own colours, and every other control character but newline and
145
+ tab is removed, on a terminal and through a pipe alike. Content you asked for
146
+ byte for byte — `foldrun source cat`, `storage cat`, `library cat`, a
147
+ download or CSV to stdout, `api spec` — is exact when it goes into a file or
148
+ another program, and filtered like everything else when it lands on a
149
+ screen. `--json` is exact too: JSON writes control characters as escapes.
150
+
137
151
  ## What is still yours to think about
138
152
 
139
153
  - A model reading a web page reads whatever is on it. Give the agent the
package/docs/tools.md CHANGED
@@ -54,7 +54,7 @@ headers:
54
54
 
55
55
  | field | |
56
56
  |---|---|
57
- | `base` | the URL every call is relative to |
57
+ | `base` | the URL every call is relative to. `${FOLDRUN_API_URL}` is this install's own API (`base: ${FOLDRUN_API_URL}`), so a tool that reads the account's runs never names a host; a base naming it on an install that has no public address is reported unavailable |
58
58
  | `methods` | the verb allowlist — a tool that declares none is read-only |
59
59
  | `headers` | `${SECRET}` placeholders, resolved host-side at call time |
60
60
  | `query` | query parameters appended to every call — for an API that carries its key in the query string; a `${SECRET}` is resolved host-side |
@@ -63,6 +63,13 @@ headers:
63
63
  | `openapi` | a URL or file; turns one generic tool into typed ones, one per operation |
64
64
  | `operations` | only these operations, by `operationId` or `METHOD /path`; the generic tool is withheld. It fails closed: if the document does not load or none of them resolve, the API has no tools that run, never the generic one. Keep an allowlisted document in the workspace, so a vendor renaming an operation cannot empty it |
65
65
 
66
+ **The body is the manual.** Everything under a `tool.md`'s frontmatter goes
67
+ to the model with the tool, after `description:` — how to call it, what it
68
+ refuses, what its output means, examples of a call (up to 6,000 characters;
69
+ a longer body is cut there and says so). A single-file tool's fenced program
70
+ is code, not guidance, and stays out. This holds for script and HTTP tools
71
+ alike, workspace or library.
72
+
66
73
  The model never sees a credential — the host substitutes it as the request
67
74
  goes out. The method allowlist protects against the agent; the key's own scopes
68
75
  protect against everyone else, so pair a read-only tool with a read-only key.
@@ -221,6 +228,14 @@ the agent — which is already the model — to answer from; `extract` by
221
228
  `schema=` or `prompt=`, which needs a model to read the page, needs a
222
229
  provider.
223
230
 
231
+ Granting `web` grants **Read** with it: several actions write what they
232
+ found to a file and say so (a screenshot, a crawl, a page saved whole), and
233
+ an agent told to read a file it could not open was refused. `disallowedTools:
234
+ [Read]` takes it away again. A provider that times out or answers busy (429,
235
+ 5xx) is asked twice more, about 2 s and 6 s apart, before the action reports
236
+ it unreachable — a fan-out of many steps asking one provider at once is the
237
+ usual cause.
238
+
224
239
  ```yaml
225
240
  tools: [web]
226
241
  web:
@@ -1393,11 +1408,36 @@ own defaults.
1393
1408
  next one: the cookies and localStorage the call ends with are written to
1394
1409
  `workspace/state/browser/<name>.json` and loaded before any later call that
1395
1410
  names it, in this run or a run next month. It is the agent's own login,
1396
- made with `actions` from credentials it can see — `state` refuses
1397
- `cookies=` and `storage=` and a session those seeded, because `state/` is a
1398
- workspace file every later step can read, and a vault secret written there
1399
- would stop being one. `mode=diff` keeps its baselines in the same place,
1400
- under `state/browser/diff/`, for the same reason: they must outlive the run.
1411
+ made with `actions` from credentials it can see — or a login a cookie secret
1412
+ seeded, when `state_key` encrypts it (below). Without a key `state` refuses
1413
+ `cookies=` and a session they seeded, and it always refuses `storage=`,
1414
+ because `state/` is a workspace file every later step can read, and a vault
1415
+ secret written there in the clear would stop being one. `mode=diff` keeps its
1416
+ baselines in the same place, under `state/browser/diff/`, for the same
1417
+ reason: they must outlive the run.
1418
+
1419
+ **A cookie secret that seeds a saved login.** Some sites — Google above all —
1420
+ rotate their sign-in cookies while they are used, so a copied `Cookie` line in
1421
+ the vault goes stale within the hour and every later run meets a sign-in
1422
+ page. Put `state:` and `state_key:` beside `cookies:` in the block:
1423
+
1424
+ ```yaml
1425
+ web:
1426
+ browse:
1427
+ cookies: YOUTUBE_COOKIES
1428
+ cookie_domain: .youtube.com
1429
+ state: youtube
1430
+ state_key: BROWSER_STATE_KEY
1431
+ secrets: [YOUTUBE_COOKIES, BROWSER_STATE_KEY]
1432
+ ```
1433
+
1434
+ The first call seeds from the secret; every call saves the session it ends
1435
+ with, encrypted, and the next loads that rather than the vault's copy. The
1436
+ state file records which secret seeded it and a keyed fingerprint of its
1437
+ value, so pasting fresh cookies into the secret seeds it again. Script in the
1438
+ page (`js`, `eval`, a `get` of storage) stays refused on such a login, as it
1439
+ is on the secret itself. `check` refuses `state` beside `cookies` without
1440
+ `state_key`.
1401
1441
 
1402
1442
  ### Where the browser runs
1403
1443
 
package/docs/versions.md CHANGED
@@ -22,8 +22,70 @@ under its own name — `v2026.09.30.2` deployed again is still `v2026.09.30.2`.
22
22
  Behind each name are the commits of the parts that make up the platform —
23
23
  `core` (the runtime), `platform` (queue, worker, storage, billing), `web` (the
24
24
  dashboard and the API), `docs` and `infra` — recorded when it was deployed.
25
- The `foldrun` CLI and `@foldrun/core` on npm are packages a person publishes,
26
- and keep ordinary semver (`0.6.0`).
25
+ The `foldrun` CLI and `@foldrun/core` on npm are packages, and follow
26
+ semantic versioning instead — see [the packages](#the-packages).
27
+
28
+ ## The packages
29
+
30
+ `foldrun` (the CLI) and `@foldrun/core` follow
31
+ [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) from 1.0.0:
32
+
33
+ | | Means | Example |
34
+ |---|---|---|
35
+ | Patch | a bug fix, nothing new — safe to update | 1.4.2 → 1.4.3 |
36
+ | Minor | a new feature; everything that worked still works | 1.4.2 → 1.5.0 |
37
+ | Major | a breaking change: something old stops working or works differently | 1.4.2 → 2.0.0 |
38
+
39
+ What the promise covers is the public API. For the CLI that is every command
40
+ and flag `foldrun --help` lists, and the Node.js version it needs. For
41
+ `@foldrun/core` it is `@foldrun/core` itself and the subpaths in its
42
+ `package.json` under `foldrun.publicApi`. Other `@foldrun/core/*` modules can
43
+ be imported, but they are internal and may change in any release.
44
+
45
+ The release decides the number, not a person's memory. It compares the
46
+ public API at the last release with the new one. Anything gone, or a
47
+ function that now needs more arguments, makes it a major. Anything new makes
48
+ it at least a minor. A change in behaviour that the API cannot show is marked
49
+ in the commit, and that makes it a major too. A major's release notes open
50
+ with **Breaking changes**, saying what stops working.
51
+
52
+ Nothing is removed without warning. A command, flag or export is first marked
53
+ deprecated, in a minor, and still works. It is taken out in a later major.
54
+ Both are in the release notes.
55
+
56
+ Pre-releases, like `1.5.0-rc.1`, are published under npm's `next` tag. So
57
+ `npm install -g foldrun` gets the last stable release, and
58
+ `npm install -g foldrun@next` gets the pre-release. A stable CLI never
59
+ suggests updating to a pre-release.
60
+
61
+ `npm install -g foldrun@^1` stays within 1.x, so nothing that works breaks
62
+ under it. Every release is listed in each package's `CHANGELOG.md` and on
63
+ GitHub Releases.
64
+
65
+ ## Rollback and the database
66
+
67
+ A rollback redeploys older code, but not an older database: the schema stays
68
+ where the newest release left it, because migrations only run forwards. So
69
+ every migration has to work with the code of the release before it — the
70
+ expand/contract rule. A release only expands: a new table, a nullable column,
71
+ a column with a `DEFAULT`, an index. Taking something away that released code
72
+ still uses — dropping or renaming a table or column, changing a column's
73
+ type, making a column `NOT NULL` with no default, dropping a constraint or a
74
+ default, `TRUNCATE`, a `DELETE` with no `WHERE` — is the contract half, and
75
+ ships a release later, once no deployed version reads it. A migration that
76
+ has been released is never edited; the next change is a new file.
77
+
78
+ The platform enforces this. `scripts/migration-guard.mjs` in
79
+ `foldrun-platform` reads the migrations added since the deployed version (in
80
+ CI, since the commit a push or pull request started from) and refuses those
81
+ statements, in CI and in the pre-push hook. A deliberate contract step says so
82
+ on the line above the statement, with a reason, and is reported rather than
83
+ refused:
84
+
85
+ ```sql
86
+ -- migration-guard: contract api_keys.label unread since v2026.09.30.1
87
+ ALTER TABLE "api_keys" DROP COLUMN "label";
88
+ ```
27
89
 
28
90
  ## Where to see it
29
91
 
@@ -54,6 +54,85 @@ pulled, only edited in Settings.
54
54
  A single folder with `agents/` and `flows/` at its root is still a workspace
55
55
  and still works everywhere; `foldrun init --flat` makes one.
56
56
 
57
+ ## A new workspace starts blank
58
+
59
+ **Create workspace** on the dashboard, `POST /api/workspaces` with
60
+ `template: true`, and `foldrun new <name>` all make a workspace with nothing in
61
+ it to delete: an `AGENTS.md` (plus, on a laptop, the `.gitignore` that keeps
62
+ its secret key out of git and a `CLAUDE.md` for your coding tool). No example
63
+ agents, no flow. `foldrun new <name> --starter` and `starter: true` still make
64
+ the example researcher, writer and `publish` flow; `foldrun init` makes it for
65
+ an account's first workspace, which the getting-started guide runs.
66
+
67
+ A workspace with no agents yet deploys; `check` and the deploy say so as a
68
+ warning. A flow that names an agent the workspace lacks is still an error.
69
+
70
+ ### Importing an agent you already have
71
+
72
+ The agents worth having in a new workspace are often ones already written in
73
+ another: **Import agent** on the Agents page (and in the empty state of a blank
74
+ workspace) lists every agent in the account's other workspaces you can read,
75
+ and copies the one you pick. From a terminal, `foldrun agent import
76
+ <workspace>/<agent>` does it between workspaces of an account folder, or on the
77
+ platform with `--to <workspace>`; the route is `POST
78
+ /api/workspaces/<ws>/agents/import` with `{ from, agent, as? }`.
79
+
80
+ What is copied is what the agent **is**: `agent.md` and its own `skills/`,
81
+ `scripts/` and `knowledge/`. What it **accumulated** stays where it was learned:
82
+ `memory/`, `outputs/`, `state/` and session files. A name already taken is
83
+ refused — import it under another name with `--as` / `as`, which rewrites its
84
+ `name:`. The import then says what the copy uses that this workspace lacks —
85
+ tools, skills, scripts, secrets — without refusing: set the secret, import the
86
+ tool, and it runs. The copy is independent; editing one does not change the
87
+ other.
88
+
89
+ ### Export and import
90
+
91
+ Agent import works inside one account. To move a desk to another account or
92
+ installation — or to hand someone a flow — export it as a `.zip`:
93
+
94
+ - **A workspace:** Settings → **Export and import** → **Export workspace**.
95
+ - **A flow:** **Export** on its card on the Flows page. The package holds the
96
+ flow, every flow it runs as a step, every agent those steps name (with
97
+ `on-fail:`, `delegate:` and the colleagues those agents consult or delegate to),
98
+ and the workspace tools, skills and scripts they grant — including the
99
+ script a single-file tool's `run:` names.
100
+ - **An agent:** **Export** on its page: its folder (what agent import copies)
101
+ and the workspace tools, skills and scripts it grants. Colleagues it consults
102
+ are named, not carried.
103
+
104
+ A package is authored source only: `AGENTS.md` and the `agents/`, `flows/`,
105
+ `evals/`, `knowledge/`, `skills/`, `tools/` and `scripts/` folders. It never holds
106
+ `memory/`, `state/`, `outputs/`, storage, runs, `.env` files or a secret's
107
+ value. The secrets it uses travel by **name**, so the importer knows what to
108
+ set. An agent with no `skills:` line gets every skill in scope at run time, so
109
+ its package carries every workspace skill.
110
+
111
+ Anything else in a zip — memory, state, a `.gitignore` or `CLAUDE.md` beside a
112
+ folder you zipped yourself — is **not imported**, and the preview lists it.
113
+
114
+ To import, use **Import .zip** on the Flows or Agents page or in Settings, or
115
+ **Add new → Import workspace** on the home page. You pick the file and first
116
+ see a preview, with nothing written yet:
117
+
118
+ - what it adds;
119
+ - what is already identical;
120
+ - which files it would **replace** (only with a tick);
121
+ - what it needs that this account lacks: secrets, library tools and skills,
122
+ scripts, agents and flows it names.
123
+
124
+ An import never deletes anything, and it is all or nothing: a file it cannot
125
+ write (a folder already in its place, a link on the way) refuses the whole
126
+ import before anything is written. It lands as one revision, so History can
127
+ restore what it replaced. A workspace package imported under a new name makes
128
+ that workspace. A `.zip` of a workspace folder made by hand (a Mac's
129
+ Compress included) imports the same way.
130
+
131
+ From a terminal: `foldrun export [workspace] [--flow <name> | --agent <name>]`
132
+ and `foldrun import <file.zip> --to <workspace> [--dry-run] [--overwrite]`.
133
+ The routes are `GET /api/workspaces/<ws>/export` and
134
+ `POST /api/workspaces/<ws>/import` (`?dryRun=1`, `?overwrite=1`).
135
+
57
136
  ## `AGENTS.md` — context and defaults
58
137
 
59
138
  The body is prose every agent in the workspace sees before its own prompt.
@@ -147,6 +226,14 @@ memory an agent wrote that your push does not mention. Those belong to the
147
226
  platform, not to git, and a deploy that reverted what an agent learned would
148
227
  make every run a little dumber.
149
228
 
229
+ The agent engine's own files are not workspace content either. Each step
230
+ runs in a sandbox on the Claude Agent SDK — the engine, whichever model
231
+ answers — and the engine writes its settings and session transcripts in the
232
+ agent's folder there (`agents/<name>/.claude.json`, `agents/<name>/.claude/`).
233
+ They stay in the sandbox: never copied back, never copied in. (Your own
234
+ `.claude/agents/*.md` at the workspace root is different — a Claude Code
235
+ subagent you wrote, deployed as an agent.)
236
+
150
237
  A push while a run is in flight is accepted and applied when the run
151
238
  finishes; git tells you so at push time. A run parked at an approval gate
152
239
  counts as in flight. See [Deploying](deploying).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foldrun",
3
- "version": "0.8.0",
3
+ "version": "1.0.0",
4
4
  "description": "Agents are just folders. Write them, check them, run them — on your machine.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -11,7 +11,7 @@
11
11
  "node": ">=22"
12
12
  },
13
13
  "dependencies": {
14
- "@foldrun/core": "^0.6.0"
14
+ "@foldrun/core": "^1.0.0"
15
15
  },
16
16
  "files": [
17
17
  "bin",
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "scripts": {
23
23
  "e2e": "FOLDRUN_E2E=1 FOLDRUN_DATA=$(mktemp -d /tmp/foldrun-e2e-XXXXXX) node --test --test-timeout=300000 tests/e2e.test.ts",
24
- "test": "FOLDRUN_DATA=$(mktemp -d /tmp/foldrun-test-XXXXXX) node --test tests/cli-account.test.ts tests/model-credential.test.ts tests/cli-approvals.test.ts tests/cli-stop.test.ts tests/cli-account-settings.test.ts tests/cli-schedule.test.ts tests/cli-billing.test.ts tests/cli-storage.test.ts tests/cli-scaffold.test.ts tests/cli-secrets.test.ts tests/cli-site-login.test.ts tests/cli-check-library.test.ts tests/cli-check-timezone.test.ts tests/cli-check-subagents.test.ts tests/cli-connect.test.ts tests/cli-accounts.test.ts tests/cli-remote.test.ts tests/cli-stream.test.ts tests/cli-doctor.test.ts tests/cli-tool-test.test.ts tests/cli-agent-run.test.ts tests/cli-check-remote.test.ts tests/cli-shares.test.ts tests/cli-triggers.test.ts tests/cli-providers.test.ts tests/cli-rerun-put.test.ts tests/cli-guide.test.ts tests/cli-runtimes.test.ts tests/cli-deploy-safety.test.ts tests/cli-operator.test.ts tests/cli-flow-patterns.test.ts tests/cli-flow-rm-step.test.ts tests/cli-flow-dup-step.test.ts tests/cli-flow-write-stale.test.ts tests/cli-agent-link-stale.test.ts tests/cli-parity.test.ts tests/cli-invoke-inputs.test.ts tests/cli-audit-keys.test.ts tests/cli-version.test.ts tests/cli-check-web-warnings.test.ts tests/cli-report-image.test.ts tests/cli-check-workspace-paths.test.ts tests/cli-parity-dashboard.test.ts tests/cli-api-standards.test.ts tests/cli-backups-onboarding.test.ts tests/cli-check-limits.test.ts tests/cli-gallery.test.ts tests/cli-status-platform.test.ts tests/cli-webhooks-notifications.test.ts",
24
+ "test": "FOLDRUN_DATA=$(mktemp -d /tmp/foldrun-test-XXXXXX) node --test tests/cli-account.test.ts tests/model-credential.test.ts tests/cli-approvals.test.ts tests/cli-stop.test.ts tests/cli-account-settings.test.ts tests/cli-schedule.test.ts tests/cli-billing.test.ts tests/cli-storage.test.ts tests/cli-scaffold.test.ts tests/cli-secrets.test.ts tests/cli-site-login.test.ts tests/cli-check-library.test.ts tests/cli-check-timezone.test.ts tests/cli-check-frontmatter.test.ts tests/cli-agent-import.test.ts tests/cli-check-subagents.test.ts tests/cli-connect.test.ts tests/cli-accounts.test.ts tests/cli-remote.test.ts tests/cli-stream.test.ts tests/cli-doctor.test.ts tests/cli-tool-test.test.ts tests/cli-agent-run.test.ts tests/cli-check-remote.test.ts tests/cli-shares.test.ts tests/cli-triggers.test.ts tests/cli-providers.test.ts tests/cli-rerun-put.test.ts tests/cli-guide.test.ts tests/cli-runtimes.test.ts tests/cli-deploy-safety.test.ts tests/cli-operator.test.ts tests/cli-flow-patterns.test.ts tests/cli-flow-rm-step.test.ts tests/cli-flow-dup-step.test.ts tests/cli-flow-write-stale.test.ts tests/cli-agent-link-stale.test.ts tests/cli-parity.test.ts tests/cli-invoke-inputs.test.ts tests/cli-audit-keys.test.ts tests/cli-version.test.ts tests/cli-check-web-warnings.test.ts tests/cli-report-image.test.ts tests/cli-check-workspace-paths.test.ts tests/cli-parity-dashboard.test.ts tests/cli-api-standards.test.ts tests/cli-backups-onboarding.test.ts tests/cli-check-limits.test.ts tests/cli-gallery.test.ts tests/cli-status-platform.test.ts tests/cli-webhooks-notifications.test.ts tests/cli-flags.test.ts tests/cli-api-coverage.test.ts tests/cli-hooks.test.ts tests/cli-release.test.ts tests/cli-terminal.test.ts",
25
25
  "release": "node scripts/release.mjs",
26
26
  "typecheck": "tsc -p tsconfig.json",
27
27
  "docs:sync": "node scripts/sync-docs.mjs",
@@ -47,7 +47,7 @@
47
47
  "access": "public"
48
48
  },
49
49
  "devDependencies": {
50
- "@types/node": "^22.20.2",
50
+ "@types/node": "^26.6.4",
51
51
  "gray-matter": "^4.0.3",
52
52
  "typescript": "^5.9.3"
53
53
  }