@iamoberlin/chorus 1.2.8 → 1.2.9

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/scheduler.ts +34 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamoberlin/chorus",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "description": "CHORUS: Hierarchy Of Recursive Unified Self-improvement — with Prayer Requests social network",
5
5
  "author": "Oberlin <iam@oberlin.ai>",
6
6
  "license": "MIT",
package/src/scheduler.ts CHANGED
@@ -12,6 +12,7 @@ import { recordExecution, type ChoirExecution } from "./metrics.js";
12
12
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
13
13
  import { join } from "path";
14
14
  import { homedir } from "os";
15
+ import { spawnSync } from "child_process";
15
16
 
16
17
  interface ChoirContext {
17
18
  choirId: string;
@@ -109,7 +110,7 @@ export function createChoirScheduler(
109
110
  return prompt;
110
111
  }
111
112
 
112
- // Execute a choir
113
+ // Execute a choir using openclaw agent CLI
113
114
  async function executeChoir(choir: Choir): Promise<void> {
114
115
  const state = runState.get(choir.id) || { runCount: 0 };
115
116
  const startTime = Date.now();
@@ -127,19 +128,42 @@ export function createChoirScheduler(
127
128
  try {
128
129
  const prompt = buildPrompt(choir);
129
130
 
130
- // Use OpenClaw's session system to run an agent turn
131
- const result = await api.runAgentTurn?.({
132
- sessionLabel: `chorus:${choir.id}`,
133
- message: prompt,
134
- isolated: true,
135
- timeoutSeconds: 300, // 5 min max
131
+ // Use openclaw agent CLI (same as Vision mode)
132
+ const result = spawnSync('openclaw', [
133
+ 'agent',
134
+ '--session-id', `chorus:${choir.id}`,
135
+ '--message', prompt,
136
+ '--json',
137
+ ], {
138
+ encoding: 'utf-8',
139
+ timeout: 300000, // 5 min
140
+ maxBuffer: 1024 * 1024, // 1MB
136
141
  });
137
142
 
138
- const output = result?.response || "(no response)";
143
+ let output = "(no response)";
144
+
145
+ if (result.status === 0 && result.stdout) {
146
+ // Extract JSON from output (may have plugin logs before it)
147
+ const stdout = result.stdout;
148
+ const jsonStart = stdout.indexOf('{');
149
+ if (jsonStart >= 0) {
150
+ try {
151
+ const parsed = JSON.parse(stdout.slice(jsonStart));
152
+ output = parsed.response || parsed.content || stdout;
153
+ } catch {
154
+ output = stdout;
155
+ }
156
+ } else {
157
+ output = stdout;
158
+ }
159
+ } else if (result.stderr) {
160
+ log.warn(`[chorus] ${choir.name} stderr: ${result.stderr.slice(0, 200)}`);
161
+ }
162
+
139
163
  execution.durationMs = Date.now() - startTime;
140
- execution.success = true;
164
+ execution.success = result.status === 0;
141
165
  execution.outputLength = output.length;
142
- execution.tokensUsed = result?.meta?.tokensUsed || estimateTokens(output);
166
+ execution.tokensUsed = estimateTokens(output);
143
167
 
144
168
  // Parse output for metrics (findings, alerts, improvements)
145
169
  execution.findings = countFindings(output);