pi-jarvis 1.6.0 → 1.7.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.
Files changed (45) hide show
  1. package/AGENTS.md +20 -2
  2. package/README.md +124 -8
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +55 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/jarvis-branding.d.ts +21 -0
  7. package/dist/jarvis-branding.d.ts.map +1 -0
  8. package/dist/jarvis-branding.js +86 -0
  9. package/dist/jarvis-branding.js.map +1 -0
  10. package/dist/jarvis-config.d.ts.map +1 -1
  11. package/dist/jarvis-config.js +7 -22
  12. package/dist/jarvis-config.js.map +1 -1
  13. package/dist/memory-config.d.ts +21 -0
  14. package/dist/memory-config.d.ts.map +1 -0
  15. package/dist/memory-config.js +325 -0
  16. package/dist/memory-config.js.map +1 -0
  17. package/dist/memory-content.d.ts +26 -0
  18. package/dist/memory-content.d.ts.map +1 -0
  19. package/dist/memory-content.js +223 -0
  20. package/dist/memory-content.js.map +1 -0
  21. package/dist/memory-extension.d.ts +12 -0
  22. package/dist/memory-extension.d.ts.map +1 -0
  23. package/dist/memory-extension.js +286 -0
  24. package/dist/memory-extension.js.map +1 -0
  25. package/dist/memory-service.d.ts +52 -0
  26. package/dist/memory-service.d.ts.map +1 -0
  27. package/dist/memory-service.js +390 -0
  28. package/dist/memory-service.js.map +1 -0
  29. package/dist/memory-store.d.ts +47 -0
  30. package/dist/memory-store.d.ts.map +1 -0
  31. package/dist/memory-store.js +659 -0
  32. package/dist/memory-store.js.map +1 -0
  33. package/dist/memory-types.d.ts +49 -0
  34. package/dist/memory-types.d.ts.map +1 -0
  35. package/dist/memory-types.js +2 -0
  36. package/dist/memory-types.js.map +1 -0
  37. package/dist/overlay.d.ts +4 -1
  38. package/dist/overlay.d.ts.map +1 -1
  39. package/dist/overlay.js +21 -2
  40. package/dist/overlay.js.map +1 -1
  41. package/dist/side-session.d.ts +4 -0
  42. package/dist/side-session.d.ts.map +1 -1
  43. package/dist/side-session.js +21 -5
  44. package/dist/side-session.js.map +1 -1
  45. package/package.json +4 -3
package/AGENTS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Project Scope
4
4
  - `pi-jarvis` is a Pi extension that opens a `/jarvis` side-conversation overlay.
5
- - Core runtime files: `index.ts`, `side-session.ts`, `native-mcp.ts`, `overlay.ts`, `overlay-layout.ts`, `draft-editor.ts`, `transcript-viewport.ts`, `model-picker.ts`, `jarvis-config.ts`, `session-ref.ts`.
5
+ - Core runtime files: `index.ts`, `side-session.ts`, `native-mcp.ts`, `overlay.ts`, `overlay-layout.ts`, `draft-editor.ts`, `transcript-viewport.ts`, `jarvis-branding.ts`, `model-picker.ts`, `jarvis-config.ts`, `session-ref.ts`, and `memory-{types,config,content,store,service,extension}.ts`.
6
6
  - Current baseline: Pi 1.0.0 (`@earendil-works` packages), Node.js >=22.19.0. Older Pi hosts are not supported.
7
7
 
8
8
  ## Current `/jarvis-model` and `/jarvis-thinking` Behavior
@@ -15,7 +15,7 @@
15
15
  - `/jarvis-thinking [--project|--global] auto|follow-main|off|minimal|low|medium|high|xhigh|max` stores a scoped thinking override without changing the main session thinking level.
16
16
  - `/jarvis-thinking [--project|--global] clear` removes that scope's thinking override so fallback applies.
17
17
  - Resolution order is: project config, then global config, then built-in defaults (`follow-main` for model, `auto` for thinking). Global writes never override an active project setting.
18
- - Config writes use atomic same-directory replacement. I/O errors must not trigger malformed-JSON recovery. Cross-process concurrent config writes are not locked.
18
+ - Config writes use atomic same-directory replacement. Malformed shared JSON requires manual repair: model/thinking set/clear must never replace/delete it and reset unknown memory privacy controls. Keep I/O errors distinct and parser input snippets out of UI errors. Legacy model/thinking cross-process writes remain unlocked.
19
19
  - `auto` thinking follows main only when `/jarvis` follows the main model; pinned `/jarvis` models default to thinking `off`.
20
20
  - `follow-main` thinking follows the main thinking level regardless of model selection, except xAI `/jarvis` models force thinking `off`.
21
21
  - `/compact`, `/tree`, and `/new` entered inside `/jarvis` operate on the isolated `/jarvis` side-session, not the main Pi session.
