diff --git a/.changeset/agent-replace-grant-gate.md b/.changeset/agent-replace-grant-gate.md deleted file mode 100644 index 47ac71e..0000000 --- a/.changeset/agent-replace-grant-gate.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@boardstate/server": patch ---- - -Security: the `dashboard_workspace_replace` agent tool now passes the structural -replace gate (`reconcileReplaceApproval`), so an agent can no longer self-grant a -capability by writing `status: "granted"` into `capabilitiesRegistry`. Only -`dashboard.capability.approve` (operator-only) grants. The RPC replace path was -already gated; this closes the agent-tool path. diff --git a/.changeset/broker-mcp-client-manager.md b/.changeset/broker-mcp-client-manager.md deleted file mode 100644 index 9dcab69..0000000 --- a/.changeset/broker-mcp-client-manager.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -"@boardstate/broker": minor ---- - -New package `@boardstate/broker` — the MCP CLIENT manager (M5a-1, epic #37). It connects -outward to the external MCP servers an operator declares in a `boardstate.connectors.json` -config, discovers their tools into a namespaced `ToolManifest`, and calls them behind a -narrow API the host/server layers consume. - -- **Config is operator-authored only**: `loadConnectorsConfig(path)` + a programmatic - `new McpBroker(config)`. A connector name not in the config is inert. `env` values are - process-env var NAMES (references), never literal secrets — validated up front and never - echoed into errors or logs. -- **Transports**: `StdioClientTransport` for local servers, `StreamableHTTPClientTransport` - with SSE fallback for remotes. Lazy connect on first use, warm/pooled clients, capped - exponential-backoff reconnect, clean close. -- **`listTools()` → `ToolManifest`**: `connector:tool` ids AND provider-safe - `connector__tool` names (both inside a 64-char budget, collisions fail loud), input - schemas, `readOnlyHint` honored (absent ⇒ treated as a mutation — fail-safe), and a - stable manifest hash over sorted (id + canonical input-schema) pairs — the anti-rug-pull - snapshot the grant lifecycle (M5b-2) pins to. -- **`callTool(id, args, { timeout })`**: resolves the client, strips the namespace, - enforces a hard timeout, and normalizes `isError: true` results into a typed - `BrokerToolError`. - -Depends only on `@modelcontextprotocol/sdk` and `@boardstate/server` (types only). Ships -an in-repo fake MCP server fixture (stdio child + in-process HTTP) so CI needs no network. diff --git a/.changeset/m5-schema-train.md b/.changeset/m5-schema-train.md deleted file mode 100644 index 94603dc..0000000 --- a/.changeset/m5-schema-train.md +++ /dev/null @@ -1,24 +0,0 @@ ---- -"@boardstate/schema": minor -"@boardstate/core": minor ---- - -feat(schema): SPEC §17 v2 tool grants + all M5 schema surface (one schema train, M5b-1) - -The single S5-1 schema train — all M5 (Operational Workspace) schema surface rides -one release so later sprints consume a released schema. Fully additive: boards using -none of the new surface validate + normalize byte-identically (regression-tested). - -- **Tool grants (SPEC §17 v2):** `DashboardCapabilityGrant` gains `tools?: string[]` - (namespaced `connector:tool` ids, shape-validated — NOT against - `DATA_READ_RPC_ALLOWLIST`) and `toolsHash?`. `methods`/`streams`/`tools` are - optional-in / always-array-out. -- **Pending-action record:** `PendingActionRecord` type + `validatePendingAction` - shape guard for the #41 engine (type + validation only). -- **`builtin:action-button`** kind + props validator `{connector, tool, args?, label?}`. -- **action-form `mode:"tool"`:** `mode`/`connector`/`tool`/`argsFrom` extend the - fixed key-set; prompt mode stays the default and byte-identical. -- **`source:"mcp"` binding:** `{source:"mcp", connector, tool, args?}` (shape only; - host resolution is #45). -- **`dashboard.connector.list`** added to `DATA_READ_RPC_ALLOWLIST` (broker status read). -- **WIDGET_CATALOG:** `action-button` entry + action-form tool-mode example (honesty-gate valid). diff --git a/.changeset/m5-trust-layer.md b/.changeset/m5-trust-layer.md deleted file mode 100644 index 3fe3f11..0000000 --- a/.changeset/m5-trust-layer.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -"@boardstate/broker": minor -"@boardstate/server": minor -"@boardstate/core": minor -"@boardstate/lit": minor -"@boardstate/host": patch -"@boardstate/schema": patch ---- - -M5 trust layer (M5b-2 + M5b-3, epic #37): the grant lifecycle for external MCP tools -and the server-enforced pending-action engine — closes #40 and #41. - -**Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, #40)** - -- `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's - discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, - a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s - request-on-install. An already-`granted` grant survives a restart; real manifest drift is - caught at invoke time. -- Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared - to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call - succeeds. -- Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to - `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the - red-team hole where an agent could append a tool id to a granted grant through - `workspace.replace` or import. -- Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the - decision applies to the intersection with the requested set and the granted subset gets - its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). -- Approvals console: capability rows surface their requested tool ids for per-tool selection - (approve-all = one click); the core transform + lit renderer + strings render it. - -**Pending-action engine (SPEC §18, #41)** - -- In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at - invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes - directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, - expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only - (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. -- TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), - server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + - decision, and lifecycle broadcasts on `dashboard.action.changed`. -- `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks - on: it resolves with the tool result on confirm and rejects on deny/expiry. - -The engine consumes the broker through the narrow structural `ActionBroker` interface — -`@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real -`McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema -train (#39) left implementation-pending markers. diff --git a/conformance/CHANGELOG.md b/conformance/CHANGELOG.md index fc2b36b..ec149d6 100644 --- a/conformance/CHANGELOG.md +++ b/conformance/CHANGELOG.md @@ -1,5 +1,14 @@ # @boardstate/conformance +## 0.1.11 + +### Patch Changes + +- Updated dependencies [[`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938), [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/server@1.2.0 + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + ## 0.1.10 ### Patch Changes diff --git a/conformance/package.json b/conformance/package.json index 1ed02b4..ea521bd 100644 --- a/conformance/package.json +++ b/conformance/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/conformance", - "version": "0.1.10", + "version": "0.1.11", "description": "The Boardstate transport conformance suite: run it against your own host implementation", "type": "module", "license": "MIT", diff --git a/examples/app/CHANGELOG.md b/examples/app/CHANGELOG.md index 41ae523..774ba97 100644 --- a/examples/app/CHANGELOG.md +++ b/examples/app/CHANGELOG.md @@ -1,5 +1,17 @@ # boardstate-example-app +## 0.0.12 + +### Patch Changes + +- Updated dependencies [[`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938), [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/server@1.2.0 + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + - @boardstate/lit@0.4.0 + - @boardstate/host@1.2.0 + - @boardstate/agent@0.2.8 + ## 0.0.11 ### Patch Changes diff --git a/examples/app/package.json b/examples/app/package.json index fedb98b..a31cd21 100644 --- a/examples/app/package.json +++ b/examples/app/package.json @@ -1,7 +1,7 @@ { "name": "boardstate-example-app", "private": true, - "version": "0.0.11", + "version": "0.0.12", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/standalone/CHANGELOG.md b/examples/standalone/CHANGELOG.md index 08f550d..127c636 100644 --- a/examples/standalone/CHANGELOG.md +++ b/examples/standalone/CHANGELOG.md @@ -1,5 +1,16 @@ # boardstate-example-standalone +## 0.0.12 + +### Patch Changes + +- Updated dependencies [[`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938), [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/server@1.2.0 + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + - @boardstate/lit@0.4.0 + - @boardstate/host@1.2.0 + ## 0.0.11 ### Patch Changes diff --git a/examples/standalone/package.json b/examples/standalone/package.json index 35073b4..b2d6927 100644 --- a/examples/standalone/package.json +++ b/examples/standalone/package.json @@ -1,7 +1,7 @@ { "name": "boardstate-example-standalone", "private": true, - "version": "0.0.11", + "version": "0.0.12", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index ac48532..094216f 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -1,5 +1,13 @@ # @boardstate/agent +## 0.2.8 + +### Patch Changes + +- Updated dependencies [[`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938), [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/server@1.2.0 + - @boardstate/schema@1.2.0 + ## 0.2.7 ### Patch Changes diff --git a/packages/agent/package.json b/packages/agent/package.json index bc2890f..8083b0a 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/agent", - "version": "0.2.7", + "version": "0.2.8", "description": "The provider loop that turns any LLM into a Boardstate dashboard-building agent", "type": "module", "license": "MIT", diff --git a/packages/broker/CHANGELOG.md b/packages/broker/CHANGELOG.md new file mode 100644 index 0000000..8542f3d --- /dev/null +++ b/packages/broker/CHANGELOG.md @@ -0,0 +1,75 @@ +# @boardstate/broker + +## 0.2.0 + +### Minor Changes + +- [#50](https://github.com/100yenadmin/boardstate/pull/50) [`e96a33f`](https://github.com/100yenadmin/boardstate/commit/e96a33fd2b3f06f6c610650a27074d4561154428) Thanks [@100yenadmin](https://github.com/100yenadmin)! - New package `@boardstate/broker` — the MCP CLIENT manager (M5a-1, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)). It connects + outward to the external MCP servers an operator declares in a `boardstate.connectors.json` + config, discovers their tools into a namespaced `ToolManifest`, and calls them behind a + narrow API the host/server layers consume. + + - **Config is operator-authored only**: `loadConnectorsConfig(path)` + a programmatic + `new McpBroker(config)`. A connector name not in the config is inert. `env` values are + process-env var NAMES (references), never literal secrets — validated up front and never + echoed into errors or logs. + - **Transports**: `StdioClientTransport` for local servers, `StreamableHTTPClientTransport` + with SSE fallback for remotes. Lazy connect on first use, warm/pooled clients, capped + exponential-backoff reconnect, clean close. + - **`listTools()` → `ToolManifest`**: `connector:tool` ids AND provider-safe + `connector__tool` names (both inside a 64-char budget, collisions fail loud), input + schemas, `readOnlyHint` honored (absent ⇒ treated as a mutation — fail-safe), and a + stable manifest hash over sorted (id + canonical input-schema) pairs — the anti-rug-pull + snapshot the grant lifecycle (M5b-2) pins to. + - **`callTool(id, args, { timeout })`**: resolves the client, strips the namespace, + enforces a hard timeout, and normalizes `isError: true` results into a typed + `BrokerToolError`. + + Depends only on `@modelcontextprotocol/sdk` and `@boardstate/server` (types only). Ships + an in-repo fake MCP server fixture (stdio child + in-process HTTP) so CI needs no network. + +- [#53](https://github.com/100yenadmin/boardstate/pull/53) [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477) Thanks [@100yenadmin](https://github.com/100yenadmin)! - M5 trust layer (M5b-2 + M5b-3, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)): the grant lifecycle for external MCP tools + and the server-enforced pending-action engine — closes [#40](https://github.com/100yenadmin/boardstate/issues/40) and [#41](https://github.com/100yenadmin/boardstate/issues/41). + + **Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, [#40](https://github.com/100yenadmin/boardstate/issues/40))** + + - `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's + discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, + a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s + request-on-install. An already-`granted` grant survives a restart; real manifest drift is + caught at invoke time. + - Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared + to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call + succeeds. + - Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to + `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the + red-team hole where an agent could append a tool id to a granted grant through + `workspace.replace` or import. + - Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the + decision applies to the intersection with the requested set and the granted subset gets + its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). + - Approvals console: capability rows surface their requested tool ids for per-tool selection + (approve-all = one click); the core transform + lit renderer + strings render it. + + **Pending-action engine (SPEC §18, [#41](https://github.com/100yenadmin/boardstate/issues/41))** + + - In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at + invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes + directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, +expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only + (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. + - TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), + server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + + decision, and lifecycle broadcasts on `dashboard.action.changed`. + - `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks + on: it resolves with the tool result on confirm and rejects on deny/expiry. + + The engine consumes the broker through the narrow structural `ActionBroker` interface — + `@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real + `McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema + train ([#39](https://github.com/100yenadmin/boardstate/issues/39)) left implementation-pending markers. + +### Patch Changes + +- Updated dependencies [[`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/server@1.2.0 diff --git a/packages/broker/package.json b/packages/broker/package.json index 2992b6b..f1dbc6e 100644 --- a/packages/broker/package.json +++ b/packages/broker/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/broker", - "version": "0.1.0", + "version": "0.2.0", "description": "The MCP client manager: connect outward to external MCP servers, discover their tools, and call them behind a narrow, provider-safe API", "type": "module", "license": "MIT", diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 596dbfa..f76c123 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,75 @@ # @boardstate/core +## 1.2.0 + +### Minor Changes + +- [#51](https://github.com/100yenadmin/boardstate/pull/51) [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470) Thanks [@100yenadmin](https://github.com/100yenadmin)! - feat(schema): SPEC §17 v2 tool grants + all M5 schema surface (one schema train, M5b-1) + + The single S5-1 schema train — all M5 (Operational Workspace) schema surface rides + one release so later sprints consume a released schema. Fully additive: boards using + none of the new surface validate + normalize byte-identically (regression-tested). + + - **Tool grants (SPEC §17 v2):** `DashboardCapabilityGrant` gains `tools?: string[]` + (namespaced `connector:tool` ids, shape-validated — NOT against + `DATA_READ_RPC_ALLOWLIST`) and `toolsHash?`. `methods`/`streams`/`tools` are + optional-in / always-array-out. + - **Pending-action record:** `PendingActionRecord` type + `validatePendingAction` + shape guard for the [#41](https://github.com/100yenadmin/boardstate/issues/41) engine (type + validation only). + - **`builtin:action-button`** kind + props validator `{connector, tool, args?, label?}`. + - **action-form `mode:"tool"`:** `mode`/`connector`/`tool`/`argsFrom` extend the + fixed key-set; prompt mode stays the default and byte-identical. + - **`source:"mcp"` binding:** `{source:"mcp", connector, tool, args?}` (shape only; + host resolution is [#45](https://github.com/100yenadmin/boardstate/issues/45)). + - **`dashboard.connector.list`** added to `DATA_READ_RPC_ALLOWLIST` (broker status read). + - **WIDGET_CATALOG:** `action-button` entry + action-form tool-mode example (honesty-gate valid). + +- [#53](https://github.com/100yenadmin/boardstate/pull/53) [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477) Thanks [@100yenadmin](https://github.com/100yenadmin)! - M5 trust layer (M5b-2 + M5b-3, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)): the grant lifecycle for external MCP tools + and the server-enforced pending-action engine — closes [#40](https://github.com/100yenadmin/boardstate/issues/40) and [#41](https://github.com/100yenadmin/boardstate/issues/41). + + **Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, [#40](https://github.com/100yenadmin/boardstate/issues/40))** + + - `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's + discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, + a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s + request-on-install. An already-`granted` grant survives a restart; real manifest drift is + caught at invoke time. + - Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared + to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call + succeeds. + - Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to + `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the + red-team hole where an agent could append a tool id to a granted grant through + `workspace.replace` or import. + - Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the + decision applies to the intersection with the requested set and the granted subset gets + its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). + - Approvals console: capability rows surface their requested tool ids for per-tool selection + (approve-all = one click); the core transform + lit renderer + strings render it. + + **Pending-action engine (SPEC §18, [#41](https://github.com/100yenadmin/boardstate/issues/41))** + + - In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at + invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes + directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, +expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only + (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. + - TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), + server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + + decision, and lifecycle broadcasts on `dashboard.action.changed`. + - `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks + on: it resolves with the tool result on confirm and rejects on deny/expiry. + + The engine consumes the broker through the narrow structural `ActionBroker` interface — + `@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real + `McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema + train ([#39](https://github.com/100yenadmin/boardstate/issues/39)) left implementation-pending markers. + +### Patch Changes + +- Updated dependencies [[`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/schema@1.2.0 + ## 1.1.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index a6f3ecd..25bf3d9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/core", - "version": "1.1.0", + "version": "1.2.0", "description": "Headless Boardstate runtime: store, bindings, grid math, history", "type": "module", "license": "MIT", diff --git a/packages/host/CHANGELOG.md b/packages/host/CHANGELOG.md index 2d32abc..d6b8985 100644 --- a/packages/host/CHANGELOG.md +++ b/packages/host/CHANGELOG.md @@ -1,5 +1,54 @@ # @boardstate/host +## 1.2.0 + +### Patch Changes + +- [#53](https://github.com/100yenadmin/boardstate/pull/53) [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477) Thanks [@100yenadmin](https://github.com/100yenadmin)! - M5 trust layer (M5b-2 + M5b-3, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)): the grant lifecycle for external MCP tools + and the server-enforced pending-action engine — closes [#40](https://github.com/100yenadmin/boardstate/issues/40) and [#41](https://github.com/100yenadmin/boardstate/issues/41). + + **Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, [#40](https://github.com/100yenadmin/boardstate/issues/40))** + + - `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's + discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, + a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s + request-on-install. An already-`granted` grant survives a restart; real manifest drift is + caught at invoke time. + - Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared + to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call + succeeds. + - Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to + `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the + red-team hole where an agent could append a tool id to a granted grant through + `workspace.replace` or import. + - Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the + decision applies to the intersection with the requested set and the granted subset gets + its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). + - Approvals console: capability rows surface their requested tool ids for per-tool selection + (approve-all = one click); the core transform + lit renderer + strings render it. + + **Pending-action engine (SPEC §18, [#41](https://github.com/100yenadmin/boardstate/issues/41))** + + - In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at + invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes + directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, +expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only + (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. + - TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), + server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + + decision, and lifecycle broadcasts on `dashboard.action.changed`. + - `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks + on: it resolves with the tool result on confirm and rejects on deny/expiry. + + The engine consumes the broker through the narrow structural `ActionBroker` interface — + `@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real + `McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema + train ([#39](https://github.com/100yenadmin/boardstate/issues/39)) left implementation-pending markers. + +- Updated dependencies [[`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + ## 1.1.0 ### Minor Changes diff --git a/packages/host/package.json b/packages/host/package.json index df0079e..014f9f2 100644 --- a/packages/host/package.json +++ b/packages/host/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/host", - "version": "1.1.0", + "version": "1.2.0", "description": "Framework-free DOM host for Boardstate custom widgets: sandbox mount + postMessage bridge", "type": "module", "license": "MIT", diff --git a/packages/lit/CHANGELOG.md b/packages/lit/CHANGELOG.md index dce5104..053c8c4 100644 --- a/packages/lit/CHANGELOG.md +++ b/packages/lit/CHANGELOG.md @@ -1,5 +1,57 @@ # @boardstate/lit +## 0.4.0 + +### Minor Changes + +- [#53](https://github.com/100yenadmin/boardstate/pull/53) [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477) Thanks [@100yenadmin](https://github.com/100yenadmin)! - M5 trust layer (M5b-2 + M5b-3, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)): the grant lifecycle for external MCP tools + and the server-enforced pending-action engine — closes [#40](https://github.com/100yenadmin/boardstate/issues/40) and [#41](https://github.com/100yenadmin/boardstate/issues/41). + + **Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, [#40](https://github.com/100yenadmin/boardstate/issues/40))** + + - `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's + discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, + a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s + request-on-install. An already-`granted` grant survives a restart; real manifest drift is + caught at invoke time. + - Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared + to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call + succeeds. + - Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to + `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the + red-team hole where an agent could append a tool id to a granted grant through + `workspace.replace` or import. + - Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the + decision applies to the intersection with the requested set and the granted subset gets + its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). + - Approvals console: capability rows surface their requested tool ids for per-tool selection + (approve-all = one click); the core transform + lit renderer + strings render it. + + **Pending-action engine (SPEC §18, [#41](https://github.com/100yenadmin/boardstate/issues/41))** + + - In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at + invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes + directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, +expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only + (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. + - TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), + server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + + decision, and lifecycle broadcasts on `dashboard.action.changed`. + - `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks + on: it resolves with the tool result on confirm and rejects on deny/expiry. + + The engine consumes the broker through the narrow structural `ActionBroker` interface — + `@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real + `McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema + train ([#39](https://github.com/100yenadmin/boardstate/issues/39)) left implementation-pending markers. + +### Patch Changes + +- Updated dependencies [[`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + - @boardstate/host@1.2.0 + ## 0.3.0 ### Minor Changes diff --git a/packages/lit/package.json b/packages/lit/package.json index a80c9c4..8522050 100644 --- a/packages/lit/package.json +++ b/packages/lit/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/lit", - "version": "0.3.0", + "version": "0.4.0", "description": "The Boardstate reference view — and 15 builtin widgets as custom elements", "type": "module", "license": "MIT", diff --git a/packages/mcp/CHANGELOG.md b/packages/mcp/CHANGELOG.md index fdf1a25..f70eae5 100644 --- a/packages/mcp/CHANGELOG.md +++ b/packages/mcp/CHANGELOG.md @@ -1,5 +1,15 @@ # @boardstate/mcp +## 0.2.4 + +### Patch Changes + +- Updated dependencies [[`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938), [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/server@1.2.0 + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + - @boardstate/lit@0.4.0 + ## 0.2.3 ### Patch Changes diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 3b1c575..76be620 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/mcp", - "version": "0.2.3", + "version": "0.2.4", "description": "MCP server exposing the Boardstate dashboard control plane to any AI", "type": "module", "license": "MIT", diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index a62f8bb..ca1a56c 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,15 @@ # @boardstate/react +## 0.1.8 + +### Patch Changes + +- Updated dependencies [[`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + - @boardstate/lit@0.4.0 + - @boardstate/host@1.2.0 + ## 0.1.7 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 02e71a5..64ada89 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/react", - "version": "0.1.7", + "version": "0.1.8", "description": "Typed React wrappers for the Boardstate view", "type": "module", "license": "MIT", diff --git a/packages/schema/CHANGELOG.md b/packages/schema/CHANGELOG.md index 4a0bfb2..eb00145 100644 --- a/packages/schema/CHANGELOG.md +++ b/packages/schema/CHANGELOG.md @@ -1,5 +1,72 @@ # @boardstate/schema +## 1.2.0 + +### Minor Changes + +- [#51](https://github.com/100yenadmin/boardstate/pull/51) [`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470) Thanks [@100yenadmin](https://github.com/100yenadmin)! - feat(schema): SPEC §17 v2 tool grants + all M5 schema surface (one schema train, M5b-1) + + The single S5-1 schema train — all M5 (Operational Workspace) schema surface rides + one release so later sprints consume a released schema. Fully additive: boards using + none of the new surface validate + normalize byte-identically (regression-tested). + + - **Tool grants (SPEC §17 v2):** `DashboardCapabilityGrant` gains `tools?: string[]` + (namespaced `connector:tool` ids, shape-validated — NOT against + `DATA_READ_RPC_ALLOWLIST`) and `toolsHash?`. `methods`/`streams`/`tools` are + optional-in / always-array-out. + - **Pending-action record:** `PendingActionRecord` type + `validatePendingAction` + shape guard for the [#41](https://github.com/100yenadmin/boardstate/issues/41) engine (type + validation only). + - **`builtin:action-button`** kind + props validator `{connector, tool, args?, label?}`. + - **action-form `mode:"tool"`:** `mode`/`connector`/`tool`/`argsFrom` extend the + fixed key-set; prompt mode stays the default and byte-identical. + - **`source:"mcp"` binding:** `{source:"mcp", connector, tool, args?}` (shape only; + host resolution is [#45](https://github.com/100yenadmin/boardstate/issues/45)). + - **`dashboard.connector.list`** added to `DATA_READ_RPC_ALLOWLIST` (broker status read). + - **WIDGET_CATALOG:** `action-button` entry + action-form tool-mode example (honesty-gate valid). + +### Patch Changes + +- [#53](https://github.com/100yenadmin/boardstate/pull/53) [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477) Thanks [@100yenadmin](https://github.com/100yenadmin)! - M5 trust layer (M5b-2 + M5b-3, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)): the grant lifecycle for external MCP tools + and the server-enforced pending-action engine — closes [#40](https://github.com/100yenadmin/boardstate/issues/40) and [#41](https://github.com/100yenadmin/boardstate/issues/41). + + **Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, [#40](https://github.com/100yenadmin/boardstate/issues/40))** + + - `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's + discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, + a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s + request-on-install. An already-`granted` grant survives a restart; real manifest drift is + caught at invoke time. + - Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared + to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call + succeeds. + - Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to + `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the + red-team hole where an agent could append a tool id to a granted grant through + `workspace.replace` or import. + - Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the + decision applies to the intersection with the requested set and the granted subset gets + its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). + - Approvals console: capability rows surface their requested tool ids for per-tool selection + (approve-all = one click); the core transform + lit renderer + strings render it. + + **Pending-action engine (SPEC §18, [#41](https://github.com/100yenadmin/boardstate/issues/41))** + + - In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at + invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes + directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, +expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only + (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. + - TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), + server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + + decision, and lifecycle broadcasts on `dashboard.action.changed`. + - `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks + on: it resolves with the tool result on confirm and rejects on deny/expiry. + + The engine consumes the broker through the narrow structural `ActionBroker` interface — + `@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real + `McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema + train ([#39](https://github.com/100yenadmin/boardstate/issues/39)) left implementation-pending markers. + ## 1.0.0 ### Minor Changes diff --git a/packages/schema/package.json b/packages/schema/package.json index f253a28..00d700b 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/schema", - "version": "1.0.0", + "version": "1.2.0", "description": "The Boardstate workspace document schema, validators, and protocol spec", "type": "module", "license": "MIT", diff --git a/packages/server/CHANGELOG.md b/packages/server/CHANGELOG.md index d33ec8b..3cc40bd 100644 --- a/packages/server/CHANGELOG.md +++ b/packages/server/CHANGELOG.md @@ -1,5 +1,61 @@ # @boardstate/server +## 1.2.0 + +### Minor Changes + +- [#53](https://github.com/100yenadmin/boardstate/pull/53) [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477) Thanks [@100yenadmin](https://github.com/100yenadmin)! - M5 trust layer (M5b-2 + M5b-3, epic [#37](https://github.com/100yenadmin/boardstate/issues/37)): the grant lifecycle for external MCP tools + and the server-enforced pending-action engine — closes [#40](https://github.com/100yenadmin/boardstate/issues/40) and [#41](https://github.com/100yenadmin/boardstate/issues/41). + + **Grant lifecycle + both-direction anti-rug-pull (SPEC §17.1, [#40](https://github.com/100yenadmin/boardstate/issues/40))** + + - `installBrokerActions` (`@boardstate/server/node`) registers each configured connector's + discovered tools as a `requested` tools-only grant (explicit `methods: []`/`streams: []`, + a `tools` id snapshot, and a subset-scoped `toolsHash`), mirroring `installConnector`'s + request-on-install. An already-`granted` grant survives a restart; real manifest drift is + caught at invoke time. + - Server-side anti-rug-pull: on every granted-tool call the live manifest hash is compared + to the stored `toolsHash`; a mismatch re-pends the grant to `requested` BEFORE any call + succeeds. + - Agent-side anti-rug-pull: `reconcileReplaceApproval` now forces a `granted` grant back to + `requested` on ANY `tools`/`toolsHash` mutation (not just status flips) — closing the + red-team hole where an agent could append a tool id to a granted grant through + `workspace.replace` or import. + - Partial grants: `dashboard.capability.approve` gains an optional `tools` subset; the + decision applies to the intersection with the requested set and the granted subset gets + its OWN hash (`McpBroker.hashToolSubset`, injected as `capabilityToolsHash`). + - Approvals console: capability rows surface their requested tool ids for per-tool selection + (approve-all = one click); the core transform + lit renderer + strings render it. + + **Pending-action engine (SPEC §18, [#41](https://github.com/100yenadmin/boardstate/issues/41))** + + - In-memory pending-action registry. `dashboard.action.invoke` AND-gates a call (granted at + invoke time + connector configured + hash unchanged): a `readOnly` granted tool executes + directly; a mutation parks as a `PendingActionRecord` and returns `{ pending: true, id, +expiresAt }`. `dashboard.action.confirm`/`dashboard.action.deny` are operator-only + (`OPERATOR_ONLY_METHODS`) — a networked client can directly execute only `readOnly` tools. + - TTL expiry (~5 min), single-shot terminal states (a replay of a terminal id errors), + server-side invoke rate limiting (prompt-gate discipline), an audit entry per invoke + + decision, and lifecycle broadcasts on `dashboard.action.changed`. + - `confirmAndExecute(id)` is exposed as the awaitable an agent-mediated call (M5c-1) blocks + on: it resolves with the tool result on confirm and rejects on deny/expiry. + + The engine consumes the broker through the narrow structural `ActionBroker` interface — + `@boardstate/broker` never enters `@boardstate/server` (no dependency cycle); the real + `McpBroker` fits it structurally. SPEC §17.1/§18 normative text filled where the schema + train ([#39](https://github.com/100yenadmin/boardstate/issues/39)) left implementation-pending markers. + +### Patch Changes + +- [`c895241`](https://github.com/100yenadmin/boardstate/commit/c8952418b9fd2b64a2a014927476502899d07938) - Security: the `dashboard_workspace_replace` agent tool now passes the structural + replace gate (`reconcileReplaceApproval`), so an agent can no longer self-grant a + capability by writing `status: "granted"` into `capabilitiesRegistry`. Only + `dashboard.capability.approve` (operator-only) grants. The RPC replace path was + already gated; this closes the agent-tool path. +- Updated dependencies [[`b05c7cd`](https://github.com/100yenadmin/boardstate/commit/b05c7cd5c50d10b83374bad0dde92c128cd00470), [`a0feba7`](https://github.com/100yenadmin/boardstate/commit/a0feba7dc3939c577387c0509aa3fb1ba710e477)]: + - @boardstate/schema@1.2.0 + - @boardstate/core@1.2.0 + ## 1.1.0 ### Patch Changes diff --git a/packages/server/package.json b/packages/server/package.json index 0df3063..4b1cb95 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@boardstate/server", - "version": "1.1.0", + "version": "1.2.0", "description": "The Boardstate dashboard.* control plane, agent tools, widget serving, CLI", "type": "module", "license": "MIT",