@xingular/harness 0.1.6 → 0.1.7

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 (133) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/NOTICE.md +38 -0
  3. package/README.md +118 -26
  4. package/dist/cli.js +6106 -912
  5. package/dist/terminal-pi.js +462 -11
  6. package/docs/README.md +12 -0
  7. package/docs/decisions/ADR-0001-owned-terminal.md +87 -0
  8. package/docs/evidence/terminal-2026-10-17/120x40-completed-transcript.ansi.gz +0 -0
  9. package/docs/evidence/terminal-2026-10-17/40x20-settings-interaction.ansi.gz +0 -0
  10. package/docs/evidence/terminal-2026-10-17/40x20-settings-keyboard.ansi.gz +0 -0
  11. package/docs/evidence/terminal-2026-10-17/40x20-welcome.ansi.gz +0 -0
  12. package/docs/evidence/terminal-2026-10-17/80x24-approval-0.ansi.gz +0 -0
  13. package/docs/evidence/terminal-2026-10-17/80x24-question.ansi.gz +0 -0
  14. package/docs/evidence/terminal-2026-10-17/verification.json +130 -0
  15. package/docs/evidence/terminal-2026-10-17-followup/120x40-completed-transcript.ansi.gz +0 -0
  16. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-interaction.ansi.gz +0 -0
  17. package/docs/evidence/terminal-2026-10-17-followup/40x20-settings-keyboard.ansi.gz +0 -0
  18. package/docs/evidence/terminal-2026-10-17-followup/40x20-welcome.ansi.gz +0 -0
  19. package/docs/evidence/terminal-2026-10-17-followup/80x24-approval-0.ansi.gz +0 -0
  20. package/docs/evidence/terminal-2026-10-17-followup/80x24-plugin-light.ansi.gz +0 -0
  21. package/docs/evidence/terminal-2026-10-17-followup/80x24-question-batch.ansi.gz +0 -0
  22. package/docs/evidence/terminal-2026-10-17-followup/80x24-question.ansi.gz +0 -0
  23. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-approval-0.ansi.gz +0 -0
  24. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-plugin-light.ansi.gz +0 -0
  25. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question-batch.ansi.gz +0 -0
  26. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/80x24-question.ansi.gz +0 -0
  27. package/docs/evidence/terminal-2026-10-17-followup/app-bundle/verification.json +95 -0
  28. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-approval-0.ansi.gz +0 -0
  29. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-plugin-light.ansi.gz +0 -0
  30. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question-batch.ansi.gz +0 -0
  31. package/docs/evidence/terminal-2026-10-17-followup/global-install/80x24-question.ansi.gz +0 -0
  32. package/docs/evidence/terminal-2026-10-17-followup/global-install/README.md +27 -0
  33. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command-80x24.ansi.gz +0 -0
  34. package/docs/evidence/terminal-2026-10-17-followup/global-install/shell-command.json +18 -0
  35. package/docs/evidence/terminal-2026-10-17-followup/global-install/verification.json +95 -0
  36. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-80x24.json.gz +0 -0
  37. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-final-80x24.json.gz +0 -0
  38. package/docs/evidence/terminal-2026-10-17-followup/harness-reference-scenario.json +60 -0
  39. package/docs/evidence/terminal-2026-10-17-followup/live-codex/README.md +24 -0
  40. package/docs/evidence/terminal-2026-10-17-followup/live-codex/complete-80x24.ansi.gz +0 -0
  41. package/docs/evidence/terminal-2026-10-17-followup/live-codex/verification.json +57 -0
  42. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24-early.json.gz +0 -0
  43. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-80x24.json.gz +0 -0
  44. package/docs/evidence/terminal-2026-10-17-followup/omp-reference-scenario.json +58 -0
  45. package/docs/evidence/terminal-2026-10-17-followup/omp-supplemental-static.json.gz +0 -0
  46. package/docs/evidence/terminal-2026-10-17-followup/rea-artifacts.json +320 -0
  47. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.json +30 -0
  48. package/docs/evidence/terminal-2026-10-17-followup/reference-comparison.md +133 -0
  49. package/docs/evidence/terminal-2026-10-17-followup/reference-source-observations.json +20 -0
  50. package/docs/evidence/terminal-2026-10-17-followup/verification.json +207 -0
  51. package/docs/terminal-tui.md +254 -0
  52. package/package.json +8 -2
  53. package/src/accounts/accounts.test.ts +110 -0
  54. package/src/accounts/accounts.ts +146 -10
  55. package/src/cli.ts +7 -3
  56. package/src/harness.ts +16 -3
  57. package/src/hub/catalog.json +123 -0
  58. package/src/hub/cli.ts +59 -0
  59. package/src/hub/hub.test.ts +205 -0
  60. package/src/hub/hub.ts +256 -0
  61. package/src/hub/schema.ts +81 -0
  62. package/src/index.ts +6 -1
  63. package/src/memory/api.ts +16 -2
  64. package/src/memory/blocks.ts +3 -1
  65. package/src/memory/caller.ts +13 -1
  66. package/src/memory/curation.test.ts +163 -0
  67. package/src/memory/curation.ts +64 -0
  68. package/src/memory/maintenance.ts +199 -11
  69. package/src/memory/operations.ts +12 -0
  70. package/src/memory/proposals.ts +16 -8
  71. package/src/memory/recall.test.ts +11 -0
  72. package/src/memory/recall.ts +9 -2
  73. package/src/server/methods.ts +37 -2
  74. package/src/sessions/contracts.ts +29 -3
  75. package/src/sessions/conversation.test.ts +27 -0
  76. package/src/sessions/policy.ts +4 -0
  77. package/src/sessions/questionBatches.test.ts +110 -0
  78. package/src/sessions/registry.ts +109 -22
  79. package/src/sessions/runner.ts +36 -1
  80. package/src/sessions/sessions.test.ts +95 -1
  81. package/src/sessions/sessions.ts +53 -9
  82. package/src/skills/registry.ts +16 -10
  83. package/src/terminal/accountsMenu.test.ts +225 -0
  84. package/src/terminal/accountsMenu.ts +382 -0
  85. package/src/terminal/control.test.ts +23 -0
  86. package/src/terminal/control.ts +23 -0
  87. package/src/terminal/controller.ts +68 -4
  88. package/src/terminal/hubMenu.ts +24 -0
  89. package/src/terminal/launch.test.ts +5 -14
  90. package/src/terminal/launch.ts +2 -42
  91. package/src/terminal/piExtension.lifecycle.test.ts +55 -0
  92. package/src/terminal/piExtension.ts +50 -1
  93. package/src/terminal/socket.ts +13 -2
  94. package/src/terminal/standalone.test.ts +37 -0
  95. package/src/terminal/standalone.ts +16 -7
  96. package/src/terminal/terminal.test.ts +70 -1
  97. package/src/terminal/terminals.ts +122 -12
  98. package/src/terminal/tui/application.test.ts +114 -0
  99. package/src/terminal/tui/application.ts +491 -0
  100. package/src/terminal/tui/commands.test.ts +218 -0
  101. package/src/terminal/tui/commands.ts +361 -0
  102. package/src/terminal/tui/dialogs.ts +301 -0
  103. package/src/terminal/tui/editor.test.ts +84 -0
  104. package/src/terminal/tui/editor.ts +79 -0
  105. package/src/terminal/tui/keybindings.test.ts +22 -0
  106. package/src/terminal/tui/keybindings.ts +50 -0
  107. package/src/terminal/tui/piAdapter.ts +62 -0
  108. package/src/terminal/tui/presentation.test.ts +79 -0
  109. package/src/terminal/tui/questions.test.ts +41 -0
  110. package/src/terminal/tui/questions.ts +47 -0
  111. package/src/terminal/tui/runtime.socket.test.ts +104 -0
  112. package/src/terminal/tui/runtime.test.ts +215 -0
  113. package/src/terminal/tui/runtime.ts +388 -0
  114. package/src/terminal/tui/sessionUi.ts +24 -0
  115. package/src/terminal/tui/settings.test.ts +150 -0
  116. package/src/terminal/tui/settings.ts +188 -0
  117. package/src/terminal/tui/status.test.ts +70 -0
  118. package/src/terminal/tui/status.ts +109 -0
  119. package/src/terminal/tui/theme.ts +174 -0
  120. package/src/terminal/tui/tools.test.ts +145 -0
  121. package/src/terminal/tui/tools.ts +142 -0
  122. package/src/terminal/tui/transcript.test.ts +25 -0
  123. package/src/terminal/tui/transcript.ts +124 -0
  124. package/src/terminal/tui/ui.test.ts +313 -0
  125. package/src/terminal/tui/ui.ts +166 -0
  126. package/src/terminal/tui/welcome.ts +102 -0
  127. package/src/tools/askUser.test.ts +69 -0
  128. package/src/tools/askUser.ts +31 -17
  129. package/src/tools/maintenance.ts +24 -0
  130. package/src/tools/memoryTools.ts +1 -1
  131. package/src/tools/registryWrite.test.ts +101 -0
  132. package/src/tools/registryWrite.ts +182 -0
  133. package/src/tools/spawnSubagent.ts +92 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ - Harness owns the standalone terminal frontend, using persistent Pi 1.2.0 sessions and the inspected Oh My Pi 18.11.3 presentation.
