tmuxes 0.1.9 → 0.1.10
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/agentHooks.js +91 -0
- package/dist/agentHooks.js.map +1 -0
- package/dist/agentOutput.js +30 -0
- package/dist/agentOutput.js.map +1 -0
- package/dist/agentState.js +45 -0
- package/dist/agentState.js.map +1 -0
- package/dist/config.js +32 -0
- package/dist/config.js.map +1 -0
- package/dist/exe.js +37 -0
- package/dist/exe.js.map +1 -0
- package/dist/exec.js +43 -0
- package/dist/exec.js.map +1 -0
- package/dist/files.js +308 -0
- package/dist/files.js.map +1 -0
- package/dist/foldersStore.js +103 -0
- package/dist/foldersStore.js.map +1 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.js +16 -0
- package/dist/logger.js.map +1 -0
- package/{server/src/monitor.ts → dist/monitor.js} +9 -10
- package/dist/monitor.js.map +1 -0
- package/dist/openBrowser.js +31 -0
- package/dist/openBrowser.js.map +1 -0
- package/{server/src/platform.ts → dist/platform.js} +5 -4
- package/dist/platform.js.map +1 -0
- package/dist/rest/router.js +198 -0
- package/dist/rest/router.js.map +1 -0
- package/dist/targetCommand.js +60 -0
- package/dist/targetCommand.js.map +1 -0
- package/dist/targets.js +131 -0
- package/dist/targets.js.map +1 -0
- package/dist/tmux/builder.js +174 -0
- package/dist/tmux/builder.js.map +1 -0
- package/dist/tmux/formats.js +61 -0
- package/dist/tmux/formats.js.map +1 -0
- package/dist/tmux/sessions.js +157 -0
- package/dist/tmux/sessions.js.map +1 -0
- package/dist/validate.js +65 -0
- package/dist/validate.js.map +1 -0
- package/dist/windowsSsh.js +209 -0
- package/dist/windowsSsh.js.map +1 -0
- package/dist/winshell/manager.js +267 -0
- package/dist/winshell/manager.js.map +1 -0
- package/dist/ws/protocol.js +4 -0
- package/dist/ws/protocol.js.map +1 -0
- package/dist/ws/sshState.js +35 -0
- package/dist/ws/sshState.js.map +1 -0
- package/dist/ws/terminalSession.js +204 -0
- package/dist/ws/terminalSession.js.map +1 -0
- package/dist/ws/wsServer.js +151 -0
- package/dist/ws/wsServer.js.map +1 -0
- package/dist/wsl.js +35 -0
- package/dist/wsl.js.map +1 -0
- package/package.json +49 -16
- package/public/assets/index-D_X5SnGx.css +1 -0
- package/public/assets/index-Dl69CPyt.js +44 -0
- package/{client → public}/index.html +3 -2
- package/.node-version +0 -1
- package/.nvmrc +0 -1
- package/.tmp-npm-cache/_cacache/content-v2/sha512/43/27/5e000b8b9c56a6ccc66f709485499f4304e2cb1982582ba571321c07b3ef56fcabd2c671898cc8003365a0485b6fd8e73e7b17b073cec0f7d1628c1a99df +0 -0
- package/.tmp-npm-cache/_cacache/content-v2/sha512/51/cf/4301295d74559ed494bae160d54d8741077f89faebb311882ac065019246951e7b53f3dcb913793c42b331e14c7070c4810c3cdc27a427d103a7db4614e0 +0 -0
- package/.tmp-npm-cache/_cacache/content-v2/sha512/c3/4d/d68a454a916e74c2617f586fbf770981b33811d667c2547eb0e9fc21938f4ee7e98f1ceee4bde8ad8815b5f6efe21b60eee798837d68f51a3340d7e5bb7a +0 -0
- package/.tmp-npm-cache/_cacache/content-v2/sha512/fe/40/2abfbefc96299e8bf714aa91d62607190ae299e102cf5933db2e2904640d65d25d67dbbb6fa2ddc92a17f00b9dbfdf2e37487f67d96ec36c64a285b59a7d +0 -0
- package/.tmp-npm-cache/_cacache/index-v5/27/fe/81a3de6ce7ae3d1e41a3421de20c5629998c4ee5d0ffe2037630f03b03b2 +0 -4
- package/.tmp-npm-cache/_cacache/index-v5/65/22/dd66711f62681fce09aabb2357a2907b4a0c778ac5227c4baf9603fd86e8 +0 -4
- package/.tmp-npm-cache/_update-notifier-last-checked +0 -0
- package/AGENTS.md +0 -15
- package/CLAUDE.md +0 -3
- package/README.en.md +0 -304
- package/SECURITY.md +0 -31
- package/client/package.json +0 -29
- package/client/src/App.tsx +0 -123
- package/client/src/activity.ts +0 -5
- package/client/src/api.ts +0 -130
- package/client/src/attention.tsx +0 -157
- package/client/src/components/FileExplorer.tsx +0 -156
- package/client/src/components/FileViewer.tsx +0 -194
- package/client/src/components/SessionRow.tsx +0 -108
- package/client/src/components/SessionTree.tsx +0 -197
- package/client/src/components/SettingsButton.tsx +0 -122
- package/client/src/components/Sidebar.tsx +0 -96
- package/client/src/components/StatusBanner.tsx +0 -31
- package/client/src/components/TargetGroup.tsx +0 -275
- package/client/src/components/TerminalPanel.tsx +0 -192
- package/client/src/folders.ts +0 -245
- package/client/src/hooks/useTerminal.ts +0 -67
- package/client/src/hooks/useTmuxSocket.ts +0 -65
- package/client/src/i18n.ts +0 -213
- package/client/src/main.tsx +0 -17
- package/client/src/settings.tsx +0 -87
- package/client/src/styles.css +0 -723
- package/client/src/types.ts +0 -93
- package/client/src/util.ts +0 -65
- package/client/tsconfig.json +0 -13
- package/client/vite.config.ts +0 -15
- package/fig/fig1.png +0 -0
- package/scripts/prepack.mjs +0 -35
- package/server/package.json +0 -61
- package/server/src/agentHooks.ts +0 -120
- package/server/src/agentOutput.ts +0 -36
- package/server/src/agentState.ts +0 -70
- package/server/src/config.ts +0 -31
- package/server/src/exe.ts +0 -34
- package/server/src/exec.ts +0 -61
- package/server/src/files.ts +0 -330
- package/server/src/foldersStore.ts +0 -114
- package/server/src/index.ts +0 -114
- package/server/src/logger.ts +0 -16
- package/server/src/openBrowser.ts +0 -28
- package/server/src/rest/router.ts +0 -290
- package/server/src/targetCommand.ts +0 -79
- package/server/src/targets.ts +0 -152
- package/server/src/tmux/builder.ts +0 -198
- package/server/src/tmux/formats.ts +0 -95
- package/server/src/tmux/sessions.ts +0 -204
- package/server/src/validate.ts +0 -79
- package/server/src/windowsSsh.ts +0 -239
- package/server/src/winshell/manager.ts +0 -296
- package/server/src/ws/protocol.ts +0 -15
- package/server/src/ws/sshState.ts +0 -36
- package/server/src/ws/terminalSession.ts +0 -207
- package/server/src/ws/wsServer.ts +0 -153
- package/server/src/wsl.ts +0 -38
- package/server/test/agentHooks.test.ts +0 -66
- package/server/test/agentOutput.test.ts +0 -26
- package/server/test/agentState.test.ts +0 -24
- package/server/test/builder.test.ts +0 -162
- package/server/test/files.test.ts +0 -81
- package/server/test/formats.test.ts +0 -123
- package/server/test/monitor.test.ts +0 -25
- package/server/test/validate.test.ts +0 -71
- package/server/test/wsl.test.ts +0 -18
- package/server/tsconfig.json +0 -9
- package/server/vitest.config.ts +0 -12
- package/start.cmd +0 -30
- package/start.command +0 -20
- package/start.sh +0 -20
- package/tsconfig.base.json +0 -19
- /package/{server/bin → bin}/tmuxes.js +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { agentHookCommand, } from './agentState.js';
|
|
2
|
+
function isDisabled() {
|
|
3
|
+
const v = process.env.TMUXES_NO_AUTOHOOK;
|
|
4
|
+
return v === '1' || v === 'true';
|
|
5
|
+
}
|
|
6
|
+
function baseName(token) {
|
|
7
|
+
return (token.split(/[\\/]/).pop() || '').toLowerCase().replace(/\.(exe|cmd|bat)$/, '');
|
|
8
|
+
}
|
|
9
|
+
export function detectAgentKind(command) {
|
|
10
|
+
if (isDisabled())
|
|
11
|
+
return undefined;
|
|
12
|
+
const trimmed = command.trim();
|
|
13
|
+
if (!trimmed)
|
|
14
|
+
return undefined;
|
|
15
|
+
const m = /^(\S+)(\s+[\s\S]*)?$/.exec(trimmed);
|
|
16
|
+
if (!m)
|
|
17
|
+
return undefined;
|
|
18
|
+
switch (baseName(m[1])) {
|
|
19
|
+
case 'claude':
|
|
20
|
+
return 'claude';
|
|
21
|
+
case 'codex':
|
|
22
|
+
return 'codex';
|
|
23
|
+
default:
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function hook(kind, state, reason, event) {
|
|
28
|
+
return { type: 'command', command: agentHookCommand(kind, state, reason, event) };
|
|
29
|
+
}
|
|
30
|
+
function claudeSettings() {
|
|
31
|
+
return JSON.stringify({
|
|
32
|
+
hooks: {
|
|
33
|
+
UserPromptSubmit: [{ hooks: [hook('claude', 'running', '', 'UserPromptSubmit')] }],
|
|
34
|
+
PreToolUse: [{ matcher: '', hooks: [hook('claude', 'running', '', 'PreToolUse')] }],
|
|
35
|
+
PostToolUse: [{ matcher: '', hooks: [hook('claude', 'running', '', 'PostToolUse')] }],
|
|
36
|
+
PermissionRequest: [
|
|
37
|
+
{ matcher: '', hooks: [hook('claude', 'waiting', 'decision', 'PermissionRequest')] },
|
|
38
|
+
],
|
|
39
|
+
Notification: [
|
|
40
|
+
{
|
|
41
|
+
matcher: 'permission_prompt',
|
|
42
|
+
hooks: [hook('claude', 'waiting', 'decision', 'Notification.permission_prompt')],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
matcher: 'elicitation_dialog',
|
|
46
|
+
hooks: [hook('claude', 'waiting', 'decision', 'Notification.elicitation_dialog')],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
Stop: [{ hooks: [hook('claude', 'idle', 'done', 'Stop')] }],
|
|
50
|
+
StopFailure: [{ hooks: [hook('claude', 'idle', 'error', 'StopFailure')] }],
|
|
51
|
+
SessionEnd: [{ hooks: [hook('claude', 'idle', 'done', 'SessionEnd')] }],
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function tomlString(v) {
|
|
56
|
+
return `"${v.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
57
|
+
}
|
|
58
|
+
function codexHookConfig(event, cmd, opts = {}) {
|
|
59
|
+
const matcher = opts.matcher === undefined ? '' : `matcher=${tomlString(opts.matcher)},`;
|
|
60
|
+
return `hooks.${event}=[{${matcher}hooks=[{type="command",command=${tomlString(cmd)}}]}]`;
|
|
61
|
+
}
|
|
62
|
+
function codexConfigArgs() {
|
|
63
|
+
const configs = [
|
|
64
|
+
codexHookConfig('UserPromptSubmit', agentHookCommand('codex', 'running', '', 'UserPromptSubmit')),
|
|
65
|
+
codexHookConfig('PreToolUse', agentHookCommand('codex', 'running', '', 'PreToolUse'), {
|
|
66
|
+
matcher: '',
|
|
67
|
+
}),
|
|
68
|
+
codexHookConfig('PostToolUse', agentHookCommand('codex', 'running', '', 'PostToolUse'), {
|
|
69
|
+
matcher: '',
|
|
70
|
+
}),
|
|
71
|
+
codexHookConfig('PermissionRequest', agentHookCommand('codex', 'waiting', 'decision', 'PermissionRequest'), { matcher: '' }),
|
|
72
|
+
codexHookConfig('Stop', agentHookCommand('codex', 'idle', 'done', 'Stop')),
|
|
73
|
+
];
|
|
74
|
+
return configs.map((c) => `-c '${c}'`).join(' ');
|
|
75
|
+
}
|
|
76
|
+
export function augmentAgentCommand(command) {
|
|
77
|
+
const kind = detectAgentKind(command);
|
|
78
|
+
if (!kind)
|
|
79
|
+
return { command };
|
|
80
|
+
const trimmed = command.trim();
|
|
81
|
+
const m = /^(\S+)(\s+[\s\S]*)?$/.exec(trimmed);
|
|
82
|
+
if (!m)
|
|
83
|
+
return { command };
|
|
84
|
+
const prog = m[1];
|
|
85
|
+
const rest = m[2] ?? '';
|
|
86
|
+
if (kind === 'claude') {
|
|
87
|
+
return { kind, command: `${prog} --settings '${claudeSettings()}'${rest}` };
|
|
88
|
+
}
|
|
89
|
+
return { kind, command: `${prog} ${codexConfigArgs()}${rest}` };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=agentHooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentHooks.js","sourceRoot":"","sources":["../src/agentHooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const ERROR_PATTERNS = [
|
|
2
|
+
{
|
|
3
|
+
event: 'CodexStreamDisconnected',
|
|
4
|
+
kinds: ['codex'],
|
|
5
|
+
re: /stream disconnected before completion.*error sending request for url.*\/codex\/responses/i,
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
event: 'StreamDisconnected',
|
|
9
|
+
re: /stream disconnected before completion/i,
|
|
10
|
+
},
|
|
11
|
+
];
|
|
12
|
+
function normalizeTerminalText(text) {
|
|
13
|
+
return text
|
|
14
|
+
.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '')
|
|
15
|
+
.replace(/\s+/g, ' ')
|
|
16
|
+
.trim();
|
|
17
|
+
}
|
|
18
|
+
export function classifyAgentTerminalError(text, kind) {
|
|
19
|
+
const normalized = normalizeTerminalText(text);
|
|
20
|
+
if (!normalized)
|
|
21
|
+
return undefined;
|
|
22
|
+
for (const pattern of ERROR_PATTERNS) {
|
|
23
|
+
if (pattern.kinds && !pattern.kinds.includes(kind))
|
|
24
|
+
continue;
|
|
25
|
+
if (pattern.re.test(normalized))
|
|
26
|
+
return pattern.event;
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=agentOutput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentOutput.js","sourceRoot":"","sources":["../src/agentOutput.ts"],"names":[],"mappings":"AAQA,MAAM,cAAc,GAA2B;IAC7C;QACE,KAAK,EAAE,yBAAyB;QAChC,KAAK,EAAE,CAAC,OAAO,CAAC;QAChB,EAAE,EAAE,2FAA2F;KAChG;IACD;QACE,KAAK,EAAE,oBAAoB;QAC3B,EAAE,EAAE,wCAAwC;KAC7C;CACF,CAAC;AAEF,SAAS,qBAAqB,CAAC,IAAY;IACzC,OAAO,IAAI;SACR,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;SACzC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,IAAY,EAAE,IAAe;IACtE,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAClC,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7D,IAAI,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE,OAAO,OAAO,CAAC,KAAK,CAAC;IACxD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const AGENT_OPTION = '@tmuxes_agent';
|
|
2
|
+
function isAgentKind(v) {
|
|
3
|
+
return v === 'claude' || v === 'codex';
|
|
4
|
+
}
|
|
5
|
+
function isAgentState(v) {
|
|
6
|
+
return v === 'running' || v === 'waiting' || v === 'idle';
|
|
7
|
+
}
|
|
8
|
+
function isAttentionReason(v) {
|
|
9
|
+
return v === 'decision' || v === 'done' || v === 'error';
|
|
10
|
+
}
|
|
11
|
+
function cleanToken(v) {
|
|
12
|
+
return v.replace(/[^A-Za-z0-9_.-]/g, '_');
|
|
13
|
+
}
|
|
14
|
+
export function agentValue(kind, state, reason, event, nonce) {
|
|
15
|
+
return [
|
|
16
|
+
kind,
|
|
17
|
+
state,
|
|
18
|
+
reason,
|
|
19
|
+
cleanToken(event),
|
|
20
|
+
nonce.replace(/:/g, '_'),
|
|
21
|
+
].join(':');
|
|
22
|
+
}
|
|
23
|
+
export function agentInitialValue(kind) {
|
|
24
|
+
return agentValue(kind, 'idle', '', 'launch', String(Date.now()));
|
|
25
|
+
}
|
|
26
|
+
export function agentHookCommand(kind, state, reason, event) {
|
|
27
|
+
return `tmux set-option -q ${AGENT_OPTION} ${agentValue(kind, state, reason, event, '$(date +%s).$$')}`;
|
|
28
|
+
}
|
|
29
|
+
export function parseAgentValue(raw) {
|
|
30
|
+
if (!raw)
|
|
31
|
+
return undefined;
|
|
32
|
+
const [kind, state, reason, event, ...nonceParts] = raw.split(':');
|
|
33
|
+
if (!isAgentKind(kind) || !isAgentState(state))
|
|
34
|
+
return undefined;
|
|
35
|
+
const snap = { agentKind: kind, agentState: state };
|
|
36
|
+
if (isAttentionReason(reason))
|
|
37
|
+
snap.attentionReason = reason;
|
|
38
|
+
if (event)
|
|
39
|
+
snap.agentEvent = event;
|
|
40
|
+
const nonce = nonceParts.join(':');
|
|
41
|
+
if (nonce)
|
|
42
|
+
snap.agentNonce = nonce;
|
|
43
|
+
return snap;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=agentState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentState.js","sourceRoot":"","sources":["../src/agentState.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,YAAY,GAAG,eAAe,CAAC;AAE5C,SAAS,WAAW,CAAC,CAAS;IAC5B,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,OAAO,CAAC;AACzC,CAAC;AAED,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,MAAM,CAAC;AAC5D,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAS;IAClC,OAAO,CAAC,KAAK,UAAU,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,OAAO,CAAC;AAC3D,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,IAAe,EACf,KAAiB,EACjB,MAA4B,EAC5B,KAAa,EACb,KAAa;IAEb,OAAO;QACL,IAAI;QACJ,KAAK;QACL,MAAM;QACN,UAAU,CAAC,KAAK,CAAC;QACjB,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;KACzB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAe;IAC/C,OAAO,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAe,EACf,KAAiB,EACjB,MAA4B,EAC5B,KAAa;IAEb,OAAO,sBAAsB,YAAY,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC;AAC1G,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAuB;IACrD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACjE,MAAM,IAAI,GAAkB,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACnE,IAAI,iBAAiB,CAAC,MAAM,CAAC;QAAE,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC;IAC7D,IAAI,KAAK;QAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IACnC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,KAAK;QAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IACnC,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Central configuration. Localhost-only by design — see README/SECURITY. */
|
|
2
|
+
export const config = {
|
|
3
|
+
/** Bind address. Intentionally not configurable: this is a no-auth local shell UI. */
|
|
4
|
+
host: '127.0.0.1',
|
|
5
|
+
port: Number(process.env.TMUXES_PORT ?? 7420),
|
|
6
|
+
/** ssh timeouts (seconds). */
|
|
7
|
+
ssh: {
|
|
8
|
+
/** Management calls fail fast so the UI never hangs. */
|
|
9
|
+
connectTimeoutMgmt: 8,
|
|
10
|
+
/** Interactive attach is allowed a little longer. */
|
|
11
|
+
connectTimeoutTty: 10,
|
|
12
|
+
/** Keep the OpenSSH control master alive for long-lived SSH reuse. */
|
|
13
|
+
controlPersist: 'yes',
|
|
14
|
+
},
|
|
15
|
+
/**
|
|
16
|
+
* Allowed WebSocket Origins. The WS upgrade bypasses Express middleware, so
|
|
17
|
+
* we enforce this in the upgrade handler to block DNS-rebind / cross-site WS
|
|
18
|
+
* hijack. Empty/absent Origin (non-browser clients) is allowed.
|
|
19
|
+
*/
|
|
20
|
+
isAllowedOrigin(origin) {
|
|
21
|
+
if (!origin)
|
|
22
|
+
return true;
|
|
23
|
+
try {
|
|
24
|
+
const { hostname } = new URL(origin);
|
|
25
|
+
return hostname === '127.0.0.1' || hostname === 'localhost' || hostname === '[::1]';
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,sFAAsF;IACtF,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC;IAE7C,8BAA8B;IAC9B,GAAG,EAAE;QACH,wDAAwD;QACxD,kBAAkB,EAAE,CAAC;QACrB,qDAAqD;QACrD,iBAAiB,EAAE,EAAE;QACrB,sEAAsE;QACtE,cAAc,EAAE,KAAK;KACtB;IAED;;;;OAIG;IACH,eAAe,CAAC,MAA0B;QACxC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;YACrC,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ,KAAK,OAAO,CAAC;QACtF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACO,CAAC"}
|
package/dist/exe.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { isAbsolute, join, delimiter } from 'node:path';
|
|
3
|
+
import { isWindows } from './platform.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a command name to a full path for node-pty on Windows.
|
|
6
|
+
*
|
|
7
|
+
* Unlike child_process.spawn, node-pty's ConPTY path does NOT search PATH or
|
|
8
|
+
* append a PATHEXT extension, so `pty.spawn('ssh', …)` fails with
|
|
9
|
+
* "File not found". We resolve the executable ourselves (PATH + common system
|
|
10
|
+
* locations). On POSIX, execvp already searches PATH, so the name is returned
|
|
11
|
+
* unchanged.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveExecutable(file) {
|
|
14
|
+
if (!isWindows)
|
|
15
|
+
return file;
|
|
16
|
+
if (isAbsolute(file) && existsSync(file))
|
|
17
|
+
return file;
|
|
18
|
+
const hasExt = /\.[A-Za-z0-9]+$/.test(file);
|
|
19
|
+
const exts = hasExt ? [''] : (process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM').split(';');
|
|
20
|
+
const sysRoot = process.env.SystemRoot || process.env.windir || 'C:\\Windows';
|
|
21
|
+
const dirs = [
|
|
22
|
+
...(process.env.PATH || '').split(delimiter),
|
|
23
|
+
join(sysRoot, 'System32'),
|
|
24
|
+
join(sysRoot, 'System32', 'OpenSSH'), // ssh.exe ships here, not always on PATH
|
|
25
|
+
];
|
|
26
|
+
for (const dir of dirs) {
|
|
27
|
+
if (!dir)
|
|
28
|
+
continue;
|
|
29
|
+
for (const ext of exts) {
|
|
30
|
+
const candidate = join(dir, file + ext);
|
|
31
|
+
if (existsSync(candidate))
|
|
32
|
+
return candidate;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return file; // fall back; node-pty surfaces a clear error if truly missing
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=exe.js.map
|
package/dist/exe.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exe.js","sourceRoot":"","sources":["../src/exe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtD,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,qBAAqB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC;IAC9E,MAAM,IAAI,GAAG;QACX,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC;QACzB,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,yCAAyC;KAChF,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,GAAG,CAAC,CAAC;YACxC,IAAI,UAAU,CAAC,SAAS,CAAC;gBAAE,OAAO,SAAS,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,8DAA8D;AAC7E,CAAC"}
|
package/dist/exec.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Run a command as an argv array with NO shell. Never rejects — a nonzero exit
|
|
4
|
+
* or spawn error resolves with the captured output so callers can interpret it
|
|
5
|
+
* (e.g. tmux "no server running" is a normal empty case, not a throw).
|
|
6
|
+
*/
|
|
7
|
+
export function runCommand(file, args, opts = {}) {
|
|
8
|
+
const encoding = opts.encoding ?? 'utf8';
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
const child = spawn(file, args, { shell: false });
|
|
11
|
+
const outChunks = [];
|
|
12
|
+
const errChunks = [];
|
|
13
|
+
let settled = false;
|
|
14
|
+
const timer = opts.timeoutMs
|
|
15
|
+
? setTimeout(() => {
|
|
16
|
+
child.kill('SIGKILL');
|
|
17
|
+
}, opts.timeoutMs)
|
|
18
|
+
: null;
|
|
19
|
+
child.stdout.on('data', (d) => outChunks.push(d));
|
|
20
|
+
child.stderr.on('data', (d) => errChunks.push(d));
|
|
21
|
+
if (opts.input !== undefined) {
|
|
22
|
+
child.stdin.on('error', () => {
|
|
23
|
+
/* ignore EPIPE if the child exits early */
|
|
24
|
+
});
|
|
25
|
+
child.stdin.end(opts.input);
|
|
26
|
+
}
|
|
27
|
+
const done = (code, signal, extraErr) => {
|
|
28
|
+
if (settled)
|
|
29
|
+
return;
|
|
30
|
+
settled = true;
|
|
31
|
+
if (timer)
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
const stderr = Buffer.concat(errChunks).toString(encoding) + (extraErr ?? '');
|
|
34
|
+
resolve({ code, signal, stdout: Buffer.concat(outChunks).toString(encoding), stderr });
|
|
35
|
+
};
|
|
36
|
+
child.on('error', (err) => {
|
|
37
|
+
// e.g. ENOENT when ssh/tmux/wsl.exe is missing — surface as a failed result.
|
|
38
|
+
done(null, null, err.message);
|
|
39
|
+
});
|
|
40
|
+
child.on('close', (code, signal) => done(code, signal));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=exec.js.map
|
package/dist/exec.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAiB3C;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,IAAc,EAAE,OAAmB,EAAE;IAC5E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC;IACzC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS;YAC1B,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE;gBACd,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YACpB,CAAC,CAAC,IAAI,CAAC;QAET,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1D,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC7B,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC3B,2CAA2C;YAC7C,CAAC,CAAC,CAAC;YACH,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,IAAmB,EAAE,MAA6B,EAAE,QAAiB,EAAE,EAAE;YACrF,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;YAC9E,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACzF,CAAC,CAAC;QAEF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,6EAA6E;YAC7E,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/files.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { promises as fsp } from 'node:fs';
|
|
2
|
+
import { basename as posixBasename, dirname as posixDirname } from 'node:path/posix';
|
|
3
|
+
import { commandArgv } from './tmux/builder.js';
|
|
4
|
+
import { TmuxError } from './tmux/sessions.js';
|
|
5
|
+
import { runTargetCommand } from './targetCommand.js';
|
|
6
|
+
const REMOTE_TIMEOUT_MS = 15_000;
|
|
7
|
+
/** Max bytes returned for a file preview. */
|
|
8
|
+
export const FILE_PREVIEW_CAP = 2_000_000;
|
|
9
|
+
/** A NUL anywhere in a preview means the file is binary. */
|
|
10
|
+
const NUL = String.fromCharCode(0);
|
|
11
|
+
const SESSION_DIRECTORY_SCRIPT = [
|
|
12
|
+
'session=$1',
|
|
13
|
+
'requested=$2',
|
|
14
|
+
'cwd=$(tmux display-message -p -t "$session" \'#{pane_current_path}\') || exit $?',
|
|
15
|
+
'if [ -z "$cwd" ]; then echo "empty session cwd" >&2; exit 70; fi',
|
|
16
|
+
'root=$(realpath -- "$cwd") || exit $?',
|
|
17
|
+
'if [ -z "$requested" ]; then requested=$cwd; fi',
|
|
18
|
+
'case "$requested" in /*) ;; *) echo "path must be absolute" >&2; exit 64;; esac',
|
|
19
|
+
'candidate=$(realpath -- "$requested") || exit $?',
|
|
20
|
+
'if [ "$root" = "/" ]; then inside=1; else case "$candidate" in "$root"|"$root"/*) inside=1 ;; *) inside=0 ;; esac; fi',
|
|
21
|
+
'if [ "$inside" != 1 ]; then echo "path is outside the session working directory" >&2; exit 77; fi',
|
|
22
|
+
'if [ ! -d "$candidate" ]; then echo "not a directory" >&2; exit 66; fi',
|
|
23
|
+
'printf "%s\\0%s\\0" "$cwd" "$candidate"',
|
|
24
|
+
'ls -Ap1 -- "$candidate"',
|
|
25
|
+
].join('\n');
|
|
26
|
+
function timeout(t) {
|
|
27
|
+
return t.kind === 'local' ? undefined : REMOTE_TIMEOUT_MS;
|
|
28
|
+
}
|
|
29
|
+
function normalizeRoot(path) {
|
|
30
|
+
if (path === '/')
|
|
31
|
+
return path;
|
|
32
|
+
return path.replace(/\/+$/, '');
|
|
33
|
+
}
|
|
34
|
+
export function isInsideRoot(root, candidate) {
|
|
35
|
+
const normalizedRoot = normalizeRoot(root);
|
|
36
|
+
return normalizedRoot === '/' || candidate === normalizedRoot || candidate.startsWith(`${normalizedRoot}/`);
|
|
37
|
+
}
|
|
38
|
+
async function remoteRealpath(t, path) {
|
|
39
|
+
const r = await run(t, ['realpath', path]);
|
|
40
|
+
if (r.code !== 0) {
|
|
41
|
+
if (/No such file|not found/i.test(r.stderr))
|
|
42
|
+
throw new TmuxError(404, 'path not found');
|
|
43
|
+
if (/Permission denied/i.test(r.stderr))
|
|
44
|
+
throw new TmuxError(403, 'permission denied');
|
|
45
|
+
throw new TmuxError(502, r.stderr.trim().split('\n')[0] || 'cannot resolve path');
|
|
46
|
+
}
|
|
47
|
+
const resolved = r.stdout.trim().split('\n')[0];
|
|
48
|
+
if (!resolved)
|
|
49
|
+
throw new TmuxError(502, 'empty resolved path');
|
|
50
|
+
return resolved;
|
|
51
|
+
}
|
|
52
|
+
async function realpath(t, path) {
|
|
53
|
+
if (t.kind === 'local') {
|
|
54
|
+
try {
|
|
55
|
+
return await fsp.realpath(path);
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
throw fsError(e, path);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return remoteRealpath(t, path);
|
|
62
|
+
}
|
|
63
|
+
async function tryRealpath(t, path) {
|
|
64
|
+
try {
|
|
65
|
+
return await realpath(t, path);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
if (e instanceof TmuxError && e.status === 404)
|
|
69
|
+
return null;
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Resolve a requested target path and verify it stays inside the session's cwd.
|
|
75
|
+
* This keeps the file browser/editor scoped to the agent workspace instead of
|
|
76
|
+
* exposing arbitrary host files through the no-auth local server.
|
|
77
|
+
*/
|
|
78
|
+
export async function resolveScopedPath(t, rootPath, requestedPath, opts = {}) {
|
|
79
|
+
if (!requestedPath.startsWith('/'))
|
|
80
|
+
throw new TmuxError(400, 'path must be absolute');
|
|
81
|
+
const root = await realpath(t, rootPath);
|
|
82
|
+
let candidate = null;
|
|
83
|
+
if (opts.forWrite) {
|
|
84
|
+
candidate = await tryRealpath(t, requestedPath);
|
|
85
|
+
if (!candidate) {
|
|
86
|
+
const name = posixBasename(requestedPath);
|
|
87
|
+
if (!name || name === '.' || name === '..')
|
|
88
|
+
throw new TmuxError(400, 'invalid path');
|
|
89
|
+
const parent = await realpath(t, posixDirname(requestedPath));
|
|
90
|
+
candidate = parent === '/' ? `/${name}` : `${parent}/${name}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
candidate = await realpath(t, requestedPath);
|
|
95
|
+
}
|
|
96
|
+
if (!isInsideRoot(root, candidate)) {
|
|
97
|
+
throw new TmuxError(403, 'path is outside the session working directory');
|
|
98
|
+
}
|
|
99
|
+
return candidate;
|
|
100
|
+
}
|
|
101
|
+
async function run(t, argv) {
|
|
102
|
+
return runTargetCommand(t, (opts) => commandArgv(t, argv, opts), { timeoutMs: timeout(t) });
|
|
103
|
+
}
|
|
104
|
+
/** The working directory of a session's active pane (tmux #{pane_current_path}). */
|
|
105
|
+
export async function getSessionCwd(t, session) {
|
|
106
|
+
const r = await run(t, ['tmux', 'display-message', '-p', '-t', session, '#{pane_current_path}']);
|
|
107
|
+
if (r.code !== 0) {
|
|
108
|
+
if (/can't find|no server running|session not found/i.test(r.stderr)) {
|
|
109
|
+
throw new TmuxError(404, `session "${session}" not found`);
|
|
110
|
+
}
|
|
111
|
+
throw new TmuxError(502, r.stderr.trim().split('\n')[0] || 'cannot read session cwd');
|
|
112
|
+
}
|
|
113
|
+
const cwd = r.stdout.trim();
|
|
114
|
+
if (!cwd)
|
|
115
|
+
throw new TmuxError(502, 'empty session cwd');
|
|
116
|
+
return cwd;
|
|
117
|
+
}
|
|
118
|
+
function sortEntries(entries) {
|
|
119
|
+
return entries.sort((a, b) => {
|
|
120
|
+
if (a.type !== b.type)
|
|
121
|
+
return a.type === 'dir' ? -1 : 1;
|
|
122
|
+
return a.name.localeCompare(b.name, undefined, { numeric: true, sensitivity: 'base' });
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function parseRemoteEntries(stdout) {
|
|
126
|
+
return stdout
|
|
127
|
+
.split('\n')
|
|
128
|
+
.filter((l) => l.length > 0)
|
|
129
|
+
.map((line) => {
|
|
130
|
+
const isDir = line.endsWith('/');
|
|
131
|
+
const name = isDir ? line.slice(0, -1) : line;
|
|
132
|
+
return { name, type: isDir ? 'dir' : 'file' };
|
|
133
|
+
})
|
|
134
|
+
.filter((e) => e.name && e.name !== '.' && e.name !== '..');
|
|
135
|
+
}
|
|
136
|
+
function sessionDirectoryError(session, stderr) {
|
|
137
|
+
const first = stderr.trim().split('\n')[0] || 'cannot list directory';
|
|
138
|
+
if (/can't find|no server running|session not found/i.test(stderr)) {
|
|
139
|
+
return new TmuxError(404, `session "${session}" not found`);
|
|
140
|
+
}
|
|
141
|
+
if (/path must be absolute/i.test(stderr))
|
|
142
|
+
return new TmuxError(400, 'path must be absolute');
|
|
143
|
+
if (/not a directory/i.test(stderr))
|
|
144
|
+
return new TmuxError(400, 'not a directory');
|
|
145
|
+
if (/Permission denied/i.test(stderr))
|
|
146
|
+
return new TmuxError(403, 'permission denied');
|
|
147
|
+
if (/outside the session working directory/i.test(stderr)) {
|
|
148
|
+
return new TmuxError(403, 'path is outside the session working directory');
|
|
149
|
+
}
|
|
150
|
+
if (/No such file|not found|realpath:/i.test(stderr))
|
|
151
|
+
return new TmuxError(404, 'path not found');
|
|
152
|
+
return new TmuxError(502, first);
|
|
153
|
+
}
|
|
154
|
+
async function remoteSessionDirectory(t, session, requestedPath) {
|
|
155
|
+
if (requestedPath !== undefined && !requestedPath.startsWith('/')) {
|
|
156
|
+
throw new TmuxError(400, 'path must be absolute');
|
|
157
|
+
}
|
|
158
|
+
const r = await run(t, [
|
|
159
|
+
'sh',
|
|
160
|
+
'-c',
|
|
161
|
+
SESSION_DIRECTORY_SCRIPT,
|
|
162
|
+
'tmuxes-session-directory',
|
|
163
|
+
session,
|
|
164
|
+
requestedPath ?? '',
|
|
165
|
+
]);
|
|
166
|
+
if (r.code !== 0)
|
|
167
|
+
throw sessionDirectoryError(session, r.stderr);
|
|
168
|
+
const firstSep = r.stdout.indexOf(NUL);
|
|
169
|
+
const secondSep = firstSep < 0 ? -1 : r.stdout.indexOf(NUL, firstSep + 1);
|
|
170
|
+
if (firstSep < 0 || secondSep < 0)
|
|
171
|
+
throw new TmuxError(502, 'cannot parse directory listing');
|
|
172
|
+
const cwd = r.stdout.slice(0, firstSep);
|
|
173
|
+
const path = r.stdout.slice(firstSep + 1, secondSep);
|
|
174
|
+
const entries = parseRemoteEntries(r.stdout.slice(secondSep + 1));
|
|
175
|
+
return { cwd, path, entries: sortEntries(entries) };
|
|
176
|
+
}
|
|
177
|
+
export async function listSessionDirectory(t, session, requestedPath) {
|
|
178
|
+
if (t.kind !== 'local')
|
|
179
|
+
return remoteSessionDirectory(t, session, requestedPath);
|
|
180
|
+
const cwd = await getSessionCwd(t, session);
|
|
181
|
+
const path = await resolveScopedPath(t, cwd, requestedPath ?? cwd);
|
|
182
|
+
return { cwd, path, entries: await listDirectory(t, path) };
|
|
183
|
+
}
|
|
184
|
+
/** List a directory ON THE TARGET. Local uses fs; wsl/ssh shell out to `ls`. */
|
|
185
|
+
export async function listDirectory(t, path) {
|
|
186
|
+
if (t.kind === 'local') {
|
|
187
|
+
let dirents;
|
|
188
|
+
try {
|
|
189
|
+
dirents = await fsp.readdir(path, { withFileTypes: true });
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
throw fsError(e, path);
|
|
193
|
+
}
|
|
194
|
+
const entries = [];
|
|
195
|
+
for (const d of dirents) {
|
|
196
|
+
if (d.name.startsWith('.') && (d.name === '.' || d.name === '..'))
|
|
197
|
+
continue;
|
|
198
|
+
let isDir = d.isDirectory();
|
|
199
|
+
if (d.isSymbolicLink()) {
|
|
200
|
+
// Resolve symlinks so linked dirs are navigable.
|
|
201
|
+
try {
|
|
202
|
+
const st = await fsp.stat(path.replace(/\/$/, '') + '/' + d.name);
|
|
203
|
+
isDir = st.isDirectory();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
isDir = false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
entries.push({ name: d.name, type: isDir ? 'dir' : 'file' });
|
|
210
|
+
}
|
|
211
|
+
return sortEntries(entries);
|
|
212
|
+
}
|
|
213
|
+
// wsl/ssh: `ls -Ap1 -- <path>` → one per line, dirs end with "/".
|
|
214
|
+
const r = await run(t, ['ls', '-Ap1', '--', path]);
|
|
215
|
+
if (r.code !== 0) {
|
|
216
|
+
if (/No such file|not found/i.test(r.stderr))
|
|
217
|
+
throw new TmuxError(404, 'directory not found');
|
|
218
|
+
if (/Permission denied/i.test(r.stderr))
|
|
219
|
+
throw new TmuxError(403, 'permission denied');
|
|
220
|
+
throw new TmuxError(502, r.stderr.trim().split('\n')[0] || 'cannot list directory');
|
|
221
|
+
}
|
|
222
|
+
return sortEntries(parseRemoteEntries(r.stdout));
|
|
223
|
+
}
|
|
224
|
+
/** Read a (capped) file preview ON THE TARGET. */
|
|
225
|
+
export async function readFilePreview(t, path) {
|
|
226
|
+
if (t.kind === 'local') {
|
|
227
|
+
let fh;
|
|
228
|
+
try {
|
|
229
|
+
fh = await fsp.open(path, 'r');
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
throw fsError(e, path);
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const st = await fh.stat();
|
|
236
|
+
if (st.isDirectory())
|
|
237
|
+
throw new TmuxError(400, 'path is a directory');
|
|
238
|
+
const cap = FILE_PREVIEW_CAP;
|
|
239
|
+
const buf = Buffer.alloc(Math.min(cap, Number(st.size)));
|
|
240
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, 0);
|
|
241
|
+
const slice = buf.subarray(0, bytesRead);
|
|
242
|
+
return {
|
|
243
|
+
path,
|
|
244
|
+
content: slice.toString('utf8'),
|
|
245
|
+
truncated: st.size > cap,
|
|
246
|
+
binary: slice.includes(0),
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
await fh.close();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// wsl/ssh: read up to cap+1 bytes; if we got cap+1 the file is larger.
|
|
254
|
+
const r = await run(t, ['head', '-c', String(FILE_PREVIEW_CAP + 1), '--', path]);
|
|
255
|
+
if (r.code !== 0) {
|
|
256
|
+
if (/No such file|not found/i.test(r.stderr))
|
|
257
|
+
throw new TmuxError(404, 'file not found');
|
|
258
|
+
if (/Is a directory/i.test(r.stderr))
|
|
259
|
+
throw new TmuxError(400, 'path is a directory');
|
|
260
|
+
if (/Permission denied/i.test(r.stderr))
|
|
261
|
+
throw new TmuxError(403, 'permission denied');
|
|
262
|
+
throw new TmuxError(502, r.stderr.trim().split('\n')[0] || 'cannot read file');
|
|
263
|
+
}
|
|
264
|
+
const truncated = r.stdout.length > FILE_PREVIEW_CAP;
|
|
265
|
+
const content = truncated ? r.stdout.slice(0, FILE_PREVIEW_CAP) : r.stdout;
|
|
266
|
+
return { path, content, truncated, binary: content.includes(NUL) };
|
|
267
|
+
}
|
|
268
|
+
/** Overwrite a file ON THE TARGET with `content` (UTF-8). Local uses fs;
|
|
269
|
+
* wsl/ssh pipe the bytes into `tee -- <path>` over stdin (tee truncates). */
|
|
270
|
+
export async function writeFile(t, path, content) {
|
|
271
|
+
if (t.kind === 'local') {
|
|
272
|
+
try {
|
|
273
|
+
await fsp.writeFile(path, content, 'utf8');
|
|
274
|
+
}
|
|
275
|
+
catch (e) {
|
|
276
|
+
throw fsError(e, path);
|
|
277
|
+
}
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// `tee` opens the file with O_TRUNC|O_CREAT, so shorter content can't leave a
|
|
281
|
+
// stale tail. Its stdout echo of the content is ignored.
|
|
282
|
+
const r = await runTargetCommand(t, (opts) => commandArgv(t, ['tee', '--', path], opts), {
|
|
283
|
+
timeoutMs: REMOTE_TIMEOUT_MS,
|
|
284
|
+
input: content,
|
|
285
|
+
});
|
|
286
|
+
if (r.code !== 0) {
|
|
287
|
+
if (/No such file|not found/i.test(r.stderr))
|
|
288
|
+
throw new TmuxError(404, 'directory not found');
|
|
289
|
+
if (/Is a directory/i.test(r.stderr))
|
|
290
|
+
throw new TmuxError(400, 'path is a directory');
|
|
291
|
+
if (/Permission denied/i.test(r.stderr))
|
|
292
|
+
throw new TmuxError(403, 'permission denied');
|
|
293
|
+
throw new TmuxError(502, r.stderr.trim().split('\n')[0] || 'cannot write file');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function fsError(e, path) {
|
|
297
|
+
const code = e?.code;
|
|
298
|
+
if (code === 'ENOENT')
|
|
299
|
+
return new TmuxError(404, `not found: ${path}`);
|
|
300
|
+
if (code === 'EACCES')
|
|
301
|
+
return new TmuxError(403, `permission denied: ${path}`);
|
|
302
|
+
if (code === 'ENOTDIR')
|
|
303
|
+
return new TmuxError(400, `not a directory: ${path}`);
|
|
304
|
+
if (code === 'EISDIR')
|
|
305
|
+
return new TmuxError(400, `path is a directory: ${path}`);
|
|
306
|
+
return new TmuxError(502, e instanceof Error ? e.message : 'filesystem error');
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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"}
|