@cluesmith/codev 3.2.2 → 3.2.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.
Files changed (175) hide show
  1. package/dashboard-dist/assets/index-BZ1x7x1X.js.map +1 -1
  2. package/dist/agent-farm/cli.d.ts.map +1 -1
  3. package/dist/agent-farm/cli.js +31 -0
  4. package/dist/agent-farm/cli.js.map +1 -1
  5. package/dist/agent-farm/commands/attach.js +2 -2
  6. package/dist/agent-farm/commands/attach.js.map +1 -1
  7. package/dist/agent-farm/commands/send.d.ts +2 -2
  8. package/dist/agent-farm/commands/send.js +3 -3
  9. package/dist/agent-farm/commands/send.js.map +1 -1
  10. package/dist/agent-farm/commands/setup.d.ts +4 -1
  11. package/dist/agent-farm/commands/setup.d.ts.map +1 -1
  12. package/dist/agent-farm/commands/setup.js +8 -4
  13. package/dist/agent-farm/commands/setup.js.map +1 -1
  14. package/dist/agent-farm/commands/spawn-worktree.d.ts +11 -0
  15. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
  16. package/dist/agent-farm/commands/spawn-worktree.js +64 -16
  17. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
  18. package/dist/agent-farm/commands/status.d.ts.map +1 -1
  19. package/dist/agent-farm/commands/status.js +26 -2
  20. package/dist/agent-farm/commands/status.js.map +1 -1
  21. package/dist/agent-farm/commands/tower-sweep-husks.d.ts +6 -0
  22. package/dist/agent-farm/commands/tower-sweep-husks.d.ts.map +1 -0
  23. package/dist/agent-farm/commands/tower-sweep-husks.js +77 -0
  24. package/dist/agent-farm/commands/tower-sweep-husks.js.map +1 -0
  25. package/dist/agent-farm/commands/tower.d.ts.map +1 -1
  26. package/dist/agent-farm/commands/tower.js +34 -0
  27. package/dist/agent-farm/commands/tower.js.map +1 -1
  28. package/dist/agent-farm/commands/whoami.d.ts +65 -0
  29. package/dist/agent-farm/commands/whoami.d.ts.map +1 -0
  30. package/dist/agent-farm/commands/whoami.js +196 -0
  31. package/dist/agent-farm/commands/whoami.js.map +1 -0
  32. package/dist/agent-farm/commands/workspace-recover.d.ts +31 -0
  33. package/dist/agent-farm/commands/workspace-recover.d.ts.map +1 -1
  34. package/dist/agent-farm/commands/workspace-recover.js +70 -30
  35. package/dist/agent-farm/commands/workspace-recover.js.map +1 -1
  36. package/dist/agent-farm/db/index.d.ts.map +1 -1
  37. package/dist/agent-farm/db/index.js +8 -2
  38. package/dist/agent-farm/db/index.js.map +1 -1
  39. package/dist/agent-farm/lib/tower-client.d.ts +1 -1
  40. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  41. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  42. package/dist/agent-farm/servers/architect-session-holder.d.ts +133 -0
  43. package/dist/agent-farm/servers/architect-session-holder.d.ts.map +1 -0
  44. package/dist/agent-farm/servers/architect-session-holder.js +268 -0
  45. package/dist/agent-farm/servers/architect-session-holder.js.map +1 -0
  46. package/dist/agent-farm/servers/process-census.d.ts +41 -0
  47. package/dist/agent-farm/servers/process-census.d.ts.map +1 -0
  48. package/dist/agent-farm/servers/process-census.js +62 -0
  49. package/dist/agent-farm/servers/process-census.js.map +1 -0
  50. package/dist/agent-farm/servers/send-buffer.d.ts.map +1 -1
  51. package/dist/agent-farm/servers/send-buffer.js +13 -0
  52. package/dist/agent-farm/servers/send-buffer.js.map +1 -1
  53. package/dist/agent-farm/servers/session-log-sweep.d.ts +93 -0
  54. package/dist/agent-farm/servers/session-log-sweep.d.ts.map +1 -0
  55. package/dist/agent-farm/servers/session-log-sweep.js +165 -0
  56. package/dist/agent-farm/servers/session-log-sweep.js.map +1 -0
  57. package/dist/agent-farm/servers/shellper-husk-sweep.d.ts +87 -0
  58. package/dist/agent-farm/servers/shellper-husk-sweep.d.ts.map +1 -0
  59. package/dist/agent-farm/servers/shellper-husk-sweep.js +129 -0
  60. package/dist/agent-farm/servers/shellper-husk-sweep.js.map +1 -0
  61. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  62. package/dist/agent-farm/servers/tower-instances.js +203 -36
  63. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  64. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  65. package/dist/agent-farm/servers/tower-routes.js +147 -4
  66. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  67. package/dist/agent-farm/servers/tower-server.js +95 -1
  68. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  69. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  70. package/dist/agent-farm/servers/tower-terminals.js +66 -8
  71. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  72. package/dist/agent-farm/servers/tower-utils.d.ts +106 -4
  73. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  74. package/dist/agent-farm/servers/tower-utils.js +155 -19
  75. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  76. package/dist/agent-farm/state.d.ts +13 -1
  77. package/dist/agent-farm/state.d.ts.map +1 -1
  78. package/dist/agent-farm/state.js +17 -2
  79. package/dist/agent-farm/state.js.map +1 -1
  80. package/dist/agent-farm/utils/claude-session-discovery.d.ts +12 -0
  81. package/dist/agent-farm/utils/claude-session-discovery.d.ts.map +1 -1
  82. package/dist/agent-farm/utils/claude-session-discovery.js +42 -4
  83. package/dist/agent-farm/utils/claude-session-discovery.js.map +1 -1
  84. package/dist/agent-farm/utils/harness.d.ts +15 -3
  85. package/dist/agent-farm/utils/harness.d.ts.map +1 -1
  86. package/dist/agent-farm/utils/harness.js +4 -1
  87. package/dist/agent-farm/utils/harness.js.map +1 -1
  88. package/dist/commands/adopt.d.ts +3 -2
  89. package/dist/commands/adopt.d.ts.map +1 -1
  90. package/dist/commands/adopt.js +7 -6
  91. package/dist/commands/adopt.js.map +1 -1
  92. package/dist/commands/consult/agy-auth-cache.d.ts +97 -0
  93. package/dist/commands/consult/agy-auth-cache.d.ts.map +1 -0
  94. package/dist/commands/consult/agy-auth-cache.js +320 -0
  95. package/dist/commands/consult/agy-auth-cache.js.map +1 -0
  96. package/dist/commands/consult/index.d.ts.map +1 -1
  97. package/dist/commands/consult/index.js +59 -0
  98. package/dist/commands/consult/index.js.map +1 -1
  99. package/dist/commands/doctor.d.ts +28 -0
  100. package/dist/commands/doctor.d.ts.map +1 -1
  101. package/dist/commands/doctor.js +187 -3
  102. package/dist/commands/doctor.js.map +1 -1
  103. package/dist/commands/init.d.ts +3 -2
  104. package/dist/commands/init.d.ts.map +1 -1
  105. package/dist/commands/init.js +7 -6
  106. package/dist/commands/init.js.map +1 -1
  107. package/dist/commands/porch/index.d.ts.map +1 -1
  108. package/dist/commands/porch/index.js +11 -8
  109. package/dist/commands/porch/index.js.map +1 -1
  110. package/dist/commands/update.d.ts +4 -4
  111. package/dist/commands/update.d.ts.map +1 -1
  112. package/dist/commands/update.js +9 -11
  113. package/dist/commands/update.js.map +1 -1
  114. package/dist/lib/config.d.ts +1 -0
  115. package/dist/lib/config.d.ts.map +1 -1
  116. package/dist/lib/config.js.map +1 -1
  117. package/dist/lib/default-branch.d.ts +1 -1
  118. package/dist/lib/default-branch.js +1 -1
  119. package/dist/lib/gitignore.d.ts +25 -2
  120. package/dist/lib/gitignore.d.ts.map +1 -1
  121. package/dist/lib/gitignore.js +70 -0
  122. package/dist/lib/gitignore.js.map +1 -1
  123. package/dist/lib/migration-backup-audit.d.ts +64 -0
  124. package/dist/lib/migration-backup-audit.d.ts.map +1 -0
  125. package/dist/lib/migration-backup-audit.js +145 -0
  126. package/dist/lib/migration-backup-audit.js.map +1 -0
  127. package/dist/lib/protocol-drift-audit.d.ts +118 -0
  128. package/dist/lib/protocol-drift-audit.d.ts.map +1 -0
  129. package/dist/lib/protocol-drift-audit.js +217 -0
  130. package/dist/lib/protocol-drift-audit.js.map +1 -0
  131. package/dist/lib/scaffold.d.ts +10 -3
  132. package/dist/lib/scaffold.d.ts.map +1 -1
  133. package/dist/lib/scaffold.js +29 -26
  134. package/dist/lib/scaffold.js.map +1 -1
  135. package/dist/terminal/pty-manager.d.ts +7 -0
  136. package/dist/terminal/pty-manager.d.ts.map +1 -1
  137. package/dist/terminal/pty-manager.js +16 -0
  138. package/dist/terminal/pty-manager.js.map +1 -1
  139. package/dist/terminal/pty-session.d.ts +25 -4
  140. package/dist/terminal/pty-session.d.ts.map +1 -1
  141. package/dist/terminal/pty-session.js +83 -11
  142. package/dist/terminal/pty-session.js.map +1 -1
  143. package/dist/terminal/session-manager.d.ts +109 -0
  144. package/dist/terminal/session-manager.d.ts.map +1 -1
  145. package/dist/terminal/session-manager.js +314 -45
  146. package/dist/terminal/session-manager.js.map +1 -1
  147. package/dist/terminal/shellper-client.d.ts +19 -4
  148. package/dist/terminal/shellper-client.d.ts.map +1 -1
  149. package/dist/terminal/shellper-client.js +70 -8
  150. package/dist/terminal/shellper-client.js.map +1 -1
  151. package/dist/terminal/shellper-process.d.ts.map +1 -1
  152. package/dist/terminal/shellper-process.js +20 -5
  153. package/dist/terminal/shellper-process.js.map +1 -1
  154. package/dist/terminal/shellper-protocol.d.ts +40 -2
  155. package/dist/terminal/shellper-protocol.d.ts.map +1 -1
  156. package/dist/terminal/shellper-protocol.js +72 -5
  157. package/dist/terminal/shellper-protocol.js.map +1 -1
  158. package/package.json +8 -8
  159. package/skeleton/.claude/skills/afx/SKILL.md +13 -0
  160. package/skeleton/.claude/skills/arch-init/SKILL.md +122 -0
  161. package/skeleton/.claude/skills/codev/SKILL.md +2 -2
  162. package/skeleton/.codex/skills/afx/SKILL.md +157 -0
  163. package/skeleton/.codex/skills/arch-init/SKILL.md +122 -0
  164. package/skeleton/.codex/skills/codev/SKILL.md +59 -0
  165. package/skeleton/.codex/skills/consult/SKILL.md +96 -0
  166. package/skeleton/.codex/skills/generate-image/SKILL.md +45 -0
  167. package/skeleton/.codex/skills/porch/SKILL.md +60 -0
  168. package/skeleton/.codex/skills/update-arch-docs/SKILL.md +132 -0
  169. package/skeleton/protocols/pir/prompts/implement.md +1 -1
  170. package/skeleton/protocols/pir/prompts/review.md +1 -1
  171. package/skeleton/protocols/pir/protocol.md +3 -3
  172. package/skeleton/resources/commands/agent-farm.md +89 -0
  173. package/skeleton/resources/commands/codev.md +5 -0
  174. package/skeleton/resources/commands/consult.md +26 -0
  175. package/skeleton/roles/architect.md +11 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Issue #1224: detect and reclaim live processes that hold an architect's
