@arnilo/prism 0.1.0 → 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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.2] - 2026-08-10
4
+
5
+ ### Changed
6
+ - **Release 0.1.2 (plan 014)** is the Alibaba Cloud provider enrichment patch on the frozen 0.1.x line, additive-only vs 0.1.1 (freeze manifest `scripts/phase14-freeze-manifest.json`): (1) **embeddings** — `createAlibabaEmbedder` in `@arnilo/prism-provider-alibaba` over the OpenAI-compatible `POST {base}/embeddings` (text-embedding-v3/v4), a structural `Embedder` assignable to `@arnilo/prism-memory`'s without a dependency; inputs chunked at the DashScope cap (10/request), vectors in input order, dimensions 64–2048 (default 1024) + `encoding_format` passthrough, key resolved per call and redacted from errors; (2) **video input** — `file` blocks with `video/*` media types serialize to compatible-mode `video_url` content parts on Qwen-VL models, gated on the `file` input capability (`mapAlibabaModel` advertises `["text", "image", "file"]` for the qwen-vl family); (3) **documented deferrals** — document input (compatible path is the OpenAI Files API `file-extract` + `fileid://` reference, an upload/status lifecycle) and rerank (only workspace-dedicated `compatible-api/v1/reranks` exists, not on the public presets) are recorded in the verified decision table in [docs/providers/alibaba.md](docs/providers/alibaba.md) as demand-gated follow-ups; (4) **opt-in live probe** — `PRISM_LIVE_DASHSCOPE_KEY`-gated `test:live` script (skips when absent, never in CI). Store compatibility with 0.1.1: **compatible, no migration**; declaration surface additive-only vs the frozen 0.1.x contract.
7
+
8
+ ## [0.1.1] - 2026-08-10
9
+
10
+ ### Changed
11
+ - **Release 0.1.1 (plan 013)** is the post-release hardening patch on the frozen 0.1.x line, five scoped fixes and no new public packages/exports (freeze manifest `scripts/phase13-freeze-manifest.json`): (1) **build single-flight** — `npm run clean` removed from `npm run build` (standalone `npm run clean`; concurrent tsc is idempotent, the destructive `rm -rf` race is gone); (2) **deterministic MCP SSE relay test** — `relayStatelessBody` extracted as an internal export in `@arnilo/prism-mcp` with unit + E2E coverage (`packages/mcp/src/__tests__/sse-relay.test.ts`), closing the plan 011 relay compromise for the stateless path; (3) **combined coverage summary** — `scripts/coverage-summary.mjs` runs the core gate + 41 workspace suites and prints one labeled table (appended to `test:coverage`); (4) **canonical manifest-count narrative** — 49 publishable manifests = root + 48 workspace (14 provider + 9 `prism-*` + 25 capability), one statement in [docs/release-and-install.md](docs/release-and-install.md) with a tripwire; (5) **ACP modes/config ownership-scoped persistence guidance** — the agent never persists `modeId`/`configValues`; host stores MUST key by `sessions.ownership` (cross-tenant restore rejects `ERR_PRISM_ACP_INPUT`), asserted in `acp-modes-config.test.ts`. Store compatibility with 0.1.0: **compatible, no migration**; declaration surface additive-only vs the frozen 0.1.x contract (see [docs/migration.md](docs/migration.md) `0.1.0 → 0.1.1`).
12
+
3
13
  ## [0.1.0] - 2026-08-09
4
14
 
5
15
  ### Changed
