@synapsor/runner 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -92,6 +92,9 @@ then read the concepts once the safety boundary is visible.
92
92
 
93
93
  - [Current Scope](current-scope.md): compact v0.1 scope summary.
94
94
  - [Current Limitations](limitations.md): intentional safety limits.
95
+ - [Production-Candidate Guide](production.md): single-node OSS deployment
96
+ scope, database roles, receipt grants, local ledger backup, restart behavior,
97
+ Docker/systemd shapes, TLS, and release-gate expectations.
95
98
  - [Cloud Mode](cloud-mode.md): what stays local and what Cloud-linked mode adds.
96
99
  - [Release Notes](release-notes.md): release history and behavior changes.
97
100
  - [Release Policy](release-policy.md): stable gates and publish verification.
@@ -0,0 +1,91 @@
1
+ # Conformance Fixtures
2
+
3
+ Conformance fixtures prove behavior, not just JSON shape.
4
+
5
+ `@synapsor/spec` owns the fixtures under:
6
+
7
+ ```text
8
+ packages/spec/fixtures/conformance/
9
+ ```
10
+
11
+ Each fixture contains:
12
+
13
+ - `contract.json`: canonical `@synapsor/spec` contract;
14
+ - `scenario.json`: trusted context, invocation, and mocked source data;
15
+ - `expected.*.json`: expected evidence, proposal, receipt, replay, redaction,
16
+ or external action result.
17
+
18
+ Current fixture groups:
19
+
20
+ - `read-capability`
21
+ - `proposal-capability`
22
+ - `kept-out-fields`
23
+ - `manual-approval`
24
+
25
+ The fixture set is intentionally small in 0.1. It covers the runner-supported
26
+ semantic surface first: trusted context, scoped reads, evidence handles,
27
+ proposal boundaries, kept-out fields, manual approval, and replay envelopes.
28
+
29
+ ## Runner Usage
30
+
31
+ Runner tests load every conformance `contract.json` and verify that the MCP
32
+ runtime can expose the contract as semantic tools without exposing raw SQL,
33
+ approval, commit, or writeback tools.
34
+
35
+ Run:
36
+
37
+ ```bash
38
+ corepack pnpm --filter @synapsor-runner/mcp-server test
39
+ ```
40
+
41
+ The spec package also validates every conformance contract:
42
+
43
+ ```bash
44
+ corepack pnpm --filter @synapsor/spec test
45
+ ```
46
+
47
+ ## Cloud/C++ Usage
48
+
49
+ The proprietary Cloud/C++ engine uses the same fixture contracts for
50
+ import/export alignment of the 0.1 overlapping subset:
51
+
52
+ 1. load `contract.json`;
53
+ 2. validate the 0.1 core fields and extension policy;
54
+ 3. compile the overlapping subset to internal context/capability/workflow
55
+ models;
56
+ 4. emit normalized `@synapsor/spec` JSON;
57
+ 5. compare unsupported fields and extension handling explicitly.
58
+
59
+ The main Synapsor repo also keeps C++ export fixtures under:
60
+
61
+ ```text
62
+ tests/fixtures/synapsor_contract_exports/
63
+ ```
64
+
65
+ Those exported contracts are validated by `@synapsor/spec` and loaded by
66
+ `@synapsor/runner` through the main repo verifier:
67
+
68
+ ```bash
69
+ SYNAPSOR_RUNNER_REPO=/path/to/synapsor-runner \
70
+ ./scripts/verify_contract_roundtrip.sh
71
+ ```
72
+
73
+ Full runtime parity is not required for every Cloud-only feature in 0.1, but
74
+ unsupported fields must fail clearly or be represented through documented
75
+ `x-cloud-*` extensions.
76
+
77
+ ## Add A Fixture
78
+
79
+ 1. Create a new directory under `packages/spec/fixtures/conformance/<name>/`.
80
+ 2. Add a valid `contract.json`.
81
+ 3. Add a minimal `scenario.json`.
82
+ 4. Add one or more `expected.*.json` files.
83
+ 5. Run:
84
+
85
+ ```bash
86
+ corepack pnpm --filter @synapsor/spec test
87
+ corepack pnpm --filter @synapsor-runner/mcp-server test
88
+ ```
89
+
90
+ Keep fixtures deterministic. Do not include secrets, database URLs, live table
91
+ rows, bearer tokens, or customer data.
@@ -0,0 +1,191 @@
1
+ # Migrating To `@synapsor/spec`
2
+
3
+ `@synapsor/spec` is the canonical Synapsor contract format.
4
+
5
+ Older Runner configs may still embed capabilities directly inside
6
+ `synapsor.runner.json`. That remains supported. New projects should separate
7
+ the portable business contract from local runtime wiring.
8
+
9
+ ## Old Shape
10
+
11
+ ```json
12
+ {
13
+ "version": 1,
14
+ "mode": "review",
15
+ "storage": { "sqlite_path": "./.synapsor/local.db" },
16
+ "sources": {
17
+ "local_postgres": {
18
+ "engine": "postgres",
19
+ "read_url_env": "DATABASE_URL"
20
+ }
21
+ },
22
+ "trusted_context": {
23
+ "provider": "environment",
24
+ "values": {
25
+ "tenant_id_env": "SYNAPSOR_TENANT_ID",
26
+ "principal_env": "SYNAPSOR_PRINCIPAL"
27
+ }
28
+ },
29
+ "capabilities": [
30
+ {
31
+ "name": "billing.inspect_invoice",
32
+ "kind": "read",
33
+ "source": "local_postgres",
34
+ "target": {
35
+ "schema": "public",
36
+ "table": "invoices",
37
+ "primary_key": "id",
38
+ "tenant_key": "tenant_id"
39
+ },
40
+ "args": {
41
+ "invoice_id": { "type": "string", "required": true }
42
+ },
43
+ "lookup": { "id_from_arg": "invoice_id" },
44
+ "visible_columns": ["id", "tenant_id", "status", "late_fee_cents"],
45
+ "evidence": "required",
46
+ "max_rows": 1
47
+ }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ ## New Shape
53
+
54
+ Put context, resources, capabilities, workflows, evidence requirements,
55
+ proposal boundaries, and kept-out fields in `synapsor.contract.json`.
56
+
57
+ ```json
58
+ {
59
+ "spec_version": "0.1",
60
+ "kind": "SynapsorContract",
61
+ "metadata": {
62
+ "name": "billing invoice review",
63
+ "version": "0.1.0"
64
+ },
65
+ "resources": [
66
+ {
67
+ "name": "billing_invoices",
68
+ "engine": "postgres",
69
+ "schema": "public",
70
+ "table": "invoices",
71
+ "primary_key": "id",
72
+ "tenant_key": "tenant_id",
73
+ "conflict_key": "updated_at"
74
+ }
75
+ ],
76
+ "contexts": [
77
+ {
78
+ "name": "local_operator",
79
+ "tenant_binding": "tenant_id",
80
+ "principal_binding": "principal",
81
+ "bindings": [
82
+ { "name": "tenant_id", "source": "environment", "key": "SYNAPSOR_TENANT_ID", "required": true },
83
+ { "name": "principal", "source": "environment", "key": "SYNAPSOR_PRINCIPAL", "required": true }
84
+ ]
85
+ }
86
+ ],
87
+ "capabilities": [
88
+ {
89
+ "name": "billing.inspect_invoice",
90
+ "kind": "read",
91
+ "context": "local_operator",
92
+ "source": "local_postgres",
93
+ "subject": {
94
+ "resource": "billing_invoices"
95
+ },
96
+ "args": {
97
+ "invoice_id": { "type": "string", "required": true, "max_length": 128 }
98
+ },
99
+ "lookup": { "id_from_arg": "invoice_id" },
100
+ "visible_fields": ["id", "tenant_id", "status", "late_fee_cents", "updated_at"],
101
+ "kept_out_fields": ["internal_notes"],
102
+ "evidence": { "required": true, "query_audit": true },
103
+ "max_rows": 1
104
+ }
105
+ ]
106
+ }
107
+ ```
108
+
109
+ Then keep only local wiring in `synapsor.runner.json`.
110
+
111
+ ```json
112
+ {
113
+ "version": 1,
114
+ "mode": "read_only",
115
+ "result_format": 2,
116
+ "storage": {
117
+ "sqlite_path": "./.synapsor/local.db"
118
+ },
119
+ "contracts": ["./synapsor.contract.json"],
120
+ "sources": {
121
+ "local_postgres": {
122
+ "engine": "postgres",
123
+ "read_url_env": "DATABASE_URL",
124
+ "statement_timeout_ms": 3000
125
+ }
126
+ }
127
+ }
128
+ ```
129
+
130
+ ## Validate
131
+
132
+ ```bash
133
+ synapsor-runner contract validate ./synapsor.contract.json
134
+ synapsor-runner contract normalize ./synapsor.contract.json --out ./synapsor.contract.normalized.json
135
+ synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
136
+ ```
137
+
138
+ You can also compile from the SQL-like authoring layer:
139
+
140
+ ```bash
141
+ synapsor-runner dsl validate ./contract.synapsor
142
+ synapsor-runner dsl compile ./contract.synapsor --out ./synapsor.contract.json
143
+ ```
144
+
145
+ ## Bundle For Local Runner
146
+
147
+ Cloud/exported or hand-written contracts can become a local Runner bundle:
148
+
149
+ ```bash
150
+ synapsor-runner contract bundle ./synapsor.contract.json --out ./synapsor-runner-bundle
151
+ ```
152
+
153
+ The bundle includes:
154
+
155
+ - `synapsor.contract.json`
156
+ - `synapsor.runner.json`
157
+ - `.env.example`
158
+ - `README.md`
159
+ - `mcp-client-examples/generic-stdio.json`
160
+
161
+ It does not include database passwords, write credentials, bearer tokens,
162
+ customer rows, or table data.
163
+
164
+ ## Common Errors
165
+
166
+ `UNKNOWN_FIELD`
167
+
168
+ The contract has a field outside the 0.1 core schema. Use explicit extension
169
+ fields such as `x-cloud-*`, `x-runner-*`, or `x-experimental-*`.
170
+
171
+ `MODEL_CONTROLLED_TRUST_SCOPE`
172
+
173
+ A capability argument tries to accept trusted scope from the model, such as
174
+ `tenant_id`, `principal`, table names, column names, or `expected_version`.
175
+ Bind those values from trusted context instead.
176
+
177
+ `KEPT_OUT_VISIBLE_CONFLICT`
178
+
179
+ A field appears in both `visible_fields` and `kept_out_fields`. Remove it from
180
+ `visible_fields`. Kept-out fields must not reach evidence, proposals, or replay.
181
+
182
+ `PROPOSAL_CONFLICT_GUARD_REQUIRED`
183
+
184
+ A proposal capability needs a conflict guard, or an explicit weak-guard
185
+ acknowledgement for a known dev-only path.
186
+
187
+ ## Compatibility
188
+
189
+ Embedded Runner capabilities are still supported for existing users. The new
190
+ contract split is the forward path because it lets OSS Runner, Cloud, C++ import
191
+ tests, and the DSL compiler all validate the same canonical shape.
@@ -0,0 +1,289 @@
1
+ # Production-Candidate Guide
2
+
3
+ Synapsor Runner is not self-hosted Synapsor Cloud. This guide is for the
4
+ narrow OSS production-candidate shape:
5
+
6
+ ```text
7
+ MCP agent
8
+ -> reviewed semantic capability
9
+ -> trusted tenant/principal context
10
+ -> scoped Postgres/MySQL read
11
+ -> evidence/query audit/proposal
12
+ -> approval outside MCP
13
+ -> guarded one-row update or app-owned executor
14
+ -> receipt/replay
15
+ ```
16
+
17
+ Use this only for bounded database workflows where you can accept a single-node
18
+ local ledger and local/operator approval. Use Synapsor Cloud when you need HA,
19
+ central audit, RBAC/SSO, multi-reviewer approvals, hosted retention, managed
20
+ runners, policy packs, or production support/SLA.
21
+
22
+ ## Supported Scope
23
+
24
+ Production-candidate OSS scope:
25
+
26
+ - Postgres/MySQL reads through fixed semantic MCP tools;
27
+ - trusted context from environment/session values, not model arguments;
28
+ - local SQLite ledger for evidence, query audit, proposals, receipts, replay,
29
+ and lifecycle events;
30
+ - direct guarded single-row `UPDATE` for simple approved edits;
31
+ - app-owned `http_handler` or `command_handler` executors for richer approved
32
+ business transactions;
33
+ - stdio MCP and Streamable HTTP MCP.
34
+
35
+ Out of scope:
36
+
37
+ - raw `execute_sql` or model-generated SQL;
38
+ - generic direct `INSERT`, `DELETE`, `UPSERT`, DDL, or multi-row SQL writeback;
39
+ - physical branching of external Postgres/MySQL;
40
+ - workflow DAGs, auto-merge/settlement, RBAC/SSO, HA ledger, or compliance
41
+ retention;
42
+ - making prompt injection impossible.
43
+
44
+ ## Database Roles
45
+
46
+ Use separate read and write credentials.
47
+
48
+ Read credential:
49
+
50
+ - can connect to the selected database;
51
+ - can inspect metadata for selected schemas;
52
+ - can `SELECT` only the tables/views used by capabilities;
53
+ - should be restricted by views/RLS where possible.
54
+
55
+ Write credential for direct `sql_update`:
56
+
57
+ - can update only the allowed business columns;
58
+ - cannot modify primary-key or tenant columns;
59
+ - can create/write the `synapsor_writeback_receipts` table, or the table is
60
+ pre-created and granted by an administrator;
61
+ - is never exposed to MCP clients.
62
+
63
+ Example config:
64
+
65
+ ```json
66
+ {
67
+ "sources": {
68
+ "billing_postgres": {
69
+ "engine": "postgres",
70
+ "read_url_env": "SYNAPSOR_DATABASE_READ_URL",
71
+ "write_url_env": "SYNAPSOR_DATABASE_WRITE_URL"
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ `synapsor-runner apply --config ...` reads the writer env var named by
78
+ `write_url_env`. `SYNAPSOR_DATABASE_URL` is only a legacy fallback for direct
79
+ worker flows that do not pass a local config.
80
+
81
+ ## Receipt Table
82
+
83
+ Direct SQL writeback stores idempotency receipts in the source database. Runner
84
+ creates this table if allowed:
85
+
86
+ ```sql
87
+ CREATE TABLE IF NOT EXISTS synapsor_writeback_receipts (...);
88
+ ```
89
+
90
+ Before using direct writeback in staging or production-like environments:
91
+
92
+ ```bash
93
+ synapsor-runner writeback migration --engine postgres
94
+ synapsor-runner writeback grants --engine postgres --writer-role app_writer
95
+ synapsor-runner doctor --config synapsor.runner.json --check-writeback
96
+ ```
97
+
98
+ For MySQL, replace `postgres` with `mysql`.
99
+
100
+ If the writer should not create application-schema tables, pre-create the
101
+ receipt table with an administrator role, grant only the needed receipt-table
102
+ permissions to the writer, or use an app-owned executor that stores receipts in
103
+ your application boundary.
104
+
105
+ ## Direct Writeback Vs App-Owned Executor
106
+
107
+ Use direct `sql_update` when the approved change is:
108
+
109
+ ```text
110
+ one existing row -> one allowed-column patch -> one guarded UPDATE
111
+ ```
112
+
113
+ Use an app-owned executor when the change is richer:
114
+
115
+ - insert a credit/refund/review row;
116
+ - update more than one row;
117
+ - touch more than one table;
118
+ - emit an event or call another internal service;
119
+ - enforce business logic that belongs in your app.
120
+
121
+ Handlers must re-check tenant/scope, expected version, idempotency, allowed
122
+ business action, transaction boundaries, and safe errors. See
123
+ [Writeback Executors](writeback-executors.md) and
124
+ [Handler Helper](handler-helper.md).
125
+
126
+ ## Local Ledger
127
+
128
+ Default local ledger path:
129
+
130
+ ```text
131
+ ./.synapsor/local.db
132
+ ```
133
+
134
+ This SQLite file stores local evidence, query audit, proposals, approvals,
135
+ receipts, replay, and events. Back it up like local operational state if you
136
+ depend on replay after restarts.
137
+
138
+ Recommended single-node practices:
139
+
140
+ - keep the ledger on persistent disk;
141
+ - back up `local.db`, `local.db-wal`, and `local.db-shm` together when the
142
+ server is stopped, or use your platform's filesystem snapshot mechanism;
143
+ - do not run multiple active MCP server modes against the same ledger unless
144
+ you intentionally pass `--allow-concurrent-store` for local debugging;
145
+ - use `store prune --dry-run` before retention cleanup;
146
+ - use `store vacuum` during a planned maintenance window.
147
+
148
+ Useful commands:
149
+
150
+ ```bash
151
+ synapsor-runner store stats --store ./.synapsor/local.db
152
+ synapsor-runner events tail --store ./.synapsor/local.db --follow
153
+ synapsor-runner store prune --store ./.synapsor/local.db --older-than 30d --dry-run
154
+ synapsor-runner store vacuum --store ./.synapsor/local.db
155
+ ```
156
+
157
+ Details: [Store Lifecycle](store-lifecycle.md).
158
+
159
+ ## Restart And Recovery
160
+
161
+ Runner stores proposal/evidence/replay state before writeback.
162
+
163
+ Expected restart behavior:
164
+
165
+ - after proposal creation: proposal, evidence, query audit, and replay remain
166
+ inspectable from the local ledger;
167
+ - after approval but before apply: rerun `apply`; the approved proposal remains
168
+ pending until a terminal receipt is recorded;
169
+ - after apply succeeds: retry returns an idempotent receipt, not a second write;
170
+ - after stale row or tenant mismatch: retry returns the recorded conflict path.
171
+
172
+ Inspection commands:
173
+
174
+ ```bash
175
+ synapsor-runner proposals show latest --store ./.synapsor/local.db
176
+ synapsor-runner receipts list --proposal wrp_... --store ./.synapsor/local.db
177
+ synapsor-runner replay show latest --store ./.synapsor/local.db
178
+ synapsor-runner activity search --proposal wrp_... --store ./.synapsor/local.db
179
+ ```
180
+
181
+ ## Deployment Recipes
182
+
183
+ ### Docker Compose Shape
184
+
185
+ Use Compose to run the MCP server next to your app and database network. Keep
186
+ secrets in environment variables or your platform secret manager.
187
+
188
+ ```yaml
189
+ services:
190
+ synapsor-runner:
191
+ image: node:22-bookworm
192
+ working_dir: /app
193
+ command: >
194
+ sh -lc "npm install -g @synapsor/runner &&
195
+ synapsor-runner up --review --config /config/synapsor.runner.json
196
+ --store /data/local.db --host 0.0.0.0 --port 8766"
197
+ environment:
198
+ SYNAPSOR_DATABASE_READ_URL: ${SYNAPSOR_DATABASE_READ_URL}
199
+ SYNAPSOR_DATABASE_WRITE_URL: ${SYNAPSOR_DATABASE_WRITE_URL}
200
+ SYNAPSOR_TENANT_ID: ${SYNAPSOR_TENANT_ID}
201
+ SYNAPSOR_PRINCIPAL: ${SYNAPSOR_PRINCIPAL}
202
+ volumes:
203
+ - ./synapsor.runner.json:/config/synapsor.runner.json:ro
204
+ - synapsor-runner-data:/data
205
+ ports:
206
+ - "8766:8766"
207
+
208
+ volumes:
209
+ synapsor-runner-data:
210
+ ```
211
+
212
+ ### systemd Shape
213
+
214
+ ```ini
215
+ [Unit]
216
+ Description=Synapsor Runner MCP server
217
+ After=network-online.target
218
+
219
+ [Service]
220
+ Type=simple
221
+ User=synapsor-runner
222
+ WorkingDirectory=/opt/synapsor-runner
223
+ EnvironmentFile=/etc/synapsor-runner.env
224
+ ExecStart=/usr/bin/synapsor-runner up --review --config /etc/synapsor.runner.json --store /var/lib/synapsor-runner/local.db --host 127.0.0.1 --port 8766
225
+ Restart=on-failure
226
+ RestartSec=5
227
+ NoNewPrivileges=true
228
+ PrivateTmp=true
229
+
230
+ [Install]
231
+ WantedBy=multi-user.target
232
+ ```
233
+
234
+ Put database credentials in `/etc/synapsor-runner.env` or your system secret
235
+ manager, not in `synapsor.runner.json`.
236
+
237
+ ## TLS And SSL
238
+
239
+ For staging or production-like databases:
240
+
241
+ - keep certificate verification enabled;
242
+ - use provider CA bundles when required;
243
+ - do not use `sslmode=disable` except disposable local fixtures;
244
+ - do not document or paste real DB URLs into logs, tickets, prompts, or MCP
245
+ client config.
246
+
247
+ For disposable local Docker fixtures, `sslmode=disable` is acceptable when the
248
+ database is bound to loopback and contains only test data.
249
+
250
+ ## Health And Doctor
251
+
252
+ Run these before exposing tools to an agent:
253
+
254
+ ```bash
255
+ synapsor-runner config validate --config synapsor.runner.json
256
+ synapsor-runner doctor --config synapsor.runner.json --report --redact --output synapsor-doctor.md
257
+ synapsor-runner doctor --config synapsor.runner.json --check-writeback
258
+ synapsor-runner tools preview --config synapsor.runner.json --store ./.synapsor/local.db
259
+ ```
260
+
261
+ Doctor reports should be redacted by default before sharing. They must not
262
+ include database passwords, bearer tokens, handler secrets, or raw driver
263
+ connection strings.
264
+
265
+ ## Logging And Redaction
266
+
267
+ Expected public outputs must avoid secrets in:
268
+
269
+ - demo output;
270
+ - doctor reports;
271
+ - evidence exports;
272
+ - query-audit output;
273
+ - replay exports;
274
+ - thrown errors and logs.
275
+
276
+ If you find a leak, treat it as a security bug. See [SECURITY.md](../SECURITY.md).
277
+
278
+ ## Release Gate
279
+
280
+ Before promoting a package or calling a build production-candidate:
281
+
282
+ ```bash
283
+ ./scripts/verify-release-gate.sh
284
+ ```
285
+
286
+ The release gate should cover typecheck, focused tests, packed-package install,
287
+ quick demo, own-db fixture, MCP stdio/HTTP checks, direct writeback,
288
+ app-owned executor paths, package dry-run, and docs/package consistency.
289
+
@@ -10,6 +10,17 @@ npx -y -p @synapsor/runner synapsor-runner demo --quick
10
10
  The OSS runner command is `synapsor-runner`. The `synapsor` command is reserved
11
11
  for the Synapsor Cloud CLI.
12
12
 
13
+ ## 0.1.2
14
+
15
+ ### Contract Compatibility
16
+
17
+ - Documents the canonical `synapsor.contract.json` path for contracts produced
18
+ by the DSL, Cloud, or the C++ exporter.
19
+ - Adds OSS-side conformance notes for C++/Cloud export snapshots that validate
20
+ with `@synapsor/spec` and load in Runner.
21
+ - Keeps `@synapsor/runner` publishable after `0.1.1` by reserving the next
22
+ stable patch version for this contract round-trip readiness pass.
23
+
13
24
  ## 0.1.1
14
25
 
15
26
  ### OSS Launch Readiness
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapsor/runner",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Stop giving AI agents execute_sql; expose reviewed Postgres/MySQL MCP actions with proposals, approval, writeback, and replay.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -52,11 +52,6 @@
52
52
  "engines": {
53
53
  "node": ">=22.5.0"
54
54
  },
55
- "scripts": {
56
- "build": "tsc -b && node ../../scripts/build-runner-package.mjs",
57
- "prepack": "cd ../.. && corepack pnpm build:runner-package",
58
- "test": "vitest run"
59
- },
60
55
  "dependencies": {
61
56
  "@modelcontextprotocol/sdk": "1.29.0",
62
57
  "mysql2": "^3.11.0",
@@ -77,5 +72,9 @@
77
72
  },
78
73
  "publishConfig": {
79
74
  "access": "public"
75
+ },
76
+ "scripts": {
77
+ "build": "tsc -b && node ../../scripts/build-runner-package.mjs",
78
+ "test": "vitest run"
80
79
  }
81
- }
80
+ }