@enderfga/claw-orchestrator 4.1.2 → 4.4.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.
Files changed (61) hide show
  1. package/README.md +11 -7
  2. package/dist/src/autoloop/dispatcher.js +28 -4
  3. package/dist/src/autoloop/dispatcher.js.map +1 -1
  4. package/dist/src/autoloop/messages.js +16 -3
  5. package/dist/src/autoloop/messages.js.map +1 -1
  6. package/dist/src/autoloop/runner.js +24 -5
  7. package/dist/src/autoloop/runner.js.map +1 -1
  8. package/dist/src/autoloop/types.d.ts +6 -0
  9. package/dist/src/consensus.d.ts +9 -0
  10. package/dist/src/consensus.js +11 -3
  11. package/dist/src/consensus.js.map +1 -1
  12. package/dist/src/council.d.ts +3 -0
  13. package/dist/src/council.js +26 -2
  14. package/dist/src/council.js.map +1 -1
  15. package/dist/src/embedded-server.js +64 -6
  16. package/dist/src/embedded-server.js.map +1 -1
  17. package/dist/src/fanout.d.ts +81 -0
  18. package/dist/src/fanout.js +146 -0
  19. package/dist/src/fanout.js.map +1 -0
  20. package/dist/src/inbox-manager.js +6 -1
  21. package/dist/src/inbox-manager.js.map +1 -1
  22. package/dist/src/index.js +214 -4
  23. package/dist/src/index.js.map +1 -1
  24. package/dist/src/openai-compat.js +7 -1
  25. package/dist/src/openai-compat.js.map +1 -1
  26. package/dist/src/persistent-codex-app-session.d.ts +34 -0
  27. package/dist/src/persistent-codex-app-session.js +112 -3
  28. package/dist/src/persistent-codex-app-session.js.map +1 -1
  29. package/dist/src/persistent-codex-session.d.ts +8 -0
  30. package/dist/src/persistent-codex-session.js +39 -2
  31. package/dist/src/persistent-codex-session.js.map +1 -1
  32. package/dist/src/persistent-custom-session.js +31 -5
  33. package/dist/src/persistent-custom-session.js.map +1 -1
  34. package/dist/src/persistent-opencode-session.js +3 -1
  35. package/dist/src/persistent-opencode-session.js.map +1 -1
  36. package/dist/src/persistent-session.d.ts +8 -0
  37. package/dist/src/persistent-session.js +69 -8
  38. package/dist/src/persistent-session.js.map +1 -1
  39. package/dist/src/proxy/anthropic-adapter.js +9 -2
  40. package/dist/src/proxy/anthropic-adapter.js.map +1 -1
  41. package/dist/src/proxy/handler.d.ts +3 -0
  42. package/dist/src/proxy/handler.js +5 -1
  43. package/dist/src/proxy/handler.js.map +1 -1
  44. package/dist/src/session-manager.d.ts +63 -0
  45. package/dist/src/session-manager.js +265 -38
  46. package/dist/src/session-manager.js.map +1 -1
  47. package/dist/src/types.d.ts +18 -1
  48. package/dist/src/ultraapp/fix-on-failure-session.js +4 -1
  49. package/dist/src/ultraapp/fix-on-failure-session.js.map +1 -1
  50. package/dist/src/ultraapp/fix-on-failure.js +9 -2
  51. package/dist/src/ultraapp/fix-on-failure.js.map +1 -1
  52. package/dist/src/ultraapp/json-patch.js.map +1 -1
  53. package/dist/src/ultraapp/patcher.js +23 -3
  54. package/dist/src/ultraapp/patcher.js.map +1 -1
  55. package/openclaw.plugin.json +10 -0
  56. package/package.json +2 -2
  57. package/skills/SKILL.md +9 -3
  58. package/skills/references/claude-cli-tracking.md +3 -1
  59. package/skills/references/multi-engine.md +10 -5
  60. package/skills/references/sessions.md +18 -0
  61. package/skills/references/tools.md +63 -1
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Fan-out — run one task across N engines/models in parallel and collect the
3
+ * results, with an optional synthesis pass.
4
+ *
5
+ * This is the cross-engine "diverse perspectives / best-of-N" primitive: each
6
+ * agent runs in its own session (any engine) against the shared projectDir and
7
+ * returns an answer. Unlike `council`, there is no consensus voting, no rounds,
8
+ * and no git-worktree isolation — so it is intended for analysis/generation
9
+ * that returns text (review from N angles, best-of-N drafts), NOT parallel file
10
+ * edits. For isolated parallel editing use `council` (per-agent worktrees).
11
+ */
12
+ import { randomUUID } from 'node:crypto';
13
+ const DEFAULT_AGENT_TIMEOUT_MS = 600_000;
14
+ const DEFAULT_MAX_TURNS = 30;
15
+ export class Fanout {
16
+ config;
17
+ manager;
18
+ logger;
19
+ session;
20
+ _aborted = false;
21
+ constructor(config, manager, logger) {
22
+ this.config = config;
23
+ this.manager = manager;
24
+ this.logger = logger;
25
+ this.session = {
26
+ id: `fanout-${randomUUID().slice(0, 8)}`,
27
+ status: 'running',
28
+ task: config.task,
29
+ agentCount: config.agents.length,
30
+ startedAt: new Date().toISOString(),
31
+ results: [],
32
+ };
33
+ }
34
+ init() {
35
+ return this.session;
36
+ }
37
+ getSession() {
38
+ return this.session;
39
+ }
40
+ abort() {
41
+ this._aborted = true;
42
+ this.session.status = 'aborted';
43
+ }
44
+ async run() {
45
+ try {
46
+ // Each agent isolates its own failure (never throws); collect all.
47
+ this.session.results = await Promise.all(this.config.agents.map((a) => this._runAgent(a)));
48
+ if (!this._aborted && this.config.synthesize) {
49
+ const ok = this.session.results.filter((r) => r.ok);
50
+ if (ok.length >= 2)
51
+ this.session.synthesis = await this._synthesize(ok);
52
+ }
53
+ if (!this._aborted) {
54
+ this.session.status = 'done';
55
+ this.session.finishedAt = new Date().toISOString();
56
+ }
57
+ }
58
+ catch (err) {
59
+ this.session.status = 'error';
60
+ this.session.error = err.message;
61
+ this.session.finishedAt = new Date().toISOString();
62
+ }
63
+ return this.session;
64
+ }
65
+ async _runAgent(spec) {
66
+ const engine = spec.engine || 'claude';
67
+ const sessionName = `${this.session.id}-${spec.name}`;
68
+ const start = Date.now();
69
+ try {
70
+ await this.manager.startSession({
71
+ name: sessionName,
72
+ cwd: this.config.projectDir,
73
+ engine,
74
+ model: spec.model,
75
+ baseUrl: spec.baseUrl,
76
+ permissionMode: spec.permissionMode ?? 'bypassPermissions',
77
+ maxTurns: this.config.maxTurnsPerAgent ?? DEFAULT_MAX_TURNS,
78
+ maxBudgetUsd: this.config.maxBudgetUsd,
79
+ customEngine: spec.customEngine,
80
+ });
81
+ const result = await this.manager.sendMessage(sessionName, spec.prompt || this.config.task, {
82
+ timeout: this.config.agentTimeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS,
83
+ });
84
+ return {
85
+ agent: spec.name,
86
+ engine,
87
+ model: spec.model,
88
+ ok: true,
89
+ output: result.output,
90
+ durationMs: Date.now() - start,
91
+ };
92
+ }
93
+ catch (err) {
94
+ return {
95
+ agent: spec.name,
96
+ engine,
97
+ model: spec.model,
98
+ ok: false,
99
+ output: '',
100
+ error: err.message,
101
+ durationMs: Date.now() - start,
102
+ };
103
+ }
104
+ finally {
105
+ await this.manager.stopSession(sessionName).catch(() => {
106
+ // Best-effort cleanup; a dead session is fine to ignore.
107
+ });
108
+ }
109
+ }
110
+ async _synthesize(results) {
111
+ const sessionName = `${this.session.id}-synthesis`;
112
+ const combined = results
113
+ .map((r, i) => `### Response ${i + 1} — ${r.agent} (${r.engine}${r.model ? `/${r.model}` : ''})\n\n${r.output}`)
114
+ .join('\n\n---\n\n');
115
+ const prompt = `You are synthesizing ${results.length} independent responses to the same task. Produce one ` +
116
+ `consolidated best answer: reconcile agreements, note meaningful disagreements, and keep the ` +
117
+ `strongest ideas from each.\n\nTask:\n${this.config.task}\n\nResponses:\n\n${combined}`;
118
+ try {
119
+ await this.manager.startSession({
120
+ name: sessionName,
121
+ cwd: this.config.projectDir,
122
+ engine: this.config.synthesisEngine || 'claude',
123
+ model: this.config.synthesisModel,
124
+ permissionMode: 'bypassPermissions',
125
+ maxTurns: this.config.maxTurnsPerAgent ?? DEFAULT_MAX_TURNS,
126
+ maxBudgetUsd: this.config.maxBudgetUsd,
127
+ });
128
+ const result = await this.manager.sendMessage(sessionName, prompt, {
129
+ timeout: this.config.agentTimeoutMs ?? DEFAULT_AGENT_TIMEOUT_MS,
130
+ });
131
+ return result.output;
132
+ }
133
+ catch (err) {
134
+ const msg = err.message;
135
+ this.session.synthesisError = msg;
136
+ this.logger?.error?.(`Fanout synthesis failed: ${msg}`);
137
+ return undefined;
138
+ }
139
+ finally {
140
+ await this.manager.stopSession(sessionName).catch(() => {
141
+ // Best-effort cleanup.
142
+ });
143
+ }
144
+ }
145
+ }
146
+ //# sourceMappingURL=fanout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fanout.js","sourceRoot":"","sources":["../../src/fanout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAqEzC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AACzC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B,MAAM,OAAO,MAAM;IAKP;IACA;IACA;IANF,OAAO,CAAgB;IACvB,QAAQ,GAAG,KAAK,CAAC;IAEzB,YACU,MAAoB,EACpB,OAA2B,EAC3B,MAAe;QAFf,WAAM,GAAN,MAAM,CAAc;QACpB,YAAO,GAAP,OAAO,CAAoB;QAC3B,WAAM,GAAN,MAAM,CAAS;QAEvB,IAAI,CAAC,OAAO,GAAG;YACb,EAAE,EAAE,UAAU,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACxC,MAAM,EAAE,SAAS;YACjB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM;YAChC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IACD,KAAK;QACH,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,GAAG;QACP,IAAI,CAAC;YACH,mEAAmE;YACnE,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3F,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC7C,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACpD,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC;oBAAE,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC1E,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACrD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC;YAC9B,IAAI,CAAC,OAAO,CAAC,KAAK,GAAI,GAAa,CAAC,OAAO,CAAC;YAC5C,IAAI,CAAC,OAAO,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrD,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,IAAqB;QAC3C,MAAM,MAAM,GAAe,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC;QACnD,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;gBAC9B,IAAI,EAAE,WAAW;gBACjB,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;gBAC3B,MAAM;gBACN,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,mBAAmB;gBAC1D,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB,IAAI,iBAAiB;gBAC3D,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;gBACtC,YAAY,EAAE,IAAI,CAAC,YAAY;aAChC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;gBAC1F,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,wBAAwB;aAChE,CAAC,CAAC;YACH,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,IAAI;gBAChB,MAAM;gBACN,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,EAAE,EAAE,IAAI;gBACR,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;aAC/B,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,KAAK,EAAE,IAAI,CAAC,IAAI;gBAChB,MAAM;gBACN,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,EAAE;gBACV,KAAK,EAAG,GAAa,CAAC,OAAO;gBAC7B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;aAC/B,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACrD,yDAAyD;YAC3D,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,OAA4B;QACpD,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;QACnD,MAAM,QAAQ,GAAG,OAAO;aACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;aAC/G,IAAI,CAAC,aAAa,CAAC,CAAC;QACvB,MAAM,MAAM,GACV,wBAAwB,OAAO,CAAC,MAAM,uDAAuD;YAC7F,8FAA8F;YAC9F,wCAAwC,IAAI,CAAC,MAAM,CAAC,IAAI,qBAAqB,QAAQ,EAAE,CAAC;QAC1F,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;gBAC9B,IAAI,EAAE,WAAW;gBACjB,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU;gBAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,QAAQ;gBAC/C,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc;gBACjC,cAAc,EAAE,mBAAmB;gBACnC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB,IAAI,iBAAiB;gBAC3D,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;aACvC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE;gBACjE,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,wBAAwB;aAChE,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAI,GAAa,CAAC,OAAO,CAAC;YACnC,IAAI,CAAC,OAAO,CAAC,cAAc,GAAG,GAAG,CAAC;YAClC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,4BAA4B,GAAG,EAAE,CAAC,CAAC;YACxD,OAAO,SAAS,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBACrD,uBAAuB;YACzB,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF"}
@@ -78,10 +78,15 @@ export class InboxManager {
78
78
  this.inboxes.delete(name);
79
79
  }
