@particle-academy/agent-integrations 0.9.1 → 0.11.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/terminal.d.cts +80 -0
- package/dist/bridges/terminal.d.ts +80 -0
- package/dist/bridges-terminal.cjs +332 -0
- package/dist/bridges-terminal.cjs.map +1 -0
- package/dist/bridges-terminal.js +7 -0
- package/dist/bridges-terminal.js.map +1 -0
- package/dist/chunk-FZ7Q5NS3.js +212 -0
- package/dist/chunk-FZ7Q5NS3.js.map +1 -0
- package/dist/index.cjs +282 -76
- 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 +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { T as ToolHost } from '../tool-host-BQuUygLF.cjs';
|
|
2
|
+
import { B as Bridge } from '../types-CCSBGW9T.cjs';
|
|
3
|
+
import '../types-aOQLTW0E.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A shell/profile an agent can switch the terminal to. Mirrors fancy-term's
|
|
7
|
+
* `ShellProfile` (kept local so the bridge never imports fancy-term).
|
|
8
|
+
*/
|
|
9
|
+
type TerminalShell = {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
icon?: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Host-provided window into a terminal surface (e.g. a fancy-term `<Terminal>`'s
|
|
16
|
+
* `TerminalHandle`). The bridge never touches the DOM — it reads + writes through
|
|
17
|
+
* these functions, so it works with any terminal the host wires up.
|
|
18
|
+
*/
|
|
19
|
+
type TerminalBridgeAdapter = {
|
|
20
|
+
/** fancy-screens screen id (optional) so activity events know which screen the terminal lives in. */
|
|
21
|
+
screenId?: string;
|
|
22
|
+
/** Read the visible terminal buffer as text (wire to `TerminalHandle.getBuffer`). */
|
|
23
|
+
getBuffer: () => string;
|
|
24
|
+
/** Write raw data / keystrokes to the terminal (wire to `TerminalHandle.write`). */
|
|
25
|
+
write: (data: string) => void;
|
|
26
|
+
/** Run a command. Defaults to writing `${command}\r` (submit to a PTY); override to call a real command runner. */
|
|
27
|
+
runCommand?: (command: string) => void | Promise<void>;
|
|
28
|
+
/** Optional: clear the terminal viewport (wire to `TerminalHandle.clear`). */
|
|
29
|
+
clear?: () => void;
|
|
30
|
+
/** Optional: the shells the host offers (cmd, powershell, git-bash, …). Enables `terminal_list_shells`. */
|
|
31
|
+
listShells?: () => TerminalShell[];
|
|
32
|
+
/** Optional: switch the active shell by id (wire to `TerminalHandle.setShell` + a host backend reconnect). Enables `terminal_set_shell`. */
|
|
33
|
+
setShell?: (id: string) => void | Promise<void>;
|
|
34
|
+
/** Optional: the currently active shell id (wire to `TerminalHandle.getShell`). */
|
|
35
|
+
getShell?: () => string | undefined;
|
|
36
|
+
};
|
|
37
|
+
type StagedKind = "write" | "run";
|
|
38
|
+
type Staged = {
|
|
39
|
+
id: string;
|
|
40
|
+
kind: StagedKind;
|
|
41
|
+
data: string;
|
|
42
|
+
};
|
|
43
|
+
type TerminalBridgeOptions = {
|
|
44
|
+
adapter: TerminalBridgeAdapter;
|
|
45
|
+
agent?: {
|
|
46
|
+
id: string;
|
|
47
|
+
name?: string;
|
|
48
|
+
color?: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Trust-but-verify (Human+ contract for inhabited surfaces). When on,
|
|
52
|
+
* `terminal_write` + `terminal_run` don't execute — they **stage** the command
|
|
53
|
+
* (returning a pending id) and fire `onPending`. A human confirms via the
|
|
54
|
+
* `terminal_confirm` tool or the returned bridge's `confirm(id)`. Default off.
|
|
55
|
+
*/
|
|
56
|
+
pendingMode?: boolean;
|
|
57
|
+
/** Notified when a command is staged (pendingMode) — show it + offer confirm / reject. */
|
|
58
|
+
onPending?: (pending: Staged) => void;
|
|
59
|
+
};
|
|
60
|
+
type TerminalBridge = Bridge & {
|
|
61
|
+
/** Execute a staged command by id — wire a host confirm button to this. No-op if not pending. */
|
|
62
|
+
confirm: (id: string) => void;
|
|
63
|
+
/** Drop a staged command by id without executing. */
|
|
64
|
+
reject: (id: string) => void;
|
|
65
|
+
/** Commands currently awaiting confirmation. */
|
|
66
|
+
pending: () => Staged[];
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* registerTerminalBridge — MCP access to a terminal surface. An agent reads the
|
|
70
|
+
* visible buffer (`terminal_read`), writes input (`terminal_write`), and runs
|
|
71
|
+
* commands (`terminal_run`) through the host adapter; every mutation broadcasts
|
|
72
|
+
* an `AgentActivity` event. With `pendingMode`, destructive actions are staged
|
|
73
|
+
* for human confirmation (`terminal_confirm` / `terminal_reject` /
|
|
74
|
+
* `terminal_pending`). When the adapter offers shells, the agent can also list
|
|
75
|
+
* (`terminal_list_shells`) and switch (`terminal_set_shell`) the active shell —
|
|
76
|
+
* cmd, PowerShell, Git Bash, etc. Tool prefix `terminal_*`.
|
|
77
|
+
*/
|
|
78
|
+
declare function registerTerminalBridge(host: ToolHost, options: TerminalBridgeOptions): TerminalBridge;
|
|
79
|
+
|
|
80
|
+
export { type TerminalBridge, type TerminalBridgeAdapter, type TerminalBridgeOptions, type TerminalShell, registerTerminalBridge };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { T as ToolHost } from '../tool-host-C8JMMGYq.js';
|
|
2
|
+
import { B as Bridge } from '../types-DIVNcIQO.js';
|
|
3
|
+
import '../types-aOQLTW0E.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A shell/profile an agent can switch the terminal to. Mirrors fancy-term's
|
|
7
|
+
* `ShellProfile` (kept local so the bridge never imports fancy-term).
|
|
8
|
+
*/
|
|
9
|
+
type TerminalShell = {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
icon?: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Host-provided window into a terminal surface (e.g. a fancy-term `<Terminal>`'s
|
|
16
|
+
* `TerminalHandle`). The bridge never touches the DOM — it reads + writes through
|
|
17
|
+
* these functions, so it works with any terminal the host wires up.
|
|
18
|
+
*/
|
|
19
|
+
type TerminalBridgeAdapter = {
|
|
20
|
+
/** fancy-screens screen id (optional) so activity events know which screen the terminal lives in. */
|
|
21
|
+
screenId?: string;
|
|
22
|
+
/** Read the visible terminal buffer as text (wire to `TerminalHandle.getBuffer`). */
|
|
23
|
+
getBuffer: () => string;
|
|
24
|
+
/** Write raw data / keystrokes to the terminal (wire to `TerminalHandle.write`). */
|
|
25
|
+
write: (data: string) => void;
|
|
26
|
+
/** Run a command. Defaults to writing `${command}\r` (submit to a PTY); override to call a real command runner. */
|
|
27
|
+
runCommand?: (command: string) => void | Promise<void>;
|
|
28
|
+
/** Optional: clear the terminal viewport (wire to `TerminalHandle.clear`). */
|
|
29
|
+
clear?: () => void;
|
|
30
|
+
/** Optional: the shells the host offers (cmd, powershell, git-bash, …). Enables `terminal_list_shells`. */
|
|
31
|
+
listShells?: () => TerminalShell[];
|
|
32
|
+
/** Optional: switch the active shell by id (wire to `TerminalHandle.setShell` + a host backend reconnect). Enables `terminal_set_shell`. */
|
|
33
|
+
setShell?: (id: string) => void | Promise<void>;
|
|
34
|
+
/** Optional: the currently active shell id (wire to `TerminalHandle.getShell`). */
|
|
35
|
+
getShell?: () => string | undefined;
|
|
36
|
+
};
|
|
37
|
+
type StagedKind = "write" | "run";
|
|
38
|
+
type Staged = {
|
|
39
|
+
id: string;
|
|
40
|
+
kind: StagedKind;
|
|
41
|
+
data: string;
|
|
42
|
+
};
|
|
43
|
+
type TerminalBridgeOptions = {
|
|
44
|
+
adapter: TerminalBridgeAdapter;
|
|
45
|
+
agent?: {
|
|
46
|
+
id: string;
|
|
47
|
+
name?: string;
|
|
48
|
+
color?: string;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Trust-but-verify (Human+ contract for inhabited surfaces). When on,
|
|
52
|
+
* `terminal_write` + `terminal_run` don't execute — they **stage** the command
|
|
53
|
+
* (returning a pending id) and fire `onPending`. A human confirms via the
|
|
54
|
+
* `terminal_confirm` tool or the returned bridge's `confirm(id)`. Default off.
|
|
55
|
+
*/
|
|
56
|
+
pendingMode?: boolean;
|
|
57
|
+
/** Notified when a command is staged (pendingMode) — show it + offer confirm / reject. */
|
|
58
|
+
onPending?: (pending: Staged) => void;
|
|
59
|
+
};
|
|
60
|
+
type TerminalBridge = Bridge & {
|
|
61
|
+
/** Execute a staged command by id — wire a host confirm button to this. No-op if not pending. */
|
|
62
|
+
confirm: (id: string) => void;
|
|
63
|
+
/** Drop a staged command by id without executing. */
|
|
64
|
+
reject: (id: string) => void;
|
|
65
|
+
/** Commands currently awaiting confirmation. */
|
|
66
|
+
pending: () => Staged[];
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* registerTerminalBridge — MCP access to a terminal surface. An agent reads the
|
|
70
|
+
* visible buffer (`terminal_read`), writes input (`terminal_write`), and runs
|
|
71
|
+
* commands (`terminal_run`) through the host adapter; every mutation broadcasts
|
|
72
|
+
* an `AgentActivity` event. With `pendingMode`, destructive actions are staged
|
|
73
|
+
* for human confirmation (`terminal_confirm` / `terminal_reject` /
|
|
74
|
+
* `terminal_pending`). When the adapter offers shells, the agent can also list
|
|
75
|
+
* (`terminal_list_shells`) and switch (`terminal_set_shell`) the active shell —
|
|
76
|
+
* cmd, PowerShell, Git Bash, etc. Tool prefix `terminal_*`.
|
|
77
|
+
*/
|
|
78
|
+
declare function registerTerminalBridge(host: ToolHost, options: TerminalBridgeOptions): TerminalBridge;
|
|
79
|
+
|
|
80
|
+
export { type TerminalBridge, type TerminalBridgeAdapter, type TerminalBridgeOptions, type TerminalShell, registerTerminalBridge };
|
|
@@ -0,0 +1,332 @@
|
|
|
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: 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/terminal.ts
|
|
126
|
+
var DEFAULT_AGENT = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
127
|
+
var truncate = (s, n = 60) => s.length > n ? s.slice(0, n) + "\u2026" : s;
|
|
128
|
+
function registerTerminalBridge(host, options) {
|
|
129
|
+
const { adapter } = options;
|
|
130
|
+
const agent = { ...DEFAULT_AGENT, ...options.agent ?? {} };
|
|
131
|
+
const pendingMode = options.pendingMode ?? false;
|
|
132
|
+
const disposers = [];
|
|
133
|
+
const staged = /* @__PURE__ */ new Map();
|
|
134
|
+
let seq = 0;
|
|
135
|
+
ensureUndoToolsRegistered(host);
|
|
136
|
+
const target = (label) => ({
|
|
137
|
+
kind: "terminal",
|
|
138
|
+
screenId: adapter.screenId,
|
|
139
|
+
elementId: adapter.screenId ?? "terminal",
|
|
140
|
+
label: label ?? "terminal"
|
|
141
|
+
});
|
|
142
|
+
const reg = (name, description, properties, required, handler, isMutation, resolveTarget) => {
|
|
143
|
+
const wrapped = async (args) => {
|
|
144
|
+
try {
|
|
145
|
+
return await handler(args);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
return errorResult(e instanceof Error ? e.message : String(e));
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const final = isMutation ? wrapToolWithActivity(wrapped, {
|
|
151
|
+
toolName: name,
|
|
152
|
+
agent,
|
|
153
|
+
kind: "terminal",
|
|
154
|
+
screenId: adapter.screenId,
|
|
155
|
+
resolveTarget: ({ args, result }) => resolveTarget?.(args, result) ?? target()
|
|
156
|
+
}) : wrapped;
|
|
157
|
+
disposers.push(
|
|
158
|
+
host.registerTool(
|
|
159
|
+
{
|
|
160
|
+
name,
|
|
161
|
+
description,
|
|
162
|
+
inputSchema: { type: "object", properties, required, additionalProperties: false }
|
|
163
|
+
},
|
|
164
|
+
final
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
async function exec(kind, data) {
|
|
169
|
+
if (kind === "run") {
|
|
170
|
+
if (adapter.runCommand) await adapter.runCommand(data);
|
|
171
|
+
else adapter.write(data + "\r");
|
|
172
|
+
} else {
|
|
173
|
+
adapter.write(data);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async function stageOrExec(kind, data) {
|
|
177
|
+
if (!pendingMode) {
|
|
178
|
+
await exec(kind, data);
|
|
179
|
+
return textResult(`${kind === "run" ? "ran" : "wrote"}: ${truncate(data)}`, { kind, data, executed: true });
|
|
180
|
+
}
|
|
181
|
+
const id = `t${++seq}`;
|
|
182
|
+
const entry = { id, kind, data };
|
|
183
|
+
staged.set(id, entry);
|
|
184
|
+
options.onPending?.(entry);
|
|
185
|
+
return textResult(
|
|
186
|
+
`Staged ${kind} (id ${id}) \u2014 awaiting human confirmation: ${truncate(data)}`,
|
|
187
|
+
{ ...entry, pending: true }
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
reg(
|
|
191
|
+
"terminal_read",
|
|
192
|
+
"Read the visible terminal buffer as text \u2014 what the user sees. Pass `tail` for only the last N lines.",
|
|
193
|
+
{ tail: { type: "number", description: "Return only the last N lines." } },
|
|
194
|
+
[],
|
|
195
|
+
(args) => {
|
|
196
|
+
let buf = adapter.getBuffer();
|
|
197
|
+
const tail = typeof args.tail === "number" ? args.tail : void 0;
|
|
198
|
+
if (tail && tail > 0) buf = buf.split("\n").slice(-tail).join("\n");
|
|
199
|
+
return textResult(buf, { buffer: buf });
|
|
200
|
+
},
|
|
201
|
+
false
|
|
202
|
+
);
|
|
203
|
+
reg(
|
|
204
|
+
"terminal_pending",
|
|
205
|
+
"List commands staged for human confirmation (pendingMode).",
|
|
206
|
+
{},
|
|
207
|
+
[],
|
|
208
|
+
() => {
|
|
209
|
+
const list = [...staged.values()];
|
|
210
|
+
return textResult(
|
|
211
|
+
list.length ? list.map((s) => `${s.id}: ${s.kind} ${truncate(s.data)}`).join("\n") : "(none)",
|
|
212
|
+
{ pending: list }
|
|
213
|
+
);
|
|
214
|
+
},
|
|
215
|
+
false
|
|
216
|
+
);
|
|
217
|
+
reg(
|
|
218
|
+
"terminal_write",
|
|
219
|
+
"Write raw data / keystrokes to the terminal (input, control chars, ANSI). In pendingMode this stages instead of executing.",
|
|
220
|
+
{ data: { type: "string", description: "Raw bytes to write." } },
|
|
221
|
+
["data"],
|
|
222
|
+
(args) => stageOrExec("write", String(args.data)),
|
|
223
|
+
true
|
|
224
|
+
);
|
|
225
|
+
reg(
|
|
226
|
+
"terminal_run",
|
|
227
|
+
"Run a shell command \u2014 writes the command followed by Enter (or the host's command runner). In pendingMode this stages it for confirmation.",
|
|
228
|
+
{ command: { type: "string", description: "The command line to run." } },
|
|
229
|
+
["command"],
|
|
230
|
+
(args) => stageOrExec("run", String(args.command)),
|
|
231
|
+
true,
|
|
232
|
+
(args) => target(truncate(String(args.command ?? "")))
|
|
233
|
+
);
|
|
234
|
+
reg(
|
|
235
|
+
"terminal_confirm",
|
|
236
|
+
"Confirm + execute a staged command by id (pendingMode).",
|
|
237
|
+
{ id: { type: "string" } },
|
|
238
|
+
["id"],
|
|
239
|
+
async (args) => {
|
|
240
|
+
const id = String(args.id);
|
|
241
|
+
const entry = staged.get(id);
|
|
242
|
+
if (!entry) return errorResult(`No staged command ${id}`);
|
|
243
|
+
staged.delete(id);
|
|
244
|
+
await exec(entry.kind, entry.data);
|
|
245
|
+
return textResult(`Confirmed ${id}: ${entry.kind} ${truncate(entry.data)}`, { ...entry, executed: true });
|
|
246
|
+
},
|
|
247
|
+
true
|
|
248
|
+
);
|
|
249
|
+
reg(
|
|
250
|
+
"terminal_reject",
|
|
251
|
+
"Drop a staged command by id without executing it.",
|
|
252
|
+
{ id: { type: "string" } },
|
|
253
|
+
["id"],
|
|
254
|
+
(args) => {
|
|
255
|
+
const id = String(args.id);
|
|
256
|
+
if (!staged.delete(id)) return errorResult(`No staged command ${id}`);
|
|
257
|
+
return textResult(`Rejected ${id}`, { id, rejected: true });
|
|
258
|
+
},
|
|
259
|
+
false
|
|
260
|
+
);
|
|
261
|
+
if (adapter.clear) {
|
|
262
|
+
reg(
|
|
263
|
+
"terminal_clear",
|
|
264
|
+
"Clear the terminal viewport.",
|
|
265
|
+
{},
|
|
266
|
+
[],
|
|
267
|
+
() => {
|
|
268
|
+
adapter.clear();
|
|
269
|
+
return textResult("cleared");
|
|
270
|
+
},
|
|
271
|
+
true
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (adapter.listShells) {
|
|
275
|
+
reg(
|
|
276
|
+
"terminal_list_shells",
|
|
277
|
+
"List the shells the host can switch to (cmd, PowerShell, Git Bash, \u2026) \u2014 id + label, with the active one marked.",
|
|
278
|
+
{},
|
|
279
|
+
[],
|
|
280
|
+
() => {
|
|
281
|
+
const shells = adapter.listShells();
|
|
282
|
+
const active = adapter.getShell?.();
|
|
283
|
+
const text = shells.length ? shells.map((s) => `${s.id === active ? "* " : " "}${s.id} \u2014 ${s.label}`).join("\n") : "(none)";
|
|
284
|
+
return textResult(text, { shells, active });
|
|
285
|
+
},
|
|
286
|
+
false
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
if (adapter.setShell) {
|
|
290
|
+
reg(
|
|
291
|
+
"terminal_set_shell",
|
|
292
|
+
"Switch the active shell by id (e.g. 'powershell', 'git-bash'). Call terminal_list_shells first for valid ids. The host reconnects its backend to the chosen shell.",
|
|
293
|
+
{ id: { type: "string", description: "Shell id to switch to." } },
|
|
294
|
+
["id"],
|
|
295
|
+
async (args) => {
|
|
296
|
+
const id = String(args.id);
|
|
297
|
+
const shells = adapter.listShells?.();
|
|
298
|
+
if (shells && shells.length && !shells.some((s) => s.id === id)) {
|
|
299
|
+
return errorResult(`Unknown shell '${id}'. Use terminal_list_shells for valid ids.`);
|
|
300
|
+
}
|
|
301
|
+
await adapter.setShell(id);
|
|
302
|
+
return textResult(`Switched shell to ${id}`, { shell: id });
|
|
303
|
+
},
|
|
304
|
+
true,
|
|
305
|
+
(args) => target(`shell:${String(args.id ?? "")}`)
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
id: "terminal",
|
|
310
|
+
title: "Terminal",
|
|
311
|
+
dispose: () => {
|
|
312
|
+
disposers.forEach((d) => d());
|
|
313
|
+
disposers.length = 0;
|
|
314
|
+
staged.clear();
|
|
315
|
+
},
|
|
316
|
+
confirm: (id) => {
|
|
317
|
+
const e = staged.get(id);
|
|
318
|
+
if (e) {
|
|
319
|
+
staged.delete(id);
|
|
320
|
+
void exec(e.kind, e.data);
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
reject: (id) => {
|
|
324
|
+
staged.delete(id);
|
|
325
|
+
},
|
|
326
|
+
pending: () => [...staged.values()]
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
exports.registerTerminalBridge = registerTerminalBridge;
|
|
331
|
+
//# sourceMappingURL=bridges-terminal.cjs.map
|
|
332
|
+
//# sourceMappingURL=bridges-terminal.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/terminal.ts"],"names":["emitActivity","undoOne","redoOne","readHistory"],"mappings":"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","file":"bridges-terminal.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);\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): 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);\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 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): 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: 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\";\nimport type { AgentTarget } from \"../presence/types\";\n\n/**\n * A shell/profile an agent can switch the terminal to. Mirrors fancy-term's\n * `ShellProfile` (kept local so the bridge never imports fancy-term).\n */\nexport type TerminalShell = { id: string; label: string; icon?: string };\n\n/**\n * Host-provided window into a terminal surface (e.g. a fancy-term `<Terminal>`'s\n * `TerminalHandle`). The bridge never touches the DOM — it reads + writes through\n * these functions, so it works with any terminal the host wires up.\n */\nexport type TerminalBridgeAdapter = {\n /** fancy-screens screen id (optional) so activity events know which screen the terminal lives in. */\n screenId?: string;\n /** Read the visible terminal buffer as text (wire to `TerminalHandle.getBuffer`). */\n getBuffer: () => string;\n /** Write raw data / keystrokes to the terminal (wire to `TerminalHandle.write`). */\n write: (data: string) => void;\n /** Run a command. Defaults to writing `${command}\\r` (submit to a PTY); override to call a real command runner. */\n runCommand?: (command: string) => void | Promise<void>;\n /** Optional: clear the terminal viewport (wire to `TerminalHandle.clear`). */\n clear?: () => void;\n /** Optional: the shells the host offers (cmd, powershell, git-bash, …). Enables `terminal_list_shells`. */\n listShells?: () => TerminalShell[];\n /** Optional: switch the active shell by id (wire to `TerminalHandle.setShell` + a host backend reconnect). Enables `terminal_set_shell`. */\n setShell?: (id: string) => void | Promise<void>;\n /** Optional: the currently active shell id (wire to `TerminalHandle.getShell`). */\n getShell?: () => string | undefined;\n};\n\ntype StagedKind = \"write\" | \"run\";\ntype Staged = { id: string; kind: StagedKind; data: string };\n\nexport type TerminalBridgeOptions = {\n adapter: TerminalBridgeAdapter;\n agent?: { id: string; name?: string; color?: string };\n /**\n * Trust-but-verify (Human+ contract for inhabited surfaces). When on,\n * `terminal_write` + `terminal_run` don't execute — they **stage** the command\n * (returning a pending id) and fire `onPending`. A human confirms via the\n * `terminal_confirm` tool or the returned bridge's `confirm(id)`. Default off.\n */\n pendingMode?: boolean;\n /** Notified when a command is staged (pendingMode) — show it + offer confirm / reject. */\n onPending?: (pending: Staged) => void;\n};\n\nexport type TerminalBridge = Bridge & {\n /** Execute a staged command by id — wire a host confirm button to this. No-op if not pending. */\n confirm: (id: string) => void;\n /** Drop a staged command by id without executing. */\n reject: (id: string) => void;\n /** Commands currently awaiting confirmation. */\n pending: () => Staged[];\n};\n\nconst DEFAULT_AGENT = { id: \"agent\", name: \"Agent\", color: \"#a855f7\" };\n\nconst truncate = (s: string, n = 60): string => (s.length > n ? s.slice(0, n) + \"…\" : s);\n\n/**\n * registerTerminalBridge — MCP access to a terminal surface. An agent reads the\n * visible buffer (`terminal_read`), writes input (`terminal_write`), and runs\n * commands (`terminal_run`) through the host adapter; every mutation broadcasts\n * an `AgentActivity` event. With `pendingMode`, destructive actions are staged\n * for human confirmation (`terminal_confirm` / `terminal_reject` /\n * `terminal_pending`). When the adapter offers shells, the agent can also list\n * (`terminal_list_shells`) and switch (`terminal_set_shell`) the active shell —\n * cmd, PowerShell, Git Bash, etc. Tool prefix `terminal_*`.\n */\nexport function registerTerminalBridge(host: ToolHost, options: TerminalBridgeOptions): TerminalBridge {\n const { adapter } = options;\n const agent = { ...DEFAULT_AGENT, ...(options.agent ?? {}) };\n const pendingMode = options.pendingMode ?? false;\n const disposers: Array<() => void> = [];\n const staged = new Map<string, Staged>();\n let seq = 0;\n\n // Enables agent_history (a log of what agents did across every bridge).\n ensureUndoToolsRegistered(host);\n\n const target = (label?: string): AgentTarget => ({\n kind: \"terminal\",\n screenId: adapter.screenId,\n elementId: adapter.screenId ?? \"terminal\",\n label: label ?? \"terminal\",\n });\n\n const reg = (\n name: string,\n description: string,\n properties: Record<string, unknown>,\n required: string[],\n handler: (args: JsonObject) => Promise<any> | any,\n isMutation: boolean,\n resolveTarget?: (args: JsonObject, result: any) => AgentTarget | null,\n ) => {\n const wrapped = async (args: JsonObject) => {\n try {\n return await handler(args);\n } catch (e) {\n return errorResult(e instanceof Error ? e.message : String(e));\n }\n };\n const final = isMutation\n ? wrapToolWithActivity(wrapped, {\n toolName: name,\n agent,\n kind: \"terminal\",\n screenId: adapter.screenId,\n resolveTarget: ({ args, result }) => resolveTarget?.(args, result) ?? target(),\n })\n : wrapped;\n disposers.push(\n host.registerTool(\n {\n name,\n description,\n inputSchema: { type: \"object\", properties: properties as any, required, additionalProperties: false },\n },\n final as any,\n ),\n );\n };\n\n async function exec(kind: StagedKind, data: string): Promise<void> {\n if (kind === \"run\") {\n if (adapter.runCommand) await adapter.runCommand(data);\n else adapter.write(data + \"\\r\");\n } else {\n adapter.write(data);\n }\n }\n\n async function stageOrExec(kind: StagedKind, data: string) {\n if (!pendingMode) {\n await exec(kind, data);\n return textResult(`${kind === \"run\" ? \"ran\" : \"wrote\"}: ${truncate(data)}`, { kind, data, executed: true });\n }\n const id = `t${++seq}`;\n const entry: Staged = { id, kind, data };\n staged.set(id, entry);\n options.onPending?.(entry);\n return textResult(\n `Staged ${kind} (id ${id}) — awaiting human confirmation: ${truncate(data)}`,\n { ...entry, pending: true },\n );\n }\n\n // ── Read ──────────────────────────────────────────────────────────────────\n reg(\n \"terminal_read\",\n \"Read the visible terminal buffer as text — what the user sees. Pass `tail` for only the last N lines.\",\n { tail: { type: \"number\", description: \"Return only the last N lines.\" } },\n [],\n (args) => {\n let buf = adapter.getBuffer();\n const tail = typeof args.tail === \"number\" ? args.tail : undefined;\n if (tail && tail > 0) buf = buf.split(\"\\n\").slice(-tail).join(\"\\n\");\n return textResult(buf, { buffer: buf });\n },\n false,\n );\n\n reg(\n \"terminal_pending\",\n \"List commands staged for human confirmation (pendingMode).\",\n {},\n [],\n () => {\n const list = [...staged.values()];\n return textResult(\n list.length ? list.map((s) => `${s.id}: ${s.kind} ${truncate(s.data)}`).join(\"\\n\") : \"(none)\",\n { pending: list },\n );\n },\n false,\n );\n\n // ── Mutations ───────────────────────────────────────────────────────────────\n reg(\n \"terminal_write\",\n \"Write raw data / keystrokes to the terminal (input, control chars, ANSI). In pendingMode this stages instead of executing.\",\n { data: { type: \"string\", description: \"Raw bytes to write.\" } },\n [\"data\"],\n (args) => stageOrExec(\"write\", String(args.data)),\n true,\n );\n\n reg(\n \"terminal_run\",\n \"Run a shell command — writes the command followed by Enter (or the host's command runner). In pendingMode this stages it for confirmation.\",\n { command: { type: \"string\", description: \"The command line to run.\" } },\n [\"command\"],\n (args) => stageOrExec(\"run\", String(args.command)),\n true,\n (args) => target(truncate(String(args.command ?? \"\"))),\n );\n\n reg(\n \"terminal_confirm\",\n \"Confirm + execute a staged command by id (pendingMode).\",\n { id: { type: \"string\" } },\n [\"id\"],\n async (args) => {\n const id = String(args.id);\n const entry = staged.get(id);\n if (!entry) return errorResult(`No staged command ${id}`);\n staged.delete(id);\n await exec(entry.kind, entry.data);\n return textResult(`Confirmed ${id}: ${entry.kind} ${truncate(entry.data)}`, { ...entry, executed: true });\n },\n true,\n );\n\n reg(\n \"terminal_reject\",\n \"Drop a staged command by id without executing it.\",\n { id: { type: \"string\" } },\n [\"id\"],\n (args) => {\n const id = String(args.id);\n if (!staged.delete(id)) return errorResult(`No staged command ${id}`);\n return textResult(`Rejected ${id}`, { id, rejected: true });\n },\n false,\n );\n\n if (adapter.clear) {\n reg(\n \"terminal_clear\",\n \"Clear the terminal viewport.\",\n {},\n [],\n () => {\n adapter.clear!();\n return textResult(\"cleared\");\n },\n true,\n );\n }\n\n // ── Shells ──────────────────────────────────────────────────────────────────\n if (adapter.listShells) {\n reg(\n \"terminal_list_shells\",\n \"List the shells the host can switch to (cmd, PowerShell, Git Bash, …) — id + label, with the active one marked.\",\n {},\n [],\n () => {\n const shells = adapter.listShells!();\n const active = adapter.getShell?.();\n const text = shells.length\n ? shells.map((s) => `${s.id === active ? \"* \" : \" \"}${s.id} — ${s.label}`).join(\"\\n\")\n : \"(none)\";\n return textResult(text, { shells, active });\n },\n false,\n );\n }\n\n if (adapter.setShell) {\n reg(\n \"terminal_set_shell\",\n \"Switch the active shell by id (e.g. 'powershell', 'git-bash'). Call terminal_list_shells first for valid ids. The host reconnects its backend to the chosen shell.\",\n { id: { type: \"string\", description: \"Shell id to switch to.\" } },\n [\"id\"],\n async (args) => {\n const id = String(args.id);\n const shells = adapter.listShells?.();\n if (shells && shells.length && !shells.some((s) => s.id === id)) {\n return errorResult(`Unknown shell '${id}'. Use terminal_list_shells for valid ids.`);\n }\n await adapter.setShell!(id);\n return textResult(`Switched shell to ${id}`, { shell: id });\n },\n true,\n (args) => target(`shell:${String(args.id ?? \"\")}`),\n );\n }\n\n return {\n id: \"terminal\",\n title: \"Terminal\",\n dispose: () => {\n disposers.forEach((d) => d());\n disposers.length = 0;\n staged.clear();\n },\n confirm: (id: string) => {\n const e = staged.get(id);\n if (e) {\n staged.delete(id);\n void exec(e.kind, e.data);\n }\n },\n reject: (id: string) => {\n staged.delete(id);\n },\n pending: () => [...staged.values()],\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { registerTerminalBridge } from './chunk-FZ7Q5NS3.js';
|
|
2
|
+
import './chunk-KJ5AOOV7.js';
|
|
3
|
+
import './chunk-ULJL53DL.js';
|
|
4
|
+
import './chunk-C3TYI5TJ.js';
|
|
5
|
+
import './chunk-4KAIV6OD.js';
|
|
6
|
+
//# sourceMappingURL=bridges-terminal.js.map
|
|
7
|
+
//# sourceMappingURL=bridges-terminal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"bridges-terminal.js"}
|