@@ -34,6 +34,13 @@
34
34
  - Queue count excludes active work; processing includes boot and complete queue settlement. Keep activity separate from scrollback and never replay uncertain sends.
35
35
  - Bound overlay history (500 entries, 512K UTF-16 units total, 64K per entry) with explicit omission notices; never truncate persisted history.
36
36
 
37
+ ## Branding intro (1.6.1)
38
+ - The first overlay for each main-session ID in the loaded extension shows a 1.8-second neon/chrome ASCII sweep, then returns to the compact UI. Reopen, side `/new`, tree navigation, and returning to an already-seen main session must not replay it. Reload/restart resets this in-memory bookkeeping.
39
+ - The intro is decoration, never a boot/queue gate. Keep editor, permissions, and activity available. Input dismisses it without being consumed; paste framing still precedes shortcuts. Confirmations and warnings/errors preempt it.
40
+ - Use a bounded, unreferenced, lazily started timer; stop on dismissal, expiry, or disposal. No blinking, flashing, terminal-clearing commands, transcript entries, or persisted session changes.
41
+ - Suppress with `PI_JARVIS_NO_ANIMATION=1`, non-empty `NO_COLOR`, or `TERM=dumb`. Use compact/no intro on small terminals and readable palettes for light themes and 256-color output.
42
+ - `jarvis-branding.ts` owns the original wordmark. `npm run render:branding` regenerates README SVGs with local renderer fixtures, not live provider/session data. Label fixture previews honestly.
43
+
37
44
  ## Native MCP (1.6.0)
38
45
  - Use Pi's root-exported native factories, not private registry/runtime/transport internals. Jarvis owns separate configured-server connections; main-only extension registrations are not inherited.
39
46
  - No native startup/credential expansion while initially off. Respect project trust, enabled states, native tool exposures, and live Repo tools permission for direct/deferred/codemode/resource execution.
@@ -42,6 +49,17 @@
42
49
  - Keep server administration in main Pi. Disable codemode model helpers (`models: false`); preserve independent Note main/Redirect gates and the overlay-owned bridge subscription.
43
50
  - Tests use temporary agent/workspace directories and local fixture servers only; never start real user MCP servers or resolve real credentials during validation.
44
51
 
52
+ ## Shared memory (1.7.0)
53
+ - Main Pi and the isolated Jarvis SDK session explicitly mount one shared local service. Memory is enabled by default in trusted projects, independently of Repo tools, Note main, Redirect, and overlay open/close. It can share historical facts even when bridge delivery is off; it never steers or queues work.
54
+ - `/jarvis-memory` reports status; `help` documents controls. `[--global|--project] on|off|capture on|off|recall on|off|clear` controls default to GLOBAL (unlike model/thinking). Per-field project > global > defaults, except global enabled=false is a master kill switch. Untrusted projects and config errors pause all memory. Full off means no memory-record reads/capture/injection/tool execution; retain data. Explicit admin inspection still requires enabled memory; capture/recall-only pauses do not block manual commands.
55
+ - Inside the overlay, `/memory …` and `/jarvis-memory …` execute immediately without model/boot/queue work. `clear` removes settings, never data; `forget-all --confirm [--global|--all]` defaults to only the current project's records. Data scope flags follow the action.
56
+ - Disclose capture/recall before first use and only then persist the global disclosure marker. No silent historical import, background providers, embeddings, real user credential access, or real MCP servers during tests. Isolate every test's agent/workspace directories.
57
+ - Capture only new finalized user/assistant text, not thinking/tool/custom/system/attachment data or aborted/error output. Stage only event metadata (max 256 anchors); resolve at turn/settlement boundaries from at most 1,024 newly persisted parent-chain entries, stopping before the old leaf. Never archive intermediate message_end payloads before later redaction hooks. Discard pending anchors on revocation, session/tree change or disposal; never backfill. Secret filtering is best-effort, not a guarantee; reject suspected secrets in curated notes. Cap text at 16 KiB UTF-8; omit oversized archive captures, reject oversized notes. Archive retains newest 10,000 records; curated notes cap at 1,000 without automatic deletion.
58
+ - Keep auto recall scoped to global + canonical current cwd; explicit all-project search is supported. Request-local context injection is bounded to 6,000 bytes of untrusted record JSON plus notice; search results 12,000 bytes with excerpt/omission markers. Never persist automatically injected context via appendEntry/sendMessage or treat stored instructions as authority. Explicit tool calls/results still follow normal Pi persistence; don't promise that disabling/forgetting erases earlier tool results or already-viewed output.
59
+ - Store is lazy local SQLite under the active agent directory (`extensions/pi-jarvis-memory/memory.sqlite`), not a project-selected path. SQLite coordinates record writers; memory settings use atomic cooperative locking that legacy model/thinking writes do not participate in. Fail closed on malformed settings; never repair automatically.
60
+ - Memory guidance is also request-local: use a custom advisory so Pi's later forced-prompt projection cannot discard it. Preserve other prompt/tool state; a mid-turn disable removes both advisory and recalled records from future requests.
61
+ - Model tools recheck live trust/settings/cancellation and permission generations at execution, including captured definitions. Broadcast observed policy changes across mounted lanes and revoke per-binding generations at session/tree boundaries; don't promise live push delivery across processes. Model forget requires cancellable human review and transactionally compares the reviewed version. Tombstones prevent identical event/title resurrection, not every semantic mention; Pi transcripts, backups and already-sent context remain. Do not promise encryption, a sandbox, or forensic erasure.
62
+
45
63
  ## Git and Release Policy
