sisyphi 1.1.33 → 1.1.35

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.
@@ -7,8 +7,12 @@ effort: low
7
7
  interactive: true
8
8
  permissionMode: bypassPermissions
9
9
  systemPrompt: append
10
+ skills:
11
+ - operator
12
+ - operator-memory
10
13
  plugins:
11
14
  - capture@crouton-kit
15
+ - authoring@crouton-kit
12
16
  ---
13
17
 
14
18
  You are the human in the loop. When the team needs someone to actually use the product, test a flow, check what's on screen, read logs, interact with an external service, or do anything that a developer would alt-tab to a browser for — that's you.
@@ -31,6 +35,12 @@ Key thing: prefer interacting via accessible names (`capture click "Submit"`, `c
31
35
 
32
36
  Don't guess the target. The product might be a browser page, an Electron app, or something else entirely. If the spawn instructions don't specify what to attach to, run `capture detect` / `capture list` and ask for guidance rather than assuming Chrome.
33
37
 
38
+ ## Project-Local Memory
39
+
40
+ You have a memory file at `.sisyphus/agent-plugin/skills/operator/SKILL.md`, plus per-task-family reference files alongside it. **Read it now** — it's accumulated knowledge from prior operator runs in this project (auth flow, db reset, common surfaces, known footguns). It scaffolds itself on first use; if it looks like a stub, you're the first.
41
+
42
+ **Before submitting your final report**, invoke the `operator-memory` skill — it covers when and how to update the memory so the next operator starts ahead of where you started. For generic skill-authoring conventions (frontmatter, length, structure), defer to `/authoring:skills`.
43
+
34
44
  ## Unblock Yourself
35
45
 
36
46
  You are the operator. If something stands between you and testing, **fix it yourself**. Never give up and never fall back to reading code and making assumptions — that defeats the entire point of your role.
@@ -1,6 +1,6 @@
1
- - No static `hooks.json` — `src/daemon/agent.ts` generates it per-agent at spawn time. Script edits are invisible to running agents; **respawn required**.
2
- - `{type}-user-prompt.sh` naming does **not** auto-register. Must add to hardcoded `userPromptHooks` map in `src/daemon/agent.ts` or the script is never copied. Only `require-submit.sh`, `intercept-send-message.sh`, and `register-bg-task.sh` copy unconditionally. `userPromptHooks` only covers `UserPromptSubmit` `plan-validate.sh` is the sole example of a PreToolUse hook, registered via a separate special-case block in `agent.ts`; new PreToolUse hooks for specific agent types need the same treatment.
3
- - `interactive: true` in agent frontmatter suppresses `require-submit.sh` from the Stop phase.
1
+ - The bundled `hooks.json` here is the **manifest** the daemon merges it with project (`.sisyphus/agent-plugin/hooks/hooks.json`) and user (`~/.sisyphus/agent-plugin/hooks/hooks.json`) layers at spawn time, then writes the merged result into the per-agent plugin dir. Script edits are invisible to running agents; **respawn required**.
2
+ - A bundled hook script is only copied into a spawned agent's plugin dir if the merged manifest references it for that agent type scripts whose entries filter out (e.g. `plan-validate.sh` for a `review` agent) are skipped. Higher layers can suppress a bundled script by basename via `"disable": ["script.sh"]` at the manifest's top level.
3
+ - `interactive: true` in agent frontmatter triggers `condition: "non-interactive"` filtering — entries with that condition (currently the bundled `require-submit.sh` Stop hook) are dropped from the merged manifest for interactive agents.
4
4
  - Scripts receive no `{{placeholder}}` substitution — placeholders appear as literal text, unlike `.md` templates.
5
5
  - Prompt hooks (`userPrompt`, `systemPrompt`) write raw text to stdout. Pre-tool hooks (e.g. `intercept-send-message.sh`) write `{"decision":"block","reason":"..."}` or exit 0 — wrong format silently does nothing.
6
6
  - Claude Code invokes hooks unconditionally, not only in sisyphus sessions. Guard: `if [ -z "$SISYPHUS_SESSION_ID" ]; then exit 0; fi`. Stop hooks also need `$SISYPHUS_AGENT_ID`.
@@ -1,7 +1,39 @@
1
1
  #!/bin/bash
2
- # UserPromptSubmit hook: reinforce paranoid testing for operator agents.
2
+ # UserPromptSubmit hook: scaffold project-local operator memory on first run,
3
+ # then reinforce paranoid testing.
3
4
  if [ -z "$SISYPHUS_SESSION_ID" ]; then exit 0; fi
4
5
 
6
+ # ── Scaffold project-local operator memory ──────────────────────────────────
7
+ # On first run in a project, .sisyphus/agent-plugin/skills/operator/ doesn't
8
+ # exist. The bundled seed has already been copied into this agent's per-spawn
9
+ # plugin dir by the daemon (operator.md frontmatter lists skills: [operator]),
10
+ # so it's reachable via $CLAUDE_PLUGIN_ROOT — copy it from there to the
11
+ # project layer so future operator runs pick up the project-layer overlay.
12
+ SCAFFOLDED=0
13
+ if [ -n "$SISYPHUS_CWD" ] && [ -n "$CLAUDE_PLUGIN_ROOT" ]; then
14
+ PROJECT_MEMORY_DIR="$SISYPHUS_CWD/.sisyphus/agent-plugin/skills/operator"
15
+ BUNDLED_SEED_DIR="$CLAUDE_PLUGIN_ROOT/skills/operator"
16
+ if [ ! -f "$PROJECT_MEMORY_DIR/SKILL.md" ] && [ -d "$BUNDLED_SEED_DIR" ]; then
17
+ mkdir -p "$PROJECT_MEMORY_DIR"
18
+ cp -R "$BUNDLED_SEED_DIR/." "$PROJECT_MEMORY_DIR/"
19
+ SCAFFOLDED=1
20
+ fi
21
+ fi
22
+
23
+ if [ "$SCAFFOLDED" = "1" ]; then
24
+ cat <<'HINT'
25
+ <operator-memory-scaffolded>
26
+ Project-local operator memory was just scaffolded at .sisyphus/agent-plugin/skills/operator/ — read it now (it's a stub; you're the first operator in this project). Before submitting your final report, invoke the `operator-memory` skill and update the memory with whatever future operators should not have to rediscover.
27
+ </operator-memory-scaffolded>
28
+ HINT
29
+ else
30
+ cat <<'HINT'
31
+ <operator-memory>
32
+ Project-local operator memory is at .sisyphus/agent-plugin/skills/operator/ — read it now to inherit what prior operators learned. Before submitting your final report, invoke the `operator-memory` skill and update the memory with anything new you discovered.
33
+ </operator-memory>
34
+ HINT
35
+ fi
36
+
5
37
  cat <<'HINT'
6
38
  <operator-reminder>
7
39
  Click EVERYTHING — assume something is broken and prove it:
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: operator
3
+ description: Project-local operational knowledge for THIS app, accumulated by prior operator runs. Covers app surfaces (routes, ports, processes, admin overlays), auth/login flow, db state management, common UI flows, and known footguns. Use whenever the operator agent needs project-specific operating knowledge — read at session start, update before submitting.
4
+ ---
5
+
6
+ # Operator memory for this project
7
+
8
+ This is the operator agent's accumulated memory for THIS project. Each prior operator run added what it learned. You should add what you learn before submitting.
9
+
10
+ If this file looks mostly empty, you're early — populate as you go. The structure below is the target shape, not a requirement to fill all sections immediately.
11
+
12
+ ## App surfaces
13
+
14
+ Routes, ports, processes, admin overlays, debug flags. One line each — link to a reference file if there's depth.
15
+
16
+ - *(populate as you discover them)*
17
+
18
+ ## Common operational patterns
19
+
20
+ Login, logout, db reset, seeding, environment toggles. Brief — defer details to reference files.
21
+
22
+ - *(populate as you discover them)*
23
+
24
+ ## Known footguns
25
+
26
+ Things that broke once and might break again — race conditions, ordering requirements, stale-cache traps.
27
+
28
+ - *(populate as you discover them)*
29
+
30
+ ## Reference files
31
+
32
+ One line per file in this directory. Add an entry here when you create a new reference.
33
+
34
+ - *(none yet)*
35
+
36
+ ---
37
+
38
+ For guidance on what to capture, where to put it (SKILL.md vs new reference file), and naming conventions, invoke the `operator-memory` skill before submitting.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: operator-memory
3
+ description: Use right before the operator agent submits its final report. Provides guidance for updating the project-local operator memory at .sisyphus/agent-plugin/skills/operator/ — what to capture, where to put it (SKILL.md vs a new reference file), naming conventions, and what to skip. Defers to /authoring:skills for generic skill conventions (frontmatter, length budgets, structure).
4
+ user-invocable: false
5
+ ---
6
+
7
+ # Updating operator memory
8
+
9
+ You're about to submit. Spend a minute capturing what the next operator should not have to rediscover.
10
+
11
+ The memory lives at `.sisyphus/agent-plugin/skills/operator/`:
12
+ - `SKILL.md` — the high-level map of this app's surfaces and operations
13
+ - per-task-family reference files alongside it (`auth.md`, `db-reset.md`, `checkout-flow.md`, etc.)
14
+
15
+ ## When to update (and when NOT to)
16
+
17
+ The bar is **"will future operators benefit from this?"** Specifics:
18
+
19
+ UPDATE when you discovered:
20
+ - A repeatable operational procedure (login flow, db reset, seed step, environment toggle)
21
+ - A surface that wasn't obvious (admin route, debug overlay, hidden flag, internal port)
22
+ - A footgun you hit and worked around (race condition, ordering requirement, stale-cache trap)
23
+ - A convention this app uses that differs from defaults (custom auth headers, non-standard ports, weird redirect chains)
24
+
25
+ DON'T update when:
26
+ - It's session-specific state (this user's email, this session's seeded data)
27
+ - It's a one-off observation that won't reproduce
28
+ - It's already covered (read existing files first — duplication is worse than nothing)
29
+ - It's about the codebase, not about operating the app — that's the orchestrator's domain, not yours
30
+
31
+ ## SKILL.md vs a reference file
32
+
33
+ **SKILL.md** is the high-level map. It answers "what surfaces does this app have, what are the most common operations, where do I find deep dives?" Keep it dense — under ~80 lines. Each entry is a line or two with a pointer.
34
+
35
+ **A reference file** is the deep dive for one task family. It answers "exactly how do I do X step by step in this project". Each file has scope: `auth.md`, `db-reset.md`, `checkout-flow.md`, `feature-flags.md`.
36
+
37
+ Decision rule:
38
+ - New task family the operator might face → new reference file (and add a one-line entry to SKILL.md's Reference Files section).
39
+ - Refinement to existing knowledge → update the existing reference file or SKILL.md.
40
+ - A surface name you keep referencing → add it to SKILL.md's App Surfaces section once.
41
+
42
+ ## Naming conventions
43
+
44
+ - Reference files: kebab-case, task-family scope, no `operator-` prefix (the directory already implies it), `.md` extension.
45
+ - Good: `auth.md`, `admin-panel.md`, `db-reset.md`, `feature-flags.md`.
46
+ - Bad: `operator-auth.md`, `flows.md`, `notes.md`, `stuff.md`.
47
+ - One file per task family. If `auth.md` exists, append to it; don't create `auth-new.md` or `auth-2.md`.
48
+
49
+ ## How to update
50
+
51
+ 1. **Read first.** Open the current `SKILL.md` and any reference file you'll touch — orient before writing. Avoid duplicating what's already there.
52
+ 2. **Write/edit with the Write or Edit tool.** The directory already exists at `.sisyphus/agent-plugin/skills/operator/` (the hook scaffolds it on first run).
53
+ 3. **Keep prose dense.** The next operator pays in tokens for everything you write. If a step is obvious, omit it.
54
+ 4. **Register new reference files** by adding a one-line entry to `SKILL.md`'s "Reference files" section so they're discoverable.
55
+
56
+ For frontmatter, length budgets, and general skill structure rules, invoke `/authoring:skills`. Don't reinvent those rules here — this skill only covers operator-specific guidance.
57
+
58
+ ## Examples
59
+
60
+ **Discovered magic-link auth flow:** Create `auth.md` with the steps (email submit → check inbox → click link → cookie set). Add a one-liner to `SKILL.md` App Surfaces (`/login` — magic-link, see `auth.md`). Add to Common Operational Patterns (`Log in: see auth.md`).
61
+
62
+ **Hit a stale-cache footgun:** The `/dashboard` route serves stale data for ~30s after a write because of an SWR cache. Add a single bullet to `SKILL.md` Known Footguns: `Dashboard SWR cache holds stale data ~30s after writes — hard refresh or wait`. No new reference file needed — it's a one-liner.
63
+
64
+ **Found admin overlay:** `?admin=1` query param toggles an admin panel with seed/reset buttons. Add to `SKILL.md` App Surfaces: `Admin overlay: append ?admin=1 to any page; has seed/reset/feature-flag buttons`. If the overlay is rich enough to need step-by-step coverage, create `admin-panel.md` and link from there.
@@ -110,10 +110,16 @@ The cycle shape:
110
110
  plan phase 1 → implement phase 1 → validate phase 1 → plan phase 2 → implement phase 2 → validate phase 2 → ...
111
111
  ```
112
112
 
113
- After a phase's implementation passes e2e validation, yield back to planning mode for the next phase:
113
+ **Not every phase needs its own plan cycle.** Before yielding back, look at phase N+1 in `strategy.md`. If it's wrapper-shaped (every change backs onto an existing CLI/API/handler), mechanical (rename, move, reformat), or scoped to a single agent-cycle of work, yield directly to implementation and let the implement agent work from `strategy.md` plus what phase N taught you. Reserve the plan cycle for phases where the *how* is genuinely open.
114
+
115
+ After a phase's implementation passes e2e validation, yield for the next phase — pick the mode that matches its shape:
114
116
 
115
117
  ```bash
118
+ # Phase N+1 needs planning (default):
116
119
  sis orch yield --mode planning --prompt "Phase N validated. Plan phase N+1 per strategy.md."
120
+
121
+ # Phase N+1 is wrapper-shaped or single-cycle:
122
+ sis orch yield --mode implementation --prompt "Phase N validated. Implement phase N+1 per strategy.md."
117
123
  ```
118
124
 
119
125
  When spawning the phase-scoped plan lead, name in the prompt:
package/dist/tui.js CHANGED
@@ -1217,7 +1217,7 @@ function autoExpandCycle(state2) {
1217
1217
 
1218
1218
  // src/tui/app.ts
1219
1219
  import { readFileSync as readFileSync15, existsSync as existsSync10, readdirSync as readdirSync7, statSync as statSync4 } from "fs";
1220
- import { join as join14 } from "path";
1220
+ import { join as join15 } from "path";
1221
1221
 
1222
1222
  // src/tui/input.ts
1223
1223
  import { execSync } from "child_process";
@@ -3239,7 +3239,7 @@ function renderHelpOverlay(buf, rows, cols) {
3239
3239
  helpRow(" r re-run agent", " g edit goal", innerWidth),
3240
3240
  helpRow(" p open roadmap", " S edit strategy", innerWidth),
3241
3241
  helpRow(" w go to window", " o resume claude", innerWidth),
3242
- helpRow(" c claude companion", " q quit", innerWidth),
3242
+ helpRow(" c side claude pane", " q quit", innerWidth),
3243
3243
  " ".padEnd(innerWidth),
3244
3244
  // Leader direct keys (top-level space-key)
3245
3245
  helpRow(" space s cycle session", " space h home/dashboard", innerWidth),
@@ -3248,10 +3248,12 @@ function renderHelpOverlay(buf, rows, cols) {
3248
3248
  helpRow(" space x kill pane", " space / search", innerWidth),
3249
3249
  helpRow(" space ? help", " space 1-9 jump to session", innerWidth),
3250
3250
  " ".padEnd(innerWidth),
3251
+ // Direct top-level leader keys
3252
+ helpRow(" space c side claude pane", " space y \u203A Yank", innerWidth),
3251
3253
  // Submenu prefixes
3252
- helpRow(" space c \u203A Copy", " space o \u203A Open", innerWidth),
3253
- helpRow(" space a \u203A Agent", " space S \u203A Session", innerWidth),
3254
- helpRow(" space g \u203A Go", "", innerWidth),
3254
+ helpRow(" space o \u203A Open", " space a \u203A Agent", innerWidth),
3255
+ helpRow(" space S \u203A Session", " space g \u203A Go", innerWidth),
3256
+ helpRow(" space C \u203A Companion", "", innerWidth),
3255
3257
  " ".padEnd(innerWidth),
3256
3258
  ansiDim(" Changed: space a \u2192 space a s (spawn agent)".padEnd(innerWidth))
3257
3259
  ];
@@ -3896,7 +3898,8 @@ var KEYMAP = {
3896
3898
  { key: "/", label: " Search / filter", action: { type: "script", name: "sisyphus-search-reports" }, tuiAction: "search" },
3897
3899
  { key: " ", label: " Open popup explicitly", action: { type: "tui", action: "show-leader" } },
3898
3900
  { key: "y", label: " Yank \u203A", action: { type: "submenu", ref: "copy" } },
3899
- { key: "c", label: " Companion \u203A", action: { type: "submenu", ref: "companion" } },
3901
+ { key: "c", label: " Side claude pane", action: { type: "script", name: "sisyphus-companion-pane" }, tuiAction: "companion-pane" },
3902
+ { key: "C", label: " Companion (gamification) \u203A", action: { type: "submenu", ref: "companion" } },
3900
3903
  { key: "o", label: " Open \u203A", action: { type: "submenu", ref: "open" } },
3901
3904
  { key: "a", label: " Agent \u203A", action: { type: "submenu", ref: "agent" } },
3902
3905
  { key: "S", label: " Session \u203A", action: { type: "submenu", ref: "session" } },
@@ -3908,8 +3911,7 @@ var KEYMAP = {
3908
3911
  title: " Companion ",
3909
3912
  items: [
3910
3913
  { key: "p", label: " profile (overlay)", action: { type: "tui", action: "companion-overlay" } },
3911
- { key: "d", label: " debug (mood signals)", action: { type: "tui", action: "companion-debug" } },
3912
- { key: "t", label: " open in tmux pane", action: { type: "tui", action: "companion-pane" } }
3914
+ { key: "d", label: " debug (mood signals)", action: { type: "tui", action: "companion-debug" } }
3913
3915
  ]
3914
3916
  },
3915
3917
  copy: {
@@ -5540,7 +5542,6 @@ function registerDashboardWindow(cwd2) {
5540
5542
  }
5541
5543
  }
5542
5544
  }
5543
- var companionPaneId = null;
5544
5545
  function setupCompanionPlugin() {
5545
5546
  const srcDir = join12(import.meta.dirname, "templates", "companion-plugin");
5546
5547
  const destDir = join12(globalDir(), "companion-plugin");
@@ -5551,9 +5552,23 @@ function setupCompanionPlugin() {
5551
5552
  function paneExists(paneId) {
5552
5553
  return execSafe(`tmux display-message -t ${shellQuote(paneId)} -p "#{pane_id}"`) !== null;
5553
5554
  }
5555
+ function findCompanionPaneForCwd(normalizedCwd) {
5556
+ const out = execSafe(`tmux list-panes -aF "#{pane_id} #{@sisyphus_companion}"`);
5557
+ if (!out) return null;
5558
+ for (const line of out.split("\n")) {
5559
+ const tabIdx = line.indexOf(" ");
5560
+ if (tabIdx < 0) continue;
5561
+ const paneId = line.slice(0, tabIdx);
5562
+ const marker = line.slice(tabIdx + 1);
5563
+ if (paneId && marker === normalizedCwd) return paneId;
5564
+ }
5565
+ return null;
5566
+ }
5554
5567
  function openCompanionPane(cwd2) {
5555
- if (companionPaneId && paneExists(companionPaneId)) {
5556
- execSafe(`tmux select-pane -t ${shellQuote(companionPaneId)}`);
5568
+ const normalizedCwd = cwd2.replace(/\/+$/, "");
5569
+ const existing = findCompanionPaneForCwd(normalizedCwd);
5570
+ if (existing) {
5571
+ execSafe(`tmux select-pane -t ${shellQuote(existing)}`);
5557
5572
  return;
5558
5573
  }
5559
5574
  const pluginDir = setupCompanionPlugin();
@@ -5572,9 +5587,12 @@ Run \`sis list\` and \`sis status\` to see current state.`;
5572
5587
  const pathEnv = augmentedPath();
5573
5588
  const claudeCmd = `SISYPHUS_COMPANION_CWD=${shellQuote(cwd2)} PATH=${shellQuote(pathEnv)} claude --dangerously-skip-permissions --plugin-dir ${shellQuote(pluginDir)} --append-system-prompt "$(cat ${shellQuote(promptPath)})"`;
5574
5589
  const result = exec(
5575
- `tmux split-window -h -d -l 33% -P -F "#{pane_id}" -c ${shellQuote(cwd2)} ${shellQuote(claudeCmd)}`
5590
+ `tmux split-window -h -l 33% -P -F "#{pane_id}" -c ${shellQuote(cwd2)} ${shellQuote(claudeCmd)}`
5576
5591
  );
5577
- companionPaneId = result.trim() || null;
5592
+ const newPaneId = result.trim();
5593
+ if (newPaneId) {
5594
+ execSafe(`tmux set-option -p -t ${shellQuote(newPaneId)} @sisyphus_companion ${shellQuote(normalizedCwd)}`);
5595
+ }
5578
5596
  }
5579
5597
  var TERMINAL_EDITORS = /* @__PURE__ */ new Set(["nvim", "vim", "vi", "nano", "emacs", "micro", "helix", "hx", "joe", "ne", "kak"]);
5580
5598
  function switchToSession(sessionName) {
@@ -8247,9 +8265,14 @@ init_paths();
8247
8265
  // src/tui/lib/popup-compose.ts
8248
8266
  init_shell();
8249
8267
  import { execSync as execSync5 } from "child_process";
8250
- import { mkdtempSync as mkdtempSync2, mkdirSync as mkdirSync9, writeFileSync as writeFileSync10, readFileSync as readFileSync14, rmSync as rmSync5, existsSync as existsSync9, cpSync as cpSync3 } from "fs";
8268
+ import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync10, readFileSync as readFileSync14, rmSync as rmSync5 } from "fs";
8269
+ import { join as join14 } from "path";
8270
+ import { tmpdir as tmpdir2 } from "os";
8271
+
8272
+ // src/shared/sisyphus-init-lua.ts
8273
+ import { mkdirSync as mkdirSync9, existsSync as existsSync9, cpSync as cpSync3 } from "fs";
8251
8274
  import { join as join13 } from "path";
8252
- import { tmpdir as tmpdir2, homedir as homedir4 } from "os";
8275
+ import { homedir as homedir4 } from "os";
8253
8276
  var initLuaEnsured = false;
8254
8277
  function ensureSisyphusInitLua() {
8255
8278
  if (initLuaEnsured) return;
@@ -8264,9 +8287,11 @@ function ensureSisyphusInitLua() {
8264
8287
  } catch {
8265
8288
  }
8266
8289
  }
8290
+
8291
+ // src/tui/lib/popup-compose.ts
8267
8292
  function composeViaPopup(action, state2, actions) {
8268
- const tmpDir = mkdtempSync2(join13(tmpdir2(), "sisyphus-popup-"));
8269
- const tempFile = join13(tmpDir, "compose.md");
8293
+ const tmpDir = mkdtempSync2(join14(tmpdir2(), "sisyphus-popup-"));
8294
+ const tempFile = join14(tmpDir, "compose.md");
8270
8295
  try {
8271
8296
  writeFileSync10(tempFile, "", "utf-8");
8272
8297
  const cmd = `NVIM_APPNAME=sisyphus nvim ${shellQuote(tempFile)}`;
@@ -8448,7 +8473,7 @@ function startApp(state2, cleanup2) {
8448
8473
  } catch {
8449
8474
  }
8450
8475
  try {
8451
- const cp = join14(contextDir(state2.cwd, state2.selectedSessionId), "completion-summary.md");
8476
+ const cp = join15(contextDir(state2.cwd, state2.selectedSessionId), "completion-summary.md");
8452
8477
  if (existsSync10(cp)) {
8453
8478
  completionSummaryContent = readFileSync15(cp, "utf-8");
8454
8479
  }
@@ -8467,7 +8492,7 @@ function startApp(state2, cleanup2) {
8467
8492
  if (!fileSet.has(key)) cachedLogFiles.delete(key);
8468
8493
  }
8469
8494
  for (const f of files) {
8470
- const filePath = join14(ld, f);
8495
+ const filePath = join15(ld, f);
8471
8496
  const mtime = statSync4(filePath).mtimeMs;
8472
8497
  const cached = cachedLogFiles.get(f);
8473
8498
  if (!cached || cached.mtime !== mtime) {
@@ -8493,7 +8518,7 @@ function startApp(state2, cleanup2) {
8493
8518
  for (const e of entries) {
8494
8519
  if (e.isDirectory()) {
8495
8520
  try {
8496
- const sub = readdirSync7(join14(cd, e.name)).filter((f) => !f.startsWith(".")).map((f) => `${e.name}/${f}`);
8521
+ const sub = readdirSync7(join15(cd, e.name)).filter((f) => !f.startsWith(".")).map((f) => `${e.name}/${f}`);
8497
8522
  flat.push(...sub);
8498
8523
  } catch {
8499
8524
  }