@agfpd/iapeer 0.2.53 → 0.2.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agfpd/iapeer",
3
- "version": "0.2.53",
3
+ "version": "0.2.54",
4
4
  "description": "Foundation core for the iapeer multi-agent ecosystem: identity, registry, storage, codec.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -79,6 +79,22 @@ describe('canary script (pure)', () => {
79
79
  expect(s).toContain('/r/logs/iapeer/server-deaths/claude-bob') // forensics file
80
80
  expect(s).toContain('vm_stat') // memory evidence (OOM hypothesis)
81
81
  expect(s).toContain(`'/opt/homebrew/bin/tmux' -S '/tmp/x.sock'`) // abs tmux, quoted
82
+ expect(s).not.toContain('cmdlog-tail') // no cmdLogDir → no cmdlog capture line
83
+ })
84
+
85
+ test('with cmdLogDir → forensics tail the dead server cmdlog (client-COMMAND kill attribution)', () => {
86
+ const s = canaryScript({
87
+ identity: 'claude-bob',
88
+ sock: '/tmp/x.sock',
89
+ tmuxBin: '/opt/homebrew/bin/tmux',
90
+ exitLogFile: '/r/logs/iapeer/exits.log',
91
+ forensicsDir: '/r/logs/iapeer/server-deaths',
92
+ cmdLogDir: '/r/logs/iapeer/tmux-cmdlog/claude-bob',
93
+ })
94
+ expect(s).toContain('cmdlog-tail') // the kill-server/kill-session witness
95
+ // tails the dead server's own -v log by its captured pid, greps the command lines
96
+ expect(s).toContain(`'/r/logs/iapeer/tmux-cmdlog/claude-bob/tmux-server-'"$SPID"'.log'`)
97
+ expect(s).toContain(`grep -aE 'command:'`)
82
98
  })
83
99
 
84
100
  test('ensureServerCanary without exitLogDir → skipped (observability off)', () => {
@@ -49,6 +49,7 @@ import { spawn, spawnSync } from 'child_process'
49
49
  import { mkdirSync } from 'fs'
50
50
  import { join } from 'path'
51
51
  import { resolveExecutable } from './launchd.ts'
52
+ import { cmdLogDirFor } from './cmdlog.ts'
52
53
 
53
54
  /** The exit-cause log file inside `exitLogDir` (sibling to lifecycle.log).
54
55
  * Lives here (not index.ts) so canary ⇆ launch never import-cycle; index.ts
@@ -74,6 +75,12 @@ export interface CanaryScriptOptions {
74
75
  tmuxBin: string
75
76
  exitLogFile: string
76
77
  forensicsDir: string
78
+ /** The identity's tmux-cmdlog dir (<exitLogDir>/tmux-cmdlog/<identity>). When set,
79
+ * the death forensics tail the dead server's `tmux-server-<SPID>.log` — the ONLY
80
+ * witness of a client-COMMAND kill (`kill-server`/`kill-session`), which leaves zero
81
+ * signals (so signal forensics see nothing) and is otherwise wiped by the respawn's
82
+ * prepareCmdLogDir before anyone reads it. Best-effort: absent log → grep no-ops. */
83
+ cmdLogDir?: string
77
84
  }
78
85
 
79
86
  /**
@@ -129,6 +136,17 @@ export function canaryScript(o: CanaryScriptOptions): string {
129
136
  ` echo '--- ps-top-rss'; ps axo pid,ppid,rss,etime,command | sort -rn -k3 | head -25`,
130
137
  ` echo '--- diagnosticreports-user'; ls -t "$HOME/Library/Logs/DiagnosticReports" 2>/dev/null | head`,
131
138
  ` echo '--- diagnosticreports-system'; ls -t /Library/Logs/DiagnosticReports 2>/dev/null | head`,
139
+ // The death-class discriminator signal-forensics structurally cannot see: a tmux
140
+ // server killed by a CLIENT COMMAND (`kill-server`/`kill-session`) leaves zero
141
+ // signals. Its only witness is the dead server's own -v cmdlog, which the respawn
142
+ // wipes seconds later — captured HERE (canary fires ~+2 s, respawn ~+7 s) so the
143
+ // killer's `client-<pid> command: …` survives into the forensics.
144
+ ...(o.cmdLogDir
145
+ ? [
146
+ ` echo '--- cmdlog-tail (last client commands; a kill-server/kill-session here IS the killer)'`,
147
+ ` tail -c 131072 '${o.cmdLogDir}/tmux-server-'"$SPID"'.log' 2>/dev/null | grep -aE 'command:' | tail -30`,
148
+ ]
149
+ : []),
132
150
  `} > "$f" 2>&1`,
133
151
  `printf 'ts=%s ev=server-exit identity=${o.identity} server_pid=%s wait_rc=%s cause=%s forensics=%s\\n' "$ts" "$SPID" "$rc" "$cause" "$f" >> '${o.exitLogFile}'`,
134
152
  ].join('\n')
@@ -172,6 +190,7 @@ export function ensureServerCanary(o: EnsureCanaryOptions): CanaryEnsureState {
172
190
  tmuxBin,
173
191
  exitLogFile: exitLogPath(o.exitLogDir),
174
192
  forensicsDir,
193
+ cmdLogDir: cmdLogDirFor(o.exitLogDir, o.identity),
175
194
  })
176
195
  const child = spawn('/bin/sh', ['-c', script], { detached: true, stdio: 'ignore', env })
177
196
  child.unref()