80
80
  // ── Private ─────────────────────────────────────────────────────────────
81
- async _deliverOrQueue(sessionName, msg, lookup) {
81
+ async _deliverOrQueue(sessionName, sharedMsg, lookup) {
82
82
  const managed = lookup.getSession(sessionName);
83
83
  if (!managed)
84
84
  return false;
85
+ // Per-recipient copy: a broadcast passes the SAME message object to every
86
+ // recipient, so mutating read-state in place would let an idle recipient's
87
+ // delivery mark a busy recipient's queued copy as already-read (then
88
+ // deliverInbox filters it out and it's lost).
89
+ const msg = { ...sharedMsg };
85
90
  // If session is idle, deliver directly
86
91
  if (!managed.session.isBusy && managed.session.isReady) {
87
92
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"inbox-manager.js","sourceRoot":"","sources":["../../src/inbox-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inbox-manager.js","sourceRoot":"","sources":["../../src/inbox-manager.ts"],"names":[],"mappings":"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"}
package/dist/src/index.js CHANGED
@@ -120,8 +120,13 @@ const plugin = {
120
120
  enum: ['acceptEdits', 'bypassPermissions', 'default', 'delegate', 'dontAsk', 'plan', 'auto'],
121
121
  },
122
122
  effort: { type: 'string', enum: ['low', 'medium', 'high', 'xhigh', 'max', 'auto'] },
123
- allowedTools: { type: 'array', items: { type: 'string' }, description: 'Tools to auto-approve' },
124
- disallowedTools: { type: 'array', items: { type: 'string' }, description: 'Tools to deny' },
123
+ allowedTools: {
124
+ type: 'array',
125
+ maxItems: 200,
126
+ items: { type: 'string' },
127
+ description: 'Tools to auto-approve',
128
+ },
129
+ disallowedTools: { type: 'array', maxItems: 200, items: { type: 'string' }, description: 'Tools to deny' },
125
130
  maxTurns: { type: 'number', description: 'Max agent loop turns' },
126
131
  maxBudgetUsd: { type: 'number', description: 'Max API spend (USD)' },
127
132
  systemPrompt: { type: 'string', description: 'Replace system prompt' },
@@ -130,7 +135,11 @@ const plugin = {
130
135
  agent: { type: 'string', description: 'Default agent to use' },
131
136
  bare: { type: 'boolean', description: 'Minimal mode: skip hooks, LSP, auto-memory, CLAUDE.md' },
132
137
  worktree: { type: ['string', 'boolean'], description: 'Run in git worktree' },
133
- fallbackModel: { type: 'string', description: 'Auto fallback when primary overloaded' },
138
+ fallbackModel: {
139
+ type: ['string', 'array'],
140
+ items: { type: 'string' },
141
+ description: 'Auto fallback when primary overloaded. String or array (tried in order).',
142
+ },
134
143
  jsonSchema: { type: 'string', description: 'JSON Schema for structured output' },
135
144
  mcpConfig: {
136
145
  type: ['string', 'array'],
@@ -138,6 +147,14 @@ const plugin = {
138
147
  description: 'MCP server config file(s)',
139
148
  },
140
149
  settings: { type: 'string', description: 'Settings.json path or inline JSON' },
150
+ ultracode: {
151
+ type: 'boolean',
152
+ description: 'Claude engine only. Enable "ultracode" / dynamic workflows: Claude plans a JS orchestration script per substantive task and fans out to subagents. Injected as the ultracode:true settings key (not a --effort value).',
153
+ },
154
+ codexProfile: {
155
+ type: 'string',
156
+ description: 'Codex engine only. Named config profile from ~/.codex/config.toml, passed as `codex exec --profile`. Reasoning effort is mapped from the engine-agnostic `effort` param to `-c model_reasoning_effort` automatically.',
157
+ },
141
158
  noSessionPersistence: { type: 'boolean', description: 'Do not save session to disk' },
142
159
  betas: { type: ['string', 'array'], items: { type: 'string' }, description: 'Custom beta headers' },
143
160
  enableAgentTeams: { type: 'boolean', description: 'Enable experimental agent teams' },
@@ -244,7 +261,7 @@ const plugin = {
244
261
  },
245
262
  contextWindow: { type: 'number' },
246
263
  env: { type: 'object', description: 'Extra environment variables' },
247
- sanitizePatterns: { type: 'array', items: { type: 'string' } },
264
+ sanitizePatterns: { type: 'array', maxItems: 100, items: { type: 'string' } },
248
265
  },
249
266
  required: ['name', 'bin', 'args'],
250
267
  },
@@ -754,6 +771,184 @@ const plugin = {
754
771
  return await getManager().codexGoalCommand(args.name, 'clear', args.timeout);
755
772
  },
756
773
  });
774
+ // ─── Codex app-server v2 RPC tools (codex-app engine, Codex 0.137) ────
775
+ api.registerTool({
776
+ name: 'codex_interrupt',
777
+ description: 'Cancel the in-flight turn on a codex-app session (`turn/interrupt`).',
778
+ parameters: {
779
+ type: 'object',
780
+ properties: { name: { type: 'string', description: 'Session name.' } },
781
+ required: ['name'],
782
+ },
783
+ execute: async (_id, args) => getManager().codexInterrupt(args.name),
784
+ });
785
+ api.registerTool({
786
+ name: 'codex_steer',
787
+ description: 'Add input to the in-flight turn on a codex-app session without restarting it (`turn/steer`). Falls back to a normal turn when idle.',
788
+ parameters: {
789
+ type: 'object',
790
+ properties: {
791
+ name: { type: 'string', description: 'Session name.' },
792
+ message: { type: 'string', description: 'Text to steer the turn with.' },
793
+ },
794
+ required: ['name', 'message'],
795
+ },
796
+ execute: async (_id, args) => getManager().codexSteer(args.name, args.message),
797
+ });
798
+ api.registerTool({
799
+ name: 'codex_fork',
800
+ description: 'Branch a codex-app thread into a new one (`thread/fork`); returns the forked thread id.',
801
+ parameters: {
802
+ type: 'object',
803
+ properties: { name: { type: 'string', description: 'Session name.' } },
804
+ required: ['name'],
805
+ },
806
+ execute: async (_id, args) => getManager().codexForkThread(args.name),
807
+ });
808
+ api.registerTool({
809
+ name: 'codex_rollback',
810
+ description: 'Drop the last N turns from a codex-app thread (`thread/rollback`).',
811
+ parameters: {
812
+ type: 'object',
813
+ properties: {
814
+ name: { type: 'string', description: 'Session name.' },
815
+ numTurns: { type: 'number', minimum: 1, description: 'Number of turns to roll back (>=1).' },
816
+ },
817
+ required: ['name', 'numTurns'],
818
+ },
819
+ execute: async (_id, args) => getManager().codexRollback(args.name, args.numTurns),
820
+ });
821
+ api.registerTool({
822
+ name: 'codex_models',
823
+ description: 'List models available to a codex-app session (`model/list`), incl. supported reasoning efforts.',
824
+ parameters: {
825
+ type: 'object',
826
+ properties: { name: { type: 'string', description: 'Session name.' } },
827
+ required: ['name'],
828
+ },
829
+ execute: async (_id, args) => getManager().codexModels(args.name),
830
+ });
831
+ api.registerTool({
832
+ name: 'codex_threads',
833
+ description: 'List Codex threads visible to a codex-app session (`thread/list`), with optional filters.',
834
+ parameters: {
835
+ type: 'object',
836
+ properties: {
837
+ name: { type: 'string', description: 'Session name.' },
838
+ searchTerm: { type: 'string', description: 'Filter threads by text.' },
839
+ cwd: { type: 'string', description: 'Filter to threads under this directory.' },
840
+ archived: { type: 'boolean', description: 'Include archived threads.' },
841
+ cursor: { type: 'string', description: 'Pagination cursor (from a prior nextCursor).' },
842
+ limit: { type: 'number', description: 'Max threads to return.' },
843
+ },
844
+ required: ['name'],
845
+ },
846
+ execute: async (_id, args) => getManager().codexThreads(args.name, {
847
+ searchTerm: args.searchTerm,
848
+ cwd: args.cwd ? sanitizeCwd(args.cwd) : undefined,
849
+ archived: args.archived,
850
+ cursor: args.cursor,
851
+ limit: args.limit,
852
+ }),
853
+ });
854
+ // ─── Tool: claude_agents_list (Claude CLI 2.1.x, claude engine) ───────
855
+ api.registerTool({
856
+ name: 'claude_agents_list',
857
+ description: 'List Claude Code background agent sessions via `claude agents --json` (state/model/title/progress). One-shot, not tied to a managed session.',
858
+ parameters: {
859
+ type: 'object',
860
+ properties: {
861
+ all: { type: 'boolean', description: 'Include completed sessions (`--all`).' },
862
+ cwd: { type: 'string', description: 'Scope to sessions started under this directory (`--cwd`).' },
863
+ },
864
+ },
865
+ execute: async (_id, args) => getManager().claudeAgentsList({ all: args.all, cwd: args.cwd }),
866
+ });
867
+ // ─── Fan-out tools (parallel multi-engine task, no consensus) ─────────
868
+ api.registerTool({
869
+ name: 'fanout_start',
870
+ description: 'Run one task across N engine/model agents IN PARALLEL and collect their answers (optional synthesis). Cross-engine best-of-N / diverse-perspective primitive. No rounds, votes, or worktrees — use council for isolated parallel edits. Runs in background; poll with fanout_status.',
871
+ parameters: {
872
+ type: 'object',
873
+ properties: {
874
+ task: {
875
+ type: 'string',
876
+ description: 'The shared task/prompt sent to every agent (unless an agent overrides it).',
877
+ },
878
+ projectDir: { type: 'string', description: 'Working directory all agents run in.' },
879
+ agents: {
880
+ type: 'array',
881
+ maxItems: 16,
882
+ description: 'Agent specs: { name, engine?, model?, prompt?, baseUrl?, permissionMode?, customEngine? }.',
883
+ items: {
884
+ type: 'object',
885
+ properties: {
886
+ name: { type: 'string', minLength: 1, description: 'Unique label (forms the session name).' },
887
+ engine: {
888
+ type: 'string',
889
+ enum: ['claude', 'codex', 'codex-app', 'gemini', 'cursor', 'opencode', 'custom'],
890
+ },
891
+ model: { type: 'string' },
892
+ prompt: { type: 'string' },
893
+ baseUrl: { type: 'string' },
894
+ },
895
+ required: ['name'],
896
+ },
897
+ },
898
+ synthesize: {
899
+ type: 'boolean',
900
+ description: 'Run a final synthesis pass over the successful results (>=2 needed).',
901
+ },
902
+ synthesisModel: { type: 'string', description: 'Model for the synthesis pass.' },
903
+ synthesisEngine: {
904
+ type: 'string',
905
+ enum: ['claude', 'codex', 'codex-app', 'gemini', 'cursor', 'opencode', 'custom'],
906
+ description: 'Engine for the synthesis pass (default claude).',
907
+ },
908
+ agentTimeoutMs: { type: 'number', description: 'Per-agent timeout in ms (default 600000).' },
909
+ maxTurnsPerAgent: { type: 'number', description: 'Max agent loop turns (default 30).' },
910
+ maxBudgetUsd: { type: 'number', description: 'Per-agent spend cap (USD).' },
911
+ },
912
+ required: ['task', 'projectDir', 'agents'],
913
+ },
914
+ execute: async (_id, args) => {
915
+ const session = getManager().fanoutStart({
916
+ task: args.task,
917
+ projectDir: sanitizeCwd(args.projectDir),
918
+ agents: args.agents,
919
+ synthesize: args.synthesize,
920
+ synthesisModel: args.synthesisModel,
921
+ synthesisEngine: args.synthesisEngine,
922
+ agentTimeoutMs: args.agentTimeoutMs,
923
+ maxTurnsPerAgent: args.maxTurnsPerAgent,
924
+ maxBudgetUsd: args.maxBudgetUsd,
925
+ });
926
+ return { ok: true, ...session, note: 'Fan-out running in background. Poll with fanout_status.' };
927
+ },
928
+ });
929
+ api.registerTool({
930
+ name: 'fanout_status',
931
+ description: 'Poll a running or finished fan-out by id; returns per-agent results and any synthesis.',
932
+ parameters: {
933
+ type: 'object',
934
+ properties: { id: { type: 'string', description: 'Fan-out id from fanout_start.' } },
935
+ required: ['id'],
936
+ },
937
+ execute: async (_id, args) => ({ ok: true, ...getManager().fanoutStatus(args.id) }),
938
+ });
939
+ api.registerTool({
940
+ name: 'fanout_abort',
941
+ description: 'Abort a running fan-out by id (already-started agents finish; synthesis is skipped).',
942
+ parameters: {
943
+ type: 'object',
944
+ properties: { id: { type: 'string', description: 'Fan-out id from fanout_start.' } },
945
+ required: ['id'],
946
+ },
947
+ execute: async (_id, args) => {
948
+ getManager().fanoutAbort(args.id);
949
+ return { ok: true };
950
+ },
951
+ });
757
952
  // ─── Tool: council_start ────────────────────────────────────────────
758
953
  api.registerTool({
759
954
  name: 'council_start',
@@ -780,6 +975,15 @@ const plugin = {
780
975
  model: { type: 'string', description: 'Model to use' },
781
976
  baseUrl: { type: 'string', description: 'Custom API endpoint (for proxy)' },
782
977
  customEngine: { type: 'object', description: 'Custom engine config (when engine="custom")' },
978
+ effort: {
979
+ type: 'string',
980
+ enum: ['low', 'medium', 'high', 'xhigh', 'max', 'auto'],
981
+ description: 'Per-agent reasoning effort.',
982
+ },
983
+ ultracode: {
984
+ type: 'boolean',
985
+ description: 'Per-agent ultracode / dynamic workflows (claude engine only).',
986
+ },
783
987
  },
784
988
  required: ['name', 'emoji', 'persona'],
785
989
  },
@@ -1010,6 +1214,11 @@ const plugin = {
1010
1214
  maxDurationMinutes: { type: 'number', description: 'Max review duration in minutes (5-25, default 10)' },
1011
1215
  model: { type: 'string', description: 'Model for reviewers (default: session default)' },
1012
1216
  focus: { type: 'string', description: 'Review focus area (default: bugs + security + quality)' },
1217
+ engines: {
1218
+ type: 'array',
1219
+ items: { type: 'string', enum: ['claude', 'codex', 'codex-app', 'gemini', 'cursor', 'opencode'] },
1220
+ description: 'Engines to round-robin reviewers across (default ["claude"]). Reviewers fan out in parallel; per-agent failures are isolated.',
1221
+ },
1013
1222
  },
1014
1223
  required: ['cwd'],
1015
1224
  },
@@ -1019,6 +1228,7 @@ const plugin = {
1019
1228
  maxDurationMinutes: args.maxDurationMinutes,
1020
1229
  model: args.model,
1021
1230
  focus: args.focus,
1231
+ engines: args.engines,
1022
1232
  });
1023
1233
  return { ok: true, ...result, note: 'Ultrareview running in background. Poll with ultrareview_status.' };
1024
1234
  },