@agentmeshhq/agent 0.4.15 → 0.4.18

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 (111) hide show
  1. package/dist/__tests__/bootstrap.test.js +24 -0
  2. package/dist/__tests__/bootstrap.test.js.map +1 -1
  3. package/dist/__tests__/injection-verify.test.d.ts +1 -0
  4. package/dist/__tests__/injection-verify.test.js +93 -0
  5. package/dist/__tests__/injection-verify.test.js.map +1 -0
  6. package/dist/__tests__/injector.test.js +115 -1
  7. package/dist/__tests__/injector.test.js.map +1 -1
  8. package/dist/__tests__/lead-loop.test.d.ts +1 -0
  9. package/dist/__tests__/lead-loop.test.js +170 -0
  10. package/dist/__tests__/lead-loop.test.js.map +1 -0
  11. package/dist/__tests__/relay.test.d.ts +1 -0
  12. package/dist/__tests__/relay.test.js +17 -0
  13. package/dist/__tests__/relay.test.js.map +1 -0
  14. package/dist/__tests__/roles.test.d.ts +1 -0
  15. package/dist/__tests__/roles.test.js +78 -0
  16. package/dist/__tests__/roles.test.js.map +1 -0
  17. package/dist/__tests__/runner.test.js +17 -0
  18. package/dist/__tests__/runner.test.js.map +1 -1
  19. package/dist/__tests__/session-recovery.test.js +214 -11
  20. package/dist/__tests__/session-recovery.test.js.map +1 -1
  21. package/dist/__tests__/start-team-id.test.js +8 -3
  22. package/dist/__tests__/start-team-id.test.js.map +1 -1
  23. package/dist/__tests__/startup-diagnostics.test.d.ts +1 -0
  24. package/dist/__tests__/startup-diagnostics.test.js +250 -0
  25. package/dist/__tests__/startup-diagnostics.test.js.map +1 -0
  26. package/dist/__tests__/tmux-runtime.test.js +13 -0
  27. package/dist/__tests__/tmux-runtime.test.js.map +1 -1
  28. package/dist/__tests__/watcher-queue.test.d.ts +1 -0
  29. package/dist/__tests__/watcher-queue.test.js +85 -0
  30. package/dist/__tests__/watcher-queue.test.js.map +1 -0
  31. package/dist/__tests__/watcher-state.test.d.ts +1 -0
  32. package/dist/__tests__/watcher-state.test.js +159 -0
  33. package/dist/__tests__/watcher-state.test.js.map +1 -0
  34. package/dist/cli/commands.d.ts +32 -0
  35. package/dist/cli/commands.js +165 -0
  36. package/dist/cli/commands.js.map +1 -0
  37. package/dist/cli/index.js +95 -5
  38. package/dist/cli/index.js.map +1 -1
  39. package/dist/cli/relay.d.ts +1 -0
  40. package/dist/cli/relay.js +16 -2
  41. package/dist/cli/relay.js.map +1 -1
  42. package/dist/cli/start.d.ts +2 -0
  43. package/dist/cli/start.js +42 -7
  44. package/dist/cli/start.js.map +1 -1
  45. package/dist/config/schema.d.ts +1 -1
  46. package/dist/core/chat-output-parser.d.ts +24 -0
  47. package/dist/core/chat-output-parser.js +134 -0
  48. package/dist/core/chat-output-parser.js.map +1 -0
  49. package/dist/core/chat-output-parser.test.d.ts +7 -0
  50. package/dist/core/chat-output-parser.test.js +130 -0
  51. package/dist/core/chat-output-parser.test.js.map +1 -0
  52. package/dist/core/daemon/bootstrap.js +14 -4
  53. package/dist/core/daemon/bootstrap.js.map +1 -1
  54. package/dist/core/daemon/context-template.d.ts +5 -1
  55. package/dist/core/daemon/context-template.js +16 -2
  56. package/dist/core/daemon/context-template.js.map +1 -1
  57. package/dist/core/daemon/crash-log.js +5 -0
  58. package/dist/core/daemon/crash-log.js.map +1 -1
  59. package/dist/core/daemon/injection-verify.d.ts +25 -0
  60. package/dist/core/daemon/injection-verify.js +94 -0
  61. package/dist/core/daemon/injection-verify.js.map +1 -0
  62. package/dist/core/daemon/lead-loop.d.ts +22 -0
  63. package/dist/core/daemon/lead-loop.js +155 -0
  64. package/dist/core/daemon/lead-loop.js.map +1 -0
  65. package/dist/core/daemon/roles.d.ts +25 -0
  66. package/dist/core/daemon/roles.js +46 -0
  67. package/dist/core/daemon/roles.js.map +1 -0
  68. package/dist/core/daemon/session-recovery.d.ts +18 -1
  69. package/dist/core/daemon/session-recovery.js +89 -5
  70. package/dist/core/daemon/session-recovery.js.map +1 -1
  71. package/dist/core/daemon/startup-diagnostics.d.ts +76 -0
  72. package/dist/core/daemon/startup-diagnostics.js +277 -0
  73. package/dist/core/daemon/startup-diagnostics.js.map +1 -0
  74. package/dist/core/daemon/watcher-loop.d.ts +27 -0
  75. package/dist/core/daemon/watcher-loop.js +134 -0
  76. package/dist/core/daemon/watcher-loop.js.map +1 -0
  77. package/dist/core/daemon/watcher-queue.d.ts +33 -0
  78. package/dist/core/daemon/watcher-queue.js +71 -0
  79. package/dist/core/daemon/watcher-queue.js.map +1 -0
  80. package/dist/core/daemon/watcher-state.d.ts +66 -0
  81. package/dist/core/daemon/watcher-state.js +151 -0
  82. package/dist/core/daemon/watcher-state.js.map +1 -0
  83. package/dist/core/daemon.d.ts +14 -0
  84. package/dist/core/daemon.js +182 -3
  85. package/dist/core/daemon.js.map +1 -1
  86. package/dist/core/injector.js +198 -1
  87. package/dist/core/injector.js.map +1 -1
  88. package/dist/core/registry.d.ts +5 -0
  89. package/dist/core/registry.js +19 -0
  90. package/dist/core/registry.js.map +1 -1
  91. package/dist/core/runner/build.js +7 -31
  92. package/dist/core/runner/build.js.map +1 -1
  93. package/dist/core/runner/detect.js +2 -8
  94. package/dist/core/runner/detect.js.map +1 -1
  95. package/dist/core/runner/index.d.ts +3 -1
  96. package/dist/core/runner/index.js +2 -0
  97. package/dist/core/runner/index.js.map +1 -1
  98. package/dist/core/runner/kimi-models.d.ts +4 -0
  99. package/dist/core/runner/kimi-models.js +24 -0
  100. package/dist/core/runner/kimi-models.js.map +1 -0
  101. package/dist/core/runner/registry.d.ts +3 -0
  102. package/dist/core/runner/registry.js +75 -0
  103. package/dist/core/runner/registry.js.map +1 -0
  104. package/dist/core/runner/types.d.ts +17 -1
  105. package/dist/core/tmux-runtime.d.ts +1 -1
  106. package/dist/core/tmux-runtime.js +13 -0
  107. package/dist/core/tmux-runtime.js.map +1 -1
  108. package/dist/core/tmux.d.ts +4 -0
  109. package/dist/core/tmux.js +49 -11
  110. package/dist/core/tmux.js.map +1 -1
  111. package/package.json +1 -1
