@ganglion/xacpx 0.17.0-beta.3 → 0.17.0-beta.4
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/cli.js
CHANGED
|
@@ -25585,6 +25585,10 @@ function terminalIdleTimeoutSeconds(config4) {
|
|
|
25585
25585
|
const v = config4.terminal?.idleTimeoutSeconds;
|
|
25586
25586
|
return typeof v === "number" && v > 0 ? v : 900;
|
|
25587
25587
|
}
|
|
25588
|
+
function terminalShell(config4) {
|
|
25589
|
+
const v = config4.terminal?.shell;
|
|
25590
|
+
return typeof v === "string" && v.trim() ? v : undefined;
|
|
25591
|
+
}
|
|
25588
25592
|
function filesWriteEnabled(config4) {
|
|
25589
25593
|
return config4.files?.writeEnabled === true;
|
|
25590
25594
|
}
|
|
@@ -34840,6 +34844,11 @@ ${chunk}` : chunk
|
|
|
34840
34844
|
throw new Error("session-not-found");
|
|
34841
34845
|
return this.deps.terminal.create({ cwd: session3.cwd, cols, rows });
|
|
34842
34846
|
}
|
|
34847
|
+
attachTerminal(terminalId) {
|
|
34848
|
+
if (!this.deps.terminalEnabled())
|
|
34849
|
+
throw new Error("terminal-disabled");
|
|
34850
|
+
return this.deps.terminal.attach(terminalId);
|
|
34851
|
+
}
|
|
34843
34852
|
writeTerminal(terminalId, data) {
|
|
34844
34853
|
this.deps.terminal.write(terminalId, data);
|
|
34845
34854
|
}
|
|
@@ -34886,6 +34895,7 @@ var init_control_service = __esm(() => {
|
|
|
34886
34895
|
// src/control/terminal-service.ts
|
|
34887
34896
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
34888
34897
|
import { createRequire as createRequire6 } from "node:module";
|
|
34898
|
+
import { statSync as statSync3 } from "node:fs";
|
|
34889
34899
|
import { spawn as spawnPty2 } from "node-pty";
|
|
34890
34900
|
function scrubEnv() {
|
|
34891
34901
|
const out = {};
|
|
@@ -34900,9 +34910,33 @@ function scrubEnv() {
|
|
|
34900
34910
|
out.LANG = out.LANG ?? "en_US.UTF-8";
|
|
34901
34911
|
return out;
|
|
34902
34912
|
}
|
|
34903
|
-
function
|
|
34904
|
-
|
|
34905
|
-
return
|
|
34913
|
+
function defaultExists(p) {
|
|
34914
|
+
try {
|
|
34915
|
+
return statSync3(p).isFile();
|
|
34916
|
+
} catch {
|
|
34917
|
+
return false;
|
|
34918
|
+
}
|
|
34919
|
+
}
|
|
34920
|
+
function resolveShell(args) {
|
|
34921
|
+
const { platform, env, shellOverride } = args;
|
|
34922
|
+
const exists = args.exists ?? defaultExists;
|
|
34923
|
+
if (shellOverride && shellOverride.trim())
|
|
34924
|
+
return shellOverride;
|
|
34925
|
+
if (platform === "win32") {
|
|
34926
|
+
const pathValue = env.PATH ?? env.Path ?? "";
|
|
34927
|
+
const dirs = pathValue.split(";").filter(Boolean);
|
|
34928
|
+
for (const name of ["pwsh.exe", "powershell.exe"]) {
|
|
34929
|
+
for (const dir of dirs) {
|
|
34930
|
+
const clean = dir.replace(/^"|"$/g, "");
|
|
34931
|
+
const full = `${clean}\\${name}`;
|
|
34932
|
+
if (exists(full))
|
|
34933
|
+
return full;
|
|
34934
|
+
}
|
|
34935
|
+
}
|
|
34936
|
+
return env.ComSpec ?? "cmd.exe";
|
|
34937
|
+
}
|
|
34938
|
+
if (env.SHELL)
|
|
34939
|
+
return env.SHELL;
|
|
34906
34940
|
return platform === "darwin" ? "/bin/zsh" : "/bin/bash";
|
|
34907
34941
|
}
|
|
34908
34942
|
function realPtySpawn(file, args, opts) {
|
|
@@ -34910,6 +34944,26 @@ function realPtySpawn(file, args, opts) {
|
|
|
34910
34944
|
ensureNodePtyHelperExecutable(helperPath);
|
|
34911
34945
|
return spawnPty2(file, args, opts);
|
|
34912
34946
|
}
|
|
34947
|
+
function appendToBuffer(session3, data) {
|
|
34948
|
+
session3.buffer += data;
|
|
34949
|
+
session3.bufBytes += Buffer.byteLength(data, "utf8");
|
|
34950
|
+
if (session3.bufBytes <= MAX_BUFFER_BYTES)
|
|
34951
|
+
return;
|
|
34952
|
+
while (session3.bufBytes > MAX_BUFFER_BYTES) {
|
|
34953
|
+
const nl = session3.buffer.indexOf(`
|
|
34954
|
+
`);
|
|
34955
|
+
if (nl === -1)
|
|
34956
|
+
break;
|
|
34957
|
+
const removed = session3.buffer.slice(0, nl + 1);
|
|
34958
|
+
session3.buffer = session3.buffer.slice(nl + 1);
|
|
34959
|
+
session3.bufBytes -= Buffer.byteLength(removed, "utf8");
|
|
34960
|
+
}
|
|
34961
|
+
while (session3.bufBytes > MAX_BUFFER_BYTES && session3.buffer.length > 0) {
|
|
34962
|
+
const ch = session3.buffer[0];
|
|
34963
|
+
session3.buffer = session3.buffer.slice(1);
|
|
34964
|
+
session3.bufBytes -= Buffer.byteLength(ch, "utf8");
|
|
34965
|
+
}
|
|
34966
|
+
}
|
|
34913
34967
|
function createTerminalService(deps) {
|
|
34914
34968
|
const spawn12 = deps.spawn ?? realPtySpawn;
|
|
34915
34969
|
const platform = deps.platform ?? process.platform;
|
|
@@ -34934,13 +34988,13 @@ function createTerminalService(deps) {
|
|
|
34934
34988
|
};
|
|
34935
34989
|
return {
|
|
34936
34990
|
create({ cwd, cols, rows }) {
|
|
34937
|
-
|
|
34938
|
-
throw new Error("terminal-unsupported-platform");
|
|
34991
|
+
const shell = resolveShell({ platform, env: process.env, shellOverride: deps.shell?.() });
|
|
34939
34992
|
const terminalId = randomUUID4();
|
|
34940
|
-
const handle = spawn12(
|
|
34941
|
-
const session3 = { handle, seq: 0, idleTimer: null };
|
|
34993
|
+
const handle = spawn12(shell, [], { name: "xterm-256color", cols, rows, cwd, env: scrubEnv() });
|
|
34994
|
+
const session3 = { handle, seq: 0, idleTimer: null, buffer: "", bufBytes: 0 };
|
|
34942
34995
|
sessions.set(terminalId, session3);
|
|
34943
34996
|
handle.onData((data) => {
|
|
34997
|
+
appendToBuffer(session3, data);
|
|
34944
34998
|
deps.events.emit({ type: "terminal-output", terminalId, seq: session3.seq++, data });
|
|
34945
34999
|
});
|
|
34946
35000
|
handle.onExit(({ exitCode }) => {
|
|
@@ -34952,6 +35006,13 @@ function createTerminalService(deps) {
|
|
|
34952
35006
|
resetIdle(terminalId);
|
|
34953
35007
|
return { terminalId };
|
|
34954
35008
|
},
|
|
35009
|
+
attach(terminalId) {
|
|
35010
|
+
const s = sessions.get(terminalId);
|
|
35011
|
+
if (!s)
|
|
35012
|
+
return { ok: false };
|
|
35013
|
+
resetIdle(terminalId);
|
|
35014
|
+
return { ok: true, buffer: s.buffer, lastSeq: s.seq - 1 };
|
|
35015
|
+
},
|
|
34955
35016
|
write(terminalId, data) {
|
|
34956
35017
|
const s = sessions.get(terminalId);
|
|
34957
35018
|
if (!s)
|
|
@@ -34990,7 +35051,7 @@ function createTerminalService(deps) {
|
|
|
34990
35051
|
}
|
|
34991
35052
|
};
|
|
34992
35053
|
}
|
|
34993
|
-
var require5, SENSITIVE_ENV_KEYS;
|
|
35054
|
+
var require5, SENSITIVE_ENV_KEYS, MAX_BUFFER_BYTES;
|
|
34994
35055
|
var init_terminal_service = __esm(() => {
|
|
34995
35056
|
init_node_pty_helper();
|
|
34996
35057
|
require5 = createRequire6(import.meta.url);
|
|
@@ -35008,6 +35069,7 @@ var init_terminal_service = __esm(() => {
|
|
|
35008
35069
|
"GITHUB_TOKEN",
|
|
35009
35070
|
"NPM_TOKEN"
|
|
35010
35071
|
];
|
|
35072
|
+
MAX_BUFFER_BYTES = 256 * 1024;
|
|
35011
35073
|
});
|
|
35012
35074
|
|
|
35013
35075
|
// src/control/upload-store.ts
|
|
@@ -35685,7 +35747,8 @@ async function buildApp(paths, deps = {}) {
|
|
|
35685
35747
|
const controlEvents = createControlEventBus(logger2);
|
|
35686
35748
|
const terminalService = createTerminalService({
|
|
35687
35749
|
events: controlEvents,
|
|
35688
|
-
idleTimeoutSeconds: () => terminalIdleTimeoutSeconds(config4)
|
|
35750
|
+
idleTimeoutSeconds: () => terminalIdleTimeoutSeconds(config4),
|
|
35751
|
+
shell: () => terminalShell(config4)
|
|
35689
35752
|
});
|
|
35690
35753
|
const uploadStore = new UploadStore;
|
|
35691
35754
|
uploadStore.cleanup();
|
package/dist/config/types.d.ts
CHANGED
|
@@ -47,6 +47,8 @@ export interface TerminalConfig {
|
|
|
47
47
|
enabled: boolean;
|
|
48
48
|
/** Idle seconds before a terminal PTY is auto-killed. Defaults to 900 (15 min). */
|
|
49
49
|
idleTimeoutSeconds?: number;
|
|
50
|
+
/** Explicit shell override (absolute path or bare name). Cross-platform: wins over SHELL / platform default. */
|
|
51
|
+
shell?: string;
|
|
50
52
|
}
|
|
51
53
|
export interface FilesConfig {
|
|
52
54
|
/** Default false. When false, all fs write ops (new/rename/delete/copy) are rejected
|
|
@@ -119,4 +121,5 @@ export interface AppConfig {
|
|
|
119
121
|
}
|
|
120
122
|
export declare function terminalEnabled(config: AppConfig): boolean;
|
|
121
123
|
export declare function terminalIdleTimeoutSeconds(config: AppConfig): number;
|
|
124
|
+
export declare function terminalShell(config: AppConfig): string | undefined;
|
|
122
125
|
export declare function filesWriteEnabled(config: AppConfig): boolean;
|
|
@@ -241,6 +241,7 @@ export declare class ControlService {
|
|
|
241
241
|
createTerminal(chatKey: string, sessionAlias: string, cols: number, rows: number): Promise<{
|
|
242
242
|
terminalId: string;
|
|
243
243
|
}>;
|
|
244
|
+
attachTerminal(terminalId: string): import("./terminal-service").TerminalAttachResult;
|
|
244
245
|
writeTerminal(terminalId: string, data: string): void;
|
|
245
246
|
resizeTerminal(terminalId: string, cols: number, rows: number): void;
|
|
246
247
|
closeTerminal(terminalId: string): void;
|
|
@@ -27,10 +27,18 @@ export interface TerminalCreateInput {
|
|
|
27
27
|
cols: number;
|
|
28
28
|
rows: number;
|
|
29
29
|
}
|
|
30
|
+
export type TerminalAttachResult = {
|
|
31
|
+
ok: false;
|
|
32
|
+
} | {
|
|
33
|
+
ok: true;
|
|
34
|
+
buffer: string;
|
|
35
|
+
lastSeq: number;
|
|
36
|
+
};
|
|
30
37
|
export interface TerminalService {
|
|
31
38
|
create(input: TerminalCreateInput): {
|
|
32
39
|
terminalId: string;
|
|
33
40
|
};
|
|
41
|
+
attach(terminalId: string): TerminalAttachResult;
|
|
34
42
|
write(terminalId: string, data: string): void;
|
|
35
43
|
resize(terminalId: string, cols: number, rows: number): void;
|
|
36
44
|
close(terminalId: string): void;
|
|
@@ -39,10 +47,25 @@ export interface TerminalService {
|
|
|
39
47
|
export interface TerminalServiceDeps {
|
|
40
48
|
events: ControlEventBus;
|
|
41
49
|
idleTimeoutSeconds: () => number;
|
|
50
|
+
/** Optional explicit shell override from config (terminal.shell). */
|
|
51
|
+
shell?: () => string | undefined;
|
|
42
52
|
spawn?: PtySpawn;
|
|
43
53
|
platform?: NodeJS.Platform;
|
|
44
54
|
/** Injectable timer primitives; defaults to global setTimeout/clearTimeout. */
|
|
45
55
|
setTimer?: (fn: () => void, ms: number) => unknown;
|
|
46
56
|
clearTimer?: (id: unknown) => void;
|
|
47
57
|
}
|
|
58
|
+
export interface ResolveShellArgs {
|
|
59
|
+
platform: NodeJS.Platform;
|
|
60
|
+
env: NodeJS.ProcessEnv;
|
|
61
|
+
/** Explicit override from config terminal.shell — wins on every platform. */
|
|
62
|
+
shellOverride?: string;
|
|
63
|
+
/** Injectable executable-existence predicate (defaults to fs statSync). */
|
|
64
|
+
exists?: (p: string) => boolean;
|
|
65
|
+
}
|
|
66
|
+
/** Pick the shell to spawn. Priority: explicit override -> platform default.
|
|
67
|
+
* win32 deliberately ignores SHELL (git-bash sets it to an MSYS path that
|
|
68
|
+
* node-pty can't spawn on Windows) and scans PATH for pwsh -> powershell,
|
|
69
|
+
* falling back to %ComSpec% (cmd.exe). Never throws — always returns a value. */
|
|
70
|
+
export declare function resolveShell(args: ResolveShellArgs): string;
|
|
48
71
|
export declare function createTerminalService(deps: TerminalServiceDeps): TerminalService;
|