@songsid/agend 2.1.6-beta.12 → 2.1.6-beta.13

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/README.md CHANGED
@@ -123,6 +123,28 @@ graph LR
123
123
  | Antigravity CLI | `curl -fsSL https://antigravity.google/cli/install.sh \| bash` | `agy` (Google Sign-In) |
124
124
  | Grok Build | `curl -fsSL https://x.ai/cli/install.sh \| bash` | `grok` (x.ai OAuth device flow) |
125
125
 
126
+ ### Codex session upgrade note
127
+
128
+ AgEnD now resumes Codex by an explicit, per-instance session ID. It never uses
129
+ `codex resume --last`: that option can select another instance's conversation
130
+ when worktrees or credential homes overlap. On the first restart after upgrading,
131
+ an existing **live** Codex pane is linked to its exact open session when its
132
+ rollout and writer lock can be verified. If a legacy pane was already stopped
133
+ and has no instance-owned ID, the instance starts a new session and posts a
134
+ one-time notice to its topic. Older rollout files remain on disk. A stored ID
135
+ whose rollout cannot be verified is different: startup holds instead of
136
+ silently opening a new conversation.
137
+
138
+ To recover an older conversation, stop the instance, identify and verify its
139
+ session UUID in your Codex session history, then run
140
+ `agend fleet codex-resume <instance> <session-id>` and start the instance.
141
+ The command refuses a different repository or a session with a live owner;
142
+ it does not infer ownership from the newest session in a directory.
143
+ If Codex keeps multiple rollout locks open after `/new`, AgEnD uses Codex's
144
+ current-session footer to identify the new chat. Without that positive proof,
145
+ automatic resume is held and the instance topic is notified; the existing
146
+ conversation files remain available for an explicit manual attach.
147
+
126
148
  ## Requirements
127
149
 
128
150
  - Node.js >= 20
