@integrity-labs/agt-cli 0.27.138 → 0.27.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/agt.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  success,
29
29
  table,
30
30
  warn
31
- } from "../chunk-SCZVYC5P.js";
31
+ } from "../chunk-5UTHUT4E.js";
32
32
  import {
33
33
  CHANNEL_REGISTRY,
34
34
  DEPLOYMENT_TEMPLATES,
@@ -54,7 +54,7 @@ import {
54
54
  renderTemplate,
55
55
  resolveChannels,
56
56
  serializeManifestForSlackCli
57
- } from "../chunk-PDDU4Z5V.js";
57
+ } from "../chunk-WCXA7EEP.js";
58
58
 
59
59
  // src/bin/agt.ts
60
60
  import { join as join20 } from "path";
@@ -4934,7 +4934,7 @@ import { execFileSync, execSync } from "child_process";
4934
4934
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4935
4935
  import chalk18 from "chalk";
4936
4936
  import ora16 from "ora";
4937
- var cliVersion = true ? "0.27.138" : "dev";
4937
+ var cliVersion = true ? "0.27.140" : "dev";
4938
4938
  async function fetchLatestVersion() {
4939
4939
  const host2 = getHost();
4940
4940
  if (!host2) return null;
@@ -5857,7 +5857,7 @@ function handleError(err) {
5857
5857
  }
5858
5858
 
5859
5859
  // src/bin/agt.ts
5860
- var cliVersion2 = true ? "0.27.138" : "dev";
5860
+ var cliVersion2 = true ? "0.27.140" : "dev";
5861
5861
  var program = new Command();
5862
5862
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
5863
5863
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -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":[]}
@@ -9,7 +9,7 @@ import {
9
9
  parseDeliveryTarget,
10
10
  registerFramework,
11
11
  wrapScheduledTaskPrompt
12
- } from "./chunk-PDDU4Z5V.js";
12
+ } from "./chunk-WCXA7EEP.js";
13
13
 
14
14
  // ../../packages/core/dist/integrations/registry.js
15
15
  var INTEGRATION_REGISTRY = [
@@ -7731,4 +7731,4 @@ export {
7731
7731
  managerInstallSystemUnitCommand,
7732
7732
  managerUninstallSystemUnitCommand
7733
7733
  };
7734
- //# sourceMappingURL=chunk-SCZVYC5P.js.map
7734
+ //# sourceMappingURL=chunk-5UTHUT4E.js.map