6
+ - Add titanium and light themes, native session navigation, local command help and completion, account/plugin/Hub controls, and trusted extension UI hosting.
7
+ - Keep account isolation, exact prepared context and resource selection, the final tool gate, native histories and Harness run recording.
8
+ - Support grouped questions with atomic answers, cancellation and restored draft focus.
9
+ - Isolate stale plugin UI callbacks across session replacement and resource reload; restore terminal modes after fatal asynchronous failures and cleanup errors.
10
+
11
+ Implementation and verification limits are recorded in [the terminal reference](docs/terminal-tui.md).
package/NOTICE.md ADDED
@@ -0,0 +1,38 @@
1
+ # Third-party notices
2
+
3
+ The Harness terminal presentation adapts the titanium color palette, five-row Pi logo,
4
+ diagonal gradient and related terminal presentation conventions from Oh My Pi 18.11.3,
5
+ particularly `@oh-my-pi/pi-tui/src/theme/defaults/titanium.json` and
6
+ `@oh-my-pi/pi-tui/src/prompt/welcome.ts`.
7
+
8
+ Upstream: https://github.com/can1357/oh-my-pi
9
+
10
+ The adapted portions are included under the following upstream license. Harness-specific
11
+ product identity and runtime integration are maintained in this package. Dependencies retain
12
+ their own licenses and notices.
13
+
14
+ ```text
15
+ MIT License
16
+
17
+ Copyright (c) 2025 Mario Zechner
18
+ Copyright (c) 2025-2026 Can Bölük
19
+ Copyright (c) 2026 Stencil Labs, Inc.
20
+
21
+ Permission is hereby granted, free of charge, to any person obtaining a copy
22
+ of this software and associated documentation files (the "Software"), to deal
23
+ in the Software without restriction, including without limitation the rights
24
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
+ copies of the Software, and to permit persons to whom the Software is
26
+ furnished to do so, subject to the following conditions:
27
+
28
+ The above copyright notice and this permission notice shall be included in all
29
+ copies or substantial portions of the Software.
30
+
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
+ SOFTWARE.
38
+ ```
package/README.md CHANGED
@@ -13,10 +13,18 @@ needs to work for someone over time, and nothing about any particular applicatio
13
13
  | Plugins | `src/plugins/` | What a Pi session loads, chosen by the harness and never by Pi's own discovery; trust for a working folder's code; the list of every plugin and what reaches one caller. |