package/dist/index.d.ts CHANGED
@@ -105,5 +105,5 @@ export { createToolParameterValidator, createToolRegistry, dispatchToolCall, fil
105
105
  export type { ResolvedUseCaseModel, ResolveUseCaseModelInput, UseCaseModelBinding, } from "./use-case-model.js";
106
106
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
107
107
  export declare const name = "prism";
108
- export declare const version = "0.1.0";
108
+ export declare const version = "0.1.2";
109
109
  export declare const description = "Agent harness for AI providers, agents, sessions, and tools.";
package/dist/index.js CHANGED
@@ -57,6 +57,6 @@ export { DEFAULT_TOOL_RESULT_FOLD_MAX_SUMMARY_BYTES, DEFAULT_TOOL_RESULT_FOLD_MI
57
57
  export { createToolParameterValidator, createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
58
58
  export { resolveUseCaseModel, resolveUseCaseModelBinding, useCaseCredentialProviderId, } from "./use-case-model.js";
59
59
  export const name = "prism";
60
- export const version = "0.1.0";
60
+ export const version = "0.1.2";
61
61
  export const description = "Agent harness for AI providers, agents, sessions, and tools.";
62
62
  //# sourceMappingURL=index.js.map
@@ -1,6 +1,6 @@
1
1
  # 0.1.0 / 1.0 Readiness Gates
2
2
 
3
- Status: **0.1.0** is the current release line (Phase 12 release-candidate hardening; plan 012); **1.0** readiness remains operator-gated, not automatic.
3
+ Status: **0.1.1** is the current release line (plan 013 hardening patch on the frozen 0.1.x line; plan 012 release-candidate hardening); **1.0** readiness remains operator-gated, not automatic.
4
4
 
5
5
  This page distills runnable readiness gates into one command-per-gate table.
6
6
  The **Last evidence** column records the 0.1.0-tree snapshot (plan 012 Tasks
@@ -15,13 +15,26 @@ Evidence trail: [`docs/review-coverage-2026-07-26-phase-11.md`](./review-coverag
15
15
  [`docs/migration.md`](./migration.md), [`docs/performance.md`](./performance.md),
16
16
  [`docs/public-contracts.md`](./public-contracts.md) (frozen 0.1.x contract).
17
17
  Historical release lines (0.0.16 floor → 0.0.27 Phase 10 ACP interop → 0.1.0)
18
- keep their per-phase evidence in the pages above; this page records the 0.1.0 snapshot.
18
+ keep their per-phase evidence in the pages above; this page records the 0.1.1
19
+ snapshot (plan 013) with the 0.1.0 table below as the previous line.
20
+
21
+ ## Current line (0.1.1)
22
+
23
+ | Item | Status |
24
+ |---|---|
25
+ | Published graph | **49** publishable manifests at exact **0.1.1** (root + 48 workspace packages; `docs/release-and-install.md`) |
26
+ | Plan 013 hardening patch | Five scoped fixes (plan 013 freeze `scripts/phase13-freeze-manifest.json`): build single-flight (`npm run clean` standalone), deterministic MCP SSE relay test (`relayStatelessBody` internal export, `sse-relay.test.ts`), combined coverage summary (`scripts/coverage-summary.mjs`, core gate the only hard threshold), canonical manifest-count narrative (49 = root + 48: 14 provider + 9 prism-* + 25 capability), ACP modes/config ownership-scoped persistence guidance (agent never persists them; host stores key by `sessions.ownership`, cross-tenant restore rejects `ERR_PRISM_ACP_INPUT`) |
27
+ | Upgrade path | `docs/migration.md` `0.1.0 → 0.1.1` (additive, no migration); store-compatible both directions |
28
+ | Compat promise | Additive-only vs the frozen 0.1.x contract; `scripts/compat-baseline` regenerated at 0.1.1 (single version-literal delta + one additive internal relay export), zero breaking deltas |
29
+ | Security policy | `npm audit --audit-level=moderate` 0 at 0.1.1; threat-suites leg unchanged (plan 012) |
30
+ | Docs freeze | tripwires green including the manifest-count tripwire and the plan 013 Task 6 handoff/migration tripwire |
31
+ | Previous line | the **0.1.0** table below keeps the plan 012 snapshot; the **0.0.16** values remain the historical network-free floor |
19
32
 
20
33
  ## Current line (0.1.0)
21
34
 
22
35
  | Item | Status |
23
36
  |---|---|
24
- | Published graph | **48** publishable manifests at exact **0.1.0** (root + 48 workspace packages; `docs/release-and-install.md`) |
37
+ | Published graph | **49** publishable manifests at exact **0.1.0** (root + 48 workspace packages; `docs/release-and-install.md`) |
25
38
  | Phase 12 RC hardening | Freeze manifest (`scripts/phase12-freeze-manifest.json`): no new packages/exports/migrations/dependencies, additive-only compat promise vs `scripts/compat-baseline`; compatibility/support matrix machine-checked (Node 20+24 measured, PostgreSQL 16, linux-x64, protocol SDK pins) |
26
39
  | Upgrade path | `docs/migration.md` `0.0.28 → 0.1.0` (no migration) + full `0.0.17 → 0.1.0` upgrade matrix (compatible / tested migration / tested refusal per release line) |
27
40
  | Packed-install e2e journeys | enterprise + coding journeys install the exact packed 0.1.0 manifest graph into fresh consumers (`scripts/e2e-*-journey.test.mjs`, in `npm test`) |
@@ -35,7 +48,7 @@ keep their per-phase evidence in the pages above; this page records the 0.1.0 sn
35
48
 
36
49
  | Gate | Command | Last evidence (0.1.0 tree; 0.0.16 floor where noted) | Owner |
37
50
  |---|---|---|---|
38
- | Full quality gate | `npm run sdk:ready` | RC=0 at 0.1.0: typecheck (+examples), lint 0, format clean, full test, coverage, pack, release:gate (clean-checkout run is part of the operator release checklist) | CI |
51
+ | Full quality gate | `npm run sdk:ready` | RC=0 at 0.1.0: typecheck (+examples), lint 0, format clean, full test, coverage, pack, release:gate (clean-checkout run is part of the operator release checklist). `npm run test:coverage` also prints the combined coverage summary (core + 41 workspace suites, additive reporting; core gate lines≥60 / functions≥70 / branches≥75 is the only hard threshold — plan 013 Task 3) | CI |
39
52
  | Exact version graph | `node scripts/release.mjs check --version 0.1.0` | pass at 0.1.0: exact versions/ranges/lockfile/access + registry-collision check, **49** manifests | CI + operator |
40
53
  | Frozen public API surface + compat gate | `node scripts/release.mjs gate` | 0 breaks / 0 errors vs checked-in baselines (`scripts/compat-baseline/`); additive-only delta (empty at the 0.0.28 → 0.1.0 bump) | CI |
41
54
  | Migration coverage + docs tripwires | `node --test dist/__tests__/docs.test.js` | 121/121 at 0.1.0; `docs/migration.md` sections tripwired per release line | Maintainer |
package/docs/acp.md CHANGED
@@ -109,6 +109,32 @@ const agent = createPrismAcpAgent({
109
109
  - **Lifecycle wiring.** Pass your `createCodingLifecycleEmitter()` as `coding.lifecycle`; `file_changed` etc. then flow to streaming sessions. `configuration_changed` broadcasts `config_option_update` (agent-message fallback if the SDK rejects the kind).
110
110
  - **Stream budgets.** Every lifecycle update counts against the same per-run stream event/byte budget as prompt updates; overflowing closes the update, never the run.
111
111
 
112
+ ### Persistence and ownership
113
+
114
+ - **The agent never persists `modeId`/`configValues`.** Defaults are recomputed per session from the `modes`/`configOptions` seams — a fresh `session/new`, `load`, or `resume` always starts from `defaultModeId` / option `defaultValue`, and the agent's per-session registry is in-memory only. Persisting mode/config across sessions is a **host** decision, and host-side persistence MUST be ownership-scoped.
115
+ - **Host persistence MUST key by `sessions.ownership`.** `authorize` binds transport identity to ownership; a host store that persists `modeId`/`configValues` must refuse any restore whose stored ownership differs from the current session's ownership — a `sessionId` alone is never a sufficient key (session ids may collide across tenants). A cross-tenant restore rejects with `ERR_PRISM_ACP_INPUT` and never returns the other tenant's mode/config.
116
+ - **Ownership-scoped restore (host-owned store).** The store is keyed by `sessionId` and records the owning `userId`; restore refuses on mismatch (this exact pattern is asserted in `packages/ag-ui/src/__tests__/acp-modes-config.test.ts`):
117
+
118
+ ```ts
119
+ // Host-owned store; the agent is never asked to persist anything.
120
+ class HostModeConfigStore {
121
+ private readonly entries = new Map<string, { userId: string; modeId?: string; configValues: Record<string, boolean | string> }>();
122
+ save(userId: string, sessionId: string, state: { modeId?: string; configValues: Record<string, boolean | string> }): void {
123
+ this.entries.set(sessionId, { userId, ...state });
124
+ }
125
+ restore(userId: string, sessionId: string): { modeId?: string; configValues: Record<string, boolean | string> } | undefined {
126
+ const entry = this.entries.get(sessionId);
127
+ if (entry && entry.userId !== userId) {
128
+ throw new AcpError("ERR_PRISM_ACP_INPUT", `mode/config load rejected: ownership mismatch for session '${sessionId}'`);
129
+ }
130
+ return entry; // absent or cross-tenant -> nothing restored, fail closed
131
+ }
132
+ }
133
+ ```
134
+
135
+ Because the agent recomputes defaults on every `load`/`resume`, a host that restores state re-applies it after load through the same gated seams (`session/set_mode`, `session/set_config_option` — both run the `apply`/`onChange` hooks) and must refuse cross-tenant loads at the `authorize` seam first (falsy `authorize` = `Unauthorized ACP session`, before any mode/config state is reachable).
136
+ - **Agent-owned persistence is 0.2.0.** A durable, ownership-scoped ACP session store (agent-side persistence of mode/config and session state) is roadmap 0.2.0 Module E, demand-gated; on the 0.1.x line the agent stays a thin per-session registry. See the [Host security guide](host-security.md) fail-closed checklist for the ACP boundary rows.
137
+
112
138
  ## Security and performance notes
113
139
 
114
140
  - **Untrusted client input.** Client-supplied paths, `additionalDirectories`, MCP server configs, terminal env/args, and media are validated at the boundary: count/byte caps, ownership-scoped sessions, path policy via the `sessions.additionalDirectories` seam, MCP servers only through host `select` (never auto-connected), UNSTABLE `acp` transport always rejected.
@@ -219,7 +219,7 @@ Every durable `AgentEventSource` page/subscribe and tool-effect claim rechecks e
219
219
  ## Related APIs
220
220
 
221
221
  - [Web-standard server handler](server.md): remote agent/workflow route, ownership, limits, abort, and deployment boundary.
222
- - [Frontend interoperability (AG-UI and ACP)](ag-ui.md): authorize every protocol selector/operation; full AG-UI input/output only through bounded host allow-lists; exact interrupt/version resume; redacted, ownership-scoped replay. [ACP coding-host interop](acp.md): untrusted client fs/terminal/paths/MCP configs are boundary-validated (caps + host seams); client MCP servers never auto-connect; mode switches only narrow or host-authorized widen; updates are redacted and never carry raw tool I/O.
222
+ - [Frontend interoperability (AG-UI and ACP)](ag-ui.md): authorize every protocol selector/operation; full AG-UI input/output only through bounded host allow-lists; exact interrupt/version resume; redacted, ownership-scoped replay. [ACP coding-host interop](acp.md): untrusted client fs/terminal/paths/MCP configs are boundary-validated (caps + host seams); client MCP servers never auto-connect; mode switches only narrow or host-authorized widen; updates are redacted and never carry raw tool I/O; host-persisted modes/config MUST be ownership-scoped — cross-tenant restore rejects (`ERR_PRISM_ACP_INPUT`, [acp.md Persistence and ownership](acp.md#persistence-and-ownership)).
223
223
  - [Supervisor delegation](supervisors.md): local child permission/memory/budget boundary.
224
224
  - [A2A interoperability](a2a.md): remote card/auth/origin/signature boundary.
225
225
  - [Settings, auth, trust, and security controls](settings-auth-trust-security.md): low-level helpers and boundary hardening table.
package/docs/index.md CHANGED
@@ -99,7 +99,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
99
99
  - [Supervisor delegation](supervisors.md): optional explicit child allow-list, derived memory scopes, narrowing-only permissions, lifecycle hooks, nested delegation, cancellation, finite budgets, host-projected delegation telemetry, and separate A2A durable adapter boundary.
100
100
  - [A2A interoperability](a2a.md): A2A 1.0 JSON-RPC/HTTPS cards plus host-owned durable task get/list/cancel/subscribe, shared `AgentEventSource` task adapter, bounded rich parts/replay, principal-scoped push configs, exact-origin verified client, rich stream seam for explicit AG-UI fronting, and server-side `createAgUiA2AServer` exposure of a local AG-UI agent (0.0.26).
101
101
  - [Frontend interoperability (AG-UI and ACP)](ag-ui.md): optional `@arnilo/prism-ag-ui` full AG-UI 0.0.57 input/event/capability mapper, authorized Web handler/distributed source follow, opt-in A2UI painting middleware, explicit hardened MCP/MCP Apps/remote A2A adapters, a framework-free reference renderer subpath (`@arnilo/prism-ag-ui/renderer`, 0.0.26), and stable ACP sibling over shared redacted event and durable-approval seams; 0.0.14 adds reconnectable co-work events.
102
- - [ACP coding-host interop](acp.md): stable ACP v1 `createPrismAcpAgent()`/`createAcpEventMapper()` over `@agentclientprotocol/sdk@1.3.0` — capability advertisement is a pure function of host seams (sessions load/list/delete/resume/dirs, close always, prompt media/embedded, MCP http/sse), client fs/terminal adapters, modes and config options as host overlays, `CodingLifecycleEvent` mapping, four-outcome approvals with elicitation, and frozen caps (0.0.27).
102
+ - [ACP coding-host interop](acp.md): stable ACP v1 `createPrismAcpAgent()`/`createAcpEventMapper()` over `@agentclientprotocol/sdk@1.3.0` — capability advertisement is a pure function of host seams (sessions load/list/delete/resume/dirs, close always, prompt media/embedded, MCP http/sse), client fs/terminal adapters, modes and config options as host overlays, `CodingLifecycleEvent` mapping, four-outcome approvals with elicitation, and frozen caps (0.0.27); 0.1.1 adds ownership-scoped persistence guidance for host-persisted modes/config (plan 013 Task 5 — the agent never persists them).
103
103
  - [AG-UI adoption evaluation](ag-ui-adoption.md): official 0.0.57 input/event/capability matrix and shipped hardened MCP/MCP Apps/A2A handshake boundaries.
104
104
 
105
105
  ## CLI/RPC
@@ -129,7 +129,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
129
129
  - [Ponytail behavior integration](ponytail.md): optional `@arnilo/prism-ponytail` — upstream Ponytail skills/commands, `ponytail-mode` injector, session `ponytail-mode` persistence; resolves peer `@dietrichgebert/ponytail` or `upstreamPath`; opt-in (not in code/sdk profiles).
130
130
 
131
131
  ## Release and install
132
- - [Release and install](release-and-install.md): current **0.1.0** 48-package graph (Phase 12 release-candidate hardening; plan 012 — freeze manifest, compatibility matrix, upgrade matrix, packed-install e2e journeys, restart-recovery evidence, capacity envelopes, security policy), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, frozen 0.1.x compatibility and support matrix (Node/PostgreSQL/platform/provider/protocol pins and unsupported combinations, machine-checked against `scripts/phase12-freeze-manifest.json`), protected PostgreSQL gate, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates.
132
+ - [Release and install](release-and-install.md): current **0.1.2** 49-package graph (root + 48 workspace packages; plan 014 Alibaba provider enrichment on the frozen 0.1.x line — embeddings, video input, verified compatible-mode surface decision table; plan 013 post-release hardening — build single-flight, MCP SSE relay test, combined coverage summary, canonical manifest-count narrative, ACP modes/config persistence guidance; Phase 12 release-candidate hardening; plan 012 — freeze manifest, compatibility matrix, upgrade matrix, packed-install e2e journeys, restart-recovery evidence, capacity envelopes, security policy), exact-peer/install/tarball rules, deterministic resumable publication and publish dry-run, frozen 0.1.x compatibility and support matrix (Node/PostgreSQL/platform/provider/protocol pins and unsupported combinations, machine-checked against `scripts/phase12-freeze-manifest.json`), protected PostgreSQL gate, pinned supply-chain gates, offline tests, the 0.0.15 provider/AI-SDK/RAG/memory protected live-canary matrix, and sandbox-browser Docker/Playwright gates.
133
133
  - [0.1.0 / 1.0 readiness gates](0.1.0-readiness.md): command-per-gate 1.0 readiness table — frozen API surface + compat gate, migration/docs tripwires, budget table, live-suite matrix, security matrix, current-line status (**0.0.23** published target), signed-publication/live-canary prerequisites for 1.0, and Phase 12 demand-evidence entry criteria.
134
134
  - [Review coverage (2026-07-26 Phase 11)](review-coverage-2026-07-26-phase-11.md): Plan 079 evidence freeze — baseline size/startup/benchmark budgets, hotspot domain extraction table, confirmed duplication survivors (redactor/cleanJson/row-codecs/checkpoints/exec-runner/approval/ownership), profile adoption recommendations, and tarball artifact-diet findings for 0.0.16.
135
135
  - [Review coverage (2026-07-26 Phase 10)](review-coverage-2026-07-26-phase-10.md): Plan 078 evidence freeze — OpenAI hosted tools/continuation/realtime, AI SDK version matrix, remaining provider metadata parity, RAG replaceSource/loaders/parsers/reranker/provenance/ingestion-status, memory export/rebuild/conformance, and 0.0.15 (43 → 43 manifests; no new package) release gates.
package/docs/migration.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Migration guide
2
2
 
3
+ ## 0.1.0 → 0.1.1 post-release hardening (additive, no migration)
4
+
5
+ Release **0.1.1** (plan 013) is a hardening patch on the frozen 0.1.x line: five scoped fixes — build single-flight (`npm run clean` removed from `npm run build`, standalone), deterministic MCP SSE relay test (`relayStatelessBody` internal export in `@arnilo/prism-mcp`, not in the package entry surface), combined core + workspace coverage summary (`scripts/coverage-summary.mjs`), canonical manifest-count narrative (49 publishable manifests = root + 48 workspace packages), and ACP modes/config ownership-scoped persistence guidance (the agent never persists `modeId`/`configValues`; host stores MUST key by `sessions.ownership`). **Store compatibility: compatible** — no persisted shape, event schema, or default behavior changed; the 0.0.28 → 0.1.0 → 0.1.1 lines all stay on the same checksum-protected contract, so no upgrade or rollback step exists (rollback = restore the 0.1.0 manifests/tag; stores never change). Declaration surface is additive-only vs the frozen 0.1.x contract (`scripts/compat-baseline` regenerated at 0.1.1 with zero breaking deltas, enforced by `node scripts/release.mjs gate`). No breaking defaults.
6
+
3
7
  ## 0.0.28 → 0.1.0 release-candidate hardening (no migration)
4
8
 
5
9
  Release **0.1.0** (Phase 12) is a release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (frozen in `scripts/phase12-freeze-manifest.json`; deviations require a recorded plan 012 Task 0 entry). No persisted shape, event schema, or default behavior changed. **Store compatibility: compatible** — session-store and enterprise PostgreSQL schemas stay at the checksum-protected contract shipped in 0.0.24–0.0.28; no upgrade or rollback step exists for 0.0.28 → 0.1.0. No breaking defaults. 0.1.x patch releases promise additive-only declaration deltas vs `scripts/compat-baseline` (enforced by `node scripts/release.mjs gate`).
@@ -29,12 +29,38 @@ serialization, dynamic model discovery, and explicit/implicit cache accounting.
29
29
  Do not use it for automatic credential discovery, setup-time catalog fetches, or
30
30
  real-network tests (live tests stay opt-in).
31
31
 
32
+ ## Compatible-mode surface (verified 2026-08-10)
33
+
34
+ Decision record for which DashScope / Model Studio surfaces are reachable through
35
+ OpenAI-compatible endpoints on the package's public presets. Sources retrieved
36
+ 2026-08-10; links in the table. This table is the authority for what the package
37
+ implements vs defers (plan 014 Task 1).
38
+
39
+ | Surface | OpenAI-compatible? | Verified route | Decision |
40
+ | --- | --- | --- | --- |
41
+ | Embeddings | Yes | `POST {base}/embeddings` on all public presets (intl/beijing/us); `text-embedding-v3`/`v4`; dimensions 64–2048 (default 1024); max 10 inputs per request, 8,192 tokens each | Implemented in 0.1.2 (`createAlibabaEmbedder`) |
42
+ | Video input | Yes | Chat content part `{"type":"video_url","video_url":{"url":…},"fps":2}` on Qwen-VL models; URL must be publicly reachable with correct `Content-Length`/`Content-Type`; `fps` 0.1–10 (default 2) | Implemented in 0.1.2 (video `file` blocks → `video_url`) |
43
+ | Document input | Partial | OpenAI Files API `POST {base}/files` (`purpose: "file-extract"`, ≤150 MB) then reference `fileid://<id>` as a system message (qwen-long, ≤100 files); no document content part exists in compatible mode; `doc_url` parts are native-only (qwen-doc-turbo) | Deferred — upload + status lifecycle, not a serialization mapping; demand-gated follow-up |
44
+ | Rerank | Partial | `POST {workspaceId}.{region}.maas.aliyuncs.com/compatible-api/v1/reranks` (`qwen3-rerank`, ≤500 documents, 4,000 tokens/item) — workspace-dedicated only, base path `compatible-api/v1` (not `compatible-mode/v1`); no rerank route on the public presets | Deferred — no route on public presets; workspace-dedicated route recorded for a future `baseUrl`-supplied reranker |
45
+ | Text-to-SQL | n/a | No dedicated endpoint; SQL generation is a chat prompt use case on `chat/completions` | Nothing to implement — covered by the existing chat provider |
46
+ | Async task polling | No | `X-DashScope-Async: enable` + `GET /api/v1/tasks/{id}` — native-only | Deferred (documented) |
47
+
48
+ Sources:
49
+
50
+ - OpenAI compatibility overview: <https://help.aliyun.com/en/model-studio/compatibility-of-openai-with-dashscope>
51
+ - Embeddings (models, dimensions): <https://www.alibabacloud.com/help/en/model-studio/models>; batch limits: <https://docs.qwencloud.com/resources/faq-embedding-reranking>
52
+ - Video input (`video_url` part): <https://help.aliyun.com/en/model-studio/qwen-api-via-openai-chat-completions>
53
+ - Document input (file-extract): <https://help.aliyun.com/en/model-studio/long-context-qwen-long> and <https://help.aliyun.com/en/model-studio/openai-file-interface>; native `doc_url`: <https://help.aliyun.com/en/model-studio/data-mining-qwen-doc>
54
+ - Rerank (`compatible-api/v1/reranks`): <https://www.alibabacloud.com/help/en/model-studio/rerank>
55
+ - Async task polling (native): <https://help.aliyun.com/en/model-studio/asynchronous-call-api-reference>
56
+
32
57
  ## Inputs / request
33
58
 
34
59
  ```ts
35
60
  import {
36
61
  createAlibabaProviderPackage,
37
62
  createAlibabaProvider,
63
+ createAlibabaEmbedder,
38
64
  listAlibabaModels,
39
65
  defineAlibabaModel,
40
66
  alibabaBaseUrl,
@@ -42,6 +68,7 @@ import {
42
68
 
43
69
  createAlibabaProviderPackage(options: AlibabaProviderPackageOptions): ProviderPackage
44
70
  createAlibabaProvider(options?: AlibabaProviderOptions): AIProvider
71
+ createAlibabaEmbedder(options: AlibabaEmbedderOptions): AlibabaEmbedder
45
72
  listAlibabaModels(options?: ListAlibabaModelsOptions): Promise<ModelConfig[]>
46
73
  defineAlibabaModel(config: AlibabaModelConfig): ModelConfig
47
74
  alibabaBaseUrl(options?: { baseUrl?: string; preset?: AlibabaBasePreset }): string
@@ -69,6 +96,70 @@ Workspace-dedicated endpoints
69
96
  (`https://{workspaceId}.{region}.maas.aliyuncs.com/compatible-mode/v1`) are supplied
70
97
  verbatim via `baseUrl`.
71
98
 
99
+ ## Embeddings
100
+
101
+ `createAlibabaEmbedder()` calls the OpenAI-compatible `POST {base}/embeddings`
102
+ (text-embedding-v3/v4) and returns a structural `Embedder` — assignable to
103
+ `@arnilo/prism-memory`'s `Embedder` without importing it (the package stays
104
+ dependency-free).
105
+
106
+ ```ts
107
+ import { createAlibabaEmbedder } from "@arnilo/prism-provider-alibaba";
108
+
109
+ const embedder = createAlibabaEmbedder({
110
+ apiKey: process.env.DASHSCOPE_API_KEY,
111
+ model: "text-embedding-v4",
112
+ dimensions: 1024, // 64–2048, default 1024
113
+ });
114
+
115
+ const vectors = await embedder.embed(["hello", "world"]); // number[2][1024]
116
+ ```
117
+
118
+ - Inputs are chunked at `ALIBABA_EMBEDDING_BATCH_SIZE` (10) per request — the
119
+ DashScope cap (8,192 tokens per text) — and vectors are returned in input order.
120
+ Empty input returns `[]` without a fetch.
121
+ - `dimensions` (64–2048, default 1024) and `encoding_format` (default `float`)
122
+ pass through on the wire; `baseUrl`/`preset`/`fetch`/`headers` mirror the
123
+ provider options.
124
+ - Caller-gated like discovery: construction never fetches; the key is resolved per
125
+ call and redacted from all thrown errors; provider-owned headers
126
+ (`authorization`, `content-type`) cannot be overridden by caller headers.
127
+
128
+ ## Multimodal input
129
+
130
+ Video input (0.1.2): a `file` content block with a `video/*` media type serializes
131
+ to the compatible-mode `video_url` content part on Qwen-VL models:
132
+
133
+ ```ts
134
+ // host side
135
+ { type: "file", mediaType: "video/mp4", url: "https://example.com/clip.mp4" }
136
+ // wire shape emitted by serializeAlibabaMessage
137
+ { "type": "video_url", "video_url": { "url": "https://example.com/clip.mp4" } }
138
+ ```
139
+
140
+ - Gated on the `file` input capability (no core `"video"` capability in 0.1.2);
141
+ `mapAlibabaModel()` advertises `["text", "image", "file"]` for the qwen-vl
142
+ family; `defineAlibabaModel` capability overrides still win.
143
+ - `url` (publicly reachable, correct `Content-Length`/`Content-Type`) or base64
144
+ `data:` URL pass through; `resourceUri`-only blocks throw before fetch (the
145
+ provider never fetches). `fps` defaults upstream to 2.0.
146
+ - Document input is **deferred**: compatible-mode chat has no document content
147
+ part — the compatible path is the OpenAI Files API (`purpose: file-extract`,
148
+ ≤150 MB) plus a `fileid://<id>` system-message reference (qwen-long, ≤100
149
+ files), an upload/status lifecycle outside serialization. `document` and
150
+ non-video `file` blocks keep failing before fetch.
151
+
152
+ ## Rerank (deferred)
153
+
154
+ No OpenAI-compatible rerank route exists on the public presets, so 0.1.2 ships no
155
+ reranker. The verified compatible route is workspace-dedicated only:
156
+ `POST {workspaceId}.{region}.maas.aliyuncs.com/compatible-api/v1/reranks`
157
+ (`qwen3-rerank`, ≤500 documents, 4,000 tokens/item; base path `compatible-api/v1`,
158
+ not `compatible-mode/v1`). A future `createAlibabaReranker` over that route is
159
+ demand-gated: implement when a caller supplies a workspace-dedicated `baseUrl` and
160
+ needs rerank (structural `Reranker` shape from `@arnilo/prism-rag`, no new
161
+ dependency). Multimodal rerank (`qwen3-vl-rerank`) is native-only and stays out.
162
+
72
163
  ## Outputs / response / events
73
164
 
74
165
  | Surface | Behavior |
@@ -163,6 +254,10 @@ await kernel.load([
163
254
  - The API key is resolved per request via `resolveCredentialValue` and sent only as
164
255
  `Authorization: Bearer`; keys are redacted from all thrown errors (including
165
256
  discovery failures). No local filesystem paths enter request payloads.
257
+ - Opt-in live probe (never part of `npm test`/CI):
258
+ `PRISM_LIVE_DASHSCOPE_KEY=… npm run test:live --workspace @arnilo/prism-provider-alibaba`
259
+ exercises an embeddings round-trip against the real endpoint (model override via
260
+ `PRISM_LIVE_DASHSCOPE_MODEL`); absent env = documented skip, never a failure.
166
261
  - Caller-supplied `ProviderRequest.options.headers` can add non-owned headers, but
167
262
  provider-owned headers (`content-type`, `authorization`) are applied last and
168
263
  cannot be overridden.
@@ -453,6 +453,13 @@ exports only. **0.1.x patch promise:** additive-only declaration deltas vs the
453
453
  0.1.0 baselines, enforced by `node scripts/release.mjs gate`; a genuine break
454
454
  requires `--allow-break` plus a `docs/migration.md` entry naming the version.
455
455
 
456
+ **0.1.1 verification (plan 013 Task 6).** The 0.1.1 hardening patch re-ran the
457
+ gate against the frozen contract: `scripts/compat-baseline` regenerated with
458
+ zero breaking deltas — a single version-literal change in the `@arnilo/prism`
459
+ entry and one additive internal export (`relayStatelessBody` in
460
+ `@arnilo/prism-mcp`, not re-exported from the package entry surface). The
461
+ additive-only promise holds; no contract text changes.
462
+
456
463
  **Events.** The `AgentEvent` union (`agent_*`/`artifact_*`/`tool_*` variants),
457
464
  the durable `AgentEventRecord`/`DurableAgentEventRecord` shapes
458
465
  (`turn_started`, `turn_finished`, `tool_execution_started`, `message_finished`;
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## What it does
4
4
 
5
- Prism is published as one core package, forty-one first-party capability packages, and six pure-manifest family/profile packages (**48** publishable manifests total). This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
5
+ Prism is published as **49 publishable manifests**: the root `@arnilo/prism` core package plus **48 workspace packages** — 14 provider adapters, 9 `prism-*` family/profile packages, and 25 capability packages. (Regenerate the counts: `ls packages/*/package.json | wc -l` = 48 workspace; `ls -d packages/provider-*/ | wc -l` = 14; `ls -d packages/prism-*/ | wc -l` = 9; capability = 48 − 14 − 9 = 25; publishable = root + 48 = 49.) This page describes how they are packed, what each tarball contains, how to install them, the required `@arnilo/prism` peer dependency, the release workflow, and the offline test budget. The measurable 1.0 readiness gates (command-per-gate) live in [`0.1.0-readiness.md`](./0.1.0-readiness.md).
6
6
 
7
7
  Core `@arnilo/prism` ships runtime, CLI, templates, and docs. Every code package has a required `@arnilo/prism@0.1.0` peer; profiles are pure manifests. Installation activates no provider, listener, database, browser, credential, or tool capability.
8
8
 
9
- Current **48** publishable manifests:
9
+ Current **49** publishable manifests (root + 48 workspace packages):
10
10
 
11
11
  `@arnilo/prism`, `@arnilo/prism-ag-ui`, `@arnilo/prism-browser`, `@arnilo/prism-coding-agent`, `@arnilo/prism-coding-security`, `@arnilo/prism-compaction-llm`
12
12
  `@arnilo/prism-compaction-observational-memory`, `@arnilo/prism-credentials-node`, `@arnilo/prism-enterprise-postgres`, `@arnilo/prism-evals`, `@arnilo/prism-mcp`, `@arnilo/prism-memory`
@@ -42,6 +42,7 @@ Consumers install the core package for the runtime and add first-party packages
42
42
  | Install bounded web research tools | `npm install @arnilo/prism @arnilo/prism-web-tools @arnilo/prism-tool-validator-json-schema` |
43
43
  | Install browser automation tools | `npm install @arnilo/prism @arnilo/prism-browser playwright-core@1.61.0` |
44
44
  | Build everything (core + workspaces) | `npm run build` |
45
+ | Delete all build output (explicit one-shot, see build notes) | `npm run clean` |
45
46
  | Run the default (network-free) test suite | `npm test` |
46
47
  | Dry-run pack core + every package | `npm run pack:dry-run` |
47
48
  | Local mirror of the release verify gate | `npm run release:dry-run` |
@@ -51,7 +52,11 @@ Consumers install the core package for the runtime and add first-party packages
51
52
  | Protected PostgreSQL enterprise suite | `PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres` |
52
53
  | Full SDK readiness gate (typecheck + offline tests + pack) | `npm run sdk:ready` |
53
54
 
54
- Public core import specifiers (from the root `exports` map):
55
+ > **Build notes (0.1.1+).** `npm run build` no longer runs `npm run clean` first: concurrent builds/tests (`npm test`, `npm run typecheck`) are now race-free because the only destructive step was the `rm -rf` clean, and concurrent `tsc` is write-only and idempotent on identical input (two processes emitting the same files end byte-identical regardless of interleaving).
56
+ >
57
+ > `ponytail:` concurrent `tsc` is idempotent on identical input, so no single-flight lock is needed; orphaned `dist/` files from deleted sources fail loudly on the next `node --test` (broken imports) and are filtered from tarballs by the `files` allowlists; run `npm run clean` after source deletions or branch switches; `tsc --build` (0.2.0 Module F) auto-cleans orphans.
58
+
59
+ Run `npm run clean` explicitly after deleting source files or switching branches: a deleted `src/__tests__/*.test.ts` leaves an orphan `dist/__tests__/*.test.js` (tsc never auto-cleans). If the orphan's import chain still resolves it keeps running as a stale test — silent staleness, which is exactly what the explicit clean prevents — and if the chain is broken the next `node --test dist/__tests__/*.test.js` fails loudly (`ERR_MODULE_NOT_FOUND`), never silently swallowed. A fresh `npm run clean && npm run build` and the new `npm run build` from a clean state produce byte-identical `dist/` (tsc overwrites per-file outputs).
55
60
 
56
61
  | Specifier | Resolves to |
57
62
  | --- | --- |
@@ -151,7 +156,7 @@ For SDK readiness, run the same one-command gate directly. It composes existing
151
156
  npm run sdk:ready
152
157
  ```
153
158
 
154
- Release publication derives all **48** manifests from the workspace once, validates exact `0.1.0` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.1.0` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
159
+ Release publication derives all **49** manifests from the workspace once, validates exact `0.1.0` manifest/lockfile/internal ranges, then uses deterministic dependency order. `release:check` requires a clean commit tagged `v0.1.0` and rejects any existing registry version. `release:publish --resume` skips only registry versions whose internal dependency fingerprint matches the local manifest; conflicting versions fail closed. Each attempted package is written immediately to the JSON report, so a failed job can rerun safely. `--dry-run` performs registry availability checks and invokes `npm publish --dry-run` with explicit public access, provenance, and `latest` tag, but does not publish.
155
160
 
156
161
  ```bash
157
162
  npm run release:check -- --version 0.1.0
@@ -172,7 +177,7 @@ PRISM_LIVE_PROVIDER_TESTS=1 npm run test --workspaces --if-present
172
177
 
173
178
  ### 0.1.0 publish handoff (plan 012 Task 7)
174
179
 
175
- **Decision: GO when the operator prerequisites below are recorded.** Release **0.1.0** (Phase 12, plan 012) is the release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (freeze manifest `scripts/phase12-freeze-manifest.json`). Publishable graph stays **48** manifests at exact **0.1.0**. Store compatibility with 0.0.28: **compatible, no migration** ([migration](migration.md) `0.0.28 → 0.1.0`); the full `0.0.17 → 0.1.0` upgrade matrix is in the same page. All evidence for the tree under publication is recorded in [0.1.0 readiness](0.1.0-readiness.md) (capacity envelopes, restart-recovery, e2e journeys, threat-suites leg, audit at moderate).
180
+ **Decision: GO when the operator prerequisites below are recorded.** Release **0.1.0** (Phase 12, plan 012) is the release-candidate hardening cut of the **0.0.28** graph: no new packages, public exports, schema migrations, or runtime dependencies (freeze manifest `scripts/phase12-freeze-manifest.json`). Publishable graph stays **49** publishable manifests (root + 48 workspace packages) at exact **0.1.0**. Store compatibility with 0.0.28: **compatible, no migration** ([migration](migration.md) `0.0.28 → 0.1.0`); the full `0.0.17 → 0.1.0` upgrade matrix is in the same page. All evidence for the tree under publication is recorded in [0.1.0 readiness](0.1.0-readiness.md) (capacity envelopes, restart-recovery, e2e journeys, threat-suites leg, audit at moderate).
176
181
 
177
182
  ```bash
178
183
  # Operator prerequisites (each a named blocked gate — none may be skipped):
@@ -204,9 +209,73 @@ git push origin v0.1.0 # tag push triggers release.yml publish job (prove
204
209
 
205
210
  **Rollback notes.** `release:publish --version 0.1.0 --resume --report release-artifacts/publish-report.json` resumes an interrupted publication and skips only registry versions whose internal dependency fingerprint matches the local manifest. A failed package aborts the run with its status written to the report; re-run after fixing the cause. npm cannot unpublish the `0.1.0` line after 72 hours — a post-publication defect ships as a `0.1.x` patch (additive-only compat promise, `release:gate` enforced), or as a documented break in the next line with a `docs/migration.md` entry. `0.1.0` is store-compatible with `0.0.28` in both directions (no migration ran), so an operator may defer adoption of `0.1.0` without a database rollback.
206
211
 
212
+ ### 0.1.1 publish handoff (plan 013 Task 6)
213
+
214
+ **Decision: GO when the operator prerequisites below are recorded.** Release **0.1.1** (plan 013) is the post-release hardening patch on the frozen 0.1.x line: five scoped fixes — build single-flight (clean removed from `npm run build`; standalone `npm run clean`), deterministic MCP SSE relay test (`relayStatelessBody` internal export in `@arnilo/prism-mcp`, not in the package entry surface), combined core + workspace coverage summary (`scripts/coverage-summary.mjs`, appended to `test:coverage`), canonical manifest-count narrative (49 publishable manifests = root + 48 workspace packages), and ACP modes/config ownership-scoped persistence guidance (the agent never persists them; host stores MUST key by `sessions.ownership`). Publishable graph stays **49** manifests (root + 48 workspace) at exact **0.1.1**. Store compatibility with 0.1.0: **compatible, no migration** ([migration](migration.md) `0.1.0 → 0.1.1`); declaration surface additive-only vs the frozen 0.1.x contract (`scripts/compat-baseline` regenerated at 0.1.1 with zero breaking deltas).
215
+
216
+ ```bash
217
+ # Operator prerequisites (each a named blocked gate — none may be skipped):
218
+ # 1. protected live-canary matrix green (live-canaries.yml, canary-report.json retained)
219
+ # 2. PostgreSQL + keychain protected suites green (test:postgres, keychain suite)
220
+ # 3. CodeQL SAST green on the release commit (security.yml / release.yml codeql-release)
221
+ # 4. npm OIDC trusted publishing identity authenticated (NPM_TOKEN with id-token, provenance)
222
+
223
+ git diff --check
224
+ npm ci
225
+ npm run sdk:ready # includes typecheck, lint, format, full test, coverage, pack, release:gate
226
+ npm run security:threat-suites
227
+ PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres # Phase 7 + Phase 12 restart-recovery
228
+ npm audit --audit-level=moderate
229
+ npm run release:check -- --version 0.1.1 --report /tmp/prism-0.1.1-preflight.json
230
+ npm run release:publish -- --version 0.1.1 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.1.1-dry-run.json
231
+ # run the dry-run twice and diff the reports: deterministic, byte-identical
232
+
233
+ # Sign the release on the clean tagged tree (operator GPG key):
234
+ git tag -s v0.1.1 -m "Prism 0.1.1"
235
+ git verify-tag v0.1.1
236
+ git push origin v0.1.1 # tag push triggers release.yml publish job (provenance, attestations)
237
+
238
+ # Real publication never bypasses the gates: release.mjs refuses
239
+ # --allow-dirty/--allow-untagged without --dry-run.
240
+ ```
241
+
242
+ **Rollback notes.** `release:publish --version 0.1.1 --resume --report release-artifacts/publish-report.json` resumes an interrupted publication and skips only registry versions whose internal dependency fingerprint matches the local manifest. A failed package aborts the run with its status written to the report; re-run after fixing the cause. npm cannot unpublish the `0.1.1` line after 72 hours — a post-publication defect ships as a `0.1.x` patch (additive-only compat promise, `release:gate` enforced), or as a documented break in the next line with a `docs/migration.md` entry. `0.1.1` is store-compatible with `0.1.0` in **both directions** (no migration ran — same checksum-protected contract), so an operator may defer or roll back the patch without a database rollback.
243
+
244
+ ### 0.1.2 publish handoff (plan 014 Task 6)
245
+
246
+ **Decision: GO when the operator prerequisites below are recorded.** Release **0.1.2** (plan 014) is the Alibaba Cloud provider enrichment patch on the frozen 0.1.x line: `createAlibabaEmbedder` over the OpenAI-compatible `POST {base}/embeddings` (structural `Embedder`, no new dependency), video input via `video_url` content parts on Qwen-VL models (gated on the `file` input capability), a verified compatible-mode surface decision table in [providers/alibaba.md](providers/alibaba.md) (document input and rerank deferred as demand-gated follow-ups), and an opt-in `PRISM_LIVE_DASHSCOPE_KEY` live probe. Publishable graph stays **49** manifests (root + 48 workspace) at exact **0.1.2**. Store compatibility with 0.1.1: **compatible, no migration**; declaration surface additive-only vs the frozen 0.1.x contract (`scripts/compat-baseline` regenerated at 0.1.2 with zero breaking deltas).
247
+
248
+ ```bash
249
+ # Operator prerequisites (each a named blocked gate — none may be skipped):
250
+ # 1. protected live-canary matrix green (live-canaries.yml, canary-report.json retained)
251
+ # 2. PostgreSQL + keychain protected suites green (test:postgres, keychain suite)
252
+ # 3. CodeQL SAST green on the release commit (security.yml / release.yml codeql-release)
253
+ # 4. npm OIDC trusted publishing identity authenticated (NPM_TOKEN with id-token, provenance)
254
+
255
+ git diff --check
256
+ npm ci
257
+ npm run sdk:ready # includes typecheck, lint, format, full test, coverage, pack, release:gate
258
+ npm run security:threat-suites
259
+ PRISM_TEST_POSTGRES_URL="$DATABASE_URL" npm run test:postgres # Phase 7 + Phase 12 restart-recovery
260
+ npm audit --audit-level=moderate
261
+ npm run release:check -- --version 0.1.2 --report /tmp/prism-0.1.2-preflight.json
262
+ npm run release:publish -- --version 0.1.2 --dry-run --allow-dirty --allow-untagged --report /tmp/prism-0.1.2-dry-run.json
263
+ # run the dry-run twice and diff the reports: deterministic, byte-identical
264
+
265
+ # Sign the release on the clean tagged tree (operator GPG key):
266
+ git tag -s v0.1.2 -m "Prism 0.1.2"
267
+ git verify-tag v0.1.2
268
+ git push origin v0.1.2 # tag push triggers release.yml publish job (provenance, attestations)
269
+
270
+ # Real publication never bypasses the gates: release.mjs refuses
271
+ # --allow-dirty/--allow-untagged without --dry-run.
272
+ ```
273
+
274
+ **Rollback notes.** `release:publish --version 0.1.2 --resume --report release-artifacts/publish-report.json` resumes an interrupted publication and skips only registry versions whose internal dependency fingerprint matches the local manifest. A failed package aborts the run with its status written to the report; re-run after fixing the cause. npm cannot unpublish the `0.1.2` line after 72 hours — a post-publication defect ships as a `0.1.x` patch (additive-only compat promise, `release:gate` enforced), or as a documented break in the next line with a `docs/migration.md` entry. `0.1.2` is store-compatible with `0.1.1` in **both directions** (no migration ran — same checksum-protected contract), so an operator may defer or roll back the patch without a database rollback.
275
+
207
276
  ### 0.0.28 publish handoff (historical)
208
277
 
209
- **Decision: GO after protected operator prerequisites below.** Release **0.0.28** (Phase 11, plan 011) ships the optional enterprise adapter seams: OIDC/JWKS identity verification (`@arnilo/prism-credentials-node/oidc`), OPA policy evaluation into the durable ledger (`@arnilo/prism-policy/opa`), MCP OAuth client/server support (`@arnilo/prism-mcp`), host-selected OpenAPI operations as effect-gated tools (`@arnilo/prism-openapi-tools`), and an S3-compatible artifact body store behind the new core body contract (`@arnilo/prism-server/artifact-bodies`). Every seam is opt-in and fail-closed; hosts that wire none keep exact prior behavior. Publishable graph stays **48** manifests. See [migration](migration.md) `0.0.27 → 0.0.28`.
278
+ **Decision: GO after protected operator prerequisites below.** Release **0.0.28** (Phase 11, plan 011) ships the optional enterprise adapter seams: OIDC/JWKS identity verification (`@arnilo/prism-credentials-node/oidc`), OPA policy evaluation into the durable ledger (`@arnilo/prism-policy/opa`), MCP OAuth client/server support (`@arnilo/prism-mcp`), host-selected OpenAPI operations as effect-gated tools (`@arnilo/prism-openapi-tools`), and an S3-compatible artifact body store behind the new core body contract (`@arnilo/prism-server/artifact-bodies`). Every seam is opt-in and fail-closed; hosts that wire none keep exact prior behavior. Publishable graph stays **49** publishable manifests (root + 48 workspace packages; `prism-openapi-tools` joined the graph in this release). See [migration](migration.md) `0.0.27 → 0.0.28`.
210
279
 
211
280
  ```bash
212
281
  git diff --check
@@ -402,7 +471,7 @@ Audit fixes, dependency updates, and security patches land only for the supporte
402
471
  ## Extension and configuration notes
403
472
 
404
473
  - **Required `@arnilo/prism` peer.** Every first-party code package declares a non-optional `@arnilo/prism@0.0.28` peer (`peerDependenciesMeta` must not mark `@arnilo/prism` optional; other peers such as `playwright-core` may be optional). The range stays pinned to `0.0.28` for the current 0.x release and will widen to `^1.0.0` at the 1.x stable release. Inside the workspace each package also declares `"@arnilo/prism": "file:../.."` in `devDependencies` so `npm install` resolves the peer locally; that devDependency is stripped from consumer installs and is not a runtime dependency.
405
- - **Public access.** All 48 manifests (42 code packages + 6 family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
474
+ - **Public access.** All 49 manifests (root + 48 workspace packages: 42 code packages + 6 pure-manifest family/profile packages) declare `"publishConfig": { "access": "public" }`; the publisher also passes `--access public` explicitly because scoped packages otherwise default to restricted on first publish.
406
475
  - **Map retention knob.** Source maps are emitted locally but stripped from tarballs by `!dist/**/*.map`. Removing that `files` negation ships maps in releases (larger tarballs, better consumer stack traces).
407
476
  - **Release workflow.** `.github/workflows/release.yml` has six jobs. `verify` runs network-free SDK readiness on Node 24; `node20-compat` builds/imports every public root `exports` default target on Node 20 for declared `engines.node >=20` (docs examples need Node >=22.6 native TypeScript stripping); `postgres-integration` uses `pgvector/pgvector:pg16`; `supply-chain` runs high-severity audit, SPDX/license policy, and tracked-source secret scanning; and tag-only `codeql-release` runs SAST. Tag-only `publish` needs all five gates, preserves clean exact-tag/version/topological publication, and alone receives `NPM_TOKEN`, `id-token: write`, and `attestations: write`. Before npm publish it packs all current tarballs, generates checksums plus SPDX, scans unpacked public artifacts, creates GitHub attestations for tarballs and SBOM, then retains artifacts for 30 days. Registry state remains the resumable journal. Local `npm run release:dry-run` remains network-free SDK readiness; local PostgreSQL coverage is `PRISM_TEST_POSTGRES_URL=... npm run test:postgres`.
408
477
  - **Adding a package.** New workspace packages are picked up automatically by `npm run build --workspaces`, `npm test --workspaces`, `npm run pack:dry-run`, the packaging guard (`src/__tests__/packaging.test.ts`), and the install-smoke test (`src/__tests__/install-smoke.test.ts`) via the workspace glob; add the package to both tests' config arrays for explicit per-package assertions.
@@ -434,7 +503,7 @@ Audit fixes, dependency updates, and security patches land only for the supporte
434
503
  - **Install smoke is offline.** The install-smoke test packs core + every package into a temp dir and installs tarballs with `--offline --no-audit --no-fund` into a fresh project. External dependencies are satisfied from the lockfile-backed npm cache prepared by `npm ci`; any attempted uncached registry fetch fails the gate.
435
504
  - **Packed-install e2e journeys (plan 012 Task 3).** `scripts/e2e-enterprise-journey.test.mjs` and `scripts/e2e-coding-journey.test.mjs` pack the first-party packages for their journey, install the exact tarballs into a fresh consumer project, and run the journey script inside that consumer — public exports only, no workspace-relative resolution (asserted per run). The **enterprise journey** composes OIDC identity → OPA policy decision (durable ledger) → agent run with durable events (memory, or real PostgreSQL when `PRISM_TEST_POSTGRES_URL` is set) → batched approval → OpenAPI side effect with idempotency → artifact upload + signed delivery, with policy-deny and hash-mismatch fail-closed injections. The **coding journey** composes an ACP editor session (init capability negotiation, session new + load/resume) → bounded coding tools (git-aware list/search, glob, read-before-write write, delete, move) → sandboxed process session → forge handoff with idempotent PR creation, with execution-policy and read-before-write denial paths. Each fixture asserts the installed version matches the packed manifest graph and stays within the frozen `e2eJourneyFixtureMsCeiling` (120 s in `scripts/phase12-freeze-manifest.json`).
436
505
  - **Protected restart-recovery leg (plan 012 Task 4).** `scripts/phase12-restart-recovery.test.mjs` (run by `npm run test:postgres` after the Phase 7 suite) spawns two real processes against one PostgreSQL schema: replica A runs a durable agent, suspends on a batched tool approval, appends durable events and is then SIGKILLed by the driver; replica B reconnects and resumes. Operators re-run the leg with `PRISM_TEST_POSTGRES_URL="postgresql://…" npm run test:postgres` against a disposable PostgreSQL 16 (e.g. `pgvector/pgvector:pg16`). Without the URL the gate records a named `BLOCKED GATE` failure instead of skipping. Reconnect p95 and 16-worker append contention p95 are asserted against the frozen `reconnectP95Ms` / `pointOpP95Ms` ceilings; set `PRISM_PHASE12_RECORD_EVIDENCE=1` to refresh the checked-in evidence file `scripts/phase12-restart-recovery.json`.
437
- - **Offline test budget.** The default `npm test` (no `PRISM_LIVE_PROVIDER_TESTS`) is pinned at **< 60s on Node 20** with a measured local baseline of ~45s (build ~18s + network-free tests/workspace tests/packaging smoke ~27s). The full CI `sdk:ready` gate runs on Node 24 because docs tests execute `examples/*.ts` via native TypeScript stripping. `npm run sdk:ready` also runs typecheck and pack dry-run, so it is allowed to exceed the `npm test` budget while remaining network-free. The CI `sdk:ready` step has `timeout-minutes: 5` as a hang backstop; the separate Node 20 compatibility step has `timeout-minutes: 3`. The budget was raised from 30s after the default suite grew to include every first-party package, offline install smoke, packaging guards, docs examples, and workspace tests; optimize before raising it again.
506
+ - **Offline test budget.** The default `npm test` (no `PRISM_LIVE_PROVIDER_TESTS`) is pinned at **< 60s on Node 20** with a measured local baseline of ~45s (build ~18s + network-free tests/workspace tests/packaging smoke ~27s). The full CI `sdk:ready` gate runs on Node 24 because docs tests execute `examples/*.ts` via native TypeScript stripping. `npm run sdk:ready` also runs typecheck, pack dry-run, and the coverage summary, so it is allowed to exceed the `npm test` budget while remaining network-free. `npm run test:coverage` additionally runs the combined coverage summary (`npm run coverage:summary`, ~25s local: core + each workspace suite once with `--experimental-test-coverage`; measured total ~70s on Node 24) — additive reporting only, the core gate stays the only hard threshold. The CI `sdk:ready` step has `timeout-minutes: 5` as a hang backstop; the separate Node 20 compatibility step has `timeout-minutes: 3`. The budget was raised from 30s after the default suite grew to include every first-party package, offline install smoke, packaging guards, docs examples, and workspace tests; optimize before raising it again.
438
507
 
439
508
  ### 0.0.12 release-candidate verification — 2026-07-22
440
509
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Agent harness for AI providers, agents, sessions, and tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -139,10 +139,11 @@
139
139
  "scripts": {
140
140
  "build:core": "tsc",
141
141
  "clean": "rm -rf dist packages/*/dist",
142
- "build": "npm run clean && npm run build:core && npm run build --workspaces --if-present",
142
+ "build": "npm run build:core && npm run build --workspaces --if-present",
143
143
  "typecheck": "npm run build && npm run typecheck --workspaces --if-present && tsc -p examples --noEmit",
144
- "test": "npm run build && node --test dist/__tests__/*.test.js && node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs && npm run test --workspaces --if-present",
145
- "test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=70 --test-coverage-branches=75 --test-coverage-exclude='**/__tests__/**' --test-coverage-exclude='**/node_modules/**' --test-coverage-exclude='**/scripts/**' --test-coverage-exclude='**/packages/**' --test-coverage-exclude='**/examples/**' dist/__tests__/*.test.js",
144
+ "test": "npm run build && node --test dist/__tests__/*.test.js && node --test scripts/release-gate.test.mjs scripts/tooling-gate.test.mjs scripts/budget-gate.test.mjs scripts/phase8-conformance.test.mjs scripts/phase9-conformance.test.mjs scripts/phase10-conformance.test.mjs scripts/phase11-conformance.test.mjs scripts/phase11-freeze.test.mjs scripts/phase12-freeze.test.mjs scripts/phase13-freeze.test.mjs scripts/phase14-freeze.test.mjs scripts/benchmark-0.1.0.test.mjs scripts/e2e-enterprise-journey.test.mjs scripts/e2e-coding-journey.test.mjs && npm run test --workspaces --if-present",
145
+ "test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=70 --test-coverage-branches=75 --test-coverage-exclude='**/__tests__/**' --test-coverage-exclude='**/node_modules/**' --test-coverage-exclude='**/scripts/**' --test-coverage-exclude='**/packages/**' --test-coverage-exclude='**/examples/**' dist/__tests__/*.test.js && node scripts/coverage-summary.mjs",
146
+ "coverage:summary": "node scripts/coverage-summary.mjs",
146
147
  "lint": "biome lint .",
147
148
  "format": "biome format --write .",
148
149
  "format:check": "biome format .",