lobstah 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runner.js CHANGED
@@ -739,6 +739,18 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
739
739
  }
740
740
 
741
741
  // packages/core/dist/config.js
742
+ var BRIEF_KINDS = ["conflict", "checks", "review", "ciFix", "rebase"];
743
+ function parseBriefHooks(raw) {
744
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
745
+ return void 0;
746
+ const out = {};
747
+ for (const kind of [...BRIEF_KINDS, "all"]) {
748
+ const text = raw[kind];
749
+ if (typeof text === "string" && text.trim())
750
+ out[kind] = text.trim();
751
+ }
752
+ return Object.keys(out).length ? out : void 0;
753
+ }
742
754
  var ATTENTION_KINDS = ["question", "decision", "landed", "pr:draft", "pr:review", "pr:checks", "pr:conflict", "pr:ready", "report"];
743
755
  var DEFAULT_ATTENTION_KINDS = ["question", "decision", "pr:ready", "pr:review", "pr:conflict", "pr:checks"];
744
756
  function parseAttentionKinds(raw) {
@@ -766,7 +778,7 @@ var DEFAULT_HELM = {
766
778
  armGraceSecs: 5
767
779
  };
768
780
  var DEFAULT_GLASS = { port: 4949 };
769
- var DEFAULT_WATCH = { maxForksPerCycle: 3, autoRepair: true, conflicts: true, checks: true, maxRepairsPerPr: 2, repairSettleSecs: 600, repairTrapWaitSecs: 600 };
781
+ var DEFAULT_WATCH = { maxForksPerCycle: 3, autoRepair: true, conflicts: true, checks: true, maxRepairsPerPr: 2, maxRepairsWithoutProgress: 2, repairSettleSecs: 600, repairTrapWaitSecs: 600 };
770
782
  var DEFAULT_LIMITS = {
771
783
  maxConcurrent: 2,
772
784
  choreConcurrent: 1,
@@ -809,7 +821,8 @@ function loadConfig() {
809
821
  pushEarly: r.pushEarly === void 0 ? void 0 : Boolean(r.pushEarly),
810
822
  draftPr: r.draftPr === void 0 ? void 0 : Boolean(r.draftPr),
811
823
  checkpointOnStop: r.checkpointOnStop === void 0 ? void 0 : Boolean(r.checkpointOnStop),
812
- humanGateChecks: Array.isArray(r.humanGateChecks) ? r.humanGateChecks.map(String).filter(Boolean) : void 0
824
+ humanGateChecks: Array.isArray(r.humanGateChecks) ? r.humanGateChecks.map(String).filter(Boolean) : void 0,
825
+ briefHooks: parseBriefHooks(r.briefHooks)
813
826
  };
814
827
  }
815
828
  const groundsRaw = raw.grounds ?? {};
@@ -1728,11 +1741,11 @@ function chainPr(id, lane) {
1728
1741
  // packages/core/dist/pr-repair.js
1729
1742
  var PUSH_RETRIES = 3;
1730
1743
  var PUSH_REJECTED = "push rejected:";
1731
- function pushRule(branch, id = "<dispatch id>") {
1744
+ function pushRule(branch, id = "<dispatch id>", mode = "rebase") {
1732
1745
  const b = branch ?? "the PR's head branch";
1733
1746
  return [
1734
1747
  `Push only to the existing branch ${b}.`,
1735
- `If the push is rejected as non-fast-forward because ${b} moved, fetch ${b}, rebase your commits onto the moved head again, and push with \`--force-with-lease=${b}:<the head you just fetched>\`. Retry at most ${PUSH_RETRIES} times.`,
1748
+ mode === "merge" ? `If the push is rejected as non-fast-forward because ${b} moved, fetch ${b}, merge the moved head into your branch, and push again with a normal push. Retry at most ${PUSH_RETRIES} times. Never force-push.` : `If the push is rejected as non-fast-forward because ${b} moved, fetch ${b}, rebase your commits onto the moved head again, and push with \`--force-with-lease=${b}:<the head you just fetched>\`. Retry at most ${PUSH_RETRIES} times.`,
1736
1749
  "If a push hook fails with a real test or type error, do not retry the push: fix the error, commit, and push again.",
1737
1750
  `If you still cannot push, report \`lobstah report ${id} failed "${PUSH_REJECTED} <rejection text>; moved head <full sha of the head you fetched>"\` and leave the PR as it was.`,
1738
1751
  "Never push to another branch. Never open a new PR."
@@ -42,6 +42,25 @@ rather than relying on the default — left unset, a Claude session takes
42
42
  `effortLevel` from the host's settings files, including the user's own
43
43
  `~/.claude/settings.json`.
44
44
 
45
+ `[repos.<key>.briefHooks]` — markdown appended to the briefs lobstah
46
+ writes for this repo, one key per kind. Each value is a string; lobstah
47
+ appends it as written and does not read it.
48
+
49
+ | Key | Appended to |
50
+ |---|---|
51
+ | `conflict` | A daemon repair of a PR with a merge conflict. |
52
+ | `checks` | A daemon repair of a PR with failing checks. |
53
+ | `review` | A daemon repair of a PR with requested changes, and a pickup review-feedback round. |
54
+ | `ciFix` | A CI-fix continuation a PR watch forks. |
55
+ | `rebase` | A rebase chore from pickup's merge loop. |
56
+ | `all` | Every kind above, after that kind's own text. |
57
+
58
+ ```toml
59
+ [repos.web.briefHooks]
60
+ all = "Before you report done, run the repo's PR refresh (`/pr-refresh`)."
61
+ checks = "Run `pnpm test:ci` before you push."
62
+ ```
63
+
45
64
  `lobstah repos add <path> [--pickup]` detects and appends a block (origin,
46
65
  default branch from `origin/HEAD`, setup from the lockfile); `lobstah init
47
66
  --scan <dir>...` does the same for every git repo found under the given
@@ -113,7 +132,8 @@ send a continuation.
113
132
  | `conflicts` | `true` | Repair conflicts when `autoRepair` is on. Set `false` to show conflict attention without a repair. |
114
133
  | `checks` | `true` | Repair failed current checks when `autoRepair` is on. Set `false` to show check attention without a repair. |
115
134
  | `maxRepairsPerPr` | `2` | Maximum repair follow-ups for one PR head SHA. When the limit is reached and the issue remains, `pr:conflict`, `pr:checks`, or `pr:review` attention names the limit. A repair that waits is not an attempt. Below this limit, each failing check gets at most one repair round per PR and head SHA: a check that had its round and still fails on the same head waits for a new commit, with `repair.status: waiting` and `heldBy: repaired`, and raises `pr:checks` attention. A CI-fix continuation from `lobstah pick` (`autoRepair = false`) follows the same rule. Human gates (`[repos.<key>].humanGateChecks`, `report --human-gate`) get no round. |
116
- | `repairSettleSecs` | `600` | A repair is queued only after the PR's head, its base branch's head, and its failing checks have been unchanged for this many seconds. Until then the PR record shows `repair.status: waiting` with `heldBy: settle` and `until`. |
135
+ | `repairSettleSecs` | `600` | A repair is queued only after the PR's head, its base branch's head, and its failing checks have been unchanged for this many seconds. A conflict repair also waits this many seconds after the PR's latest approval. Until then the PR record shows `repair.status: waiting` with `heldBy: settle` and `until`. |
136
+ | `maxRepairsWithoutProgress` | `2` | Maximum repairs in a row on one PR that end `done` while the PR stays at the head the repair pushed and does not merge. Past the cap, lobstah stops repairing that PR: the PR record shows `repair.status: gave-up`, `pr:conflict` (or `pr:checks`, `pr:review`) attention names the cap, and one `repair-stopped` notice is posted. The count resets when the PR merges or closes, when a push that is not the repair's moves the head, and on `lobstah watch release <key>` (or `--all`). |
117
137
  | `repairTrapWaitSecs` | `600` | A daemon repair chore addressed to the PR-owning trap waits this many seconds for that trap. If still queued, it becomes headless. A person's addressed work never falls back. |
118
138
 
119
139
  ## `[grounds.*]` — helm territories
package/docs/man.md CHANGED
@@ -192,20 +192,47 @@ with `paused --waiting-on pr` or `--waiting-on review` merges, the daemon
192
192
  finishes that dispatch `done` with the note `the PR merged: <url>`. When
193
193
  the PR closes without merge, it finishes it `failed` with `the PR closed
194
194
  without merge: <url>`. The PR waited on is the `--link` when it names a
195
- GitHub PR, else the dispatch's own PR, else its chain's PR. Every paused
196
- dispatch waiting on that PR is finished, in the whole chain. The daemon
197
- does this after it observes PR watches and before its cull pass, so
198
- `[limits].releaseOnMerge` releases the chain's worktrees in the same pass.
199
- `report paused --waiting-on pr|review` registers the watch of the
200
- dispatch's own PR when it has none, so the merge is observed.
195
+ GitHub PR that is not one of the dispatch's own. Otherwise the dispatch
196
+ waits on all of its own PRs (its evidence, which `lobstah catch` shows),
197
+ else its chain's PR, else the PRs of the `pr:` watches it owns. A
198
+ dispatch with several PRs finishes only when every one of them has merged
199
+ or closed: `done` when at least one merged (`the PRs merged: <urls>`, or
200
+ `the PRs ended — merged: <urls>; closed without merge: <urls>`), `failed`
201
+ when all closed without merge. Every paused dispatch waiting on those PRs
202
+ is finished, in the whole chain. The daemon does this after it observes PR watches and before its
203
+ cull pass, so `[limits].releaseOnMerge` releases the chain's worktrees in
204
+ the same pass. `report paused --waiting-on pr|review` registers the watch
205
+ of the dispatch's own PR when it has none. The daemon also reads, at
206
+ `[pickup].pollSecs`, each waited-on PR that no live dispatch-owned watch
207
+ observes (a linked PR with no watch, or a helm-owned watch), so its merge
208
+ or close is seen without `lobstah pick`. When lobstah knows no PR for the
209
+ wait, the report prints a `warning` and a merge will not finish the
210
+ dispatch: report again with `--link <PR url>`.
201
211
 
202
212
  ### PR state after done
203
213
 
204
214
  A dispatch reports its PR with `report <id> <verb> --pr <url>`, which
205
215
  registers a `pr:` watch for the chain so the PR stays observed (see the
206
216
  PR preset in [vocabulary.md](vocabulary.md#the-pr-preset); `--no-watch`
207
- opts out). A trap's PR is tracked from its first push. What you get
208
- depends on what runs:
217
+ opts out). A trap's PR is tracked from its first push.
218
+
219
+ A dispatch can own several PRs. `--pr` is repeatable: each PR is recorded
220
+ and gets its own `pr:` watch. The first is the dispatch's `prUrl`; all of
221
+ them are its `prUrls`. When a reported PR is part of a stack, the other PRs
222
+ of the stack are recorded too:
223
+
224
+ - a gh stack: the `gh-stack` state in the dispatch's checkout (from
225
+ `gh stack init` or `gh stack submit`) lists a stack that holds the PR;
226
+ - a base chain: the dispatch pushed two or more branches, and
227
+ `gh pr view <branch>` links their PRs to the reported one by base
228
+ branch.
229
+
230
+ The report prints `prs` with every PR it recorded. `lobstah catch` and
231
+ `lobstah status <id>` list each PR (`prs`), `man tend` lists each with its
232
+ state in the story's `pr` column, and the glass links each by number. Each
233
+ PR has its own record, so `pr:*` attention and the merged/closed notice are
234
+ per PR. `[limits].releaseOnMerge` keeps the worktree while another PR of
235
+ the dispatch is open. What you get depends on what runs:
209
236
 
210
237
  - **Only the helm park or `man wait`** (no service): PR state badges in
211
238
  `man tend`, `lobstah catch`, and the glass (`merged`, `draft`, `review`,
@@ -223,16 +250,21 @@ succeeds and the watch's check records `lastError`.
223
250
 
224
251
  Which commands register a watch. Only these write points register one:
225
252
 
226
- - `lobstah report <id> <verb> --pr <url>` registers the watch for the PR the
227
- worker opened. Any verb but `failed` does this. A PR already watched is
228
- not registered again.
253
+ - `lobstah report <id> <verb> --pr <url> [--pr <url> ...]` registers the
254
+ watch for each PR the worker opened, and for the other PRs of a stack
255
+ that holds one of them. Any verb but `failed` does this. A PR already
256
+ watched is not registered again.
229
257
  - `lobstah report <id> paused --waiting-on pr|review` registers the watch
230
- for the dispatch's own PR. A `--link` to another PR registers nothing.
258
+ for the dispatch's own PR. A `--link` to another PR registers nothing; the
259
+ daemon reads that PR while the dispatch waits on it.
231
260
  - `lobstah soak beat` registers the watch for a trap's PR from its first
232
261
  push. At most once a minute, it reads the trap's branch. When the branch
233
- is not trunk and has an upstream, it asks `gh pr view <branch>` for the PR.
234
- It records a new PR in the dispatch's evidence, where `lobstah catch` and
235
- `lobstah status <id>` show it.
262
+ is not trunk, has an upstream, and its head commit is newer than the
263
+ dispatch's claim, it asks `gh pr view <branch>` for the PR. A trap that
264
+ takes new work on the branch of its last dispatch does not give that PR
265
+ to the new dispatch until the new dispatch commits. It records a new PR in
266
+ the dispatch's evidence, where `lobstah catch` and `lobstah status <id>`
267
+ show it.
236
268
  - `lobstah watch add <key>` registers the watch you name.
237
269
  - `lobstah watch backfill --apply` registers watches for PRs in old dispatch
238
270
  history, and fetches the title of each PR record that has none (one
@@ -304,6 +336,8 @@ and the glass show the repair's PR, chore lane, worker, and trap wait.
304
336
  PR whose head branch is its base branch.
305
337
  - The PR's head, its base branch's head, or its failing checks changed less
306
338
  than `[watch].repairSettleSecs` ago (default 600).
339
+ - For a conflict repair: the PR was approved less than
340
+ `[watch].repairSettleSecs` ago.
307
341
  - For a checks repair: a fresh read of the latest run of each failing check
308
342
  shows that run in progress or passed.
309
343
  - The PR's watch is held. `lobstah cancel` on a repair dispatch holds its
@@ -322,13 +356,29 @@ in the `repairs waiting` table, the PR badge ends in `repair waits: <heldBy>`,
322
356
  the glass PR modal shows the reason, and `lobstah doctor` lists it. When the
323
357
  wait ends, the normal rules apply again.
324
358
 
359
+ **Repairs stop** on a PR after `[watch].maxRepairsWithoutProgress`
360
+ (default 2) repairs in a row that each ended `done` while the PR stayed at
361
+ the head the repair pushed and did not merge. lobstah then queues no repair
362
+ for that PR, marks its repair `gave-up`, raises `pr:conflict` (or
363
+ `pr:checks`, `pr:review`) attention that names the cap, and posts one
364
+ `repair-stopped` notice. The count resets when the PR merges or closes,
365
+ when a push that is not the repair's moves the head, and on
366
+ `lobstah watch release <key>`, which prints `repairsResumed` with the PRs it
367
+ resumed.
368
+
325
369
  **A repair pushes** to its PR's head branch, and so does a rebase chore
326
370
  from pickup's merge loop. The descriptor of each names its PR (`pr`), so
327
371
  the runner pushes no branch and opens no PR for it. The brief gives the
328
- worker the push rule: push only to the PR's head branch. On a
329
- non-fast-forward rejection, fetch the branch, rebase the commits onto the
330
- moved head again, and push with `--force-with-lease` on the head just
331
- fetched, at most three times. A push hook that fails with a real test or
372
+ worker the push rule: push only to the PR's head branch. A conflict
373
+ repair of a **standalone** PR (its base is the repo's `trunk`) merges the
374
+ base into the PR branch with a merge commit and pushes normally; on a
375
+ non-fast-forward rejection it fetches the moved head, merges it, and
376
+ pushes again, never with force. A conflict repair of a **stacked** PR (its
377
+ base is another PR's branch) rebases onto that base and pushes with
378
+ `--force-with-lease`; on a rejection it rebases onto the moved head again
379
+ and pushes with a lease on the head just fetched. A checks or review
380
+ repair follows the rebase rule on a rejection. Each retries at most three
381
+ times. A push hook that fails with a real test or
332
382
  type error is not retried: the worker fixes the error and pushes again.
333
383
  For code already on main, the repair keeps main's version and only this
334
384
  PR's own changes. It does not change behavior. If a conflict resolution
@@ -83,9 +83,14 @@ Effects of `paused` with `--waiting-on`:
83
83
  - With `--waiting-on pr` or `--waiting-on review`: when the PR it waits on
84
84
  merges, the daemon finishes the dispatch `done` (`the PR merged: <url>`);
85
85
  closed without merge, `failed`. The PR is the `--link` when it names a
86
- GitHub PR, else the dispatch's own PR, else its chain's PR. Every paused
87
- dispatch in the chain that waits on the PR is finished. The report
88
- registers the watch of the dispatch's own PR when it has none.
86
+ GitHub PR that is not the dispatch's own. Otherwise it is every PR of the
87
+ dispatch (`prUrl` and `prUrls`), else its chain's PR, else the PRs of the
88
+ `pr:` watches the dispatch owns; the dispatch finishes when all of them
89
+ have ended. Every paused dispatch in the chain that waits on the PR is
90
+ finished. The report registers the watch of the
91
+ dispatch's own PR when it has none, and the daemon reads a waited-on PR
92
+ that no live dispatch-owned watch observes. When no PR is known, the
93
+ report prints a `warning`.
89
94
  - No attention, no notice, no pet. It is a state, not a question.
90
95
 
91
96
  Source of truth: `WAITING_ON` in `packages/core/src/types.ts`.
@@ -349,7 +354,7 @@ evidence).
349
354
  | `draft` | Draft flipped (`value`). Evidence only. |
350
355
  | `merged` / `closed` | Terminal; the check sets `done`, and the watch retires once delivered. Emitted only on an open → terminal change, never on the first observation. |
351
356
  | evidence `pr` | `{ url, number, state, draft, reviewDecision, mergeStateStatus, headSha, checks: { total, passed, failed, pending, unknown? }, review: { unresolvedThreads, changesRequested, lastReviewAt }, observedAt }`. Check counts use only the latest run per check name and app/workflow. `CANCELLED` and `STALE` latest runs are unknown, not failed. The PR record also stores repair status, attempts, and reason. `prBadge` shows `repairing: conflict (attempt 1 of 2)` while a repair is in flight, and ends in `repair waits: <heldBy>` while a repair waits; tend, `catch`, and the glass share the badge. |
352
- | waiting repair | `repair.status: waiting` on a PR record: a repair is due but is not queued. `heldBy` names the holder: `wt:<trap>` or `dispatch:<id8>` (a live worker holds the PR's head branch or the head branch of a PR below it in the stack), `helm` (the helm cancelled a repair of this PR), `hold` or `dispatch:<id8>` (`watch hold`), `settle` (the head, base head, or failing checks changed less than `[watch].repairSettleSecs` ago; `until` says when), or `checks` (the latest run of a failing check is in progress or passed). `reason` says what holds it. A wait is not an attempt and raises no attention item. |
357
+ | waiting repair | `repair.status: waiting` on a PR record: a repair is due but is not queued. `heldBy` names the holder: `wt:<trap>` or `dispatch:<id8>` (a live worker holds the PR's head branch or the head branch of a PR below it in the stack), `helm` (the helm cancelled a repair of this PR), `hold` or `dispatch:<id8>` (`watch hold`), `settle` (the head, base head, or failing checks changed less than `[watch].repairSettleSecs` ago, or, for a conflict repair, the PR was approved less than that ago; `until` says when), or `checks` (the latest run of a failing check is in progress or passed). `reason` says what holds it. A wait is not an attempt and raises no attention item. |
353
358
  | repair chore | A daemon repair or rebase runs in the `chore` lane under `[limits].choreConcurrent`. A repair chore for a trap-built PR waits for its live owning trap up to `[watch].repairTrapWaitSecs` (default 600), then runs headless in its own PR-branch checkout. A headless-built PR's repair runs headless in its origin worktree when safe. No headless chore uses a trap's worktree. This bounded fallback applies only to system repair chores; a person's addressed work is sticky and never falls back. Tend, daemon status, doctor, and the glass show the PR, lane, worker, and trap wait. |
354
359
  | live worker | An active headless dispatch, or a trap with an open catch. It holds a branch that its worktree has checked out, that its current branch tracks, or that it pushed during its current dispatch (evidence `pushes`). It holds a PR that its evidence names or that its chain owns. |
355
360
  | evidence `pushes` | `[{ branch, at }]`: the branches a dispatch pushed, as lobstah saw them. The runner records its own pushes; the runner records a headless worker's `git push` from the harness event stream (branch names only); `soak beat` records a trap's `git push`. |
@@ -368,7 +373,11 @@ PR's head branch or a branch below it in the stack, until the PR has settled
368
373
  for `[watch].repairSettleSecs`, while a failing check's latest run is in
369
374
  progress or passed, and while the PR's watch is held. A wait is not an
370
375
  attempt. A repair whose worker reported `failed "push rejected: ..."` is `blocked` at the
371
- moved head and at the head it started from. The rest is evidence.
376
+ moved head and at the head it started from. After
377
+ `[watch].maxRepairsWithoutProgress` repairs in a row that left the PR at
378
+ their own push and unmerged, repairs of that PR stop (`gave-up`, a
379
+ `repair-stopped` notice) until it merges or closes, a push that is not the
380
+ repair's moves the head, or `lobstah watch release <key>`. The rest is evidence.
372
381
  Merged and closed reach the helm as a `pr-merged` / `pr-closed` notice,
373
382
  posted once by whichever process first records the open → terminal
374
383
  transition on the **PR record** — not by event routing. A PR whose first
@@ -431,7 +440,7 @@ worktree is refused (the session lock); a stale one is adopted.
431
440
  | defective enlistment | A stale registration that **never parked** — signed on but never listened (usually no Stop hook). Not swept: the helm gets a `trap-defective` notice with the remedy (`soak --wait`), and the registration stays so the address keeps protecting its work. |
432
441
  | reserved trap | A trap `lobstah trap reserve` created before any session signs on as it: a name, a `wt:` id, and a one-time ticket, shown as `starting`. Work addressed to it waits. A session redeems the ticket with `soak --ticket` (or `LOBSTAH_TRAP_TICKET`) and signs on as that trap. Unredeemed past its deadline, it fails with a `trap-start-failed` notice and its work stays queued. `stow --wt <name>` withdraws it. |
433
442
  | trap request | A trap the human asked for from the glass's **+ New trap** button: a `trap-request` request in `requests/<id>.json` with a repo and a harness. It wakes the helm as a `trap-request` event; the helm reserves it with `trap reserve --request <id>`, which closes it. |
434
- | notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; a first park (`trap-listening`) is consumed without waking anyone. tend always shows the recent tail. |
443
+ | notice | The helm's attention channel for non-status events (`~/.lobstah/notices/`): reservations (`trap-starting`), reservations that did not start (`trap-start-failed`), trap requests from the glass (`trap-request`), sign-ons, first parks, sign-offs, ghosts, defective enlistments, orphaned work, bounced messages, PRs merged or closed, watches held over the fork cap (`watch-held`), failing (`watch-failing`), and recovered (`watch-recovered`), free-space holds (`disk-held`, `disk-cleared`), worktrees released after their PR merged (`worktree-released`, one per cull pass), a repair or rebase that could not push to its PR's branch (`push-failed`), repairs stopped on a PR that made no progress (`repair-stopped`), and a human's answer to a decision (`decision-answer`; its ref is the request id in `~/.lobstah/requests/`). A trap leaves the registry only through a `trap-stowed` or `trap-ghosted` notice — the end-state is always explicit. Consumed by `man wait`/the park; a first park (`trap-listening`) is consumed without waking anyone. tend always shows the recent tail. |
435
444
 
436
445
  Delivery routes by ownership, same as watches: a continuation for a chain
437
446
  claimed by a live trap is addressed back to that trap and stays sticky.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lobstah",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "Harness-agnostic, token-efficient supervision framework for coding agents",
5
5
  "license": "MIT",
6
6
  "author": "aequitas labs LLC",