@volter/supercode-terminal 0.2.57 → 0.2.58
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/index.mjs +17 -5
- package/package.json +7 -17
- package/substrate/pane-server.mjs +8 -1
package/index.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { appendFileSync, cpSync, existsSync, mkdirSync, readFileSync, renameSync
|
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
6
|
import { connect as netConnect } from 'node:net';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
7
8
|
import { fileURLToPath } from 'node:url';
|
|
8
9
|
import { createServer as defaultCreateServer } from 'node:http';
|
|
9
10
|
|
|
@@ -560,11 +561,18 @@ export class PtyTerminalHost {
|
|
|
560
561
|
if ([...this.#sessions.values()].some((entry) => entry.name === name)) {
|
|
561
562
|
throw new TerminalHostError('session_exists', `A pane named ${name} already exists.`);
|
|
562
563
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
564
|
+
let pty, headless, serialize;
|
|
565
|
+
try {
|
|
566
|
+
[{ default: pty }, { default: headless }, { default: serialize }] = await Promise.all([
|
|
567
|
+
import('@homebridge/node-pty-prebuilt-multiarch'),
|
|
568
|
+
import('@xterm/headless'),
|
|
569
|
+
import('@xterm/addon-serialize'),
|
|
570
|
+
]);
|
|
571
|
+
} catch (error) {
|
|
572
|
+
// A process that failed this load may keep failing it after the package is installed (Node keeps what it read of
|
|
573
|
+
// a half-installed package): the pane server answers this code by ending itself, and the next one loads afresh.
|
|
574
|
+
throw new TerminalHostError('pane_runtime_missing', `The pane runtime could not load: ${errorMessage(error)}`);
|
|
575
|
+
}
|
|
568
576
|
const env = { ...process.env, ...(input.env ?? {}) };
|
|
569
577
|
const { file, args } = windowsLaunch(input.command.program, input.command.arguments ?? [], env);
|
|
570
578
|
// The watchdog is running before the pane is, and the pane is on its list the moment it exists.
|
|
@@ -974,6 +982,10 @@ export class PaneServerHost {
|
|
|
974
982
|
rmSync(staging, { recursive: true, force: true });
|
|
975
983
|
cpSync(root, join(staging, 'node_modules', '@volter', 'supercode-terminal'), { recursive: true, filter: (path) => !path.slice(root.length).split(/[\\/]/).includes('node_modules') });
|
|
976
984
|
for (const name of PANE_RUNTIME_PACKAGES) cpSync(packageDir(name), join(staging, 'node_modules', ...name.split('/')), { recursive: true });
|
|
985
|
+
// A copy taken of a half-installed package would stay broken under its version: it is complete only when every
|
|
986
|
+
// runtime package resolves to an entry that exists in it.
|
|
987
|
+
const fromCopy = createRequire(join(staging, 'node_modules', '@volter', 'supercode-terminal', 'package.json'));
|
|
988
|
+
for (const name of PANE_RUNTIME_PACKAGES) if (!existsSync(fromCopy.resolve(name))) throw new Error(`${name} has no entry in the copy`);
|
|
977
989
|
writeFileSync(join(staging, '.complete'), `${version}\n`);
|
|
978
990
|
rmSync(target, { recursive: true, force: true });
|
|
979
991
|
renameSync(staging, target);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-terminal",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.58",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional leak-safe terminal and tmux host adapter for Volter Harness frontends",
|
|
6
6
|
"exports": {
|
|
@@ -95,8 +95,12 @@
|
|
|
95
95
|
"prepack": "npm run build",
|
|
96
96
|
"build:substrate": "tsc -p tsconfig.substrate.json"
|
|
97
97
|
},
|
|
98
|
-
"
|
|
98
|
+
"dependencies": {
|
|
99
99
|
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1 || ^0.14.1",
|
|
100
|
+
"@xterm/addon-serialize": "^0.14.0",
|
|
101
|
+
"@xterm/headless": "^6.0.0"
|
|
102
|
+
},
|
|
103
|
+
"peerDependencies": {
|
|
100
104
|
"@xterm/addon-fit": "^0.11.0",
|
|
101
105
|
"@xterm/addon-search": "^0.16.0",
|
|
102
106
|
"@xterm/addon-web-links": "^0.12.0",
|
|
@@ -104,14 +108,9 @@
|
|
|
104
108
|
"preact": ">=10.19.0 <11",
|
|
105
109
|
"react": ">=18 <20",
|
|
106
110
|
"ws": "^8.21.0",
|
|
107
|
-
"@volter/supercode-harness-sdk": "^0.3.18"
|
|
108
|
-
"@xterm/headless": "^6.0.0",
|
|
109
|
-
"@xterm/addon-serialize": "^0.14.0"
|
|
111
|
+
"@volter/supercode-harness-sdk": "^0.3.18"
|
|
110
112
|
},
|
|
111
113
|
"peerDependenciesMeta": {
|
|
112
|
-
"@homebridge/node-pty-prebuilt-multiarch": {
|
|
113
|
-
"optional": true
|
|
114
|
-
},
|
|
115
114
|
"@xterm/addon-fit": {
|
|
116
115
|
"optional": true
|
|
117
116
|
},
|
|
@@ -135,24 +134,15 @@
|
|
|
135
134
|
},
|
|
136
135
|
"@volter/supercode-harness-sdk": {
|
|
137
136
|
"optional": true
|
|
138
|
-
},
|
|
139
|
-
"@xterm/headless": {
|
|
140
|
-
"optional": true
|
|
141
|
-
},
|
|
142
|
-
"@xterm/addon-serialize": {
|
|
143
|
-
"optional": true
|
|
144
137
|
}
|
|
145
138
|
},
|
|
146
139
|
"devDependencies": {
|
|
147
|
-
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
|
|
148
140
|
"@types/node": "^22.20.1",
|
|
149
141
|
"@types/ws": "^8.18.1",
|
|
150
142
|
"@volter/supercode-harness-sdk": "^0.3.18",
|
|
151
143
|
"@xterm/addon-fit": "^0.11.0",
|
|
152
144
|
"@xterm/addon-search": "^0.16.0",
|
|
153
|
-
"@xterm/addon-serialize": "^0.14.0",
|
|
154
145
|
"@xterm/addon-web-links": "^0.12.0",
|
|
155
|
-
"@xterm/headless": "^6.0.0",
|
|
156
146
|
"@xterm/xterm": "^6.0.0",
|
|
157
147
|
"esbuild": "^0.25.0",
|
|
158
148
|
"preact": "^10.19.0",
|
|
@@ -86,7 +86,14 @@ const server = createServer((connection) => {
|
|
|
86
86
|
const { id, op, args = [] } = message;
|
|
87
87
|
if (op === 'attach') { attach(id, args, message.stream); continue; }
|
|
88
88
|
if (!OPS.has(op)) { refuse(id, { code: 'unsupported', message: `pane server: no operation ${op}` }); continue; }
|
|
89
|
-
Promise.resolve().then(() => host[op](...args)).then((result) => answer(id, result), (error) =>
|
|
89
|
+
Promise.resolve().then(() => host[op](...args)).then((result) => answer(id, result), async (error) => {
|
|
90
|
+
refuse(id, error);
|
|
91
|
+
// The pane runtime failed to load in this process: with no pane to keep, it ends once the answer is out, so
|
|
92
|
+
// the next request starts a pane server that loads the runtime afresh (one installed since this one started).
|
|
93
|
+
if (error?.code === 'pane_runtime_missing' && !(await host.listSessions().catch(() => [])).length) {
|
|
94
|
+
connection.end(() => { host.dispose(); process.exit(0); });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
90
97
|
}
|
|
91
98
|
});
|
|
92
99
|
// A client that goes (its daemon restarting) takes only its viewers with it: the panes stay.
|