appduct 0.11.1 → 0.12.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/README.md +3 -3
- package/dist/bin.js +7 -1
- package/dist/cli/routes/daemon/run.js +83 -21
- package/dist/cli/routes/daemon/start.js +6 -0
- package/dist/cli/routes/daemon/status.js +6 -0
- package/dist/cli/routes/daemon/stop.js +6 -0
- package/dist/cli/routes/events.js +8 -1
- package/dist/cli/routes/invoke.js +6 -0
- package/dist/cli/routes/keygen.js +1 -0
- package/dist/cli/routes/link.js +6 -0
- package/dist/cli/routes/ls.js +6 -0
- package/dist/cli/routes/mcp.js +17 -15
- package/dist/cli/routes/revoke.js +6 -0
- package/dist/cli/routes/tools.js +6 -0
- package/dist/client/index.js +8 -4
- package/dist/commands/events.d.ts +3 -2
- package/dist/daemon/config.d.ts +4 -1
- package/dist/daemon/daemon.d.ts +3 -0
- package/dist/daemon/event-bus.d.ts +4 -4
- package/dist/daemon/events-log.d.ts +31 -0
- package/dist/daemon/memory-append-only-file.d.ts +17 -0
- package/dist/daemon/node-append-only-file.d.ts +9 -0
- package/dist/daemon/state-dir.d.ts +2 -0
- package/dist/index.js +7 -1
- package/dist/mcp/events-tool.d.ts +0 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ That's the whole loop. There is no host process to start — `appduct` auto-spaw
|
|
|
42
42
|
| `appduct tools [selector] [name] [--full] [--group <name>] [--filter <text>] [--limit <n>] [--offset <n>]` | list a session's tools (one call signature + description per line), or show one tool's full schema |
|
|
43
43
|
| `appduct tools [selector] --groups` | list a session's tool groups with their tool counts |
|
|
44
44
|
| `appduct invoke [selector] <tool> --input '<json>' [--timeout <ms>]` | call a tool |
|
|
45
|
-
| `appduct events [selector] [--follow] [--since <cursor>]` | stream
|
|
45
|
+
| `appduct events [selector] [--follow] [--since <cursor>]` | stream the events the app posts with `postEvent` (default), or one-shot pull the ones retained since `<cursor>` (`--since`); `--json` emits NDJSON |
|
|
46
46
|
| `appduct revoke [selector]` | revoke a session |
|
|
47
47
|
| `appduct daemon run\|start\|stop\|status` | daemon lifecycle |
|
|
48
48
|
| `appduct mcp [--scheme <s>]` | start a stdio MCP server proxying connected apps' tools to MCP clients |
|
|
@@ -289,13 +289,13 @@ This writes an unencrypted PEM private key (PKCS#8) to `<state-dir>/key.pem` by
|
|
|
289
289
|
|
|
290
290
|
## Daemon lifecycle
|
|
291
291
|
|
|
292
|
-
The daemon auto-starts the first time any CLI or MCP command needs it — you don't normally run `appduct daemon start` yourself. It writes state to `<state-dir>/` (`daemon.sock`, `daemon.pid`, `daemon.log`, `daemon.log.1`, `key.pem`, `config.json`, `audit/`), holds a single-instance lock via the pidfile, and runs independently of any one device's connection, so a reload or crash on the device side never costs you the daemon process.
|
|
292
|
+
The daemon auto-starts the first time any CLI or MCP command needs it — you don't normally run `appduct daemon start` yourself. It writes state to `<state-dir>/` (`daemon.sock`, `daemon.pid`, `daemon.log`, `daemon.log.1`, `events.log`, `events.log.1`, `key.pem`, `config.json`, `audit/`), holds a single-instance lock via the pidfile, and runs independently of any one device's connection, so a reload or crash on the device side never costs you the daemon process.
|
|
293
293
|
|
|
294
294
|
Use `appduct daemon status` to see what's running (version, pid, `wssPort`, pinned keys, live sessions, effective policy, and the audit log's retention window, file count, size, and failure counters) and `appduct daemon stop` to shut it down explicitly.
|
|
295
295
|
|
|
296
296
|
Because the daemon outlives the CLI that started it, upgrading Appduct would otherwise leave the old daemon serving your commands. Every CLI/MCP process compares its version with the daemon's on its first command and replaces a stale daemon when nothing would be lost; when there is something at stake — connected sessions, or an unexpired link nobody has scanned yet — the command stops instead, naming both versions, until you run `appduct daemon stop` or pass `--daemon-restart`. A daemon newer than your CLI is left alone with a warning, so a project-local install never downgrades a global one's daemon.
|
|
297
297
|
|
|
298
|
-
|
|
298
|
+
No log grows without bound: `audit/<YYYY-MM-DD>.jsonl` files older than `auditRetentionDays` (default 30) are pruned at daemon start and once a day after, a `daemon.log` over `daemonLogMaxBytes` (default 10 MiB) is rotated to `daemon.log.1` when a daemon is next spawned, and `events.log` is rotated to `events.log.1` as soon as it passes `eventsLogMaxBytes` (default 10 MiB). `events.log` records the daemon's own events (links, sessions, tool registries and tool calls), one JSON line each, for debugging Appduct itself; your app's events are never written to it. All three are `config.json` keys — see [`ARCHITECTURE.md` §3][architecture].
|
|
299
299
|
|
|
300
300
|
## Release gate: `appduct doctor`
|
|
301
301
|
|
package/dist/bin.js
CHANGED
|
@@ -142,7 +142,7 @@ var createCli = () => {
|
|
|
142
142
|
"--timeout <ms>",
|
|
143
143
|
"Call timeout in milliseconds. Shortens the deadline; it cannot extend one past the app's own timer, which is the tool's declared timeoutMs (else 10000)."
|
|
144
144
|
);
|
|
145
|
-
cli.command("events [selector]", "Stream
|
|
145
|
+
cli.command("events [selector]", "Stream the events the app posts until interrupted.").option("--follow", "Accepted for script readability; the default behavior already follows.").option("--since <cursor>", "One-shot: print the app events retained since this cursor instead of streaming live.");
|
|
146
146
|
cli.command("revoke [selector]", "Revoke a session.");
|
|
147
147
|
cli.command("mcp", "Start a stdio MCP server that gives MCP clients access to connected apps' tools.").option(
|
|
148
148
|
"--scheme <scheme>",
|
|
@@ -166,6 +166,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
166
166
|
"eventBufferSize",
|
|
167
167
|
"auditRetentionDays",
|
|
168
168
|
"daemonLogMaxBytes",
|
|
169
|
+
"eventsLogMaxBytes",
|
|
169
170
|
"policy",
|
|
170
171
|
"advertisedIp",
|
|
171
172
|
"scheme",
|
|
@@ -225,6 +226,7 @@ var defaultConfig = (paths) => {
|
|
|
225
226
|
eventBufferSize: 256,
|
|
226
227
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
227
228
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
229
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
228
230
|
restartDaemonOnVersionMismatch: false,
|
|
229
231
|
policy: {
|
|
230
232
|
default: "allow",
|
|
@@ -287,6 +289,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
287
289
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
288
290
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
289
291
|
}
|
|
292
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
293
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
294
|
+
}
|
|
290
295
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
291
296
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
292
297
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -335,6 +340,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
335
340
|
socketPath: join3(stateDir, "daemon.sock"),
|
|
336
341
|
pidFilePath: join3(stateDir, "daemon.pid"),
|
|
337
342
|
logFilePath: join3(stateDir, "daemon.log"),
|
|
343
|
+
eventsLogPath: join3(stateDir, "events.log"),
|
|
338
344
|
keyPath: join3(stateDir, "key.pem"),
|
|
339
345
|
configPath: join3(stateDir, "config.json"),
|
|
340
346
|
auditDir: join3(stateDir, "audit"),
|
|
@@ -139,6 +139,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
139
139
|
"eventBufferSize",
|
|
140
140
|
"auditRetentionDays",
|
|
141
141
|
"daemonLogMaxBytes",
|
|
142
|
+
"eventsLogMaxBytes",
|
|
142
143
|
"policy",
|
|
143
144
|
"advertisedIp",
|
|
144
145
|
"scheme",
|
|
@@ -198,6 +199,7 @@ var defaultConfig = (paths) => {
|
|
|
198
199
|
eventBufferSize: 256,
|
|
199
200
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
200
201
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
202
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
201
203
|
restartDaemonOnVersionMismatch: false,
|
|
202
204
|
policy: {
|
|
203
205
|
default: "allow",
|
|
@@ -260,6 +262,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
260
262
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
261
263
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
262
264
|
}
|
|
265
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
266
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
267
|
+
}
|
|
263
268
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
264
269
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
265
270
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -609,7 +614,6 @@ var createCallsManager = (options) => {
|
|
|
609
614
|
|
|
610
615
|
// src/daemon/event-bus.ts
|
|
611
616
|
var TERMINAL_EVENT_KINDS = /* @__PURE__ */ new Set(["session_expired", "session_revoked"]);
|
|
612
|
-
var EXCLUDED_FROM_RETENTION = /* @__PURE__ */ new Set(["tool_call_progress"]);
|
|
613
617
|
var createEventBus = (options = {}) => {
|
|
614
618
|
const clock = options.clock ?? { now: () => /* @__PURE__ */ new Date() };
|
|
615
619
|
const bufferSize = options.bufferSize ?? 256;
|
|
@@ -640,7 +644,7 @@ var createEventBus = (options = {}) => {
|
|
|
640
644
|
if (TERMINAL_EVENT_KINDS.has(notification.kind)) {
|
|
641
645
|
buffers.delete(sessionId);
|
|
642
646
|
cursors.delete(sessionId);
|
|
643
|
-
} else if (
|
|
647
|
+
} else if (notification.kind === "app_event") {
|
|
644
648
|
appendToBuffer(sessionId, notification);
|
|
645
649
|
}
|
|
646
650
|
}
|
|
@@ -664,10 +668,6 @@ var createEventBus = (options = {}) => {
|
|
|
664
668
|
if (query.since !== void 0) {
|
|
665
669
|
events = events.filter((event) => event.seq > query.since);
|
|
666
670
|
}
|
|
667
|
-
if (query.kinds !== void 0) {
|
|
668
|
-
const kinds = new Set(query.kinds);
|
|
669
|
-
events = events.filter((event) => kinds.has(event.kind));
|
|
670
|
-
}
|
|
671
671
|
if (query.limit !== void 0 && events.length > query.limit) {
|
|
672
672
|
events = events.slice(0, query.limit);
|
|
673
673
|
}
|
|
@@ -681,6 +681,28 @@ var createEventBus = (options = {}) => {
|
|
|
681
681
|
};
|
|
682
682
|
};
|
|
683
683
|
|
|
684
|
+
// src/daemon/events-log.ts
|
|
685
|
+
var createEventsLog = (options) => {
|
|
686
|
+
const { file, maxBytes, warn } = options;
|
|
687
|
+
let queue = Promise.resolve();
|
|
688
|
+
return {
|
|
689
|
+
record: (event) => {
|
|
690
|
+
const line = JSON.stringify(event);
|
|
691
|
+
queue = queue.then(async () => {
|
|
692
|
+
try {
|
|
693
|
+
await file.append(line);
|
|
694
|
+
if (await file.size() > maxBytes) {
|
|
695
|
+
await file.rotate();
|
|
696
|
+
}
|
|
697
|
+
} catch (error) {
|
|
698
|
+
warn(`appduct daemon: failed to write events.log: ${error.message}`);
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
},
|
|
702
|
+
flush: () => queue
|
|
703
|
+
};
|
|
704
|
+
};
|
|
705
|
+
|
|
684
706
|
// src/daemon/listener.ts
|
|
685
707
|
import { createServer as createHttpsServer } from "node:https";
|
|
686
708
|
import { isSessionClaimMessage, isSessionResumeMessage, isSessionBoundMessage } from "@appduct/shared";
|
|
@@ -1409,6 +1431,37 @@ var acquirePidfile = async (pidFilePath, options = {}) => {
|
|
|
1409
1431
|
throw new Error(`Failed to acquire the Appduct daemon pidfile at "${pidFilePath}".`);
|
|
1410
1432
|
};
|
|
1411
1433
|
|
|
1434
|
+
// src/daemon/node-append-only-file.ts
|
|
1435
|
+
import { open as open3, rename, stat as stat2 } from "node:fs/promises";
|
|
1436
|
+
var NodeAppendOnlyFile = class {
|
|
1437
|
+
constructor(path) {
|
|
1438
|
+
this.path = path;
|
|
1439
|
+
}
|
|
1440
|
+
async append(line) {
|
|
1441
|
+
const handle = await open3(this.path, "a", 384);
|
|
1442
|
+
try {
|
|
1443
|
+
await handle.appendFile(`${line}
|
|
1444
|
+
`);
|
|
1445
|
+
await handle.chmod(384);
|
|
1446
|
+
} finally {
|
|
1447
|
+
await handle.close();
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
async size() {
|
|
1451
|
+
try {
|
|
1452
|
+
return (await stat2(this.path)).size;
|
|
1453
|
+
} catch (error) {
|
|
1454
|
+
if (error.code === "ENOENT") {
|
|
1455
|
+
return 0;
|
|
1456
|
+
}
|
|
1457
|
+
throw error;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
async rotate() {
|
|
1461
|
+
await rename(this.path, `${this.path}.1`);
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1412
1465
|
// src/daemon/rpc-server.ts
|
|
1413
1466
|
import { createServer } from "node:net";
|
|
1414
1467
|
import { chmod as chmod2, rm as rm3 } from "node:fs/promises";
|
|
@@ -1594,6 +1647,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
1594
1647
|
socketPath: join4(stateDir, "daemon.sock"),
|
|
1595
1648
|
pidFilePath: join4(stateDir, "daemon.pid"),
|
|
1596
1649
|
logFilePath: join4(stateDir, "daemon.log"),
|
|
1650
|
+
eventsLogPath: join4(stateDir, "events.log"),
|
|
1597
1651
|
keyPath: join4(stateDir, "key.pem"),
|
|
1598
1652
|
configPath: join4(stateDir, "config.json"),
|
|
1599
1653
|
auditDir: join4(stateDir, "audit"),
|
|
@@ -1612,7 +1666,7 @@ var ensureStateDir = async (stateDir) => {
|
|
|
1612
1666
|
};
|
|
1613
1667
|
|
|
1614
1668
|
// src/daemon/tls.ts
|
|
1615
|
-
import { stat as
|
|
1669
|
+
import { stat as stat3, readFile as readFile3 } from "node:fs/promises";
|
|
1616
1670
|
|
|
1617
1671
|
// src/host-certificate.ts
|
|
1618
1672
|
import "reflect-metadata";
|
|
@@ -1789,7 +1843,7 @@ var generateHostCertificate = async (keyPem, advertisedIp) => {
|
|
|
1789
1843
|
// src/key-material.ts
|
|
1790
1844
|
import { generateKeyPairSync } from "node:crypto";
|
|
1791
1845
|
import { dirname as dirname2 } from "node:path";
|
|
1792
|
-
import { mkdir as mkdir3, rename, rm as rm4, writeFile } from "node:fs/promises";
|
|
1846
|
+
import { mkdir as mkdir3, rename as rename2, rm as rm4, writeFile } from "node:fs/promises";
|
|
1793
1847
|
var generatePrivateKeyPem = () => {
|
|
1794
1848
|
const { privateKey } = generateKeyPairSync("rsa", {
|
|
1795
1849
|
modulusLength: 2048,
|
|
@@ -1809,7 +1863,7 @@ var writePrivateKeyAtomically = async (path, keyPem) => {
|
|
|
1809
1863
|
mode: 384,
|
|
1810
1864
|
flag: "wx"
|
|
1811
1865
|
});
|
|
1812
|
-
await
|
|
1866
|
+
await rename2(temporaryPath, path);
|
|
1813
1867
|
} catch (error) {
|
|
1814
1868
|
await rm4(temporaryPath, { force: true }).catch(() => {
|
|
1815
1869
|
});
|
|
@@ -1825,7 +1879,7 @@ var HostKeyError = class extends Error {
|
|
|
1825
1879
|
}
|
|
1826
1880
|
};
|
|
1827
1881
|
var loadHostKeyPem = async (keyPath) => {
|
|
1828
|
-
const fileStat = await
|
|
1882
|
+
const fileStat = await stat3(keyPath);
|
|
1829
1883
|
if ((fileStat.mode & 63) !== 0) {
|
|
1830
1884
|
throw new HostKeyError(
|
|
1831
1885
|
`Appduct host key at "${keyPath}" is group- or world-readable (mode ${(fileStat.mode & 511).toString(8)}). Refusing to load it \u2014 run "chmod 600 ${keyPath}" or re-run "appduct keygen".`
|
|
@@ -2030,14 +2084,6 @@ var asEventsSinceParams = (params) => {
|
|
|
2030
2084
|
if (since !== void 0 && (typeof since !== "number" || !Number.isInteger(since) || since < 0)) {
|
|
2031
2085
|
throw new RpcApplicationError("invalid_request", '"since" must be a non-negative integer.');
|
|
2032
2086
|
}
|
|
2033
|
-
const kindsRaw = record.kinds;
|
|
2034
|
-
let kinds;
|
|
2035
|
-
if (kindsRaw !== void 0) {
|
|
2036
|
-
if (!Array.isArray(kindsRaw) || !kindsRaw.every((kind) => typeof kind === "string" && KNOWN_EVENT_KINDS.has(kind))) {
|
|
2037
|
-
throw new RpcApplicationError("invalid_request", '"kinds" must be an array of known event kinds.');
|
|
2038
|
-
}
|
|
2039
|
-
kinds = kindsRaw;
|
|
2040
|
-
}
|
|
2041
2087
|
const limit = record.limit;
|
|
2042
2088
|
if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit <= 0)) {
|
|
2043
2089
|
throw new RpcApplicationError("invalid_request", '"limit" must be a positive integer.');
|
|
@@ -2045,7 +2091,6 @@ var asEventsSinceParams = (params) => {
|
|
|
2045
2091
|
return {
|
|
2046
2092
|
selector,
|
|
2047
2093
|
since,
|
|
2048
|
-
kinds,
|
|
2049
2094
|
limit
|
|
2050
2095
|
};
|
|
2051
2096
|
};
|
|
@@ -2080,10 +2125,19 @@ var startDaemon = async (options) => {
|
|
|
2080
2125
|
retentionDays: config.auditRetentionDays,
|
|
2081
2126
|
warn: options.warn
|
|
2082
2127
|
});
|
|
2128
|
+
const eventsLog = createEventsLog({
|
|
2129
|
+
file: new NodeAppendOnlyFile(paths.eventsLogPath),
|
|
2130
|
+
maxBytes: config.eventsLogMaxBytes,
|
|
2131
|
+
warn: options.warn ?? ((message) => {
|
|
2132
|
+
process.stderr.write(`${message}
|
|
2133
|
+
`);
|
|
2134
|
+
})
|
|
2135
|
+
});
|
|
2083
2136
|
let auditPruneInterval;
|
|
2084
2137
|
let pidfile;
|
|
2085
2138
|
let server;
|
|
2086
2139
|
let listener;
|
|
2140
|
+
let tlsManager;
|
|
2087
2141
|
let sessionManager;
|
|
2088
2142
|
let callsManager;
|
|
2089
2143
|
let eventBus;
|
|
@@ -2110,6 +2164,7 @@ var startDaemon = async (options) => {
|
|
|
2110
2164
|
await pidfile?.release();
|
|
2111
2165
|
await rm5(getSocketPath(paths), { force: true });
|
|
2112
2166
|
await auditLogger.flush();
|
|
2167
|
+
await eventsLog.flush();
|
|
2113
2168
|
} finally {
|
|
2114
2169
|
resolveExited();
|
|
2115
2170
|
}
|
|
@@ -2122,8 +2177,14 @@ var startDaemon = async (options) => {
|
|
|
2122
2177
|
});
|
|
2123
2178
|
eventBus = createEventBus({ clock, bufferSize: config.eventBufferSize });
|
|
2124
2179
|
const activeEventBus = eventBus;
|
|
2180
|
+
activeEventBus.subscribe((event) => {
|
|
2181
|
+
if (event.kind !== "app_event") {
|
|
2182
|
+
eventsLog.record(event);
|
|
2183
|
+
}
|
|
2184
|
+
});
|
|
2125
2185
|
const detectAddress = options.detectAddress ?? (() => detectAdvertisedAddress({ override: config.advertisedIp }));
|
|
2126
2186
|
const tls = await createTlsManager({ keyPath: config.keyPath, detectAddress, warn: options.warn });
|
|
2187
|
+
tlsManager = tls;
|
|
2127
2188
|
sessionManager = createSessionManager({
|
|
2128
2189
|
graceSeconds: config.graceSeconds,
|
|
2129
2190
|
keepaliveIntervalSeconds: config.keepaliveIntervalSeconds,
|
|
@@ -2367,9 +2428,9 @@ var startDaemon = async (options) => {
|
|
|
2367
2428
|
return { ok: true };
|
|
2368
2429
|
},
|
|
2369
2430
|
[RPC_METHODS.eventsSince]: (params) => {
|
|
2370
|
-
const { selector, since,
|
|
2431
|
+
const { selector, since, limit } = asEventsSinceParams(params);
|
|
2371
2432
|
const resolved = activeSessionManager.describe(selector);
|
|
2372
|
-
return activeEventBus.since(resolved.sessionId, { since,
|
|
2433
|
+
return activeEventBus.since(resolved.sessionId, { since, limit });
|
|
2373
2434
|
}
|
|
2374
2435
|
}
|
|
2375
2436
|
});
|
|
@@ -2395,6 +2456,7 @@ var startDaemon = async (options) => {
|
|
|
2395
2456
|
startedAt,
|
|
2396
2457
|
server,
|
|
2397
2458
|
listener,
|
|
2459
|
+
tls: tlsManager,
|
|
2398
2460
|
eventBus,
|
|
2399
2461
|
exited,
|
|
2400
2462
|
shutdown
|
|
@@ -22,6 +22,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
22
22
|
"eventBufferSize",
|
|
23
23
|
"auditRetentionDays",
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
|
+
"eventsLogMaxBytes",
|
|
25
26
|
"policy",
|
|
26
27
|
"advertisedIp",
|
|
27
28
|
"scheme",
|
|
@@ -81,6 +82,7 @@ var defaultConfig = (paths) => {
|
|
|
81
82
|
eventBufferSize: 256,
|
|
82
83
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
83
84
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
84
86
|
restartDaemonOnVersionMismatch: false,
|
|
85
87
|
policy: {
|
|
86
88
|
default: "allow",
|
|
@@ -143,6 +145,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
143
145
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
144
146
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
145
147
|
}
|
|
148
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
149
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
150
|
+
}
|
|
146
151
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
147
152
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
148
153
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -243,6 +248,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
243
248
|
socketPath: join(stateDir, "daemon.sock"),
|
|
244
249
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
245
250
|
logFilePath: join(stateDir, "daemon.log"),
|
|
251
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
246
252
|
keyPath: join(stateDir, "key.pem"),
|
|
247
253
|
configPath: join(stateDir, "config.json"),
|
|
248
254
|
auditDir: join(stateDir, "audit"),
|
|
@@ -66,6 +66,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
66
66
|
"eventBufferSize",
|
|
67
67
|
"auditRetentionDays",
|
|
68
68
|
"daemonLogMaxBytes",
|
|
69
|
+
"eventsLogMaxBytes",
|
|
69
70
|
"policy",
|
|
70
71
|
"advertisedIp",
|
|
71
72
|
"scheme",
|
|
@@ -125,6 +126,7 @@ var defaultConfig = (paths) => {
|
|
|
125
126
|
eventBufferSize: 256,
|
|
126
127
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
127
128
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
129
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
128
130
|
restartDaemonOnVersionMismatch: false,
|
|
129
131
|
policy: {
|
|
130
132
|
default: "allow",
|
|
@@ -187,6 +189,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
187
189
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
188
190
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
189
191
|
}
|
|
192
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
193
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
194
|
+
}
|
|
190
195
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
191
196
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
192
197
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -287,6 +292,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
287
292
|
socketPath: join3(stateDir, "daemon.sock"),
|
|
288
293
|
pidFilePath: join3(stateDir, "daemon.pid"),
|
|
289
294
|
logFilePath: join3(stateDir, "daemon.log"),
|
|
295
|
+
eventsLogPath: join3(stateDir, "events.log"),
|
|
290
296
|
keyPath: join3(stateDir, "key.pem"),
|
|
291
297
|
configPath: join3(stateDir, "config.json"),
|
|
292
298
|
auditDir: join3(stateDir, "audit"),
|
|
@@ -49,6 +49,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
49
49
|
socketPath: join(stateDir, "daemon.sock"),
|
|
50
50
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
51
51
|
logFilePath: join(stateDir, "daemon.log"),
|
|
52
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
52
53
|
keyPath: join(stateDir, "key.pem"),
|
|
53
54
|
configPath: join(stateDir, "config.json"),
|
|
54
55
|
auditDir: join(stateDir, "audit"),
|
|
@@ -84,6 +85,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
84
85
|
"eventBufferSize",
|
|
85
86
|
"auditRetentionDays",
|
|
86
87
|
"daemonLogMaxBytes",
|
|
88
|
+
"eventsLogMaxBytes",
|
|
87
89
|
"policy",
|
|
88
90
|
"advertisedIp",
|
|
89
91
|
"scheme",
|
|
@@ -143,6 +145,7 @@ var defaultConfig = (paths) => {
|
|
|
143
145
|
eventBufferSize: 256,
|
|
144
146
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
145
147
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
148
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
146
149
|
restartDaemonOnVersionMismatch: false,
|
|
147
150
|
policy: {
|
|
148
151
|
default: "allow",
|
|
@@ -205,6 +208,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
205
208
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
206
209
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
207
210
|
}
|
|
211
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
212
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
213
|
+
}
|
|
208
214
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
209
215
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
210
216
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -22,6 +22,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
22
22
|
"eventBufferSize",
|
|
23
23
|
"auditRetentionDays",
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
|
+
"eventsLogMaxBytes",
|
|
25
26
|
"policy",
|
|
26
27
|
"advertisedIp",
|
|
27
28
|
"scheme",
|
|
@@ -81,6 +82,7 @@ var defaultConfig = (paths) => {
|
|
|
81
82
|
eventBufferSize: 256,
|
|
82
83
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
83
84
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
84
86
|
restartDaemonOnVersionMismatch: false,
|
|
85
87
|
policy: {
|
|
86
88
|
default: "allow",
|
|
@@ -143,6 +145,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
143
145
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
144
146
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
145
147
|
}
|
|
148
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
149
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
150
|
+
}
|
|
146
151
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
147
152
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
148
153
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -243,6 +248,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
243
248
|
socketPath: join(stateDir, "daemon.sock"),
|
|
244
249
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
245
250
|
logFilePath: join(stateDir, "daemon.log"),
|
|
251
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
246
252
|
keyPath: join(stateDir, "key.pem"),
|
|
247
253
|
configPath: join(stateDir, "config.json"),
|
|
248
254
|
auditDir: join(stateDir, "audit"),
|
|
@@ -1028,7 +1034,8 @@ var handleEventsCommand = async (options, context) => {
|
|
|
1028
1034
|
const stream = await openDaemonStream({ stateDir: context.stateDir, spawn: context.spawn });
|
|
1029
1035
|
try {
|
|
1030
1036
|
await stream.call(RPC_METHODS2.eventsSubscribe, {
|
|
1031
|
-
sessionSelector: options.selector
|
|
1037
|
+
sessionSelector: options.selector,
|
|
1038
|
+
kinds: ["app_event"]
|
|
1032
1039
|
});
|
|
1033
1040
|
} catch (error) {
|
|
1034
1041
|
stream.close();
|
|
@@ -42,6 +42,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
42
42
|
"eventBufferSize",
|
|
43
43
|
"auditRetentionDays",
|
|
44
44
|
"daemonLogMaxBytes",
|
|
45
|
+
"eventsLogMaxBytes",
|
|
45
46
|
"policy",
|
|
46
47
|
"advertisedIp",
|
|
47
48
|
"scheme",
|
|
@@ -101,6 +102,7 @@ var defaultConfig = (paths) => {
|
|
|
101
102
|
eventBufferSize: 256,
|
|
102
103
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
103
104
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
105
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
104
106
|
restartDaemonOnVersionMismatch: false,
|
|
105
107
|
policy: {
|
|
106
108
|
default: "allow",
|
|
@@ -163,6 +165,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
163
165
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
164
166
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
165
167
|
}
|
|
168
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
169
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
170
|
+
}
|
|
166
171
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
167
172
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
168
173
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -263,6 +268,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
263
268
|
socketPath: join(stateDir, "daemon.sock"),
|
|
264
269
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
265
270
|
logFilePath: join(stateDir, "daemon.log"),
|
|
271
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
266
272
|
keyPath: join(stateDir, "key.pem"),
|
|
267
273
|
configPath: join(stateDir, "config.json"),
|
|
268
274
|
auditDir: join(stateDir, "audit"),
|
|
@@ -9,6 +9,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
9
9
|
socketPath: join(stateDir, "daemon.sock"),
|
|
10
10
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
11
11
|
logFilePath: join(stateDir, "daemon.log"),
|
|
12
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
12
13
|
keyPath: join(stateDir, "key.pem"),
|
|
13
14
|
configPath: join(stateDir, "config.json"),
|
|
14
15
|
auditDir: join(stateDir, "audit"),
|
package/dist/cli/routes/link.js
CHANGED
|
@@ -25,6 +25,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
25
25
|
"eventBufferSize",
|
|
26
26
|
"auditRetentionDays",
|
|
27
27
|
"daemonLogMaxBytes",
|
|
28
|
+
"eventsLogMaxBytes",
|
|
28
29
|
"policy",
|
|
29
30
|
"advertisedIp",
|
|
30
31
|
"scheme",
|
|
@@ -84,6 +85,7 @@ var defaultConfig = (paths) => {
|
|
|
84
85
|
eventBufferSize: 256,
|
|
85
86
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
86
87
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
88
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
87
89
|
restartDaemonOnVersionMismatch: false,
|
|
88
90
|
policy: {
|
|
89
91
|
default: "allow",
|
|
@@ -146,6 +148,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
146
148
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
147
149
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
148
150
|
}
|
|
151
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
152
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
153
|
+
}
|
|
149
154
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
150
155
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
151
156
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -246,6 +251,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
246
251
|
socketPath: join(stateDir, "daemon.sock"),
|
|
247
252
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
248
253
|
logFilePath: join(stateDir, "daemon.log"),
|
|
254
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
249
255
|
keyPath: join(stateDir, "key.pem"),
|
|
250
256
|
configPath: join(stateDir, "config.json"),
|
|
251
257
|
auditDir: join(stateDir, "audit"),
|
package/dist/cli/routes/ls.js
CHANGED
|
@@ -22,6 +22,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
22
22
|
"eventBufferSize",
|
|
23
23
|
"auditRetentionDays",
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
|
+
"eventsLogMaxBytes",
|
|
25
26
|
"policy",
|
|
26
27
|
"advertisedIp",
|
|
27
28
|
"scheme",
|
|
@@ -81,6 +82,7 @@ var defaultConfig = (paths) => {
|
|
|
81
82
|
eventBufferSize: 256,
|
|
82
83
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
83
84
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
84
86
|
restartDaemonOnVersionMismatch: false,
|
|
85
87
|
policy: {
|
|
86
88
|
default: "allow",
|
|
@@ -143,6 +145,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
143
145
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
144
146
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
145
147
|
}
|
|
148
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
149
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
150
|
+
}
|
|
146
151
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
147
152
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
148
153
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -243,6 +248,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
243
248
|
socketPath: join(stateDir, "daemon.sock"),
|
|
244
249
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
245
250
|
logFilePath: join(stateDir, "daemon.log"),
|
|
251
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
246
252
|
keyPath: join(stateDir, "key.pem"),
|
|
247
253
|
configPath: join(stateDir, "config.json"),
|
|
248
254
|
auditDir: join(stateDir, "audit"),
|
package/dist/cli/routes/mcp.js
CHANGED
|
@@ -12,6 +12,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
12
12
|
"eventBufferSize",
|
|
13
13
|
"auditRetentionDays",
|
|
14
14
|
"daemonLogMaxBytes",
|
|
15
|
+
"eventsLogMaxBytes",
|
|
15
16
|
"policy",
|
|
16
17
|
"advertisedIp",
|
|
17
18
|
"scheme",
|
|
@@ -71,6 +72,7 @@ var defaultConfig = (paths) => {
|
|
|
71
72
|
eventBufferSize: 256,
|
|
72
73
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
73
74
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
75
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
74
76
|
restartDaemonOnVersionMismatch: false,
|
|
75
77
|
policy: {
|
|
76
78
|
default: "allow",
|
|
@@ -133,6 +135,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
133
135
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
134
136
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
135
137
|
}
|
|
138
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
139
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
140
|
+
}
|
|
136
141
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
137
142
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
138
143
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -178,6 +183,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
178
183
|
socketPath: join(stateDir, "daemon.sock"),
|
|
179
184
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
180
185
|
logFilePath: join(stateDir, "daemon.log"),
|
|
186
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
181
187
|
keyPath: join(stateDir, "key.pem"),
|
|
182
188
|
configPath: join(stateDir, "config.json"),
|
|
183
189
|
auditDir: join(stateDir, "audit"),
|
|
@@ -2650,27 +2656,24 @@ var resolveAppTool = async (call, selector, name) => {
|
|
|
2650
2656
|
|
|
2651
2657
|
// src/mcp/events-tool.ts
|
|
2652
2658
|
import {
|
|
2653
|
-
RPC_METHODS as RPC_METHODS5
|
|
2654
|
-
EVENT_KINDS
|
|
2659
|
+
RPC_METHODS as RPC_METHODS5
|
|
2655
2660
|
} from "@appduct/shared";
|
|
2656
2661
|
var EVENTS_TOOL_NAME = "appduct_events";
|
|
2657
2662
|
var WAIT_FOR_EVENT_TOOL_NAME = "appduct_wait_for_event";
|
|
2658
2663
|
var DEFAULT_WAIT_FOR_EVENT_TIMEOUT_MS = 12e4;
|
|
2659
2664
|
var MAX_WAIT_FOR_EVENT_TIMEOUT_MS = 25 * 60 * 1e3;
|
|
2660
2665
|
var WAIT_FOR_EVENT_PROGRESS_INTERVAL_MS = 6e4;
|
|
2661
|
-
var KNOWN_EVENT_KINDS = new Set(EVENT_KINDS);
|
|
2662
2666
|
var clampWaitForEventTimeoutMs = (requestedMs) => {
|
|
2663
2667
|
return Math.min(requestedMs ?? DEFAULT_WAIT_FOR_EVENT_TIMEOUT_MS, MAX_WAIT_FOR_EVENT_TIMEOUT_MS);
|
|
2664
2668
|
};
|
|
2665
2669
|
var EVENTS_TOOL_DESCRIPTOR = {
|
|
2666
2670
|
name: EVENTS_TOOL_NAME,
|
|
2667
|
-
description: "Drain events
|
|
2671
|
+
description: "Drain the events the app posted with postEvent(name, payload) that the daemon retained for a session since a cursor, for checking what the app reported after calling a tool or triggering app behavior. With no selector, targets the sole active/suspended session. Returns { events, cursor }; pass cursor back as since on the next call to avoid re-reading events you've already seen. limit (if given) keeps the OLDEST events in the window and advances cursor only past what was actually returned, so repeated calls page forward through everything retained rather than skipping ahead.",
|
|
2668
2672
|
inputSchema: {
|
|
2669
2673
|
type: "object",
|
|
2670
2674
|
properties: {
|
|
2671
2675
|
selector: { type: "string" },
|
|
2672
2676
|
since: { type: "integer", minimum: 0 },
|
|
2673
|
-
kinds: { type: "array", items: { type: "string", enum: EVENT_KINDS } },
|
|
2674
2677
|
limit: { type: "integer", exclusiveMinimum: 0 }
|
|
2675
2678
|
},
|
|
2676
2679
|
additionalProperties: false
|
|
@@ -2734,14 +2737,13 @@ var asOptionalPositiveNumber2 = (value, field) => {
|
|
|
2734
2737
|
}
|
|
2735
2738
|
return value;
|
|
2736
2739
|
};
|
|
2737
|
-
var
|
|
2738
|
-
if (
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2740
|
+
var rejectKinds = (args) => {
|
|
2741
|
+
if (args.kinds !== void 0) {
|
|
2742
|
+
throw new McpBuiltinToolError(
|
|
2743
|
+
"invalid_request",
|
|
2744
|
+
'"kinds" is not supported: these tools return only the events the app posted with postEvent.'
|
|
2745
|
+
);
|
|
2743
2746
|
}
|
|
2744
|
-
return value;
|
|
2745
2747
|
};
|
|
2746
2748
|
var isMatchPrimitive = (value) => {
|
|
2747
2749
|
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
@@ -2766,10 +2768,10 @@ var asOptionalMatch = (value) => {
|
|
|
2766
2768
|
};
|
|
2767
2769
|
var handleEventsTool = async (rawArgs, deps) => {
|
|
2768
2770
|
const args = asRecord3(rawArgs);
|
|
2771
|
+
rejectKinds(args);
|
|
2769
2772
|
return deps.call(RPC_METHODS5.eventsSince, {
|
|
2770
2773
|
selector: asOptionalString2(args.selector, "selector"),
|
|
2771
2774
|
since: asOptionalNonNegativeInteger(args.since, "since"),
|
|
2772
|
-
kinds: asOptionalEventKinds(args.kinds),
|
|
2773
2775
|
limit: asOptionalPositiveInteger(args.limit, "limit")
|
|
2774
2776
|
});
|
|
2775
2777
|
};
|
|
@@ -2782,6 +2784,7 @@ var payloadShallowMatches = (payload, match) => {
|
|
|
2782
2784
|
};
|
|
2783
2785
|
var handleWaitForEventTool = async (rawArgs, deps) => {
|
|
2784
2786
|
const args = asRecord3(rawArgs);
|
|
2787
|
+
rejectKinds(args);
|
|
2785
2788
|
const selector = asOptionalString2(args.selector, "selector");
|
|
2786
2789
|
const name = asOptionalString2(args.name, "name");
|
|
2787
2790
|
if (!name) {
|
|
@@ -2824,8 +2827,7 @@ var handleWaitForEventTool = async (rawArgs, deps) => {
|
|
|
2824
2827
|
await stream.call(RPC_METHODS5.eventsSubscribe, { sessionSelector: sessionId, kinds: ["app_event"] });
|
|
2825
2828
|
const sinceResult = await stream.call(RPC_METHODS5.eventsSince, {
|
|
2826
2829
|
selector: sessionId,
|
|
2827
|
-
since
|
|
2828
|
-
kinds: ["app_event"]
|
|
2830
|
+
since
|
|
2829
2831
|
});
|
|
2830
2832
|
const seenSeqs = /* @__PURE__ */ new Set();
|
|
2831
2833
|
const backlog = [];
|
|
@@ -22,6 +22,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
22
22
|
"eventBufferSize",
|
|
23
23
|
"auditRetentionDays",
|
|
24
24
|
"daemonLogMaxBytes",
|
|
25
|
+
"eventsLogMaxBytes",
|
|
25
26
|
"policy",
|
|
26
27
|
"advertisedIp",
|
|
27
28
|
"scheme",
|
|
@@ -81,6 +82,7 @@ var defaultConfig = (paths) => {
|
|
|
81
82
|
eventBufferSize: 256,
|
|
82
83
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
83
84
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
85
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
84
86
|
restartDaemonOnVersionMismatch: false,
|
|
85
87
|
policy: {
|
|
86
88
|
default: "allow",
|
|
@@ -143,6 +145,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
143
145
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
144
146
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
145
147
|
}
|
|
148
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
149
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
150
|
+
}
|
|
146
151
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
147
152
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
148
153
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -243,6 +248,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
243
248
|
socketPath: join(stateDir, "daemon.sock"),
|
|
244
249
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
245
250
|
logFilePath: join(stateDir, "daemon.log"),
|
|
251
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
246
252
|
keyPath: join(stateDir, "key.pem"),
|
|
247
253
|
configPath: join(stateDir, "config.json"),
|
|
248
254
|
auditDir: join(stateDir, "audit"),
|
package/dist/cli/routes/tools.js
CHANGED
|
@@ -25,6 +25,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
25
25
|
"eventBufferSize",
|
|
26
26
|
"auditRetentionDays",
|
|
27
27
|
"daemonLogMaxBytes",
|
|
28
|
+
"eventsLogMaxBytes",
|
|
28
29
|
"policy",
|
|
29
30
|
"advertisedIp",
|
|
30
31
|
"scheme",
|
|
@@ -84,6 +85,7 @@ var defaultConfig = (paths) => {
|
|
|
84
85
|
eventBufferSize: 256,
|
|
85
86
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
86
87
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
88
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
87
89
|
restartDaemonOnVersionMismatch: false,
|
|
88
90
|
policy: {
|
|
89
91
|
default: "allow",
|
|
@@ -146,6 +148,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
146
148
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
147
149
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
148
150
|
}
|
|
151
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
152
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
153
|
+
}
|
|
149
154
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
150
155
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
151
156
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -246,6 +251,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
246
251
|
socketPath: join(stateDir, "daemon.sock"),
|
|
247
252
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
248
253
|
logFilePath: join(stateDir, "daemon.log"),
|
|
254
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
249
255
|
keyPath: join(stateDir, "key.pem"),
|
|
250
256
|
configPath: join(stateDir, "config.json"),
|
|
251
257
|
auditDir: join(stateDir, "audit"),
|
package/dist/client/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
14
14
|
socketPath: join(stateDir, "daemon.sock"),
|
|
15
15
|
pidFilePath: join(stateDir, "daemon.pid"),
|
|
16
16
|
logFilePath: join(stateDir, "daemon.log"),
|
|
17
|
+
eventsLogPath: join(stateDir, "events.log"),
|
|
17
18
|
keyPath: join(stateDir, "key.pem"),
|
|
18
19
|
configPath: join(stateDir, "config.json"),
|
|
19
20
|
auditDir: join(stateDir, "audit"),
|
|
@@ -49,6 +50,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
49
50
|
"eventBufferSize",
|
|
50
51
|
"auditRetentionDays",
|
|
51
52
|
"daemonLogMaxBytes",
|
|
53
|
+
"eventsLogMaxBytes",
|
|
52
54
|
"policy",
|
|
53
55
|
"advertisedIp",
|
|
54
56
|
"scheme",
|
|
@@ -108,6 +110,7 @@ var defaultConfig = (paths) => {
|
|
|
108
110
|
eventBufferSize: 256,
|
|
109
111
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
110
112
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
113
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
111
114
|
restartDaemonOnVersionMismatch: false,
|
|
112
115
|
policy: {
|
|
113
116
|
default: "allow",
|
|
@@ -170,6 +173,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
170
173
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
171
174
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
172
175
|
}
|
|
176
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
177
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
178
|
+
}
|
|
173
179
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
174
180
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
175
181
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -1134,8 +1140,7 @@ var makeAppClient = (stream, sessionId) => {
|
|
|
1134
1140
|
const result = await stream.call(RPC_METHODS2.eventsSince, {
|
|
1135
1141
|
selector: sessionId,
|
|
1136
1142
|
since: options.since,
|
|
1137
|
-
limit: options.limit
|
|
1138
|
-
kinds: ["app_event"]
|
|
1143
|
+
limit: options.limit
|
|
1139
1144
|
});
|
|
1140
1145
|
return {
|
|
1141
1146
|
events: result.events.map((event) => appEventFrom(event, sessionId)).filter((event) => event !== void 0),
|
|
@@ -1194,8 +1199,7 @@ var makeAppClient = (stream, sessionId) => {
|
|
|
1194
1199
|
await stream.call(RPC_METHODS2.eventsSubscribe, { sessionSelector: sessionId, kinds: ["app_event"] });
|
|
1195
1200
|
const sinceResult = await stream.call(RPC_METHODS2.eventsSince, {
|
|
1196
1201
|
selector: sessionId,
|
|
1197
|
-
since: options.since
|
|
1198
|
-
kinds: ["app_event"]
|
|
1202
|
+
since: options.since
|
|
1199
1203
|
});
|
|
1200
1204
|
const seenSeqs = /* @__PURE__ */ new Set();
|
|
1201
1205
|
const backlog = [];
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `appduct events` (ARCHITECTURE.md §10): subscribes to `events.subscribe`
|
|
3
|
-
* connection and streams
|
|
2
|
+
* `appduct events` (ARCHITECTURE.md §10): subscribes to `events.subscribe` for `app_event` only
|
|
3
|
+
* over a persistent connection and streams the app's own events until interrupted (Ctrl-C) or the
|
|
4
|
+
* connection drops. Appduct's lifecycle and tool-call kinds are not printed (issue #98). This is
|
|
4
5
|
* the one command whose output isn't a single rendered `CliResult` — each event is written as it
|
|
5
6
|
* arrives (NDJSON under `--json`, a human line otherwise) — so it plugs into `executeHostedCommand`
|
|
6
7
|
* with a live reporter that suppresses the default one-shot bootstrap render (`cli/runner.ts`).
|
package/dist/daemon/config.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export type AppductConfig = {
|
|
|
34
34
|
graceSeconds: number;
|
|
35
35
|
linkTtlSeconds: number;
|
|
36
36
|
keepaliveIntervalSeconds: number;
|
|
37
|
-
/** Max retained `app_event
|
|
37
|
+
/** Max retained `app_event`s per session (ARCHITECTURE.md §5's `events.since`
|
|
38
38
|
* retention buffer); default 256. */
|
|
39
39
|
eventBufferSize: number;
|
|
40
40
|
/** Days of `audit/<YYYY-MM-DD>.jsonl` history to keep; files older than this are pruned on
|
|
@@ -43,6 +43,9 @@ export type AppductConfig = {
|
|
|
43
43
|
/** Size at which `daemon.log` is rotated to `daemon.log.1` before a daemon is spawned
|
|
44
44
|
* (ARCHITECTURE.md §3/§4). Default 10 MiB. */
|
|
45
45
|
daemonLogMaxBytes: number;
|
|
46
|
+
/** Size past which the daemon rotates `events.log` to `events.log.1` (ARCHITECTURE.md §3).
|
|
47
|
+
* Default 10 MiB. */
|
|
48
|
+
eventsLogMaxBytes: number;
|
|
46
49
|
policy: AppductPolicyConfig;
|
|
47
50
|
/**
|
|
48
51
|
* When the CLI/MCP client finds the running daemon on a different Appduct version, restart it
|
package/dist/daemon/daemon.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { type DaemonListener } from "./listener.js";
|
|
|
14
14
|
import { type RpcServer } from "./rpc-server.js";
|
|
15
15
|
import { type StateDirPaths } from "./state-dir.js";
|
|
16
16
|
import { type TimerFns } from "./timers.js";
|
|
17
|
+
import { type TlsManager } from "./tls.js";
|
|
17
18
|
/** How often audit retention runs after the startup prune (ARCHITECTURE.md §3: "once a day"). */
|
|
18
19
|
export declare const AUDIT_PRUNE_INTERVAL_MS: number;
|
|
19
20
|
export type DaemonOptions = {
|
|
@@ -33,6 +34,8 @@ export type RunningDaemon = {
|
|
|
33
34
|
startedAt: Date;
|
|
34
35
|
server: RpcServer;
|
|
35
36
|
listener: DaemonListener;
|
|
37
|
+
/** The host certificate the listener serves, so an in-process client can trust it. */
|
|
38
|
+
tls: TlsManager;
|
|
36
39
|
eventBus: EventBus;
|
|
37
40
|
/** Resolves once graceful teardown (sockets closed, RPC/listener closed, pidfile released) completes. */
|
|
38
41
|
exited: Promise<void>;
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* per-session retention ring buffer, and must never let a throwing subscriber take down the daemon
|
|
5
5
|
* or another subscriber.
|
|
6
6
|
*
|
|
7
|
-
* Retention (issue #6): every session-scoped event
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Retention (issue #6, #98): every session-scoped event gets a monotonically increasing per-session
|
|
8
|
+
* `seq`, but only `app_event` is appended to the per-session ring buffer, capped at `bufferSize`
|
|
9
|
+
* entries (oldest dropped first). Appduct's own kinds (lifecycle, tool calls) are fanned out live
|
|
10
|
+
* and never retained, so no number of tool calls can evict an app event. A
|
|
10
11
|
* session's buffer is discarded the moment it emits a terminal event (`session_expired` /
|
|
11
12
|
* `session_revoked`) — "terminal states free the alias" (sessions.ts) applies to retained events
|
|
12
13
|
* too, matching "no persisted history" (ARCHITECTURE.md §3/§13) — or via an explicit `drop()` for
|
|
@@ -22,7 +23,6 @@ export type EventBusEmitInput = Omit<EventNotification, "ts" | "seq"> & {
|
|
|
22
23
|
export type EventBusListener = (event: EventNotification) => void;
|
|
23
24
|
export type EventsSinceQuery = {
|
|
24
25
|
since?: number;
|
|
25
|
-
kinds?: EventKind[];
|
|
26
26
|
limit?: number;
|
|
27
27
|
};
|
|
28
28
|
export type EventsSinceQueryResult = {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon's own event log, `<stateDir>/events.log` (ARCHITECTURE.md §3): one JSON line per
|
|
3
|
+
* event, for debugging Appduct itself. The daemon decides which events to record; this module only
|
|
4
|
+
* writes them and keeps the file bounded.
|
|
5
|
+
*
|
|
6
|
+
* Writes are serialized on a promise queue, so {@link EventsLog.record} returns at once and never
|
|
7
|
+
* blocks the emitter. After each append the file is rotated to a single backup once it is over
|
|
8
|
+
* `maxBytes`, so the current file is never above the cap once a write has settled. A failed write
|
|
9
|
+
* or rotation is warned, never thrown, and never stops later writes.
|
|
10
|
+
*/
|
|
11
|
+
import type { EventNotification } from "@appduct/shared";
|
|
12
|
+
/** A file that only ever grows by whole lines, with one backup slot. */
|
|
13
|
+
export type AppendOnlyFile = {
|
|
14
|
+
/** Appends `line` plus a newline, creating the file at mode `0600` if it is missing. */
|
|
15
|
+
append(line: string): Promise<void>;
|
|
16
|
+
/** Current size in bytes; `0` when the file does not exist. */
|
|
17
|
+
size(): Promise<number>;
|
|
18
|
+
/** Moves the file to the backup slot, replacing any previous backup. */
|
|
19
|
+
rotate(): Promise<void>;
|
|
20
|
+
};
|
|
21
|
+
export type EventsLog = {
|
|
22
|
+
/** Queues `event` as one JSON line; returns immediately. */
|
|
23
|
+
record(event: EventNotification): void;
|
|
24
|
+
/** Resolves once every write queued so far has settled. */
|
|
25
|
+
flush(): Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
export declare const createEventsLog: (options: {
|
|
28
|
+
file: AppendOnlyFile;
|
|
29
|
+
maxBytes: number;
|
|
30
|
+
warn: (message: string) => void;
|
|
31
|
+
}) => EventsLog;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** In-memory {@link AppendOnlyFile} for tests: inspect the lines written and the backup, or make
|
|
2
|
+
* appends fail. */
|
|
3
|
+
import type { AppendOnlyFile } from "./events-log.js";
|
|
4
|
+
export declare class MemoryAppendOnlyFile implements AppendOnlyFile {
|
|
5
|
+
private current;
|
|
6
|
+
private backup;
|
|
7
|
+
private appendError;
|
|
8
|
+
append(line: string): Promise<void>;
|
|
9
|
+
size(): Promise<number>;
|
|
10
|
+
rotate(): Promise<void>;
|
|
11
|
+
/** Lines in the current file, without their newlines. */
|
|
12
|
+
lines(): string[];
|
|
13
|
+
/** Lines in the backup, without their newlines. */
|
|
14
|
+
backupLines(): string[];
|
|
15
|
+
/** Makes every append throw `error` until called again with `undefined`. */
|
|
16
|
+
failAppendsWith(error: Error | undefined): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** {@link AppendOnlyFile} on the real filesystem; the backup is `<path>.1`. */
|
|
2
|
+
import type { AppendOnlyFile } from "./events-log.js";
|
|
3
|
+
export declare class NodeAppendOnlyFile implements AppendOnlyFile {
|
|
4
|
+
private readonly path;
|
|
5
|
+
constructor(path: string);
|
|
6
|
+
append(line: string): Promise<void>;
|
|
7
|
+
size(): Promise<number>;
|
|
8
|
+
rotate(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -11,6 +11,8 @@ export type StateDirPaths = {
|
|
|
11
11
|
socketPath: string;
|
|
12
12
|
pidFilePath: string;
|
|
13
13
|
logFilePath: string;
|
|
14
|
+
/** The daemon's own event log; rotated to `<eventsLogPath>.1`. */
|
|
15
|
+
eventsLogPath: string;
|
|
14
16
|
keyPath: string;
|
|
15
17
|
configPath: string;
|
|
16
18
|
auditDir: string;
|
package/dist/index.js
CHANGED
|
@@ -140,7 +140,7 @@ var createCli = () => {
|
|
|
140
140
|
"--timeout <ms>",
|
|
141
141
|
"Call timeout in milliseconds. Shortens the deadline; it cannot extend one past the app's own timer, which is the tool's declared timeoutMs (else 10000)."
|
|
142
142
|
);
|
|
143
|
-
cli.command("events [selector]", "Stream
|
|
143
|
+
cli.command("events [selector]", "Stream the events the app posts until interrupted.").option("--follow", "Accepted for script readability; the default behavior already follows.").option("--since <cursor>", "One-shot: print the app events retained since this cursor instead of streaming live.");
|
|
144
144
|
cli.command("revoke [selector]", "Revoke a session.");
|
|
145
145
|
cli.command("mcp", "Start a stdio MCP server that gives MCP clients access to connected apps' tools.").option(
|
|
146
146
|
"--scheme <scheme>",
|
|
@@ -164,6 +164,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
164
164
|
"eventBufferSize",
|
|
165
165
|
"auditRetentionDays",
|
|
166
166
|
"daemonLogMaxBytes",
|
|
167
|
+
"eventsLogMaxBytes",
|
|
167
168
|
"policy",
|
|
168
169
|
"advertisedIp",
|
|
169
170
|
"scheme",
|
|
@@ -223,6 +224,7 @@ var defaultConfig = (paths) => {
|
|
|
223
224
|
eventBufferSize: 256,
|
|
224
225
|
auditRetentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
|
|
225
226
|
daemonLogMaxBytes: DEFAULT_DAEMON_LOG_MAX_BYTES,
|
|
227
|
+
eventsLogMaxBytes: 10 * 1024 * 1024,
|
|
226
228
|
restartDaemonOnVersionMismatch: false,
|
|
227
229
|
policy: {
|
|
228
230
|
default: "allow",
|
|
@@ -285,6 +287,9 @@ var loadConfig = async (paths, options = {}) => {
|
|
|
285
287
|
if (parsed.daemonLogMaxBytes !== void 0) {
|
|
286
288
|
config.daemonLogMaxBytes = requirePositiveInteger(parsed.daemonLogMaxBytes, "daemonLogMaxBytes");
|
|
287
289
|
}
|
|
290
|
+
if (parsed.eventsLogMaxBytes !== void 0) {
|
|
291
|
+
config.eventsLogMaxBytes = requirePositiveInteger(parsed.eventsLogMaxBytes, "eventsLogMaxBytes");
|
|
292
|
+
}
|
|
288
293
|
if (parsed.restartDaemonOnVersionMismatch !== void 0) {
|
|
289
294
|
config.restartDaemonOnVersionMismatch = requireBoolean(
|
|
290
295
|
parsed.restartDaemonOnVersionMismatch,
|
|
@@ -333,6 +338,7 @@ var getStateDirPaths = (stateDir) => {
|
|
|
333
338
|
socketPath: join3(stateDir, "daemon.sock"),
|
|
334
339
|
pidFilePath: join3(stateDir, "daemon.pid"),
|
|
335
340
|
logFilePath: join3(stateDir, "daemon.log"),
|
|
341
|
+
eventsLogPath: join3(stateDir, "events.log"),
|
|
336
342
|
keyPath: join3(stateDir, "key.pem"),
|
|
337
343
|
configPath: join3(stateDir, "config.json"),
|
|
338
344
|
auditDir: join3(stateDir, "audit"),
|
|
@@ -38,13 +38,6 @@ export declare const EVENTS_TOOL_DESCRIPTOR: {
|
|
|
38
38
|
readonly type: "integer";
|
|
39
39
|
readonly minimum: 0;
|
|
40
40
|
};
|
|
41
|
-
readonly kinds: {
|
|
42
|
-
readonly type: "array";
|
|
43
|
-
readonly items: {
|
|
44
|
-
readonly type: "string";
|
|
45
|
-
readonly enum: readonly ["daemon_started", "link_created", "link_expired", "session_claimed", "session_suspended", "session_resumed", "session_revoked", "session_expired", "tools_changed", "app_event", "tool_call_started", "tool_call_progress", "tool_call_finished"];
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
41
|
readonly limit: {
|
|
49
42
|
readonly type: "integer";
|
|
50
43
|
readonly exclusiveMinimum: 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appduct",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Driving React Native tools without in-app debug UI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"reflect-metadata": "^0.2.2",
|
|
46
46
|
"toqr": "^0.1.1",
|
|
47
47
|
"ws": "^8.18.3",
|
|
48
|
-
"@appduct/shared": "0.
|
|
48
|
+
"@appduct/shared": "0.12.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "^22.10.0",
|