46
64
  - Every new commit MUST have an annotated **stable version tag `vX.Y.Z`**. No `dev`, alpha, beta, release-candidate, build-metadata, or SHA-only tags. This is a released extension, not a prerelease channel.
47
65
  - Before committing, choose the next unused stable version and update package metadata, lockfile, README, and a dated changelog entry together. Tag every commit, including intermediate and merge commits; never leave a new commit untagged. Run `npm run check:tags`, then push the commit and version tag atomically. Do not move or replace existing tags or rewrite shared history.
package/README.md CHANGED
@@ -2,28 +2,51 @@
2
2
 
3
3
  <div align="center">
4
4
 
5
+ <img src="https://raw.githubusercontent.com/crustyhacker/pi-jarvis/main/docs/assets/jarvis-logo.svg" alt="JARVIS — Pi / A second lane of thought. Cyan, violet, and pink ASCII chrome." width="720">
6
+
5
7
  ## A cinematic side-conversation overlay for Pi
6
8
 
7
9
  **Open a second lane of thought without derailing the main session.**
8
10
 
9
11
  `pi-jarvis` adds `/jarvis`: a polished overlay where you can ask for status, inspect the repo when you explicitly allow it, and send a quiet note or a confirmed redirect back to the main lane.
10
12
 
13
+ [![CI](https://img.shields.io/github/actions/workflow/status/crustyhacker/pi-jarvis/ci.yml?branch=main&style=for-the-badge&label=CI)](https://github.com/crustyhacker/pi-jarvis/actions/workflows/ci.yml)
11
14
  [![npm version](https://img.shields.io/npm/v/pi-jarvis?style=for-the-badge&color=7c3aed)](https://www.npmjs.com/package/pi-jarvis)
12
15
  [![license](https://img.shields.io/badge/license-MIT-111827?style=for-the-badge)](./LICENSE)
13
16
  [![Pi extension](https://img.shields.io/badge/Pi-extension-06b6d4?style=for-the-badge)](https://github.com/crustyhacker/pi-jarvis)
14
17
  [![TypeScript](https://img.shields.io/badge/TypeScript-powered-2563eb?style=for-the-badge)](./package.json)
15
18
 
16
- <p><strong>Current version:</strong> 1.6.0</p>
19
+ <p><strong>Current version:</strong> 1.7.0</p>
17
20
 
18
21
  <p>
22
+ <strong>Shared persistent memory</strong> ·
19
23
  <strong>Persistent side session</strong> ·
20
24
  <strong>Live main-session awareness</strong> ·
21
- <strong>Permission-gated tools</strong> ·
25
+ <strong>Opt-in local tools + native MCP</strong> ·
22
26
  <strong>Safe redirect flow</strong>
23
27
  </p>
24
28
 
25
29
  </div>
26
30
 
31
+ <details>
32
+ <summary>Plain-text wordmark</summary>
33
+
34
+ ```text
35
+ _ _ ____ __ _____ ____
36
+ | | / \ | _ \\ \ / /_ _/ ___|
37
+ _ | | / _ \ | |_) |\ \ / / | |\___ \
38
+ | |_| |/ ___ \| _ < \ V / | | ___) |
39
+ \___//_/ \_\_| \_\ \_/ |___|____/
40
+
41
+ PI / A SECOND LANE OF THOUGHT
42
+ ```
43
+
44
+ </details>
45
+
46
+ ![Jarvis compact overlay, rendered with deterministic demo data](https://raw.githubusercontent.com/crustyhacker/pi-jarvis/main/docs/assets/jarvis-overlay.svg)
47
+
48
+ *Renderer preview with a custom dark palette and demo conversation—not a live provider session. Your Pi theme controls the normal overlay.*
49
+
27
50
  ---
28
51
 
29
52
  ## The pitch
@@ -55,12 +78,13 @@ The main Pi session should stay on the critical path.
55
78
 
56
79
  | Capability | What you get |
57
80
  |---|---|
81
+ | **Shared memory** | Main Pi and Jarvis remember useful discussions across sessions; enabled by default, with global/project controls and a master off switch |
58
82
  | **Persistent side lane** | `/jarvis` keeps its own isolated conversation state and restores prior side-session history |
59
83
  | **Live awareness** | Jarvis sees the current main-session summary plus a delta since the last `/jarvis` turn |
60
- | **Permission-gated tools** | Local `read`, `bash`, `edit`, and `write` stay off until you enable them |
84
+ | **Permission-gated tools** | Local `read`, `bash`, `edit`, `write`, and configured native MCP stay off until you enable Repo tools |
61
85
  | **Safe main-session handoff** | `Note main` is quiet; `Redirect` is confirmation-gated |
62
86
  | **Independent model control** | Follow the main model or pin `/jarvis` to a separate model |
63
- | **Cleaner UX** | Compact header, scrollable history, multiline drafts, and independent activity/queue feedback |
87
+ | **Cleaner UX** | A one-time neon ASCII intro, then compact diagnostics, scrollback, multiline drafts, and independent activity/queue feedback |
64
88
 
65
89
  ---
66
90
 
@@ -71,7 +95,10 @@ flowchart LR
71
95
  U[You] -->|primary work| M[Main Pi session]
72
96
  U -->|open /jarvis| J[Jarvis overlay]
73
97
  M -->|summary + recent delta| J
98
+ M <-->|independent memory controls| S[Shared local memory]
99
+ J <-->|independent memory controls| S
74
100
  J -->|Repo tools enabled| R[Local tools\nread • bash • edit • write]
101
+ J -->|Repo tools enabled| C[Configured native MCP\nside-owned connections]
75
102
  J -. Note main .-> M
76
103
  J -. Redirect after confirmation .-> M
77
104
  ```
@@ -125,6 +152,8 @@ Requires **Pi 1.0.0** and **Node.js 22.19.0 or newer**. Version **1.6.0** suppor
125
152
  ### 2) Restart or reload Pi
126
153
 
127
154
  `pi install` registers the package automatically. For local development, build and load `./dist/index.js` with `pi -e ./dist/index.js`.
155
+ **New in 1.7.0: shared memory is enabled by default in trusted projects**, including main Pi even if you never open the overlay. A first-use notice explains capture and recall. Already using another memory extension? Run `/jarvis-memory off` before your first prompt; this disables both main and Jarvis memory without deleting anything.
156
+
128
157
  ### 3) Open Jarvis
129
158
 
130
159
  ```bash
@@ -139,8 +168,8 @@ Or open it and send the first message immediately:
139
168
 
140
169
  ### 4) Turn on more power only when you want it
141
170
 
142
- - leave `Repo tools` off for pure context / analysis
143
- - turn `Repo tools` on when you want local `read`, `bash`, `edit`, and `write`
171
+ - leave `Repo tools` off for context / analysis without repository or MCP access; shared memory has separate controls
172
+ - turn `Repo tools` on when you want local `read`, `bash`, `edit`, `write`, and configured native MCP capabilities
144
173
  - turn `Note main` on when you want Jarvis to quietly message the main session
145
174
  - turn `Redirect` on when you want Jarvis to propose a redirect that you still explicitly confirm
146
175
 
@@ -175,6 +204,9 @@ Sets the thinking level used by `/jarvis` without changing the main session thin
175
204
  ### `/jarvis-thinking [--project|--global] clear`
176
205
  Removes the selected scope so `/jarvis` thinking falls back through the remaining config layers to the built-in `auto` default.
177
206
 
207
+ ### `/jarvis-memory`
208
+ Reports shared-memory status. Use `/jarvis-memory help` for controls and data-management commands. Memory controls default to **global**, unlike model/thinking controls. See [Shared memory](#shared-memory) below.
209
+
178
210
  ### Side-session commands inside `/jarvis`
179
211
  The `/jarvis` input handles a small set of built-in commands against the isolated side-session:
180
212
 
@@ -183,6 +215,74 @@ The `/jarvis` input handles a small set of built-in commands against the isolate
183
215
  - `/tree <entry-id>` navigates the `/jarvis` session tree to that entry.
184
216
  - `/tree --summarize <entry-id> [instructions]` navigates and summarizes the branch being left.
185
217
  - `/new` starts a fresh `/jarvis` side-session without changing the main Pi session.
218
+ - `/memory …` or `/jarvis-memory …` manages shared memory immediately, without sending a model prompt or waiting for queued side work. Initial forms such as `/jarvis /memory off` are also handled locally, without booting a side session.
219
+
220
+ ---
221
+
222
+ ## Shared memory
223
+
224
+ Main Pi and Jarvis use **one local memory service**, independent of the overlay lifecycle. Useful Jarvis discussions can inform a later main session and vice versa—even when `Note main` is off. Memory does not steer or queue messages into the other session; it supplies historical context when recalled. Close/reopen, `/new`, and project changes do not erase it.
225
+
226
+ ### What is remembered
227
+
228
+ - **Conversation archive:** only newly finalized user/assistant text observed after loading this feature, labeled with project, main/Jarvis lane, session ID, event identity and timestamps. No silent historical import or reconstruction from old session files.
229
+ - **Curated notes:** your active model can save concise preferences, corrections, project decisions and references during normal foreground work. Stable scoped titles update/deduplicate notes. You can save or edit notes explicitly too. Curation depends on the model choosing the tool; it is not a separate background summarizer.
230
+ - **Bounded recall:** a small request-local selection of global/current-project notes and matching conversation excerpts, using local keyword search. Other projects are available through explicit `search --all` or the model's cross-project search tool. Project scope uses the canonical working directory, not a remote repository name; separate worktrees remain separate scopes unless a note is global.
231
+
232
+ There are **no embeddings, background model calls, telemetry, or memory-server connections**. Retrieval and saving tools can add normal foreground model turns/tokens. Recalled text is sent to the active model as untrusted historical data, not instructions. Automatic recall is capped at 6,000 UTF-8 bytes of record JSON plus a short notice; tool search results are capped at 12,000 bytes with explicit excerpt/omission markers. Automatically injected memory guidance and recall are request-local, not appended to Pi's persisted transcript. Explicit memory-tool calls/results are recorded normally by Pi and may contain saved facts; model replies may repeat them too.
233
+
234
+ ### Controls
235
+
236
+ ```text
237
+ /jarvis-memory # status, without reading stored memories
238
+ /jarvis-memory off # global MASTER OFF for main + Jarvis
239
+ /jarvis-memory on # enable globally; project restrictions still apply
240
+ /jarvis-memory capture off # saving default off (project overrides apply)
241
+ /jarvis-memory recall off # recall default off (project overrides apply)
242
+ /jarvis-memory --project off # pause memory in this project
243
+ /jarvis-memory --project clear # remove this project's memory settings
244
+ /jarvis-memory --global clear # remove global settings, not stored data
245
+ ```
246
+
247
+ `enabled`, `capture`, and `recall` default to `true`. Each field resolves project → global → default, **except global `enabled: false` is a master switch that no project can override**. Untrusted projects and unreadable/malformed settings pause all memory. Use `--project capture off` or `--project recall off` to pause that capability specifically here; inspect status for the effective setting. The full off switch means no capture, memory-record reads, injection, tool execution, or background work; existing data remains on disk. Even inspection requires re-enabling memory. Explicit management commands still work with only capture or recall turned off. Turning memory off does not erase facts/tool results already in the current conversation or already-viewed output.
248
+
249
+ Controls share the existing settings files and preserve model/thinking/unknown keys:
250
+
251
+ ```json
252
+ {
253
+ "memory": { "enabled": false }
254
+ }
255
+ ```
256
+
257
+ Place this in `<agentDir>/extensions/pi-jarvis.json` to disable memory before installation/startup (normally `~/.pi/agent/extensions/pi-jarvis.json`; honors `PI_CODING_AGENT_DIR`). Project overrides live in `.pi/jarvis.json`. Memory settings writes are atomic and use a bounded cooperative lock; legacy model/thinking writers do not share that lock, so avoid concurrent configuration changes. Corrupt shared settings are never automatically repaired or overwritten—even by model/thinking set or clear commands. Repair the JSON manually while preserving privacy settings. A crashed config writer can leave a `.memory.lock` file; remove it only after confirming no writer is running.
258
+
259
+ ### Inspect, edit and forget
260
+
261
+ ```text
262
+ /jarvis-memory list # recent global/current-project records
263
+ /jarvis-memory search deployment # local keyword search
264
+ /jarvis-memory search --all deployment # explicitly search every project
265
+ /jarvis-memory show <id>
266
+ /jarvis-memory remember --global Answer style | Prefer concise answers.
267
+ /jarvis-memory remember Build choice | This project uses npm, not pnpm.
268
+ /jarvis-memory edit <id> Replacement fact, preserving the note's scope/title.
269
+ /jarvis-memory forget <id>
270
+ /jarvis-memory forget-all --confirm # this project's records only
271
+ /jarvis-memory forget-all --confirm --global
272
+ /jarvis-memory forget-all --confirm --all
273
+ ```
274
+
275
+ Put data scope flags **after the action**. `list --global` and `search --global …` restrict results to global records; `show --all <id>` and `forget --all <id>` explicitly allow another project's record. Lists and searches are bounded; narrow your query to find older records. Model-requested deletion is limited to one current/global record and requires human confirmation; commands above are explicit user actions. Confirmation is cancelled on observed permission change, abort or disposal, and a concurrently changed record must be reviewed again. Settings are rechecked at operation boundaries; other processes do not receive a live push notification.
276
+
277
+ ### Storage and privacy
278
+
279
+ The store is `<agentDir>/extensions/pi-jarvis-memory/memory.sqlite`, with SQLite transaction/WAL coordination across processes. It is opened lazily; Node 22/24 may print an experimental SQLite warning on first actual use. On POSIX, the owned directory is mode `0700` and database mode `0600`; this is **local plaintext, not encryption or a sandbox**. Backups of your agent directory may include it.
280
+
281
+ Only newly finalized visible text is captured—not thinking blocks, tool results/calls, images, custom/system messages, failed/aborted assistant outputs, or old session files. Metadata-only event anchors are resolved after Pi's message-finalization/redaction hooks, at turn/settlement boundaries. Pending captures are discarded on permission/session changes or disposal, not replayed after re-enable. Recognizable credential blocks are omitted and common secret formats redacted, but **filtering is best-effort and cannot detect every sensitive detail**. Pause capture or disable memory for sensitive work. Notes containing detected secrets are rejected rather than silently changed. Oversized captures (over 16 KiB UTF-8) are omitted, not truncated into misleading facts; curated-note writes over that limit fail explicitly.
282
+
283
+ Retention is bounded to the newest 10,000 captured messages and 1,000 curated notes. Archive rollover never truncates Pi's original history; notes are not automatically discarded at their limit. Forgetting tombstones the record identity so the same captured event/scoped note title is not automatically restored; an explicit `remember` command can restore a forgotten title. This is not semantic erasure of every mention: other records, original Pi transcripts, already-sent model context and backups may still contain the fact. SQLite deletion is logical, **not forensic secure erasure**.
284
+
285
+ The combined live-record/tombstone budget is 100,000 identities: new identity saves fail at capacity rather than dropping deletion markers; existing records always reserve room for forgetting. First database open performs synchronous integrity checks and can briefly pause on a large archive. SQLite WAL files can temporarily grow while another process holds a reader snapshot; there is no strict total-directory disk quota. To completely reset/delete this local store without re-enabling memory, stop every Pi process using it, then remove only the `pi-jarvis-memory` directory yourself. This also removes tombstones, not original Pi transcripts.
186
286
 
187
287
  ---
188
288
 
@@ -208,7 +308,7 @@ Model and thinking settings resolve through the same config layers, then fall ba
208
308
  2. global config: `~/.pi/agent/extensions/pi-jarvis.json` or the equivalent path under a custom Pi agent dir
209
309
  3. built-in defaults: model `follow-main`, thinking `auto`
210
310
 
211
- Global writes do not displace an existing project override. Config writes use same-directory atomic replacement and preserve unrelated keys; unreadable files are never treated as malformed JSON and overwritten. Malformed JSON can still be explicitly cleared or replaced. Avoid simultaneous configuration writes from multiple Pi processes: cross-process locking is not implemented.
311
+ Global writes do not displace an existing project override. Config writes use same-directory atomic replacement and preserve unrelated keys; unreadable files are never treated as malformed JSON and overwritten. Malformed JSON must be manually repaired: set/clear commands will not replace or delete a corrupt shared file and risk resetting memory privacy controls. Avoid simultaneous configuration writes from multiple Pi processes: cross-process locking is not implemented.
212
312
 
213
313
  ---
214
314
 
@@ -226,6 +326,14 @@ The overlay header exposes three controls, all **off by default**:
226
326
 
227
327
  Long redirects are paged: review every page with Up/Down or PageUp/PageDown before pressing Y. Resize if the terminal is too small to review safely. Configured Pi selection keybindings are respected.
228
328
 
329
+ ### First-open neon intro
330
+
331
+ The first `/jarvis` open for each main-session ID shows the ASCII wordmark with a **1.8-second cyan/violet/pink chrome sweep**. It is decorative, not a loading screen: startup and queued prompts continue normally, and the editor and permission controls remain usable. Type or paste to dismiss it immediately; your input is preserved. Escape still closes the overlay. Confirmation review and warnings/errors take priority.
332
+
333
+ Reopening Jarvis, side `/new`, tree navigation, and returning to a previously opened main session do not replay it. The once-per-session memory lives in the loaded extension; restarting Pi or `/reload` resets it. Small terminals use a compact wordmark or skip the intro entirely. Light themes and 256-color terminals are supported; there is no flashing or terminal blinking.
334
+
335
+ To skip the intro, start Pi with `PI_JARVIS_NO_ANIMATION=1`. A non-empty `NO_COLOR` or `TERM=dumb` also suppresses it. These switches affect the intro, not Pi's other animations or colors.
336
+
229
337
  ### Keyboard and drafts
230
338
 
231
339
  Version **1.5.0** adds compact diagnostics, scrollback, and a multiline draft editor.
@@ -246,7 +354,7 @@ The compact header keeps main status, the side model, main focus, and permission
246
354
 
247
355
  The multiline editor uses Pi's public editor and configured editing keybindings. Up/Down move within a draft; Up at the beginning of the first line (or in an empty editor) recalls prompts. Down past recalled prompts restores the draft. Pasted indentation and newlines are preserved, with Pi's normal tab-to-spaces normalization. Oversized drafts (over 64 KiB) and terminal-control payloads are rejected explicitly, never silently truncated or sent.
248
356
 
249
- Unsent drafts survive closing and reopening `/jarvis` in the same running Pi session. They are not saved to disk. Side `/new`, main-session replacement, and switching to an unrelated side-session reference clear them; navigating the side tree only resets the transcript view. Closing still revokes every permission.
357
+ Unsent drafts survive closing and reopening `/jarvis` in the same running Pi session. They are not saved to disk. Side `/new`, main-session replacement, and switching to an unrelated side-session reference clear them; navigating the side tree only resets the transcript view. Closing still revokes all three overlay permissions; shared memory follows its separate persistent controls.
250
358
 
251
359
  Scrollback follows new output until you scroll up. To bound rendering work, the overlay retains up to 500 recent entries and 512K UTF-16 code units of source text, with a 64K-unit per-entry limit. Omitted content is marked explicitly; these display limits do not modify persisted conversation history. Resizing preserves the reading position on a best-effort basis.
252
360
 
@@ -398,6 +506,14 @@ Check the mandatory annotated **version-number** tag policy for committed histor
398
506
  npm run check:tags
399
507
  ```
400
508
 
509
+ Regenerate the shared logo and actual-renderer demo artwork after visual changes:
510
+
511
+ ```bash
512
+ npm run render:branding
513
+ ```
514
+
515
+ This uses deterministic fixtures, without opening a terminal, calling a provider, or connecting to MCP servers.
516
+
401
517
  ### Release automation
402
518
 
403
519
  GitHub Actions validate branch pushes and pull requests on Node 22.19.0 and 24. They require an annotated **stable `vX.Y.Z` tag** on every reachable post-policy-baseline commit and run tests, build, and package verification. Every commit bumps the matching package and documentation versions; prerelease (`dev`, alpha, beta, RC), build-metadata, and SHA-only tags do not qualify. Fork PR jobs are read-only.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,YAAY,EAGjB,MAAM,iCAAiC,CAAC;AAkGzC,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAwhB9D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEN,KAAK,YAAY,EAGjB,MAAM,iCAAiC,CAAC;AAqGzC,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA4iB9D"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
+ import { getAgentDir, } from "@earendil-works/pi-coding-agent";
2
3
  import { JarvisModelPicker } from "./model-picker.js";
3
4
  import { buildMainSessionContext } from "./main-context.js";
4
5
  import { MainSessionTracker } from "./main-session-state.js";
@@ -6,6 +7,8 @@ import { attachOverlayBridge, JarvisOverlayBridge, JarvisOverlayComponent } from
6
7
  import { createJarvisSessionRef, readJarvisSessionRef, JARVIS_SESSION_REF_CUSTOM_TYPE } from "./session-ref.js";
7
8
  import { MalformedJarvisConfigError, clearJarvisModelSelectionSetting, clearJarvisThinkingSelectionSetting, loadJarvisModelSelectionSetting, loadJarvisThinkingSelectionSetting, saveJarvisModelSelectionSetting, saveJarvisThinkingSelectionSetting, } from "./jarvis-config.js";
8
9
  import { JarvisSideSessionRuntime, createSideSessionFile } from "./side-session.js";
10
+ import { SharedMemoryService } from "./memory-service.js";
11
+ import { createMemoryExtensionFactory } from "./memory-extension.js";
9
12
  class StaleJarvisBootError extends Error {
10
13
  constructor() {
11
14
  super("/jarvis startup was superseded by a newer session lifecycle event.");
@@ -16,9 +19,13 @@ function isStaleJarvisBootError(error) {
16
19
  return error instanceof StaleJarvisBootError;
17
20
  }
18
21
  export default function jarvisExtension(pi) {
22
+ // Presentation-only memory, keyed by MAIN identity, never by the side tree.
23
+ // Reopening or returning to a session does not replay the intro.
24
+ const introSeenSessions = new Set();
19
25
  const mainSession = new MainSessionTracker();
20
26
  const state = {
21
27
  bridge: new JarvisOverlayBridge(),
28
+ memory: new SharedMemoryService(getAgentDir()),
22
29
  mainSession,
23
30
  mainContext: buildMainSessionContext(mainSession.snapshot()),
24
31
  lastJarvisSeenMainContext: undefined,
@@ -43,6 +50,11 @@ export default function jarvisExtension(pi) {
43
50
  ctx.ui.notify("/jarvis requires Pi's interactive terminal UI.", "warning");
44
51
  return;
45
52
  }
53
+ const memoryRequest = parseMemoryCommand(args);
54
+ if (memoryRequest !== undefined) {
55
+ dispatchMemoryCommand(state, memoryRequest, ctx, Boolean(state.overlayOpen));
56
+ return;
57
+ }
46
58
  if (state.overlayOpen) {
47
59
  ctx.ui.notify("/jarvis is already open.", "info");
48
60
  return;
@@ -75,7 +87,10 @@ export default function jarvisExtension(pi) {
75
87
  queueMicrotask(() => tui.requestRender());
76
88
  };
77
89
  state.closeOverlay = closeOverlay;
78
- return attachOverlayBridge(new JarvisOverlayComponent(tui, theme, state.bridge, overlayView, closeOverlay, keybindings), state.bridge, tui);
90
+ const sessionId = ctx.sessionManager.getSessionId();
91
+ const component = attachOverlayBridge(new JarvisOverlayComponent(tui, theme, state.bridge, overlayView, closeOverlay, keybindings, { showIntro: !introSeenSessions.has(sessionId) }), state.bridge, tui);
92
+ introSeenSessions.add(sessionId);
93
+ return component;
79
94
  }, {
80
95
  overlay: true,
81
96
  overlayOptions: {
@@ -314,6 +329,10 @@ export default function jarvisExtension(pi) {
314
329
  ctx.ui.notify(`Set /jarvis thinking to ${formatJarvisThinkingSelection(selection)} ${scopeLabel}. Effective /jarvis thinking is ${getDesiredJarvisThinkingLevel(state) ?? "off"}.`, "info");
315
330
  },
316
331
  });
332
+ pi.registerCommand("jarvis-memory", {
333
+ description: "Shared main Pi/Jarvis memory: status, on/off, capture/recall, search, remember, edit, forget (help for syntax)",
334
+ handler: async (args, ctx) => { dispatchMemoryCommand(state, args, ctx, false); },
335
+ });
317
336
  pi.on("session_start", async (_event, ctx) => {
318
337
  state.closeOverlay?.();
319
338
  state.bootGeneration += 1;
@@ -464,6 +483,7 @@ export default function jarvisExtension(pi) {
464
483
  // hang while the session is torn down.
465
484
  state.bridge.reset();
466
485
  });
486
+ createMemoryExtensionFactory(state.memory, "main")(pi);
467
487
  }
468
488
  function updateContextState(pi, state, ctx) {
469
489
  state.model = ctx.model;
@@ -829,6 +849,32 @@ function queueMessage(state, message) {
829
849
  state.queuedMessages.push(message);
830
850
  state.bridge.refresh();
831
851
  }
852
+ function parseMemoryCommand(message) {
853
+ const match = /^\/(?:jarvis-memory|memory)(?:\s+([\s\S]*))?$/.exec(message.trim());
854
+ return match ? match[1] ?? "" : undefined;
855
+ }
856
+ function dispatchMemoryCommand(state, args, ctx, overlay) {
857
+ try {
858
+ const text = state.memory.command(args, ctx);
859
+ if (overlay && state.runtime)
860
+ state.runtime.addSystemMessage(text);
861
+ else if (overlay)
862
+ state.bridge.notify(text, "info");
863
+ else if (ctx.hasUI)
864
+ ctx.ui.notify(text, "info");
865
+ else
866
+ process.stderr.write(`${text}\n`);
867
+ }
868
+ catch (error) {
869
+ const text = error instanceof Error ? error.message : "Shared memory operation failed.";
870
+ if (overlay)
871
+ state.bridge.notify(text, "error");
872
+ else if (ctx.hasUI)
873
+ ctx.ui.notify(text, "error");
874
+ else
875
+ process.stderr.write(`${text}\n`);
876
+ }
877
+ }
832
878
  function parseJarvisSideCommand(message) {
833
879
  const text = message.trim();
834
880
  if (text === "/new") {
@@ -907,6 +953,12 @@ function createOverlayView(pi, state, ctx) {
907
953
  sendMessage: async (text) => {
908
954
  if (state.queuedMessages !== queue)
909
955
  return;
956
+ // Memory controls must work immediately, even while a side turn is busy.
957
+ const memoryCommand = parseMemoryCommand(text);
958
+ if (memoryCommand !== undefined) {
959
+ dispatchMemoryCommand(state, memoryCommand, ctx, true);
960
+ return;
961
+ }
910
962
  queueMessage(state, text);
911
963
  if (state.queuedMessages !== queue)
912
964
  return;
@@ -1058,6 +1110,8 @@ async function ensureRuntime(pi, state, ctx) {
1058
1110
  bridge: state.bridge,
1059
1111
  cwd: ctx.cwd,
1060
1112
  projectTrusted: ctx.isProjectTrusted(),
1113
+ memory: state.memory,
1114
+ memoryTrustProvider: () => isCurrentBoot() && ctx.isProjectTrusted(),
1061
1115
  modelRegistry: ctx.modelRegistry,
1062
1116
  model: getDesiredJarvisModel(state),
1063
1117
  jarvisModelModeProvider: () => state.jarvisModelSelection.mode,