bridge-agent 0.17.1 → 0.18.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/dist/bridge-mcp.cjs +302 -82
- package/dist/index.js +87 -79
- package/package.json +1 -1
package/dist/bridge-mcp.cjs
CHANGED
|
@@ -1299,21 +1299,21 @@ var require_errors = __commonJS({
|
|
|
1299
1299
|
function extendErrors({ gen, keyword, schemaValue, data, errsCount, it }) {
|
|
1300
1300
|
if (errsCount === void 0)
|
|
1301
1301
|
throw new Error("ajv implementation error");
|
|
1302
|
-
const
|
|
1302
|
+
const err6 = gen.name("err");
|
|
1303
1303
|
gen.forRange("i", errsCount, names_1.default.errors, (i) => {
|
|
1304
|
-
gen.const(
|
|
1305
|
-
gen.if((0, codegen_1._)`${
|
|
1306
|
-
gen.assign((0, codegen_1._)`${
|
|
1304
|
+
gen.const(err6, (0, codegen_1._)`${names_1.default.vErrors}[${i}]`);
|
|
1305
|
+
gen.if((0, codegen_1._)`${err6}.instancePath === undefined`, () => gen.assign((0, codegen_1._)`${err6}.instancePath`, (0, codegen_1.strConcat)(names_1.default.instancePath, it.errorPath)));
|
|
1306
|
+
gen.assign((0, codegen_1._)`${err6}.schemaPath`, (0, codegen_1.str)`${it.errSchemaPath}/${keyword}`);
|
|
1307
1307
|
if (it.opts.verbose) {
|
|
1308
|
-
gen.assign((0, codegen_1._)`${
|
|
1309
|
-
gen.assign((0, codegen_1._)`${
|
|
1308
|
+
gen.assign((0, codegen_1._)`${err6}.schema`, schemaValue);
|
|
1309
|
+
gen.assign((0, codegen_1._)`${err6}.data`, data);
|
|
1310
1310
|
}
|
|
1311
1311
|
});
|
|
1312
1312
|
}
|
|
1313
1313
|
exports2.extendErrors = extendErrors;
|
|
1314
1314
|
function addError(gen, errObj) {
|
|
1315
|
-
const
|
|
1316
|
-
gen.if((0, codegen_1._)`${names_1.default.vErrors} === null`, () => gen.assign(names_1.default.vErrors, (0, codegen_1._)`[${
|
|
1315
|
+
const err6 = gen.const("err", errObj);
|
|
1316
|
+
gen.if((0, codegen_1._)`${names_1.default.vErrors} === null`, () => gen.assign(names_1.default.vErrors, (0, codegen_1._)`[${err6}]`), (0, codegen_1._)`${names_1.default.vErrors}.push(${err6})`);
|
|
1317
1317
|
gen.code((0, codegen_1._)`${names_1.default.errors}++`);
|
|
1318
1318
|
}
|
|
1319
1319
|
function returnErrors(it, errs) {
|
|
@@ -7541,8 +7541,8 @@ var ZodType = class {
|
|
|
7541
7541
|
} : {
|
|
7542
7542
|
issues: ctx.common.issues
|
|
7543
7543
|
};
|
|
7544
|
-
} catch (
|
|
7545
|
-
if (
|
|
7544
|
+
} catch (err6) {
|
|
7545
|
+
if (err6?.message?.toLowerCase()?.includes("encountered")) {
|
|
7546
7546
|
this["~standard"].async = true;
|
|
7547
7547
|
}
|
|
7548
7548
|
ctx.common = {
|
|
@@ -21243,16 +21243,16 @@ var handleFetchError = (e) => new Response(null, {
|
|
|
21243
21243
|
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
|
21244
21244
|
});
|
|
21245
21245
|
var handleResponseError = (e, outgoing) => {
|
|
21246
|
-
const
|
|
21247
|
-
if (
|
|
21246
|
+
const err6 = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
|
21247
|
+
if (err6.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
|
21248
21248
|
console.info("The user aborted a request.");
|
|
21249
21249
|
} else {
|
|
21250
21250
|
console.error(e);
|
|
21251
21251
|
if (!outgoing.headersSent) {
|
|
21252
21252
|
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
|
21253
21253
|
}
|
|
21254
|
-
outgoing.end(`Error: ${
|
|
21255
|
-
outgoing.destroy(
|
|
21254
|
+
outgoing.end(`Error: ${err6.message}`);
|
|
21255
|
+
outgoing.destroy(err6);
|
|
21256
21256
|
}
|
|
21257
21257
|
};
|
|
21258
21258
|
var flushHeaders = (outgoing) => {
|
|
@@ -21309,8 +21309,8 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
21309
21309
|
if (options.errorHandler) {
|
|
21310
21310
|
try {
|
|
21311
21311
|
res = await res;
|
|
21312
|
-
} catch (
|
|
21313
|
-
const errRes = await options.errorHandler(
|
|
21312
|
+
} catch (err6) {
|
|
21313
|
+
const errRes = await options.errorHandler(err6);
|
|
21314
21314
|
if (!errRes) {
|
|
21315
21315
|
return;
|
|
21316
21316
|
}
|
|
@@ -22300,19 +22300,20 @@ async function request(ctx, method, url, body, opts) {
|
|
|
22300
22300
|
throw new Error(message || `HTTP ${res.status}`);
|
|
22301
22301
|
}
|
|
22302
22302
|
return res.json();
|
|
22303
|
-
} catch (
|
|
22303
|
+
} catch (err6) {
|
|
22304
22304
|
clearTimeout(timer);
|
|
22305
|
-
if (
|
|
22305
|
+
if (err6 instanceof Error && err6.name === "AbortError") {
|
|
22306
22306
|
throw new Error(`Request timed out after ${timeoutMs}ms: ${method} ${url}`);
|
|
22307
22307
|
}
|
|
22308
|
-
throw
|
|
22308
|
+
throw err6;
|
|
22309
22309
|
}
|
|
22310
22310
|
}
|
|
22311
22311
|
async function getProject(ctx) {
|
|
22312
22312
|
return request(ctx, "GET", projectPath(ctx));
|
|
22313
22313
|
}
|
|
22314
22314
|
async function updateProject(ctx, description) {
|
|
22315
|
-
|
|
22315
|
+
const res = await request(ctx, "PATCH", projectPath(ctx), { description });
|
|
22316
|
+
return res.project;
|
|
22316
22317
|
}
|
|
22317
22318
|
async function getTodos(ctx, scope) {
|
|
22318
22319
|
const qs = scope === "active" ? "?scope=active" : "";
|
|
@@ -22392,9 +22393,12 @@ async function killAgent(ctx, agentId) {
|
|
|
22392
22393
|
async function assignTask(ctx, todoId, agentId) {
|
|
22393
22394
|
return request(ctx, "POST", projectPath(ctx, `/todos/${todoId}/assign`), { agentId });
|
|
22394
22395
|
}
|
|
22395
|
-
async function getAgentOutput(ctx, agentId, lines) {
|
|
22396
|
-
const
|
|
22397
|
-
|
|
22396
|
+
async function getAgentOutput(ctx, agentId, lines, cursor) {
|
|
22397
|
+
const params = new URLSearchParams();
|
|
22398
|
+
if (lines !== void 0) params.set("lines", String(lines));
|
|
22399
|
+
if (cursor) params.set("cursor", cursor);
|
|
22400
|
+
const qs = params.toString();
|
|
22401
|
+
return request(ctx, "GET", projectPath(ctx, `/panels/${agentId}/output${qs ? `?${qs}` : ""}`));
|
|
22398
22402
|
}
|
|
22399
22403
|
async function sendAgentInput(ctx, agentId, text) {
|
|
22400
22404
|
return request(ctx, "POST", workspacePath(ctx, `/agents/${agentId}/input`), { text });
|
|
@@ -22533,9 +22537,37 @@ function registerPlanTools(server, ctx) {
|
|
|
22533
22537
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
22534
22538
|
}
|
|
22535
22539
|
);
|
|
22540
|
+
server.tool(
|
|
22541
|
+
"bridge_get_blueprint",
|
|
22542
|
+
"Get the project blueprint \u2014 the architecture/conventions/features/decisions markdown doc for this project. Returns { blueprint, updatedAt }; updatedAt is null when the blueprint was never seeded.",
|
|
22543
|
+
{},
|
|
22544
|
+
async () => {
|
|
22545
|
+
const project = await getProject(ctx);
|
|
22546
|
+
return {
|
|
22547
|
+
content: [{
|
|
22548
|
+
type: "text",
|
|
22549
|
+
text: JSON.stringify({ blueprint: project.description ?? "", updatedAt: project.blueprintUpdatedAt ?? null })
|
|
22550
|
+
}]
|
|
22551
|
+
};
|
|
22552
|
+
}
|
|
22553
|
+
);
|
|
22554
|
+
server.tool(
|
|
22555
|
+
"bridge_update_blueprint",
|
|
22556
|
+
"Update the project blueprint markdown doc. Stored as the project description and immediately reflected in the Bridge UI. Returns { ok, blueprint, updatedAt }.",
|
|
22557
|
+
{ content: external_exports.string().describe("New blueprint content in Markdown") },
|
|
22558
|
+
async ({ content }) => {
|
|
22559
|
+
const project = await updateProject(ctx, content);
|
|
22560
|
+
return {
|
|
22561
|
+
content: [{
|
|
22562
|
+
type: "text",
|
|
22563
|
+
text: JSON.stringify({ ok: true, blueprint: project.description ?? "", updatedAt: project.blueprintUpdatedAt ?? null })
|
|
22564
|
+
}]
|
|
22565
|
+
};
|
|
22566
|
+
}
|
|
22567
|
+
);
|
|
22536
22568
|
server.tool(
|
|
22537
22569
|
"bridge_get_plan",
|
|
22538
|
-
"Get the current plan / spec for this Bridge project
|
|
22570
|
+
"DEPRECATED \u2014 use bridge_get_blueprint. Get the current plan / spec for this Bridge project (legacy { plan } response shape).",
|
|
22539
22571
|
{},
|
|
22540
22572
|
async () => {
|
|
22541
22573
|
const project = await getProject(ctx);
|
|
@@ -22549,14 +22581,14 @@ function registerPlanTools(server, ctx) {
|
|
|
22549
22581
|
);
|
|
22550
22582
|
server.tool(
|
|
22551
22583
|
"bridge_update_plan",
|
|
22552
|
-
"Update the plan / spec for this Bridge project
|
|
22584
|
+
"DEPRECATED \u2014 use bridge_update_blueprint. Update the plan / spec for this Bridge project (legacy response shape).",
|
|
22553
22585
|
{ content: external_exports.string().describe("New plan content in Markdown") },
|
|
22554
22586
|
async ({ content }) => {
|
|
22555
|
-
|
|
22587
|
+
await updateProject(ctx, content);
|
|
22556
22588
|
return {
|
|
22557
22589
|
content: [{
|
|
22558
22590
|
type: "text",
|
|
22559
|
-
text: JSON.stringify(
|
|
22591
|
+
text: JSON.stringify({ ok: true })
|
|
22560
22592
|
}]
|
|
22561
22593
|
};
|
|
22562
22594
|
}
|
|
@@ -22672,65 +22704,84 @@ var EVENT_ROLES = [...AGENT_ROLES, "system"];
|
|
|
22672
22704
|
// ../shared/dist/tool-registry.js
|
|
22673
22705
|
var BRIDGE_TOOL_DOCS = {
|
|
22674
22706
|
// Project / plan
|
|
22675
|
-
bridge_get_project: "Project metadata
|
|
22676
|
-
|
|
22677
|
-
|
|
22678
|
-
bridge_get_project_history: "Past
|
|
22679
|
-
bridge_get_execution_status: "Run history
|
|
22707
|
+
bridge_get_project: "Project metadata (name, cwd, machineId)",
|
|
22708
|
+
bridge_get_blueprint: "Read project blueprint doc ({blueprint, updatedAt})",
|
|
22709
|
+
bridge_update_blueprint: "Update project blueprint doc",
|
|
22710
|
+
bridge_get_project_history: "Past runs + failure patterns",
|
|
22711
|
+
bridge_get_execution_status: "Run history + todo completion counts",
|
|
22680
22712
|
// Todos
|
|
22681
|
-
bridge_get_todos: "List todos + session state
|
|
22682
|
-
bridge_add_todo: "Create
|
|
22683
|
-
bridge_update_todo: "Update
|
|
22684
|
-
bridge_cancel_run: "Cancel active run (
|
|
22713
|
+
bridge_get_todos: "List todos + session state",
|
|
22714
|
+
bridge_add_todo: "Create todo (title, todoType, dependsOn)",
|
|
22715
|
+
bridge_update_todo: "Update todo title/status",
|
|
22716
|
+
bridge_cancel_run: "Cancel active run (before restarting a stale plan)",
|
|
22685
22717
|
// Panel management
|
|
22686
|
-
bridge_list_agents: "All agents: role, status, inRun
|
|
22687
|
-
bridge_get_agent_status: "Single agent status
|
|
22688
|
-
bridge_spawn_worker: "Spawn
|
|
22689
|
-
bridge_kill_agent: "Terminate
|
|
22690
|
-
bridge_get_agent_output: "Read terminal output
|
|
22691
|
-
bridge_send_input: "Send text input to
|
|
22718
|
+
bridge_list_agents: "All agents: role, status, inRun",
|
|
22719
|
+
bridge_get_agent_status: "Single agent status",
|
|
22720
|
+
bridge_spawn_worker: "Spawn worker (agentKey, role)",
|
|
22721
|
+
bridge_kill_agent: "Terminate stuck/dead agent",
|
|
22722
|
+
bridge_get_agent_output: "Read agent terminal output (round-trip cursor = delta read)",
|
|
22723
|
+
bridge_send_input: "Send text input to agent PTY",
|
|
22692
22724
|
// Worker task lifecycle
|
|
22693
|
-
bridge_get_my_task: "
|
|
22725
|
+
bridge_get_my_task: "This agent's assigned task",
|
|
22694
22726
|
bridge_complete_task: "Signal task completion",
|
|
22695
|
-
bridge_fail_task: "Signal
|
|
22696
|
-
bridge_get_todo_context: "Read todo output/error
|
|
22697
|
-
bridge_assign_task: "Assign
|
|
22727
|
+
bridge_fail_task: "Signal failure with reason",
|
|
22728
|
+
bridge_get_todo_context: "Read a todo's output/error",
|
|
22729
|
+
bridge_assign_task: "Assign pending todo to an agent",
|
|
22698
22730
|
// Workspace scope (Phase 6)
|
|
22699
|
-
bridge_list_groups: "
|
|
22700
|
-
bridge_get_group_status: "
|
|
22701
|
-
bridge_dispatch_to_group: "Send
|
|
22702
|
-
|
|
22703
|
-
|
|
22704
|
-
|
|
22705
|
-
|
|
22706
|
-
|
|
22731
|
+
bridge_list_groups: "Groups + member agentIds",
|
|
22732
|
+
bridge_get_group_status: "Group agents: status + last output line",
|
|
22733
|
+
bridge_dispatch_to_group: "Send message to every agent in a group",
|
|
22734
|
+
bridge_create_group: "Create group (name, optional color)",
|
|
22735
|
+
bridge_update_group: "Rename/recolor a group",
|
|
22736
|
+
bridge_delete_group: "Delete a group",
|
|
22737
|
+
bridge_assign_agent_to_group: "Move agent into a group, or remove (groupId: null); orchestrators cannot join",
|
|
22738
|
+
bridge_list_workspace_projects: "Workspace projects: name, cwd, active run count",
|
|
22739
|
+
bridge_query_workspace: "Natural-language query of orchestration state",
|
|
22740
|
+
bridge_list_active_runs: "Active runs across workspace projects",
|
|
22741
|
+
bridge_peek_panel: "Read any panel output workspace-wide (cursor = delta read)",
|
|
22742
|
+
bridge_status_panel: "Status of any panel workspace-wide",
|
|
22707
22743
|
// Personas
|
|
22708
|
-
bridge_get_persona: "
|
|
22709
|
-
bridge_list_personas: "
|
|
22710
|
-
bridge_create_persona: "Create
|
|
22711
|
-
bridge_update_persona: "Update persona
|
|
22712
|
-
bridge_archive_persona: "Archive
|
|
22713
|
-
bridge_launch_persona: "Spawn
|
|
22714
|
-
bridge_apply_persona: "Apply persona
|
|
22744
|
+
bridge_get_persona: "Persona by id (name, systemPrompt, role, agentKey)",
|
|
22745
|
+
bridge_list_personas: "Visible personas (workspace + personal)",
|
|
22746
|
+
bridge_create_persona: "Create persona",
|
|
22747
|
+
bridge_update_persona: "Update persona fields",
|
|
22748
|
+
bridge_archive_persona: "Archive a persona",
|
|
22749
|
+
bridge_launch_persona: "Spawn worker with a persona",
|
|
22750
|
+
bridge_apply_persona: "Apply persona to a running worker",
|
|
22751
|
+
// Group Schemas (reusable team templates)
|
|
22752
|
+
bridge_list_group_schemas: "Reusable team/group schema templates",
|
|
22753
|
+
bridge_create_group_schema: "Create group schema from current groups",
|
|
22754
|
+
bridge_update_group_schema: "Update a group schema (name/slug/desc/color/groups/shared)",
|
|
22755
|
+
bridge_apply_group_schema: "Spawn a schema's groups and agents",
|
|
22756
|
+
// Agent Model Info
|
|
22757
|
+
bridge_list_agent_models: "Available models for an agent key on a daemon",
|
|
22715
22758
|
// Messaging
|
|
22716
|
-
bridge_send_message: "
|
|
22717
|
-
bridge_poll_messages: "Poll unread messages
|
|
22759
|
+
bridge_send_message: "Direct message to a peer agent",
|
|
22760
|
+
bridge_poll_messages: "Poll unread messages for this agent",
|
|
22718
22761
|
// Role Prompts
|
|
22719
|
-
bridge_list_role_prompts: "
|
|
22720
|
-
bridge_get_role_prompt: "Fetch resolved
|
|
22721
|
-
bridge_update_role_prompt: "Update custom role prompt
|
|
22722
|
-
bridge_delete_role_prompt: "Delete custom role prompt
|
|
22762
|
+
bridge_list_role_prompts: "Role prompt templates",
|
|
22763
|
+
bridge_get_role_prompt: "Fetch resolved role prompt",
|
|
22764
|
+
bridge_update_role_prompt: "Update custom role prompt",
|
|
22765
|
+
bridge_delete_role_prompt: "Delete custom role prompt",
|
|
22723
22766
|
// Events & Memory
|
|
22724
|
-
bridge_agent_is_idle: "
|
|
22725
|
-
bridge_record_event: "Record
|
|
22726
|
-
bridge_get_project_events: "
|
|
22727
|
-
bridge_get_project_memory: "
|
|
22728
|
-
bridge_update_todo_status: "Update todo status
|
|
22767
|
+
bridge_agent_is_idle: "Is agent PTY idle (ready for injection)",
|
|
22768
|
+
bridge_record_event: "Record event/constraint/blocker to orchestration memory",
|
|
22769
|
+
bridge_get_project_events: "Project events filtered by tags/permanence",
|
|
22770
|
+
bridge_get_project_memory: "Durable guardrails + constraints",
|
|
22771
|
+
bridge_update_todo_status: "Update todo status only"
|
|
22729
22772
|
};
|
|
22730
22773
|
if (Object.keys(BRIDGE_TOOL_DOCS).length === 0) {
|
|
22731
22774
|
throw new Error("BRIDGE_TOOL_DOCS registry is empty at module load \u2014 fail fast");
|
|
22732
22775
|
}
|
|
22733
22776
|
|
|
22777
|
+
// ../shared/dist/blueprint.js
|
|
22778
|
+
var BLUEPRINT_H1_AREAS = ["Frontend", "Backend", "Other"];
|
|
22779
|
+
var BLUEPRINT_H2_ASPECTS = ["Architecture", "Conventions", "Features", "Decisions"];
|
|
22780
|
+
var BLUEPRINT_DOC_TEMPLATE = BLUEPRINT_H1_AREAS.map((area) => `# ${area}
|
|
22781
|
+
|
|
22782
|
+
` + BLUEPRINT_H2_ASPECTS.map((aspect) => `## ${aspect}
|
|
22783
|
+
`).join("\n")).join("\n");
|
|
22784
|
+
|
|
22734
22785
|
// ../mcp-server/src/tools/orchestration.ts
|
|
22735
22786
|
function ok(data) {
|
|
22736
22787
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
@@ -22815,12 +22866,13 @@ function registerOrchestrationTools(server, ctx) {
|
|
|
22815
22866
|
);
|
|
22816
22867
|
server.tool(
|
|
22817
22868
|
"bridge_get_agent_output",
|
|
22818
|
-
"Read the last N lines of a panel's terminal output (ANSI codes stripped). Use this to check a dev server for errors, verify a build succeeded, or read a shell panel's result. Works on any agent type \u2014 dev servers, shells, AI agents.",
|
|
22869
|
+
"Read the last N lines of a panel's terminal output (ANSI codes stripped). Returns { output, cursor, cursor_reset }. Round-trip the returned cursor on the next call to get only new output (delta) \u2014 omit it for a full tail. cursor_reset: true means the cursor went stale (buffer evicted or panel respawned) and a full tail was returned. Use this to check a dev server for errors, verify a build succeeded, or read a shell panel's result. Works on any agent type \u2014 dev servers, shells, AI agents.",
|
|
22819
22870
|
{
|
|
22820
22871
|
agentId: external_exports.string().describe("The agent ID to read"),
|
|
22821
|
-
lines: external_exports.number().int().min(1).max(300).optional().describe("Trailing lines
|
|
22872
|
+
lines: external_exports.number().int().min(1).max(300).optional().describe("Trailing lines for full-tail reads (default 50, max 300); delta reads return all new lines"),
|
|
22873
|
+
cursor: external_exports.string().optional().describe("Opaque cursor from a previous response \u2014 pass it back to receive only new output since that read")
|
|
22822
22874
|
},
|
|
22823
|
-
({ agentId, lines }) => safe(() => getAgentOutput(ctx, agentId, lines))
|
|
22875
|
+
({ agentId, lines, cursor }) => safe(() => getAgentOutput(ctx, agentId, lines, cursor))
|
|
22824
22876
|
);
|
|
22825
22877
|
server.tool(
|
|
22826
22878
|
"bridge_send_input",
|
|
@@ -23000,12 +23052,19 @@ function registerWorkspaceTools(server, ctx) {
|
|
|
23000
23052
|
);
|
|
23001
23053
|
server.tool(
|
|
23002
23054
|
"bridge_peek_panel",
|
|
23003
|
-
"Read the last N lines of a panel's terminal output. Project-scoped contexts may only peek at their own project's panels (403 cross_project_block otherwise); workspace scope has no project boundary. Use this to check what a specific agent is doing.",
|
|
23055
|
+
"Read the last N lines of a panel's terminal output. Project-scoped contexts may only peek at their own project's panels (403 cross_project_block otherwise); workspace scope has no project boundary. Use this to check what a specific agent is doing. Returns { output, cursor, cursor_reset } \u2014 round-trip the cursor on the next call to get only new output (delta); omit it for a full tail.",
|
|
23004
23056
|
{
|
|
23005
23057
|
agentId: external_exports.string().describe("The panel/agent ID to peek at"),
|
|
23006
|
-
lines: external_exports.number().int().min(1).max(300).optional().describe("Trailing lines
|
|
23058
|
+
lines: external_exports.number().int().min(1).max(300).optional().describe("Trailing lines for full-tail reads (default 50, max 300); delta reads return all new lines"),
|
|
23059
|
+
cursor: external_exports.string().optional().describe("Opaque cursor from a previous response \u2014 pass it back to receive only new output since that read")
|
|
23007
23060
|
},
|
|
23008
|
-
({ agentId, lines }) => safe2(() =>
|
|
23061
|
+
({ agentId, lines, cursor }) => safe2(() => {
|
|
23062
|
+
const params = new URLSearchParams();
|
|
23063
|
+
if (lines !== void 0) params.set("lines", String(lines));
|
|
23064
|
+
if (cursor) params.set("cursor", cursor);
|
|
23065
|
+
const qs = params.toString();
|
|
23066
|
+
return request(ctx, "GET", workspacePath(ctx, `/agents/${agentId}/output${qs ? `?${qs}` : ""}`));
|
|
23067
|
+
})
|
|
23009
23068
|
);
|
|
23010
23069
|
server.tool(
|
|
23011
23070
|
"bridge_status_panel",
|
|
@@ -23013,6 +23072,49 @@ function registerWorkspaceTools(server, ctx) {
|
|
|
23013
23072
|
{ agentId: external_exports.string().describe("The panel/agent ID to inspect") },
|
|
23014
23073
|
({ agentId }) => safe2(() => request(ctx, "GET", workspacePath(ctx, `/agents/${agentId}`)))
|
|
23015
23074
|
);
|
|
23075
|
+
server.tool(
|
|
23076
|
+
"bridge_create_group",
|
|
23077
|
+
"Create a new agent group in the current project with an optional color.",
|
|
23078
|
+
{
|
|
23079
|
+
name: external_exports.string().min(1).max(64).describe("Human-readable group name"),
|
|
23080
|
+
color: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/).optional().describe("Hex color e.g. #6366f1")
|
|
23081
|
+
},
|
|
23082
|
+
({ name, color }) => safe2(() => {
|
|
23083
|
+
if (!ctx.projectId) throw new Error("Project-scoped context required");
|
|
23084
|
+
return request(ctx, "POST", workspacePath(ctx, `/projects/${ctx.projectId}/groups`), { name, color });
|
|
23085
|
+
})
|
|
23086
|
+
);
|
|
23087
|
+
server.tool(
|
|
23088
|
+
"bridge_update_group",
|
|
23089
|
+
"Rename or recolor an existing agent group.",
|
|
23090
|
+
{
|
|
23091
|
+
groupId: external_exports.string().describe("The group ID to update"),
|
|
23092
|
+
name: external_exports.string().min(1).max(64).optional().describe("New group name"),
|
|
23093
|
+
color: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/).optional().describe("New hex color e.g. #6366f1")
|
|
23094
|
+
},
|
|
23095
|
+
({ groupId, name, color }) => safe2(() => {
|
|
23096
|
+
if (!ctx.projectId) throw new Error("Project-scoped context required");
|
|
23097
|
+
return request(ctx, "PATCH", workspacePath(ctx, `/projects/${ctx.projectId}/groups/${groupId}`), { name, color });
|
|
23098
|
+
})
|
|
23099
|
+
);
|
|
23100
|
+
server.tool(
|
|
23101
|
+
"bridge_assign_agent_to_group",
|
|
23102
|
+
"Assign a running agent to a group (team), or remove it with groupId:null. Orchestrator panels cannot join groups. Project-scoped context required; the group must already exist (use bridge_create_group first).",
|
|
23103
|
+
{ agentId: external_exports.string().min(1), groupId: external_exports.string().nullable() },
|
|
23104
|
+
({ agentId, groupId }) => safe2(() => {
|
|
23105
|
+
if (!ctx.projectId) throw new Error("Project-scoped context required");
|
|
23106
|
+
return request(ctx, "PATCH", workspacePath(ctx, `/projects/${ctx.projectId}/agents/${agentId}/group`), { groupId });
|
|
23107
|
+
})
|
|
23108
|
+
);
|
|
23109
|
+
server.tool(
|
|
23110
|
+
"bridge_delete_group",
|
|
23111
|
+
"Delete an agent group. Members are detached but keep running.",
|
|
23112
|
+
{ groupId: external_exports.string().describe("The group ID to delete") },
|
|
23113
|
+
({ groupId }) => safe2(() => {
|
|
23114
|
+
if (!ctx.projectId) throw new Error("Project-scoped context required");
|
|
23115
|
+
return request(ctx, "DELETE", workspacePath(ctx, `/projects/${ctx.projectId}/groups/${groupId}`));
|
|
23116
|
+
})
|
|
23117
|
+
);
|
|
23016
23118
|
}
|
|
23017
23119
|
|
|
23018
23120
|
// ../mcp-server/src/tools/personas.ts
|
|
@@ -23188,6 +23290,123 @@ function registerRolePromptTools(server, ctx) {
|
|
|
23188
23290
|
);
|
|
23189
23291
|
}
|
|
23190
23292
|
|
|
23293
|
+
// ../mcp-server/src/tools/group-schemas.ts
|
|
23294
|
+
function ok5(data) {
|
|
23295
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
23296
|
+
}
|
|
23297
|
+
function err5(message) {
|
|
23298
|
+
return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: message }) }] };
|
|
23299
|
+
}
|
|
23300
|
+
async function safe5(fn) {
|
|
23301
|
+
try {
|
|
23302
|
+
return ok5(await fn());
|
|
23303
|
+
} catch (e) {
|
|
23304
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
23305
|
+
if (e instanceof Error && (e.name === "TypeError" || e.name === "ReferenceError")) {
|
|
23306
|
+
console.error("[mcp-bridge] unexpected error in group-schema tool handler", { name: e.name, message, stack: e.stack });
|
|
23307
|
+
}
|
|
23308
|
+
return err5(message);
|
|
23309
|
+
}
|
|
23310
|
+
}
|
|
23311
|
+
function registerGroupSchemaTools(server, ctx) {
|
|
23312
|
+
server.tool(
|
|
23313
|
+
"bridge_list_group_schemas",
|
|
23314
|
+
"List reusable team/group schema templates saved in this workspace. Returns name, slug, color, groupsJson payload, and metadata for each schema.",
|
|
23315
|
+
{
|
|
23316
|
+
scope: external_exports.enum(["personal", "workspace", "project"]).optional().describe("Scope filter"),
|
|
23317
|
+
projectId: external_exports.string().optional().describe("Filter to a specific project"),
|
|
23318
|
+
q: external_exports.string().optional().describe("Substring search on name")
|
|
23319
|
+
},
|
|
23320
|
+
({ scope, projectId, q }) => safe5(() => {
|
|
23321
|
+
let path = "/group-schemas";
|
|
23322
|
+
const params = new URLSearchParams();
|
|
23323
|
+
if (scope) params.set("scope", scope);
|
|
23324
|
+
if (projectId) params.set("projectId", projectId);
|
|
23325
|
+
if (q) params.set("q", q);
|
|
23326
|
+
const qs = params.toString();
|
|
23327
|
+
if (qs) path += "?" + qs;
|
|
23328
|
+
return request(ctx, "GET", workspacePath(ctx, path));
|
|
23329
|
+
})
|
|
23330
|
+
);
|
|
23331
|
+
server.tool(
|
|
23332
|
+
"bridge_apply_group_schema",
|
|
23333
|
+
"Apply a group schema template to spawn all its groups and agents in one call. Validates model availability against the target daemon. Returns created groups + agent IDs and any partial failures.",
|
|
23334
|
+
{
|
|
23335
|
+
schemaId: external_exports.string().describe("The group schema ID to apply"),
|
|
23336
|
+
projectId: external_exports.string().describe("Target project ID"),
|
|
23337
|
+
daemonId: external_exports.string().optional().describe("Target daemon ID (auto-resolves if omitted)"),
|
|
23338
|
+
mode: external_exports.enum(["auto-suffix", "replace"]).optional().describe("Name collision mode: auto-suffix (default) appends -2, -3, etc; replace reaps existing teams first")
|
|
23339
|
+
},
|
|
23340
|
+
({ schemaId, projectId, daemonId, mode }) => safe5(
|
|
23341
|
+
() => request(
|
|
23342
|
+
ctx,
|
|
23343
|
+
"POST",
|
|
23344
|
+
workspacePath(ctx, `/group-schemas/${schemaId}/apply`),
|
|
23345
|
+
{ projectId, daemonId, mode }
|
|
23346
|
+
)
|
|
23347
|
+
)
|
|
23348
|
+
);
|
|
23349
|
+
server.tool(
|
|
23350
|
+
"bridge_create_group_schema",
|
|
23351
|
+
"Create a reusable group schema template from the current project group setup. Serializes groups and agent slots into a template that can be applied later with bridge_apply_group_schema.",
|
|
23352
|
+
{
|
|
23353
|
+
name: external_exports.string().min(1).max(80).describe("Display name for the schema"),
|
|
23354
|
+
slug: external_exports.string().regex(/^[a-z][a-z0-9_]{1,62}$/).describe("Unique slug (lowercase, starts with letter, a-z0-9_ only, 2-63 chars)"),
|
|
23355
|
+
description: external_exports.string().max(200).optional().describe("Optional description"),
|
|
23356
|
+
color: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/).optional().describe("Hex colour for the schema card"),
|
|
23357
|
+
groupsJson: external_exports.any().optional().describe("GroupSchemaPayload: { version:1, groups:[{name, color?, slots:[{agentKey, model?, role?, count, cmd?}]}] }"),
|
|
23358
|
+
scope: external_exports.enum(["personal", "workspace", "project"]).optional().describe("Visibility scope (default: workspace)"),
|
|
23359
|
+
projectId: external_exports.string().optional().describe("Project ID (required if scope=project)")
|
|
23360
|
+
},
|
|
23361
|
+
({ name, slug, description, color, groupsJson, scope, projectId }) => safe5(
|
|
23362
|
+
() => request(
|
|
23363
|
+
ctx,
|
|
23364
|
+
"POST",
|
|
23365
|
+
workspacePath(ctx, "/group-schemas"),
|
|
23366
|
+
{ name, slug, description, color, groupsJson, scope, projectId }
|
|
23367
|
+
)
|
|
23368
|
+
)
|
|
23369
|
+
);
|
|
23370
|
+
server.tool(
|
|
23371
|
+
"bridge_update_group_schema",
|
|
23372
|
+
"Update an existing (non-archived) group schema template. Pass schemaId plus only the fields to change (name, slug, description, color, groupsJson, shared). Returns the updated schema.",
|
|
23373
|
+
{
|
|
23374
|
+
schemaId: external_exports.string().describe("The group schema ID to update"),
|
|
23375
|
+
name: external_exports.string().min(1).max(80).optional().describe("New display name"),
|
|
23376
|
+
slug: external_exports.string().regex(/^[a-z][a-z0-9_]{1,62}$/).optional().describe("New unique slug (lowercase, starts with letter, a-z0-9_, 2-63 chars)"),
|
|
23377
|
+
description: external_exports.string().max(200).optional().describe("New description"),
|
|
23378
|
+
color: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/).optional().describe("New hex colour e.g. #6366f1"),
|
|
23379
|
+
groupsJson: external_exports.any().optional().describe("Replacement GroupSchemaPayload: { version:1, groups:[{name, color?, slots:[{agentKey, model?, role?, count, cmd?}]}] }"),
|
|
23380
|
+
shared: external_exports.boolean().optional().describe("Workspace-scope only: mark the schema shared across the workspace")
|
|
23381
|
+
},
|
|
23382
|
+
({ schemaId, name, slug, description, color, groupsJson, shared }) => safe5(
|
|
23383
|
+
() => request(
|
|
23384
|
+
ctx,
|
|
23385
|
+
"PATCH",
|
|
23386
|
+
workspacePath(ctx, `/group-schemas/${schemaId}`),
|
|
23387
|
+
{ name, slug, description, color, groupsJson, shared }
|
|
23388
|
+
)
|
|
23389
|
+
)
|
|
23390
|
+
);
|
|
23391
|
+
server.tool(
|
|
23392
|
+
"bridge_list_agent_models",
|
|
23393
|
+
"List available models for an agent key on a target daemon. Validates model portability across machines; use before applying a group schema to verify required models exist.",
|
|
23394
|
+
{
|
|
23395
|
+
agentKey: external_exports.string().optional().describe("Filter by agent key (e.g. claude, kimi, qwen)"),
|
|
23396
|
+
daemonId: external_exports.string().optional().describe("Filter by daemon ID")
|
|
23397
|
+
},
|
|
23398
|
+
({ agentKey, daemonId }) => safe5(() => {
|
|
23399
|
+
let path = "/agent-models";
|
|
23400
|
+
const params = new URLSearchParams();
|
|
23401
|
+
if (agentKey) params.set("agentKey", agentKey);
|
|
23402
|
+
if (daemonId) params.set("daemonId", daemonId);
|
|
23403
|
+
const qs = params.toString();
|
|
23404
|
+
if (qs) path += "?" + qs;
|
|
23405
|
+
return request(ctx, "GET", workspacePath(ctx, path));
|
|
23406
|
+
})
|
|
23407
|
+
);
|
|
23408
|
+
}
|
|
23409
|
+
|
|
23191
23410
|
// ../mcp-server/src/index.ts
|
|
23192
23411
|
var sessions = /* @__PURE__ */ new Map();
|
|
23193
23412
|
function buildMcpServer(ctx) {
|
|
@@ -23199,6 +23418,7 @@ function buildMcpServer(ctx) {
|
|
|
23199
23418
|
registerWorkspaceTools(srv, ctx);
|
|
23200
23419
|
registerPersonaTools(srv, ctx);
|
|
23201
23420
|
registerRolePromptTools(srv, ctx);
|
|
23421
|
+
registerGroupSchemaTools(srv, ctx);
|
|
23202
23422
|
return srv;
|
|
23203
23423
|
}
|
|
23204
23424
|
async function parseBody(req) {
|
|
@@ -23303,8 +23523,8 @@ function startHttpServer() {
|
|
|
23303
23523
|
const mcpServer = buildMcpServer(ctx);
|
|
23304
23524
|
await mcpServer.connect(transport);
|
|
23305
23525
|
await transport.handleRequest(req, res, body);
|
|
23306
|
-
} catch (
|
|
23307
|
-
console.error("[bridge-mcp] request error:",
|
|
23526
|
+
} catch (err6) {
|
|
23527
|
+
console.error("[bridge-mcp] request error:", err6);
|
|
23308
23528
|
if (!res.headersSent) {
|
|
23309
23529
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
23310
23530
|
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
@@ -23339,8 +23559,8 @@ async function startStdioServer() {
|
|
|
23339
23559
|
if (process.env["HTTP_MODE"] !== "false") {
|
|
23340
23560
|
startHttpServer();
|
|
23341
23561
|
} else {
|
|
23342
|
-
startStdioServer().catch((
|
|
23343
|
-
console.error("[bridge-mcp] fatal:",
|
|
23562
|
+
startStdioServer().catch((err6) => {
|
|
23563
|
+
console.error("[bridge-mcp] fatal:", err6);
|
|
23344
23564
|
process.exit(1);
|
|
23345
23565
|
});
|
|
23346
23566
|
}
|