@wrenautomation/raven 0.2.0 → 0.2.1

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/README.md CHANGED
@@ -23,7 +23,8 @@ learns. Raven never loops; the runner takes the edge.
23
23
  Needs Node 24+. The model is a command that reads the prompt on stdin and prints the answer.
24
24
  Default `claude -p --output-format json`, so Claude Code is the model in any terminal and its
25
25
  envelope gives the cost per call; `RAVEN_MODEL` or `--model` changes it (plain text out is fine);
26
- `--no-model` plans from your own queries only.
26
+ `--no-model` plans from your own queries only. A command that says nothing for 3 minutes is
27
+ killed and the call fails with why.
27
28
 
28
29
  ```sh
29
30
  npm i @wrenautomation/raven
package/dist/model.d.ts CHANGED
@@ -31,7 +31,9 @@ export declare function readOutput(stdout: string): {
31
31
  /**
32
32
  * A model that is a shell command: the prompt on stdin, the answer on stdout. When stdout is
33
33
  * Claude Code's JSON envelope (`claude -p --output-format json`) the usage comes with it.
34
+ * A command that says nothing for `timeoutMs` (3 minutes) is killed and the ask fails with
35
+ * why, so a hung model never hangs the run.
34
36
  */
35
- export declare function commandModel(command: string, id?: string): Model;
37
+ export declare function commandModel(command: string, id?: string, timeoutMs?: number): Model;
36
38
  /** A model that answers from a fixed list, in order: tests and dry runs. */
37
39
  export declare function scriptedModel(answers: unknown[], id?: string): Model;
package/dist/model.js CHANGED
@@ -72,17 +72,30 @@ export function readOutput(stdout) {
72
72
  /**
73
73
  * A model that is a shell command: the prompt on stdin, the answer on stdout. When stdout is
74
74
  * Claude Code's JSON envelope (`claude -p --output-format json`) the usage comes with it.
75
+ * A command that says nothing for `timeoutMs` (3 minutes) is killed and the ask fails with
76
+ * why, so a hung model never hangs the run.
75
77
  */
76
- export function commandModel(command, id = command) {
78
+ export function commandModel(command, id = command, timeoutMs = 180_000) {
77
79
  return {
78
80
  id,
79
81
  ask: (prompt, shape) => new Promise((resolve, reject) => {
80
82
  const child = spawn(command, { shell: true, stdio: ["pipe", "pipe", "inherit"] });
81
83
  const out = [];
84
+ let timedOut = false;
85
+ const timer = setTimeout(() => {
86
+ timedOut = true;
87
+ child.kill();
88
+ }, timeoutMs);
82
89
  child.stdout.on("data", (b) => out.push(b));
83
- child.on("error", reject);
90
+ child.on("error", (e) => {
91
+ clearTimeout(timer);
92
+ reject(e);
93
+ });
84
94
  child.on("close", (code) => {
95
+ clearTimeout(timer);
85
96
  const stdout = Buffer.concat(out).toString("utf8");
97
+ if (timedOut)
98
+ return reject(new Error(`${command}: no answer in ${Math.round(timeoutMs / 1000)}s`));
86
99
  if (code !== 0)
87
100
  return reject(new Error(`${command} exited ${code}: ${stdout.slice(0, 400)}`));
88
101
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrenautomation/raven",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Ask in, plan out. The planner of Wren's research engine: typed queries with who proposed them and why, proposals merged into one plan under a plan file per ask kind, read-or-skip on hits, and the edge to take after a round. Pure functions and prompts; the model is injected.",
5
5
  "license": "PolyForm-Shield-1.0.0",
6
6
  "repository": {