samagotchi 0.149.0 → 0.150.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 +48 -1
- data/README.md +4 -2
- data/docs/architecture.md +2 -2
- data/docs/cli.md +59 -24
- data/docs/configuration.md +5 -5
- data/docs/internals/background-tasks.md +1 -1
- data/docs/internals/bridge.md +8 -0
- data/docs/internals/bundles.md +42 -14
- data/docs/internals/objectives.md +7 -2
- data/docs/internals/web-frontend.md +1 -1
- data/docs/internals/web-push.md +2 -2
- data/docs/internals/working-set.md +5 -2
- data/docs/memory.md +47 -9
- data/docs/plugins.md +7 -1
- data/docs/sessions.md +5 -4
- data/docs/testing.md +5 -0
- data/lib/samagotchi/atomic_file.rb +3 -0
- data/lib/samagotchi/bootstrap_command.rb +5 -2
- data/lib/samagotchi/bridge/card_store.rb +52 -7
- data/lib/samagotchi/bridge.rb +1 -1
- data/lib/samagotchi/bundle_command.rb +91 -68
- data/lib/samagotchi/bundler_env.rb +24 -0
- data/lib/samagotchi/bundles/dev/manifest.yml +2 -2
- data/lib/samagotchi/bundles/github-pr/manifest.yml +3 -3
- data/lib/samagotchi/bundles/github-pr/plugin.rb +2 -1
- data/lib/samagotchi/bundles/known-names/hooks/known_names.rb +3 -1
- data/lib/samagotchi/bundles/known-names/manifest.yml +3 -2
- data/lib/samagotchi/bundles/source-links/hooks/source_links.rb +2 -2
- data/lib/samagotchi/bundles/source-links/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/manifest.yml +3 -3
- data/lib/samagotchi/bundles/system/memory_guide.md +5 -5
- data/lib/samagotchi/bundles/system/self_map.md +1 -1
- data/lib/samagotchi/chi_home.rb +4 -2
- data/lib/samagotchi/chi_shim.rb +2 -1
- data/lib/samagotchi/child_env.rb +10 -3
- data/lib/samagotchi/engine.rb +1 -1
- data/lib/samagotchi/git_env.rb +43 -0
- data/lib/samagotchi/guardrails/context.rb +2 -0
- data/lib/samagotchi/guardrails/targets.rb +4 -1
- data/lib/samagotchi/memory_bundle/asset_installer.rb +16 -2
- data/lib/samagotchi/memory_bundle/file_standing.rb +167 -0
- data/lib/samagotchi/memory_bundle/installed_bundle.rb +62 -1
- data/lib/samagotchi/memory_bundle/installer.rb +161 -52
- data/lib/samagotchi/memory_bundle/listing.rb +4 -3
- data/lib/samagotchi/memory_bundle/merger.rb +209 -8
- data/lib/samagotchi/memory_bundle/placeholder.rb +2 -1
- data/lib/samagotchi/memory_bundle/profile.rb +7 -3
- data/lib/samagotchi/memory_bundle/provenance.rb +178 -20
- data/lib/samagotchi/memory_bundle/remerge.rb +167 -0
- data/lib/samagotchi/memory_bundle/shipped_history.rb +79 -0
- data/lib/samagotchi/memory_bundle/shipped_update.rb +89 -24
- data/lib/samagotchi/memory_bundle/source.rb +3 -3
- data/lib/samagotchi/memory_bundle/status.rb +21 -3
- data/lib/samagotchi/memory_bundle/system_bundle.rb +98 -33
- data/lib/samagotchi/memory_bundle/text_merge.rb +399 -0
- data/lib/samagotchi/memory_bundle/trash.rb +58 -2
- data/lib/samagotchi/memory_bundle/uninstaller.rb +26 -6
- data/lib/samagotchi/objectives_check.rb +37 -7
- data/lib/samagotchi/project_env.rb +3 -2
- data/lib/samagotchi/self_report.rb +2 -0
- data/lib/samagotchi/testing/boundary.rb +1 -0
- data/lib/samagotchi/testing/minitest.rb +3 -0
- data/lib/samagotchi/testing/rspec.rb +3 -0
- data/lib/samagotchi/testing/sandbox.rb +3 -1
- data/lib/samagotchi/tools/delegate.rb +2 -1
- data/lib/samagotchi/tools/task_runtime.rb +13 -10
- data/lib/samagotchi/turn_flow.rb +3 -1
- data/lib/samagotchi/update_command.rb +76 -28
- data/lib/samagotchi/update_hint.rb +4 -1
- data/lib/samagotchi/version.rb +1 -1
- data/lib/samagotchi/web/auto_update.rb +8 -8
- data/lib/samagotchi/web/auto_update_record.rb +6 -4
- data/lib/samagotchi/web/participant_view.rb +1 -1
- data/lib/samagotchi/web/public/app.js +5 -3
- data/lib/samagotchi/web/public/block_open.js +13 -0
- data/lib/samagotchi/web/public/bubbles.js +4 -2
- data/lib/samagotchi/web/public/cards_place.js +10 -5
- data/lib/samagotchi/web/public/details_motion.js +2 -1
- data/lib/samagotchi/web/public/index.html +18 -14
- data/lib/samagotchi/web/public/stage_model.js +5 -6
- data/lib/samagotchi/web/public/stage_view.js +8 -7
- data/lib/samagotchi/web/public/turn_block.js +34 -19
- data/lib/samagotchi/web/public/turn_model.js +1 -1
- data/lib/samagotchi/web/public/update_sheet.js +8 -3
- data/lib/samagotchi/web/public/working_set_view.js +10 -7
- data/lib/samagotchi/web/push/notifier.rb +7 -9
- data/lib/samagotchi/web/session_hub.rb +2 -1
- data/lib/samagotchi/web/update_ops.rb +2 -1
- metadata +8 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: caeb209690eb9b78ab3977c53ed4c7bbe7388b0a15e51b59b70da653ac9a9bdc
|
|
4
|
+
data.tar.gz: 43cd03b5039cc16b588323f82ca0e063053d4b78de83b9785e66dd7dbf8d4a71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 84a48999dd02619caa8900b8e2897614c93089519fa5e87d05e5f743b7073546e61b2c4e49a768798f1e612ef29eb768a86c7e69197e1880348ab5b767291ec4
|
|
7
|
+
data.tar.gz: 65ff02a943a5d58615976d531b22114c40d015b24098d230b5b389abff7bdacd33cabcb9b5622a3b57d054d2e156878a945a6e83895547ffe6dba8c929e0ab5b
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,52 @@ and commands may change between minor versions. How releases are made:
|
|
|
7
7
|
[docs/releasing.md](docs/releasing.md).
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.150.0] - 2026-11-05
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- The web's steps block closes to its summary line after a turn and after a reload, whatever its steps said; opened, it shows the outline as before. A canceled or failed turn with a narrated step stays open. [docs/cli.md](docs/cli.md#how-the-page-draws-a-turn)
|
|
15
|
+
- The web's working-set footprint is now the steps block's summary line, in body colour, the steps' count at its right (a phone shows the footprint alone); there is no separate line under the block. A click on its words opens the turn's list, the chevron or the count opens the steps. [docs/cli.md](docs/cli.md#the-working-set)
|
|
16
|
+
- Check this also reads the agent's visible answers, never its thinking, so a claim about what the agent said or asked can be confirmed. They settle only that: a claim of work with nothing but the agent's words behind it isn't `confirmed`. With `objectives.check_model` they go to that host too. [docs/sessions.md](docs/sessions.md#objectives)
|
|
17
|
+
- An upgrade now merges a memory you edited with the bundle's new version instead of leaving it behind. `chi bundle upgrade`, `chi update` and the automatic system bundle update run a text merge (needs `git`): a clean merge replaces the file, with the old one in the bundle trash and the report saying `merged 0.8.0 into your x.md`, and `--dry-run` says `would merge`. When a chi start updates the system bundle, a terminal launch says so in one line. Entries both sides added under a `Changelog` heading are kept, yours first. A real conflict, no `git`, or no recorded base leaves your file untouched, as before, and a file marked by an older chi can stay behind too (see the next line).
|
|
18
|
+
- A memory left behind as a conflict gets another try without waiting for the bundle's next version: the system bundle retries its files marked conflict at every chi start and on `chi update`, the other bundles chi ships on `chi update`, and any other bundle on `chi bundle upgrade`. It touches memory files only, and a row reads `0.8.0 merged 0.8.0 into your x.md`. A file marked by an older chi merges normally when its recorded base is a version chi shipped, checked against the samagotchi gems still installed. Otherwise that base may be your own text, so the file merges only if the bundle takes out or rewords no line it still holds. If it does, it stays behind until resolved by hand, with `--agent` or with `--force`, and the retry can't fix that.
|
|
19
|
+
- Everything that reports an edited bundle file now says what happened in one wording: `merged 0.8.0 into your x.md`, or `x.md stays behind 0.8.0: missed ## Steps, ## Rules and 2 more` with the reason when there is one (`no merge possible (git not found)`). The record keeps why and what was missed, and the bundle's text is saved at `.bundles/<name>/incoming/<file>` until the file settles. `kept your edits` is gone from `chi update`, whose `--json` rows gain `merged` next to `kept`, and from `chi bundle upgrade`, `chi bootstrap` and the system bundle's line at a start.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `bundle exec chi home set --ruby X` no longer records the bundle's vendor folder as X's gems when the bundle has a `path` and holds samagotchi: the probe of X still took `BUNDLER_SETUP`. A home set that way keeps its wrong `gem_home` until you run `chi home set` again.
|
|
24
|
+
- Under a `bundle exec chi`, a tool's plain `ruby` no longer loads Bundler: `BUNDLER_SETUP` still reached it, so in a folder whose Gemfile needs a missing gem `ruby -e` exited 1, and with Bundler 4 (`BUNDLE_LOCKFILE`) a folder with any other Gemfile had its lock written over chi's own `Gemfile.lock`. `execute`, tasks, `!cmd`, context sources and MCP servers all run without them, and `task_create` refuses them in `env`, saying to write `KEY=value cmd` in the command instead.
|
|
25
|
+
- `chi bundle install <git url>` run from a git hook or `git rebase --exec` no longer takes the repo git's variables name for its own: `GIT_WORK_TREE` failed the clone, `GIT_OBJECT_DIRECTORY` wrote the bundle's objects into that repo, and `GIT_DIR` alone recorded that repo's HEAD as the bundle's `source_commit`. Settings given around chi (`git -c url.….insteadOf=…`, `GIT_CONFIG_COUNT`) still apply to the clone. `delegate`'s `cwd:` check also asks about the folder it was given, as do the known-names (the git name), github-pr (the branch, `gh pr view`) and source-links (the remote) bundles.
|
|
26
|
+
- The web no longer loses a reply you steered: a line sent while a text-only step streamed left that step's whole text hidden, with no row or summary to open, live and after a reload. The step is now a row of the steps block (`1 step`), like any other text step.
|
|
27
|
+
- A web card updated just as a finished turn slid into the history no longer stays stuck on its first text until a reload (`/short` could stay on "Short version: …").
|
|
28
|
+
- A web card no longer lands a turn too early for good after `!rollback` of a canceled or failed turn: the rollback takes the turn out of the count. A rolled-back or failed turn's own cards stay where the turn was, without their buttons, instead of being read as the next turn's.
|
|
29
|
+
- A web card no longer lands one turn late for good after a worker was killed in the next turn (`kill -9`, a pod that didn't wait): the turn is counted, since its prompt stays in the session.
|
|
30
|
+
- A web card keeps its place after a reload when the turn after it failed with nothing kept: above the failed prompt, as it showed live, not below it, and an older card no longer lands one turn too late. A failed prompt isn't counted as a turn any more.
|
|
31
|
+
- `chi bundle list` and `chi self` say when a bundle has a file behind (`1 file behind`), and `chi bundle status` says it per file. `issues=` now counts files that stay behind, are missing or can't be read: an edit alone is no issue. A file `chi bundle status` can't read no longer crashes it.
|
|
32
|
+
- Every merge now leaves a note on the file's record, since a worker's reaches only the log and an automatic update's rows no one reads: `chi bundle status` shows it (with the old copy's folder), `chi update` names an earlier one in its row, and a row printed to you, or `chi bundle upgrade`'s output, ends the note. An automatic update names it without clearing it.
|
|
33
|
+
- `chi update` no longer crashes on an edited memory it can't read at a newer version: that bundle's row fails and says which file, and the others go on.
|
|
34
|
+
- The start-up hint `… can be updated: chi update` counts a bundle whose file would now merge at the same version.
|
|
35
|
+
- The update sheet shows `chi update`'s own words for an edited file, and the phone's push after an automatic update counts both sides (`Merged the update into 1 file you edited. 2 files stay behind.`): a merge used to go unmentioned, and every kept file read as `Kept your edits`.
|
|
36
|
+
- `chi update` no longer reads `up to date` for a file that stays behind at the same version: a real conflict, no `git`, a timeout, a file it can't read, or one left for the bundle's next version now name the file and why, and the summary counts them.
|
|
37
|
+
- A file marked by an older chi whose base chi can't vouch for no longer claims to hold your edits: it says chi can't tell, and why.
|
|
38
|
+
- `chi update`'s table no longer carries the trash's long path: the row says `old copies: chi bundle trash`, and `--json`'s `trash_copy` has the full line.
|
|
39
|
+
- The `--force` suggestions say what happens to your file: it is copied to the trash first.
|
|
40
|
+
- `chi bundle install --force` and `chi bundle upgrade --force` no longer destroy what they overwrite: a memory that differs from the bundle's, your own same-name file too, is copied to the bundle trash first, and the output names it (`Copied to the trash first: …`; `chi bundle trash` lists it).
|
|
41
|
+
- An install, upgrade or `chi update` that replaces or removes a hook, rule, plugin or script you edited copies it to the bundle trash first, under its own subfolder (`hooks/x`, `scripts/sub/x`) at any depth, and says so. A `--dev` install's links are left out.
|
|
42
|
+
- `chi bundle uninstall`, with `--force` or without, copies a hook, rule, plugin or script you edited to the bundle trash before removing it, and names it. Only memories reached the trash before.
|
|
43
|
+
- An install, upgrade or uninstall that can't read a file or write the bundle trash fails with a message naming the file, not a backtrace, and running it again after fixing that picks up where it stopped.
|
|
44
|
+
- A memory whose conflict was resolved through `chi bundle upgrade --agent` keeps its description in the bundle's record.
|
|
45
|
+
- `chi bundle upgrade --agent` no longer calls a conflict resolved when nothing merged it. A file the session didn't change, or one still holding conflict markers, stays a conflict, the output says so (`Nothing changed in X: still behind.`), and the command exits 2. It used to mark the file resolved, so later upgrades kept it without a word and the bundle's change never arrived.
|
|
46
|
+
- An edited memory with no recorded base keeps surviving upgrades as a conflict. Its own text used to become the base, so the following upgrade overwrote it with nothing in the trash. A record an older chi already left that way (marked conflict, the base being your text) stays behind when the update would take out a line it holds. Otherwise it takes the update, with your text copied to the bundle trash first and a line saying so.
|
|
47
|
+
- A plain `chi bundle install` keeps the conflict mark on a file it skipped, so `chi bundle status` still shows the file missed an update.
|
|
48
|
+
- `chi bundle upgrade --dry-run` no longer prints a false `Checksum mismatch` for a memory you edited, and its `Kept` line now names those files. This only changes a dry run's output.
|
|
49
|
+
- `chi bundle upgrade --agent` no longer takes your file as the new base when the bundle's copy disappears during the session. The next upgrade used to overwrite the edit with nothing in the trash; the file now stays a conflict and the command says so.
|
|
50
|
+
- An install or upgrade no longer fails at its last step on a memory that isn't valid UTF-8.
|
|
51
|
+
- A Changelog merge compares whole entries, nested items included: your `- a` / ` - note` beside the bundle's `- b` / ` - note` no longer loses the bundle's ` - note`.
|
|
52
|
+
- Putting back a deleted system memory at the same version now restores that file alone. It used to run a whole upgrade, replacing hooks, rules and the plugin under live sessions.
|
|
53
|
+
|
|
54
|
+
Update with `chi update` (github-pr 0.6.3, known-names 0.1.9, source-links 0.6.3: their git calls ask about the session's folder, and they need this chi; dev profile 0.7.6).
|
|
55
|
+
|
|
10
56
|
## [0.149.0] - 2026-11-04
|
|
11
57
|
|
|
12
58
|
### Added
|
|
@@ -5624,7 +5670,8 @@ and long-lived sessions.
|
|
|
5624
5670
|
- A macOS desktop helper (`chi desktop install`): a "Send to chi" Service and a
|
|
5625
5671
|
hotkey panel that send selected text or the clipboard to your sessions.
|
|
5626
5672
|
|
|
5627
|
-
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.
|
|
5673
|
+
[Unreleased]: https://github.com/dm1try/samagotchi/compare/v0.150.0...HEAD
|
|
5674
|
+
[0.150.0]: https://github.com/dm1try/samagotchi/compare/v0.149.0...v0.150.0
|
|
5628
5675
|
[0.149.0]: https://github.com/dm1try/samagotchi/compare/v0.148.0...v0.149.0
|
|
5629
5676
|
[0.148.0]: https://github.com/dm1try/samagotchi/compare/v0.147.0...v0.148.0
|
|
5630
5677
|
[0.147.0]: https://github.com/dm1try/samagotchi/compare/v0.146.0...v0.147.0
|
data/README.md
CHANGED
|
@@ -53,8 +53,10 @@ chi update # the gem, then the bundles and the desktop helper
|
|
|
53
53
|
`chi update` installs the newest samagotchi from rubygems.org (old versions
|
|
54
54
|
stay installed: running sessions still use them), then brings the rest up to
|
|
55
55
|
the new version: the system bundle, the bundles chi ships that you installed,
|
|
56
|
-
and the macOS helper (rebuilt only when its sources changed).
|
|
57
|
-
edited
|
|
56
|
+
and the macOS helper (rebuilt only when its sources changed). A memory file you
|
|
57
|
+
edited takes the update in a text merge (the old file goes to the bundle trash),
|
|
58
|
+
or stays behind as it is when no merge is possible, and the table says which
|
|
59
|
+
and why. Running sessions keep their chi
|
|
58
60
|
until restarted (`chi sessions restart ID`, or the Restart badge on the web);
|
|
59
61
|
new and woken ones start on the new chi. A running `chi web` needs a restart,
|
|
60
62
|
and its page says so. From a checkout, `git pull` instead. See
|
data/docs/architecture.md
CHANGED
|
@@ -102,7 +102,7 @@ terminal renders the events it gets over the Bridge.
|
|
|
102
102
|
| Model loops | `KernelLoop` (via `LLM::NativeBackend`), `LLM::ChatLoop` | The model↔tool loop: raw prompt, or a chat API (OpenAI chat, Anthropic Messages), chosen per host (see below). |
|
|
103
103
|
| Adapters | `Samagotchi::Client`, `LLM::OpenAIChat`, `LLM::AnthropicMessages`, `LLM::HTTP` | Raw-prompt servers, the OpenAI chat API, Anthropic's Messages API, and the HTTP they share. |
|
|
104
104
|
| Tools | `lib/samagotchi/tools/*` | Execute, read, edit, write, memory, task_*, web_fetch, delegate/delegate_result, ask_user_question, reminders, send_note, list_sessions, context_read, objectives, forget_outputs, find_tools/call_tool (the tool index), plus runtime/output-guardrails. |
|
|
105
|
-
| Bundles | `lib/samagotchi/memory_bundle/*`, `BundleCommand` | `chi bundle`: install/upgrade (3-way merge), build, uninstall; the install record under `.bundles/<name>/` that the hook, guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
105
|
+
| Bundles | `lib/samagotchi/memory_bundle/*`, `BundleCommand` | `chi bundle`: install/upgrade (3-way, with a text merge of edited memories), build, uninstall; the install record under `.bundles/<name>/` that the hook, guardrail and plugin loaders read ([internals/bundles.md](internals/bundles.md)). |
|
|
106
106
|
| Background | `Samagotchi::Worker`, `Samagotchi::SessionManager` | `SessionManager` forks/spawns one worker process per session; its `Worker` builds the `Engine` and `Bridge` (no terminal rendering) and runs queued turns. The spawned process (own process group) forks the worker, which `setsid`s and is reparented to init once its starter exits (it waits until the worker holds `owner.lock`, so the spawner's `Process.detach` waiter tells a starting worker): nothing that walks the spawner's process tree reaches it (`SAMAGOTCHI_WORKER_DETACH=1`, `detach_from_spawner`). The lock's pid is the worker's; `spawn`'s `child_pid` is its starter's. |
|
|
107
107
|
| Web | `Samagotchi::Web::App`, `Samagotchi::Web::Server`, `Samagotchi::Web::SessionHub` | Rack+WEBrick on one port, `127.0.0.1:4567` (index.html + `/api/*` + SSE); with `web.host: lan` also on this machine's LAN address, behind an access token (`Web::Lan`, `Web::Token`). The hub is chi web's projection of the session list, pushed to every tab over `GET /api/events`. |
|
|
108
108
|
| Sessions | `Samagotchi::Session`, `SessionManager` | File `sessions/<uuid>.json` + sidecar `input/`/`output/`; retention 14d/500, `updated_at desc`, lazy sweep. |
|
|
@@ -394,7 +394,7 @@ record starts at `phase: installed` and the run goes on as below. Ahead of every
|
|
|
394
394
|
`SessionHub#auto_offer_restart` (`auto_offers`, in memory) when a run on record for the newest installed chi is closed with
|
|
395
395
|
this chi web still older, or that chi has waited `HELD_FOR` (1 h): the trying goes on, and the page has its buttons back;
|
|
396
396
|
`restart_failed` and a failed install call it at once. Its record is `update_check.json`'s `auto`:
|
|
397
|
-
`{version, from, at, kept, phase: installed|workers|web|retrying|done|failed, workers: {restarted, left}, detail, pushed}`,
|
|
397
|
+
`{version, from, at, kept, merged, phase: installed|workers|web|retrying|done|failed, workers: {restarted, left}, detail, pushed}`,
|
|
398
398
|
in Ruby the value object `Web::AutoUpdateRecord`, which owns that shape (`from_h`, `to_store`).
|
|
399
399
|
With `update.restart: never` the run ends at the install (`chi_notice` `installed`). With `idle` it goes on
|
|
400
400
|
(`phase` `installed` → `workers` → `web` → `retrying` → `done`): `UpdateOps#restart_workers(select:)` over the stale workers whose
|
data/docs/cli.md
CHANGED
|
@@ -228,9 +228,11 @@ $ chi models qwen # only the names containing "qwen" (any case)
|
|
|
228
228
|
```
|
|
229
229
|
component from to status
|
|
230
230
|
chi (gem) 0.2.0 0.3.0 updated
|
|
231
|
-
system bundle 0.2.0 0.3.0 updated (
|
|
231
|
+
system bundle 0.2.0 0.3.0 updated (identity.md stays behind 0.3.0: missed ## Who you are (chi bundle diff samagotchi-system identity.md))
|
|
232
232
|
btw 0.1.1 up to date
|
|
233
|
-
known-names 0.1.0 0.1.1 updated
|
|
233
|
+
known-names 0.1.0 0.1.1 updated (merged 0.1.1 into your known_names.md; old copies: chi bundle trash)
|
|
234
|
+
coordinator 0.8.0 merged 0.8.0 into your skill_coordinator.md; old copies: chi bundle trash
|
|
235
|
+
loop-guard 0.2.0 notes.md stays behind 0.2.0: no merge possible (git not found) (chi bundle diff loop-guard notes.md)
|
|
234
236
|
core 0.1.0 0.2.0 updated (+ new-bundle)
|
|
235
237
|
infra_tools 1.0.0 skipped (not from chi)
|
|
236
238
|
infra_tools warn api plugin.rb:3: ctx.old_name isn't in chi 0.3.0's plugin API (fix: docs/plugins.md has the API)
|
|
@@ -238,15 +240,17 @@ Chi Helper 0.2.0 up to date (launch file refreshed)
|
|
|
238
240
|
workers 2 live on 0.2.0: they keep it until restarted (chi sessions restart 2ea8c1f0 91b0d2aa); or they idle out after 30 min with nothing attached
|
|
239
241
|
Bundles not from chi are left as they are: their author's next version, or chi bundle upgrade NAME, is what changes them
|
|
240
242
|
Also shipped, not installed: dev (mcp, skills, source-links) (chi bundle install NAME)
|
|
241
|
-
|
|
243
|
+
2 files stay behind (see above)
|
|
242
244
|
```
|
|
243
245
|
|
|
244
246
|
- `--to VERSION` installs exactly that gem version instead of checking for the
|
|
245
247
|
newest release. It must be newer than the running chi; an equal or older
|
|
246
248
|
version is refused.
|
|
247
249
|
- `--json` writes the component rows as one JSON array on stdout. Each row has
|
|
248
|
-
`component`, `from`, `to`, `status`, `failed`, `kept` and `level` fields;
|
|
249
|
-
`kept` is an array of edited filenames
|
|
250
|
+
`component`, `from`, `to`, `status`, `failed`, `kept`, `merged`, `earlier`, `trash_copy` and `level` fields;
|
|
251
|
+
`kept` is an array of edited filenames left behind, `merged` of those this run
|
|
252
|
+
merged, `earlier` of those an earlier merge's note names, `trash_copy` the full line
|
|
253
|
+
saying where the old copies went (the table says `chi bundle trash`), and `level` is `warn` or `error` on a
|
|
250
254
|
re-check's row (below), `null` on the others. Install progress is written to
|
|
251
255
|
stderr.
|
|
252
256
|
|
|
@@ -304,11 +308,36 @@ done
|
|
|
304
308
|
the row says what it did.
|
|
305
309
|
- **Shipped bundles**: each one you installed from chi (`chi bundle install
|
|
306
310
|
NAME`) is upgraded when chi ships a newer version. Memory files get the
|
|
307
|
-
3-way merge of `chi bundle upgrade`: an unedited file is updated, an
|
|
308
|
-
one that the new version also changes
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
311
|
+
3-way merge of `chi bundle upgrade`: an unedited file is updated, and an
|
|
312
|
+
edited one that the new version also changes takes a text merge, with the old
|
|
313
|
+
file in the bundle trash and `merged 0.8.0 into your FILE` in the row. A real
|
|
314
|
+
conflict, no `git`, or no recorded base keeps your file untouched, and the row
|
|
315
|
+
says `FILE stays behind 0.8.0:` with why and what it missed (up to three headings
|
|
316
|
+
and a count, or `2 places`). `chi bundle diff NAME FILE` shows it; `chi bundle
|
|
317
|
+
upgrade NAME --force` takes the bundle's, with a copy of yours in the bundle
|
|
318
|
+
trash first. A later run retries such a file at the same version: its row reads
|
|
319
|
+
`0.8.0 merged 0.8.0 into your FILE` when it merges, and names it as behind when
|
|
320
|
+
it doesn't. So does a file left for the bundle's next version (it matches its old
|
|
321
|
+
base), or one the retry can't read, and the row never says `up to date` while a file
|
|
322
|
+
stays behind. Once a file has the bundle's bytes it isn't behind, however it got
|
|
323
|
+
them. A file marked by an older chi
|
|
324
|
+
merges normally when its recorded base is a version chi shipped (an installed
|
|
325
|
+
samagotchi gem still has it). Otherwise that base may be your own text, so it merges only if the bundle takes out or
|
|
326
|
+
rewords no line it still holds. If it does, chi can't tell whether the file holds
|
|
327
|
+
edits of yours, says so, and the file stays behind until resolved by
|
|
328
|
+
hand, with `--agent` or with `--force`; the retry can't fix that. Every merge
|
|
329
|
+
leaves a note on the file's record, since a worker's reaches only the log and an
|
|
330
|
+
automatic update's rows may be read by no one. `chi bundle status` shows it while it
|
|
331
|
+
exists. A `chi update` row names an earlier one (`up to date (merged 0.8.0 into your
|
|
332
|
+
FILE on 2026-11-05 14:03; …)`), and a row printed to you ends the note for what it
|
|
333
|
+
printed, that run's own merges included; so does `chi bundle upgrade`, which prints
|
|
334
|
+
the merge itself, and `--force` replacing the file. A dry run and an automatic update
|
|
335
|
+
(`update.auto`) show it and leave it, and so does a failed row or one with no place
|
|
336
|
+
for it (a skipped system bundle). A memory that can't be read at a
|
|
337
|
+
newer version fails that bundle's row with the file's name. Hooks, rules and the plugin are replaced; an edited one didn't
|
|
338
|
+
load anyway (its sha no longer matched), the row says it was replaced, and
|
|
339
|
+
a copy goes to the bundle trash first (`chi bundle trash`; `hooks/x`,
|
|
340
|
+
`guardrails/x`, `plugin/x`, `scripts/x` inside the dir).
|
|
312
341
|
A bundle of the same name from elsewhere (a zip, git) is skipped ("not from
|
|
313
342
|
chi"), a newer installed one is left, one whose new version needs a newer
|
|
314
343
|
chi is skipped, and bundles you didn't install stay uninstalled.
|
|
@@ -367,9 +396,10 @@ this version's view: bundles that only a newer gem ships newer show up once
|
|
|
367
396
|
that gem is installed (the real run installs it first and hands over).
|
|
368
397
|
`--no-gem`, `--no-bundles` and `--no-desktop` leave a part alone for one run;
|
|
369
398
|
`update.gem`, `update.bundles` and `update.desktop: false` in config.yml turn
|
|
370
|
-
one off for good. It exits 0 when nothing failed (
|
|
399
|
+
one off for good. It exits 0 when nothing failed (merged edits, files that stay behind and skips are
|
|
371
400
|
fine), 1 when a part failed, 2 on a usage error. A second run changes nothing
|
|
372
|
-
and ends with "everything is up to date"
|
|
401
|
+
and ends with "everything is up to date", or with `N files stay behind (see above)`
|
|
402
|
+
when some do.
|
|
373
403
|
|
|
374
404
|
From a checkout it refuses (`git pull`, or `chi bundle upgrade NAME` for one
|
|
375
405
|
bundle). After a gem update, the first interactive start of the new version
|
|
@@ -1189,14 +1219,17 @@ again). When a step ends its thinking closes to a plain `thinking` line
|
|
|
1189
1219
|
(unless you opened it); a step that only thought shows that line alone. The
|
|
1190
1220
|
live narration is a box of about three lines that fills sentence by
|
|
1191
1221
|
sentence (a sentence shows once it is complete) and scrolls to the newest
|
|
1192
|
-
when full. When the turn ends the block
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1222
|
+
when full. When the turn ends the block closes to its summary (`3 steps
|
|
1223
|
+
· 8 tool calls · execute ×7 · read ×1`, after the turn's
|
|
1224
|
+
[footprint](#the-working-set) when it has one). Opened, it shows its outline when any of
|
|
1225
|
+
its steps said something: one line per step that wrote text (that text's first
|
|
1226
|
+
line), and each run of steps that only called tools or thought sits behind one
|
|
1227
|
+
`· N steps` line that shows them. That includes a reply a line was steered into: its
|
|
1228
|
+
step is a row like any other, and the answer that follows is the bubble. A canceled or failed turn with such a step
|
|
1229
|
+
stays open, as its last narrated step is the only text you get. A reload draws
|
|
1230
|
+
the same from what was saved: a failed turn whose stream dropped mid-narration
|
|
1231
|
+
saved no such step, so it reloads closed. Either way the answer is a normal bubble under the block (Markdown,
|
|
1232
|
+
annotate). A plain answer
|
|
1200
1233
|
without tools ends exactly as it does today. Rows the code collapses stay
|
|
1201
1234
|
as you toggled them. A reloaded session shows the same block
|
|
1202
1235
|
from the saved messages (each step's thinking, narration, tool parameters
|
|
@@ -1239,12 +1272,14 @@ session bar shows the `mem N` chip again.
|
|
|
1239
1272
|
folds it to one line (`SET 17 + ◆ name`), kept per browser; a click opens the
|
|
1240
1273
|
list. In a stage narrower than 760 px it is one line under the last calls;
|
|
1241
1274
|
on a phone it isn't shown.
|
|
1242
|
-
- **The footprint**,
|
|
1275
|
+
- **The footprint**, each finished turn's block's summary line, live and after
|
|
1243
1276
|
a reload: `touched …/web/public/ · 4 files · ◆ 2 memories s2–10 · +1 url ·
|
|
1244
1277
|
edited 1`, then `n stale`, `n forgotten` or `n dropped` while some are (a file
|
|
1245
|
-
changed after the turn read it, even at its very end, says so here)
|
|
1246
|
-
tag (`s2`) goes to that call's row; the rest
|
|
1247
|
-
|
|
1278
|
+
changed after the turn read it, even at its very end, says so here), with the
|
|
1279
|
+
steps' count at the right. A step tag (`s2`) goes to that call's row; the rest
|
|
1280
|
+
of its words opens the turn's list; the chevron or the count opens the steps.
|
|
1281
|
+
A phone shows the footprint alone, no count. A turn that touched nothing has
|
|
1282
|
+
none: its summary is the count.
|
|
1248
1283
|
- **The `set N` chip** in the session bar, in place of the `mem N` chip (whose
|
|
1249
1284
|
tooltip goes too): the session's whole set, preloaded (`--memory`) and muted
|
|
1250
1285
|
(`--mute`) memories included; its dot lights when the set changed since you
|
data/docs/configuration.md
CHANGED
|
@@ -2141,7 +2141,7 @@ Both are read when chi web starts (restart it to apply a change). What it does,
|
|
|
2141
2141
|
install isn't blocked (a source checkout, Bundler, a RubyGems directory chi can't write: those stay a notice, with
|
|
2142
2142
|
the command to run). `chi update` also merges the shipped bundles that live sessions read, hence "no turn anywhere".
|
|
2143
2143
|
2. **Installs** exactly the release the notice named, as the **Update** button does (the system bundle and shipped
|
|
2144
|
-
bundles are merged three ways;
|
|
2144
|
+
bundles are merged three ways; a file you edited takes a text merge, one with a real conflict stays behind, and the push counts both). The page's sticky toast says
|
|
2145
2145
|
"Automatic chi update in progress" and its sheet shows the rows; with `update.restart: idle` no "installed"
|
|
2146
2146
|
toast with **Restart** buttons follows (the run restarts by itself). A failed install is tried **once per version**:
|
|
2147
2147
|
it pushes the failed row's reason and stays quiet until a newer release (or you, with the button) tries again.
|
|
@@ -2158,7 +2158,7 @@ Both are read when chi web starts (restart it to apply a change). What it does,
|
|
|
2158
2158
|
the install; after that they wait for their own idle exit or the session's **Restart**. A newer release in that day
|
|
2159
2159
|
installs as usual and takes them over.
|
|
2160
2160
|
4. **Says so.** The restarted chi web pushes "chi updated to X" ("chi web and 3 sessions restarted; 1 restarts when
|
|
2161
|
-
idle.
|
|
2161
|
+
idle. Merged the update into 1 file you edited. 2 files stay behind."); the later restarts of those sessions push nothing more. With
|
|
2162
2162
|
`update.restart: never` the push is "chi X is installed" and chi web and the workers move over when you restart them (the page's toast offers it). The push needs the phone set up
|
|
2163
2163
|
([Phone notifications](#phone-notifications-web-push)); without it the page's toasts and
|
|
2164
2164
|
`$XDG_STATE_HOME/samagotchi/update_check.json` (`auto`) are the record.
|
|
@@ -2273,7 +2273,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2273
2273
|
| `context.candidates.threshold` | `0.8` | | The probability at which the judge attaches a candidate in on mode (a judged line's `would: attach`). config.yml only. |
|
|
2274
2274
|
| `context.candidates.offer_threshold` | `0.6` | | The probability from which on mode shows the candidate's card, once (`would: offer`, below `threshold`). config.yml only. |
|
|
2275
2275
|
| `context.candidates.reask_after_turns` | `3` | | Owner prompts after a judged ask before the judge's one re-ask of that candidate. config.yml only. |
|
|
2276
|
-
| `objectives.check_model` | none | | The model [Check this](sessions.md#objectives) asks, its one side request (a host:id, an alias, a host's model id); none: the session's own. **Each Check this sends that model's host up to 24,000 characters of the session's tool output and
|
|
2276
|
+
| `objectives.check_model` | none | | The model [Check this](sessions.md#objectives) asks, its one side request (a host:id, an alias, a host's model id); none: the session's own. **Each Check this sends that model's host up to 24,000 characters of the session's tool output, messages and the agent's visible answers, off the machine with a hosted model even from a local session;** known key shapes and `token=`-style values are redacted first, by pattern only. config.yml only. |
|
|
2277
2277
|
| `objectives.system_one` | `off` | | `audit`: System 1 answers a yes/no per active objective on what comes in and goes out, saved as runs and acted on by nothing; see [System 1's saved runs](system-one.md#objectives-in-audit). `off` (the default): no conversation text goes to a System 1 host for this. Its host and model are `system_one.host` / `.model`. config.yml only. |
|
|
2278
2278
|
| `toolkit.default` | `full` | | The toolkit a new session is stored on: the tools its prompts declare (`full`, `lean`, `child`, one of `toolkit.kits` or a bundle's). `chi --toolkit` picks one per session. See "Toolkits". |
|
|
2279
2279
|
| `toolkit.child` | `full` | | A delegate child's toolkit, unless its `delegate` call names one (`toolkit:`). See "Toolkits". |
|
|
@@ -2305,7 +2305,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2305
2305
|
| `update.bundles` | `true` | | `false`: `chi update` leaves the shipped bundles to `chi bundle upgrade` (`--no-bundles`). |
|
|
2306
2306
|
| `update.desktop` | `true` | | `false`: `chi update` leaves the desktop helper alone (`--no-desktop`). |
|
|
2307
2307
|
| `update.notify` | `on` | | `on`: chi web checks RubyGems once a day and shows aged stable releases newer than both this chi and the newest installed chi; `off`: no thread or network check. |
|
|
2308
|
-
| `update.auto` | `off` | | `install`: chi web installs the release its checker found (aged by `update.min_age_hours`) once no turn runs and no question waits in any session, as the **Update** button would (shipped bundles merged,
|
|
2308
|
+
| `update.auto` | `off` | | `install`: chi web installs the release its checker found (aged by `update.min_age_hours`) once no turn runs and no question waits in any session, as the **Update** button would (shipped bundles merged, a file that can't merge left behind, both reported), then pushes how it went; `update.restart` says what follows, also for a chi installed some other way (`chi update` in a terminal). An install that fails is tried once per version (a newer release, or the **Update** button, tries again). The check runs even with `update.notify: off` (which then only silences the page's and the phone's "available"). An install that can't run here (a checkout, Bundler, an unwritable gem dir) stays a notice. `off`: notice only. See [Unattended updates](#unattended-updates-updateauto). |
|
|
2309
2309
|
| `update.restart` | `idle` | | With `update.auto: install`: `idle` restarts the stale workers whose session is idle and untouched for 10 minutes, then chi web itself, once no turn runs anywhere and the newest chi has answered `chi --version`; it pushes "chi updated to X". `never`: the install only (the page's toast offers the restarts, workers also exit on their own when idle). |
|
|
2310
2310
|
| `update.check_hours` | `24` | | Hours between RubyGems checks (at least 1). The first check starts about 30 seconds after chi web starts. |
|
|
2311
2311
|
| `update.min_age_hours` | `24` | | A release must be this old before chi web offers it; `0` disables the age delay. |
|
|
@@ -2329,7 +2329,7 @@ column says so, a `--kebab-name` flag. The maps (`hosts:`, `models:`,
|
|
|
2329
2329
|
| `web.port` | `4567` | `--port` | `chi web`'s port. See [CLI](cli.md). |
|
|
2330
2330
|
| `web.host` | `127.0.0.1` | yes | `127.0.0.1`, `::1` or `localhost`; `lan` (this machine's private IPv4 address) or one of its IPv4 addresses also opens `chi web` to the network, with an access token, asked of this machine's 127.0.0.1 too (its `Local:` link carries a one-time code; `chi web --new-token` replaces the token). Anything else binds `127.0.0.1` with a warning. See [CLI: chi web on your phone](cli.md#chi-web-on-your-phone). |
|
|
2331
2331
|
| `web.markdown` | `false` | yes | Render answers as Markdown in `chi web`. |
|
|
2332
|
-
| `web.working_set` | `true` | yes | The stage view's working set: the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint
|
|
2332
|
+
| `web.working_set` | `true` | yes | The stage view's working set: the files, memories and URLs a turn brought into the model's context, in a rail in the stage, a footprint as each finished turn's block summary and a `set N` chip in place of the mem chip; `false` brings the mem chip back. `?working_set=1` or `?working_set=0` on the page URL overrides it for that page load. See [CLI: the working set](cli.md#the-working-set). |
|
|
2333
2333
|
| `web.annotate_presets` | `Agreed\|Could you please elaborate?` | yes | Quick replies next to Annotate in `chi web`, `\|`-separated (a YAML list works too); `""` in the file or on the CLI leaves only Annotate (an empty env value means the default). See [CLI](cli.md#web-annotate-presets). |
|
|
2334
2334
|
| `web.editor` | `vscode` | yes | What a file ref in `chi web` (a file tool row's title, a diff line) opens, for a viewer on this machine: a preset (`vscode`, `vscode-insiders`, `cursor`, `zed`) or a URL template with `{path}` and an optional `{line}`; `none` turns refs off. See [Opening files from chi web](#opening-files-from-chi-web). |
|
|
2335
2335
|
| `web.start_dir` | the folder `chi web` runs in | | The folder `chi web` starts in (`chi web --start-dir DIR` for one run): its page (the printed link, a bare `/`, the LAN link and QR code, the Home Screen app) opens on that folder's project, outside a repo on every session, and a new session from the all view starts there; the header's project picker switches projects. `~` and a relative path (resolved from your home folder) work; one that isn't a folder stops `chi web` from starting. `chi web` never changes its own folder. See [CLI](cli.md). |
|
|
@@ -42,7 +42,7 @@ Behavior:
|
|
|
42
42
|
again or stop it (`TaskWait::MESSAGE_WAITING_NOTE`), and `waited: Ns`; the task keeps running and stays watched
|
|
43
43
|
(below). A task that finished meanwhile gives its finished result, as after a Stop. A `chi -p` turn has no probe. The same probe ends a blocking `delegate_result` (and `delegate`'s wait) early; see [Sessions: Delegating](../sessions.md).
|
|
44
44
|
- `task_create` accepts `env` as a JSON object string for deterministic overrides such as `PATH`; use an absolute interpreter path when that is simpler. Ruby/Bundler isolation variables remain protected.
|
|
45
|
-
- `execute` and `task_create` both spawn with chi's own Ruby/Bundler setup scrubbed (`TaskRuntime.sanitized_spawn_env`): `RUBYOPT` loses its `-r…bundler/setup` flags (others stay) and `RUBYLIB
|
|
45
|
+
- `execute` and `task_create` both spawn with chi's own Ruby/Bundler setup scrubbed (`TaskRuntime.sanitized_spawn_env`): `RUBYOPT` loses its `-r…bundler/setup` flags (others stay) and `RUBYLIB` and what `bundle exec` sets (`BundlerEnv::VARS`: `BUNDLE_GEMFILE`, `BUNDLE_LOCKFILE`, `BUNDLE_BIN_PATH`, `BUNDLER_VERSION`, `BUNDLER_SETUP`) are unset, so a project's `ruby -e` or `bundle exec` uses its own Gemfile, or none, when chi runs under `bundle exec`. RubyGems requires what `BUNDLER_SETUP` names at boot, whatever `RUBYOPT` says. A project's own settings (`BUNDLE_PATH`, `BUNDLE_WITHOUT`) stay. `task_create` refuses those keys in the model's `env`, its error saying to write `KEY=value cmd` in the command instead; `execute`'s `env` comes from chi's callers (`Builtins`, `!cmd`), not the model, and is set over the scrub. An `execute` handed over at its limit keeps the process it spawned, so the task runs with the same env.
|
|
46
46
|
- `execute` and `task_create` export chi's own markers into the command, set over the model's `env` (which can't set them: `Error: env key is reserved`): `SAMAGOTCHI_PARENT_SESSION` (the session's id, `chi` without one; a chi started there answers as a parent agent), `SAMAGOTCHI_SESSION_MODEL` (the resolved ref the session runs on, read at each call so it follows `/model`; unset when unknown) `SAMAGOTCHI_SESSION_THINKING` (the session's own thinking level; unset when it has none) and `SAMAGOTCHI_SESSION_REASONING_HISTORY` (its own reasoning_history level, the same way). `chi self` reads the last three for its model, thinking level and reasoning history. The four are `ChildEnv::SESSION_MARKERS` (`TaskRuntime::MARKER_ENV_KEYS`), which a spawned worker unsets (`ChildEnv.unset`, merged into its spawn env). A session's worker never inherits them from whoever started it (a `chi send` run by another session's `execute`): its other commands (a user's `!cmd`, an MCP server, a context command) have none.
|
|
47
47
|
- They also pass on a set `XDG_STATE_HOME` / `XDG_CONFIG_HOME` made absolute (`Builtins.xdg_absolute`, via `Paths`), so a chi the command runs in another `cwd` (`chi send`) reads this chi's state and config. These aren't reserved: an XDG dir the model sets in `task_create`'s `env` stays its own.
|
|
48
48
|
- Every runner starts from the session's project env, `ProjectEnv.tools_env`: the overlay a spawned worker computed once at boot (`SessionManager.apply_project_env` → `ProjectEnv.compute` → `ProjectEnv.install!`; its folder's `mise env`, and the chi shim's dir first on PATH so `chi` is the chi home's), less `ProjectEnv::TOOLS_DROP` (`RUBYOPT`, `RUBYLIB`, Bundler's: the scrub above sets those). Outside a worker (`ProjectEnv::NONE`) it is `{}`. The sites: `execute` and `task_create` (`Tools::Builtins#project_env`, under the markers and the model's `env`; a participant's turn gets `{}`), the user's `!cmd` (`SessionCommands#shell`), and through `ProjectEnv.spawn_env` (the scrub above, then `tools_env`: what `execute` spawns with, for the runners that don't go through it) a context source's command (`ContextFetch#env_for`) and an MCP server, under the server's own keys (`bundles/mcp/plugin.rb` `server_env`, from mcp 0.7.4; no participant rule: the server is the session's). chi's own process env is never changed, and the project env never enters the prompt. User docs: [Project env](../sessions.md#project-env); the launch side: [How chi launches itself](../architecture.md#how-chi-launches-itself).
|
data/docs/internals/bridge.md
CHANGED
|
@@ -52,6 +52,9 @@ the "asking again" and steer-cut rows, ✂ rows and questions (with how they wer
|
|
|
52
52
|
- **Placement is relative.** An entry carries `turns` and lists with `turns_since` (turns completed after it) and
|
|
53
53
|
`current` (a card of the running turn). A card that comes mid-turn but isn't the turn's (an anytime command's, such as
|
|
54
54
|
`/btw`) goes after that turn (`during`). A card with an earlier card's id replaces it in place.
|
|
55
|
+
- **A turn that leaves nothing.** `!rollback` (`TurnFlow#rollback!`, `:turn_rolled_back`) takes a kept turn's count
|
|
56
|
+
back. Of a rolled-back turn, and a failed one with nothing kept, the cards and hook notices become between-turns entries
|
|
57
|
+
at its place (the cards lose their actions); its other rows go, having no step to sit in.
|
|
55
58
|
- **Caps.** `CAPACITY` (20) each for notices, ✂ rows (`LLM_CONTEXT_TYPES`) and cards, so one burst cannot push out
|
|
56
59
|
another kind. An open question (an approval too) is never pushed out.
|
|
57
60
|
- **Saved.** With a `path` (`cards.json` in the session's folder) the store rewrites the file after each event in
|
|
@@ -60,6 +63,11 @@ the "asking again" and steer-cut rows, ✂ rows and questions (with how they wer
|
|
|
60
63
|
and an unanswered question waits for no one: neither is saved or seeded. An entry from an earlier worker lists with
|
|
61
64
|
`earlier: true`; one shown during a turn comes back **without its actions** (their turn no longer runs), while a
|
|
62
65
|
between-turns card keeps its buttons.
|
|
66
|
+
- **A killed turn counts.** A worker killed mid-turn never saw the turn end, but `TurnCheckpoint` keeps its prompt (the
|
|
67
|
+
next worker settles it as canceled). The Bridge's store (`killed_turn_stays:`) saves `"running": true` at
|
|
68
|
+
`:turn_started`, and a store started from that adds the one turn. An ordered end clears it, so a graceful stop's
|
|
69
|
+
cancel counts once; a file without the field counts none. A REPL's store never saves it: it keeps no running turn in
|
|
70
|
+
the session, so a kill takes the prompt too.
|
|
63
71
|
|
|
64
72
|
## SSEWriter
|
|
65
73
|
|
data/docs/internals/bundles.md
CHANGED
|
@@ -13,9 +13,14 @@ user-facing side (what a bundle owns, profiles, needs) is in [memory.md](../memo
|
|
|
13
13
|
*.md, index.md the bundle's memories, one managed index line each ("· from <bundle>")
|
|
14
14
|
<system memories>/.bundles/ MemoryPaths.bundles_dir
|
|
15
15
|
<name>/manifest.json the install record (Provenance#write, read as InstalledBundle)
|
|
16
|
-
<name>/bases/ each file
|
|
16
|
+
<name>/bases/ each file's base for the next upgrade's 3-way merge: as installed, or the
|
|
17
|
+
bundle's own text after a merge
|
|
18
|
+
<name>/incoming/ the bundle's text for each file marked conflict, until the file settles (Provenance:
|
|
19
|
+
#write, #refresh_marks, gone with #resolve_conflicts); nothing globs it for memories
|
|
20
|
+
(Builder takes the scope dir's top level), and an uninstall's rm_rf sweeps it
|
|
17
21
|
<name>/hooks/ guardrails/ plugin/ scripts/
|
|
18
|
-
.trash/<name>-<stamp>/ files an uninstall or upgrade took away
|
|
22
|
+
.trash/<name>-<stamp>/ files an uninstall or upgrade took away, and copies of what an install
|
|
23
|
+
overwrote (Trash), never deleted
|
|
19
24
|
```
|
|
20
25
|
|
|
21
26
|
## Components
|
|
@@ -35,15 +40,19 @@ user-facing side (what a bundle owns, profiles, needs) is in [memory.md](../memo
|
|
|
35
40
|
| `MemoryFiles` | which top-level `*.md` files of a bundle are its memories (`.select`: the `files:` list, else all but README/LICENSE and the like), `.unshipped` (listed, not shipped) and `.symlinks` (skipped: a symlink is never a memory) |
|
|
36
41
|
| `Manifest` | parses/validates `manifest.yml` (`name:` is the bundle's name and a directory under `.bundles/`, so a path such as `../x`, `a/b`, `.` or `..` is refused: `name: … is not a bundle name`; YAML that doesn't parse or isn't a mapping is a `ValidationError` too; files, hooks as `BundleHook`, plugin, scripts, needs, requires_chi, includes, context_providers, session_settings: the keys a session's `chi --set` may give, a list or a mapping of them to types (`SESSION_SETTING_TYPES`), recorded at install in `manifest.json` (`session_settings`, `session_setting_types`) for `SessionConfig` to check; settings: the keys config.yml's `bundles: <name>:` may have, the same shape, recorded as `settings` (nil when the manifest has none) and `setting_types` for `BundleSettingsCheck`, whose warnings the Engine holds for the first turn and `SessionConfig`'s refusals share the words of) and writes it (`Manifest.write`, for Builder). It ignores `requires_chi_next`, a shipped bundle's release-time marker (`script/release/release_tools.rb`, docs/releasing.md) |
|
|
37
42
|
| `Installer` | one install/upgrade/dry run of one bundle (below) |
|
|
38
|
-
| `AssetInstaller` | the parts that live in `.bundles/<name>/`: hooks, guardrail rules, plugin, scripts; returns `AssetInstaller::Installed` (the paths the record keeps) |
|
|
39
|
-
| `Merger` | 3-way classification per file: `install`, `fast_forward`, `keep`, `noop`, `conflict` |
|
|
40
|
-
| `
|
|
43
|
+
| `AssetInstaller` | the parts that live in `.bundles/<name>/`: hooks, guardrail rules, plugin, scripts; returns `AssetInstaller::Installed` (the paths the record keeps). A file it replaces or removes whose bytes are neither the recorded sha nor the incoming file's is copied to the Installer's `Trash` first (`Trash#copy_edit`, `#copy_edits` for a folder at any depth, as `hooks/x`, `guardrails/x`, `plugin/x`, `scripts/sub/x`; no sha recorded counts as edited; a dev link never is) |
|
|
44
|
+
| `Merger` | 3-way classification per file: `.classify` → an `Outcome` (`status`: `install`, `fast_forward`, `keep`, `noop`, `conflict`, `merged`; `base`: where the file's next base comes from, `:on_disk`, `:recorded` or `:incoming`; a new outcome and its base go in its constants, and it needs a branch in `Installer#merge_memory`, a kind in `#next_base` if its base is new, and its status word in `#preview_memory`, `#verify_memory_checksums` and `#summary`). `.classify` never merges and answers `conflict` for two changed sides; `Merger::Upgrade` (provenance, target dir, source dir) is the one way to ask what an upgrade does to a file, nothing written: `#outcome` (`.classify`, then `TextMerge` where both sides changed, git once per call: `merged`, with its `TextMerge::Result` and the digest it read as the Outcome's `merge` and `current_sha`; `ALREADY_MERGED`, a `keep` with base `:incoming`, when the merge adds nothing; or `conflict` with that `merge`, whose `why` says why none was possible), `#classified`, `#forecast` (a `Forecast` of `merged` and `behind` in one pass), `#behind` (a `conflict` outcome as a `FileStanding::Behind`: why, and from `TextMerge.changed_sections` what it missed, nothing for an older mark, whose base may be the user's text), `#paths`, used by the Installer's merge and dry run, `ShippedUpdate.plan` and `SystemBundle.sync(dry_run:)`. `.write_merged` puts a merge in place: the digest checked just before the rename (`AtomicFile.write`'s block), through a symlink, the mode kept, the old file in the `Trash`; false when a live `memory_write` got in. A mark from an older chi (`InstalledBundle.legacy_mark?`: no `incoming_sha`, or `legacy_base`, which keeps that known once the digest is recorded, until the mark goes) may have the user's own text as its base, 0.149's doing, and a merge against it would undo that text with nothing to show, or a fast-forward replace all of it: `#outcome` makes a fast-forward that takes a line out of the file, and `.merge_outcome` a merge that does, a `conflict` (`FileStanding::LEGACY_BASE`), on the Installer's and `Remerge`'s path alike, unless `ShippedHistory` proves the base is a version chi shipped. The price, with no such gem left or for a bundle chi doesn't ship: a real base looks the same, so such a file whose bundle rewords or removes a line it still holds stays behind until it is resolved by hand, with `--agent` or with `--force`; no retry fixes it. `Installer#save_marked_file` serves a fast-forward that goes ahead over a mark: a file put back to its base under this chi's mark, or an older mark with a proved base or an update that only adds. `.markers?` (a file holding a merge's `<<<<<<<`/`>>>>>>>` lines; `=======` alone is a Markdown underline) |
|
|
45
|
+
| `ShippedHistory` | `.shipped?(bundle, file, path)`: whether those bytes are that file of that bundle (by manifest name, since a shipped dir can be renamed) in an installed `samagotchi-<version>` gem. Reads `<gem dir>/gems/` by hand, for `Gem.path` (set by a chi home's boot string) and the home's `gem_dirs` from home.json (a checkout or another Ruby runs on other gems), never `Gem::Specification`. Size, then bytes, then the manifest. Anything it can't read is no match, which keeps the guard. Asked only when `Merger`'s guard would otherwise fire: with 54 gems on the Studio a miss costs about 4 ms, a hit less |
|
|
46
|
+
| `TextMerge` | the text merge: `.merge(base:, ours:, theirs:)` → a `Result` (`status` `:clean` with `text`, `:conflict` with `hunks`, `:failed` with `why`). `git merge-file -p --diff3 --marker-size=20` on temp copies in a temp cwd, with every `GIT_*` that points at a repository or a config unset or at `/dev/null` (it can run inside another tool's hook). git isn't a runtime dependency: none on PATH, or macOS's `/usr/bin/git` with no developer tools behind it (`.apple_stub?`, by `xcode-select -p`; running it pops a dialog), is `:failed`. So is a git past `TIMEOUT` (10 s; its process group is killed: this runs under `SystemBundle`'s lock), and any doubt about the answer: `min(hunks, 127)` against the exit status, a status over 127, a NUL in a side, marker lines that don't pair up (a user's line equal to one), a line no input holds, or an empty answer to non-empty inputs. `Scan` reads the output: a hunk unions (ours, then the entries of theirs that ours lacks) only when the last heading before it, at level 1 or 2 and outside code fences, HTML comments and any hunk, is titled exactly `Changelog` or `Change log`, with nothing but list entries (an item and its indented lines) since that heading and no fence or comment open, and base, ours and theirs each hold only list entries, with every base entry still on both sides: both only added. Any other hunk is a real conflict, and markers never leave the module. An entry is an item and the lines indented deeper under it, nested items too, and the union compares whole entries. `.changed_sections(base, theirs, ours)`: the headings of the sections the bundle changed and the file hasn't got, and whether text under no heading did, which is what names a miss: a conflict's hunks can't, since the whole file stays and the one hunk may be a Changelog line beside a whole new section. `Hunk#heading` counts the places under no heading |
|
|
47
|
+
| `FileStanding` | the one owner of what chi says of an edited bundle file, used by every surface: `Behind` (`#state`, `#line`: `x.md stays behind 0.8.0: no merge possible (why); missed ## A, ## B, ## C and 2 more`, `would stay` in a dry run), `MergeNote`, `.merged_line`, `.no_merge` (for `LEGACY_BASE` it says chi can't tell whether the file holds edits), `.clauses` (a report's clauses for one bundle), `.behind_count`, `.stay_behind`, `.counts_sentence` (the push), `.still_behind`, `.text` (UTF-8, whatever a name or heading was tagged), `FORCE_TAKES`, `FORCE_MOVES`, `IN_THE_TRASH`. Behind means marked and bytes other than the mark's `incoming_sha` (`.behind?`, read by `InstalledBundle#behind_files` and `Remerge` alike): a file brought level by hand isn't, a missing one is a missing file, and one that can't be read is. An older mark no retry has looked at reads `may be behind` (`Behind#unsure`, and the counts say so), and isn't behind at all when level with its recorded source on disk (`InstalledBundle#behind_file?`). A new surface reads these and adds no wording |
|
|
48
|
+
| `Remerge` | the retry at the same version, memory files only, for a file marked `conflict`: `#run(dry_run:)` → a `Result` (`merged`, `settled`, `stamped`, `behind`, `warnings`, `trash_copy`, `trash_dir`). It merges what merges and settles those entries (`Provenance#resolve_conflicts`, the index line refreshed), leaving `version`, `installed_at` and the assets alone: the Installer would `rm_rf` guardrails, plugin and scripts under live sessions. Every file it leaves is in `behind`, with why: one not shipped now (`MemoryFiles.select`) keeps its mark, base and text; one whose `incoming_sha` isn't the shipped text (a checkout at one VERSION) is left alone, no git runs, and it reads as its mark says; a mark with no digest (older chi) is tried as well, and a real conflict then records it (`Provenance#refresh_marks`, which writes only when the mark would read differently, so a conflict at each start writes nothing). A mark whose digest matches is tried on every run, since the file or git may have changed. `noop` and `keep` settle quietly; `fast_forward` waits for the next upgrade, reading as behind until then; `install` is a missing file, which isn't behind, and a warning says so. A file it can't read or replace stays as it is, saying why. Called from `ShippedUpdate.plan_row`/`apply` (`chi update`) and `SystemBundle.sync`'s equal-version branch, under its lock (each chi start and `chi update`); a bundle chi doesn't ship retries through `chi bundle upgrade`. No marks: nothing is read beyond the record. One marked file costs one git run per Engine start, about 12 ms on the Studio (0.1 ms with none) |
|
|
49
|
+
| `Provenance` | the `.bundles/<name>/` dir: `#write` the record + bases (its `files:` is the full list: a key left out is dropped, a nil value keeps the entry with no base; `marks:` are the files left behind, each a `FileStanding::Behind`, and `incoming_dir:` the bundle text each speaks of, recorded as `incoming_sha` and saved at `#incoming_path`; an older mark that stays keeps `legacy_base`), `#resolve_conflicts` (base to the incoming file, mark and its fields (`MARK_FIELDS`) and saved text gone; a file whose incoming copy is gone keeps both), `#refresh_marks` (what a retry found: why, missed, the digest and `legacy_base`, the saved text), `#note_merged` and `#clear_merge_notes(notes)` (`MERGE_NOTE_FIELDS`, kept through `#write`; the saved text is best effort, after the manifest, so it can't leave a plugin under the old record's sha; any other failure writing the record still can, until a retry), `#record` → `InstalledBundle`, `.each_installed`, `.claimants` (which bundles own a file) |
|
|
41
50
|
| `InstalledBundle`, `BundleHook`, `PluginRef` | value objects for the record; tolerant of older records (missing keys read as empty). `BundleHook#events` is the manifest's `event:` or its `events:` list (written back as `event:` for one, as an older chi reads it); `Hooks::BundleLoader#load_hook_file` builds the hook once and registers it under each |
|
|
42
51
|
| `Builder` | `chi bundle build`: memories (+ the installed bundle's hooks, rules, plugin, scripts) → zip/tar/dir |
|
|
43
52
|
| `Profile` | meta bundles (`includes:`): install the members, record which; `InstallResult#kept_own` names a new member's memory files the user already had, with other bytes (`kept_own_line`, printed by `chi bundle`, `chi update` and `chi bootstrap`); a dry run runs each member's Installer as a dry run too, so it names them as well |
|
|
44
|
-
| `SystemBundle`, `ShippedUpdate` | the built-in system bundle (`ensure!` at Engine start, `sync` in `chi update`) and `chi update`'s upgrade of shipped bundles; both drive the Installer with `upgrade: true
|
|
53
|
+
| `SystemBundle`, `ShippedUpdate` | the built-in system bundle (`ensure!` at Engine start, `sync` in `chi update`) and `chi update`'s upgrade of shipped bundles; both drive the Installer with `upgrade: true` and `Remerge` at an equal version (`ShippedUpdate::Row`'s `:would_merge`, `:merged`; `SystemBundle::Result`'s `:merged`). `SystemBundle` also puts back a memory missing at an equal version, that file alone, with no Installer (`verify_files_present`, `Provenance#record_restored`). `ensure!` echoes a merge in one line, in the row's words. That reaches a terminal launch; a worker has only its log (`Log.configure(stderr: false)`), so every merge leaves a note on the file's record (`Installer#note_merges`, a failed run's too, and `Remerge#note_merges`; `Provenance#note_merged`: version, time, trash dir). `chi bundle status` shows it, and `chi update` reads the notes before the run (`SystemBundle.merge_notes`, `ShippedUpdate::Row#earlier`), names them in the row and clears after it those exact ones and the notes of the files that run merged (a worker's meanwhile, on another file, stays), unless it was a dry run, the row failed or has no place for them (a skipped system row), or the run is unattended (`ChildEnv::UNATTENDED_UPDATE`, which `Web::UpdateOps` sets for `update.auto`, an env marker so a hand-over's exec keeps it and an older chi ignores it; `--json` alone says nothing, as a person or script may use it). `chi bundle upgrade` clears the notes of what it printed, and `--force` those of the files it replaced. `--json`'s `merged` is this run's, `earlier` the notes'. `ensure!` says what an upgrade left behind and nothing of a file already behind, which `Result#behind` still has for the row. A plan or sync that can't read a file is that bundle's failed row, in `Trash.failure_message`'s words (`ShippedUpdate.plan_row`, `SystemBundle.sync`). `ShippedUpdate.external` is the rest: what `chi update` only checks |
|
|
45
54
|
| `InstalledCopy`, `BundleCommand::InstalledCheck` | `chi update`'s re-check of the bundles chi didn't ship ([docs/cli.md](../cli.md#updating)). `InstalledCopy` lays a record and its installed files out as a source folder (manifest.yml from `Manifest.write`, the files' own shas, memories from `bases/`); `InstalledCheck` forks per bundle (a plugin's `exit` or hang is that bundle's row; stdio to /dev/null, so `--json` stays parseable; `TIMEOUT`, then KILL of its group) and runs `Check.new(dir, installed: true)` there, which leaves out what only suits a source tree. Its `boundary` finding is narrower there than in a source tree: `Testing::Boundary.gone?` calls a reference gone only when its constant doesn't resolve or the object has no method the name names, so a bundle reaching `Samagotchi::Log` gets no row. lib loads lazily, so when a name doesn't resolve `gone?` requires every file of this chi's library in that same child and asks again (about 0.2 s, only for a bundle that reaches into chi at all); anything it can't read — a `const_get`, a require of a file that is there — is taken as still there. The fork is the point: `Sandbox` swaps ENV and the plugin's code is arbitrary. `UpdateCommand#external_rows` makes the rows (`level`, never `failed`) and holds the check back while a newer gem is yet to take over (`@not_checked`), since a fork is this chi's code |
|
|
46
|
-
| `Uninstaller`, `Trash`, `Status`, `Listing` | remove, keep removed files
|
|
55
|
+
| `Uninstaller`, `Trash`, `Status`, `Listing` | remove (the bundle's own folder too: an edited file there is copied to the trash first, `Uninstaller#trash_copy_line`); keep removed files (`Trash#move`) and a copy of overwritten ones (`Trash#copy`, its `as:` keeping a subfolder); `chi bundle status` (per file, `behind`, `merge_note`, `unreadable`; `issues=` counts behind, missing and unreadable, not edited); `chi bundle list` (`Installed#behind`) |
|
|
47
56
|
| `IndexUpdater`, `IndexSync` | the managed `index.md` lines (Installer; and the write/edit tools for memories) |
|
|
48
57
|
| `EntrySize` | one memory's size in tokens: `memory.entry_warn_tokens`' crossing note after a memory write, `chi self`'s `big memories` row |
|
|
49
58
|
| `IndexSize` | one scope's memory index as the prompt carries it (tokens, lines, bytes): `memory.index_warn_tokens`' crossing note after a memory write, `chi self`'s summary, the prompt's figures (`SystemPrompt`) |
|
|
@@ -86,25 +95,44 @@ The order matters: warnings print in it, and a plugin/script the manifest names
|
|
|
86
95
|
`#source_change` (the summary's first line, `Source changes: old → new`). A source `SourceIdentity` can't place
|
|
87
96
|
(an older record's relative path) never refuses.
|
|
88
97
|
3. `install_memories`, per memory (`MemoryFiles.select`: a non-empty `files:` list, else every top-level `*.md` but
|
|
89
|
-
README, CHANGELOG, LICENSE and the like; a listed name not shipped warns; a symlink is skipped with a warning): an upgrade 3-way merges the files the bundle owns (`merge_memory`), a dry run only
|
|
90
|
-
classifies (`preview_memory`), a plain install writes new files and skips existing ones (`skip_existing`)
|
|
98
|
+
README, CHANGELOG, LICENSE and the like; a listed name not shipped warns; a symlink is skipped with a warning): an upgrade 3-way merges the files the bundle owns (`merge_memory`: a clean text merge replaces the file through `Merger.write_merged`, and a real conflict, no git or no base leaves it untouched, `note_conflict`, in `#behind`; a fast-forward over an entry this chi marked `conflict`, a file put back by hand, copies it to the trash first: `save_marked_file`), a dry run only
|
|
99
|
+
classifies (`preview_memory`, `would_merge` for a merge, git running on temp copies; both through `Merger::Upgrade`), a plain install writes new files and skips existing ones (`skip_existing`), and `--force` overwrites, a file that
|
|
100
|
+
differs copied to the trash first (`Trash#copy`, said by `#trash_copy_line`; a profile's in `InstallResult#trash_copies`). A
|
|
91
101
|
same-name file the bundle didn't write is the user's: skipped and never recorded (`@owned`). Model overlays
|
|
92
102
|
(`<name>.<key>.md`) get no index line (`note_overlay`).
|
|
93
103
|
4. `AssetInstaller#run`: hooks (manifest-listed, else every `hooks/*.rb`), prune dropped hooks, hook checksums,
|
|
94
|
-
guardrails, plugin, scripts; each set replaces the previous version's. requires_chi warnings for hooks/rules. A
|
|
104
|
+
guardrails, plugin, scripts; each set replaces the previous version's, an edited file copied to the trash first. requires_chi warnings for hooks/rules. A
|
|
95
105
|
file that is a symlink or resolves outside the bundle dir (`AssetInstaller#linked?`, a linked `hooks/` too) is
|
|
96
106
|
skipped with a warning (a hook or rule) or raises `InstallError` (the plugin, a script).
|
|
97
107
|
5. An upgrade's `prune_dropped_files`: unchanged → trash; edited → kept (`kept_pruned`); owned by another bundle → kept.
|
|
98
108
|
6. `verify_memory_checksums` (strict), `warn_missing_needs`.
|
|
99
|
-
7. `write_provenance` (manifest, not a dry run): bases come from
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
7. `write_provenance` (manifest, not a dry run): an upgrade's bases come from each file's `Merger::Outcome`
|
|
110
|
+
(`Installer#next_base`): the file on disk, which has the bundle's bytes; the incoming file for a merge, since the merged
|
|
111
|
+
file holds the user's edit and taking it would make current == base, so the next upgrade would fast-forward over the
|
|
112
|
+
edit (the edited signal stays current != base, which `chi bundle status` and uninstall's refusal read); and where the user's edit was
|
|
113
|
+
kept (keep, conflict, whose `FileStanding::Behind` goes in `marks:`; a file the bundle dropped, kept_pruned, and a re-install's skipped edit take the same path by their
|
|
114
|
+
status and reason): those keep the old base, so the next upgrade still sees the edit. One with no base stays without one (a nil in `Provenance#write`'s `files:`, which keeps the
|
|
115
|
+
entry and its recorded checksum): taking the user's file would let the next upgrade fast-forward over it. A plain
|
|
116
|
+
install carries the `conflict` mark of a file it skipped (`held_conflict_marks`), a newer source moving `version`
|
|
117
|
+
included; it goes once the file has the incoming bytes. A plain install also keeps the record (the old base) of a file an earlier install
|
|
102
118
|
owned and this version doesn't ship, while it is on disk (`dropped_owned_files`), so the next upgrade prunes it.
|
|
103
119
|
8. `detect_placeholders`.
|
|
104
120
|
|
|
121
|
+
A file system error in steps 3 to 5 (`Installer#replace_files`; a `.trash` it can't write, an edited file it can't read) is an
|
|
122
|
+
`InstallError` in `Trash.failure_message`'s words, as it is an `UninstallError` in `Uninstaller#run`. Each save comes before
|
|
123
|
+
its removal, so no edit is lost, and the record isn't written, so a retry is the same upgrade. Not atomic: files the
|
|
124
|
+
failed run already placed stay.
|
|
125
|
+
|
|
126
|
+
Which files a plan asks `Merger::Upgrade` about is the caller's, and the lists differ, each less the files the bundle
|
|
127
|
+
doesn't own: the Installer's `MemoryFiles.select`; `ShippedUpdate.forecast`' every shipped `*.md`, so `chi update`'s plan
|
|
128
|
+
can name a file dropped from `files:` or now a symlink, which the upgrade doesn't merge: edited, it stays (`kept_pruned`, or `kept_shared` when another bundle has it too); `SystemBundle`'s dry
|
|
129
|
+
run the manifest's `files:`, so a manifest with none plans nothing (the shipped one lists its files).
|
|
130
|
+
|
|
105
131
|
Results are `@results` (file → `{status:, reason:}`), summarised by `#summary`. An upgrade with conflicts keeps an
|
|
106
132
|
owned source dir alive (`#source_dir`) until `#cleanup_source!`, because the conflict agent reads the incoming
|
|
107
|
-
files; `
|
|
133
|
+
files; `BundleCommand#settle_conflicts` then runs `Provenance#resolve_conflicts`, which moves a base forward and keeps
|
|
134
|
+
the entry's description, only for a file the agent step changed that holds no markers (`Merger.markers?`), and whose incoming
|
|
135
|
+
copy is still there. Any other keeps its old base and mark, and the command exits `CONFLICTS_KEPT`.
|
|
108
136
|
|
|
109
137
|
## Builder#run, in order
|
|
110
138
|
|
|
@@ -220,8 +220,13 @@ the record settles is `unclear`, and a file changed since isn't seen. If that tu
|
|
|
220
220
|
next step, and the file and view below can stay.
|
|
221
221
|
|
|
222
222
|
**Independence.** The request (`ObjectivesCheck.request`) has its own system text and no tools. Its record is what people and
|
|
223
|
-
notes said
|
|
224
|
-
|
|
223
|
+
notes said, what tools returned, and the agent's visible answers labelled `[agent's own words]` (`.record`, each entry cut at 1,500 characters, the
|
|
224
|
+
newest 24,000 kept). Without those answers a claim about what the agent said or asked could only come back `unclear`. So the request says they settle
|
|
225
|
+
what was said or asked and are never proof of work, which needs a tool's output or a person's word. That rule is words to a model, not a mechanism: a
|
|
226
|
+
probe on Qwen3.8 Flash Next held it 3 of 3 (only the agent's "all pass": `unclear`), and a verdict is information only either way.
|
|
227
|
+
The record never holds the agent's thinking (`own_words`: a chat entry's `thinking` and `anthropic_content` aren't read; a native
|
|
228
|
+
entry's content is the raw response, so its inline thoughts, a thought cut off unclosed, and its call markup come out), the system prompt, the list's
|
|
229
|
+
notes, a continue's carry note, an earlier session's answer that would read as outside news
|
|
225
230
|
(`Objectives.outside_note?`, the rule the audit shares), or the objectives tool's calls, since a move isn't evidence for itself.
|
|
226
231
|
Note and evidence are capped at 1,000 characters each. Mid-turn it reads the loop's conversation (`Engine#live_conversation`), the running turn's runs too.
|
|
227
232
|
|
|
@@ -23,7 +23,7 @@ page. A factory dep a new version stops passing is the same hazard the other way
|
|
|
23
23
|
out of `send_turn.js`, `session_actions.js` and `lists_view.js`); a page loaded before keeps all its old modules
|
|
24
24
|
until a reload, so the risk is a mixed cache, not an open tab. `answer_fold.js`, `details_motion.js`,
|
|
25
25
|
`turn_range.js`, `history_reveal.js`, `latest.js`, `session_payload.js`, `method_api.js`, `session_store.js`,
|
|
26
|
-
`session_fields.js`, `feature_gates.js`, `revise_stack.js`, `revise_switch.js`, `shell_command.js`, `stale_params.js`, `popover_modal.js`, `more_sheet.js`, `hash_intent.js` (what the hash asks for: session, all, start or keep), `worker_features.js` and the `objectives_*.js` modules are new modules for that reason.
|
|
26
|
+
`session_fields.js`, `feature_gates.js`, `revise_stack.js`, `revise_switch.js`, `shell_command.js`, `stale_params.js`, `popover_modal.js`, `more_sheet.js`, `hash_intent.js` (what the hash asks for: session, all, start or keep), `worker_features.js`, `block_open.js` and the `objectives_*.js` modules are new modules for that reason.
|
|
27
27
|
|
|
28
28
|
## Two pages, two models
|
|
29
29
|
|
data/docs/internals/web-push.md
CHANGED
|
@@ -181,9 +181,9 @@ from saying it twice across restarts). The key's `chi:` prefix keeps sw.js from
|
|
|
181
181
|
|
|
182
182
|
| `kind` | key | title / body |
|
|
183
183
|
|---|---|---|
|
|
184
|
-
| `installed` (`update.restart: never`) | `chi:installed:<X>` | "chi X is installed" / "chi web and its sessions switch over when you restart them." +
|
|
184
|
+
| `installed` (`update.restart: never`) | `chi:installed:<X>` | "chi X is installed" / "chi web and its sessions switch over when you restart them." + the edited files (`FileStanding.counts_sentence`) |
|
|
185
185
|
| `failed` | `chi:update_failed:<X>` | "chi X didn't install" (or "installed with a problem" when the gem row was fine) / the first failed row's status, "Open chi web for details." |
|
|
186
|
-
| `updated` | `chi:updated:<X>` | "chi updated to X" / "chi web and 3 sessions restarted; 1 restarts when idle." +
|
|
186
|
+
| `updated` | `chi:updated:<X>` | "chi updated to X" / "chi web and 3 sessions restarted; 1 restarts when idle." + the edited files |
|
|
187
187
|
| `restart_failed` | `chi:restart_failed:<X>` | "chi X is installed; chi web didn't restart" / why (a failed `--version` preflight, no wrapper), "Restart chi web in its terminal." |
|
|
188
188
|
|
|
189
189
|
`updated` is sent by the **restarted** chi web (its AutoUpdate finds the run at `phase: web`): the exec ends the
|
|
@@ -242,7 +242,10 @@ session's set (load, resync) and when the list opens (a file changed while the s
|
|
|
242
242
|
passes `working_set_updated` to it, and does nothing when the flag is off. A new snapshot redraws:
|
|
243
243
|
- the session bar's chip and the open list;
|
|
244
244
|
- the footprints, in place (`refreshFootprints`, the same node; a `data-ws-sig` of the items' states skips an
|
|
245
|
-
unchanged one)
|
|
245
|
+
unchanged one). A footprint is a `<span>` in its block's summary line, `.turn-work > summary > .tw-sum`, before the
|
|
246
|
+
steps' `.turn-steps`: drawn in the reload's template (`turnHistoryNodes`), prepended at the hand-off
|
|
247
|
+
(`stage_view.js handOff`, while the stage still hides the summary). A click there must not toggle the block:
|
|
248
|
+
`details_motion.js` skips `.ws-foot`, and `footClick` cancels the click;
|
|
246
249
|
- the rail (`onServer`, the stage's `scheduleRefresh`).
|
|
247
250
|
|
|
248
251
|
A state is the item's state now, not when its turn ran. A state change never refolds and never moves a line: the
|
|
@@ -287,7 +290,7 @@ leaves nothing behind. The rail adds a dashed `+ name · next turn` line per pen
|
|
|
287
290
|
(`working_set_rail.js addLabels`, inside the rail's budget), and `read again next turn` on a held line's title.
|
|
288
291
|
|
|
289
292
|
**Looks** (design spec §3, §5): a stale line is faded (`--ws-stale-opacity`: `.55` on the light palette, `.4` on the
|
|
290
|
-
dark one, where a lighter grey reads as plain secondary text; a footprint label `.55` on both
|
|
293
|
+
dark one, where a lighter grey reads as plain secondary text; a footprint label `.55` on both); a forgotten one is struck in `--text-faint`
|
|
291
294
|
at `opacity: .5`. A group shows `✂n` for its forgotten members. It is struck only when all its members are
|
|
292
295
|
forgotten, and faded when all are stale or forgotten (`groupState`). The list's ops text says `stale` or `forgotten`
|
|
293
296
|
in words (colour is never alone) and shows `~1.2k` tokens per row (`tokensText`). A footprint adds `n stale` (plain; a file the turn's
|