14
14
  | Tools | `src/tools/` | Tool definitions, the memory tools, `ask_user`; a gate that asks the application's policy, then standing approvals, then the person. |
15
15
  | Connected apps | `src/mcp/` | MCP connections, OAuth, per-session grants, redaction, a trace of what each call returned. |
16
- | Terminal | `src/terminal/` | Interactive Pi sessions with isolated accounts, compiled instructions, a telemetry and tool extension, and the session socket with the `xagent-wiki` and `xagent-mcp` commands. |
16
+ | Terminal | `src/terminal/` | A Harness-owned terminal frontend over persistent Pi sessions, isolated accounts, compiled instructions, the tool gate and telemetry bridge, native history, plugin UI, `/plugins`, `/hub`, `/accounts`, and the existing session socket. |
17
17
  | Server | `src/server/` | The same API over newline-delimited JSON, for a host that is not a Node program. |
18
18
 
19
19
  It was split out of Xingular Agent, which is now an application built on it.
20
+ The [documentation index](docs/README.md) links current terminal architecture and decisions.
21
+
22
+ ### Session options for applications
23
+
24
+ - `subagents: { maxDepth }` offers `spawn_subagent`: the model may start a child run of the same caller (`relation: 'subagent'`). The child has no more tools than the parent and settles before the tool returns.
25
+ - `providers: false` runs a session with the harness's own tools only.
26
+ - On the caller, `vaultAccess: 'propose'` writes no memory directly, and `recallExcludeAgents` hides those agents' conversations from recall.
27
+ - `maintenanceRunTrigger: false` (a harness option) leaves memory to explicit proposals and scheduled merges.
20
28
 