@@ -0,0 +1,155 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const execAsync = promisify(exec);
4
+ function ciGreen(pr) {
5
+ const checks = pr.statusCheckRollup;
6
+ if (!checks || checks.length === 0)
7
+ return true; // no checks = assume green
8
+ return checks.every((c) => {
9
+ if (c.conclusion)
10
+ return c.conclusion === "SUCCESS";
11
+ if (c.state)
12
+ return c.state === "SUCCESS";
13
+ return false;
14
+ });
15
+ }
16
+ /** Fetch the reviewer agent ID from the hub at tick time. */
17
+ async function resolveReviewerAgentId(hubUrl, workspace, token) {
18
+ try {
19
+ const res = await fetch(`${hubUrl}/api/v1/workspaces/${workspace}/agents`, {
20
+ headers: { Authorization: `Bearer ${token}` },
21
+ });
22
+ if (!res.ok)
23
+ return null;
24
+ const body = (await res.json());
25
+ const agents = body.data ?? [];
26
+ // Find agent with role "reviewer" or display_name containing "reviewer"
27
+ const reviewer = agents.find((a) => a.metadata?.role === "reviewer" || a.display_name?.toLowerCase().includes("reviewer"));
28
+ return reviewer?.agent_id ?? null;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ /**
35
+ * Check whether an active (non-completed, non-rejected) handoff already exists
36
+ * for this PR number sent from this agent.
37
+ */
38
+ async function handoffExistsForPr(hubUrl, workspace, token, prNumber) {
39
+ try {
40
+ const res = await fetch(`${hubUrl}/api/v1/workspaces/${workspace}/handoffs?limit=50`, {
41
+ headers: { Authorization: `Bearer ${token}` },
42
+ });
43
+ if (!res.ok)
44
+ return false;
45
+ const body = (await res.json());
46
+ const handoffs = body.data ?? [];
47
+ return handoffs.some((h) => h.scope?.includes(`#${prNumber}`) && h.status !== "completed" && h.status !== "rejected");
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ /** Create a handoff to the reviewer agent for this PR. */
54
+ async function createReviewHandoff(hubUrl, workspace, token, reviewerAgentId, pr) {
55
+ try {
56
+ const res = await fetch(`${hubUrl}/api/v1/workspaces/${workspace}/handoffs`, {
57
+ method: "POST",
58
+ headers: {
59
+ Authorization: `Bearer ${token}`,
60
+ "Content-Type": "application/json",
61
+ },
62
+ body: JSON.stringify({
63
+ to_agent_id: reviewerAgentId,
64
+ scope: `Review PR #${pr.number}: ${pr.title}`,
65
+ reason: `PR #${pr.number} (${pr.headRefName}) is open and needs review before merge.`,
66
+ metadata: { pr_number: pr.number, watcher_generated: true },
67
+ }),
68
+ });
69
+ if (!res.ok)
70
+ return null;
71
+ const body = (await res.json());
72
+ return body.handoff_id ?? null;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ /**
79
+ * One coordination tick for a lead agent:
80
+ * 1. Poll open PRs via `gh pr list`
81
+ * 2. Update BEHIND branches via `gh pr update-branch`
82
+ * 3. Route unreviewed PRs to the reviewer via hub handoffs
83
+ * 4. Merge APPROVED + CI-green + MERGEABLE PRs
84
+ */
85
+ export async function runLeadTick(ctx) {
86
+ const run = ctx.exec ?? execAsync;
87
+ let prs;
88
+ try {
89
+ const { stdout } = await run("gh pr list --state open --json number,title,headRefName,mergeable,reviewDecision,statusCheckRollup");
90
+ prs = JSON.parse(stdout.trim());
91
+ }
92
+ catch (err) {
93
+ ctx.log(`[lead-tick] Failed to list PRs: ${err.message}`);
94
+ return;
95
+ }
96
+ if (prs.length === 0) {
97
+ ctx.log("[lead-tick] No open PRs.");
98
+ return;
99
+ }
100
+ // Resolve reviewer once per tick
101
+ const reviewerAgentId = ctx.reviewerAgentId ?? (await resolveReviewerAgentId(ctx.hubUrl, ctx.workspace, ctx.token));
102
+ let updated = 0;
103
+ let routed = 0;
104
+ let merged = 0;
105
+ let skipped = 0;
106
+ for (const pr of prs) {
107
+ try {
108
+ // 1. Update BEHIND branches
109
+ if (pr.mergeable === "BEHIND") {
110
+ try {
111
+ await run(`gh pr update-branch ${pr.number}`);
112
+ ctx.log(`[lead-tick] PR #${pr.number}: updated BEHIND branch`);
113
+ updated++;
114
+ }
115
+ catch (err) {
116
+ ctx.log(`[lead-tick] PR #${pr.number}: update-branch failed: ${err.message}`);
117
+ }
118
+ }
119
+ // 2. Route unreviewed PRs to reviewer
120
+ if ((!pr.reviewDecision || pr.reviewDecision === "REVIEW_REQUIRED") && reviewerAgentId) {
121
+ const alreadySent = await handoffExistsForPr(ctx.hubUrl, ctx.workspace, ctx.token, pr.number);
122
+ if (!alreadySent) {
123
+ const handoffId = await createReviewHandoff(ctx.hubUrl, ctx.workspace, ctx.token, reviewerAgentId, pr);
124
+ if (handoffId) {
125
+ ctx.log(`[lead-tick] PR #${pr.number}: review handoff created → ${handoffId}`);
126
+ routed++;
127
+ }
128
+ else {
129
+ ctx.log(`[lead-tick] PR #${pr.number}: failed to create review handoff`);
130
+ }
131
+ }
132
+ }
133
+ // 3. Merge APPROVED + CI-green + MERGEABLE PRs
134
+ if (pr.reviewDecision === "APPROVED" && pr.mergeable === "MERGEABLE" && ciGreen(pr)) {
135
+ try {
136
+ await run(`gh pr merge ${pr.number} --squash --delete-branch`);
137
+ ctx.log(`[lead-tick] PR #${pr.number}: merged`);
138
+ merged++;
139
+ }
140
+ catch (err) {
141
+ ctx.log(`[lead-tick] PR #${pr.number}: merge failed: ${err.message}`);
142
+ }
143
+ }
144
+ else if (pr.reviewDecision === "APPROVED") {
145
+ skipped++;
146
+ ctx.log(`[lead-tick] PR #${pr.number}: approved but not mergeable (mergeable=${pr.mergeable}, ci=${ciGreen(pr)})`);
147
+ }
148
+ }
149
+ catch (err) {
150
+ ctx.log(`[lead-tick] PR #${pr.number}: unexpected error: ${err.message}`);
151
+ }
152
+ }
153
+ ctx.log(`[lead-tick] done — prs=${prs.length} updated=${updated} routed=${routed} merged=${merged} skipped=${skipped}`);
154
+ }
155
+ //# sourceMappingURL=lead-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lead-loop.js","sourceRoot":"","sources":["../../../src/core/daemon/lead-loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Predefined agent roles — each role activates specific daemon behaviour and
3
+ * injects a role-scoped system prompt into the agent's CLAUDE.md context.
4
+ *
5
+ * Adding a new role requires updating all three exports below.
6
+ */
7
+ /** Canonical set of predefined roles. Free-form strings are still accepted for
8
+ * hub auto-assignment but will not activate role-specific daemon behaviour. */
9
+ export type AgentRole = "coordinator" | "developer" | "reviewer" | "lead" | "observer" | "watcher";
10
+ export declare const VALID_ROLES: readonly AgentRole[];
11
+ export declare function isKnownRole(role: string): role is AgentRole;
12
+ /**
13
+ * System prompt injected into CLAUDE.md for each predefined role.
14
+ * Injected at session start — works for all runners (opencode, claude, codex, custom).
15
+ */
16
+ export declare const ROLE_SYSTEM_PROMPTS: Record<AgentRole, string>;
17
+ /**
18
+ * Maps each predefined role to a daemon behaviour mode:
19
+ * - "lead-loop" → starts runLeadTick every 2 minutes
20
+ * - "worker" → standard inbox poll + auto-accept handoffs
21
+ * - "observer" → heartbeat only; no auto-accept, no lead loop
22
+ *
23
+ * Replaces inferAttendedFromRole() in bootstrap.ts for known roles.
24
+ */
25
+ export declare const ROLE_DAEMON_BEHAVIOUR: Record<AgentRole, "lead-loop" | "worker" | "observer" | "watcher-loop">;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Predefined agent roles — each role activates specific daemon behaviour and
3
+ * injects a role-scoped system prompt into the agent's CLAUDE.md context.
4
+ *
5
+ * Adding a new role requires updating all three exports below.
6
+ */
7
+ export const VALID_ROLES = [
8
+ "coordinator",
9
+ "developer",
10
+ "reviewer",
11
+ "lead",
12
+ "observer",
13
+ "watcher",
14
+ ];
15
+ export function isKnownRole(role) {
16
+ return VALID_ROLES.includes(role);
17
+ }
18
+ /**
19
+ * System prompt injected into CLAUDE.md for each predefined role.
20
+ * Injected at session start — works for all runners (opencode, claude, codex, custom).
21
+ */
22
+ export const ROLE_SYSTEM_PROMPTS = {
23
+ coordinator: "You are a coordinator agent. Your job is to route work, manage PR reviews via handoffs, and merge approved pull requests. Do not implement features yourself — delegate to developer agents.",
24
+ developer: "You are a developer agent. Your job is to implement features and bug fixes assigned via handoffs, write tests, and open pull requests for review.",
25
+ reviewer: "You are a reviewer agent. Your job is to review pull requests and handoff proposals for correctness, quality, and consistency. Approve, request changes, or reject with clear reasoning.",
26
+ lead: "You are a lead agent. You coordinate the team, route work to the right agents, monitor SLAs, and escalate blockers. You also review high-level architecture decisions.",
27
+ observer: "You are an observer agent. You monitor team activity and provide strategic input when asked. You do not accept handoffs automatically and do not modify code directly.",
28
+ watcher: "You are a watcher agent. Every ~2 minutes you receive a project state snapshot showing handoffs, agent health, blockers, and claims. Analyze the state and take corrective actions using agentmesh CLI commands: nudge stuck agents, escalate breached SLAs, reassign stalled handoffs, create blockers, release stale claims. Process one tick at a time — after analysis and action, wait for the next tick. Do not take actions unprompted between ticks.",
29
+ };
30
+ /**
31
+ * Maps each predefined role to a daemon behaviour mode:
32
+ * - "lead-loop" → starts runLeadTick every 2 minutes
33
+ * - "worker" → standard inbox poll + auto-accept handoffs
34
+ * - "observer" → heartbeat only; no auto-accept, no lead loop
35
+ *
36
+ * Replaces inferAttendedFromRole() in bootstrap.ts for known roles.
37
+ */
38
+ export const ROLE_DAEMON_BEHAVIOUR = {
39
+ coordinator: "lead-loop",
40
+ developer: "worker",
41
+ reviewer: "worker",
42
+ lead: "lead-loop",
43
+ observer: "observer",
44
+ watcher: "watcher-loop",
45
+ };
46
+ //# sourceMappingURL=roles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.js","sourceRoot":"","sources":["../../../src/core/daemon/roles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,CAAC,MAAM,WAAW,GAAyB;IAC/C,aAAa;IACb,WAAW;IACX,UAAU;IACV,MAAM;IACN,UAAU;IACV,SAAS;CACV,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAQ,WAAiC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA8B;IAC5D,WAAW,EACT,8LAA8L;IAChM,SAAS,EACP,mJAAmJ;IACrJ,QAAQ,EACN,0LAA0L;IAC5L,IAAI,EAAE,wKAAwK;IAC9K,QAAQ,EACN,wKAAwK;IAC1K,OAAO,EACL,8bAA8b;CACjc,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAG9B;IACF,WAAW,EAAE,WAAW;IACxB,SAAS,EAAE,QAAQ;IACnB,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,WAAW;IACjB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,cAAc;CACxB,CAAC"}
@@ -1 +1,18 @@
1
- export declare function isRecoverableSessionFailure(reason: string): boolean;
1
+ import { type ProcessExitEvent } from "./startup-diagnostics.js";
2
+ /**
3
+ * Gets the most recent process exit event from diagnostics
4
+ */
5
+ export declare function getLastProcessExit(agentName: string): ProcessExitEvent | null;
6
+ /**
7
+ * Determines if a session failure is recoverable based on the reason
8
+ * and startup diagnostics.
9
+ *
10
+ * A failure is considered recoverable if:
11
+ * 1. The reason matches known recoverable patterns
12
+ * 2. The process exited during startup (within 15s) AND the exit event is fresh
13
+ * (within 60s) - this suggests a transient issue that may resolve on retry
14
+ *
15
+ * The freshness guard prevents old exit events from misclassifying unrelated
16
+ * future failures as recoverable.
17
+ */
18
+ export declare function isRecoverableSessionFailure(reason: string, agentName?: string): boolean;
@@ -1,7 +1,91 @@
1
- export function isRecoverableSessionFailure(reason) {
2
- return (reason === "session_not_found" ||
3
- reason === "pane_dead" ||
4
- reason === "no_pid" ||
5
- reason.startsWith("check_failed"));
1
+ import { readStartupDiagnostics } from "./startup-diagnostics.js";
2
+ /**
3
+ * Extended reasons that can indicate a recoverable session failure
4
+ */
5
+ const RECOVERABLE_REASONS = [
6
+ "session_not_found",
7
+ "pane_dead",
8
+ "no_pid",
9
+ "pane_died",
10
+ "process_replaced",
11
+ "session_terminated",
12
+ ];
13
+ /**
14
+ * Maximum age of an exit event to consider it relevant (60 seconds)
15
+ * Exit events older than this are considered stale and unrelated to current failures
16
+ */
17
+ const MAX_EXIT_EVENT_AGE_MS = 60000;
18
+ /**
19
+ * Startup window - if process exits within this time of startup, it's recoverable
20
+ */
21
+ const STARTUP_WINDOW_MS = 15000;
22
+ /**
23
+ * Check if a reason string matches recoverable patterns
24
+ */
25
+ function matchesRecoverablePattern(reason) {
26
+ return (RECOVERABLE_REASONS.includes(reason) ||
27
+ reason.startsWith("check_failed") ||
28
+ reason.startsWith("session_creation_failed") ||
29
+ reason.startsWith("pane_dead"));
30
+ }
31
+ /**
32
+ * Gets the most recent process exit event from diagnostics
33
+ */
34
+ export function getLastProcessExit(agentName) {
35
+ const entries = readStartupDiagnostics(agentName);
36
+ // Find the most recent exit entry
37
+ for (let i = entries.length - 1; i >= 0; i--) {
38
+ if (entries[i].type === "exit") {
39
+ return entries[i].data;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ /**
45
+ * Determines if a session failure is recoverable based on the reason
46
+ * and startup diagnostics.
47
+ *
48
+ * A failure is considered recoverable if:
49
+ * 1. The reason matches known recoverable patterns
50
+ * 2. The process exited during startup (within 15s) AND the exit event is fresh
51
+ * (within 60s) - this suggests a transient issue that may resolve on retry
52
+ *
53
+ * The freshness guard prevents old exit events from misclassifying unrelated
54
+ * future failures as recoverable.
55
+ */
56
+ export function isRecoverableSessionFailure(reason, agentName) {
57
+ // First check pattern match
58
+ if (matchesRecoverablePattern(reason)) {
59
+ return true;
60
+ }
61
+ // If we have agent name, check startup diagnostics
62
+ if (agentName) {
63
+ const entries = readStartupDiagnostics(agentName);
64
+ let lastExit = null;
65
+ for (let i = entries.length - 1; i >= 0; i--) {
66
+ if (entries[i].type === "exit") {
67
+ lastExit = {
68
+ exit: entries[i].data,
69
+ timestamp: entries[i].timestamp,
70
+ };
71
+ break;
72
+ }
73
+ }
74
+ if (lastExit) {
75
+ // Check freshness: exit event must be recent enough to be relevant
76
+ const exitTimestamp = new Date(lastExit.timestamp).getTime();
77
+ const now = Date.now();
78
+ const exitAgeMs = now - exitTimestamp;
79
+ // Only consider fresh exit events (within last 60 seconds)
80
+ if (exitAgeMs <= MAX_EXIT_EVENT_AGE_MS) {
81
+ // If process exited within 15 seconds of startup, consider it recoverable
82
+ // This catches cases where the runner crashed immediately
83
+ if (lastExit.exit.elapsedMs < STARTUP_WINDOW_MS) {
84
+ return true;
85
+ }
86
+ }
87
+ }
88
+ }
89
+ return false;
6
90
  }
7
91
  //# sourceMappingURL=session-recovery.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-recovery.js","sourceRoot":"","sources":["../../../src/core/daemon/session-recovery.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,2BAA2B,CAAC,MAAc;IACxD,OAAO,CACL,MAAM,KAAK,mBAAmB;QAC9B,MAAM,KAAK,WAAW;QACtB,MAAM,KAAK,QAAQ;QACnB,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAClC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"session-recovery.js","sourceRoot":"","sources":["../../../src/core/daemon/session-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEzF;;GAEG;AACH,MAAM,mBAAmB,GAAG;IAC1B,mBAAmB;IACnB,WAAW;IACX,QAAQ;IACR,WAAW;IACX,kBAAkB;IAClB,oBAAoB;CACrB,CAAC;AAEF;;;GAGG;AACH,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC;;GAEG;AACH,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEhC;;GAEG;AACH,SAAS,yBAAyB,CAAC,MAAc;IAC/C,OAAO,CACL,mBAAmB,CAAC,QAAQ,CAAC,MAAM,CAAC;QACpC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC;QACjC,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC;QAC5C,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,MAAM,OAAO,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IAClD,kCAAkC;IAClC,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,IAAwB,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAc,EAAE,SAAkB;IAC5E,4BAA4B;IAC5B,IAAI,yBAAyB,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,mDAAmD;IACnD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAOlD,IAAI,QAAQ,GAAqB,IAAI,CAAC;QAEtC,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC/B,QAAQ,GAAG;oBACT,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAwB;oBACzC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;iBAChC,CAAC;gBACF,MAAM;YACR,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,mEAAmE;YACnE,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;YAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,SAAS,GAAG,GAAG,GAAG,aAAa,CAAC;YAEtC,2DAA2D;YAC3D,IAAI,SAAS,IAAI,qBAAqB,EAAE,CAAC;gBACvC,0EAA0E;gBAC1E,0DAA0D;gBAC1D,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,iBAAiB,EAAE,CAAC;oBAChD,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Startup Diagnostics for Agent Tmux Sessions
3
+ *
4
+ * Provides structured logging for runner startup to diagnose
5
+ * session creation failures and early exits.
6
+ */
7
+ export interface StartupDiagnostics {
8
+ /** The final resolved command (with args) that was executed */
9
+ resolvedCommand: string;
10
+ /** Environment variables set (keys only, values redacted) */
11
+ envKeys: string[];
12
+ /** Session name used for tmux */
13
+ sessionName: string;
14
+ /** Working directory for the session */
15
+ workdir?: string;
16
+ /** Timestamp when session creation started */
17
+ startTime: string;
18
+ /** Runner type detected */
19
+ runnerKind: "opencode" | "claude" | "codex" | "other";
20
+ /** Whether autonomous mode was enabled */
21
+ autonomous?: boolean;
22
+ }
23
+ export interface ProcessExitEvent {
24
+ /** Exit code (null if killed by signal) */
25
+ code: number | null;
26
+ /** Signal that killed the process (null if exited normally) */
27
+ signal: string | null;
28
+ /** Time elapsed since session creation (ms) */
29
+ elapsedMs: number;
30
+ /** Reason classification */
31
+ reason: string;
32
+ }
33
+ interface DiagnosticsEntry {
34
+ type: "startup" | "exit";
35
+ timestamp: string;
36
+ agentName: string;
37
+ data: StartupDiagnostics | ProcessExitEvent;
38
+ }
39
+ /**
40
+ * Redacts sensitive environment variable values, keeping only keys
41
+ */
42
+ export declare function redactEnvKeys(env: Record<string, string | undefined>): string[];
43
+ /**
44
+ * Detects the runner type from the command
45
+ */
46
+ export declare function detectRunnerKind(command: string): "opencode" | "claude" | "codex" | "other";
47
+ /**
48
+ * Logs startup diagnostics for a new tmux session
49
+ */
50
+ export declare function logSessionStartup(agentName: string, diagnostics: StartupDiagnostics): void;
51
+ /**
52
+ * Logs a process exit event
53
+ */
54
+ export declare function logProcessExit(agentName: string, exitEvent: ProcessExitEvent): void;
55
+ /**
56
+ * Reads the recent diagnostics for an agent
57
+ */
58
+ export declare function readStartupDiagnostics(agentName: string): DiagnosticsEntry[];
59
+ /**
60
+ * Clears old diagnostics for an agent (keeps last 100 entries)
61
+ */
62
+ export declare function cleanupOldDiagnostics(agentName: string): void;
63
+ /**
64
+ * Captures the current pane PID for an agent's session
65
+ */
66
+ export declare function capturePanePid(sessionName: string): number | null;
67
+ /**
68
+ * Monitors a tmux session for early process exit
69
+ * Returns a cleanup function to stop monitoring
70
+ */
71
+ export declare function monitorSessionExit(agentName: string, sessionName: string, startTime: Date, onEarlyExit?: (event: ProcessExitEvent) => void): () => void;
72
+ /**
73
+ * Formats a diagnostic summary for display
74
+ */
75
+ export declare function formatDiagnosticSummary(agentName: string): string;
76
+ export {};