@treeport/treeport 0.1.0
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/LICENSE +21 -0
- package/README.md +12 -0
- package/bin/treeport.mjs +2 -0
- package/dist/dist-CUkImh2W.js +254 -0
- package/dist/node/cli/index.js +865 -0
- package/dist/node/server/core/launcher.js +189 -0
- package/dist/node/server/index.js +5489 -0
- package/dist/shell-integration-7aBNr-p0.js +256 -0
- package/dist/web/assets/index-C2QPZrxe.js +146 -0
- package/dist/web/assets/index-CC-O69aQ.css +2 -0
- package/dist/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/web/favicon.svg +1 -0
- package/dist/web/icon-192.png +0 -0
- package/dist/web/icon-512.png +0 -0
- package/dist/web/index.html +19 -0
- package/dist/web/manifest.webmanifest +13 -0
- package/drizzle/0000_public_baseline.sql +89 -0
- package/drizzle/meta/0000_snapshot.json +579 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +101 -0
- package/skills/treeport/SKILL.md +153 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as integrateShellLaunch } from "../../../shell-integration-7aBNr-p0.js";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
//#region src/server/core/launcher.ts
|
|
8
|
+
const FORWARDED_SIGNALS = [
|
|
9
|
+
"SIGTERM",
|
|
10
|
+
"SIGINT",
|
|
11
|
+
"SIGHUP"
|
|
12
|
+
];
|
|
13
|
+
function safeDiagnostic(value) {
|
|
14
|
+
return [...value].map((character) => {
|
|
15
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
16
|
+
return codePoint <= 31 || codePoint >= 127 && codePoint <= 159 ? " " : character;
|
|
17
|
+
}).join("").trim();
|
|
18
|
+
}
|
|
19
|
+
function safeLabel(label) {
|
|
20
|
+
return safeDiagnostic(label) || "setup task";
|
|
21
|
+
}
|
|
22
|
+
function runChild(argv, options) {
|
|
23
|
+
const [executable, ...args] = argv;
|
|
24
|
+
if (!executable) return Promise.resolve({
|
|
25
|
+
code: 127,
|
|
26
|
+
signal: null,
|
|
27
|
+
forwardedSignal: null,
|
|
28
|
+
timedOut: false,
|
|
29
|
+
spawnError: /* @__PURE__ */ new Error("argv is empty")
|
|
30
|
+
});
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
let child;
|
|
33
|
+
try {
|
|
34
|
+
child = options.spawnProcess(executable, args, {
|
|
35
|
+
cwd: options.cwd,
|
|
36
|
+
env: options.env,
|
|
37
|
+
stdio: "inherit",
|
|
38
|
+
shell: false
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
resolve({
|
|
42
|
+
code: 127,
|
|
43
|
+
signal: null,
|
|
44
|
+
forwardedSignal: null,
|
|
45
|
+
timedOut: false,
|
|
46
|
+
spawnError: error instanceof Error ? error : new Error(String(error))
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let settled = false;
|
|
51
|
+
let timedOut = false;
|
|
52
|
+
let forwardedSignal = null;
|
|
53
|
+
let timer;
|
|
54
|
+
let killTimer;
|
|
55
|
+
const forwarders = FORWARDED_SIGNALS.map((signal) => [signal, () => {
|
|
56
|
+
forwardedSignal ??= signal;
|
|
57
|
+
child.kill(signal);
|
|
58
|
+
}]);
|
|
59
|
+
const finish = (result) => {
|
|
60
|
+
if (settled) return;
|
|
61
|
+
settled = true;
|
|
62
|
+
if (timer) clearTimeout(timer);
|
|
63
|
+
if (killTimer) clearTimeout(killTimer);
|
|
64
|
+
for (const [signal, forward] of forwarders) options.signalSource.off(signal, forward);
|
|
65
|
+
resolve(result);
|
|
66
|
+
};
|
|
67
|
+
for (const [signal, forward] of forwarders) options.signalSource.on(signal, forward);
|
|
68
|
+
if (options.timeoutMs && options.timeoutMs > 0) {
|
|
69
|
+
timer = setTimeout(() => {
|
|
70
|
+
timedOut = true;
|
|
71
|
+
child.kill("SIGTERM");
|
|
72
|
+
killTimer = setTimeout(() => child.kill("SIGKILL"), 5e3);
|
|
73
|
+
killTimer.unref?.();
|
|
74
|
+
}, options.timeoutMs);
|
|
75
|
+
timer.unref?.();
|
|
76
|
+
}
|
|
77
|
+
child.once("error", (error) => finish({
|
|
78
|
+
code: 127,
|
|
79
|
+
signal: null,
|
|
80
|
+
forwardedSignal,
|
|
81
|
+
timedOut,
|
|
82
|
+
spawnError: error
|
|
83
|
+
}));
|
|
84
|
+
child.once("exit", (code, signal) => finish({
|
|
85
|
+
code,
|
|
86
|
+
signal,
|
|
87
|
+
forwardedSignal,
|
|
88
|
+
timedOut,
|
|
89
|
+
spawnError: null
|
|
90
|
+
}));
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function runLaunchSpec(spec, dependencies = {}) {
|
|
94
|
+
const spawnProcess = dependencies.spawnProcess ?? spawn;
|
|
95
|
+
const stdout = dependencies.stdout ?? process.stdout;
|
|
96
|
+
const stderr = dependencies.stderr ?? process.stderr;
|
|
97
|
+
const signalSource = dependencies.signalSource ?? process;
|
|
98
|
+
if (spec.setupError) {
|
|
99
|
+
stderr.write(`[Treeport setup] ${safeDiagnostic(spec.setupError) || "setup preparation failed"}\n`);
|
|
100
|
+
return 1;
|
|
101
|
+
}
|
|
102
|
+
for (const task of spec.setupTasks ?? []) {
|
|
103
|
+
const label = safeLabel(task.label);
|
|
104
|
+
stdout.write(`[Treeport setup] ${label}\n`);
|
|
105
|
+
const result = await runChild(task.argv, {
|
|
106
|
+
cwd: task.cwd,
|
|
107
|
+
env: {
|
|
108
|
+
...process.env,
|
|
109
|
+
...spec.env,
|
|
110
|
+
...task.env
|
|
111
|
+
},
|
|
112
|
+
timeoutMs: task.timeoutMs,
|
|
113
|
+
spawnProcess,
|
|
114
|
+
signalSource
|
|
115
|
+
});
|
|
116
|
+
if (result.spawnError) {
|
|
117
|
+
stderr.write(`[Treeport setup] ${label} failed: ${safeDiagnostic(result.spawnError.message) || "spawn error"}\n`);
|
|
118
|
+
return 127;
|
|
119
|
+
}
|
|
120
|
+
if (result.timedOut) {
|
|
121
|
+
stderr.write(`[Treeport setup] ${label} failed: timed out after ${task.timeoutMs}ms\n`);
|
|
122
|
+
return 124;
|
|
123
|
+
}
|
|
124
|
+
const terminationSignal = result.forwardedSignal ?? result.signal;
|
|
125
|
+
if (terminationSignal) {
|
|
126
|
+
stderr.write(`[Treeport setup] ${label} failed: terminated by ${terminationSignal}\n`);
|
|
127
|
+
return 1;
|
|
128
|
+
}
|
|
129
|
+
if (result.code !== 0) {
|
|
130
|
+
stderr.write(`[Treeport setup] ${label} failed: exit ${result.code ?? 1}\n`);
|
|
131
|
+
return result.code ?? 1;
|
|
132
|
+
}
|
|
133
|
+
stdout.write(`[Treeport setup] ${label} complete\n`);
|
|
134
|
+
}
|
|
135
|
+
if (!spec.argv[0]) {
|
|
136
|
+
stderr.write("Treeport launcher: argv is empty\n");
|
|
137
|
+
return 127;
|
|
138
|
+
}
|
|
139
|
+
const commandEnvironment = {
|
|
140
|
+
...process.env,
|
|
141
|
+
...spec.env
|
|
142
|
+
};
|
|
143
|
+
const command = integrateShellLaunch(spec.argv, commandEnvironment, spec.shellIntegrationDir, spec.tmuxExecutable);
|
|
144
|
+
const result = await runChild(command.argv, {
|
|
145
|
+
cwd: spec.cwd,
|
|
146
|
+
env: command.env,
|
|
147
|
+
spawnProcess,
|
|
148
|
+
signalSource
|
|
149
|
+
});
|
|
150
|
+
if (result.spawnError) stderr.write(`Treeport launcher: ${safeDiagnostic(result.spawnError.message) || "spawn error"}\n`);
|
|
151
|
+
if (result.forwardedSignal && (!spec.fallbackArgv || result.forwardedSignal !== "SIGINT")) return 1;
|
|
152
|
+
if (spec.fallbackArgv) {
|
|
153
|
+
const fallback = integrateShellLaunch(spec.fallbackArgv, commandEnvironment, spec.shellIntegrationDir, spec.tmuxExecutable);
|
|
154
|
+
const fallbackResult = await runChild(fallback.argv, {
|
|
155
|
+
cwd: spec.cwd,
|
|
156
|
+
env: fallback.env,
|
|
157
|
+
spawnProcess,
|
|
158
|
+
signalSource
|
|
159
|
+
});
|
|
160
|
+
if (fallbackResult.spawnError) {
|
|
161
|
+
stderr.write(`Treeport launcher: ${safeDiagnostic(fallbackResult.spawnError.message) || "spawn error"}\n`);
|
|
162
|
+
return 127;
|
|
163
|
+
}
|
|
164
|
+
if (fallbackResult.forwardedSignal || fallbackResult.signal) return 1;
|
|
165
|
+
return fallbackResult.code ?? 1;
|
|
166
|
+
}
|
|
167
|
+
if (result.spawnError) return 127;
|
|
168
|
+
if (result.signal) return 1;
|
|
169
|
+
return result.code ?? 1;
|
|
170
|
+
}
|
|
171
|
+
async function main() {
|
|
172
|
+
const specPath = process.argv[2];
|
|
173
|
+
if (!specPath) {
|
|
174
|
+
process.stderr.write("Treeport launcher: missing launch spec\n");
|
|
175
|
+
process.exit(127);
|
|
176
|
+
}
|
|
177
|
+
let spec;
|
|
178
|
+
try {
|
|
179
|
+
spec = JSON.parse(await fs.readFile(specPath, "utf8"));
|
|
180
|
+
} catch (error) {
|
|
181
|
+
process.stderr.write(`Treeport launcher: cannot read launch spec: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
182
|
+
process.exit(127);
|
|
183
|
+
}
|
|
184
|
+
process.exit(await runLaunchSpec(spec));
|
|
185
|
+
}
|
|
186
|
+
const invokedPath = process.argv[1];
|
|
187
|
+
if (invokedPath && path.resolve(invokedPath) === path.resolve(fileURLToPath(import.meta.url))) main();
|
|
188
|
+
//#endregion
|
|
189
|
+
export { runLaunchSpec };
|