@ekkos/cli 1.0.11 → 1.0.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.
@@ -301,7 +301,9 @@ function resolveJsonlPath(sessionName, createdAfterMs) {
301
301
  * This prevents picking up old sessions that are still being modified.
302
302
  */
303
303
  function findLatestJsonl(projectPath, createdAfterMs) {
304
- const encoded = projectPath.replace(/\//g, '-');
304
+ // Claude encodes project paths by replacing ALL separators (/ and \) with -.
305
+ // On Windows projectPath uses backslashes, so we must normalize both.
306
+ const encoded = projectPath.replace(/[\\/]/g, '-');
305
307
  const projectDir = path.join(os.homedir(), '.claude', 'projects', encoded);
306
308
  if (!fs.existsSync(projectDir))
307
309
  return null;
@@ -349,6 +351,28 @@ async function waitForNewSession() {
349
351
  const startWait = Date.now();
350
352
  let candidateName = null;
351
353
  while (Date.now() - startWait < maxWaitMs) {
354
+ // ── Windows hook hint file ──────────────────────────────────────────────
355
+ // On Windows, active-sessions.json is never populated because hook processes
356
+ // are short-lived and their PIDs are dead by the time we poll. Instead, the
357
+ // user-prompt-submit.ps1 hook writes ~/.ekkos/hook-session-hint.json with
358
+ // { sessionName, sessionId, projectPath, ts } on every turn. Read it here.
359
+ const hintPath = path.join(state_js_1.EKKOS_DIR, 'hook-session-hint.json');
360
+ try {
361
+ if (fs.existsSync(hintPath)) {
362
+ const hint = JSON.parse(fs.readFileSync(hintPath, 'utf-8'));
363
+ if (hint.ts >= launchTs - 5000 && hint.sessionName && hint.projectPath) {
364
+ candidateName = hint.sessionName;
365
+ const jsonlPath = findLatestJsonl(hint.projectPath, launchTs)
366
+ || resolveJsonlPath(hint.sessionName, launchTs);
367
+ if (jsonlPath) {
368
+ console.log(chalk_1.default.green(` Found session (hook hint): ${hint.sessionName}`));
369
+ return { sessionName: hint.sessionName, jsonlPath };
370
+ }
371
+ }
372
+ }
373
+ }
374
+ catch { /* ignore */ }
375
+ // ── Standard: active-sessions.json (works on Mac/Linux) ────────────────
352
376
  const sessions = (0, state_js_1.getActiveSessions)();
353
377
  // Find sessions that started after our launch
354
378
  for (const s of sessions) {
@@ -840,15 +840,18 @@ function launchWithDashboardWindows(options) {
840
840
  fs.writeFileSync(markerPath, `${launchTime}\n${cwd}`);
841
841
  }
842
842
  catch { }
843
- const runCommand = `node "${ekkosCmd}" ${runArgs.join(' ')}`;
844
- const dashCommand = `node "${ekkosCmd}" dashboard --wait-for-new --refresh 2000`;
843
+ // Use single-quoted inner args so backslashes in Windows paths survive PowerShell expansion.
844
+ // The wt command runs each pane as: powershell -NoExit -Command "& 'node' 'C:\path\ekkos' ..."
845
+ const ekkosCmdEscaped = ekkosCmd.replace(/'/g, "''"); // escape single quotes in path
846
+ const runPsCmd = `& node '${ekkosCmdEscaped}' ${runArgs.join(' ')}`;
847
+ const dashPsCmd = `& node '${ekkosCmdEscaped}' dashboard --wait-for-new --refresh 2000`;
845
848
  // Windows Terminal split pane command:
846
849
  // wt --window 0 split-pane -V --size 0.4 --title "ekkOS Dashboard" powershell -NoExit -Command "..."
847
850
  // If no WT window exists yet, open a new one with two panes
848
851
  const wtCmd = [
849
852
  'wt',
850
- `new-tab --title "ekkOS" powershell -NoExit -Command "${runCommand}"`,
851
- `; split-pane -V --size 0.4 --title "ekkOS Dashboard" powershell -NoExit -Command "${dashCommand}"`
853
+ `new-tab --title "ekkOS" powershell -NoExit -Command "${runPsCmd}"`,
854
+ `; split-pane -V --size 0.4 --title "ekkOS Dashboard" powershell -NoExit -Command "${dashPsCmd}"`
852
855
  ].join(' ');
853
856
  try {
854
857
  (0, child_process_1.execSync)(wtCmd, { stdio: 'inherit', shell: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekkos/cli",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Setup ekkOS memory for AI coding assistants (Claude Code, Cursor, Windsurf)",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -260,6 +260,25 @@ if (Test-Path $configFile) {
260
260
 
261
261
  $timestamp = (Get-Date).ToString("yyyy-MM-dd hh:mm:ss tt") + " EST"
262
262
 
263
+ # ═══════════════════════════════════════════════════════════════════════════
264
+ # DASHBOARD HINT FILE: write session info for ekkos dashboard --wait-for-new
265
+ # On Windows, active-sessions.json is never populated (hook PIDs are dead).
266
+ # The dashboard reads this file instead to locate the JSONL path.
267
+ # ═══════════════════════════════════════════════════════════════════════════
268
+ if ($sessionName -ne "unknown-session") {
269
+ try {
270
+ $projectPath = if ($env:PWD) { $env:PWD } else { (Get-Location).Path }
271
+ $hintFile = Join-Path $EkkosConfigDir "hook-session-hint.json"
272
+ $hint = @{
273
+ sessionName = $sessionName
274
+ sessionId = $rawSessionId
275
+ projectPath = $projectPath
276
+ ts = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
277
+ } | ConvertTo-Json -Compress
278
+ Set-Content -Path $hintFile -Value $hint -Force
279
+ } catch {}
280
+ }
281
+
263
282
  # ═══════════════════════════════════════════════════════════════════════════
264
283
  # OUTPUT SYSTEM REMINDER
265
284
  # ═══════════════════════════════════════════════════════════════════════════