21
29
  ## Using it from Node
22
30
 
@@ -64,9 +72,14 @@ An application adds what it knows through six points:
64
72
  The harness provides the web tools itself: `webTools({ secrets })` gives `web_search` (Brave Search,
65
73
  key read from the secret store) and `web_fetch` (checked reads of public pages). An application
66
74
  passes it to `harness.sessions.provide` and switches the names on for each agent.
75
+ `registryTools({ harness })` gives `registry_write` (a skill, rule, or prompt) and `plugin_write`
76
+ (a plugin). Each writes for the calling agent only: the item is on for that agent, and a plugin's
77
+ code is trusted once written. An item others already use goes to the Inbox instead.
67
78
  3. **`ToolPolicy`**. `scope` says whether a call is inside what the run may do (or needs one
68
- approval); `authorize` says whether the tool is still switched on; `approval` adds facts for
69
- standing approvals; `connections` narrows the connected apps a session reaches.
79
+ approval). A decision with `humanOnly` is for a person alone: the always-approve switch and
80
+ remembered answers do not apply to it. `authorize` says whether the tool is still switched on;
81
+ `approval` adds facts for standing approvals; `connections` narrows the connected apps a session
82
+ reaches.
70
83
  4. **`SecretStore`**. Where credentials live (a keychain, a vault). Keys are
71
84
  `<account id>/<name>`.
72
85
  5. **`Directory`**. Names for the application's ids, shown in what the harness writes.
@@ -111,8 +124,10 @@ working folder brings.
111
124
  does nothing. A tool an extension registered is offered to the model and asks before every
112
125
  call. A command it registered runs when a message starts with it.
113
126
  - **The gate runs last.** In an SDK session it is an inline extension, loaded after those on
114
- disk; in a terminal the harness's extension is the last `--extension`. A plugin that changes a
115
- tool call's input does so before the gate sees it.
127
+ disk. A terminal retains its final prepared `--extension` bridge argument; the owned frontend
128
+ loads that bridge as the final trusted inline factory. A plugin that changes a tool call's
129
+ input does so before the gate sees it. Every resource reload revalidates the parent's original
130
+ trusted selection; changed or revoked code requires review and a fresh terminal.
116
131
  - **A required part can be extended.** A package names the part it adds to and, optionally, a
117
132
  hooks file: `"harness": { "extends": ["memory"], "hooks": "./hooks.mjs" }`. The harness runs
118
133
  hooks itself (`src/plugins/hooks.ts`), in its own process, because most memory is written while
@@ -138,8 +153,8 @@ working folder brings.
138
153
  - **A person can do the same from a terminal.** In a terminal session, `/plugins` lists what the
139
154
  session loads and switches a plugin, or one thing it brings, for the session's project or for
140
155
  everyone, and trusts code after showing its files. The session's shell can read the session
141
- token from its environment, so a change is taken only with a second key that the harness's
142
- extension claims once as it loads (`control.claim`) and keeps in its own memory; the socket's
156
+ token from its environment, so a change is taken only with a second key that the trusted
157
+ terminal process claims once (`control.claim`) and shares with its bridge in memory; the socket's
143
158
  `plugins.list` is open to the session, and `plugins.attach`, `plugins.detach`, `plugins.trust`
144
159
  and `plugins.untrust` refuse without that key. A change applies when the session restarts.
145
160
  Outside a session, `xingular-harness plugins list | show | install | remove | update | attach |
@@ -162,9 +177,10 @@ working folder brings.
162
177
  one caller, each item attributed to a plugin, with `unattributed` naming any prompt section,
163
178
  tool group or tool no plugin accounts for.
164
179
 
165
- A terminal session's `pi` command has four extensions of its own (`builtin:mcp`, `codemode`,
166
- `tool-search`, `llama.cpp`). They are passed by name unless Pi's settings switch them off. An SDK
167
- session does not have them.
180
+ A terminal session can load Pi's four existing builtins (`builtin:mcp`, `codemode`,
181
+ `tool-search`, `llama.cpp`). The Harness resource selection passes enabled builtins by name,
182
+ and the pinned compatibility adapter supplies their implementations to the persistent SDK
183
+ runtime. The separate per-turn SDK execution path does not load these terminal builtins.
168
184
 
169
185
  ## Using it from another language
170
186
 
@@ -201,7 +217,7 @@ has no knowledge of the application feature that may call it.
201
217
  `npm run prove` starts that server on a throwaway data root, with no application present, and
202
218
  exercises accounts, memory, skills, the prompt, connected apps, and a recorded session.
203
219
 
204
- ## Run it as a standalone Pi terminal
220
+ ## Run it as a standalone Harness terminal
205
221
 
206
222
  After the CLI package is published to npm or your company's npm registry, install and launch it:
207
223
 
@@ -210,26 +226,66 @@ npm install --global @xingular/harness
210
226
  xingular-harness
211
227
  ```
