@phnx-labs/agents-cli 1.20.34 → 1.20.36
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/CHANGELOG.md +113 -0
- package/LICENSE +185 -21
- package/README.md +13 -5
- package/dist/commands/audit.d.ts +14 -0
- package/dist/commands/audit.js +68 -0
- package/dist/commands/browser.js +82 -8
- package/dist/commands/check.d.ts +15 -0
- package/dist/commands/check.js +84 -0
- package/dist/commands/cloud.js +143 -3
- package/dist/commands/computer-actions.d.ts +15 -0
- package/dist/commands/computer-actions.js +120 -22
- package/dist/commands/computer.js +81 -0
- package/dist/commands/cost.js +17 -12
- package/dist/commands/daemon.js +4 -1
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +54 -97
- package/dist/commands/events.d.ts +16 -0
- package/dist/commands/events.js +173 -0
- package/dist/commands/exec.d.ts +19 -0
- package/dist/commands/exec.js +283 -12
- package/dist/commands/hosts.js +37 -29
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +62 -16
- package/dist/commands/lock.d.ts +12 -0
- package/dist/commands/lock.js +70 -0
- package/dist/commands/logs.d.ts +17 -0
- package/dist/commands/logs.js +139 -0
- package/dist/commands/message.d.ts +15 -0
- package/dist/commands/message.js +56 -0
- package/dist/commands/models.d.ts +3 -0
- package/dist/commands/models.js +27 -8
- package/dist/commands/permissions.js +9 -2
- package/dist/commands/repo.d.ts +34 -0
- package/dist/commands/repo.js +243 -65
- package/dist/commands/resource-view.d.ts +20 -0
- package/dist/commands/resource-view.js +90 -28
- package/dist/commands/routines.js +101 -5
- package/dist/commands/secrets-migrate.js +106 -57
- package/dist/commands/secrets.d.ts +31 -18
- package/dist/commands/secrets.js +196 -91
- package/dist/commands/serve.d.ts +10 -0
- package/dist/commands/serve.js +37 -0
- package/dist/commands/sessions-inject.d.ts +14 -0
- package/dist/commands/sessions-inject.js +111 -0
- package/dist/commands/sessions-picker.d.ts +2 -0
- package/dist/commands/sessions-picker.js +24 -3
- package/dist/commands/sessions-resume.d.ts +2 -0
- package/dist/commands/sessions-resume.js +221 -0
- package/dist/commands/sessions-tail.d.ts +10 -0
- package/dist/commands/sessions-tail.js +11 -0
- package/dist/commands/sessions.d.ts +143 -1
- package/dist/commands/sessions.js +628 -80
- package/dist/commands/setup.js +4 -2
- package/dist/commands/sync.d.ts +3 -1
- package/dist/commands/sync.js +156 -4
- package/dist/commands/teams.js +217 -0
- package/dist/commands/versions.js +2 -4
- package/dist/commands/view.d.ts +3 -0
- package/dist/commands/view.js +19 -8
- package/dist/commands/wallet.d.ts +6 -0
- package/dist/commands/wallet.js +22 -5
- package/dist/commands/watchdog.d.ts +18 -0
- package/dist/commands/watchdog.js +238 -0
- package/dist/index.js +82 -32
- package/dist/lib/agents.js +30 -9
- package/dist/lib/audit/log.d.ts +92 -0
- package/dist/lib/audit/log.js +177 -0
- package/dist/lib/auto-pull.js +2 -1
- package/dist/lib/browser/cdp.js +5 -1
- package/dist/lib/browser/chrome.d.ts +10 -0
- package/dist/lib/browser/chrome.js +18 -7
- package/dist/lib/browser/drivers/ssh.d.ts +8 -0
- package/dist/lib/browser/drivers/ssh.js +77 -16
- package/dist/lib/browser/har.d.ts +84 -0
- package/dist/lib/browser/har.js +77 -0
- package/dist/lib/browser/ipc.d.ts +3 -0
- package/dist/lib/browser/ipc.js +37 -12
- package/dist/lib/browser/profiles.d.ts +1 -1
- package/dist/lib/browser/profiles.js +8 -10
- package/dist/lib/browser/refs.d.ts +65 -0
- package/dist/lib/browser/refs.js +73 -1
- package/dist/lib/browser/runtime-state.js +1 -0
- package/dist/lib/browser/service.d.ts +38 -2
- package/dist/lib/browser/service.js +183 -23
- package/dist/lib/browser/types.d.ts +14 -1
- package/dist/lib/budget/live-cloud.d.ts +42 -0
- package/dist/lib/budget/live-cloud.js +79 -0
- package/dist/lib/budget/live-team.d.ts +31 -0
- package/dist/lib/budget/live-team.js +115 -0
- package/dist/lib/cloud/codex.js +4 -0
- package/dist/lib/cloud/rush.d.ts +12 -1
- package/dist/lib/cloud/rush.js +13 -3
- package/dist/lib/cloud/types.d.ts +9 -0
- package/dist/lib/computer/dispatch.d.ts +8 -0
- package/dist/lib/computer/dispatch.js +125 -0
- package/dist/lib/computer/loop.d.ts +62 -0
- package/dist/lib/computer/loop.js +98 -0
- package/dist/lib/computer/model.d.ts +44 -0
- package/dist/lib/computer/model.js +157 -0
- package/dist/lib/concurrency.d.ts +19 -0
- package/dist/lib/concurrency.js +33 -0
- package/dist/lib/daemon.d.ts +92 -0
- package/dist/lib/daemon.js +222 -18
- package/dist/lib/devices/connect.d.ts +3 -2
- package/dist/lib/devices/connect.js +5 -3
- package/dist/lib/devices/registry.d.ts +7 -0
- package/dist/lib/devices/registry.js +24 -0
- package/dist/lib/devices/tailscale.js +1 -1
- package/dist/lib/drift.d.ts +52 -0
- package/dist/lib/drift.js +112 -0
- package/dist/lib/events.d.ts +10 -3
- package/dist/lib/events.js +101 -24
- package/dist/lib/exec.d.ts +17 -0
- package/dist/lib/exec.js +100 -12
- package/dist/lib/git.d.ts +27 -0
- package/dist/lib/git.js +56 -1
- package/dist/lib/hooks/cache.d.ts +6 -0
- package/dist/lib/hooks/cache.js +54 -12
- package/dist/lib/hooks.d.ts +27 -0
- package/dist/lib/hooks.js +135 -10
- package/dist/lib/hosts/dispatch.d.ts +15 -0
- package/dist/lib/hosts/dispatch.js +45 -13
- package/dist/lib/hosts/logs.d.ts +16 -0
- package/dist/lib/hosts/logs.js +74 -0
- package/dist/lib/hosts/option.js +1 -1
- package/dist/lib/hosts/passthrough.js +3 -1
- package/dist/lib/hosts/progress.d.ts +66 -0
- package/dist/lib/hosts/progress.js +125 -17
- package/dist/lib/hosts/ready.d.ts +51 -7
- package/dist/lib/hosts/ready.js +98 -25
- package/dist/lib/hosts/reconcile.d.ts +53 -0
- package/dist/lib/hosts/reconcile.js +81 -0
- package/dist/lib/hosts/registry.d.ts +19 -2
- package/dist/lib/hosts/registry.js +58 -2
- package/dist/lib/hosts/remote-cmd.d.ts +62 -1
- package/dist/lib/hosts/remote-cmd.js +70 -1
- package/dist/lib/hosts/remote-os.d.ts +17 -0
- package/dist/lib/hosts/remote-os.js +30 -0
- package/dist/lib/hosts/session-index.d.ts +34 -0
- package/dist/lib/hosts/session-index.js +56 -0
- package/dist/lib/hosts/tasks.d.ts +22 -0
- package/dist/lib/hosts/tasks.js +29 -0
- package/dist/lib/lock.d.ts +93 -0
- package/dist/lib/lock.js +207 -0
- package/dist/lib/loop.js +16 -1
- package/dist/lib/machine-id.d.ts +21 -0
- package/dist/lib/machine-id.js +26 -0
- package/dist/lib/mailbox-target.d.ts +36 -0
- package/dist/lib/mailbox-target.js +45 -0
- package/dist/lib/mailbox.d.ts +47 -0
- package/dist/lib/mailbox.js +194 -0
- package/dist/lib/mcp.d.ts +5 -0
- package/dist/lib/mcp.js +24 -8
- package/dist/lib/migrate.d.ts +19 -0
- package/dist/lib/migrate.js +134 -26
- package/dist/lib/overdue.js +3 -0
- package/dist/lib/permissions.d.ts +4 -0
- package/dist/lib/permissions.js +35 -0
- package/dist/lib/picker.d.ts +26 -0
- package/dist/lib/picker.js +127 -0
- package/dist/lib/platform/exec.d.ts +46 -0
- package/dist/lib/platform/exec.js +74 -0
- package/dist/lib/platform/process.d.ts +31 -0
- package/dist/lib/platform/process.js +34 -1
- package/dist/lib/platform/winpath.js +2 -0
- package/dist/lib/plugin-marketplace.d.ts +30 -0
- package/dist/lib/plugin-marketplace.js +215 -2
- package/dist/lib/plugins.d.ts +5 -0
- package/dist/lib/plugins.js +61 -10
- package/dist/lib/profiles.d.ts +25 -0
- package/dist/lib/profiles.js +22 -6
- package/dist/lib/pty-client.js +2 -1
- package/dist/lib/rotate.d.ts +61 -0
- package/dist/lib/rotate.js +52 -0
- package/dist/lib/routines.d.ts +40 -2
- package/dist/lib/routines.js +66 -8
- package/dist/lib/runner.d.ts +11 -2
- package/dist/lib/runner.js +49 -7
- package/dist/lib/scheduler.js +6 -1
- package/dist/lib/secrets/bundles.d.ts +60 -4
- package/dist/lib/secrets/bundles.js +131 -12
- package/dist/lib/secrets/filestore.d.ts +3 -0
- package/dist/lib/secrets/filestore.js +42 -16
- package/dist/lib/secrets/index.d.ts +43 -2
- package/dist/lib/secrets/index.js +102 -3
- package/dist/lib/secrets/mcp.d.ts +93 -0
- package/dist/lib/secrets/mcp.js +205 -0
- package/dist/lib/secrets/remote.js +12 -5
- package/dist/lib/secrets/sync.js +83 -4
- package/dist/lib/secrets/windows.js +14 -3
- package/dist/lib/serve/data.d.ts +81 -0
- package/dist/lib/serve/data.js +91 -0
- package/dist/lib/serve/page.d.ts +7 -0
- package/dist/lib/serve/page.js +140 -0
- package/dist/lib/serve/server.d.ts +46 -0
- package/dist/lib/serve/server.js +115 -0
- package/dist/lib/session/active.d.ts +61 -0
- package/dist/lib/session/active.js +196 -17
- package/dist/lib/session/discover.d.ts +37 -0
- package/dist/lib/session/discover.js +204 -27
- package/dist/lib/session/inject.d.ts +18 -0
- package/dist/lib/session/inject.js +21 -0
- package/dist/lib/session/parse.d.ts +6 -0
- package/dist/lib/session/parse.js +286 -2
- package/dist/lib/session/pid-registry.d.ts +22 -0
- package/dist/lib/session/pid-registry.js +104 -0
- package/dist/lib/session/provenance.d.ts +14 -2
- package/dist/lib/session/provenance.js +39 -8
- package/dist/lib/session/remote-active.d.ts +26 -0
- package/dist/lib/session/remote-active.js +153 -0
- package/dist/lib/session/remote-list.d.ts +51 -0
- package/dist/lib/session/remote-list.js +213 -0
- package/dist/lib/session/remote.d.ts +7 -1
- package/dist/lib/session/remote.js +18 -8
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/sync/config.d.ts +1 -7
- package/dist/lib/session/sync/config.js +4 -11
- package/dist/lib/session/types.d.ts +18 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +44 -6
- package/dist/lib/shims.js +143 -57
- package/dist/lib/ssh-exec.d.ts +26 -3
- package/dist/lib/ssh-exec.js +47 -3
- package/dist/lib/ssh-tunnel.d.ts +24 -5
- package/dist/lib/ssh-tunnel.js +62 -63
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +8 -0
- package/dist/lib/startup/command-registry.js +17 -1
- package/dist/lib/state.d.ts +13 -0
- package/dist/lib/state.js +103 -9
- package/dist/lib/sync-umbrella.d.ts +14 -7
- package/dist/lib/sync-umbrella.js +17 -9
- package/dist/lib/teams/forEach.d.ts +110 -0
- package/dist/lib/teams/forEach.js +186 -0
- package/dist/lib/teams/index.d.ts +1 -0
- package/dist/lib/teams/index.js +1 -0
- package/dist/lib/teams/pr-watch.d.ts +226 -0
- package/dist/lib/teams/pr-watch.js +371 -0
- package/dist/lib/teams/registry.js +25 -9
- package/dist/lib/teams/supervisor.d.ts +14 -1
- package/dist/lib/teams/supervisor.js +19 -0
- package/dist/lib/teams/worktree.d.ts +9 -0
- package/dist/lib/teams/worktree.js +32 -0
- package/dist/lib/terminal/backends/ghostty.d.ts +6 -0
- package/dist/lib/terminal/backends/ghostty.js +69 -0
- package/dist/lib/terminal/backends/index.d.ts +19 -0
- package/dist/lib/terminal/backends/index.js +31 -0
- package/dist/lib/terminal/backends/iterm.d.ts +6 -0
- package/dist/lib/terminal/backends/iterm.js +62 -0
- package/dist/lib/terminal/backends/tmux.d.ts +14 -0
- package/dist/lib/terminal/backends/tmux.js +23 -0
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +31 -0
- package/dist/lib/terminal/backends/vscodium-agent.js +72 -0
- package/dist/lib/terminal/engine.d.ts +39 -0
- package/dist/lib/terminal/engine.js +54 -0
- package/dist/lib/terminal/index.d.ts +17 -0
- package/dist/lib/terminal/index.js +8 -0
- package/dist/lib/terminal/inject.d.ts +204 -0
- package/dist/lib/terminal/inject.js +247 -0
- package/dist/lib/terminal/policy.d.ts +11 -0
- package/dist/lib/terminal/policy.js +11 -0
- package/dist/lib/terminal/quote.d.ts +11 -0
- package/dist/lib/terminal/quote.js +13 -0
- package/dist/lib/terminal/resolve.d.ts +64 -0
- package/dist/lib/terminal/resolve.js +90 -0
- package/dist/lib/terminal/shell.d.ts +6 -0
- package/dist/lib/terminal/shell.js +23 -0
- package/dist/lib/terminal/transport.d.ts +15 -0
- package/dist/lib/terminal/transport.js +40 -0
- package/dist/lib/terminal/types.d.ts +59 -0
- package/dist/lib/terminal/types.js +13 -0
- package/dist/lib/triggers/webhook.d.ts +85 -0
- package/dist/lib/triggers/webhook.js +141 -0
- package/dist/lib/types.d.ts +7 -0
- package/dist/lib/versions.d.ts +30 -3
- package/dist/lib/versions.js +129 -18
- package/dist/lib/watchdog/index.d.ts +3 -0
- package/dist/lib/watchdog/index.js +5 -0
- package/dist/lib/watchdog/read.d.ts +35 -0
- package/dist/lib/watchdog/read.js +149 -0
- package/dist/lib/watchdog/runner.d.ts +127 -0
- package/dist/lib/watchdog/runner.js +322 -0
- package/dist/lib/watchdog/watchdog.d.ts +40 -0
- package/dist/lib/watchdog/watchdog.js +166 -0
- package/dist/lib/watchdog/watchdogTail.d.ts +5 -0
- package/dist/lib/watchdog/watchdogTail.js +154 -0
- package/dist/lib/whats-new.d.ts +9 -0
- package/dist/lib/whats-new.js +35 -0
- package/dist/lib/workflows.d.ts +166 -0
- package/dist/lib/workflows.js +193 -0
- package/package.json +5 -4
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { itermBackend } from './iterm.js';
|
|
2
|
+
import { ghosttyBackend } from './ghostty.js';
|
|
3
|
+
import { tmuxBackend } from './tmux.js';
|
|
4
|
+
import { vscodiumAgentBackend } from './vscodium-agent.js';
|
|
5
|
+
/** All known interactive backends, keyed by id. */
|
|
6
|
+
export const BACKENDS = {
|
|
7
|
+
iterm: itermBackend,
|
|
8
|
+
ghostty: ghosttyBackend,
|
|
9
|
+
tmux: tmuxBackend,
|
|
10
|
+
'vscodium-agent': vscodiumAgentBackend,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The backend for the terminal the CLI is currently running in, or null if we
|
|
14
|
+
* can't open a surface into it. tmux wins (via `$TMUX`) because a tmux pane can
|
|
15
|
+
* live inside iTerm/Ghostty; otherwise fall back to `TERM_PROGRAM`.
|
|
16
|
+
*/
|
|
17
|
+
export function detectCurrentBackend(ctx) {
|
|
18
|
+
if (ctx.env.TMUX)
|
|
19
|
+
return 'tmux';
|
|
20
|
+
const term = (ctx.env.TERM_PROGRAM || '').toLowerCase();
|
|
21
|
+
if (term.includes('iterm'))
|
|
22
|
+
return 'iterm';
|
|
23
|
+
if (term.includes('ghostty'))
|
|
24
|
+
return 'ghostty';
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
/** Backends that can actually be driven in this context. */
|
|
28
|
+
export function availableBackends(ctx) {
|
|
29
|
+
return Object.values(BACKENDS).filter((b) => b.isAvailable(ctx));
|
|
30
|
+
}
|
|
31
|
+
export { itermBackend, ghosttyBackend, tmuxBackend, vscodiumAgentBackend };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TerminalBackend, SplitDirection } from '../types.js';
|
|
2
|
+
/** AppleScript that opens an iTerm tab (a window if none is open) running the command. */
|
|
3
|
+
export declare function itermTabScript(cwd: string, command: string[]): string;
|
|
4
|
+
/** AppleScript that splits the current iTerm session (a window if none is open). */
|
|
5
|
+
export declare function itermSplitScript(cwd: string, command: string[], direction: SplitDirection): string;
|
|
6
|
+
export declare const itermBackend: TerminalBackend;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* iTerm backend — drives iTerm2 via AppleScript (`osascript`).
|
|
3
|
+
*
|
|
4
|
+
* Tab: creates a tab in the current window (or a window when none is open).
|
|
5
|
+
* Split: splits the current session — `split vertically` (side-by-side, a
|
|
6
|
+
* vertical divider) for `right`, `split horizontally` (stacked) for `down`.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import { appleScriptStr } from '../quote.js';
|
|
10
|
+
import { loginExec, iLoginShell } from '../shell.js';
|
|
11
|
+
const ITERM_APP = '/Applications/iTerm.app';
|
|
12
|
+
function appExists(p) {
|
|
13
|
+
try {
|
|
14
|
+
return fs.existsSync(p);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** AppleScript that opens an iTerm tab (a window if none is open) running the command. */
|
|
21
|
+
export function itermTabScript(cwd, command) {
|
|
22
|
+
const cmd = appleScriptStr(iLoginShell(loginExec(cwd, command)));
|
|
23
|
+
return [
|
|
24
|
+
'tell application "iTerm2"',
|
|
25
|
+
' activate',
|
|
26
|
+
' if (count of windows) is 0 then',
|
|
27
|
+
` create window with default profile command ${cmd}`,
|
|
28
|
+
' else',
|
|
29
|
+
` tell current window to create tab with default profile command ${cmd}`,
|
|
30
|
+
' end if',
|
|
31
|
+
'end tell',
|
|
32
|
+
].join('\n');
|
|
33
|
+
}
|
|
34
|
+
/** AppleScript that splits the current iTerm session (a window if none is open). */
|
|
35
|
+
export function itermSplitScript(cwd, command, direction) {
|
|
36
|
+
const cmd = appleScriptStr(iLoginShell(loginExec(cwd, command)));
|
|
37
|
+
// iTerm: "split vertically" = a vertical divider = panes side by side (right).
|
|
38
|
+
const verb = direction === 'right' ? 'split vertically' : 'split horizontally';
|
|
39
|
+
return [
|
|
40
|
+
'tell application "iTerm2"',
|
|
41
|
+
' activate',
|
|
42
|
+
' if (count of windows) is 0 then',
|
|
43
|
+
` create window with default profile command ${cmd}`,
|
|
44
|
+
' else',
|
|
45
|
+
` tell current session of current window to ${verb} with default profile command ${cmd}`,
|
|
46
|
+
' end if',
|
|
47
|
+
'end tell',
|
|
48
|
+
].join('\n');
|
|
49
|
+
}
|
|
50
|
+
export const itermBackend = {
|
|
51
|
+
id: 'iterm',
|
|
52
|
+
label: 'iTerm',
|
|
53
|
+
isAvailable(ctx) {
|
|
54
|
+
return ctx.platform === 'darwin' && appExists(ITERM_APP);
|
|
55
|
+
},
|
|
56
|
+
buildTab(cwd, command) {
|
|
57
|
+
return { argv: ['osascript', '-e', itermTabScript(cwd, command)] };
|
|
58
|
+
},
|
|
59
|
+
buildSplit(cwd, command, direction) {
|
|
60
|
+
return { argv: ['osascript', '-e', itermSplitScript(cwd, command, direction)] };
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tmux backend — opens windows and splits in the running tmux server.
|
|
3
|
+
*
|
|
4
|
+
* cwd is passed natively via `-c`, so the command is wrapped in `zsh -ilc` with
|
|
5
|
+
* no `cd`. `split-window -h` = side-by-side (right); `-v` = stacked (down).
|
|
6
|
+
* Available only when the CLI is running inside tmux (`$TMUX` set) — otherwise
|
|
7
|
+
* there is no current window/pane to attach to.
|
|
8
|
+
*/
|
|
9
|
+
import type { TerminalBackend, SplitDirection } from '../types.js';
|
|
10
|
+
/** argv that opens a new tmux window running the command in cwd. */
|
|
11
|
+
export declare function tmuxTabArgv(cwd: string, command: string[]): string[];
|
|
12
|
+
/** argv that splits the current tmux pane, running the command in cwd. */
|
|
13
|
+
export declare function tmuxSplitArgv(cwd: string, command: string[], direction: SplitDirection): string[];
|
|
14
|
+
export declare const tmuxBackend: TerminalBackend;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { execOnly, iLoginShell } from '../shell.js';
|
|
2
|
+
/** argv that opens a new tmux window running the command in cwd. */
|
|
3
|
+
export function tmuxTabArgv(cwd, command) {
|
|
4
|
+
return ['tmux', 'new-window', '-c', cwd, iLoginShell(execOnly(command))];
|
|
5
|
+
}
|
|
6
|
+
/** argv that splits the current tmux pane, running the command in cwd. */
|
|
7
|
+
export function tmuxSplitArgv(cwd, command, direction) {
|
|
8
|
+
const flag = direction === 'right' ? '-h' : '-v';
|
|
9
|
+
return ['tmux', 'split-window', flag, '-c', cwd, iLoginShell(execOnly(command))];
|
|
10
|
+
}
|
|
11
|
+
export const tmuxBackend = {
|
|
12
|
+
id: 'tmux',
|
|
13
|
+
label: 'tmux',
|
|
14
|
+
isAvailable(ctx) {
|
|
15
|
+
return Boolean(ctx.env.TMUX);
|
|
16
|
+
},
|
|
17
|
+
buildTab(cwd, command) {
|
|
18
|
+
return { argv: tmuxTabArgv(cwd, command) };
|
|
19
|
+
},
|
|
20
|
+
buildSplit(cwd, command, direction) {
|
|
21
|
+
return { argv: tmuxSplitArgv(cwd, command, direction) };
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { TerminalBackend, SplitDirection } from '../types.js';
|
|
2
|
+
/** An editor flavour that speaks the swarm-ext URI protocol. */
|
|
3
|
+
export interface EditorVariant {
|
|
4
|
+
/** CLI on PATH, invoked with `--open-url`. */
|
|
5
|
+
cli: string;
|
|
6
|
+
/** URL scheme the product registers (must match the CLI's product). */
|
|
7
|
+
scheme: string;
|
|
8
|
+
/** macOS app bundle, for local availability detection. */
|
|
9
|
+
app: string;
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Known editors, in preference order. VSCodium first — the backend is named for
|
|
14
|
+
* it and is the user's editor; Cursor and VS Code also ship the extension and
|
|
15
|
+
* are wired here for `makeVscodiumAgentBackend` / future registration.
|
|
16
|
+
*/
|
|
17
|
+
export declare const EDITOR_VARIANTS: EditorVariant[];
|
|
18
|
+
/**
|
|
19
|
+
* The `<scheme>://swarmify.swarm-ext/spawn?p=<payload>` URL the extension handles.
|
|
20
|
+
*
|
|
21
|
+
* The payload is base64url-encoded JSON in a single `p` param — NOT one param per
|
|
22
|
+
* field. VS Code percent-*decodes* `uri.query` once before the extension parses
|
|
23
|
+
* it, so a `command`/`cwd` containing `&` (or `=`) would be mis-split by a naive
|
|
24
|
+
* multi-param query. base64url is `[A-Za-z0-9_-]` only (no `&`, `=`, `%`, `+`,
|
|
25
|
+
* `/`), so it survives that decode untouched and round-trips exactly.
|
|
26
|
+
*/
|
|
27
|
+
export declare function spawnUri(scheme: string, cwd: string, command: string[], direction?: SplitDirection): string;
|
|
28
|
+
/** Build a backend bound to one editor variant. */
|
|
29
|
+
export declare function makeVscodiumAgentBackend(variant: EditorVariant): TerminalBackend;
|
|
30
|
+
/** Default backend: VSCodium (`codium` CLI, `vscodium://` scheme). */
|
|
31
|
+
export declare const vscodiumAgentBackend: TerminalBackend;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VSCodium agent-terminal backend — opens an agent terminal in a VSCodium /
|
|
3
|
+
* Cursor / VS Code window via the swarmify `swarm-ext` extension's URI handler.
|
|
4
|
+
*
|
|
5
|
+
* Unlike iTerm/Ghostty (GUI terminal apps driven by AppleScript), the editor is
|
|
6
|
+
* already running; we hand it a `<scheme>://swarmify.swarm-ext/spawn?…` URL via
|
|
7
|
+
* the editor CLI's `--open-url` flag. The extension opens an editor-tab terminal
|
|
8
|
+
* in `cwd`, runs `command`, and its shell-adoption promotes a resume command
|
|
9
|
+
* (e.g. `claude --resume <id>`) to the matching agent chip. Driving the editor
|
|
10
|
+
* CLI (not macOS `open`) means this works over `--host` SSH and on Linux, needs
|
|
11
|
+
* no OS URL-scheme handler registration, and sends the command into an
|
|
12
|
+
* already-interactive login shell — so no `zsh -ilc` wrap (the other backends'
|
|
13
|
+
* wrapper) is applied here.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
/** The swarmify extension identifier that owns the `/spawn` URI verb. */
|
|
17
|
+
const EXTENSION_AUTHORITY = 'swarmify.swarm-ext';
|
|
18
|
+
/**
|
|
19
|
+
* Known editors, in preference order. VSCodium first — the backend is named for
|
|
20
|
+
* it and is the user's editor; Cursor and VS Code also ship the extension and
|
|
21
|
+
* are wired here for `makeVscodiumAgentBackend` / future registration.
|
|
22
|
+
*/
|
|
23
|
+
export const EDITOR_VARIANTS = [
|
|
24
|
+
{ cli: 'codium', scheme: 'vscodium', app: '/Applications/VSCodium.app', label: 'VSCodium' },
|
|
25
|
+
{ cli: 'cursor', scheme: 'cursor', app: '/Applications/Cursor.app', label: 'Cursor' },
|
|
26
|
+
{ cli: 'code', scheme: 'vscode', app: '/Applications/Visual Studio Code.app', label: 'VS Code' },
|
|
27
|
+
];
|
|
28
|
+
function appExists(p) {
|
|
29
|
+
try {
|
|
30
|
+
return fs.existsSync(p);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The `<scheme>://swarmify.swarm-ext/spawn?p=<payload>` URL the extension handles.
|
|
38
|
+
*
|
|
39
|
+
* The payload is base64url-encoded JSON in a single `p` param — NOT one param per
|
|
40
|
+
* field. VS Code percent-*decodes* `uri.query` once before the extension parses
|
|
41
|
+
* it, so a `command`/`cwd` containing `&` (or `=`) would be mis-split by a naive
|
|
42
|
+
* multi-param query. base64url is `[A-Za-z0-9_-]` only (no `&`, `=`, `%`, `+`,
|
|
43
|
+
* `/`), so it survives that decode untouched and round-trips exactly.
|
|
44
|
+
*/
|
|
45
|
+
export function spawnUri(scheme, cwd, command, direction) {
|
|
46
|
+
const payload = {
|
|
47
|
+
command: command.join(' '),
|
|
48
|
+
cwd,
|
|
49
|
+
};
|
|
50
|
+
if (direction)
|
|
51
|
+
payload.split = direction;
|
|
52
|
+
const p = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64url');
|
|
53
|
+
return `${scheme}://${EXTENSION_AUTHORITY}/spawn?p=${p}`;
|
|
54
|
+
}
|
|
55
|
+
/** Build a backend bound to one editor variant. */
|
|
56
|
+
export function makeVscodiumAgentBackend(variant) {
|
|
57
|
+
return {
|
|
58
|
+
id: 'vscodium-agent',
|
|
59
|
+
label: `${variant.label} agent`,
|
|
60
|
+
isAvailable(ctx) {
|
|
61
|
+
return ctx.platform === 'darwin' && appExists(variant.app);
|
|
62
|
+
},
|
|
63
|
+
buildTab(cwd, command) {
|
|
64
|
+
return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command)] };
|
|
65
|
+
},
|
|
66
|
+
buildSplit(cwd, command, direction) {
|
|
67
|
+
return { argv: [variant.cli, '--open-url', spawnUri(variant.scheme, cwd, command, direction)] };
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Default backend: VSCodium (`codium` CLI, `vscodium://` scheme). */
|
|
72
|
+
export const vscodiumAgentBackend = makeVscodiumAgentBackend(EDITOR_VARIANTS[0]);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine — turns requests into open surfaces.
|
|
3
|
+
*
|
|
4
|
+
* `specForRequest` and `buildRequests` are pure (planning); `openSurface` and
|
|
5
|
+
* `openSurfaces` add the side-effecting transport. A batch runs sequentially and
|
|
6
|
+
* staggered so a `split-right` lands in the tab that was just opened (the split
|
|
7
|
+
* targets the front pane).
|
|
8
|
+
*/
|
|
9
|
+
import type { Backend, EngineContext, LaunchRequest, LaunchResult, LaunchSpec } from './types.js';
|
|
10
|
+
import { type Packing } from './policy.js';
|
|
11
|
+
import { type HostResolver } from './transport.js';
|
|
12
|
+
/** The concrete launch command for a request (pure — no side effects). */
|
|
13
|
+
export declare function specForRequest(req: LaunchRequest): LaunchSpec;
|
|
14
|
+
export interface OpenOptions {
|
|
15
|
+
resolveHost?: HostResolver;
|
|
16
|
+
ctx?: EngineContext;
|
|
17
|
+
}
|
|
18
|
+
/** Open a single surface for one request. Never throws — failures come back in the result. */
|
|
19
|
+
export declare function openSurface(req: LaunchRequest, opts?: OpenOptions): Promise<LaunchResult>;
|
|
20
|
+
/** One command to run as a surface. */
|
|
21
|
+
export interface SurfaceItem {
|
|
22
|
+
cwd: string;
|
|
23
|
+
command: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface BuildRequestsOptions {
|
|
26
|
+
backend: Backend;
|
|
27
|
+
host?: string;
|
|
28
|
+
packing?: Packing;
|
|
29
|
+
}
|
|
30
|
+
/** Turn a list of commands into layout-assigned requests (pure — the planning step). */
|
|
31
|
+
export declare function buildRequests(items: SurfaceItem[], opts: BuildRequestsOptions): LaunchRequest[];
|
|
32
|
+
export interface OpenManyOptions extends OpenOptions, BuildRequestsOptions {
|
|
33
|
+
staggerMs?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Open many surfaces, applying the layout policy (default: two-per-tab).
|
|
37
|
+
* Sequential + staggered so each split follows the tab it splits.
|
|
38
|
+
*/
|
|
39
|
+
export declare function openSurfaces(items: SurfaceItem[], opts: OpenManyOptions): Promise<LaunchResult[]>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BACKENDS } from './backends/index.js';
|
|
2
|
+
import { planLayouts } from './policy.js';
|
|
3
|
+
import { runSpec } from './transport.js';
|
|
4
|
+
const DEFAULT_STAGGER_MS = 400;
|
|
5
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
6
|
+
/** The concrete launch command for a request (pure — no side effects). */
|
|
7
|
+
export function specForRequest(req) {
|
|
8
|
+
const backend = BACKENDS[req.backend];
|
|
9
|
+
if (!backend)
|
|
10
|
+
throw new Error(`unknown backend: ${req.backend}`);
|
|
11
|
+
if (req.layout === 'tab')
|
|
12
|
+
return backend.buildTab(req.cwd, req.command);
|
|
13
|
+
return backend.buildSplit(req.cwd, req.command, req.layout === 'split-down' ? 'down' : 'right');
|
|
14
|
+
}
|
|
15
|
+
/** Open a single surface for one request. Never throws — failures come back in the result. */
|
|
16
|
+
export async function openSurface(req, opts = {}) {
|
|
17
|
+
try {
|
|
18
|
+
// Both can throw: specForRequest on an unknown backend, runSpec when the
|
|
19
|
+
// SSH transport rejects an invalid --host target. Keep them inside the
|
|
20
|
+
// catch so a bad request degrades to a per-surface failure, never a throw.
|
|
21
|
+
const spec = specForRequest(req);
|
|
22
|
+
const res = await runSpec(spec, req.host, opts.resolveHost);
|
|
23
|
+
return { ok: res.ok, request: req, error: res.error };
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return { ok: false, request: req, error: err?.message ?? String(err) };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Turn a list of commands into layout-assigned requests (pure — the planning step). */
|
|
30
|
+
export function buildRequests(items, opts) {
|
|
31
|
+
const layouts = planLayouts(items.length, opts.packing ?? 'two-per-tab');
|
|
32
|
+
return items.map((item, i) => ({
|
|
33
|
+
backend: opts.backend,
|
|
34
|
+
layout: layouts[i],
|
|
35
|
+
cwd: item.cwd,
|
|
36
|
+
command: item.command,
|
|
37
|
+
host: opts.host,
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Open many surfaces, applying the layout policy (default: two-per-tab).
|
|
42
|
+
* Sequential + staggered so each split follows the tab it splits.
|
|
43
|
+
*/
|
|
44
|
+
export async function openSurfaces(items, opts) {
|
|
45
|
+
const requests = buildRequests(items, opts);
|
|
46
|
+
const stagger = opts.staggerMs ?? DEFAULT_STAGGER_MS;
|
|
47
|
+
const results = [];
|
|
48
|
+
for (let i = 0; i < requests.length; i++) {
|
|
49
|
+
results.push(await openSurface(requests[i], opts));
|
|
50
|
+
if (i < requests.length - 1)
|
|
51
|
+
await sleep(stagger);
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
54
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal launch engine — open an interactive command as a tab or split pane
|
|
3
|
+
* in iTerm / Ghostty / tmux, on this machine or a remote host.
|
|
4
|
+
*
|
|
5
|
+
* Public entry point. Callers typically use `openSurfaces` (a batch with a
|
|
6
|
+
* layout policy) or `openSurface` (a single request), and `availableBackends` /
|
|
7
|
+
* `detectCurrentBackend` to pick a target. See docs/terminal-engine.md.
|
|
8
|
+
*/
|
|
9
|
+
export type { Backend, SplitDirection, Layout, EngineContext, LaunchSpec, LaunchRequest, LaunchResult, TerminalBackend, } from './types.js';
|
|
10
|
+
export { currentContext } from './types.js';
|
|
11
|
+
export { BACKENDS, detectCurrentBackend, availableBackends, itermBackend, ghosttyBackend, tmuxBackend, vscodiumAgentBackend } from './backends/index.js';
|
|
12
|
+
export { makeVscodiumAgentBackend, spawnUri, EDITOR_VARIANTS, type EditorVariant } from './backends/vscodium-agent.js';
|
|
13
|
+
export { planLayouts, type Packing } from './policy.js';
|
|
14
|
+
export { specForRequest, buildRequests, openSurface, openSurfaces, type OpenOptions, type OpenManyOptions, type BuildRequestsOptions, type SurfaceItem, } from './engine.js';
|
|
15
|
+
export { runLocal, runRemote, runSpec, remoteCommand, type HostResolver, type RunResult } from './transport.js';
|
|
16
|
+
export { injectIntoTerminal, tmuxSendKeysArgv, tmuxInjectSpecs, itermInjectScript, ghosttyInjectScript, appleScriptInjectSpec, vscodiumInjectUri, vscodiumInjectSpec, type InjectTarget, type InjectBackend, type InjectOptions, type InjectResult, } from './inject.js';
|
|
17
|
+
export { resolveInjectTarget, resolveInjectTargetForSession, type InjectResolution, type InjectRail, type ResolveOptions, } from './resolve.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { currentContext } from './types.js';
|
|
2
|
+
export { BACKENDS, detectCurrentBackend, availableBackends, itermBackend, ghosttyBackend, tmuxBackend, vscodiumAgentBackend } from './backends/index.js';
|
|
3
|
+
export { makeVscodiumAgentBackend, spawnUri, EDITOR_VARIANTS } from './backends/vscodium-agent.js';
|
|
4
|
+
export { planLayouts } from './policy.js';
|
|
5
|
+
export { specForRequest, buildRequests, openSurface, openSurfaces, } from './engine.js';
|
|
6
|
+
export { runLocal, runRemote, runSpec, remoteCommand } from './transport.js';
|
|
7
|
+
export { injectIntoTerminal, tmuxSendKeysArgv, tmuxInjectSpecs, itermInjectScript, ghosttyInjectScript, appleScriptInjectSpec, vscodiumInjectUri, vscodiumInjectSpec, } from './inject.js';
|
|
8
|
+
export { resolveInjectTarget, resolveInjectTargetForSession, } from './resolve.js';
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal injection — Gap 2 of the Terminal Engine.
|
|
3
|
+
*
|
|
4
|
+
* Where the rest of the engine OPENS a surface (a tab / split running a
|
|
5
|
+
* command), injection types into an ALREADY-running surface. It's the primitive
|
|
6
|
+
* a native watchdog (RUSH-1415) needs to nudge a stalled agent with "continue"
|
|
7
|
+
* delivered into the exact terminal that agent lives in — the gap flagged in
|
|
8
|
+
* src/lib/session/provenance.ts:20:
|
|
9
|
+
*
|
|
10
|
+
* > Actually delivering the keystrokes is Gap 2 (pty/tmux send-keys).
|
|
11
|
+
*
|
|
12
|
+
* It mirrors the engine's shape exactly: pure per-backend spec builders (like
|
|
13
|
+
* `tmuxTabArgv` / `itermTabScript`) produce a `LaunchSpec` (argv), and the same
|
|
14
|
+
* `runSpec` transport runs it — so injection inherits the engine's local/remote
|
|
15
|
+
* (`--host` over SSH) execution for free. A `LaunchSpec` never opens anything;
|
|
16
|
+
* building one is side-effect-free and unit-testable without a display.
|
|
17
|
+
*
|
|
18
|
+
* Backends (each addresses the EXACT split, not the frontmost surface):
|
|
19
|
+
* - tmux → `tmux send-keys -t <pane>` — the send-keys primitive addressed by
|
|
20
|
+
* pane id + socket (the exact rail provenance.ts identifies).
|
|
21
|
+
* - iterm (macOS) → AppleScript `tell session id "<uuid>" to write text` —
|
|
22
|
+
* addresses the precise iTerm2 split by its session UUID WITHOUT
|
|
23
|
+
* `activate`, so it never steals focus or types into the wrong split.
|
|
24
|
+
* Uses the engine's `appleScriptStr` escaper; guarded by the iterm
|
|
25
|
+
* backend's `isAvailable` (platform + app installed).
|
|
26
|
+
* - vscodium (VSCodium / Cursor / VS Code) → the editor CLI's `--open-url`
|
|
27
|
+
* into the swarmify `swarm-ext` extension's `/inject` verb, targeting
|
|
28
|
+
* a live-terminals.json terminal by id. Focus-independent, exact
|
|
29
|
+
* terminal, and (like the launch backend, src/lib/terminal/backends/
|
|
30
|
+
* vscodium-agent.ts) works over `--host` SSH and on Linux.
|
|
31
|
+
* - ghostty (macOS) → COARSE only: Ghostty has no scripting dictionary, so
|
|
32
|
+
* there is no per-split addressing — this raises a window and types
|
|
33
|
+
* via System Events keystrokes, stealing focus. The resolver refuses
|
|
34
|
+
* to route here by default (see resolve.ts); it stays behind an
|
|
35
|
+
* explicit opt-in.
|
|
36
|
+
* - pty → the `agents pty write` sidecar path (ptyRequest). Local-only —
|
|
37
|
+
* the sidecar is not an engine transport surface.
|
|
38
|
+
*
|
|
39
|
+
* Ink-TUI Enter semantics: Claude's Ink TUI swallows an Enter fused to the text,
|
|
40
|
+
* so the default path delivers the text and the Enter as TWO SEPARATE writes
|
|
41
|
+
* (swarmify's `sendText(text,false)` then `sendText('\r',false)`). `combined`
|
|
42
|
+
* opts into one fused write for plain shells / REPLs.
|
|
43
|
+
*/
|
|
44
|
+
import { type HostResolver } from './transport.js';
|
|
45
|
+
import { type LaunchSpec, type EngineContext } from './types.js';
|
|
46
|
+
/**
|
|
47
|
+
* An already-running surface to type into. A superset of the engine's launch
|
|
48
|
+
* `Backend` — it adds `pty` (the sidecar), which the engine can't launch but can
|
|
49
|
+
* be injected into.
|
|
50
|
+
*/
|
|
51
|
+
export type InjectTarget = {
|
|
52
|
+
backend: 'tmux';
|
|
53
|
+
pane: string;
|
|
54
|
+
socket?: string;
|
|
55
|
+
} | {
|
|
56
|
+
backend: 'iterm';
|
|
57
|
+
session?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A VSCodium / Cursor / VS Code integrated terminal, addressed by the id the
|
|
61
|
+
* swarm-ext extension keys `live-terminals.json` on (the session UUID). `cli`
|
|
62
|
+
* is the editor CLI on PATH (`codium` / `cursor` / `code`); `scheme` is its
|
|
63
|
+
* URL scheme (`vscodium` / `cursor` / `vscode`) — the resolver fills both.
|
|
64
|
+
*/
|
|
65
|
+
| {
|
|
66
|
+
backend: 'vscodium';
|
|
67
|
+
terminalId: string;
|
|
68
|
+
cli: string;
|
|
69
|
+
scheme: string;
|
|
70
|
+
} | {
|
|
71
|
+
backend: 'ghostty';
|
|
72
|
+
window?: string;
|
|
73
|
+
} | {
|
|
74
|
+
backend: 'pty';
|
|
75
|
+
id: string;
|
|
76
|
+
};
|
|
77
|
+
export type InjectBackend = InjectTarget['backend'];
|
|
78
|
+
export interface InjectOptions {
|
|
79
|
+
/** Append Enter after the text. Default true. */
|
|
80
|
+
enter?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Fuse the text and its Enter into a SINGLE write. Default false — the safe
|
|
83
|
+
* default sends the text, then the Enter, as two separate writes (Ink-TUI
|
|
84
|
+
* safe). Set true for plain shells / REPLs that want one atomic line.
|
|
85
|
+
*/
|
|
86
|
+
combined?: boolean;
|
|
87
|
+
/** tmux socket override (defaults to `target.socket`, then tmux's default socket). */
|
|
88
|
+
socket?: string;
|
|
89
|
+
/** Remote host for the tmux / AppleScript backends (runs the spec over SSH). Local by default. */
|
|
90
|
+
host?: string;
|
|
91
|
+
/** Resolve a host alias to an ssh target (see the engine's transport). */
|
|
92
|
+
resolveHost?: HostResolver;
|
|
93
|
+
/** Ambient context for the availability check (defaults to the live process context). */
|
|
94
|
+
ctx?: EngineContext;
|
|
95
|
+
/** Don't execute — return the spec(s) that WOULD run. Lets the macOS paths be asserted on Linux. */
|
|
96
|
+
dryRun?: boolean;
|
|
97
|
+
}
|
|
98
|
+
export interface InjectResult {
|
|
99
|
+
ok: boolean;
|
|
100
|
+
backend: InjectBackend;
|
|
101
|
+
/** Discrete writes delivered: 2 for the Ink-safe text+Enter split, 1 when combined or enter=false. */
|
|
102
|
+
writes: number;
|
|
103
|
+
/** For the tmux / AppleScript backends (or any dryRun), the spec(s) that ran / would run. */
|
|
104
|
+
specs?: LaunchSpec[];
|
|
105
|
+
error?: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* argv for `tmux send-keys` targeting a pane by id. Starts with `tmux` (like the
|
|
109
|
+
* engine's `tmuxTabArgv`) so the same transport runs it locally or over SSH. The
|
|
110
|
+
* socket, when set, is positioned before the subcommand (`-S` must lead). `-l`
|
|
111
|
+
* sends the keys literally; without it tmux interprets a key name like `Enter`.
|
|
112
|
+
*
|
|
113
|
+
* NOTE: distinct from `sendKeys()` in src/lib/tmux/session.ts — that one
|
|
114
|
+
* addresses by session *name* on the default socket (the `agents tmux` surface)
|
|
115
|
+
* and shells out directly; this one addresses by *pane id* + arbitrary socket and
|
|
116
|
+
* returns an SSH-capable `LaunchSpec` for the engine transport. Don't collapse them.
|
|
117
|
+
*/
|
|
118
|
+
export declare function tmuxSendKeysArgv(pane: string, keys: string, opts?: {
|
|
119
|
+
literal?: boolean;
|
|
120
|
+
socket?: string;
|
|
121
|
+
}): string[];
|
|
122
|
+
/** The one-or-two send-keys specs for a tmux injection (Ink-safe split by default). */
|
|
123
|
+
export declare function tmuxInjectSpecs(target: Extract<InjectTarget, {
|
|
124
|
+
backend: 'tmux';
|
|
125
|
+
}>, text: string, o: {
|
|
126
|
+
enter: boolean;
|
|
127
|
+
combined: boolean;
|
|
128
|
+
socket?: string;
|
|
129
|
+
}): LaunchSpec[];
|
|
130
|
+
/**
|
|
131
|
+
* AppleScript that types into a SPECIFIC iTerm2 split via `tell session id
|
|
132
|
+
* "<uuid>" to write text` — the exact split provenance's iterm rail identifies,
|
|
133
|
+
* addressed by its session UUID. Crucially there is NO `activate`: `write text`
|
|
134
|
+
* delivers to that session directly, so injection never brings iTerm forward or
|
|
135
|
+
* types into whatever split happens to be focused. Omitting `session` targets
|
|
136
|
+
* the current session (a direct-call convenience; the resolver always supplies
|
|
137
|
+
* one).
|
|
138
|
+
*
|
|
139
|
+
* Enter semantics — iTerm's `write text` appends a trailing newline, which fuses
|
|
140
|
+
* text+Enter into ONE write and Claude's Ink TUI swallows it. So the Ink-safe
|
|
141
|
+
* default (enter, not combined) suppresses that newline (`write text … newline
|
|
142
|
+
* no`) and sends the Return as a SEPARATE `write text` of a lone CR (`character
|
|
143
|
+
* id 13`) — two distinct pty writes, Enter seen on its own. `combined` opts into
|
|
144
|
+
* the single fused `write text` (auto-newline) for plain shells / REPLs.
|
|
145
|
+
*
|
|
146
|
+
* NOTE (macOS-only verification pending): the two-write CR path is the safe
|
|
147
|
+
* choice because it mirrors the tmux/pty Ink-safe split that IS verified here on
|
|
148
|
+
* Linux; whether a single `write text T` would also submit under Ink can only be
|
|
149
|
+
* confirmed on a Mac running iTerm (see the PR body).
|
|
150
|
+
*/
|
|
151
|
+
export declare function itermInjectScript(text: string, opts: {
|
|
152
|
+
session?: string;
|
|
153
|
+
enter: boolean;
|
|
154
|
+
combined?: boolean;
|
|
155
|
+
}): string;
|
|
156
|
+
/**
|
|
157
|
+
* AppleScript for Ghostty (no scripting dictionary): raise the target window via
|
|
158
|
+
* System Events, then keystroke the text and a separate Return. `window` matches
|
|
159
|
+
* a window whose title contains the string; omitted → the frontmost Ghostty window.
|
|
160
|
+
*/
|
|
161
|
+
export declare function ghosttyInjectScript(text: string, opts: {
|
|
162
|
+
window?: string;
|
|
163
|
+
enter: boolean;
|
|
164
|
+
}): string;
|
|
165
|
+
/** The osascript spec for a macOS injection. One invocation delivers the text + Return. */
|
|
166
|
+
export declare function appleScriptInjectSpec(target: Extract<InjectTarget, {
|
|
167
|
+
backend: 'iterm' | 'ghostty';
|
|
168
|
+
}>, text: string, enter: boolean, combined?: boolean): LaunchSpec;
|
|
169
|
+
/**
|
|
170
|
+
* The `<scheme>://swarmify.swarm-ext/inject?p=<payload>` URL the extension
|
|
171
|
+
* handles to type into an ALREADY-open integrated terminal (the inject sibling
|
|
172
|
+
* of the launch backend's `/spawn`, src/lib/terminal/backends/vscodium-agent.ts).
|
|
173
|
+
*
|
|
174
|
+
* Payload is base64url-encoded JSON in a single `p` param — identical encoding
|
|
175
|
+
* to `spawnUri`, and for the same reason: VS Code percent-decodes `uri.query`
|
|
176
|
+
* once before the extension parses it, so a naive multi-param query would
|
|
177
|
+
* mis-split a text containing `&`/`=`; base64url (`[A-Za-z0-9_-]`) survives that
|
|
178
|
+
* decode untouched. `terminalId` is the id the extension keys live-terminals.json
|
|
179
|
+
* on (the session UUID); `enter` tells the extension to submit; `combined` asks
|
|
180
|
+
* it to fuse text+Enter into one write (default is the Ink-safe two-write split,
|
|
181
|
+
* mirroring the tmux/iterm paths — the extension owns that split on its side).
|
|
182
|
+
*
|
|
183
|
+
* DEPENDENCY: the `/inject` verb ships in the swarm-ext extension via PR #608's
|
|
184
|
+
* successor (PR #608 introduces `/spawn`; the inject verb + `write`/`enter`
|
|
185
|
+
* handling is its follow-up). Until that lands, this routes correctly on the CLI
|
|
186
|
+
* side but the extension will no-op the unknown verb. See the PR body.
|
|
187
|
+
*/
|
|
188
|
+
export declare function vscodiumInjectUri(scheme: string, terminalId: string, text: string, opts: {
|
|
189
|
+
enter: boolean;
|
|
190
|
+
combined: boolean;
|
|
191
|
+
}): string;
|
|
192
|
+
/** The editor-CLI spec for a VSCodium/Cursor/VS Code injection (one `--open-url` invocation). */
|
|
193
|
+
export declare function vscodiumInjectSpec(target: Extract<InjectTarget, {
|
|
194
|
+
backend: 'vscodium';
|
|
195
|
+
}>, text: string, opts: {
|
|
196
|
+
enter: boolean;
|
|
197
|
+
combined: boolean;
|
|
198
|
+
}): LaunchSpec;
|
|
199
|
+
/**
|
|
200
|
+
* Deliver `text` (+ Enter) into an existing terminal surface. Resolves the
|
|
201
|
+
* target's backend and routes to the matching primitive. Never throws — launch
|
|
202
|
+
* failures come back in the result, like the engine's `openSurface`.
|
|
203
|
+
*/
|
|
204
|
+
export declare function injectIntoTerminal(target: InjectTarget, text: string, opts?: InjectOptions): Promise<InjectResult>;
|