mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-13 18:49:34 -10:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a7f003249 | ||
|
|
44eb0fc8aa | ||
|
|
3b75325407 | ||
|
|
b7485e0968 | ||
|
|
f7cc92853c | ||
|
|
ab0b5b2c0e | ||
|
|
2ad1dbd259 | ||
|
|
b88eb36768 |
No files matched your search
+420
@@ -8,6 +8,426 @@ deprecations, and behavioral changes. Breaking changes are called out explicitly
|
||||
|
||||
---
|
||||
|
||||
## [0.7.15]
|
||||
|
||||
OpenRig 0.7.15 is a patch for steadier, more truthfully reported teams. A busy
|
||||
daemon does less repeated synchronous work on a few read paths and names more
|
||||
of what it was doing when it stalls. `rig daemon start` waits longer for a slow
|
||||
start, and restore tries a saved conversation when an eligible seat has no
|
||||
saved startup context. There are fixes across delivery, Slack replies, Codex seats and
|
||||
connected assistants, many contributed by people using OpenRig. See Known
|
||||
limits for what this release doesn't fix.
|
||||
|
||||
### Before you upgrade
|
||||
|
||||
- **Stop the daemon, back up the database, install 0.7.15, then start the
|
||||
daemon.** Your agents keep running through a daemon restart; don't use
|
||||
`rig down`, which ends them.
|
||||
|
||||
```sh
|
||||
rig daemon stop
|
||||
cp "$(rig config get db.path)" "$(rig config get db.path).before-0.7.15"
|
||||
npm install -g @openrig/cli@0.7.15 # or your existing installation method
|
||||
rig daemon start
|
||||
```
|
||||
|
||||
- **One migration runs before the daemon listens.** Migration 165 adds four
|
||||
columns and two indexes to `activity_grants`, binding a runner's activity
|
||||
credentials to its actual launch. Going back to 0.7.14 after it isn't
|
||||
established; keep the backup. ([#3060](https://github.com/mvschwarz/openrig/pull/3060))
|
||||
- **A slow start:** `rig daemon start` now gives the daemon child it started a
|
||||
180-second readiness budget, instead of 20 s, and prints
|
||||
"Waiting for daemon child <PID> readiness (…s elapsed; 180s limit)" about
|
||||
every 20 s. A quick start still returns at once, and a child that exits ends
|
||||
the wait. Let the wait finish. The budget bounds scheduling: synchronous work
|
||||
can run past the budget. A child still not ready when that budget is
|
||||
exhausted is reported pending as before: "Daemon startup is pending after the readiness deadline".
|
||||
Readiness remains unconfirmed; the child keeps running and the startup
|
||||
reservation is retained. Inspect the address and log it prints, and don't
|
||||
start it again until its restart steps are done: stop the named child PID and
|
||||
wait for it to exit, inspect `daemon-start.lock`, and only when both recorded
|
||||
launcher and child PIDs are absent, archive the lock and run
|
||||
`rig daemon start`. `rig daemon stop` cannot stop that unpublished child. ([#3118](https://github.com/mvschwarz/openrig/pull/3118))
|
||||
- **The plugins:** the `openrig` plugin carries the CLI's version, 0.7.15.
|
||||
openrig-core moves to 0.1.30, because its skills changed.
|
||||
|
||||
### Under load
|
||||
|
||||
- The wake ladder reads its prompt-refusal candidates from the open rows,
|
||||
instead of scanning the whole transition log on every tick. It returns the
|
||||
same rows. This removes one repeated scan; it isn't a measured fix for every
|
||||
stall. ([#3098](https://github.com/mvschwarz/openrig/pull/3098))
|
||||
- The execution view's candidate read steps through the queue in windows and,
|
||||
on its cooperative path, yields to the event loop between them, so a mission
|
||||
filter that matches few rows no longer holds the loop for a whole history
|
||||
walk. One large row, or the history count, can still take time. Inside a
|
||||
transaction, on a memory or temporary database, or on a non-WAL file, the
|
||||
candidate read keeps its synchronous fallback. ([#3122](https://github.com/mvschwarz/openrig/pull/3122))
|
||||
- Snapshot refreshes share process listings where each seat's order and the
|
||||
2 s freshness allow; each seat still gets its two ordered observations and
|
||||
its own fallback. The reduction is derived from the source, not measured. ([#3154](https://github.com/mvschwarz/openrig/pull/3154))
|
||||
- The slow-operation log adds three queue sites and three selected steps of an
|
||||
ordinary nodes read: `nodes.inventory.build`,
|
||||
`nodes.inventory.activity_sync` and `nodes.inventory.terminal_work`. These
|
||||
nodes records are written after a slow call completes; a missing record does
|
||||
not rule out unfinished work or work outside those steps. This changes no
|
||||
behaviour. ([#3100](https://github.com/mvschwarz/openrig/pull/3100), [#3138](https://github.com/mvschwarz/openrig/pull/3138))
|
||||
|
||||
### Restore and seats
|
||||
|
||||
- For an eligible seat in a rig with pods that restore starts in its own pane,
|
||||
a resume token with no saved startup context now lets restore try the saved
|
||||
conversation with an empty plan. It records the `startup_context` gap. A
|
||||
successful resume with that gap makes the rig read `partially_restored`; a
|
||||
missing conversation or failed start keeps its own status. No saved startup
|
||||
plan is replayed or saved startup-context row written; the adapter's ordinary
|
||||
bootstrap and existing skill restoration still run. An external CLI
|
||||
attachment is kept, no-token seats still wait for a decision, and legacy
|
||||
seats are unchanged. `restore-check` reads an eligible seat with a token
|
||||
yellow; for one with no saved context and no eligible token, it points to the
|
||||
read-only `rig up <rig> --existing --plan` preview. ([#3177](https://github.com/mvschwarz/openrig/pull/3177))
|
||||
- When `rig seat restart --keep-conversation` refuses a recoverable seat whose
|
||||
tmux session is gone, it names the way back: `rig launch '<rig>' '<node>'`
|
||||
(add `--plan` to preview). ([#3135](https://github.com/mvschwarz/openrig/pull/3135))
|
||||
- `restore-check` and a full restore warn when a snapshot recorded a named
|
||||
Codex profile that the current seat has cleared; restore uses the current
|
||||
selection. Nothing is refused. ([#3155](https://github.com/mvschwarz/openrig/pull/3155))
|
||||
- A context-usage watchdog reads its own seat's current occupant, not an
|
||||
archived generation's. A context watch whose seat can't be pinned, or has no
|
||||
recorded tenure, skips that tick with its reason instead of ending. ([#3027](https://github.com/mvschwarz/openrig/pull/3027), [#3139](https://github.com/mvschwarz/openrig/pull/3139))
|
||||
|
||||
### Delivery and people
|
||||
|
||||
- Right before an automatic paste into a seat with the draft-aware guard,
|
||||
OpenRig re-checks: it holds the paste after recent client activity, re-reads
|
||||
the input after a short wait, and holds when tmux can't be read. The message
|
||||
is held and retained; `rig seat held-messages` shows it. An ordinary guarded
|
||||
paste waits about 300 ms longer. This narrows [#3076](https://github.com/mvschwarz/openrig/issues/3076)'s window; it doesn't close it. ([#3097](https://github.com/mvschwarz/openrig/pull/3097))
|
||||
- A terminal seat whose tmux session runs under another name gets the exact
|
||||
text of a send, and a queued wake no longer types OpenRig's From/To envelope
|
||||
into its shell. ([#3074](https://github.com/mvschwarz/openrig/pull/3074))
|
||||
- When the arrival note is recorded before the answer is routed, an answer to
|
||||
a reply in an older Slack thread posts back into that thread, not as a new
|
||||
top-level message; see Known limits for when it posts top-level. Only the
|
||||
conversation's newest thread answers a parked question, as before. ([#3120](https://github.com/mvschwarz/openrig/pull/3120))
|
||||
- Slack previews on posts to a person are a setting: `rig slack setup --unfurl on|off`,
|
||||
and `rig slack status` shows which is in effect from the connector's next
|
||||
rewire. The default is off; see "Behaviour that changed". ([#3157](https://github.com/mvschwarz/openrig/pull/3157))
|
||||
|
||||
### Connected assistants
|
||||
|
||||
- An assistant that passes its team's display name as `rig_team`'s `rigId` is
|
||||
told to leave `rigId` out to see its own team, and a hosted member with no
|
||||
wake trigger is told it picks up work when its person asks, or on a schedule
|
||||
they set. ([#3104](https://github.com/mvschwarz/openrig/pull/3104))
|
||||
- An external grant that works its own inbox is told only about the tools it's
|
||||
offered. ([#3140](https://github.com/mvschwarz/openrig/pull/3140))
|
||||
- The TUI keeps connected assistants' check-in lines when a rig's seat
|
||||
inventory can't be read, with the error beside them. ([#3105](https://github.com/mvschwarz/openrig/pull/3105))
|
||||
- The `openrig` plugin needs Claude Code 2.1.119 or later. On earlier versions,
|
||||
with the plugin's OpenRig seat setting left blank, Claude Code drops its MCP
|
||||
server: the skill loads, but the agent has no OpenRig tools. ([#3137](https://github.com/mvschwarz/openrig/pull/3137))
|
||||
|
||||
### Codex, runners and harnesses
|
||||
|
||||
- **OpenRig renews its own changed Codex hook approvals.** When a new
|
||||
openrig-core changes one of OpenRig's six Codex hook declarations, the launch
|
||||
that installs it renews those approvals from OpenRig's own record instead of
|
||||
stopping at Codex's hook review. This runs at daemon start in the daemon's
|
||||
Codex home, when hooks are on and a Codex seat selected openrig-core, and at
|
||||
each such seat's launch in its own Codex home. It renews only when the
|
||||
installed plugin matches the shipped one and every current approval matches
|
||||
OpenRig's saved record. A person's own choice in any layer OpenRig reads
|
||||
keeps the review; profile files passed with `-p` aren't read. No real Codex
|
||||
seat ran in its tests. ([#3143](https://github.com/mvschwarz/openrig/pull/3143))
|
||||
- A Codex seat's resume command in the node inventory and detail panel is
|
||||
built from what a real resume uses, with a label when the recorded launch
|
||||
differs. Workspace options that aren't recorded per launch can still read as
|
||||
a match. ([#3043](https://github.com/mvschwarz/openrig/pull/3043))
|
||||
- Runner activity grants are bound to the actual launch, and the
|
||||
replacement's activation revokes its predecessor's grant. A grant made before
|
||||
this release stays tied to the seat's occupant until then. A grant that can't
|
||||
be bound never blocks a launch or restore. This attributes reports to
|
||||
the run OpenRig selected; it doesn't prove a runner's identity. ([#3060](https://github.com/mvschwarz/openrig/pull/3060))
|
||||
- Terminal views find tmux again when its cached path is gone, instead of
|
||||
tiles exiting 126 until a daemon restart. ([#3129](https://github.com/mvschwarz/openrig/pull/3129))
|
||||
- A `SKILL.md` with CRLF line endings is discovered and reaches a seat's
|
||||
managed plugin loadout. ([#3153](https://github.com/mvschwarz/openrig/pull/3153))
|
||||
- `rig context work-install --mission <missing>` warns that the mission
|
||||
doesn't exist, and `missionRoot` reads null; the exit code is unchanged. ([#3141](https://github.com/mvschwarz/openrig/pull/3141))
|
||||
- OpenRig's own transitions (`daemon@kernel` and `system:*`) no longer count
|
||||
toward ceremony amplification, and the post-restore audit message matches
|
||||
the restore skill. ([#3124](https://github.com/mvschwarz/openrig/pull/3124), [#3127](https://github.com/mvschwarz/openrig/pull/3127))
|
||||
|
||||
### Behaviour that changed
|
||||
|
||||
- **Slack previews:** posts to a person no longer show link and media previews
|
||||
by default. An existing install stops showing them after its next connector
|
||||
rewire or daemon restart. Run `rig slack setup --unfurl on` to turn them back
|
||||
on; earlier previews aren't removed. ([#3157](https://github.com/mvschwarz/openrig/pull/3157))
|
||||
- **Restore of an eligible seat with a resume token and no startup context**
|
||||
now tries its saved conversation, and a successful resume reads
|
||||
`partially_restored`. It used to stop with "Harness not started: no startup
|
||||
context" and read the rig not restorable. ([#3177](https://github.com/mvschwarz/openrig/pull/3177))
|
||||
|
||||
### Known limits
|
||||
|
||||
- **Daemon start:** the longer readiness budget doesn't identify or cure the
|
||||
cause of a slow start, synchronous work can run past the budget, and a child
|
||||
still not ready when that budget is exhausted stays pending. ([#3118](https://github.com/mvschwarz/openrig/pull/3118))
|
||||
- **Daemon memory:** 0.7.14's comparison under load established neither equal
|
||||
memory nor a regression against 0.7.13. This release makes no memory claim.
|
||||
- **Restore's overall result:** a rig can still read `fully_restored` while a
|
||||
seat restore didn't start (one claimed or added after its roster or snapshot
|
||||
was recorded), or a seat kept in its external CLI attachment, goes unnamed.
|
||||
A seat restore left as a bare shell after "Harness not started" still counts
|
||||
as running in `rig ps`.
|
||||
- **Draft-aware delivery ([#3076](https://github.com/mvschwarz/openrig/issues/3076)):** typing after the guard's final check and before
|
||||
the paste can still leave the notice beside the person's draft. In the tested
|
||||
append-mode schedule Enter was refused and nothing was submitted or deleted;
|
||||
this is not a guarantee for every interleaving. The prior conditional-send
|
||||
Enter-window case is unchanged: characters typed during OpenRig's last checks
|
||||
before Enter submitted with OpenRig's text.
|
||||
- **Draft-aware delivery with a wide Claude Code footer:** with Claude Code's
|
||||
full-width auto-update-failure footer on screen (seen at 200x50), a seat in
|
||||
the opt-in draft-aware typing mode whose input is empty can hold an ordinary
|
||||
send instead of delivering it. The message is kept, not lost, and
|
||||
`rig seat held-messages` shows it. The clipped footer at 80x24 doesn't do
|
||||
this.
|
||||
- **Draft-aware delivery to a busy Codex seat:** on Codex (seen with 0.167.1
|
||||
and 0.167.2), a send to a seat in the opt-in draft-aware typing mode while
|
||||
it's busy can be pasted into its input without Enter. The message isn't
|
||||
delivered, and it isn't kept for `rig seat held-messages`. A deliberate send
|
||||
reports failed, and its text stays in the seat's input box. This was seen on
|
||||
0.7.12 and 0.7.14, and there's no fix for it in this release.
|
||||
- **Linked Codex config files:** when a Codex seat's `config.toml` or
|
||||
`hooks.json` is a symbolic link, OpenRig records its hook trust under the
|
||||
link's target, as in 0.7.14. A change to key it by the file's own name isn't
|
||||
in this release, and such a seat may be asked to review hooks again. With a
|
||||
linked `config.toml`, OpenRig can also miss a setting stored for it that
|
||||
turns OpenRig's hooks off, and set those hooks up anyway when it moves them
|
||||
into `hooks.json`. ([#3078](https://github.com/mvschwarz/openrig/issues/3078))
|
||||
- **Slack reply threads:** recording the arrival note is best effort: a failed
|
||||
write is not retried and that answer posts top-level. Creating the message
|
||||
and recording the arrival note are separate writes, so a notification can
|
||||
also be posted before the note is recorded, with the same top-level outcome.
|
||||
The person's message is kept. ([#3120](https://github.com/mvschwarz/openrig/pull/3120))
|
||||
- **From 0.7.14:** [its known limits](https://github.com/mvschwarz/openrig/releases/tag/v0.7.14)
|
||||
still apply, except where this release changes them. [#3105](https://github.com/mvschwarz/openrig/pull/3105) fixes the
|
||||
TUI tables' dropped check-in line, and [#3097](https://github.com/mvschwarz/openrig/pull/3097) narrows the draft-aware paste
|
||||
window described above. 0.7.14's other limits weren't re-checked for this
|
||||
release unless named here.
|
||||
|
||||
### Credits
|
||||
|
||||
Thanks to @dajiaohuang, @Kayhusk, @billbenetti, @Aummadour, @smota,
|
||||
@vanducng, @zichen0116 and @Nikhila-Dhevi-R for merged contributions. Thanks
|
||||
also for the reports behind these fixes: @Aummadour ([#2989](https://github.com/mvschwarz/openrig/issues/2989)), @vanducng
|
||||
([#3128](https://github.com/mvschwarz/openrig/issues/3128)), @Alejandro-SJ ([#2990](https://github.com/mvschwarz/openrig/issues/2990)), @billbenetti ([#2976](https://github.com/mvschwarz/openrig/issues/2976)) and @Kayhusk
|
||||
([#3131](https://github.com/mvschwarz/openrig/issues/3131)).
|
||||
|
||||
## [0.7.14]
|
||||
|
||||
OpenRig 0.7.14 is a patch for steadier circulation on a busy team. A burst of node
|
||||
reads now takes turns. In the change's own tests, a health check or a queue read
|
||||
then waited for one step of it instead of the whole burst; a comparison under
|
||||
load didn't attribute that gain to this change. Bounded queue listings over a
|
||||
long retained history use indexes instead of scanning it. An assistant connected to
|
||||
your team can reach a seat by the name its team shows, connected assistants
|
||||
appear in `rig ps` and the TUI, and setup guidance tells the agent to fit a
|
||||
first team to your logins. There are fixes across delivery, seats and the TUI,
|
||||
many contributed by people using OpenRig. See Known limits for what this
|
||||
release doesn't fix.
|
||||
|
||||
### Before you upgrade
|
||||
|
||||
- **Stop the daemon, back up the database, install 0.7.14, then start the
|
||||
daemon.** Your agents keep running through a daemon restart; don't use
|
||||
`rig down`, which ends them.
|
||||
|
||||
```sh
|
||||
rig daemon stop
|
||||
cp "$(rig config get db.path)" "$(rig config get db.path).before-0.7.14"
|
||||
npm install -g @openrig/cli@0.7.14 # or your existing installation method
|
||||
rig daemon start
|
||||
```
|
||||
|
||||
- **Three migrations run before the daemon listens.** Migration 163 adds the
|
||||
`network_installations` table and four columns to `network_bindings`.
|
||||
Migrations 164 and 166 build indexes. The author's measurement of 166 took
|
||||
3.47 s on 28,976 rows, not a real installation's size, so a large database can
|
||||
take longer. The write overhead, and going back to 0.7.13 after these three
|
||||
migrations, aren't established; keep the backup. ([#3007](https://github.com/mvschwarz/openrig/pull/3007), [#3008](https://github.com/mvschwarz/openrig/pull/3008), [#3090](https://github.com/mvschwarz/openrig/pull/3090))
|
||||
- **If the start is reported pending:** the CLI waits 20 s, then may print
|
||||
"Daemon startup is pending after the readiness deadline". Readiness remains
|
||||
unconfirmed. It leaves the child running and the startup reservation
|
||||
retained, without recording the daemon. Inspect the address and log it
|
||||
prints. The child may later answer, and status can then report it running,
|
||||
but that does not finish this start's recording or release its reservation.
|
||||
Don't start it again until the steps below are done. The message's restart
|
||||
steps stop that child and clear the reservation: stop the named child PID and
|
||||
wait for it to exit, inspect `daemon-start.lock`, and only when both recorded
|
||||
launcher and child PIDs are absent, archive the lock and run
|
||||
`rig daemon start`. On a large database the new start can be reported pending
|
||||
again; reaching a recorded start this way hasn't been tested.
|
||||
`rig daemon stop` cannot stop that unpublished child.
|
||||
- **The `openrig` plugin carries the CLI's version, 0.7.14; openrig-core stays
|
||||
0.1.29.**
|
||||
|
||||
### Under load
|
||||
|
||||
- Node reads (`rig ps --nodes`, the TUI, several agents at once) take turns,
|
||||
one step at a time. In the change's own tests, health checks and queue reads
|
||||
were no longer held behind a whole burst. A comparison under load didn't
|
||||
attribute a gain to this change: health checks and queue reads were faster
|
||||
for the release as a whole, `rig ps --nodes` showed no change, and sends were
|
||||
inconclusive. ([#3101](https://github.com/mvschwarz/openrig/pull/3101))
|
||||
- Bounded queue listings over retained history use indexes for their ordering
|
||||
and for live and archived owner notifications. ([#3090](https://github.com/mvschwarz/openrig/pull/3090))
|
||||
- Codex seats re-checked in one readiness poll share process listings where
|
||||
each seat's observation order and the 2 s freshness allow; each keeps its own
|
||||
later observation and its own fallback. ([#3061](https://github.com/mvschwarz/openrig/pull/3061))
|
||||
- New tmux servers raise their soft open-file limit to 8,192 or the hard limit
|
||||
where they can, keeping an already higher limit. This makes descriptor
|
||||
exhaustion less likely as panes and viewers add up; servers already running
|
||||
keep their limits. ([#3070](https://github.com/mvschwarz/openrig/pull/3070))
|
||||
- A delegation parent gets one standing notice per child seat for unclaimed
|
||||
rows, not one per row, and held work gets its notice back when its typing
|
||||
hold clears. ([#3049](https://github.com/mvschwarz/openrig/pull/3049), [#3082](https://github.com/mvschwarz/openrig/pull/3082))
|
||||
|
||||
### Your team and the people it works for
|
||||
|
||||
- An assistant connected over MCP reaches a seat by its plain name, stored
|
||||
under the seat's actual session; an unknown name, or one several seats match,
|
||||
says so. ([#3088](https://github.com/mvschwarz/openrig/pull/3088))
|
||||
- Connected assistants appear, with their check-in, in `rig ps`, `rig_team` and
|
||||
the TUI's tables, and their person sees plain tool titles. ([#3057](https://github.com/mvschwarz/openrig/pull/3057), [#3058](https://github.com/mvschwarz/openrig/pull/3058), [#3092](https://github.com/mvschwarz/openrig/pull/3092))
|
||||
- `rig doctor` and setup say a login is needed when a seat you start runs on
|
||||
that harness. The operator is taught to check each seat's runtime against
|
||||
your logins before launch, name any missing sign-in and let you choose.
|
||||
([#3077](https://github.com/mvschwarz/openrig/pull/3077))
|
||||
- When the readable person registry holds nobody, `rig daemon start` and
|
||||
`rig gateway participants` tell the setup agent to offer registration. The
|
||||
kernel operator is taught to include that offer in its greeting and register
|
||||
only on your yes. ([#3041](https://github.com/mvschwarz/openrig/pull/3041), [#3071](https://github.com/mvschwarz/openrig/pull/3071))
|
||||
- A team your agent hands work to knows how to ask you a question, and your
|
||||
answer wakes it. A click on an ask with several questions records that
|
||||
choice; the ask stays open until the last one. ([#3059](https://github.com/mvschwarz/openrig/pull/3059), [#3045](https://github.com/mvschwarz/openrig/pull/3045))
|
||||
- A pairing request's description of itself is quoted wherever it's shown. ([#3067](https://github.com/mvschwarz/openrig/pull/3067))
|
||||
- `rig queue list` takes exact `--tag`, `--mission` and `--slice` filters, and
|
||||
several tags must all match. ([#3066](https://github.com/mvschwarz/openrig/pull/3066))
|
||||
- A skill-only edition of the `openrig` plugin, for Claude's plugin directory,
|
||||
follows handed-on work and keeps its reply route. ([#3056](https://github.com/mvschwarz/openrig/pull/3056), [#3075](https://github.com/mvschwarz/openrig/pull/3075))
|
||||
|
||||
### Fixes
|
||||
|
||||
- An ordinary send is refused as needing input while an open Claude Code or
|
||||
Codex `/model` picker is positively identified; nothing is typed. Close the
|
||||
picker before trying to deliver the message. This is shown by the change's
|
||||
own tests; it hasn't yet been checked with the real Claude Code and Codex
|
||||
programs on this release. ([#3083](https://github.com/mvschwarz/openrig/pull/3083))
|
||||
- On a resume of a Codex seat's own conversation in a rig with pods, including
|
||||
`rig up --existing`, OpenRig avoids adding missing guidance blocks to the
|
||||
repository's tracked `AGENTS.md` when Codex is 0.164.0 or later, no guidance
|
||||
file or developer instructions are configured, and the configuration and
|
||||
block sources can be read. ([#3039](https://github.com/mvschwarz/openrig/pull/3039))
|
||||
- With `recovery.auto_drive_provider_prompts` on, Claude Code's gated-grants
|
||||
trust check is never answered for you, and the plain trust prompt is answered
|
||||
"Yes". ([#3073](https://github.com/mvschwarz/openrig/pull/3073))
|
||||
- `rig terminal open --provider herdr` reuses a live Herdr workspace, and Rex
|
||||
tiles show the seat's agent and its activity. ([#3068](https://github.com/mvschwarz/openrig/pull/3068), [#2992](https://github.com/mvschwarz/openrig/pull/2992))
|
||||
- `rig broadcast` prints a held recipient as retained, not sent. ([#3054](https://github.com/mvschwarz/openrig/pull/3054))
|
||||
- Account erasure also removes OpenRig's own wakes and notices for that
|
||||
account's seats. ([#3089](https://github.com/mvschwarz/openrig/pull/3089))
|
||||
- A snapshot without sessions returns its `invalid_snapshot_data` blocker
|
||||
instead of throwing a TypeError; the restore still stops there. A retried
|
||||
no-launch import recovers the original rig by its operation ID. ([#3069](https://github.com/mvschwarz/openrig/pull/3069), [#3042](https://github.com/mvschwarz/openrig/pull/3042))
|
||||
- A rebuilt briefing limits optional superseded recap paths to the newest
|
||||
three by default when one folder covers that history; the current recap and
|
||||
all artifact records remain. Other layouts keep the full list, and
|
||||
`output.rebuild_recaps` set to 0 lists all paths. ([#3055](https://github.com/mvschwarz/openrig/pull/3055))
|
||||
- `rig compact --state` names the input check that stopped a managed
|
||||
compaction, and the TUI's graph shows a seat the daemon reads as unknown as
|
||||
unknown. ([#3053](https://github.com/mvschwarz/openrig/pull/3053), [#3046](https://github.com/mvschwarz/openrig/pull/3046))
|
||||
- Setting a context-pressure threshold explains when an environment override
|
||||
inverts the pair, and `rig workflow validate` warns that harness pins aren't
|
||||
checked against seats. ([#2567](https://github.com/mvschwarz/openrig/pull/2567), [#3102](https://github.com/mvschwarz/openrig/pull/3102))
|
||||
- The config browser's entries say each setting's type, choices, range, format
|
||||
and write route. ([#3050](https://github.com/mvschwarz/openrig/pull/3050))
|
||||
|
||||
### Experimental
|
||||
|
||||
- `rig network` is experimental, unsupported and at your own risk. Its connector
|
||||
isn't inert: the daemon starts it, sweeps leftover credential folders and
|
||||
schedules local rounds even with no binding. ([#3007](https://github.com/mvschwarz/openrig/pull/3007), [#3084](https://github.com/mvschwarz/openrig/pull/3084))
|
||||
- A grant service can hold back only new work under its fair-use limit, and an
|
||||
app can read what needs a person, and the answers to it, by link. ([#3048](https://github.com/mvschwarz/openrig/pull/3048), [#3008](https://github.com/mvschwarz/openrig/pull/3008))
|
||||
|
||||
### Behaviour that changed
|
||||
|
||||
- **Node reads:** a nodes response is no longer one snapshot across its steps,
|
||||
and in a burst each nodes response comes later: about 43 ms against 21 ms
|
||||
median in a 24-request burst. One very large rig is still one step. ([#3101](https://github.com/mvschwarz/openrig/pull/3101))
|
||||
- **An assistant naming a seat now hears three errors:** `destination_ambiguous`
|
||||
(several seats match; the candidates are listed), `destination_not_found` (no
|
||||
seat it can reach has that name) and `destination_unchecked` (the team
|
||||
couldn't be read; try again). ([#3088](https://github.com/mvschwarz/openrig/pull/3088))
|
||||
|
||||
### Known limits
|
||||
|
||||
- **Queue listings:** the new indexes aren't a cure for every stall. Listings of
|
||||
active work showed no gain, one case was slower, and writes weren't measured. ([#3090](https://github.com/mvschwarz/openrig/pull/3090))
|
||||
- **Daemon memory:** in a before-and-after comparison under load, the daemon's
|
||||
resident anonymous memory and its memory when idle afterwards had medians
|
||||
about 23-25 MiB higher on 0.7.14 than on 0.7.13, but the two versions' runs
|
||||
overlapped. Neither equal memory nor a regression is established.
|
||||
- **Draft-aware delivery ([#3076](https://github.com/mvschwarz/openrig/issues/3076)):** an automatic OpenRig notice can still be left beside
|
||||
a draft started during delivery. In the reproduced paste-window cases the person's draft
|
||||
stayed intact and no Enter was sent, but OpenRig's text stayed in the input.
|
||||
Those cases don't cover a later window. On a conditional send, one that names
|
||||
the conversation it expects, an isolated test with a scripted terminal showed
|
||||
characters typed while OpenRig ran its last checks before Enter submitted
|
||||
together with OpenRig's text, and the send reported success. The same test
|
||||
reproduces it on 0.7.13. It hasn't been tested with a real client or model.
|
||||
- **The TUI's tables** can drop a connected assistant's check-in line when its
|
||||
rig's seat inventory can't be read; `rig roster` still prints it. ([#3105](https://github.com/mvschwarz/openrig/pull/3105) isn't in this release)
|
||||
- **Repository guidance on restore:** rigs without pods, old or unknown Codex
|
||||
versions, configured guidance and unreadable configuration keep the existing
|
||||
file path. Fresh, fork and handover launches are outside this resume fix.
|
||||
Existing managed blocks may still refresh, and the seat-skills line still
|
||||
belongs to the file writer; check `git status`. A block whose source can't be
|
||||
read is reported missing.
|
||||
- **Linked Codex config files:** when a Codex seat's `config.toml` or
|
||||
`hooks.json` is a symbolic link, OpenRig records its hook trust under the
|
||||
link's target, as in 0.7.13. A change to key it by the file's own name isn't
|
||||
in this release, and such a seat may be asked to review hooks again. With a
|
||||
linked `config.toml`, OpenRig can also miss a setting stored for it that
|
||||
turns OpenRig's hooks off, and set those hooks up anyway when it moves them
|
||||
into `hooks.json`. ([#3078](https://github.com/mvschwarz/openrig/issues/3078))
|
||||
- **From 0.7.13:** [its known limits](https://github.com/mvschwarz/openrig/releases/tag/v0.7.13)
|
||||
still apply, except where this release fixes them. The runtime fixes cover
|
||||
adding missing guidance on the eligible Codex resumes described above
|
||||
([#3039](https://github.com/mvschwarz/openrig/pull/3039)) and the unquoted pairing description ([#3067](https://github.com/mvschwarz/openrig/pull/3067)). The fix for
|
||||
recognized model pickers ([#3083](https://github.com/mvschwarz/openrig/pull/3083)) is shown by the change's own tests and
|
||||
hasn't yet been checked with the real programs on this release.
|
||||
This release also changes the operator-first registration ([#3041](https://github.com/mvschwarz/openrig/pull/3041),
|
||||
[#3071](https://github.com/mvschwarz/openrig/pull/3071)) and pre-launch login guidance ([#3077](https://github.com/mvschwarz/openrig/pull/3077)). In a few test
|
||||
runs with real agents, the operator offered registration once in its
|
||||
greeting, on Claude Code and on Codex (one run each); a no registered nobody,
|
||||
and a yes registered the default person. The person saw the offer in 3 of 4
|
||||
runs; in the fourth, the setup agent didn't pass the operator's offer on.
|
||||
The login guidance worked in both runs tested, once from the setup agent and
|
||||
once from the operator. 0.7.13's other limits weren't re-checked for this
|
||||
release unless named here.
|
||||
|
||||
### Credits
|
||||
|
||||
Thanks to @Kayhusk, @billbenetti, @cavalcanticampos, @Aummadour, @Tankard,
|
||||
@w4rc0n and @Totopo27 for merged contributions. Thanks also for the reports
|
||||
behind these fixes: @Kayhusk ([#3035](https://github.com/mvschwarz/openrig/issues/3035)), @Tankard ([#2583](https://github.com/mvschwarz/openrig/issues/2583)),
|
||||
@dajiaohuang ([#2529](https://github.com/mvschwarz/openrig/issues/2529)), @billbenetti ([#2728](https://github.com/mvschwarz/openrig/issues/2728)), @emilio-gagliardi ([#3087](https://github.com/mvschwarz/openrig/issues/3087)), @korallis
|
||||
([#161](https://github.com/mvschwarz/openrig/issues/161)) and @w4rc0n ([#3017](https://github.com/mvschwarz/openrig/issues/3017)).
|
||||
|
||||
## [0.7.13]
|
||||
|
||||
OpenRig 0.7.13 is a patch for people running their own agent teams. When you answer a runner's permission request, you now get a
|
||||
|
||||
@@ -26,9 +26,9 @@ use:
|
||||
|
||||
```sh
|
||||
# Claude Code
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.12/skills/rigs --skill rigs --agent claude-code
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.15/skills/rigs --skill rigs --agent claude-code
|
||||
# Codex
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.12/skills/rigs --skill rigs --agent codex
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.15/skills/rigs --skill rigs --agent codex
|
||||
```
|
||||
|
||||
Then type `/rigs` in Claude Code, or `$rigs` in Codex, and say what you want built. The skill has your agent tell
|
||||
@@ -68,11 +68,11 @@ Requires Node.js 22 or 24 and tmux, on macOS or Linux, and one working Claude Co
|
||||
|
||||
### Install it yourself
|
||||
|
||||
This runs OpenRig's install script from the `v0.7.12` release. It checks Node.js and npm, installs the latest published `@openrig/cli` with `npm install -g`, runs the Node.js and SQLite check, then runs `rig setup --dry-run` and `rig setup`. The first line prints that plan and changes nothing:
|
||||
This runs OpenRig's install script from the `v0.7.15` release. It checks Node.js and npm, installs the latest published `@openrig/cli` with `npm install -g`, runs the Node.js and SQLite check, then runs `rig setup --dry-run` and `rig setup`. The first line prints that plan and changes nothing:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.12/scripts/install.sh | sh -s -- --dry-run
|
||||
curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.12/scripts/install.sh | sh
|
||||
curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.15/scripts/install.sh | sh -s -- --dry-run
|
||||
curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.15/scripts/install.sh | sh
|
||||
```
|
||||
|
||||
If the last step isn't ready, the installer reports `INSTALLED, SETUP NOT COMPLETE` and points to the details from `rig setup` above. Follow that output and any reported Fix, then rerun `rig setup`; the CLI does not need reinstalling. If the only remaining failures are provider sign-ins, sign in to each selected provider as below and continue.
|
||||
|
||||
@@ -185,10 +185,10 @@ agent doing the setup. Both use this release's tag:
|
||||
|
||||
```sh
|
||||
# Claude Code
|
||||
npx skills add "https://github.com/mvschwarz/openrig/tree/v0.7.12/skills/rigs" --skill rigs --agent claude-code
|
||||
npx skills add "https://github.com/mvschwarz/openrig/tree/v0.7.15/skills/rigs" --skill rigs --agent claude-code
|
||||
|
||||
# Codex
|
||||
npx skills add "https://github.com/mvschwarz/openrig/tree/v0.7.12/skills/rigs" --skill rigs --agent codex
|
||||
npx skills add "https://github.com/mvschwarz/openrig/tree/v0.7.15/skills/rigs" --skill rigs --agent codex
|
||||
```
|
||||
|
||||
If OpenRig is already installed, use the release tag matching your installed `rig --version` instead: replace the tag
|
||||
@@ -203,11 +203,11 @@ You can also read [`skills/rigs/SKILL.md`](../../skills/rigs/SKILL.md) directly.
|
||||
script will do and changes nothing:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.12/scripts/install.sh | sh -s -- --dry-run
|
||||
curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.15/scripts/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
The same command without `--dry-run`,
|
||||
`curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.12/scripts/install.sh | sh`, installs the
|
||||
`curl -fsSL https://raw.githubusercontent.com/mvschwarz/openrig/v0.7.15/scripts/install.sh | sh`, installs the
|
||||
latest published `@openrig/cli` with `npm install -g`, runs the Node.js and SQLite check if the installed checker is
|
||||
present (otherwise it reports the check skipped), then runs `rig setup --dry-run` and `rig setup`. `rig setup` checks both Claude Code and
|
||||
Codex and may install a missing one, as described below. A failed step prints
|
||||
|
||||
@@ -12,9 +12,9 @@ In your project folder, add OpenRig's `rigs` skill to the agent you use:
|
||||
|
||||
```sh
|
||||
# Claude Code
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.12/skills/rigs --skill rigs --agent claude-code
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.15/skills/rigs --skill rigs --agent claude-code
|
||||
# Codex
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.12/skills/rigs --skill rigs --agent codex
|
||||
npx skills add https://github.com/mvschwarz/openrig/tree/v0.7.15/skills/rigs --skill rigs --agent codex
|
||||
```
|
||||
|
||||
These use this release's tag, for a new install. If OpenRig is already installed, replace the tag after `tree/` with
|
||||
|
||||
+975
-178
File diff suppressed because it is too large.
Load diff
Generated
+5
-5
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "openrig",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "openrig",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"license": "Apache-2.0",
|
||||
"workspaces": [
|
||||
"packages/daemon",
|
||||
@@ -7298,7 +7298,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@openrig/cli",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -7336,7 +7336,7 @@
|
||||
},
|
||||
"packages/daemon": {
|
||||
"name": "@openrig/daemon",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@hono/node-server": "^1.13.0",
|
||||
@@ -7380,7 +7380,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@openrig/ui",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openrig",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openrig/acp",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"description": "OpenRig as an agent in ACP apps: starts rig acp serve from the @openrig/cli it pins.",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
@@ -15,7 +15,7 @@
|
||||
"node": ">=22"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openrig/cli": "0.7.1"
|
||||
"@openrig/cli": "0.7.15"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"author": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "openrig",
|
||||
"name": "OpenRig",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"description": "Send work to your OpenRig team of agents and follow it through to the result",
|
||||
"repository": "https://github.com/mvschwarz/openrig",
|
||||
"website": "https://openrig.dev",
|
||||
@@ -12,7 +12,7 @@
|
||||
"license_url": "https://github.com/mvschwarz/openrig/blob/main/LICENSE",
|
||||
"distribution": {
|
||||
"npx": {
|
||||
"package": "@openrig/[email protected]"
|
||||
"package": "@openrig/[email protected]5"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openrig/cli",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"type": "module",
|
||||
"description": "Build your own network of agents from Claude Code, Codex and Pi: persistent teams with roles, shared context and owned work.",
|
||||
"keywords": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openrig-core",
|
||||
"version": "0.1.29",
|
||||
"version": "0.1.30",
|
||||
"description": "OpenRig canonical skills and hooks for cross-runtime agent topology coordination, continuity, and operating discipline.",
|
||||
"author": {
|
||||
"name": "Mike Schwarz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openrig-core",
|
||||
"version": "0.1.29",
|
||||
"version": "0.1.30",
|
||||
"description": "OpenRig canonical skills and hooks for cross-runtime agent topology coordination, continuity, and operating discipline.",
|
||||
"author": {
|
||||
"name": "Mike Schwarz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openrig",
|
||||
"version": "0.1.0",
|
||||
"version": "0.7.15",
|
||||
"description": "Work with your OpenRig team from your coding agent: hand it work, follow that work, answer its questions and read what it returns.",
|
||||
"author": {
|
||||
"name": "Mike Schwarz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openrig",
|
||||
"version": "0.1.0",
|
||||
"version": "0.7.15",
|
||||
"description": "Work with your OpenRig team from your coding agent: hand it work, follow that work, answer its questions and read what it returns.",
|
||||
"author": {
|
||||
"name": "Mike Schwarz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openrig",
|
||||
"version": "0.1.0",
|
||||
"version": "0.7.15",
|
||||
"description": "Work with your OpenRig team from your coding agent: hand it work, follow that work, answer its questions and read what it returns.",
|
||||
"logo": "assets/logo.svg"
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
||||
"name": "openrig",
|
||||
"version": "0.1.0",
|
||||
"version": "0.7.15",
|
||||
"description": "Work with your OpenRig team from your coding agent: hand it work, follow that work, answer its questions and read what it returns.",
|
||||
"author": {
|
||||
"name": "Mike Schwarz",
|
||||
|
||||
@@ -11,7 +11,7 @@ not know exists.** So the point of what follows is not skill. It is recognition:
|
||||
lands, something rhymes, and you go check instead of building.
|
||||
|
||||
Ninety-three top-level verbs ship (capability canon refreshed through
|
||||
`capability-delta-v0.7.13`). This marker describes the pack's teaching, not publication or live
|
||||
`capability-delta-v0.7.15`). This marker describes the pack's teaching, not publication or live
|
||||
adoption. Read this once for shape, and let it make you suspicious that a thing already exists.
|
||||
What changed in the installed version, and what to do about it, is one read away:
|
||||
`rig context get reference/whats-new.md`.
|
||||
@@ -33,7 +33,10 @@ one command away. Your memory of the fleet is a claim about the past.
|
||||
*including the broken ones*. **The bare form is the question you usually want:** `--active`
|
||||
filters to running and **hides detached, exited and attention states** — which are exactly the
|
||||
cells you were scanning for. A seat whose tmux session is confirmed gone reads `detached`
|
||||
(activity reason `session_missing`), and `rig ps --nodes` says to restore or relaunch it.
|
||||
(activity reason `session_missing`), and `rig ps --nodes` says to restore or relaunch it. Since 0.7.14 `rig ps` ends with connected
|
||||
assistants and their check-in line, and node reads take turns through their three synchronous
|
||||
steps, so other reads and sends aren't held behind a burst of them; a nodes response is no longer
|
||||
one snapshot across those steps, and in a burst each one comes later.
|
||||
A verified exited process in a retained pane reads `pane_exited`, instead of running and ready;
|
||||
outstanding work uses the existing recovery-finding route. An unknown observation is not an exit.
|
||||
`rig ps --nodes` also shows the model each seat was last seen using (`modelObservation`, with its
|
||||
@@ -109,7 +112,8 @@ one command away. Your memory of the fleet is a claim about the past.
|
||||
Closed work's content and metadata can also be erased on a schedule
|
||||
(`retention.closed_content_days`, `retention.closed_metadata_days`; `0`, the default, keeps them),
|
||||
with an optional `retention.erasure_ledger`, for a retention policy or an account deletion. It's
|
||||
opt-in, and a retried create can't bring erased work back.
|
||||
opt-in, and a retried create can't bring erased work back. Since 0.7.14 an account's erasure also
|
||||
removes OpenRig's own wakes and notices for that account's seats.
|
||||
- **Check the exit code.** Many commands used to print nothing and exit 0 when a daemon read
|
||||
failed; now they exit 1 or 2. Empty output from a failed read is not empty state.
|
||||
|
||||
@@ -124,7 +128,9 @@ unseen — which makes messages the one delivery channel that never gets skipped
|
||||
consequential delivery gets an effect check at the far end rather than a blind retry.
|
||||
`--verify` exits 1 when it can't confirm what its Enter did (`submission unconfirmed`, or text
|
||||
staged but not submitted): the message may still have arrived, so inspect with `rig capture`
|
||||
before any resend, and don't let a script resend on that exit code alone. A
|
||||
before any resend, and don't let a script resend on that exit code alone. Since 0.7.14 an ordinary
|
||||
send is refused as needing input while an open Claude Code or Codex `/model` picker is
|
||||
positively identified; nothing is typed. A
|
||||
producer-link advisory reading `no_activity_signal` means activity could not be determined;
|
||||
confirm by effect, never relaunch on it. A send or wake to a seat whose latest hook is a
|
||||
question waiting for a person is refused with `target_needs_input`, even when its screen
|
||||
@@ -175,7 +181,8 @@ unseen — which makes messages the one delivery channel that never gets skipped
|
||||
and the box was empty after Enter; it only reports.
|
||||
- **`rig broadcast`** — one fact to everyone at once, rather than relaying it N times and getting
|
||||
the wording wrong on the fourth. **Blast radius is real** — on a large rig this lands in every
|
||||
seat's turn. A broadcast that reached no one says so.
|
||||
seat's turn. A broadcast that reached no one says so, and a recipient a seat's setting held
|
||||
reads as retained, not sent.
|
||||
- **`rig capture <seat>`** — read what is on their screen right now. **`--rig` / `--pod`** captures
|
||||
every seat in one call. `--lines N` is the last N lines (stderr says how many earlier lines were
|
||||
cut); `--history-plus-pane` gives the older N history lines plus the whole pane. A short capture
|
||||
@@ -255,7 +262,7 @@ unseen — which makes messages the one delivery channel that never gets skipped
|
||||
default. **Opening `rig terminal open saved:kernel --window` is the step after install or start**:
|
||||
say you're opening it, run it on the daemon's desktop, then tell the person where it opened. Don't
|
||||
wait for a phrase like “show me my agents”; the same command brings their agents back later. No
|
||||
YAML, herdr when installed or plain tmux. The layout follows the terminal's width: on a narrow
|
||||
YAML, herdr when installed or plain tmux. Rex tiles show each seat's agent and its activity. The layout follows the terminal's width: on a narrow
|
||||
one the operator gets the first tab; on a wide one the dashboard and operator sit side by side
|
||||
and the advisor gets its own tab. A `kernel` view the person saved still wins.
|
||||
Tiles show their seat's screen without attaching, so whole lines show at any tile width; a
|
||||
@@ -345,7 +352,12 @@ unseen — which makes messages the one delivery channel that never gets skipped
|
||||
never posted. By default, an emoji reaction on a message posted for an ask reaches the asking seat
|
||||
as a task tagged `human-reaction`: a signal to interpret, not an answer, and the ask stays open.
|
||||
`rig slack setup --reactions off` disables that routing; the default is `route`, and regenerating
|
||||
the app manifest preserves the setting.
|
||||
the app manifest preserves the setting. Since 0.7.15 link and media previews on posts to a person
|
||||
are off by default: `rig slack setup --unfurl on` turns them back on from the connector's next
|
||||
rewire, and `rig slack status` shows the mode. When the arrival note is recorded before the
|
||||
answer is routed, an answer to a reply in an older thread posts back into that thread; a failed
|
||||
note write posts it top-level; a notification posted before the note is recorded can also lead
|
||||
to a top-level answer.
|
||||
It needs the `reactions:read` scope and the `reaction_added` event (reinstall the app);
|
||||
`rig slack verify` warns when the scope is missing. A long ask is posted in numbered thread parts; one that
|
||||
still can't be posted comes back to the asking seat as a `slack-undeliverable` task. Replies
|
||||
@@ -480,7 +492,8 @@ relay is a reason to inspect the available routing, not to surrender judgment to
|
||||
- **`rig workflow validate`** — will this spec instantiate at all, before a run finds out for you. A
|
||||
step with no allowed exit that can finish it or route onward is reported as `step_cannot_finish`.
|
||||
An allowed mapped exit is valid; in a dependency graph, `handoff` can finish a sink without a next
|
||||
step.
|
||||
step. Since 0.7.14 each step with a `harness:` pin gets a `harness_pin_unchecked` warning:
|
||||
validation doesn't check pins against seats.
|
||||
- **`rig workflow compile <mission>`** / **`instantiate-lifecycle`** — derive one executable graph
|
||||
from `project.yaml` → `mission.yaml` → `slice.yaml`, inspect it without writing, then start an
|
||||
eligible graph with an opaque replay key. Typed acceptance candidate, verdict, and evidence
|
||||
@@ -632,6 +645,9 @@ not have to tear one down to change it, and you rarely have to start from nothin
|
||||
steps): hand it work, follow it, answer the team's questions in their own words, and read the
|
||||
result. VS Code, Copilot CLI and Cursor load it with no seat: give the app its own
|
||||
`rig mcp serve --front-door` server with `OPENRIG_SESSION_NAME` set and turn the plugin's off.
|
||||
A skill-only edition for Claude's plugin directory, in `plugins/claude-directory/`, follows
|
||||
handed-on work and keeps its reply route. The plugin needs Claude Code 2.1.119 or later: on
|
||||
earlier versions, with its OpenRig seat setting blank, the agent has no OpenRig tools.
|
||||
- **A Claude member can bring its own setup** in the rig spec: `agent_file`,
|
||||
`append_system_prompt_file`, `plugin_dirs` and `advisor` (an Advisor model). They're copied into
|
||||
that seat's own storage, never the project, so one seat in a shared repository can have its own
|
||||
@@ -715,6 +731,8 @@ not have to tear one down to change it, and you rarely have to start from nothin
|
||||
(or, when it names none, the only one Codex has logged since it started); OpenRig can't tell
|
||||
which conversation Codex is on now. If the conversation was changed inside the running Codex,
|
||||
the restart may refuse or resume the earlier one, so look at the pane (`rig capture <seat>`) first.
|
||||
Since 0.7.15, when it refuses a recoverable seat whose tmux session is gone (`session_not_live`),
|
||||
it names the way back: `rig launch '<rig>' '<node>'` (add `--plan` to preview).
|
||||
- **`rig add`** / **`rig expand`** — graft one more member, or a whole new pod, onto a rig that is
|
||||
already running. `rig add`, `rig grow` and `rig remove` take the rig's name or ID; a name two active rigs share is refused
|
||||
with `rig_ambiguous` and the candidates. `rig grow --new-pod` and `rig expand` are one ingress; choose by input shape.
|
||||
@@ -782,6 +800,14 @@ version, from checking the environment to a useful report to the OpenRig team.
|
||||
Stop distinguishes process/listener exit from a clean asynchronous drain: inspect the matching
|
||||
`daemon-shutdown.json` and log when completion is incomplete or unverified. No target is a
|
||||
distinct no-op, and a timeout never proves down. Use command help for exact limits and recovery.
|
||||
Since 0.7.15 start gives the child it started a 180-second readiness budget, with a progress
|
||||
line about every 20 s: let it finish rather than starting again. Synchronous work can run past
|
||||
the budget, and it isn't a cure for a slow start.
|
||||
When the daemon stalls, read `$OPENRIG_HOME/logs/slow-operations.jsonl` before guessing: it names
|
||||
slow synchronous steps by site, since 0.7.15 including three queue sites and three selected steps
|
||||
of an ordinary nodes read (`nodes.inventory.build`, `nodes.inventory.activity_sync`,
|
||||
`nodes.inventory.terminal_work`). These nodes records are written after a slow call completes; a
|
||||
missing record doesn't rule out unfinished work or work outside those steps.
|
||||
On Linux, when the daemon runs as a systemd user service, the seats' tmux server starts in its
|
||||
own user scope, so stopping or restarting the daemon's unit keeps the seats; otherwise it starts
|
||||
as before, with one log line giving the reason.
|
||||
@@ -848,6 +874,12 @@ version, from checking the environment to a useful report to the OpenRig team.
|
||||
Use `rig launch ... --snapshot-id <id>` when selection must be exact, and `rig restore status
|
||||
<attempt> --rig <rig>` for the derived intended-set receipt after an asynchronous restore.
|
||||
restore-check's per-seat `seat.<s>.queue-file` check is now `seat.<s>.queue-store`.
|
||||
Since 0.7.15, for an eligible seat in a rig with pods that it starts in its own pane, restore
|
||||
tries the saved conversation when the seat has a resume token but no saved startup context, and
|
||||
records the `startup_context` gap; a successful resume reads `partially_restored`, and a missing
|
||||
conversation or failed start keeps its own status. restore-check reads that seat yellow. Both warn when a snapshot's named Codex profile was cleared
|
||||
from the current seat. A rig can still read `fully_restored` past a seat restore didn't start or
|
||||
one left attached, and a seat left as a bare shell still counts as running in `rig ps`.
|
||||
- **`rig restore-packet write` / `read` / `validate`** — a seat is about to die or must move
|
||||
runtimes; capture what it knows into a portable artifact instead of losing it with the process.
|
||||
- **Upgrading is agent-led** — load the shipped `openrig-upgrade` skill for the bounded inspect,
|
||||
@@ -946,6 +978,12 @@ version, from checking the environment to a useful report to the OpenRig team.
|
||||
re-nudges). `--enabled true|false` remains compatible: true selects hold, false selects off.
|
||||
Known limit: in `draft-aware`, a multi-line message to a Claude seat can stay unsubmitted when the
|
||||
paste changes Claude's footer hint, and later sends wait behind it; check the seat's composer.
|
||||
Since 0.7.15 `draft-aware` re-checks right before an automatic paste and holds after recent
|
||||
client activity or when tmux can't be read; typing after that last check still isn't seen. With
|
||||
Claude Code's full-width auto-update-failure footer on screen, an empty `draft-aware` seat can
|
||||
hold an ordinary send; `rig seat held-messages` shows it. On Codex (seen with 0.167.1 and
|
||||
0.167.2), a send to a busy `draft-aware` seat can be pasted without Enter, neither delivered
|
||||
nor held; its text stays in the input, and there's no fix for it in this release.
|
||||
`rig seat status` shows the requested/effective mode; wait for pending activation to finish.
|
||||
**`rig seat held-messages`** lists what was retained and **`rig seat retire-held-message`**
|
||||
retires one; changing mode does not replay old held messages. A seat that starts, or a successor
|
||||
@@ -962,7 +1000,8 @@ version, from checking the environment to a useful report to the OpenRig team.
|
||||
- **`rig compact-plan`** → **`rig compact`** — who is near the context wall, then act on it.
|
||||
**Ordering matters: running `compact` without the plan is guessing which seat needed it.**
|
||||
Managed compaction waits for the seat's restore map before compacting; `rig compact --state`,
|
||||
`--cancel` and `--skip-map` inspect, stop or skip that wait. If preparation stops at an ordinary
|
||||
`--cancel` and `--skip-map` inspect, stop or skip that wait; since 0.7.14 `--state` also names the
|
||||
input check behind a `draft_input_unknown` stop (`inputReadFailure`). If preparation stops at an ordinary
|
||||
approval, a manual `rig compact` keeps waiting for someone to answer it, within its 180-second
|
||||
budget; OpenRig never answers it, and the request times out after 240 seconds. The `claude-compaction-restore`
|
||||
skill covers writing and reading the map; `claude-compact-in-place` no longer ships. After a
|
||||
@@ -1018,6 +1057,11 @@ version, from checking the environment to a useful report to the OpenRig team.
|
||||
cached hook keeps that trust, as with any hook trusted in Codex; the trust covers that
|
||||
`CODEX_HOME`, so your own Codex sessions there load the plugin too, and its hooks do nothing
|
||||
outside an OpenRig seat; adding your own Codex hook can trigger a re-review of one OpenRig hook.
|
||||
Since 0.7.15, when a new openrig-core changes one of those six hook declarations, the boot or
|
||||
launch that installs it renews OpenRig's approvals from its own record, in the daemon's Codex
|
||||
home at boot and in a seat's own Codex home at its launch, instead of stopping at Codex's review.
|
||||
A person's own choice in any layer OpenRig reads keeps the review. A linked `config.toml` or
|
||||
`hooks.json` still has its trust recorded under the link's target.
|
||||
- **Know what compaction costs before you reach for it.** On some runtimes what comes back has
|
||||
enough context left to believe it knows everything and not enough to actually know anything — and
|
||||
**the compacted agent is the only one who knows it happened**, while every other seat keeps
|
||||
@@ -1098,7 +1142,8 @@ scheme, and nothing downstream can see it.
|
||||
System World, topology, and Project World plan. Add `--runtime` to see the composed managed skill
|
||||
loadout, `--apply-skills` to reconcile its owned harness projection, or `--deliver` to emit the
|
||||
exact extant files in order while marking absent pieces visibly. Without the flags it remains
|
||||
plan-only. Without `--project` it picks the project itself, in order: the only project, the
|
||||
plan-only. Since 0.7.15 a `--mission` that doesn't exist adds a warning and reads
|
||||
`missionRoot` null, instead of quietly serving the project's context. Without `--project` it picks the project itself, in order: the only project, the
|
||||
project whose `rigs:` lists the seat's rig, the deepest project root containing the working
|
||||
folder, then the only unclaimed project. It reports `position.selectedBy`. If a step is
|
||||
ambiguous (two projects list the rig, or two roots tie), it stops there and asks for
|
||||
@@ -1502,7 +1547,10 @@ your circumstances is configuration, and the ones that are not, another agent ca
|
||||
0.7.13, `rig daemon start` ends with that offer when the person registry can be read and holds
|
||||
nobody. The kernel operator's startup is also taught to run `rig gateway participants` before its
|
||||
first greeting and offer registration when nobody is registered. The agent asks first and
|
||||
registers only on the person's yes.
|
||||
registers only on the person's yes. Since 0.7.14 setup guidance tells the agent to fit a first
|
||||
team to the person's logins: a login `rig doctor` reports missing matters when a seat you'd start
|
||||
runs on that harness, so say which one before launch
|
||||
(`rig specs preview <team> --kind rig --json` shows each seat's runtime).
|
||||
- **`rig usage series`** — what a seat's token curve has looked like over time: climbing steadily,
|
||||
reset, or stopped reporting entirely. The last one is a signal, not a gap.
|
||||
- **`rig usage top`** — which of this machine's seats used the most tokens over a window (`--window
|
||||
@@ -1587,7 +1635,12 @@ your circumstances is configuration, and the ones that are not, another agent ca
|
||||
Clients on MCP protocol revision 2026-07-28 and on the 2025 revisions share the same endpoint.
|
||||
With a grant service (experimental and off by default; you serve it to the internet behind
|
||||
your own tunnel), `--task-destination <member@rig>` names where a caller's `rig_queue_create`
|
||||
goes when it gives no destination, and a seat's name alone resolves within the grant's team. A
|
||||
goes when it gives no destination, and a seat's name alone resolves within the grant's team. Since
|
||||
0.7.14 a plain name finds the seat's actual session (its own name, then its pod-member form, then
|
||||
that name's slug, among seats the grant can address): an ambiguous name returns
|
||||
`destination_ambiguous` with the candidates, an unknown one `destination_not_found`, and an
|
||||
unreadable team `destination_unchecked`. Its person sees each tool's plain title, and under a
|
||||
grant service's fair-use limit only new work is held back. A
|
||||
grant that names a person adds `rig_question_list` and `rig_question_answer`, so that person
|
||||
answers the team's questions from their assistant, recorded as their answer through that
|
||||
connection.
|
||||
@@ -1601,7 +1654,10 @@ your circumstances is configuration, and the ones that are not, another agent ca
|
||||
member nothing can wake, or a rung member doesn't claim it in time, its person is told.
|
||||
A hosted member's roster entry shows whether it's checking in: its expected cadence and its last
|
||||
check-in, read as checking in, overdue, not yet checked in or checking in on request, and unknown
|
||||
when that can't be read. It's a status, never a gate on delivery.
|
||||
when that can't be read. It's a status, never a gate on delivery. Since 0.7.14 `rig ps`,
|
||||
`rig_team` and the TUI's tables list connected assistants with that check-in line; since 0.7.15
|
||||
the TUI keeps it when a rig's inventory can't be read. An assistant that passes its team's
|
||||
display name as `rig_team`'s `rigId` is told to leave `rigId` out to see its own team.
|
||||
**Internet-facing hosted members are experimental, unsupported, off by default and at your
|
||||
own risk.** Local assistants can connect locally. Internet access needs your own TLS tunnel or
|
||||
proxy and a narrowly scoped, revocable token; see `reference/hosted-members.md`. Task terminal
|
||||
@@ -1659,7 +1715,8 @@ database. It is one more set of primitives on a machine full of them.
|
||||
original byte size and the exact expansion command. Read the complete original record with
|
||||
`rig queue show <qitemId> --full --json`; a preview or a compact list is not the whole body.
|
||||
Compact `rig queue list` rows carry `summary`; the fields they leave out are absent, not empty,
|
||||
and `fieldsElided` names them.
|
||||
and `fieldsElided` names them. Since 0.7.14 `--tag` (repeatable; every tag must match),
|
||||
`--mission` and `--slice` filter exactly, and bounded listings over retained history use indexes.
|
||||
Delivery status is separate from content: inspect its receipt before claiming it was consumed.
|
||||
- **"What am I waiting on?"** — the queue row's `waiting` view derives its owner, exact blocker
|
||||
and blocker owner, last meaningful change, activity confidence and next backstop from live
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openrig/daemon",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
|
||||
@@ -675,7 +675,7 @@ export class CodexRuntimeAdapter implements RuntimeAdapter {
|
||||
return;
|
||||
}
|
||||
const command = `node "${relay}"`;
|
||||
const keySource = codexHookSourcePath(hooksPath);
|
||||
const keySource = canonicalCodexHookSource(hooksPath);
|
||||
const stripped = upsertCodexFeaturesHooksEnabled(stripCodexActivityHooks(existing, command));
|
||||
let before: unknown = null;
|
||||
let expected: { hooks?: { state?: CodexHookState } } | null = null;
|
||||
@@ -685,7 +685,7 @@ export class CodexRuntimeAdapter implements RuntimeAdapter {
|
||||
return;
|
||||
}
|
||||
if (!expected) return;
|
||||
const inlineSource = codexHookSourcePath(configPath);
|
||||
const inlineSource = canonicalCodexHookSource(configPath);
|
||||
let config = stripped;
|
||||
for (const event of OPENRIG_ACTIVITY_HOOK_EVENTS) {
|
||||
const groups = document.hooks[event] ?? [];
|
||||
@@ -721,13 +721,22 @@ export class CodexRuntimeAdapter implements RuntimeAdapter {
|
||||
|
||||
/**
|
||||
* OPR.0.4.3.33 — compute + splice Codex's `[hooks.state."<key>"] trusted_hash` for our 4
|
||||
* authored activity hooks into `content`. Codex 0.167.2 resolves the source folder but
|
||||
* keeps the file name, including a linked file, as returned by app-server hooks/list. The command
|
||||
* authored activity hooks into `content`. `key_source` is the canonicalized config path
|
||||
* (Codex keys trust by `std::fs::canonicalize(config.toml).display()`); we best-effort
|
||||
* `realpathSync` the config path to match — on a miss (file not yet on real disk, or a mock
|
||||
* fs in tests) we fall back to the plain absolute path, and any resulting key mismatch just
|
||||
* degrades to the launch-time trust gate (Layer-2 floor), never a broken run. The command
|
||||
* string is the value Codex deserializes from our TOML literal `'node "<relay>"'` — i.e.
|
||||
* `node "<relay>"` WITHOUT the outer TOML quote delimiters. Timeout=5, matcher/status None.
|
||||
*/
|
||||
private applyCodexActivityHookTrust(content: string, configPath: string, relay: string): string {
|
||||
const keySource = codexHookSourcePath(configPath);
|
||||
let keySource = configPath;
|
||||
try {
|
||||
keySource = fs.realpathSync.native(configPath);
|
||||
} catch {
|
||||
// config.toml not on the real filesystem (first write / unit-test mock fs) — the plain
|
||||
// absolute path is the honest best guess; a canonicalization delta is fail-safe (gate reappears).
|
||||
}
|
||||
const command = `node "${relay}"`;
|
||||
// upsertCodexActivityHooks has just written our marked block. Codex keys by the
|
||||
// group's position among this event's groups, not its position inside our block.
|
||||
@@ -770,7 +779,7 @@ export class CodexRuntimeAdapter implements RuntimeAdapter {
|
||||
try {
|
||||
const original = this.fs.readFile(hooksPath);
|
||||
const document = parseCodexHooksJson(original);
|
||||
const keySource = codexHookSourcePath(hooksPath);
|
||||
const keySource = canonicalCodexHookSource(hooksPath);
|
||||
let config = updated ?? "";
|
||||
const expected = parseToml(config) as { hooks?: { state?: CodexHookState } };
|
||||
for (const event of OPENRIG_ACTIVITY_HOOK_EVENTS) {
|
||||
@@ -2449,10 +2458,9 @@ function tomlSections(text: string, current?: string): TomlSection[] {
|
||||
return sections;
|
||||
}
|
||||
|
||||
function codexHookSourcePath(file: string): string {
|
||||
// Resolve a linked home folder, but retain a linked config.toml/hooks.json file's own name.
|
||||
try { return nodePath.join(fs.realpathSync.native(nodePath.dirname(file)), nodePath.basename(file)); }
|
||||
catch { return file; } // The folder may not exist yet, including with an injected filesystem.
|
||||
function canonicalCodexHookSource(path: string): string {
|
||||
// Codex keys hook trust by the canonical source path; a file not on the real filesystem keeps its plain path.
|
||||
try { return fs.realpathSync.native(path); } catch { return path; }
|
||||
}
|
||||
|
||||
/** A hooks.json document as Codex reads it: `hooks` maps each event to matcher groups, each with a `hooks` list. */
|
||||
|
||||
@@ -9,12 +9,11 @@
|
||||
// values THIS reproduction emits and the perturbation tests prove the identity fields are folded in
|
||||
// — but the DEFINITIVE correctness check is a byte-for-byte read-back of a real Codex `[hooks.state]`
|
||||
// after `/hooks`→"Trust all" (the QA VM proof). Until that read-back confirms them, the exact
|
||||
// key_source (resolved folder plus file name) and positional indices are PROVISIONAL. A mismatch is
|
||||
// key_source (canonicalized config path) and positional indices are PROVISIONAL. A mismatch is
|
||||
// fail-safe (gate reappears + Layer-2 keystroke floor), never a false-trusted run.
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import nodeFs from "node:fs";
|
||||
import nodePath from "node:path";
|
||||
import nodeOs from "node:os";
|
||||
import { parse as parseToml } from "smol-toml";
|
||||
import {
|
||||
CodexRuntimeAdapter,
|
||||
@@ -30,8 +29,8 @@ const COMMAND = `node "${RELAY}"`;
|
||||
const EVENTS = ["SessionStart", "UserPromptSubmit", "Stop", "PermissionRequest"] as const;
|
||||
|
||||
// PIN TO VM READ-BACK (qa gate) — PROVISIONAL from open-source reproduction (PR #20321 / commits
|
||||
// 0452dca, ffcc9cc; codex-rs fingerprint.rs version_for_toml). Codex0.167.2 hooks/list confirms
|
||||
// the source folder is resolved, while the config file keeps its own name even when it is linked.
|
||||
// 0452dca, ffcc9cc; codex-rs fingerprint.rs version_for_toml). keySource here is the NON-canonical
|
||||
// mock path `/home/test/.codex/config.toml`; the real key_source is std::fs::canonicalize(config.toml).
|
||||
const PROVISIONAL_FIXTURE: Record<(typeof EVENTS)[number], { key: string; hash: string }> = {
|
||||
SessionStart: {
|
||||
key: `${CONFIG}:session_start:0:0`,
|
||||
@@ -268,53 +267,22 @@ describe("OPR.0.4.3.33 — provisioning-seam coupling (ensureCodexActivityHooks
|
||||
expect(fs._store[CONFIG]).toBe(before);
|
||||
});
|
||||
|
||||
it("resolves the source folder while retaining the config file name", () => {
|
||||
const canonicalHome = nodePath.join("/resolved", "codex");
|
||||
const nativeRealpath = vi.spyOn(nodeFs.realpathSync, "native").mockReturnValue(canonicalHome);
|
||||
it("uses native canonical path casing for Codex hook trust keys", () => {
|
||||
const canonicalConfigPath = "C:\\Users\\Test\\.codex\\config.toml";
|
||||
const nativeRealpath = vi.spyOn(nodeFs.realpathSync, "native").mockReturnValue(canonicalConfigPath);
|
||||
try {
|
||||
const fakeFs = mockCodexFs({ [RELAY]: "// relay" });
|
||||
makeAdapter(fakeFs).ensureCodexActivityHooks();
|
||||
const configPath = Object.keys(fakeFs._store).find((path) => path.endsWith("config.toml"))!;
|
||||
const config = fakeFs._store[configPath]!;
|
||||
|
||||
expect(config).toContain(`[hooks.state.${JSON.stringify(`${nodePath.join(canonicalHome, "config.toml")}:session_start:0:0`)}]`);
|
||||
expect(config).not.toContain(`[hooks.state.${JSON.stringify(`${configPath}:session_start:0:0`)}]`);
|
||||
expect(nativeRealpath).toHaveBeenCalledWith(configPath);
|
||||
expect(config).toContain(`[hooks.state.${JSON.stringify(`${canonicalConfigPath}:session_start:0:0`)}]`);
|
||||
} finally {
|
||||
nativeRealpath.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it.skipIf(process.platform === "win32").each([
|
||||
{ json: false, linkedHome: false }, { json: true, linkedHome: false },
|
||||
{ json: false, linkedHome: true }, { json: true, linkedHome: true },
|
||||
])("trusts file names inside the resolved home (JSON: $json, linked home: $linkedHome)", ({ json, linkedHome }) => {
|
||||
const root = nodeFs.mkdtempSync(nodePath.join(nodeOs.tmpdir(), "codex-linked-trust-"));
|
||||
try {
|
||||
const home = nodePath.join(root, "home"); nodeFs.mkdirSync(home);
|
||||
const selectedHome = linkedHome ? nodePath.join(root, "linked-home") : home;
|
||||
if (linkedHome) nodeFs.symlinkSync(home, selectedHome);
|
||||
const source = nodePath.join(root, "source.toml"); nodeFs.writeFileSync(source, 'model = "fixture"\n');
|
||||
nodeFs.symlinkSync(source, nodePath.join(home, "config.toml"));
|
||||
const relay = nodePath.join(root, "relay.cjs"); nodeFs.writeFileSync(relay, "// never executed");
|
||||
if (json) {
|
||||
const hooks = nodePath.join(root, "source-hooks.json"); nodeFs.writeFileSync(hooks, '{"hooks":{}}\n');
|
||||
nodeFs.symlinkSync(hooks, nodePath.join(home, "hooks.json"));
|
||||
}
|
||||
const adapter = new CodexRuntimeAdapter({ tmux: mockTmux(), activityRelayPath: relay, fsOps: {
|
||||
exists: nodeFs.existsSync, readFile: p => nodeFs.readFileSync(p, "utf8"),
|
||||
writeFile: (p,c) => nodeFs.writeFileSync(p,c), mkdirp: p => { nodeFs.mkdirSync(p,{ recursive:true }); },
|
||||
} });
|
||||
adapter.ensureCodexActivityHooks(selectedHome);
|
||||
const hooks = parseToml(nodeFs.readFileSync(source,"utf8")).hooks;
|
||||
if (!hooks || typeof hooks !== "object") throw new Error("missing hook table");
|
||||
const states: unknown = Reflect.get(hooks, "state");
|
||||
if (!states || typeof states !== "object") throw new Error("missing trust table");
|
||||
expect(Object.keys(states).sort()).toEqual(["permission_request", "session_start", "stop", "user_prompt_submit"]
|
||||
.map(event => `${nodePath.join(nodeFs.realpathSync.native(home), json ? "hooks.json" : "config.toml")}:${event}:0:0`).sort());
|
||||
expect(nodeFs.lstatSync(nodePath.join(home, "config.toml")).isSymbolicLink()).toBe(true);
|
||||
} finally { nodeFs.rmSync(root,{recursive:true,force:true}); }
|
||||
});
|
||||
|
||||
it("is idempotent — re-running produces byte-identical config (no duplicate trust tables)", () => {
|
||||
const fs = mockCodexFs({ [RELAY]: "// relay" });
|
||||
const adapter = makeAdapter(fs);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openrig/ui",
|
||||
"version": "0.7.1",
|
||||
"version": "0.7.15",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"release": "0.7.12",
|
||||
"archiveSha256": "e90b2487fb744d7ca69e52e13b2aaef2a204fcfa76db00c373248acc0795eb52",
|
||||
"release": "0.7.14",
|
||||
"archiveSha256": "866fb734b32c18c7a938d6f1edbda44c51fce1c87ee4c44839a8a3083d2aba25",
|
||||
"plugins": {
|
||||
"openrig": {
|
||||
"version": "0.1.0",
|
||||
"sha256": "ee8a1300119576f36889cc6494988c69faa3dfb2c3172cfd856a7ecc3edc0506"
|
||||
"version": "0.7.14",
|
||||
"sha256": "42286256af8e2b6153086a95c1eebbcfd40eaf7b70086a88f263a5606d54e591"
|
||||
},
|
||||
"openrig-core": {
|
||||
"version": "0.1.28",
|
||||
"sha256": "59b2fb34be931a423583283696c22034fa417530ea682268a68156a70730fb5f"
|
||||
"version": "0.1.29",
|
||||
"sha256": "5e08deffe33feed6f7beff6df39d70402248632f87e3b63f074835b400fff54d"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user