@enderfga/claw-orchestrator 7.14.0 → 7.16.0
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 +162 -135
- package/configs/autoloop-reviewer-prompt.md +1 -1
- package/configs/engines/README.md +31 -11
- package/dist/bin/acp-server.js +7 -12
- package/dist/bin/acp-server.js.map +1 -1
- package/dist/bin/cli.js +84 -46
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/mcp-server.js +2 -54
- package/dist/bin/mcp-server.js.map +1 -1
- package/dist/src/acp-server.d.ts +17 -9
- package/dist/src/acp-server.js +149 -30
- package/dist/src/acp-server.js.map +1 -1
- package/dist/src/autoloop/agent-tools.d.ts +2 -0
- package/dist/src/autoloop/agent-tools.js +7 -0
- package/dist/src/autoloop/agent-tools.js.map +1 -1
- package/dist/src/autoloop/dispatcher.d.ts +6 -0
- package/dist/src/autoloop/dispatcher.js +72 -9
- package/dist/src/autoloop/dispatcher.js.map +1 -1
- package/dist/src/autoloop/planner-tools.js +2 -0
- package/dist/src/autoloop/planner-tools.js.map +1 -1
- package/dist/src/claude-goal-session.d.ts +147 -0
- package/dist/src/claude-goal-session.js +355 -0
- package/dist/src/claude-goal-session.js.map +1 -0
- package/dist/src/council.d.ts +8 -0
- package/dist/src/council.js +45 -12
- package/dist/src/council.js.map +1 -1
- package/dist/src/dashboard/index.html +28 -14
- package/dist/src/embedded-server.js +27 -8
- package/dist/src/embedded-server.js.map +1 -1
- package/dist/src/engine-spawn.js +3 -1
- package/dist/src/engine-spawn.js.map +1 -1
- package/dist/src/fanout.d.ts +13 -3
- package/dist/src/fanout.js +10 -0
- package/dist/src/fanout.js.map +1 -1
- package/dist/src/inbox-manager.d.ts +9 -0
- package/dist/src/inbox-manager.js +8 -2
- package/dist/src/inbox-manager.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +135 -53
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/agent-step.d.ts +6 -0
- package/dist/src/kernel/agent-step.js.map +1 -1
- package/dist/src/kernel/conditions.d.ts +1 -1
- package/dist/src/kernel/conditions.js +1 -1
- package/dist/src/kernel/engine.d.ts +28 -8
- package/dist/src/kernel/engine.js +93 -19
- package/dist/src/kernel/engine.js.map +1 -1
- package/dist/src/kernel/nodes/agent.js +2 -0
- package/dist/src/kernel/nodes/agent.js.map +1 -1
- package/dist/src/kernel/nodes/council.js +9 -4
- package/dist/src/kernel/nodes/council.js.map +1 -1
- package/dist/src/kernel/nodes/fanout.js +5 -0
- package/dist/src/kernel/nodes/fanout.js.map +1 -1
- package/dist/src/kernel/nodes/goal.d.ts +19 -5
- package/dist/src/kernel/nodes/goal.js +81 -34
- package/dist/src/kernel/nodes/goal.js.map +1 -1
- package/dist/src/kernel/nodes/subflow.js +9 -1
- package/dist/src/kernel/nodes/subflow.js.map +1 -1
- package/dist/src/kernel/nodes/ultraapp.d.ts +1 -0
- package/dist/src/kernel/nodes/ultraapp.js +1 -0
- package/dist/src/kernel/nodes/ultraapp.js.map +1 -1
- package/dist/src/kernel/nodes/verifier.js +5 -1
- package/dist/src/kernel/nodes/verifier.js.map +1 -1
- package/dist/src/kernel/projections.d.ts +1 -0
- package/dist/src/kernel/projections.js +7 -1
- package/dist/src/kernel/projections.js.map +1 -1
- package/dist/src/kernel/templates/index.d.ts +16 -11
- package/dist/src/kernel/templates/index.js +14 -8
- package/dist/src/kernel/templates/index.js.map +1 -1
- package/dist/src/kernel/types.d.ts +37 -13
- package/dist/src/kernel/types.js.map +1 -1
- package/dist/src/logger.d.ts +6 -0
- package/dist/src/logger.js +14 -0
- package/dist/src/logger.js.map +1 -1
- package/dist/src/mcp-annotations.d.ts +13 -0
- package/dist/src/mcp-annotations.js +100 -0
- package/dist/src/mcp-annotations.js.map +1 -0
- package/dist/src/models.d.ts +7 -0
- package/dist/src/models.js +9 -0
- package/dist/src/models.js.map +1 -1
- package/dist/src/openai-compat.d.ts +11 -5
- package/dist/src/openai-compat.js +55 -54
- package/dist/src/openai-compat.js.map +1 -1
- package/dist/src/persistent-acp-session.d.ts +7 -0
- package/dist/src/persistent-acp-session.js +26 -2
- package/dist/src/persistent-acp-session.js.map +1 -1
- package/dist/src/persistent-codex-app-session.d.ts +2 -0
- package/dist/src/persistent-codex-app-session.js +18 -9
- package/dist/src/persistent-codex-app-session.js.map +1 -1
- package/dist/src/persistent-codex-session.d.ts +14 -3
- package/dist/src/persistent-codex-session.js +22 -19
- package/dist/src/persistent-codex-session.js.map +1 -1
- package/dist/src/persistent-custom-session.d.ts +9 -0
- package/dist/src/persistent-custom-session.js +41 -21
- package/dist/src/persistent-custom-session.js.map +1 -1
- package/dist/src/persistent-grok-session.js +1 -1
- package/dist/src/persistent-grok-session.js.map +1 -1
- package/dist/src/persistent-session.d.ts +9 -0
- package/dist/src/persistent-session.js +23 -0
- package/dist/src/persistent-session.js.map +1 -1
- package/dist/src/run-ledger.d.ts +3 -3
- package/dist/src/session-manager.d.ts +45 -1
- package/dist/src/session-manager.js +199 -34
- package/dist/src/session-manager.js.map +1 -1
- package/dist/src/types.d.ts +34 -11
- package/dist/src/types.js.map +1 -1
- package/dist/src/ultraapp/build.d.ts +5 -11
- package/dist/src/ultraapp/build.js +5 -11
- package/dist/src/ultraapp/build.js.map +1 -1
- package/dist/src/ultraapp/council-adapter.d.ts +5 -2
- package/dist/src/ultraapp/council-adapter.js +6 -6
- package/dist/src/ultraapp/council-adapter.js.map +1 -1
- package/dist/src/ultraapp/files.d.ts +7 -0
- package/dist/src/ultraapp/files.js +7 -1
- package/dist/src/ultraapp/files.js.map +1 -1
- package/dist/src/ultraapp/manager.d.ts +23 -3
- package/dist/src/ultraapp/manager.js +170 -72
- package/dist/src/ultraapp/manager.js.map +1 -1
- package/dist/src/ultraapp/narrator.js +1 -1
- package/dist/src/ultraapp/narrator.js.map +1 -1
- package/dist/src/ultraapp/versions.d.ts +27 -5
- package/dist/src/ultraapp/versions.js +58 -13
- package/dist/src/ultraapp/versions.js.map +1 -1
- package/openclaw.plugin.json +4 -13
- package/package.json +13 -6
- package/skills/SKILL.md +52 -24
- package/skills/references/acp.md +140 -61
- package/skills/references/autoloop.md +148 -38
- package/skills/references/claude-cli-tracking.md +9 -6
- package/skills/references/cli.md +139 -108
- package/skills/references/council.md +44 -22
- package/skills/references/dashboard.md +37 -21
- package/skills/references/getting-started.md +49 -15
- package/skills/references/inbox.md +13 -8
- package/skills/references/mcp.md +25 -17
- package/skills/references/multi-engine.md +161 -145
- package/skills/references/observability.md +90 -58
- package/skills/references/openai-compat.md +172 -82
- package/skills/references/sessions.md +101 -65
- package/skills/references/tools.md +217 -158
- package/skills/references/ultra.md +7 -7
- package/skills/references/ultraapp.md +101 -56
- package/skills/references/verification.md +112 -56
- package/skills/references/workflow.md +275 -97
- package/assets/banner.jpg +0 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Claude Code `/goal` behind the `GoalSession` surface the kernel's `goal`
|
|
3
|
+
* node drives, so one node runs a goal on either engine.
|
|
4
|
+
*
|
|
5
|
+
* Codex's app-server owns a goal: it has RPCs to set, pause and read it, and
|
|
6
|
+
* notifies every status change. Claude Code has none of that. What it has,
|
|
7
|
+
* measured on CLI 2.1.312 in stream-json mode:
|
|
8
|
+
*
|
|
9
|
+
* - `/goal <condition>` sets the goal and starts working. A Stop hook judges
|
|
10
|
+
* the condition after every turn and feeds the turn back while it does not
|
|
11
|
+
* hold, all inside the one send; a single `result` arrives when the goal is
|
|
12
|
+
* met, and the goal clears itself.
|
|
13
|
+
* - A bare `/goal` answers at once, without a model turn: `Goal active: …` or
|
|
14
|
+
* `No goal set. …`. That is the only way to read the goal.
|
|
15
|
+
* - The goal is part of the transcript. A process that dies and is resumed
|
|
16
|
+
* with `--resume` still has it, but nothing drives it until a message comes.
|
|
17
|
+
* - The `interrupt` control request ends the running turn with an
|
|
18
|
+
* `error_during_execution` result and leaves the goal set.
|
|
19
|
+
* - A turn that fails (an auth error, a usage limit) ends with an `is_error`
|
|
20
|
+
* result, and the CLI clears the goal then too ("Goal cleared after an
|
|
21
|
+
* unrecoverable error"). "No goal set" alone does not mean the goal was met.
|
|
22
|
+
* - The condition is judged by a separate model reading the transcript, not by
|
|
23
|
+
* the agent. When it blocks the agent's stop 9 times running, the CLI ends
|
|
24
|
+
* the turn anyway and says so in an `informational` system event; the goal
|
|
25
|
+
* stays set.
|
|
26
|
+
*
|
|
27
|
+
* So the status here is partly the adapter's own bookkeeping. `active` while a
|
|
28
|
+
* goal turn runs. `complete` only when a turn that started with the goal set
|
|
29
|
+
* ended without an error and the goal is gone: the Stop hook let it end. A
|
|
30
|
+
* goal still set with nothing driving it, a failed turn, and a reopened thread
|
|
31
|
+
* whose goal is gone are all `paused`, which the node resumes within its bound;
|
|
32
|
+
* resuming re-arms the goal (`/goal <objective>` again) when the CLI dropped
|
|
33
|
+
* it, so a goal already met costs one turn to confirm. A failed login is
|
|
34
|
+
* `blocked`: resuming cannot fix it. So is a turn the CLI had to end over the
|
|
35
|
+
* Stop hook: the agent asked to stop again and again, and continuing it only
|
|
36
|
+
* repeats that. The node goes on to its verifier either way, and the contract,
|
|
37
|
+
* not the agent or the hook, decides.
|
|
38
|
+
*
|
|
39
|
+
* Tokens are the session's input, output and cache-read tokens; the CLI reports
|
|
40
|
+
* no goal-level count. A reopened process starts its counters at zero, so the
|
|
41
|
+
* node hands over what the thread had already spent.
|
|
42
|
+
*/
|
|
43
|
+
import { EventEmitter } from 'node:events';
|
|
44
|
+
import { SESSION_EVENT } from './constants.js';
|
|
45
|
+
/** Sent to pick a goal back up: the Stop hook keeps it going from there. */
|
|
46
|
+
export const CLAUDE_GOAL_CONTINUE = 'Continue working toward the active goal. Pick up from where the work stands now.';
|
|
47
|
+
const PROBE_TIMEOUT_MS = 60_000;
|
|
48
|
+
/** Map a failed turn's text onto the codex error codes the node treats as transient. */
|
|
49
|
+
export function classifyClaudeError(text, apiStatus) {
|
|
50
|
+
const status = typeof apiStatus === 'number' ? apiStatus : Number.NaN;
|
|
51
|
+
if (status === 401 ||
|
|
52
|
+
status === 403 ||
|
|
53
|
+
/not logged in|\/login|invalid api key|authentication|unauthorized/i.test(text)) {
|
|
54
|
+
return 'unauthorized';
|
|
55
|
+
}
|
|
56
|
+
if (status === 429 || /usage limit|rate limit|limit reached|hit your limit|\b429\b/i.test(text)) {
|
|
57
|
+
return 'usageLimitExceeded';
|
|
58
|
+
}
|
|
59
|
+
if (status === 529 || /overloaded|\b529\b/i.test(text))
|
|
60
|
+
return 'serverOverloaded';
|
|
61
|
+
if ((status >= 500 && status < 600) ||
|
|
62
|
+
/\b5\d\d\b|internal server error|api error|ECONNRESET|ETIMEDOUT|socket hang up|fetch failed|network/i.test(text)) {
|
|
63
|
+
return 'internalServerError';
|
|
64
|
+
}
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
/** Read a bare `/goal` answer. */
|
|
68
|
+
export function parseGoalProbe(text) {
|
|
69
|
+
const t = text.trim();
|
|
70
|
+
if (/^no goal set/i.test(t))
|
|
71
|
+
return { active: false };
|
|
72
|
+
const m = /^goal active:\s*([\s\S]*?)(?:\s*\((?:not yet evaluated|[^()]*)\))?\s*$/i.exec(t);
|
|
73
|
+
if (m)
|
|
74
|
+
return { active: true, objective: m[1].trim() };
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
export class ClaudeGoalSession extends EventEmitter {
|
|
78
|
+
host;
|
|
79
|
+
open;
|
|
80
|
+
_goal = null;
|
|
81
|
+
_lastError = null;
|
|
82
|
+
_turnActive = false;
|
|
83
|
+
_interrupting = false;
|
|
84
|
+
/** The CLI held the goal when the running (or last) turn started. */
|
|
85
|
+
_armed = false;
|
|
86
|
+
/** The CLI's notice that it ended the running turn over the Stop hook. */
|
|
87
|
+
_hookOverride = null;
|
|
88
|
+
_tokensAtOpen;
|
|
89
|
+
_budgetFrom = 0;
|
|
90
|
+
_turnStartedAt = null;
|
|
91
|
+
_timeUsed;
|
|
92
|
+
_seedTokens;
|
|
93
|
+
_onText = (...args) => this.emit(SESSION_EVENT.TEXT, ...args);
|
|
94
|
+
_onClose = (...args) => {
|
|
95
|
+
this._endTurn();
|
|
96
|
+
// What the dead process spent, so the node hands it to the one it reopens.
|
|
97
|
+
if (this._goal)
|
|
98
|
+
this.emit('goal:updated', this._snapshot());
|
|
99
|
+
this.emit(SESSION_EVENT.CLOSE, ...args);
|
|
100
|
+
};
|
|
101
|
+
/** `_settle` reading why the last turn ended; nothing else may probe meanwhile. */
|
|
102
|
+
_settling = null;
|
|
103
|
+
_onResult = (...args) => {
|
|
104
|
+
const settling = this._settle(args[0]).finally(() => {
|
|
105
|
+
if (this._settling === settling)
|
|
106
|
+
this._settling = null;
|
|
107
|
+
});
|
|
108
|
+
this._settling = settling;
|
|
109
|
+
};
|
|
110
|
+
_onSystem = (...args) => {
|
|
111
|
+
const e = args[0];
|
|
112
|
+
if (!this._turnActive || e?.subtype !== 'informational' || typeof e.content !== 'string')
|
|
113
|
+
return;
|
|
114
|
+
if (/blocked the turn from ending \d+ consecutive times/i.test(e.content))
|
|
115
|
+
this._hookOverride = e.content;
|
|
116
|
+
};
|
|
117
|
+
constructor(host, open = {}) {
|
|
118
|
+
super();
|
|
119
|
+
this.host = host;
|
|
120
|
+
this.open = open;
|
|
121
|
+
this._tokensAtOpen = this._sessionTokens();
|
|
122
|
+
this._seedTokens = open.tokensUsed ?? 0;
|
|
123
|
+
this._timeUsed = open.timeUsedSeconds ?? 0;
|
|
124
|
+
host.on(SESSION_EVENT.TEXT, this._onText);
|
|
125
|
+
host.on(SESSION_EVENT.CLOSE, this._onClose);
|
|
126
|
+
host.on(SESSION_EVENT.RESULT, this._onResult);
|
|
127
|
+
host.on(SESSION_EVENT.SYSTEM, this._onSystem);
|
|
128
|
+
}
|
|
129
|
+
/** Stop listening to the host. The session itself is the manager's to stop. */
|
|
130
|
+
detach() {
|
|
131
|
+
this.host.off(SESSION_EVENT.TEXT, this._onText);
|
|
132
|
+
this.host.off(SESSION_EVENT.CLOSE, this._onClose);
|
|
133
|
+
this.host.off(SESSION_EVENT.RESULT, this._onResult);
|
|
134
|
+
this.host.off(SESSION_EVENT.SYSTEM, this._onSystem);
|
|
135
|
+
}
|
|
136
|
+
/** The Claude session id. Named for the interface, which Codex defined. */
|
|
137
|
+
get codexThreadId() {
|
|
138
|
+
return this.host.sessionId || this.open.threadId;
|
|
139
|
+
}
|
|
140
|
+
get goal() {
|
|
141
|
+
return this._goal ? this._snapshot() : null;
|
|
142
|
+
}
|
|
143
|
+
get lastError() {
|
|
144
|
+
return this._lastError;
|
|
145
|
+
}
|
|
146
|
+
get turnActive() {
|
|
147
|
+
return this._turnActive;
|
|
148
|
+
}
|
|
149
|
+
async setGoal(p) {
|
|
150
|
+
if (p.objective !== undefined) {
|
|
151
|
+
this._goal = {
|
|
152
|
+
objective: p.objective,
|
|
153
|
+
status: 'active',
|
|
154
|
+
tokenBudget: p.tokenBudget ?? null,
|
|
155
|
+
tokensUsed: this._tokensUsed(),
|
|
156
|
+
timeUsedSeconds: this._seconds(),
|
|
157
|
+
};
|
|
158
|
+
this._budgetFrom = this._tokensUsed();
|
|
159
|
+
await this._startTurn(`/goal ${p.objective}`, true);
|
|
160
|
+
}
|
|
161
|
+
else if (p.status === 'paused') {
|
|
162
|
+
if (this._turnActive)
|
|
163
|
+
this._interrupt();
|
|
164
|
+
this._setStatus('paused');
|
|
165
|
+
}
|
|
166
|
+
else if (p.status === 'active') {
|
|
167
|
+
await this._settling;
|
|
168
|
+
if (!this._goal)
|
|
169
|
+
throw new Error('no goal to resume: set an objective first');
|
|
170
|
+
this._setStatus('active');
|
|
171
|
+
if (!this._turnActive) {
|
|
172
|
+
// A failed turn or a restart may have cost the CLI its goal: set it again rather than chat.
|
|
173
|
+
const probe = await this._probe();
|
|
174
|
+
if (probe?.active)
|
|
175
|
+
await this._startTurn(CLAUDE_GOAL_CONTINUE, true);
|
|
176
|
+
else
|
|
177
|
+
await this._startTurn(`/goal ${this._goal.objective}`, true);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return this._snapshot();
|
|
181
|
+
}
|
|
182
|
+
async getGoal() {
|
|
183
|
+
if (this._settling) {
|
|
184
|
+
// A turn just ended and its own probe decides the status: a second `/goal` would race it.
|
|
185
|
+
await this._settling;
|
|
186
|
+
return this._goal ? this._snapshot() : null;
|
|
187
|
+
}
|
|
188
|
+
if (this._turnActive) {
|
|
189
|
+
this._enforceBudget();
|
|
190
|
+
return this._snapshot();
|
|
191
|
+
}
|
|
192
|
+
const status = this._goal?.status;
|
|
193
|
+
if (status === 'complete' || status === 'budgetLimited' || status === 'blocked')
|
|
194
|
+
return this._snapshot();
|
|
195
|
+
const probe = await this._probe();
|
|
196
|
+
if (probe?.active) {
|
|
197
|
+
// Set, and nothing is working on it: a node that sees `paused` resumes it.
|
|
198
|
+
const keep = this._goal?.status === 'usageLimited' ? 'usageLimited' : 'paused';
|
|
199
|
+
this._goal = this._goal
|
|
200
|
+
? { ...this._goal, status: keep }
|
|
201
|
+
: {
|
|
202
|
+
objective: this.open.objective || probe.objective,
|
|
203
|
+
status: keep,
|
|
204
|
+
tokenBudget: null,
|
|
205
|
+
tokensUsed: 0,
|
|
206
|
+
timeUsedSeconds: 0,
|
|
207
|
+
};
|
|
208
|
+
this._budgetFrom = this._budgetFrom || this._tokensUsed();
|
|
209
|
+
}
|
|
210
|
+
else if (probe && !probe.active) {
|
|
211
|
+
// Gone, but not seen to be met (that is `_settle`'s call): met, or dropped by a failed turn.
|
|
212
|
+
// Paused, so resuming re-arms it; a goal already met then ends in one turn.
|
|
213
|
+
if (this._goal?.status === 'active') {
|
|
214
|
+
this._goal = { ...this._goal, status: 'paused' };
|
|
215
|
+
}
|
|
216
|
+
else if (!this._goal && this.open.resumed && this.open.objective) {
|
|
217
|
+
const objective = this.open.objective;
|
|
218
|
+
this._goal = { objective, status: 'paused', tokenBudget: null, tokensUsed: 0, timeUsedSeconds: 0 };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return this._goal ? this._snapshot() : null;
|
|
222
|
+
}
|
|
223
|
+
async clearGoal() {
|
|
224
|
+
if (this._turnActive)
|
|
225
|
+
this._interrupt();
|
|
226
|
+
await this.host.send('/goal clear', { waitForComplete: true, timeout: PROBE_TIMEOUT_MS }).catch(() => undefined);
|
|
227
|
+
this._goal = null;
|
|
228
|
+
}
|
|
229
|
+
async steer(text) {
|
|
230
|
+
if (!this._turnActive)
|
|
231
|
+
return { steered: false };
|
|
232
|
+
// A message written during a turn is folded into it by the CLI.
|
|
233
|
+
await this.host.send(text, { waitForComplete: false });
|
|
234
|
+
return { steered: true };
|
|
235
|
+
}
|
|
236
|
+
async interrupt() {
|
|
237
|
+
if (!this._turnActive)
|
|
238
|
+
return { interrupted: false };
|
|
239
|
+
return { interrupted: this._interrupt() };
|
|
240
|
+
}
|
|
241
|
+
// ─── Internals ─────────────────────────────────────────────────────────
|
|
242
|
+
_sessionTokens() {
|
|
243
|
+
try {
|
|
244
|
+
const s = this.host.getStats();
|
|
245
|
+
return (s.tokensIn || 0) + (s.tokensOut || 0) + (s.cachedTokens || 0);
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
_tokensUsed() {
|
|
252
|
+
return this._seedTokens + Math.max(0, this._sessionTokens() - this._tokensAtOpen);
|
|
253
|
+
}
|
|
254
|
+
_seconds() {
|
|
255
|
+
const running = this._turnStartedAt === null ? 0 : (Date.now() - this._turnStartedAt) / 1000;
|
|
256
|
+
return Math.round(this._timeUsed + running);
|
|
257
|
+
}
|
|
258
|
+
_snapshot() {
|
|
259
|
+
const g = this._goal;
|
|
260
|
+
return { ...g, tokensUsed: this._tokensUsed(), timeUsedSeconds: this._seconds() };
|
|
261
|
+
}
|
|
262
|
+
_setStatus(status) {
|
|
263
|
+
if (!this._goal || this._goal.status === status)
|
|
264
|
+
return;
|
|
265
|
+
this._goal = { ...this._goal, status };
|
|
266
|
+
this.emit('goal:updated', this._snapshot());
|
|
267
|
+
}
|
|
268
|
+
async _startTurn(text, armed) {
|
|
269
|
+
this._turnActive = true;
|
|
270
|
+
this._interrupting = false;
|
|
271
|
+
this._armed = armed;
|
|
272
|
+
this._hookOverride = null;
|
|
273
|
+
this._turnStartedAt = Date.now();
|
|
274
|
+
try {
|
|
275
|
+
await this.host.send(text, { waitForComplete: false });
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
this._endTurn();
|
|
279
|
+
this._fail(err.message, null);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
_endTurn() {
|
|
283
|
+
if (this._turnStartedAt !== null)
|
|
284
|
+
this._timeUsed += (Date.now() - this._turnStartedAt) / 1000;
|
|
285
|
+
this._turnStartedAt = null;
|
|
286
|
+
this._turnActive = false;
|
|
287
|
+
}
|
|
288
|
+
_interrupt() {
|
|
289
|
+
this._interrupting = true;
|
|
290
|
+
return this.host.interruptTurn();
|
|
291
|
+
}
|
|
292
|
+
_fail(message, code) {
|
|
293
|
+
this._lastError = { message, code, willRetry: false, at: new Date().toISOString() };
|
|
294
|
+
this.emit('codex:error', this._lastError);
|
|
295
|
+
}
|
|
296
|
+
/** Past its budget the goal stops, as Codex's does: `budgetLimited` is terminal. */
|
|
297
|
+
_enforceBudget() {
|
|
298
|
+
const budget = this._goal?.tokenBudget;
|
|
299
|
+
if (!budget || this._goal?.status !== 'active')
|
|
300
|
+
return;
|
|
301
|
+
if (this._tokensUsed() - this._budgetFrom < budget)
|
|
302
|
+
return;
|
|
303
|
+
if (this._turnActive)
|
|
304
|
+
this._interrupt();
|
|
305
|
+
this._setStatus('budgetLimited');
|
|
306
|
+
}
|
|
307
|
+
async _probe() {
|
|
308
|
+
try {
|
|
309
|
+
const r = (await this.host.send('/goal', { waitForComplete: true, timeout: PROBE_TIMEOUT_MS }));
|
|
310
|
+
return typeof r?.text === 'string' ? parseGoalProbe(r.text) : undefined;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/** A goal turn ended: read why, and what the goal is now. */
|
|
317
|
+
async _settle(event) {
|
|
318
|
+
if (!this._turnActive || !event)
|
|
319
|
+
return;
|
|
320
|
+
this._endTurn();
|
|
321
|
+
this.emit(SESSION_EVENT.RESULT, event);
|
|
322
|
+
const text = typeof event.result === 'string' ? event.result : '';
|
|
323
|
+
const failed = !!event.is_error || event.stop_reason === 'error' || String(event.subtype ?? '').startsWith('error');
|
|
324
|
+
if (this._interrupting) {
|
|
325
|
+
this._interrupting = false;
|
|
326
|
+
// A stop we asked for: pause and budget already set the status.
|
|
327
|
+
if (this._goal?.status === 'active')
|
|
328
|
+
this._setStatus('paused');
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (failed) {
|
|
332
|
+
// The CLI drops the goal with a failed turn; resuming re-arms it.
|
|
333
|
+
this._armed = false;
|
|
334
|
+
const code = classifyClaudeError(text, event.api_error_status);
|
|
335
|
+
this._fail(text || String(event.subtype ?? 'the turn failed'), code);
|
|
336
|
+
this._setStatus(code === 'usageLimitExceeded' ? 'usageLimited' : code === 'unauthorized' ? 'blocked' : 'paused');
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const armed = this._armed;
|
|
340
|
+
const probe = await this._probe();
|
|
341
|
+
this._enforceBudget();
|
|
342
|
+
if (this._goal?.status !== 'active')
|
|
343
|
+
return;
|
|
344
|
+
// Met: the goal was set when the turn started, the turn ended cleanly, and the CLI cleared it.
|
|
345
|
+
if (armed && probe && !probe.active)
|
|
346
|
+
this._setStatus('complete');
|
|
347
|
+
else if (probe?.active && this._hookOverride) {
|
|
348
|
+
this._fail(this._hookOverride, null);
|
|
349
|
+
this._setStatus('blocked');
|
|
350
|
+
}
|
|
351
|
+
else
|
|
352
|
+
this._setStatus('paused');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
//# sourceMappingURL=claude-goal-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-goal-session.js","sourceRoot":"","sources":["../../src/claude-goal-session.ts"],"names":[],"mappings":"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"}
|
package/dist/src/council.d.ts
CHANGED
|
@@ -38,6 +38,12 @@ interface SessionManagerLike {
|
|
|
38
38
|
* `split(/\s+/)[0]` truncates any path containing a space.
|
|
39
39
|
*/
|
|
40
40
|
export declare function councilWorktreePaths(projectDir: string): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* The package this module belongs to: the nearest directory above it holding a
|
|
43
|
+
* package.json. A fixed `..` is right from `src/` but lands on `dist/` from the
|
|
44
|
+
* built `dist/src/`, which would leave the package root itself unguarded.
|
|
45
|
+
*/
|
|
46
|
+
export declare function programRoot(moduleFile?: string): string;
|
|
41
47
|
export declare class Council extends EventEmitter {
|
|
42
48
|
private config;
|
|
43
49
|
private manager;
|
|
@@ -60,6 +66,8 @@ export declare class Council extends EventEmitter {
|
|
|
60
66
|
* from a rebuilt session. This is what lets them run after a restart, which
|
|
61
67
|
* the in-memory registry made impossible.
|
|
62
68
|
*/
|
|
69
|
+
/** Add one send's cost to the council's total. */
|
|
70
|
+
private _charge;
|
|
63
71
|
adoptSession(session: CouncilSession): void;
|
|
64
72
|
getSession(): CouncilSession | undefined;
|
|
65
73
|
injectMessage(message: string): void;
|
package/dist/src/council.js
CHANGED
|
@@ -127,17 +127,26 @@ async function setupWorktrees(projectDir, agents, logger) {
|
|
|
127
127
|
if (!isGit) {
|
|
128
128
|
await spawnAsync('git', ['-C', projectDir, 'init'], { timeout: GIT_CMD_TIMEOUT_MS });
|
|
129
129
|
}
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
130
|
+
// Commits here (and the agents' own, in the worktrees) need an identity. Only
|
|
131
|
+
// a missing one is filled in: `.git/config` belongs to the user and outlives
|
|
132
|
+
// the council, so an identity they configured at any level is left alone.
|
|
133
|
+
for (const [key, value] of [
|
|
134
|
+
['user.email', 'council@openclaw'],
|
|
135
|
+
['user.name', 'Council'],
|
|
136
|
+
]) {
|
|
137
|
+
const configured = await spawnAsync('git', ['-C', projectDir, 'config', '--get', key], {
|
|
138
|
+
timeout: GIT_CMD_TIMEOUT_MS,
|
|
139
|
+
})
|
|
140
|
+
.then((r) => r.stdout.trim().length > 0)
|
|
141
|
+
.catch(() => false);
|
|
142
|
+
if (configured)
|
|
143
|
+
continue;
|
|
144
|
+
await spawnAsync('git', ['-C', projectDir, 'config', '--local', key, value], {
|
|
145
|
+
timeout: GIT_CMD_TIMEOUT_MS,
|
|
146
|
+
}).catch((err) => {
|
|
147
|
+
log.error(`Failed to set git ${key}:`, err.message);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
141
150
|
// Ensure at least one commit
|
|
142
151
|
const hasCommit = await spawnAsync('git', ['-C', projectDir, 'rev-parse', 'HEAD'], { timeout: GIT_CMD_TIMEOUT_MS })
|
|
143
152
|
.then(() => true)
|
|
@@ -288,6 +297,22 @@ Collaboration ends **only when all members vote YES**.
|
|
|
288
297
|
|
|
289
298
|
Start working!`;
|
|
290
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* The package this module belongs to: the nearest directory above it holding a
|
|
302
|
+
* package.json. A fixed `..` is right from `src/` but lands on `dist/` from the
|
|
303
|
+
* built `dist/src/`, which would leave the package root itself unguarded.
|
|
304
|
+
*/
|
|
305
|
+
export function programRoot(moduleFile = fileURLToPath(import.meta.url)) {
|
|
306
|
+
let dir = path.dirname(moduleFile);
|
|
307
|
+
for (;;) {
|
|
308
|
+
if (fs.existsSync(path.join(dir, 'package.json')))
|
|
309
|
+
return dir;
|
|
310
|
+
const parent = path.dirname(dir);
|
|
311
|
+
if (parent === dir)
|
|
312
|
+
return path.resolve(path.dirname(moduleFile), '..');
|
|
313
|
+
dir = parent;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
291
316
|
/** Resolve the path to configs/ relative to this module (works from both src/ and dist/) */
|
|
292
317
|
function resolveConfigPath(filename) {
|
|
293
318
|
const filePath = fileURLToPath(import.meta.url);
|
|
@@ -352,6 +377,11 @@ export class Council extends EventEmitter {
|
|
|
352
377
|
* from a rebuilt session. This is what lets them run after a restart, which
|
|
353
378
|
* the in-memory registry made impossible.
|
|
354
379
|
*/
|
|
380
|
+
/** Add one send's cost to the council's total. */
|
|
381
|
+
_charge(result) {
|
|
382
|
+
if (this._session && result.usage)
|
|
383
|
+
this._session.costUsd = (this._session.costUsd ?? 0) + result.usage.costUsd;
|
|
384
|
+
}
|
|
355
385
|
adoptSession(session) {
|
|
356
386
|
this._session = session;
|
|
357
387
|
}
|
|
@@ -420,6 +450,7 @@ export class Council extends EventEmitter {
|
|
|
420
450
|
maxTurns: this.config.maxTurnsPerAgent || DEFAULT_MAX_TURNS_PER_AGENT,
|
|
421
451
|
maxBudgetUsd: this.config.maxBudgetUsd,
|
|
422
452
|
customEngine: agent.customEngine,
|
|
453
|
+
...(agent.acpAgent === undefined ? {} : { acpAgent: agent.acpAgent }),
|
|
423
454
|
effort: agent.effort,
|
|
424
455
|
ultracode: agent.ultracode,
|
|
425
456
|
});
|
|
@@ -431,6 +462,7 @@ export class Council extends EventEmitter {
|
|
|
431
462
|
this.emitEvent({ type: 'agent-chunk', sessionId, round, agent: agent.name, content: chunk });
|
|
432
463
|
},
|
|
433
464
|
});
|
|
465
|
+
this._charge(result);
|
|
434
466
|
content = result.output;
|
|
435
467
|
// Check if response is substantive
|
|
436
468
|
const stripped = content.replace(/^\[Agent completed[^\]]*\]\s*/i, '').trim();
|
|
@@ -448,6 +480,7 @@ export class Council extends EventEmitter {
|
|
|
448
480
|
break;
|
|
449
481
|
try {
|
|
450
482
|
const followup = await this.manager.sendMessage(sessionName, 'Stop all tool calls. Output your complete report now, including your consensus vote [CONSENSUS: YES] or [CONSENSUS: NO].', { timeout: FOLLOWUP_TIMEOUT_MS, parentRunId: sessionId });
|
|
483
|
+
this._charge(followup);
|
|
451
484
|
if (followup.output.trim().length > 0) {
|
|
452
485
|
content = followup.output;
|
|
453
486
|
if (hasConsensusMarker(content) || content.length >= MIN_COMPLETE_RESPONSE_LENGTH)
|
|
@@ -509,7 +542,7 @@ export class Council extends EventEmitter {
|
|
|
509
542
|
throw new Error('Council not initialised — call init() first');
|
|
510
543
|
const trimmedTask = session.task;
|
|
511
544
|
// Safety check: prevent council from running inside the program's own directory
|
|
512
|
-
const moduleRoot =
|
|
545
|
+
const moduleRoot = programRoot();
|
|
513
546
|
const resolvedProjectDir = path.resolve(this.config.projectDir);
|
|
514
547
|
const rel = path.relative(moduleRoot, resolvedProjectDir);
|
|
515
548
|
const isInside = rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
|