macro-agent 0.2.3 → 0.2.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.
- package/dist/agent/agent-manager-v2.d.ts.map +1 -1
- package/dist/agent/agent-manager-v2.js +182 -43
- package/dist/agent/agent-manager-v2.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +17 -0
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +21 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/acp.js +0 -0
- package/dist/cli/index.js +0 -0
- package/dist/cli/mcp.js +0 -0
- package/dist/cognitive/macro-agent-backend.d.ts.map +1 -1
- package/dist/cognitive/macro-agent-backend.js +37 -8
- package/dist/cognitive/macro-agent-backend.js.map +1 -1
- package/dist/cognitive/types.d.ts +24 -0
- package/dist/cognitive/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/map/mail-bridge.d.ts +7 -0
- package/dist/map/mail-bridge.d.ts.map +1 -1
- package/dist/map/mail-bridge.js +39 -9
- package/dist/map/mail-bridge.js.map +1 -1
- package/dist/map/sidecar.d.ts.map +1 -1
- package/dist/map/sidecar.js +19 -4
- package/dist/map/sidecar.js.map +1 -1
- package/dist/teams/team-runtime-v2.d.ts.map +1 -1
- package/dist/teams/team-runtime-v2.js +23 -6
- package/dist/teams/team-runtime-v2.js.map +1 -1
- package/package.json +4 -2
- package/renovate.json5 +6 -0
- package/src/agent/__tests__/agent-manager-v2.completion-signal.test.ts +284 -0
- package/src/agent/agent-manager-v2.ts +216 -50
- package/src/agent/agent-manager.ts +17 -0
- package/src/agent/types.ts +23 -2
- package/src/cognitive/__tests__/macro-agent-backend.test.ts +158 -5
- package/src/cognitive/macro-agent-backend.ts +39 -7
- package/src/cognitive/types.ts +24 -0
- package/src/index.ts +2 -0
- package/src/map/__tests__/mail-bridge.test.ts +39 -2
- package/src/map/__tests__/sidecar-diff-install-smoke.test.ts +17 -2
- package/src/map/mail-bridge.ts +61 -13
- package/src/map/sidecar.ts +21 -4
- package/src/teams/team-runtime-v2.ts +29 -6
- package/dist/workspace/dataplane-adapter.d.ts +0 -260
- package/dist/workspace/dataplane-adapter.d.ts.map +0 -1
- package/dist/workspace/dataplane-adapter.js +0 -416
- package/dist/workspace/dataplane-adapter.js.map +0 -1
|
@@ -57,11 +57,14 @@ export class MacroAgentBackend {
|
|
|
57
57
|
this.onSessionComplete = config?.onSessionComplete;
|
|
58
58
|
this.inboxAdapter = config?.inboxAdapter;
|
|
59
59
|
|
|
60
|
-
// Register analyst role if not already present
|
|
60
|
+
// Register analyst role if not already present. Use getRole() (exact match,
|
|
61
|
+
// returns undefined on a miss) rather than resolveRole(): the real
|
|
62
|
+
// DefaultRoleRegistry.resolveRole() never throws on an unknown role — it
|
|
63
|
+
// logs "Role 'analyst' not found, falling back to 'generic'" and returns
|
|
64
|
+
// GenericRole — so a resolveRole()/try-catch guard would silently skip
|
|
65
|
+
// registration and every spawn would fall back to GenericRole.
|
|
61
66
|
const registry = this.agentManager.getRoleRegistry();
|
|
62
|
-
|
|
63
|
-
registry.resolveRole("analyst");
|
|
64
|
-
} catch {
|
|
67
|
+
if (!registry.getRole("analyst")) {
|
|
65
68
|
registry.registerRole(AnalystRole);
|
|
66
69
|
}
|
|
67
70
|
}
|
|
@@ -189,6 +192,29 @@ export class MacroAgentBackend {
|
|
|
189
192
|
config: CognitiveAgentSpawnConfig,
|
|
190
193
|
taskId?: string,
|
|
191
194
|
): Promise<CognitiveAgentSession> {
|
|
195
|
+
// Per-attempt reset hook — runs BEFORE the agent is driven so each attempt
|
|
196
|
+
// (initial spawn AND each refinement re-spawn) starts from a clean external
|
|
197
|
+
// state (e.g. a deleted benchmark reward sink). Best-effort: a failing hook
|
|
198
|
+
// must not abort the spawn.
|
|
199
|
+
if (config.beforeSpawn) {
|
|
200
|
+
try {
|
|
201
|
+
await config.beforeSpawn();
|
|
202
|
+
} catch {
|
|
203
|
+
// Best effort — reset failure should not block the spawn.
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Forward env and MCP servers into the raw macro spawn's `config`. Build
|
|
208
|
+
// the AgentConfig only when at least one field is present so non-MCP,
|
|
209
|
+
// non-env spawns keep passing `config: undefined` (byte-identical to M0).
|
|
210
|
+
const rawConfig =
|
|
211
|
+
config.env || config.mcpServers
|
|
212
|
+
? {
|
|
213
|
+
...(config.env ? { env: config.env } : {}),
|
|
214
|
+
...(config.mcpServers ? { mcpServers: config.mcpServers } : {}),
|
|
215
|
+
}
|
|
216
|
+
: undefined;
|
|
217
|
+
|
|
192
218
|
const spawned = await this.agentManager.spawn({
|
|
193
219
|
task: config.task.description,
|
|
194
220
|
task_id: taskId,
|
|
@@ -197,7 +223,7 @@ export class MacroAgentBackend {
|
|
|
197
223
|
? this.config.coordinatorAgentId
|
|
198
224
|
: null,
|
|
199
225
|
cwd: config.cwd,
|
|
200
|
-
config:
|
|
226
|
+
config: rawConfig,
|
|
201
227
|
customPrompt: config.systemPromptAdditions,
|
|
202
228
|
});
|
|
203
229
|
|
|
@@ -319,12 +345,18 @@ export class MacroAgentBackend {
|
|
|
319
345
|
updateSessionFromEvent(session, update);
|
|
320
346
|
config.onMessage?.(session.messages[session.messages.length - 1]!);
|
|
321
347
|
},
|
|
348
|
+
// Forward the caller's completion predicate (e.g. a benchmark reward
|
|
349
|
+
// sink wrote done:true). When it fires, promptUntilDone returns
|
|
350
|
+
// completedExternally:true instead of exhausting maxFollowUps.
|
|
351
|
+
isComplete: config.completionSignal,
|
|
322
352
|
},
|
|
323
353
|
);
|
|
324
354
|
|
|
325
355
|
if (session.state === "running") {
|
|
326
|
-
|
|
327
|
-
|
|
356
|
+
// External completion (predicate) is a success path, same as done().
|
|
357
|
+
const completed = result.doneCalled || result.completedExternally;
|
|
358
|
+
session.state = completed ? "completed" : "failed";
|
|
359
|
+
if (!completed) session.error = "Agent did not call done()";
|
|
328
360
|
session.endTime = new Date();
|
|
329
361
|
session.result = result.doneStatus;
|
|
330
362
|
}
|
package/src/cognitive/types.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import type { AgentId } from "../store/types/index.js";
|
|
13
13
|
import type { TasksAdapter, InboxAdapter } from "../adapters/types.js";
|
|
14
|
+
import type { MCPServerConfig } from "../agent/types.js";
|
|
14
15
|
|
|
15
16
|
// ─────────────────────────────────────────────────────────────────
|
|
16
17
|
// Agent Session Types (matches cognitive-core/src/runtime/types.ts)
|
|
@@ -78,6 +79,29 @@ export interface CognitiveAgentSpawnConfig {
|
|
|
78
79
|
cwd?: string;
|
|
79
80
|
timeout?: number;
|
|
80
81
|
onMessage?: (message: CognitiveAgentMessage) => void;
|
|
82
|
+
/**
|
|
83
|
+
* MCP servers to mount on the spawned agent (e.g. a per-task tau-env
|
|
84
|
+
* server). Forwarded verbatim into the macro `AgentManager.spawn`'s
|
|
85
|
+
* `config.mcpServers`. Optional / back-compat: non-MCP spawns are
|
|
86
|
+
* unaffected. Matches macro `AgentConfig.mcpServers` (the stdio/http union).
|
|
87
|
+
*/
|
|
88
|
+
mcpServers?: MCPServerConfig[];
|
|
89
|
+
/**
|
|
90
|
+
* Optional completion predicate forwarded into `promptUntilDone`. When it
|
|
91
|
+
* returns true the agent loop completes externally (without the macro done()
|
|
92
|
+
* tool) — e.g. a benchmark env wrote its reward sink with done:true. Generic:
|
|
93
|
+
* the backend has no knowledge of what it reads. Back-compat: absent →
|
|
94
|
+
* unchanged.
|
|
95
|
+
*/
|
|
96
|
+
completionSignal?: () => boolean | Promise<boolean>;
|
|
97
|
+
/**
|
|
98
|
+
* Optional per-attempt hook invoked BEFORE the agent is driven (and again
|
|
99
|
+
* before each refinement re-spawn, since refine() spreads this config). Used
|
|
100
|
+
* to reset per-attempt external state — e.g. delete a benchmark reward sink so
|
|
101
|
+
* each attempt only sees its OWN completion signal. Back-compat: absent →
|
|
102
|
+
* unchanged.
|
|
103
|
+
*/
|
|
104
|
+
beforeSpawn?: () => void | Promise<void>;
|
|
81
105
|
}
|
|
82
106
|
|
|
83
107
|
// ─────────────────────────────────────────────────────────────────
|
package/src/index.ts
CHANGED
|
@@ -55,6 +55,8 @@ export {
|
|
|
55
55
|
AgentManagerError,
|
|
56
56
|
type AgentManagerErrorCode,
|
|
57
57
|
type MCPServerConfig as AgentMCPServerConfig,
|
|
58
|
+
type MCPServerStdioConfig as AgentMCPServerStdioConfig,
|
|
59
|
+
type MCPServerHttpConfig as AgentMCPServerHttpConfig,
|
|
58
60
|
type AgentConfig as SpawnAgentConfig,
|
|
59
61
|
} from './agent/types.js';
|
|
60
62
|
|
|
@@ -67,11 +67,12 @@ describe("setupMailBridge", () => {
|
|
|
67
67
|
);
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
it("
|
|
70
|
+
it("delivers plain-text turns into the inbox as a text message", async () => {
|
|
71
71
|
const logs: string[] = [];
|
|
72
72
|
await setupMailBridge({
|
|
73
73
|
connection: conn,
|
|
74
74
|
inboxAdapter: inbox as any,
|
|
75
|
+
dispatcherAgentId: "dispatcher:host:1234:abc",
|
|
75
76
|
log: (m) => logs.push(m),
|
|
76
77
|
});
|
|
77
78
|
|
|
@@ -81,10 +82,46 @@ describe("setupMailBridge", () => {
|
|
|
81
82
|
participant_id: "some-agent",
|
|
82
83
|
content_type: "text/plain",
|
|
83
84
|
content: "hello world",
|
|
85
|
+
thread_id: "thread-xyz",
|
|
86
|
+
importance: "high",
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(inbox.send).toHaveBeenCalledOnce();
|
|
90
|
+
const [from, to, content, opts] = inbox.send.mock.calls[0];
|
|
91
|
+
expect(from).toBe("some-agent");
|
|
92
|
+
expect(to).toBe("dispatcher:host:1234:abc");
|
|
93
|
+
// Delivered as a text message that normalizeContent passes through,
|
|
94
|
+
// carrying the conversation id for reply threading.
|
|
95
|
+
expect(content).toMatchObject({
|
|
96
|
+
type: "text",
|
|
97
|
+
text: "hello world",
|
|
98
|
+
_conversationId: "conv-1",
|
|
99
|
+
});
|
|
100
|
+
// Not shaped as a work envelope — the classifier must not match it.
|
|
101
|
+
expect(content).not.toHaveProperty("schema");
|
|
102
|
+
expect(opts?.threadTag).toBe("thread-xyz");
|
|
103
|
+
expect(opts?.importance).toBe("high");
|
|
104
|
+
expect(logs.some((l) => l.includes("Forwarded text turn"))).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("skips empty / whitespace-only text turns", async () => {
|
|
108
|
+
const logs: string[] = [];
|
|
109
|
+
await setupMailBridge({
|
|
110
|
+
connection: conn,
|
|
111
|
+
inboxAdapter: inbox as any,
|
|
112
|
+
log: (m) => logs.push(m),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await conn._fire({
|
|
116
|
+
conversation_id: "conv-empty",
|
|
117
|
+
turn_id: "turn-empty",
|
|
118
|
+
participant_id: "some-agent",
|
|
119
|
+
content_type: "text/plain",
|
|
120
|
+
content: " ",
|
|
84
121
|
});
|
|
85
122
|
|
|
86
123
|
expect(inbox.send).not.toHaveBeenCalled();
|
|
87
|
-
expect(logs.some((l) => l.includes("
|
|
124
|
+
expect(logs.some((l) => l.includes("Skipping empty"))).toBe(true);
|
|
88
125
|
});
|
|
89
126
|
|
|
90
127
|
describe("with dispatcherAgentId", () => {
|
|
@@ -65,11 +65,26 @@ describe('sidecar.ts cascade-diff install (structural smoke)', () => {
|
|
|
65
65
|
expect(cleanupBlock).toContain('diffCleanup()');
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it('only declares cascade
|
|
68
|
+
it('only declares the cascade capability when adapter is wired (S1.10)', () => {
|
|
69
69
|
// The capability declaration is a conditional spread keyed on
|
|
70
70
|
// gitCascadeAdapter. Without an adapter, no `cascade:` block is sent.
|
|
71
71
|
expect(sidecarSource).toMatch(
|
|
72
|
-
/\.\.\.\(gitCascadeAdapter\s*\?\s*\{\s*cascade:\s
|
|
72
|
+
/\.\.\.\(gitCascadeAdapter\s*\?\s*\{\s*cascade:\s*cascadeCapability\s*\}\s*:\s*\{\}\)/,
|
|
73
73
|
);
|
|
74
74
|
});
|
|
75
|
+
|
|
76
|
+
it('declares the full cascade capability (canServeDiff + canAct + emitsConflicts)', () => {
|
|
77
|
+
// macro-agent is a full-control cascade runtime: it serves diffs,
|
|
78
|
+
// handles inbound x-cascade/request.* actions, and forwards conflict
|
|
79
|
+
// events. The CascadeCapability constant must reflect all three.
|
|
80
|
+
const capBlock = sidecarSource.match(
|
|
81
|
+
/const cascadeCapability:\s*CascadeCapability\s*=\s*{[\s\S]*?};/,
|
|
82
|
+
)?.[0];
|
|
83
|
+
expect(capBlock).toBeDefined();
|
|
84
|
+
expect(capBlock).toContain('canServeDiff: true');
|
|
85
|
+
expect(capBlock).toContain('canAct: true');
|
|
86
|
+
expect(capBlock).toContain('emitsConflicts: true');
|
|
87
|
+
// autoCloseOnMerge is an opt-in close policy with no wiring — not declared.
|
|
88
|
+
expect(capBlock).not.toContain('autoCloseOnMerge');
|
|
89
|
+
});
|
|
75
90
|
});
|
package/src/map/mail-bridge.ts
CHANGED
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
* 2. The classifier recognizes `x-dispatch/work` schema and routes the
|
|
14
14
|
* prompt to a worker agent (existing or freshly spawned).
|
|
15
15
|
*
|
|
16
|
+
* Turns that aren't structured `x-dispatch/work` envelopes (e.g.
|
|
17
|
+
* natural-language spec-discussion replies) are delivered into the inbox as
|
|
18
|
+
* plain-text messages instead of being dropped. The classifier won't match
|
|
19
|
+
* them (so no worker spawns), but the delivery still wakes the agent via
|
|
20
|
+
* TriggerSystemV2 (importance → wake action) so it reads the reply on its
|
|
21
|
+
* next turn.
|
|
22
|
+
*
|
|
16
23
|
* Without this bridge, hub-side mail turns never reach macro-agent's
|
|
17
24
|
* dispatcher. The MessagePort is wired to local inbox events only.
|
|
18
25
|
*/
|
|
@@ -135,14 +142,64 @@ export async function setupMailBridge(
|
|
|
135
142
|
metadata: { source: "openhive-mail-forward" },
|
|
136
143
|
});
|
|
137
144
|
|
|
145
|
+
// Importance derivation shared by the structured-work and plain-text
|
|
146
|
+
// delivery paths. Defaults to "normal" when the hub doesn't tag the turn.
|
|
147
|
+
const VALID_IMPORTANCE = ["low", "normal", "high", "urgent"];
|
|
148
|
+
const deriveImportance = (
|
|
149
|
+
value: string | undefined,
|
|
150
|
+
): "low" | "normal" | "high" | "urgent" =>
|
|
151
|
+
typeof value === "string" && VALID_IMPORTANCE.includes(value)
|
|
152
|
+
? (value as "low" | "normal" | "high" | "urgent")
|
|
153
|
+
: "normal";
|
|
154
|
+
|
|
138
155
|
const handler = async (params: unknown): Promise<void> => {
|
|
139
156
|
const turn = (params ?? {}) as MailTurnReceivedParams;
|
|
157
|
+
const wireImportance = deriveImportance(turn.importance);
|
|
140
158
|
const raw = parseTurnContent(turn.content, turn.content_type);
|
|
159
|
+
|
|
160
|
+
// Plain-text (non-JSON) turn — e.g. a natural-language spec-discussion
|
|
161
|
+
// reply. Previously dropped; now delivered into the local inbox as a
|
|
162
|
+
// text message so the agent wakes (TriggerSystemV2 maps importance to a
|
|
163
|
+
// wake action) and reads it on its next turn. The dispatcher's
|
|
164
|
+
// MessagePort classifier won't match a text payload, so no worker is
|
|
165
|
+
// spawned — correct for a conversational message. The conversation id
|
|
166
|
+
// rides along (mirrors the structured path) so the agent's reply can be
|
|
167
|
+
// threaded back to the right hub conversation.
|
|
141
168
|
if (!raw) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
169
|
+
const text = typeof turn.content === "string" ? turn.content : "";
|
|
170
|
+
if (!text.trim()) {
|
|
171
|
+
log(
|
|
172
|
+
`[mail-bridge] Skipping empty/non-text turn (conv=${turn.conversation_id ?? "?"} ` +
|
|
173
|
+
`participant=${turn.participant_id ?? "?"})`,
|
|
174
|
+
);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const textContent: Record<string, unknown> = {
|
|
178
|
+
type: "text",
|
|
179
|
+
text,
|
|
180
|
+
...(turn.conversation_id
|
|
181
|
+
? { _conversationId: turn.conversation_id }
|
|
182
|
+
: {}),
|
|
183
|
+
};
|
|
184
|
+
try {
|
|
185
|
+
await inboxAdapter.send(
|
|
186
|
+
turn.participant_id ?? "openhive-hub",
|
|
187
|
+
recipientId,
|
|
188
|
+
textContent as never,
|
|
189
|
+
{
|
|
190
|
+
threadTag: turn.thread_id,
|
|
191
|
+
importance: wireImportance,
|
|
192
|
+
},
|
|
193
|
+
);
|
|
194
|
+
log(
|
|
195
|
+
`[mail-bridge] Forwarded text turn ${turn.turn_id ?? "?"} into local inbox`,
|
|
196
|
+
);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
log(
|
|
199
|
+
`[mail-bridge] Forward failed for text turn ${turn.turn_id ?? "?"}: ` +
|
|
200
|
+
`${(err as Error).message}`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
146
203
|
return;
|
|
147
204
|
}
|
|
148
205
|
|
|
@@ -172,15 +229,6 @@ export async function setupMailBridge(
|
|
|
172
229
|
...(turn.conversation_id ? { _conversationId: turn.conversation_id } : {}),
|
|
173
230
|
};
|
|
174
231
|
|
|
175
|
-
// Derive importance from the hub's wire params. Default to "normal"
|
|
176
|
-
// when the hub doesn't tag the turn (backward compat).
|
|
177
|
-
const VALID_IMPORTANCE = ["low", "normal", "high", "urgent"];
|
|
178
|
-
const wireImportance =
|
|
179
|
-
typeof turn.importance === "string" &&
|
|
180
|
-
VALID_IMPORTANCE.includes(turn.importance)
|
|
181
|
-
? (turn.importance as "low" | "normal" | "high" | "urgent")
|
|
182
|
-
: "normal";
|
|
183
|
-
|
|
184
232
|
try {
|
|
185
233
|
await inboxAdapter.send(
|
|
186
234
|
turn.participant_id ?? "openhive-hub",
|
package/src/map/sidecar.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
TaskBridge,
|
|
24
24
|
} from "./types.js";
|
|
25
25
|
import type { AgentLifecycleCallback } from "../agent/types.js";
|
|
26
|
+
import type { CascadeCapability } from "git-cascade/events";
|
|
26
27
|
import {
|
|
27
28
|
REPO_PROTOCOL_VERSION,
|
|
28
29
|
RepoClient,
|
|
@@ -66,6 +67,22 @@ export function createMAPSidecar(
|
|
|
66
67
|
let workspaceTransport: RepoClientTransport | null = null;
|
|
67
68
|
let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
|
|
68
69
|
|
|
70
|
+
// Cascade capability — declared only when a git-cascade adapter is wired.
|
|
71
|
+
// Each flag reflects what macro-agent *actually wired up* (honest declaration):
|
|
72
|
+
// - canServeDiff: the diff server is wired alongside the adapter
|
|
73
|
+
// (setupCascadeDiffServer answers cascade/diff.request).
|
|
74
|
+
// - canAct: the inbound action handler is wired
|
|
75
|
+
// (setupCascadeActionHandlers handles x-cascade/request.*).
|
|
76
|
+
// - emitsConflicts: the cascade-bridge forwards stream.conflicted /
|
|
77
|
+
// stream.conflict_resolved events.
|
|
78
|
+
// autoCloseOnMerge is omitted — it is an opt-in close policy (default
|
|
79
|
+
// manual) and macro-agent has no config/wiring for it.
|
|
80
|
+
const cascadeCapability: CascadeCapability = {
|
|
81
|
+
canServeDiff: true,
|
|
82
|
+
canAct: true,
|
|
83
|
+
emitsConflicts: true,
|
|
84
|
+
};
|
|
85
|
+
|
|
69
86
|
// Resolve the workspace capability from env vars. Setting OPENHIVE_WORKSPACE_DECLARE=off
|
|
70
87
|
// disables both explicit declare AND trajectory-handler bootstrap on the hub side.
|
|
71
88
|
const workspaceCapability: WorkspaceCapability = {
|
|
@@ -173,11 +190,11 @@ export function createMAPSidecar(
|
|
|
173
190
|
canUpdate: true,
|
|
174
191
|
canList: true,
|
|
175
192
|
},
|
|
176
|
-
//
|
|
177
|
-
// — without it there are no worktrees to shell out against,
|
|
178
|
-
// declaring
|
|
193
|
+
// Cascade capability is gated on whether a git-cascade adapter is
|
|
194
|
+
// wired — without it there are no worktrees to shell out against,
|
|
195
|
+
// so declaring it would just produce timeouts on the hub.
|
|
179
196
|
...(gitCascadeAdapter
|
|
180
|
-
? { cascade:
|
|
197
|
+
? { cascade: cascadeCapability }
|
|
181
198
|
: {}),
|
|
182
199
|
workspace: workspaceCapability,
|
|
183
200
|
},
|
|
@@ -532,12 +532,35 @@ export class TeamRuntimeV2 {
|
|
|
532
532
|
...options.config,
|
|
533
533
|
mcpServers: [
|
|
534
534
|
...(options.config?.mcpServers ?? []),
|
|
535
|
-
...teamMcpServers.map((s) =>
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
535
|
+
...teamMcpServers.map((s) => {
|
|
536
|
+
// openteams' static McpServerEntry is stdio-only, but a
|
|
537
|
+
// resolved loadout entry may carry a remote transport
|
|
538
|
+
// (type/url/headers — see openteams McpProviderSpec). Pass
|
|
539
|
+
// those through unchanged so http/sse loadout servers reach
|
|
540
|
+
// the spawn conversion; otherwise emit the stdio shape.
|
|
541
|
+
const remote = s as unknown as {
|
|
542
|
+
type?: "stdio" | "http" | "sse";
|
|
543
|
+
url?: string;
|
|
544
|
+
headers?: Record<string, string>;
|
|
545
|
+
};
|
|
546
|
+
if (
|
|
547
|
+
(remote.type === "http" || remote.type === "sse") &&
|
|
548
|
+
remote.url
|
|
549
|
+
) {
|
|
550
|
+
return {
|
|
551
|
+
name: s.name,
|
|
552
|
+
type: remote.type,
|
|
553
|
+
url: remote.url,
|
|
554
|
+
headers: remote.headers,
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
return {
|
|
558
|
+
name: s.name,
|
|
559
|
+
command: s.command,
|
|
560
|
+
args: s.args,
|
|
561
|
+
env: s.env,
|
|
562
|
+
};
|
|
563
|
+
}),
|
|
541
564
|
],
|
|
542
565
|
env: {
|
|
543
566
|
...options.config?.env,
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dataplane Adapter
|
|
3
|
-
*
|
|
4
|
-
* Wraps MultiAgentRepoTracker to integrate with macro-agent's event system
|
|
5
|
-
* and provide a simplified interface for workspace management.
|
|
6
|
-
*
|
|
7
|
-
* @module workspace/dataplane-adapter
|
|
8
|
-
* @implements [[s-7ktd]] Dataplane Integration section
|
|
9
|
-
*/
|
|
10
|
-
import Database from 'better-sqlite3';
|
|
11
|
-
import { MultiAgentRepoTracker, type Stream, type StreamStatus, type CreateStreamOptions, type AgentWorktree, type CreateWorktreeOptions, type WorkerTask, type CreateTaskOptions, type StartTaskOptions, type CompleteTaskOptions, type StartTaskResult, type CompleteTaskResult, type ListTasksOptions, type CleanupWorkerBranchesOptions, type CleanupResult, type Checkpoint } from 'git-cascade';
|
|
12
|
-
import type { DataplaneConfig } from './config.js';
|
|
13
|
-
/**
|
|
14
|
-
* Event types emitted by DataplaneAdapter
|
|
15
|
-
*/
|
|
16
|
-
export type DataplaneEventType = 'stream:created' | 'stream:updated' | 'stream:abandoned' | 'worktree:created' | 'worktree:deallocated' | 'task:created' | 'task:started' | 'task:completed' | 'task:abandoned';
|
|
17
|
-
/**
|
|
18
|
-
* Event payload for dataplane events
|
|
19
|
-
*/
|
|
20
|
-
export interface DataplaneEvent {
|
|
21
|
-
type: DataplaneEventType;
|
|
22
|
-
timestamp: number;
|
|
23
|
-
data: Record<string, unknown>;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Callback for dataplane events
|
|
27
|
-
*/
|
|
28
|
-
export type DataplaneEventCallback = (event: DataplaneEvent) => void;
|
|
29
|
-
/**
|
|
30
|
-
* DataplaneAdapter wraps MultiAgentRepoTracker for macro-agent integration.
|
|
31
|
-
*
|
|
32
|
-
* Key responsibilities:
|
|
33
|
-
* - Initialize dataplane with shared or dedicated database
|
|
34
|
-
* - Emit events on dataplane operations
|
|
35
|
-
* - Provide simplified API for workspace management
|
|
36
|
-
*/
|
|
37
|
-
export declare class DataplaneAdapter {
|
|
38
|
-
private readonly tracker;
|
|
39
|
-
private readonly config;
|
|
40
|
-
private readonly eventListeners;
|
|
41
|
-
private readonly ownsDb;
|
|
42
|
-
/**
|
|
43
|
-
* Create a new DataplaneAdapter.
|
|
44
|
-
*
|
|
45
|
-
* @param config - Dataplane configuration
|
|
46
|
-
*/
|
|
47
|
-
constructor(config: DataplaneConfig);
|
|
48
|
-
/**
|
|
49
|
-
* Get whether dataplane is enabled.
|
|
50
|
-
*/
|
|
51
|
-
get enabled(): boolean;
|
|
52
|
-
/**
|
|
53
|
-
* Get the repository path.
|
|
54
|
-
*/
|
|
55
|
-
get repoPath(): string;
|
|
56
|
-
/**
|
|
57
|
-
* Get the underlying database connection.
|
|
58
|
-
* Use with caution - prefer adapter methods for operations.
|
|
59
|
-
*/
|
|
60
|
-
get db(): Database.Database;
|
|
61
|
-
/**
|
|
62
|
-
* Get the underlying tracker.
|
|
63
|
-
* Use with caution - prefer adapter methods for operations.
|
|
64
|
-
*/
|
|
65
|
-
get rawTracker(): MultiAgentRepoTracker;
|
|
66
|
-
/**
|
|
67
|
-
* Subscribe to dataplane events.
|
|
68
|
-
*
|
|
69
|
-
* @param callback - Function called when events occur
|
|
70
|
-
* @returns Unsubscribe function
|
|
71
|
-
*/
|
|
72
|
-
onEvent(callback: DataplaneEventCallback): () => void;
|
|
73
|
-
/**
|
|
74
|
-
* Emit an event to all listeners.
|
|
75
|
-
*/
|
|
76
|
-
private emit;
|
|
77
|
-
/**
|
|
78
|
-
* Create a new stream (integration branch).
|
|
79
|
-
*
|
|
80
|
-
* @param options - Stream creation options
|
|
81
|
-
* @returns Stream ID
|
|
82
|
-
*/
|
|
83
|
-
createStream(options: CreateStreamOptions): string;
|
|
84
|
-
/**
|
|
85
|
-
* Get a stream by ID.
|
|
86
|
-
*/
|
|
87
|
-
getStream(streamId: string): Stream | null;
|
|
88
|
-
/**
|
|
89
|
-
* List streams with optional filters.
|
|
90
|
-
*/
|
|
91
|
-
listStreams(options?: {
|
|
92
|
-
agentId?: string;
|
|
93
|
-
status?: StreamStatus;
|
|
94
|
-
}): Stream[];
|
|
95
|
-
/**
|
|
96
|
-
* Update a stream.
|
|
97
|
-
*/
|
|
98
|
-
updateStream(streamId: string, updates: Partial<Pick<Stream, 'name' | 'status' | 'metadata'>>): void;
|
|
99
|
-
/**
|
|
100
|
-
* Abandon a stream.
|
|
101
|
-
*/
|
|
102
|
-
abandonStream(streamId: string, options?: {
|
|
103
|
-
reason?: string;
|
|
104
|
-
cascade?: boolean;
|
|
105
|
-
}): void;
|
|
106
|
-
/**
|
|
107
|
-
* Get the git branch name for a stream.
|
|
108
|
-
*/
|
|
109
|
-
getStreamBranchName(streamId: string): string;
|
|
110
|
-
/**
|
|
111
|
-
* Get the HEAD commit of a stream.
|
|
112
|
-
*/
|
|
113
|
-
getStreamHead(streamId: string): string;
|
|
114
|
-
/**
|
|
115
|
-
* Create a worktree for an agent.
|
|
116
|
-
*
|
|
117
|
-
* @param options - Worktree creation options
|
|
118
|
-
* @returns Created worktree info
|
|
119
|
-
*/
|
|
120
|
-
createWorktree(options: CreateWorktreeOptions): AgentWorktree;
|
|
121
|
-
/**
|
|
122
|
-
* Get a worktree by agent ID.
|
|
123
|
-
*/
|
|
124
|
-
getWorktree(agentId: string): AgentWorktree | null;
|
|
125
|
-
/**
|
|
126
|
-
* List all worktrees.
|
|
127
|
-
*/
|
|
128
|
-
listWorktrees(): AgentWorktree[];
|
|
129
|
-
/**
|
|
130
|
-
* Update the stream associated with a worktree.
|
|
131
|
-
*/
|
|
132
|
-
updateWorktreeStream(agentId: string, streamId: string | null): void;
|
|
133
|
-
/**
|
|
134
|
-
* Deallocate a worktree.
|
|
135
|
-
*/
|
|
136
|
-
deallocateWorktree(agentId: string): void;
|
|
137
|
-
/**
|
|
138
|
-
* Create a worker task under a stream.
|
|
139
|
-
*
|
|
140
|
-
* @param options - Task creation options
|
|
141
|
-
* @returns Task ID
|
|
142
|
-
*/
|
|
143
|
-
createTask(options: CreateTaskOptions): string;
|
|
144
|
-
/**
|
|
145
|
-
* Get a task by ID.
|
|
146
|
-
*/
|
|
147
|
-
getTask(taskId: string): WorkerTask | null;
|
|
148
|
-
/**
|
|
149
|
-
* List tasks for a stream.
|
|
150
|
-
*/
|
|
151
|
-
listTasks(streamId: string, options?: ListTasksOptions): WorkerTask[];
|
|
152
|
-
/**
|
|
153
|
-
* Start a task - assigns agent and creates worker branch.
|
|
154
|
-
*
|
|
155
|
-
* @param options - Start task options
|
|
156
|
-
* @returns Branch name and start commit
|
|
157
|
-
*/
|
|
158
|
-
startTask(options: StartTaskOptions): StartTaskResult;
|
|
159
|
-
/**
|
|
160
|
-
* Complete a task - merges worker branch to stream.
|
|
161
|
-
*
|
|
162
|
-
* @param options - Complete task options
|
|
163
|
-
* @returns Merge result
|
|
164
|
-
*/
|
|
165
|
-
completeTask(options: CompleteTaskOptions): CompleteTaskResult;
|
|
166
|
-
/**
|
|
167
|
-
* Abandon a task.
|
|
168
|
-
*
|
|
169
|
-
* @param taskId - Task ID
|
|
170
|
-
* @param options - Options
|
|
171
|
-
*/
|
|
172
|
-
abandonTask(taskId: string, options?: {
|
|
173
|
-
deleteBranch?: boolean;
|
|
174
|
-
}): void;
|
|
175
|
-
/**
|
|
176
|
-
* Release a task back to 'open' status.
|
|
177
|
-
*/
|
|
178
|
-
releaseTask(taskId: string): void;
|
|
179
|
-
/**
|
|
180
|
-
* Detect conflicts for a task before completing.
|
|
181
|
-
*
|
|
182
|
-
* @param taskId - Task ID
|
|
183
|
-
* @param worktree - Worktree path
|
|
184
|
-
* @returns Array of conflicting file paths, empty if no conflicts
|
|
185
|
-
*/
|
|
186
|
-
detectTaskConflicts(taskId: string, worktree: string): string[];
|
|
187
|
-
/**
|
|
188
|
-
* Recover stale tasks that have been in_progress too long.
|
|
189
|
-
*
|
|
190
|
-
* @param thresholdMs - Tasks older than this are considered stale
|
|
191
|
-
* @returns Result with released task IDs
|
|
192
|
-
*/
|
|
193
|
-
recoverStaleTasks(thresholdMs?: number): {
|
|
194
|
-
released: string[];
|
|
195
|
-
};
|
|
196
|
-
/**
|
|
197
|
-
* Create checkpoints for commits made during a task.
|
|
198
|
-
*
|
|
199
|
-
* Creates a checkpoint for each commit between the task's startCommit and
|
|
200
|
-
* the current HEAD of the task's stream. This captures the work done during
|
|
201
|
-
* the task for future review and merge workflows.
|
|
202
|
-
*
|
|
203
|
-
* @param taskId - Task ID to create checkpoints for
|
|
204
|
-
* @param agentId - Agent ID (used as createdBy)
|
|
205
|
-
* @returns Array of created checkpoints
|
|
206
|
-
*/
|
|
207
|
-
createCheckpointsForTask(taskId: string, agentId: string): Checkpoint[];
|
|
208
|
-
/**
|
|
209
|
-
* Commit changes in a worktree with Change tracking.
|
|
210
|
-
*
|
|
211
|
-
* @param options - Commit options
|
|
212
|
-
* @returns Commit hash and change ID
|
|
213
|
-
*/
|
|
214
|
-
commitChanges(options: {
|
|
215
|
-
streamId: string;
|
|
216
|
-
agentId: string;
|
|
217
|
-
worktree: string;
|
|
218
|
-
message: string;
|
|
219
|
-
}): {
|
|
220
|
-
commit: string;
|
|
221
|
-
changeId: string;
|
|
222
|
-
};
|
|
223
|
-
/**
|
|
224
|
-
* Clean up old worker branches.
|
|
225
|
-
*
|
|
226
|
-
* Deletes branches for:
|
|
227
|
-
* - Completed tasks older than threshold (default 24h)
|
|
228
|
-
* - Abandoned tasks
|
|
229
|
-
* - Orphaned branches (no task record)
|
|
230
|
-
*
|
|
231
|
-
* @param options - Cleanup options
|
|
232
|
-
* @returns Deleted branches and any errors
|
|
233
|
-
*/
|
|
234
|
-
cleanupWorkerBranches(options?: CleanupWorkerBranchesOptions): CleanupResult;
|
|
235
|
-
/**
|
|
236
|
-
* Delete a specific worker branch.
|
|
237
|
-
*
|
|
238
|
-
* @param branchName - Branch name to delete
|
|
239
|
-
* @returns true if deleted, false if branch didn't exist
|
|
240
|
-
*/
|
|
241
|
-
deleteWorkerBranch(branchName: string): boolean;
|
|
242
|
-
/**
|
|
243
|
-
* Check system health.
|
|
244
|
-
*/
|
|
245
|
-
healthCheck(): ReturnType<MultiAgentRepoTracker['healthCheck']>;
|
|
246
|
-
/**
|
|
247
|
-
* Close the adapter and release resources.
|
|
248
|
-
*
|
|
249
|
-
* Only closes the database if we created it (not if using shared DB).
|
|
250
|
-
*/
|
|
251
|
-
close(): void;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Create a DataplaneAdapter instance.
|
|
255
|
-
*
|
|
256
|
-
* @param config - Configuration options
|
|
257
|
-
* @returns DataplaneAdapter instance
|
|
258
|
-
*/
|
|
259
|
-
export declare function createDataplaneAdapter(config: DataplaneConfig): DataplaneAdapter;
|
|
260
|
-
//# sourceMappingURL=dataplane-adapter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dataplane-adapter.d.ts","sourceRoot":"","sources":["../../src/workspace/dataplane-adapter.ts"],"names":[],"mappings":"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"}
|