@particle-academy/agent-integrations 0.30.0 → 0.31.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/bridges/git.d.cts +44 -0
- package/dist/bridges/git.d.ts +44 -0
- package/dist/bridges-git.cjs +214 -0
- package/dist/bridges-git.cjs.map +1 -0
- package/dist/bridges-git.js +7 -0
- package/dist/bridges-git.js.map +1 -0
- package/dist/chunk-4D3II37O.js +94 -0
- package/dist/chunk-4D3II37O.js.map +1 -0
- package/dist/index.cjs +88 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/package.json +35 -7
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { T as ToolHost } from '../tool-host-EuYHYSSH.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-NFGP769G.cjs';
|
|
3
|
+
import '../types-C58ZXs4K.cjs';
|
|
4
|
+
|
|
5
|
+
type GitProposal = {
|
|
6
|
+
operation: string;
|
|
7
|
+
arguments: Record<string, unknown>;
|
|
8
|
+
summary: string;
|
|
9
|
+
};
|
|
10
|
+
type GitBridgeAdapter = {
|
|
11
|
+
status: () => Promise<unknown>;
|
|
12
|
+
log: (query: {
|
|
13
|
+
ref?: string;
|
|
14
|
+
limit?: number;
|
|
15
|
+
skip?: number;
|
|
16
|
+
}) => Promise<unknown>;
|
|
17
|
+
diff: (query: {
|
|
18
|
+
from?: string;
|
|
19
|
+
to?: string;
|
|
20
|
+
staged?: boolean;
|
|
21
|
+
paths?: string[];
|
|
22
|
+
}) => Promise<unknown>;
|
|
23
|
+
reviews?: (query: {
|
|
24
|
+
state?: string;
|
|
25
|
+
cursor?: string;
|
|
26
|
+
limit?: number;
|
|
27
|
+
}) => Promise<unknown>;
|
|
28
|
+
checks?: (revision: string) => Promise<unknown>;
|
|
29
|
+
propose: (operation: string, args: Record<string, unknown>) => Promise<GitProposal>;
|
|
30
|
+
applyProposal?: (proposal: GitProposal) => Promise<unknown>;
|
|
31
|
+
};
|
|
32
|
+
type GitBridgeOptions = {
|
|
33
|
+
adapter: GitBridgeAdapter;
|
|
34
|
+
agent?: {
|
|
35
|
+
id: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
color?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Defaults to proposal-only. Set true only when the host has its own confirmation policy. */
|
|
40
|
+
allowApply?: boolean;
|
|
41
|
+
};
|
|
42
|
+
declare function registerGitBridge(host: ToolHost, options: GitBridgeOptions): Bridge;
|
|
43
|
+
|
|
44
|
+
export { type GitBridgeAdapter, type GitBridgeOptions, type GitProposal, registerGitBridge };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { T as ToolHost } from '../tool-host-CWTOJEm2.js';
|
|
2
|
+
import { B as Bridge } from '../types-BKD6uf86.js';
|
|
3
|
+
import '../types-C58ZXs4K.js';
|
|
4
|
+
|
|
5
|
+
type GitProposal = {
|
|
6
|
+
operation: string;
|
|
7
|
+
arguments: Record<string, unknown>;
|
|
8
|
+
summary: string;
|
|
9
|
+
};
|
|
10
|
+
type GitBridgeAdapter = {
|
|
11
|
+
status: () => Promise<unknown>;
|
|
12
|
+
log: (query: {
|
|
13
|
+
ref?: string;
|
|
14
|
+
limit?: number;
|
|
15
|
+
skip?: number;
|
|
16
|
+
}) => Promise<unknown>;
|
|
17
|
+
diff: (query: {
|
|
18
|
+
from?: string;
|
|
19
|
+
to?: string;
|
|
20
|
+
staged?: boolean;
|
|
21
|
+
paths?: string[];
|
|
22
|
+
}) => Promise<unknown>;
|
|
23
|
+
reviews?: (query: {
|
|
24
|
+
state?: string;
|
|
25
|
+
cursor?: string;
|
|
26
|
+
limit?: number;
|
|
27
|
+
}) => Promise<unknown>;
|
|
28
|
+
checks?: (revision: string) => Promise<unknown>;
|
|
29
|
+
propose: (operation: string, args: Record<string, unknown>) => Promise<GitProposal>;
|
|
30
|
+
applyProposal?: (proposal: GitProposal) => Promise<unknown>;
|
|
31
|
+
};
|
|
32
|
+
type GitBridgeOptions = {
|
|
33
|
+
adapter: GitBridgeAdapter;
|
|
34
|
+
agent?: {
|
|
35
|
+
id: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
color?: string;
|
|
38
|
+
};
|
|
39
|
+
/** Defaults to proposal-only. Set true only when the host has its own confirmation policy. */
|
|
40
|
+
allowApply?: boolean;
|
|
41
|
+
};
|
|
42
|
+
declare function registerGitBridge(host: ToolHost, options: GitBridgeOptions): Bridge;
|
|
43
|
+
|
|
44
|
+
export { type GitBridgeAdapter, type GitBridgeOptions, type GitProposal, registerGitBridge };
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fancyAutoCommon = require('@particle-academy/fancy-auto-common');
|
|
4
|
+
|
|
5
|
+
// src/mcp/server.ts
|
|
6
|
+
function textResult(text, structured) {
|
|
7
|
+
return {
|
|
8
|
+
content: [{ type: "text", text }],
|
|
9
|
+
...structured !== void 0 ? { structuredContent: structured } : {}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function errorResult(text) {
|
|
13
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/presence/wrap-tool-with-activity.ts
|
|
17
|
+
function wrapToolWithActivity(handler, options) {
|
|
18
|
+
return async (args) => {
|
|
19
|
+
const result = await handler(args);
|
|
20
|
+
if (result.isError) return result;
|
|
21
|
+
let target;
|
|
22
|
+
if (options.resolveTarget) {
|
|
23
|
+
target = options.resolveTarget({ toolName: options.toolName, args, result });
|
|
24
|
+
} else {
|
|
25
|
+
target = { kind: options.kind, screenId: options.screenId };
|
|
26
|
+
}
|
|
27
|
+
if (!target) return result;
|
|
28
|
+
fancyAutoCommon.emitActivity({
|
|
29
|
+
agentId: options.agent.id,
|
|
30
|
+
agentName: options.agent.name,
|
|
31
|
+
agentColor: options.agent.color,
|
|
32
|
+
target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },
|
|
33
|
+
action: options.toolName,
|
|
34
|
+
timestamp: Date.now(),
|
|
35
|
+
meta: options.buildMeta ? options.buildMeta(result) : extractMeta(result),
|
|
36
|
+
ttlMs: options.ttlMs
|
|
37
|
+
});
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function extractMeta(result) {
|
|
42
|
+
const sc = result.structuredContent;
|
|
43
|
+
if (sc && typeof sc === "object" && !Array.isArray(sc)) {
|
|
44
|
+
return sc;
|
|
45
|
+
}
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/undo/undo-tools.ts
|
|
50
|
+
var installedHosts = /* @__PURE__ */ new WeakSet();
|
|
51
|
+
function ensureUndoToolsRegistered(host, options = {}) {
|
|
52
|
+
if (installedHosts.has(host)) return;
|
|
53
|
+
installedHosts.add(host);
|
|
54
|
+
registerUndoTools(host, options);
|
|
55
|
+
}
|
|
56
|
+
function registerUndoTools(host, options = {}) {
|
|
57
|
+
const defaultAgent = options.defaultAgentId ?? "agent";
|
|
58
|
+
const disposers = [];
|
|
59
|
+
const agentOf = (args) => typeof args?.agentId === "string" ? args.agentId : defaultAgent;
|
|
60
|
+
disposers.push(
|
|
61
|
+
host.registerTool(
|
|
62
|
+
{
|
|
63
|
+
name: "agent_undo",
|
|
64
|
+
description: "Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: { agentId: { type: "string" } },
|
|
68
|
+
additionalProperties: false
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
async (args) => {
|
|
72
|
+
const entry = await fancyAutoCommon.undoOne(agentOf(args));
|
|
73
|
+
if (!entry) return errorResult("Nothing to undo.");
|
|
74
|
+
return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
disposers.push(
|
|
79
|
+
host.registerTool(
|
|
80
|
+
{
|
|
81
|
+
name: "agent_redo",
|
|
82
|
+
description: "Redo the most recently undone action.",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: { agentId: { type: "string" } },
|
|
86
|
+
additionalProperties: false
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
async (args) => {
|
|
90
|
+
const entry = await fancyAutoCommon.redoOne(agentOf(args));
|
|
91
|
+
if (!entry) return errorResult("Nothing to redo.");
|
|
92
|
+
return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
disposers.push(
|
|
97
|
+
host.registerTool(
|
|
98
|
+
{
|
|
99
|
+
name: "agent_history",
|
|
100
|
+
description: "List the agent's undo stack (oldest first). Useful for understanding what's reversible.",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: { agentId: { type: "string" } },
|
|
104
|
+
additionalProperties: false
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
async (args) => {
|
|
108
|
+
const history = fancyAutoCommon.readHistory(agentOf(args)).map(serialize);
|
|
109
|
+
const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join("\n");
|
|
110
|
+
return textResult(text || "(empty)", history);
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
);
|
|
114
|
+
return () => disposers.forEach((d) => d());
|
|
115
|
+
}
|
|
116
|
+
function serialize(entry) {
|
|
117
|
+
return {
|
|
118
|
+
timestamp: entry.timestamp,
|
|
119
|
+
bridgeId: entry.bridgeId,
|
|
120
|
+
action: entry.action,
|
|
121
|
+
label: entry.label
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/bridges/git.ts
|
|
126
|
+
function registerGitBridge(host, options) {
|
|
127
|
+
const agent = { id: "agent", name: "Agent", color: "#a855f7", ...options.agent ?? {} };
|
|
128
|
+
const disposers = [];
|
|
129
|
+
ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
|
|
130
|
+
const reg = (name, description, properties, required, handler, mutation2 = false) => {
|
|
131
|
+
const wrapped = async (args) => {
|
|
132
|
+
try {
|
|
133
|
+
return await handler(args);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
return errorResult(error instanceof Error ? error.message : String(error));
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
const final = mutation2 ? wrapToolWithActivity(wrapped, {
|
|
139
|
+
toolName: name,
|
|
140
|
+
agent,
|
|
141
|
+
kind: "git",
|
|
142
|
+
resolveTarget: ({ args }) => ({ kind: "git", elementId: typeof args.path === "string" ? args.path : void 0 })
|
|
143
|
+
}) : wrapped;
|
|
144
|
+
disposers.push(host.registerTool({
|
|
145
|
+
name,
|
|
146
|
+
description,
|
|
147
|
+
inputSchema: { type: "object", properties, required, additionalProperties: false }
|
|
148
|
+
}, final));
|
|
149
|
+
};
|
|
150
|
+
reg("git_status", "Read normalized working-tree and branch status.", {}, [], async () => {
|
|
151
|
+
const result = await options.adapter.status();
|
|
152
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
153
|
+
});
|
|
154
|
+
reg("git_log", "Read normalized commit history.", {
|
|
155
|
+
ref: { type: "string" },
|
|
156
|
+
limit: { type: "number" },
|
|
157
|
+
skip: { type: "number" }
|
|
158
|
+
}, [], async (args) => {
|
|
159
|
+
const result = await options.adapter.log(args);
|
|
160
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
161
|
+
});
|
|
162
|
+
reg("git_diff", "Read a normalized Git diff.", {
|
|
163
|
+
from: { type: "string" },
|
|
164
|
+
to: { type: "string" },
|
|
165
|
+
staged: { type: "boolean" },
|
|
166
|
+
paths: { type: "array", items: { type: "string" } }
|
|
167
|
+
}, [], async (args) => {
|
|
168
|
+
const result = await options.adapter.diff(args);
|
|
169
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
170
|
+
});
|
|
171
|
+
if (options.adapter.reviews) reg("git_reviews_list", "List normalized pull/merge requests.", {
|
|
172
|
+
state: { type: "string" },
|
|
173
|
+
cursor: { type: "string" },
|
|
174
|
+
limit: { type: "number" }
|
|
175
|
+
}, [], async (args) => {
|
|
176
|
+
const result = await options.adapter.reviews(args);
|
|
177
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
178
|
+
});
|
|
179
|
+
if (options.adapter.checks) reg("git_checks", "Read checks or pipeline summaries for a revision.", {
|
|
180
|
+
revision: { type: "string" }
|
|
181
|
+
}, ["revision"], async (args) => {
|
|
182
|
+
const result = await options.adapter.checks(String(args.revision));
|
|
183
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
184
|
+
});
|
|
185
|
+
const mutation = (name, description, properties, required) => reg(name, description, properties, required, async (args) => {
|
|
186
|
+
const proposal = await options.adapter.propose(name.slice(4), args);
|
|
187
|
+
if (args.apply === true) {
|
|
188
|
+
if (!options.allowApply || !options.adapter.applyProposal) return errorResult("This host requires human confirmation before applying Git writes.");
|
|
189
|
+
const result = await options.adapter.applyProposal(proposal);
|
|
190
|
+
return textResult(`Applied: ${proposal.summary}`, result);
|
|
191
|
+
}
|
|
192
|
+
return textResult(`Proposed: ${proposal.summary}`, proposal);
|
|
193
|
+
}, true);
|
|
194
|
+
mutation("git_stage", "Propose staging paths.", { paths: { type: "array", items: { type: "string" } }, apply: { type: "boolean" } }, ["paths"]);
|
|
195
|
+
mutation("git_unstage", "Propose unstaging paths.", { paths: { type: "array", items: { type: "string" } }, apply: { type: "boolean" } }, ["paths"]);
|
|
196
|
+
mutation("git_commit", "Propose committing staged changes.", { message: { type: "string" }, apply: { type: "boolean" } }, ["message"]);
|
|
197
|
+
mutation("git_checkout", "Propose checking out a ref.", { target: { type: "string" }, apply: { type: "boolean" } }, ["target"]);
|
|
198
|
+
mutation("git_fetch", "Propose fetching a remote.", { remote: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
199
|
+
mutation("git_pull", "Propose a fast-forward-only pull.", { remote: { type: "string" }, branch: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
200
|
+
mutation("git_push", "Propose pushing a branch.", { remote: { type: "string" }, branch: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
201
|
+
mutation("git_review_create", "Propose creating a pull/merge request.", {
|
|
202
|
+
title: { type: "string" },
|
|
203
|
+
body: { type: "string" },
|
|
204
|
+
sourceBranch: { type: "string" },
|
|
205
|
+
targetBranch: { type: "string" },
|
|
206
|
+
draft: { type: "boolean" },
|
|
207
|
+
apply: { type: "boolean" }
|
|
208
|
+
}, ["title", "sourceBranch", "targetBranch"]);
|
|
209
|
+
return { id: "git", title: "Git", dispose: () => disposers.forEach((dispose) => dispose()) };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
exports.registerGitBridge = registerGitBridge;
|
|
213
|
+
//# sourceMappingURL=bridges-git.cjs.map
|
|
214
|
+
//# sourceMappingURL=bridges-git.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/server.ts","../src/presence/wrap-tool-with-activity.ts","../src/undo/undo-tools.ts","../src/bridges/git.ts"],"names":["emitActivity","undoOne","redoOne","readHistory","mutation"],"mappings":"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","file":"bridges-git.cjs","sourcesContent":["import {\n type CallToolResult,\n type JsonObject,\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcId,\n type RegisteredTool,\n type ServerCapabilities,\n type ServerInfo,\n type ToolDefinition,\n type ToolHandler,\n JSONRPC_INTERNAL_ERROR,\n JSONRPC_INVALID_PARAMS,\n JSONRPC_METHOD_NOT_FOUND,\n MCP_PROTOCOL_VERSION,\n} from \"./types\";\nimport { ToolRegistry } from \"./tool-host\";\n\nexport type McpServerOptions = {\n info: ServerInfo;\n /** Defaults to { tools: { listChanged: true } } */\n capabilities?: ServerCapabilities;\n /** Free-text instructions surfaced to clients during initialize. */\n instructions?: string;\n};\n\nexport type Transport = {\n /** Called by the server when it has a message to deliver to the client. */\n send: (message: JsonRpcMessage) => void;\n /** Called by the server when it's torn down so the transport can clean up. */\n close?: () => void;\n};\n\n/**\n * MicroMcpServer — protocol-level MCP server, transport-agnostic.\n *\n * Use it like:\n *\n * const server = new MicroMcpServer({ info: { name: \"session\", version: \"0.1\" } });\n * server.registerTool({ name: \"...\", inputSchema: { type: \"object\" } }, async (args) => ({...}));\n * const transport = new InProcessTransport();\n * server.attach(transport);\n * transport.deliver({ ... }); // client → server frames\n *\n * The same server can serve multiple transports (e.g. an in-process agent\n * AND a relayed external client) by attaching each one.\n */\nexport class MicroMcpServer extends ToolRegistry {\n private transports = new Set<Transport>();\n private notifyListChangedScheduled = false;\n\n readonly info: ServerInfo;\n readonly capabilities: ServerCapabilities;\n readonly instructions?: string;\n\n constructor(options: McpServerOptions) {\n super();\n this.info = options.info;\n this.capabilities = options.capabilities ?? { tools: { listChanged: true } };\n this.instructions = options.instructions;\n }\n\n attach(transport: Transport): () => void {\n this.transports.add(transport);\n return () => this.detach(transport);\n }\n\n detach(transport: Transport): void {\n if (this.transports.delete(transport)) {\n transport.close?.();\n }\n }\n\n unregisterTool(name: string): void {\n if (this.tools.delete(name)) {\n this.scheduleListChangedNotification();\n }\n }\n\n protected onToolsChanged(): void {\n this.scheduleListChangedNotification();\n }\n\n /**\n * Receive a JSON-RPC frame from a client (called by the transport).\n * The transport is responsible for sending the response back.\n */\n async receive(transport: Transport, message: JsonRpcMessage): Promise<void> {\n if (!(\"method\" in message)) return; // It's a response, not a request — ignore.\n\n const isNotification = !(\"id\" in message);\n if (isNotification) {\n // Notifications are fire-and-forget. We ignore unknown methods.\n return;\n }\n\n const request = message as JsonRpcRequest;\n try {\n const result = await this.handle(request, transport);\n transport.send({ jsonrpc: \"2.0\", id: request.id, result });\n } catch (err) {\n transport.send({\n jsonrpc: \"2.0\",\n id: request.id,\n error: this.toRpcError(err),\n });\n }\n }\n\n private async handle(request: JsonRpcRequest, transport: Transport): Promise<any> {\n const { method, params } = request;\n switch (method) {\n case \"initialize\":\n return {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: this.capabilities,\n serverInfo: this.info,\n ...(this.instructions ? { instructions: this.instructions } : {}),\n };\n\n case \"tools/list\":\n return { tools: this.listTools() };\n\n case \"tools/call\": {\n const name = params?.name;\n const args = (params?.arguments ?? {}) as JsonObject;\n if (typeof name !== \"string\") {\n throw rpcError(JSONRPC_INVALID_PARAMS, \"tools/call requires `name`\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unknown tool: ${name}`);\n }\n const result = await tool.handler(args, { transport });\n return result satisfies CallToolResult;\n }\n\n case \"ping\":\n return {};\n\n default:\n throw rpcError(JSONRPC_METHOD_NOT_FOUND, `Unsupported method: ${method}`);\n }\n }\n\n private scheduleListChangedNotification(): void {\n if (this.notifyListChangedScheduled) return;\n this.notifyListChangedScheduled = true;\n queueMicrotask(() => {\n this.notifyListChangedScheduled = false;\n this.broadcast({ jsonrpc: \"2.0\", method: \"notifications/tools/list_changed\" });\n });\n }\n\n /** Send an application notification to every client, or one attached transport. */\n notify(message: JsonRpcMessage, transport?: Transport): void {\n if (transport) transport.send(message);\n else this.broadcast(message);\n }\n\n private broadcast(message: JsonRpcMessage): void {\n for (const t of this.transports) t.send(message);\n }\n\n private toRpcError(err: unknown): { code: number; message: string; data?: any } {\n if (err && typeof err === \"object\" && \"code\" in err && \"message\" in err) {\n return err as any;\n }\n return {\n code: JSONRPC_INTERNAL_ERROR,\n message: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function rpcError(code: number, message: string, data?: any) {\n return { code, message, ...(data !== undefined ? { data } : {}) };\n}\n\n/**\n * Helper to build a CallToolResult from a string or structured value.\n */\nexport function textResult(text: string, structured?: any): CallToolResult {\n return {\n content: [{ type: \"text\", text }],\n ...(structured !== undefined ? { structuredContent: structured } : {}),\n };\n}\n\nexport function errorResult(text: string): CallToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n\n// Internal helper so the JsonRpcId import isn't dropped by tsup\ntype _KeepIdImport = JsonRpcId;\n","import type { CallToolResult } from \"../mcp/types\";\nimport { emitActivity } from \"./registry\";\nimport type { AgentTarget } from \"./types\";\n\nexport type ActivityAgent = { id: string; name?: string; color?: string };\n\nexport type ActivityResolverContext<TArgs = Record<string, unknown>> = {\n /** Tool name as registered. */\n toolName: string;\n /** Arguments the tool was called with. */\n args: TArgs;\n /** The CallToolResult the underlying handler produced. */\n result: CallToolResult;\n};\n\n/**\n * Resolves an `AgentTarget` for an executed tool. Bridges declare one of\n * these per registration so the wrapper knows which surface / element /\n * screen the activity belongs to.\n *\n * The resolver runs AFTER the tool handler so it can inspect the result\n * (e.g. read a newly-created item id from `structuredContent`).\n */\nexport type ActivityTargetResolver<TArgs = Record<string, unknown>> = (\n ctx: ActivityResolverContext<TArgs>,\n) => AgentTarget | null;\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n) => Promise<CallToolResult> | CallToolResult;\n\n/**\n * wrapToolWithActivity — decorate a bridge tool handler so every successful\n * call emits an `AgentActivityEvent`. Returns a new handler with the same shape.\n *\n * Usage in a bridge:\n *\n * server.registerTool(\n * definition,\n * wrapToolWithActivity(\n * handler,\n * { agent, kind: \"whiteboard\", resolveTarget: ({ args }) => ({\n * kind: \"whiteboard\", elementId: args.id as string,\n * }) },\n * ),\n * );\n */\nexport function wrapToolWithActivity<TArgs = Record<string, unknown>>(\n handler: ToolHandler<TArgs>,\n options: {\n toolName: string;\n agent: ActivityAgent;\n /** Optional fancy-screens screen id this bridge is scoped to. */\n screenId?: string;\n /** Default target kind if the resolver returns one without `kind`. */\n kind: AgentTarget[\"kind\"];\n /** Per-call resolver. Return `null` to skip emitting (e.g. for read-only tools). */\n resolveTarget?: ActivityTargetResolver<TArgs>;\n /** Optional ttl override. */\n ttlMs?: number;\n /**\n * Build the `meta` broadcast to all relay peers. Defaults to the tool's full\n * `structuredContent`. Override to REDACT sensitive fields before fan-out —\n * e.g. the terminal bridge strips raw command/keystroke bytes so a command\n * line (or its secrets) is never broadcast verbatim to every peer.\n */\n buildMeta?: (result: CallToolResult) => Record<string, unknown> | undefined;\n },\n): ToolHandler<TArgs> {\n return async (args) => {\n const result = await handler(args);\n if (result.isError) return result;\n\n let target: AgentTarget | null;\n if (options.resolveTarget) {\n target = options.resolveTarget({ toolName: options.toolName, args, result });\n } else {\n target = { kind: options.kind, screenId: options.screenId };\n }\n if (!target) return result;\n\n emitActivity({\n agentId: options.agent.id,\n agentName: options.agent.name,\n agentColor: options.agent.color,\n target: { ...target, kind: target.kind ?? options.kind, screenId: target.screenId ?? options.screenId },\n action: options.toolName,\n timestamp: Date.now(),\n meta: options.buildMeta ? options.buildMeta(result) : extractMeta(result),\n ttlMs: options.ttlMs,\n });\n return result;\n };\n}\n\nfunction extractMeta(result: CallToolResult): Record<string, unknown> | undefined {\n const sc = result.structuredContent;\n if (sc && typeof sc === \"object\" && !Array.isArray(sc)) {\n return sc as Record<string, unknown>;\n }\n return undefined;\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport { readHistory, redoOne, undoOne } from \"./undo-stack\";\n\nexport type UndoToolsOptions = {\n /** Default agent id when the caller doesn't pass one. */\n defaultAgentId?: string;\n};\n\n/**\n * Idempotent tracker so multiple bridges on the same server only register\n * agent_undo / agent_redo / agent_history once.\n */\nconst installedHosts = new WeakSet<ToolHost>();\n\n/**\n * ensureUndoToolsRegistered — bridges call this on construction. Safe to\n * call repeatedly with the same server; subsequent calls are no-ops.\n */\nexport function ensureUndoToolsRegistered(host: ToolHost, options: UndoToolsOptions = {}): void {\n if (installedHosts.has(host)) return;\n installedHosts.add(host);\n registerUndoTools(host, options);\n}\n\n/**\n * registerUndoTools — add agent_undo / agent_redo / agent_history to the\n * server. Returns a disposer that unregisters all three.\n */\nexport function registerUndoTools(host: ToolHost, options: UndoToolsOptions = {}): () => void {\n const defaultAgent = options.defaultAgentId ?? \"agent\";\n const disposers: Array<() => void> = [];\n const agentOf = (args: any): string =>\n typeof args?.agentId === \"string\" ? args.agentId : defaultAgent;\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_undo\",\n description: \"Undo the most recent action on the agent's stack. Optional agentId targets a specific agent.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const entry = await undoOne(agentOf(args));\n if (!entry) return errorResult(\"Nothing to undo.\");\n return textResult(`Undid: ${entry.label}`, { entry: serialize(entry) });\n },\n ),\n );\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_redo\",\n description: \"Redo the most recently undone action.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const entry = await redoOne(agentOf(args));\n if (!entry) return errorResult(\"Nothing to redo.\");\n return textResult(`Redid: ${entry.label}`, { entry: serialize(entry) });\n },\n ),\n );\n\n disposers.push(\n host.registerTool(\n {\n name: \"agent_history\",\n description: \"List the agent's undo stack (oldest first). Useful for understanding what's reversible.\",\n inputSchema: {\n type: \"object\",\n properties: { agentId: { type: \"string\" } },\n additionalProperties: false,\n },\n },\n async (args) => {\n const history = readHistory(agentOf(args)).map(serialize);\n const text = history.map((e) => `${new Date(e.timestamp).toISOString()} ${e.bridgeId} ${e.action}: ${e.label}`).join(\"\\n\");\n return textResult(text || \"(empty)\", history);\n },\n ),\n );\n\n return () => disposers.forEach((d) => d());\n}\n\nfunction serialize(entry: import(\"./undo-stack\").UndoEntry) {\n return {\n timestamp: entry.timestamp,\n bridgeId: entry.bridgeId,\n action: entry.action,\n label: entry.label,\n };\n}\n","import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\nexport type GitProposal = {\n operation: string;\n arguments: Record<string, unknown>;\n summary: string;\n};\n\nexport type GitBridgeAdapter = {\n status: () => Promise<unknown>;\n log: (query: { ref?: string; limit?: number; skip?: number }) => Promise<unknown>;\n diff: (query: { from?: string; to?: string; staged?: boolean; paths?: string[] }) => Promise<unknown>;\n reviews?: (query: { state?: string; cursor?: string; limit?: number }) => Promise<unknown>;\n checks?: (revision: string) => Promise<unknown>;\n propose: (operation: string, args: Record<string, unknown>) => Promise<GitProposal>;\n applyProposal?: (proposal: GitProposal) => Promise<unknown>;\n};\n\nexport type GitBridgeOptions = {\n adapter: GitBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n /** Defaults to proposal-only. Set true only when the host has its own confirmation policy. */\n allowApply?: boolean;\n};\n\nexport function registerGitBridge(host: ToolHost, options: GitBridgeOptions): Bridge {\n const agent = { id: \"agent\", name: \"Agent\", color: \"#a855f7\", ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<unknown>,\n mutation = false,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (error) {\n return errorResult(error instanceof Error ? error.message : String(error));\n }\n };\n const final = mutation\n ? wrapToolWithActivity(wrapped as any, {\n toolName: name,\n agent,\n kind: \"git\",\n resolveTarget: ({ args }) => ({ kind: \"git\", elementId: typeof args.path === \"string\" ? args.path : undefined } as any),\n })\n : wrapped;\n disposers.push(host.registerTool({\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n }, final as any));\n };\n\n reg(\"git_status\", \"Read normalized working-tree and branch status.\", {}, [], async () => {\n const result = await options.adapter.status();\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n reg(\"git_log\", \"Read normalized commit history.\", {\n ref: { type: \"string\" }, limit: { type: \"number\" }, skip: { type: \"number\" },\n }, [], async (args) => {\n const result = await options.adapter.log(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n reg(\"git_diff\", \"Read a normalized Git diff.\", {\n from: { type: \"string\" }, to: { type: \"string\" }, staged: { type: \"boolean\" },\n paths: { type: \"array\", items: { type: \"string\" } },\n }, [], async (args) => {\n const result = await options.adapter.diff(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n if (options.adapter.reviews) reg(\"git_reviews_list\", \"List normalized pull/merge requests.\", {\n state: { type: \"string\" }, cursor: { type: \"string\" }, limit: { type: \"number\" },\n }, [], async (args) => {\n const result = await options.adapter.reviews!(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n if (options.adapter.checks) reg(\"git_checks\", \"Read checks or pipeline summaries for a revision.\", {\n revision: { type: \"string\" },\n }, [\"revision\"], async (args) => {\n const result = await options.adapter.checks!(String(args.revision));\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n\n const mutation = (name: string, description: string, properties: Record<string, unknown>, required: string[]) =>\n reg(name, description, properties, required, async (args) => {\n const proposal = await options.adapter.propose(name.slice(4), args);\n if (args.apply === true) {\n if (!options.allowApply || !options.adapter.applyProposal) return errorResult(\"This host requires human confirmation before applying Git writes.\");\n const result = await options.adapter.applyProposal(proposal);\n return textResult(`Applied: ${proposal.summary}`, result as any);\n }\n return textResult(`Proposed: ${proposal.summary}`, proposal as any);\n }, true);\n\n mutation(\"git_stage\", \"Propose staging paths.\", { paths: { type: \"array\", items: { type: \"string\" } }, apply: { type: \"boolean\" } }, [\"paths\"]);\n mutation(\"git_unstage\", \"Propose unstaging paths.\", { paths: { type: \"array\", items: { type: \"string\" } }, apply: { type: \"boolean\" } }, [\"paths\"]);\n mutation(\"git_commit\", \"Propose committing staged changes.\", { message: { type: \"string\" }, apply: { type: \"boolean\" } }, [\"message\"]);\n mutation(\"git_checkout\", \"Propose checking out a ref.\", { target: { type: \"string\" }, apply: { type: \"boolean\" } }, [\"target\"]);\n mutation(\"git_fetch\", \"Propose fetching a remote.\", { remote: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_pull\", \"Propose a fast-forward-only pull.\", { remote: { type: \"string\" }, branch: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_push\", \"Propose pushing a branch.\", { remote: { type: \"string\" }, branch: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_review_create\", \"Propose creating a pull/merge request.\", {\n title: { type: \"string\" }, body: { type: \"string\" }, sourceBranch: { type: \"string\" }, targetBranch: { type: \"string\" }, draft: { type: \"boolean\" }, apply: { type: \"boolean\" },\n }, [\"title\", \"sourceBranch\", \"targetBranch\"]);\n\n return { id: \"git\", title: \"Git\", dispose: () => disposers.forEach((dispose) => dispose()) };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { registerGitBridge } from './chunk-4D3II37O.js';
|
|
2
|
+
import './chunk-CT3LRNH7.js';
|
|
3
|
+
import './chunk-2VENWGLZ.js';
|
|
4
|
+
import './chunk-C3TYI5TJ.js';
|
|
5
|
+
import './chunk-DF3PLL2E.js';
|
|
6
|
+
//# sourceMappingURL=bridges-git.js.map
|
|
7
|
+
//# sourceMappingURL=bridges-git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"bridges-git.js"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ensureUndoToolsRegistered } from './chunk-CT3LRNH7.js';
|
|
2
|
+
import { wrapToolWithActivity } from './chunk-2VENWGLZ.js';
|
|
3
|
+
import { errorResult, textResult } from './chunk-DF3PLL2E.js';
|
|
4
|
+
|
|
5
|
+
// src/bridges/git.ts
|
|
6
|
+
function registerGitBridge(host, options) {
|
|
7
|
+
const agent = { id: "agent", name: "Agent", color: "#a855f7", ...options.agent ?? {} };
|
|
8
|
+
const disposers = [];
|
|
9
|
+
ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
|
|
10
|
+
const reg = (name, description, properties, required, handler, mutation2 = false) => {
|
|
11
|
+
const wrapped = async (args) => {
|
|
12
|
+
try {
|
|
13
|
+
return await handler(args);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
return errorResult(error instanceof Error ? error.message : String(error));
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const final = mutation2 ? wrapToolWithActivity(wrapped, {
|
|
19
|
+
toolName: name,
|
|
20
|
+
agent,
|
|
21
|
+
kind: "git",
|
|
22
|
+
resolveTarget: ({ args }) => ({ kind: "git", elementId: typeof args.path === "string" ? args.path : void 0 })
|
|
23
|
+
}) : wrapped;
|
|
24
|
+
disposers.push(host.registerTool({
|
|
25
|
+
name,
|
|
26
|
+
description,
|
|
27
|
+
inputSchema: { type: "object", properties, required, additionalProperties: false }
|
|
28
|
+
}, final));
|
|
29
|
+
};
|
|
30
|
+
reg("git_status", "Read normalized working-tree and branch status.", {}, [], async () => {
|
|
31
|
+
const result = await options.adapter.status();
|
|
32
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
33
|
+
});
|
|
34
|
+
reg("git_log", "Read normalized commit history.", {
|
|
35
|
+
ref: { type: "string" },
|
|
36
|
+
limit: { type: "number" },
|
|
37
|
+
skip: { type: "number" }
|
|
38
|
+
}, [], async (args) => {
|
|
39
|
+
const result = await options.adapter.log(args);
|
|
40
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
41
|
+
});
|
|
42
|
+
reg("git_diff", "Read a normalized Git diff.", {
|
|
43
|
+
from: { type: "string" },
|
|
44
|
+
to: { type: "string" },
|
|
45
|
+
staged: { type: "boolean" },
|
|
46
|
+
paths: { type: "array", items: { type: "string" } }
|
|
47
|
+
}, [], async (args) => {
|
|
48
|
+
const result = await options.adapter.diff(args);
|
|
49
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
50
|
+
});
|
|
51
|
+
if (options.adapter.reviews) reg("git_reviews_list", "List normalized pull/merge requests.", {
|
|
52
|
+
state: { type: "string" },
|
|
53
|
+
cursor: { type: "string" },
|
|
54
|
+
limit: { type: "number" }
|
|
55
|
+
}, [], async (args) => {
|
|
56
|
+
const result = await options.adapter.reviews(args);
|
|
57
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
58
|
+
});
|
|
59
|
+
if (options.adapter.checks) reg("git_checks", "Read checks or pipeline summaries for a revision.", {
|
|
60
|
+
revision: { type: "string" }
|
|
61
|
+
}, ["revision"], async (args) => {
|
|
62
|
+
const result = await options.adapter.checks(String(args.revision));
|
|
63
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
64
|
+
});
|
|
65
|
+
const mutation = (name, description, properties, required) => reg(name, description, properties, required, async (args) => {
|
|
66
|
+
const proposal = await options.adapter.propose(name.slice(4), args);
|
|
67
|
+
if (args.apply === true) {
|
|
68
|
+
if (!options.allowApply || !options.adapter.applyProposal) return errorResult("This host requires human confirmation before applying Git writes.");
|
|
69
|
+
const result = await options.adapter.applyProposal(proposal);
|
|
70
|
+
return textResult(`Applied: ${proposal.summary}`, result);
|
|
71
|
+
}
|
|
72
|
+
return textResult(`Proposed: ${proposal.summary}`, proposal);
|
|
73
|
+
}, true);
|
|
74
|
+
mutation("git_stage", "Propose staging paths.", { paths: { type: "array", items: { type: "string" } }, apply: { type: "boolean" } }, ["paths"]);
|
|
75
|
+
mutation("git_unstage", "Propose unstaging paths.", { paths: { type: "array", items: { type: "string" } }, apply: { type: "boolean" } }, ["paths"]);
|
|
76
|
+
mutation("git_commit", "Propose committing staged changes.", { message: { type: "string" }, apply: { type: "boolean" } }, ["message"]);
|
|
77
|
+
mutation("git_checkout", "Propose checking out a ref.", { target: { type: "string" }, apply: { type: "boolean" } }, ["target"]);
|
|
78
|
+
mutation("git_fetch", "Propose fetching a remote.", { remote: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
79
|
+
mutation("git_pull", "Propose a fast-forward-only pull.", { remote: { type: "string" }, branch: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
80
|
+
mutation("git_push", "Propose pushing a branch.", { remote: { type: "string" }, branch: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
81
|
+
mutation("git_review_create", "Propose creating a pull/merge request.", {
|
|
82
|
+
title: { type: "string" },
|
|
83
|
+
body: { type: "string" },
|
|
84
|
+
sourceBranch: { type: "string" },
|
|
85
|
+
targetBranch: { type: "string" },
|
|
86
|
+
draft: { type: "boolean" },
|
|
87
|
+
apply: { type: "boolean" }
|
|
88
|
+
}, ["title", "sourceBranch", "targetBranch"]);
|
|
89
|
+
return { id: "git", title: "Git", dispose: () => disposers.forEach((dispose) => dispose()) };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { registerGitBridge };
|
|
93
|
+
//# sourceMappingURL=chunk-4D3II37O.js.map
|
|
94
|
+
//# sourceMappingURL=chunk-4D3II37O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bridges/git.ts"],"names":["mutation"],"mappings":"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","file":"chunk-4D3II37O.js","sourcesContent":["import { textResult, errorResult } from \"../mcp/server\";\nimport type { ToolHost } from \"../mcp/tool-host\";\nimport type { JsonObject } from \"../mcp/types\";\nimport type { Bridge } from \"./types\";\nimport { wrapToolWithActivity } from \"../presence/wrap-tool-with-activity\";\nimport { ensureUndoToolsRegistered } from \"../undo/undo-tools\";\n\nexport type GitProposal = {\n operation: string;\n arguments: Record<string, unknown>;\n summary: string;\n};\n\nexport type GitBridgeAdapter = {\n status: () => Promise<unknown>;\n log: (query: { ref?: string; limit?: number; skip?: number }) => Promise<unknown>;\n diff: (query: { from?: string; to?: string; staged?: boolean; paths?: string[] }) => Promise<unknown>;\n reviews?: (query: { state?: string; cursor?: string; limit?: number }) => Promise<unknown>;\n checks?: (revision: string) => Promise<unknown>;\n propose: (operation: string, args: Record<string, unknown>) => Promise<GitProposal>;\n applyProposal?: (proposal: GitProposal) => Promise<unknown>;\n};\n\nexport type GitBridgeOptions = {\n adapter: GitBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n /** Defaults to proposal-only. Set true only when the host has its own confirmation policy. */\n allowApply?: boolean;\n};\n\nexport function registerGitBridge(host: ToolHost, options: GitBridgeOptions): Bridge {\n const agent = { id: \"agent\", name: \"Agent\", color: \"#a855f7\", ...(options.agent ?? {}) };\n const disposers: Array<() => void> = [];\n ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<unknown>,\n mutation = false,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (error) {\n return errorResult(error instanceof Error ? error.message : String(error));\n }\n };\n const final = mutation\n ? wrapToolWithActivity(wrapped as any, {\n toolName: name,\n agent,\n kind: \"git\",\n resolveTarget: ({ args }) => ({ kind: \"git\", elementId: typeof args.path === \"string\" ? args.path : undefined } as any),\n })\n : wrapped;\n disposers.push(host.registerTool({\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n }, final as any));\n };\n\n reg(\"git_status\", \"Read normalized working-tree and branch status.\", {}, [], async () => {\n const result = await options.adapter.status();\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n reg(\"git_log\", \"Read normalized commit history.\", {\n ref: { type: \"string\" }, limit: { type: \"number\" }, skip: { type: \"number\" },\n }, [], async (args) => {\n const result = await options.adapter.log(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n reg(\"git_diff\", \"Read a normalized Git diff.\", {\n from: { type: \"string\" }, to: { type: \"string\" }, staged: { type: \"boolean\" },\n paths: { type: \"array\", items: { type: \"string\" } },\n }, [], async (args) => {\n const result = await options.adapter.diff(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n if (options.adapter.reviews) reg(\"git_reviews_list\", \"List normalized pull/merge requests.\", {\n state: { type: \"string\" }, cursor: { type: \"string\" }, limit: { type: \"number\" },\n }, [], async (args) => {\n const result = await options.adapter.reviews!(args as any);\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n if (options.adapter.checks) reg(\"git_checks\", \"Read checks or pipeline summaries for a revision.\", {\n revision: { type: \"string\" },\n }, [\"revision\"], async (args) => {\n const result = await options.adapter.checks!(String(args.revision));\n return textResult(JSON.stringify(result, null, 2), result as any);\n });\n\n const mutation = (name: string, description: string, properties: Record<string, unknown>, required: string[]) =>\n reg(name, description, properties, required, async (args) => {\n const proposal = await options.adapter.propose(name.slice(4), args);\n if (args.apply === true) {\n if (!options.allowApply || !options.adapter.applyProposal) return errorResult(\"This host requires human confirmation before applying Git writes.\");\n const result = await options.adapter.applyProposal(proposal);\n return textResult(`Applied: ${proposal.summary}`, result as any);\n }\n return textResult(`Proposed: ${proposal.summary}`, proposal as any);\n }, true);\n\n mutation(\"git_stage\", \"Propose staging paths.\", { paths: { type: \"array\", items: { type: \"string\" } }, apply: { type: \"boolean\" } }, [\"paths\"]);\n mutation(\"git_unstage\", \"Propose unstaging paths.\", { paths: { type: \"array\", items: { type: \"string\" } }, apply: { type: \"boolean\" } }, [\"paths\"]);\n mutation(\"git_commit\", \"Propose committing staged changes.\", { message: { type: \"string\" }, apply: { type: \"boolean\" } }, [\"message\"]);\n mutation(\"git_checkout\", \"Propose checking out a ref.\", { target: { type: \"string\" }, apply: { type: \"boolean\" } }, [\"target\"]);\n mutation(\"git_fetch\", \"Propose fetching a remote.\", { remote: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_pull\", \"Propose a fast-forward-only pull.\", { remote: { type: \"string\" }, branch: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_push\", \"Propose pushing a branch.\", { remote: { type: \"string\" }, branch: { type: \"string\" }, apply: { type: \"boolean\" } }, []);\n mutation(\"git_review_create\", \"Propose creating a pull/merge request.\", {\n title: { type: \"string\" }, body: { type: \"string\" }, sourceBranch: { type: \"string\" }, targetBranch: { type: \"string\" }, draft: { type: \"boolean\" }, apply: { type: \"boolean\" },\n }, [\"title\", \"sourceBranch\", \"targetBranch\"]);\n\n return { id: \"git\", title: \"Git\", dispose: () => disposers.forEach((dispose) => dispose()) };\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -2508,6 +2508,93 @@ function registerMapBridge(host, options) {
|
|
|
2508
2508
|
};
|
|
2509
2509
|
}
|
|
2510
2510
|
|
|
2511
|
+
// src/bridges/git.ts
|
|
2512
|
+
function registerGitBridge(host, options) {
|
|
2513
|
+
const agent = { id: "agent", name: "Agent", color: "#a855f7", ...options.agent ?? {} };
|
|
2514
|
+
const disposers = [];
|
|
2515
|
+
ensureUndoToolsRegistered(host, { defaultAgentId: agent.id });
|
|
2516
|
+
const reg = (name, description, properties, required, handler, mutation2 = false) => {
|
|
2517
|
+
const wrapped = async (args) => {
|
|
2518
|
+
try {
|
|
2519
|
+
return await handler(args);
|
|
2520
|
+
} catch (error) {
|
|
2521
|
+
return errorResult(error instanceof Error ? error.message : String(error));
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
const final = mutation2 ? wrapToolWithActivity(wrapped, {
|
|
2525
|
+
toolName: name,
|
|
2526
|
+
agent,
|
|
2527
|
+
kind: "git",
|
|
2528
|
+
resolveTarget: ({ args }) => ({ kind: "git", elementId: typeof args.path === "string" ? args.path : void 0 })
|
|
2529
|
+
}) : wrapped;
|
|
2530
|
+
disposers.push(host.registerTool({
|
|
2531
|
+
name,
|
|
2532
|
+
description,
|
|
2533
|
+
inputSchema: { type: "object", properties, required, additionalProperties: false }
|
|
2534
|
+
}, final));
|
|
2535
|
+
};
|
|
2536
|
+
reg("git_status", "Read normalized working-tree and branch status.", {}, [], async () => {
|
|
2537
|
+
const result = await options.adapter.status();
|
|
2538
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
2539
|
+
});
|
|
2540
|
+
reg("git_log", "Read normalized commit history.", {
|
|
2541
|
+
ref: { type: "string" },
|
|
2542
|
+
limit: { type: "number" },
|
|
2543
|
+
skip: { type: "number" }
|
|
2544
|
+
}, [], async (args) => {
|
|
2545
|
+
const result = await options.adapter.log(args);
|
|
2546
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
2547
|
+
});
|
|
2548
|
+
reg("git_diff", "Read a normalized Git diff.", {
|
|
2549
|
+
from: { type: "string" },
|
|
2550
|
+
to: { type: "string" },
|
|
2551
|
+
staged: { type: "boolean" },
|
|
2552
|
+
paths: { type: "array", items: { type: "string" } }
|
|
2553
|
+
}, [], async (args) => {
|
|
2554
|
+
const result = await options.adapter.diff(args);
|
|
2555
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
2556
|
+
});
|
|
2557
|
+
if (options.adapter.reviews) reg("git_reviews_list", "List normalized pull/merge requests.", {
|
|
2558
|
+
state: { type: "string" },
|
|
2559
|
+
cursor: { type: "string" },
|
|
2560
|
+
limit: { type: "number" }
|
|
2561
|
+
}, [], async (args) => {
|
|
2562
|
+
const result = await options.adapter.reviews(args);
|
|
2563
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
2564
|
+
});
|
|
2565
|
+
if (options.adapter.checks) reg("git_checks", "Read checks or pipeline summaries for a revision.", {
|
|
2566
|
+
revision: { type: "string" }
|
|
2567
|
+
}, ["revision"], async (args) => {
|
|
2568
|
+
const result = await options.adapter.checks(String(args.revision));
|
|
2569
|
+
return textResult(JSON.stringify(result, null, 2), result);
|
|
2570
|
+
});
|
|
2571
|
+
const mutation = (name, description, properties, required) => reg(name, description, properties, required, async (args) => {
|
|
2572
|
+
const proposal = await options.adapter.propose(name.slice(4), args);
|
|
2573
|
+
if (args.apply === true) {
|
|
2574
|
+
if (!options.allowApply || !options.adapter.applyProposal) return errorResult("This host requires human confirmation before applying Git writes.");
|
|
2575
|
+
const result = await options.adapter.applyProposal(proposal);
|
|
2576
|
+
return textResult(`Applied: ${proposal.summary}`, result);
|
|
2577
|
+
}
|
|
2578
|
+
return textResult(`Proposed: ${proposal.summary}`, proposal);
|
|
2579
|
+
}, true);
|
|
2580
|
+
mutation("git_stage", "Propose staging paths.", { paths: { type: "array", items: { type: "string" } }, apply: { type: "boolean" } }, ["paths"]);
|
|
2581
|
+
mutation("git_unstage", "Propose unstaging paths.", { paths: { type: "array", items: { type: "string" } }, apply: { type: "boolean" } }, ["paths"]);
|
|
2582
|
+
mutation("git_commit", "Propose committing staged changes.", { message: { type: "string" }, apply: { type: "boolean" } }, ["message"]);
|
|
2583
|
+
mutation("git_checkout", "Propose checking out a ref.", { target: { type: "string" }, apply: { type: "boolean" } }, ["target"]);
|
|
2584
|
+
mutation("git_fetch", "Propose fetching a remote.", { remote: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
2585
|
+
mutation("git_pull", "Propose a fast-forward-only pull.", { remote: { type: "string" }, branch: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
2586
|
+
mutation("git_push", "Propose pushing a branch.", { remote: { type: "string" }, branch: { type: "string" }, apply: { type: "boolean" } }, []);
|
|
2587
|
+
mutation("git_review_create", "Propose creating a pull/merge request.", {
|
|
2588
|
+
title: { type: "string" },
|
|
2589
|
+
body: { type: "string" },
|
|
2590
|
+
sourceBranch: { type: "string" },
|
|
2591
|
+
targetBranch: { type: "string" },
|
|
2592
|
+
draft: { type: "boolean" },
|
|
2593
|
+
apply: { type: "boolean" }
|
|
2594
|
+
}, ["title", "sourceBranch", "targetBranch"]);
|
|
2595
|
+
return { id: "git", title: "Git", dispose: () => disposers.forEach((dispose) => dispose()) };
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2511
2598
|
// src/bridges/files.ts
|
|
2512
2599
|
var DEFAULT_AGENT9 = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
2513
2600
|
var MAX_SNAPSHOT_DEPTH = 8;
|
|
@@ -5578,6 +5665,7 @@ exports.registerDocBridge = registerDocBridge;
|
|
|
5578
5665
|
exports.registerFeaturesBridge = registerFeaturesBridge;
|
|
5579
5666
|
exports.registerFilesBridge = registerFilesBridge;
|
|
5580
5667
|
exports.registerFormBridge = registerFormBridge;
|
|
5668
|
+
exports.registerGitBridge = registerGitBridge;
|
|
5581
5669
|
exports.registerMapBridge = registerMapBridge;
|
|
5582
5670
|
exports.registerNavigationBridge = registerNavigationBridge;
|
|
5583
5671
|
exports.registerSceneBridge = registerSceneBridge;
|