agent-sh 0.14.1 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent-loop.d.ts +1 -1
- package/dist/agent/agent-loop.js +42 -31
- package/dist/agent/conversation-state.d.ts +3 -2
- package/dist/agent/conversation-state.js +20 -3
- package/dist/agent/events.d.ts +2 -0
- package/dist/agent/host-types.d.ts +3 -0
- package/dist/agent/index.js +2 -1
- package/dist/agent/subagent.d.ts +1 -1
- package/dist/agent/subagent.js +5 -1
- package/dist/agent/tool-protocol.d.ts +2 -2
- package/dist/agent/tool-protocol.js +5 -4
- package/dist/agent/tools/glob.d.ts +1 -1
- package/dist/agent/tools/glob.js +4 -2
- package/dist/agent/tools/grep.d.ts +1 -1
- package/dist/agent/tools/grep.js +4 -2
- package/dist/agent/tools/ls.d.ts +1 -1
- package/dist/agent/tools/ls.js +4 -2
- package/dist/agent/tools/read-file.d.ts +1 -1
- package/dist/agent/tools/read-file.js +30 -2
- package/dist/agent/types.d.ts +11 -1
- package/dist/agent/types.js +6 -1
- package/dist/cli/index.js +0 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/settings.d.ts +3 -0
- package/dist/core/settings.js +2 -2
- package/dist/shell/index.d.ts +6 -0
- package/dist/shell/index.js +10 -10
- package/dist/shell/shell.d.ts +4 -0
- package/dist/shell/shell.js +15 -29
- package/dist/shell/terminal.d.ts +33 -0
- package/dist/shell/terminal.js +62 -0
- package/examples/extensions/ash-scheme/index.ts +2170 -0
- package/examples/extensions/ash-scheme/package.json +11 -0
- package/examples/extensions/ash-scheme-render.ts +58 -0
- package/examples/extensions/ashi/README.md +36 -26
- package/examples/extensions/ashi/package.json +9 -1
- package/examples/extensions/ashi/src/capture.ts +1 -0
- package/examples/extensions/ashi/src/cli.ts +21 -7
- package/examples/extensions/ashi/src/compaction.ts +25 -96
- package/examples/extensions/ashi/src/components.ts +64 -166
- package/examples/extensions/ashi/src/default-schema-renderers.ts +229 -0
- package/examples/extensions/ashi/src/display-config.ts +21 -22
- package/examples/extensions/ashi/src/frontend.ts +64 -65
- package/examples/extensions/ashi/src/hooks.ts +47 -63
- package/examples/extensions/ashi/src/multi-session-store.ts +44 -3
- package/examples/extensions/ashi/src/schema.ts +407 -0
- package/examples/extensions/ashi/src/session-store.ts +55 -4
- package/examples/extensions/ashi/src/status-footer.ts +27 -6
- package/examples/extensions/ashi-compact-llm.ts +93 -0
- package/examples/extensions/claude-code-bridge/index.ts +2 -0
- package/examples/extensions/opencode-bridge/index.ts +3 -0
- package/examples/extensions/opencode-provider.ts +252 -0
- package/examples/extensions/pi-bridge/index.ts +1 -0
- package/package.json +12 -1
- package/examples/extensions/ashi/src/default-renderers.ts +0 -171
package/dist/shell/index.js
CHANGED
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import "./events.js"; // augments BusEvents with shell-owned events
|
|
7
7
|
import { Shell } from "./shell.js";
|
|
8
|
-
import { DefaultCompositor
|
|
8
|
+
import { DefaultCompositor } from "../utils/compositor.js";
|
|
9
9
|
import { TerminalBuffer } from "../utils/terminal-buffer.js";
|
|
10
10
|
import { setPalette } from "../utils/palette.js";
|
|
11
11
|
import * as streamTransform from "../utils/stream-transform.js";
|
|
12
12
|
import activateShellContext from "./shell-context.js";
|
|
13
13
|
import activateTuiRenderer from "./tui-renderer.js";
|
|
14
|
+
import { processTerminal, surfaceFromTerminal } from "./terminal.js";
|
|
14
15
|
/**
|
|
15
16
|
* Register shell-owned handlers extensions can `ctx.call`, and attach
|
|
16
17
|
* the shell surface to ctx. Must run before `loadExtensions` so user
|
|
@@ -77,10 +78,11 @@ export function registerShellHandlers(ctx) {
|
|
|
77
78
|
* `src/cli/index.ts`) uses to drive lifecycle from process-level events.
|
|
78
79
|
*/
|
|
79
80
|
export function activateShell(ctx, opts) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
ctx.shell.compositor.setDefault("
|
|
83
|
-
ctx.shell.compositor.setDefault("
|
|
81
|
+
const terminal = opts.terminal ?? processTerminal();
|
|
82
|
+
const surface = surfaceFromTerminal(terminal);
|
|
83
|
+
ctx.shell.compositor.setDefault("agent", surface);
|
|
84
|
+
ctx.shell.compositor.setDefault("query", surface);
|
|
85
|
+
ctx.shell.compositor.setDefault("status", surface);
|
|
84
86
|
const shell = new Shell({
|
|
85
87
|
bus: ctx.bus,
|
|
86
88
|
handlers: { define: ctx.define, call: ctx.call },
|
|
@@ -90,13 +92,11 @@ export function activateShell(ctx, opts) {
|
|
|
90
92
|
cwd: opts.cwd,
|
|
91
93
|
instanceId: ctx.instanceId,
|
|
92
94
|
onShowAgentInfo: opts.onShowAgentInfo,
|
|
95
|
+
terminal,
|
|
93
96
|
});
|
|
94
|
-
const
|
|
95
|
-
shell.resize(process.stdout.columns || 80, process.stdout.rows || 24);
|
|
96
|
-
};
|
|
97
|
-
process.stdout.on("resize", onResize);
|
|
97
|
+
const offResize = terminal.onResize((cols, rows) => shell.resize(cols, rows));
|
|
98
98
|
ctx.onDispose(() => {
|
|
99
|
-
|
|
99
|
+
offResize();
|
|
100
100
|
shell.kill();
|
|
101
101
|
});
|
|
102
102
|
return {
|
package/dist/shell/shell.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EventBus } from "../core/event-bus.js";
|
|
2
2
|
import { type InputContext } from "./input-handler.js";
|
|
3
|
+
import { type Terminal } from "./terminal.js";
|
|
3
4
|
export interface ShellHandlers {
|
|
4
5
|
define: (name: string, fn: (...args: any[]) => any) => void;
|
|
5
6
|
call: (name: string, ...args: any[]) => any;
|
|
@@ -19,6 +20,8 @@ export declare class Shell implements InputContext {
|
|
|
19
20
|
private handlers;
|
|
20
21
|
private inputHandler;
|
|
21
22
|
private outputParser;
|
|
23
|
+
private terminal;
|
|
24
|
+
private inputDispose;
|
|
22
25
|
private hardMuteScopes;
|
|
23
26
|
private softMuteScopes;
|
|
24
27
|
private unmuteScopes;
|
|
@@ -38,6 +41,7 @@ export declare class Shell implements InputContext {
|
|
|
38
41
|
shell: string;
|
|
39
42
|
cwd: string;
|
|
40
43
|
instanceId: string;
|
|
44
|
+
terminal?: Terminal;
|
|
41
45
|
});
|
|
42
46
|
/** Compositing-layer claim — overrides any unmute. */
|
|
43
47
|
acquireHardMute(reason: string): ShellScope;
|
package/dist/shell/shell.js
CHANGED
|
@@ -5,6 +5,7 @@ import { InputHandler } from "./input-handler.js";
|
|
|
5
5
|
import { OutputParser } from "./output-parser.js";
|
|
6
6
|
import { getSettings } from "../core/settings.js";
|
|
7
7
|
import { clearOpost } from "../utils/tty.js";
|
|
8
|
+
import { processTerminal } from "./terminal.js";
|
|
8
9
|
import { pickStrategy, FALLBACK_STRATEGY, SUPPORTED_SHELL_NAMES, } from "./strategies/index.js";
|
|
9
10
|
export class Shell {
|
|
10
11
|
ptyProcess;
|
|
@@ -12,6 +13,8 @@ export class Shell {
|
|
|
12
13
|
handlers;
|
|
13
14
|
inputHandler;
|
|
14
15
|
outputParser;
|
|
16
|
+
terminal;
|
|
17
|
+
inputDispose = null;
|
|
15
18
|
// hardMute is unconditional (overlay compositing); softMute is overridable
|
|
16
19
|
// by unmute (terminal_keys, permission UI). Gate: hard wins; otherwise
|
|
17
20
|
// muted iff softMute held without an unmute.
|
|
@@ -23,6 +26,7 @@ export class Shell {
|
|
|
23
26
|
strategy;
|
|
24
27
|
tmpDir;
|
|
25
28
|
constructor(opts) {
|
|
29
|
+
this.terminal = opts.terminal ?? processTerminal();
|
|
26
30
|
// Build environment — filter out undefined values (node-pty's native
|
|
27
31
|
// posix_spawnp fails if any env value is undefined)
|
|
28
32
|
const env = {};
|
|
@@ -58,18 +62,10 @@ export class Shell {
|
|
|
58
62
|
this.tmpDir = spawnConfig.tmpDir;
|
|
59
63
|
Object.assign(env, spawnConfig.envOverrides);
|
|
60
64
|
const shellArgs = spawnConfig.args;
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
process.stdin.setRawMode(false);
|
|
67
|
-
process.stdin.pause();
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
// Ignore
|
|
71
|
-
}
|
|
72
|
-
}
|
|
65
|
+
// The PTY will become the controlling terminal for the child shell;
|
|
66
|
+
// suspend the host terminal's input around spawn to avoid TTY contention
|
|
67
|
+
// on macOS. Headless terminals make this a no-op.
|
|
68
|
+
const suspended = this.terminal.suspendInput?.();
|
|
73
69
|
this.ptyProcess = pty.spawn(shellBin, shellArgs, {
|
|
74
70
|
name: "xterm-256color",
|
|
75
71
|
cols: opts.cols,
|
|
@@ -77,18 +73,7 @@ export class Shell {
|
|
|
77
73
|
cwd: opts.cwd,
|
|
78
74
|
env,
|
|
79
75
|
});
|
|
80
|
-
|
|
81
|
-
if (process.stdin.isTTY) {
|
|
82
|
-
try {
|
|
83
|
-
process.stdin.resume();
|
|
84
|
-
if (wasRaw) {
|
|
85
|
-
process.stdin.setRawMode(true);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// Ignore - will be set up later in index.ts
|
|
90
|
-
}
|
|
91
|
-
}
|
|
76
|
+
suspended?.resume();
|
|
92
77
|
clearOpost();
|
|
93
78
|
this.bus = opts.bus;
|
|
94
79
|
this.handlers = opts.handlers;
|
|
@@ -259,15 +244,14 @@ export class Shell {
|
|
|
259
244
|
this.pendingEchoSkips--;
|
|
260
245
|
const rest = data.slice(nlIdx + 1);
|
|
261
246
|
if (rest)
|
|
262
|
-
|
|
247
|
+
this.terminal.write(rest);
|
|
263
248
|
return;
|
|
264
249
|
}
|
|
265
|
-
|
|
250
|
+
this.terminal.write(data);
|
|
266
251
|
});
|
|
267
252
|
}
|
|
268
253
|
setupInput() {
|
|
269
|
-
|
|
270
|
-
const str = data.toString("utf-8");
|
|
254
|
+
this.inputDispose = this.terminal.onInput((str) => {
|
|
271
255
|
this.inputHandler.handleInput(str);
|
|
272
256
|
});
|
|
273
257
|
}
|
|
@@ -304,7 +288,7 @@ export class Shell {
|
|
|
304
288
|
this.bus.onPipeAsync("shell:exec-request", async (payload) => {
|
|
305
289
|
const visible = this.acquireUnmute("exec-request");
|
|
306
290
|
this.skipNextLine();
|
|
307
|
-
|
|
291
|
+
this.terminal.write("\r\n");
|
|
308
292
|
this.bus.emit("shell:agent-exec-start", {});
|
|
309
293
|
try {
|
|
310
294
|
const output = await new Promise((resolve, reject) => {
|
|
@@ -347,6 +331,8 @@ export class Shell {
|
|
|
347
331
|
this.ptyProcess.onExit(callback);
|
|
348
332
|
}
|
|
349
333
|
kill() {
|
|
334
|
+
this.inputDispose?.();
|
|
335
|
+
this.inputDispose = null;
|
|
350
336
|
this.ptyProcess.kill();
|
|
351
337
|
if (this.tmpDir) {
|
|
352
338
|
fs.rmSync(this.tmpDir, { recursive: true, force: true });
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal — the user-facing I/O endpoint that a Shell talks to.
|
|
3
|
+
*
|
|
4
|
+
* Shell wraps a *pseudo*-terminal (the PTY the child shell sees). This
|
|
5
|
+
* interface is the *real* terminal (or its substitute) on the other end:
|
|
6
|
+
* bytes in, bytes out, dimensions, resize notifications. The default
|
|
7
|
+
* factory wires it to process.stdin/stdout for the CLI; headless hosts
|
|
8
|
+
* (multi-session web hubs, tests) supply their own.
|
|
9
|
+
*/
|
|
10
|
+
import type { RenderSurface } from "../utils/compositor.js";
|
|
11
|
+
export interface Terminal {
|
|
12
|
+
write(data: string): void;
|
|
13
|
+
onInput(cb: (data: string) => void): () => void;
|
|
14
|
+
onResize(cb: (cols: number, rows: number) => void): () => void;
|
|
15
|
+
cols(): number;
|
|
16
|
+
rows(): number;
|
|
17
|
+
/**
|
|
18
|
+
* Called around PTY spawn to avoid TTY contention: the child PTY becomes
|
|
19
|
+
* the controlling tty for the spawned shell. No-op when the terminal
|
|
20
|
+
* isn't a real tty.
|
|
21
|
+
*/
|
|
22
|
+
suspendInput?(): {
|
|
23
|
+
resume(): void;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Default Terminal: wraps process.stdin/stdout. */
|
|
27
|
+
export declare function processTerminal(): Terminal;
|
|
28
|
+
/**
|
|
29
|
+
* Adapt a Terminal to a RenderSurface (the compositor's sink type). Adds
|
|
30
|
+
* the OPOST-cleared `\n` → `\r\n` translation that StdoutSurface applies,
|
|
31
|
+
* since the PTY has OPOST disabled.
|
|
32
|
+
*/
|
|
33
|
+
export declare function surfaceFromTerminal(terminal: Terminal): RenderSurface;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** Default Terminal: wraps process.stdin/stdout. */
|
|
2
|
+
export function processTerminal() {
|
|
3
|
+
return {
|
|
4
|
+
write(data) {
|
|
5
|
+
if (process.stdout.writable) {
|
|
6
|
+
try {
|
|
7
|
+
process.stdout.write(data);
|
|
8
|
+
}
|
|
9
|
+
catch { /* ignore */ }
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
onInput(cb) {
|
|
13
|
+
const handler = (b) => cb(b.toString("utf-8"));
|
|
14
|
+
process.stdin.on("data", handler);
|
|
15
|
+
return () => { process.stdin.off("data", handler); };
|
|
16
|
+
},
|
|
17
|
+
onResize(cb) {
|
|
18
|
+
const handler = () => cb(process.stdout.columns || 80, process.stdout.rows || 24);
|
|
19
|
+
process.stdout.on("resize", handler);
|
|
20
|
+
return () => { process.stdout.off("resize", handler); };
|
|
21
|
+
},
|
|
22
|
+
cols() { return process.stdout.columns || 80; },
|
|
23
|
+
rows() { return process.stdout.rows || 24; },
|
|
24
|
+
suspendInput() {
|
|
25
|
+
const wasRaw = process.stdin.isTTY && process.stdin.isRaw;
|
|
26
|
+
if (process.stdin.isTTY) {
|
|
27
|
+
try {
|
|
28
|
+
process.stdin.setRawMode(false);
|
|
29
|
+
process.stdin.pause();
|
|
30
|
+
}
|
|
31
|
+
catch { /* ignore */ }
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
resume() {
|
|
35
|
+
if (process.stdin.isTTY) {
|
|
36
|
+
try {
|
|
37
|
+
process.stdin.resume();
|
|
38
|
+
if (wasRaw)
|
|
39
|
+
process.stdin.setRawMode(true);
|
|
40
|
+
}
|
|
41
|
+
catch { /* ignore */ }
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Adapt a Terminal to a RenderSurface (the compositor's sink type). Adds
|
|
50
|
+
* the OPOST-cleared `\n` → `\r\n` translation that StdoutSurface applies,
|
|
51
|
+
* since the PTY has OPOST disabled.
|
|
52
|
+
*/
|
|
53
|
+
export function surfaceFromTerminal(terminal) {
|
|
54
|
+
const write = (text) => terminal.write(text.replace(/(?<!\r)\n/g, "\r\n"));
|
|
55
|
+
return {
|
|
56
|
+
write,
|
|
57
|
+
writeLine: (line) => write(line + "\n"),
|
|
58
|
+
get columns() { return terminal.cols(); },
|
|
59
|
+
get rows() { return terminal.rows(); },
|
|
60
|
+
onResize: (cb) => terminal.onResize(cb),
|
|
61
|
+
};
|
|
62
|
+
}
|