@arnilo/prism 0.0.25 → 0.0.27
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 +36 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/docs/0.1.0-readiness.md +10 -10
- package/docs/a2a.md +24 -0
- package/docs/acp.md +126 -0
- package/docs/ag-ui.md +69 -7
- package/docs/agent-events.md +26 -1
- package/docs/coding-agent-tools.md +30 -3
- package/docs/coding-security.md +36 -1
- package/docs/forge-integration.md +113 -0
- package/docs/host-security.md +2 -1
- package/docs/index.md +12 -8
- package/docs/language-intelligence.md +162 -0
- package/docs/mcp-tools.md +1 -0
- package/docs/migration.md +40 -1
- package/docs/performance.md +16 -0
- package/docs/process-sessions.md +147 -0
- package/docs/release-and-install.md +30 -26
- package/package.json +3 -3
package/docs/coding-security.md
CHANGED
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
| `createSandboxCodingTools` / `createSandboxReadOnlyTools` | Thin wrappers that return `tools` only (compat); still require `workspaceMode`. |
|
|
14
14
|
| `createSandboxFilesystemOperations` / `createSandboxRepositoryOperations` | Optional execFile-backed FS/list/search backends for a disposable sandbox tree. |
|
|
15
15
|
| `createDockerSandbox(options)` | Creates one disposable non-root Docker container with read-only root/source, bounded tmpfs workspace, typed `execFile`, import/export, and stop/kill/cleanup. |
|
|
16
|
+
| `SandboxProcessHandle` | Optional long-running process handle (`write`/`signal`/`kill`/`release`/`wait`) returned by `DisposableSandbox.startProcess?`. |
|
|
17
|
+
| `createEgressPolicy(options)` | Deny-all allow-list policy: exact host/port/protocol rules plus frozen `npm-registry` / `github` presets; SHA-256 fingerprint. |
|
|
18
|
+
| `createAllowListEgressProxy(options)` | HTTP forward proxy + CONNECT tunnel enforcing the policy: pinned DNS (rebinding defense), private/metadata IP denial, redirect re-validation + hop cap, byte/time caps, per-decision audit, attestation for sandbox composition. |
|
|
19
|
+
| `composeEgressSandboxNetwork(attestation, name)` | Validated custom Docker network carrying proxy attestation; recorded as `prism.egress.*` container labels. |
|
|
20
|
+
| `assertEgressAttestation(attestation)` | Fail-closed validation of proxy attestation evidence. |
|
|
16
21
|
| `assertPathInsideRoots`, `isPathInsideReal` | Symlink-aware path containment helpers. |
|
|
17
22
|
| `evaluateCommandRules`, `hasShellMetacharacters` | Command classification helpers. |
|
|
18
23
|
|
|
@@ -28,6 +33,32 @@ Use this package when coding tools need path scoping, human approval, command ru
|
|
|
28
33
|
|
|
29
34
|
Use `createDockerSandbox()` when the host wants a production-reference containment boundary. Prism does **not** claim OS-level isolation unless the host constructs this adapter (or supplies an equivalent custom `DisposableSandbox`). Default policy denies shell/write/edit/delete/move without an `approve` callback and rejects paths outside configured roots. Coding shell definitions are marked `exclusive: true`, matching the approval policy's shell decision, so a single-shot turn containing shell work runs sequentially even when `toolConcurrency > 1`. Non-shell turns retain configured parallelism.
|
|
30
35
|
|
|
36
|
+
Use `createEgressPolicy()` + `createAllowListEgressProxy()` when a coding agent needs outbound network access under an explicit allow list: package installs, forge API calls, or source fetches — never unrestricted egress. The proxy is inert until `start()`; nothing binds or resolves on import or construction.
|
|
37
|
+
|
|
38
|
+
## Allow-list egress composition
|
|
39
|
+
|
|
40
|
+
`createEgressPolicy({ allow, presets })` builds a deny-all policy. Rules are exact `{ host, port, protocol }` triples — no wildcards, no CIDR, no regex. Presets (`npm-registry`, `github`) expand to explicit rule lists at construction. The policy exposes a stable SHA-256 `fingerprint` over the canonical rule set.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { createEgressPolicy, createAllowListEgressProxy } from "@arnilo/prism-coding-security";
|
|
44
|
+
|
|
45
|
+
const policy = createEgressPolicy({
|
|
46
|
+
allow: [{ host: "api.github.com", port: 443, protocol: "https" }],
|
|
47
|
+
presets: ["npm-registry"],
|
|
48
|
+
});
|
|
49
|
+
const proxy = createAllowListEgressProxy({ policy, audit: (record) => host.recordEgress(record) });
|
|
50
|
+
const endpoint = await proxy.start(); // 127.0.0.1:0 by default; bind a reachable interface for containers
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Every request is checked against the policy before any DNS or connect. HTTPS goes through CONNECT tunnels with TLS passed through untouched — no interception, no MITM. DNS answers are resolved once, pinned, and the connected socket's remote address is verified against the pinned set (rebinding defense); private/link-local/metadata ranges (`10/8`, `172.16/12`, `192.168/16`, `127/8`, `169.254/16` incl. `169.254.169.254`, CGNAT, ULA, `::1`, `fe80::/10`) are denied unless the matching rule sets `allowPrivate: true`. Plain-HTTP redirects are followed up to `redirectHops` with every hop re-validated against policy; redirects to unlisted hosts or non-http targets fail closed. Request/response bytes and total transfer time are capped; oversized or slow-loris transfers are cut with `ERR_PRISM_EGRESS_LIMIT`. Every allow/deny writes an `EgressAuditRecord` (id, ts, decision, host, port, protocol, reason, bytes, duration, client address) — never headers, bodies, or tokens. `reloadPolicy()` is the only way to change rules and bumps `policyVersion`; `attestation()` returns `{ proxyEndpoint, denyDirectEgress: true, policyFingerprint, policyVersion, startedAt }` for sandbox composition.
|
|
54
|
+
|
|
55
|
+
Sandbox composition: `composeEgressSandboxNetwork(proxy.attestation(), networkName)` returns a custom `DockerNetworkConfig` whose attestation is validated and recorded as `prism.egress.endpoint` / `prism.egress.fingerprint` / `prism.egress.policyVersion` / `prism.egress.denyDirect=1` container labels. The adapter records evidence; the host must actually restrict the Docker network so the proxy is the only reachable path (e.g., a dedicated network with only the proxy container attached). A custom network without valid attestation fails closed for egress claims, mirroring `assertBrowserSandboxNetwork`.
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const network = composeEgressSandboxNetwork(proxy.attestation(), "egress-net");
|
|
59
|
+
const sandbox = await createDockerSandbox({ docker, image, sourceRoot, user, network, limits });
|
|
60
|
+
```
|
|
61
|
+
|
|
31
62
|
## Inputs / request
|
|
32
63
|
|
|
33
64
|
| Option | Default | Purpose |
|
|
@@ -72,7 +103,7 @@ Use `createDockerSandbox()` when the host wants a production-reference containme
|
|
|
72
103
|
|
|
73
104
|
`createSandboxCodingComposition()` returns `{ tools, composition }` where `SandboxCodingComposition` carries `workspaceMode`, `containmentClaim`, `mixedWiringAllowed`, `warnings`, `workspaceRoot`, and optional `treeIdentity` (from `importIdentity` / `lastExportIdentity`). `containmentClaim` is `true` only for sandbox mode with tree backends bound and mixed wiring denied. Host mode and escape-hatch mixed wiring always set `containmentClaim: false` — never treat host mode as contained execution.
|
|
74
105
|
|
|
75
|
-
`createDockerSandbox()` returns a `DisposableSandbox`: typed `execFile(file, args)`, shell-compatible `exec`, `status`, cooperative `stop`, forced `kill`, and idempotent `close`. Import may surface `importIdentity`; successful export updates `lastExportIdentity`. `close({ export })` can stream a bounded workspace tar plus SHA-256/entry/byte metadata through a host callback; checkpoints should retain only host artifact references/hashes, never whole workspaces.
|
|
106
|
+
`createDockerSandbox()` returns a `DisposableSandbox`: typed `execFile(file, args)`, shell-compatible `exec`, `status`, cooperative `stop`, forced `kill`, and idempotent `close`. Import may surface `importIdentity`; successful export updates `lastExportIdentity`. `close({ export })` can stream a bounded workspace tar plus SHA-256/entry/byte metadata through a host callback; checkpoints should retain only host artifact references/hashes, never whole workspaces. Optional `startProcess?(SandboxExecFileRequest)` returns a `SandboxProcessHandle` for long-running work consumed by coding-agent `createProcessSessions({ sandbox })`; absence means one-shot-only — ProcessSessions fails closed with `ERR_PRISM_PROCESS_UNSUPPORTED` (no native fallback). The Docker reference adapter does not implement `startProcess` yet; capability is detected, never assumed. See [Process sessions](process-sessions.md).
|
|
76
107
|
|
|
77
108
|
## Request/response example
|
|
78
109
|
|
|
@@ -151,11 +182,15 @@ Containment resolves symlinks and rejects paths outside roots. Command rules are
|
|
|
151
182
|
|
|
152
183
|
Docker sandbox containment—not command regexes—enforces filesystem/network/process boundaries for the reference adapter. Network defaults to none; a custom Docker network still requires a host firewall/proxy for DNS/egress claims. Import rejects symlink escapes, devices, FIFOs, and sockets; export counts entries/bytes and hashes before host retention. Secrets in `secrets` are redacted from adapter errors and never exported as environment metadata. Unified workspace mode reuses existing sandbox/repo/coding hard caps and does not introduce unbounded host↔container sync loops. Host mode and `allowMixedWorkspaceWiring` never claim disposable containment. Durable workflow denial/cancellation is terminal and attributable; approved resume still fails if roots, command rules, read-only mode, or other policy changed while suspended. Cache keys are fixed-size SHA-256 digests of selected identity plus action shape; caches remain process-local, retain at most 1,000 decisions with oldest-entry eviction, and have no default/global mode. Path checks and cache lookup are local; sandbox latency belongs to the supplied adapter and Docker daemon.
|
|
153
184
|
|
|
185
|
+
The egress proxy is a policy enforcer, not a firewall: it cannot stop a container whose Docker network reaches the internet directly. Egress attestation (`denyDirectEgress: true`) is a claim the host must make true by network topology; the adapter records it as evidence and fails closed when it is absent or malformed. The proxy performs no TLS interception, no DNS rebinding of its own beyond pinning, and no content filtering; audit records contain no secrets. Frozen caps: 32 concurrent connections (hard 256), 64 MiB request/response bytes (hard 1 GiB), 600 s transfer time (hard 1 h), 128 rules (hard 1,024), 5 redirect hops (hard 10).
|
|
186
|
+
|
|
154
187
|
## Related APIs
|
|
155
188
|
|
|
156
189
|
- [Coding agent tools](coding-agent-tools.md): durable plan/todo Markdown helpers and `state.coding` checkpoint metadata for restart/resume without a second runtime
|
|
157
190
|
- [Workflows](workflows.md): `runWorkflow` / `resumeWorkflow` / `startWorkflowBackground` composition for coding tasks
|
|
158
191
|
- [Host security guide](host-security.md)
|
|
159
192
|
- [Performance limits](performance.md)
|
|
193
|
+
- [Forge integration](forge-integration.md): GitHub adapter whose mutations can be routed through the egress proxy
|
|
160
194
|
- [Tool execution primitives](tool-execution-primitives.md)
|
|
161
195
|
- [Security/auth/trust](settings-auth-trust-security.md)
|
|
196
|
+
- [ACP coding-host interop](acp.md): when an ACP client supplies fs/terminal methods and MCP servers, the same containment story applies at the protocol boundary — client paths/dirs pass host seams, MCP servers need host `select` approval (never auto-connect), updates are redacted and capped, and mode switches only narrow or host-authorized widen.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# GitHub forge integration
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`createGitHubForge` is an optional host-activated adapter in `@arnilo/prism-coding-agent` for the six **proven** GitHub operations: issue context read, authenticated push, pull-request create/update, review comments, and check/status retrieval, plus bounded handoff reconciliation. It is GitHub-first by freeze decision — there is no multi-forge generic abstraction, and no octokit dependency: HTTP uses Node's global `fetch` with a bounded streaming reader, timeout, and rate-limit backoff; push reuses the existing `BoundGitRunner` with the token injected via `GIT_CONFIG_*` environment variables (`http.extraHeader`) — never argv, never persisted, never in logs/events. Every mutation flows through Phase 8 approval (`ExecutionPolicy`) and Phase 7 `ToolEffectStore` idempotency keys; a retry after a completed call returns the existing record instead of duplicating the PR or comment.
|
|
6
|
+
|
|
7
|
+
| Export | Purpose |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `createGitHubForge(options)` | Build a `ForgeOperations` adapter bound to one `"owner/repo"`. |
|
|
10
|
+
| `ForgeOperations` | `issueContext` / `push` / `createPullRequest` / `updatePullRequest` / `createReviewComment` / `checks` / `reconcileHandoff`. |
|
|
11
|
+
| `ForgeIssueContext` / `ForgePullRequest` / `ForgeCheck` | Bounded response shapes (state, head/base, url, check status/conclusion). |
|
|
12
|
+
| `ForgeHandoffReport` | Push/PR/check state, commits, changed paths, diffstat, warnings; never auto-merges. |
|
|
13
|
+
| `ForgeError` | Typed failures: `ERR_PRISM_FORGE_AUTH` / `_API` / `_STALE` / `_RATE_LIMIT` / `_LIMIT` / `_OWNERSHIP`. |
|
|
14
|
+
| `resolveForgeLimits` / `DEFAULT_MAX_FORGE_*` / `HARD_MAX_FORGE_*` | Pages per operation, payload bytes, comments, concurrency ceiling, request timeout. |
|
|
15
|
+
|
|
16
|
+
## When to use it
|
|
17
|
+
|
|
18
|
+
Use when a coding agent needs to open/update PRs, comment on reviews, push a branch with scoped credentials, or verify handoff state against GitHub before deciding the next step. Do not use as a general GitHub SDK, an auto-merge engine (`reconcileHandoff` never merges), or a replacement for host-owned App installation flows — the adapter resolves credentials through the host's `CredentialResolverSource`-compatible resolver and never stores them.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { createGitHubForge } from "@arnilo/prism-coding-agent";
|
|
22
|
+
|
|
23
|
+
const forge = createGitHubForge({
|
|
24
|
+
credentials: { name: "github", resolver: myCredentialResolver }, // App installation token preferred; PAT allowed
|
|
25
|
+
repository: "acme/repo",
|
|
26
|
+
cwd: workspaceRoot, // local checkout for push
|
|
27
|
+
git: { gitPath: "/usr/bin/git" },
|
|
28
|
+
policy, // mutations gated here; denials propagate as ERR_PRISM_EXECUTION_DENIED, no request attempted
|
|
29
|
+
effectStore, // REQUIRED: idempotency + unknown-outcome recovery
|
|
30
|
+
identity, ownership, sessionId, runId, // durable context for mutation effect keys
|
|
31
|
+
});
|
|
32
|
+
const pr = await forge.createPullRequest({ head: "feature/x", base: "main", title: "Add x", body: "Closes #1" });
|
|
33
|
+
const report = await forge.reconcileHandoff({ base: "main", head: "feature/x" });
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Inputs / request
|
|
37
|
+
|
|
38
|
+
`createGitHubForge` options:
|
|
39
|
+
|
|
40
|
+
| Field | Type | Purpose |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `credentials` | `ForgeCredentialResolverSource` | `{ name, resolver }`; resolver is called per request with `provider: "github"` and `metadata.repository`. |
|
|
43
|
+
| `repository` | `string` | `"owner/repo"`, validated at construction and immutable per instance. |
|
|
44
|
+
| `cwd` | `string` | Local checkout the adapter pushes from. |
|
|
45
|
+
| `git` | `CreateGitRunnerOptions \| BoundGitRunner` | Reused for authenticated push (`git push origin <ref>`). |
|
|
46
|
+
| `policy?` | `ExecutionPolicy` | Every mutation is gated (`kind: "forge"`, risk `high`) before any network or git call. |
|
|
47
|
+
| `effectStore` | `ToolEffectStore` | **Required.** `begin → markDispatched → execute → complete/fail` per mutation. |
|
|
48
|
+
| `identity?` / `ownership?` / `sessionId?` / `runId?` | durable context | Required for mutations; without them mutations fail closed with `ERR_PRISM_FORGE_LIMIT`. Tenant mismatch fails at construction with `ERR_PRISM_FORGE_OWNERSHIP`. |
|
|
49
|
+
| `limits?` | `ForgeLimits` | Pages per operation (default 10, hard 100), payload bytes (1 MiB / 8 MiB), comments per review (100 / 1000), request concurrency ceiling (4 / 8), timeout (30 s / 120 s). |
|
|
50
|
+
| `fetch?` | `typeof fetch` | Host-injectable fetch (defaults to `globalThis.fetch`); route through an egress proxy or inject a mock in tests. |
|
|
51
|
+
|
|
52
|
+
Mutation inputs are validated before any request: refs must not start with `-` or contain NUL/newlines and fit the git ref cap; numbers must be positive integers; PR title/body and comment body are required and bounded by `payloadBytes`. `updatePullRequest` with no fields to change fails closed.
|
|
53
|
+
|
|
54
|
+
## Outputs / response / events
|
|
55
|
+
|
|
56
|
+
- `issueContext({ number })` → `ForgeIssueContext` (title, state, body, labels, author, updatedAt, url). Read-only; no policy gate, no effect record.
|
|
57
|
+
- `push({ refspec? })` → `{ remoteRef }` (`refs/heads/<branch>`). Resolves the current branch with `git rev-parse` when no refspec is given. Token reaches git as `GIT_CONFIG_VALUE_0 = "AUTHORIZATION: basic <base64(x-access-token:<token>)>"`; argv carries only `git push origin <ref>`.
|
|
58
|
+
- `createPullRequest({ head, base, title, body })` → `ForgePullRequest`. Idempotent twice over: the effect key replays completed results, and a 422 `"already exists"` response fetches and returns the open PR instead of failing.
|
|
59
|
+
- `updatePullRequest({ number, title?, body?, state? })` → `ForgePullRequest`. 422 (stale head/base) maps to `ERR_PRISM_FORGE_STALE`.
|
|
60
|
+
- `createReviewComment({ number, path, line, body })` → `{ id }`. Retry with identical args replays the completed effect — no duplicate comment.
|
|
61
|
+
- `checks({ ref })` → `ForgeCheck[]`: check-runs plus commit statuses, deduped by name, paginated up to `pagesPerOperation`.
|
|
62
|
+
- `reconcileHandoff({ base, head })` → `ForgeHandoffReport`: `pushed`, `aheadBy`/`behindBy`, `alreadyUpToDate`, `alreadyMerged`, `pullRequest?`, `checks`, bounded `commits`/`changedPaths`/`diffstat`, `warnings`. A missing head ref reports `pushed: false` with a warning. Never pushes, opens, or merges — the host decides next steps from the report.
|
|
63
|
+
|
|
64
|
+
Every mutation result is recorded in the `effectStore` with a stable key derived from tenant + session + run + operation + canonical arguments. Replay of a completed record returns the stored result; replay of a `dispatched`/`unknown` record fails closed (`ERR_PRISM_FORGE_API`, "requires reconciliation") so a crash mid-mutation never duplicates work — verify actual state via `reconcileHandoff`, then resolve through the store.
|
|
65
|
+
|
|
66
|
+
## Request/response example
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"action": { "kind": "forge", "operation": "create_pull_request", "risk": "high", "metadata": { "repository": "acme/repo", "head": "feature/x", "base": "main" } },
|
|
71
|
+
"decision": { "allowed": true }
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Implementation example
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { createGitHubForge } from "@arnilo/prism-coding-agent";
|
|
79
|
+
|
|
80
|
+
const forge = createGitHubForge({
|
|
81
|
+
credentials: { name: "github-app", resolver },
|
|
82
|
+
repository: "acme/repo",
|
|
83
|
+
cwd: "/srv/jobs/task-1/checkout",
|
|
84
|
+
git: { gitPath: "/usr/bin/git" },
|
|
85
|
+
policy,
|
|
86
|
+
effectStore,
|
|
87
|
+
identity, ownership, sessionId, runId,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await forge.push({ refspec: "feature/x" });
|
|
91
|
+
await forge.createPullRequest({ head: "feature/x", base: "main", title: "Add x", body: "Closes #1" });
|
|
92
|
+
const checks = await forge.checks({ ref: "feature/x" });
|
|
93
|
+
const report = await forge.reconcileHandoff({ base: "main", head: "feature/x" });
|
|
94
|
+
if (!report.alreadyMerged && report.pushed) {
|
|
95
|
+
// host decides: update PR, comment, or stop — the adapter never auto-merges
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Extension and configuration notes
|
|
100
|
+
|
|
101
|
+
Credentials resolve per call through the host resolver; GitHub App installation tokens and PATs are both supported (same `Bearer` REST header and `x-access-token` git header). Least-privilege guidance: App installation tokens with `contents: write` + `pull_requests: write` + `issues: read` cover the six operations; PATs should be fine-grained to the single repository and read/write scope needed. Policy denials propagate as the core `ExecutionDeniedError` (`ERR_PRISM_EXECUTION_DENIED`) — no forge request is attempted — so hosts can distinguish refusal from forge failure. Pagination is sequential (per-request `pagesPerOperation` cap); `requestConcurrency` is a validated ceiling, not a target. The adapter performs no DNS/egress control itself — sandboxed hosts route forge traffic through the Phase 9 egress policy (Task 6).
|
|
102
|
+
|
|
103
|
+
## Security and performance notes
|
|
104
|
+
|
|
105
|
+
Tokens never appear in argv, git config files, logs, model context, or stored events: REST uses the `Authorization` header on a bounded `fetch`, and git uses `GIT_CONFIG_*` environment variables scoped to the single push process. Request bodies and responses are bounded by `payloadBytes` (streamed, content-length pre-checked); timeouts and rate-limit backoff respect `requestTimeoutMs` and `Retry-After`; page fetches stop at `pagesPerOperation`. Repository binding is fixed at construction; tenant binding is checked per mutation; ownership mismatch fails closed. Rate-limit responses map to `ERR_PRISM_FORGE_RATE_LIMIT`, 404 to `ERR_PRISM_FORGE_API`, 422 to `ERR_PRISM_FORGE_STALE`, 401/403 to `ERR_PRISM_FORGE_AUTH`, and cap violations to `ERR_PRISM_FORGE_LIMIT`.
|
|
106
|
+
|
|
107
|
+
## Related APIs
|
|
108
|
+
|
|
109
|
+
- [Tool effects](tool-effects.md): `ToolEffectStore` idempotency and unknown-outcome recovery used by every forge mutation
|
|
110
|
+
- [Coding agent tools](coding-agent-tools.md): `createGitTools`, `createBoundGitRunner`, `createGitOperations` (push rides the same runner)
|
|
111
|
+
- [Coding execution approval and sandboxing](coding-security.md): `ExecutionPolicy` gates, egress policy (Phase 9)
|
|
112
|
+
- [Host security guide](host-security.md)
|
|
113
|
+
- [Performance limits](performance.md)
|
package/docs/host-security.md
CHANGED
|
@@ -148,6 +148,7 @@ Wire those values where they matter: provider adapters receive the resolved cred
|
|
|
148
148
|
- AG-UI A2A requires exact-origin verified client, host-owned task selection/correlation, explicit data/tool/A2UI projection, and reauthorized follow/cancel.
|
|
149
149
|
- `@arnilo/prism-server` exposes no agent/workflow by default and requires `authorize()` for every matched operation. Derive complete tenant/account/user ownership from validated host identity, never request JSON. Workflow active identity and cancellation compare exact ownership; a tenant-only scope intentionally cannot cancel a checkpoint/run carrying account or user identity. The artifact review service (`createArtifactService`) requires authenticated identity + thread ownership on every attach/revise/compare/approve/reject/download, resolves concurrent reviewers via checkpoint CAS (no lost approvals), rejects local filesystem paths in `uri`/citations, redacts records before persist and on response, and serves downloads only through signed expiring links that are reauthorized against the token's ownership per request. Pass the current explicitly revised workflow definition so recursive hash mismatch fails before abort or durable mutation. Configure exact host/origin allow-lists where needed, wire redaction before execution, retain tool/workflow policy checks, and adapt the Web handler behind host TLS/rate limits. Disconnect abort is default; persistent reconnect/status belongs to durable workflow checkpoints, not an invented in-memory agent result cache.
|
|
150
150
|
- Coding tools from `@arnilo/prism-coding-agent` accept an optional `ExecutionPolicy` checked inside each tool before side effects; shared policy propagation includes `createReadOnlyTools()`. They enforce finite text-scan/image/edit/write/shell limits, repository list/search depth/entry/match/scan/time caps, structured Git path/ref/message/output/patch/worktree caps, named-check concurrency/output caps, a 600-second default shell wall time, and a 64 MiB default total-output ceiling. Opt-in `createGitTools()` uses argument arrays with hooks/credential prompts/external diff disabled, requires host `commitIdentity` for commits, and never pushes or opens PRs. Successful truncated shell output leaves a host-owned exclusive `0600` temp file; delete `metadata.fullOutputPath` after use. Error/abort/timeout/overflow removes unpublished spills. Custom read/edit/shell/repository backends must honor supplied caps/signals. Use `@arnilo/prism-coding-security` for path roots, command rules, identity-scoped approval caching, required `workspaceMode` on `createSandboxCodingComposition()` / `createSandboxCodingTools()`, and the optional `createDockerSandbox()` reference adapter. **Host mode is never contained execution** (`containmentClaim: false`). Sandbox mode claims containment only when FS backends target the disposable tree; mixed wiring requires `allowMixedWorkspaceWiring` and still does not claim containment. Limits alone are not containment: construct the Docker adapter (absolute CLI, digest-pinned image, network none by default) or an equivalent host sandbox before treating coding execution as production-safe. Docker daemon/image trust, egress firewall/proxy, and artifact retention remain host-owned.
|
|
151
|
+
- Allow-list egress (0.0.26, `@arnilo/prism-coding-security`): `createEgressPolicy()` is deny-all with exact host/port/protocol rules and frozen `npm-registry`/`github` presets; `createAllowListEgressProxy()` is an HTTP forward proxy + CONNECT tunnel that pins DNS answers and verifies the connected address (rebinding defense), denies private/link-local/metadata ranges unless a rule opts in, re-validates every redirect hop against policy, and cuts oversized/slow transfers at frozen byte/time caps. TLS passes through without interception. Every allow/deny writes an audit record with no secrets. The proxy is inert until `start()`; `reloadPolicy()` is the only rule change path. `composeEgressSandboxNetwork(proxy.attestation(), name)` records validated attestation as `prism.egress.*` container labels — evidence, not enforcement: the host must restrict the Docker network so the proxy is the only reachable path, and `denyDirectEgress: true` is a claim the host makes true by topology. The proxy is not a firewall and cannot stop a container whose network reaches the internet directly.
|
|
151
152
|
- Optional `@arnilo/prism-browser` requires a host-supplied Playwright Browser (`playwright-core@1.61.0` peer). Import is inert. One non-persistent context belongs to one run; actions serialize; refs are snapshot-scoped; CSS/evaluate/CDP/persistent profiles are denied. Context routing + `serviceWorkers: "block"` deny file/data/blob/devtools/private/loopback by default and require contained-proxy attestation for external egress (Playwright routing is defense in depth, not DNS containment). Uploads are realpath-rooted; downloads quarantine with hash/MIME until host `approveRelease`; screenshots return bounded `ImageContent`. Observation vs mutation/high-impact actions map to `ExecutionPolicy`. Treat snapshot/page text as untrusted external content. Close contexts with `browser_close` or `manager.closeRun(runId)` on abort/terminal. Browser control endpoint, binary/image pin, and real egress firewall/proxy remain host-owned. Shared sandbox: `createSharedSandboxBrowserOptions()` + `assertBrowserSandboxNetwork()`.
|
|
152
153
|
- Browser verified-state checkpoints (0.0.14, `createBrowserCheckpointLedger()`) store URL + domain-state hash + host data refs only — never serialized browser internals (cookies/storage/contexts). After any resume/interruption the ledger fails closed (`assertVerifiedBeforeSideEffect`) until the host reloads + verifies, so side effects never replay on stale state.
|
|
153
154
|
- Device adapters (0.0.14, `resolveDevicePolicy`/`assertDeviceAdmit`) are deny-by-default: admission fails closed without explicit `enabled`, an explicit sandbox, approval (when required), an under-budget session count, and shared `RunLimits`. Stream chunks over the frozen cap are dropped with a marker; telemetry is redacted before emit/persist. No vendor voice/desktop package ships in 0.0.14 (demand-gated 0.1.x); device adapters cannot broaden consent/memory/network/file/browser/connector/tool permissions (gate 8).
|
|
@@ -209,7 +210,7 @@ Every durable `AgentEventSource` page/subscribe and tool-effect claim rechecks e
|
|
|
209
210
|
## Related APIs
|
|
210
211
|
|
|
211
212
|
- [Web-standard server handler](server.md): remote agent/workflow route, ownership, limits, abort, and deployment boundary.
|
|
212
|
-
- [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.
|
|
213
|
+
- [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.
|
|
213
214
|
- [Supervisor delegation](supervisors.md): local child permission/memory/budget boundary.
|
|
214
215
|
- [A2A interoperability](a2a.md): remote card/auth/origin/signature boundary.
|
|
215
216
|
- [Settings, auth, trust, and security controls](settings-auth-trust-security.md): low-level helpers and boundary hardening table.
|
package/docs/index.md
CHANGED
|
@@ -15,11 +15,11 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
15
15
|
- [Agent definitions](agent-definitions.md): resolve declarative `AgentDefinition` values via `resolveAgentDefinition`, and turn app-config `<configRoot>/agents/<name>/AGENT.md` bundles into runnable agents via `discoverAgentBundles` / `resolveAgentBundle` (explicit tool/skill activation by name, fail-closed omitted capabilities, migration-only `activateAllCapabilities`, strict duplicate scope checks, configurable prompt layers, no auto-discovery).
|
|
16
16
|
- [Agent loops](agent-loops.md): replaceable per-run control loops — `singleShotLoop` default, opt-in bounded artifact-loop tool rounds, and durable custom-loop `revision`/`snapshot`/`restore` hooks with fail-closed resume.
|
|
17
17
|
- [Guardrails](guardrails.md): typed fail-closed input/output/tool checks with buffered provider output and redacted decision records.
|
|
18
|
-
- [Agent events](agent-events.md): live `session.subscribe` plus durable `AgentEventSource` page/subscribe/resume for cross-replica reconnect; message/progress deltas never create spans.
|
|
18
|
+
- [Agent events](agent-events.md): live `session.subscribe` plus durable `AgentEventSource` page/subscribe/resume for cross-replica reconnect; message/progress deltas never create spans. Durable sources: PostgreSQL `LISTEN`/`NOTIFY` (reference, `@arnilo/prism-session-store-postgres` root export) and NATS JetStream (`@arnilo/prism-session-store-nats`, FR-5).
|
|
19
19
|
- [Observability](observability.md): OTel GenAI agent/provider/tool hierarchy, host context parenting, bounded trace linkage, safe evaluation events, controlled metrics, and exporter isolation.
|
|
20
20
|
- [Evaluations](evaluations.md): deterministic and bounded trace/model-judge/pairwise scoring, CI thresholds, OTel trace-reference linkage, coding/browser adversarial fixtures, ID-only linkage to immutable owned run feedback, and optional durable PostgreSQL records.
|
|
21
21
|
- [Runs and usage ledger](runs-and-usage.md): durable run/event/tool/usage persistence, optional bounded FIFO durability policies, session snapshot caching, and immutable run/trace feedback.
|
|
22
|
-
- [Performance limits](performance.md): 0.0.25 durable-loop/HITL/A2UI network-free evidence, 0.0.24 distributed event/effect PostgreSQL evidence, 0.0.23 enterprise state evidence, 0.0.15 network-free provider/RAG/memory benchmark evidence and frozen caps, bounded evaluation traces/judges/reports, and production sizing assumptions.
|
|
22
|
+
- [Performance limits](performance.md): 0.0.26 coding-intelligence/process/forge/egress network-free evidence, 0.0.25 durable-loop/HITL/A2UI network-free evidence, 0.0.24 distributed event/effect PostgreSQL evidence, 0.0.23 enterprise state evidence, 0.0.15 network-free provider/RAG/memory benchmark evidence and frozen caps, bounded evaluation traces/judges/reports, and production sizing assumptions.
|
|
23
23
|
- [Structured output](structured-output.md): the `Artifact*` seam plus provider-native `StructuredOutputOptions` / `structuredOutputMode` for capable models.
|
|
24
24
|
|
|
25
25
|
## Compaction/session memory
|
|
@@ -35,7 +35,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
35
35
|
- [SQLite persistence](sqlite-persistence.md): optional `better-sqlite3` adapter with session/run storage, checkpoints/leases, feedback, FTS `searchSessions` (migration-v4), and transactionally verified/backfilled migration metadata.
|
|
36
36
|
- [PostgreSQL persistence](postgres-persistence.md): optional pooled `pg` adapter with session/run/checkpoint/lease/feedback storage, FTS `searchSessions` (migration-v4), advisory-locked checksummed/full-shape migrations, and opt-in live conformance.
|
|
37
37
|
- [Enterprise PostgreSQL state](enterprise-postgres-state.md): optional `@arnilo/prism-enterprise-postgres` composition for durable policy/evaluation/work-idempotency/model-router/`toolEffects` state, exact ownership, checksummed migrations, and explicit cleanup.
|
|
38
|
-
- [Migration guide](migration.md): **0.0.25** durable custom loops and shared human-in-the-loop decisions; **0.0.24** distributed events and recoverable tool effects; **0.0.23** enterprise PostgreSQL state adapters (async router and work reconciliation); **0.0.22** third-party behavior integrations (Caveman, Ponytail); **0.0.21** coding-tool capability gaps (`outputMode`, glob, read-before-write, delete/move, aggregator 9/4); **0.0.20** progressive skill disclosure, empty registry default, `load_skill`, priority budget demotion, optional tool-result fold; **0.0.19** observational memory lifecycle; **0.0.15** OpenAI hosted tools/continuation/Realtime, exact AI SDK v4 matrix, RAG lifecycle/reranking/trust/status, and memory export/rebuild; **0.0.14** conversations, memory consent/lifecycle, artifact co-work review, AG-UI co-work events, scoped M365/GWS OAuth connectors, browser checkpoints, device contracts, and Alibaba/Ollama providers; plus prior release migrations.
|
|
38
|
+
- [Migration guide](migration.md): **0.0.27** ACP coding-host interop (capability advertise-when, session modes/config, MCP select, lifecycle events, elicitation); **0.0.26** coding intelligence, managed processes, forge, and safe egress; **0.0.25** durable custom loops and shared human-in-the-loop decisions; **0.0.24** distributed events and recoverable tool effects; **0.0.23** enterprise PostgreSQL state adapters (async router and work reconciliation); **0.0.22** third-party behavior integrations (Caveman, Ponytail); **0.0.21** coding-tool capability gaps (`outputMode`, glob, read-before-write, delete/move, aggregator 9/4); **0.0.20** progressive skill disclosure, empty registry default, `load_skill`, priority budget demotion, optional tool-result fold; **0.0.19** observational memory lifecycle; **0.0.15** OpenAI hosted tools/continuation/Realtime, exact AI SDK v4 matrix, RAG lifecycle/reranking/trust/status, and memory export/rebuild; **0.0.14** conversations, memory consent/lifecycle, artifact co-work review, AG-UI co-work events, scoped M365/GWS OAuth connectors, browser checkpoints, device contracts, and Alibaba/Ollama providers; plus prior release migrations.
|
|
39
39
|
- [Node JSONL session store](node-jsonl-session-store.md): development-only JSONL file adapter for single-process Node hosts; no cross-process safety; `searchSessions` throws `SessionSearchUnsupportedError`.
|
|
40
40
|
- [Persistence, credentials, and multimodality primitives](persistence-credentials-multimodality-primitives.md): Plan 056 inventory — session/run-ledger/persistence contracts, credential/OAuth seams, content/resource/model capabilities, package dependency matrix, conformance matrix, and threat model for production adapters.
|
|
41
41
|
|
|
@@ -73,8 +73,11 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
73
73
|
- [Work connectors](work-connectors.md): connector principles, capability gates, scoped OAuth establishment (0.0.14), and out-of-scope boundaries (Slack/Teams channels not shipped) for Microsoft 365 / Google Workspace.
|
|
74
74
|
- [Browser automation](browser-automation.md): optional `@arnilo/prism-browser` with host-supplied Playwright contexts, AI-mode snapshots/refs, ordered `browser_open`/`browser_snapshot`/`browser_act`/`browser_close`, egress/side-effect/upload/download/screenshot policy, finite page/action/snapshot/network/artifact caps, and 0.0.14 verified-state checkpoints with reload/verify-before-side-effect.
|
|
75
75
|
- [Device adapters](device-adapters.md): deny-by-default realtime voice / desktop-control contract + conformance (0.0.14); no vendor package — admission fails closed without explicit consent+sandbox+approval, stream bounds, shared `RunLimits`, redacted telemetry.
|
|
76
|
-
- [Coding agent tools](coding-agent-tools.md): optional `shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, and `move` definitions plus opt-in `createGitTools()` / `coding_check`, opt-in `createAskUserDecisionTool` (single/multi/free-text + durable suspend glue), and `runCodingGoalVerify`; durable plan/todo Markdown helpers with workflow `state.coding` checkpoint metadata; streamed text pages, `repo_search` `outputMode`, bounded glob, optional read-before-write, finite Git/check/plan/ask caps, bounded image/edit reads and write/edit payloads, finite shell wall/total-output limits, secure host-owned spill cleanup, pluggable bounded operation contracts, per-path mutation serialization, and optional `ExecutionPolicy`. No PDF/trash/PTY
|
|
77
|
-
- [
|
|
76
|
+
- [Coding agent tools](coding-agent-tools.md): optional `shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, and `move` definitions plus opt-in `createGitTools()` / `coding_check`, opt-in `createAskUserDecisionTool` (single/multi/free-text + durable suspend glue), and `runCodingGoalVerify`; durable plan/todo Markdown helpers with workflow `state.coding` checkpoint metadata; streamed text pages, `repo_search` `outputMode`, bounded glob, optional read-before-write, optional Git-aware (`createGitAwareRepositoryOperations`) ignore-aware enumeration with native fallback, finite Git/check/plan/ask caps, bounded image/edit reads and write/edit payloads, finite shell wall/total-output limits, secure host-owned spill cleanup, pluggable bounded operation contracts, per-path mutation serialization, and optional `ExecutionPolicy`. No PDF/trash/PTY in the 0.0.21 baseline; Phase 9 adds optional language intelligence (separate page). Limits do not sandbox host access—gate with permission/trust policy and `@arnilo/prism-coding-security`.
|
|
77
|
+
- [Language intelligence](language-intelligence.md): optional host-activated `createLanguageIntelligence` — bounded in-package LSP 3.17 JSON-RPC client (Content-Length framing), host-selected server command/args per language, workspace symbols/definitions/references/diagnostics/hover/rename; lazy spawn; URI root confinement; rename gated by `ExecutionPolicy` + atomic write/mutation queue; frozen message/diagnostic/pending/result/timeout/server caps. No `vscode-languageserver-protocol` dependency.
|
|
78
|
+
- [Process sessions](process-sessions.md): optional host-activated `createProcessSessions` — long-running process registry (start/cursor-paged output/input/wait/signal/kill/release), native or sandbox `startProcess` backend (fail closed when absent), ownership/identity + expiry sweep on access, `reconcile` / sandbox-loss → `unknown` (never fabricates exitCode), durable command fingerprint metadata, `CodingProcessEvent` host sink, `ExecutionPolicy` before spawn and on mutate, frozen session/input/lifetime/output caps; PTY fails closed as unsupported.
|
|
79
|
+
- [Forge integration](forge-integration.md): optional host-activated `createGitHubForge` — reference GitHub adapter (issue context, authenticated push via `BoundGitRunner` + `GIT_CONFIG_*` credential injection, PR create/update, review comments, check/status retrieval, bounded `reconcileHandoff`), every mutation gated by `ExecutionPolicy` and recorded in `ToolEffectStore` (retry never duplicates PRs/comments), typed `ForgeError` codes (auth/API/stale/rate-limit/limit/ownership), frozen page/payload/comment/concurrency/timeout caps, no octokit dependency, tokens never in argv/logs/events.
|
|
80
|
+
- [Coding execution approval and sandboxing](coding-security.md): path/command approval, identity-scoped caching, shell-turn exclusivity, required `workspaceMode` (`host`/`sandbox`) with fail-closed mixed wiring, `createSandboxCodingComposition()` containment metadata, disposable Docker/OCI sandbox reference with bounded workspace import/export, optional `DisposableSandbox.startProcess` / `SandboxProcessHandle` for process-session backends, and allow-list egress (`createEgressPolicy` deny-all exact rules + frozen presets, `createAllowListEgressProxy` HTTP/CONNECT proxy with pinned-DNS rebinding defense, private/metadata IP denial, redirect re-validation + hop cap, byte/time caps, per-decision audit, `composeEgressSandboxNetwork` attestation recorded as `prism.egress.*` labels; TLS pass-through, no interception).
|
|
78
81
|
|
|
79
82
|
## Extensions/plugins
|
|
80
83
|
- [Contribution discovery (workspace)](contribution-discovery.md): opt-in, realpath-contained directory scanner turning `SKILL.md`/`manifest.json` into inert `DiscoveredContribution` envelopes the host registers — no `import()`, no auto-activate, no provider scanning. Per-agent bundles remain app-controlled and are documented under Agent/session runtime.
|
|
@@ -93,8 +96,9 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
93
96
|
|
|
94
97
|
## Multi-agent and interoperability
|
|
95
98
|
- [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.
|
|
96
|
-
- [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,
|
|
97
|
-
- [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, and stable ACP sibling over shared redacted event and durable-approval seams; 0.0.14 adds reconnectable co-work events.
|
|
99
|
+
- [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).
|
|
100
|
+
- [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.
|
|
101
|
+
- [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).
|
|
98
102
|
- [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.
|
|
99
103
|
|
|
100
104
|
## CLI/RPC
|
|
@@ -117,7 +121,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
117
121
|
- [Compaction conformance](compaction-conformance.md): assert any `CompactionStrategy` returns a non-empty redacted summary and observes abort from `@arnilo/prism/testing/compaction-conformance`.
|
|
118
122
|
- [Tool conformance](tool-conformance.md): assert the tool-dispatch blocked-reason matrix (unknown/denied/invalid/permission/validator) and success path from `@arnilo/prism/testing/tool-conformance`.
|
|
119
123
|
- [Extension conformance](extension-conformance.md): assert an `Extension` setup runs, contributions stay inert, and setup errors are redacted or rethrown from `@arnilo/prism/testing/extension-conformance`.
|
|
120
|
-
- `examples/`: compile-checked typed examples and runnable mock demos (SDK basics, provider registration, auth, tools, [`examples/ag-ui-server.ts`](../examples/ag-ui-server.ts), [`examples/ag-ui-a2ui.ts`](../examples/ag-ui-a2ui.ts), [`examples/ag-ui-mcp-apps.ts`](../examples/ag-ui-mcp-apps.ts), [`examples/enterprise-identity.ts`](../examples/enterprise-identity.ts), [`examples/enterprise-policy-audit.ts`](../examples/enterprise-policy-audit.ts), [`examples/enterprise-work-connectors.ts`](../examples/enterprise-work-connectors.ts), [`examples/enterprise-postgres-state.ts`](../examples/enterprise-postgres-state.ts), [`examples/conversation-durable-replay.ts`](../examples/conversation-durable-replay.ts), [`examples/artifact-review-delivery.ts`](../examples/artifact-review-delivery.ts), [`examples/server-deployment-seams.ts`](../examples/server-deployment-seams.ts), cache-aware prompt assembly, NeuralWatt agent run ([`examples/neuralwatt-agent-run.ts`](../examples/neuralwatt-agent-run.ts)), [`examples/coding-compaction.ts`](../examples/coding-compaction.ts), [`examples/caveman-ponytail.ts`](../examples/caveman-ponytail.ts), stores/branching, structured-output/artifact-loop, CLI, RPC, workflow orchestration).
|
|
124
|
+
- `examples/`: compile-checked typed examples and runnable mock demos (SDK basics, provider registration, auth, tools, [`examples/ag-ui-server.ts`](../examples/ag-ui-server.ts), [`examples/ag-ui-a2ui.ts`](../examples/ag-ui-a2ui.ts), [`examples/ag-ui-mcp-apps.ts`](../examples/ag-ui-mcp-apps.ts), [`examples/enterprise-identity.ts`](../examples/enterprise-identity.ts), [`examples/enterprise-policy-audit.ts`](../examples/enterprise-policy-audit.ts), [`examples/enterprise-work-connectors.ts`](../examples/enterprise-work-connectors.ts), [`examples/enterprise-postgres-state.ts`](../examples/enterprise-postgres-state.ts), [`examples/conversation-durable-replay.ts`](../examples/conversation-durable-replay.ts), [`examples/artifact-review-delivery.ts`](../examples/artifact-review-delivery.ts), [`examples/server-deployment-seams.ts`](../examples/server-deployment-seams.ts), cache-aware prompt assembly, NeuralWatt agent run ([`examples/neuralwatt-agent-run.ts`](../examples/neuralwatt-agent-run.ts)), [`examples/coding-compaction.ts`](../examples/coding-compaction.ts), [`examples/acp-coding-host.ts`](../examples/acp-coding-host.ts), [`examples/caveman-ponytail.ts`](../examples/caveman-ponytail.ts), stores/branching, structured-output/artifact-loop, CLI, RPC, workflow orchestration).
|
|
121
125
|
|
|
122
126
|
## Third-party integrations
|
|
123
127
|
- [Caveman behavior integration](caveman.md): optional `@arnilo/prism-caveman` — upstream Caveman skills/commands, `caveman-mode` injector, session `caveman-level` persistence, progressive catalog + `load_skill`; requires host `upstreamPath` and session attach callbacks; inert until `kernel.load`.
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Language intelligence
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`createLanguageIntelligence` is an optional host-activated contract in `@arnilo/prism-coding-agent` that talks to **host-selected** language servers over one bounded in-package JSON-RPC client (LSP 3.17 Content-Length framing). It exposes workspace symbols, definitions, references, diagnostics, hover, and rename/workspace edits. No `vscode-languageserver-protocol` dependency. Nothing spawns on import or construction — servers start lazily on first use and stop on `dispose()`.
|
|
6
|
+
|
|
7
|
+
| Export | Purpose |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `createLanguageIntelligence(options)` | Build a `LanguageIntelligence` instance for one workspace root. |
|
|
10
|
+
| `LanguageIntelligence` | Contract: `workspaceSymbols`, `definitions`, `references`, `diagnostics`, `hover`, `rename`, `dispose`. |
|
|
11
|
+
| `LanguageServerSpec` | Host allow-listed `{ command, args?, languages, env? }`. Never model-supplied. |
|
|
12
|
+
| `LanguageLocation` / `LanguageSymbol` / `LanguageDiagnostic` / `LanguageWorkspaceEdit` | Normalized result shapes (paths workspace-relative; positions LSP 0-based). |
|
|
13
|
+
| `LanguageIntelligenceError` | Typed fail-closed errors (`ERR_PRISM_LSP_*`). |
|
|
14
|
+
| `resolveLanguageIntelligenceLimits` / `DEFAULT_MAX_LSP_*` / `HARD_MAX_LSP_*` | Finite caps for message bytes, diagnostics/file, pending requests, results/query, timeout, servers. |
|
|
15
|
+
| `encodeLspFrame` / `LspFrameReader` | Framing helpers (tests/hosts). |
|
|
16
|
+
|
|
17
|
+
## When to use it
|
|
18
|
+
|
|
19
|
+
Use when a host wants IDE-like language intelligence without embedding a parser framework or trusting model-chosen server commands. Wire host-pinned server binaries (for example `typescript-language-server --stdio`) and gate renames with the same `ExecutionPolicy` used for write/edit tools.
|
|
20
|
+
|
|
21
|
+
Do not use this as a sandbox, tool registry, or process session manager. Optional process-session registration of LSP children can use `createProcessSessions` ([Process sessions](process-sessions.md)).
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createLanguageIntelligence } from "@arnilo/prism-coding-agent";
|
|
25
|
+
|
|
26
|
+
const lang = createLanguageIntelligence({
|
|
27
|
+
workspaceRoot,
|
|
28
|
+
servers: {
|
|
29
|
+
typescript: {
|
|
30
|
+
command: "/usr/bin/typescript-language-server",
|
|
31
|
+
args: ["--stdio"],
|
|
32
|
+
languages: ["typescript", "typescriptreact"],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
policy: hostExecutionPolicy, // rename gated like edit
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const defs = await lang.definitions({ file: "src/a.ts", line: 10, character: 4 });
|
|
39
|
+
await lang.rename({ file: "src/a.ts", line: 10, character: 4, newName: "renamed" });
|
|
40
|
+
await lang.dispose();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Inputs / request
|
|
44
|
+
|
|
45
|
+
`createLanguageIntelligence` options:
|
|
46
|
+
|
|
47
|
+
| Field | Type | Purpose |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| `workspaceRoot` | `string` | Absolute or relative workspace root; all file URIs must stay inside. |
|
|
50
|
+
| `servers` | `Record<string, LanguageServerSpec>` | Host map keyed by server name; size capped (`maxServers`). |
|
|
51
|
+
| `limits?` | `LanguageIntelligenceLimits` | Optional overrides; invalid values fail instead of clamping. |
|
|
52
|
+
| `policy?` | `ExecutionPolicy` | Applied before rename writes (`kind: "edit"`, `operation: "rename"`). |
|
|
53
|
+
|
|
54
|
+
`LanguageServerSpec`:
|
|
55
|
+
|
|
56
|
+
| Field | Purpose |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `command` | Host allow-listed executable path. |
|
|
59
|
+
| `args?` | Fixed argv (never from the model). |
|
|
60
|
+
| `languages` | Language ids this server handles (matched from file extension). |
|
|
61
|
+
| `env?` | Extra env merged onto `process.env` for the child. |
|
|
62
|
+
|
|
63
|
+
Operation inputs use workspace-relative `file` plus LSP **0-based** `line` / `character`. `rename` also requires `newName`.
|
|
64
|
+
|
|
65
|
+
## Outputs / response / events
|
|
66
|
+
|
|
67
|
+
| Method | Result |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `workspaceSymbols(query)` | `LanguageSymbol[]` (capped). |
|
|
70
|
+
| `definitions` / `references` | `LanguageLocation[]` (capped). |
|
|
71
|
+
| `diagnostics(file?)` | Normalized `LanguageDiagnostic[]` (per-file and aggregate caps). |
|
|
72
|
+
| `hover` | `{ text }` or `undefined`. |
|
|
73
|
+
| `rename` | `LanguageWorkspaceEdit` after policy-checked atomic writes. |
|
|
74
|
+
| `dispose` | Stops all spawned servers (bounded). |
|
|
75
|
+
|
|
76
|
+
Errors are `LanguageIntelligenceError` with codes: `ERR_PRISM_LSP_FRAMING`, `ERR_PRISM_LSP_SERVER`, `ERR_PRISM_LSP_TIMEOUT`, `ERR_PRISM_LSP_LIMIT`, `ERR_PRISM_LSP_UNSUPPORTED`, `ERR_PRISM_LSP_WORKSPACE`.
|
|
77
|
+
|
|
78
|
+
No package-owned events; hosts observe via their own run/tool wiring.
|
|
79
|
+
|
|
80
|
+
## Request/response example
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
// definitions request (host API, not JSON-RPC wire)
|
|
84
|
+
{ "file": "src/a.ts", "line": 10, "character": 4 }
|
|
85
|
+
|
|
86
|
+
// normalized definition
|
|
87
|
+
{ "file": "src/a.ts", "line": 2, "character": 0 }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
// rename workspace edit (after apply)
|
|
92
|
+
{
|
|
93
|
+
"edits": [
|
|
94
|
+
{
|
|
95
|
+
"file": "src/a.ts",
|
|
96
|
+
"newText": "renamed",
|
|
97
|
+
"range": {
|
|
98
|
+
"start": { "line": 10, "character": 4 },
|
|
99
|
+
"end": { "line": 10, "character": 7 }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Implementation example
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import {
|
|
110
|
+
createLanguageIntelligence,
|
|
111
|
+
DEFAULT_MAX_LSP_TIMEOUT_MS,
|
|
112
|
+
} from "@arnilo/prism-coding-agent";
|
|
113
|
+
import { createCodingApprovalPolicy } from "@arnilo/prism-coding-security";
|
|
114
|
+
|
|
115
|
+
const policy = createCodingApprovalPolicy({
|
|
116
|
+
roots: [workspaceRoot],
|
|
117
|
+
approve: async ({ action }) => host.confirm(action),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const lang = createLanguageIntelligence({
|
|
121
|
+
workspaceRoot,
|
|
122
|
+
servers: {
|
|
123
|
+
ts: {
|
|
124
|
+
command: process.execPath, // example only — pin a real language server in production
|
|
125
|
+
args: ["/path/to/typescript-language-server", "--stdio"],
|
|
126
|
+
languages: ["typescript", "typescriptreact"],
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
limits: { requestTimeoutMs: DEFAULT_MAX_LSP_TIMEOUT_MS },
|
|
130
|
+
policy,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const diags = await lang.diagnostics("src/app.ts");
|
|
135
|
+
const hover = await lang.hover({ file: "src/app.ts", line: 0, character: 0 });
|
|
136
|
+
console.log(diags.length, hover?.text);
|
|
137
|
+
} finally {
|
|
138
|
+
await lang.dispose();
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Extension and configuration notes
|
|
143
|
+
|
|
144
|
+
- **Server map is the only language binding.** Extension ids map from common file extensions (`.ts` → `typescript`, `.py` → `python`, …); unknown extensions use `plaintext`. Hosts register servers for the language ids they need.
|
|
145
|
+
- **Lazy start.** First request for a language starts that server (`initialize` / `initialized`); `workspaceSymbols` / aggregate `diagnostics` start all configured servers.
|
|
146
|
+
- **Pluggable policy only.** Renames reuse `assertExecutionAllowed` + `withFileMutationQueue` + `atomicWriteUtf8File`. No second write path.
|
|
147
|
+
- **Framing helpers** (`encodeLspFrame`, `LspFrameReader`) are exported for tests and custom transports; production hosts normally use only `createLanguageIntelligence`.
|
|
148
|
+
- **Not in default tool aggregators.** Hosts call the contract directly or wrap it in their own `ToolDefinition`s.
|
|
149
|
+
|
|
150
|
+
## Security and performance notes
|
|
151
|
+
|
|
152
|
+
- Server `command`/`args` are host-config only — never taken from model tool arguments.
|
|
153
|
+
- File URIs must be `file:` and resolve inside `workspaceRoot`; escapes fail with `ERR_PRISM_LSP_WORKSPACE`.
|
|
154
|
+
- LSP payloads are untrusted: Content-Length framing is bounded; oversized/malformed frames fail closed; result lists and diagnostics are capped.
|
|
155
|
+
- Crash loop: unexpected exit increments a per-server restart counter; after the freeze budget (`LSP_RESTARTS_PER_SERVER` = 3) further starts fail with `ERR_PRISM_LSP_SERVER`.
|
|
156
|
+
- Defaults / hard caps (Phase 9 freeze): message 4 MiB / 32 MiB; diagnostics/file 200 / 1000; pending requests 32 / 128; results/query 500 / 5000; timeout 30 s / 120 s; servers/workspace 4 / 8.
|
|
157
|
+
|
|
158
|
+
## Related APIs
|
|
159
|
+
|
|
160
|
+
- [Coding agent tools](coding-agent-tools.md): shell/read/write/edit/list/search/glob and shared limits/policy seams this contract reuses for rename.
|
|
161
|
+
- [Coding execution approval and sandboxing](coding-security.md): `ExecutionPolicy` / approval composition for gating rename.
|
|
162
|
+
- [Tools](tools.md): host-owned `ToolDefinition` registration if you wrap language intelligence as tools.
|
package/docs/mcp-tools.md
CHANGED
|
@@ -241,6 +241,7 @@ Official Exa/Firecrawl MCP servers may be tested only as explicit hardened proto
|
|
|
241
241
|
- [Host security guide](host-security.md): permission, trust, validation checklist
|
|
242
242
|
- [Web-standard server handler](server.md): agent/workflow HTTP routes and shared remote-boundary rules
|
|
243
243
|
- Package README: [`@arnilo/prism-mcp`](../packages/mcp/README.md)
|
|
244
|
+
- [ACP coding-host interop](acp.md): ACP clients may attach MCP servers to sessions — bounded configs (8/32 servers, 16 KiB/256 KiB config, 4 KiB/64 KiB header values), http/sse only when advertised, stdio accepted behind the gate, UNSTABLE `acp` always rejected, and every server approved by host `mcp.select` before the bridge connects.
|
|
244
245
|
|
|
245
246
|
## Testing
|
|
246
247
|
|
package/docs/migration.md
CHANGED
|
@@ -1,8 +1,47 @@
|
|
|
1
1
|
# Migration guide
|
|
2
2
|
|
|
3
|
+
## 0.0.26 → 0.0.27 ACP coding-host interop (intentional advertise/surface changes)
|
|
4
|
+
|
|
5
|
+
Release **0.0.27** (Phase 10) turns `@arnilo/prism-ag-ui/acp` from a text/tool/usage/approval glue layer into a full coding-host adapter over the Phase 8/9 primitives: host-seam capability advertisement, session persistence, modes and config options, client fs/terminal, MCP bridging behind a host gate, coding lifecycle events, and elicitation. ACP stays stable **v1** on `@agentclientprotocol/sdk@1.3.0`; UNSTABLE fields are never advertised or consumed. Publishable graph stays **48** manifests.
|
|
6
|
+
|
|
7
|
+
1. **`initialize` advertisement is now a pure function of host seams — hosts that parsed the old response must re-check.** Previously the agent advertised only `sessionCapabilities.close` (plus `loadSession` when a lifecycle seam existed). Now: `loadSession` iff `sessions.load` is wired, `sessionCapabilities.list`/`delete`/`resume`/`additionalDirectories` iff the matching seam exists (`close` stays always-on), `promptCapabilities.image`/`audio`/`embeddedContext` iff the matching `capabilities.prompt` policy seam exists, and `mcpCapabilities.http`/`sse` iff `mcp.select` is wired with that transport. Removing a seam withdraws the method — there is no separate capability flag. Clients must treat every session method they call as capability-gated.
|
|
8
|
+
2. **New session surface.** `session/load`, `session/resume`, `session/list`, `session/delete` register only with their seams; `session/new` input carries policy-checked `cwd`/`additionalDirectories`/`mcpServers`; `session/resume`/`session/load` responses carry `modes`/`configOptions` state when wired. Resuming a still-registered session rejects with `ERR_PRISM_ACP_INPUT` ("ACP session already exists") — reconnect after a replica change must resume a stored session, not a live one. `session/set_mode` and `session/set_config_option` are new when `modes`/`configOptions` are wired; `set_config_option` additionally requires the client to advertise `session.configOptions.boolean`.
|
|
9
|
+
3. **Client fs/terminal are opt-in per client.** When the client advertises `fs.readTextFile`/`writeTextFile` (or `terminal`), `sessionFactory` input gains `coding.filesystem`/`coding.processes` adapters over the client's methods, keyed by a pre-generated session id. Hosts that do not use them keep prior behavior; clients that do not advertise them never see the methods called.
|
|
10
|
+
4. **MCP servers require a host gate.** `mcpServers` on `session/new`/`load` are accepted only when `mcp.select` is wired and approves; the UNSTABLE `acp` transport is always rejected, stdio has no capability advertisement (accepted when the gate exists), and http/sse must match an advertised transport. Unapproved or unconfigured servers fail closed.
|
|
11
|
+
5. **Lifecycle events map to updates.** With `coding.lifecycle` wired, `file_changed` → `tool_call_update` with `locations` (diff only from the `fileDiff` projection allow-list), `worktree_changed`/process events → projection-gated `agent_message_chunk`, `permission_denied` → `failed` status, `configuration_changed` → `config_option_update`. Nothing is emitted without a projection or a streaming session.
|
|
12
|
+
6. **Elicitation, when the client advertises it.** All-elicitation suspensions surface as `elicitation/create` (form mode, bounded schema); otherwise they stay on the shared four-option permission path. Permission semantics are unchanged: `allow_once`/`allow_always`→`allow_for_run`/`reject_once`/`reject_always`→`reject_for_run`, cancel and unknown options deny.
|
|
13
|
+
7. **Frozen caps.** Sessions 32/128, additional directories 8/32, MCP servers 8/32 (config 16 KiB/256 KiB), modes 16/64, config options 16/64, list page 20/100, diff 64 KiB/1 MiB, locations 32/128 per update, media parts 16/64 and 64 KiB/1 MiB, terminal chunks at Phase 9 `process.outputChunkBytes`. Exceeded caps fail closed with `ERR_PRISM_ACP_LIMIT`.
|
|
14
|
+
8. **Errors.** `AcpError` codes `ERR_PRISM_ACP_INPUT` / `LIMIT` / `POLICY` / `CAPABILITY` / `MCP`; over the wire the SDK wraps them as JSON-RPC `-32603` with the message in `data.details` (the code string itself is transport-local). Unadvertised methods surface as `-32601 method not found`.
|
|
15
|
+
|
|
16
|
+
No core, coding-agent, or AG-UI behavior changed; hosts that never wire the new seams see the old minimal advertisement and all prior mappings. Conformance: `node --test scripts/phase10-conformance.test.mjs`; example: `node examples/acp-coding-host.ts`; docs: [ACP coding-host interop](acp.md).
|
|
17
|
+
|
|
18
|
+
## 0.0.25 → 0.0.26 coding intelligence, managed processes, forge, and safe egress (additive)
|
|
19
|
+
|
|
20
|
+
Release **0.0.26** (Phase 9) adds four opt-in capability families to `@arnilo/prism-coding-agent` and `@arnilo/prism-coding-security`: Git-aware repository enumeration, host-selected LSP language intelligence, managed process sessions, a reference GitHub forge adapter with idempotent handoff, and an allow-list egress proxy with DNS-rebinding defense. All are **additive** — no existing export, event, or persisted shape changes; hosts that do not activate the new factories keep prior behavior. Publishable graph stays **48** manifests.
|
|
21
|
+
|
|
22
|
+
1. **Git-aware enumeration is opt-in.** `createLocalRepositoryOperations` keeps the native walker. `createGitAwareRepositoryOperations(cwd, options?)` runs a fixed `git ls-files --cached --others --exclude-standard -z` and falls back to native enumeration when the directory is not a Git work tree or git is unavailable. `includeIgnored` is host-only (never surfaced to tools). No change to `listLocal`/`searchLocal`/`globLocal` callers.
|
|
23
|
+
2. **Language intelligence is host-activated.** `createLanguageIntelligence(options)` spawns the host-selected LSP server lazily (no spawn at construction) and speaks LSP 3.17 over bounded JSON-RPC. Unsupported languages fail closed with `ERR_PRISM_LSP_UNSUPPORTED`; out-of-workspace URIs fail with `ERR_PRISM_LSP_WORKSPACE`. Rename applies through `ExecutionPolicy` (kind `edit`, risk `high`) and atomic writes; hosts that never call it are unaffected.
|
|
24
|
+
3. **Process sessions are a new contract.** `createProcessSessions(options)` manages start/output/input/wait/signal/kill/release with ownership scoping and expiry sweep. Sessions may run natively or through an optional sandbox `startProcess` backend; sandbox loss marks sessions `unknown` for host reconciliation. PTY is not supported (`ERR_PRISM_PROCESS_PTY_UNSUPPORTED`). No change to the existing `shell`/`bash` primitives.
|
|
25
|
+
4. **Forge adapter is a new contract.** `createGitHubForge(options)` is GitHub-first by freeze decision; mutations require durable context (`identity`/`ownership`/`sessionId`/`runId`) and a `ToolEffectStore`, and are gated by `ExecutionPolicy`. Push injects the token via `GIT_CONFIG_*` environment variables — never argv, never persisted. `CreateGitHubForgeOptions.fetch?` (new in 0.0.26) lets hosts route forge traffic through the egress proxy or inject a mock; it defaults to `globalThis.fetch`.
|
|
26
|
+
5. **Egress is deny-all by default.** `createEgressPolicy()` allows nothing; presets (`npm-registry`, `github`) are explicit allow-lists. `createAllowListEgressProxy` pins DNS and verifies the socket peer before tunneling (rebinding defense), denies private/metadata IPs unless `allowPrivate`, re-validates redirects per hop, and caps bytes/time/concurrency. `composeEgressSandboxNetwork` records the attestation as `prism.egress.*` container labels; `denyDirectEgress` is asserted on sandbox start.
|
|
27
|
+
6. **No migration steps required.** No persisted shape, event schema, or default behavior changed. Hosts upgrading from 0.0.25 can adopt any subset of the new factories; the previous `docs/migration.md` sections remain accurate for their releases.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { createGitAwareRepositoryOperations } from "@arnilo/prism-coding-agent";
|
|
31
|
+
const repo = createGitAwareRepositoryOperations(process.cwd());
|
|
32
|
+
const { entries } = await repo.listLocal({ maxDepth: 3 });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Examples: `node examples/phase9-coding-intelligence.ts` (composed, network-free).
|
|
36
|
+
7. **Durable `AgentEventSource` root export (FR-6/FR-7).** `@arnilo/prism-session-store-postgres` now re-exports `createPostgresAgentEventSource`, `ClosablePostgresAgentEventSource`, and `PostgresAgentEventSourceOptions` from the package root — previously reachable only via a `dist/...` subpath. `persistence.events` remains the canonical bundled path and is unchanged. Placement answer: the durable event source stays in this package for the 0.0.26 line; PostgreSQL `LISTEN`/`NOTIFY` remains the reference durable implementation. Any future relocation ships a replacement export with a deprecation note before removal — no migration action today. See [agent events](agent-events.md) and `prism-agent-event-source-export-and-location.md`.
|
|
37
|
+
8. **NATS JetStream `AgentEventSource` (FR-5).** New sibling package `@arnilo/prism-session-store-nats` implements the durable `AgentEventSource` contract over JetStream: per-run subjects, per-subject replay, durable pull consumers with explicit acks (at-least-once, 30s redelivery), idempotent `append` by `record.id` within the stream dedupe window, HMAC-signed resumable cursors, and ownership-scoped `page`/`subscribe`/`cleanup`. The host provisions the stream (`prism.agent-events.>`, retention limits, dedupe window); the package is inert on import. Postgres remains the reference durable implementation — NATS is a sibling adapter for JetStream backbones. See [agent events](agent-events.md).
|
|
38
|
+
9. **A2A server-side exposure (Task 13).** `createAgUiA2AServer()` in `@arnilo/prism-ag-ui` fronts one host-selected local AG-UI agent as an A2A 1.0 server: remote A2A clients start and stream local runs through the AG-UI input allow-list and event mapper (same projection/redaction/caps as the AG-UI SSE path), reusing `@arnilo/prism-supervisor` `createA2AHandler` transport. No new runtime, task store, or worker; no route added to `createPrismHandler()` (A2A stays separately mounted). Optional `durable` wiring replays finished runs from an `AgentEventSource` with cursor event ids. Requires the optional `@arnilo/prism-supervisor` peer only when the factory is called (lazy import). See [A2A interoperability](a2a.md).
|
|
39
|
+
10. **Reference frontend renderer (Task 14).** `@arnilo/prism-ag-ui/renderer` subpath export ships a framework-free client renderer: it consumes an AG-UI event stream (SSE or in-memory `AsyncIterable`) and renders `a2ui-surface` snapshots/deltas into DOM surfaces from a host component catalog. DOM-free core (`reduceA2UiOps` operation state machine) plus a thin binding layer with a built-in default text/container catalog; server-side A2UI caps are enforced client-side (ops/message, op bytes, surfaces/run, component depth); invalid/oversized ops drop closed with a bounded error event; unknown components render an explicit placeholder; remote HTML is never executed (createElement/text nodes only). The main `@arnilo/prism-ag-ui` entry stays runtime-agnostic — DOM code lives only behind the `renderer` subpath. Requires no new dependency and no host build step. See [AG-UI](ag-ui.md).
|
|
40
|
+
11. **Async `AgUiProjection` hooks (Task 15).** Every `AgUiProjection` callback return is now `Awaitable<T>` (`T | Promise<T>`), so projectors can call async host APIs like `session.entries()` directly; the AG-UI and ACP mappers await hooks in event order (never `Promise.all`) with per-event fail-closed exactly like sync throw handling. `createMessagesFromSessionProjection({ getMessages })` accepts an async transcript source and emits `MESSAGES_SNAPSHOT` at `agent_started`/`message_finished`. Sync-only hosts keep exact prior behavior — sync values short-circuit, no behavior change, and the sync-path mapper p95 is budget-gated. `projectCoWorkEvent` is now async (it may await the `coWork` hook). See [AG-UI](ag-ui.md).
|
|
41
|
+
|
|
3
42
|
## 0.0.24 → 0.0.25 durable custom loops and human-in-the-loop (intentional pre-1.0 contract changes)
|
|
4
43
|
|
|
5
|
-
Release **0.0.25** makes custom loops durable and replaces sequential binary approvals with one shared pending-decision model. Protocol adapters (AG-UI, ACP, MCP, coding `ask_user_decision`, server resume, supervisor nesting) map onto that model. Opt-in A2UI painting and standard AG-UI projectors ship in `@arnilo/prism-ag-ui`. Publishable graph stays **
|
|
44
|
+
Release **0.0.25** makes custom loops durable and replaces sequential binary approvals with one shared pending-decision model. Protocol adapters (AG-UI, ACP, MCP, coding `ask_user_decision`, server resume, supervisor nesting) map onto that model. Opt-in A2UI painting and standard AG-UI projectors ship in `@arnilo/prism-ag-ui`. Publishable graph stays **48** manifests.
|
|
6
45
|
|
|
7
46
|
1. **Custom loops on durable runs need hooks.** Built-in `single-shot` / `generate-validate-revise` stay durable. A custom `AgentLoopStrategy` on `runState` must expose `snapshot` + `restore` (and usually `revision`) or the run fails closed with `AgentLoopStateError` / `ERR_PRISM_LOOP_NOT_DURABLE` before any provider call. Snapshots must be JSON-compatible and fit the run-state byte/depth caps (`ERR_PRISM_LOOP_SNAPSHOT`).
|
|
8
47
|
2. **Fingerprint loop entry shape changed.** Durable fingerprints now store `{ name, revision }` instead of a bare loop name string. Persisted **0.0.24** runs fail closed on **0.0.25** resume (fingerprint mismatch / `ERR_PRISM_LOOP_REVISION`). Finish or abandon in-flight 0.0.24 durable runs before upgrading, or rebuild from a fresh suspension under 0.0.25.
|
package/docs/performance.md
CHANGED
|
@@ -19,6 +19,22 @@ This page states Prism runtime limits that keep slow consumers and long sessions
|
|
|
19
19
|
|
|
20
20
|
Conformance: `scripts/phase8-conformance.test.mjs` (8 network-free cases). Values are environment evidence, not universal SLOs.
|
|
21
21
|
|
|
22
|
+
## Release 0.0.26 coding intelligence, processes, forge, and egress
|
|
23
|
+
|
|
24
|
+
`node scripts/benchmark-0.0.26.mjs` is network-free (fake LSP/forge/proxy, synthetic 100k-file repo, real process spill). Checked `scripts/benchmark-0.0.26.json` (Node v24.18.0/Linux x64): 5 warmups, 20 measured ops, 100k enumeration files, 1 GiB process spill, 1,000 LSP diagnostics, 100 forge pages × 100 items, 64 MiB proxy download.
|
|
25
|
+
|
|
26
|
+
| Scenario | Recorded p95 ms | Ceiling |
|
|
27
|
+
| --- | ---: | ---: |
|
|
28
|
+
| Git-aware enumeration (100k-file repo, ≤ 2 git invocations, 10k results cap) | 299.166 | 2,000 |
|
|
29
|
+
| Process chunk page (50 KiB pages over 1 GiB spill, 64 MiB retained) | 0.051 | 10 |
|
|
30
|
+
| LSP diagnostic normalization (1,000 diagnostics at hard per-file cap) | 0.210 | 100 |
|
|
31
|
+
| Forge pagination (100 pages × 100 check-runs, deduped) | 144.233 | 10,000 |
|
|
32
|
+
| Proxy download (64 MiB at default response cap, resident buffering ≤ 2× maxBytes) | 93.667 | 30,000 |
|
|
33
|
+
| Renderer stream (1,000-op A2UI surface as 16×64-op batches + full tree render) | 2.000 | 100 |
|
|
34
|
+
| AG-UI mapper sync path (4,000 events through the async pipeline, sync hooks only) | 30.924 | 100 |
|
|
35
|
+
|
|
36
|
+
Conformance: `scripts/phase9-conformance.test.mjs` (8 network-free cases: composed enumeration → LSP rename → process → forge → egress, symlink/ignore escape, LSP URI escape, process ownership, forge cross-tenant + token hygiene, egress private/metadata bypass, limit ladder, packed example). Values are environment evidence, not universal SLOs.
|
|
37
|
+
|
|
22
38
|
## Release 0.0.24 distributed events and tool effects
|
|
23
39
|
|
|
24
40
|
`node scripts/benchmark-0.0.24.mjs` is an explicit protected PostgreSQL benchmark behind `PRISM_TEST_POSTGRES_URL`. Checked `scripts/benchmark-0.0.24.json` (Node v24.18.0/Linux x64, PostgreSQL 16.14): 10 tenants × 10 principals × 1,000 events/owner, 16 producers/subscribers, 100 warmups, 1,000 measured ops, 10,000-event sustained replay, 100-row cleanup.
|