@songsid/agend 2.1.10-beta.2 → 2.1.10-beta.4

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.
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Keep crash dumps small, from inside the fleet (#1113 hotfix).
3
+ *
4
+ * On WSL every crash is piped to /wsl-capture-crash, which ignores
5
+ * RLIMIT_CORE, so kiro-cli and the fleet left ~1 GB / ~450 MB dumps in
6
+ * %TEMP%\wsl-crashes. A zero /proc/<pid>/coredump_filter writes no memory
7
+ * mappings into a dump (a few KB). The unit's `CoredumpFilter=0` was meant to
8
+ * set it, but systemd 249 silently ignores that directive in a unit file
9
+ * (only a transient `systemd-run -p` honours it), so the fleet sets its own
10
+ * filter at startup instead. The value is inherited across fork/exec by a
11
+ * tmux server the fleet starts; panes of a server that already existed get
12
+ * it from coredumpFilterLaunchPrefix below.
13
+ *
14
+ * Linux only. No privilege needed: a process may always narrow its own filter.
15
+ */
16
+ import { readFileSync, writeFileSync } from "node:fs";
17
+ export function disableCoredumpMemory(path = "/proc/self/coredump_filter", platform = process.platform, env = process.env) {
18
+ if (platform !== "linux")
19
+ return "unsupported";
20
+ // An operator debugging a crash keeps full dumps (and any filter they set).
21
+ if (env.AGEND_KEEP_COREDUMP_FILTER === "1")
22
+ return "kept";
23
+ try {
24
+ if (/^0+$/.test(readFileSync(path, "utf-8").trim()))
25
+ return "already";
26
+ }
27
+ catch {
28
+ return "unsupported"; // no such file: a kernel without it
29
+ }
30
+ try {
31
+ writeFileSync(path, "0");
32
+ return /^0+$/.test(readFileSync(path, "utf-8").trim()) ? "set" : "failed";
33
+ }
34
+ catch {
35
+ return "failed";
36
+ }
37
+ }
38
+ /**
39
+ * The fleet process's start-up step: called once the fleet owns its lock,
40
+ * before anything is spawned, so a tmux server it starts inherits it.
41
+ */
42
+ export function limitFleetCoreDumps(log, disable = disableCoredumpMemory) {
43
+ const outcome = disable();
44
+ if (outcome === "set" || outcome === "already")
45
+ log.info("Crash dumps limited to a few KB (coredump_filter=0 for the fleet and every CLI it launches).");
46
+ else if (outcome === "failed")
47
+ log.error("⚠ Could not set /proc/self/coredump_filter to 0; a crash may write a full-size core dump (#1113).");
48
+ }
49
+ /**
50
+ * Shell prefix for AgEnD's own CLI launch commands (#1125 review). The fleet's
51
+ * filter reaches a CLI only if the tmux server was started by this fleet; a
52
+ * server that already existed (the default socket may hold a user's own
53
+ * session, which AgEnD reuses and never kills) forks panes with ITS filter.
54
+ * So each launch sets the filter of the pane's own shell before the CLI
55
+ * starts: `echo` is a builtin in sh, bash, zsh and fish, the redirect order
56
+ * silences a failure, and the CLI and everything it spawns inherit the value.
57
+ * Empty where it does not apply or the operator opted out.
58
+ */
59
+ export function coredumpFilterLaunchPrefix(platform = process.platform, env = process.env) {
60
+ if (platform !== "linux" || env.AGEND_KEEP_COREDUMP_FILTER === "1")
61
+ return "";
62
+ return "echo 0 2>/dev/null >/proc/self/coredump_filter; ";
63
+ }
64
+ //# sourceMappingURL=coredump-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coredump-filter.js","sourceRoot":"","sources":["../src/coredump-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAItD,MAAM,UAAU,qBAAqB,CACnC,IAAI,GAAG,4BAA4B,EACnC,WAA4B,OAAO,CAAC,QAAQ,EAC5C,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,aAAa,CAAC;IAC/C,4EAA4E;IAC5E,IAAI,GAAG,CAAC,0BAA0B,KAAK,GAAG;QAAE,OAAO,MAAM,CAAC;IAC1D,IAAI,CAAC;QACH,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAAE,OAAO,SAAS,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,CAAC,CAAC,oCAAoC;IAC5D,CAAC;IACD,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAA0D,EAC1D,UAAgD,qBAAqB;IAErE,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO,KAAK,SAAS;QAAE,GAAG,CAAC,IAAI,CAAC,8FAA8F,CAAC,CAAC;SACpJ,IAAI,OAAO,KAAK,QAAQ;QAAE,GAAG,CAAC,KAAK,CAAC,mGAAmG,CAAC,CAAC;AAChJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CACxC,WAA4B,OAAO,CAAC,QAAQ,EAC5C,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,0BAA0B,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC;IAC9E,OAAO,kDAAkD,CAAC;AAC5D,CAAC"}
package/dist/daemon.js CHANGED
@@ -5,6 +5,7 @@ import { ensureInstanceDir } from "./private-dir.js";
5
5
  import { createHash, randomBytes, randomUUID } from "node:crypto";
6
6
  import { EventEmitter } from "node:events";
7
7
  import { rotateLogIfNeeded } from "./logger.js";
8
+ import { coredumpFilterLaunchPrefix } from "./coredump-filter.js";
8
9
  import { mcpServerState } from "./mcp-liveness.js";
9
10
  import { clearPausedMarker, writePausedMarker } from "./pause-marker.js";
10
11
  import { TmuxManager, resolveTmuxLogicalSize } from "./tmux-manager.js";
@@ -8206,7 +8207,10 @@ export class Daemon extends EventEmitter {
8206
8207
  clearMuseUsageSnapshot(this.instanceDir);
8207
8208
  }
8208
8209
  }
8209
- const cmd = `${envPrefix} ` + this.backend.buildCommand(launchConfig);
8210
+ // The CLI's own shell sets a zero coredump_filter first (#1113): this pane
8211
+ // may belong to a tmux server the fleet did not start, which would hand
8212
+ // the CLI its own (full) filter instead of the fleet's.
8213
+ const cmd = coredumpFilterLaunchPrefix() + `${envPrefix} ` + this.backend.buildCommand(launchConfig);
8210
8214
  // Every launched command re-arms the passive-transient check, including a
8211
8215
  // retry inside the same spawn: its load is a new one.
8212
8216
  this.launchAttempt++;