@arnilo/prism 0.0.96 → 0.1.0
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 +285 -2
- package/README.md +17 -3
- package/dist/agent-definitions.js +2 -3
- package/dist/agent-event-source.d.ts +11 -0
- package/dist/agent-event-source.js +512 -0
- package/dist/agent-loops.d.ts +5 -0
- package/dist/agent-loops.js +99 -14
- package/dist/agent-run-lifecycle.d.ts +5 -2
- package/dist/agent-run-lifecycle.js +18 -2
- package/dist/agent-run-state.d.ts +27 -1
- package/dist/agent-run-state.js +113 -7
- package/dist/agents.d.ts +3 -1
- package/dist/agents.js +1255 -129
- package/dist/artifacts.d.ts +132 -0
- package/dist/artifacts.js +44 -0
- package/dist/cache-helpers.js +18 -9
- package/dist/checkpoints.d.ts +4 -0
- package/dist/checkpoints.js +17 -9
- package/dist/cli-init.js +3 -7
- package/dist/cli-runner.d.ts +2 -6
- package/dist/cli-runner.js +71 -33
- package/dist/compaction.js +5 -4
- package/dist/config.js +7 -4
- package/dist/content.js +26 -24
- package/dist/context-budget.d.ts +67 -0
- package/dist/context-budget.js +288 -0
- package/dist/contracts.d.ts +590 -8
- package/dist/contracts.js +142 -1
- package/dist/contribution-parsing.js +6 -2
- package/dist/contributions.d.ts +2 -0
- package/dist/contributions.js +3 -0
- package/dist/conversations.d.ts +50 -0
- package/dist/conversations.js +98 -0
- package/dist/credentials.d.ts +22 -2
- package/dist/credentials.js +18 -3
- package/dist/devices.d.ts +94 -0
- package/dist/devices.js +138 -0
- package/dist/event-multiplexer.js +18 -4
- package/dist/extensions.d.ts +18 -1
- package/dist/extensions.js +79 -6
- package/dist/feedback.js +12 -10
- package/dist/guardrails.d.ts +1 -1
- package/dist/guardrails.js +26 -17
- package/dist/identity.d.ts +92 -0
- package/dist/identity.js +265 -0
- package/dist/index.d.ts +94 -72
- package/dist/index.js +48 -36
- package/dist/input.d.ts +10 -1
- package/dist/input.js +152 -52
- package/dist/instruction-injection.d.ts +1 -1
- package/dist/middleware.js +9 -1
- package/dist/models.d.ts +2 -0
- package/dist/models.js +3 -0
- package/dist/node/agent-definitions.js +16 -8
- package/dist/node/contribution-discovery.d.ts +1 -2
- package/dist/node/contribution-discovery.js +3 -3
- package/dist/node/session-store-jsonl.js +13 -7
- package/dist/node/settings.d.ts +1 -1
- package/dist/node/settings.js +1 -1
- package/dist/node/system-project-prompts.js +2 -4
- package/dist/node/trust.js +1 -1
- package/dist/persistence-lifecycle.d.ts +103 -0
- package/dist/persistence-lifecycle.js +202 -0
- package/dist/provider-events.d.ts +1 -0
- package/dist/provider-events.js +6 -1
- package/dist/provider-request-policy.js +3 -4
- package/dist/providers/media.d.ts +1 -1
- package/dist/providers/openai-compatible.d.ts +46 -1
- package/dist/providers/openai-compatible.js +123 -53
- package/dist/providers/openai-primitives.js +10 -7
- package/dist/providers/transport.d.ts +6 -0
- package/dist/providers/transport.js +21 -0
- package/dist/providers.d.ts +2 -0
- package/dist/providers.js +3 -0
- package/dist/redaction.d.ts +1 -0
- package/dist/redaction.js +26 -9
- package/dist/resources.d.ts +2 -2
- package/dist/resources.js +2 -2
- package/dist/retry.d.ts +5 -0
- package/dist/retry.js +8 -1
- package/dist/rpc.js +55 -11
- package/dist/run-ledger.d.ts +6 -0
- package/dist/run-ledger.js +16 -13
- package/dist/run-limits.js +49 -10
- package/dist/secure-agent.js +8 -2
- package/dist/security.js +7 -2
- package/dist/session-stores.d.ts +7 -2
- package/dist/session-stores.js +195 -21
- package/dist/skill-disclosure.d.ts +35 -0
- package/dist/skill-disclosure.js +101 -0
- package/dist/skill-load.d.ts +25 -0
- package/dist/skill-load.js +112 -0
- package/dist/structured-output.d.ts +5 -1
- package/dist/structured-output.js +20 -2
- package/dist/system-prompts.js +7 -2
- package/dist/testing/agent-event-source-conformance.d.ts +4 -0
- package/dist/testing/agent-event-source-conformance.js +54 -0
- package/dist/testing/compaction-conformance.js +5 -1
- package/dist/testing/extension-conformance.js +15 -3
- package/dist/testing/feedback.d.ts +1 -3
- package/dist/testing/feedback.js +1 -1
- package/dist/testing/persistence-schema.d.ts +2 -2
- package/dist/testing/persistence-schema.js +280 -35
- package/dist/testing/provider-conformance.js +3 -3
- package/dist/testing/run-ledger-conformance.js +1 -1
- package/dist/testing/session-store-conformance.d.ts +6 -0
- package/dist/testing/session-store-conformance.js +37 -2
- package/dist/testing/tool-conformance.js +30 -5
- package/dist/testing/tool-effect-store-conformance.d.ts +9 -0
- package/dist/testing/tool-effect-store-conformance.js +85 -0
- package/dist/thinking.js +4 -1
- package/dist/tool-effects.d.ts +15 -0
- package/dist/tool-effects.js +352 -0
- package/dist/tool-result-fold.d.ts +40 -0
- package/dist/tool-result-fold.js +176 -0
- package/dist/tools.d.ts +8 -3
- package/dist/tools.js +248 -13
- package/docs/0.1.0-readiness.md +202 -0
- package/docs/a2a.md +33 -2
- package/docs/acp.md +126 -0
- package/docs/ag-ui-adoption.md +77 -0
- package/docs/ag-ui.md +225 -0
- package/docs/agent-events.md +34 -3
- package/docs/agent-identity.md +144 -0
- package/docs/agent-loops.md +17 -2
- package/docs/agent-session-runtime.md +21 -4
- package/docs/browser-automation.md +5 -0
- package/docs/caveman.md +129 -0
- package/docs/cli-rpc.md +3 -6
- package/docs/coding-agent-tools.md +229 -25
- package/docs/coding-security.md +77 -11
- package/docs/compaction-and-retry.md +5 -2
- package/docs/compaction-llm.md +20 -1
- package/docs/compaction-observational-memory.md +52 -8
- package/docs/context-and-skills.md +94 -7
- package/docs/contribution-registries.md +1 -0
- package/docs/conversations.md +135 -0
- package/docs/credential-storage.md +34 -1
- package/docs/credentials-and-redaction.md +11 -1
- package/docs/database-persistence.md +27 -7
- package/docs/device-adapters.md +97 -0
- package/docs/enterprise-postgres-state.md +178 -0
- package/docs/evaluations.md +14 -1
- package/docs/extensions.md +4 -1
- package/docs/forge-integration.md +113 -0
- package/docs/guardrails.md +16 -2
- package/docs/host-security.md +35 -4
- package/docs/index.md +69 -37
- package/docs/input-and-prompt-assembly.md +8 -7
- package/docs/language-intelligence.md +162 -0
- package/docs/mcp-tools.md +62 -5
- package/docs/middleware-hooks.md +2 -2
- package/docs/migration.md +423 -2
- package/docs/model-routing.md +111 -0
- package/docs/multimodal-content.md +8 -5
- package/docs/node-jsonl-session-store.md +1 -1
- package/docs/observability.md +2 -0
- package/docs/openapi-tools.md +56 -0
- package/docs/performance.md +282 -0
- package/docs/policy-and-audit.md +171 -0
- package/docs/ponytail.md +127 -0
- package/docs/postgres-persistence.md +8 -4
- package/docs/process-sessions.md +147 -0
- package/docs/provider-caching.md +13 -1
- package/docs/provider-conformance.md +29 -5
- package/docs/provider-packages.md +43 -2
- package/docs/provider-request-policies.md +2 -0
- package/docs/providers/ai-sdk.md +24 -7
- package/docs/providers/alibaba.md +179 -0
- package/docs/providers/anthropic.md +93 -0
- package/docs/providers/azure.md +74 -0
- package/docs/providers/bedrock.md +72 -0
- package/docs/providers/google.md +89 -0
- package/docs/providers/ollama.md +166 -0
- package/docs/providers/openai-compatible.md +31 -2
- package/docs/providers/openai.md +24 -5
- package/docs/providers/openrouter.md +2 -0
- package/docs/providers/vertex.md +71 -0
- package/docs/public-contracts.md +61 -4
- package/docs/rag.md +41 -12
- package/docs/release-and-install.md +323 -206
- package/docs/resource-loading.md +3 -0
- package/docs/runs-and-usage.md +3 -0
- package/docs/server.md +44 -6
- package/docs/session-store-conformance.md +2 -0
- package/docs/session-stores.md +41 -2
- package/docs/sqlite-persistence.md +11 -3
- package/docs/structured-output.md +7 -1
- package/docs/supervisors.md +8 -0
- package/docs/tool-effects.md +95 -0
- package/docs/tools.md +5 -0
- package/docs/work-artifacts-and-review.md +102 -0
- package/docs/work-connectors.md +32 -0
- package/docs/work-tools.md +137 -0
- package/docs/workflows.md +6 -0
- package/docs/working-and-semantic-memory.md +40 -7
- package/package.json +30 -8
- package/templates/init/providers.json +22 -0
- package/docs/review-coverage-2026-07-14.md +0 -260
- package/docs/review-coverage-2026-07-15.md +0 -193
- package/docs/review-coverage-2026-07-17-provider-validation.md +0 -192
- package/docs/review-coverage-2026-07-19-phase-3.md +0 -174
- package/docs/review-coverage-2026-07-20-phase-4.md +0 -175
|
@@ -106,6 +106,9 @@ await browser.close();
|
|
|
106
106
|
- Observation (`snapshot`, `wait`, open-without-url, `close`) vs mutation/high-impact (`navigate`, click/form, dialog accept, upload, download release, popup select) is classified for `ExecutionPolicy` / `beforeSideEffect`.
|
|
107
107
|
- `createSharedSandboxBrowserOptions()` aligns browser uploads/downloads with Task 1 sandbox `/workspace` and `/downloads`. `assertBrowserSandboxNetwork()` in `@arnilo/prism-coding-security` fails closed for custom Docker networks without browser egress attestation.
|
|
108
108
|
- Raw CSS is absent from production defaults. Ref resolution uses Playwright’s built-in `aria-ref=` selector with a package-owned snapshot ref table for staleness checks.
|
|
109
|
+
- Verified-state checkpoints (0.0.14): `createBrowserCheckpointLedger()` records navigation state — URL, a domain-state hash, and host-owned data refs — never serialized browser internals (cookies/storage/contexts), which are fragile and secret-bearing. Frozen caps: URL 8 KiB/16 KiB, domain-state hash 256 B/1 KiB, host-data ref 2 KiB/8 KiB (refs only, never bodies), 16/64 checkpoints per run (oldest evicted). After any resume/interruption `markResumed(runId)` marks state stale; `assertVerifiedBeforeSideEffect(runId)` fails closed until the host reloads + `verify()`s, so side effects never replay on stale state. Checkpoints are run-scoped: a conversation thread composes through the run it owns, reusing the manager's sandbox/egress/approval/limit policy above.
|
|
110
|
+
|
|
111
|
+
Observation tools declare `kind: none`; mutations are `external_mutation`/`unsupported` and fail closed on stale checkpoint state. See [tool effects](tool-effects.md).
|
|
109
112
|
|
|
110
113
|
## Security and performance notes
|
|
111
114
|
|
|
@@ -121,4 +124,6 @@ Default tests use fake Playwright APIs only. Protected live gate: `PRISM_LIVE_PL
|
|
|
121
124
|
- [Host security](host-security.md): browser endpoint, approval, egress proxy, and artifact trust boundaries.
|
|
122
125
|
- [Performance and resource limits](performance.md): browser ceilings and charging points.
|
|
123
126
|
- [Coding execution approval and sandboxing](coding-security.md): optional shared disposable sandbox for coding+browser.
|
|
127
|
+
- [Conversations](conversations.md): durable threads that own the runs browser checkpoints scope to.
|
|
128
|
+
- [Device adapters](device-adapters.md): deny-by-default voice/desktop-control contracts (no vendor package in 0.0.14).
|
|
124
129
|
- [Migration](migration.md): additive optional package activation.
|
package/docs/caveman.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Caveman behavior integration
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`@arnilo/prism-caveman` is an optional package that wires [juliusbrussee/caveman](https://github.com/juliusbrussee/caveman) into Prism contribution contracts.
|
|
6
|
+
|
|
7
|
+
It registers upstream skills and commands, injects active level prompt slices via `InstructionInjector`, and persists level as session custom `caveman-level` entries. Import and extension `setup` without a resolvable upstream path fail closed with a bounded redacted error and register zero contributions.
|
|
8
|
+
|
|
9
|
+
Upstream prompt fragments, skill bodies, and rules load from the host-supplied upstream checkout — Prism does not reimplement or vendor Caveman content.
|
|
10
|
+
|
|
11
|
+
## When to use it
|
|
12
|
+
|
|
13
|
+
Use it when a host wants terse token-efficient communication modes (`lite`, `full`, `ultra`, wenyan variants, `micro`) with upstream Caveman skills (`caveman-commit`, `caveman-review`, `caveman-stats`, `caveman-compress`, `caveman-help`, `cavecrew`) in a Prism extension kernel.
|
|
14
|
+
|
|
15
|
+
Skip it when you do not have a local Caveman checkout (Caveman is not published on npm) or when you only need progressive skill catalog without mode injection.
|
|
16
|
+
|
|
17
|
+
Pair with Phase 3 progressive disclosure: register `createLoadSkillTool` and keep `skillsDisclosure: "progressive"` so full `SKILL.md` bodies stay catalog-only; mode slices come from the `caveman-mode` injector, not eager skill bodies.
|
|
18
|
+
|
|
19
|
+
## Inputs / request
|
|
20
|
+
|
|
21
|
+
`createCavemanExtension(options)`:
|
|
22
|
+
|
|
23
|
+
| Field | Type | Required | Purpose |
|
|
24
|
+
| --- | --- | --- | --- |
|
|
25
|
+
| `upstreamPath` | `string` | yes | Absolute path to a Caveman checkout containing `skills/`. |
|
|
26
|
+
| `defaultLevel` | `CavemanLevel` | no | Initial level when no session entry exists (default upstream: `full`). |
|
|
27
|
+
| `showStatus` | `boolean` | no | Emit `caveman:status` extension events on level changes. |
|
|
28
|
+
| `appendEntry` | `(entry, opts?) => Promise<void>` | yes | Host session append (OM `attach` pattern). |
|
|
29
|
+
| `getEntries` | `() => readonly SessionEntry[] \| Promise<...>` | yes | Current branch entries for level restore. |
|
|
30
|
+
| `configPath` | `string` | no | Bounded local config file for `defaultLevel` / `showStatus`. |
|
|
31
|
+
|
|
32
|
+
`CavemanLevel`: `off` \| `lite` \| `full` \| `ultra` \| `wenyan-lite` \| `wenyan` \| `wenyan-ultra` \| `micro`.
|
|
33
|
+
|
|
34
|
+
Session custom entry shape:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{ "kind": "custom", "data": { "type": "caveman-level", "level": "full" } }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Registered skills: `caveman`, `caveman-commit`, `caveman-review`, `caveman-stats`, `caveman-compress`, `caveman-help`, `cavecrew`.
|
|
41
|
+
|
|
42
|
+
Registered commands: `caveman`, `caveman-init`, `caveman-commit`, `caveman-review`, `caveman-stats`, `caveman-compress`.
|
|
43
|
+
|
|
44
|
+
## Outputs / response / events
|
|
45
|
+
|
|
46
|
+
| Export | Purpose |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `createCavemanExtension(options)` | Returns an inert `Extension` until `kernel.load([...])`. |
|
|
49
|
+
| `caveman-mode` injector | `InstructionInjector` — upstream filtered `skills/caveman/SKILL.md` slice when level ≠ `off`. |
|
|
50
|
+
| `caveman` command | Set level (`/caveman lite\|full\|ultra\|wenyan\|micro\|off`) or toggle `off`↔`full`. |
|
|
51
|
+
| Alias commands | Dispatch `{ skill, dispatch: "load_skill" }` metadata for companion skills. |
|
|
52
|
+
| `caveman:status` event | Optional metadata when `showStatus: true`. |
|
|
53
|
+
|
|
54
|
+
Deactivation phrases `stop caveman` and `normal mode` clear active injection without erasing session history.
|
|
55
|
+
|
|
56
|
+
## Request/response example
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{ "command": "caveman", "args": { "level": "ultra" }, "sessionId": "s1" }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{ "kind": "custom", "data": { "type": "caveman-level", "level": "ultra" } }
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Implementation example
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createCavemanExtension } from "@arnilo/prism-caveman";
|
|
70
|
+
import {
|
|
71
|
+
createExtensionKernel,
|
|
72
|
+
createLoadSkillTool,
|
|
73
|
+
createLoadedSkillSet,
|
|
74
|
+
createMemorySessionStore,
|
|
75
|
+
createSkillRegistry,
|
|
76
|
+
createSessionEntry,
|
|
77
|
+
} from "@arnilo/prism";
|
|
78
|
+
|
|
79
|
+
const store = createMemorySessionStore();
|
|
80
|
+
const callbacks = {
|
|
81
|
+
appendEntry: async (entry, options) => store.append(entry, options),
|
|
82
|
+
getEntries: async () => store.list("s1"),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const kernel = createExtensionKernel({ errorPolicy: "throw" });
|
|
86
|
+
await kernel.load([
|
|
87
|
+
createCavemanExtension({
|
|
88
|
+
upstreamPath: "/path/to/juliusbrussee-caveman",
|
|
89
|
+
defaultLevel: "full",
|
|
90
|
+
...callbacks,
|
|
91
|
+
}),
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
const registry = createSkillRegistry(kernel.registries.skills.list());
|
|
95
|
+
const loaded = createLoadedSkillSet();
|
|
96
|
+
const loadSkill = createLoadSkillTool({ registry, loaded });
|
|
97
|
+
|
|
98
|
+
await kernel.registries.commands.get("caveman")!.execute({ level: "lite" }, { sessionId: "s1" });
|
|
99
|
+
// Select instructionInjectors: ["caveman-mode"] on runs that should receive level slices.
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
See `examples/caveman-ponytail.ts` for progressive catalog + `load_skill` wiring with fixture upstream trees (network-free).
|
|
103
|
+
|
|
104
|
+
## Extension and configuration notes
|
|
105
|
+
|
|
106
|
+
- Import alone registers nothing and starts no timers, watchers, or network I/O (`sideEffects: false`).
|
|
107
|
+
- `kernel.load` calls `setup`, which resolves upstream first; failure throws before any `register*`.
|
|
108
|
+
- Level restore scans `getEntries()` for the latest `data.type === "caveman-level"` — same OM attach pattern; core does not auto-emit `session_start`.
|
|
109
|
+
- Host must register `createLoadSkillTool` and pass `skillsDisclosure: "progressive"` for catalog-only skill bodies.
|
|
110
|
+
- `caveman-stats` dispatches skill metadata only; full stats need host session-log integration.
|
|
111
|
+
- `caveman-init` returns upstream guidance text; it does not write files in the host repo.
|
|
112
|
+
- No TUI status bar; optional `caveman:status` events for host UI.
|
|
113
|
+
|
|
114
|
+
## Security and performance notes
|
|
115
|
+
|
|
116
|
+
- Upstream `SKILL.md` and injected text are untrusted host-supplied content; reads are size-bounded (`MAX_SKILL_FILE_BYTES` 256 KiB, `MAX_INJECTED_INSTRUCTION_BYTES` 32 KiB).
|
|
117
|
+
- Config read/write is bounded (`MAX_CONFIG_FILE_BYTES` 16 KiB) at host-owned `configPath` only.
|
|
118
|
+
- Errors redact home directories and absolute paths.
|
|
119
|
+
- Setup is O(skills) directory scan; mode read/write is O(1) per change; injection is O(1) upstream lookup per turn.
|
|
120
|
+
- Session custom entries respect host session ownership and redaction policies.
|
|
121
|
+
|
|
122
|
+
## Related APIs
|
|
123
|
+
|
|
124
|
+
- [Ponytail behavior integration](ponytail.md): complementary lazy-minimalism mode package.
|
|
125
|
+
- [Extension kernel and event bus](extensions.md): `kernel.load` and contribution registration.
|
|
126
|
+
- [Context and skills](context-and-skills.md): progressive disclosure + `createLoadSkillTool`.
|
|
127
|
+
- [Instruction injection](instruction-injection.md): `caveman-mode` injector selection.
|
|
128
|
+
- [Observational memory compaction package](compaction-observational-memory.md): `appendEntry` / `getEntries` attach precedent.
|
|
129
|
+
- [Migration guide](migration.md): `0.0.21 → 0.0.22` install and opt-in notes.
|
package/docs/cli-rpc.md
CHANGED
|
@@ -45,10 +45,6 @@ Default generation installs only `@arnilo/prism` (mock provider). Selecting a re
|
|
|
45
45
|
| `--provider <name>` | Explicit provider id. The built-in `mock` id is only a smoke-test provider. |
|
|
46
46
|
| `--model <name>` | Explicit model name. |
|
|
47
47
|
| `--session <id>` | Session id. |
|
|
48
|
-
| `--config <path>` | Explicit config path recorded by the adapter; not auto-loaded. |
|
|
49
|
-
| `--resource <uri>` | Explicit resource URI recorded by the adapter; not auto-loaded. |
|
|
50
|
-
| `--extension <name>` | Explicit extension name recorded by the adapter; not auto-loaded/imported. |
|
|
51
|
-
| `--tool <name>` | Explicit tool name recorded by the adapter; not auto-enabled. |
|
|
52
48
|
| `--system <text>` | System instructions. |
|
|
53
49
|
| `--context <text>` | Context text reserved for host adapters. |
|
|
54
50
|
| `--compact <entries>` | Auto-compaction threshold for the run. |
|
|
@@ -106,7 +102,7 @@ Branch-aware session commands return live handle details:
|
|
|
106
102
|
|
|
107
103
|
`sessionId` identifies the durable session. `leafId` is the selected branch tip. `handleId` is the RPC map key used by `switchSession`; forks that share the same `sessionId` get stable ids like `session-1#2` so the parent handle is not overwritten.
|
|
108
104
|
|
|
109
|
-
Invalid CLI flags return exit code `2`. Invalid JSON, missing ids, unknown RPC commands,
|
|
105
|
+
Invalid CLI flags return exit code `2`. Invalid JSON, missing ids, unknown RPC commands, unknown command contributions, and runtime failures return `ok: false` response envelopes without executing unknown tools or commands. `steer` with no active run (or overflow) returns `ok: false`.
|
|
110
106
|
|
|
111
107
|
## Request/response example
|
|
112
108
|
|
|
@@ -128,6 +124,7 @@ Invalid CLI flags return exit code `2`. Invalid JSON, missing ids, unknown RPC c
|
|
|
128
124
|
- `state`, `messages`, `setModel`, `switchSession`, `forkSession`, `cloneSession`, `checkout`, and registered `command` requests are processed immediately.
|
|
129
125
|
- `compact` is fail-closed: if the current session has an active run, it returns `ok: false` because the session rejects compaction during a run.
|
|
130
126
|
- A second `prompt` or `followUp` for the same session while it already has an active run returns `ok: false` immediately instead of blocking the input loop.
|
|
127
|
+
- `steer` enqueues mid-run user text for the active session (`params.input`, optional `params.softInterrupt`). Fails closed when no active run or when the pending steer queue overflows (8 messages / 64 KiB). Soft interrupt aborts the current provider stream only; the run continues.
|
|
131
128
|
|
|
132
129
|
Events streamed during a run keep the original prompt request id, even when an `abort` with a different request id cancels the run. The completion or error response for the prompt also uses the original prompt request id.
|
|
133
130
|
|
|
@@ -201,6 +198,6 @@ Suspended workflow resume parameters are `{ workflowId, runId, decision: "approv
|
|
|
201
198
|
- [Observational memory compaction package](compaction-observational-memory.md): optional `om:status` and `om:view` command factories for explicitly wired hosts.
|
|
202
199
|
- [Workflows](workflows.md): optional `createWorkflowCommands()` for direct/background/replay/status/cancel/resume and selected schedule control over the same RPC `command` seam.
|
|
203
200
|
|
|
204
|
-
The CLI records flags but does not auto-load project-local resources, extensions, tools, or config. The two system/project prompt files are the exception: in print/json modes the CLI auto-loads `<workspaceRoot>/AGENTS.md` (trust-gated) and an app-supplied `SYSTEM.md` layer as `AgentConfig.systemPrompt` layers composed with `--system` (base); `--no-agents-md` / `--no-system-md` skip them and `--agents-md-file` / `--system-md-file` override the paths. The CLI does not default `globalRoot` to the user's home directory — pass it from a host adapter or use `--agents-config <path>` for the app-config bundle layout. RPC mode does not auto-read these files (the host owns the session factory). Hosts must make explicit trust and permission decisions before wiring any other local loading.
|
|
201
|
+
The CLI records flags but does not auto-load project-local resources, extensions, tools, or config. `--config`, `--resource`, `--extension`, and `--tool` were parsed-and-recorded in earlier builds without any effect; they are now rejected loudly (`<flag> is not supported in this build`) until a CLI-harness plan wires them. The two system/project prompt files are the exception: in print/json modes the CLI auto-loads `<workspaceRoot>/AGENTS.md` (trust-gated) and an app-supplied `SYSTEM.md` layer as `AgentConfig.systemPrompt` layers composed with `--system` (base); `--no-agents-md` / `--no-system-md` skip them and `--agents-md-file` / `--system-md-file` override the paths. The CLI does not default `globalRoot` to the user's home directory — pass it from a host adapter or use `--agents-config <path>` for the app-config bundle layout. RPC mode does not auto-read these files (the host owns the session factory). Hosts must make explicit trust and permission decisions before wiring any other local loading.
|
|
205
202
|
|
|
206
203
|
For app-controlled agent bundles under `<configRoot>/agents/<name>/AGENT.md` (including the three-layer `SYSTEM.md` → `AGENT.md` body → repo `AGENTS.md` prompt append and the union skill/tool scopes), see [Agent definitions](agent-definitions.md).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## What it does
|
|
4
4
|
|
|
5
|
-
`@arnilo/prism-coding-agent` is an optional first-party package that provides host shell/filesystem/repository tools as Prism `ToolDefinition` objects. It ships
|
|
5
|
+
`@arnilo/prism-coding-agent` is an optional first-party package that provides host shell/filesystem/repository tools as Prism `ToolDefinition` objects. It ships nine default coding tools — `shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, `move` — plus opt-in structured Git/check set (`createGitTools`), opt-in `createAskUserDecisionTool({ ask })`, and bounded coding-plan/checkpoint helpers. The tools are **inert** until a host imports them and registers them into a `ToolRegistry`. Hosts may register any subset, omit aggregators entirely, or mix first-party tools with host-owned `ToolDefinition`s. Behavior for shell/read/write/edit is a behavioral port of the pi coding agent's tools, adapted to Prism's `ToolDefinition` / `ToolResult` contracts (no `@earendil-works/*` or `typebox` dependencies; only `diff` plus the Node standard library). List/search/glob/Git are native Prism tools with no picomatch/ripgrep/Git-library dependency (hand-rolled `*`/`?`/`**` glob matcher).
|
|
6
6
|
|
|
7
7
|
| Export | Purpose |
|
|
8
8
|
| --- | --- |
|
|
@@ -11,13 +11,22 @@
|
|
|
11
11
|
| `createWriteTool(cwd, options?)` | `write` tool: create or overwrite a file, creating parent directories. |
|
|
12
12
|
| `createEditTool(cwd, options?)` | `edit` tool: precise exact-then-fuzzy text replacement in an existing file. |
|
|
13
13
|
| `createRepoListTool(cwd, options?)` | `repo_list` tool: bounded deterministic repository listing. |
|
|
14
|
-
| `createRepoSearchTool(cwd, options?)` | `repo_search` tool: bounded literal
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
14
|
+
| `createRepoSearchTool(cwd, options?)` | `repo_search` tool: bounded literal text search (`outputMode`: content / files_with_matches / count). |
|
|
15
|
+
| `createGlobTool(cwd, options?)` | `glob` tool: bounded filename-pattern match (`*` / `?` / `**`; no brace expansion). |
|
|
16
|
+
| `createDeleteTool(cwd, options?)` | `delete` tool: high-risk delete of a file or empty directory (no recursive delete, no trash). |
|
|
17
|
+
| `createMoveTool(cwd, options?)` | `move` tool: high-risk rename/move within the workspace (`overwrite` default false). |
|
|
18
|
+
| `createReadPathSet()` | Session-scoped path set for optional `requireReadBeforeWrite` soft guard. |
|
|
19
|
+
| `createCodingTools(cwd, options?)` | Default nine tools (`shell`, `read`, `write`, `edit`, `repo_list`, `repo_search`, `glob`, `delete`, `move`). |
|
|
20
|
+
| `createReadOnlyTools(cwd, options?)` | Read-only subset: `read`, `repo_list`, `repo_search`, `glob`. |
|
|
17
21
|
| `createAllTools(cwd, options?)` | Identical to `createCodingTools` (Git tools remain opt-in via `createGitTools`). |
|
|
18
22
|
| `createGitTools(cwd, options?)` | Opt-in Git tools (`git_status`/`git_diff`/`git_branch`/`git_worktree`/`git_apply`/`git_commit`/`git_pr_handoff`) plus optional `coding_check`. |
|
|
19
23
|
| `createCodingCheckTool(cwd, options)` | Named host-declared checks; model selects only a name. |
|
|
20
|
-
| `
|
|
24
|
+
| `createAskUserDecisionTool(options)` | Opt-in user decision tool (`ask_user_decision`); host supplies `ask` callback. Not in default aggregators. |
|
|
25
|
+
| `createLocalRepositoryOperations(limits?)` | Default streaming Node filesystem backend for list/search/glob. |
|
|
26
|
+
| `createGitAwareRepositoryOperations(cwd, options?)` | Optional Git `ls-files` ignore-aware enumeration with native fallback; host-only `includeIgnored`. |
|
|
27
|
+
| `createLanguageIntelligence(options)` | Optional host-activated LSP language intelligence (symbols/definitions/references/diagnostics/hover/rename); see [Language intelligence](language-intelligence.md). |
|
|
28
|
+
| `createProcessSessions(options)` | Optional managed long-running process sessions (start/output/input/wait/signal/kill/release); see [Process sessions](process-sessions.md). |
|
|
29
|
+
| `createGitHubForge(options)` | Optional reference GitHub forge adapter (issue context, push, PR create/update, review comments, checks, handoff reconcile) with `ToolEffectStore` idempotency; see [Forge integration](forge-integration.md). |
|
|
21
30
|
| `createGitOperations(options)` | Typed Git operations backend (argument arrays, safe config, finite output). |
|
|
22
31
|
| `buildCodingCheckpointMetadata` / `validateCodingCheckpointMetadata` / `assertCodingResumeAllowed` | Bounded durable coding-task metadata for workflow `state.coding` (no second runtime). |
|
|
23
32
|
| `writeCodingPlanFile` / `readCodingPlanFile` / `createCodingPlanMarkdown` / `parseCodingPlanTodos` | Workspace plan/todo Markdown helpers with finite byte/todo caps and hash verification. |
|
|
@@ -65,13 +74,41 @@ const tools = createCodingTools(workspaceRoot, {
|
|
|
65
74
|
| `read` | `read` |
|
|
66
75
|
| `write` | `write` |
|
|
67
76
|
| `edit` | `edit` |
|
|
68
|
-
| `repo_list` / `repo_search` | _(native; no pi equivalent)_ |
|
|
77
|
+
| `repo_list` / `repo_search` / `glob` | _(native; no pi equivalent)_ |
|
|
78
|
+
| `delete` / `move` | _(native; no pi equivalent)_ |
|
|
79
|
+
|
|
80
|
+
### Tool selection guide
|
|
81
|
+
|
|
82
|
+
| Need | Prefer | Avoid |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| Enumerate directories | `repo_list` | `shell` `find`/`ls` |
|
|
85
|
+
| Match filename patterns | `glob` | `shell` `find` |
|
|
86
|
+
| Find text in files | `repo_search` | `shell` `grep`/`rg` |
|
|
87
|
+
| Read one file (paged) | `read` | `shell` `cat` |
|
|
88
|
+
| Create / full overwrite | `write` | — |
|
|
89
|
+
| Targeted replace | `edit` | full `write` rewrite when a small edit works |
|
|
90
|
+
| Remove file / empty dir | `delete` | `shell` `rm` |
|
|
91
|
+
| Rename / relocate | `move` | `shell` `mv` |
|
|
92
|
+
| Arbitrary process | `shell` | dedicated tools above |
|
|
93
|
+
|
|
94
|
+
### Phase 4 non-goals (0.0.21)
|
|
95
|
+
|
|
96
|
+
These are **out of scope** for the 0.0.21 package baseline (see roadmap Phase 9 / later for LSP and process work):
|
|
97
|
+
|
|
98
|
+
- **No PDF / document reader** — text and supported images only via `read`.
|
|
99
|
+
- **No trash / recycle daemon** — `delete` / `move` are permanent; host undo is not automatic.
|
|
100
|
+
- **No PTY / interactive process control in `shell`** — `shell` stays one-shot; optional `createProcessSessions` covers long-running attach/input (PTY still unsupported — see [Process sessions](process-sessions.md)).
|
|
101
|
+
- **LSP language-server tools** — not in default aggregators; optional `createLanguageIntelligence` is Phase 9 (see [Language intelligence](language-intelligence.md)).
|
|
102
|
+
- **Managed process sessions** — not in default aggregators; optional `createProcessSessions` is Phase 9 (see [Process sessions](process-sessions.md)).
|
|
103
|
+
- **GitHub forge adapter** — not in default aggregators; optional `createGitHubForge` is Phase 9 (see [Forge integration](forge-integration.md)); no octokit dependency, no multi-forge abstraction.
|
|
104
|
+
- **No recursive directory delete** — `delete` refuses non-empty directories.
|
|
105
|
+
- **No brace-expansion globs** — `glob` supports only `*`, `?`, and `**`.
|
|
69
106
|
|
|
70
107
|
## Inputs / request
|
|
71
108
|
|
|
72
109
|
### `shell`
|
|
73
110
|
|
|
74
|
-
Run a shell command and return combined stdout+stderr.
|
|
111
|
+
Run a shell command and return combined stdout+stderr. Prefer dedicated coding tools (table above) when they fit.
|
|
75
112
|
|
|
76
113
|
**Inputs:**
|
|
77
114
|
|
|
@@ -140,7 +177,7 @@ const read = createReadTool(cwd, {
|
|
|
140
177
|
|
|
141
178
|
### `write`
|
|
142
179
|
|
|
143
|
-
Create or overwrite a file, creating parent directories as needed.
|
|
180
|
+
Create or **overwrite** a file (full replace), creating parent directories as needed. Prefer `edit` for targeted changes.
|
|
144
181
|
|
|
145
182
|
**Inputs:**
|
|
146
183
|
|
|
@@ -148,11 +185,27 @@ Create or overwrite a file, creating parent directories as needed.
|
|
|
148
185
|
| --- | --- | --- |
|
|
149
186
|
| `path` | `string` | Path to the file to write (relative or absolute). Required. |
|
|
150
187
|
| `content` | `string` | Content to write (empty string creates an empty file). Required. |
|
|
188
|
+
| `force` | `boolean` | Bypass optional read-before-write guard when the host enabled `requireReadBeforeWrite`. |
|
|
151
189
|
|
|
152
190
|
**Outputs:** a `TextContent` confirmation naming the **absolute path** with UTF-8 byte and line counts (e.g. `Successfully wrote 42 bytes (3 lines) to /abs/path.txt`). `maxInputBytes` defaults to 8 MiB (64 MiB hard cap); oversized UTF-8 input fails before policy evaluation, directory creation, or write. Write failures and abort are error results. Empty `content` is valid.
|
|
153
191
|
|
|
192
|
+
Default local `writeFile` uses same-directory temp + `rename` so a crash mid-write cannot truncate the target; custom `WriteOperations` should provide equivalent durability.
|
|
193
|
+
|
|
154
194
|
`write` result `metadata`: `{ bytes, lines, path }` (absolute path). Concurrent writes to the same path serialize through `withFileMutationQueue`; writes to different paths run in parallel.
|
|
155
195
|
|
|
196
|
+
### Optional read-before-write guard
|
|
197
|
+
|
|
198
|
+
Hosts may opt in to a session-scoped soft guard: share one `createReadPathSet()` across `read` / `write` / `edit` and set `requireReadBeforeWrite: true` on write/edit options. Successful `read` marks the path; unread existing-file writes/edits fail with a clear error unless `force: true`. Default is **off** (no behavior change for hosts that ignore it).
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { createReadPathSet, createReadTool, createWriteTool, createEditTool } from "@arnilo/prism-coding-agent";
|
|
202
|
+
|
|
203
|
+
const readPaths = createReadPathSet();
|
|
204
|
+
const read = createReadTool(cwd, { readPathSet: readPaths });
|
|
205
|
+
const write = createWriteTool(cwd, { requireReadBeforeWrite: true, readPathSet: readPaths });
|
|
206
|
+
const edit = createEditTool(cwd, { requireReadBeforeWrite: true, readPathSet: readPaths });
|
|
207
|
+
```
|
|
208
|
+
|
|
156
209
|
### `edit`
|
|
157
210
|
|
|
158
211
|
Precise text replacement in an existing file via exact-then-fuzzy matching.
|
|
@@ -163,8 +216,13 @@ Precise text replacement in an existing file via exact-then-fuzzy matching.
|
|
|
163
216
|
| --- | --- | --- |
|
|
164
217
|
| `path` | `string` | Path to the file to edit. Required. |
|
|
165
218
|
| `edits` | `Array<{ oldText: string, newText: string }>` | Targeted replacements, each matched against the **original** file (not incrementally). No overlapping/nested edits. Required, non-empty. |
|
|
219
|
+
| `force` | `boolean` | Bypass optional read-before-write guard when enabled. |
|
|
220
|
+
|
|
221
|
+
Each `edits[].oldText` must match a unique, non-overlapping region of the original file. Matching is exact first, then fuzzy (unicode normalization / whitespace collapse).
|
|
166
222
|
|
|
167
|
-
|
|
223
|
+
**Fuzzy silent-success tradeoff (loud):** when exact match fails, fuzzy may still apply a replacement **without warning the model**. That can edit the wrong region if `oldText` is slightly off (extra/missing whitespace, unicode lookalikes). Prefer exact `oldText` copied from a fresh `read`. Duplicate / non-unique matches already **fail closed** and leave the file unchanged — ambiguity is not silently resolved by picking the first hit.
|
|
224
|
+
|
|
225
|
+
A BOM is stripped before matching and re-prepended on write; original line endings are restored. Defaults reject targets over 8 MiB, aggregate old/new UTF-8 input over 2 MiB, or more than 100 edits (hard caps: 64 MiB, 16 MiB, and 1,000). Stat and bounded read checks run before matching or mutation. Default local `writeFile` uses same-directory temp + `rename` (crash-safe replace).
|
|
168
226
|
|
|
169
227
|
**Outputs:** a `TextContent` confirmation (`Successfully replaced N block(s) in {path}.`) plus `metadata`. Any failure — missing/unreadable file, no match, duplicate (non-unique) match, overlap, empty `oldText`, no-op edit, or abort — is an error result, and the file is left **unchanged** (the match runs before the write).
|
|
170
228
|
|
|
@@ -172,7 +230,24 @@ Each `edits[].oldText` must match a unique, non-overlapping region of the origin
|
|
|
172
230
|
|
|
173
231
|
### `repo_list`
|
|
174
232
|
|
|
175
|
-
List repository entries with deterministic relative paths. Uses Node `opendir`/`lstat` only — no glob dependency. Does not follow symlinks; rejects path escapes outside the workspace root. Hidden names and excluded basenames (default `.git`, `node_modules`, `dist`) are skipped unless `includeHidden` is set / host `exclude` is overridden.
|
|
233
|
+
List repository entries with deterministic relative paths. Uses Node `opendir`/`lstat` only — no glob dependency. Prefer `glob` when you already know a filename pattern. Prefer `repo_search` to find text inside files. Does not follow symlinks; rejects path escapes outside the workspace root. Hidden names and excluded basenames (default `.git`, `node_modules`, `dist`) are skipped unless `includeHidden` is set / host `exclude` is overridden.
|
|
234
|
+
|
|
235
|
+
#### Git-aware enumeration
|
|
236
|
+
|
|
237
|
+
`createGitAwareRepositoryOperations(cwd, options?)` is an optional `RepositoryOperations` backend that enumerates via fixed `git ls-files --cached --others --exclude-standard -z` (honors nested `.gitignore`, `$GIT_DIR/info/exclude`, and exclude-standard rules). Inject it through `ToolsOptions.repository.operations` (or per-tool `repository.operations`).
|
|
238
|
+
|
|
239
|
+
- **Detection:** cached `git rev-parse --is-inside-work-tree`. Outside a Git work tree, or when detection fails, delegates to `options.fallback` (default: `createLocalRepositoryOperations`).
|
|
240
|
+
- **Fail closed:** after successful detection, `ls-files` errors throw `RepositoryError` — no silent mid-session fallback.
|
|
241
|
+
- **Ignored paths:** stay excluded unless the host sets `includeIgnored: true` (factory option only; never a model-facing tool argument). Tracked-but-ignored files remain visible via `--cached` (Git semantics).
|
|
242
|
+
- **Bounds:** at most two Git invocations per operation; stdout capped by `DEFAULT_MAX_LS_FILES_OUTPUT_BYTES` (8 MiB, hard 64 MiB). Existing repo depth/entry/file/result/time caps still apply. No per-file Git spawn; no hand-rolled ignore parser; argv is never model-supplied.
|
|
243
|
+
- **Security:** `.git` internals never listed; paths re-checked against the workspace root; symlink escapes match native fail-closed behavior.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import { createCodingTools, createGitAwareRepositoryOperations } from "@arnilo/prism-coding-agent";
|
|
247
|
+
|
|
248
|
+
const operations = createGitAwareRepositoryOperations(cwd); // native fallback outside Git
|
|
249
|
+
const tools = createCodingTools(cwd, { repository: { operations } });
|
|
250
|
+
```
|
|
176
251
|
|
|
177
252
|
**Inputs:**
|
|
178
253
|
|
|
@@ -188,21 +263,70 @@ List repository entries with deterministic relative paths. Uses Node `opendir`/`
|
|
|
188
263
|
|
|
189
264
|
### `repo_search`
|
|
190
265
|
|
|
191
|
-
Search text files under the workspace
|
|
266
|
+
Search text files under the workspace using literal substring match. Binary files (NUL in a bounded prefix) and oversize files are skipped. Aggregate scanned bytes, matches, line bytes, pattern bytes, and wall time are finite.
|
|
192
267
|
|
|
193
268
|
**Inputs:**
|
|
194
269
|
|
|
195
270
|
| Field | Type | Purpose |
|
|
196
271
|
| --- | --- | --- |
|
|
197
|
-
| `query` | `string` | Literal
|
|
272
|
+
| `query` | `string` | Literal substring (required). |
|
|
198
273
|
| `path` | `string` | Workspace-relative start path. |
|
|
199
|
-
| `mode` | `"literal"
|
|
274
|
+
| `mode` | `"literal"` | Literal only (default). `regex` removed in 0.0.18. |
|
|
200
275
|
| `caseSensitive` | `boolean` | Default false. |
|
|
201
276
|
| `includeHidden` | `boolean` | Default false. |
|
|
202
|
-
| `context` | `number` | Context lines before/after each match (default 5, hard 20). |
|
|
277
|
+
| `context` | `number` | Context lines before/after each match (default 5, hard 20). Ignored for non-content `outputMode`. |
|
|
203
278
|
| `maxMatches` | `number` | Match cap (default 1,000, hard 10,000). |
|
|
279
|
+
| `outputMode` | `"content"` \| `"files_with_matches"` \| `"count"` | Result shape (default `content`). |
|
|
280
|
+
|
|
281
|
+
**Outputs:**
|
|
282
|
+
- `content` (default): ripgrep-like lines `path:line:column:text` with optional `path-` / `path+` context.
|
|
283
|
+
- `files_with_matches`: unique matching paths only.
|
|
284
|
+
- `count`: totals (`N matches in M files`) without line bodies.
|
|
285
|
+
|
|
286
|
+
Metadata includes `matches`, `truncated`, scan/skip counts; non-content modes also expose `fileCount`.
|
|
287
|
+
|
|
288
|
+
### `glob`
|
|
289
|
+
|
|
290
|
+
Find workspace files by filename pattern without shell `find`. Hand-rolled matcher: `*` (one path segment), `?` (one char), `**` (directories). Brace expansion (`{a,b}`) is **rejected**. Patterns match workspace-relative full paths (e.g. `src/util/a.ts`). Returns **files only** (directories traversed but not listed). Same exclude/hidden/depth/page/time caps as `repo_list`.
|
|
291
|
+
|
|
292
|
+
**Inputs:**
|
|
204
293
|
|
|
205
|
-
|
|
294
|
+
| Field | Type | Purpose |
|
|
295
|
+
| --- | --- | --- |
|
|
296
|
+
| `pattern` | `string` | Glob pattern (required). |
|
|
297
|
+
| `path` | `string` | Workspace-relative start directory (default root). |
|
|
298
|
+
| `includeHidden` | `boolean` | Default false. |
|
|
299
|
+
| `maxDepth` | `number` | Depth cap (default 32, hard 128). |
|
|
300
|
+
| `maxResults` | `number` | Page size (default 1,000, hard 10,000). |
|
|
301
|
+
| `offset` | `number` | Matches to skip (default 0). |
|
|
302
|
+
|
|
303
|
+
**Outputs:** one relative path per line plus metadata (`truncated`, `truncatedBy`, `nextOffset`, scan counts). Continue with `offset=nextOffset` when truncated.
|
|
304
|
+
|
|
305
|
+
### `delete`
|
|
306
|
+
|
|
307
|
+
High-risk: permanently delete a **single file or empty directory**. Non-empty directories fail closed (no recursive delete). Symlinks are unlinked as links (targets not followed for containment). **No trash daemon** — host undo is not automatic; gate with approval policy.
|
|
308
|
+
|
|
309
|
+
**Inputs:**
|
|
310
|
+
|
|
311
|
+
| Field | Type | Purpose |
|
|
312
|
+
| --- | --- | --- |
|
|
313
|
+
| `path` | `string` | File or empty directory to delete. Required. |
|
|
314
|
+
|
|
315
|
+
**Outputs:** confirmation with absolute path, or error (missing, non-empty dir, escape, abort).
|
|
316
|
+
|
|
317
|
+
### `move`
|
|
318
|
+
|
|
319
|
+
High-risk: rename or move a file within the workspace. Dual-path mutation queue (lexicographic lock order). `overwrite` defaults **false**; when true, replaces an existing destination **file** only. Does not create parent directories. **No trash** — host undo is not automatic.
|
|
320
|
+
|
|
321
|
+
**Inputs:**
|
|
322
|
+
|
|
323
|
+
| Field | Type | Purpose |
|
|
324
|
+
| --- | --- | --- |
|
|
325
|
+
| `from` | `string` | Source path. Required. |
|
|
326
|
+
| `to` | `string` | Destination path. Required. |
|
|
327
|
+
| `overwrite` | `boolean` | Replace existing destination file (default false). |
|
|
328
|
+
|
|
329
|
+
**Outputs:** confirmation with absolute from/to, or error (missing source, dest exists without overwrite, escape, abort).
|
|
206
330
|
|
|
207
331
|
### Structured Git tools (`createGitTools`)
|
|
208
332
|
|
|
@@ -231,6 +355,72 @@ const gitTools = createGitTools(workspaceRoot, {
|
|
|
231
355
|
});
|
|
232
356
|
```
|
|
233
357
|
|
|
358
|
+
### Ask-user decision (`createAskUserDecisionTool`)
|
|
359
|
+
|
|
360
|
+
Opt-in `ask_user_decision` for ambiguous, high-impact direction choices. Model must pass a question plus 2+ options, each with **exactly 3 pros and 3 cons**. Host supplies `ask` (blocks until the user picks). Not in `createCodingTools` / `createAllTools` / `createReadOnlyTools`.
|
|
361
|
+
|
|
362
|
+
| Mode | How |
|
|
363
|
+
| --- | --- |
|
|
364
|
+
| Single (default) | `selectionMode: "single"` → host returns `{ selectedId }` (or length-1 `selectedIds`) |
|
|
365
|
+
| Multi | `selectionMode: "multiple"` → `{ selectedIds: [...] }` (non-empty, known ids) |
|
|
366
|
+
| Free-text | `allowCustom: true` → host may return `{ customText }` **XOR** selection (never both) |
|
|
367
|
+
| Blocking tool | `createAskUserDecisionTool({ ask })` — in-process UI callback |
|
|
368
|
+
| Durable workflow | `suspendAskUserDecision(request)` + `createAskUserDecisionResumeValidator()` / `validateAskUserDecisionResume` on `resumeWorkflow` |
|
|
369
|
+
| Agent durable adapter | `validateAskUserDecisionAgentResume({ request, answer })` — same validation; **no** new `AgentRunInterruption` kinds in 0.0.11 |
|
|
370
|
+
|
|
371
|
+
Custom-text caps match question defaults (2 KiB / hard 8 KiB). Options default max 6 (hard 16).
|
|
372
|
+
|
|
373
|
+
```ts
|
|
374
|
+
import { createToolRegistry } from "@arnilo/prism";
|
|
375
|
+
import {
|
|
376
|
+
createAskUserDecisionTool,
|
|
377
|
+
createCodingTools,
|
|
378
|
+
suspendAskUserDecision,
|
|
379
|
+
createAskUserDecisionResumeValidator,
|
|
380
|
+
} from "@arnilo/prism-coding-agent";
|
|
381
|
+
|
|
382
|
+
const tools = createToolRegistry([
|
|
383
|
+
...createCodingTools(workspaceRoot),
|
|
384
|
+
createAskUserDecisionTool({
|
|
385
|
+
ask: async ({ question, options, selectionMode, allowCustom }) =>
|
|
386
|
+
ui.ask({ question, options, selectionMode, allowCustom }),
|
|
387
|
+
}),
|
|
388
|
+
]);
|
|
389
|
+
|
|
390
|
+
// Workflow node:
|
|
391
|
+
return suspendAskUserDecision({
|
|
392
|
+
question: "Ship sqlite or postgres?",
|
|
393
|
+
options: [/* ≥2 with 3 pros + 3 cons each */],
|
|
394
|
+
selectionMode: "single",
|
|
395
|
+
allowCustom: false,
|
|
396
|
+
});
|
|
397
|
+
// resumeWorkflow(..., { validateResume: createAskUserDecisionResumeValidator() })
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Goal → verify helper (`runCodingGoalVerify`)
|
|
401
|
+
|
|
402
|
+
Thin composition over existing plan Markdown, named checks, workflow `suspend`/`resumeWorkflow`, and bounded PR handoff. **No Goal table / second runtime.** Peer `@arnilo/prism-workflows`. Example: `examples/coding-goal-verify.ts`.
|
|
403
|
+
|
|
404
|
+
```ts
|
|
405
|
+
import { runCodingGoalVerify } from "@arnilo/prism-coding-agent";
|
|
406
|
+
|
|
407
|
+
const result = await runCodingGoalVerify({
|
|
408
|
+
goal: "Fix the flake",
|
|
409
|
+
cwd: process.cwd(),
|
|
410
|
+
taskId: "flake-1",
|
|
411
|
+
baseBranch: "main",
|
|
412
|
+
branch: "fix/flake",
|
|
413
|
+
checkNames: ["test"],
|
|
414
|
+
checkDefinitions: { test: { file: "/usr/bin/npm", args: ["test"] } },
|
|
415
|
+
runCheck: hostRunCheck,
|
|
416
|
+
buildHandoff: hostBuildHandoff,
|
|
417
|
+
approval: { validateResume: hostValidate },
|
|
418
|
+
checkpoints,
|
|
419
|
+
ownership,
|
|
420
|
+
redactor,
|
|
421
|
+
});
|
|
422
|
+
```
|
|
423
|
+
|
|
234
424
|
### Durable coding plans and checkpoints
|
|
235
425
|
|
|
236
426
|
There is no `CodingRun`, todo database, or second approval engine. Persist executable plan/todos as ordinary workspace Markdown (for example `plans/<task>.md`) and store only bounded metadata under workflow `state.coding`:
|
|
@@ -282,10 +472,10 @@ Minimal drop-in for any Prism app:
|
|
|
282
472
|
import { createToolRegistry } from "@arnilo/prism";
|
|
283
473
|
import { createCodingTools, createReadOnlyTools } from "@arnilo/prism-coding-agent";
|
|
284
474
|
|
|
285
|
-
// Full coding set (shell + read + write + edit + repo_list + repo_search
|
|
475
|
+
// Full coding set (shell + read + write + edit + repo_list + repo_search + glob + delete + move):
|
|
286
476
|
const tools = createToolRegistry(createCodingTools(process.cwd()));
|
|
287
477
|
|
|
288
|
-
// Or a read-only set for inspection-only agents (read + repo_list + repo_search):
|
|
478
|
+
// Or a read-only set for inspection-only agents (read + repo_list + repo_search + glob):
|
|
289
479
|
const ro = createToolRegistry(createReadOnlyTools(process.cwd()));
|
|
290
480
|
```
|
|
291
481
|
|
|
@@ -300,6 +490,8 @@ const shell = createShellTool("/repo", {
|
|
|
300
490
|
maxLines: 500,
|
|
301
491
|
timeout: 600,
|
|
302
492
|
maxTotalOutputBytes: 64 * 1024 * 1024,
|
|
493
|
+
// Optional: scrub the environment the spawn hook and child process see (default: full process.env clone).
|
|
494
|
+
envAllowlist: ["PATH", "HOME", "LANG"],
|
|
303
495
|
});
|
|
304
496
|
|
|
305
497
|
const remoteWrite = createWriteTool("/repo", {
|
|
@@ -310,22 +502,29 @@ const remoteWrite = createWriteTool("/repo", {
|
|
|
310
502
|
});
|
|
311
503
|
```
|
|
312
504
|
|
|
505
|
+
Packed capability demo: `examples/coding-tools-capability-gaps.ts` (search modes, glob, read-before-write, delete/move).
|
|
506
|
+
|
|
313
507
|
## Extension and configuration notes
|
|
314
508
|
|
|
315
|
-
- **
|
|
316
|
-
- **
|
|
317
|
-
- **
|
|
318
|
-
- **
|
|
509
|
+
- **Long coding sessions.** Use `createCodingCompactionStrategy()` from optional `@arnilo/prism-compaction-llm` when history needs a bounded coding handoff. It is selected explicitly through normal `session.compact()` / agent compaction configuration, preserves raw session entries, and prioritizes file paths, patch intent, checks, plan/todo state, blockers, and verification steps. It does not read files, retain full diffs, or create a second coding runtime.
|
|
510
|
+
- **Pluggable operation backends.** Every tool accepts an `operations` seam. Custom `ReadOperations` must implement bounded `readText` plus `statFile`; custom `EditOperations` must implement `statFile`; read/write methods receive caps/signals. `BashOperations` must stream through `onData` and honor `signal`/`timeout`. Custom `RepositoryOperations` must honor depth/entry/file/match/scan/time caps and abort (including `glob`). Custom `DeleteOperations` / `MoveOperations` must honor containment and abort. A hostile custom backend can still violate its host-owned contract, so isolate it separately.
|
|
511
|
+
- **Per-tool options.** `ShellToolOptions` adds `timeout` and `maxTotalOutputBytes`; `ReadToolOptions` adds `maxScanBytes` and optional `readPathSet`; `WriteToolOptions` / `EditToolOptions` add input caps plus optional `requireReadBeforeWrite` / `readPathSet` / `force`; list/search/glob accept `repository` limits and shared aggregator `ToolsOptions.repository`.
|
|
512
|
+
- **Aggregator options.** `ToolsOptions` (`{ executionPolicy?, shell?, read?, write?, edit?, delete?, move?, list?, search?, glob?, repository? }`) threads each sub-object to the matching tool. `createCodingTools()`, `createAllTools()`, and `createReadOnlyTools()` apply the shared policy unless that tool has an explicit per-tool override. Full membership is nine tools; read-only is `read` + `repo_list` + `repo_search` + `glob`.
|
|
513
|
+
- **Sandbox composition.** Prefer `@arnilo/prism-coding-security` `createSandboxCodingComposition(cwd, { workspaceMode, sandbox, ... })` (or tools-only wrappers). `workspaceMode` is required: `"sandbox"` keeps shell/read/write/edit/list/search/glob/delete/move on one disposable tree; `"host"` runs against host cwd and never claims containment. Mixed sandbox-shell + host-FS wiring throws unless `allowMixedWorkspaceWiring: true`. Same-tree Git: `createGitTools(composition.workspaceRoot, { execFile: sandbox.execFile, commitIdentity })`.
|
|
319
514
|
- **`ToolsOptions`** and the per-tool option types are exported from the package barrel for host configuration.
|
|
320
515
|
- No auto-discovery or manifest registration: import and register explicitly. This package registers no extensions and owns no globals (the mutation queue is a process-wide per-path map — see `ponytail:` note in the source).
|
|
321
516
|
|
|
517
|
+
Read/list/search/glob are observation effects; write/edit/delete/move are optional local mutations; shell/check are unsupported external mutations. `reconcileCodingToolEffect` proves local postconditions or returns `unknown`. See [tool effects](tool-effects.md).
|
|
518
|
+
|
|
322
519
|
## Security and performance notes
|
|
323
520
|
|
|
324
|
-
- **Host shell/filesystem access.** These tools run real commands and read/write/list/search real files. They provide **no sandbox**. Gate them with Prism `PermissionPolicy` / `ToolValidator` / trust policies before registering them for any provider turn. Shared `executionPolicy` applies to both full and read-only aggregators before filesystem/process side effects. See [Host security guide](host-security.md) and [Security/auth/trust](settings-auth-trust-security.md).
|
|
521
|
+
- **Host shell/filesystem access.** These tools run real commands and read/write/list/search/glob/delete/move real files. They provide **no sandbox**. Gate them with Prism `PermissionPolicy` / `ToolValidator` / trust policies before registering them for any provider turn. Shared `executionPolicy` applies to both full and read-only aggregators before filesystem/process side effects. See [Host security guide](host-security.md) and [Security/auth/trust](settings-auth-trust-security.md).
|
|
522
|
+
- **High-risk mutations.** `delete` and `move` are permanent (no trash). Prefer host confirmation via `ExecutionPolicy` before allowing them. Do not instruct models to bypass policy/sandbox.
|
|
325
523
|
- **Non-zero exit is not an error.** A failing command is a normal `shell` result (exit code in metadata); only timeout/abort/spawn failures are error results. Do not assume `error == undefined` means the command succeeded.
|
|
326
|
-
- **Bounded I/O.** `read` streams one page and bounds scan bytes; image/edit reads use stat plus a shared cap-enforcing reader; write/edit inputs are measured before mutation. `repo_list`/`repo_search` stream walks and charge depth/entry/file/match/scan/time before retention. Structured Git tools use argument arrays with finite output/path/ref/message/patch caps, disable hooks/credential prompts/external diff by default, and never push or open PRs. `shell` retains only a rolling display tail and synchronously spills accepted raw chunks so stream backpressure cannot grow heap; wall time and total raw output remain finite.
|
|
327
|
-
- **Per-path serialization.** Concurrent mutations to the same file serialize; concurrent mutations to different files do not block each other. The queue is a process-wide map — across sessions in one process, same-path writes still serialize (upgrade path: scope per registry if throughput matters).
|
|
524
|
+
- **Bounded I/O.** `read` streams one page and bounds scan bytes; image/edit reads use stat plus a shared cap-enforcing reader; write/edit inputs are measured before mutation. `repo_list`/`repo_search`/`glob` stream walks and charge depth/entry/file/match/scan/time before retention. Structured Git tools use argument arrays with finite output/path/ref/message/patch caps, disable hooks/credential prompts/external diff by default, and never push or open PRs. `shell` retains only a rolling display tail and synchronously spills accepted raw chunks so stream backpressure cannot grow heap; wall time and total raw output remain finite.
|
|
525
|
+
- **Per-path serialization.** Concurrent mutations to the same file serialize; concurrent mutations to different files do not block each other. `move` locks both paths in lexicographic order. The queue is a process-wide map — across sessions in one process, same-path writes still serialize (upgrade path: scope per registry if throughput matters).
|
|
328
526
|
- **Bounded image reads.** `read` rejects images over `maxImageBytes` (default 10 MB) by `stat` before read when possible; MIME is detected from magic bytes only. Optional `transformImage` is host-owned — the base package has no image-processing dependency.
|
|
527
|
+
- **Fuzzy edit risk.** Silent fuzzy success can mis-apply edits; duplicate matches fail closed. See the `edit` section above.
|
|
329
528
|
|
|
330
529
|
### Resource-limit defaults and hard caps
|
|
331
530
|
|
|
@@ -340,7 +539,7 @@ const remoteWrite = createWriteTool("/repo", {
|
|
|
340
539
|
| Shell total stdout+stderr | 64 MiB | 1 GiB | process-tree kill; spill removal |
|
|
341
540
|
| Repo depth / entries / files / page | 32 / 10,000 / 10,000 / 1,000 | 128 / 100,000 / 100,000 / 10,000 | before descending/retaining next entry |
|
|
342
541
|
| Search scan / file / matches | 64 MiB / 8 MiB / 1,000 | 1 GiB / 64 MiB / 10,000 | before next file/match retention |
|
|
343
|
-
| Search pattern / line / context / time | 512 B / 50 KiB / 5 / 30 s | 4 KiB / 1 MiB / 20 / 300 s | before
|
|
542
|
+
| Search pattern / line / context / time | 512 B / 50 KiB / 5 / 30 s | 4 KiB / 1 MiB / 20 / 300 s | before pattern compile / line retain / deadline |
|
|
344
543
|
| Git paths / refs / message | 1,000 / 1 KiB / 64 KiB | 10,000 / 4 KiB / 256 KiB | before process/temp-file creation |
|
|
345
544
|
| Git output / diff lines / changed files / patch | 4 MiB / 10,000 / 1,000 / 16 MiB | 64 MiB / 100,000 / 10,000 / 64 MiB | stream before retain; artifact spill optional |
|
|
346
545
|
| Worktrees | 4 | 16 | before add |
|
|
@@ -354,7 +553,12 @@ Every configurable value is a positive safe integer (context may be zero); Prism
|
|
|
354
553
|
|
|
355
554
|
## Related APIs
|
|
356
555
|
|
|
556
|
+
- [Language intelligence](language-intelligence.md): optional host-activated LSP contract (`createLanguageIntelligence`) — symbols/definitions/references/diagnostics/hover/rename.
|
|
557
|
+
- [Process sessions](process-sessions.md): optional managed long-running processes (`createProcessSessions`) — start/output/input/wait/signal/kill/release.
|
|
558
|
+
- [Forge integration](forge-integration.md): optional GitHub adapter (`createGitHubForge`) — issue context, authenticated push, PR create/update, review comments, checks, bounded handoff reconcile; effect-store idempotency, no duplicate PRs/comments on retry, tokens never in argv/logs/events.
|
|
357
559
|
- [Tools](tools.md): the host-owned tool harness — `createToolRegistry`, `dispatchToolCall`, filtering, and the `ToolDefinition` contract these factories satisfy.
|
|
358
560
|
- [Public contracts](public-contracts.md): `ToolDefinition`, `ToolResult`, `ToolExecutionContext`, `ContentBlock`, and `JsonObject` shapes.
|
|
359
561
|
- [Host security guide](host-security.md): fail-closed checklist for permission policies, tool validation, and trust boundaries that must gate these tools.
|
|
360
562
|
- [Tool conformance](tool-conformance.md): assertions for the tool-dispatch blocked-reason matrix these tools participate in.
|
|
563
|
+
- [ACP coding-host interop](acp.md): host editors drive these tools through stable ACP v1 — client fs/terminal adapters, `CodingLifecycleEvent` emission (`file_changed` etc. via the `onEvent` options), and permission/elicitation through the shared four-outcome decision model.
|
|
564
|
+
- [LLM compaction package](compaction-llm.md): optional `createCodingCompactionStrategy()` retains bounded paths, patch intent, checks, plan/todo state, blockers, and next verification—not complete diffs or raw command output.
|