@integrity-labs/agt-cli 0.27.149 → 0.27.150-test.16

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,173 @@
1
+ // src/lib/daily-session.ts
2
+ import { randomUUID } from "crypto";
3
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+ var HISTORY_DAYS = 7;
7
+ function profileDir(codeName) {
8
+ return join(homedir(), ".augmented", codeName);
9
+ }
10
+ function dailySessionPath(codeName) {
11
+ return join(profileDir(codeName), "daily-session.json");
12
+ }
13
+ function todayLocalIso(now = /* @__PURE__ */ new Date(), timezone) {
14
+ if (timezone) {
15
+ try {
16
+ const fmt = new Intl.DateTimeFormat("en-CA", {
17
+ timeZone: timezone,
18
+ year: "numeric",
19
+ month: "2-digit",
20
+ day: "2-digit"
21
+ });
22
+ return fmt.format(now);
23
+ } catch {
24
+ }
25
+ }
26
+ const y = now.getFullYear();
27
+ const m = String(now.getMonth() + 1).padStart(2, "0");
28
+ const d = String(now.getDate()).padStart(2, "0");
29
+ return `${y}-${m}-${d}`;
30
+ }
31
+ function readFile(codeName) {
32
+ const path = dailySessionPath(codeName);
33
+ if (!existsSync(path)) return { current: null, history: [] };
34
+ try {
35
+ const raw = readFileSync(path, "utf-8");
36
+ const parsed = JSON.parse(raw);
37
+ return {
38
+ current: parsed.current ?? null,
39
+ history: Array.isArray(parsed.history) ? parsed.history : []
40
+ };
41
+ } catch {
42
+ return { current: null, history: [] };
43
+ }
44
+ }
45
+ function writeFile(codeName, data) {
46
+ const dir = profileDir(codeName);
47
+ mkdirSync(dir, { recursive: true });
48
+ const finalPath = dailySessionPath(codeName);
49
+ const tmpPath = `${finalPath}.${process.pid}.${randomUUID()}.tmp`;
50
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf-8");
51
+ renameSync(tmpPath, finalPath);
52
+ }
53
+ function trimHistory(history, now, timezone) {
54
+ const cutoff = new Date(now);
55
+ cutoff.setDate(cutoff.getDate() - HISTORY_DAYS);
56
+ const cutoffIso = todayLocalIso(cutoff, timezone);
57
+ return history.filter((h) => h.date >= cutoffIso).slice(0, HISTORY_DAYS);
58
+ }
59
+ function getOrCreateDailySession(codeName, now = /* @__PURE__ */ new Date(), timezone) {
60
+ const today = todayLocalIso(now, timezone);
61
+ const file = readFile(codeName);
62
+ if (file.current && file.current.date === today) {
63
+ return { sessionId: file.current.sessionId, isNew: false };
64
+ }
65
+ const next = {
66
+ date: today,
67
+ sessionId: randomUUID(),
68
+ startedAt: now.toISOString()
69
+ };
70
+ const history = trimHistory(
71
+ [...file.current ? [file.current] : [], ...file.history],
72
+ now,
73
+ timezone
74
+ );
75
+ writeFile(codeName, { current: next, history });
76
+ return { sessionId: next.sessionId, isNew: true };
77
+ }
78
+ function markDailySessionSpawn(codeName, sessionId, now = /* @__PURE__ */ new Date(), timezone) {
79
+ const today = todayLocalIso(now, timezone);
80
+ const file = readFile(codeName);
81
+ if (file.current && file.current.date === today && file.current.sessionId === sessionId) {
82
+ return;
83
+ }
84
+ const next = {
85
+ date: today,
86
+ sessionId,
87
+ startedAt: now.toISOString()
88
+ };
89
+ const history = trimHistory(
90
+ [...file.current ? [file.current] : [], ...file.history],
91
+ now,
92
+ timezone
93
+ );
94
+ writeFile(codeName, { current: next, history });
95
+ }
96
+ function rotateDailySession(codeName, now = /* @__PURE__ */ new Date(), timezone) {
97
+ const today = todayLocalIso(now, timezone);
98
+ const file = readFile(codeName);
99
+ const next = {
100
+ date: today,
101
+ sessionId: randomUUID(),
102
+ startedAt: now.toISOString()
103
+ };
104
+ const history = trimHistory(
105
+ [...file.current ? [file.current] : [], ...file.history],
106
+ now,
107
+ timezone
108
+ );
109
+ writeFile(codeName, { current: next, history });
110
+ return next.sessionId;
111
+ }
112
+ function encodeProjectPath(projectDir) {
113
+ return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
114
+ }
115
+ function sessionFileExists(projectDir, sessionId) {
116
+ const path = join(
117
+ homedir(),
118
+ ".claude",
119
+ "projects",
120
+ encodeProjectPath(projectDir),
121
+ `${sessionId}.jsonl`
122
+ );
123
+ return existsSync(path);
124
+ }
125
+ function sessionTranscriptDir(projectDir) {
126
+ return join(homedir(), ".claude", "projects", encodeProjectPath(projectDir));
127
+ }
128
+ function sessionFilePath(projectDir, sessionId) {
129
+ return join(sessionTranscriptDir(projectDir), `${sessionId}.jsonl`);
130
+ }
131
+ function transcriptActivityAgeSeconds(projectDir, sessionId, now = /* @__PURE__ */ new Date()) {
132
+ if (!sessionId) return null;
133
+ try {
134
+ const mtimeMs = statSync(sessionFilePath(projectDir, sessionId)).mtimeMs;
135
+ return Math.max(0, Math.floor((now.getTime() - mtimeMs) / 1e3));
136
+ } catch {
137
+ return null;
138
+ }
139
+ }
140
+ function isAgentIdle(projectDir, sessionId, idleSeconds = 60, now = /* @__PURE__ */ new Date()) {
141
+ const path = sessionFilePath(projectDir, sessionId);
142
+ if (!existsSync(path)) return true;
143
+ try {
144
+ const mtimeMs = statSync(path).mtimeMs;
145
+ return now.getTime() - mtimeMs >= idleSeconds * 1e3;
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+ function isStaleForToday(codeName, now = /* @__PURE__ */ new Date(), timezone) {
151
+ const file = readFile(codeName);
152
+ if (!file.current) return false;
153
+ return file.current.date !== todayLocalIso(now, timezone);
154
+ }
155
+ function peekCurrentSession(codeName) {
156
+ return readFile(codeName).current;
157
+ }
158
+ var _internals = { todayLocalIso, dailySessionPath, profileDir, encodeProjectPath };
159
+
160
+ export {
161
+ getOrCreateDailySession,
162
+ markDailySessionSpawn,
163
+ rotateDailySession,
164
+ sessionFileExists,
165
+ sessionTranscriptDir,
166
+ sessionFilePath,
167
+ transcriptActivityAgeSeconds,
168
+ isAgentIdle,
169
+ isStaleForToday,
170
+ peekCurrentSession,
171
+ _internals
172
+ };
173
+ //# sourceMappingURL=chunk-354FAVQR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/daily-session.ts"],"sourcesContent":["/**\n * ENG-4642: per-agent / per-day Claude session pinning.\n *\n * The persistent-session manager kills the tmux session on every spawn\n * (clean slate) and starts a fresh `claude` invocation. Pre-this-module,\n * that meant a new conversation every restart — operators lost context\n * any time the manager respawned.\n *\n * Goal: each calendar day is a fresh conversation, but every spawn\n * inside that day reuses the same conversation. We achieve this by\n * generating a stable UUID up front (Claude CLI accepts\n * `--session-id <uuid>` for the first spawn, `--resume <uuid>` for\n * subsequent ones) and persisting it to a tiny per-agent JSON file.\n *\n * Storage: `~/.augmented/<codeName>/daily-session.json` — same root the\n * persistent-session manager already owns via getProjectDir(). Schema:\n *\n * { \"date\": \"YYYY-MM-DD\", \"sessionId\": \"<uuid>\", \"history\": [...] }\n *\n * `history` keeps the last few days' entries so an operator can debug\n * which session was bound to which day. We trim to 7 days so the file\n * doesn't grow unbounded.\n *\n * Day boundary: defaults to host-local date (server timezone). Callers\n * may pass an IANA timezone (e.g. `Australia/Melbourne`) and the\n * rollover will fire at that zone's midnight instead — see ENG-5371.\n * The manager passes the agent's resolved `agentTimezone` (same source\n * as ENG-5363's channel MCP `TZ` env var: `teamSettings.timezone`,\n * defaulting to UTC) so the daily rollover lines up with what an\n * operator in the agent's timezone calls \"today\".\n *\n * Failure mode: if the on-disk JSONL Claude writes for the resumed\n * session is missing (host moved, profile wiped, claude version\n * incompatibility), `--resume` would fail and the agent would land on\n * the login picker. Callers verify the JSONL exists via\n * `sessionFileExists()` before choosing `--resume`; if it's gone we\n * fall back to `--session-id` (treat the stored UUID as fresh, claude\n * will materialise the JSONL on first turn).\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nconst HISTORY_DAYS = 7;\n\ninterface DailySessionEntry {\n date: string; // YYYY-MM-DD\n sessionId: string; // UUID v4\n startedAt: string; // ISO 8601\n}\n\ninterface DailySessionFile {\n current: DailySessionEntry | null;\n history: DailySessionEntry[];\n}\n\nexport interface DailySessionResult {\n sessionId: string;\n /** `true` when this call generated a new UUID (first spawn of a new day or first ever). */\n isNew: boolean;\n}\n\nfunction profileDir(codeName: string): string {\n return join(homedir(), '.augmented', codeName);\n}\n\nfunction dailySessionPath(codeName: string): string {\n return join(profileDir(codeName), 'daily-session.json');\n}\n\nfunction todayLocalIso(now: Date = new Date(), timezone?: string): string {\n // ENG-5371: when an IANA timezone is supplied (e.g. Australia/Melbourne),\n // compute the date in that zone via Intl.DateTimeFormat. Falling back to\n // Date getters preserves the original host-local behaviour for callers\n // (and tests) that don't supply a timezone — important for\n // backward-compatibility with the ENG-4642 contract.\n if (timezone) {\n try {\n const fmt = new Intl.DateTimeFormat('en-CA', {\n timeZone: timezone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n // en-CA renders as `YYYY-MM-DD` already — no parts assembly needed.\n // Wrapped in try/catch in case the timezone string is invalid, in\n // which case we fall through to host-local rather than throw.\n return fmt.format(now);\n } catch {\n // Invalid IANA zone — fall back to host-local.\n }\n }\n const y = now.getFullYear();\n const m = String(now.getMonth() + 1).padStart(2, '0');\n const d = String(now.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\nfunction readFile(codeName: string): DailySessionFile {\n const path = dailySessionPath(codeName);\n if (!existsSync(path)) return { current: null, history: [] };\n try {\n const raw = readFileSync(path, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<DailySessionFile>;\n return {\n current: parsed.current ?? null,\n history: Array.isArray(parsed.history) ? parsed.history : [],\n };\n } catch {\n // Corrupt file — start fresh rather than crashing the manager.\n return { current: null, history: [] };\n }\n}\n\nfunction writeFile(codeName: string, data: DailySessionFile): void {\n const dir = profileDir(codeName);\n mkdirSync(dir, { recursive: true });\n // Atomic write: tmp + rename. A reader catching us mid-writeFileSync\n // would otherwise see truncated JSON and the corrupt-file branch in\n // readFile() would silently treat the agent as fresh state, losing\n // today's UUID and forcing a rollover the operator didn't ask for.\n // PID + randomUUID in the tmp suffix so two managers (or a respawn\n // racing with its predecessor) can't collide on the temp path and\n // have one rename remove the file the other is about to rename.\n // Mirrors the pattern in restart-flags.ts.\n const finalPath = dailySessionPath(codeName);\n const tmpPath = `${finalPath}.${process.pid}.${randomUUID()}.tmp`;\n writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf-8');\n renameSync(tmpPath, finalPath);\n}\n\nfunction trimHistory(\n history: DailySessionEntry[],\n now: Date,\n timezone?: string,\n): DailySessionEntry[] {\n // Keep newest first, drop entries older than HISTORY_DAYS by date.\n // Take the injected `now` so callers with a frozen clock (tests\n // walking the day forward) don't get inconsistent cutoffs against\n // `new Date()`. The cutoff is computed in the same timezone as the\n // current entry's date string so equality comparisons hold across DST.\n const cutoff = new Date(now);\n cutoff.setDate(cutoff.getDate() - HISTORY_DAYS);\n const cutoffIso = todayLocalIso(cutoff, timezone);\n return history.filter((h) => h.date >= cutoffIso).slice(0, HISTORY_DAYS);\n}\n\n/**\n * Resolve the session UUID this agent should use right now. Generates\n * (and persists) a new UUID on the first call of a new local day, or\n * when the file is missing/corrupt; otherwise returns the day's\n * existing UUID. Idempotent within the same day.\n *\n * Concurrency: the read-then-write here is not under a file lock.\n * In our deployment the manager runs supervised, one process per\n * host (`agt manager start --supervise` / runSupervisorLoop), so\n * concurrent invocation for the same `codeName` is bounded to the\n * sub-second respawn window when the supervisor restarts the\n * worker. The atomic tmp+rename in writeFile() guarantees we never\n * read torn JSON, so the worst-case under a respawn race is two\n * managers minting different UUIDs and one rename winning — both\n * processes converge on the winner's UUID on the next supervisor\n * tick (which re-reads the file). We've taken that trade-off\n * over a proper inter-process lock because a stale lockfile (from\n * a SIGKILL'd manager) would block all subsequent runs and need\n * its own recovery path; the lossy outcome of a UUID race is one\n * tick of conversation churn, not a permanent block.\n */\nexport function getOrCreateDailySession(\n codeName: string,\n now: Date = new Date(),\n timezone?: string,\n): DailySessionResult {\n const today = todayLocalIso(now, timezone);\n const file = readFile(codeName);\n\n if (file.current && file.current.date === today) {\n return { sessionId: file.current.sessionId, isNew: false };\n }\n\n // Roll over: yesterday's (or older) entry moves to history, new one\n // takes its place.\n const next: DailySessionEntry = {\n date: today,\n sessionId: randomUUID(),\n startedAt: now.toISOString(),\n };\n const history = trimHistory(\n [...(file.current ? [file.current] : []), ...file.history],\n now,\n timezone,\n );\n writeFile(codeName, { current: next, history });\n return { sessionId: next.sessionId, isNew: true };\n}\n\n/**\n * Record the UUID a caller just spawned with so the day-rollover\n * marker (`current.date`) advances to today.\n *\n * ENG-5431: a spawn that bypasses `getOrCreateDailySession` (today the\n * AGT_DISABLE_SESSION_RESUME path, which mints a fresh `randomUUID()`;\n * under ENG-5397 it was every spawn) never writes `daily-session.json`,\n * so `isStaleForToday()` keeps returning true once the previous\n * `current.date` falls behind — re-firing the day-rollover restart on\n * every supervisor tick. Calling this after each spawn keeps the\n * marker in lockstep with the actual running session. On the ENG-6039\n * resume/fresh paths it's an idempotent no-op.\n *\n * Idempotent: re-calling with the same (date, sessionId) is a no-op\n * write of the same content. Different sessionId on the same date\n * just overwrites `current.sessionId` (the old one moves to history).\n */\nexport function markDailySessionSpawn(\n codeName: string,\n sessionId: string,\n now: Date = new Date(),\n timezone?: string,\n): void {\n const today = todayLocalIso(now, timezone);\n const file = readFile(codeName);\n if (file.current && file.current.date === today && file.current.sessionId === sessionId) {\n return;\n }\n const next: DailySessionEntry = {\n date: today,\n sessionId,\n startedAt: now.toISOString(),\n };\n const history = trimHistory(\n [...(file.current ? [file.current] : []), ...file.history],\n now,\n timezone,\n );\n writeFile(codeName, { current: next, history });\n}\n\n/**\n * Reset the day's pin — used as a recovery hatch after `--resume` is\n * rejected by claude (corrupt state, version mismatch). Writes a new\n * UUID for today, demotes the old one to history.\n */\nexport function rotateDailySession(\n codeName: string,\n now: Date = new Date(),\n timezone?: string,\n): string {\n const today = todayLocalIso(now, timezone);\n const file = readFile(codeName);\n const next: DailySessionEntry = {\n date: today,\n sessionId: randomUUID(),\n startedAt: now.toISOString(),\n };\n const history = trimHistory(\n [...(file.current ? [file.current] : []), ...file.history],\n now,\n timezone,\n );\n writeFile(codeName, { current: next, history });\n return next.sessionId;\n}\n\n/**\n * Encode an absolute project dir the way Claude Code stores it under\n * ~/.claude/projects/. Claude collapses runs of `/` and `.` into single\n * `-` separators with a leading `-` (no separator at the start). The\n * earlier \"/ only\" encoder produced a stale path for any project dir\n * containing a `.` (e.g. `/root/.augmented/scout/project`), which made\n * sessionFileExists() return false even when the JSONL was on disk.\n *\n * Diagnosed live on prod scout (ENG-4659): the on-disk dir was\n * /root/.claude/projects/-root--augmented-scout-project/\n * but our encoder produced\n * /root/.claude/projects/-root-.augmented-scout-project/\n * — the dot in `.augmented` wasn't translated. Result: every \"is\n * there JSONL on disk\" check returned false, the manager fell back to\n * `--session-id` reuse, and Claude rejected the same UUID with\n * \"Session ID already in use\" forever.\n *\n * Empirical observations from /root/.claude/projects/ on a live host:\n * /usr/bin -> -usr-bin\n * /root/.augmented/scout/project -> -root--augmented-scout-project\n * Behaviour: `[/.]` -> `-`, with consecutive separators preserved\n * (the `/.` between `root/` and `.augmented` becomes `--`).\n */\nfunction encodeProjectPath(projectDir: string): string {\n return '-' + projectDir.replace(/^\\//, '').replace(/[/.]/g, '-');\n}\n\n/**\n * Check whether claude has actually written a session JSONL for this\n * UUID. If the file is missing the `--resume` would fail and put the\n * agent on the login picker; callers should fall back to `--session-id`\n * instead. See encodeProjectPath() for the encoding rules.\n */\nexport function sessionFileExists(\n projectDir: string,\n sessionId: string,\n): boolean {\n const path = join(\n homedir(),\n '.claude',\n 'projects',\n encodeProjectPath(projectDir),\n `${sessionId}.jsonl`,\n );\n return existsSync(path);\n}\n\n/**\n * Directory under ~/.claude/projects/ where Claude Code stores every session\n * transcript for the given project dir. All of an agent's sessions —\n * persistent respawns (one pinned UUID per agent-tz day, ENG-6039, plus\n * rotations), scheduled tasks, and direct-chat invocations — share this one\n * directory because they all run with the same cwd (getProjectDir). The\n * token-usage monitor enumerates it.\n */\nexport function sessionTranscriptDir(projectDir: string): string {\n return join(homedir(), '.claude', 'projects', encodeProjectPath(projectDir));\n}\n\nexport function sessionFilePath(projectDir: string, sessionId: string): string {\n return join(sessionTranscriptDir(projectDir), `${sessionId}.jsonl`);\n}\n\n/**\n * ENG-6238: age (s) of the current session's transcript JSONL — the wedge\n * detector's \"is the model actually producing tokens right now\" signal. The\n * transcript grows as the model streams turns/tool calls, so a fresh mtime\n * means real work is happening, where pane.log can be kept fresh by a frozen\n * but animated spinner. Returns null when there's no session id or the file\n * can't be stat'd (the detector then degrades to the pane-age fallback).\n */\nexport function transcriptActivityAgeSeconds(\n projectDir: string,\n sessionId: string | null,\n now: Date = new Date(),\n): number | null {\n if (!sessionId) return null;\n try {\n const mtimeMs = statSync(sessionFilePath(projectDir, sessionId)).mtimeMs;\n return Math.max(0, Math.floor((now.getTime() - mtimeMs) / 1000));\n } catch {\n return null;\n }\n}\n\n/**\n * Is the agent's session JSONL idle — i.e. has it not been written for\n * at least `idleSeconds`? Claude appends to the file on every turn\n * (tool calls, assistant messages, user messages) so a stale mtime is\n * a reliable proxy for \"nothing in flight\". Returns true if the file\n * is missing (no in-flight work to interrupt) or if its mtime is\n * older than the threshold.\n *\n * Used by the scheduled-rollover gate so we don't kill a tmux session\n * mid-task at the day boundary — defer the rollover one tick at a\n * time until the agent is between turns.\n */\nexport function isAgentIdle(\n projectDir: string,\n sessionId: string,\n idleSeconds = 60,\n now: Date = new Date(),\n): boolean {\n const path = sessionFilePath(projectDir, sessionId);\n if (!existsSync(path)) return true;\n try {\n const mtimeMs = statSync(path).mtimeMs;\n return now.getTime() - mtimeMs >= idleSeconds * 1000;\n } catch {\n // stat failed (race, permissions). Treat as non-idle to err on the\n // side of NOT interrupting a possibly-running task.\n return false;\n }\n}\n\n/**\n * Cheap \"should we roll over?\" check for the supervisor tick. Reads\n * the persisted current entry and compares its date against today's.\n * Does NOT mint a new UUID — the caller decides what to do with the\n * answer (typically: kill the tmux session iff isAgentIdle is true,\n * letting the next tick respawn fresh via getOrCreateDailySession).\n */\nexport function isStaleForToday(\n codeName: string,\n now: Date = new Date(),\n timezone?: string,\n): boolean {\n const file = readFile(codeName);\n if (!file.current) return false; // never seeded — nothing to roll\n return file.current.date !== todayLocalIso(now, timezone);\n}\n\n/**\n * Read-only accessor for the current entry, returns null when the\n * file doesn't exist or has no current entry. Useful to grab the\n * sessionId for the idle check without triggering a roll-over write.\n */\nexport function peekCurrentSession(codeName: string): {\n date: string;\n sessionId: string;\n startedAt: string;\n} | null {\n return readFile(codeName).current;\n}\n\n// Exported for unit tests — keep the surface small.\nexport const _internals = { todayLocalIso, dailySessionPath, profileDir, encodeProjectPath };\n"],"mappings":"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","names":[]}
@@ -1,16 +1,22 @@
1
1
  import {
2
2
  claudeModelAlias,
3
3
  isClaudeFastMode
4
- } from "./chunk-A75AOK6E.js";
4
+ } from "./chunk-WOOYOAPG.js";
5
+ import {
6
+ getOrCreateDailySession,
7
+ markDailySessionSpawn,
8
+ rotateDailySession,
9
+ sessionFileExists
10
+ } from "./chunk-354FAVQR.js";
5
11
  import {
6
12
  reapOrphanChannelMcps
7
13
  } from "./chunk-XWVM4KPK.js";
8
14
 
9
15
  // src/lib/persistent-session.ts
10
16
  import { spawn, execSync, execFileSync as execFileSync3 } from "child_process";
11
- import { join as join2, dirname } from "path";
12
- import { homedir as homedir2, platform, userInfo } from "os";
13
- import { existsSync as existsSync3, readFileSync as readFileSync4, readdirSync, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, copyFileSync, rmSync } from "fs";
17
+ import { join, dirname } from "path";
18
+ import { homedir, platform, userInfo } from "os";
19
+ import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync2, appendFileSync, mkdirSync, chmodSync, copyFileSync, rmSync } from "fs";
14
20
  import { fileURLToPath } from "url";