212
228
 
213
- The machine needs Node 22.19 or newer. On macOS and Linux, the `pi` command must be on `PATH`;
214
- on Windows, Harness runs the pinned Pi CLI package through the active Node runtime. On first
215
- launch, the harness creates a `Default` Pi account; Pi handles provider sign-in.
229
+ The machine needs Node 22.19 or newer. Harness runs its own terminal frontend through the
230
+ active Node runtime on every platform, using its pinned Pi SDK; no separate global `pi`
231
+ installation is required. On first launch, it creates a `Default` isolated account. Use
232
+ `/accounts` or `/login` to sign in.
233
+
234
+ Provider sign-in progress lives in the running Harness process. An embedding application can call
235
+ `accounts.loginStatus` after reconnecting to recover the current device code or prompt by account;
236
+ the status carries a revision so it can be safely merged with streamed login events. Progress is
237
+ never written to account files, and a completed or cancelled attempt no longer exposes its code.
216
238
 
217
- To build and run from a source checkout instead:
239
+ To build and run from a source checkout, use the development command:
218
240
 
219
241
  ```sh
220
242
  npm install
221
- npm run build
222
- node dist/cli.js
243
+ npm run dev
223
244
  ```
224
245
 
225
- This opens Pi's interactive terminal in the current working directory. The harness adds its
226
- compiled context, isolated account, approval gate, Wiki commands, and terminal extension while
227
- Pi provides the interface.
246
+ `npm run dev` rebuilds the CLI and opens the Harness terminal in the current working directory.
247
+ It uses the normal Harness data and state directories. Press `/quit` or Ctrl+C to close it.
248
+ For separate development data, pass the usual `--data <dir>` and `--state <dir>` arguments:
249
+ `npm run dev -- --data <dir> --state <dir>`.
250
+
251
+ Building a checkout does not update an existing global `xingular-harness` installation.
252
+ To replace that command with this checkout, run `npm pack`, then install the exact tarball
253
+ filename it prints with `npm install --global ./<tarball-filename>`. This is a local install;
254
+ it does not publish a release. Close an already-running terminal session and launch the command
255
+ again to load the new frontend. A package version alone cannot distinguish an unreleased local
256
+ build from an older installed build with the same version.
257
+
258
+ This opens the Harness-owned terminal frontend in the current working directory. Its
259
+ presentation follows the inspected Oh My Pi 18.11.3 titanium and light palettes, centered welcome, filled
260
+ status band and curved `╰─` prompt, with Harness identity and existing capabilities. Harness
261
+ owns screen composition, editing/input dispatch, scrolling, command routing and plugin UI;
262
+ Pi supplies the persistent execution runtime, native history and rich content components.
263
+ The existing isolated account, compiled context, approval gate, telemetry and Wiki/socket
264
+ commands remain behind the terminal. No Pi `InteractiveMode` is constructed.
265
+
266
+ `/resume` stays inside the prepared history and working folder; `/import` accepts an explicitly
267
+ selected native JSONL file only for the same working folder. Cancel an active response before
268
+ changing or reloading a session. Full OMP visual parity is not established by the current
269
+ verification. See [terminal architecture and evidence](docs/terminal-tui.md),
270
+ [the decision](docs/decisions/ADR-0001-owned-terminal.md), and [third-party notices](NOTICE.md).
271
+
272
+ ### `/accounts` in the terminal
273
+
274
+ `/accounts` manages the Pi accounts the same way the app's Accounts screen does: add, rename,
275
+ check, make default, sign in (browser or API key), sign out, remove a provider or an account,
276
+ manage pools, and read the activity log. Each change is made by the person at the terminal; a
277
+ command the model runs in the shell cannot make it.
278
+
279
+ A running session stays on the account it started with. To use another account for this
280
+ session, choose **Use for this session**: the terminal child restarts and the same conversation
281
+ resumes on that account. Removing an account that a running terminal is using is refused. Only
282
+ terminals in this process are counted, so an account used by another running `xingular-harness` window can
283
+ still be removed; that session then asks for another account the next time it starts.
228
284
 
