@commandgarden/cli 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +185 -71
- package/node_modules/@commandgarden/app/dist/server/main.js +1 -1
- package/node_modules/@commandgarden/app/dist/server/store.js +70 -26
- package/node_modules/@commandgarden/app/package.json +1 -2
- package/node_modules/@commandgarden/daemon/dist/audit-store.d.ts +5 -1
- package/node_modules/@commandgarden/daemon/dist/audit-store.d.ts.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/audit-store.js +69 -15
- package/node_modules/@commandgarden/daemon/dist/audit-store.js.map +1 -1
- package/node_modules/@commandgarden/daemon/dist/main.js +1 -1
- package/node_modules/@commandgarden/daemon/dist/main.js.map +1 -1
- package/node_modules/@commandgarden/daemon/package.json +1 -2
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -12202,7 +12202,7 @@ var {
|
|
|
12202
12202
|
|
|
12203
12203
|
// src/main.ts
|
|
12204
12204
|
import { join as join4, dirname as dirname2, resolve } from "path";
|
|
12205
|
-
import { readFileSync as
|
|
12205
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
12206
12206
|
import { homedir } from "os";
|
|
12207
12207
|
import { fileURLToPath } from "url";
|
|
12208
12208
|
|
|
@@ -12640,7 +12640,7 @@ function stepSummary(step) {
|
|
|
12640
12640
|
// src/commands/validate.ts
|
|
12641
12641
|
import { readFileSync as readFileSync3 } from "fs";
|
|
12642
12642
|
|
|
12643
|
-
//
|
|
12643
|
+
// node_modules/@commandgarden/shared/dist/capabilities.js
|
|
12644
12644
|
var CAPABILITIES = [
|
|
12645
12645
|
"navigate",
|
|
12646
12646
|
"cookie_read",
|
|
@@ -16702,7 +16702,7 @@ var coerce = {
|
|
|
16702
16702
|
};
|
|
16703
16703
|
var NEVER = INVALID;
|
|
16704
16704
|
|
|
16705
|
-
//
|
|
16705
|
+
// node_modules/@commandgarden/shared/dist/pipeline.js
|
|
16706
16706
|
var STEP_CAPABILITY_MAP = {
|
|
16707
16707
|
navigate: "navigate",
|
|
16708
16708
|
wait: "navigate",
|
|
@@ -16795,7 +16795,7 @@ var pipelineStepSchema = external_exports.discriminatedUnion("step", [
|
|
|
16795
16795
|
jsEvaluateStepSchema
|
|
16796
16796
|
]);
|
|
16797
16797
|
|
|
16798
|
-
//
|
|
16798
|
+
// node_modules/@commandgarden/shared/dist/connector.js
|
|
16799
16799
|
var capabilityEnum = external_exports.enum(CAPABILITIES);
|
|
16800
16800
|
var connectorArgSchema = external_exports.object({
|
|
16801
16801
|
name: external_exports.string(),
|
|
@@ -16822,7 +16822,7 @@ var connectorSchema = external_exports.object({
|
|
|
16822
16822
|
pipeline: external_exports.array(pipelineStepSchema).min(1)
|
|
16823
16823
|
});
|
|
16824
16824
|
|
|
16825
|
-
//
|
|
16825
|
+
// node_modules/@commandgarden/shared/dist/loader.js
|
|
16826
16826
|
var import_yaml = __toESM(require_dist(), 1);
|
|
16827
16827
|
function parseConnectorYaml(yamlContent) {
|
|
16828
16828
|
let parsed;
|
|
@@ -16893,7 +16893,7 @@ function validateConnectorSemantics(connector) {
|
|
|
16893
16893
|
return errors;
|
|
16894
16894
|
}
|
|
16895
16895
|
|
|
16896
|
-
//
|
|
16896
|
+
// node_modules/@commandgarden/shared/dist/events.js
|
|
16897
16897
|
import { randomUUID } from "crypto";
|
|
16898
16898
|
|
|
16899
16899
|
// src/commands/validate.ts
|
|
@@ -16932,8 +16932,47 @@ function executeValidate(filePath) {
|
|
|
16932
16932
|
|
|
16933
16933
|
// src/commands/daemon-cmd.ts
|
|
16934
16934
|
import { spawn } from "child_process";
|
|
16935
|
-
import { readFileSync as
|
|
16935
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync2, mkdirSync, openSync, closeSync } from "fs";
|
|
16936
16936
|
import { join as join2 } from "path";
|
|
16937
|
+
|
|
16938
|
+
// src/poll.ts
|
|
16939
|
+
async function pollUntilReady(opts) {
|
|
16940
|
+
for (let i = 0; i < opts.maxAttempts; i++) {
|
|
16941
|
+
if (!opts.isAlive()) return "died";
|
|
16942
|
+
if (await opts.checkReady()) return "ready";
|
|
16943
|
+
await new Promise((r) => setTimeout(r, opts.intervalMs));
|
|
16944
|
+
}
|
|
16945
|
+
return "timeout";
|
|
16946
|
+
}
|
|
16947
|
+
|
|
16948
|
+
// src/process-alive.ts
|
|
16949
|
+
function isProcessAlive(pid) {
|
|
16950
|
+
try {
|
|
16951
|
+
process.kill(pid, 0);
|
|
16952
|
+
return true;
|
|
16953
|
+
} catch {
|
|
16954
|
+
return false;
|
|
16955
|
+
}
|
|
16956
|
+
}
|
|
16957
|
+
|
|
16958
|
+
// src/lockfile.ts
|
|
16959
|
+
import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync2, unlinkSync } from "fs";
|
|
16960
|
+
function acquireLock(lockPath) {
|
|
16961
|
+
if (existsSync2(lockPath)) {
|
|
16962
|
+
const holderPid = parseInt(readFileSync4(lockPath, "utf-8").trim(), 10);
|
|
16963
|
+
if (isProcessAlive(holderPid)) return { acquired: false, holderPid };
|
|
16964
|
+
}
|
|
16965
|
+
writeFileSync(lockPath, String(process.pid));
|
|
16966
|
+
return { acquired: true };
|
|
16967
|
+
}
|
|
16968
|
+
function releaseLock(lockPath) {
|
|
16969
|
+
try {
|
|
16970
|
+
unlinkSync(lockPath);
|
|
16971
|
+
} catch {
|
|
16972
|
+
}
|
|
16973
|
+
}
|
|
16974
|
+
|
|
16975
|
+
// src/commands/daemon-cmd.ts
|
|
16937
16976
|
async function executeDaemonStatus(baseUrl) {
|
|
16938
16977
|
try {
|
|
16939
16978
|
const resp = await fetch(`${baseUrl}/api/status`);
|
|
@@ -16950,33 +16989,82 @@ async function executeDaemonStatus(baseUrl) {
|
|
|
16950
16989
|
async function executeDaemonStart(baseUrl, cgHome, daemonScript) {
|
|
16951
16990
|
try {
|
|
16952
16991
|
const resp = await fetch(`${baseUrl}/api/status`);
|
|
16953
|
-
if (resp.ok) return "Daemon is already running.";
|
|
16992
|
+
if (resp.ok) return { status: "already-running", message: "Daemon is already running." };
|
|
16954
16993
|
} catch {
|
|
16955
16994
|
}
|
|
16956
|
-
const pidPath = join2(cgHome, "daemon.pid");
|
|
16957
16995
|
mkdirSync(cgHome, { recursive: true });
|
|
16958
|
-
const
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16996
|
+
const lockPath = join2(cgHome, "daemon.lock");
|
|
16997
|
+
const lock = acquireLock(lockPath);
|
|
16998
|
+
if (!lock.acquired) {
|
|
16999
|
+
return {
|
|
17000
|
+
status: "locked",
|
|
17001
|
+
message: `Another cg up/daemon start is already in progress (PID ${lock.holderPid}).`
|
|
17002
|
+
};
|
|
17003
|
+
}
|
|
17004
|
+
try {
|
|
17005
|
+
const pidPath = join2(cgHome, "daemon.pid");
|
|
17006
|
+
const logPath = join2(cgHome, "daemon.log");
|
|
17007
|
+
console.error("Starting daemon...");
|
|
17008
|
+
const logFd = openSync(logPath, "a");
|
|
17009
|
+
const child = spawn("node", [daemonScript], { detached: true, stdio: ["ignore", logFd, logFd] });
|
|
17010
|
+
closeSync(logFd);
|
|
17011
|
+
let spawnFailed = false;
|
|
17012
|
+
child.on("error", () => {
|
|
17013
|
+
spawnFailed = true;
|
|
17014
|
+
});
|
|
17015
|
+
if (child.pid) writeFileSync2(pidPath, String(child.pid));
|
|
17016
|
+
child.unref();
|
|
17017
|
+
const outcome = await pollUntilReady({
|
|
17018
|
+
checkReady: async () => {
|
|
17019
|
+
try {
|
|
17020
|
+
const resp = await fetch(`${baseUrl}/api/status`);
|
|
17021
|
+
return resp.ok;
|
|
17022
|
+
} catch {
|
|
17023
|
+
return false;
|
|
17024
|
+
}
|
|
17025
|
+
},
|
|
17026
|
+
isAlive: () => !spawnFailed && (!child.pid || isProcessAlive(child.pid)),
|
|
17027
|
+
maxAttempts: 20,
|
|
17028
|
+
intervalMs: 500
|
|
17029
|
+
});
|
|
17030
|
+
if (outcome === "ready") {
|
|
17031
|
+
return { status: "started", message: `Daemon started (PID: ${child.pid ?? "unknown"}).`, pid: child.pid };
|
|
17032
|
+
}
|
|
17033
|
+
if (outcome === "died") {
|
|
17034
|
+
if (existsSync3(pidPath)) unlinkSync2(pidPath);
|
|
17035
|
+
const tail = readLogTail(logPath, 10);
|
|
17036
|
+
return { status: "failed", message: `Daemon failed to start.
|
|
17037
|
+
${tail}` };
|
|
17038
|
+
}
|
|
17039
|
+
return {
|
|
17040
|
+
status: "unresponsive",
|
|
17041
|
+
message: `Daemon started (PID: ${child.pid ?? "unknown"}) but is not responding. Check ${logPath} for details.`,
|
|
17042
|
+
pid: child.pid
|
|
17043
|
+
};
|
|
17044
|
+
} finally {
|
|
17045
|
+
releaseLock(lockPath);
|
|
17046
|
+
}
|
|
17047
|
+
}
|
|
17048
|
+
function readLogTail(logPath, lines) {
|
|
17049
|
+
try {
|
|
17050
|
+
const content = readFileSync5(logPath, "utf-8");
|
|
17051
|
+
return content.split("\n").slice(-lines).join("\n").trim();
|
|
17052
|
+
} catch {
|
|
17053
|
+
return "(no log available)";
|
|
16964
17054
|
}
|
|
16965
|
-
child.unref();
|
|
16966
|
-
return `Daemon started (PID: ${child.pid ?? "unknown"}).`;
|
|
16967
17055
|
}
|
|
16968
17056
|
async function executeDaemonStop(cgHome) {
|
|
16969
17057
|
const pidPath = join2(cgHome, "daemon.pid");
|
|
16970
|
-
if (!
|
|
17058
|
+
if (!existsSync3(pidPath)) {
|
|
16971
17059
|
return "Daemon is not running (no PID file found).";
|
|
16972
17060
|
}
|
|
16973
|
-
const pid = parseInt(
|
|
17061
|
+
const pid = parseInt(readFileSync5(pidPath, "utf-8").trim(), 10);
|
|
16974
17062
|
try {
|
|
16975
17063
|
process.kill(pid, "SIGTERM");
|
|
16976
|
-
|
|
17064
|
+
unlinkSync2(pidPath);
|
|
16977
17065
|
return `Daemon stopped (PID: ${pid}).`;
|
|
16978
17066
|
} catch {
|
|
16979
|
-
|
|
17067
|
+
unlinkSync2(pidPath);
|
|
16980
17068
|
return `Daemon process ${pid} not found (stale PID file cleaned up).`;
|
|
16981
17069
|
}
|
|
16982
17070
|
}
|
|
@@ -17106,16 +17194,16 @@ async function executeAuditShow(client, id) {
|
|
|
17106
17194
|
}
|
|
17107
17195
|
|
|
17108
17196
|
// src/commands/config-cmd.ts
|
|
17109
|
-
import { readFileSync as
|
|
17197
|
+
import { readFileSync as readFileSync6, existsSync as existsSync4 } from "fs";
|
|
17110
17198
|
function executeConfigShow(configPath) {
|
|
17111
|
-
if (!
|
|
17199
|
+
if (!existsSync4(configPath)) {
|
|
17112
17200
|
return [
|
|
17113
17201
|
"No config file found.",
|
|
17114
17202
|
`Expected at: ${configPath}`,
|
|
17115
17203
|
'Using defaults. Run "commandgarden config set <key> <value>" to create one.'
|
|
17116
17204
|
].join("\n");
|
|
17117
17205
|
}
|
|
17118
|
-
return
|
|
17206
|
+
return readFileSync6(configPath, "utf-8");
|
|
17119
17207
|
}
|
|
17120
17208
|
async function executeConfigSet(client, key, value) {
|
|
17121
17209
|
try {
|
|
@@ -17129,12 +17217,12 @@ async function executeConfigSet(client, key, value) {
|
|
|
17129
17217
|
// src/commands/gui-cmd.ts
|
|
17130
17218
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
17131
17219
|
import { spawn as spawn2 } from "child_process";
|
|
17132
|
-
import { readFileSync as
|
|
17220
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync3, existsSync as existsSync5, unlinkSync as unlinkSync3, mkdirSync as mkdirSync2, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
17133
17221
|
import { join as join3 } from "path";
|
|
17134
17222
|
function readAppPort(configPath) {
|
|
17135
17223
|
try {
|
|
17136
|
-
if (
|
|
17137
|
-
const config2 = (0, import_yaml2.parse)(
|
|
17224
|
+
if (existsSync5(configPath)) {
|
|
17225
|
+
const config2 = (0, import_yaml2.parse)(readFileSync7(configPath, "utf-8"));
|
|
17138
17226
|
const port = config2?.app?.port;
|
|
17139
17227
|
if (typeof port === "number") return port;
|
|
17140
17228
|
}
|
|
@@ -17148,41 +17236,67 @@ async function executeGuiStart(baseUrl, cgHome, appScript, opts) {
|
|
|
17148
17236
|
const resp = await fetch(`${baseUrl}/api/status`);
|
|
17149
17237
|
if (!resp.ok) throw new Error();
|
|
17150
17238
|
} catch {
|
|
17151
|
-
|
|
17239
|
+
const message = "Daemon is not running. Start it with: cg daemon start (or use cg up)";
|
|
17240
|
+
return opts.background ? { status: "failed", message } : message;
|
|
17152
17241
|
}
|
|
17153
17242
|
const pidPath = join3(cgHome, "app.pid");
|
|
17154
|
-
if (
|
|
17155
|
-
const pid = parseInt(
|
|
17156
|
-
|
|
17157
|
-
|
|
17158
|
-
return
|
|
17159
|
-
} catch {
|
|
17160
|
-
unlinkSync2(pidPath);
|
|
17243
|
+
if (existsSync5(pidPath)) {
|
|
17244
|
+
const pid = parseInt(readFileSync7(pidPath, "utf-8").trim(), 10);
|
|
17245
|
+
if (isProcessAlive(pid)) {
|
|
17246
|
+
const message = "GUI is already running.";
|
|
17247
|
+
return opts.background ? { status: "already-running", message } : message;
|
|
17161
17248
|
}
|
|
17249
|
+
unlinkSync3(pidPath);
|
|
17162
17250
|
}
|
|
17163
17251
|
mkdirSync2(cgHome, { recursive: true });
|
|
17164
17252
|
if (opts.background) {
|
|
17165
|
-
const
|
|
17166
|
-
const
|
|
17167
|
-
|
|
17168
|
-
|
|
17169
|
-
|
|
17170
|
-
|
|
17171
|
-
|
|
17253
|
+
const lockPath = join3(cgHome, "app.lock");
|
|
17254
|
+
const lock = acquireLock(lockPath);
|
|
17255
|
+
if (!lock.acquired) {
|
|
17256
|
+
return { status: "locked", message: `Another cg up/gui start is already in progress (PID ${lock.holderPid}).` };
|
|
17257
|
+
}
|
|
17258
|
+
try {
|
|
17259
|
+
console.error("Starting GUI...");
|
|
17260
|
+
const logPath = join3(cgHome, "app.log");
|
|
17261
|
+
const logFd = openSync2(logPath, "a");
|
|
17262
|
+
const child2 = spawn2("node", [appScript], { detached: true, stdio: ["ignore", logFd, logFd] });
|
|
17263
|
+
closeSync2(logFd);
|
|
17264
|
+
let spawnFailed = false;
|
|
17265
|
+
child2.on("error", () => {
|
|
17266
|
+
spawnFailed = true;
|
|
17267
|
+
});
|
|
17268
|
+
if (child2.pid) writeFileSync3(pidPath, String(child2.pid));
|
|
17269
|
+
child2.unref();
|
|
17270
|
+
if (opts.noOpen) {
|
|
17271
|
+
return { status: "started", message: `GUI started (PID: ${child2.pid ?? "unknown"}).`, pid: child2.pid };
|
|
17272
|
+
}
|
|
17172
17273
|
const appUrl = `http://127.0.0.1:${appPort}`;
|
|
17173
|
-
const
|
|
17174
|
-
|
|
17274
|
+
const outcome = await pollUntilReady({
|
|
17275
|
+
checkReady: async () => {
|
|
17276
|
+
try {
|
|
17277
|
+
await fetch(appUrl);
|
|
17278
|
+
return true;
|
|
17279
|
+
} catch {
|
|
17280
|
+
return false;
|
|
17281
|
+
}
|
|
17282
|
+
},
|
|
17283
|
+
isAlive: () => !spawnFailed && (!child2.pid || isProcessAlive(child2.pid)),
|
|
17284
|
+
maxAttempts: 40,
|
|
17285
|
+
intervalMs: 500
|
|
17286
|
+
});
|
|
17287
|
+
if (outcome === "ready") {
|
|
17175
17288
|
openBrowser(appUrl);
|
|
17176
|
-
|
|
17177
|
-
|
|
17178
|
-
|
|
17179
|
-
|
|
17180
|
-
|
|
17181
|
-
if (existsSync4(pidPath)) unlinkSync2(pidPath);
|
|
17182
|
-
return `GUI failed to start. Check ${logPath} for errors.`;
|
|
17289
|
+
return { status: "started", message: `GUI started (PID: ${child2.pid ?? "unknown"}).`, pid: child2.pid };
|
|
17290
|
+
}
|
|
17291
|
+
if (child2.pid) try {
|
|
17292
|
+
process.kill(child2.pid, "SIGTERM");
|
|
17293
|
+
} catch {
|
|
17183
17294
|
}
|
|
17295
|
+
if (existsSync5(pidPath)) unlinkSync3(pidPath);
|
|
17296
|
+
return { status: "failed", message: `GUI failed to start. Check ${logPath} for errors.` };
|
|
17297
|
+
} finally {
|
|
17298
|
+
releaseLock(lockPath);
|
|
17184
17299
|
}
|
|
17185
|
-
return `GUI started (PID: ${child2.pid ?? "unknown"}).`;
|
|
17186
17300
|
}
|
|
17187
17301
|
const child = spawn2("node", [appScript], { stdio: "inherit" });
|
|
17188
17302
|
if (!opts.noOpen) {
|
|
@@ -17195,21 +17309,21 @@ async function executeGuiStart(baseUrl, cgHome, appScript, opts) {
|
|
|
17195
17309
|
}
|
|
17196
17310
|
function executeGuiStop(cgHome) {
|
|
17197
17311
|
const pidPath = join3(cgHome, "app.pid");
|
|
17198
|
-
if (!
|
|
17199
|
-
const pid = parseInt(
|
|
17312
|
+
if (!existsSync5(pidPath)) return "GUI is not running (no PID file found).";
|
|
17313
|
+
const pid = parseInt(readFileSync7(pidPath, "utf-8").trim(), 10);
|
|
17200
17314
|
try {
|
|
17201
17315
|
process.kill(pid, "SIGTERM");
|
|
17202
|
-
|
|
17316
|
+
unlinkSync3(pidPath);
|
|
17203
17317
|
return `GUI stopped (PID: ${pid}).`;
|
|
17204
17318
|
} catch {
|
|
17205
|
-
|
|
17319
|
+
unlinkSync3(pidPath);
|
|
17206
17320
|
return `GUI process ${pid} not found (stale PID file cleaned up).`;
|
|
17207
17321
|
}
|
|
17208
17322
|
}
|
|
17209
17323
|
function executeGuiStatus(cgHome) {
|
|
17210
17324
|
const pidPath = join3(cgHome, "app.pid");
|
|
17211
|
-
if (!
|
|
17212
|
-
const pid = parseInt(
|
|
17325
|
+
if (!existsSync5(pidPath)) return "GUI: not running (no PID file found).";
|
|
17326
|
+
const pid = parseInt(readFileSync7(pidPath, "utf-8").trim(), 10);
|
|
17213
17327
|
try {
|
|
17214
17328
|
process.kill(pid, 0);
|
|
17215
17329
|
return `GUI: running (PID: ${pid}).`;
|
|
@@ -17241,16 +17355,14 @@ function openBrowser(url) {
|
|
|
17241
17355
|
// src/commands/up-down.ts
|
|
17242
17356
|
async function executeUp(baseUrl, cgHome, daemonScript, appScript, configPath) {
|
|
17243
17357
|
const lines = [];
|
|
17244
|
-
|
|
17245
|
-
|
|
17246
|
-
|
|
17247
|
-
|
|
17248
|
-
|
|
17249
|
-
} catch {
|
|
17250
|
-
}
|
|
17251
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
17358
|
+
const daemonResult = await executeDaemonStart(baseUrl, cgHome, daemonScript);
|
|
17359
|
+
lines.push(daemonResult.message);
|
|
17360
|
+
const canProceed = daemonResult.status === "started" || daemonResult.status === "already-running";
|
|
17361
|
+
if (!canProceed) {
|
|
17362
|
+
return lines.join("\n");
|
|
17252
17363
|
}
|
|
17253
|
-
|
|
17364
|
+
const guiResult = await executeGuiStart(baseUrl, cgHome, appScript, { background: true, configPath });
|
|
17365
|
+
lines.push(typeof guiResult === "string" ? guiResult : guiResult.message);
|
|
17254
17366
|
return lines.join("\n");
|
|
17255
17367
|
}
|
|
17256
17368
|
async function executeDown(cgHome) {
|
|
@@ -17266,7 +17378,7 @@ var __filename = fileURLToPath(import.meta.url);
|
|
|
17266
17378
|
var __dirname = dirname2(__filename);
|
|
17267
17379
|
var CLI_VERSION = (() => {
|
|
17268
17380
|
try {
|
|
17269
|
-
const pkg = JSON.parse(
|
|
17381
|
+
const pkg = JSON.parse(readFileSync8(resolve(__dirname, "..", "package.json"), "utf-8"));
|
|
17270
17382
|
return pkg.version ?? "0.0.0";
|
|
17271
17383
|
} catch {
|
|
17272
17384
|
return "0.0.0";
|
|
@@ -17316,7 +17428,8 @@ daemon.command("status").description("Check daemon status").action(async () => {
|
|
|
17316
17428
|
console.log(await executeDaemonStatus(BASE_URL));
|
|
17317
17429
|
});
|
|
17318
17430
|
daemon.command("start").description("Start the daemon in background").action(async () => {
|
|
17319
|
-
|
|
17431
|
+
const result = await executeDaemonStart(BASE_URL, CG_HOME, getDaemonScript());
|
|
17432
|
+
console.log(result.message);
|
|
17320
17433
|
});
|
|
17321
17434
|
daemon.command("stop").description("Stop the daemon").action(async () => {
|
|
17322
17435
|
console.log(await executeDaemonStop(CG_HOME));
|
|
@@ -17353,11 +17466,12 @@ config.command("set <key> <value>").description("Set a configuration value (e.g.
|
|
|
17353
17466
|
});
|
|
17354
17467
|
var gui = program2.command("gui").description("Manage the GUI app server");
|
|
17355
17468
|
gui.command("start", { isDefault: true }).description("Start the GUI (foreground by default)").option("-b, --background", "Run in background").option("--no-open", "Do not open browser").action(async (opts) => {
|
|
17356
|
-
|
|
17469
|
+
const result = await executeGuiStart(BASE_URL, CG_HOME, getAppScript(), {
|
|
17357
17470
|
background: opts.background,
|
|
17358
17471
|
noOpen: opts.open === false,
|
|
17359
17472
|
configPath: CONFIG_PATH
|
|
17360
|
-
})
|
|
17473
|
+
});
|
|
17474
|
+
console.log(typeof result === "string" ? result : result.message);
|
|
17361
17475
|
});
|
|
17362
17476
|
gui.command("stop").description("Stop the GUI").action(() => {
|
|
17363
17477
|
console.log(executeGuiStop(CG_HOME));
|
|
@@ -34,7 +34,7 @@ async function start() {
|
|
|
34
34
|
const port = readAppPort();
|
|
35
35
|
const daemonUrl = 'http://127.0.0.1:19825';
|
|
36
36
|
const daemon = new DaemonClient(daemonUrl, token);
|
|
37
|
-
const store =
|
|
37
|
+
const store = await AppStore.create(join(CG_HOME, 'app.db'));
|
|
38
38
|
const app = Fastify();
|
|
39
39
|
registerRoutes(app, daemon, store);
|
|
40
40
|
// Serve static SPA files in production
|
|
@@ -1,53 +1,97 @@
|
|
|
1
|
-
import
|
|
1
|
+
import initSqlJs from 'sql.js';
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
2
4
|
import { randomUUID } from 'node:crypto';
|
|
3
5
|
export class AppStore {
|
|
4
6
|
db;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
this.db
|
|
8
|
-
this.
|
|
7
|
+
dbPath;
|
|
8
|
+
constructor(db, dbPath) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
this.dbPath = dbPath;
|
|
11
|
+
}
|
|
12
|
+
static async create(dbPath) {
|
|
13
|
+
const SQL = await initSqlJs();
|
|
14
|
+
let db;
|
|
15
|
+
if (dbPath !== ':memory:' && existsSync(dbPath)) {
|
|
16
|
+
const buf = readFileSync(dbPath);
|
|
17
|
+
db = new SQL.Database(buf);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
db = new SQL.Database();
|
|
21
|
+
}
|
|
22
|
+
const store = new AppStore(db, dbPath);
|
|
23
|
+
store.migrate();
|
|
24
|
+
if (dbPath !== ':memory:')
|
|
25
|
+
store.persist();
|
|
26
|
+
return store;
|
|
27
|
+
}
|
|
28
|
+
// sql.js requires full-DB export on every write; acceptable for small app databases.
|
|
29
|
+
// Write to a temp file then atomically rename to prevent corruption on crash.
|
|
30
|
+
persist() {
|
|
31
|
+
if (this.dbPath === ':memory:')
|
|
32
|
+
return;
|
|
33
|
+
const data = this.db.export();
|
|
34
|
+
const dir = dirname(this.dbPath);
|
|
35
|
+
mkdirSync(dir, { recursive: true });
|
|
36
|
+
const tmpPath = this.dbPath + '.tmp';
|
|
37
|
+
writeFileSync(tmpPath, Buffer.from(data));
|
|
38
|
+
renameSync(tmpPath, this.dbPath);
|
|
39
|
+
}
|
|
40
|
+
query(sql, params = []) {
|
|
41
|
+
const results = this.db.exec(sql, params);
|
|
42
|
+
if (results.length === 0)
|
|
43
|
+
return [];
|
|
44
|
+
const { columns, values } = results[0];
|
|
45
|
+
return values.map(row => {
|
|
46
|
+
const obj = {};
|
|
47
|
+
columns.forEach((col, i) => { obj[col] = row[i]; });
|
|
48
|
+
return obj;
|
|
49
|
+
});
|
|
9
50
|
}
|
|
10
51
|
migrate() {
|
|
11
|
-
this.db.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
);
|
|
23
|
-
`);
|
|
52
|
+
this.db.run(`CREATE TABLE IF NOT EXISTS preferences (
|
|
53
|
+
key TEXT PRIMARY KEY,
|
|
54
|
+
value TEXT NOT NULL
|
|
55
|
+
)`);
|
|
56
|
+
this.db.run(`CREATE TABLE IF NOT EXISTS saved_views (
|
|
57
|
+
id TEXT PRIMARY KEY,
|
|
58
|
+
app TEXT NOT NULL,
|
|
59
|
+
name TEXT NOT NULL,
|
|
60
|
+
config TEXT NOT NULL,
|
|
61
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
62
|
+
)`);
|
|
24
63
|
}
|
|
25
64
|
getPreference(key) {
|
|
26
|
-
const
|
|
27
|
-
return
|
|
65
|
+
const rows = this.query('SELECT value FROM preferences WHERE key = ?', [key]);
|
|
66
|
+
return rows.length > 0 ? rows[0].value : undefined;
|
|
28
67
|
}
|
|
29
68
|
setPreference(key, value) {
|
|
30
|
-
this.db.
|
|
69
|
+
this.db.run('INSERT OR REPLACE INTO preferences (key, value) VALUES (?, ?)', [key, value]);
|
|
70
|
+
this.persist();
|
|
31
71
|
}
|
|
32
72
|
getAllPreferences() {
|
|
33
|
-
const rows = this.
|
|
73
|
+
const rows = this.query('SELECT key, value FROM preferences');
|
|
34
74
|
const result = {};
|
|
35
75
|
for (const row of rows)
|
|
36
76
|
result[row.key] = row.value;
|
|
37
77
|
return result;
|
|
38
78
|
}
|
|
39
79
|
listViews(app) {
|
|
40
|
-
return this.
|
|
80
|
+
return this.query('SELECT * FROM saved_views WHERE app = ? ORDER BY created_at DESC', [app]);
|
|
41
81
|
}
|
|
42
82
|
createView(app, name, config) {
|
|
43
83
|
const id = randomUUID();
|
|
44
84
|
const created_at = new Date().toISOString();
|
|
45
|
-
this.db.
|
|
85
|
+
this.db.run('INSERT INTO saved_views (id, app, name, config, created_at) VALUES (?, ?, ?, ?, ?)', [id, app, name, config, created_at]);
|
|
86
|
+
this.persist();
|
|
46
87
|
return { id, app, name, config, created_at };
|
|
47
88
|
}
|
|
48
89
|
deleteView(id) {
|
|
49
|
-
|
|
50
|
-
|
|
90
|
+
this.db.run('DELETE FROM saved_views WHERE id = ?', [id]);
|
|
91
|
+
const changes = this.db.getRowsModified();
|
|
92
|
+
if (changes > 0)
|
|
93
|
+
this.persist();
|
|
94
|
+
return changes > 0;
|
|
51
95
|
}
|
|
52
96
|
close() {
|
|
53
97
|
this.db.close();
|
|
@@ -17,14 +17,13 @@
|
|
|
17
17
|
"@commandgarden/shared": "*",
|
|
18
18
|
"fastify": "^5.0.0",
|
|
19
19
|
"@fastify/static": "^8.0.0",
|
|
20
|
-
"
|
|
20
|
+
"sql.js": "^1.11.0",
|
|
21
21
|
"yaml": "^2.4.0",
|
|
22
22
|
"react": "^18.3.0",
|
|
23
23
|
"react-dom": "^18.3.0",
|
|
24
24
|
"react-router-dom": "^6.23.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
28
27
|
"@types/node": "^22.0.0",
|
|
29
28
|
"@types/react": "^18.3.0",
|
|
30
29
|
"@types/react-dom": "^18.3.0",
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { AuditEvent } from '@commandgarden/shared';
|
|
2
2
|
export declare class AuditStore {
|
|
3
3
|
private db;
|
|
4
|
-
|
|
4
|
+
private dbPath;
|
|
5
|
+
private constructor();
|
|
6
|
+
static create(dbPath: string): Promise<AuditStore>;
|
|
7
|
+
private persist;
|
|
8
|
+
private query;
|
|
5
9
|
private migrate;
|
|
6
10
|
insert(event: AuditEvent): void;
|
|
7
11
|
list(opts?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-store.d.ts","sourceRoot":"","sources":["../src/audit-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit-store.d.ts","sourceRoot":"","sources":["../src/audit-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,uBAAuB,CAAC;AAIrE,qBAAa,UAAU;IACrB,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;WAKM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IA0BxD,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,OAAO;IAoBf,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAoB/B,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,EAAE;IAW9F,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAK3C,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM;IAQpC,KAAK,IAAI,IAAI;IAEb,OAAO,CAAC,OAAO;CAoBhB"}
|
|
@@ -1,27 +1,67 @@
|
|
|
1
1
|
// src/audit-store.ts
|
|
2
|
-
import
|
|
3
|
-
import { chmodSync } from 'node:fs';
|
|
2
|
+
import initSqlJs from 'sql.js';
|
|
3
|
+
import { chmodSync, existsSync, readFileSync, writeFileSync, renameSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
4
5
|
export class AuditStore {
|
|
5
6
|
db;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
this.db
|
|
9
|
-
this.
|
|
7
|
+
dbPath;
|
|
8
|
+
constructor(db, dbPath) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
this.dbPath = dbPath;
|
|
11
|
+
}
|
|
12
|
+
static async create(dbPath) {
|
|
13
|
+
const SQL = await initSqlJs();
|
|
14
|
+
let db;
|
|
15
|
+
if (dbPath !== ':memory:' && existsSync(dbPath)) {
|
|
16
|
+
const buf = readFileSync(dbPath);
|
|
17
|
+
db = new SQL.Database(buf);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
db = new SQL.Database();
|
|
21
|
+
}
|
|
22
|
+
db.run(`CREATE TABLE IF NOT EXISTS audit_events (
|
|
10
23
|
id TEXT PRIMARY KEY, timestamp TEXT NOT NULL, type TEXT NOT NULL,
|
|
11
24
|
user TEXT NOT NULL, connector TEXT NOT NULL, args TEXT NOT NULL,
|
|
12
25
|
domains TEXT NOT NULL, capabilities TEXT NOT NULL, row_count INTEGER,
|
|
13
26
|
columns TEXT, duration_ms INTEGER NOT NULL, error TEXT, denial_reason TEXT
|
|
14
27
|
)`);
|
|
15
|
-
|
|
28
|
+
const store = new AuditStore(db, dbPath);
|
|
29
|
+
store.migrate();
|
|
16
30
|
if (dbPath !== ':memory:') {
|
|
31
|
+
store.persist();
|
|
17
32
|
try {
|
|
18
33
|
chmodSync(dbPath, 0o600);
|
|
19
34
|
}
|
|
20
35
|
catch { /* ignore for read-only fs */ }
|
|
21
36
|
}
|
|
37
|
+
return store;
|
|
38
|
+
}
|
|
39
|
+
// sql.js requires full-DB export on every write; acceptable for small audit databases.
|
|
40
|
+
// Write to a temp file then atomically rename to prevent corruption on crash.
|
|
41
|
+
persist() {
|
|
42
|
+
if (this.dbPath === ':memory:')
|
|
43
|
+
return;
|
|
44
|
+
const data = this.db.export();
|
|
45
|
+
const dir = dirname(this.dbPath);
|
|
46
|
+
mkdirSync(dir, { recursive: true });
|
|
47
|
+
const tmpPath = this.dbPath + '.tmp';
|
|
48
|
+
writeFileSync(tmpPath, Buffer.from(data));
|
|
49
|
+
renameSync(tmpPath, this.dbPath);
|
|
50
|
+
}
|
|
51
|
+
query(sql, params = []) {
|
|
52
|
+
const results = this.db.exec(sql, params);
|
|
53
|
+
if (results.length === 0)
|
|
54
|
+
return [];
|
|
55
|
+
const { columns, values } = results[0];
|
|
56
|
+
return values.map(row => {
|
|
57
|
+
const obj = {};
|
|
58
|
+
columns.forEach((col, i) => { obj[col] = row[i]; });
|
|
59
|
+
return obj;
|
|
60
|
+
});
|
|
22
61
|
}
|
|
23
62
|
migrate() {
|
|
24
|
-
const
|
|
63
|
+
const colResults = this.db.exec('PRAGMA table_info(audit_events)');
|
|
64
|
+
const cols = new Set(colResults.length > 0 ? colResults[0].values.map(row => row[1]) : []);
|
|
25
65
|
const additions = [
|
|
26
66
|
['correlation_id', 'TEXT'],
|
|
27
67
|
['connector_hash', 'TEXT'],
|
|
@@ -32,15 +72,25 @@ export class AuditStore {
|
|
|
32
72
|
];
|
|
33
73
|
for (const [name, type] of additions) {
|
|
34
74
|
if (!cols.has(name)) {
|
|
35
|
-
this.db.
|
|
75
|
+
this.db.run(`ALTER TABLE audit_events ADD COLUMN ${name} ${type}`);
|
|
36
76
|
}
|
|
37
77
|
}
|
|
38
78
|
}
|
|
39
79
|
insert(event) {
|
|
40
|
-
this.db.
|
|
80
|
+
this.db.run(`INSERT INTO audit_events (id, timestamp, type, user, connector, args, domains,
|
|
41
81
|
capabilities, row_count, columns, duration_ms, error, denial_reason,
|
|
42
82
|
correlation_id, connector_hash, steps, source, previous_value, new_value)
|
|
43
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
83
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`, [
|
|
84
|
+
event.id, event.timestamp, event.type, event.user, event.connector,
|
|
85
|
+
JSON.stringify(event.args), JSON.stringify(event.domains),
|
|
86
|
+
JSON.stringify(event.capabilities), event.rowCount ?? null,
|
|
87
|
+
event.columns ? JSON.stringify(event.columns) : null,
|
|
88
|
+
event.durationMs, event.error ?? null, event.denialReason ?? null,
|
|
89
|
+
event.correlationId ?? null, event.connectorHash ?? null,
|
|
90
|
+
event.steps ? JSON.stringify(event.steps) : null,
|
|
91
|
+
event.source ?? null, event.previousValue ?? null, event.newValue ?? null,
|
|
92
|
+
]);
|
|
93
|
+
this.persist();
|
|
44
94
|
}
|
|
45
95
|
list(opts) {
|
|
46
96
|
let sql = 'SELECT * FROM audit_events WHERE 1=1';
|
|
@@ -62,15 +112,19 @@ export class AuditStore {
|
|
|
62
112
|
sql += ' LIMIT ?';
|
|
63
113
|
params.push(opts.limit);
|
|
64
114
|
}
|
|
65
|
-
return this.
|
|
115
|
+
return this.query(sql, params).map(r => this.toEvent(r));
|
|
66
116
|
}
|
|
67
117
|
getById(id) {
|
|
68
|
-
const
|
|
69
|
-
return
|
|
118
|
+
const rows = this.query('SELECT * FROM audit_events WHERE id = ?', [id]);
|
|
119
|
+
return rows.length > 0 ? this.toEvent(rows[0]) : undefined;
|
|
70
120
|
}
|
|
71
121
|
prune(retentionDays) {
|
|
72
122
|
const cutoff = new Date(Date.now() - retentionDays * 86_400_000).toISOString();
|
|
73
|
-
|
|
123
|
+
this.db.run('DELETE FROM audit_events WHERE timestamp < ?', [cutoff]);
|
|
124
|
+
const changes = this.db.getRowsModified();
|
|
125
|
+
if (changes > 0)
|
|
126
|
+
this.persist();
|
|
127
|
+
return changes;
|
|
74
128
|
}
|
|
75
129
|
close() { this.db.close(); }
|
|
76
130
|
toEvent(r) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-store.js","sourceRoot":"","sources":["../src/audit-store.ts"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,OAAO,
|
|
1
|
+
{"version":3,"file":"audit-store.js","sourceRoot":"","sources":["../src/audit-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ async function main() {
|
|
|
19
19
|
console.log(`Session token written to ${tokenPath}`);
|
|
20
20
|
// Audit store
|
|
21
21
|
const dbPath = expandHome(config.audit.dbPath);
|
|
22
|
-
const auditStore =
|
|
22
|
+
const auditStore = await AuditStore.create(dbPath);
|
|
23
23
|
const pruned = auditStore.prune(config.audit.retentionDays);
|
|
24
24
|
if (pruned > 0) {
|
|
25
25
|
console.log(`Pruned ${pruned} old audit events`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAEtC,aAAa;IACb,MAAM,YAAY,GAAG,oBAAoB,EAAE,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAChD,iBAAiB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,4BAA4B,SAAS,EAAE,CAAC,CAAC;IAErD,cAAc;IACd,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,13 +15,12 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@commandgarden/shared": "*",
|
|
18
|
-
"
|
|
18
|
+
"sql.js": "^1.11.0",
|
|
19
19
|
"fastify": "^5.0.0",
|
|
20
20
|
"@fastify/websocket": "^11.0.0",
|
|
21
21
|
"yaml": "^2.4.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
25
24
|
"@types/node": "^22.0.0",
|
|
26
25
|
"@types/ws": "^8.5.0",
|
|
27
26
|
"typescript": "^5.4.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commandgarden/cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Enterprise browser automation CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@commandgarden/shared": "*",
|
|
40
40
|
"@fastify/static": "^8.0.0",
|
|
41
41
|
"@fastify/websocket": "^11.0.0",
|
|
42
|
-
"
|
|
42
|
+
"sql.js": "^1.11.0",
|
|
43
43
|
"cli-table3": "^0.6.0",
|
|
44
44
|
"commander": "^12.0.0",
|
|
45
45
|
"fastify": "^5.0.0",
|