@enderfga/claw-orchestrator 3.4.2 → 3.5.5

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 (46) hide show
  1. package/README.md +9 -9
  2. package/configs/autoloop-coder-prompt.md +59 -0
  3. package/configs/autoloop-planner-prompt.md +136 -0
  4. package/configs/autoloop-reviewer-prompt.md +76 -0
  5. package/dist/src/autoloop/agent-tools.d.ts +44 -0
  6. package/dist/src/autoloop/agent-tools.js +71 -0
  7. package/dist/src/autoloop/agent-tools.js.map +1 -0
  8. package/dist/src/autoloop/dispatcher.d.ts +137 -0
  9. package/dist/src/autoloop/dispatcher.js +580 -0
  10. package/dist/src/autoloop/dispatcher.js.map +1 -0
  11. package/dist/src/autoloop/messages.d.ts +114 -0
  12. package/dist/src/autoloop/messages.js +92 -0
  13. package/dist/src/autoloop/messages.js.map +1 -0
  14. package/dist/src/autoloop/notify.d.ts +36 -0
  15. package/dist/src/autoloop/notify.js +166 -0
  16. package/dist/src/autoloop/notify.js.map +1 -0
  17. package/dist/src/autoloop/planner-tools.d.ts +81 -0
  18. package/dist/src/autoloop/planner-tools.js +140 -0
  19. package/dist/src/autoloop/planner-tools.js.map +1 -0
  20. package/dist/src/autoloop/runner.d.ts +48 -0
  21. package/dist/src/autoloop/runner.js +214 -0
  22. package/dist/src/autoloop/runner.js.map +1 -0
  23. package/dist/src/autoloop/types.d.ts +69 -0
  24. package/dist/src/autoloop/types.js +16 -0
  25. package/dist/src/autoloop/types.js.map +1 -0
  26. package/dist/src/dashboard/index.html +910 -0
  27. package/dist/src/embedded-server.js +173 -32
  28. package/dist/src/embedded-server.js.map +1 -1
  29. package/dist/src/index.d.ts +5 -2
  30. package/dist/src/index.js +67 -105
  31. package/dist/src/index.js.map +1 -1
  32. package/dist/src/session-manager.d.ts +47 -14
  33. package/dist/src/session-manager.js +135 -47
  34. package/dist/src/session-manager.js.map +1 -1
  35. package/package.json +2 -2
  36. package/skills/references/autoloop.md +176 -193
  37. package/configs/autoloop-bootstrap-prompt.md +0 -30
  38. package/configs/autoloop-compress-prompt.md +0 -50
  39. package/configs/autoloop-propose-prompt.md +0 -57
  40. package/configs/autoloop-ratchet-prompt.md +0 -56
  41. package/dist/src/autoloop-types.d.ts +0 -218
  42. package/dist/src/autoloop-types.js +0 -130
  43. package/dist/src/autoloop-types.js.map +0 -1
  44. package/dist/src/autoloop.d.ts +0 -70
  45. package/dist/src/autoloop.js +0 -910
  46. package/dist/src/autoloop.js.map +0 -1
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Autoloop — thin orchestrator.
3
+ *
4
+ * Pure transport: validates messages, dispatches to agents, handles the
5
+ * tiny set of runner-self-targeted messages (iter_artifacts, review_verdict,
6
+ * pause/resume/terminate, push_user). No LLM logic lives here — that's the
7
+ * AgentDispatcher's job (S2-S4 will plug in real Claude sessions; S1 ships
8
+ * with a mock dispatcher used by tests).
9
+ *
10
+ * Contract: tasks/autoloop.md §3.4 (phase machine lives inside Coder/Reviewer
11
+ * dispatchers, not here).
12
+ */
13
+ import { EventEmitter } from 'node:events';
14
+ import { type AnyAutoloopMessage } from './messages.js';
15
+ import { type AutoloopConfig, type AutoloopState } from './types.js';
16
+ /**
17
+ * Events emitted by the runner (string keys, documented payloads):
18
+ * - 'message' : (env: AnyAutoloopMessage) — every routed message
19
+ * - 'state' : (state: AutoloopState) — status / iter changes
20
+ * - 'push' : ({ level, summary, detail?, channel }) — fired before notifyUser
21
+ * - 'iter_done' : ({ iter, verdict, metric }) — Reviewer verdict committed
22
+ * - 'terminated' : (reason: string) — final state, no more messages
23
+ * - 'error' : (err: Error) — routing or dispatcher errors
24
+ */
25
+ export declare class AutoloopRunner extends EventEmitter {
26
+ readonly config: AutoloopConfig;
27
+ state: AutoloopState;
28
+ /** Queue of messages awaiting routing. Drained by the active dispatch loop. */
29
+ private queue;
30
+ private draining;
31
+ private regressionStreak;
32
+ private rejectStreak;
33
+ /** Recent push events for dedup (5 min window). */
34
+ private recentPushes;
35
+ constructor(config: AutoloopConfig);
36
+ start(): Promise<void>;
37
+ /** Enqueue a message and drain the queue. Resolves when the queue is idle. */
38
+ send(env: AnyAutoloopMessage): Promise<void>;
39
+ /** External entry: user typed something to Planner. */
40
+ chat(text: string): Promise<void>;
41
+ /** Mark subagents spawned (called by S3's spawn_subagents tool handler). */
42
+ markSubagentsSpawned(): void;
43
+ private drain;
44
+ private handleOne;
45
+ private handleRunnerInbox;
46
+ private handlePushUser;
47
+ private firePolicyPush;
48
+ }
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Autoloop — thin orchestrator.
3
+ *
4
+ * Pure transport: validates messages, dispatches to agents, handles the
5
+ * tiny set of runner-self-targeted messages (iter_artifacts, review_verdict,
6
+ * pause/resume/terminate, push_user). No LLM logic lives here — that's the
7
+ * AgentDispatcher's job (S2-S4 will plug in real Claude sessions; S1 ships
8
+ * with a mock dispatcher used by tests).
9
+ *
10
+ * Contract: tasks/autoloop.md §3.4 (phase machine lives inside Coder/Reviewer
11
+ * dispatchers, not here).
12
+ */
13
+ import { EventEmitter } from 'node:events';
14
+ import { AutoloopRoutingError, Msg, validateMessage } from './messages.js';
15
+ import { DEFAULT_PUSH_POLICY } from './types.js';
16
+ const MAX_DISPATCH_DEPTH = 64;
17
+ /**
18
+ * Events emitted by the runner (string keys, documented payloads):
19
+ * - 'message' : (env: AnyAutoloopMessage) — every routed message
20
+ * - 'state' : (state: AutoloopState) — status / iter changes
21
+ * - 'push' : ({ level, summary, detail?, channel }) — fired before notifyUser
22
+ * - 'iter_done' : ({ iter, verdict, metric }) — Reviewer verdict committed
23
+ * - 'terminated' : (reason: string) — final state, no more messages
24
+ * - 'error' : (err: Error) — routing or dispatcher errors
25
+ */
26
+ export class AutoloopRunner extends EventEmitter {
27
+ config;
28
+ state;
29
+ /** Queue of messages awaiting routing. Drained by the active dispatch loop. */
30
+ queue = [];
31
+ draining = false;
32
+ regressionStreak = 0;
33
+ rejectStreak = 0;
34
+ /** Recent push events for dedup (5 min window). */
35
+ recentPushes = [];
36
+ constructor(config) {
37
+ super();
38
+ this.config = config;
39
+ this.state = {
40
+ run_id: config.run_id,
41
+ status: 'planning',
42
+ iter: 0,
43
+ subagents_spawned: false,
44
+ started_at: new Date().toISOString(),
45
+ workspace: config.workspace,
46
+ ledger_dir: config.ledger_dir,
47
+ push_log_count: 0,
48
+ status_reason: null,
49
+ };
50
+ }
51
+ async start() {
52
+ await this.config.dispatcher.init?.(this.state);
53
+ // Surface initial state so listeners can render the planning UI.
54
+ this.emit('state', this.state);
55
+ }
56
+ /** Enqueue a message and drain the queue. Resolves when the queue is idle. */
57
+ async send(env) {
58
+ validateMessage(env);
59
+ this.queue.push(env);
60
+ await this.drain();
61
+ }
62
+ /** External entry: user typed something to Planner. */
63
+ chat(text) {
64
+ return this.send(Msg.chat(this.state.iter, { text }));
65
+ }
66
+ /** Mark subagents spawned (called by S3's spawn_subagents tool handler). */
67
+ markSubagentsSpawned() {
68
+ if (this.state.subagents_spawned)
69
+ return;
70
+ this.state.subagents_spawned = true;
71
+ this.state.status = 'running';
72
+ this.emit('state', this.state);
73
+ }
74
+ // ─── Drain loop ────────────────────────────────────────────────────────────
75
+ async drain() {
76
+ if (this.draining)
77
+ return; // a previous send() is already draining; new items will be picked up
78
+ this.draining = true;
79
+ try {
80
+ let depth = 0;
81
+ while (this.queue.length > 0) {
82
+ if (depth++ > MAX_DISPATCH_DEPTH) {
83
+ throw new AutoloopRoutingError(`dispatch depth exceeded ${MAX_DISPATCH_DEPTH} — likely message ping-pong`);
84
+ }
85
+ const env = this.queue.shift();
86
+ if (!env)
87
+ break;
88
+ await this.handleOne(env);
89
+ }
90
+ }
91
+ finally {
92
+ this.draining = false;
93
+ }
94
+ }
95
+ async handleOne(env) {
96
+ this.emit('message', env);
97
+ // Runner is the target for a small set of messages — handle them inline.
98
+ if (env.to === 'runner') {
99
+ await this.handleRunnerInbox(env);
100
+ return;
101
+ }
102
+ // user → planner: forward to dispatcher.
103
+ // user is not a real agent; we don't dispatch to it, we consume `push_user`.
104
+ if (env.to === 'user') {
105
+ await this.handlePushUser(env);
106
+ return;
107
+ }
108
+ // Everything else goes to the agent dispatcher.
109
+ if (this.state.status === 'terminated')
110
+ return;
111
+ const replies = await this.config.dispatcher.deliver(env);
112
+ for (const r of replies) {
113
+ validateMessage(r);
114
+ this.queue.push(r);
115
+ }
116
+ }
117
+ async handleRunnerInbox(env) {
118
+ switch (env.type) {
119
+ case 'iter_artifacts': {
120
+ // Coder produced work for iter N; ask Reviewer to audit.
121
+ const req = Msg.reviewRequest(env.iter, {
122
+ iter: env.iter,
123
+ ledger_path: this.config.ledger_dir,
124
+ prior_metrics: [], // S4 will populate from metric.json
125
+ });
126
+ this.queue.push(req);
127
+ return;
128
+ }
129
+ case 'review_verdict': {
130
+ const v = env.payload;
131
+ const regression = v.decision === 'rollback';
132
+ if (v.decision === 'hold' || v.decision === 'rollback') {
133
+ this.rejectStreak++;
134
+ }
135
+ else {
136
+ this.rejectStreak = 0;
137
+ }
138
+ if (regression)
139
+ this.regressionStreak++;
140
+ else
141
+ this.regressionStreak = 0;
142
+ const done = Msg.iterDone(env.iter, {
143
+ iter: env.iter,
144
+ verdict: v.decision,
145
+ metric: v.metric,
146
+ regression,
147
+ });
148
+ this.queue.push(done);
149
+ this.emit('iter_done', { iter: env.iter, verdict: v.decision, metric: v.metric });
150
+ // Trigger policy-based push hooks.
151
+ if (this.regressionStreak >= 2)
152
+ await this.firePolicyPush('on_metric_regression_2', env.iter);
153
+ if (this.rejectStreak >= 2)
154
+ await this.firePolicyPush('on_reviewer_reject_2', env.iter);
155
+ return;
156
+ }
157
+ case 'pause': {
158
+ this.state.status = 'paused';
159
+ this.state.status_reason = env.payload.reason;
160
+ this.emit('state', this.state);
161
+ return;
162
+ }
163
+ case 'resume': {
164
+ if (this.state.status === 'paused') {
165
+ this.state.status = 'running';
166
+ this.state.status_reason = null;
167
+ this.emit('state', this.state);
168
+ }
169
+ return;
170
+ }
171
+ case 'terminate': {
172
+ this.state.status = 'terminated';
173
+ this.state.status_reason = env.payload.reason;
174
+ this.emit('state', this.state);
175
+ await this.config.dispatcher.shutdown?.(env.payload.reason);
176
+ this.emit('terminated', env.payload.reason);
177
+ return;
178
+ }
179
+ default:
180
+ // review_request / iter_done etc. arriving with to=runner is a routing bug.
181
+ throw new AutoloopRoutingError(`Unexpected runner-targeted message type: ${env.type}`, env);
182
+ }
183
+ }
184
+ async handlePushUser(env) {
185
+ if (env.type !== 'push_user')
186
+ return;
187
+ const p = env.payload;
188
+ const key = `${p.level}:${p.summary}`;
189
+ const now = Date.now();
190
+ // 5 min dedup
191
+ this.recentPushes = this.recentPushes.filter((r) => now - r.ts < 5 * 60_000);
192
+ if (this.recentPushes.some((r) => r.key === key))
193
+ return;
194
+ this.recentPushes.push({ key, ts: now });
195
+ this.state.push_log_count++;
196
+ this.emit('push', { level: p.level, summary: p.summary, detail: p.detail, channel: p.channel });
197
+ await this.config.notifyUser(p.level, p.summary, p.detail, p.channel);
198
+ }
199
+ async firePolicyPush(rule, iter) {
200
+ const policy = this.config.push_policy ?? DEFAULT_PUSH_POLICY;
201
+ const r = policy[rule];
202
+ if (!r || r.silent)
203
+ return;
204
+ const summary = `[${rule}] iter ${iter}`;
205
+ // We synthesise a push_user envelope as if Planner had asked for it, so
206
+ // dedup + push_log book-keeping go through the same path.
207
+ this.queue.push(Msg.pushUser(iter, {
208
+ level: r.level ?? 'info',
209
+ summary,
210
+ channel: r.channel ?? 'auto',
211
+ }));
212
+ }
213
+ }
214
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/autoloop/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Runner-level types for autoloop (three-agent architecture).
3
+ *
4
+ * Contract: tasks/autoloop.md.
5
+ */
6
+ import type { AnyAutoloopMessage, PushChannel, PushLevel } from './messages.js';
7
+ export type AutoloopStatus = 'planning' | 'running' | 'paused' | 'terminated' | 'crashed';
8
+ export interface AutoloopState {
9
+ run_id: string;
10
+ status: AutoloopStatus;
11
+ iter: number;
12
+ /** Set once Planner calls `spawn_subagents`. Until then we are in "planning" mode. */
13
+ subagents_spawned: boolean;
14
+ started_at: string;
15
+ workspace: string;
16
+ ledger_dir: string;
17
+ push_log_count: number;
18
+ /** Last reason set when status flips to terminated/crashed/paused. */
19
+ status_reason: string | null;
20
+ }
21
+ export interface PushPolicyRule {
22
+ silent?: boolean;
23
+ level?: PushLevel;
24
+ channel?: PushChannel;
25
+ }
26
+ export interface PushPolicy {
27
+ on_start: PushPolicyRule;
28
+ on_iter_done_ok: PushPolicyRule;
29
+ on_target_hit: PushPolicyRule;
30
+ on_metric_regression_2: PushPolicyRule;
31
+ on_reviewer_reject_2: PushPolicyRule;
32
+ on_phase_error: PushPolicyRule;
33
+ on_stall_30min: PushPolicyRule;
34
+ on_decision_needed: PushPolicyRule;
35
+ }
36
+ export declare const DEFAULT_PUSH_POLICY: PushPolicy;
37
+ /**
38
+ * Pluggable agent layer. The runner stays transport-only; an AgentDispatcher
39
+ * implementation owns the actual Claude (or mock) sessions and turns inbound
40
+ * messages into outbound replies. S2/S3/S4 swap mocks for real persistent
41
+ * sessions; the runner contract stays the same.
42
+ */
43
+ export interface AgentDispatcher {
44
+ /**
45
+ * Deliver `env` to its target agent and return any messages the agent emits
46
+ * synchronously in reply. Asynchronous emissions should also be returned
47
+ * (the runner awaits this call).
48
+ */
49
+ deliver(env: AnyAutoloopMessage): Promise<AnyAutoloopMessage[]>;
50
+ /** Called once when the runner is starting up — agent may pre-warm sessions. */
51
+ init?(state: AutoloopState): Promise<void>;
52
+ /** Called on terminate — agent must release sessions cleanly. */
53
+ shutdown?(reason: string): Promise<void>;
54
+ }
55
+ export interface AutoloopConfig {
56
+ run_id: string;
57
+ workspace: string;
58
+ ledger_dir: string;
59
+ /** Optional override; defaults to DEFAULT_PUSH_POLICY. */
60
+ push_policy?: PushPolicy;
61
+ /**
62
+ * Notifier the runner calls when a `push_user` message arrives.
63
+ * S3 will plug in the wechat→whatsapp→email fallback chain; S1/S2 use
64
+ * a recording stub.
65
+ */
66
+ notifyUser: (level: PushLevel, summary: string, detail: string | undefined, channel: PushChannel) => Promise<void>;
67
+ /** Agent transport layer (mockable). */
68
+ dispatcher: AgentDispatcher;
69
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Runner-level types for autoloop (three-agent architecture).
3
+ *
4
+ * Contract: tasks/autoloop.md.
5
+ */
6
+ export const DEFAULT_PUSH_POLICY = {
7
+ on_start: { level: 'info', channel: 'wechat' },
8
+ on_iter_done_ok: { silent: true },
9
+ on_target_hit: { level: 'info', channel: 'both' },
10
+ on_metric_regression_2: { level: 'warn', channel: 'both' },
11
+ on_reviewer_reject_2: { level: 'warn', channel: 'both' },
12
+ on_phase_error: { level: 'error', channel: 'both' },
13
+ on_stall_30min: { level: 'warn', channel: 'wechat' },
14
+ on_decision_needed: { level: 'decision', channel: 'both' },
15
+ };
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/autoloop/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqCH,MAAM,CAAC,MAAM,mBAAmB,GAAe;IAC7C,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;IAC9C,eAAe,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IACjC,aAAa,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;IACjD,sBAAsB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;IAC1D,oBAAoB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;IACxD,cAAc,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE;IACnD,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;IACpD,kBAAkB,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE;CAC3D,CAAC"}