samagotchi 0.3.0 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +162 -1
- data/README.md +29 -2
- data/bin/chi +60 -69
- data/docs/cli.md +211 -77
- data/docs/configuration.md +118 -21
- data/docs/desktop.md +39 -4
- data/docs/guardrails.md +11 -0
- data/docs/hooks.md +89 -7
- data/docs/memory.md +40 -0
- data/docs/plugins.md +50 -0
- data/docs/releasing.md +15 -12
- data/docs/sessions.md +20 -18
- data/lib/samagotchi/bootstrap/config_writer.rb +1 -2
- data/lib/samagotchi/bridge/sse_writer.rb +0 -3
- data/lib/samagotchi/bridge/turn_accumulator.rb +2 -0
- data/lib/samagotchi/bridge.rb +20 -12
- data/lib/samagotchi/bundles/skills/manifest.yml +10 -0
- data/lib/samagotchi/bundles/skills/plugin.rb +419 -0
- data/lib/samagotchi/bundles/source-links/hooks/source_links.rb +178 -5
- data/lib/samagotchi/bundles/source-links/manifest.yml +3 -3
- data/lib/samagotchi/bundles/source-links/source_links.md +1 -1
- data/lib/samagotchi/bundles/system/config_modification_protocol.md +9 -10
- data/lib/samagotchi/bundles/system/delegated.md +6 -7
- data/lib/samagotchi/bundles/system/identity.md +5 -0
- data/lib/samagotchi/bundles/system/manifest.yml +6 -6
- data/lib/samagotchi/bundles/system/memory_guide.md +26 -0
- data/lib/samagotchi/bundles/system/self_map.md +2 -1
- data/lib/samagotchi/client.rb +25 -26
- data/lib/samagotchi/commands/registry.rb +8 -0
- data/lib/samagotchi/config.rb +97 -113
- data/lib/samagotchi/desktop/macos/App.swift +12 -8
- data/lib/samagotchi/desktop/macos/ChiRunner.swift +4 -2
- data/lib/samagotchi/desktop/macos/Images.swift +113 -0
- data/lib/samagotchi/desktop/macos/Info.plist.erb +6 -0
- data/lib/samagotchi/desktop/macos/Panel.swift +112 -9
- data/lib/samagotchi/desktop/macos.rb +59 -8
- data/lib/samagotchi/desktop_command.rb +6 -3
- data/lib/samagotchi/edit_preview.rb +82 -0
- data/lib/samagotchi/engine.rb +236 -443
- data/lib/samagotchi/gem_update.rb +89 -0
- data/lib/samagotchi/guardrails/approval.rb +26 -4
- data/lib/samagotchi/guardrails/load_failures.rb +9 -3
- data/lib/samagotchi/host_registry.rb +8 -12
- data/lib/samagotchi/idle_client.rb +24 -15
- data/lib/samagotchi/idle_reminders.rb +2 -2
- data/lib/samagotchi/image_store.rb +10 -6
- data/lib/samagotchi/kernel_loop.rb +59 -123
- data/lib/samagotchi/live_versions.rb +65 -0
- data/lib/samagotchi/llm/api_key.rb +41 -0
- data/lib/samagotchi/llm/chat_loop.rb +77 -13
- data/lib/samagotchi/llm/errors.rb +38 -7
- data/lib/samagotchi/llm/http.rb +19 -22
- data/lib/samagotchi/llm/openai_chat.rb +22 -26
- data/lib/samagotchi/memory_bundle/installer.rb +65 -63
- data/lib/samagotchi/memory_bundle/provenance.rb +51 -12
- data/lib/samagotchi/memory_bundle/shipped_update.rb +157 -0
- data/lib/samagotchi/memory_bundle/status.rb +4 -1
- data/lib/samagotchi/memory_bundle/system_bundle.rb +81 -53
- data/lib/samagotchi/model_profile.rb +27 -10
- data/lib/samagotchi/note_command.rb +2 -1
- data/lib/samagotchi/prompt.rb +4 -2
- data/lib/samagotchi/reminder_store.rb +1 -9
- data/lib/samagotchi/reply_wait.rb +48 -4
- data/lib/samagotchi/self_report.rb +37 -5
- data/lib/samagotchi/send_command.rb +190 -17
- data/lib/samagotchi/session.rb +4 -2
- data/lib/samagotchi/session_commands.rb +38 -8
- data/lib/samagotchi/session_manager.rb +19 -53
- data/lib/samagotchi/system_prompt.rb +403 -0
- data/lib/samagotchi/terminal_ui/attach_launcher.rb +5 -3
- data/lib/samagotchi/terminal_ui/attached_loop.rb +141 -108
- data/lib/samagotchi/terminal_ui/attached_view.rb +27 -12
- data/lib/samagotchi/terminal_ui/event_renderer.rb +29 -8
- data/lib/samagotchi/terminal_ui/formatting.rb +41 -22
- data/lib/samagotchi/terminal_ui/input_support.rb +7 -23
- data/lib/samagotchi/terminal_ui/plain_surface.rb +13 -7
- data/lib/samagotchi/terminal_ui/question_prompt.rb +35 -0
- data/lib/samagotchi/terminal_ui/status_row.rb +81 -0
- data/lib/samagotchi/terminal_ui/surface.rb +1 -1
- data/lib/samagotchi/terminal_ui.rb +142 -923
- data/lib/samagotchi/text_diff.rb +181 -0
- data/lib/samagotchi/thinking.rb +126 -0
- data/lib/samagotchi/tool_activity.rb +52 -2
- data/lib/samagotchi/tool_runner.rb +37 -1
- data/lib/samagotchi/tools/ask_user_question.rb +41 -33
- data/lib/samagotchi/tools/edit.rb +23 -9
- data/lib/samagotchi/tools/execute.rb +3 -3
- data/lib/samagotchi/tools/output_guardrails.rb +8 -7
- data/lib/samagotchi/tools/read.rb +4 -4
- data/lib/samagotchi/tools/write.rb +4 -0
- data/lib/samagotchi/turn_flow.rb +12 -2
- data/lib/samagotchi/update_command.rb +309 -0
- data/lib/samagotchi/update_hint.rb +59 -0
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/vision_support.rb +6 -4
- data/lib/samagotchi/web/app.rb +173 -38
- data/lib/samagotchi/web/lan.rb +99 -0
- data/lib/samagotchi/web/message_parts.rb +19 -10
- data/lib/samagotchi/web/public/activity.js +10 -0
- data/lib/samagotchi/web/public/app.js +135 -78
- data/lib/samagotchi/web/public/chat_view.js +8 -1
- data/lib/samagotchi/web/public/data.js +2 -0
- data/lib/samagotchi/web/public/diff_view.js +58 -0
- data/lib/samagotchi/web/public/index.html +185 -18
- data/lib/samagotchi/web/public/model_pick.js +136 -0
- data/lib/samagotchi/web/public/model_picker.js +224 -0
- data/lib/samagotchi/web/public/notify.js +10 -0
- data/lib/samagotchi/web/public/question_card.js +3 -1
- data/lib/samagotchi/web/public/stage_model.js +110 -0
- data/lib/samagotchi/web/public/stage_view.js +580 -0
- data/lib/samagotchi/web/public/timing.js +6 -2
- data/lib/samagotchi/web/public/turn_events.js +38 -10
- data/lib/samagotchi/web/public/turn_model.js +11 -3
- data/lib/samagotchi/web/public/turn_view.js +76 -20
- data/lib/samagotchi/web/qr.rb +40 -0
- data/lib/samagotchi/web/server.rb +101 -11
- data/lib/samagotchi/web/token.rb +97 -0
- data/lib/samagotchi/worker.rb +5 -4
- metadata +38 -3
- data/lib/samagotchi/terminal_ui/legacy_surface.rb +0 -111
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 94cd11abcfad07ad2843b4e0fc2eea368d77ab6080403d308db906270a1832c6
|
|
4
|
+
data.tar.gz: 21ac6e7093ee196d98e2ba50979cdbb28f1a3a10ab0e9cac9bad01c88a078daf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fa39259864928d70d8cf830d0c7cc15c6865cea75d383484979897800a9f79d6f9fa4d79df3700285d9871e8d0cf5420e9af7c0143ab08e71182befa287b52af
|
|
7
|
+
data.tar.gz: 24f0fe6863767b628c1eec6957bf6cf33d8966b45f8b2cbdfd7ab268d6c323835dba8ff09fbdd9359775263693228a7a11f0d125cf0a38d7f044d6932ca7c4b9
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,165 @@ and commands may change between minor versions. How releases are made:
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.5.0] - 2026-09-30
|
|
12
|
+
|
|
13
|
+
### Security
|
|
14
|
+
|
|
15
|
+
- `chi web` and the worker Bridge refuse requests from other websites. Before,
|
|
16
|
+
a page open in your browser could start a session that runs commands, or
|
|
17
|
+
read your sessions and their output. Please update if you run `chi web`.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Skills: a memory named `skill_<name>` holds the steps of a task you did with
|
|
22
|
+
chi. Say "let's memorize this" and chi saves it; next time it reads and
|
|
23
|
+
follows it, and fixes a step that turned out different in the same turn
|
|
24
|
+
(docs/memory.md, Skills). The system bundle's identity and memory guide
|
|
25
|
+
teach it.
|
|
26
|
+
- The `skills` bundle (`chi bundle install skills`): `/skill save [name]
|
|
27
|
+
[--system]`, `/skill list`, `/skill show`, `/skill diff`; older versions of
|
|
28
|
+
each skill kept (`history_keep`) with a one-line diff after every update;
|
|
29
|
+
a nudge when a followed skill's step fails and the model goes on without
|
|
30
|
+
fixing it (docs/plugins.md, The skills bundle).
|
|
31
|
+
- `chi web --web-host lan` (`web.host: lan`, or one of this machine's IPv4
|
|
32
|
+
addresses): the web UI on your phone. chi web also listens on the LAN
|
|
33
|
+
address and prints a link with an access token and its QR code; every
|
|
34
|
+
request from another machine needs the token, which the page keeps in a
|
|
35
|
+
cookie. `chi web --new-token` replaces it; `chi self` says when chi web runs
|
|
36
|
+
on the LAN. Plain http: for a home network only. New runtime dependency:
|
|
37
|
+
`rqrcode_core`.
|
|
38
|
+
- A third web view, `web.view: stage` (`--web-view stage`): the running turn
|
|
39
|
+
sits above the composer, its tool calls in an expandable cloud, and hands
|
|
40
|
+
off smoothly into the history when it ends. `web.view: turn | stage | chat`
|
|
41
|
+
replaces `web.turn_view` (turn stays the default).
|
|
42
|
+
- The start page's model picker is searchable: models grouped by host, your
|
|
43
|
+
last 5 picks first, every typed word matched ("deepseek4.1 fla" finds
|
|
44
|
+
`openrouter · deepseek/deepseek-v4.1-flash`), arrow keys, Enter and Esc.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- config.yml edits apply without restarting `chi web`: new sessions read the
|
|
49
|
+
file, and running ones pick up settings they read each time (retries,
|
|
50
|
+
limits, log level). Old flat `UPPER_CASE` keys and `backend:` are no longer
|
|
51
|
+
read; they warn as unknown keys.
|
|
52
|
+
- The terminal REPL (`chi --no-shared`, `chi scratch`) shows turns the way
|
|
53
|
+
the attached terminal does, and all three UIs end a turn with the same
|
|
54
|
+
words ("✕ turn canceled (Ctrl-C) · 3.1s", "✕ turn failed: …"); a provider
|
|
55
|
+
retry shows as a dim line. The REPL-only settings `thinking.ui`,
|
|
56
|
+
`thinking.render_interval` and `status.width_mode` / `max_width` /
|
|
57
|
+
`fixed_width` are gone.
|
|
58
|
+
- `session.keep_status` defaults to none: a session left "running" by a
|
|
59
|
+
crashed worker is cleaned up like any other; a session with a live worker
|
|
60
|
+
is never removed.
|
|
61
|
+
- `chi send --image` to a model that can't take images is refused before
|
|
62
|
+
anything is sent, with the reason, instead of failing in the session.
|
|
63
|
+
- A low/medium/high thinking level on a llama.cpp chat host whose template
|
|
64
|
+
ignores it says so once.
|
|
65
|
+
- The web answers `/stats`, `/recap` and `/detach` itself (they're terminal
|
|
66
|
+
commands) instead of showing a worker error.
|
|
67
|
+
- Piped input to an attached chi (`echo "do X" | chi`, `chi -p X` with no
|
|
68
|
+
terminal) waits for its turns to end and exits 1 if one failed, instead of
|
|
69
|
+
detaching at once.
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- OpenRouter's "overloaded" error sent inside an HTTP 200 is retried like a
|
|
74
|
+
503 instead of failing the turn.
|
|
75
|
+
- The context line the model sees during a long tool loop counts the tool
|
|
76
|
+
output added since the last request, so the model knows when to wrap up.
|
|
77
|
+
- `chi send --wait` no longer hangs when the turn fails very fast (for
|
|
78
|
+
example right after an earlier failure); it says the turn failed and why.
|
|
79
|
+
- On Linux the system prompt now gets the "prefer rg" hint when rg is
|
|
80
|
+
installed (the check only worked on macOS).
|
|
81
|
+
- `chi sessions list --live` shows the test sessions of a test run.
|
|
82
|
+
- `chi -p` with no terminal (stdin from a pipe or /dev/null) sends its prompt
|
|
83
|
+
once: a failed turn re-sent it in a loop (hundreds of requests a second),
|
|
84
|
+
and an attached `chi -p` didn't send it at all.
|
|
85
|
+
|
|
86
|
+
Update with `chi update`. Bundle added: skills 0.1.0 (`chi bundle install
|
|
87
|
+
skills`).
|
|
88
|
+
|
|
89
|
+
## [0.4.0] - 2026-09-30
|
|
90
|
+
|
|
91
|
+
### Added
|
|
92
|
+
|
|
93
|
+
- `chi update`: brings an installed chi up to date in one command: the gem
|
|
94
|
+
from rubygems, then the system bundle, the shipped bundles you installed and
|
|
95
|
+
the desktop helper (rebuilt only when its sources changed), shown in one
|
|
96
|
+
table. Your edits to bundle files are kept and reported, running workers and
|
|
97
|
+
an old `chi web` are only reported, `--dry-run` shows the plan, and
|
|
98
|
+
`--no-gem` / `--no-bundles` / `--no-desktop` (or `update.*` in config.yml)
|
|
99
|
+
skip parts. The first start of a new chi version says in one line when
|
|
100
|
+
something can be updated.
|
|
101
|
+
- A thinking level per model, host or run: `thinking: off | low | medium |
|
|
102
|
+
high | default` (`models.<key>.thinking`, `hosts.<name>.thinking`,
|
|
103
|
+
`thinking.level`, `--thinking LEVEL`). Chat hosts get the matching request
|
|
104
|
+
fields; native Qwen and Gemma turn thinking off. chi says once when a level
|
|
105
|
+
can't work on a host, and a host that refuses the thinking fields (gpt-oss
|
|
106
|
+
on OpenRouter) is asked again without them. `/model` and `chi self` show
|
|
107
|
+
the level.
|
|
108
|
+
- Edit previews: an edit/write approval shows the diff it would make, in the
|
|
109
|
+
web card and in the terminal, and every edit/write row gets a
|
|
110
|
+
"diff +3 −1" that opens to the change (live, after a reload and on a join).
|
|
111
|
+
- `chi send --image PATH` (repeatable, up to 20): images go with the message
|
|
112
|
+
as attachments, the same as the web composer's chips; converted and
|
|
113
|
+
downscaled once, then copied into each session. Works with `--new` (the
|
|
114
|
+
session starts idle, then gets the message with its images) and `--wait`.
|
|
115
|
+
A missing file or a non-image stops the send before anything goes out.
|
|
116
|
+
- The desktop helper takes images: a clipboard screenshot, image files from
|
|
117
|
+
Finder's Send to chi, other apps' image data, or a drop on the panel; they
|
|
118
|
+
show as thumbnails and go with the message.
|
|
119
|
+
- source-links 0.3.0: `#12` links to the current project's repo (from its git
|
|
120
|
+
remote) and `owner/repo#12` to that repo; `url:` templates take `{1}`,
|
|
121
|
+
`{name}`, `{repo}` and `{host}`, with `remote:` and `remote_host:` per
|
|
122
|
+
source, and the note lists each link once.
|
|
123
|
+
- The web shows when the provider is asked again after an error ("↻ retrying
|
|
124
|
+
(503) in 3 s, 1/2") or a turn waits for a plugin's setup.
|
|
125
|
+
|
|
126
|
+
### Changed
|
|
127
|
+
|
|
128
|
+
- A model named with a host that isn't configured (`nosuch:org/model`, or a
|
|
129
|
+
provider's name like `openrouter:x`) is an error that names the host and
|
|
130
|
+
lists the configured ones, in the CLI, `chi send --new`, the web and
|
|
131
|
+
`/model`, instead of going to the default host.
|
|
132
|
+
- The terminal no longer rewrites `#word` into a memory reference: "PR #1"
|
|
133
|
+
and "#ff0000" reach the model as typed (Tab still completes `#name`).
|
|
134
|
+
- A question you dismiss reaches the model as dismissed, not as a tool
|
|
135
|
+
error, so it keeps asking when it should.
|
|
136
|
+
- `/quit` works in the REPL like `/exit`, and the web answers it too;
|
|
137
|
+
`/stats` and `/recap` take trailing words in both terminals.
|
|
138
|
+
- A delegated session gets reworded rules: the answer first, then evidence,
|
|
139
|
+
then what's unverified; follow-up messages arrive as new turns.
|
|
140
|
+
|
|
141
|
+
### Fixed
|
|
142
|
+
|
|
143
|
+
- A llama.cpp server started with `--api-key` works: the key in
|
|
144
|
+
`api_key_env` is sent on every request (it got 401). A 401/403 from any host
|
|
145
|
+
now says which variable to check or to set `api_key_env`.
|
|
146
|
+
- A bundle upgrade that keeps your edited file no longer disables the
|
|
147
|
+
bundle's plugin, and the system bundle stops warning about the same edit on
|
|
148
|
+
every start.
|
|
149
|
+
- One bundle with a broken manifest.json no longer stops the hooks of the
|
|
150
|
+
bundles after it from loading.
|
|
151
|
+
- A long-running worker picks up edited guardrail rules.
|
|
152
|
+
- `write` without content fails instead of emptying the file.
|
|
153
|
+
- Per-model `vision:` follows a model alias, like `profile:` and `sampling:`.
|
|
154
|
+
- A timeout of 0 in config means the default on llama.cpp hosts too (it was a
|
|
155
|
+
0-second timeout).
|
|
156
|
+
- A reminder turn drops a pending continue offer, so a later "no" can't roll
|
|
157
|
+
the reminder back.
|
|
158
|
+
- More than 8 options in `ask_user_question` is always an error (one path
|
|
159
|
+
silently used the first 8).
|
|
160
|
+
- A memory read with a comma list counts each name in the REPL and the web.
|
|
161
|
+
- `/archive` or `/quit` typed during a REPL turn no longer goes to the model
|
|
162
|
+
as text; `EXIT --DELETE` works in any case in an attached terminal.
|
|
163
|
+
- `chi bundle status` finds index lines again (it said "no-index" for every
|
|
164
|
+
file).
|
|
165
|
+
|
|
166
|
+
Update with `chi update` (new in this version: from 0.3.0, run
|
|
167
|
+
`gem install samagotchi` once, then `chi update`). Bundle moved:
|
|
168
|
+
source-links 0.3.0.
|
|
169
|
+
|
|
11
170
|
## [0.3.0] - 2026-09-29
|
|
12
171
|
|
|
13
172
|
### Added
|
|
@@ -153,6 +312,8 @@ and long-lived sessions.
|
|
|
153
312
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
154
313
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
155
314
|
|
|
156
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
315
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.5.0...HEAD
|
|
316
|
+
[0.5.0]: https://github.com/dm1try/samagotchi/compare/v0.4.0...v0.5.0
|
|
317
|
+
[0.4.0]: https://github.com/dm1try/samagotchi/compare/v0.3.0...v0.4.0
|
|
157
318
|
[0.3.0]: https://github.com/dm1try/samagotchi/compare/v0.2.0...v0.3.0
|
|
158
319
|
[0.2.0]: https://github.com/dm1try/samagotchi/releases/tag/v0.2.0
|
data/README.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# samagotchi
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
chi is a local-first, human-in-the-loop agent harness. It remembers what you
|
|
4
|
+
teach it, as memories and skills, and corrects them when a step turns out
|
|
5
|
+
different. You stay in the loop from the terminal or the browser.
|
|
6
|
+
|
|
7
|
+
Samagotchi is the engine; chi (pronounced "chee") is its short name and CLI
|
|
8
|
+
command.
|
|
5
9
|
|
|
6
10
|
> **Pre-1.0:** config and commands may change between minor versions (0.2 →
|
|
7
11
|
> 0.3); the [CHANGELOG](CHANGELOG.md) says what changed. chi is used daily and
|
|
@@ -32,6 +36,22 @@ bin/chi self
|
|
|
32
36
|
`bin/chi` runs the checkout; `bundle exec rake gem:install` installs it as a
|
|
33
37
|
local gem, which puts `chi` on your PATH.
|
|
34
38
|
|
|
39
|
+
### Updating
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
chi update --dry-run # what would change
|
|
43
|
+
chi update # the gem, then the bundles and the desktop helper
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`chi update` installs the newest samagotchi from rubygems.org (old versions
|
|
47
|
+
stay installed: running sessions still use them), then brings the rest up to
|
|
48
|
+
the new version: the system bundle, the bundles chi ships that you installed,
|
|
49
|
+
and the macOS helper (rebuilt only when its sources changed). Memory files you
|
|
50
|
+
edited are kept, and the table says which. Running sessions move to the new
|
|
51
|
+
chi when their worker idles out (30 min) or on `chi sessions stop ID`; a
|
|
52
|
+
running `chi web` needs a restart. From a checkout, `git pull` instead. See
|
|
53
|
+
[CLI: Updating](docs/cli.md#updating).
|
|
54
|
+
|
|
35
55
|
## Set up
|
|
36
56
|
|
|
37
57
|
Point chi at your model server; it works out the rest and writes
|
|
@@ -87,6 +107,7 @@ chi --no-shared # the plain in-process REPL
|
|
|
87
107
|
chi -p "explain lib/" --non-interactive # one turn, print the answer, exit
|
|
88
108
|
chi --resume <session-id> # continue a saved session
|
|
89
109
|
chi web --open # web UI: this project's sessions (--scope=all: every one)
|
|
110
|
+
chi web --web-host lan # the web UI on your phone too: scan the QR code it prints
|
|
90
111
|
chi sessions list # this project's saved sessions (--scope=all: every one)
|
|
91
112
|
pbpaste | chi note --source slack <id> # background context for a session (no turn)
|
|
92
113
|
pbpaste | chi send -m "same bug?" <id> # a message to a session, the clipboard quoted above it
|
|
@@ -97,6 +118,12 @@ chi send --new --wait -m "review feat/x" # a new session you can watch in the w
|
|
|
97
118
|
|
|
98
119
|
`/model` switches models, Ctrl-C cancels a turn, and Ctrl-D or `/detach` detaches (the session keeps running; `chi --attach ID` comes back). `/exit` detaches and stops the session's worker too, unless something still needs it (a running turn, another UI); `chi --resume ID` picks the conversation up again. `/exit --delete` also deletes the session once the worker has gone; `chi sessions delete ID` deletes one from the shell. `/archive` (or `chi sessions archive ID`) hides a session from every list and keeps it for good; `chi sessions list --archived` finds it again.
|
|
99
120
|
|
|
121
|
+
`chi web --web-host lan` opens the web UI to your home network with an
|
|
122
|
+
access token: anyone with the printed link (or its QR code) can run commands
|
|
123
|
+
as you, and it is plain http, readable by anyone on the same Wi-Fi. Use it at
|
|
124
|
+
home, never on a shared network, and `chi web --new-token` if a link leaks.
|
|
125
|
+
See [chi web on your phone](docs/cli.md#chi-web-on-your-phone).
|
|
126
|
+
|
|
100
127
|
### Context notes
|
|
101
128
|
|
|
102
129
|
`chi note` pushes text into one or more sessions as background, not as a
|
data/bin/chi
CHANGED
|
@@ -14,7 +14,7 @@ end
|
|
|
14
14
|
require "optparse"
|
|
15
15
|
require "samagotchi/config"
|
|
16
16
|
|
|
17
|
-
Samagotchi::ConfigFile.
|
|
17
|
+
Samagotchi::ConfigFile.load!
|
|
18
18
|
require "samagotchi"
|
|
19
19
|
|
|
20
20
|
# `chi self`: print version, source dir, config/memory/session paths, model and
|
|
@@ -50,7 +50,7 @@ if ARGV[0] == "sessions"
|
|
|
50
50
|
puts " delete [--force] ID... # delete sessions for good (IDs or unique prefixes); --force stops a live worker first"
|
|
51
51
|
puts " prune [--dry-run] [--days N] [--keep N] [--keep-status running,...] [--test-only]"
|
|
52
52
|
puts " clean [--dry-run] [--days N] # test sessions (SAMAGOTCHI_ENV=test, CI) and leftover chi scratch ones: all of them, or those older than N days"
|
|
53
|
-
puts "Defaults: days=14 keep=500 keep_status=
|
|
53
|
+
puts "Defaults: days=14 keep=500 keep_status=none (config: session.retention_days, session.max_count, session.keep_status)"
|
|
54
54
|
exit 0
|
|
55
55
|
end
|
|
56
56
|
dry_run = sessions_args.include?("--dry-run")
|
|
@@ -110,10 +110,12 @@ if ARGV[0] == "sessions"
|
|
|
110
110
|
project = scope == "all" || cwd ? nil : Samagotchi::ProjectScope.root_for(Dir.pwd)
|
|
111
111
|
scope_note = ->(count) { "#{count} session(s) in #{File.basename(project)} (--scope=all: every project)" }
|
|
112
112
|
# The picker (chi note from a script): filters apply before the limit,
|
|
113
|
-
# and test runs stay out
|
|
113
|
+
# and test runs stay out, unless this is one (SAMAGOTCHI_ENV=test, CI):
|
|
114
|
+
# then its own sessions are what it looks for.
|
|
114
115
|
if live || cwd || (format && format != "text")
|
|
115
116
|
summaries = Samagotchi::SessionManager.session_summaries(
|
|
116
|
-
live: live, cwd: cwd, limit: limit || (live ? 10 : nil), include_tests:
|
|
117
|
+
live: live, cwd: cwd, limit: limit || (live ? 10 : nil), include_tests: Samagotchi::Session.test_session_env?,
|
|
118
|
+
project_root: project,
|
|
117
119
|
include_archived: include_archived
|
|
118
120
|
)
|
|
119
121
|
case format
|
|
@@ -142,7 +144,7 @@ if ARGV[0] == "sessions"
|
|
|
142
144
|
end
|
|
143
145
|
# A delegated session points at its parent.
|
|
144
146
|
child = summary[:parent_short_id] ? " ↳ #{summary[:parent_short_id]}" : ""
|
|
145
|
-
flag = summary[:scratch] ? " [scratch]" : ""
|
|
147
|
+
flag = summary[:scratch] ? " [scratch]" : (summary[:test_run] ? " [test]" : "")
|
|
146
148
|
flag += " [archived]" if summary[:archived]
|
|
147
149
|
ctx = Samagotchi::SessionMetrics.context_label(summary[:ctx_pct])
|
|
148
150
|
puts "#{summary[:id]} #{state.ljust(8)} #{ctx.ljust(8)} #{summary[:updated_at]} #{desc}#{flag}#{child}"
|
|
@@ -257,6 +259,12 @@ if ARGV[0] == "bootstrap"
|
|
|
257
259
|
exit Samagotchi::BootstrapCommand.new(ARGV[1..] || []).run
|
|
258
260
|
end
|
|
259
261
|
|
|
262
|
+
# `chi update`: bring an installed chi up to date, before OptionParser (its own flags)
|
|
263
|
+
if ARGV[0] == "update"
|
|
264
|
+
require "samagotchi/update_command"
|
|
265
|
+
exit Samagotchi::UpdateCommand.new(ARGV[1..] || []).run
|
|
266
|
+
end
|
|
267
|
+
|
|
260
268
|
# `chi desktop`: the native "Send to chi" helper, before OptionParser (its own flags)
|
|
261
269
|
if ARGV[0] == "desktop"
|
|
262
270
|
require "samagotchi/desktop_command"
|
|
@@ -372,7 +380,7 @@ if ARGV[0] == "bundle"
|
|
|
372
380
|
lines << ""
|
|
373
381
|
lines << "Your task: resolve each conflict by editing the file in place using the memory_write tool."
|
|
374
382
|
lines << "Use memory_read to inspect current content if needed. The correct scope for memory_write is the bundle's scope."
|
|
375
|
-
lines << "When all conflicts are resolved, type /exit to finish. If you
|
|
383
|
+
lines << "When all conflicts are resolved, type /exit to finish. If you stop early, the files stay as they are (the rest of the upgrade is already applied)."
|
|
376
384
|
lines.join("\n")
|
|
377
385
|
end
|
|
378
386
|
|
|
@@ -529,7 +537,7 @@ if ARGV[0] == "bundle"
|
|
|
529
537
|
ans = begin; $stdin.gets; rescue => _e; nil; end
|
|
530
538
|
launch = ans && ans.strip.downcase.start_with?("y")
|
|
531
539
|
else
|
|
532
|
-
puts "Non-interactive terminal
|
|
540
|
+
puts "Non-interactive terminal: kept your edits in the file(s) above; the rest is upgraded. Re-run with --force to take the bundle's version, or --agent in a TTY to merge."
|
|
533
541
|
exit 2
|
|
534
542
|
end
|
|
535
543
|
if launch
|
|
@@ -537,37 +545,15 @@ if ARGV[0] == "bundle"
|
|
|
537
545
|
puts "Launching interactive session for conflict resolution… (/exit when done)"
|
|
538
546
|
require "samagotchi/terminal_ui"
|
|
539
547
|
Samagotchi::TerminalUI.new(prompt: prompt).run
|
|
540
|
-
#
|
|
541
|
-
#
|
|
542
|
-
#
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
# Re-collect provenance files from target dir for this bundle
|
|
546
|
-
prov_files = {}
|
|
547
|
-
target_scope = scope || provenance.read[:scope]&.to_s || "system"
|
|
548
|
-
target_dir = Samagotchi::MemoryBundle::Installer.new(source: expanded_source, name: bundle_name, scope: target_scope).send(:resolve_target_dir, target_scope)
|
|
549
|
-
# Actually reuse provenance write with current target files for bundle keys
|
|
550
|
-
bundle_files = installer.conflicts.keys + installer.results.select { |_, r| %w[installed updated].include?(r[:status]) }.keys
|
|
551
|
-
# Fallback: collect all md that exist and were in installer results
|
|
552
|
-
all_keys = installer.results.keys
|
|
553
|
-
all_keys.each do |k|
|
|
554
|
-
p = File.join(target_dir, k)
|
|
555
|
-
prov_files[k] = p if File.exist?(p)
|
|
556
|
-
end
|
|
557
|
-
if prov_files.any?
|
|
558
|
-
Samagotchi::MemoryBundle::Provenance.new(name: bundle_name).write(
|
|
559
|
-
files: prov_files,
|
|
560
|
-
scope: target_scope,
|
|
561
|
-
version: manifest.version,
|
|
562
|
-
source_path: expanded_source
|
|
563
|
-
)
|
|
564
|
-
puts "Provenance updated after interactive resolution."
|
|
565
|
-
end
|
|
566
|
-
end
|
|
548
|
+
# The installer already recorded the upgrade (conflicted files
|
|
549
|
+
# kept their old base); the resolved files now start from the
|
|
550
|
+
# bundle's version.
|
|
551
|
+
Samagotchi::MemoryBundle::Provenance.new(name: bundle_name).resolve_conflicts(installer.conflicts)
|
|
552
|
+
puts "Provenance updated after interactive resolution."
|
|
567
553
|
puts "Upgrade resolved interactively."
|
|
568
554
|
exit 0
|
|
569
555
|
else
|
|
570
|
-
puts "
|
|
556
|
+
puts "Kept your edits in the file(s) above; the rest is upgraded. chi bundle diff #{bundle_name} FILE shows the base; re-run with --force to take the bundle's version."
|
|
571
557
|
exit 2
|
|
572
558
|
end
|
|
573
559
|
end
|
|
@@ -637,6 +623,7 @@ if ARGV[0] == "bundle"
|
|
|
637
623
|
puts "Target: #{st[:target_dir]}"
|
|
638
624
|
st[:files].each do |k, info|
|
|
639
625
|
mods = []
|
|
626
|
+
mods << "conflict (kept your edits over v#{st[:provenance][:version]}: chi bundle diff #{name} #{k})" if info[:conflict]
|
|
640
627
|
mods << "modified" if info[:modified]
|
|
641
628
|
mods << "missing" if info[:missing]
|
|
642
629
|
mods << "no-index" unless info[:index_present]
|
|
@@ -806,6 +793,7 @@ if ARGV[0] == "bundle"
|
|
|
806
793
|
line += " (shipped v#{b.upgrade.version}: chi bundle upgrade #{b.upgrade.source})" if b.upgrade
|
|
807
794
|
puts line
|
|
808
795
|
end
|
|
796
|
+
puts " (or all at once: chi update)" if installed.any?(&:upgrade)
|
|
809
797
|
end
|
|
810
798
|
unless available.empty?
|
|
811
799
|
puts ""
|
|
@@ -913,15 +901,9 @@ scratch = ARGV[0] == "scratch"
|
|
|
913
901
|
ARGV.shift if scratch
|
|
914
902
|
|
|
915
903
|
# no_interrupt / no_default_input start from config.yml or the env; the flags below turn them on.
|
|
916
|
-
options = { verbose: false, no_interrupt: Samagotchi::Config.get("no_interrupt"), non_interactive: false, no_default_input: Samagotchi::Config.get("no_default_input"), web: false, web_port: nil, web_open: false, web_markdown: nil,
|
|
904
|
+
options = { verbose: false, no_interrupt: Samagotchi::Config.get("no_interrupt"), non_interactive: false, no_default_input: Samagotchi::Config.get("no_default_input"), web: false, web_port: nil, web_open: false, web_markdown: nil, web_view: nil }
|
|
917
905
|
cli_overrides = {}
|
|
918
906
|
|
|
919
|
-
if ARGV.any? { |arg| arg == "--backend" || arg.start_with?("--backend=") }
|
|
920
|
-
warn "Error: --backend was removed. A host's api: in config.yml picks the loop " \
|
|
921
|
-
"(api: openai for the chat API; see docs/configuration.md)."
|
|
922
|
-
exit 1
|
|
923
|
-
end
|
|
924
|
-
|
|
925
907
|
# Strict kebab enforcement: --recap_base_url is unknown (OptionParser would otherwise accept _ as -)
|
|
926
908
|
ARGV.each do |arg|
|
|
927
909
|
next unless arg.start_with?("--") && arg.include?("_")
|
|
@@ -930,7 +912,7 @@ ARGV.each do |arg|
|
|
|
930
912
|
base = arg.split("=", 2).first
|
|
931
913
|
# If dashed version is a known flag (registry or hardcoded), reject underscore variant
|
|
932
914
|
dashed = base.tr("_", "-")
|
|
933
|
-
known = %w[--prompt --resume --attach --shared --no-shared --model --memory --mute --no-interrupt --non-interactive --verbose --no-default-input --port --open] + Samagotchi::Config.cli_entries.map(&:cli_flag)
|
|
915
|
+
known = %w[--prompt --resume --attach --shared --no-shared --model --thinking --memory --mute --no-interrupt --non-interactive --verbose --no-default-input --port --open --new-token] + Samagotchi::Config.cli_entries.map(&:cli_flag)
|
|
934
916
|
if known.include?(dashed) || known.include?(base)
|
|
935
917
|
warn "Unknown option: #{arg} (did you mean #{dashed}?)"
|
|
936
918
|
exit 1
|
|
@@ -949,6 +931,7 @@ parser = OptionParser.new do |opts|
|
|
|
949
931
|
chi bundle <install|upgrade|uninstall|status|diff|list|build>
|
|
950
932
|
chi desktop <install|upgrade|uninstall|status> macOS "Send to chi" helper
|
|
951
933
|
chi self version, paths, model and bundles
|
|
934
|
+
chi update [--dry-run] update this chi, its bundles and the desktop helper
|
|
952
935
|
(each subcommand takes --help)
|
|
953
936
|
|
|
954
937
|
BANNER
|
|
@@ -959,6 +942,8 @@ parser = OptionParser.new do |opts|
|
|
|
959
942
|
opts.on("--model NAME", "Model selector (runtime only, overrides --resume) [alias for --default-model]") { |m| options[:model] = m; cli_overrides["default.model"] = m }
|
|
960
943
|
opts.on("--profile NAME", Samagotchi::ModelProfile::NAMES,
|
|
961
944
|
"Prompt profile for every model in this run (#{Samagotchi::ModelProfile::NAMES.join('|')}) [alias for --model-profile]") { |p| cli_overrides["model.profile"] = p }
|
|
945
|
+
opts.on("--thinking LEVEL", Samagotchi::Thinking::LEVELS.map(&:to_s), "How much the model thinks this run: off|low|medium|high|default (outranks config.yml; " \
|
|
946
|
+
"sessions already running keep theirs) [env SAMAGOTCHI_THINKING_LEVEL]") { |l| cli_overrides["thinking.level"] = l }
|
|
962
947
|
opts.on("--memory NAME", "Preload a memory entry into the system prompt (repeatable; a comma list too)") { |m| (options[:memories] ||= []) << m }
|
|
963
948
|
opts.on("--mute NAME", "Hide a memory from this session: not in the prompt, refused by memory_read (repeatable; a comma list too)") { |m| (options[:muted] ||= []) << m }
|
|
964
949
|
opts.on("--no-interrupt", "Raise the tool call limit to 1000 iterations (useful for long tasks)") { options[:no_interrupt] = true; cli_overrides["no_interrupt"] = true }
|
|
@@ -967,12 +952,12 @@ parser = OptionParser.new do |opts|
|
|
|
967
952
|
opts.on("--no-default-input", "Skip default REPL input prefill") { options[:no_default_input] = true; cli_overrides["no_default_input"] = true }
|
|
968
953
|
opts.on("--port PORT", "Port for `chi web` (default: 4567, env SAMAGOTCHI_WEB_PORT)") { |p| options[:web_port] = p.to_i; cli_overrides["web.port"] = p.to_s }
|
|
969
954
|
opts.on("--open", "Open browser for `chi web`") { options[:web_open] = true }
|
|
955
|
+
opts.on("--new-token", "`chi web`: replace the LAN access token (web.host: lan); links and QR codes made with the old one stop working") { options[:new_token] = true }
|
|
970
956
|
opts.on("--scope VALUE", %w[project all],
|
|
971
957
|
"Which sessions `chi web` and `chi sessions list` show: project (the default: this folder's git project; " \
|
|
972
958
|
"every session outside a repo) or all") { |v| options[:scope] = v }
|
|
973
959
|
# Accepted values of string entries that the registry doesn't type as enums.
|
|
974
|
-
value_hints = { "
|
|
975
|
-
"web.host" => "127.0.0.1|::1|localhost", "recap.sentences" => "N|N-M",
|
|
960
|
+
value_hints = { "status.line" => "on|off", "web.host" => "127.0.0.1|::1|localhost|lan|IP", "recap.sentences" => "N|N-M",
|
|
976
961
|
"web.annotate_presets" => "text|text" }
|
|
977
962
|
# Universal config flags (implicit convention: ENV SAMAGOTCHI_* ↔ YAML dotted ↔ CLI --kebab)
|
|
978
963
|
# Generated from Samagotchi::Config registry — Option A: snake leaf in YAML, kebab in CLI.
|
|
@@ -980,7 +965,7 @@ parser = OptionParser.new do |opts|
|
|
|
980
965
|
next if %w[no_interrupt no_default_input].include?(entry.key)
|
|
981
966
|
next if entry.key == "web.port" # already handled as --port
|
|
982
967
|
next if entry.key == "default.model" # alias --model above
|
|
983
|
-
next if
|
|
968
|
+
next if entry.key == "web.markdown" # handled below with explicit inverse flags
|
|
984
969
|
case entry.type
|
|
985
970
|
when :bool
|
|
986
971
|
# --[no-]: a bool that defaults to on is only useful switched off.
|
|
@@ -1000,8 +985,6 @@ parser = OptionParser.new do |opts|
|
|
|
1000
985
|
end
|
|
1001
986
|
opts.on("--web-markdown", "Render finalized LLM Markdown in `chi web` (requires optional commonmarker gem)") { options[:web_markdown] = true; cli_overrides["web.markdown"] = true }
|
|
1002
987
|
opts.on("--no-web-markdown", "Disable Markdown rendering in `chi web`") { options[:web_markdown] = false; cli_overrides["web.markdown"] = false }
|
|
1003
|
-
opts.on("--web-turn-view", "Show each turn in `chi web` as one block of steps (the live one at the bottom; the default); ?view=turn|chat overrides per page") { options[:web_turn_view] = true; cli_overrides["web.turn_view"] = true }
|
|
1004
|
-
opts.on("--no-web-turn-view", "Show turns in `chi web` as the classic row of bubbles instead of the turn view") { options[:web_turn_view] = false; cli_overrides["web.turn_view"] = false }
|
|
1005
988
|
# Strict underscore rejection: --recap_base_url etc. are not registered and will raise OptionParser::InvalidOption
|
|
1006
989
|
opts.on("--version", "Print chi's version") { puts "chi #{Samagotchi::VERSION}"; exit }
|
|
1007
990
|
opts.on("-h", "--help", "Show help") { puts opts; exit }
|
|
@@ -1022,6 +1005,10 @@ if stray
|
|
|
1022
1005
|
warn "Error: #{web || scratch ? "unexpected argument" : "unknown command"} #{stray} (see chi --help)"
|
|
1023
1006
|
exit 1
|
|
1024
1007
|
end
|
|
1008
|
+
if options[:new_token] && !web
|
|
1009
|
+
warn "Error: --new-token goes with chi web (chi web --new-token)"
|
|
1010
|
+
exit 1
|
|
1011
|
+
end
|
|
1025
1012
|
|
|
1026
1013
|
# A scratch session is new, runs here and goes when it ends.
|
|
1027
1014
|
if scratch
|
|
@@ -1032,16 +1019,9 @@ if scratch
|
|
|
1032
1019
|
end
|
|
1033
1020
|
end
|
|
1034
1021
|
|
|
1035
|
-
# Apply CLI precedence: CLI > ENV > file
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
# Keep ENV in sync for legacy readers still using ENV directly
|
|
1039
|
-
cli_overrides.each do |k, v|
|
|
1040
|
-
entry = Samagotchi::Config.find_by_key(k)
|
|
1041
|
-
next unless entry&.env_exposed?
|
|
1042
|
-
ENV[entry.env_key] = v.to_s
|
|
1043
|
-
end
|
|
1044
|
-
end
|
|
1022
|
+
# Apply CLI precedence: CLI > ENV > file. Workers this chi spawns get
|
|
1023
|
+
# these through their env (Config.cli_env).
|
|
1024
|
+
Samagotchi::Config.reload!(cli_overrides: cli_overrides) unless cli_overrides.empty?
|
|
1045
1025
|
|
|
1046
1026
|
# The debug log (Samagotchi::LogPath, level log.level) for every command.
|
|
1047
1027
|
# -v (the plain REPL only): debug records, each mirrored to stderr.
|
|
@@ -1064,27 +1044,35 @@ when "web"
|
|
|
1064
1044
|
options[:web_markdown] = true
|
|
1065
1045
|
elsif arg == "--no-web-markdown"
|
|
1066
1046
|
options[:web_markdown] = false
|
|
1067
|
-
elsif arg == "--web-
|
|
1068
|
-
options[:
|
|
1069
|
-
elsif arg
|
|
1070
|
-
options[:
|
|
1047
|
+
elsif arg == "--web-view" && Samagotchi::Config::BY_KEY["web.view"].enum_values.include?(web_args[i + 1])
|
|
1048
|
+
options[:web_view] = web_args[i + 1]
|
|
1049
|
+
elsif arg.start_with?("--web-view=") && Samagotchi::Config::BY_KEY["web.view"].enum_values.include?(arg.split("=", 2).last)
|
|
1050
|
+
options[:web_view] = arg.split("=", 2).last
|
|
1071
1051
|
elsif arg.start_with?("--port=")
|
|
1072
1052
|
options[:web_port] = arg.split("=", 2).last.to_i
|
|
1073
1053
|
end
|
|
1074
1054
|
end
|
|
1075
1055
|
end
|
|
1076
1056
|
|
|
1057
|
+
# The first interactive start of a new installed chi says what `chi update` would update.
|
|
1058
|
+
chi_update_hint = lambda do
|
|
1059
|
+
require "samagotchi/installed_gem"
|
|
1060
|
+
require "samagotchi/update_hint"
|
|
1061
|
+
if Samagotchi::UpdateHint.wanted?(prompt: options[:prompt], non_interactive: options[:non_interactive],
|
|
1062
|
+
tty: $stdin.tty? && $stdout.tty?, installed: Samagotchi::InstalledGem.spec)
|
|
1063
|
+
Samagotchi::UpdateHint.show
|
|
1064
|
+
end
|
|
1065
|
+
end
|
|
1066
|
+
|
|
1077
1067
|
if options[:web]
|
|
1068
|
+
chi_update_hint.call
|
|
1078
1069
|
require "samagotchi/web/server"
|
|
1079
|
-
port = options[:web_port] || Samagotchi::Config.get("web.port")
|
|
1080
|
-
# legacy env fallback
|
|
1081
|
-
port = ENV.fetch("SAMAGOTCHI_WEB_PORT", port.to_s).to_i rescue port.to_i
|
|
1070
|
+
port = options[:web_port] || Samagotchi::Config.get("web.port")
|
|
1082
1071
|
markdown = options[:web_markdown]
|
|
1083
1072
|
markdown = Samagotchi::Config.get("web.markdown") if markdown.nil?
|
|
1084
|
-
|
|
1085
|
-
turn_view = Samagotchi::Config.get("web.turn_view") if turn_view.nil?
|
|
1073
|
+
view = options[:web_view] || Samagotchi::Config.get("web.view")
|
|
1086
1074
|
exit Samagotchi::Web::Server.launch(port: port, scope: options[:scope] || "project", open_browser: options[:web_open],
|
|
1087
|
-
markdown: markdown,
|
|
1075
|
+
markdown: markdown, view: view, new_token: options[:new_token],
|
|
1088
1076
|
annotate_presets: Samagotchi::Config.get("web.annotate_presets"))
|
|
1089
1077
|
end
|
|
1090
1078
|
|
|
@@ -1143,6 +1131,7 @@ if options[:memories] || options[:muted]
|
|
|
1143
1131
|
end
|
|
1144
1132
|
end
|
|
1145
1133
|
|
|
1134
|
+
chi_update_hint.call
|
|
1146
1135
|
require "samagotchi/launch_mode"
|
|
1147
1136
|
launch, launch_note = if scratch
|
|
1148
1137
|
[:repl, nil]
|
|
@@ -1182,7 +1171,7 @@ if launch == :attached
|
|
|
1182
1171
|
end
|
|
1183
1172
|
|
|
1184
1173
|
begin
|
|
1185
|
-
Samagotchi::TerminalUI.new(
|
|
1174
|
+
ended = Samagotchi::TerminalUI.new(
|
|
1186
1175
|
prompt: options[:prompt],
|
|
1187
1176
|
session_id: options[:resume],
|
|
1188
1177
|
no_interrupt: options[:no_interrupt] || options[:non_interactive],
|
|
@@ -1193,6 +1182,8 @@ begin
|
|
|
1193
1182
|
model_name: options[:model],
|
|
1194
1183
|
scratch: scratch
|
|
1195
1184
|
).run
|
|
1185
|
+
# `chi -p X </dev/null`: the turn failed (nothing was sent again).
|
|
1186
|
+
exit 1 if ended == :turn_failed
|
|
1196
1187
|
rescue Samagotchi::TerminalUI::SessionBusy, Samagotchi::TerminalUI::SessionNotFound, Samagotchi::ModelProfile::MissingModel => e
|
|
1197
1188
|
warn "Error: #{e.message}"
|
|
1198
1189
|
exit 1
|