@@ -0,0 +1,45 @@
1
+ export declare const CODEX_SESSION_ID: RegExp;
2
+ export declare class CodexResumeConflictError extends Error {
3
+ readonly ownerPid: number | null;
4
+ constructor(ownerPid: number | null);
5
+ }
6
+ export declare class CodexResumeUnavailableError extends Error {
7
+ constructor(message?: string);
8
+ }
9
+ export declare class CodexResumeIdentityError extends CodexResumeUnavailableError {
10
+ constructor();
11
+ }
12
+ export interface CodexSessionRecord {
13
+ id: string;
14
+ /** Instance directory basename, never a credential/profile identifier. */
15
+ owner: string;
16
+ cwd: string;
17
+ rolloutPath: string;
18
+ }
19
+ /** Read only the first JSONL line. A rollout can contain private conversation text. */
20
+ export declare function readCodexRolloutMeta(path: string): {
21
+ id: string;
22
+ cwd: string;
23
+ } | null;
24
+ /** Explicit/manual lookup; never infer ownership from the newest CWD row. */
25
+ export declare function codexRolloutForId(home: string, id: string): {
26
+ id: string;
27
+ cwd: string;
28
+ rolloutPath: string;
29
+ } | null;
30
+ /** The first footer item is Codex's own `session-id`, not a guessed rollout order. */
31
+ export declare function codexCurrentSessionFromPane(pane: string): string | null;
32
+ /** A pane process group identifies candidates; `/new` can retain both locks. */
33
+ export declare function codexSessionsForPane(panePid: number, sharedHome: string, procRoot?: string): Array<{
34
+ id: string;
35
+ cwd: string;
36
+ rolloutPath: string;
37
+ }>;
38
+ /** Compatibility helper: never choose among multiple open writer-lock pairs. */
39
+ export declare function codexSessionForPane(panePid: number, sharedHome: string, procRoot?: string): {
40
+ id: string;
41
+ cwd: string;
42
+ rolloutPath: string;
43
+ } | null;
44
+ /** Any process holding this session's writer lock is a live competing owner. */
45
+ export declare function codexSessionOwners(id: string, procRoot?: string): number[];
@@ -0,0 +1,202 @@
1
+ import { closeSync, openSync, readFileSync, readlinkSync, readdirSync, readSync, realpathSync } from "node:fs";
2
+ import { execFileSync } from "node:child_process";
3
+ import { basename, isAbsolute, join, sep } from "node:path";
4
+ export const CODEX_SESSION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5
+ export class CodexResumeConflictError extends Error {
6
+ ownerPid;
7
+ constructor(ownerPid) {
8
+ super(ownerPid
9
+ ? `Codex conversation is still open in process ${ownerPid}; no second resumer was started. Close that owner, then restart this instance.`
10
+ : "Codex conversation is locked by another owner; no second resumer was started. Close that owner, then restart this instance.");
11
+ this.ownerPid = ownerPid;
12
+ this.name = "CodexResumeConflictError";
13
+ }
14
+ }
15
+ export class CodexResumeUnavailableError extends Error {
16
+ constructor(message = "Codex could not resume the verified session. It was preserved; automatic restart is paused. Check the pane and restart this instance after resolving the cause.") {
17
+ super(message);
18
+ this.name = "CodexResumeUnavailableError";
19
+ }
20
+ }
21
+ export class CodexResumeIdentityError extends CodexResumeUnavailableError {
22
+ constructor() {
23
+ super("Stored Codex session identity could not be verified. Its record and rollout were preserved; no new session was started. Inspect the session ID and rollout before a manual restart.");
24
+ this.name = "CodexResumeIdentityError";
25
+ }
26
+ }
27
+ /** Read only the first JSONL line. A rollout can contain private conversation text. */
28
+ export function readCodexRolloutMeta(path) {
29
+ let fd;
30
+ try {
31
+ fd = openSync(path, "r");
32
+ const buf = Buffer.alloc(65_536);
33
+ const bytes = readSync(fd, buf, 0, buf.length, 0);
34
+ const end = buf.subarray(0, bytes).indexOf(10);
35
+ if (end < 0)
36
+ return null;
37
+ const row = JSON.parse(buf.toString("utf8", 0, end));
38
+ const id = row?.payload?.id;
39
+ const cwd = row?.payload?.cwd;
40
+ return row?.type === "session_meta" && typeof id === "string" && CODEX_SESSION_ID.test(id)
41
+ && typeof cwd === "string" && isAbsolute(cwd) ? { id, cwd } : null;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ finally {
47
+ if (fd !== undefined)
48
+ closeSync(fd);
49
+ }
50
+ }
51
+ function procGroup(pid, procRoot) {
52
+ try {
53
+ const stat = readFileSync(join(procRoot, String(pid), "stat"), "utf8");
54
+ const afterName = stat.slice(stat.lastIndexOf(")") + 2).trim().split(/\s+/);
55
+ const group = Number(afterName[2]); // field 5 (pgrp); afterName[0] is field 3
56
+ return Number.isSafeInteger(group) ? group : null;
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ function processIds(procRoot) {
63
+ try {
64
+ return readdirSync(procRoot).filter(name => /^\d+$/.test(name)).map(Number);
65
+ }
66
+ catch {
67
+ return [];
68
+ }
69
+ }
70
+ function macOutput(command, args) {
71
+ try {
72
+ return execFileSync(command, args, { encoding: "utf8", timeout: 2_000, maxBuffer: 2_000_000 });
73
+ }
74
+ catch {
75
+ return "";
76
+ }
77
+ }
78
+ function paneProcessIds(panePid, procRoot) {
79
+ if (process.platform !== "darwin" || procRoot !== "/proc") {
80
+ return processIds(procRoot).filter(pid => procGroup(pid, procRoot) === panePid);
81
+ }
82
+ return macOutput("ps", ["-axo", "pid=,pgid="]).split("\n").flatMap(row => {
83
+ const [pid, group] = row.trim().split(/\s+/).map(Number);
84
+ return group === panePid && Number.isSafeInteger(pid) ? [pid] : [];
85
+ });
86
+ }
87
+ function openPaths(pid, procRoot) {
88
+ if (process.platform === "darwin" && procRoot === "/proc") {
89
+ return macOutput("lsof", ["-Fn", "-p", String(pid)]).split("\n")
90
+ .filter(row => row.startsWith("n/")).map(row => row.slice(1));
91
+ }
92
+ const dir = join(procRoot, String(pid), "fd");
93
+ try {
94
+ return readdirSync(dir).flatMap(fd => {
95
+ try {
96
+ return [readlinkSync(join(dir, fd))];
97
+ }
98
+ catch {
99
+ return [];
100
+ }
101
+ });
102
+ }
103
+ catch {
104
+ return [];
105
+ }
106
+ }
107
+ function* rolloutFiles(dir, depth = 0) {
108
+ if (depth > 4)
109
+ return;
110
+ try {
111
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
112
+ const path = join(dir, entry.name);
113
+ if (entry.isDirectory())
114
+ yield* rolloutFiles(path, depth + 1);
115
+ else if (entry.isFile() && entry.name.endsWith(".jsonl"))
116
+ yield path;
117
+ }
118
+ }
119
+ catch { /* missing sessions dir is ordinary on first install */ }
120
+ }
121
+ /** Explicit/manual lookup; never infer ownership from the newest CWD row. */
122
+ export function codexRolloutForId(home, id) {
123
+ if (!CODEX_SESSION_ID.test(id))
124
+ return null;
125
+ for (const path of rolloutFiles(join(home, "sessions"))) {
126
+ if (!basename(path).endsWith(`${id}.jsonl`))
127
+ continue;
128
+ const meta = readCodexRolloutMeta(path);
129
+ if (meta?.id === id)
130
+ return { ...meta, rolloutPath: realpathSync(path) };
131
+ }
132
+ return null;
133
+ }
134
+ /** The first footer item is Codex's own `session-id`, not a guessed rollout order. */
135
+ export function codexCurrentSessionFromPane(pane) {
136
+ const rows = pane.replace(/\r/g, "").split("\n");
137
+ while (rows.length && !rows[rows.length - 1].trim())
138
+ rows.pop();
139
+ const footer = rows.at(-1)?.trim() ?? "";
140
+ const match = footer.match(/^([0-9a-f-]{36})\s+·\s+Context\b/i);
141
+ if (!match || !CODEX_SESSION_ID.test(match[1]))
142
+ return null;
143
+ rows.pop();
144
+ while (rows.length && !rows[rows.length - 1].trim())
145
+ rows.pop();
146
+ // A quoted UUID-shaped transcript line is not current-session evidence.
147
+ // Only Codex's live empty input followed by its status footer counts.
148
+ return /^[>›]\s+Ask Codex to do anything\s*$/.test(rows.at(-1) ?? "") ? match[1] : null;
149
+ }
150
+ /** A pane process group identifies candidates; `/new` can retain both locks. */
151
+ export function codexSessionsForPane(panePid, sharedHome, procRoot = "/proc") {
152
+ if (!Number.isSafeInteger(panePid) || panePid <= 0)
153
+ return [];
154
+ let sessionsRoot;
155
+ try {
156
+ sessionsRoot = realpathSync(join(sharedHome, "sessions")) + sep;
157
+ }
158
+ catch {
159
+ return [];
160
+ }
161
+ const candidates = new Map();
162
+ for (const pid of paneProcessIds(panePid, procRoot)) {
163
+ const paths = openPaths(pid, procRoot);
164
+ const lockIds = new Set(paths.map(path => basename(path).match(/^([0-9a-f-]{36})\.lock$/i)?.[1]).filter((id) => !!id && CODEX_SESSION_ID.test(id)));
165
+ for (const path of paths) {
166
+ if (!path.endsWith(".jsonl") || !path.includes(`${sep}sessions${sep}`))
167
+ continue;
168
+ let actual;
169
+ try {
170
+ actual = realpathSync(path);
171
+ }
172
+ catch {
173
+ continue;
174
+ }
175
+ if (!actual.startsWith(sessionsRoot))
176
+ continue;
177
+ const meta = readCodexRolloutMeta(actual);
178
+ if (meta && lockIds.has(meta.id))
179
+ candidates.set(meta.id, { ...meta, rolloutPath: actual });
180
+ }
181
+ }
182
+ return [...candidates.values()];
183
+ }
184
+ /** Compatibility helper: never choose among multiple open writer-lock pairs. */
185
+ export function codexSessionForPane(panePid, sharedHome, procRoot = "/proc") {
186
+ const candidates = codexSessionsForPane(panePid, sharedHome, procRoot);
187
+ return candidates.length === 1 ? candidates[0] : null;
188
+ }
189
+ /** Any process holding this session's writer lock is a live competing owner. */
190
+ export function codexSessionOwners(id, procRoot = "/proc") {
191
+ if (!CODEX_SESSION_ID.test(id))
192
+ return [];
193
+ const name = `${id}.lock`;
194
+ const pids = process.platform === "darwin" && procRoot === "/proc"
195
+ ? macOutput("ps", ["-axo", "pid=,comm="]).split("\n").flatMap(row => {
196
+ const match = row.trim().match(/^(\d+)\s+(.+)$/);
197
+ return match && basename(match[2]) === "codex" ? [Number(match[1])] : [];
198
+ })
199
+ : processIds(procRoot);
200
+ return pids.filter(pid => openPaths(pid, procRoot).some(path => basename(path) === name));
201
+ }
202
+ //# sourceMappingURL=codex-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-session.js","sourceRoot":"","sources":["../../src/backend/codex-session.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,37 @@
1
1
  import { type CliBackend, type CliBackendConfig, type ErrorPattern, type InputUnavailableTransient, type ModelOption, type RuntimeDialog, type StartupDialog } from "./types.js";
2
+ type CodexResumeDirectoryPrompt = {
3
+ active: boolean;
4
+ sessionCwd: string | null;
5
+ currentCwd: string | null;
6
+ safeChoice: boolean;
7
+ };
8
+ /** Captured from Codex 0.156; only the live, bottom-of-pane four-choice menu. */
9
+ export declare function codexResumeDirectoryPromptState(pane: string): CodexResumeDirectoryPrompt;
10
+ /** Unknown variants still own stdin; only the exact canonical menu may be answered. */
11
+ export declare function codexResumeDirectoryVisible(pane: string): boolean;
12
+ /** Codex's concurrent-owner screen is a hold, never an invitation to press R. */
13
+ export declare function codexResumeLockActive(pane: string): boolean;
14
+ /** A changed lock-screen footer is still a hold, never a ready prompt. */
15
+ export declare function codexResumeLockVisible(pane: string): boolean;
16
+ /** macOS lockf and Linux flock both fail immediately with status 75 on contention. */
17
+ export declare function codexResumeClaimCommand(platform: NodeJS.Platform, lockPath: string, launch: string): string;
18
+ /** Explicit, stopped-instance recovery for an old conversation without an AgEnD owner record. */
19
+ export declare function attachCodexSession(instanceDir: string, sharedHome: string, currentCwd: string, id: string): void;
2
20
  export declare class CodexBackend implements CliBackend {
3
21
  private instanceDir;
22
+ private readonly procRoot;
4
23
  readonly binaryName = "codex";
5
24
  private binaryPath;
6
25
  private readonly sharedCodexHome;
7
26
  private readonly isolatedCodexHome;
8
27
  /** Which subscription this instance runs on, or null for the shared login. */
9
28
  private credentialProfile;
10
- constructor(instanceDir: string);
29
+ /** Set only after preTrust wrote and read back this instance's private config. */
30
+ private authorizedTrust;
31
+ private activePanePid;
32
+ private resumeRecord;
33
+ private get unconfirmedSessionPath();
34
+ constructor(instanceDir: string, procRoot?: string);
11
35
  supportsQueuedInput(): boolean;
12
36
  /**
13
37
  * Codex's input row, from live captures on codex-cli 0.153.4: `› Ask Codex to
@@ -26,6 +50,8 @@ export declare class CodexBackend implements CliBackend {
26
50
  * (updatePickerDialog) before any delivery path reads this pattern.
27
51
  */
28
52
  getBottomReadyPattern(): RegExp | null;
53
+ /** Observed on real Codex 0.156.0: the live input row precedes its footer. */
54
+ isDeliveryInputReadyPane(pane: string): boolean;
29
55
  /** Live status chrome that must veto the broad prompt/context ready match. */
30
56
  getBusyPattern(): RegExp;
31
57
  /**
@@ -49,6 +75,15 @@ export declare class CodexBackend implements CliBackend {
49
75
  */
50
76
  getQueuedInputMarker(): RegExp | null;
51
77
  buildCommand(config: CliBackendConfig): string;
78
+ setActivePanePid(pid: number | null): void;
79
+ /** A fresh launch has no resume identity; it must not be counted as --resume. */
80
+ canResume(workingDirectory: string): boolean;
81
+ hasSessionIdentity(): boolean;
82
+ hasInvalidSessionIdentity(workingDirectory: string): boolean;
83
+ hasUnconfirmedSessionIdentity(): boolean;
84
+ /** Positive owner evidence, not merely a stale lock-file name on disk. */
85
+ resumeOwner(workingDirectory: string): number | null;
86
+ private validResumeRecord;
52
87
  writeConfig(config: CliBackendConfig): void;
53
88
  /**
54
89
  * Stop Codex opening its "Update available!" picker when an instance starts.
@@ -68,16 +103,10 @@ export declare class CodexBackend implements CliBackend {
68
103
  */
69
104
  private disableStartupUpdateCheck;
70
105
  /**
71
- * Ensure Codex's TUI status line shows context usage so /ctx can scrape it.
72
- * Rules (never overwrites the user's status_line):
73
- * 1. status_line already has a context item (context-remaining / -usage /
74
- * -used) → leave the whole config untouched (they already show context).
75
- * 2. no context item:
76
- * - no status_line at all → write status_line = ["context-remaining"]
77
- * - status_line exists → append "context-remaining" to it
78
- * If a user's own status_line is long and truncates at 80 cols, that's their
79
- * config — /ctx just reports context unavailable. Best-effort string edit of
80
- * ~/.codex/config.toml (no toml dependency); other settings untouched.
106
+ * The first status-line item is Codex's own current session ID. Unlike fd
107
+ * order, this changes when /new switches chats while old writer locks stay
108
+ * open. Keep context too, then preserve all user-selected remaining items.
109
+ * If the footer is hidden/truncated, checkpointing fails closed instead.
81
110
  */
82
111
  private enableContextStatusLine;
83
112
  /** Null when the instance did not ask for a profile — today's behaviour. */
@@ -127,13 +156,19 @@ export declare class CodexBackend implements CliBackend {
127
156
  */
128
157
  private cleanSharedConfig;
129
158
  getReadyPattern(): RegExp;
159
+ /** A proxy reply filters chrome per line; whole-pane readiness is separate. */
160
+ isProxyReplyChromeLine(line: string): boolean;
130
161
  getErrorPatterns(): ErrorPattern[];
131
162
  getStartupDialogs(): StartupDialog[];
163
+ private trustHoldDialog;
164
+ private resumeDirectoryHoldDialog;
165
+ private resumeLockHoldDialog;
132
166
  private updatePickerDialog;
167
+ private unknownSelectionHoldDialog;
133
168
  getRuntimeDialogs(): RuntimeDialog[];
134
169
  getInputUnavailableTransients(): InputUnavailableTransient[];
135
170
  getContextUsage(): number | null;
136
- getSessionId(): string | null;
171
+ getSessionId(pane?: string): string | null;
137
172
  getQuitCommand(): string;
138
173
  getCompactCommand(): string;
139
174
  getClearCommand(): string;
@@ -195,3 +230,4 @@ export declare class CodexBackend implements CliBackend {
195
230
  }>;
196
231
  cleanup(config: CliBackendConfig): void;
197
232
  }
233
+ export {};