agenshield 0.6.1 → 0.7.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/package.json +9 -8
- package/src/commands/setup.d.ts.map +1 -1
- package/src/commands/setup.js +23 -5
- package/src/commands/setup.js.map +1 -1
- package/src/setup-server/routes.d.ts.map +1 -1
- package/src/setup-server/routes.js +67 -0
- package/src/setup-server/routes.js.map +1 -1
- package/src/setup-server/server.d.ts +1 -1
- package/src/setup-server/server.d.ts.map +1 -1
- package/src/setup-server/server.js +6 -0
- package/src/setup-server/server.js.map +1 -1
- package/src/setup-server/sse.d.ts +1 -1
- package/src/setup-server/sse.d.ts.map +1 -1
- package/src/setup-server/sse.js.map +1 -1
- package/src/utils/daemon.d.ts.map +1 -1
- package/src/utils/daemon.js +10 -0
- package/src/utils/daemon.js.map +1 -1
- package/src/wizard/engine.d.ts +5 -2
- package/src/wizard/engine.d.ts.map +1 -1
- package/src/wizard/engine.js +561 -120
- package/src/wizard/engine.js.map +1 -1
- package/src/wizard/types.d.ts +55 -3
- package/src/wizard/types.d.ts.map +1 -1
- package/src/wizard/types.js +87 -16
- package/src/wizard/types.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agenshield",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgenShield - CLI for managing AI agent security sandbox",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -37,13 +37,14 @@
|
|
|
37
37
|
"sandbox"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@agenshield/broker": "0.
|
|
41
|
-
"@agenshield/daemon": "0.
|
|
42
|
-
"@agenshield/
|
|
43
|
-
"@agenshield/
|
|
44
|
-
"@agenshield/
|
|
45
|
-
"@agenshield/
|
|
46
|
-
"@agenshield/
|
|
40
|
+
"@agenshield/broker": "0.7.0",
|
|
41
|
+
"@agenshield/daemon": "0.7.0",
|
|
42
|
+
"@agenshield/integrations": "0.7.0",
|
|
43
|
+
"@agenshield/interceptor": "0.7.0",
|
|
44
|
+
"@agenshield/ipc": "0.7.0",
|
|
45
|
+
"@agenshield/patcher": "0.7.0",
|
|
46
|
+
"@agenshield/sandbox": "0.7.0",
|
|
47
|
+
"@agenshield/skills": "0.7.0",
|
|
47
48
|
"commander": "^14.0.0",
|
|
48
49
|
"ink": "^5.2.0",
|
|
49
50
|
"ink-spinner": "^5.0.0",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/commands/setup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/commands/setup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6NpC;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAkF5C"}
|
package/src/commands/setup.js
CHANGED
|
@@ -117,9 +117,22 @@ async function runSetupWebUI(wizardOptions) {
|
|
|
117
117
|
const { ensureSudoAccess } = await import('../utils/privileges.js');
|
|
118
118
|
ensureSudoAccess();
|
|
119
119
|
}
|
|
120
|
-
//
|
|
120
|
+
// Kill any existing process on port 5200 (previous daemon / setup server)
|
|
121
|
+
// so the setup server can bind successfully.
|
|
122
|
+
const port = 5200;
|
|
123
|
+
try {
|
|
124
|
+
const { execSync } = await import('node:child_process');
|
|
125
|
+
const pids = execSync(`lsof -ti :${port} 2>/dev/null || true`, { encoding: 'utf-8' }).trim();
|
|
126
|
+
if (pids) {
|
|
127
|
+
console.log(` Stopping existing process on port ${port} (PID: ${pids.split('\n').join(', ')})...`);
|
|
128
|
+
execSync(`lsof -ti :${port} 2>/dev/null | xargs kill -9 2>/dev/null || true`, { encoding: 'utf-8' });
|
|
129
|
+
// Brief wait for port to be released
|
|
130
|
+
await new Promise(r => setTimeout(r, 500));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch { /* ignore — lsof/kill may fail if nothing is listening */ }
|
|
134
|
+
// Create and start the setup server
|
|
121
135
|
const server = createSetupServer(engine);
|
|
122
|
-
const port = 5200; // Setup wizard uses 5200, daemon uses 5200
|
|
123
136
|
const url = await server.start(port);
|
|
124
137
|
console.log(` Setup wizard is running at: ${url}`);
|
|
125
138
|
console.log('');
|
|
@@ -135,16 +148,21 @@ async function runSetupWebUI(wizardOptions) {
|
|
|
135
148
|
// Non-fatal — user can open the URL manually
|
|
136
149
|
}
|
|
137
150
|
// Wait for setup to complete or be cancelled (SIGINT/SIGTERM)
|
|
151
|
+
let interrupted = false;
|
|
138
152
|
const completionOrSignal = Promise.race([
|
|
139
153
|
server.waitForCompletion(),
|
|
140
154
|
new Promise((resolve) => {
|
|
141
|
-
process.on('SIGINT', resolve);
|
|
142
|
-
process.on('SIGTERM', resolve);
|
|
155
|
+
process.on('SIGINT', () => { interrupted = true; resolve(); });
|
|
156
|
+
process.on('SIGTERM', () => { interrupted = true; resolve(); });
|
|
143
157
|
}),
|
|
144
158
|
]);
|
|
145
159
|
await completionOrSignal;
|
|
146
|
-
console.log(' Setup complete! Shutting down server...');
|
|
147
160
|
await server.stop();
|
|
161
|
+
if (interrupted) {
|
|
162
|
+
console.log('\n Setup cancelled.');
|
|
163
|
+
process.exit(130);
|
|
164
|
+
}
|
|
165
|
+
console.log(' Setup complete! Shutting down server...');
|
|
148
166
|
// Stop any existing daemon first
|
|
149
167
|
console.log(' Stopping any existing daemon...');
|
|
150
168
|
const { startDaemon, stopDaemon } = await import('../utils/daemon.js');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/commands/setup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD;;;GAGG;AACH,KAAK,UAAU,yBAAyB,CAAC,OAAkC;IACzE,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;IACpE,gBAAgB,EAAE,CAAC;IAEnB,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAE7B,IAAI,CAAC,KAAK,CAAC,SAAS;QAAE,OAAO,CAAC,2BAA2B;IAEzD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtF,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;YACnD,EAAE,CAAC,QAAQ,CAAC,wDAAwD,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC5E,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,CAAC;YACf,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IAC9E,CAAC;IAED,cAAc;IACd,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC1D,MAAM,UAAU,EAAE,CAAC;IAEnB,kBAAkB;IAClB,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,QAAQ,EAAE,EAAE;QACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,+BAA+B,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,gEAAgE;IAChE,qEAAqE;IACrE,mEAAmE;IACnE,sEAAsE;IACtE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;QACzF,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,QAAQ;IACrB,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC;IACjE,MAAM,aAAa,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAAC,aAA4B;IACvD,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAEvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,oEAAoE;IACpE,MAAM,MAAM,GAAG,kBAAkB,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;IAEzD,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,uBAAuB,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,IAAI,gBAAgB,EAAE,CAAC,CAAC;IAChF,CAAC;SAAM,IAAI,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IACrE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,gGAAgG,CAAC,CAAC;QAChH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,6EAA6E;IAC7E,sEAAsE;IACtE,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;QACpE,gBAAgB,EAAE,CAAC;IACrB,CAAC;IAED,2EAA2E;IAC3E,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,2CAA2C;IAC9D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAErC,OAAO,CAAC,GAAG,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,uBAAuB;IACvB,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACpD,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;IAC/C,CAAC;IAED,8DAA8D;IAC9D,MAAM,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;QACtC,MAAM,CAAC,iBAAiB,EAAE;QAC1B,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC5B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,kBAAkB,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;IACzD,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IAEpB,iCAAiC;IACjC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACvE,MAAM,UAAU,EAAE,CAAC;IAEnB,8CAA8C;IAC9C,IAAI,CAAC;QACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACxD,QAAQ,CAAC,kEAAkE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACpG,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAExB,gCAAgC;IAChC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,MAAM,YAAY,GAAG,MAAM,WAAW,EAAE,CAAC;IACzC,IAAI,YAAY,CAAC,OAAO,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,0BAA0B,YAAY,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,cAAc,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,gCAAgC;IAChC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,OAAgC;IAC1D,MAAM,aAAa,GAAkB,EAAE,CAAC;IACxC,IAAI,OAAO,CAAC,QAAQ,CAAC;QAAE,aAAa,CAAC,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAW,CAAC;IAChF,IAAI,OAAO,CAAC,YAAY,CAAC;QAAE,aAAa,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,CAAW,CAAC;IACtF,IAAI,OAAO,CAAC,UAAU,CAAC;QAAE,aAAa,CAAC,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAW,CAAC;IAChF,IAAI,OAAO,CAAC,QAAQ,CAAC;QAAE,aAAa,CAAC,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAW,CAAC;IAC1E,IAAI,OAAO,CAAC,SAAS,CAAC;QAAE,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC,SAAS,CAAW,CAAC;IAC7E,IAAI,OAAO,CAAC,QAAQ,CAAC;QAAE,aAAa,CAAC,MAAM,GAAG,IAAI,CAAC;IACnD,IAAI,OAAO,CAAC,aAAa,CAAC;QAAE,aAAa,CAAC,WAAW,GAAG,IAAI,CAAC;IAC7D,IAAI,OAAO,CAAC,SAAS,CAAC;QAAE,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;IACrD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;SAC7B,WAAW,CAAC,sDAAsD,CAAC;SACnE,MAAM,CAAC,mBAAmB,EAAE,+DAA+D,CAAC;SAC5F,MAAM,CAAC,sBAAsB,EAAE,8CAA8C,CAAC;SAC9E,MAAM,CAAC,oBAAoB,EAAE,kDAAkD,CAAC;SAChF,MAAM,CAAC,mBAAmB,EAAE,oDAAoD,CAAC;SACjF,MAAM,CAAC,kBAAkB,EAAE,4BAA4B,EAAE,QAAQ,CAAC;SAClE,MAAM,CAAC,WAAW,EAAE,gDAAgD,CAAC;SACrE,MAAM,CAAC,gBAAgB,EAAE,2BAA2B,CAAC;SACrD,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAAC;SAC9C,MAAM,CAAC,gBAAgB,EAAE,iCAAiC,CAAC;SAC3D,MAAM,CAAC,OAAO,EAAE,4CAA4C,CAAC;SAC7D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,wBAAwB;QACxB,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;QAED,2BAA2B;QAC3B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,0BAA0B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;gBAC3D,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,CAAC,CAAC;gBAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,uCAAuC;YACvC,IAAI,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvD,OAAO,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;gBAC7E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;gBAC1B,OAAO,CAAC,KAAK,CAAC,gFAAgF,CAAC,CAAC;gBAChG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,yBAAyB,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QACxE,CAAC;QAED,kEAAkE;QAClE,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,KAAK,OAAO,EAAE,CAAC;YAC1E,OAAO,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YACjD,MAAM,aAAa,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,qDAAqD;QACrD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACpD,CAAC;QACD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;QAC7D,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;QACzD,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QACpD,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,GAAG,MAAM,CAAC;QAC7C,CAAC;QACD,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,GAAG,MAAM,CAAC;QAClD,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,GAAG,MAAM,CAAC;QAC7C,CAAC;QAED,MAAM,QAAQ,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEL,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * Setup command\n *\n * Runs the interactive setup wizard to sandbox a target application.\n * Supports presets (openclaw, custom) and configurable naming.\n * With --ui flag, launches a web-based setup wizard.\n */\n\nimport { Command } from 'commander';\nimport React from 'react';\nimport readline from 'node:readline';\nimport { render } from 'ink';\nimport { WizardApp } from '../wizard/index.js';\nimport { formatPresetList, getPreset } from '@agenshield/sandbox';\nimport { createWizardEngine } from '../wizard/engine.js';\nimport type { WizardOptions } from '../wizard/types.js';\n\n/**\n * Check for an existing AgenShield installation and offer to uninstall it.\n * Equivalent to running `agenshield uninstall --skip-backup --force` before setup.\n */\nasync function checkExistingInstallation(options: { skipConfirm?: boolean }): Promise<void> {\n const { ensureSudoAccess } = await import('../utils/privileges.js');\n ensureSudoAccess();\n\n const { canUninstall, forceUninstall } = await import('@agenshield/sandbox');\n const check = canUninstall();\n\n if (!check.hasBackup) return; // No existing installation\n\n console.log('');\n console.log(' AgenShield is already installed.');\n if (check.backup) {\n console.log(` Backup from: ${check.backup.timestamp}`);\n }\n console.log('');\n\n if (!options.skipConfirm) {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(' Uninstall existing installation and re-setup? [y/N] ', (ans) => {\n rl.close();\n resolve(ans);\n });\n });\n if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {\n console.log('');\n console.log(' Setup cancelled.');\n process.exit(0);\n }\n } else {\n console.log(' --skip-confirm: auto-uninstalling existing installation...');\n }\n\n // Stop daemon\n console.log('');\n console.log(' Stopping daemon...');\n const { stopDaemon } = await import('../utils/daemon.js');\n await stopDaemon();\n\n // Force uninstall\n console.log(' Uninstalling existing installation...');\n console.log('');\n const result = forceUninstall((progress) => {\n const icon = progress.success ? '\\x1b[32m✓\\x1b[0m' : '\\x1b[31m✗\\x1b[0m';\n console.log(` ${icon} ${progress.step}: ${progress.message || progress.error || ''}`);\n });\n\n if (!result.success) {\n console.error('');\n console.error(` \\x1b[31mUninstall failed: ${result.error}\\x1b[0m`);\n process.exit(1);\n }\n\n console.log('');\n console.log(' \\x1b[32mExisting installation removed.\\x1b[0m');\n console.log(' Proceeding with fresh setup...');\n console.log('');\n\n // Re-exec the setup command so it starts fresh after uninstall.\n // All original flags (-v, --target, --skip-confirm, etc.) carry over\n // via process.argv. The re-exec'd process will call canUninstall()\n // again, which returns hasBackup=false (already removed), so no loop.\n const { spawnSync } = await import('node:child_process');\n const child = spawnSync(process.execPath, [...process.execArgv, ...process.argv.slice(1)], {\n stdio: 'inherit',\n env: process.env,\n });\n process.exit(child.status ?? 1);\n}\n\n/**\n * Run the setup wizard (CLI/Ink mode)\n */\nasync function runSetup(): Promise<void> {\n const { waitUntilExit } = render(React.createElement(WizardApp));\n await waitUntilExit();\n}\n\n/**\n * Run the setup wizard in web UI mode\n */\nasync function runSetupWebUI(wizardOptions: WizardOptions): Promise<void> {\n const { createSetupServer } = await import('../setup-server/index.js');\n\n console.log('');\n console.log(' Starting Web UI Setup Wizard...');\n console.log('');\n\n // Create wizard engine and run detection phase BEFORE server starts\n const engine = createWizardEngine(wizardOptions);\n const detectionResult = await engine.runDetectionPhase();\n\n if (!detectionResult.success) {\n console.error(` Detection failed: ${detectionResult.error}`);\n process.exit(1);\n }\n\n if (engine.context.presetDetection?.found) {\n console.log(` Detected: ${engine.context.preset?.name ?? 'Unknown target'}`);\n } else if (engine.context.targetInstallable) {\n console.log(` No target found — Web UI will offer installation.`);\n } else {\n console.error(' No supported target found. Use --target custom --entry-point <path> for custom applications.');\n process.exit(1);\n }\n console.log('');\n\n // Acquire sudo credentials now (in the terminal) before opening the browser,\n // so the setup phase can use cached credentials without a TTY prompt.\n if (!wizardOptions.dryRun) {\n const { ensureSudoAccess } = await import('../utils/privileges.js');\n ensureSudoAccess();\n }\n\n // Create and start the setup server on a different port than daemon (5200)\n const server = createSetupServer(engine);\n const port = 5200; // Setup wizard uses 5200, daemon uses 5200\n const url = await server.start(port);\n\n console.log(` Setup wizard is running at: ${url}`);\n console.log('');\n console.log(' Opening browser...');\n console.log(' (If the browser does not open, visit the URL above manually)');\n console.log('');\n\n // Open browser (macOS)\n try {\n const { exec } = await import('node:child_process');\n exec(`open \"${url}\"`);\n } catch {\n // Non-fatal — user can open the URL manually\n }\n\n // Wait for setup to complete or be cancelled (SIGINT/SIGTERM)\n const completionOrSignal = Promise.race([\n server.waitForCompletion(),\n new Promise<void>((resolve) => {\n process.on('SIGINT', resolve);\n process.on('SIGTERM', resolve);\n }),\n ]);\n\n await completionOrSignal;\n console.log(' Setup complete! Shutting down server...');\n await server.stop();\n\n // Stop any existing daemon first\n console.log(' Stopping any existing daemon...');\n const { startDaemon, stopDaemon } = await import('../utils/daemon.js');\n await stopDaemon();\n\n // Kill any process on port 5200 (daemon port)\n try {\n const { execSync } = await import('node:child_process');\n execSync('lsof -i :5200 -t 2>/dev/null | xargs kill -9 2>/dev/null || true', { encoding: 'utf-8' });\n await new Promise(r => setTimeout(r, 500));\n } catch { /* ignore */ }\n\n // Start the daemon on port 5200\n console.log(' Starting daemon...');\n const daemonResult = await startDaemon();\n if (daemonResult.success) {\n console.log(` Daemon started (PID: ${daemonResult.pid})`);\n console.log(` Dashboard available at: http://localhost:5200`);\n } else {\n console.warn(` Warning: ${daemonResult.message}`);\n }\n\n // Force exit after grace period\n setTimeout(() => process.exit(0), 500).unref();\n}\n\n/**\n * Build WizardOptions from CLI options\n */\nfunction buildWizardOptions(options: Record<string, unknown>): WizardOptions {\n const wizardOptions: WizardOptions = {};\n if (options['target']) wizardOptions.targetPreset = options['target'] as string;\n if (options['entryPoint']) wizardOptions.entryPoint = options['entryPoint'] as string;\n if (options['baseName']) wizardOptions.baseName = options['baseName'] as string;\n if (options['prefix']) wizardOptions.prefix = options['prefix'] as string;\n if (options['baseUid']) wizardOptions.baseUid = options['baseUid'] as number;\n if (options['dryRun']) wizardOptions.dryRun = true;\n if (options['skipConfirm']) wizardOptions.skipConfirm = true;\n if (options['verbose']) wizardOptions.verbose = true;\n return wizardOptions;\n}\n\n/**\n * Create the setup command\n */\nexport function createSetupCommand(): Command {\n const cmd = new Command('setup')\n .description('Run the setup wizard to sandbox a target application')\n .option('--target <preset>', 'Target preset to use: openclaw, custom (default: auto-detect)')\n .option('--entry-point <path>', 'Entry point for custom target (Node.js file)')\n .option('--base-name <name>', 'Base name for users/groups (default: agenshield)')\n .option('--prefix <prefix>', 'Use a custom prefix for users/groups (for testing)')\n .option('--base-uid <uid>', 'Base UID for created users', parseInt)\n .option('--dry-run', 'Show what would be done without making changes')\n .option('--skip-confirm', 'Skip confirmation prompts')\n .option('-v, --verbose', 'Show verbose output')\n .option('--list-presets', 'List available presets and exit')\n .option('--cli', 'Use terminal/Ink UI instead of web browser')\n .action(async (options) => {\n // Handle --list-presets\n if (options.listPresets) {\n console.log(formatPresetList());\n return;\n }\n\n // Validate --target option\n if (options.target) {\n const preset = getPreset(options.target);\n if (!preset) {\n console.error(`Error: Unknown preset '${options.target}'`);\n console.error('');\n console.error(formatPresetList());\n process.exit(1);\n }\n\n // Custom preset requires --entry-point\n if (options.target === 'custom' && !options.entryPoint) {\n console.error('Error: --entry-point is required when using --target custom');\n console.error('');\n console.error('Example:');\n console.error(' agenshield setup --target custom --entry-point /path/to/my-app/dist/index.js');\n process.exit(1);\n }\n }\n\n // Check for existing installation (skip in dry-run mode)\n if (!options.dryRun) {\n await checkExistingInstallation({ skipConfirm: options.skipConfirm });\n }\n\n // Default to Web UI unless --cli is specified or env var opts out\n if (!options.cli && process.env['AGENSHIELD_WEBUI_REQUESTED'] !== 'false') {\n delete process.env['AGENSHIELD_WEBUI_REQUESTED'];\n await runSetupWebUI(buildWizardOptions(options));\n return;\n }\n\n // Store options in environment for wizard to pick up\n if (options.target) {\n process.env['AGENSHIELD_TARGET'] = options.target;\n }\n if (options.entryPoint) {\n process.env['AGENSHIELD_ENTRY_POINT'] = options.entryPoint;\n }\n if (options.baseName) {\n process.env['AGENSHIELD_BASE_NAME'] = options.baseName;\n }\n if (options.prefix) {\n process.env['AGENSHIELD_PREFIX'] = options.prefix;\n }\n if (options.baseUid) {\n process.env['AGENSHIELD_BASE_UID'] = String(options.baseUid);\n }\n if (options.dryRun) {\n process.env['AGENSHIELD_DRY_RUN'] = 'true';\n }\n if (options.skipConfirm) {\n process.env['AGENSHIELD_SKIP_CONFIRM'] = 'true';\n }\n if (options.verbose) {\n process.env['AGENSHIELD_VERBOSE'] = 'true';\n }\n\n await runSetup();\n });\n\n return cmd;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/commands/setup.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Setup command\n *\n * Runs the interactive setup wizard to sandbox a target application.\n * Supports presets (openclaw, custom) and configurable naming.\n * With --ui flag, launches a web-based setup wizard.\n */\n\nimport { Command } from 'commander';\nimport React from 'react';\nimport readline from 'node:readline';\nimport { render } from 'ink';\nimport { WizardApp } from '../wizard/index.js';\nimport { formatPresetList, getPreset } from '@agenshield/sandbox';\nimport { createWizardEngine } from '../wizard/engine.js';\nimport type { WizardOptions } from '../wizard/types.js';\n\n/**\n * Check for an existing AgenShield installation and offer to uninstall it.\n * Equivalent to running `agenshield uninstall --skip-backup --force` before setup.\n */\nasync function checkExistingInstallation(options: { skipConfirm?: boolean }): Promise<void> {\n const { ensureSudoAccess } = await import('../utils/privileges.js');\n ensureSudoAccess();\n\n const { canUninstall, forceUninstall } = await import('@agenshield/sandbox');\n const check = canUninstall();\n\n if (!check.hasBackup) return; // No existing installation\n\n console.log('');\n console.log(' AgenShield is already installed.');\n if (check.backup) {\n console.log(` Backup from: ${check.backup.timestamp}`);\n }\n console.log('');\n\n if (!options.skipConfirm) {\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const answer = await new Promise<string>((resolve) => {\n rl.question(' Uninstall existing installation and re-setup? [y/N] ', (ans) => {\n rl.close();\n resolve(ans);\n });\n });\n if (answer.toLowerCase() !== 'y' && answer.toLowerCase() !== 'yes') {\n console.log('');\n console.log(' Setup cancelled.');\n process.exit(0);\n }\n } else {\n console.log(' --skip-confirm: auto-uninstalling existing installation...');\n }\n\n // Stop daemon\n console.log('');\n console.log(' Stopping daemon...');\n const { stopDaemon } = await import('../utils/daemon.js');\n await stopDaemon();\n\n // Force uninstall\n console.log(' Uninstalling existing installation...');\n console.log('');\n const result = forceUninstall((progress) => {\n const icon = progress.success ? '\\x1b[32m✓\\x1b[0m' : '\\x1b[31m✗\\x1b[0m';\n console.log(` ${icon} ${progress.step}: ${progress.message || progress.error || ''}`);\n });\n\n if (!result.success) {\n console.error('');\n console.error(` \\x1b[31mUninstall failed: ${result.error}\\x1b[0m`);\n process.exit(1);\n }\n\n console.log('');\n console.log(' \\x1b[32mExisting installation removed.\\x1b[0m');\n console.log(' Proceeding with fresh setup...');\n console.log('');\n\n // Re-exec the setup command so it starts fresh after uninstall.\n // All original flags (-v, --target, --skip-confirm, etc.) carry over\n // via process.argv. The re-exec'd process will call canUninstall()\n // again, which returns hasBackup=false (already removed), so no loop.\n const { spawnSync } = await import('node:child_process');\n const child = spawnSync(process.execPath, [...process.execArgv, ...process.argv.slice(1)], {\n stdio: 'inherit',\n env: process.env,\n });\n process.exit(child.status ?? 1);\n}\n\n/**\n * Run the setup wizard (CLI/Ink mode)\n */\nasync function runSetup(): Promise<void> {\n const { waitUntilExit } = render(React.createElement(WizardApp));\n await waitUntilExit();\n}\n\n/**\n * Run the setup wizard in web UI mode\n */\nasync function runSetupWebUI(wizardOptions: WizardOptions): Promise<void> {\n const { createSetupServer } = await import('../setup-server/index.js');\n\n console.log('');\n console.log(' Starting Web UI Setup Wizard...');\n console.log('');\n\n // Create wizard engine and run detection phase BEFORE server starts\n const engine = createWizardEngine(wizardOptions);\n const detectionResult = await engine.runDetectionPhase();\n\n if (!detectionResult.success) {\n console.error(` Detection failed: ${detectionResult.error}`);\n process.exit(1);\n }\n\n if (engine.context.presetDetection?.found) {\n console.log(` Detected: ${engine.context.preset?.name ?? 'Unknown target'}`);\n } else if (engine.context.targetInstallable) {\n console.log(` No target found — Web UI will offer installation.`);\n } else {\n console.error(' No supported target found. Use --target custom --entry-point <path> for custom applications.');\n process.exit(1);\n }\n console.log('');\n\n // Acquire sudo credentials now (in the terminal) before opening the browser,\n // so the setup phase can use cached credentials without a TTY prompt.\n if (!wizardOptions.dryRun) {\n const { ensureSudoAccess } = await import('../utils/privileges.js');\n ensureSudoAccess();\n }\n\n // Kill any existing process on port 5200 (previous daemon / setup server)\n // so the setup server can bind successfully.\n const port = 5200;\n try {\n const { execSync } = await import('node:child_process');\n const pids = execSync(`lsof -ti :${port} 2>/dev/null || true`, { encoding: 'utf-8' }).trim();\n if (pids) {\n console.log(` Stopping existing process on port ${port} (PID: ${pids.split('\\n').join(', ')})...`);\n execSync(`lsof -ti :${port} 2>/dev/null | xargs kill -9 2>/dev/null || true`, { encoding: 'utf-8' });\n // Brief wait for port to be released\n await new Promise(r => setTimeout(r, 500));\n }\n } catch { /* ignore — lsof/kill may fail if nothing is listening */ }\n\n // Create and start the setup server\n const server = createSetupServer(engine);\n const url = await server.start(port);\n\n console.log(` Setup wizard is running at: ${url}`);\n console.log('');\n console.log(' Opening browser...');\n console.log(' (If the browser does not open, visit the URL above manually)');\n console.log('');\n\n // Open browser (macOS)\n try {\n const { exec } = await import('node:child_process');\n exec(`open \"${url}\"`);\n } catch {\n // Non-fatal — user can open the URL manually\n }\n\n // Wait for setup to complete or be cancelled (SIGINT/SIGTERM)\n let interrupted = false;\n const completionOrSignal = Promise.race([\n server.waitForCompletion(),\n new Promise<void>((resolve) => {\n process.on('SIGINT', () => { interrupted = true; resolve(); });\n process.on('SIGTERM', () => { interrupted = true; resolve(); });\n }),\n ]);\n\n await completionOrSignal;\n await server.stop();\n\n if (interrupted) {\n console.log('\\n Setup cancelled.');\n process.exit(130);\n }\n\n console.log(' Setup complete! Shutting down server...');\n\n // Stop any existing daemon first\n console.log(' Stopping any existing daemon...');\n const { startDaemon, stopDaemon } = await import('../utils/daemon.js');\n await stopDaemon();\n\n // Kill any process on port 5200 (daemon port)\n try {\n const { execSync } = await import('node:child_process');\n execSync('lsof -i :5200 -t 2>/dev/null | xargs kill -9 2>/dev/null || true', { encoding: 'utf-8' });\n await new Promise(r => setTimeout(r, 500));\n } catch { /* ignore */ }\n\n // Start the daemon on port 5200\n console.log(' Starting daemon...');\n const daemonResult = await startDaemon();\n if (daemonResult.success) {\n console.log(` Daemon started (PID: ${daemonResult.pid})`);\n console.log(` Dashboard available at: http://localhost:5200`);\n } else {\n console.warn(` Warning: ${daemonResult.message}`);\n }\n\n // Force exit after grace period\n setTimeout(() => process.exit(0), 500).unref();\n}\n\n/**\n * Build WizardOptions from CLI options\n */\nfunction buildWizardOptions(options: Record<string, unknown>): WizardOptions {\n const wizardOptions: WizardOptions = {};\n if (options['target']) wizardOptions.targetPreset = options['target'] as string;\n if (options['entryPoint']) wizardOptions.entryPoint = options['entryPoint'] as string;\n if (options['baseName']) wizardOptions.baseName = options['baseName'] as string;\n if (options['prefix']) wizardOptions.prefix = options['prefix'] as string;\n if (options['baseUid']) wizardOptions.baseUid = options['baseUid'] as number;\n if (options['dryRun']) wizardOptions.dryRun = true;\n if (options['skipConfirm']) wizardOptions.skipConfirm = true;\n if (options['verbose']) wizardOptions.verbose = true;\n return wizardOptions;\n}\n\n/**\n * Create the setup command\n */\nexport function createSetupCommand(): Command {\n const cmd = new Command('setup')\n .description('Run the setup wizard to sandbox a target application')\n .option('--target <preset>', 'Target preset to use: openclaw, custom (default: auto-detect)')\n .option('--entry-point <path>', 'Entry point for custom target (Node.js file)')\n .option('--base-name <name>', 'Base name for users/groups (default: agenshield)')\n .option('--prefix <prefix>', 'Use a custom prefix for users/groups (for testing)')\n .option('--base-uid <uid>', 'Base UID for created users', parseInt)\n .option('--dry-run', 'Show what would be done without making changes')\n .option('--skip-confirm', 'Skip confirmation prompts')\n .option('-v, --verbose', 'Show verbose output')\n .option('--list-presets', 'List available presets and exit')\n .option('--cli', 'Use terminal/Ink UI instead of web browser')\n .action(async (options) => {\n // Handle --list-presets\n if (options.listPresets) {\n console.log(formatPresetList());\n return;\n }\n\n // Validate --target option\n if (options.target) {\n const preset = getPreset(options.target);\n if (!preset) {\n console.error(`Error: Unknown preset '${options.target}'`);\n console.error('');\n console.error(formatPresetList());\n process.exit(1);\n }\n\n // Custom preset requires --entry-point\n if (options.target === 'custom' && !options.entryPoint) {\n console.error('Error: --entry-point is required when using --target custom');\n console.error('');\n console.error('Example:');\n console.error(' agenshield setup --target custom --entry-point /path/to/my-app/dist/index.js');\n process.exit(1);\n }\n }\n\n // Check for existing installation (skip in dry-run mode)\n if (!options.dryRun) {\n await checkExistingInstallation({ skipConfirm: options.skipConfirm });\n }\n\n // Default to Web UI unless --cli is specified or env var opts out\n if (!options.cli && process.env['AGENSHIELD_WEBUI_REQUESTED'] !== 'false') {\n delete process.env['AGENSHIELD_WEBUI_REQUESTED'];\n await runSetupWebUI(buildWizardOptions(options));\n return;\n }\n\n // Store options in environment for wizard to pick up\n if (options.target) {\n process.env['AGENSHIELD_TARGET'] = options.target;\n }\n if (options.entryPoint) {\n process.env['AGENSHIELD_ENTRY_POINT'] = options.entryPoint;\n }\n if (options.baseName) {\n process.env['AGENSHIELD_BASE_NAME'] = options.baseName;\n }\n if (options.prefix) {\n process.env['AGENSHIELD_PREFIX'] = options.prefix;\n }\n if (options.baseUid) {\n process.env['AGENSHIELD_BASE_UID'] = String(options.baseUid);\n }\n if (options.dryRun) {\n process.env['AGENSHIELD_DRY_RUN'] = 'true';\n }\n if (options.skipConfirm) {\n process.env['AGENSHIELD_SKIP_CONFIRM'] = 'true';\n }\n if (options.verbose) {\n process.env['AGENSHIELD_VERBOSE'] = 'true';\n }\n\n await runSetup();\n });\n\n return cmd;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/setup-server/routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/setup-server/routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAU/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,QAAQ,GAAG,iBAAiB,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;CACxE;AAkBD;;GAEG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6W9F"}
|
|
@@ -51,12 +51,17 @@ export async function registerRoutes(app, engine) {
|
|
|
51
51
|
let phase = 'detection';
|
|
52
52
|
const hasConfirm = engine.state.steps.find(s => s.id === 'confirm');
|
|
53
53
|
const hasComplete = engine.state.steps.find(s => s.id === 'complete');
|
|
54
|
+
const verifyStep = engine.state.steps.find(s => s.id === 'verify');
|
|
54
55
|
if (engine.state.isComplete || hasComplete?.status === 'completed') {
|
|
55
56
|
phase = 'complete';
|
|
56
57
|
}
|
|
57
58
|
else if (engine.state.steps.find(s => s.id === 'setup-passcode')?.status === 'running') {
|
|
58
59
|
phase = 'passcode';
|
|
59
60
|
}
|
|
61
|
+
else if (verifyStep?.status === 'completed') {
|
|
62
|
+
// Setup and verification done, waiting for passcode
|
|
63
|
+
phase = 'passcode';
|
|
64
|
+
}
|
|
60
65
|
else if (hasConfirm?.status === 'completed') {
|
|
61
66
|
phase = 'execution';
|
|
62
67
|
}
|
|
@@ -70,6 +75,7 @@ export async function registerRoutes(app, engine) {
|
|
|
70
75
|
context: sanitizeContext(engine.context),
|
|
71
76
|
phase,
|
|
72
77
|
targetInstallable: engine.context.targetInstallable ?? false,
|
|
78
|
+
scanResult: engine.context.scanResult ?? null,
|
|
73
79
|
},
|
|
74
80
|
};
|
|
75
81
|
});
|
|
@@ -183,6 +189,8 @@ export async function registerRoutes(app, engine) {
|
|
|
183
189
|
}
|
|
184
190
|
isRunning = true;
|
|
185
191
|
// Run setup phase asynchronously — progress streams via SSE
|
|
192
|
+
// Setup phase now stops after scan-source, broadcasting scan_complete
|
|
193
|
+
// so the UI can show the selection step.
|
|
186
194
|
engine.runSetupPhase().then(() => {
|
|
187
195
|
isRunning = false;
|
|
188
196
|
if (engine.state.hasError) {
|
|
@@ -191,6 +199,14 @@ export async function registerRoutes(app, engine) {
|
|
|
191
199
|
context: sanitizeContext(engine.context),
|
|
192
200
|
});
|
|
193
201
|
}
|
|
202
|
+
else {
|
|
203
|
+
// Setup phase completed (scan-source done) — broadcast scan result
|
|
204
|
+
broadcastSetupEvent('setup:scan_complete', {
|
|
205
|
+
state: engine.state,
|
|
206
|
+
context: sanitizeContext(engine.context),
|
|
207
|
+
scanResult: engine.context.scanResult ?? null,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
194
210
|
}).catch((err) => {
|
|
195
211
|
isRunning = false;
|
|
196
212
|
broadcastSetupEvent('setup:error', {
|
|
@@ -228,6 +244,57 @@ export async function registerRoutes(app, engine) {
|
|
|
228
244
|
});
|
|
229
245
|
return { success: true, data: { started: true } };
|
|
230
246
|
});
|
|
247
|
+
// --- Scan result (returns the scan from scan-source step) ---
|
|
248
|
+
app.get('/api/setup/scan-result', async () => {
|
|
249
|
+
if (!engine.context.scanResult) {
|
|
250
|
+
return {
|
|
251
|
+
success: false,
|
|
252
|
+
error: { code: 'NOT_READY', message: 'Scan has not completed yet' },
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
success: true,
|
|
257
|
+
data: engine.context.scanResult,
|
|
258
|
+
};
|
|
259
|
+
});
|
|
260
|
+
// --- Select items and trigger migration phase ---
|
|
261
|
+
app.post('/api/setup/select-items', async (request) => {
|
|
262
|
+
if (isRunning) {
|
|
263
|
+
return { success: false, error: { code: 'ALREADY_RUNNING', message: 'An operation is already in progress' } };
|
|
264
|
+
}
|
|
265
|
+
const { selectedSkills, selectedEnvVars } = request.body;
|
|
266
|
+
// Store user's selection in context
|
|
267
|
+
engine.context.migrationSelection = {
|
|
268
|
+
selectedSkills: selectedSkills ?? [],
|
|
269
|
+
selectedEnvVars: selectedEnvVars ?? [],
|
|
270
|
+
};
|
|
271
|
+
isRunning = true;
|
|
272
|
+
// Run migration phase asynchronously (select-items + migrate + verify)
|
|
273
|
+
engine.runMigrationPhase().then(() => {
|
|
274
|
+
isRunning = false;
|
|
275
|
+
if (engine.state.hasError) {
|
|
276
|
+
broadcastSetupEvent('setup:error', {
|
|
277
|
+
state: engine.state,
|
|
278
|
+
context: sanitizeContext(engine.context),
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Migration complete — broadcast state change so UI advances to passcode
|
|
283
|
+
broadcastSetupEvent('setup:state_change', {
|
|
284
|
+
state: engine.state,
|
|
285
|
+
context: sanitizeContext(engine.context),
|
|
286
|
+
phase: 'passcode',
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}).catch((err) => {
|
|
290
|
+
isRunning = false;
|
|
291
|
+
broadcastSetupEvent('setup:error', {
|
|
292
|
+
error: err.message,
|
|
293
|
+
state: engine.state,
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
return { success: true, data: { started: true } };
|
|
297
|
+
});
|
|
231
298
|
// --- Executables scan (using shared discovery module) ---
|
|
232
299
|
let discoveryCache = null;
|
|
233
300
|
const EXEC_CACHE_TTL = 60_000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/setup-server/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * REST API routes for the setup server\n *\n * Wraps the existing WizardEngine with HTTP endpoints and streams\n * engine.onStateChange as SSE events.\n */\n\nimport type { FastifyInstance } from 'fastify';\nimport {\n createUserConfig,\n createPathsConfig,\n userExists,\n groupExists,\n scanDiscovery,\n autoDetectPreset,\n} from '@agenshield/sandbox';\nimport type { WizardEngine } from '../wizard/engine.js';\nimport type { WizardState, WizardContext, WizardStepId } from '../wizard/types.js';\nimport { computeNames } from '../wizard/components/AdvancedConfig.js';\nimport { broadcastSetupEvent } from './sse.js';\n\nexport interface ExecutableInfo {\n name: string;\n path: string;\n dir: string;\n isProxied: boolean;\n isWrapped: boolean;\n isAllowed: boolean;\n category: 'system' | 'package-manager' | 'network' | 'shell' | 'other';\n}\n\n/**\n * Sanitize context for API response — strip non-serializable and sensitive data\n */\nfunction sanitizeContext(context: WizardContext): Record<string, unknown> {\n const { preset, passcodeValue, ...rest } = context as Record<string, unknown>;\n return {\n ...rest,\n // Add serializable preset info\n presetName: (context.preset as { name?: string } | undefined)?.name ?? null,\n presetId: (context.preset as { id?: string } | undefined)?.id ?? null,\n };\n}\n\n/** Race guard — prevent double-triggering async phases */\nlet isRunning = false;\n\n/**\n * Register all setup API routes\n */\nexport async function registerRoutes(app: FastifyInstance, engine: WizardEngine): Promise<void> {\n // --- Health ---\n app.get('/api/health', async () => {\n return {\n success: true,\n data: {\n ok: true,\n timestamp: new Date().toISOString(),\n mode: 'setup' as const,\n },\n };\n });\n\n // --- Auth status (fake — no auth needed for setup) ---\n app.get('/api/auth/status', async () => {\n return {\n protectionEnabled: false,\n passcodeSet: false,\n allowAnonymousReadOnly: true,\n lockedOut: false,\n };\n });\n\n // --- Setup state ---\n app.get('/api/setup/state', async () => {\n // Determine phase\n let phase: string = 'detection';\n const hasConfirm = engine.state.steps.find(s => s.id === 'confirm');\n const hasComplete = engine.state.steps.find(s => s.id === 'complete');\n\n if (engine.state.isComplete || hasComplete?.status === 'completed') {\n phase = 'complete';\n } else if (engine.state.steps.find(s => s.id === 'setup-passcode')?.status === 'running') {\n phase = 'passcode';\n } else if (hasConfirm?.status === 'completed') {\n phase = 'execution';\n } else if (engine.context.presetDetection?.found) {\n phase = 'configuration';\n }\n\n return {\n success: true,\n data: {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase,\n targetInstallable: engine.context.targetInstallable ?? false,\n },\n };\n });\n\n // --- Configure (set mode + baseName) ---\n app.post<{ Body: { mode: 'quick' | 'advanced'; baseName?: string } }>(\n '/api/setup/configure',\n async (request) => {\n const { mode, baseName } = request.body;\n\n const effectiveBaseName = mode === 'quick' ? 'default' : (baseName || 'default');\n\n // Update engine context\n engine.context.options = {\n ...engine.context.options,\n baseName: effectiveBaseName,\n };\n\n // Create user config\n const userConfig = createUserConfig({ baseName: effectiveBaseName });\n engine.context.userConfig = userConfig;\n engine.context.pathsConfig = createPathsConfig(userConfig);\n\n const names = computeNames(effectiveBaseName);\n\n broadcastSetupEvent('setup:state_change', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase: 'configuration',\n });\n\n return {\n success: true,\n data: { mode, baseName: effectiveBaseName, names },\n };\n },\n );\n\n // --- Check conflicts ---\n app.post<{ Body: { baseName: string } }>(\n '/api/setup/check-conflicts',\n async (request) => {\n const { baseName } = request.body;\n const names = computeNames(baseName);\n\n const existingUsers: string[] = [];\n const existingGroups: string[] = [];\n\n if (await userExists(names.agentUser)) existingUsers.push(names.agentUser);\n if (await userExists(names.brokerUser)) existingUsers.push(names.brokerUser);\n if (await groupExists(names.socketGroup)) existingGroups.push(names.socketGroup);\n if (await groupExists(names.workspaceGroup)) existingGroups.push(names.workspaceGroup);\n\n return {\n success: true,\n data: {\n hasConflicts: existingUsers.length > 0 || existingGroups.length > 0,\n users: existingUsers,\n groups: existingGroups,\n names,\n },\n };\n },\n );\n\n // --- Install target (npm install -g openclaw) ---\n app.post('/api/setup/install-target', async () => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'An operation is already in progress' } };\n }\n\n isRunning = true;\n\n try {\n const { execSync } = await import('node:child_process');\n execSync('npm install -g openclaw', {\n encoding: 'utf-8',\n timeout: 120_000,\n stdio: 'pipe',\n });\n\n // Re-run detection\n const result = await autoDetectPreset();\n if (!result) {\n isRunning = false;\n return {\n success: false,\n error: { code: 'DETECT_FAILED', message: 'openclaw was installed but could not be detected. Check your PATH.' },\n };\n }\n\n // Update engine context\n engine.context.preset = result.preset;\n engine.context.presetDetection = result.detection;\n engine.context.targetInstallable = false;\n engine.context.installTargetRequested = true;\n\n // Update step statuses\n const installTargetStep = engine.state.steps.find(s => s.id === 'install-target');\n if (installTargetStep) {\n installTargetStep.status = 'completed';\n }\n\n broadcastSetupEvent('setup:state_change', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase: 'detection',\n });\n\n isRunning = false;\n\n return {\n success: true,\n data: {\n installed: true,\n preset: result.preset.name,\n version: result.detection.version,\n },\n };\n } catch (err) {\n isRunning = false;\n return {\n success: false,\n error: { code: 'INSTALL_FAILED', message: (err as Error).message },\n };\n }\n });\n\n // --- Confirm (triggers setup phase) ---\n app.post('/api/setup/confirm', async () => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'Setup is already in progress' } };\n }\n\n isRunning = true;\n\n // Run setup phase asynchronously — progress streams via SSE\n engine.runSetupPhase().then(() => {\n isRunning = false;\n if (engine.state.hasError) {\n broadcastSetupEvent('setup:error', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n });\n }\n }).catch((err) => {\n isRunning = false;\n broadcastSetupEvent('setup:error', {\n error: (err as Error).message,\n state: engine.state,\n });\n });\n\n return { success: true, data: { started: true } };\n });\n\n // --- Passcode (triggers final phase) ---\n app.post<{ Body: { passcode?: string; skip?: boolean } }>(\n '/api/setup/passcode',\n async (request) => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'Final phase is already in progress' } };\n }\n\n const { passcode, skip } = request.body;\n\n if (skip) {\n engine.context.passcodeSetup = { configured: false, skipped: true };\n } else if (passcode) {\n engine.context.passcodeValue = passcode;\n }\n\n isRunning = true;\n\n engine.runFinalPhase().then(() => {\n isRunning = false;\n broadcastSetupEvent('setup:complete', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n });\n }).catch((err) => {\n isRunning = false;\n broadcastSetupEvent('setup:error', {\n error: (err as Error).message,\n state: engine.state,\n });\n });\n\n return { success: true, data: { started: true } };\n },\n );\n\n // --- Executables scan (using shared discovery module) ---\n let discoveryCache: { data: ReturnType<typeof scanDiscovery>; cachedAt: number } | null = null;\n const EXEC_CACHE_TTL = 60_000;\n\n app.get('/api/setup/executables', async () => {\n const now = Date.now();\n if (discoveryCache && now - discoveryCache.cachedAt < EXEC_CACHE_TTL) {\n const result = discoveryCache.data;\n return {\n success: true,\n data: {\n discovery: result,\n executables: result.binaries.map((b) => ({\n name: b.name,\n path: b.path,\n dir: b.dir,\n isProxied: b.protection === 'proxied',\n isWrapped: b.protection === 'wrapped',\n isAllowed: b.protection === 'allowed',\n category: b.category === 'language-runtime' ? 'other' : b.category,\n })),\n },\n };\n }\n\n const result = scanDiscovery({\n scanSkills: !!engine.context.presetDetection?.found,\n agentHome: engine.context.userConfig?.agentUser?.home,\n workspaceDir: engine.context.userConfig\n ? `${engine.context.userConfig.agentUser.home}/workspace`\n : undefined,\n });\n\n discoveryCache = { data: result, cachedAt: now };\n\n return {\n success: true,\n data: {\n discovery: result,\n executables: result.binaries.map((b) => ({\n name: b.name,\n path: b.path,\n dir: b.dir,\n isProxied: b.protection === 'proxied',\n isWrapped: b.protection === 'wrapped',\n isAllowed: b.protection === 'allowed',\n category: b.category === 'language-runtime' ? 'other' : b.category,\n })),\n },\n };\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/setup-server/routes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * REST API routes for the setup server\n *\n * Wraps the existing WizardEngine with HTTP endpoints and streams\n * engine.onStateChange as SSE events.\n */\n\nimport type { FastifyInstance } from 'fastify';\nimport {\n createUserConfig,\n createPathsConfig,\n userExists,\n groupExists,\n scanDiscovery,\n autoDetectPreset,\n} from '@agenshield/sandbox';\nimport type { MigrationSelection } from '@agenshield/ipc';\nimport type { WizardEngine } from '../wizard/engine.js';\nimport type { WizardState, WizardContext, WizardStepId } from '../wizard/types.js';\nimport { computeNames } from '../wizard/components/AdvancedConfig.js';\nimport { broadcastSetupEvent } from './sse.js';\n\nexport interface ExecutableInfo {\n name: string;\n path: string;\n dir: string;\n isProxied: boolean;\n isWrapped: boolean;\n isAllowed: boolean;\n category: 'system' | 'package-manager' | 'network' | 'shell' | 'other';\n}\n\n/**\n * Sanitize context for API response — strip non-serializable and sensitive data\n */\nfunction sanitizeContext(context: WizardContext): Record<string, unknown> {\n const { preset, passcodeValue, ...rest } = context as Record<string, unknown>;\n return {\n ...rest,\n // Add serializable preset info\n presetName: (context.preset as { name?: string } | undefined)?.name ?? null,\n presetId: (context.preset as { id?: string } | undefined)?.id ?? null,\n };\n}\n\n/** Race guard — prevent double-triggering async phases */\nlet isRunning = false;\n\n/**\n * Register all setup API routes\n */\nexport async function registerRoutes(app: FastifyInstance, engine: WizardEngine): Promise<void> {\n // --- Health ---\n app.get('/api/health', async () => {\n return {\n success: true,\n data: {\n ok: true,\n timestamp: new Date().toISOString(),\n mode: 'setup' as const,\n },\n };\n });\n\n // --- Auth status (fake — no auth needed for setup) ---\n app.get('/api/auth/status', async () => {\n return {\n protectionEnabled: false,\n passcodeSet: false,\n allowAnonymousReadOnly: true,\n lockedOut: false,\n };\n });\n\n // --- Setup state ---\n app.get('/api/setup/state', async () => {\n // Determine phase\n let phase: string = 'detection';\n const hasConfirm = engine.state.steps.find(s => s.id === 'confirm');\n const hasComplete = engine.state.steps.find(s => s.id === 'complete');\n const verifyStep = engine.state.steps.find(s => s.id === 'verify');\n\n if (engine.state.isComplete || hasComplete?.status === 'completed') {\n phase = 'complete';\n } else if (engine.state.steps.find(s => s.id === 'setup-passcode')?.status === 'running') {\n phase = 'passcode';\n } else if (verifyStep?.status === 'completed') {\n // Setup and verification done, waiting for passcode\n phase = 'passcode';\n } else if (hasConfirm?.status === 'completed') {\n phase = 'execution';\n } else if (engine.context.presetDetection?.found) {\n phase = 'configuration';\n }\n\n return {\n success: true,\n data: {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase,\n targetInstallable: engine.context.targetInstallable ?? false,\n scanResult: engine.context.scanResult ?? null,\n },\n };\n });\n\n // --- Configure (set mode + baseName) ---\n app.post<{ Body: { mode: 'quick' | 'advanced'; baseName?: string } }>(\n '/api/setup/configure',\n async (request) => {\n const { mode, baseName } = request.body;\n\n const effectiveBaseName = mode === 'quick' ? 'default' : (baseName || 'default');\n\n // Update engine context\n engine.context.options = {\n ...engine.context.options,\n baseName: effectiveBaseName,\n };\n\n // Create user config\n const userConfig = createUserConfig({ baseName: effectiveBaseName });\n engine.context.userConfig = userConfig;\n engine.context.pathsConfig = createPathsConfig(userConfig);\n\n const names = computeNames(effectiveBaseName);\n\n broadcastSetupEvent('setup:state_change', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase: 'configuration',\n });\n\n return {\n success: true,\n data: { mode, baseName: effectiveBaseName, names },\n };\n },\n );\n\n // --- Check conflicts ---\n app.post<{ Body: { baseName: string } }>(\n '/api/setup/check-conflicts',\n async (request) => {\n const { baseName } = request.body;\n const names = computeNames(baseName);\n\n const existingUsers: string[] = [];\n const existingGroups: string[] = [];\n\n if (await userExists(names.agentUser)) existingUsers.push(names.agentUser);\n if (await userExists(names.brokerUser)) existingUsers.push(names.brokerUser);\n if (await groupExists(names.socketGroup)) existingGroups.push(names.socketGroup);\n if (await groupExists(names.workspaceGroup)) existingGroups.push(names.workspaceGroup);\n\n return {\n success: true,\n data: {\n hasConflicts: existingUsers.length > 0 || existingGroups.length > 0,\n users: existingUsers,\n groups: existingGroups,\n names,\n },\n };\n },\n );\n\n // --- Install target (npm install -g openclaw) ---\n app.post('/api/setup/install-target', async () => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'An operation is already in progress' } };\n }\n\n isRunning = true;\n\n try {\n const { execSync } = await import('node:child_process');\n execSync('npm install -g openclaw', {\n encoding: 'utf-8',\n timeout: 120_000,\n stdio: 'pipe',\n });\n\n // Re-run detection\n const result = await autoDetectPreset();\n if (!result) {\n isRunning = false;\n return {\n success: false,\n error: { code: 'DETECT_FAILED', message: 'openclaw was installed but could not be detected. Check your PATH.' },\n };\n }\n\n // Update engine context\n engine.context.preset = result.preset;\n engine.context.presetDetection = result.detection;\n engine.context.targetInstallable = false;\n engine.context.installTargetRequested = true;\n\n // Update step statuses\n const installTargetStep = engine.state.steps.find(s => s.id === 'install-target');\n if (installTargetStep) {\n installTargetStep.status = 'completed';\n }\n\n broadcastSetupEvent('setup:state_change', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase: 'detection',\n });\n\n isRunning = false;\n\n return {\n success: true,\n data: {\n installed: true,\n preset: result.preset.name,\n version: result.detection.version,\n },\n };\n } catch (err) {\n isRunning = false;\n return {\n success: false,\n error: { code: 'INSTALL_FAILED', message: (err as Error).message },\n };\n }\n });\n\n // --- Confirm (triggers setup phase) ---\n app.post('/api/setup/confirm', async () => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'Setup is already in progress' } };\n }\n\n isRunning = true;\n\n // Run setup phase asynchronously — progress streams via SSE\n // Setup phase now stops after scan-source, broadcasting scan_complete\n // so the UI can show the selection step.\n engine.runSetupPhase().then(() => {\n isRunning = false;\n if (engine.state.hasError) {\n broadcastSetupEvent('setup:error', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n });\n } else {\n // Setup phase completed (scan-source done) — broadcast scan result\n broadcastSetupEvent('setup:scan_complete', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n scanResult: engine.context.scanResult ?? null,\n });\n }\n }).catch((err) => {\n isRunning = false;\n broadcastSetupEvent('setup:error', {\n error: (err as Error).message,\n state: engine.state,\n });\n });\n\n return { success: true, data: { started: true } };\n });\n\n // --- Passcode (triggers final phase) ---\n app.post<{ Body: { passcode?: string; skip?: boolean } }>(\n '/api/setup/passcode',\n async (request) => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'Final phase is already in progress' } };\n }\n\n const { passcode, skip } = request.body;\n\n if (skip) {\n engine.context.passcodeSetup = { configured: false, skipped: true };\n } else if (passcode) {\n engine.context.passcodeValue = passcode;\n }\n\n isRunning = true;\n\n engine.runFinalPhase().then(() => {\n isRunning = false;\n broadcastSetupEvent('setup:complete', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n });\n }).catch((err) => {\n isRunning = false;\n broadcastSetupEvent('setup:error', {\n error: (err as Error).message,\n state: engine.state,\n });\n });\n\n return { success: true, data: { started: true } };\n },\n );\n\n // --- Scan result (returns the scan from scan-source step) ---\n app.get('/api/setup/scan-result', async () => {\n if (!engine.context.scanResult) {\n return {\n success: false,\n error: { code: 'NOT_READY', message: 'Scan has not completed yet' },\n };\n }\n\n return {\n success: true,\n data: engine.context.scanResult,\n };\n });\n\n // --- Select items and trigger migration phase ---\n app.post<{ Body: MigrationSelection }>(\n '/api/setup/select-items',\n async (request) => {\n if (isRunning) {\n return { success: false, error: { code: 'ALREADY_RUNNING', message: 'An operation is already in progress' } };\n }\n\n const { selectedSkills, selectedEnvVars } = request.body;\n\n // Store user's selection in context\n engine.context.migrationSelection = {\n selectedSkills: selectedSkills ?? [],\n selectedEnvVars: selectedEnvVars ?? [],\n };\n\n isRunning = true;\n\n // Run migration phase asynchronously (select-items + migrate + verify)\n engine.runMigrationPhase().then(() => {\n isRunning = false;\n if (engine.state.hasError) {\n broadcastSetupEvent('setup:error', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n });\n } else {\n // Migration complete — broadcast state change so UI advances to passcode\n broadcastSetupEvent('setup:state_change', {\n state: engine.state,\n context: sanitizeContext(engine.context),\n phase: 'passcode',\n });\n }\n }).catch((err) => {\n isRunning = false;\n broadcastSetupEvent('setup:error', {\n error: (err as Error).message,\n state: engine.state,\n });\n });\n\n return { success: true, data: { started: true } };\n },\n );\n\n // --- Executables scan (using shared discovery module) ---\n let discoveryCache: { data: ReturnType<typeof scanDiscovery>; cachedAt: number } | null = null;\n const EXEC_CACHE_TTL = 60_000;\n\n app.get('/api/setup/executables', async () => {\n const now = Date.now();\n if (discoveryCache && now - discoveryCache.cachedAt < EXEC_CACHE_TTL) {\n const result = discoveryCache.data;\n return {\n success: true,\n data: {\n discovery: result,\n executables: result.binaries.map((b) => ({\n name: b.name,\n path: b.path,\n dir: b.dir,\n isProxied: b.protection === 'proxied',\n isWrapped: b.protection === 'wrapped',\n isAllowed: b.protection === 'allowed',\n category: b.category === 'language-runtime' ? 'other' : b.category,\n })),\n },\n };\n }\n\n const result = scanDiscovery({\n scanSkills: !!engine.context.presetDetection?.found,\n agentHome: engine.context.userConfig?.agentUser?.home,\n workspaceDir: engine.context.userConfig\n ? `${engine.context.userConfig.agentUser.home}/workspace`\n : undefined,\n });\n\n discoveryCache = { data: result, cachedAt: now };\n\n return {\n success: true,\n data: {\n discovery: result,\n executables: result.binaries.map((b) => ({\n name: b.name,\n path: b.path,\n dir: b.dir,\n isProxied: b.protection === 'proxied',\n isWrapped: b.protection === 'wrapped',\n isAllowed: b.protection === 'allowed',\n category: b.category === 'language-runtime' ? 'other' : b.category,\n })),\n },\n };\n });\n}\n"]}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Auto-shuts down 5s after completion or 5min idle (no SSE connections).
|
|
8
8
|
*/
|
|
9
|
-
import type
|
|
9
|
+
import { type WizardEngine } from '../wizard/engine.js';
|
|
10
10
|
export interface SetupServer {
|
|
11
11
|
start(port: number): Promise<string>;
|
|
12
12
|
stop(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/setup-server/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/setup-server/server.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,EAAE,KAAK,YAAY,EAAwB,MAAM,qBAAqB,CAAC;AAS9E,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CA+HnE"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import Fastify from 'fastify';
|
|
10
10
|
import cors from '@fastify/cors';
|
|
11
11
|
import fastifyStatic from '@fastify/static';
|
|
12
|
+
import { setEngineLogCallback } from '../wizard/engine.js';
|
|
12
13
|
import { registerRoutes } from './routes.js';
|
|
13
14
|
import { registerSSE, broadcastSetupEvent, getActiveConnections, closeAllSSEConnections } from './sse.js';
|
|
14
15
|
import { getUiAssetsPath } from './static.js';
|
|
@@ -21,6 +22,10 @@ export function createSetupServer(engine) {
|
|
|
21
22
|
let idleTimer = null;
|
|
22
23
|
let lastActivity = Date.now();
|
|
23
24
|
let isComplete = false;
|
|
25
|
+
// Wire engine verbose logs to SSE broadcast
|
|
26
|
+
setEngineLogCallback((message, stepId) => {
|
|
27
|
+
broadcastSetupEvent('setup:log', { message, stepId, timestamp: new Date().toISOString() });
|
|
28
|
+
});
|
|
24
29
|
// Wire engine state changes to SSE broadcast
|
|
25
30
|
const originalOnStateChange = engine.onStateChange;
|
|
26
31
|
engine.onStateChange = (state) => {
|
|
@@ -104,6 +109,7 @@ export function createSetupServer(engine) {
|
|
|
104
109
|
return url;
|
|
105
110
|
},
|
|
106
111
|
async stop() {
|
|
112
|
+
setEngineLogCallback(undefined);
|
|
107
113
|
if (idleTimer) {
|
|
108
114
|
clearInterval(idleTimer);
|
|
109
115
|
idleTimer = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/setup-server/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Setup server lifecycle\n *\n * Fastify server that wraps the WizardEngine with HTTP endpoints,\n * serves the shield-ui SPA, and streams state changes via SSE.\n *\n * Auto-shuts down 5s after completion or 5min idle (no SSE connections).\n */\n\nimport Fastify, { type FastifyInstance } from 'fastify';\nimport cors from '@fastify/cors';\nimport fastifyStatic from '@fastify/static';\nimport type { WizardEngine } from '../wizard/engine.js';\nimport { registerRoutes } from './routes.js';\nimport { registerSSE, broadcastSetupEvent, getActiveConnections, closeAllSSEConnections } from './sse.js';\nimport { getUiAssetsPath } from './static.js';\n\nconst IDLE_TIMEOUT = 5 * 60 * 1000; // 5 minutes\nconst SHUTDOWN_DELAY = 5_000; // 5 seconds after completion\nconst IDLE_CHECK_INTERVAL = 30_000; // Check idle every 30s\n\nexport interface SetupServer {\n start(port: number): Promise<string>;\n stop(): Promise<void>;\n waitForCompletion(): Promise<void>;\n}\n\nexport function createSetupServer(engine: WizardEngine): SetupServer {\n let app: FastifyInstance | null = null;\n let completionResolve: (() => void) | null = null;\n let idleTimer: ReturnType<typeof setInterval> | null = null;\n let lastActivity = Date.now();\n let isComplete = false;\n\n // Wire engine state changes to SSE broadcast\n const originalOnStateChange = engine.onStateChange;\n engine.onStateChange = (state) => {\n lastActivity = Date.now();\n originalOnStateChange?.(state);\n\n broadcastSetupEvent('setup:state_change', {\n state,\n phase: state.isComplete ? 'complete' : 'execution',\n });\n\n // Auto-shutdown after completion\n if (state.isComplete && !isComplete) {\n isComplete = true;\n setTimeout(() => {\n completionResolve?.();\n }, SHUTDOWN_DELAY);\n }\n };\n\n return {\n async start(port: number): Promise<string> {\n app = Fastify({ logger: false });\n\n // CORS\n await app.register(cors, { origin: true, methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'] });\n\n // Request logging\n app.addHook('onResponse', (request, reply, done) => {\n if (!request.url.startsWith('/sse') && !request.url.includes('.') && !request.url.endsWith('/health')) {\n const ms = Math.round(reply.elapsedTime);\n const status = reply.statusCode;\n const color = status >= 400 ? '\\x1b[31m' : status >= 300 ? '\\x1b[33m' : '\\x1b[32m';\n console.log(`${color}${request.method}\\x1b[0m ${request.url} \\x1b[2m${status} ${ms}ms\\x1b[0m`);\n }\n done();\n });\n\n // Error handler — log details and send structured response\n app.setErrorHandler((error: { statusCode?: number; message: string }, request, reply) => {\n const status = error.statusCode ?? 500;\n console.error(`\\x1b[31mERROR\\x1b[0m ${request.method} ${request.url} \\x1b[2m${status}\\x1b[0m — ${error.message}`);\n reply.status(status).send({\n success: false,\n error: { message: error.message, statusCode: status },\n });\n });\n\n // API routes\n await registerRoutes(app, engine);\n\n // SSE endpoint\n await registerSSE(app);\n\n // Serve static UI assets\n const uiPath = getUiAssetsPath();\n if (uiPath) {\n await app.register(fastifyStatic, {\n root: uiPath,\n prefix: '/',\n });\n\n // SPA fallback: non-/api and non-/sse paths serve index.html\n app.setNotFoundHandler(async (request, reply) => {\n if (request.url.startsWith('/api') || request.url.startsWith('/sse') || request.url.startsWith('/rpc')) {\n return reply.code(404).send({ error: 'Not found' });\n }\n return reply.sendFile('index.html');\n });\n } else {\n // No UI assets found — still serve the API\n app.setNotFoundHandler(async (_request, reply) => {\n return reply.code(404).send({\n error: 'UI assets not found. Build shield-ui first: npx nx build shield-ui',\n });\n });\n }\n\n // Start idle-timeout checker\n idleTimer = setInterval(() => {\n const idleTime = Date.now() - lastActivity;\n const connections = getActiveConnections();\n if (connections === 0 && idleTime > IDLE_TIMEOUT) {\n console.log('Setup server idle timeout — shutting down');\n completionResolve?.();\n }\n }, IDLE_CHECK_INTERVAL);\n\n // Listen on localhost only\n await app.listen({ port, host: '127.0.0.1' });\n\n const url = `http://localhost:${port}`;\n return url;\n },\n\n async stop(): Promise<void> {\n if (idleTimer) {\n clearInterval(idleTimer);\n idleTimer = null;\n }\n // Close SSE connections first so Fastify doesn't wait for them\n closeAllSSEConnections();\n if (app) {\n await app.close();\n app = null;\n }\n },\n\n waitForCompletion(): Promise<void> {\n return new Promise((resolve) => {\n completionResolve = resolve;\n });\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/setup-server/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Setup server lifecycle\n *\n * Fastify server that wraps the WizardEngine with HTTP endpoints,\n * serves the shield-ui SPA, and streams state changes via SSE.\n *\n * Auto-shuts down 5s after completion or 5min idle (no SSE connections).\n */\n\nimport Fastify, { type FastifyInstance } from 'fastify';\nimport cors from '@fastify/cors';\nimport fastifyStatic from '@fastify/static';\nimport { type WizardEngine, setEngineLogCallback } from '../wizard/engine.js';\nimport { registerRoutes } from './routes.js';\nimport { registerSSE, broadcastSetupEvent, getActiveConnections, closeAllSSEConnections } from './sse.js';\nimport { getUiAssetsPath } from './static.js';\n\nconst IDLE_TIMEOUT = 5 * 60 * 1000; // 5 minutes\nconst SHUTDOWN_DELAY = 5_000; // 5 seconds after completion\nconst IDLE_CHECK_INTERVAL = 30_000; // Check idle every 30s\n\nexport interface SetupServer {\n start(port: number): Promise<string>;\n stop(): Promise<void>;\n waitForCompletion(): Promise<void>;\n}\n\nexport function createSetupServer(engine: WizardEngine): SetupServer {\n let app: FastifyInstance | null = null;\n let completionResolve: (() => void) | null = null;\n let idleTimer: ReturnType<typeof setInterval> | null = null;\n let lastActivity = Date.now();\n let isComplete = false;\n\n // Wire engine verbose logs to SSE broadcast\n setEngineLogCallback((message, stepId) => {\n broadcastSetupEvent('setup:log', { message, stepId, timestamp: new Date().toISOString() });\n });\n\n // Wire engine state changes to SSE broadcast\n const originalOnStateChange = engine.onStateChange;\n engine.onStateChange = (state) => {\n lastActivity = Date.now();\n originalOnStateChange?.(state);\n\n broadcastSetupEvent('setup:state_change', {\n state,\n phase: state.isComplete ? 'complete' : 'execution',\n });\n\n // Auto-shutdown after completion\n if (state.isComplete && !isComplete) {\n isComplete = true;\n setTimeout(() => {\n completionResolve?.();\n }, SHUTDOWN_DELAY);\n }\n };\n\n return {\n async start(port: number): Promise<string> {\n app = Fastify({ logger: false });\n\n // CORS\n await app.register(cors, { origin: true, methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'] });\n\n // Request logging\n app.addHook('onResponse', (request, reply, done) => {\n if (!request.url.startsWith('/sse') && !request.url.includes('.') && !request.url.endsWith('/health')) {\n const ms = Math.round(reply.elapsedTime);\n const status = reply.statusCode;\n const color = status >= 400 ? '\\x1b[31m' : status >= 300 ? '\\x1b[33m' : '\\x1b[32m';\n console.log(`${color}${request.method}\\x1b[0m ${request.url} \\x1b[2m${status} ${ms}ms\\x1b[0m`);\n }\n done();\n });\n\n // Error handler — log details and send structured response\n app.setErrorHandler((error: { statusCode?: number; message: string }, request, reply) => {\n const status = error.statusCode ?? 500;\n console.error(`\\x1b[31mERROR\\x1b[0m ${request.method} ${request.url} \\x1b[2m${status}\\x1b[0m — ${error.message}`);\n reply.status(status).send({\n success: false,\n error: { message: error.message, statusCode: status },\n });\n });\n\n // API routes\n await registerRoutes(app, engine);\n\n // SSE endpoint\n await registerSSE(app);\n\n // Serve static UI assets\n const uiPath = getUiAssetsPath();\n if (uiPath) {\n await app.register(fastifyStatic, {\n root: uiPath,\n prefix: '/',\n });\n\n // SPA fallback: non-/api and non-/sse paths serve index.html\n app.setNotFoundHandler(async (request, reply) => {\n if (request.url.startsWith('/api') || request.url.startsWith('/sse') || request.url.startsWith('/rpc')) {\n return reply.code(404).send({ error: 'Not found' });\n }\n return reply.sendFile('index.html');\n });\n } else {\n // No UI assets found — still serve the API\n app.setNotFoundHandler(async (_request, reply) => {\n return reply.code(404).send({\n error: 'UI assets not found. Build shield-ui first: npx nx build shield-ui',\n });\n });\n }\n\n // Start idle-timeout checker\n idleTimer = setInterval(() => {\n const idleTime = Date.now() - lastActivity;\n const connections = getActiveConnections();\n if (connections === 0 && idleTime > IDLE_TIMEOUT) {\n console.log('Setup server idle timeout — shutting down');\n completionResolve?.();\n }\n }, IDLE_CHECK_INTERVAL);\n\n // Listen on localhost only\n await app.listen({ port, host: '127.0.0.1' });\n\n const url = `http://localhost:${port}`;\n return url;\n },\n\n async stop(): Promise<void> {\n setEngineLogCallback(undefined);\n if (idleTimer) {\n clearInterval(idleTimer);\n idleTimer = null;\n }\n // Close SSE connections first so Fastify doesn't wait for them\n closeAllSSEConnections();\n if (app) {\n await app.close();\n app = null;\n }\n },\n\n waitForCompletion(): Promise<void> {\n return new Promise((resolve) => {\n completionResolve = resolve;\n });\n },\n };\n}\n"]}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { EventEmitter } from 'node:events';
|
|
8
8
|
import type { FastifyInstance } from 'fastify';
|
|
9
|
-
export type SetupSSEEventType = 'setup:state_change' | 'setup:complete' | 'setup:error' | 'heartbeat';
|
|
9
|
+
export type SetupSSEEventType = 'setup:state_change' | 'setup:scan_complete' | 'setup:complete' | 'setup:error' | 'setup:log' | 'heartbeat';
|
|
10
10
|
export interface SetupSSEEvent {
|
|
11
11
|
type: SetupSSEEventType;
|
|
12
12
|
data: Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/setup-server/sse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAI7E,MAAM,MAAM,iBAAiB,GACzB,oBAAoB,GACpB,gBAAgB,GAChB,aAAa,GACb,WAAW,CAAC;AAEhB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,uBAAqB,CAAC;AAO/C,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAS7C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEhG;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCrE"}
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/setup-server/sse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAI7E,MAAM,MAAM,iBAAiB,GACzB,oBAAoB,GACpB,qBAAqB,GACrB,gBAAgB,GAChB,aAAa,GACb,WAAW,GACX,WAAW,CAAC;AAEhB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,uBAAqB,CAAC;AAO/C,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAS7C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEhG;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../src/setup-server/sse.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../src/setup-server/sse.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SSE endpoint for the setup server\n *\n * Streams wizard engine state changes to the browser UI in real-time.\n * Uses a local EventEmitter (NOT the daemon's singleton).\n */\n\nimport { EventEmitter } from 'node:events';\nimport type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';\n\nconst HEARTBEAT_INTERVAL = 15_000; // 15 seconds\n\nexport type SetupSSEEventType =\n | 'setup:state_change'\n | 'setup:scan_complete'\n | 'setup:complete'\n | 'setup:error'\n | 'setup:log'\n | 'heartbeat';\n\nexport interface SetupSSEEvent {\n type: SetupSSEEventType;\n data: Record<string, unknown>;\n}\n\n/**\n * Local event emitter for setup SSE — not shared with the daemon\n */\nexport const setupEmitter = new EventEmitter();\nsetupEmitter.setMaxListeners(20);\n\n/** Track active SSE connections for idle-timeout */\nlet activeConnections = 0;\nconst activeReplies: Set<import('node:http').ServerResponse> = new Set();\n\nexport function getActiveConnections(): number {\n return activeConnections;\n}\n\n/**\n * Close all active SSE connections so the server can shut down cleanly\n */\nexport function closeAllSSEConnections(): void {\n for (const raw of activeReplies) {\n try {\n raw.end();\n } catch {\n // Already closed\n }\n }\n activeReplies.clear();\n}\n\n/**\n * Broadcast an event to all connected SSE clients\n */\nexport function broadcastSetupEvent(type: SetupSSEEventType, data: Record<string, unknown>): void {\n setupEmitter.emit('event', { type, data });\n}\n\n/**\n * Register the SSE endpoint on a Fastify instance\n */\nexport async function registerSSE(app: FastifyInstance): Promise<void> {\n app.get('/sse/events', async (request: FastifyRequest, reply: FastifyReply) => {\n // Set SSE headers\n reply.raw.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'Access-Control-Allow-Origin': '*',\n });\n\n activeConnections++;\n activeReplies.add(reply.raw);\n\n // Heartbeat timer\n const heartbeat = setInterval(() => {\n reply.raw.write(`event: heartbeat\\ndata: ${JSON.stringify({ timestamp: new Date().toISOString() })}\\n\\n`);\n }, HEARTBEAT_INTERVAL);\n\n // Event listener\n const onEvent = (event: SetupSSEEvent) => {\n reply.raw.write(`event: ${event.type}\\ndata: ${JSON.stringify(event.data)}\\n\\n`);\n };\n\n setupEmitter.on('event', onEvent);\n\n // Send initial connected event\n reply.raw.write(`event: heartbeat\\ndata: ${JSON.stringify({ timestamp: new Date().toISOString(), connected: true })}\\n\\n`);\n\n // Cleanup on close\n request.raw.on('close', () => {\n activeConnections--;\n activeReplies.delete(reply.raw);\n clearInterval(heartbeat);\n setupEmitter.off('event', onEvent);\n });\n\n // Keep the connection open (don't call reply.send)\n await reply.hijack();\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/utils/daemon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;CAOzB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAiC7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAiCpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAMhD;AAgED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC;IACjF,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC,CA4JD;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CA0ED;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAUD"}
|
package/src/utils/daemon.js
CHANGED
|
@@ -10,6 +10,7 @@ import * as path from 'node:path';
|
|
|
10
10
|
import { createRequire } from 'node:module';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
12
|
import { isSecretEnvVar } from '@agenshield/sandbox';
|
|
13
|
+
import { isOpenClawInstalled, stopOpenClawServices } from '@agenshield/integrations';
|
|
13
14
|
import { captureCallingUserEnv } from './sudo-env.js';
|
|
14
15
|
const require = createRequire(import.meta.url);
|
|
15
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -320,6 +321,15 @@ export async function startDaemon(options = {}) {
|
|
|
320
321
|
* Stop the daemon
|
|
321
322
|
*/
|
|
322
323
|
export async function stopDaemon() {
|
|
324
|
+
// Stop OpenClaw services first (they depend on broker)
|
|
325
|
+
try {
|
|
326
|
+
if (await isOpenClawInstalled()) {
|
|
327
|
+
await stopOpenClawServices();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
// Best effort
|
|
332
|
+
}
|
|
323
333
|
const status = await getDaemonStatus();
|
|
324
334
|
if (!status.running) {
|
|
325
335
|
return {
|