@crouton-kit/crouter 0.3.41 → 0.3.43

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/bin/crouter CHANGED
@@ -1,2 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import('../dist/cli.js');
2
+ import { existsSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const entry = fileURLToPath(new URL('../dist/cli.js', import.meta.url));
6
+ if (!existsSync(entry)) {
7
+ process.stderr.write(
8
+ 'crouter: compiled output is missing (dist/cli.js not found).\n' +
9
+ 'Run `npm run build` in the crouter package, then retry.\n',
10
+ );
11
+ process.exit(1);
12
+ }
13
+ import(entry);
package/bin/crtr CHANGED
@@ -1,2 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import('../dist/cli.js');
2
+ import { existsSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const entry = fileURLToPath(new URL('../dist/cli.js', import.meta.url));
6
+ if (!existsSync(entry)) {
7
+ process.stderr.write(
8
+ 'crtr: compiled output is missing (dist/cli.js not found).\n' +
9
+ 'Run `npm run build` in the crouter package, then retry.\n',
10
+ );
11
+ process.exit(1);
12
+ }
13
+ import(entry);
package/bin/crtrd CHANGED
@@ -1,2 +1,13 @@
1
1
  #!/usr/bin/env node
2
- import('../dist/daemon/crtrd-cli.js');
2
+ import { existsSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const entry = fileURLToPath(new URL('../dist/daemon/crtrd-cli.js', import.meta.url));
6
+ if (!existsSync(entry)) {
7
+ process.stderr.write(
8
+ 'crtrd: compiled output is missing (dist/daemon/crtrd-cli.js not found).\n' +
9
+ 'Run `npm run build` in the crouter package, then retry.\n',
10
+ );
11
+ process.exit(1);
12
+ }
13
+ import(entry);
@@ -0,0 +1,34 @@
1
+ ---
2
+ kind: knowledge
3
+ when-and-why-to-read: When you see a node marked wedged (⚠ on the canvas, a doctrine-wake notice naming a child as wedged, or `node inspect list --hanging` showing a `daemon→node`/`wedged` fault) or, absent that signal, a node has been "active"/`streaming:true` implausibly long with no progress (a child whose wave is not advancing, or an orchestrator frozen with a piling inbox for hours/days), this reference should be read because it shows how to recover — kill the runaway subprocess when one exists, or, when the broker has none, confirm/trigger the daemon's own SIGTERM-and-resume kick and nudge it, without losing context.
4
+ short-form: a child stuck mid-turn (runaway bash, or a stalled broker with no subprocess) is AUTO-DETECTED by the daemon (⚠ wedged + a doctrine wake) — kill the subprocess if one exists; if none, the daemon itself SIGTERM-kicks the broker to resume it
5
+ system-prompt-visibility: none
6
+ file-read-visibility: preview
7
+ ---
8
+
9
+ A base node can wedge INDEFINITELY on a single runaway bash command (classic: `grep -rln "..." /` — a recursive grep from filesystem root that scans all of disk and never returns; also any unbounded find/scan over `/` or a network mount). The node's pi turn is blocked waiting on the bash call, so it never `push`es and never finishes.
10
+
11
+ **Detection is automatic (crtrd, issue #110).** The daemon's supervision tick corroborates two signals on every live/busy node: the busy-marker heartbeat (re-touched on every tool start/stream/end and turn end) gone quiet for 20+ minutes, AND the broker's whole process tree (broker pid + every descendant) reading near-zero CPU. Only when BOTH hold does it fire — routine long tool calls that are genuinely still producing output or burning CPU never trip it. On a 'wedged' verdict the daemon records a `daemon→node`/`wedged` Fault (the node shows ⚠ "wedged · needs you" on the canvas graph views and in `node inspect list --hanging`, the same surface provider-fault stalls use) and fans a doctrine wake to the node's subscribers — ONE notice per wedge episode, not a repeat every tick.
12
+
13
+ **Remediation branches on whether the tree has a descendant (issue #119):**
14
+
15
+ - **A subprocess exists (the common case)** — a runaway bash/find/grep is the likely cause. The daemon does NOT touch the engine here; you kill the subprocess yourself (see below).
16
+ - **No subprocess exists** — the broker pid stands alone in its own tree (the engine itself stalled, e.g. mid a `model_change`, with nothing a human could kill). The daemon performs the ONLY remaining remediation itself: it SIGTERMs the broker (the same on-demand kick `canvas revive --now` does), and its own dead-pid crash-grace path resumes it on the saved session within ~20s, no lost context. The resume alone can leave the node IDLE rather than mid-turn (it reloads the session but doesn't restart the dead turn) — if telemetry stays frozen after the kick, nudge it (see "No-subprocess case" below).
17
+
18
+ **Why it used to be invisible to the orchestrator:** the wake spine only fires on a child's push/finalize/crash. A child wedged *mid-turn* does none of those — its row stays `status=active` and the dashboard shows it `●` working. Before #110, the parent got no wake at all, so an entire wave could stall for hours looking healthy; cli-verbs-B2 sat wedged ~2h14m on a `grep /` before a safety-deadline inspection caught it. The daemon-side detection above closes that gap; you should no longer need to notice a wedge by elapsed-time vibes alone — but if you do (the daemon hasn't caught up yet, or the wedge is younger than its grace window), the manual inspection below still works.
19
+
20
+ ## Subprocess case: kill the runaway command
21
+
22
+ **How to inspect further / confirm:** `tmux capture-pane -p -t <pane>` shows the live turn (look for `Elapsed NNNNs ⠼ Working...` on one bash command); `pgrep -P <pi_pid>` + `ps -axo pid,ppid,etime,command` reveals the runaway subprocess and how long it's run.
23
+
24
+ **How to apply:** kill the runaway SUBPROCESS, not the node — `kill <grep_pid>`. The bash call then returns and the pi turn resumes on its own, no context lost, no respawn. (Killing the bash `-c` wrapper can orphan the grep; kill the actual scanner PID. A pipeline `grep / | head` resumes fastest if you kill the first-stage grep — the pipe closes and bash proceeds.) Then notify the OWNING orchestrator (deferred tier) so it steers the child to completion and knows the lost time — the doctrine wake above already does this automatically for a detected wedge, but do it yourself if you found the wedge before the daemon did. Related: the `revive-stuck-orchestrator` doc covers the orchestrator-level false-finish failure mode.
25
+
26
+ ## No-subprocess case: broker wedged mid-stream (`streaming:true` stuck)
27
+
28
+ The wedge can outlive any subprocess, or exist with none at all. A node (including a top-level **resident orchestrator**, not just a child) can sit stuck with the canvas snapshot showing `streaming: true` and a stale `last_activity` for **days**, while the broker pid is alive but doing nothing (0% CPU) and NO subprocess exists to kill — the engine deadlocked mid-stream (often right after a bash call returned, or after a `model_change`) and never closed the turn. Tells: `job/busy` lockfile present with an old mtime, `job/telemetry.json` `updated_at` frozen, `job/broker.log` stopped growing, inbox piling up (`queued (N)` in the dashboard) because the turn never ends. The `busy` marker alone is harmless (it is always AND-ed with `pidAlive`, so a stale one from a dead pid is ignored) — do not bother deleting it.
29
+
30
+ **This is now the daemon's own remediation (issue #119) — it auto-kicks the broker for you.** If it hasn't caught up yet (younger than the wedge grace, or the daemon was down), do it manually:
31
+
32
+ 1. `kill -TERM <broker_pid>` — the wedged broker. Confirm it dies (`ps -p <pid>`) and that no orphan subprocess lingers (`ps -o pid,ppid,command | awk '$2==<pid>'`).
33
+ 2. The **daemon auto-resumes** it within ~20s on the saved session — a fresh broker pid appears (`node inspect show`), `status=active`, `intent=null`, `view.sock` accepts connections. (No manual `canvas revive` needed if the daemon is up; do it manually only if it doesn't come back.)
34
+ 3. **The resume alone leaves it IDLE** — it loads the session but does not restart the dead turn, so telemetry stays frozen and it processes nothing. Send a `--tier critical` `node msg` to force a fresh turn (critical = interrupt + new turn). Word it as a recovery notice: tell it the broker was wedged, to re-orient from `context/roadmap.md`/feed, and NOT to trust that recent inbox context survived (cursor may have advanced past messages the wedged engine never folded into the conversation). Confirm success by watching `telemetry.json` `updated_at` go current and the node run bash again.