lucifer-gate 0.8.2 → 0.8.5-alpha.2.c2c1b02
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/README.md
CHANGED
|
@@ -100,6 +100,16 @@ Per-feature contracts live under [docs/specs/](docs/specs/):
|
|
|
100
100
|
For agent-specific instructions (task lifecycle, review checklist, skills),
|
|
101
101
|
start at [AGENTS.md](AGENTS.md).
|
|
102
102
|
|
|
103
|
+
## Operational limits
|
|
104
|
+
|
|
105
|
+
Before you plan a deployment, note the current shape of the runtime:
|
|
106
|
+
|
|
107
|
+
- **Single-process state.** Lucifer Gate runs as one Node process. There is no cluster-aware approval fan-out and no leader election — running more than one instance against the same data directory is not supported.
|
|
108
|
+
- **In-memory pending approvals are lost on restart.** Requests that are waiting for Telegram or web-admin approval at the moment of a restart are dropped: callers see their in-flight `POST /api/v1/execute` fail, and the approval notification stays orphaned in the channel. Approvals that have already resolved are persisted; only *pending* ones are volatile.
|
|
109
|
+
- **SQLite is the sole persistence layer.** Approvals, audit log, and related state all live in `<dataDir>/lucifer.db` via `better-sqlite3`. There is no network database driver, no clustering, and no replication; back up the file directly. Per-domain grading for these trade-offs is tracked in [docs/quality/QUALITY-GRADES.md](docs/quality/QUALITY-GRADES.md).
|
|
110
|
+
|
|
111
|
+
These are conscious pre-1.0 trade-offs, not bugs. If any of them is a blocker for your environment, open an issue before building on top of the current shape.
|
|
112
|
+
|
|
103
113
|
## Stack
|
|
104
114
|
|
|
105
115
|
- Express 5 + TypeScript
|
|
@@ -4,7 +4,7 @@ import { createChildLogger } from '../../../lib/logger.js';
|
|
|
4
4
|
const log = createChildLogger('executor');
|
|
5
5
|
let activeExecutions = 0;
|
|
6
6
|
export async function executeCommand(options) {
|
|
7
|
-
const { command, requestId, cwd,
|
|
7
|
+
const { command, requestId, cwd, maxConcurrent, aliases } = options;
|
|
8
8
|
if (activeExecutions >= maxConcurrent) {
|
|
9
9
|
log.warn({ requestId, active: activeExecutions, max: maxConcurrent }, 'Max concurrent executions reached');
|
|
10
10
|
return {
|
|
@@ -18,129 +18,124 @@ export async function executeCommand(options) {
|
|
|
18
18
|
const resolved = resolveAlias(command, aliases);
|
|
19
19
|
log.info({ requestId, command, cwd, alias: resolved ? { cwd: resolved.cwd, bin: resolved.spawnCommand } : undefined }, 'Executing command');
|
|
20
20
|
try {
|
|
21
|
-
return await
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
21
|
+
return await runChildProcess(options, resolved, startTime);
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
activeExecutions--;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function spawnChild(options, resolved) {
|
|
28
|
+
// This is a command gateway that intentionally executes user-supplied
|
|
29
|
+
// commands. Access is gated by API-key auth and configurable command
|
|
30
|
+
// rules (allow/deny lists). The spawn call below is by design.
|
|
31
|
+
if (resolved) {
|
|
32
|
+
return spawn(resolved.spawnCommand, resolved.spawnArgs, { cwd: resolved.cwd, detached: true });
|
|
33
|
+
}
|
|
34
|
+
return spawn(options.command, { shell: true, cwd: options.cwd ?? process.cwd(), detached: true }); // NOSONAR -- intentional: this gateway executes user-supplied commands gated by API-key auth and command rules
|
|
35
|
+
}
|
|
36
|
+
function killChildTree(child) {
|
|
37
|
+
try {
|
|
38
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
child.kill('SIGKILL');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function runChildProcess(options, resolved, startTime) {
|
|
45
|
+
const { requestId, timeoutMs, maxOutputBytes, abortSignal } = options;
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
const child = spawnChild(options, resolved);
|
|
48
|
+
let stdout = '';
|
|
49
|
+
let stderr = '';
|
|
50
|
+
let outputBytes = 0;
|
|
51
|
+
let killed = false;
|
|
52
|
+
const timer = setTimeout(() => {
|
|
53
|
+
killed = true;
|
|
54
|
+
killChildTree(child);
|
|
55
|
+
log.warn({ requestId, timeoutMs }, 'Command timed out');
|
|
56
|
+
}, timeoutMs);
|
|
57
|
+
const onAbort = () => {
|
|
58
|
+
killed = true;
|
|
59
|
+
killChildTree(child);
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
log.info({ requestId }, 'Command aborted (client disconnected)');
|
|
62
|
+
};
|
|
63
|
+
if (abortSignal?.aborted) {
|
|
64
|
+
killChildTree(child);
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
resolve({ requestId, status: 'failed', error: 'Request aborted' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
abortSignal?.addEventListener('abort', onAbort, { once: true });
|
|
70
|
+
const handleStdoutChunk = (chunk) => {
|
|
71
|
+
outputBytes += chunk.length;
|
|
72
|
+
if (outputBytes <= maxOutputBytes) {
|
|
73
|
+
stdout += chunk.toString();
|
|
74
|
+
return;
|
|
66
75
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
outputBytes += chunk.length;
|
|
86
|
-
if (outputBytes <= maxOutputBytes) {
|
|
87
|
-
stderr += chunk.toString();
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
child.on('close', (code) => {
|
|
91
|
-
clearTimeout(timer);
|
|
92
|
-
if (abortSignal) {
|
|
93
|
-
abortSignal.removeEventListener('abort', onAbort);
|
|
94
|
-
}
|
|
95
|
-
const durationMs = Date.now() - startTime;
|
|
96
|
-
if (killed && outputBytes > maxOutputBytes) {
|
|
97
|
-
resolve({
|
|
98
|
-
requestId,
|
|
99
|
-
status: 'failed',
|
|
100
|
-
stdout: stdout.slice(0, maxOutputBytes),
|
|
101
|
-
stderr,
|
|
102
|
-
durationMs,
|
|
103
|
-
error: `Output exceeded ${maxOutputBytes} bytes limit`,
|
|
104
|
-
});
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (killed) {
|
|
108
|
-
resolve({
|
|
109
|
-
requestId,
|
|
110
|
-
status: 'timed_out',
|
|
111
|
-
stdout,
|
|
112
|
-
stderr,
|
|
113
|
-
durationMs,
|
|
114
|
-
error: `Command timed out after ${timeoutMs}ms`,
|
|
115
|
-
});
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
76
|
+
if (killed)
|
|
77
|
+
return;
|
|
78
|
+
killed = true;
|
|
79
|
+
killChildTree(child);
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
log.warn({ requestId, outputBytes, maxOutputBytes }, 'Output buffer exceeded');
|
|
82
|
+
};
|
|
83
|
+
const handleStderrChunk = (chunk) => {
|
|
84
|
+
outputBytes += chunk.length;
|
|
85
|
+
if (outputBytes <= maxOutputBytes) {
|
|
86
|
+
stderr += chunk.toString();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const handleClose = (code) => {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
abortSignal?.removeEventListener('abort', onAbort);
|
|
92
|
+
const durationMs = Date.now() - startTime;
|
|
93
|
+
if (killed && outputBytes > maxOutputBytes) {
|
|
118
94
|
resolve({
|
|
119
95
|
requestId,
|
|
120
|
-
status:
|
|
121
|
-
|
|
122
|
-
stdout,
|
|
96
|
+
status: 'failed',
|
|
97
|
+
stdout: stdout.slice(0, maxOutputBytes),
|
|
123
98
|
stderr,
|
|
124
99
|
durationMs,
|
|
100
|
+
error: `Output exceeded ${maxOutputBytes} bytes limit`,
|
|
125
101
|
});
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
clearTimeout(timer);
|
|
130
|
-
if (abortSignal) {
|
|
131
|
-
abortSignal.removeEventListener('abort', onAbort);
|
|
132
|
-
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (killed) {
|
|
133
105
|
resolve({
|
|
134
106
|
requestId,
|
|
135
|
-
status: '
|
|
136
|
-
|
|
137
|
-
|
|
107
|
+
status: 'timed_out',
|
|
108
|
+
stdout,
|
|
109
|
+
stderr,
|
|
110
|
+
durationMs,
|
|
111
|
+
error: `Command timed out after ${timeoutMs}ms`,
|
|
138
112
|
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
resolve({
|
|
116
|
+
requestId,
|
|
117
|
+
status: code === 0 ? 'completed' : 'failed',
|
|
118
|
+
exitCode: code ?? undefined,
|
|
119
|
+
stdout,
|
|
120
|
+
stderr,
|
|
121
|
+
durationMs,
|
|
139
122
|
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
123
|
+
log.info({ requestId, exitCode: code, durationMs }, 'Command completed');
|
|
124
|
+
};
|
|
125
|
+
const handleError = (err) => {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
abortSignal?.removeEventListener('abort', onAbort);
|
|
128
|
+
resolve({
|
|
129
|
+
requestId,
|
|
130
|
+
status: 'failed',
|
|
131
|
+
error: `Failed to execute: ${err.message}`,
|
|
132
|
+
durationMs: Date.now() - startTime,
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
child.stdout.on('data', handleStdoutChunk);
|
|
136
|
+
child.stderr.on('data', handleStderrChunk);
|
|
137
|
+
child.on('close', handleClose);
|
|
138
|
+
child.on('error', handleError);
|
|
139
|
+
});
|
|
145
140
|
}
|
|
146
141
|
//# sourceMappingURL=execute_command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute_command.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/execute_command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"execute_command.js","sourceRoot":"","sources":["../../../../../server/src/domains/command-gateway/service/execute_command.ts"],"names":[],"mappings":"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"}
|