3
+ * conversation session id, so an architect launch never bakes a colliding
4
+ * `claude --resume <id>` into a permanent crash loop.
5
+ *
6
+ * Two holder classes were observed after a workspace restart (forensic timeline
7
+ * on the issue):
8
+ * 1. OUR OWN superseded shellper for the same architect identity — a remnant
9
+ * from before the restart, or a previous crash-looping instance. Its claude
10
+ * child dies within seconds of every respawn, so the child is absent most
11
+ * of the time; the durable evidence is the *shellper parent's* argv, which
12
+ * carries the session id in its JSON config (`"--session-id","<id>"`).
13
+ * 2. A FOREIGN process — e.g. an interactive `claude` the user started by hand
14
+ * on their own tty (holder case in incident 3). This must NEVER be touched:
15
+ * it is not ours to kill.
16
+ *
17
+ * The policy: reclaim (kill + resume) only OUR OWN superseded shellper, proven
18
+ * by shellper-main.js + matching session id + matching cwd + matching
19
+ * CODEV_ARCHITECT_NAME. Anything else that holds the id is foreign → mint fresh.
20
+ */
21
+ export interface ProcessEntry {
22
+ pid: number;
23
+ /** The full joined argv (as `ps ... -o args=` reports it). */
24
+ cmdline: string;
25
+ }
26
+ /**
27
+ * The session-flag needle forms a live holder's argv can carry the id in:
28
+ * - `--session-id <id>` / `--resume <id>` — a claude CHILD's shell argv
29
+ * - `--session-id=<id>` / `--resume=<id>` — the `=`-joined shell variant
30
+ * - `"--session-id","<id>"` / `"--resume","<id>"` — the shellper PARENT's
31
+ * JSON config argv (Issue #1224: catches a remnant shellper whose child is
32
+ * dead between crash-loop respawns).
33
+ */
34
+ export declare function sessionIdNeedles(sessionId: string): string[];
35
+ /** True when a process's argv references `sessionId` as a session-flag argument. */
36
+ export declare function cmdlineHoldsSession(cmdline: string, sessionId: string): boolean;
37
+ export interface ArchitectIdentity {
38
+ /** Absolute workspace path the shellper runs in (`cwd` in its config). */
39
+ workspacePath: string;
40
+ /** The architect name (shellper config env `CODEV_ARCHITECT_NAME`). */
41
+ architectName: string;
42
+ }
43
+ /**
44
+ * True when `cmdline` is one of OUR OWN shellper processes for `identity`:
45
+ * a `shellper-main.js` whose JSON config carries the matching workspace cwd and
46
+ * `CODEV_ARCHITECT_NAME`. The cwd match tolerates symlink variants (macOS
47
+ * `/tmp` vs `/private/tmp`), mirroring verifySessionOwnership.
48
+ *
49
+ * This is the airtight-identity gate before any kill: if any field cannot be
50
+ * positively confirmed, this returns false and the caller must not reclaim.
51
+ */
52
+ export declare function isOwnArchitectShellper(cmdline: string, identity: ArchitectIdentity): boolean;
53
+ /**
54
+ * Snapshot every running process as {pid, cmdline}. `ps -ww` prevents argv
55
+ * truncation (the shellper config blob is large) on both BSD and coreutils.
56
+ * Throws on `ps` failure; callers decide how to degrade.
57
+ */
58
+ export declare function listProcessEntries(): ProcessEntry[];
59
+ export interface SessionHolderClassification {
60
+ /** PIDs of OUR OWN superseded shellpers holding this session (safe to reap). */
61
+ reclaimable: number[];
62
+ /** True when some holder is NOT positively ours — must not be touched. */
63
+ foreign: boolean;
64
+ }
65
+ /**
66
+ * Classify every live holder of `sessionId` into reclaimable-own vs foreign.
67
+ * A holder is reclaimable only when it is one of our own architect shellpers
68
+ * (identity-matched); any other holder (a bare `claude`, a shellper for a
69
+ * different identity, an unparseable match) is foreign.
70
+ *
71
+ * On `ps` failure returns `{reclaimable: [], foreign: false}` — no positive
72
+ * evidence, so the caller resumes as it would have before this guard existed.
73
+ */
74
+ export declare function classifyArchitectSessionHolder(opts: {
75
+ sessionId: string;
76
+ identity: ArchitectIdentity;
77
+ /** Exclude this pid (e.g. Tower's own) from consideration. */
78
+ selfPid?: number;
79
+ /** Test seam: override the process snapshot. */
80
+ list?: () => ProcessEntry[];
81
+ }): SessionHolderClassification;
82
+ /**
83
+ * Find PIDs of OUR OWN architect shellpers for `identity`, regardless of which
84
+ * session they hold. Used by remove-architect to reap a live-process-without-a-
85
+ * registry-row zombie (Issue #1224 symptom B) — there is no stored session id to
86
+ * key on, so identity (shellper-main.js + cwd + CODEV_ARCHITECT_NAME) is the key.
87
+ */
88
+ export declare function findOwnArchitectShellpers(opts: {
89
+ identity: ArchitectIdentity;
90
+ selfPid?: number;
91
+ list?: () => ProcessEntry[];
92
+ }): number[];
93
+ /**
94
+ * Reap the given superseded-shellper PIDs: SIGTERM the process group, poll for
95
+ * death, then SIGKILL any survivor. Resolves once every pid is gone (or the
96
+ * SIGKILL grace elapses). The wait matters: the killed shellper's child must
97
+ * release the session lock before the caller's fresh `claude --resume` runs,
98
+ * else the collision recurs.
99
+ *
100
+ * Seams (`isAlive`, `kill`, `wait`) keep it unit-testable without real signals.
101
+ */
102
+ export declare function reapShellpers(pids: number[], opts?: {
103
+ isAlive?: (pid: number) => boolean;
104
+ kill?: (pid: number, signal: NodeJS.Signals) => void;
105
+ wait?: (ms: number) => Promise<void>;
106
+ graceMs?: number;
107
+ killGraceMs?: number;
108
+ pollMs?: number;
109
+ }): Promise<void>;
110
+ export type ArchitectLogger = (level: 'INFO' | 'WARN' | 'ERROR', message: string) => void;
111
+ /**
112
+ * Reconcile a stored architect session id against the live process table before
113
+ * launch, resolving whether the caller may resume it.
114
+ *
115
+ * - A FOREIGN holder → `{ foreignHolder: true }`: the caller must mint fresh
116
+ * (the session is genuinely in use by something we must not touch).
117
+ * - Only OUR OWN superseded shellper(s) hold it → reap them and return
118
+ * `{ foreignHolder: false }`: the session is now free, resume it (mint-or-
119
+ * RECLAIM, preserving the conversation instead of abandoning it).
120
+ * - No holder → `{ foreignHolder: false }`: resume as usual.
121
+ */
122
+ export declare function reconcileArchitectSessionHolder(opts: {
123
+ sessionId: string;
124
+ identity: ArchitectIdentity;
125
+ selfPid?: number;
126
+ log?: ArchitectLogger;
127
+ list?: () => ProcessEntry[];
128
+ reap?: (pids: number[]) => Promise<void>;
129
+ }): Promise<{
130
+ foreignHolder: boolean;
131
+ reclaimedPids: number[];
132
+ }>;
133
+ //# sourceMappingURL=architect-session-holder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architect-session-holder.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/servers/architect-session-holder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAM5D;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAG/E;AAsBD,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,aAAa,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAc5F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,EAAE,CAgBnD;AAED,MAAM,WAAW,2BAA2B;IAC1C,gFAAgF;IAChF,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0EAA0E;IAC1E,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,YAAY,EAAE,CAAC;CAC7B,GAAG,2BAA2B,CAqB9B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,YAAY,EAAE,CAAC;CAC7B,GAAG,MAAM,EAAE,CAcX;AA6BD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,CAAC,EAAE;IACL,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACnC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,KAAK,IAAI,CAAC;IACrD,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1F;;;;;;;;;;GAUG;AACH,wBAAsB,+BAA+B,CAAC,IAAI,EAAE;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,YAAY,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C,GAAG,OAAO,CAAC;IAAE,aAAa,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA4B/D"}
@@ -0,0 +1,268 @@
1
+ /**
2
+ * Issue #1224: detect and reclaim live processes that hold an architect's
3
+ * conversation session id, so an architect launch never bakes a colliding
4
+ * `claude --resume <id>` into a permanent crash loop.
5
+ *
6
+ * Two holder classes were observed after a workspace restart (forensic timeline
7
+ * on the issue):
8
+ * 1. OUR OWN superseded shellper for the same architect identity — a remnant
9
+ * from before the restart, or a previous crash-looping instance. Its claude
10
+ * child dies within seconds of every respawn, so the child is absent most
11
+ * of the time; the durable evidence is the *shellper parent's* argv, which
12
+ * carries the session id in its JSON config (`"--session-id","<id>"`).
13
+ * 2. A FOREIGN process — e.g. an interactive `claude` the user started by hand
14
+ * on their own tty (holder case in incident 3). This must NEVER be touched:
15
+ * it is not ours to kill.
16
+ *
17
+ * The policy: reclaim (kill + resume) only OUR OWN superseded shellper, proven
18
+ * by shellper-main.js + matching session id + matching cwd + matching
19
+ * CODEV_ARCHITECT_NAME. Anything else that holds the id is foreign → mint fresh.
20
+ */
21
+ import { execFileSync } from 'node:child_process';
22
+ import { realpathSync } from 'node:fs';
23
+ /** Marker identifying a Codev shellper process in a `ps` command line. */
24
+ const SHELLPER_MARKER = 'shellper-main.js';
25
+ /**
26
+ * The session-flag needle forms a live holder's argv can carry the id in:
27
+ * - `--session-id <id>` / `--resume <id>` — a claude CHILD's shell argv
28
+ * - `--session-id=<id>` / `--resume=<id>` — the `=`-joined shell variant
29
+ * - `"--session-id","<id>"` / `"--resume","<id>"` — the shellper PARENT's
30
+ * JSON config argv (Issue #1224: catches a remnant shellper whose child is
31
+ * dead between crash-loop respawns).
32
+ */
33
+ export function sessionIdNeedles(sessionId) {
34
+ return ['--session-id', '--resume'].flatMap((flag) => [
35
+ `${flag} ${sessionId}`,
36
+ `${flag}=${sessionId}`,
37
+ `"${flag}","${sessionId}"`,
38
+ ]);
39
+ }
40
+ /** True when a process's argv references `sessionId` as a session-flag argument. */
41
+ export function cmdlineHoldsSession(cmdline, sessionId) {
42
+ const needles = sessionIdNeedles(sessionId);
43
+ return needles.some((needle) => cmdline.includes(needle));
44
+ }
45
+ /** Canonicalize a path for comparison; fall back to the input when realpath fails. */
46
+ function realpathOrSelf(p) {
47
+ try {
48
+ return realpathSync(p);
49
+ }
50
+ catch {
51
+ return p;
52
+ }
53
+ }
54
+ /**
55
+ * Extract a `"key":"value"` string field from a shellper's JSON config as it
56
+ * appears verbatim in the `ps` argv. Regex rather than JSON.parse: the config
57
+ * embeds the full process env, so the blob is large and a partial/edge `ps`
58
+ * line must degrade to "field absent" rather than throw.
59
+ */
60
+ function extractJsonStringField(cmdline, key) {
61
+ const m = cmdline.match(new RegExp(`"${key}"\\s*:\\s*"([^"]+)"`));
62
+ return m ? m[1] : null;
63
+ }
64
+ /**
65
+ * True when `cmdline` is one of OUR OWN shellper processes for `identity`:
66
+ * a `shellper-main.js` whose JSON config carries the matching workspace cwd and
67
+ * `CODEV_ARCHITECT_NAME`. The cwd match tolerates symlink variants (macOS
68
+ * `/tmp` vs `/private/tmp`), mirroring verifySessionOwnership.
69
+ *
70
+ * This is the airtight-identity gate before any kill: if any field cannot be
71
+ * positively confirmed, this returns false and the caller must not reclaim.
72
+ */
73
+ export function isOwnArchitectShellper(cmdline, identity) {
74
+ if (!cmdline.includes(SHELLPER_MARKER))
75
+ return false;
76
+ const cfgName = extractJsonStringField(cmdline, 'CODEV_ARCHITECT_NAME');
77
+ if (cfgName !== identity.architectName)
78
+ return false;
79
+ const cfgCwd = extractJsonStringField(cmdline, 'cwd');
80
+ if (!cfgCwd)
81
+ return false;
82
+ const wanted = new Set([identity.workspacePath, realpathOrSelf(identity.workspacePath)]);
83
+ const got = new Set([cfgCwd, realpathOrSelf(cfgCwd)]);
84
+ const cwdMatches = [...got].some((g) => wanted.has(g));
85
+ if (!cwdMatches)
86
+ return false;
87
+ return true;
88
+ }
89
+ /**
90
+ * Snapshot every running process as {pid, cmdline}. `ps -ww` prevents argv
91
+ * truncation (the shellper config blob is large) on both BSD and coreutils.
92
+ * Throws on `ps` failure; callers decide how to degrade.
93
+ */
94
+ export function listProcessEntries() {
95
+ const out = execFileSync('ps', ['-ww', '-eo', 'pid=,args='], {
96
+ encoding: 'utf-8',
97
+ timeout: 5000,
98
+ maxBuffer: 16 * 1024 * 1024,
99
+ });
100
+ const entries = [];
101
+ for (const line of out.split('\n')) {
102
+ const trimmed = line.trimStart();
103
+ const sp = trimmed.indexOf(' ');
104
+ if (sp <= 0)
105
+ continue;
106
+ const pid = parseInt(trimmed.slice(0, sp), 10);
107
+ if (Number.isNaN(pid) || pid <= 0)
108
+ continue;
109
+ entries.push({ pid, cmdline: trimmed.slice(sp + 1) });
110
+ }
111
+ return entries;
112
+ }
113
+ /**
114
+ * Classify every live holder of `sessionId` into reclaimable-own vs foreign.
115
+ * A holder is reclaimable only when it is one of our own architect shellpers
116
+ * (identity-matched); any other holder (a bare `claude`, a shellper for a
117
+ * different identity, an unparseable match) is foreign.
118
+ *
119
+ * On `ps` failure returns `{reclaimable: [], foreign: false}` — no positive
120
+ * evidence, so the caller resumes as it would have before this guard existed.
121
+ */
122
+ export function classifyArchitectSessionHolder(opts) {
123
+ const list = opts.list ?? listProcessEntries;
124
+ let entries;
125
+ try {
126
+ entries = list();
127
+ }
128
+ catch {
129
+ return { reclaimable: [], foreign: false };
130
+ }
131
+ const reclaimable = [];
132
+ let foreign = false;
133
+ for (const { pid, cmdline } of entries) {
134
+ if (opts.selfPid !== undefined && pid === opts.selfPid)
135
+ continue;
136
+ if (!cmdlineHoldsSession(cmdline, opts.sessionId))
137
+ continue;
138
+ if (isOwnArchitectShellper(cmdline, opts.identity)) {
139
+ reclaimable.push(pid);
140
+ }
141
+ else {
142
+ foreign = true;
143
+ }
144
+ }
145
+ return { reclaimable, foreign };
146
+ }
147
+ /**
148
+ * Find PIDs of OUR OWN architect shellpers for `identity`, regardless of which
149
+ * session they hold. Used by remove-architect to reap a live-process-without-a-
150
+ * registry-row zombie (Issue #1224 symptom B) — there is no stored session id to
151
+ * key on, so identity (shellper-main.js + cwd + CODEV_ARCHITECT_NAME) is the key.
152
+ */
153
+ export function findOwnArchitectShellpers(opts) {
154
+ const list = opts.list ?? listProcessEntries;
155
+ let entries;
156
+ try {
157
+ entries = list();
158
+ }
159
+ catch {
160
+ return [];
161
+ }
162
+ const pids = [];
163
+ for (const { pid, cmdline } of entries) {
164
+ if (opts.selfPid !== undefined && pid === opts.selfPid)
165
+ continue;
166
+ if (isOwnArchitectShellper(cmdline, opts.identity))
167
+ pids.push(pid);
168
+ }
169
+ return pids;
170
+ }
171
+ /** Whether a pid is still alive (signal 0 probe). */
172
+ function pidAlive(pid) {
173
+ try {
174
+ process.kill(pid, 0);
175
+ return true;
176
+ }
177
+ catch (err) {
178
+ // ESRCH → gone; EPERM → alive but not ours to signal (treat as alive).
179
+ return err.code === 'EPERM';
180
+ }
181
+ }
182
+ /** Kill a shellper's whole process group (leader is detached), best-effort. */
183
+ function killProcessGroup(pid, signal) {
184
+ try {
185
+ process.kill(-pid, signal);
186
+ }
187
+ catch {
188
+ // Group gone or not permitted — fall back to the single pid.
189
+ try {
190
+ process.kill(pid, signal);
191
+ }
192
+ catch {
193
+ /* already dead */
194
+ }
195
+ }
196
+ }
197
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
198
+ /**
199
+ * Reap the given superseded-shellper PIDs: SIGTERM the process group, poll for
200
+ * death, then SIGKILL any survivor. Resolves once every pid is gone (or the
201
+ * SIGKILL grace elapses). The wait matters: the killed shellper's child must
202
+ * release the session lock before the caller's fresh `claude --resume` runs,
203
+ * else the collision recurs.
204
+ *
205
+ * Seams (`isAlive`, `kill`, `wait`) keep it unit-testable without real signals.
206
+ */
207
+ export async function reapShellpers(pids, opts) {
208
+ if (pids.length === 0)
209
+ return;
210
+ const isAlive = opts?.isAlive ?? pidAlive;
211
+ const kill = opts?.kill ?? killProcessGroup;
212
+ const wait = opts?.wait ?? sleep;
213
+ const graceMs = opts?.graceMs ?? 3000;
214
+ const killGraceMs = opts?.killGraceMs ?? 2000;
215
+ const pollMs = opts?.pollMs ?? 100;
216
+ const pollUntilDead = async (deadlineMs) => {
217
+ let waited = 0;
218
+ while (waited < deadlineMs && pids.some((pid) => isAlive(pid))) {
219
+ await wait(pollMs);
220
+ waited += pollMs;
221
+ }
222
+ };
223
+ for (const pid of pids)
224
+ kill(pid, 'SIGTERM');
225
+ await pollUntilDead(graceMs);
226
+ const survivors = pids.filter((pid) => isAlive(pid));
227
+ if (survivors.length > 0) {
228
+ for (const pid of survivors)
229
+ kill(pid, 'SIGKILL');
230
+ // Confirm SIGKILL actually took effect before returning: the caller resumes
231
+ // `claude --resume <id>` next, and a holder still in the kernel's exit path
232
+ // has not yet released the session lock — returning early would re-open the
233
+ // very collision race this reap exists to close (codex review, Issue #1224).
234
+ await pollUntilDead(killGraceMs);
235
+ }
236
+ }
237
+ /**
238
+ * Reconcile a stored architect session id against the live process table before
239
+ * launch, resolving whether the caller may resume it.
240
+ *
241
+ * - A FOREIGN holder → `{ foreignHolder: true }`: the caller must mint fresh
242
+ * (the session is genuinely in use by something we must not touch).
243
+ * - Only OUR OWN superseded shellper(s) hold it → reap them and return
244
+ * `{ foreignHolder: false }`: the session is now free, resume it (mint-or-
245
+ * RECLAIM, preserving the conversation instead of abandoning it).
246
+ * - No holder → `{ foreignHolder: false }`: resume as usual.
247
+ */
248
+ export async function reconcileArchitectSessionHolder(opts) {
249
+ const { reclaimable, foreign } = classifyArchitectSessionHolder({
250
+ sessionId: opts.sessionId,
251
+ identity: opts.identity,
252
+ selfPid: opts.selfPid,
253
+ list: opts.list,
254
+ });
255
+ const shortId = opts.sessionId.slice(0, 8);
256
+ if (foreign) {
257
+ opts.log?.('WARN', `Architect '${opts.identity.architectName}' session ${shortId}… is held by a foreign process; minting a fresh session (holder left untouched) in ${opts.identity.workspacePath}`);
258
+ return { foreignHolder: true, reclaimedPids: [] };
259
+ }
260
+ if (reclaimable.length === 0) {
261
+ return { foreignHolder: false, reclaimedPids: [] };
262
+ }
263
+ opts.log?.('WARN', `Architect '${opts.identity.architectName}' session ${shortId}… is held by our own superseded shellper(s) [${reclaimable.join(', ')}]; reaping to reclaim the conversation in ${opts.identity.workspacePath}`);
264
+ const reap = opts.reap ?? ((pids) => reapShellpers(pids));
265
+ await reap(reclaimable);
266
+ return { foreignHolder: false, reclaimedPids: reclaimable };
267
+ }
268
+ //# sourceMappingURL=architect-session-holder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"architect-session-holder.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/architect-session-holder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Issue #1227: a shared single-`ps`-call process snapshot, reused by both the
3
+ * shellper husk sweep (predicate needs pid/ppid to detect "childless") and the
4
+ * fleet-RSS observability feature (needs rss). Centralizing the scan avoids
5
+ * growing a fourth bespoke `ps` caller alongside the three that already exist
6
+ * (session-manager.ts, architect-session-holder.ts, commands/cleanup.ts).
7
+ *
8
+ * Async (`execFile`, not `execFileSync`) is load-bearing, not a style choice:
9
+ * this is called from `/health` (tower-routes.ts), a hot Tower HTTP path.
10
+ * `execFileSync` blocks the entire Node.js event loop for the duration of the
11
+ * `ps` call, freezing every open terminal's WebSocket traffic — the exact
12
+ * previously-fixed anti-pattern documented at lessons-learned.md:160
13
+ * ("execSync in HTTP request handlers blocks the entire Node.js event loop").
14
+ */
15
+ export interface ProcessCensusEntry {
16
+ pid: number;
17
+ ppid: number;
18
+ /** Resident set size in kilobytes, as `ps -o rss=` reports it. */
19
+ rssKb: number;
20
+ /** The full joined argv (as `ps ... -o args=` reports it). */
21
+ cmdline: string;
22
+ }
23
+ /**
24
+ * Snapshot every running process as {pid, ppid, rssKb, cmdline}. `ps -ww`
25
+ * prevents argv truncation (shellper config blobs are large) on both BSD and
26
+ * coreutils `ps`. Resolves to `[]` on `ps` failure (missing binary, timeout,
27
+ * non-zero exit) — callers decide how to degrade, mirroring the async
28
+ * `findShellperProcesses` convention in `../../terminal/session-manager.ts`.
29
+ *
30
+ * Deliberately raw `execFile` + a hand-rolled Promise, not `execFileSync` and
31
+ * not `util.promisify(execFile)`: this is called from `/health`
32
+ * (tower-routes.ts), a hot Tower HTTP path, so it must never block the event
33
+ * loop — `execFileSync` would freeze every open terminal's WebSocket traffic
34
+ * for the duration of the `ps` call, the exact previously-fixed anti-pattern
35
+ * documented at lessons-learned.md:160. `util.promisify` is avoided because
36
+ * `child_process.execFile` carries a built-in custom promisify resolving
37
+ * `{stdout, stderr}` via a non-standard symbol that a test mock would need to
38
+ * reproduce exactly to avoid silently promisifying to the wrong shape.
39
+ */
40
+ export declare function listProcessCensus(): Promise<ProcessCensusEntry[]>;
41
+ //# sourceMappingURL=process-census.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-census.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/servers/process-census.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;CACjB;AAkBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAUjE"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Issue #1227: a shared single-`ps`-call process snapshot, reused by both the
3
+ * shellper husk sweep (predicate needs pid/ppid to detect "childless") and the
4
+ * fleet-RSS observability feature (needs rss). Centralizing the scan avoids
5
+ * growing a fourth bespoke `ps` caller alongside the three that already exist
6
+ * (session-manager.ts, architect-session-holder.ts, commands/cleanup.ts).
7
+ *
8
+ * Async (`execFile`, not `execFileSync`) is load-bearing, not a style choice:
9
+ * this is called from `/health` (tower-routes.ts), a hot Tower HTTP path.
10
+ * `execFileSync` blocks the entire Node.js event loop for the duration of the
11
+ * `ps` call, freezing every open terminal's WebSocket traffic — the exact
12
+ * previously-fixed anti-pattern documented at lessons-learned.md:160
13
+ * ("execSync in HTTP request handlers blocks the entire Node.js event loop").
14
+ */
15
+ import { execFile } from 'node:child_process';
16
+ function parseCensus(out) {
17
+ const entries = [];
18
+ for (const line of out.split('\n')) {
19
+ const trimmed = line.trimStart();
20
+ if (!trimmed)
21
+ continue;
22
+ const fields = trimmed.match(/^(\d+)\s+(\d+)\s+(\d+)\s+(.*)$/s);
23
+ if (!fields)
24
+ continue;
25
+ const pid = parseInt(fields[1], 10);
26
+ const ppid = parseInt(fields[2], 10);
27
+ const rssKb = parseInt(fields[3], 10);
28
+ if (Number.isNaN(pid) || pid <= 0 || Number.isNaN(ppid) || Number.isNaN(rssKb))
29
+ continue;
30
+ entries.push({ pid, ppid, rssKb, cmdline: fields[4] });
31
+ }
32
+ return entries;
33
+ }
34
+ /**
35
+ * Snapshot every running process as {pid, ppid, rssKb, cmdline}. `ps -ww`
36
+ * prevents argv truncation (shellper config blobs are large) on both BSD and
37
+ * coreutils `ps`. Resolves to `[]` on `ps` failure (missing binary, timeout,
38
+ * non-zero exit) — callers decide how to degrade, mirroring the async
39
+ * `findShellperProcesses` convention in `../../terminal/session-manager.ts`.
40
+ *
41
+ * Deliberately raw `execFile` + a hand-rolled Promise, not `execFileSync` and
42
+ * not `util.promisify(execFile)`: this is called from `/health`
43
+ * (tower-routes.ts), a hot Tower HTTP path, so it must never block the event
44
+ * loop — `execFileSync` would freeze every open terminal's WebSocket traffic
45
+ * for the duration of the `ps` call, the exact previously-fixed anti-pattern
46
+ * documented at lessons-learned.md:160. `util.promisify` is avoided because
47
+ * `child_process.execFile` carries a built-in custom promisify resolving
48
+ * `{stdout, stderr}` via a non-standard symbol that a test mock would need to
49
+ * reproduce exactly to avoid silently promisifying to the wrong shape.
50
+ */
51
+ export function listProcessCensus() {
52
+ return new Promise((resolve) => {
53
+ execFile('ps', ['-A', '-ww', '-eo', 'pid=,ppid=,rss=,args='], { timeout: 5000, maxBuffer: 16 * 1024 * 1024 }, (err, stdout) => {
54
+ if (err || !stdout) {
55
+ resolve([]);
56
+ return;
57
+ }
58
+ resolve(parseCensus(stdout));
59
+ });
60
+ });
61
+ }
62
+ //# sourceMappingURL=process-census.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-census.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/process-census.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAW9C,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QAChE,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;YAAE,SAAS;QACzF,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC5H,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBACnB,OAAO,CAAC,EAAE,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"send-buffer.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/servers/send-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QACzC,EAAE,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QACvC,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;AAClE,0FAA0F;AAC1F,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AACpG,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAMhF,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,GAAG,CAAsB;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEpB,IAAI,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE;IAKxE,8CAA8C;IAC9C,OAAO,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IASnC,uEAAuE;IACvE,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI;IAQrE,+DAA+D;IAC/D,IAAI,IAAI,IAAI;IASZ,yEAAyE;IACzE,KAAK,CAAC,QAAQ,UAAQ,GAAG,IAAI;IA0C7B,qEAAqE;IACrE,IAAI,YAAY,IAAI,MAAM,CAMzB;IAED,+DAA+D;IAC/D,IAAI,YAAY,IAAI,MAAM,CAEzB;CACF"}
1
+ {"version":3,"file":"send-buffer.d.ts","sourceRoot":"","sources":["../../../src/agent-farm/servers/send-buffer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QACzC,EAAE,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QACvC,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;AAClE,0FAA0F;AAC1F,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AACpG,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAMhF,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,GAAG,CAAsB;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEpB,IAAI,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE;IAKxE,8CAA8C;IAC9C,OAAO,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IASnC,uEAAuE;IACvE,KAAK,CAAC,UAAU,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,GAAG,IAAI;IAQrE,+DAA+D;IAC/D,IAAI,IAAI,IAAI;IASZ,yEAAyE;IACzE,KAAK,CAAC,QAAQ,UAAQ,GAAG,IAAI;IAwD7B,qEAAqE;IACrE,IAAI,YAAY,IAAI,MAAM,CAMzB;IAED,+DAA+D;IAC/D,IAAI,YAAY,IAAI,MAAM,CAEzB;CACF"}
@@ -65,6 +65,19 @@ export class SendBuffer {
65
65
  const now = Date.now();
66
66
  const maxAgeExceeded = messages.some(m => now - m.timestamp >= this.maxBufferAgeMs);
67
67
  const isIdle = session.isUserIdle(this.idleThresholdMs);
68
+ // #1198: writes to a session whose shellper connection is down are
69
+ // dropped silently. Hold the messages while the connection recovers
70
+ // (in-place reconnect takes a few seconds); if it never does, drop
71
+ // loudly instead of logging a successful delivery.
72
+ if (!session.writable) {
73
+ if (forceAll || maxAgeExceeded) {
74
+ if (this.log) {
75
+ this.log('ERROR', `Dropping ${messages.length} buffered message(s) for unwritable session ${sessionId.slice(0, 8)}... (shellper connection down)`);
76
+ }
77
+ this.buffers.delete(sessionId);
78
+ }
79
+ continue;
80
+ }
68
81
  // Deliver when: forced, user idle, or max age exceeded.
69
82
  // Bugfix #492: removed composing check — it gets stuck true after non-Enter
70
83
  // keystrokes (Ctrl+C, arrows, Tab), causing messages to wait 60s max age.
@@ -1 +1 @@
1
- {"version":3,"file":"send-buffer.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/send-buffer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"send-buffer.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/send-buffer.ts"],"names":[],"mappings":"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"}