pty-auto 0.3.6
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/LICENSE +21 -0
- package/README.md +515 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/src/plugin/constants.d.ts +5 -0
- package/dist/src/plugin/constants.d.ts.map +1 -0
- package/dist/src/plugin/constants.js +7 -0
- package/dist/src/plugin/constants.js.map +1 -0
- package/dist/src/plugin/pty/buffer.d.ts +19 -0
- package/dist/src/plugin/pty/buffer.d.ts.map +1 -0
- package/dist/src/plugin/pty/buffer.js +61 -0
- package/dist/src/plugin/pty/buffer.js.map +1 -0
- package/dist/src/plugin/pty/formatters.d.ts +4 -0
- package/dist/src/plugin/pty/formatters.d.ts.map +1 -0
- package/dist/src/plugin/pty/formatters.js +22 -0
- package/dist/src/plugin/pty/formatters.js.map +1 -0
- package/dist/src/plugin/pty/manager.d.ts +33 -0
- package/dist/src/plugin/pty/manager.d.ts.map +1 -0
- package/dist/src/plugin/pty/manager.js +108 -0
- package/dist/src/plugin/pty/manager.js.map +1 -0
- package/dist/src/plugin/pty/notification-manager.d.ts +9 -0
- package/dist/src/plugin/pty/notification-manager.d.ts.map +1 -0
- package/dist/src/plugin/pty/notification-manager.js +69 -0
- package/dist/src/plugin/pty/notification-manager.js.map +1 -0
- package/dist/src/plugin/pty/output-manager.d.ts +7 -0
- package/dist/src/plugin/pty/output-manager.d.ts.map +1 -0
- package/dist/src/plugin/pty/output-manager.js +26 -0
- package/dist/src/plugin/pty/output-manager.js.map +1 -0
- package/dist/src/plugin/pty/permissions.d.ts +27 -0
- package/dist/src/plugin/pty/permissions.d.ts.map +1 -0
- package/dist/src/plugin/pty/permissions.js +54 -0
- package/dist/src/plugin/pty/permissions.js.map +1 -0
- package/dist/src/plugin/pty/session-lifecycle.d.ts +20 -0
- package/dist/src/plugin/pty/session-lifecycle.d.ts.map +1 -0
- package/dist/src/plugin/pty/session-lifecycle.js +177 -0
- package/dist/src/plugin/pty/session-lifecycle.js.map +1 -0
- package/dist/src/plugin/pty/tools/kill.d.ts +12 -0
- package/dist/src/plugin/pty/tools/kill.d.ts.map +1 -0
- package/dist/src/plugin/pty/tools/kill.js +37 -0
- package/dist/src/plugin/pty/tools/kill.js.map +1 -0
- package/dist/src/plugin/pty/tools/kill.txt +25 -0
- package/dist/src/plugin/pty/tools/list.d.ts +6 -0
- package/dist/src/plugin/pty/tools/list.d.ts.map +1 -0
- package/dist/src/plugin/pty/tools/list.js +22 -0
- package/dist/src/plugin/pty/tools/list.js.map +1 -0
- package/dist/src/plugin/pty/tools/list.txt +22 -0
- package/dist/src/plugin/pty/tools/read.d.ts +18 -0
- package/dist/src/plugin/pty/tools/read.d.ts.map +1 -0
- package/dist/src/plugin/pty/tools/read.js +165 -0
- package/dist/src/plugin/pty/tools/read.js.map +1 -0
- package/dist/src/plugin/pty/tools/read.txt +39 -0
- package/dist/src/plugin/pty/tools/spawn.d.ts +24 -0
- package/dist/src/plugin/pty/tools/spawn.d.ts.map +1 -0
- package/dist/src/plugin/pty/tools/spawn.js +75 -0
- package/dist/src/plugin/pty/tools/spawn.js.map +1 -0
- package/dist/src/plugin/pty/tools/spawn.txt +52 -0
- package/dist/src/plugin/pty/tools/write.d.ts +12 -0
- package/dist/src/plugin/pty/tools/write.d.ts.map +1 -0
- package/dist/src/plugin/pty/tools/write.js +62 -0
- package/dist/src/plugin/pty/tools/write.js.map +1 -0
- package/dist/src/plugin/pty/tools/write.txt +28 -0
- package/dist/src/plugin/pty/types.d.ts +70 -0
- package/dist/src/plugin/pty/types.d.ts.map +1 -0
- package/dist/src/plugin/pty/types.js +1 -0
- package/dist/src/plugin/pty/types.js.map +1 -0
- package/dist/src/plugin/pty/utils.d.ts +12 -0
- package/dist/src/plugin/pty/utils.d.ts.map +1 -0
- package/dist/src/plugin/pty/utils.js +17 -0
- package/dist/src/plugin/pty/utils.js.map +1 -0
- package/dist/src/plugin/pty/wildcard.d.ts +7 -0
- package/dist/src/plugin/pty/wildcard.d.ts.map +1 -0
- package/dist/src/plugin/pty/wildcard.js +51 -0
- package/dist/src/plugin/pty/wildcard.js.map +1 -0
- package/dist/src/plugin/types.d.ts +5 -0
- package/dist/src/plugin/types.d.ts.map +1 -0
- package/dist/src/plugin/types.js +1 -0
- package/dist/src/plugin/types.js.map +1 -0
- package/dist/src/plugin.d.ts +3 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +71 -0
- package/dist/src/plugin.js.map +1 -0
- package/dist/src/shared/constants.d.ts +5 -0
- package/dist/src/shared/constants.d.ts.map +1 -0
- package/dist/src/shared/constants.js +7 -0
- package/dist/src/shared/constants.js.map +1 -0
- package/dist/src/web/server/callback-manager.d.ts +8 -0
- package/dist/src/web/server/callback-manager.d.ts.map +1 -0
- package/dist/src/web/server/callback-manager.js +23 -0
- package/dist/src/web/server/callback-manager.js.map +1 -0
- package/dist/src/web/server/handlers/health.d.ts +3 -0
- package/dist/src/web/server/handlers/health.d.ts.map +1 -0
- package/dist/src/web/server/handlers/health.js +33 -0
- package/dist/src/web/server/handlers/health.js.map +1 -0
- package/dist/src/web/server/handlers/responses.d.ts +10 -0
- package/dist/src/web/server/handlers/responses.d.ts.map +1 -0
- package/dist/src/web/server/handlers/responses.js +26 -0
- package/dist/src/web/server/handlers/responses.js.map +1 -0
- package/dist/src/web/server/handlers/sessions.d.ts +13 -0
- package/dist/src/web/server/handlers/sessions.d.ts.map +1 -0
- package/dist/src/web/server/handlers/sessions.js +96 -0
- package/dist/src/web/server/handlers/sessions.js.map +1 -0
- package/dist/src/web/server/handlers/static.d.ts +2 -0
- package/dist/src/web/server/handlers/static.d.ts.map +1 -0
- package/dist/src/web/server/handlers/static.js +38 -0
- package/dist/src/web/server/handlers/static.js.map +1 -0
- package/dist/src/web/server/handlers/upgrade.d.ts +2 -0
- package/dist/src/web/server/handlers/upgrade.d.ts.map +1 -0
- package/dist/src/web/server/handlers/upgrade.js +11 -0
- package/dist/src/web/server/handlers/upgrade.js.map +1 -0
- package/dist/src/web/server/handlers/websocket.d.ts +3 -0
- package/dist/src/web/server/handlers/websocket.d.ts.map +1 -0
- package/dist/src/web/server/handlers/websocket.js +119 -0
- package/dist/src/web/server/handlers/websocket.js.map +1 -0
- package/dist/src/web/server/server.d.ts +12 -0
- package/dist/src/web/server/server.d.ts.map +1 -0
- package/dist/src/web/server/server.js +73 -0
- package/dist/src/web/server/server.js.map +1 -0
- package/dist/src/web/shared/api-client.d.ts +132 -0
- package/dist/src/web/shared/api-client.d.ts.map +1 -0
- package/dist/src/web/shared/api-client.js +79 -0
- package/dist/src/web/shared/api-client.js.map +1 -0
- package/dist/src/web/shared/constants.d.ts +11 -0
- package/dist/src/web/shared/constants.d.ts.map +1 -0
- package/dist/src/web/shared/constants.js +23 -0
- package/dist/src/web/shared/constants.js.map +1 -0
- package/dist/src/web/shared/route-builder.d.ts +30 -0
- package/dist/src/web/shared/route-builder.d.ts.map +1 -0
- package/dist/src/web/shared/route-builder.js +42 -0
- package/dist/src/web/shared/route-builder.js.map +1 -0
- package/dist/src/web/shared/routes.d.ts +37 -0
- package/dist/src/web/shared/routes.d.ts.map +1 -0
- package/dist/src/web/shared/routes.js +39 -0
- package/dist/src/web/shared/routes.js.map +1 -0
- package/dist/src/web/shared/types.d.ts +87 -0
- package/dist/src/web/shared/types.d.ts.map +1 -0
- package/dist/src/web/shared/types.js +15 -0
- package/dist/src/web/shared/types.js.map +1 -0
- package/dist/web/assets/index-CYWtqpTG.js +24 -0
- package/dist/web/assets/index-DDGTF8rc.css +1 -0
- package/dist/web/index.html +204 -0
- package/package.json +107 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { manager } from "../manager.js";
|
|
3
|
+
import { buildSessionNotFoundError } from "../utils.js";
|
|
4
|
+
import DESCRIPTION from './kill.txt';
|
|
5
|
+
export const ptyKill = tool({
|
|
6
|
+
description: DESCRIPTION,
|
|
7
|
+
args: {
|
|
8
|
+
id: tool.schema.string().describe('The PTY session ID (e.g., pty_a1b2c3d4)'),
|
|
9
|
+
cleanup: tool.schema
|
|
10
|
+
.boolean()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('If true, removes the session and frees the buffer (default: false)'),
|
|
13
|
+
},
|
|
14
|
+
async execute(args) {
|
|
15
|
+
const session = manager.get(args.id);
|
|
16
|
+
if (!session) {
|
|
17
|
+
throw buildSessionNotFoundError(args.id);
|
|
18
|
+
}
|
|
19
|
+
const wasRunning = session.status === 'running';
|
|
20
|
+
const cleanup = args.cleanup ?? false;
|
|
21
|
+
const success = manager.kill(args.id, cleanup);
|
|
22
|
+
if (!success) {
|
|
23
|
+
throw new Error(`Failed to kill PTY session '${args.id}'.`);
|
|
24
|
+
}
|
|
25
|
+
const action = wasRunning ? 'Killed' : 'Cleaned up';
|
|
26
|
+
const cleanupNote = cleanup ? ' (session removed)' : ' (session retained for log access)';
|
|
27
|
+
return [
|
|
28
|
+
`<pty_killed>`,
|
|
29
|
+
`${action}: ${args.id}${cleanupNote}`,
|
|
30
|
+
`Title: ${session.title}`,
|
|
31
|
+
`Command: ${session.command} ${session.args.join(' ')}`,
|
|
32
|
+
`Final line count: ${session.lineCount}`,
|
|
33
|
+
`</pty_killed>`,
|
|
34
|
+
].join('\n');
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=kill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kill.js","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/kill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,WAAW,MAAM,YAAY,CAAA;AAEpC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,WAAW;IACxB,IAAI,EAAE;QACJ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;QAC5E,OAAO,EAAE,IAAI,CAAC,MAAM;aACjB,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,oEAAoE,CAAC;KAClF;IACD,KAAK,CAAC,OAAO,CAAC,IAAI;QAChB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,yBAAyB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC1C,CAAC;QAED,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAA;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAA;QACrC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;QAE9C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,EAAE,IAAI,CAAC,CAAA;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAA;QACnD,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,oCAAoC,CAAA;QAEzF,OAAO;YACL,cAAc;YACd,GAAG,MAAM,KAAK,IAAI,CAAC,EAAE,GAAG,WAAW,EAAE;YACrC,UAAU,OAAO,CAAC,KAAK,EAAE;YACzB,YAAY,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YACvD,qBAAqB,OAAO,CAAC,SAAS,EAAE;YACxC,eAAe;SAChB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACd,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Terminates a PTY session and optionally cleans up its buffer.
|
|
2
|
+
|
|
3
|
+
Use this tool to:
|
|
4
|
+
- Stop a running process (sends SIGTERM)
|
|
5
|
+
- Clean up an exited session to free memory
|
|
6
|
+
- Remove a session from the list
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
- `id`: The PTY session ID (from pty_spawn or pty_list)
|
|
10
|
+
- `cleanup`: If true, removes the session and frees the buffer (default: false)
|
|
11
|
+
|
|
12
|
+
Behavior:
|
|
13
|
+
- If the session is running, it will be killed (status becomes "killed")
|
|
14
|
+
- If cleanup=false (default), the session remains in the list with its output buffer intact
|
|
15
|
+
- If cleanup=true, the session is removed entirely and the buffer is freed
|
|
16
|
+
- Keeping sessions without cleanup allows you to compare logs between runs
|
|
17
|
+
|
|
18
|
+
Tips:
|
|
19
|
+
- Use cleanup=false if you might want to read the output later
|
|
20
|
+
- Use cleanup=true when you're done with the session entirely
|
|
21
|
+
- To send Ctrl+C instead of killing, use pty_write with data="\x03"
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
- Kill but keep logs: cleanup=false (or omit)
|
|
25
|
+
- Kill and remove: cleanup=true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/list.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,OAAO;;;;CAmBlB,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { manager } from "../manager.js";
|
|
3
|
+
import { formatSessionInfo } from "../formatters.js";
|
|
4
|
+
import DESCRIPTION from './list.txt';
|
|
5
|
+
export const ptyList = tool({
|
|
6
|
+
description: DESCRIPTION,
|
|
7
|
+
args: {},
|
|
8
|
+
async execute() {
|
|
9
|
+
const sessions = manager.list();
|
|
10
|
+
if (sessions.length === 0) {
|
|
11
|
+
return '<pty_list>\nNo active PTY sessions.\n</pty_list>';
|
|
12
|
+
}
|
|
13
|
+
const lines = ['<pty_list>'];
|
|
14
|
+
for (const session of sessions) {
|
|
15
|
+
lines.push(...formatSessionInfo(session));
|
|
16
|
+
}
|
|
17
|
+
lines.push(`Total: ${sessions.length} session(s)`);
|
|
18
|
+
lines.push('</pty_list>');
|
|
19
|
+
return lines.join('\n');
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,WAAW,MAAM,YAAY,CAAA;AAEpC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,WAAW;IACxB,IAAI,EAAE,EAAE;IACR,KAAK,CAAC,OAAO;QACX,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAE/B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,kDAAkD,CAAA;QAC3D,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,YAAY,CAAC,CAAA;QAC5B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;QAC3C,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,UAAU,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAA;QAClD,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QAEzB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Lists all PTY sessions (active and exited).
|
|
2
|
+
|
|
3
|
+
Use this tool to:
|
|
4
|
+
- See all running and exited PTY sessions
|
|
5
|
+
- Get session IDs for use with other pty_* tools
|
|
6
|
+
- Check the status and output line count of each session
|
|
7
|
+
- Monitor which processes are still running
|
|
8
|
+
|
|
9
|
+
Returns for each session:
|
|
10
|
+
- `id`: Unique identifier for use with other tools
|
|
11
|
+
- `title`: Human-readable name
|
|
12
|
+
- `command`: The command that was executed
|
|
13
|
+
- `status`: Current status (running, exited, killed)
|
|
14
|
+
- `exitCode`: Exit code (if exited/killed)
|
|
15
|
+
- `pid`: Process ID
|
|
16
|
+
- `lineCount`: Number of lines in the output buffer
|
|
17
|
+
- `createdAt`: When the session was created
|
|
18
|
+
|
|
19
|
+
Tips:
|
|
20
|
+
- Use the session ID with pty_read, pty_write, or pty_kill
|
|
21
|
+
- Sessions remain in the list after exit until explicitly cleaned up with pty_kill
|
|
22
|
+
- This allows you to compare output from multiple sessions
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const ptyRead: {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
id: import("zod").ZodString;
|
|
5
|
+
offset: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
6
|
+
limit: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
7
|
+
pattern: import("zod").ZodOptional<import("zod").ZodString>;
|
|
8
|
+
ignoreCase: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
9
|
+
};
|
|
10
|
+
execute(args: {
|
|
11
|
+
id: string;
|
|
12
|
+
offset?: number | undefined;
|
|
13
|
+
limit?: number | undefined;
|
|
14
|
+
pattern?: string | undefined;
|
|
15
|
+
ignoreCase?: boolean | undefined;
|
|
16
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/read.ts"],"names":[],"mappings":"AAoNA,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;CA0ClB,CAAA"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { manager } from "../manager.js";
|
|
3
|
+
import { DEFAULT_READ_LIMIT, MAX_LINE_LENGTH } from "../../../shared/constants.js";
|
|
4
|
+
import { buildSessionNotFoundError } from "../utils.js";
|
|
5
|
+
import { formatLine } from "../formatters.js";
|
|
6
|
+
import DESCRIPTION from './read.txt';
|
|
7
|
+
const NOTIFY_ON_EXIT_REMINDER = [
|
|
8
|
+
`<system_reminder>`,
|
|
9
|
+
`This session was started with \`notifyOnExit=true\`.`,
|
|
10
|
+
`Completion signal is the future \`<pty_exited>\` message, not repeated \`pty_read\` calls.`,
|
|
11
|
+
`If you only need to know whether the command finished, stop polling and wait for \`<pty_exited>\`.`,
|
|
12
|
+
`Do not use sleep plus \`pty_read\` loops to check completion.`,
|
|
13
|
+
`Use \`pty_read\` only when you need live output now, the user explicitly asks for logs, or the exit notification reports a non-zero status and you need to investigate.`,
|
|
14
|
+
`</system_reminder>`,
|
|
15
|
+
].join('\n');
|
|
16
|
+
function buildTimeoutReminder(session) {
|
|
17
|
+
return [
|
|
18
|
+
`<system_reminder>`,
|
|
19
|
+
`This session was auto-killed after reaching \`timeoutSeconds=${session.timeoutSeconds ?? 'unknown'}\`.`,
|
|
20
|
+
`Use \`pty_read\` to inspect the final output or \`pty_list\` to review other sessions.`,
|
|
21
|
+
`</system_reminder>`,
|
|
22
|
+
].join('\n');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Formats PTY output with XML tags and pagination
|
|
26
|
+
*/
|
|
27
|
+
function formatPtyOutput(id, status, pattern, formattedLines, hasMore, paginationMessage, endMessage) {
|
|
28
|
+
const output = [
|
|
29
|
+
`<pty_output id="${id}" status="${status}"${pattern ? ` pattern="${pattern}"` : ''}>`,
|
|
30
|
+
...formattedLines,
|
|
31
|
+
'',
|
|
32
|
+
hasMore ? paginationMessage : endMessage,
|
|
33
|
+
`</pty_output>`,
|
|
34
|
+
];
|
|
35
|
+
return output.join('\n');
|
|
36
|
+
}
|
|
37
|
+
function appendNotifyOnExitReminder(output, session) {
|
|
38
|
+
if (!session.notifyOnExit || session.status !== 'running') {
|
|
39
|
+
return output;
|
|
40
|
+
}
|
|
41
|
+
return `${output}\n\n${NOTIFY_ON_EXIT_REMINDER}`;
|
|
42
|
+
}
|
|
43
|
+
function appendTimeoutReminder(output, session) {
|
|
44
|
+
if (!session.timedOut) {
|
|
45
|
+
return output;
|
|
46
|
+
}
|
|
47
|
+
return `${output}\n\n${buildTimeoutReminder(session)}`;
|
|
48
|
+
}
|
|
49
|
+
function appendSessionReminders(output, session) {
|
|
50
|
+
return appendTimeoutReminder(appendNotifyOnExitReminder(output, session), session);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Validates and creates a RegExp from pattern string
|
|
54
|
+
*/
|
|
55
|
+
function validateAndCreateRegex(pattern, ignoreCase) {
|
|
56
|
+
if (!validateRegex(pattern)) {
|
|
57
|
+
throw new Error(`Potentially dangerous regex pattern rejected: '${pattern}'. Please use a safer pattern.`);
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
return new RegExp(pattern, ignoreCase ? 'i' : '');
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
const error = e instanceof Error ? e.message : String(e);
|
|
64
|
+
throw new Error(`Invalid regex pattern '${pattern}': ${error}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Handles pattern-based reading and formatting
|
|
69
|
+
*/
|
|
70
|
+
function handlePatternRead(id, pattern, ignoreCase, session, offset, limit) {
|
|
71
|
+
const regex = validateAndCreateRegex(pattern, ignoreCase);
|
|
72
|
+
const result = manager.search(id, regex, offset, limit);
|
|
73
|
+
if (!result) {
|
|
74
|
+
throw buildSessionNotFoundError(id);
|
|
75
|
+
}
|
|
76
|
+
if (result.matches.length === 0) {
|
|
77
|
+
return appendSessionReminders([
|
|
78
|
+
`<pty_output id="${id}" status="${session.status}" pattern="${pattern}">`,
|
|
79
|
+
`No lines matched the pattern '${pattern}'.`,
|
|
80
|
+
`Total lines in buffer: ${result.totalLines}`,
|
|
81
|
+
`</pty_output>`,
|
|
82
|
+
].join('\n'), session);
|
|
83
|
+
}
|
|
84
|
+
const formattedLines = result.matches.map((match) => formatLine(match.text, match.lineNumber, MAX_LINE_LENGTH));
|
|
85
|
+
const paginationMessage = `(${result.matches.length} of ${result.totalMatches} matches shown. Use offset=${offset + result.matches.length} to see more.)`;
|
|
86
|
+
const endMessage = `(${result.totalMatches} match${result.totalMatches === 1 ? '' : 'es'} from ${result.totalLines} total lines)`;
|
|
87
|
+
return appendSessionReminders(formatPtyOutput(id, session.status, pattern, formattedLines, result.hasMore, paginationMessage, endMessage), session);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Handles plain reading and formatting
|
|
91
|
+
*/
|
|
92
|
+
function handlePlainRead(args, session, offset, limit) {
|
|
93
|
+
const result = manager.read(args.id, offset, limit);
|
|
94
|
+
if (!result) {
|
|
95
|
+
throw buildSessionNotFoundError(args.id);
|
|
96
|
+
}
|
|
97
|
+
if (result.lines.length === 0) {
|
|
98
|
+
return appendSessionReminders([
|
|
99
|
+
`<pty_output id="${args.id}" status="${session.status}">`,
|
|
100
|
+
`(No output available - buffer is empty)`,
|
|
101
|
+
`Total lines: ${result.totalLines}`,
|
|
102
|
+
`</pty_output>`,
|
|
103
|
+
].join('\n'), session);
|
|
104
|
+
}
|
|
105
|
+
const formattedLines = result.lines.map((line, index) => formatLine(line, result.offset + index + 1, MAX_LINE_LENGTH));
|
|
106
|
+
const paginationMessage = `(Buffer has more lines. Use offset=${result.offset + result.lines.length} to read beyond line ${result.offset + result.lines.length})`;
|
|
107
|
+
const endMessage = `(End of buffer - total ${result.totalLines} lines)`;
|
|
108
|
+
return appendSessionReminders(formatPtyOutput(args.id, session.status, undefined, formattedLines, result.hasMore, paginationMessage, endMessage), session);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Formats a single line with line number and truncation
|
|
112
|
+
*/
|
|
113
|
+
function validateRegex(pattern) {
|
|
114
|
+
try {
|
|
115
|
+
new RegExp(pattern);
|
|
116
|
+
// Check for potentially dangerous patterns that can cause exponential backtracking
|
|
117
|
+
// This is a basic check - more sophisticated validation could be added
|
|
118
|
+
const dangerousPatterns = [
|
|
119
|
+
/\(\?:.*\)\*.*\(\?:.*\)\*/, // nested optional groups with repetition
|
|
120
|
+
/.*\(\.\*\?\)\{2,\}.*/, // overlapping non-greedy quantifiers
|
|
121
|
+
/.*\(.*\|.*\)\{3,\}.*/, // complex alternation with repetition
|
|
122
|
+
];
|
|
123
|
+
return !dangerousPatterns.some((dangerous) => dangerous.test(pattern));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export const ptyRead = tool({
|
|
130
|
+
description: DESCRIPTION,
|
|
131
|
+
args: {
|
|
132
|
+
id: tool.schema.string().describe('The PTY session ID (e.g., pty_a1b2c3d4)'),
|
|
133
|
+
offset: tool.schema
|
|
134
|
+
.number()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe('Line number to start reading from (0-based, defaults to 0). When using pattern, this applies to filtered matches.'),
|
|
137
|
+
limit: tool.schema
|
|
138
|
+
.number()
|
|
139
|
+
.optional()
|
|
140
|
+
.describe('Number of lines to read (defaults to 500). When using pattern, this applies to filtered matches.'),
|
|
141
|
+
pattern: tool.schema
|
|
142
|
+
.string()
|
|
143
|
+
.optional()
|
|
144
|
+
.describe('Regex pattern to filter lines. When set, only matching lines are returned, then offset/limit apply to the matches.'),
|
|
145
|
+
ignoreCase: tool.schema
|
|
146
|
+
.boolean()
|
|
147
|
+
.optional()
|
|
148
|
+
.describe('Case-insensitive pattern matching (default: false)'),
|
|
149
|
+
},
|
|
150
|
+
async execute(args) {
|
|
151
|
+
const session = manager.get(args.id);
|
|
152
|
+
if (!session) {
|
|
153
|
+
throw buildSessionNotFoundError(args.id);
|
|
154
|
+
}
|
|
155
|
+
const offset = args.offset ?? 0;
|
|
156
|
+
const limit = args.limit ?? DEFAULT_READ_LIMIT;
|
|
157
|
+
if (args.pattern) {
|
|
158
|
+
return handlePatternRead(args.id, args.pattern, args.ignoreCase, session, offset, limit);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
return handlePlainRead(args, session, offset, limit);
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/read.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Reads output from a PTY session's buffer.
|
|
2
|
+
|
|
3
|
+
The PTY maintains a rolling buffer of output lines. Use offset and limit to paginate through the output, similar to reading a file.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
- `id`: The PTY session ID (from pty_spawn or pty_list)
|
|
7
|
+
- `offset`: Line number to start reading from (0-based, defaults to 0)
|
|
8
|
+
- `limit`: Number of lines to read (defaults to 500)
|
|
9
|
+
- `pattern`: Regex pattern to filter lines (optional)
|
|
10
|
+
- `ignoreCase`: Case-insensitive pattern matching (default: false)
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
- Numbered lines of output (similar to cat -n format)
|
|
14
|
+
- Total line count in the buffer
|
|
15
|
+
- Indicator if more lines are available
|
|
16
|
+
|
|
17
|
+
The buffer stores up to PTY_MAX_BUFFER_LINES (default: 50000) lines. Older lines are discarded when the limit is reached.
|
|
18
|
+
|
|
19
|
+
Pattern Filtering:
|
|
20
|
+
- When `pattern` is set, lines are FILTERED FIRST using the regex, then offset/limit apply to the MATCHES
|
|
21
|
+
- Original line numbers are preserved so you can see where matches occurred in the buffer
|
|
22
|
+
- Supports full regex syntax (e.g., "error", "ERROR|WARN", "failed.*connection", etc.)
|
|
23
|
+
- If the pattern is invalid, an error message is returned explaining the issue
|
|
24
|
+
- If no lines match the pattern, a clear message indicates zero matches
|
|
25
|
+
|
|
26
|
+
Tips:
|
|
27
|
+
- To see the latest output, use a high offset or omit offset to read from the start
|
|
28
|
+
- To tail recent output, calculate offset as (totalLines - N) where N is how many recent lines you want
|
|
29
|
+
- Lines longer than 2000 characters are truncated
|
|
30
|
+
- Empty output may mean the process hasn't produced output yet
|
|
31
|
+
- If the session was started with `notifyOnExit=true`, do not use repeated `pty_read` calls only to detect completion; wait for the future `<pty_exited>` message instead
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
- Read first 100 lines: offset=0, limit=100
|
|
35
|
+
- Read lines 500-600: offset=500, limit=100
|
|
36
|
+
- Read all available: omit both parameters
|
|
37
|
+
- Find errors: pattern="error", ignoreCase=true
|
|
38
|
+
- Find specific log levels: pattern="ERROR|WARN|FATAL"
|
|
39
|
+
- First 10 matches only: pattern="error", limit=10
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export declare const ptySpawn: {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
command: import("zod").ZodString;
|
|
5
|
+
args: import("zod").ZodArray<import("zod").ZodString>;
|
|
6
|
+
workdir: import("zod").ZodOptional<import("zod").ZodString>;
|
|
7
|
+
env: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodString>>;
|
|
8
|
+
title: import("zod").ZodOptional<import("zod").ZodString>;
|
|
9
|
+
description: import("zod").ZodString;
|
|
10
|
+
notifyOnExit: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
11
|
+
timeoutSeconds: import("zod").ZodNumber;
|
|
12
|
+
};
|
|
13
|
+
execute(args: {
|
|
14
|
+
command: string;
|
|
15
|
+
args: string[];
|
|
16
|
+
description: string;
|
|
17
|
+
timeoutSeconds: number;
|
|
18
|
+
workdir?: string | undefined;
|
|
19
|
+
env?: Record<string, string> | undefined;
|
|
20
|
+
title?: string | undefined;
|
|
21
|
+
notifyOnExit?: boolean | undefined;
|
|
22
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=spawn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/spawn.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;CA+DnB,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { manager } from "../manager.js";
|
|
3
|
+
import { checkWorkdirPermission } from "../permissions.js";
|
|
4
|
+
import DESCRIPTION from './spawn.txt';
|
|
5
|
+
const NOTIFY_ON_EXIT_INSTRUCTIONS = [
|
|
6
|
+
`<system_reminder>`,
|
|
7
|
+
`Completion signal for this session is the future \`<pty_exited>\` message.`,
|
|
8
|
+
`If you only need to know whether the command finished, do not call \`pty_read\`; wait for \`<pty_exited>\`.`,
|
|
9
|
+
`Never use sleep plus \`pty_read\` loops to check completion for this session.`,
|
|
10
|
+
`Call \`pty_read\` before exit only if you need live output now, the user explicitly asks for logs, or the exit notification reports a non-zero status and you need to investigate.`,
|
|
11
|
+
`</system_reminder>`,
|
|
12
|
+
].join('\n');
|
|
13
|
+
function requireTimeoutSeconds(timeoutSeconds) {
|
|
14
|
+
if (!Number.isInteger(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
15
|
+
throw new Error('timeoutSeconds must be a positive integer in seconds');
|
|
16
|
+
}
|
|
17
|
+
return timeoutSeconds;
|
|
18
|
+
}
|
|
19
|
+
export const ptySpawn = tool({
|
|
20
|
+
description: DESCRIPTION,
|
|
21
|
+
args: {
|
|
22
|
+
command: tool.schema.string().describe('The command/executable to run'),
|
|
23
|
+
args: tool.schema.array(tool.schema.string()).describe('Arguments to pass to the command'),
|
|
24
|
+
workdir: tool.schema.string().optional().describe('Working directory for the PTY session'),
|
|
25
|
+
env: tool.schema
|
|
26
|
+
.record(tool.schema.string(), tool.schema.string())
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Additional environment variables'),
|
|
29
|
+
title: tool.schema.string().optional().describe('Human-readable title for the session'),
|
|
30
|
+
description: tool.schema
|
|
31
|
+
.string()
|
|
32
|
+
.describe('Clear, concise description of what this PTY session is for in 5-10 words'),
|
|
33
|
+
notifyOnExit: tool.schema
|
|
34
|
+
.boolean()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('If true, sends a notification to the session when the process exits (default: false)'),
|
|
37
|
+
timeoutSeconds: tool.schema
|
|
38
|
+
.number()
|
|
39
|
+
.describe('Required positive integer timeout in seconds. The PTY is killed automatically when this duration elapses.'),
|
|
40
|
+
},
|
|
41
|
+
async execute(args, ctx) {
|
|
42
|
+
const timeoutSeconds = requireTimeoutSeconds(args.timeoutSeconds);
|
|
43
|
+
if (args.workdir) {
|
|
44
|
+
await checkWorkdirPermission(args.workdir);
|
|
45
|
+
}
|
|
46
|
+
const sessionId = ctx.sessionID;
|
|
47
|
+
const info = manager.spawn({
|
|
48
|
+
command: args.command,
|
|
49
|
+
args: args.args,
|
|
50
|
+
workdir: args.workdir,
|
|
51
|
+
env: args.env,
|
|
52
|
+
title: args.title,
|
|
53
|
+
description: args.description,
|
|
54
|
+
parentSessionId: sessionId,
|
|
55
|
+
parentAgent: ctx.agent,
|
|
56
|
+
notifyOnExit: args.notifyOnExit,
|
|
57
|
+
timeoutSeconds,
|
|
58
|
+
});
|
|
59
|
+
const output = [
|
|
60
|
+
`<pty_spawned>`,
|
|
61
|
+
`ID: ${info.id}`,
|
|
62
|
+
`Title: ${info.title}`,
|
|
63
|
+
`Command: ${info.command} ${info.args.join(' ')}`,
|
|
64
|
+
`Workdir: ${info.workdir}`,
|
|
65
|
+
`PID: ${info.pid}`,
|
|
66
|
+
`Status: ${info.status}`,
|
|
67
|
+
`NotifyOnExit: ${info.notifyOnExit}`,
|
|
68
|
+
`TimeoutSeconds: ${info.timeoutSeconds}`,
|
|
69
|
+
`</pty_spawned>`,
|
|
70
|
+
...(info.notifyOnExit ? ['', NOTIFY_ON_EXIT_INSTRUCTIONS] : []),
|
|
71
|
+
].join('\n');
|
|
72
|
+
return output;
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=spawn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn.js","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/spawn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Spawns a new interactive PTY (pseudo-terminal) session that runs in the background.
|
|
2
|
+
|
|
3
|
+
Unlike the built-in bash tool which runs commands synchronously and waits for completion, PTY sessions persist and allow you to:
|
|
4
|
+
- Run long-running processes (dev servers, watch modes, etc.)
|
|
5
|
+
- Send interactive input (including Ctrl+C, arrow keys, etc.)
|
|
6
|
+
- Read output at any time
|
|
7
|
+
- Manage multiple concurrent terminal sessions
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
- The `command` parameter is required (e.g., "npm", "python", "bash")
|
|
11
|
+
- Use `args` to pass arguments to the command (e.g., ["run", "dev"])
|
|
12
|
+
- Use `workdir` to set the working directory (defaults to project root)
|
|
13
|
+
- Use `env` to set additional environment variables
|
|
14
|
+
- Use `title` to give the session a human-readable name
|
|
15
|
+
- The `description` parameter is required: a clear, concise 5-10 word description
|
|
16
|
+
- Use `notifyOnExit` to receive a notification when the process exits (default: false)
|
|
17
|
+
- Set `timeoutSeconds` on every spawn. It is required and must be a positive integer.
|
|
18
|
+
- Use a long but finite timeout for sessions that are meant to keep running, such as dev servers, watch modes, local APIs, or REPLs.
|
|
19
|
+
- Prefer a timeout that matches the expected wall-clock budget for builds, unit test suites, end-to-end tests, migrations, or other commands where you are waiting for a result.
|
|
20
|
+
|
|
21
|
+
Returns the session info including:
|
|
22
|
+
- `id`: Unique identifier (pty_XXXXXXXX) for use with other pty_* tools
|
|
23
|
+
- `pid`: Process ID
|
|
24
|
+
- `status`: Current status ("running")
|
|
25
|
+
|
|
26
|
+
After spawning, use:
|
|
27
|
+
- `pty_write` to send input to the PTY
|
|
28
|
+
- `pty_read` to read output from the PTY
|
|
29
|
+
- `pty_list` to see all active PTY sessions
|
|
30
|
+
- `pty_kill` to terminate the PTY
|
|
31
|
+
|
|
32
|
+
Exit Notifications:
|
|
33
|
+
When `notifyOnExit` is true, you will receive a message when the process exits containing:
|
|
34
|
+
- Session ID and title
|
|
35
|
+
- Exit code
|
|
36
|
+
- Total output lines
|
|
37
|
+
- Last line of output (truncated to 250 chars)
|
|
38
|
+
|
|
39
|
+
This is useful for long-running processes where you want to be notified when they complete
|
|
40
|
+
instead of polling with `pty_read`.
|
|
41
|
+
- Completion signal is the future `<pty_exited>` message
|
|
42
|
+
- If you only need to know whether the command finished, do not call `pty_read`; wait for `<pty_exited>`
|
|
43
|
+
- Never use sleep plus `pty_read` loops to check completion
|
|
44
|
+
- Use `pty_read` before exit only if you need live output now, the user explicitly asks for logs, or the exit notification reports a non-zero status and you need to investigate
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
- Start a dev server: command="npm", args=["run", "dev"], title="Dev Server"
|
|
48
|
+
- Start a timed dev server when explicitly requested: command="npm", args=["run", "dev"], title="Dev Server", timeoutSeconds=600
|
|
49
|
+
- Start a Python REPL: command="python3", title="Python REPL"
|
|
50
|
+
- Run tests in watch mode: command="npm", args=["test", "--", "--watch"]
|
|
51
|
+
- Run build with notification and timeout: command="npm", args=["run", "build"], title="Build", notifyOnExit=true, timeoutSeconds=900
|
|
52
|
+
- Run end-to-end tests with timeout: command="npm", args=["run", "test:e2e"], title="E2E Tests", notifyOnExit=true, timeoutSeconds=1800
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const ptyWrite: {
|
|
2
|
+
description: string;
|
|
3
|
+
args: {
|
|
4
|
+
id: import("zod").ZodString;
|
|
5
|
+
data: import("zod").ZodString;
|
|
6
|
+
};
|
|
7
|
+
execute(args: {
|
|
8
|
+
id: string;
|
|
9
|
+
data: string;
|
|
10
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/write.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,QAAQ;;;;;;;;;;CAgCnB,CAAA"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
|
+
import { manager } from "../manager.js";
|
|
3
|
+
import { buildSessionNotFoundError } from "../utils.js";
|
|
4
|
+
import DESCRIPTION from './write.txt';
|
|
5
|
+
const ETX = String.fromCharCode(3);
|
|
6
|
+
const EOT = String.fromCharCode(4);
|
|
7
|
+
/**
|
|
8
|
+
* Parse escape sequences in a string to their actual byte values.
|
|
9
|
+
* Handles: \n, \r, \t, \xNN (hex), \uNNNN (unicode), \\
|
|
10
|
+
*/
|
|
11
|
+
function parseEscapeSequences(input) {
|
|
12
|
+
return input.replace(/\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|[nrt\\])/g, (match, seq) => {
|
|
13
|
+
if (seq.startsWith('x')) {
|
|
14
|
+
return String.fromCharCode(parseInt(seq.slice(1), 16));
|
|
15
|
+
}
|
|
16
|
+
if (seq.startsWith('u')) {
|
|
17
|
+
return String.fromCharCode(parseInt(seq.slice(1), 16));
|
|
18
|
+
}
|
|
19
|
+
switch (seq) {
|
|
20
|
+
case 'n':
|
|
21
|
+
return '\n';
|
|
22
|
+
case 'r':
|
|
23
|
+
return '\r';
|
|
24
|
+
case 't':
|
|
25
|
+
return '\t';
|
|
26
|
+
case '\\':
|
|
27
|
+
return '\\';
|
|
28
|
+
default:
|
|
29
|
+
return match;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
export const ptyWrite = tool({
|
|
34
|
+
description: DESCRIPTION,
|
|
35
|
+
args: {
|
|
36
|
+
id: tool.schema.string().describe('The PTY session ID (e.g., pty_a1b2c3d4)'),
|
|
37
|
+
data: tool.schema.string().describe('The input data to send to the PTY'),
|
|
38
|
+
},
|
|
39
|
+
async execute(args) {
|
|
40
|
+
const session = manager.get(args.id);
|
|
41
|
+
if (!session) {
|
|
42
|
+
throw buildSessionNotFoundError(args.id);
|
|
43
|
+
}
|
|
44
|
+
if (session.status !== 'running') {
|
|
45
|
+
throw new Error(`Cannot write to PTY '${args.id}' - session status is '${session.status}'.`);
|
|
46
|
+
}
|
|
47
|
+
// Parse escape sequences to actual bytes
|
|
48
|
+
const parsedData = parseEscapeSequences(args.data);
|
|
49
|
+
const success = manager.write(args.id, parsedData);
|
|
50
|
+
if (!success) {
|
|
51
|
+
throw new Error(`Failed to write to PTY '${args.id}'.`);
|
|
52
|
+
}
|
|
53
|
+
const preview = args.data.length > 50 ? `${args.data.slice(0, 50)}...` : args.data;
|
|
54
|
+
const displayPreview = preview
|
|
55
|
+
.replace(new RegExp(ETX, 'g'), '^C')
|
|
56
|
+
.replace(new RegExp(EOT, 'g'), '^D')
|
|
57
|
+
.replace(/\n/g, '\\n')
|
|
58
|
+
.replace(/\r/g, '\\r');
|
|
59
|
+
return `Sent ${args.data.length} bytes to ${args.id}: "${displayPreview}"`;
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../../../../src/plugin/pty/tools/write.ts"],"names":[],"mappings":"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"}
|