@visual-z/xeno 0.1.3 → 0.2.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 +19 -0
- package/README.md +143 -33
- package/docs/install.md +18 -6
- package/docs/providers.md +147 -0
- package/package.json +8 -2
- package/src/apps/cli.ts +42 -14
- package/src/apps/commands.ts +32 -4
- package/src/apps/completions.ts +9 -6
- package/src/apps/export-cli.ts +24 -0
- package/src/apps/extension-ui.ts +330 -0
- package/src/apps/input.ts +16 -1
- package/src/apps/model-catalog.ts +42 -0
- package/src/apps/project-trust.ts +49 -0
- package/src/apps/render.ts +1 -0
- package/src/apps/resource-browser.ts +75 -0
- package/src/apps/resources.ts +25 -0
- package/src/apps/session-browser.ts +113 -0
- package/src/apps/session-picker.ts +55 -0
- package/src/apps/shell.ts +1177 -378
- package/src/apps/startup.ts +400 -268
- package/src/core/action-defaults.ts +306 -0
- package/src/core/attachment-input.ts +17 -0
- package/src/core/catalog-merge.ts +19 -0
- package/src/core/event-validation.ts +19 -2
- package/src/core/events.ts +45 -2
- package/src/core/export.ts +6 -2
- package/src/core/extension-flags.ts +14 -0
- package/src/core/images.ts +46 -0
- package/src/core/json-event.ts +2 -0
- package/src/core/keymap.ts +43 -119
- package/src/core/model-replay.ts +22 -0
- package/src/core/model-scope.ts +53 -0
- package/src/core/packages.ts +47 -0
- package/src/core/progress.ts +9 -0
- package/src/core/project.ts +21 -3
- package/src/core/prompts.ts +33 -5
- package/src/core/queue.ts +18 -0
- package/src/core/resource-selection.ts +36 -0
- package/src/{runtime → core}/resume.ts +15 -22
- package/src/core/session-archive.ts +4 -0
- package/src/core/session-browser.ts +82 -0
- package/src/core/session-entry.ts +56 -0
- package/src/core/session-position.ts +26 -0
- package/src/core/settings.ts +169 -154
- package/src/core/theme.ts +15 -6
- package/src/core/thinking.ts +26 -0
- package/src/core/tokens.ts +2 -0
- package/src/core/transcript.ts +15 -5
- package/src/runtime/auth.ts +116 -11
- package/src/runtime/catalog.ts +54 -151
- package/src/runtime/clipboard.ts +114 -0
- package/src/runtime/extension-loader.ts +37 -0
- package/src/runtime/extension-ui.ts +55 -0
- package/src/runtime/extensions.ts +273 -0
- package/src/runtime/images.ts +76 -0
- package/src/runtime/loop.ts +213 -83
- package/src/runtime/model-config.ts +232 -0
- package/src/runtime/model-data.LICENSE +27 -0
- package/src/runtime/model-data.ts +21 -0
- package/src/runtime/model-replay.ts +10 -0
- package/src/runtime/model-scope.ts +20 -0
- package/src/runtime/model-sources.ts +151 -0
- package/src/runtime/model.ts +74 -11
- package/src/runtime/models-fetch.ts +6 -104
- package/src/runtime/oauth.ts +4 -3
- package/src/runtime/openai-responses.ts +12 -4
- package/src/runtime/openai.ts +13 -4
- package/src/runtime/package-manager.ts +125 -0
- package/src/runtime/pi-provider.ts +235 -0
- package/src/runtime/progress.ts +26 -0
- package/src/runtime/provider-access.ts +21 -0
- package/src/runtime/provider-protocols.ts +29 -0
- package/src/runtime/provider-request.ts +73 -0
- package/src/runtime/provider.ts +26 -6
- package/src/runtime/rich-text.ts +36 -0
- package/src/runtime/tools.ts +41 -5
- package/src/store/command.ts +7 -1
- package/src/store/context-files.ts +1 -1
- package/src/store/log.ts +65 -0
- package/src/store/models.ts +28 -9
- package/src/store/observations.ts +4 -2
- package/src/store/packages.ts +98 -0
- package/src/store/recovery.ts +8 -0
- package/src/store/resource-index.ts +170 -0
- package/src/store/resources.ts +75 -142
- package/src/store/session-archive.ts +162 -0
- package/src/store/session-browser.ts +68 -0
- package/src/store/session-position.ts +27 -0
- package/src/store/sessions.ts +87 -66
- package/src/store/trust.ts +13 -0
- package/src/store/workspace.ts +6 -0
- package/src/tui/chat-viewport.ts +47 -0
- package/src/tui/editor.ts +62 -15
- package/src/tui/host.ts +50 -9
- package/src/tui/input.ts +8 -2
- package/src/tui/select.ts +24 -6
- package/src/tui/settings.ts +4 -0
- package/src/tui/system-theme.ts +700 -0
- package/src/tui/transcript.ts +63 -11
- package/src/tui/tree.ts +161 -95
- package/src/vendor/pi-rich/LICENSE.upstream +21 -0
- package/src/vendor/pi-rich/UPSTREAM.json +17 -0
- package/src/vendor/pi-rich/clipboard-command.ts +44 -0
- package/src/vendor/pi-rich/exif-orientation.ts +182 -0
- package/src/vendor/pi-rich/html.ts +51 -0
- package/src/vendor/pi-rich/image-convert.ts +49 -0
- package/src/vendor/pi-rich/image-resize-core.ts +164 -0
- package/src/vendor/pi-rich/image-resize-worker.ts +42 -0
- package/src/vendor/pi-rich/image-resize.ts +123 -0
- package/src/vendor/pi-rich/mime.ts +116 -0
- package/src/vendor/pi-rich/photon.ts +139 -0
- package/src/vendor/pi-rich/syntax-highlight.ts +214 -0
- package/src/vendor/pi-tui/UPSTREAM.json +50 -0
- package/src/vendor/pi-tui/VENDOR.md +7 -5
- package/src/vendor/pi-tui/autocomplete.ts +35 -10
- package/src/vendor/pi-tui/colors.ts +367 -0
- package/src/vendor/pi-tui/components/box.ts +8 -9
- package/src/vendor/pi-tui/components/editor.ts +4 -2
- package/src/vendor/pi-tui/components/markdown.ts +8 -2
- package/src/vendor/pi-tui/index.ts +31 -1
- package/src/vendor/pi-tui/native/UPSTREAM.json +23 -0
- package/src/vendor/pi-tui/native/clipboard.h +208 -0
- package/src/vendor/pi-tui/native/darwin/README.md +22 -0
- package/src/vendor/pi-tui/native/darwin/build.sh +69 -0
- package/src/vendor/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
- package/src/vendor/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
- package/src/vendor/pi-tui/native/darwin/src/darwin-platform.m +132 -0
- package/src/vendor/pi-tui/native/linux/README.md +23 -0
- package/src/vendor/pi-tui/native/linux/build.sh +65 -0
- package/src/vendor/pi-tui/native/linux/prebuilds/linux-arm64/linux-platform-x11.node +0 -0
- package/src/vendor/pi-tui/native/linux/prebuilds/linux-x64/linux-platform-x11.node +0 -0
- package/src/vendor/pi-tui/native/linux/src/clipboard-worker.h +70 -0
- package/src/vendor/pi-tui/native/linux/src/linux-platform-x11.c +274 -0
- package/src/vendor/pi-tui/native/napi.h +91 -0
- package/src/vendor/pi-tui/native/win32/README.md +31 -0
- package/src/vendor/pi-tui/native/win32/build.mjs +232 -0
- package/src/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-platform.node +0 -0
- package/src/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-platform.node +0 -0
- package/src/vendor/pi-tui/native/win32/src/win32-platform.c +241 -0
- package/src/vendor/pi-tui/native-platform.ts +2 -0
- package/src/vendor/pi-tui/oklab.ts +233 -0
- package/src/vendor/pi-tui/terminal-colors.ts +26 -8
- package/src/vendor/pi-tui/terminal-image.ts +43 -8
- package/src/vendor/pi-tui/terminal.ts +16 -9
- package/src/vendor/pi-tui/tui-alt-screen.ts +26 -18
- package/src/vendor/pi-tui/tui.ts +112 -75
- package/src/vendor/pi-tui/utils.ts +89 -49
- package/src/vendor/pi-tui/wheel-scroll.ts +82 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# xeno changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 — 2026-09-30
|
|
4
|
+
|
|
5
|
+
- Restore saved model identity on session entry; cross-model history moves through a mechanical checkpoint.
|
|
6
|
+
- Align Pi terminal input, full-screen navigation, model controls, rich content, session browsing and resource reload.
|
|
7
|
+
- Add local extensions, custom UI components and explicit npm/git/local package management.
|
|
8
|
+
- Export portable JSONL archives, import independent sessions, and write local terminal diagnostics.
|
|
9
|
+
- Ship pinned native helpers, unify clipboard writes, and add typed extension CLI flags, model scopes, named sessions and offline export.
|
|
10
|
+
- Persist thinking visibility, manage model defaults, and scope cancellable authentication to its active application.
|
|
11
|
+
- Combine Pi and Models.dev into an offline catalog of 226 providers and 7,501 models, with ten native protocols and explicit exclusions.
|
|
12
|
+
- Support flat, Pi and OpenCode provider configuration, private credentials and headers, local endpoints, and a separate atomic refresh cache.
|
|
13
|
+
- Checkpoint changed wire profiles from the log, preserve native signatures, and render cumulative arguments for interleaved tool calls.
|
|
14
|
+
|
|
15
|
+
Implementation and validation records are in the task cards under `docs/tasks/`.
|
|
16
|
+
|
|
17
|
+
## 0.1.4
|
|
18
|
+
|
|
19
|
+
Earlier implementation and validation records are available in `docs/PROGRESS.md`.
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ is ever summarized by a model, and nothing is ever rewritten in place.
|
|
|
17
17
|
messages[] frozen system prefix + handoff + this node's events
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Version **0.
|
|
20
|
+
Version **0.2.0**. The on-disk session format will still change; `0.x` is that
|
|
21
21
|
statement. Published as `@visual-z/xeno`; the license is `UNLICENSED` (readable and installable, no reuse granted).
|
|
22
22
|
|
|
23
23
|
## Install
|
|
@@ -70,8 +70,9 @@ views. Its budget-limited result and negative cases are recorded in the same rep
|
|
|
70
70
|
neither segmentation nor the experimental adaptive rule has established a quality advantage.
|
|
71
71
|
`bun run scripts/compare-harness.ts smoke --output /absolute/new/smoke-directory`
|
|
72
72
|
also exercises xeno-windowed, xeno-continuous and an installed Pi CLI with shared
|
|
73
|
-
confined tools, without paid model calls. Pi runs on Node through
|
|
74
|
-
tool bridge;
|
|
73
|
+
confined tools, without paid model calls. The comparison Pi CLI runs on Node through
|
|
74
|
+
an isolated local tool bridge; xeno's providers use the pinned Pi AI runtime described below.
|
|
75
|
+
Its `plan` / `run` protocol freezes
|
|
75
76
|
source, model, task order and spending policy, including summary calls. An explicitly
|
|
76
77
|
authorized `--budget unlimited` on both `plan` and `run` records costs without a local
|
|
77
78
|
dollar ceiling; upstream errors stop the trial, with HTTP 402 marked as awaiting top-up.
|
|
@@ -82,15 +83,21 @@ This checks a controlled configuration, not stock Pi or an official leaderboard.
|
|
|
82
83
|
```
|
|
83
84
|
xeno [-m <model>] [--provider <name>] [--api-key <key>]
|
|
84
85
|
[-w <workspace>] [--log <dir>] [--max-turns N]
|
|
85
|
-
[--trigger N --hard N] [--list-models] [--fresh]
|
|
86
|
+
[--trigger N --hard N] [--list-models [search]] [--fresh]
|
|
87
|
+
[-c|--continue] [-r|--resume [id]] [--session path|id]
|
|
88
|
+
[--fork path|id] [--session-dir dir] [--session-id id] [--no-session]
|
|
89
|
+
[--models patterns] [--thinking level] [--mode text|json]
|
|
90
|
+
[--export session [output.html]] [--offline] [--version]
|
|
86
91
|
[models --refresh]
|
|
87
92
|
[--system-prompt <text-or-file>] [--append-system-prompt <text>]
|
|
88
93
|
[--no-context-files|-nc]
|
|
89
94
|
[--tools names] [--exclude-tools names] [--no-tools]
|
|
90
95
|
[--allow-tools names] [--approve|--no-approve]
|
|
91
|
-
[--theme <name|path>]
|
|
92
|
-
[--
|
|
93
|
-
[--
|
|
96
|
+
[--theme <name|path>] [--use-theme <name>] [--no-themes]
|
|
97
|
+
[--tui-mode regular|fullscreen]
|
|
98
|
+
[--skill <path>] [--no-skills|-ns]
|
|
99
|
+
[--prompt-template <path>] [--no-prompt-templates|-np]
|
|
100
|
+
[--extension|-e <path>] [--no-extensions|-ne]
|
|
94
101
|
[-p <prompt>] [prompt...]
|
|
95
102
|
```
|
|
96
103
|
|
|
@@ -98,29 +105,53 @@ xeno [-m <model>] [--provider <name>] [--api-key <key>]
|
|
|
98
105
|
- A prompt, or `-p` / `--print`: one shot, then exit. `-p` puts only the
|
|
99
106
|
assistant's final text on stdout; the banner, usage, thinking, and tool
|
|
100
107
|
lines go to stderr. Piped stdin is appended after the command-line prompt.
|
|
101
|
-
-
|
|
102
|
-
|
|
108
|
+
- Each invocation starts a new session, including `-p`. `--fresh` remains
|
|
109
|
+
an explicit alias. Nothing is deleted.
|
|
110
|
+
- `-c` continues the newest session, or starts one if none exists. `-r`
|
|
111
|
+
opens a session picker; cancelling leaves saved sessions untouched.
|
|
112
|
+
`--session <path|id>` and `-r <id>` open a specific session.
|
|
113
|
+
A portable JSONL file creates an independent imported session in the current workspace.
|
|
114
|
+
- Resume restores that session's model before consulting defaults. An
|
|
115
|
+
explicit `--model` switches through a checkpoint, preserving the original
|
|
116
|
+
log without replaying another model's thinking. Missing or ambiguous saved
|
|
117
|
+
models are reported; restore their catalog entry before resuming.
|
|
103
118
|
- A leftover `.xeno/log` is not migrated; continue it with `--log .xeno/log`.
|
|
119
|
+
- `--models 'deepseek/*:low,anthropic/*'` resolves ordered model scopes; an
|
|
120
|
+
explicit empty scope disables cycling. `--model id:level` sets thinking,
|
|
121
|
+
with an explicit `--thinking` taking precedence.
|
|
122
|
+
- `--session-id id` creates or resumes that exact local ID. `--export` writes
|
|
123
|
+
offline HTML from a saved session or portable archive without starting an agent.
|
|
124
|
+
- `--theme` can be repeated for explicit files/directories; `--use-theme`
|
|
125
|
+
selects a theme. `--no-themes` disables automatic discovery.
|
|
126
|
+
- Extensions can register typed native CLI flags, including in `--help`.
|
|
127
|
+
Normal startup stays offline; `--offline` also blocks remote preparation.
|
|
104
128
|
|
|
105
129
|
Slash commands that exist in the session (from `/help`):
|
|
106
130
|
|
|
107
131
|
```
|
|
108
132
|
/model [id] search models, or switch (cuts a node)
|
|
109
|
-
/models refresh
|
|
133
|
+
/models refresh refresh ~/.xeno/models-cache.json; preserve models.json
|
|
110
134
|
/login [provider] choose a login method, or store an API key
|
|
111
135
|
/login claude-pro|codex|github-copilot
|
|
112
136
|
subscription login (first-party client credentials)
|
|
113
137
|
/logout [provider] remove a stored credential
|
|
138
|
+
/scoped-models enable, disable and order models for cycling
|
|
114
139
|
/new start a new session beside this one
|
|
115
140
|
/resume [id] search sessions, or switch to one
|
|
116
141
|
/name <name> name this session
|
|
117
142
|
/session id, path, events, usage
|
|
118
143
|
/back [n [files|context]] [confirm]
|
|
119
|
-
/tree search
|
|
144
|
+
/tree search, filter, fold, label and navigate exact session events
|
|
120
145
|
/fork [n] choose an exchange to copy into a new session
|
|
121
146
|
/clone copy the active branch into a new session
|
|
122
|
-
/
|
|
123
|
-
/
|
|
147
|
+
/export [file] offline HTML, or a portable archive with a .jsonl filename
|
|
148
|
+
/import <file> validate and open an archive as an independent session
|
|
149
|
+
/debug [file] write local terminal and message diagnostics
|
|
150
|
+
/changelog show bundled release notes
|
|
151
|
+
/trust [once|here|parent|never]
|
|
152
|
+
/reload refresh local resources at a durable context checkpoint
|
|
153
|
+
/config search resources and edit global or project overrides
|
|
154
|
+
/settings [key v] theme, thinking, queues, viewport and editor settings
|
|
124
155
|
/hotkeys bindings in effect
|
|
125
156
|
/usage /state /help /quit
|
|
126
157
|
```
|
|
@@ -128,22 +159,53 @@ Slash commands that exist in the session (from `/help`):
|
|
|
128
159
|
Type `/` for commands, templates and skills. The editor completes command
|
|
129
160
|
arguments and paths. `@file` or `@"file name"` attaches a project file anywhere
|
|
130
161
|
outside code literals; choosing a file keeps the prompt in the editor.
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
162
|
+
`!cmd` runs in the workspace, streams output, and records it for the next model
|
|
163
|
+
request. `!!cmd` records human history while excluding its output from model
|
|
164
|
+
context. Neither starts a model request or requires a model credential.
|
|
165
|
+
Escape cancels the command and its process group. During a turn, Enter queues
|
|
166
|
+
steering after the current tools finish; Alt+Enter queues a follow-up after the
|
|
167
|
+
turn, or submits immediately while idle. Alt+Up returns the entire queue to the
|
|
168
|
+
editor. Settings expose independent `steeringMode` and `followUpMode` values
|
|
169
|
+
of `all` or `one-at-a-time`.
|
|
134
170
|
Escape interrupts; pressing Escape twice on an empty idle editor opens the tree.
|
|
135
171
|
Ctrl+C clears the draft, then a quick second press exits; Ctrl+D exits an empty
|
|
136
172
|
editor. Ctrl+O and Ctrl+T toggle tools and thinking throughout the history.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
173
|
+
Ctrl+T persists `hideThinkingBlock`. `/settings` also manages new-session model
|
|
174
|
+
defaults and per-model thinking overrides; clearing an override restores the
|
|
175
|
+
project or global setting. `showCacheMissNotices` displays the existing prefix
|
|
176
|
+
diagnostics without changing usage accounting or issuing extra model requests.
|
|
177
|
+
|
|
178
|
+
`/scoped-models` changes the current session immediately; Ctrl+S saves the range.
|
|
179
|
+
|
|
180
|
+
`-r` and `/resume` share a session browser: Tab changes workspace scope, Ctrl+N
|
|
181
|
+
filters named sessions, Ctrl+S cycles threaded/recent/relevance ordering, Ctrl+P
|
|
182
|
+
shows paths, and Ctrl+R renames. Search supports `re:<pattern>` and quoted phrases.
|
|
183
|
+
Ctrl+D asks before moving an inactive session into its sibling `.trash` directory;
|
|
184
|
+
the original files remain recoverable by moving that directory back. All-workspace
|
|
185
|
+
discovery uses registered session roots, with no 200-session result cap.
|
|
186
|
+
The tree supports Ctrl+O filter cycling, Alt+Left/Right branch folding/navigation,
|
|
187
|
+
Shift+L labels, Shift+T label timestamps, and Ctrl+X copy. These actions can be rebound.
|
|
188
|
+
Enter toggles a model, Ctrl+A/Ctrl+X enables/disables filtered models, Ctrl+P
|
|
189
|
+
toggles a provider, and Alt+Up/Down orders enabled models. An explicit empty
|
|
190
|
+
range disables cycling. `/thinking` exposes off/minimal/low/medium/high/xhigh/max
|
|
191
|
+
with model capability checks; Ctrl+S saves a default for that provider/model.
|
|
192
|
+
Automatic model changes clamp effort to a supported level.
|
|
193
|
+
|
|
194
|
+
`xeno --list-models [search]` searches the offline union of Pi and OpenCode's
|
|
195
|
+
Models.dev directory: **226 providers and 7,501 model entries** in the pinned
|
|
196
|
+
snapshot. Use `provider/model` when several providers expose the same ID.
|
|
197
|
+
`xeno models --refresh` atomically updates `~/.xeno/models-cache.json`;
|
|
198
|
+
startup never fetches and the user's `~/.xeno/models.json` remains untouched.
|
|
199
|
+
Flat catalogs, Pi `providers` and OpenCode `provider` configuration are supported.
|
|
200
|
+
See [provider configuration](docs/providers.md) for local servers, model overrides,
|
|
201
|
+
credentials, native cloud protocols, and explicit coverage limits.
|
|
141
202
|
|
|
142
203
|
## Credentials
|
|
143
204
|
|
|
144
|
-
Order: `--api-key`,
|
|
145
|
-
|
|
146
|
-
|
|
205
|
+
Order: `--api-key`, `~/.xeno/auth.json`, `models.json` provider/model credentials,
|
|
206
|
+
then the provider's environment variables. A failed explicit source does not
|
|
207
|
+
fall through to another account. `/login codex` uses the `openai-codex` protocol;
|
|
208
|
+
ordinary OpenAI API models use `openai`.
|
|
147
209
|
|
|
148
210
|
Interactive sessions can start with no key and wait for `/login`. `-p` and
|
|
149
211
|
non-tty runs exit 1 and name `--api-key` or the variable; they do not mention
|
|
@@ -221,12 +283,13 @@ Shipped, not planned:
|
|
|
221
283
|
an action/observation cycle repeats, or the request budget is nearly exhausted.
|
|
222
284
|
Existing messages, the system prefix, and tool definitions stay frozen. Model
|
|
223
285
|
notes remain annotations and cannot manufacture verified completion.
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
286
|
+
- Ten native wire protocols through a pinned Pi runtime adapter, alongside the
|
|
287
|
+
three existing verified transports. Streaming text, thinking, tools and opaque
|
|
288
|
+
signatures project from the same append-only log; deltas remain UI events.
|
|
289
|
+
- An offline provider/model union with **226 providers** and **7,501 entries**,
|
|
290
|
+
user overrides by provider/model, and a separate explicit-refresh cache.
|
|
291
|
+
Native protocol fixtures cover requests and responses; the directory is not
|
|
292
|
+
a claim that every listed remote account/model was tested live.
|
|
230
293
|
- Sessions, resume, `/new` / `/resume` / `/name` / `/session`, `/back`
|
|
231
294
|
(files, context, or both), `/tree`, read-only `branch` / `resolve`, and
|
|
232
295
|
write branches in their own git worktree.
|
|
@@ -238,14 +301,46 @@ Shipped, not planned:
|
|
|
238
301
|
Markdown, searchable pickers and settings. Durable history is a pure log
|
|
239
302
|
projection across handoff boundaries. Includes tool diffs, historical folds,
|
|
240
303
|
Pi dark/light palettes, `keybindings.json`, `/settings` and `/hotkeys`.
|
|
304
|
+
|
|
241
305
|
- Context files: `AGENTS.md` / `CLAUDE.md` and the override chain, plus
|
|
242
306
|
`--system-prompt` / `--append-system-prompt` / `-nc`.
|
|
243
307
|
- Skills (`~/.xeno/skills/`, `/skill:name`) and prompt templates
|
|
244
308
|
(`~/.xeno/prompts/`, `/name`). Untrusted projects do not load the
|
|
245
309
|
project-level copies.
|
|
310
|
+
- `/reload` refreshes local models, settings, keybindings, context files, skills,
|
|
311
|
+
templates and themes without losing the draft or active model. A changed system
|
|
312
|
+
prefix checkpoints first; unchanged resources do not create a new segment.
|
|
313
|
+
`/config` and `xeno config` share searchable resource provenance and enablement.
|
|
314
|
+
Relative resource paths resolve from the settings file that declares them;
|
|
315
|
+
project overrides cycle through inherit, load and skip. CLI paths remain explicit.
|
|
316
|
+
`/trust` opens a selector; `once` grants no persistent trust. Global
|
|
317
|
+
`defaultProjectTrust` cannot be overridden by project settings.
|
|
318
|
+
Templates support Pi's `$1`, `$@`, `$ARGUMENTS`, defaults and slices as well as
|
|
319
|
+
the existing `{{name}}` syntax. Arguments are substituted once.
|
|
320
|
+
- Local TS/JS extensions can register commands, shortcuts, tools and lifecycle
|
|
321
|
+
hooks through Pi's factory protocol. Discovery, project trust and `/reload`
|
|
322
|
+
use the same resource inventory. Custom state and messages remain append-only
|
|
323
|
+
log events. See [extension boundaries and usage](docs/extensions.md).
|
|
324
|
+
- Packages can come from local paths, npm or git: `xeno install <source>`,
|
|
325
|
+
`remove`, `update --extensions` and `list`. `--local` selects project scope;
|
|
326
|
+
`-e` tries a package for one invocation. Manifests, per-kind filters and trust
|
|
327
|
+
feed the same resource inventory. Normal startup stays offline.
|
|
328
|
+
See [package management](docs/packages.md).
|
|
246
329
|
- `/login` for API keys and for Claude Pro/Max, Codex, and GitHub
|
|
247
330
|
Copilot subscription flows. See Known gaps.
|
|
248
331
|
|
|
332
|
+
Images can be attached with `@path`, a dropped image path, or Ctrl+V (files,
|
|
333
|
+
image, then text). `/attachments` removes draft images; queue recall and history
|
|
334
|
+
forks retain them. The log stores immutable blob references. Provider adapters
|
|
335
|
+
load verified bytes for Anthropic, Chat Completions and Responses; text-only
|
|
336
|
+
models receive a visible placeholder. Custom models declare `input: ["text", "image"]`
|
|
337
|
+
in `models.json`. `terminal.showImages`, `terminal.imageWidthCells`,
|
|
338
|
+
`images.autoResize`, `images.blockImages` and `markdown.mermaid` are configurable
|
|
339
|
+
through `/settings`. Pi syntax highlighting and Mermaid use the same rendering
|
|
340
|
+
path for saved replies and live output. Image tokens are estimates until provider
|
|
341
|
+
usage is available. Enabling image blocking checkpoints an existing image context;
|
|
342
|
+
unblocking affects new submissions, preserving historical request prefixes.
|
|
343
|
+
|
|
249
344
|
## Known gaps
|
|
250
345
|
|
|
251
346
|
- **No sandbox.** See Isolation. That is a decision, not a missing feature.
|
|
@@ -258,7 +353,8 @@ Shipped, not planned:
|
|
|
258
353
|
catalog comment on `gpt-5.5-pro` notes a `context_over_200k` tier that
|
|
259
354
|
is not applied. `/usage` reports `{kind:"partial"}` when cache prices
|
|
260
355
|
are missing; it does not treat a missing cache price as zero.
|
|
261
|
-
- **
|
|
356
|
+
- **Package installation is separate from resource loading.** Local extensions,
|
|
357
|
+
skills and templates load from explicit, trusted filesystem sources.
|
|
262
358
|
There is no installer.
|
|
263
359
|
- **Bun only.** Node has not been tested.
|
|
264
360
|
- **`/back` does not restore symlinks.**
|
|
@@ -270,8 +366,22 @@ Shipped, not planned:
|
|
|
270
366
|
`docs/TUI_ARCHITECTURE.md` describes the active interaction path and verification.
|
|
271
367
|
`docs/PI_PARITY.md` records deliberate differences and remaining Pi features.
|
|
272
368
|
Pi's editor supports undo, not redo; an old `editor.redo` binding is diagnosed
|
|
273
|
-
as unsupported rather than silently accepted. Ctrl+-
|
|
274
|
-
|
|
369
|
+
as unsupported rather than silently accepted. Ctrl+- invokes Pi undo.
|
|
370
|
+
Ctrl+Z suspends the CLI on POSIX; `fg` restores the terminal and unsent draft.
|
|
371
|
+
|
|
372
|
+
`/settings tuiMode fullscreen` uses Pi's alternate-screen viewport, transcript
|
|
373
|
+
search (Ctrl+Shift+F), prompt navigation (Ctrl+Up/Down), mouse scrolling and text
|
|
374
|
+
selection. `/settings fullscreenExitOutput resume-hint` leaves a resume command
|
|
375
|
+
when exiting; `transcript` prints the conversation. Switching modes preserves
|
|
376
|
+
the editor, history and undo. Scrollbar, wheel speed, copy-on-select, editor
|
|
377
|
+
padding, autocomplete rows, cursor, output padding and double-Escape behavior
|
|
378
|
+
are configurable in `/settings`.
|
|
379
|
+
|
|
380
|
+
`/settings theme` previews built-in and custom themes from the config directory's
|
|
381
|
+
`themes/`. Escape restores the prior theme. Custom files reload after valid edits;
|
|
382
|
+
`auto` follows terminal light/dark changes and `system` derives Pi's palette from
|
|
383
|
+
terminal color replies. Pi's namespaced action IDs work in `keybindings.json`
|
|
384
|
+
alongside existing xeno names; an empty array disables an action in its own scope.
|
|
275
385
|
|
|
276
386
|
## Why this shape
|
|
277
387
|
|
|
@@ -460,7 +570,7 @@ Every path below was checked with `test -f` on this checkout.
|
|
|
460
570
|
| `store/context-files.ts` | AGENTS.md discovery |
|
|
461
571
|
| **`src/runtime/`** | impure but thin; the only layer allowed npm packages |
|
|
462
572
|
| `runtime/provider.ts` / `openai.ts` | the two wire formats |
|
|
463
|
-
| `runtime/catalog.ts` / `model.ts` |
|
|
573
|
+
| `runtime/catalog.ts` / `model-config.ts` / `model-sources.ts` | Pi + Models.dev union, offline overlays and private provider configuration |
|
|
464
574
|
| `runtime/tools.ts` / `history-tools.ts` | confined tools, complete query results and history retrieval |
|
|
465
575
|
| `runtime/benchmark.ts` | actual Session trials, bounded spending and cache diagnostics |
|
|
466
576
|
| `runtime/loop.ts` | orchestration; every judgement delegates to a pure function in core |
|
package/docs/install.md
CHANGED
|
@@ -30,8 +30,16 @@ cd xeno
|
|
|
30
30
|
bun install
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
`bun install` pulls the
|
|
34
|
-
and
|
|
33
|
+
`bun install` pulls the provider SDK, Pi text layout/Markdown dependencies,
|
|
34
|
+
syntax highlighting, Mermaid, Photon image processing, and TypeScript tooling.
|
|
35
|
+
The exact versions are in `package.json` and `bun.lock`.
|
|
36
|
+
|
|
37
|
+
Pi native helpers for macOS, Linux X11 and Windows (arm64/x64) ship with the
|
|
38
|
+
package. They are pinned upstream builds with matching source and hashes;
|
|
39
|
+
startup does not download or compile them. Missing platform support uses the
|
|
40
|
+
clipboard command fallbacks. The packaged macOS helper was load-tested on
|
|
41
|
+
this machine; Linux/Windows payloads and routing are checked without claiming
|
|
42
|
+
native device acceptance.
|
|
35
43
|
|
|
36
44
|
Run the CLI without linking:
|
|
37
45
|
|
|
@@ -55,8 +63,10 @@ xeno --list-models
|
|
|
55
63
|
`bun link` writes a shim that executes the `bin` field
|
|
56
64
|
(`src/apps/cli.ts`) with Bun. It does not copy the tree.
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
Each invocation starts a new session. `xeno -c` continues the newest one;
|
|
67
|
+
`xeno -r` opens a picker. `--fresh` is a compatibility alias for the default,
|
|
68
|
+
and nothing is deleted. Resume restores the saved model. An explicit
|
|
69
|
+
`--model` switches at a checkpoint while keeping the original log intact.
|
|
60
70
|
|
|
61
71
|
## Credentials
|
|
62
72
|
|
|
@@ -64,7 +74,8 @@ Resolution order, first match wins:
|
|
|
64
74
|
|
|
65
75
|
1. `--api-key`
|
|
66
76
|
2. `~/.xeno/auth.json` (created `0600` by `/login`)
|
|
67
|
-
3. the provider
|
|
77
|
+
3. the model or provider `apiKey` in `~/.xeno/models.json`
|
|
78
|
+
4. the provider's environment variable
|
|
68
79
|
|
|
69
80
|
A stored entry owns that provider. The environment is not a fallback
|
|
70
81
|
after a stored key fails.
|
|
@@ -111,7 +122,8 @@ In **your home directory** (`~/.xeno/`, or `$XENO_CONFIG_DIR`):
|
|
|
111
122
|
auth.json credentials (0600)
|
|
112
123
|
settings.json theme, thinking, defaults
|
|
113
124
|
trust.json which directories may load project settings
|
|
114
|
-
models.json optional
|
|
125
|
+
models.json optional user provider/model configuration
|
|
126
|
+
models-cache.json generated catalog cache (written by `xeno models --refresh`)
|
|
115
127
|
keybindings.json optional
|
|
116
128
|
prompts/ skills/ optional
|
|
117
129
|
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# 供应商、模型目录与自定义配置
|
|
2
|
+
|
|
3
|
+
xeno 内置 Pi 0.99.1 和 OpenCode 所用 Models.dev 的固定源并集:226 个供应商、7,501 个模型条目。同一个模型在不同供应商下分别计数。目录保留能力与已知价格;未提供的价格显示未知,不用零补全。
|
|
4
|
+
|
|
5
|
+
来源固定为 Pi `1b347794e2a630e4359f2584f4eea388145d0ddf`、OpenCode `2fa3363c924c5c3e367b84a87ae478296a0ed59b`,Models.dev JSON SHA256 `7345de7358c471e78ac756aed556cd804677cd0d8748b71edc3931225440158f`。SDK 固定为 `@earendil-works/pi-ai@0.99.1`;引入它是为了复用维护中的原生协议和签名处理,避免在 xeno 重写十套 SDK。SDK 仅在 runtime;原有 TUI vendor 的版本与升级方式独立。
|
|
6
|
+
|
|
7
|
+
## 目录和选择
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
xeno --list-models siliconflow
|
|
11
|
+
xeno --provider deepseek --model deepseek-flash
|
|
12
|
+
xeno --model google/gemini-2.5-flash
|
|
13
|
+
xeno models --refresh
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
按 `provider/model` 识别模型。完整标识优先于其他供应商包含斜杠的原始 ID;裸 ID 多义时给出候选,不按目录顺序猜。旧会话保存了供应商时精确恢复;只存 ID 的旧会话需要目录中的唯一匹配。
|
|
17
|
+
|
|
18
|
+
目录优先级:内置 → `~/.xeno/models-cache.json` → `~/.xeno/models.json`。启动、列举、选择、恢复和 `/reload` 共用同一解析入口。缓存更新模型元数据时保留原有已验证模型的 wire dialect;用户配置仍可明确覆盖它。刷新成功原子替换缓存,失败保留原缓存,始终不重写用户配置。`XENO_CONFIG_DIR` 可以替换这个目录。启动不联网;`--offline` 禁止显式刷新。
|
|
19
|
+
|
|
20
|
+
编辑配置后执行 `/reload`。当前模型的端点、API、wire ID 或回放格式变化会记录 checkpoint;纯凭据轮换不切段。禁用当前模型后,下一条输入保留为草稿,需要重新选择模型。供应商错误或配置错误不会使请求转到另一个账户。
|
|
21
|
+
|
|
22
|
+
新的 assistant 事件同时记录回放配置的摘要,恢复时从日志比较,配置别名不变也能识别上游协议变化。摘要不包含凭据或端点原文。没有摘要的旧原生配置在首次接入时先建立 checkpoint;旧的默认传输保持原恢复行为。
|
|
23
|
+
|
|
24
|
+
## 本地无认证端点(Pi 分组)
|
|
25
|
+
|
|
26
|
+
以下内容保存为 `~/.xeno/models.json`;端口、模型 ID 与本地服务保持一致。
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"providers": {
|
|
31
|
+
"local": {
|
|
32
|
+
"api": "openai-completions",
|
|
33
|
+
"baseUrl": "http://127.0.0.1:1234/v1",
|
|
34
|
+
"auth": false,
|
|
35
|
+
"models": [{
|
|
36
|
+
"id": "my-local-model",
|
|
37
|
+
"name": "Local model",
|
|
38
|
+
"contextWindow": 32768,
|
|
39
|
+
"maxTokens": 4096,
|
|
40
|
+
"compat": {
|
|
41
|
+
"supportsStore": false,
|
|
42
|
+
"supportsDeveloperRole": false,
|
|
43
|
+
"maxTokensField": "max_tokens"
|
|
44
|
+
},
|
|
45
|
+
"samplingParams": { "top_k": 40, "min_p": 0.05 }
|
|
46
|
+
}]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`xeno --model local/my-local-model` 使用该条目。`auth: false` 或 `authHeader: false` 关闭自动认证;SDK 构造所需的内部占位 key 不会发到服务器。`authHeader: "x-custom-key"` 可把最终解析的 key 放进指定头。Google 原生 SDK 拥有认证流程,不支持这两种头替换方式;本地兼容服务使用 OpenAI 接口。
|
|
53
|
+
|
|
54
|
+
## OpenCode 分组、别名与私有配置
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"provider": {
|
|
59
|
+
"company": {
|
|
60
|
+
"npm": "@ai-sdk/openai-compatible",
|
|
61
|
+
"options": {
|
|
62
|
+
"baseURL": "https://gateway.example.com/v1",
|
|
63
|
+
"apiKey": "{env:COMPANY_API_KEY}",
|
|
64
|
+
"temperature": 0.2
|
|
65
|
+
},
|
|
66
|
+
"headers": { "x-tenant": "${COMPANY_TENANT}" },
|
|
67
|
+
"models": {
|
|
68
|
+
"coding": {
|
|
69
|
+
"id": "upstream-model-id",
|
|
70
|
+
"limit": { "context": 128000, "output": 8192 },
|
|
71
|
+
"reasoning": true,
|
|
72
|
+
"thinkingLevelMap": { "off": null, "minimal": "low", "low": "low", "medium": "medium", "high": "high", "xhigh": null, "max": null },
|
|
73
|
+
"compat": { "supportsStore": false, "supportsDeveloperRole": false, "maxTokensField": "max_tokens" },
|
|
74
|
+
"body": { "top_p": 0.9 }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
选择 `company/coding`,线上请求使用 `upstream-model-id`。`npm` 仅用于识别已接通的协议,不会安装或执行任意供应商包;也可以直接指定 `api`。OpenCode 的完整应用配置、插件、任意 SDK 选项不在这个解析器的兼容范围。
|
|
83
|
+
|
|
84
|
+
凭据优先级为 CLI `--api-key` → `auth.json` → 模型/供应商 `apiKey` → 供应商环境变量。供应商 `apiKey` 可被模型覆盖;头和 scoped env 按字段合并。指定来源失败就报错,不向下兜底。
|
|
85
|
+
|
|
86
|
+
`apiKey`、`headers`、`env` 和 `baseUrl` 支持字面字符串、`$VAR` / `${VAR}` / `{env:VAR}`,以及以 `!` 开头的本地命令。命令只有在凭据解析或实际请求需要时执行,不在目录解析时执行。`$$` 和 `$!` 表示字面开头字符。保留 xeno 原有规则:裸 `MY_KEY` 是字面 key,引用变量要写 `$MY_KEY`。只把自己信任的命令写入用户配置;目录缓存不含用户秘密。
|
|
87
|
+
|
|
88
|
+
`env` 只作用于该供应商,不更改全局进程环境。变量顺序不影响结果,循环引用拒绝。密钥、私有请求头、env 值与请求 options 保存在私有配置中,不随模型对象进入模型列表或日志。
|
|
89
|
+
|
|
90
|
+
## 覆盖与启停
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"providers": {
|
|
95
|
+
"deepseek": {
|
|
96
|
+
"apiKey": "$DEEPSEEK_API_KEY",
|
|
97
|
+
"modelOverrides": {
|
|
98
|
+
"deepseek-flash": { "maxTokens": 8192, "headers": { "x-route": "coding" } }
|
|
99
|
+
},
|
|
100
|
+
"allowlist": ["deepseek-*"],
|
|
101
|
+
"denylist": ["*-deprecated"]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"disabled_providers": ["unused-provider"]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`modelOverrides` 只修改已有条目;`models` 可以新增。保留旧的 `[{provider,id,api,...}]` 或 `{ "models": [...] }` 扁平格式。支持 provider/model 的 `disabled: true` / `enabled: false`、全局 `enabled_providers` / `disabled_providers`,以及 `allowlist` / `denylist`(同义 `whitelist` / `blacklist`),模式支持 `*` 和 `?`,deny 优先。无效同级模型给出字段路径,有效同级项继续可用;损坏的显式覆盖不会继续使用原来的凭据。
|
|
109
|
+
|
|
110
|
+
## 原生协议和云认证
|
|
111
|
+
|
|
112
|
+
| api | 接口与认证 |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `anthropic-messages` | Anthropic、支持 Messages 的网关;API key 或已有 Claude OAuth |
|
|
115
|
+
| `openai-completions` | Chat Completions 兼容端点 |
|
|
116
|
+
| `openai-responses` | OpenAI Responses;每次发完整投影,`store: false` |
|
|
117
|
+
| `openai-codex-responses` | ChatGPT 订阅端点;`/login codex` 或 `OPENAI_CODEX_ACCESS_TOKEN` |
|
|
118
|
+
| `azure-openai-responses` | Azure key + resource/base URL;支持 `AZURE_RESOURCE_NAME` / `AZURE_API_KEY` 别名 |
|
|
119
|
+
| `google-generative-ai` | Gemini 原生 API,Google/Gemini API key |
|
|
120
|
+
| `google-vertex` | Vertex API key,或 `auth: "ambient"` + ADC;项目和位置必需 |
|
|
121
|
+
| `bedrock-converse-stream` | AWS bearer token、profile、IAM/容器/身份链;`auth: "ambient"` 显式使用 SDK 凭据链 |
|
|
122
|
+
| `mistral-conversations` | Pi 的 Mistral 原生适配 |
|
|
123
|
+
| `pi-messages` | Pi Messages 兼容服务器 |
|
|
124
|
+
|
|
125
|
+
Vertex 可配置 scoped `env`:`GOOGLE_APPLICATION_CREDENTIALS`、`GOOGLE_CLOUD_PROJECT`、`GOOGLE_CLOUD_LOCATION`;也接受 OpenCode 的 `GOOGLE_VERTEX_PROJECT` / `GOOGLE_VERTEX_LOCATION`。Bedrock 使用 `AWS_PROFILE`、`AWS_REGION` 等 SDK 环境设置;resource/project/location 不会被当成 API key。需要端点模板的服务必须提供对应变量,例如 Cloudflare 的 account/gateway。
|
|
126
|
+
|
|
127
|
+
旧 `auth.json` 中存于 `openai` 的 Codex OAuth 可由 `openai-codex` 兼容读取;显式原生条目优先,普通 OpenAI API key 不共享到订阅协议。新的 `/login codex` 写入 `openai-codex`。其他 Pi 专属订阅登录流程不冒充已接入;可按协议配置 key/token。
|
|
128
|
+
|
|
129
|
+
## 可配置参数与边界
|
|
130
|
+
|
|
131
|
+
- `compat` / `nativeCompat` 传递 Pi 协议兼容能力;`thinkingLevelMap` 明确本地思考档到上游值的映射。
|
|
132
|
+
- `options` 支持 `temperature`、`samplingParams`、`cacheRetention`、`timeoutMs`、`maxRetryDelayMs`、`metadata`;具体协议只消费自己支持的参数。云 region/profile 通过 `env`。不认识的 option 明确报错。
|
|
133
|
+
- `samplingParams` 用于 OpenAI 兼容协议的采样扩展;`body` / `extraBody` 是实际原生请求体的额外字段。模型、system、消息、工具、stream 与服务端会话字段由投影/适配器负责,不能被这些扩展覆盖。
|
|
134
|
+
- D18 保留 xeno 客户端身份;不会自动带 Pi/Claude Code/Copilot 的产品身份或 attribution 头,也不会插入 Claude Code 的身份提示。订阅服务可能因此拒绝第三方客户端;此处不承诺所有订阅账户可用。
|
|
135
|
+
- Google/Vertex SDK 自行管理 HTTP,不使用自定义 fetch;Bedrock 自行管理 AWS HTTP 与重试,外层不再叠加重试。取消与终止状态仍统一交回 xeno。
|
|
136
|
+
|
|
137
|
+
## 覆盖、排除与验证依据
|
|
138
|
+
|
|
139
|
+
`src/runtime/model-data.ts` 同时保存完整来源元数据和 1,373 条排除记录。明确无工具能力或非文本输出的模型不进入 agent 可选目录;还需要专用 SDK 的条目保留排除原因,例如 GitLab、WatsonX、Vertex Anthropic、SAP、Merge Gateway、v0、Qvac。可用兼容服务仍可由用户指定 API/端点接入,不能仅新增一个名字就算支持了专用协议。
|
|
140
|
+
|
|
141
|
+
除了两份上游源码,Cohere、Venice、AIHubMix 的接入分别核对了 [Cohere compatibility API](https://docs.cohere.com/docs/compatibility-api)、[Venice API 官方资料](https://github.com/veniceai/api-docs/blob/main/agents.md)、[AIHubMix 快速开始](https://docs.aihubmix.com/en/quick-start)。Cohere 的 reasoning effort 按官方能力映射为 none/high;不发送其未支持的 store 字段。
|
|
142
|
+
|
|
143
|
+
上游配置依据:[Pi models](https://github.com/earendil-works/pi/blob/1b347794e2a630e4359f2584f4eea388145d0ddf/packages/coding-agent/docs/models.md)、[OpenCode provider](https://github.com/anomalyco/opencode/blob/2fa3363c924c5c3e367b84a87ae478296a0ed59b/packages/opencode/src/provider/provider.ts)、[Models.dev](https://models.dev/)。
|
|
144
|
+
|
|
145
|
+
本地验证覆盖十种协议的真实受控 HTTP(包含 AWS 二进制 EventStream)、签名/工具结果往返、错误重试/取消、实际 CLI JSON 输出、实际 PTY 重载/切换。没有逐一调用付费远程模型,目录条目数量不等于账户可用性或模型质量证明。
|
|
146
|
+
|
|
147
|
+
重生成时先下载并保存 Models.dev JSON,再运行 `bun scripts/update-model-catalog.ts <snapshot.json>`,审查来源摘要、条目/排除变化及测试固定计数。应用启动不执行生成器。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visual-z/xeno",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Segmented append-only agent log with pure context and handoff projections",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"src",
|
|
12
12
|
"README.md",
|
|
13
|
-
"
|
|
13
|
+
"CHANGELOG.md",
|
|
14
|
+
"docs/install.md",
|
|
15
|
+
"docs/providers.md"
|
|
14
16
|
],
|
|
15
17
|
"engines": {
|
|
16
18
|
"bun": ">=1.1.0"
|
|
@@ -34,7 +36,11 @@
|
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"@anthropic-ai/sdk": "^0.127.0",
|
|
39
|
+
"@earendil-works/pi-ai": "0.99.1",
|
|
40
|
+
"@silvia-odwyer/photon-node": "0.3.4",
|
|
37
41
|
"get-east-asian-width": "1.6.0",
|
|
42
|
+
"grok-mermaid": "0.2.3",
|
|
43
|
+
"highlight.js": "10.7.3",
|
|
38
44
|
"marked": "18.0.11"
|
|
39
45
|
},
|
|
40
46
|
"publishConfig": {
|
package/src/apps/cli.ts
CHANGED
|
@@ -13,25 +13,53 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
-
parseArgs, startup, readPipedStdin, mergePrintPrompt, silenceTtyEarly,
|
|
16
|
+
parseArgs, startup, readPipedStdin, mergePrintPrompt, silenceTtyEarly, printCliHelp,
|
|
17
17
|
} from "./startup.ts";
|
|
18
18
|
import { runPrompt, runRepl } from "./shell.ts";
|
|
19
|
+
import { runPackageCommand } from "../runtime/package-manager.ts";
|
|
20
|
+
import { exportHtmlFile } from "./export-cli.ts";
|
|
19
21
|
|
|
20
|
-
const args = parseArgs(process.argv.slice(2));
|
|
22
|
+
const args = parseArgs(process.argv.slice(2), { deferExtensions: true });
|
|
21
23
|
// Before startup reads auth, scans context files and prints the header:
|
|
22
24
|
// in cooked mode the tty would echo anything typed during that window
|
|
23
25
|
// straight into the banner.
|
|
24
|
-
const restoreTty = silenceTtyEarly({ interactive: !args.print && !args.prompt });
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
args.
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
const restoreTty = silenceTtyEarly({ interactive: !args.packageCommand && !args.help && !args.version && !args.exportFile && !args.print && !args.prompt });
|
|
27
|
+
process.once("exit", restoreTty);
|
|
28
|
+
try {
|
|
29
|
+
if (args.help && (args.packageCommand || args.configCommand || args.exportFile || args.version || args.listModels || args.modelsCommand)) {
|
|
30
|
+
printCliHelp();
|
|
31
|
+
} else if (args.version) {
|
|
32
|
+
if (args.extensionArgv) throw new Error("Unknown flags for --version");
|
|
33
|
+
const pkg = await Bun.file(new URL("../../package.json", import.meta.url)).json() as { version: string };
|
|
34
|
+
console.log(pkg.version);
|
|
35
|
+
} else if (args.exportFile) {
|
|
36
|
+
if (args.extensionArgv) throw new Error("Unknown flags for offline export");
|
|
37
|
+
console.log(`Exported ${await exportHtmlFile(args.exportFile, args.prompt || undefined, args.workspace)}`);
|
|
38
|
+
} else if (args.packageCommand) {
|
|
39
|
+
if (args.extensionArgv) throw new Error("Unknown package command flag");
|
|
40
|
+
if ((args.offline || process.env["XENO_OFFLINE"] === "1") && (args.packageCommand.operation === "update" || args.packageCommand.operation === "install" && args.packageCommand.sources.some(source => /^(npm:|git:|git\+|https?:\/\/|ssh:\/\/|git@)/.test(source)))) throw new Error("--offline prevents remote package installation or updates");
|
|
41
|
+
const controller = new AbortController(), cancel = () => controller.abort();
|
|
42
|
+
process.once("SIGINT", cancel); process.once("SIGTERM", cancel);
|
|
43
|
+
try { await runPackageCommand(args.packageCommand, { workspace: args.workspace, signal: controller.signal, ...(args.approve === undefined ? {} : { trusted: args.approve }) }); }
|
|
44
|
+
catch (error) { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = controller.signal.aborted ? 130 : 1; }
|
|
45
|
+
finally { process.off("SIGINT", cancel); process.off("SIGTERM", cancel); }
|
|
46
|
+
} else {
|
|
47
|
+
const app = await startup(args);
|
|
48
|
+
if (args.print) {
|
|
49
|
+
// With a prompt already given, stdin is optional context: wait briefly for it.
|
|
50
|
+
args.prompt = mergePrintPrompt(args.prompt,
|
|
51
|
+
await readPipedStdin(process.stdin, args.prompt.length > 0 ? { firstByteMs: 3_000 } : {}));
|
|
52
|
+
}
|
|
53
|
+
if (args.prompt) {
|
|
54
|
+
restoreTty();
|
|
55
|
+
await runPrompt(app, args.prompt);
|
|
56
|
+
} else {
|
|
57
|
+
await runRepl(app, restoreTty);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1;
|
|
62
|
+
} finally {
|
|
63
|
+
process.off("exit", restoreTty);
|
|
32
64
|
restoreTty();
|
|
33
|
-
await runPrompt(app, args.prompt);
|
|
34
|
-
} else {
|
|
35
|
-
try { await runRepl(app); }
|
|
36
|
-
finally { restoreTty(); }
|
|
37
65
|
}
|