@arnilo/prism 0.9.0 → 0.11.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 +50 -1
- package/README.md +19 -16
- package/dist/agent-approval.d.ts +7 -1
- package/dist/agent-approval.js +15 -6
- package/dist/agent-run-lifecycle.d.ts +2 -1
- package/dist/agent-run-lifecycle.js +20 -6
- package/dist/agent-run-state.d.ts +26 -5
- package/dist/agent-run-state.js +97 -1
- package/dist/agent-session/event-subscriber.d.ts +2 -0
- package/dist/agent-session/event-subscriber.js +3 -0
- package/dist/agent-session/session/assemble.js +165 -16
- package/dist/agent-session/session/persist.js +11 -5
- package/dist/agent-session/session/provider-round.js +54 -13
- package/dist/agent-session/session/tool-round.d.ts +2 -2
- package/dist/agent-session/session/tool-round.js +86 -23
- package/dist/agent-session/session/types.d.ts +21 -2
- package/dist/agent-session/session.d.ts +66 -4
- package/dist/agent-session/session.js +159 -18
- package/dist/checkpoint-restore.d.ts +50 -14
- package/dist/checkpoint-restore.js +104 -28
- package/dist/context-budget.d.ts +11 -0
- package/dist/context-budget.js +33 -2
- package/dist/contracts-core/agent.d.ts +26 -5
- package/dist/contracts-core/extensions.d.ts +3 -0
- package/dist/contracts-core/guardrail-packs.d.ts +8 -3
- package/dist/contracts-core/loop.d.ts +36 -0
- package/dist/contracts-core/provider.d.ts +6 -1
- package/dist/contracts-core/run-limits.d.ts +10 -1
- package/dist/contracts-core/session.d.ts +2 -1
- package/dist/contracts-protocol.d.ts +6 -4
- package/dist/contracts-run-state.d.ts +48 -6
- package/dist/contributions.d.ts +2 -1
- package/dist/contributions.js +1 -0
- package/dist/extensions.d.ts +15 -1
- package/dist/extensions.js +68 -0
- package/dist/guardrail-packs/types.d.ts +10 -0
- package/dist/guardrail-packs/validation-respect.js +16 -0
- package/dist/guardrails.d.ts +42 -1
- package/dist/guardrails.js +124 -15
- package/dist/index.d.ts +7 -7
- package/dist/index.js +4 -4
- package/dist/leases.js +32 -6
- package/dist/middleware.d.ts +1 -1
- package/dist/node/contribution-discovery.d.ts +16 -1
- package/dist/node/contribution-discovery.js +47 -0
- package/dist/node/session-store-jsonl.js +67 -17
- package/dist/run-bundle.d.ts +6 -1
- package/dist/run-bundle.js +4 -1
- package/dist/run-limits.d.ts +11 -5
- package/dist/run-limits.js +13 -0
- package/dist/session-stores.js +61 -12
- package/dist/testing/prefix-stability-conformance.d.ts +73 -1
- package/dist/testing/prefix-stability-conformance.js +158 -27
- package/dist/tools.js +10 -3
- package/dist/usage-estimation.d.ts +7 -1
- package/dist/usage-estimation.js +16 -10
- package/docs/acp.md +2 -2
- package/docs/agent-events.md +15 -10
- package/docs/agent-session-runtime.md +10 -7
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-tools.md +7 -11
- package/docs/compaction-llm.md +2 -0
- package/docs/compaction-observational-memory.md +21 -1
- package/docs/context-and-skills.md +6 -7
- package/docs/contribution-discovery.md +13 -0
- package/docs/durable-runs.md +14 -6
- package/docs/embeddings.md +7 -1
- package/docs/execution-timeline.md +9 -2
- package/docs/extensions.md +21 -5
- package/docs/guardrails.md +16 -6
- package/docs/hooks.md +282 -0
- package/docs/impeccable.md +1 -2
- package/docs/index.md +28 -21
- package/docs/input-and-prompt-assembly.md +1 -1
- package/docs/instruction-injection.md +1 -0
- package/docs/live-testing.md +3 -2
- package/docs/memory-fabric.md +29 -0
- package/docs/middleware-hooks.md +54 -4
- package/docs/migrate-to-0.11.md +65 -0
- package/docs/migration.md +24 -0
- package/docs/node-jsonl-session-store.md +4 -3
- package/docs/operations.md +1 -1
- package/docs/options-index.md +3 -1
- package/docs/peer-dependencies.md +3 -5
- package/docs/policy-and-audit.md +15 -2
- package/docs/prefix-stability-conformance.md +82 -9
- package/docs/provider-packages.md +20 -20
- package/docs/public-contracts.md +2 -1
- package/docs/rag.md +94 -7
- package/docs/release-and-install.md +62 -59
- package/docs/runs-and-usage.md +21 -10
- package/docs/scoped-agent-memory.md +17 -9
- package/docs/scoped-memory.md +138 -0
- package/docs/session-stores.md +2 -2
- package/docs/supervisors.md +14 -6
- package/docs/testing.md +17 -9
- package/docs/tools.md +1 -1
- package/docs/wiki.md +4 -2
- package/docs/workflows.md +2 -2
- package/package.json +8 -5
- package/docs/caveman.md +0 -130
- package/docs/graft.md +0 -149
- package/docs/ponytail.md +0 -129
package/docs/caveman.md
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
# Caveman behavior integration
|
|
2
|
-
|
|
3
|
-
## What it does
|
|
4
|
-
|
|
5
|
-
`@arnilo/prism-coding-tools/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
|
-
Required skills (fail closed if missing): `caveman`, `caveman-commit`, `caveman-review`, `caveman-stats`, `caveman-compress`, `caveman-help`, `cavecrew`. Extra `skills/*/SKILL.md` (v2.1 extras like `caveman-explore`) register as optional skills and `load_skill` commands. Dirs without `SKILL.md` (`*.mjs`, `registry.json`, `generated/`) are skipped.
|
|
41
|
-
|
|
42
|
-
Registered commands: `caveman` (level), `caveman-init`, plus one `load_skill` dispatch per registered skill except `caveman`.
|
|
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-coding-tools/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
|
-
- Caveman 2 compression proxy/engine is **not** a Prism runtime. Only `SKILL.md` files under `skills/` load.
|
|
114
|
-
|
|
115
|
-
## Security and performance notes
|
|
116
|
-
|
|
117
|
-
- 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).
|
|
118
|
-
- Config read/write is bounded (`MAX_CONFIG_FILE_BYTES` 16 KiB) at host-owned `configPath` only.
|
|
119
|
-
- Errors redact home directories and absolute paths.
|
|
120
|
-
- Setup is O(skills) directory scan; mode read/write is O(1) per change; injection is O(1) upstream lookup per turn.
|
|
121
|
-
- Session custom entries respect host session ownership and redaction policies.
|
|
122
|
-
|
|
123
|
-
## Related APIs
|
|
124
|
-
|
|
125
|
-
- [Ponytail behavior integration](ponytail.md): complementary lazy-minimalism mode package.
|
|
126
|
-
- [Extension kernel and event bus](extensions.md): `kernel.load` and contribution registration.
|
|
127
|
-
- [Context and skills](context-and-skills.md): progressive disclosure + `createLoadSkillTool`.
|
|
128
|
-
- [Instruction injection](instruction-injection.md): `caveman-mode` injector selection.
|
|
129
|
-
- [Observational memory compaction package](compaction-observational-memory.md): `appendEntry` / `getEntries` attach precedent.
|
|
130
|
-
- [Migration guide](migration.md): `0.0.21 → 0.0.22` install and opt-in notes.
|
package/docs/graft.md
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# Graft context-graph integration
|
|
2
|
-
|
|
3
|
-
> **Optional peer install:** `@nanonets/graft` — see [Optional peer dependencies](peer-dependencies.md).
|
|
4
|
-
|
|
5
|
-
## What it does
|
|
6
|
-
|
|
7
|
-
`@arnilo/prism-memory/graft` is an optional subpath that wires [nanonets/graft](https://github.com/nanonets/graft) — a repository context-graph CLI (`graft/` directory, INDEX.md orientation, symbol-level wiring graph) — into Prism contribution contracts.
|
|
8
|
-
|
|
9
|
-
It registers six pull tools backed by the graft CLI (`--json`, argv-safe), a push-mode retrieval-pack context provider plus first-turn orientation injector carried on the `graft` skill, commands (`graft`, `graft-build`, `graft-build-deep`, `graft-check`, `graft-viz`, `graft-init`), and an edit-watch middleware that computes blast radius after mutating tool calls. Import is inert; a missing graft CLI fails closed at `setup` with a bounded redacted error.
|
|
10
|
-
|
|
11
|
-
## When to use it
|
|
12
|
-
|
|
13
|
-
Use it when a host wants agents to locate code by architecture, callers, and coupling before grep-spelunking. Three modes:
|
|
14
|
-
|
|
15
|
-
- `"pull"` (default) — register the tools; the agent decides when to query.
|
|
16
|
-
- `"push"` — per-turn retrieval pack (pointers only) + first-turn orientation, injected automatically.
|
|
17
|
-
- `"both"` — everything.
|
|
18
|
-
|
|
19
|
-
Install optional peer `@nanonets/graft@^0.16.0 || ^0.18.0` **or** pass `packageRoot`/`cliPath` explicitly. Both floors are smoke-tested by the offline peer-contract suite (`resolveGraftCli` bin discovery + packaged manifest); the range lists exactly the two released lines Prism validates, and `0.17` is absent because upstream never published one. Pair with progressive disclosure: the `graft` skill body stays small; tool schemas carry the details. Graft complements indexed code search (`repository_search`): graph/semantic locators vs literal search — neither replaces the other.
|
|
20
|
-
|
|
21
|
-
Zero-code alternative (L0): hosts can skip this package entirely and let agents call `graft <command> --json` through their shell tool, optionally seeding context with graft's own generated instruction files. This package exists for native-tool ergonomics, budgeted subprocesses, session persistence, and push mode.
|
|
22
|
-
|
|
23
|
-
## Inputs / request
|
|
24
|
-
|
|
25
|
-
`createGraftExtension(options)`:
|
|
26
|
-
|
|
27
|
-
| Field | Type | Required | Purpose |
|
|
28
|
-
| --- | --- | --- | --- |
|
|
29
|
-
| `cliPath` / `packageRoot` | `string` | no | Explicit stub/binary or checkout root with a manifest-declared bin; default resolves optional peer `@nanonets/graft`. Relative paths rejected; explicit paths existence-checked at resolve time. |
|
|
30
|
-
| `mode` | `"pull" \| "push" \| "both"` | no | Surface selection. Default `pull`. |
|
|
31
|
-
| `projectDir` | `string` | no | Directory graft operates on. Default `process.cwd()` at setup. |
|
|
32
|
-
| `retrievalBudgetMs` | `number` | no | Wall-clock budget per CLI child call (default 8000). |
|
|
33
|
-
| `maxResultBytes` | `number` | no | Stdout cap before parsing (default 512 KiB). |
|
|
34
|
-
| `maxPromptChars` | `number` | no | Prompts longer than this never become ask argv (default 4096). |
|
|
35
|
-
| `allowUpstreamTelemetry` | `boolean` | no | Default false → children run with `DO_NOT_TRACK=1`. |
|
|
36
|
-
| `providerEnv` | `Record<string, string>` | no | Explicit graft provider settings (`GRAFT_API_KEY`, …). Never inherited from host env; only `GRAFT_*` keys reach the child. |
|
|
37
|
-
| `deepModel` | `{ provider: "openai" \| "anthropic" \| "litellm" \| "orcarouter", model: string, apiKey: string, baseUrl?: string }` | no | Model for `graft build --deep` (Graft's own LLM client — **Prism's `Provider` is not Graft's LLM**; they have different protocols). Merged over `providerEnv` as `GRAFT_PROVIDER`/`GRAFT_MODEL`/`GRAFT_API_KEY`/`GRAFT_BASE_URL`; wins on conflict. |
|
|
38
|
-
| `initAgents` / `initYes` / `initWireMcp` | `readonly string[]` / `boolean` / `boolean` | no | `graft init` configuration: agent ids for `--agents`, `--yes`, and whether to wire graft MCP servers (default off — Prism provides its own graft surfaces). `graft-init` refuses to spawn without `initAgents` or `initYes` (the child has no TTY). |
|
|
39
|
-
| `buildBudgetMs` / `deepBuildBudgetMs` / `buildMaxResultBytes` | `number` | no | Budgets for graph builds: structural `build`/`init` default 120000 ms, `--deep` default 600000 ms (the LLM pass over the graph), stdout cap 2 MiB. Ask/grep stay on `retrievalBudgetMs`. |
|
|
40
|
-
| `editToolNames` | `readonly string[]` | no | Tools triggering blast-radius lookup. Default `write`, `edit`, `move`. |
|
|
41
|
-
| `quietStartup`, `hideStatus` | `boolean` | no | Suppress startup status events / status reporting. |
|
|
42
|
-
| `appendEntry` | `(entry, opts?) => Promise<void>` | yes | Host session append (OM attach pattern). |
|
|
43
|
-
| `getEntries` | `() => readonly SessionEntry[] \| Promise<...>` | yes | Current branch entries for state restore. |
|
|
44
|
-
|
|
45
|
-
Pull tools (mode includes `pull`): `graft_ask`, `graft_grep`, `graft_callers`, `graft_skeleton`, `graft_map`, `graft_blast`.
|
|
46
|
-
|
|
47
|
-
Push surfaces (mode includes `push`): skill `graft` carrying context provider `graft-context` (per-turn pointers-only pack, gated: ≥12-char prompt, dedup by seen node ids, 32 KiB block ceiling) and instruction injector `graft-orient` (`first_turn`, byte-capped INDEX.md cut + staleness banner).
|
|
48
|
-
|
|
49
|
-
Registered commands: `graft` (`status` \| `build` [deep:true] \| `check` \| `viz` \| `init` dispatch), plus `graft-build`, `graft-build-deep`, `graft-check`, `graft-viz`, `graft-init` aliases.
|
|
50
|
-
|
|
51
|
-
### Graph builds and init
|
|
52
|
-
|
|
53
|
-
- `/graft-build` — structural rebuild via `graft build` (tree-sitter pass, no API key, plain-text progress — no `JSON.parse` on this surface).
|
|
54
|
-
- `/graft-build-deep` — `graft build --deep --provider <> --model <> [--base-url <>]` using the host's `deepModel`. Without a configured model it errors before spawning. `GRAFT_API_KEY` rides in the child env, never on argv.
|
|
55
|
-
- `/graft-init` — `graft init --no-global` (never writes user-level state), default `--no-mcp --no-hooks --no-statusline` (opt in via `initWireMcp`), plus `--agents <id>` per `initAgents` and `--yes` when `initYes`. Requires one of the two; non-interactive by design.
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
# structural, no key
|
|
59
|
-
/graft-build
|
|
60
|
-
# deep — host-configured model
|
|
61
|
-
e.g. /graft-build-deep
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Outputs / response / events
|
|
65
|
-
|
|
66
|
-
| Export | Purpose |
|
|
67
|
-
| --- | --- |
|
|
68
|
-
| `createGraftExtension(options)` | Returns an inert `Extension` until `kernel.load([...])`; emits `graft:loaded` on setup. |
|
|
69
|
-
| `resolveGraftCli(options)` | Fail-closed CLI resolution (`explicit` → command+argv, `peer-bin` → node + manifest bin). |
|
|
70
|
-
| `runGraftJson(cli, argv, options)` / `runGraftExit(cli, argv, options)` / `childEnv(options)` / `childTimeoutMs` / `DEFAULT_MAX_RESULT_BYTES` | Budgeted runners for hosts building custom surfaces — JSON surfaces (`check`/`ask`) vs exit-code surfaces (`build`/`init`). |
|
|
71
|
-
| `deepProviderEnv(deepModel, providerEnv)` | `deepModel` merged over `providerEnv`, filtered to `GRAFT_*`. |
|
|
72
|
-
| `readBoundedFile` / `redactPaths` / `GraftResolveError` | Bounded-read and redaction helpers. |
|
|
73
|
-
|
|
74
|
-
Events: `graft:status` (check/build outcomes), `graft:dirty` (post-edit, repo-relative path + optional `staleCountEstimate`), `graft:loaded` (mode + cliKind metadata).
|
|
75
|
-
|
|
76
|
-
Session custom entry shape (`data.type === "graft-state"`, CAS via `expectedParentId`):
|
|
77
|
-
|
|
78
|
-
```json
|
|
79
|
-
{ "kind": "custom", "data": { "type": "graft-state", "freshness": { "checkedAt": "...", "fresh": true }, "seen": ["node-a"], "savedTokensApprox": 120 } }
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
The graph never rebuilds itself mid-session (no auto-rebuild): after edits, ask/grep results may lag one turn; graft self-refreshes on the next indexed query, or run `/graft build` for an immediate refresh. The skill text states this contract to the agent.
|
|
83
|
-
|
|
84
|
-
## Request/response example
|
|
85
|
-
|
|
86
|
-
Tool call (pull):
|
|
87
|
-
|
|
88
|
-
```json
|
|
89
|
-
{ "name": "graft_ask", "arguments": { "query": "where is auth handled?", "count": 3 } }
|
|
90
|
-
→ { "nodes": [{ "id": "auth-guard", "title": "requireAuth", "path": "src/auth.ts", "line": 41 }] }
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Status event:
|
|
94
|
-
|
|
95
|
-
```json
|
|
96
|
-
{ "type": "graft:status", "extension": "@arnilo/prism-memory/graft", "metadata": { "fresh": true, "missing": 0, "stale": 2 } }
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Implementation example
|
|
100
|
-
|
|
101
|
-
See [`examples/graft-extension.ts`](../examples/graft-extension.ts) — network-free demo against the package fixture stub: one pull-tool call, one push turn with pack injection + dedup, one simulated edit producing blast radius, and the `DO_NOT_TRACK` child-env guard.
|
|
102
|
-
|
|
103
|
-
```ts
|
|
104
|
-
import { createExtensionKernel, createMemorySessionStore } from "@arnilo/prism";
|
|
105
|
-
import { createGraftExtension } from "@arnilo/prism-memory/graft";
|
|
106
|
-
|
|
107
|
-
const store = createMemorySessionStore();
|
|
108
|
-
const kernel = createExtensionKernel({ errorPolicy: "throw" });
|
|
109
|
-
await kernel.load([
|
|
110
|
-
createGraftExtension({
|
|
111
|
-
packageRoot: "./vendor/graft-checkout",
|
|
112
|
-
mode: "both",
|
|
113
|
-
quietStartup: true,
|
|
114
|
-
deepModel: { provider: "anthropic", model: "claude-sonnet-4-5", apiKey: process.env.ANTHROPIC_API_KEY! },
|
|
115
|
-
initAgents: ["codex"],
|
|
116
|
-
appendEntry: async (entry, options) => store.append(entry, options),
|
|
117
|
-
getEntries: async () => store.list("s1"),
|
|
118
|
-
}),
|
|
119
|
-
]);
|
|
120
|
-
// Pull: dispatch graft_ask/… tools. Push: runs assemble the skill-carried
|
|
121
|
-
// provider + graft-orient injector. Edits: middleware emits graft:dirty.
|
|
122
|
-
// /graft-build-deep runs graft's own LLM pass; /graft-init wires codex, --no-global.
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## Extension and configuration notes
|
|
126
|
-
|
|
127
|
-
- Import alone registers nothing (`sideEffects: false`); no timers, watchers, or network. The only child processes are budgeted graft CLI calls.
|
|
128
|
-
- Retrieval happens in-process via Prism primitives (context provider, injector, tool_result middleware) — no external hook shims.
|
|
129
|
-
- Ask result shape is parsed tolerantly (`nodes|results|matches|hits`) because graft is pre-1.0; formatters emit pointers (`title` + `file:line` + `[[wikilink]]`), never source bodies.
|
|
130
|
-
- Deliberate opt-out from family/umbrella packaging (like Caveman/Ponytail) — opt-in install only.
|
|
131
|
-
- Multi-repo layouts work as upstream graft defines them (workspaces, submodules with `--follow-submodules`, sibling repos); point `projectDir` at the graft root that owns the target repo.
|
|
132
|
-
|
|
133
|
-
## Security and performance notes
|
|
134
|
-
|
|
135
|
-
- Telemetry default-off: children always get `DO_NOT_TRACK=1` unless `allowUpstreamTelemetry` is true; child env is fixed-base — host env vars are never inherited, and only explicit `GRAFT_*` keys from `providerEnv`/`deepModel` pass through. Route secrets like `GRAFT_API_KEY` through the host's credential resolution when populating `deepModel`/`providerEnv`. `deepModel`'s API key reaches the child via env only — never on argv (no `--api-key` flag exists in the surface), so it cannot leak through `ps` or logs.
|
|
136
|
-
- Build/init commands are budgeted separately from retrieval (`buildBudgetMs`, `deepBuildBudgetMs`, `buildMaxResultBytes`); deep builds fail closed without a configured model instead of spawning unconfigured.
|
|
137
|
-
- `graft-init` always passes `--no-global` — it never writes user-level agent state; MCP/hook/statusline wiring stays off unless the host opts in via `initWireMcp`.
|
|
138
|
-
- Upstream output is untrusted: stdout capped (`maxResultBytes`), prompts capped (`maxPromptChars`), injected packs bounded (32 KiB), orientation cut byte-capped (8 KiB); error paths are logged redacted (absolute paths/home dirs).
|
|
139
|
-
- Every CLI call is wall-clock-budgeted (`retrievalBudgetMs`, minus fixed overhead for the timeout math) and every failure degrades silently: pull tools return structured errors, the push pack contributes nothing, edit-watch passes the tool result through untouched.
|
|
140
|
-
- No background workers; state persists through two CAS appends per turn at most (freshness patch, seen-set/saved-tokens update).
|
|
141
|
-
|
|
142
|
-
## Related APIs
|
|
143
|
-
|
|
144
|
-
- [Ponytail behavior integration](ponytail.md): same adapter pattern (optional peer/upstream path, fail-closed setup, session custom entries).
|
|
145
|
-
- [Caveman behavior integration](caveman.md): complementary terse-communication mode package.
|
|
146
|
-
- [Indexed code search](indexed-code-search.md): literal `repository_search` seam — complement, not overlap.
|
|
147
|
-
- [Context and skills](context-and-skills.md): progressive catalog + `load_skill`; skill-carried context providers.
|
|
148
|
-
- [Instruction injection](instruction-injection.md): injector seams (`graft-orient` rides `first_turn`).
|
|
149
|
-
- [Extension kernel and event bus](extensions.md): explicit `kernel.load`, extension events.
|
package/docs/ponytail.md
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Ponytail behavior integration
|
|
2
|
-
|
|
3
|
-
> **Optional peer install:** `@dietrichgebert/ponytail` — see [Optional peer dependencies](peer-dependencies.md).
|
|
4
|
-
|
|
5
|
-
## What it does
|
|
6
|
-
|
|
7
|
-
`@arnilo/prism-coding-tools/ponytail` is an optional package that wires [DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail) into Prism contribution contracts.
|
|
8
|
-
|
|
9
|
-
It registers upstream skills and commands, injects active mode instructions via upstream `getPonytailInstructions` / `filterSkillBodyForMode`, and persists mode as session custom `ponytail-mode` entries. Import is inert; missing upstream fails closed at `setup` with a bounded redacted error.
|
|
10
|
-
|
|
11
|
-
## When to use it
|
|
12
|
-
|
|
13
|
-
Use it when a host wants lazy-minimalism coding behavior (`lite`, `full`, `ultra`) with upstream Ponytail skills (`ponytail-audit`, `ponytail-debt`, `ponytail-gain`, `ponytail-help`, `ponytail-review`) in a Prism extension kernel.
|
|
14
|
-
|
|
15
|
-
Install optional peer `@dietrichgebert/ponytail@^4.9.0` **or** pass `upstreamPath` to a checkout with `skills/` and `hooks/`.
|
|
16
|
-
|
|
17
|
-
Pair with progressive disclosure: mode slices on the `ponytail-mode` injector; full skill bodies via `load_skill` only.
|
|
18
|
-
|
|
19
|
-
## Inputs / request
|
|
20
|
-
|
|
21
|
-
`createPonytailExtension(options)`:
|
|
22
|
-
|
|
23
|
-
| Field | Type | Required | Purpose |
|
|
24
|
-
| --- | --- | --- | --- |
|
|
25
|
-
| `upstreamPath` | `string` | no | Override path to Ponytail root; default resolves optional peer package. |
|
|
26
|
-
| `defaultMode` | `PonytailMode` | no | Initial mode when no session entry exists (default `full`). |
|
|
27
|
-
| `quietStartup` | `boolean` | no | Suppress startup status events. |
|
|
28
|
-
| `appendEntry` | `(entry, opts?) => Promise<void>` | yes | Host session append (OM `attach` pattern). |
|
|
29
|
-
| `getEntries` | `() => readonly SessionEntry[] \| Promise<...>` | yes | Current branch entries for mode restore. |
|
|
30
|
-
| `configPath` | `string` | no | Bounded local config for `defaultMode` / `quietStartup` / `hideStatus`. |
|
|
31
|
-
|
|
32
|
-
`PonytailMode`: `off` \| `lite` \| `full` \| `ultra`.
|
|
33
|
-
|
|
34
|
-
Session custom entry shape:
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{ "kind": "custom", "data": { "type": "ponytail-mode", "mode": "full" } }
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Registered skills: `ponytail`, `ponytail-audit`, `ponytail-debt`, `ponytail-gain`, `ponytail-help`, `ponytail-review`.
|
|
41
|
-
|
|
42
|
-
Registered commands: `ponytail`, `ponytail-review`, `ponytail-audit`, `ponytail-gain`, `ponytail-debt`, `ponytail-help`.
|
|
43
|
-
|
|
44
|
-
`ponytail` command actions: empty args or `status` report current+default mode (4.9.0; does not change mode); `lite|full|ultra|off` set mode; `default <mode>` persists default.
|
|
45
|
-
|
|
46
|
-
## Outputs / response / events
|
|
47
|
-
|
|
48
|
-
| Export | Purpose |
|
|
49
|
-
| --- | --- |
|
|
50
|
-
| `createPonytailExtension(options)` | Returns an inert `Extension` until `kernel.load([...])`. |
|
|
51
|
-
| `ponytail-mode` injector | `InstructionInjector` calling upstream `getPonytailInstructions(mode)`. |
|
|
52
|
-
| `ponytail` command | Set mode, report status, or persist default mode to config file. |
|
|
53
|
-
| Alias commands | Dispatch `{ skill, dispatch: "load_skill" }` for companion skills. |
|
|
54
|
-
| `ponytail:status` / `ponytail:loaded` events | Optional host metadata (no statusline shell scripts). |
|
|
55
|
-
|
|
56
|
-
Deactivation: exact phrases `stop ponytail` and `normal mode`.
|
|
57
|
-
|
|
58
|
-
## Request/response example
|
|
59
|
-
|
|
60
|
-
```json
|
|
61
|
-
{ "command": "ponytail", "args": { "mode": "lite" }, "sessionId": "s1" }
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{ "kind": "custom", "data": { "type": "ponytail-mode", "mode": "lite" } }
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Implementation example
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
import { createPonytailExtension } from "@arnilo/prism-coding-tools/ponytail";
|
|
72
|
-
import {
|
|
73
|
-
createExtensionKernel,
|
|
74
|
-
createLoadSkillTool,
|
|
75
|
-
createLoadedSkillSet,
|
|
76
|
-
createMemorySessionStore,
|
|
77
|
-
createSkillRegistry,
|
|
78
|
-
} from "@arnilo/prism";
|
|
79
|
-
|
|
80
|
-
const store = createMemorySessionStore();
|
|
81
|
-
const callbacks = {
|
|
82
|
-
appendEntry: async (entry, options) => store.append(entry, options),
|
|
83
|
-
getEntries: async () => store.list("s1"),
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const kernel = createExtensionKernel({ errorPolicy: "throw" });
|
|
87
|
-
await kernel.load([
|
|
88
|
-
createPonytailExtension({
|
|
89
|
-
upstreamPath: undefined, // optional peer @dietrichgebert/ponytail
|
|
90
|
-
defaultMode: "full",
|
|
91
|
-
quietStartup: true,
|
|
92
|
-
...callbacks,
|
|
93
|
-
}),
|
|
94
|
-
]);
|
|
95
|
-
|
|
96
|
-
const registry = createSkillRegistry(kernel.registries.skills.list());
|
|
97
|
-
const loaded = createLoadedSkillSet();
|
|
98
|
-
const loadSkill = createLoadSkillTool({ registry, loaded });
|
|
99
|
-
|
|
100
|
-
await kernel.registries.commands.get("ponytail")!.execute({ mode: "lite" }, { sessionId: "s1" });
|
|
101
|
-
// Select instructionInjectors: ["ponytail-mode"] on runs that should receive mode slices.
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
See `examples/caveman-ponytail.ts` for combined Caveman + Ponytail progressive disclosure demo (network-free fixtures).
|
|
105
|
-
|
|
106
|
-
## Extension and configuration notes
|
|
107
|
-
|
|
108
|
-
- Import alone registers nothing (`sideEffects: false`); no timers, watchers, network, or shell scripts.
|
|
109
|
-
- Upstream hook modules load via `createRequire` from resolved root — instruction strings are not forked in Prism.
|
|
110
|
-
- Mode restore scans `getEntries()` for latest `data.type === "ponytail-mode"` (OM attach pattern).
|
|
111
|
-
- `ponytail-subagent` hook is not wired; nested-agent behavior is host responsibility. When hosts wire the upstream hook, `PONYTAIL_SUBAGENT_MATCHER` accepts only the documented safe subset — `"explore|general"` (any literal substring) or `"^general$"` (exact), case-insensitive, max 256 chars. No `RegExp` is compiled from the environment, so arbitrary regex (including catastrophic nested quantifiers) is never evaluated; unset/invalid patterns inject into every subagent.
|
|
112
|
-
- No TUI statusline scripts; use `ponytail status` command or extension events.
|
|
113
|
-
- Not included in `@arnilo/prism-coding-tools` or `@arnilo/prism-core` profiles — opt-in install only.
|
|
114
|
-
|
|
115
|
-
## Security and performance notes
|
|
116
|
-
|
|
117
|
-
- Upstream text is untrusted; reads bounded (`MAX_SKILL_FILE_BYTES` 256 KiB, `MAX_INJECTED_INSTRUCTION_BYTES` 32 KiB).
|
|
118
|
-
- Config writes only to host `configPath` with size cap (`MAX_CONFIG_FILE_BYTES` 16 KiB).
|
|
119
|
-
- Errors redact absolute paths and home directories.
|
|
120
|
-
- O(skills) setup scan; O(1) mode tracking per turn; no background workers.
|
|
121
|
-
|
|
122
|
-
## Related APIs
|
|
123
|
-
|
|
124
|
-
- [Caveman behavior integration](caveman.md): complementary terse-communication mode package.
|
|
125
|
-
- [Extension kernel and event bus](extensions.md): explicit `kernel.load`.
|
|
126
|
-
- [Context and skills](context-and-skills.md): progressive catalog + `load_skill`.
|
|
127
|
-
- [Instruction injection](instruction-injection.md): `ponytail-mode` injector.
|
|
128
|
-
- [Observational memory compaction package](compaction-observational-memory.md): session callback attach pattern.
|
|
129
|
-
- [Migration guide](migration.md): `0.0.21 → 0.0.22` notes.
|