15
21
 
16
22
  // src/lib/mcp-sanitize.ts
@@ -153,165 +159,7 @@ function probeMcpEnvSubstitution(args) {
153
159
  }
154
160
 
155
161
  // src/lib/persistent-session.ts
156
- import { randomUUID as randomUUID2 } from "crypto";
157
-
158
- // src/lib/daily-session.ts
159
162
  import { randomUUID } from "crypto";
160
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, renameSync, statSync, writeFileSync as writeFileSync2 } from "fs";
161
- import { homedir } from "os";
162
- import { join } from "path";
163
- var HISTORY_DAYS = 7;
164
- function profileDir(codeName) {
165
- return join(homedir(), ".augmented", codeName);
166
- }
167
- function dailySessionPath(codeName) {
168
- return join(profileDir(codeName), "daily-session.json");
169
- }
170
- function todayLocalIso(now = /* @__PURE__ */ new Date(), timezone) {
171
- if (timezone) {
172
- try {
173
- const fmt = new Intl.DateTimeFormat("en-CA", {
174
- timeZone: timezone,
175
- year: "numeric",
176
- month: "2-digit",
177
- day: "2-digit"
178
- });
179
- return fmt.format(now);
180
- } catch {
181
- }
182
- }
183
- const y = now.getFullYear();
184
- const m = String(now.getMonth() + 1).padStart(2, "0");
185
- const d = String(now.getDate()).padStart(2, "0");
186
- return `${y}-${m}-${d}`;
187
- }
188
- function readFile(codeName) {
189
- const path = dailySessionPath(codeName);
190
- if (!existsSync2(path)) return { current: null, history: [] };
191
- try {
192
- const raw = readFileSync3(path, "utf-8");
193
- const parsed = JSON.parse(raw);
194
- return {
195
- current: parsed.current ?? null,
196
- history: Array.isArray(parsed.history) ? parsed.history : []
197
- };
198
- } catch {
199
- return { current: null, history: [] };
200
- }
201
- }
202
- function writeFile(codeName, data) {
203
- const dir = profileDir(codeName);
204
- mkdirSync(dir, { recursive: true });
205
- const finalPath = dailySessionPath(codeName);
206
- const tmpPath = `${finalPath}.${process.pid}.${randomUUID()}.tmp`;
207
- writeFileSync2(tmpPath, JSON.stringify(data, null, 2), "utf-8");
208
- renameSync(tmpPath, finalPath);
209
- }
210
- function trimHistory(history, now, timezone) {
211
- const cutoff = new Date(now);
212
- cutoff.setDate(cutoff.getDate() - HISTORY_DAYS);
213
- const cutoffIso = todayLocalIso(cutoff, timezone);
214
- return history.filter((h) => h.date >= cutoffIso).slice(0, HISTORY_DAYS);
215
- }
216
- function getOrCreateDailySession(codeName, now = /* @__PURE__ */ new Date(), timezone) {
217
- const today = todayLocalIso(now, timezone);
218
- const file = readFile(codeName);
219
- if (file.current && file.current.date === today) {
220
- return { sessionId: file.current.sessionId, isNew: false };
221
- }
222
- const next = {
223
- date: today,
224
- sessionId: randomUUID(),
225
- startedAt: now.toISOString()
226
- };
227
- const history = trimHistory(
228
- [...file.current ? [file.current] : [], ...file.history],
229
- now,
230
- timezone
231
- );
232
- writeFile(codeName, { current: next, history });
233
- return { sessionId: next.sessionId, isNew: true };
234
- }
235
- function markDailySessionSpawn(codeName, sessionId, now = /* @__PURE__ */ new Date(), timezone) {
236
- const today = todayLocalIso(now, timezone);
237
- const file = readFile(codeName);
238
- if (file.current && file.current.date === today && file.current.sessionId === sessionId) {
239
- return;
240
- }
241
- const next = {
242
- date: today,
243
- sessionId,
244
- startedAt: now.toISOString()
245
- };
246
- const history = trimHistory(
247
- [...file.current ? [file.current] : [], ...file.history],
248
- now,
249
- timezone
250
- );
251
- writeFile(codeName, { current: next, history });
252
- }
253
- function rotateDailySession(codeName, now = /* @__PURE__ */ new Date(), timezone) {
254
- const today = todayLocalIso(now, timezone);
255
- const file = readFile(codeName);
256
- const next = {
257
- date: today,
258
- sessionId: randomUUID(),
259
- startedAt: now.toISOString()
260
- };
261
- const history = trimHistory(
262
- [...file.current ? [file.current] : [], ...file.history],
263
- now,
264
- timezone
265
- );
266
- writeFile(codeName, { current: next, history });
267
- return next.sessionId;
268
- }
269
- function encodeProjectPath(projectDir) {
270
- return "-" + projectDir.replace(/^\//, "").replace(/[/.]/g, "-");
271
- }
272
- function sessionFileExists(projectDir, sessionId) {
273
- const path = join(
274
- homedir(),
275
- ".claude",
276
- "projects",
277
- encodeProjectPath(projectDir),
278
- `${sessionId}.jsonl`
279
- );
280
- return existsSync2(path);
281
- }
282
- function sessionTranscriptDir(projectDir) {
283
- return join(homedir(), ".claude", "projects", encodeProjectPath(projectDir));
284
- }
285
- function sessionFilePath(projectDir, sessionId) {
286
- return join(sessionTranscriptDir(projectDir), `${sessionId}.jsonl`);
287
- }
288
- function transcriptActivityAgeSeconds(projectDir, sessionId, now = /* @__PURE__ */ new Date()) {
289
- if (!sessionId) return null;
290
- try {
291
- const mtimeMs = statSync(sessionFilePath(projectDir, sessionId)).mtimeMs;
292
- return Math.max(0, Math.floor((now.getTime() - mtimeMs) / 1e3));
293
- } catch {
294
- return null;
295
- }
296
- }
297
- function isAgentIdle(projectDir, sessionId, idleSeconds = 60, now = /* @__PURE__ */ new Date()) {
298
- const path = sessionFilePath(projectDir, sessionId);
299
- if (!existsSync2(path)) return true;
300
- try {
301
- const mtimeMs = statSync(path).mtimeMs;
302
- return now.getTime() - mtimeMs >= idleSeconds * 1e3;
303
- } catch {
304
- return false;
305
- }
306
- }
307
- function isStaleForToday(codeName, now = /* @__PURE__ */ new Date(), timezone) {
308
- const file = readFile(codeName);
309
- if (!file.current) return false;
310
- return file.current.date !== todayLocalIso(now, timezone);
311
- }
312
- function peekCurrentSession(codeName) {
313
- return readFile(codeName).current;
314
- }
315
163
 
316
164
  // ../../packages/core/dist/runtime/session-probe.js
317
165
  import { execFileSync } from "child_process";
@@ -593,7 +441,7 @@ function syncClaudeCredsToRoot() {
593
441
  if (platform() !== "linux") return true;
594
442
  if (typeof process.getuid !== "function" || process.getuid() !== 0) return true;
595
443
  for (const filename of [".credentials.json", "credentials.json"]) {
596
- if (existsSync3(join2("/root/.claude", filename))) return true;
444
+ if (existsSync2(join("/root/.claude", filename))) return true;
597
445
  }
598
446
  let sourcePath = null;
599
447
  try {
@@ -601,8 +449,8 @@ function syncClaudeCredsToRoot() {
601
449
  outer: for (const entry of entries) {
602
450
  if (!entry.isDirectory()) continue;
603
451
  for (const filename of [".credentials.json", "credentials.json"]) {
604
- const candidate = join2("/home", entry.name, ".claude", filename);
605
- if (existsSync3(candidate)) {
452
+ const candidate = join("/home", entry.name, ".claude", filename);
453
+ if (existsSync2(candidate)) {
606
454
  sourcePath = candidate;
607
455
  break outer;
608
456
  }
@@ -613,9 +461,9 @@ function syncClaudeCredsToRoot() {
613
461
  if (!sourcePath) return false;
614
462
  const targetDir = "/root/.claude";
615
463
  const sourceFilename = sourcePath.endsWith("credentials.json") && !sourcePath.endsWith(".credentials.json") ? "credentials.json" : ".credentials.json";
616
- const targetPath = join2(targetDir, sourceFilename);
464
+ const targetPath = join(targetDir, sourceFilename);
617
465
  try {
618
- if (!existsSync3(targetDir)) mkdirSync2(targetDir, { recursive: true, mode: 448 });
466
+ if (!existsSync2(targetDir)) mkdirSync(targetDir, { recursive: true, mode: 448 });
619
467
  copyFileSync(sourcePath, targetPath);
620
468
  chmodSync(targetPath, 384);
621
469
  return true;
@@ -627,13 +475,13 @@ var cachedClaudePath = null;
627
475
  function resolveClaudeBinary() {
628
476
  if (cachedClaudePath) return cachedClaudePath;
629
477
  const override = process.env.CLAUDE_PATH;
630
- if (override && existsSync3(override)) {
478
+ if (override && existsSync2(override)) {
631
479
  cachedClaudePath = override;
632
480
  return override;
633
481
  }
634
482
  try {
635
483
  const out = execSync("which claude 2>/dev/null", { encoding: "utf-8" }).trim();
636
- if (out && existsSync3(out)) {
484
+ if (out && existsSync2(out)) {
637
485
  cachedClaudePath = out;
638
486
  return out;
639
487
  }
@@ -645,7 +493,7 @@ function resolveClaudeBinary() {
645
493
  "/usr/local/bin/claude"
646
494
  ];
647
495
  for (const p of candidates) {
648
- if (existsSync3(p)) {
496
+ if (existsSync2(p)) {
649
497
  cachedClaudePath = p;
650
498
  return p;
651
499
  }
@@ -654,8 +502,8 @@ function resolveClaudeBinary() {
654
502
  }
655
503
  function writePersistentClaudeWrapper(args) {
656
504
  const { projectDir, claudeBin, initPrompt, claudeArgsJoined } = args;
657
- const envIntegrationsPath = join2(projectDir, ".env.integrations");
658
- const wrapperPath = join2(projectDir, ".claude", "persistent-claude.sh");
505
+ const envIntegrationsPath = join(projectDir, ".env.integrations");
506
+ const wrapperPath = join(projectDir, ".claude", "persistent-claude.sh");
659
507
  const wrapperLines = [
660
508
  "#!/usr/bin/env bash",
661
509
  "set -e",
@@ -663,7 +511,7 @@ function writePersistentClaudeWrapper(args) {
663
511
  // --dangerously-skip-permissions on dedicated EC2 hosts.
664
512
  "export IS_SANDBOX=1"
665
513
  ];
666
- if (existsSync3(envIntegrationsPath)) {
514
+ if (existsSync2(envIntegrationsPath)) {
667
515
  wrapperLines.push(
668
516
  "set -a",
669
517
  `source ${JSON.stringify(envIntegrationsPath)}`,
@@ -674,15 +522,15 @@ function writePersistentClaudeWrapper(args) {
674
522
  wrapperLines.push(
675
523
  `exec ${JSON.stringify(claudeBin)} ${initPromptArg}${claudeArgsJoined}`
676
524
  );
677
- mkdirSync2(join2(projectDir, ".claude"), { recursive: true });
678
- writeFileSync3(wrapperPath, wrapperLines.join("\n") + "\n", { mode: 448 });
525
+ mkdirSync(join(projectDir, ".claude"), { recursive: true });
526
+ writeFileSync2(wrapperPath, wrapperLines.join("\n") + "\n", { mode: 448 });
679
527
  chmodSync(wrapperPath, 448);
680
528
  return wrapperPath;
681
529
  }
682
530
  function collectMcpServerNames(mcpConfigPath) {
683
- if (!existsSync3(mcpConfigPath)) return [];
531
+ if (!existsSync2(mcpConfigPath)) return [];
684
532
  try {
685
- const data = JSON.parse(readFileSync4(mcpConfigPath, "utf-8"));
533
+ const data = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
686
534
  const servers = data.mcpServers;
687
535
  return servers ? Object.keys(servers) : [];
688
536
  } catch {
@@ -695,8 +543,8 @@ function getAcpxBin() {
695
543
  const moduleDir = dirname(fileURLToPath(import.meta.url));
696
544
  let dir = moduleDir;
697
545
  for (let i = 0; i < 6; i++) {
698
- const candidate = join2(dir, "node_modules", ".bin", "acpx");
699
- if (existsSync3(candidate)) {
546
+ const candidate = join(dir, "node_modules", ".bin", "acpx");
547
+ if (existsSync2(candidate)) {
700
548
  _acpxBin = candidate;
701
549
  return _acpxBin;
702
550
  }
@@ -744,15 +592,15 @@ function hasAcpxSession(acpxBin, projectDir, codeName) {
744
592
  return available;
745
593
  }
746
594
  var sessions = /* @__PURE__ */ new Map();
747
- var PANE_LOG_DIR = join2(homedir2(), ".augmented");
595
+ var PANE_LOG_DIR = join(homedir(), ".augmented");
748
596
  var PANE_TAIL_LINES = 20;
749
597
  function paneLogPath(codeName) {
750
- return join2(PANE_LOG_DIR, codeName, "pane.log");
598
+ return join(PANE_LOG_DIR, codeName, "pane.log");
751
599
  }
752
600
  function setupPaneLog(tmuxSession, codeName, log) {
753
601
  const logPath = paneLogPath(codeName);
754
602
  try {
755
- mkdirSync2(dirname(logPath), { recursive: true });
603
+ mkdirSync(dirname(logPath), { recursive: true });
756
604
  appendFileSync(
757
605
  logPath,
758
606
  `
@@ -770,9 +618,9 @@ function setupPaneLog(tmuxSession, codeName, log) {
770
618
  }
771
619
  function readPaneLogTail(codeName, lines = PANE_TAIL_LINES) {
772
620
  const logPath = paneLogPath(codeName);
773
- if (!existsSync3(logPath)) return null;
621
+ if (!existsSync2(logPath)) return null;
774
622
  try {
775
- const raw = readFileSync4(logPath, "utf-8");
623
+ const raw = readFileSync3(logPath, "utf-8");
776
624
  if (!raw) return null;
777
625
  const stripped = raw.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "");
778
626
  const all = stripped.split("\n").filter((l) => l.length > 0);
@@ -827,7 +675,7 @@ function resolveSessionSpawnDecision(args) {
827
675
  const disableFlag = process.env["AGT_DISABLE_SESSION_RESUME"];
828
676
  const resumeDisabled = disableFlag === "1" || disableFlag?.toLowerCase() === "true";
829
677
  if (resumeDisabled) {
830
- return { flag: "--session-id", sessionId: randomUUID2(), reason: "resume-disabled" };
678
+ return { flag: "--session-id", sessionId: randomUUID(), reason: "resume-disabled" };
831
679
  }
832
680
  const daily = getOrCreateDailySession(codeName, now, agentTimezone);
833
681
  if (!daily.isNew && sessionFileExists(projectDir, daily.sessionId)) {
@@ -887,10 +735,10 @@ function spawnSession(config, session) {
887
735
  log(`[persistent-session] No Claude Code credentials found under /root/.claude or /home/*. Pair via browser from the host page, or run 'claude /login' on the host.`);
888
736
  }
889
737
  } else {
890
- const claudeDir = join2(homedir2(), ".claude");
738
+ const claudeDir = join(homedir(), ".claude");
891
739
  for (const filename of [".credentials.json", "credentials.json"]) {
892
- const p = join2(claudeDir, filename);
893
- if (existsSync3(p)) {
740
+ const p = join(claudeDir, filename);
741
+ if (existsSync2(p)) {
894
742
  try {
895
743
  rmSync(p, { force: true });
896
744
  log(`[persistent-session] Removed ${p} (api_key mode active \u2014 preventing OAuth fallback)`);
@@ -924,7 +772,7 @@ function spawnSession(config, session) {
924
772
  if (channels.length > 0) args.push("--channels", ...channels);
925
773
  if (devChannels.length > 0) args.push("--dangerously-load-development-channels", ...devChannels);
926
774
  args.push("--mcp-config", mcpConfigPath);
927
- if (existsSync3(claudeMdPath)) args.push("--system-prompt-file", claudeMdPath);
775
+ if (existsSync2(claudeMdPath)) args.push("--system-prompt-file", claudeMdPath);
928
776
  const modelAlias = claudeModelAlias(config.primaryModel);
929
777
  if (modelAlias) args.push("--model", modelAlias);
930
778
  args.push("--allow-dangerously-skip-permissions");
@@ -952,7 +800,7 @@ function spawnSession(config, session) {
952
800
  // Treat empty-string as missing too — `HOME=""` makes ~ resolve
953
801
  // to cwd, which is the same broken outcome as no HOME, just
954
802
  // better hidden.
955
- HOME: process.env.HOME?.trim() || homedir2(),
803
+ HOME: process.env.HOME?.trim() || homedir(),
956
804
  USER: process.env.USER?.trim() || userInfo().username
957
805
  };
958
806
  if (config.runId) {
@@ -960,7 +808,7 @@ function spawnSession(config, session) {
960
808
  }
961
809
  for (const f of probeMcpEnvSubstitution({
962
810
  mcpConfigPath,
963
- envIntegrationsPath: join2(projectDir, ".env.integrations"),
811
+ envIntegrationsPath: join(projectDir, ".env.integrations"),
964
812
  baseEnv: {
965
813
  ...tmuxEnv,
966
814
  ...claudeAuthMode === "api_key" && config.anthropicApiKey ? { ANTHROPIC_API_KEY: config.anthropicApiKey } : {}
@@ -1276,10 +1124,10 @@ async function injectMessageWithStatus(codeName, type, content, meta, log) {
1276
1124
  const acpx = getAcpxBin();
1277
1125
  if (acpx && hasAcpxSession(acpx, projectDir, codeName)) {
1278
1126
  try {
1279
- const tmpDir = join2(projectDir, ".claude");
1280
- mkdirSync2(tmpDir, { recursive: true });
1281
- const tmpFile = join2(tmpDir, ".agt-inject-prompt.txt");
1282
- writeFileSync3(tmpFile, text);
1127
+ const tmpDir = join(projectDir, ".claude");
1128
+ mkdirSync(tmpDir, { recursive: true });
1129
+ const tmpFile = join(tmpDir, ".agt-inject-prompt.txt");
1130
+ writeFileSync2(tmpFile, text);
1283
1131
  _log(`[inject] acpx exec (fire-and-forget): cwd=${projectDir}, file=${tmpFile}`);
1284
1132
  const child = spawn(acpx, ["claude", "exec", "-f", tmpFile], {
1285
1133
  cwd: projectDir,
@@ -1529,7 +1377,7 @@ async function stopAllSessionsAndWait(log, opts) {
1529
1377
  await new Promise((resolve) => setTimeout(resolve, Math.min(opts.timeoutMs, 2e3)));
1530
1378
  }
1531
1379
  function getProjectDir(codeName) {
1532
- return join2(homedir2(), ".augmented", codeName, "project");
1380
+ return join(homedir(), ".augmented", codeName, "project");
1533
1381
  }
1534
1382
  function writeAcpxConfig(config) {
1535
1383
  const {
@@ -1545,7 +1393,7 @@ function writeAcpxConfig(config) {
1545
1393
  if (channels.length > 0) claudeArgs.push("--channels", ...channels);
1546
1394
  if (devChannels.length > 0) claudeArgs.push("--dangerously-load-development-channels", ...devChannels);
1547
1395
  claudeArgs.push("--mcp-config", mcpConfigPath);
1548
- if (existsSync3(claudeMdPath)) claudeArgs.push("--system-prompt-file", claudeMdPath);
1396
+ if (existsSync2(claudeMdPath)) claudeArgs.push("--system-prompt-file", claudeMdPath);
1549
1397
  const acpModelAlias = claudeModelAlias(config.primaryModel);
1550
1398
  if (acpModelAlias) claudeArgs.push("--model", acpModelAlias);
1551
1399
  claudeArgs.push("--allow-dangerously-skip-permissions");
@@ -1554,18 +1402,18 @@ function writeAcpxConfig(config) {
1554
1402
  const mcpServerNames2 = collectMcpServerNames(mcpConfigPath);
1555
1403
  claudeArgs.push("--allowedTools", buildAllowedTools(mcpServerNames2));
1556
1404
  const acpCmd = `npx -y @agentclientprotocol/claude-agent-acp ${claudeArgs.map((a) => a.includes(" ") || a.includes("*") ? JSON.stringify(a) : a).join(" ")}`;
1557
- const envIntegrationsPath = join2(projectDir, ".env.integrations");
1558
- const wrapperPath = join2(projectDir, ".claude", "acpx-agent.sh");
1405
+ const envIntegrationsPath = join(projectDir, ".env.integrations");
1406
+ const wrapperPath = join(projectDir, ".claude", "acpx-agent.sh");
1559
1407
  const wrapperLines = ["#!/usr/bin/env bash"];
1560
- if (existsSync3(envIntegrationsPath)) {
1408
+ if (existsSync2(envIntegrationsPath)) {
1561
1409
  wrapperLines.push(`set -a`, `source ${JSON.stringify(envIntegrationsPath)}`, `set +a`);
1562
1410
  }
1563
1411
  if (claudeAuthMode === "api_key" && anthropicApiKey) {
1564
1412
  wrapperLines.push(`export ANTHROPIC_API_KEY=${JSON.stringify(anthropicApiKey)}`);
1565
1413
  }
1566
1414
  wrapperLines.push(`exec ${acpCmd}`);
1567
- mkdirSync2(join2(projectDir, ".claude"), { recursive: true });
1568
- writeFileSync3(wrapperPath, wrapperLines.join("\n") + "\n", { mode: 493 });
1415
+ mkdirSync(join(projectDir, ".claude"), { recursive: true });
1416
+ writeFileSync2(wrapperPath, wrapperLines.join("\n") + "\n", { mode: 493 });
1569
1417
  chmodSync(wrapperPath, 493);
1570
1418
  const acpxConfig = {
1571
1419
  defaultAgent: "claude",
@@ -1576,7 +1424,7 @@ function writeAcpxConfig(config) {
1576
1424
  }
1577
1425
  }
1578
1426
  };
1579
- writeFileSync3(join2(projectDir, ".acpxrc.json"), JSON.stringify(acpxConfig, null, 2));
1427
+ writeFileSync2(join(projectDir, ".acpxrc.json"), JSON.stringify(acpxConfig, null, 2));
1580
1428
  }
1581
1429
 
1582
1430
  export {
@@ -1586,11 +1434,6 @@ export {
1586
1434
  probeMcpEnvSubstitution,
1587
1435
  sanitizeMcpJson,
1588
1436
  buildAllowedTools,
1589
- sessionTranscriptDir,
1590
- transcriptActivityAgeSeconds,
1591
- isAgentIdle,
1592
- isStaleForToday,
1593
- peekCurrentSession,
1594
1437
  checkChannelInputs,
1595
1438
  takeWatchdogGiveUpCount,
1596
1439
  creditWatchdogGiveUpCount,
@@ -1621,4 +1464,4 @@ export {
1621
1464
  stopAllSessionsAndWait,
1622
1465
  getProjectDir
1623
1466
  };
1624
- //# sourceMappingURL=chunk-JLS7NQFE.js.map
1467
+ //# sourceMappingURL=chunk-7GKJZBTB.js.map