229
285
  The default data and device state directories are `~/.xingular-harness/data` and
230
286
  `~/.xingular-harness/state`. Override them with `--data <dir>` and `--state <dir>`. Session
231
- history is stored per working directory and can be reopened with Pi's `/resume` command. The
232
- explicit `terminal` command is an alias for the default launch. Use `--help` to see the commands;
287
+ history is stored per working directory and can be reopened with the terminal's `/resume`
288
+ command. The explicit `terminal` command is an alias for the default launch. Use `--help` to see the commands;
233
289
  `serve` remains the host-facing RPC service for integrations such as Xingular Agent/App.
234
290
 
235
291
  ## Storage
@@ -261,14 +317,50 @@ The files are the source of truth; `index.sqlite` can be deleted and rebuilt
261
317
  ## Commands
262
318
 
263
319
  ```sh
264
- npm run typecheck
265
- npm test # unit tests and the golden prompt/memory fixtures in tests/golden
320
+ npm run ci # typecheck, unit/golden tests, and standalone proof; matches GitHub CI
266
321
  npm run build # dist/cli.js (the xingular-harness command) and dist/terminal-pi.js
267
- npm run prove # the standalone proof above
268
322
  ```
269
323
 
270
- Node 22.13 or newer (for `node:sqlite`).
324
+ Node 22.19 or newer.
271
325
 
272
326
  ## Images
273
327
 
274
328
  `SessionRunInput.requiresImageInput` optionally requires a vision-capable resolved Pi model before a prompt is delivered. The check includes direct `images` input, and the generic tool wrapper rejects image results on text-only models. Direct prompt images use Pi's `{ type: 'image', data, mimeType }` content shape. Applications own file formats, attachment selection, extraction and image preparation; the Harness only transports typed image content and validates model capability.
329
+
330
+ ## Curated Hub
331
+
332
+ `xingular-harness hub list [--refresh]`, `hub show publisher/name@version`, and
333
+ `hub install publisher/name@version` browse and install exact catalog versions. `/hub` offers the
334
+ same review in the interactive terminal, using its private control key for installation. Both the
335
+ terminal and embedding applications use `hub.list`, `hub.get`, `hub.install`, and `hub.readDocument`.
336
+ `hub.get { id, version, preview: true }` verifies data payload bytes without installing them.
337
+
338
+ Registry bundles import complete skills or single Markdown prompts/rules, disabled. Pi packages
339
+ reuse the existing installer and require an exact npm version or full GitHub commit. Documents
340
+ are saved as inert JSON for a compatible host to interpret; the harness does not apply them.
341
+ Installation grants no attachment, trust, credentials, or permission. Writes are serialized and
342
+ existing registry files are never overwritten.
343
+
344
+ Installed documents and provenance live under `<data root>/hub/`; the catalog cache is
345
+ `<state dir>/hub/catalog.json`. An offline snapshot ships with the package. Explicit refresh keeps
346
+ the last valid catalog when the network or schema fails. The prepared public distribution repository
347
+ is `../Hub`; publication remains separate from local installation and testing. Run its build with
348
+ `--sync-harness` to regenerate this package's offline snapshot after reviewing catalog changes.
349
+
350
+ Standalone defaults stay separate from a host application's folders. Use explicit `--data` and
351
+ `--state` to target the same library. CLI hub commands construct the harness without opening the
352
+ data root, so they do not migrate the Wiki or settle another process's runs.
353
+
354
+
355
+ ## External curation
356
+
357
+ An embedding application may set `externalMaintenance: true`, supply trusted `CallerContext`
358
+ `vaultAccess` (`self` or `curator`), and register `maintenanceTools`/`MAINTENANCE_PLUGIN`.
359
+ Self callers directly edit only their own writable persona/notes; shared knowledge and text-resource
360
+ writes become persistent proposals. Curator tools read original evidence, compare captured target
361
+ revisions, apply reviewed changes, persist receipts and undo without overwriting later edits.
362
+ `maintenance.list`, `maintenance.review` and `maintenance.retry` let the host dispatch its own
363
+ recorded sessions. Curator runs do not recursively queue maintenance. Optional assigned IDs freeze
364
+ which requests a batch may claim. These fields are trusted host context, never model arguments.
365
+ Executable proposals remain inert until the user reviews/trusts them. Standalone callers that omit
366
+ this option retain the existing lifecycle and direct-write contract.