@arnilo/prism 0.0.24 → 0.0.26
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 +41 -0
- package/dist/agent-loops.js +37 -5
- package/dist/agent-run-state.d.ts +27 -1
- package/dist/agent-run-state.js +80 -4
- package/dist/agents.js +884 -77
- package/dist/contracts.d.ts +181 -4
- package/dist/contracts.js +53 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/tools.d.ts +2 -1
- package/dist/tools.js +17 -2
- package/docs/0.1.0-readiness.md +9 -8
- package/docs/a2a.md +24 -0
- package/docs/ag-ui-adoption.md +1 -1
- package/docs/ag-ui.md +102 -3
- package/docs/agent-events.md +25 -0
- package/docs/agent-loops.md +9 -1
- package/docs/agent-session-runtime.md +9 -2
- package/docs/coding-agent-tools.md +29 -3
- package/docs/coding-security.md +36 -2
- package/docs/forge-integration.md +113 -0
- package/docs/host-security.md +1 -0
- package/docs/index.md +13 -10
- package/docs/language-intelligence.md +162 -0
- package/docs/mcp-tools.md +2 -0
- package/docs/migration.md +48 -0
- package/docs/performance.md +23 -6
- package/docs/process-sessions.md +147 -0
- package/docs/release-and-install.md +41 -16
- package/docs/server.md +1 -0
- package/docs/supervisors.md +4 -0
- package/docs/workflows.md +1 -1
- package/package.json +2 -2
package/docs/index.md
CHANGED
|
@@ -11,15 +11,15 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
11
11
|
- [Model routing](model-routing.md): optional `@arnilo/prism-model-router` allow-list/residency/budget/rate/circuit/fallback governance with redacted diagnostics; durable state requires awaited identity-scoped calls.
|
|
12
12
|
|
|
13
13
|
## Agent/session runtime
|
|
14
|
-
- [Agent/session runtime](agent-session-runtime.md): create explicit or opt-in secure agents/sessions, get direct `AgentRunResult` values from `run`/`prompt`, mid-run `steer` (turn-boundary or softInterrupt), use integrated `stream()`/`resumeAgentRunStream()`, subscribe to normalized events, and expose opted-in durable lifecycle capabilities.
|
|
14
|
+
- [Agent/session runtime](agent-session-runtime.md): create explicit or opt-in secure agents/sessions, get direct `AgentRunResult` values from `run`/`prompt`, mid-run `steer` (turn-boundary or softInterrupt), use integrated `stream()`/`resumeAgentRunStream()`, shared batch pending-decisions / sticky run-scope approvals, subscribe to normalized events, and expose opted-in durable lifecycle capabilities.
|
|
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
|
-
- [Agent loops](agent-loops.md): replaceable per-run control loops — `singleShotLoop` default
|
|
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.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.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.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,8 @@ 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, 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.
|
|
98
101
|
- [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
102
|
|
|
100
103
|
## CLI/RPC
|
|
@@ -117,7 +120,7 @@ Prism is a TypeScript/Node.js agent harness. Host apps and extension packages ow
|
|
|
117
120
|
- [Compaction conformance](compaction-conformance.md): assert any `CompactionStrategy` returns a non-empty redacted summary and observes abort from `@arnilo/prism/testing/compaction-conformance`.
|
|
118
121
|
- [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
122
|
- [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-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).
|
|
123
|
+
- `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).
|
|
121
124
|
|
|
122
125
|
## Third-party integrations
|
|
123
126
|
- [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
|
@@ -150,6 +150,8 @@ Duplicate prefixed names throw `McpToolNameCollisionError` at refresh time.
|
|
|
150
150
|
| `maxJsonDepth` / `maxJsonProperties` | 64 / 10,000 (hard 128 / 100,000) | Bound schema and result JSON walks |
|
|
151
151
|
| `signal` | none | Abort connect/list and trigger close on connect abort |
|
|
152
152
|
|
|
153
|
+
MCP elicitation maps onto the shared decision model: `mcpElicitationDecision(approvalId, params)` converts an untrusted `ElicitRequest` (message ≤ 2 KiB, schema ≤ 16 KiB) into a kind-`elicitation` pending decision, and `mcpElicitationResultFromDecision(decision, { humanInteraction })` maps a decision back to a protocol result — `reject_*` declines, `allow_*` accepts with the payload and fails closed unless the host proved explicit human interaction. Wire behavior is unchanged; the marker never reaches protocol output.
|
|
154
|
+
|
|
153
155
|
### Stdio transport
|
|
154
156
|
|
|
155
157
|
```ts
|
package/docs/migration.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Migration guide
|
|
2
2
|
|
|
3
|
+
## 0.0.25 → 0.0.26 coding intelligence, managed processes, forge, and safe egress (additive)
|
|
4
|
+
|
|
5
|
+
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 **47** manifests.
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
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.
|
|
9
|
+
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.
|
|
10
|
+
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`.
|
|
11
|
+
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.
|
|
12
|
+
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.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createGitAwareRepositoryOperations } from "@arnilo/prism-coding-agent";
|
|
16
|
+
const repo = createGitAwareRepositoryOperations(process.cwd());
|
|
17
|
+
const { entries } = await repo.listLocal({ maxDepth: 3 });
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Examples: `node examples/phase9-coding-intelligence.ts` (composed, network-free).
|
|
21
|
+
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`.
|
|
22
|
+
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).
|
|
23
|
+
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).
|
|
24
|
+
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).
|
|
25
|
+
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).
|
|
26
|
+
|
|
27
|
+
## 0.0.24 → 0.0.25 durable custom loops and human-in-the-loop (intentional pre-1.0 contract changes)
|
|
28
|
+
|
|
29
|
+
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 **47** manifests.
|
|
30
|
+
|
|
31
|
+
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`).
|
|
32
|
+
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.
|
|
33
|
+
3. **Batch resume.** `AgentRunResume` accepts either legacy `{ decision: "approve" | "deny" }` or `{ decisions: RunDecision[] }` — exactly one. Outcomes: `allow_once` / `allow_for_run` / `reject_once` / `reject_for_run`, optional `reason`, `modifiedArguments`, `elicitation`. One CAS transition applies the whole batch; partial batches re-suspend with remaining pendings. Sticky decisions expire at run end and match exact scope (tool/effect/identity/arguments hash + nested attribution path).
|
|
34
|
+
4. **Elicitation.** Tools may declare an `elicitation` hook; coding `ask_user_decision` uses it on durable gates. MCP hosts use `mcpElicitationDecision` / `mcpElicitationResultFromDecision` with required `humanInteraction: true` on accept.
|
|
35
|
+
5. **Nested approvals.** Supervisors with `checkpoints` + `definitionRevision` surface child approvals to the root as hashed attributed ids; `resumeNestedRun` routes decisions without widening child permission. Root sticky decisions are path-scoped.
|
|
36
|
+
6. **AG-UI / ACP / server.** Interrupts carry redacted `pendingDecisions` in metadata; resume may return a batch. ACP permission offers four outcomes (`allow_always` → `allow_for_run`, `reject_always` → `reject_for_run`); cancelled stays terminal deny. Server `/resume` validates the same shapes at the boundary.
|
|
37
|
+
7. **Opt-in generative UI.** `createAgUiHandler({ a2ui })` paints A2UI v0.9 surfaces; A2UI actions return through existing `input.project` (not an automatic tool loopback). Standard projectors (`createMessagesFromSessionProjection`, `createStateFromStoreProjection`, `createActivityFromToolProgressProjection`, `composeAgUiProjections`) are explicit opt-in.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
await resumeAgentRun(checkpoints, {
|
|
41
|
+
runId,
|
|
42
|
+
decisions: [
|
|
43
|
+
{ approvalId: "a1", outcome: "allow_for_run" },
|
|
44
|
+
{ approvalId: "a2", outcome: "reject_once", reason: "external recipient" },
|
|
45
|
+
],
|
|
46
|
+
}, { ownership, expectedVersion });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Examples: `node examples/durable-loops-and-approvals.ts`, `node examples/ag-ui-a2ui.ts`. Hosts that never set `runState` / interrupt gates keep prior behavior aside from the fingerprint shape for any already-persisted durable runs.
|
|
50
|
+
|
|
3
51
|
## 0.0.23 → 0.0.24 distributed events and recoverable tool effects (intentional pre-1.0 contract changes)
|
|
4
52
|
|
|
5
53
|
Release **0.0.24** adds a replaceable durable `AgentEventSource`, recoverable `ToolEffectStore`, full AG-UI 0.0.57 compatibility, and AG-UI fronting for MCP / MCP Apps / remote A2A. Core remains dependency-free; PostgreSQL adapters and effect stores stay opt-in. Delivery is at-least-once with consumer deduplication — not exactly-once.
|
package/docs/performance.md
CHANGED
|
@@ -6,17 +6,34 @@ Evaluation defaults are finite: 100 trace rows × 20 pages and 4 MiB aggregate t
|
|
|
6
6
|
|
|
7
7
|
This page states Prism runtime limits that keep slow consumers and long sessions from becoming unbounded memory or latency problems.
|
|
8
8
|
|
|
9
|
-
## Release 0.0.
|
|
9
|
+
## Release 0.0.25 durable loops and human-in-the-loop
|
|
10
10
|
|
|
11
|
-
`node scripts/benchmark-0.0.
|
|
11
|
+
`node scripts/benchmark-0.0.25.mjs` is network-free (in-memory checkpoint store). Checked `scripts/benchmark-0.0.25.json` (Node v24.18.0/Linux x64): 20 warmups, 100 measured ops, 32 pending decisions, ~250 KiB snapshot, 64 A2UI ops/message.
|
|
12
12
|
|
|
13
13
|
| Scenario | Recorded p95 ms | Ceiling |
|
|
14
14
|
| --- | ---: | ---: |
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
15
|
+
| Decision apply (batch CAS) | 3.913 | 5 |
|
|
16
|
+
| Sticky match | 0.407 | 5 |
|
|
17
|
+
| Snapshot capture/restore | 6.742 | 20 |
|
|
18
|
+
| A2UI paint | 0.348 | 10 |
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
Conformance: `scripts/phase8-conformance.test.mjs` (8 network-free cases). Values are environment evidence, not universal SLOs.
|
|
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.
|
|
20
37
|
|
|
21
38
|
## Release 0.0.24 distributed events and tool effects
|
|
22
39
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Process sessions
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`createProcessSessions` is an optional host-activated registry in `@arnilo/prism-coding-agent` for **long-running** child processes: start, cursor-paged output, input, wait, signal/kill, and release (detach). Sessions have bounded lifetime (sweep on registry access — no import-time timers), ownership/identity attribution, durable metadata (command fingerprint without env/secrets), and typed `CodingProcessEvent`s via a host callback. Reuses `ExecutionPolicy`, `killProcessTree`, and `OutputAccumulator` (including spill + `readRaw` cursor paging). Optional duck-typed `sandbox` backend uses `startProcess` when present; one-shot adapters fail closed. Nothing spawns on import or construction.
|
|
6
|
+
|
|
7
|
+
| Export | Purpose |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `createProcessSessions(options)` | Build a `ProcessSessions` registry bound to one workspace `cwd`. |
|
|
10
|
+
| `ProcessSessions` | `start`, `get`, `cancelOwned`, `markUnknown`, `reconcile`, `dispose`. |
|
|
11
|
+
| `ProcessSession` | Handle: `output` / `input` / `wait` / `signal` / `kill` / `release` / `metadata`. |
|
|
12
|
+
| `ProcessSessionState` | `starting` \| `running` \| `exited` \| `killed` \| `released` \| `expired` \| `unknown`. |
|
|
13
|
+
| `ProcessSandboxBackend` | Duck-typed optional sandbox (`startProcess?`, `status?`); mirrors coding-security `SandboxProcessHandle`. |
|
|
14
|
+
| `CodingProcessEvent` | Host-sink events (`process_started` / `_exited` / `_killed` / `_released` / `_expired` / `_unknown`). |
|
|
15
|
+
| `ProcessSessionError` | Typed fail-closed errors (`ERR_PRISM_PROCESS_*`). |
|
|
16
|
+
| `resolveProcessSessionLimits` / `DEFAULT_MAX_PROCESS_*` / `HARD_MAX_PROCESS_*` | Session count, input bytes, lifetime, chunk/total output caps. |
|
|
17
|
+
|
|
18
|
+
## When to use it
|
|
19
|
+
|
|
20
|
+
Use when a host needs attachable long-running processes (watch modes, language servers, interactive CLIs) that one-shot `shell` cannot model. Do not use as a job-control language or PTY emulator — `pty: true` fails closed with `ERR_PRISM_PROCESS_PTY_UNSUPPORTED` until a platform capability is wired. Pass a sandbox with `startProcess` for contained long-running work; omit `sandbox` for native spawn.
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { createProcessSessions } from "@arnilo/prism-coding-agent";
|
|
24
|
+
|
|
25
|
+
const sessions = createProcessSessions({ cwd: workspaceRoot, policy, sandbox, onEvent });
|
|
26
|
+
const p = await sessions.start({ command: "npm", args: ["test", "--", "--watch"] });
|
|
27
|
+
const out = await p.output({ cursor: 0, maxBytes: 8192 });
|
|
28
|
+
await p.input("q\n");
|
|
29
|
+
await p.wait({ timeoutMs: 5000 });
|
|
30
|
+
await sessions.dispose();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Inputs / request
|
|
34
|
+
|
|
35
|
+
`createProcessSessions` options:
|
|
36
|
+
|
|
37
|
+
| Field | Type | Purpose |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| `cwd` | `string` | Workspace root; session `cwd` must stay inside. |
|
|
40
|
+
| `policy?` | `ExecutionPolicy` | Gated before spawn and rechecked on input/signal/kill. |
|
|
41
|
+
| `limits?` | `ProcessSessionLimits` | Optional overrides; invalid values fail instead of clamping. |
|
|
42
|
+
| `onEvent?` | `(CodingProcessEvent) => void` | Host-owned sink (core `AgentEvent` unchanged); audit owner + terminal/unknown. |
|
|
43
|
+
| `ownership?` | `OwnershipScope` | Default owner key for sessions. |
|
|
44
|
+
| `identity?` | `AgentIdentity` | When ownership omitted, owner key projects from identity. |
|
|
45
|
+
| `sandbox?` | `ProcessSandboxBackend` | When set: require `startProcess` or fail closed; `status` loss → all running → `unknown`. |
|
|
46
|
+
|
|
47
|
+
`ProcessStartRequest`:
|
|
48
|
+
|
|
49
|
+
| Field | Purpose |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `command` / `args?` | Executable + argv (not a shell string). |
|
|
52
|
+
| `cwd?` | Relative/absolute path contained under registry `cwd`. |
|
|
53
|
+
| `env?` | Extra env merged onto `process.env` (never in fingerprint). |
|
|
54
|
+
| `pty?` | Default false; unsupported → `ERR_PRISM_PROCESS_PTY_UNSUPPORTED`. |
|
|
55
|
+
| `lifetimeMs?` | Bounded by `maxLifetimeMs`. |
|
|
56
|
+
| `owner?` | Override owner string. |
|
|
57
|
+
| `releaseOnCancel?` | If true, `cancelOwned` releases instead of killing. |
|
|
58
|
+
|
|
59
|
+
## Outputs / response / events
|
|
60
|
+
|
|
61
|
+
| Method | Result |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| `start` | `ProcessSession` in `running`; emits `process_started`. |
|
|
64
|
+
| `output({ cursor, maxBytes })` | `{ data, cursor, eof }` UTF-8 page from byte cursor. |
|
|
65
|
+
| `input` | Writes stdin; capped by `maxInputBytes`; fails if not running / stdin closed. |
|
|
66
|
+
| `wait` | `{ exitCode, state }` — `exitCode` is `null` for killed/released/expired/unknown. |
|
|
67
|
+
| `signal` / `kill` / `release` | Soft signal, hard kill, or detach (no re-attach). |
|
|
68
|
+
| `cancelOwned(owner)` | Kill (default) or release owned running sessions. |
|
|
69
|
+
| `markUnknown` | Backend-loss terminal state; never fabricates `exitCode`. |
|
|
70
|
+
| `reconcile()` | Host resume: mark every running/starting session `unknown` (O(sessions)). |
|
|
71
|
+
|
|
72
|
+
Events: `process_started`, `process_exited`, `process_killed`, `process_released`, `process_expired`, `process_unknown`.
|
|
73
|
+
|
|
74
|
+
Errors: `ERR_PRISM_PROCESS_POLICY`, `ERR_PRISM_PROCESS_OWNERSHIP`, `ERR_PRISM_PROCESS_STATE`, `ERR_PRISM_PROCESS_LIMIT`, `ERR_PRISM_PROCESS_PTY_UNSUPPORTED`, `ERR_PRISM_PROCESS_UNSUPPORTED`.
|
|
75
|
+
|
|
76
|
+
## Request/response example
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"command": "npm",
|
|
81
|
+
"args": ["test", "--", "--watch"],
|
|
82
|
+
"lifetimeMs": 14400000,
|
|
83
|
+
"releaseOnCancel": false
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Implementation example
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const sessions = createProcessSessions({
|
|
91
|
+
cwd: workspaceRoot,
|
|
92
|
+
ownership: { tenantId: "t1", userId: "u1" },
|
|
93
|
+
sandbox, // DisposableSandbox with startProcess, or omit for native
|
|
94
|
+
limits: { maxSessions: 8 },
|
|
95
|
+
onEvent: (e) => audit.write(e),
|
|
96
|
+
policy: hostExecutionPolicy,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const p = await sessions.start({
|
|
100
|
+
command: process.execPath,
|
|
101
|
+
args: ["server.js"],
|
|
102
|
+
lifetimeMs: 3_600_000,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
let cursor = 0;
|
|
106
|
+
for (;;) {
|
|
107
|
+
const chunk = await p.output({ cursor, maxBytes: 50_000 });
|
|
108
|
+
cursor = chunk.cursor;
|
|
109
|
+
if (chunk.eof) break;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
await sessions.cancelOwned(p.owner); // run cancellation
|
|
113
|
+
await sessions.dispose();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Extension and configuration notes
|
|
117
|
+
|
|
118
|
+
- Native when `sandbox` omitted; with `sandbox`, capability is `typeof startProcess === "function"` (never assumed).
|
|
119
|
+
- One-shot sandbox (no `startProcess`) → `ERR_PRISM_PROCESS_UNSUPPORTED` (no native fallback).
|
|
120
|
+
- Sandbox `status` not `running` (or throws) → all live sessions → `unknown`; further `start` fails closed.
|
|
121
|
+
- Host restart: call `reconcile()` on a new registry for in-memory orphans, or listen for `process_unknown` and wire Phase 7 `ToolEffectStore.markUnknown` in the host.
|
|
122
|
+
- Expiry sweep runs on registry/handle access — no timers at import.
|
|
123
|
+
- Command fingerprint is SHA-256 of `[command, ...args]` only (no env).
|
|
124
|
+
- Docker reference adapter does not implement `startProcess` yet — fail closed until a capable runtime is wired.
|
|
125
|
+
|
|
126
|
+
## Security and performance notes
|
|
127
|
+
|
|
128
|
+
| Cap | Default | Hard |
|
|
129
|
+
| --- | ---: | ---: |
|
|
130
|
+
| Sessions per registry | 8 | 32 |
|
|
131
|
+
| Input write bytes | 64 KiB | 1 MiB |
|
|
132
|
+
| Session lifetime | 4 h | 24 h |
|
|
133
|
+
| Output chunk | 50 KiB | 1 MiB |
|
|
134
|
+
| Total output / session | 64 MiB | 1 GiB |
|
|
135
|
+
|
|
136
|
+
- Wrong-owner `get(id, owner)` → `ERR_PRISM_PROCESS_OWNERSHIP`.
|
|
137
|
+
- Released sessions reject all further handle ops.
|
|
138
|
+
- `cwd` outside workspace → `ERR_PRISM_PROCESS_POLICY`.
|
|
139
|
+
- Policy denial before spawn / on mutate → `ERR_PRISM_PROCESS_POLICY`.
|
|
140
|
+
- Unknown outcome never invents an exit code.
|
|
141
|
+
|
|
142
|
+
## Related APIs
|
|
143
|
+
|
|
144
|
+
- [Coding agent tools](coding-agent-tools.md): one-shot `shell` vs long-running sessions.
|
|
145
|
+
- [Language intelligence](language-intelligence.md): LSP servers may later register as managed sessions.
|
|
146
|
+
- [Coding security](coding-security.md): `SandboxProcessHandle` / optional `DisposableSandbox.startProcess`.
|
|
147
|
+
- [Tool effects](tool-effects.md): unknown-outcome vocabulary mirrored by `markUnknown` / `process_unknown` / `reconcile`.
|