@fclef819/cdx 0.1.6 → 0.1.8

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 (2) hide show
  1. package/bin/cdx.js +60 -41
  2. package/package.json +3 -2
package/bin/cdx.js CHANGED
@@ -126,28 +126,57 @@ function getLatestSessionSnapshot(verbose) {
126
126
  return { id, mtimeMs: latest.mtimeMs, path: latest.path };
127
127
  }
128
128
 
129
- function getLastHistorySessionId(verbose) {
130
- if (!fs.existsSync(HISTORY_PATH)) return null;
131
- const lines = fs.readFileSync(HISTORY_PATH, "utf8").trim().split("\n");
132
- for (let i = lines.length - 1; i >= 0; i -= 1) {
133
- try {
134
- const record = JSON.parse(lines[i]);
135
- if (record && record.session_id) return record.session_id;
136
- } catch {
137
- // ignore malformed lines
129
+ function sessionHasUserMessage(filePath) {
130
+ try {
131
+ const lines = fs.readFileSync(filePath, "utf8").split("\n");
132
+ for (const line of lines) {
133
+ if (!line.trim()) continue;
134
+ const record = JSON.parse(line);
135
+ if (
136
+ record?.type === "event_msg" &&
137
+ record.payload?.type === "user_message"
138
+ ) {
139
+ return true;
140
+ }
138
141
  }
142
+ } catch {
143
+ // ignore malformed or missing files
139
144
  }
140
- logVerbose("No session_id found in history.jsonl", verbose);
141
- return null;
145
+ return false;
146
+ }
147
+
148
+ function getHistorySnapshot(verbose) {
149
+ if (!fs.existsSync(HISTORY_PATH)) return { size: 0 };
150
+ const stat = fs.statSync(HISTORY_PATH);
151
+ logVerbose(`History file size: ${stat.size}`, verbose);
152
+ return { size: stat.size };
142
153
  }
143
154
 
144
- function getNewestHistorySessionIdSince(previousId, verbose) {
155
+ function getNewestHistorySessionIdSince(snapshot, verbose) {
145
156
  if (!fs.existsSync(HISTORY_PATH)) return null;
146
- const lines = fs.readFileSync(HISTORY_PATH, "utf8").trim().split("\n");
157
+ const stat = fs.statSync(HISTORY_PATH);
158
+ const previousSize = snapshot?.size ?? 0;
159
+ const start = stat.size < previousSize ? 0 : previousSize;
160
+ if (stat.size <= start) {
161
+ logVerbose("No new history lines found in history.jsonl", verbose);
162
+ return null;
163
+ }
164
+
165
+ const fd = fs.openSync(HISTORY_PATH, "r");
166
+ let content = "";
167
+ try {
168
+ const buffer = Buffer.alloc(stat.size - start);
169
+ fs.readSync(fd, buffer, 0, buffer.length, start);
170
+ content = buffer.toString("utf8");
171
+ } finally {
172
+ fs.closeSync(fd);
173
+ }
174
+
175
+ const lines = content.trim().split("\n");
147
176
  for (let i = lines.length - 1; i >= 0; i -= 1) {
148
177
  try {
149
178
  const record = JSON.parse(lines[i]);
150
- if (record && record.session_id && record.session_id !== previousId) {
179
+ if (record && record.session_id) {
151
180
  return record.session_id;
152
181
  }
153
182
  } catch {
@@ -166,33 +195,21 @@ function runCodex(args, cwd, verbose) {
166
195
  } catch {
167
196
  // ignore if not supported
168
197
  }
169
- process.stdin.resume();
170
198
  }
171
199
  const result = spawnSync("codex", args, { stdio: "inherit", cwd });
172
200
  if (result.error) {
173
201
  if (result.error.code === "ENOENT" && process.platform === "win32") {
174
- logVerbose("codex not found directly; trying where.exe lookup", verbose);
175
- const whereResult = spawnSync("where.exe", ["codex"], { encoding: "utf8" });
176
- const resolved = whereResult.stdout
177
- ? whereResult.stdout.split(/\r?\n/).find(Boolean)
178
- : null;
179
- if (resolved) {
180
- logVerbose(`Resolved codex path: ${resolved}`, verbose);
181
- let resolvedResult;
182
- if (resolved.toLowerCase().endsWith(".cmd") || resolved.toLowerCase().endsWith(".bat")) {
183
- resolvedResult = spawnSync(
184
- "cmd.exe",
185
- ["/d", "/s", "/c", resolved, ...args],
186
- { stdio: "inherit", cwd }
187
- );
188
- } else {
189
- resolvedResult = spawnSync(resolved, args, { stdio: "inherit", cwd });
190
- }
191
- if (!resolvedResult.error) {
192
- return { status: resolvedResult.status ?? 0 };
193
- }
202
+ logVerbose("codex not found directly; trying cmd.exe /c", verbose);
203
+ const cmdResult = spawnSync(
204
+ "cmd.exe",
205
+ ["/d", "/s", "/c", "codex", ...args],
206
+ { stdio: "inherit", cwd }
207
+ );
208
+ if (!cmdResult.error) {
209
+ if (process.stdin.isTTY) process.stdin.pause();
210
+ return { status: cmdResult.status ?? 0 };
194
211
  }
195
- logVerbose("codex not found via where.exe; trying PowerShell fallback", verbose);
212
+ logVerbose("codex not found via cmd.exe; trying PowerShell fallback", verbose);
196
213
  const psArgs = [
197
214
  "-NoProfile",
198
215
  "-Command",
@@ -203,6 +220,7 @@ function runCodex(args, cwd, verbose) {
203
220
  cwd
204
221
  });
205
222
  if (!psResult.error) {
223
+ if (process.stdin.isTTY) process.stdin.pause();
206
224
  return { status: psResult.status ?? 0 };
207
225
  }
208
226
  }
@@ -211,6 +229,7 @@ function runCodex(args, cwd, verbose) {
211
229
  );
212
230
  process.exit(1);
213
231
  }
232
+ if (process.stdin.isTTY) process.stdin.pause();
214
233
  return { status: result.status ?? 0 };
215
234
  }
216
235
 
@@ -289,21 +308,21 @@ async function runDefault(startDir, options) {
289
308
  const labelInput = await promptLabel();
290
309
  if (!labelInput) return;
291
310
  const label = sanitizeLabel(labelInput);
292
- const previousHistoryId = getLastHistorySessionId(options.verbose);
311
+ const previousHistory = getHistorySnapshot(options.verbose);
293
312
  const previousSession = getLatestSessionSnapshot(options.verbose);
294
313
  const codexResult = runCodex([], workDir, options.verbose);
295
314
  const latestSession = getLatestSessionSnapshot(options.verbose);
296
- let newId = null;
315
+ let newId = getNewestHistorySessionIdSince(previousHistory, options.verbose);
297
316
  if (
317
+ !newId &&
298
318
  latestSession &&
299
319
  latestSession.id &&
300
320
  (!previousSession ||
301
321
  latestSession.path !== previousSession.path ||
302
- latestSession.mtimeMs > previousSession.mtimeMs)
322
+ latestSession.mtimeMs > previousSession.mtimeMs) &&
323
+ sessionHasUserMessage(latestSession.path)
303
324
  ) {
304
325
  newId = latestSession.id;
305
- } else if (previousHistoryId) {
306
- newId = getNewestHistorySessionIdSince(previousHistoryId, options.verbose);
307
326
  }
308
327
  if (!newId) {
309
328
  console.error("Could not determine new session UUID; not updating .cdx.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fclef819/cdx",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Codex session wrapper",
5
5
  "keywords": [
6
6
  "codex",
@@ -17,7 +17,8 @@
17
17
  "README.md"
18
18
  ],
19
19
  "scripts": {
20
- "release": "npm login && npm pack && npm publish --access public"
20
+ "release": "npm pack && npm publish --access public",
21
+ "gh-release": "gh release create v$npm_package_version --generate-notes"
21
22
  },
22
23
  "engines": {
23
24
  "node": ">=18"