@dosu/cli 0.62.1 → 0.64.0

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 (3) hide show
  1. package/README.md +5 -2
  2. package/bin/dosu.js +745 -414
  3. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -1083,7 +1083,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1083
1083
  function getVersionString() {
1084
1084
  return `v${VERSION}`;
1085
1085
  }
1086
- var VERSION = "0.62.1", INSTALL_CHANNEL = "npm";
1086
+ var VERSION = "0.64.0", INSTALL_CHANNEL = "npm";
1087
1087
 
1088
1088
  // src/debug/logger.ts
1089
1089
  import {
@@ -1472,6 +1472,70 @@ var init_agents = __esm(() => {
1472
1472
  init_formats();
1473
1473
  });
1474
1474
 
1475
+ // src/sessions/repo.ts
1476
+ import { execFileSync } from "node:child_process";
1477
+ function normalizeRepoRemote(remote) {
1478
+ const value = remote.trim();
1479
+ if (!value)
1480
+ return null;
1481
+ let host;
1482
+ let path;
1483
+ const scp = value.includes("://") ? null : /^(?:[^@/]+@)?([^:/]+):(.+)$/.exec(value);
1484
+ if (scp) {
1485
+ host = scp[1];
1486
+ path = scp[2];
1487
+ } else {
1488
+ try {
1489
+ const url = new URL(value);
1490
+ if (url.protocol === "file:")
1491
+ return null;
1492
+ host = url.hostname;
1493
+ path = url.pathname;
1494
+ } catch {
1495
+ return null;
1496
+ }
1497
+ }
1498
+ path = path.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
1499
+ if (!host || !path.includes("/"))
1500
+ return null;
1501
+ const lowerHost = host.toLowerCase();
1502
+ return `${lowerHost}/${lowerHost === "github.com" ? path.toLowerCase() : path}`;
1503
+ }
1504
+ function gitOutput(dir, args, timeout) {
1505
+ const env = { ...process.env };
1506
+ for (const name of GIT_LOCATION_ENV)
1507
+ delete env[name];
1508
+ try {
1509
+ return execFileSync("git", ["-C", dir, ...args], {
1510
+ encoding: "utf-8",
1511
+ env,
1512
+ stdio: ["ignore", "pipe", "ignore"],
1513
+ timeout,
1514
+ maxBuffer: 16 * 1024 * 1024
1515
+ });
1516
+ } catch {
1517
+ return null;
1518
+ }
1519
+ }
1520
+ function originRepoOfDir(dir) {
1521
+ const out = gitOutput(dir, ["remote", "get-url", "origin"], 1000);
1522
+ return out === null ? null : normalizeRepoRemote(out);
1523
+ }
1524
+ function currentBranchOfDir(dir) {
1525
+ const out = gitOutput(dir, ["symbolic-ref", "--short", "-q", "HEAD"], 1000)?.trim();
1526
+ return out ? out : null;
1527
+ }
1528
+ function headReflogOfDir(dir) {
1529
+ return gitOutput(dir, ["reflog", "show", "--date=unix", "--format=%gd%x09%gs", "HEAD"], 5000);
1530
+ }
1531
+ function displayRepo(repo) {
1532
+ return repo.split("/").slice(1).join("/") || repo;
1533
+ }
1534
+ var GIT_LOCATION_ENV;
1535
+ var init_repo = __esm(() => {
1536
+ GIT_LOCATION_ENV = ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"];
1537
+ });
1538
+
1475
1539
  // src/sessions/scan.ts
1476
1540
  import { existsSync as existsSync6, readdirSync, statSync as statSync2 } from "node:fs";
1477
1541
  import { createRequire as createRequire2 } from "node:module";
@@ -1919,6 +1983,9 @@ import { join as join6 } from "node:path";
1919
1983
  function syncStatePath(configDir = getConfigDir()) {
1920
1984
  return join6(configDir, STATE_FILENAME);
1921
1985
  }
1986
+ function stringsOf(values) {
1987
+ return values.filter((v) => typeof v === "string");
1988
+ }
1922
1989
  function loadSyncState(configDir = getConfigDir()) {
1923
1990
  const empty = {
1924
1991
  schema_version: STATE_SCHEMA_VERSION,
@@ -1954,9 +2021,8 @@ function loadSyncState(configDir = getConfigDir()) {
1954
2021
  ...lastRefusal ? { last_refusal: lastRefusal } : {},
1955
2022
  ...run ? { run } : {},
1956
2023
  ...raw.paused === true ? { paused: true } : {},
1957
- ...Array.isArray(raw.project_filter) ? {
1958
- project_filter: raw.project_filter.filter((p) => typeof p === "string")
1959
- } : {}
2024
+ ...Array.isArray(raw.repo_filter) ? { repo_filter: stringsOf(raw.repo_filter) } : {},
2025
+ ...Array.isArray(raw.project_filter) ? { project_filter: stringsOf(raw.project_filter) } : {}
1960
2026
  };
1961
2027
  } catch {
1962
2028
  return empty;
@@ -1976,6 +2042,7 @@ function resetSyncState(configDir = getConfigDir()) {
1976
2042
  schema_version: STATE_SCHEMA_VERSION,
1977
2043
  watermark: null,
1978
2044
  consecutive_failures: 0,
2045
+ ...previous.repo_filter ? { repo_filter: previous.repo_filter } : {},
1979
2046
  ...previous.project_filter ? { project_filter: previous.project_filter } : {},
1980
2047
  ...previous.paused ? { paused: true } : {}
1981
2048
  };
@@ -2002,17 +2069,34 @@ function isUnderDir(dir, base) {
2002
2069
  const root = base.endsWith("/") ? base.slice(0, -1) : base;
2003
2070
  return dir === root || dir.startsWith(`${root}/`);
2004
2071
  }
2005
- function filterSessionsByProject(sessions, filter, resolveDir) {
2006
- if (!filter || filter.length === 0)
2007
- return [...sessions];
2008
- const includeUnknown = filter.includes(UNKNOWN_PROJECT);
2009
- const dirs = filter.filter((entry) => entry !== UNKNOWN_PROJECT);
2010
- return sessions.filter((session) => {
2011
- const dir = resolveDir(session);
2012
- if (!dir)
2013
- return includeUnknown;
2014
- return dirs.some((base) => isUnderDir(dir, base));
2015
- });
2072
+ function studyRepoFilter(state, listSessions, locator) {
2073
+ if (state.repo_filter)
2074
+ return state.repo_filter;
2075
+ const folders = state.project_filter;
2076
+ if (!folders?.length)
2077
+ return null;
2078
+ const repos = new Set;
2079
+ for (const session of listSessions()) {
2080
+ const dir = locator.resolve(session);
2081
+ if (!dir || !folders.some((base) => isUnderDir(dir, base)))
2082
+ continue;
2083
+ const repo = locator.resolveRepo(session);
2084
+ if (repo)
2085
+ repos.add(repo);
2086
+ }
2087
+ return [...repos].sort();
2088
+ }
2089
+ function filterSessionsByRepo(sessions, filter, resolveRepo) {
2090
+ const kept = [];
2091
+ for (const session of sessions) {
2092
+ const repo = resolveRepo(session);
2093
+ if (repo !== null && (filter === null || filter.includes(repo))) {
2094
+ kept.push({ ...session, repo });
2095
+ } else if (filter === null) {
2096
+ kept.push(session);
2097
+ }
2098
+ }
2099
+ return kept;
2016
2100
  }
2017
2101
  function gateSessions(sessions, watermark, now = new Date, quietPeriodMs = DEFAULT_QUIET_PERIOD_MS) {
2018
2102
  const watermarkMs = watermark ? Date.parse(watermark) : Number.NEGATIVE_INFINITY;
@@ -2031,7 +2115,7 @@ function gateSessions(sessions, watermark, now = new Date, quietPeriodMs = DEFAU
2031
2115
  }
2032
2116
  return { ready, open };
2033
2117
  }
2034
- var STATE_FILENAME = "knowledge-sync.json", STATE_SCHEMA_VERSION = 1, DEFAULT_QUIET_PERIOD_MS, BACKOFF_BASE_MS, BACKOFF_MAX_MS, STUDIED_HISTORY_LIMIT = 500, UNKNOWN_PROJECT = "(unknown)";
2118
+ var STATE_FILENAME = "knowledge-sync.json", STATE_SCHEMA_VERSION = 1, DEFAULT_QUIET_PERIOD_MS, BACKOFF_BASE_MS, BACKOFF_MAX_MS, STUDIED_HISTORY_LIMIT = 500;
2035
2119
  var init_watermark = __esm(() => {
2036
2120
  init_config();
2037
2121
  DEFAULT_QUIET_PERIOD_MS = 5 * 60 * 1000;
@@ -2067,12 +2151,15 @@ function defaultHookEnabled(agentId) {
2067
2151
  return false;
2068
2152
  }
2069
2153
  }
2070
- function cwdIsStudied(cwd, filter) {
2071
- if (!filter || filter.length === 0)
2072
- return true;
2073
- if (!cwd)
2074
- return filter.includes(UNKNOWN_PROJECT);
2075
- return filter.some((base) => base !== UNKNOWN_PROJECT && isUnderDir(cwd, base));
2154
+ function cwdIsStudied(cwd, state, repoOfDir) {
2155
+ if (state.repo_filter) {
2156
+ const repo = cwd ? repoOfDir(cwd) : null;
2157
+ return repo !== null && state.repo_filter.includes(repo);
2158
+ }
2159
+ if (state.project_filter?.length) {
2160
+ return cwd !== undefined && state.project_filter.some((base) => isUnderDir(cwd, base));
2161
+ }
2162
+ return true;
2076
2163
  }
2077
2164
  function resolveStatuslineState(payload, agentId, deps = {}) {
2078
2165
  const hookEnabled = deps.hookEnabled ?? defaultHookEnabled;
@@ -2085,7 +2172,7 @@ function resolveStatuslineState(payload, agentId, deps = {}) {
2085
2172
  const state = (deps.loadState ?? loadSyncState)();
2086
2173
  if (state.paused)
2087
2174
  return "paused";
2088
- if (!cwdIsStudied(payload.cwd, state.project_filter))
2175
+ if (!cwdIsStudied(payload.cwd, state, deps.repoOfDir ?? originRepoOfDir))
2089
2176
  return "not-studied";
2090
2177
  return "on";
2091
2178
  }
@@ -2099,13 +2186,14 @@ function renderStatusline(raw, agentId, deps = {}) {
2099
2186
  var STATUSLINE_LABELS;
2100
2187
  var init_render = __esm(() => {
2101
2188
  init_agents();
2189
+ init_repo();
2102
2190
  init_incognito();
2103
2191
  init_watermark();
2104
2192
  STATUSLINE_LABELS = {
2105
2193
  on: "\uD83D\uDCDA Dosu studying…",
2106
2194
  incognito: "\uD83D\uDC7B Dosu incognito",
2107
2195
  paused: "⚪ Dosu paused",
2108
- "not-studied": "⚪ Dosu not studying this folder",
2196
+ "not-studied": "⚪ Dosu not studying this repo",
2109
2197
  off: "⚪ Dosu off"
2110
2198
  };
2111
2199
  });
@@ -9863,7 +9951,7 @@ var init_default_browser_id = __esm(() => {
9863
9951
  // node_modules/run-applescript/index.js
9864
9952
  import process6 from "node:process";
9865
9953
  import { promisify as promisify4 } from "node:util";
9866
- import { execFile as execFile4, execFileSync } from "node:child_process";
9954
+ import { execFile as execFile4, execFileSync as execFileSync2 } from "node:child_process";
9867
9955
  async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
9868
9956
  if (process6.platform !== "darwin") {
9869
9957
  throw new Error("macOS only");
@@ -11881,25 +11969,218 @@ var init_integrations = __esm(() => {
11881
11969
  };
11882
11970
  });
11883
11971
 
11972
+ // src/sessions/branch.ts
11973
+ function recordedBranch(value) {
11974
+ if (typeof value !== "string")
11975
+ return null;
11976
+ const branch = value.trim();
11977
+ return branch && branch !== "HEAD" ? branch : null;
11978
+ }
11979
+ function branchFromClaudeTranscript(text) {
11980
+ let last = null;
11981
+ for (const match of text.matchAll(/"gitBranch":\s*("(?:[^"\\]|\\.)*")/g)) {
11982
+ try {
11983
+ last = recordedBranch(JSON.parse(match[1])) ?? last;
11984
+ } catch {}
11985
+ }
11986
+ return last;
11987
+ }
11988
+ function branchFromCodexTranscript(text) {
11989
+ for (const line of text.split(`
11990
+ `, CODEX_META_LINES)) {
11991
+ if (!line.includes('"session_meta"'))
11992
+ continue;
11993
+ try {
11994
+ const record = JSON.parse(line);
11995
+ if (record.type === "session_meta")
11996
+ return recordedBranch(record.payload?.git?.branch);
11997
+ } catch {}
11998
+ }
11999
+ return null;
12000
+ }
12001
+ function parseReflog(out) {
12002
+ const entries = [];
12003
+ for (const line of out.split(`
12004
+ `)) {
12005
+ const match = /^HEAD@\{(\d+)\}\t(.*)$/.exec(line);
12006
+ if (match)
12007
+ entries.push({ at: Number(match[1]), subject: match[2] });
12008
+ }
12009
+ return entries;
12010
+ }
12011
+ function checkoutBranch(name) {
12012
+ return /^[0-9a-f]{7,40}$/.test(name) ? null : recordedBranch(name);
12013
+ }
12014
+ function branchFromReflog(entries, endSec, currentBranch) {
12015
+ if (entries.length === 0)
12016
+ return null;
12017
+ let oldest = Number.POSITIVE_INFINITY;
12018
+ let before = null;
12019
+ let after = null;
12020
+ for (const entry of entries) {
12021
+ oldest = Math.min(oldest, entry.at);
12022
+ const match = CHECKOUT.exec(entry.subject);
12023
+ if (!match)
12024
+ continue;
12025
+ if (entry.at <= endSec) {
12026
+ if (!before || entry.at > before.at)
12027
+ before = { at: entry.at, to: match[2] };
12028
+ } else if (!after || entry.at <= after.at) {
12029
+ after = { at: entry.at, from: match[1] };
12030
+ }
12031
+ }
12032
+ if (endSec < oldest)
12033
+ return null;
12034
+ if (before)
12035
+ return checkoutBranch(before.to);
12036
+ if (after)
12037
+ return checkoutBranch(after.from);
12038
+ return currentBranch();
12039
+ }
12040
+ var CODEX_META_LINES = 50, CHECKOUT;
12041
+ var init_branch = __esm(() => {
12042
+ CHECKOUT = /^checkout: moving from (\S+) to (\S+)$/;
12043
+ });
12044
+
12045
+ // src/sessions/capture.ts
12046
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync3, writeFileSync as writeFileSync7 } from "node:fs";
12047
+ import { basename as basename2, join as join10 } from "node:path";
12048
+ function capturePath(configDir, key) {
12049
+ const [harness, id, ...rest] = key.split("/");
12050
+ if (rest.length > 0 || !SAFE_SEGMENT.test(harness ?? "") || !SAFE_SEGMENT.test(id ?? "")) {
12051
+ return null;
12052
+ }
12053
+ return join10(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
12054
+ }
12055
+ function readCapturedSession(key, configDir = getConfigDir()) {
12056
+ const path = capturePath(configDir, key);
12057
+ if (!path)
12058
+ return null;
12059
+ try {
12060
+ const raw = JSON.parse(readFileSync11(path, "utf-8"));
12061
+ return {
12062
+ ...typeof raw.dir === "string" ? { dir: raw.dir } : {},
12063
+ ...typeof raw.branch === "string" ? { branch: raw.branch } : {},
12064
+ at: typeof raw.at === "string" ? raw.at : ""
12065
+ };
12066
+ } catch {
12067
+ return null;
12068
+ }
12069
+ }
12070
+ function recordCapturedSession(key, update, configDir = getConfigDir(), now = new Date) {
12071
+ const path = capturePath(configDir, key);
12072
+ if (!path)
12073
+ return false;
12074
+ const previous = readCapturedSession(key, configDir);
12075
+ const dir = update.dir ?? previous?.dir;
12076
+ const branch = update.branch ?? previous?.branch;
12077
+ const record = {
12078
+ ...dir ? { dir } : {},
12079
+ ...branch ? { branch } : {},
12080
+ at: now.toISOString()
12081
+ };
12082
+ try {
12083
+ const parent = join10(path, "..");
12084
+ if (!existsSync11(parent))
12085
+ mkdirSync7(parent, { recursive: true, mode: 448 });
12086
+ const tmp = `${path}.${process.pid}.tmp`;
12087
+ writeFileSync7(tmp, JSON.stringify(record), { mode: 384 });
12088
+ renameSync3(tmp, path);
12089
+ return true;
12090
+ } catch (err) {
12091
+ logger.debug("sync", `could not record ${key}: ${err.message}`);
12092
+ return false;
12093
+ }
12094
+ }
12095
+ function captureCursorStop(payload, deps = {}) {
12096
+ if (typeof payload !== "object" || payload === null)
12097
+ return false;
12098
+ const hook = payload;
12099
+ if (hook.cursor_version === undefined)
12100
+ return false;
12101
+ const id = typeof hook.transcript_path === "string" && hook.transcript_path.endsWith(".jsonl") ? basename2(hook.transcript_path, ".jsonl") : hook.conversation_id;
12102
+ if (typeof id !== "string")
12103
+ return false;
12104
+ const roots = hook.workspace_roots;
12105
+ const dir = Array.isArray(roots) && typeof roots[0] === "string" ? roots[0] : undefined;
12106
+ if (!dir?.startsWith("/"))
12107
+ return false;
12108
+ const branch = (deps.currentBranch ?? currentBranchOfDir)(dir);
12109
+ return recordCapturedSession(`cursor/${id}`, { dir, branch }, deps.configDir, deps.now);
12110
+ }
12111
+ function readHookStdin(stream = process.stdin, timeoutMs = HOOK_STDIN_TIMEOUT_MS, maxBytes = HOOK_STDIN_MAX_BYTES) {
12112
+ if (stream.isTTY)
12113
+ return Promise.resolve(null);
12114
+ return new Promise((resolve) => {
12115
+ const chunks = [];
12116
+ let size = 0;
12117
+ let done = false;
12118
+ let timer;
12119
+ const finish = (value) => {
12120
+ if (done)
12121
+ return;
12122
+ done = true;
12123
+ clearTimeout(timer);
12124
+ stream.removeAllListeners("data");
12125
+ stream.pause();
12126
+ stream.destroy?.();
12127
+ resolve(value);
12128
+ };
12129
+ stream.on("data", (chunk) => {
12130
+ const buf = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
12131
+ size += buf.length;
12132
+ if (size > maxBytes)
12133
+ return finish(null);
12134
+ chunks.push(buf);
12135
+ });
12136
+ stream.on("end", () => {
12137
+ try {
12138
+ finish(JSON.parse(Buffer.concat(chunks).toString("utf-8")));
12139
+ } catch {
12140
+ finish(null);
12141
+ }
12142
+ });
12143
+ stream.on("error", () => finish(null));
12144
+ timer = setTimeout(() => finish(null), timeoutMs);
12145
+ });
12146
+ }
12147
+ async function captureHookSession(stream) {
12148
+ try {
12149
+ const payload = await readHookStdin(stream);
12150
+ if (payload !== null)
12151
+ captureCursorStop(payload);
12152
+ } catch (err) {
12153
+ logger.debug("sync", `hook capture failed: ${err instanceof Error ? err.message : err}`);
12154
+ }
12155
+ }
12156
+ var CAPTURE_DIRNAME = "session-captures", HOOK_STDIN_TIMEOUT_MS = 500, HOOK_STDIN_MAX_BYTES, SAFE_SEGMENT;
12157
+ var init_capture = __esm(() => {
12158
+ init_config();
12159
+ init_logger();
12160
+ init_repo();
12161
+ HOOK_STDIN_MAX_BYTES = 1024 * 1024;
12162
+ SAFE_SEGMENT = /^[A-Za-z0-9_-]+$/;
12163
+ });
12164
+
11884
12165
  // src/sessions/project-dir.ts
11885
12166
  import {
11886
12167
  closeSync as closeSync4,
11887
- existsSync as existsSync11,
11888
- mkdirSync as mkdirSync7,
12168
+ existsSync as existsSync12,
12169
+ mkdirSync as mkdirSync8,
11889
12170
  openSync as openSync4,
11890
- readFileSync as readFileSync11,
12171
+ readFileSync as readFileSync12,
11891
12172
  readSync as readSync3,
11892
- renameSync as renameSync3,
12173
+ renameSync as renameSync4,
11893
12174
  statSync as statSync4,
11894
- writeFileSync as writeFileSync7
12175
+ writeFileSync as writeFileSync8
11895
12176
  } from "node:fs";
11896
- import { join as join10 } from "node:path";
12177
+ import { join as join11 } from "node:path";
11897
12178
  function cachePath(configDir) {
11898
- return join10(configDir, CACHE_FILENAME2);
12179
+ return join11(configDir, CACHE_FILENAME2);
11899
12180
  }
11900
12181
  function loadCacheFile(configDir) {
11901
12182
  try {
11902
- const raw = JSON.parse(readFileSync11(cachePath(configDir), "utf-8"));
12183
+ const raw = JSON.parse(readFileSync12(cachePath(configDir), "utf-8"));
11903
12184
  if (raw.schema_version !== CACHE_SCHEMA_VERSION || typeof raw.entries !== "object")
11904
12185
  return {};
11905
12186
  return raw.entries;
@@ -11909,13 +12190,13 @@ function loadCacheFile(configDir) {
11909
12190
  }
11910
12191
  function saveCacheFile(configDir, entries) {
11911
12192
  try {
11912
- if (!existsSync11(configDir))
11913
- mkdirSync7(configDir, { recursive: true, mode: 448 });
12193
+ if (!existsSync12(configDir))
12194
+ mkdirSync8(configDir, { recursive: true, mode: 448 });
11914
12195
  const path = cachePath(configDir);
11915
12196
  const tmp = `${path}.${process.pid}.tmp`;
11916
12197
  const file = { schema_version: CACHE_SCHEMA_VERSION, entries };
11917
- writeFileSync7(tmp, JSON.stringify(file), { mode: 384 });
11918
- renameSync3(tmp, path);
12198
+ writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
12199
+ renameSync4(tmp, path);
11919
12200
  } catch {}
11920
12201
  }
11921
12202
  function readHead(path, bytes = HEAD_BYTES) {
@@ -11949,7 +12230,7 @@ function cwdFromJsonlHead(text) {
11949
12230
  }
11950
12231
  return null;
11951
12232
  }
11952
- function unmungeSlug(slug, exists = existsSync11) {
12233
+ function unmungeSlug(slug, exists = existsSync12) {
11953
12234
  const tokens = slug.replace(/^-/, "").split("-");
11954
12235
  if (tokens.length === 0 || tokens[0] === "")
11955
12236
  return null;
@@ -11966,6 +12247,13 @@ function unmungeSlug(slug, exists = existsSync11) {
11966
12247
  };
11967
12248
  return walk("", 0);
11968
12249
  }
12250
+ function readWholeFile(path) {
12251
+ try {
12252
+ return readFileSync12(path, "utf-8");
12253
+ } catch {
12254
+ return null;
12255
+ }
12256
+ }
11969
12257
  function fileMtime(path) {
11970
12258
  try {
11971
12259
  return statSync4(path).mtime.toISOString();
@@ -11974,9 +12262,10 @@ function fileMtime(path) {
11974
12262
  }
11975
12263
  }
11976
12264
  function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
11977
- const exists = deps.exists ?? existsSync11;
12265
+ const exists = deps.exists ?? existsSync12;
11978
12266
  const head = deps.readHead ?? readHead;
11979
12267
  const mtime = deps.mtime ?? fileMtime;
12268
+ const captured = deps.captured ?? ((key) => readCapturedSession(key, configDir));
11980
12269
  const entries = loadCacheFile(configDir);
11981
12270
  let dirty = false;
11982
12271
  const compute = (session) => {
@@ -11994,26 +12283,81 @@ function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
11994
12283
  const text = head(session.path);
11995
12284
  return text ? cwdFromJsonlHead(text) : null;
11996
12285
  }
11997
- case "cursor":
12286
+ case "cursor": {
12287
+ const hookDir = captured(`cursor/${session.id}`)?.dir;
12288
+ if (hookDir)
12289
+ return hookDir;
11998
12290
  return session.project ? unmungeSlug(session.project, exists) : null;
12291
+ }
11999
12292
  default:
12000
12293
  return null;
12001
12294
  }
12002
12295
  };
12296
+ const repoOfDir = deps.repoOfDir ?? originRepoOfDir;
12297
+ const repoByDir = new Map;
12298
+ const readTranscript = deps.readTranscript ?? readWholeFile;
12299
+ const reflogOfDir = deps.reflogOfDir ?? headReflogOfDir;
12300
+ const currentBranch = deps.currentBranch ?? currentBranchOfDir;
12301
+ const reflogByDir = new Map;
12302
+ const currentByDir = new Map;
12303
+ const transcriptBranch = (session) => {
12304
+ if (session.harness !== "claude" && session.harness !== "codex")
12305
+ return null;
12306
+ const text = readTranscript(session.path);
12307
+ if (text === null)
12308
+ return null;
12309
+ return session.harness === "claude" ? branchFromClaudeTranscript(text) : branchFromCodexTranscript(text);
12310
+ };
12311
+ const reflogBranch = (session) => {
12312
+ const dir = resolve(session);
12313
+ const end = Date.parse(session.updated);
12314
+ if (dir === null || Number.isNaN(end))
12315
+ return null;
12316
+ let entries = reflogByDir.get(dir);
12317
+ if (!entries) {
12318
+ entries = parseReflog(reflogOfDir(dir) ?? "");
12319
+ reflogByDir.set(dir, entries);
12320
+ }
12321
+ return branchFromReflog(entries, Math.floor(end / 1000), () => {
12322
+ if (!currentByDir.has(dir))
12323
+ currentByDir.set(dir, currentBranch(dir));
12324
+ return currentByDir.get(dir) ?? null;
12325
+ });
12326
+ };
12327
+ const resolve = (session) => {
12328
+ const key = `${session.harness}/${session.id}`;
12329
+ const cached = entries[key];
12330
+ if (cached && (cached.dir !== null || cached.mtime === mtime(session.path))) {
12331
+ return cached.dir;
12332
+ }
12333
+ const dir = compute(session);
12334
+ entries[key] = { dir, mtime: mtime(session.path) };
12335
+ dirty = true;
12336
+ return dir;
12337
+ };
12003
12338
  return {
12004
12339
  cached(key) {
12005
12340
  return entries[key]?.dir ?? null;
12006
12341
  },
12007
- resolve(session) {
12008
- const key = `${session.harness}/${session.id}`;
12009
- const cached = entries[key];
12010
- if (cached && (cached.dir !== null || cached.mtime === mtime(session.path))) {
12011
- return cached.dir;
12012
- }
12013
- const dir = compute(session);
12014
- entries[key] = { dir, mtime: mtime(session.path) };
12342
+ resolve,
12343
+ resolveRepo(session) {
12344
+ const dir = resolve(session);
12345
+ if (dir === null)
12346
+ return null;
12347
+ const entry = entries[`${session.harness}/${session.id}`];
12348
+ if (entry.repo !== undefined && (entry.repo !== null || entry.mtime === mtime(session.path))) {
12349
+ return entry.repo;
12350
+ }
12351
+ if (!repoByDir.has(dir))
12352
+ repoByDir.set(dir, repoOfDir(dir));
12353
+ const repo = repoByDir.get(dir) ?? null;
12354
+ entry.repo = repo;
12355
+ entry.mtime = mtime(session.path);
12015
12356
  dirty = true;
12016
- return dir;
12357
+ return repo;
12358
+ },
12359
+ resolveBranch(session) {
12360
+ return transcriptBranch(session) ?? captured(`${session.harness}/${session.id}`)?.branch ?? reflogBranch(session);
12017
12361
  },
12018
12362
  flush() {
12019
12363
  if (!dirty)
@@ -12026,6 +12370,9 @@ function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
12026
12370
  var CACHE_FILENAME2 = "project-dirs.json", CACHE_SCHEMA_VERSION = 1, HEAD_BYTES, HEAD_LINES = 50;
12027
12371
  var init_project_dir = __esm(() => {
12028
12372
  init_config();
12373
+ init_branch();
12374
+ init_capture();
12375
+ init_repo();
12029
12376
  HEAD_BYTES = 128 * 1024;
12030
12377
  });
12031
12378
 
@@ -12766,7 +13113,7 @@ var init_queries = __esm(() => {
12766
13113
  });
12767
13114
 
12768
13115
  // src/report/digest.ts
12769
- import { readFileSync as readFileSync12 } from "node:fs";
13116
+ import { readFileSync as readFileSync13 } from "node:fs";
12770
13117
  function asRecord2(value) {
12771
13118
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
12772
13119
  }
@@ -12997,11 +13344,11 @@ function sessionToDigest(session) {
12997
13344
  try {
12998
13345
  switch (session.harness) {
12999
13346
  case "claude":
13000
- return { turns: digestClaude(readFileSync12(session.path, "utf8")) };
13347
+ return { turns: digestClaude(readFileSync13(session.path, "utf8")) };
13001
13348
  case "cursor":
13002
- return { turns: digestCursor(readFileSync12(session.path, "utf8")) };
13349
+ return { turns: digestCursor(readFileSync13(session.path, "utf8")) };
13003
13350
  case "codex":
13004
- return { turns: digestCodex(readFileSync12(session.path, "utf8")) };
13351
+ return { turns: digestCodex(readFileSync13(session.path, "utf8")) };
13005
13352
  case "opencode": {
13006
13353
  const turns = readSessionTurns(session).map((turn, index) => ({
13007
13354
  role: turn.role,
@@ -13222,17 +13569,17 @@ var init_notes = __esm(() => {
13222
13569
  });
13223
13570
 
13224
13571
  // src/report/write.ts
13225
- import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "node:fs";
13572
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "node:fs";
13226
13573
  import { tmpdir } from "node:os";
13227
- import { dirname as dirname4, join as join11, resolve } from "node:path";
13574
+ import { dirname as dirname4, join as join12, resolve } from "node:path";
13228
13575
  import { pathToFileURL } from "node:url";
13229
13576
  function defaultReportPath() {
13230
- return join11(tmpdir(), "dosu-knowledge-report.html");
13577
+ return join12(tmpdir(), "dosu-knowledge-report.html");
13231
13578
  }
13232
13579
  async function writeAndOpenReport(options) {
13233
13580
  const out = resolve(options.out ?? defaultReportPath());
13234
- mkdirSync8(dirname4(out), { recursive: true });
13235
- writeFileSync8(out, options.html, "utf8");
13581
+ mkdirSync9(dirname4(out), { recursive: true });
13582
+ writeFileSync9(out, options.html, "utf8");
13236
13583
  if (options.open !== false) {
13237
13584
  const url = pathToFileURL(out).href;
13238
13585
  if (options.openUrl) {
@@ -13247,7 +13594,7 @@ async function writeAndOpenReport(options) {
13247
13594
  var init_write = () => {};
13248
13595
 
13249
13596
  // src/report/generate.ts
13250
- import { basename as basename2 } from "node:path";
13597
+ import { basename as basename3 } from "node:path";
13251
13598
  function sessionsForNotes(notes, sessions) {
13252
13599
  const ids = new Set(notes.map((n) => n.transcript_id).filter((id) => Boolean(id)));
13253
13600
  return sessions.filter((s) => ids.has(s.id));
@@ -13256,7 +13603,7 @@ function defaultProjectName() {
13256
13603
  const resolver = createProjectDirResolver();
13257
13604
  return (session) => {
13258
13605
  const dir = resolver.resolve(session);
13259
- return dir ? basename2(dir) : null;
13606
+ return dir ? basename3(dir) : null;
13260
13607
  };
13261
13608
  }
13262
13609
  function noteTime(note) {
@@ -13309,12 +13656,11 @@ var init_generate = __esm(() => {
13309
13656
  function listSessionBacklog() {
13310
13657
  try {
13311
13658
  const state = loadSyncState();
13312
- let sessions = scanAgentSessions({});
13313
- if (state.project_filter?.length) {
13314
- const resolver = createProjectDirResolver();
13315
- sessions = filterSessionsByProject(sessions, state.project_filter, resolver.resolve);
13316
- resolver.flush();
13317
- }
13659
+ const scanned = scanAgentSessions({});
13660
+ const resolver = createProjectDirResolver();
13661
+ const filter = studyRepoFilter(state, () => scanned, resolver);
13662
+ const sessions = filterSessionsByRepo(scanned, filter, resolver.resolveRepo);
13663
+ resolver.flush();
13318
13664
  const gate = gateSessions(sessions, state.watermark);
13319
13665
  const { kept, skipped } = partitionIncognitoSessions(gate.ready);
13320
13666
  return { queued: kept.reverse(), open: gate.open.reverse(), incognito: skipped.reverse() };
@@ -13330,8 +13676,8 @@ var init_backlog = __esm(() => {
13330
13676
  });
13331
13677
 
13332
13678
  // src/sync/lock.ts
13333
- import { existsSync as existsSync12, readFileSync as readFileSync13, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync9 } from "node:fs";
13334
- import { join as join12 } from "node:path";
13679
+ import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
13680
+ import { join as join13 } from "node:path";
13335
13681
  function processAlive(pid) {
13336
13682
  try {
13337
13683
  process.kill(pid, 0);
@@ -13341,7 +13687,7 @@ function processAlive(pid) {
13341
13687
  }
13342
13688
  }
13343
13689
  function lockPath(configDir = getConfigDir()) {
13344
- return join12(configDir, LOCK_FILENAME);
13690
+ return join13(configDir, LOCK_FILENAME);
13345
13691
  }
13346
13692
  function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
13347
13693
  if (!Number.isInteger(pid) || pid <= 0)
@@ -13358,7 +13704,7 @@ function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(p
13358
13704
  }
13359
13705
  try {
13360
13706
  const path = lockPath(configDir);
13361
- if (existsSync12(path) && readFileSync13(path, "utf8") === String(pid)) {
13707
+ if (existsSync13(path) && readFileSync14(path, "utf8") === String(pid)) {
13362
13708
  rmSync2(path, { force: true });
13363
13709
  }
13364
13710
  } catch {}
@@ -13369,7 +13715,7 @@ function fileLock(configDir = getConfigDir(), now = () => new Date) {
13369
13715
  let held = false;
13370
13716
  const tryCreate = () => {
13371
13717
  try {
13372
- writeFileSync9(path, String(process.pid), { flag: "wx" });
13718
+ writeFileSync10(path, String(process.pid), { flag: "wx" });
13373
13719
  return true;
13374
13720
  } catch {
13375
13721
  return false;
@@ -13383,7 +13729,7 @@ function fileLock(configDir = getConfigDir(), now = () => new Date) {
13383
13729
  }
13384
13730
  try {
13385
13731
  const age = now().getTime() - statSync5(path).mtimeMs;
13386
- const holder = Number.parseInt(readFileSync13(path, "utf8"), 10);
13732
+ const holder = Number.parseInt(readFileSync14(path, "utf8"), 10);
13387
13733
  const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
13388
13734
  if (age > STALE_LOCK_MS || holderDead) {
13389
13735
  rmSync2(path, { force: true });
@@ -13398,7 +13744,7 @@ function fileLock(configDir = getConfigDir(), now = () => new Date) {
13398
13744
  return;
13399
13745
  held = false;
13400
13746
  try {
13401
- if (existsSync12(path) && readFileSync13(path, "utf8") === String(process.pid)) {
13747
+ if (existsSync13(path) && readFileSync14(path, "utf8") === String(process.pid)) {
13402
13748
  rmSync2(path, { force: true });
13403
13749
  }
13404
13750
  } catch {}
@@ -13412,7 +13758,7 @@ var init_lock = __esm(() => {
13412
13758
  });
13413
13759
 
13414
13760
  // src/sync/status.ts
13415
- import { readFileSync as readFileSync14, statSync as statSync6 } from "node:fs";
13761
+ import { readFileSync as readFileSync15, statSync as statSync6 } from "node:fs";
13416
13762
  function formatTokenCount(tokens) {
13417
13763
  if (tokens < 1000)
13418
13764
  return String(tokens);
@@ -13435,7 +13781,7 @@ function defaultIsProcessAlive2(pid) {
13435
13781
  }
13436
13782
  function defaultReadLog() {
13437
13783
  try {
13438
- return readFileSync14(logger.getLogPath(), "utf-8");
13784
+ return readFileSync15(logger.getLogPath(), "utf-8");
13439
13785
  } catch {
13440
13786
  return "";
13441
13787
  }
@@ -13443,7 +13789,7 @@ function defaultReadLog() {
13443
13789
  function readLockFile(configDir) {
13444
13790
  const path = lockPath(configDir);
13445
13791
  try {
13446
- const pid = Number.parseInt(readFileSync14(path, "utf-8"), 10);
13792
+ const pid = Number.parseInt(readFileSync15(path, "utf-8"), 10);
13447
13793
  return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync6(path).mtime };
13448
13794
  } catch {
13449
13795
  return null;
@@ -13535,24 +13881,33 @@ async function runKnowledgeSync(options = {}) {
13535
13881
  }
13536
13882
  let ready;
13537
13883
  let open;
13884
+ let branchOf;
13538
13885
  try {
13539
13886
  const listSessions = deps.listSessions ?? (() => options.bootstrap ? scanAgentSessions({}) : scanAgentSessions({
13540
13887
  since: new Date(now().getTime() - GATE_WINDOW_DAYS * 24 * 60 * 60 * 1000),
13541
13888
  limit: GATE_WINDOW
13542
13889
  }));
13543
- let sessions = await listSessions();
13544
- if (state.project_filter?.length) {
13545
- let resolve = deps.resolveProjectDir;
13546
- let flush;
13547
- if (!resolve) {
13548
- const resolver = createProjectDirResolver();
13549
- resolve = resolver.resolve;
13550
- flush = resolver.flush;
13551
- }
13552
- sessions = filterSessionsByProject(sessions, state.project_filter, resolve);
13553
- flush?.();
13554
- logger.debug("sync", `project filter active: ${state.project_filter.join(", ")}`);
13555
- }
13890
+ const scanned = await listSessions();
13891
+ let flush;
13892
+ let locator = deps.locator;
13893
+ let resolveBranch = deps.resolveBranch;
13894
+ if (!locator || !resolveBranch) {
13895
+ const resolver = createProjectDirResolver();
13896
+ locator ??= resolver;
13897
+ resolveBranch ??= resolver.resolveBranch;
13898
+ flush = resolver.flush;
13899
+ }
13900
+ branchOf = resolveBranch;
13901
+ const repoFilter = studyRepoFilter(state, () => scanAgentSessions({}), locator);
13902
+ if (state.project_filter) {
13903
+ delete state.project_filter;
13904
+ if (repoFilter)
13905
+ state.repo_filter = repoFilter;
13906
+ logger.debug("sync", `folder scope converted to repos: ${repoFilter?.join(", ") || "none"}`);
13907
+ }
13908
+ const sessions = filterSessionsByRepo(scanned, repoFilter, (s) => locator.resolveRepo(s));
13909
+ flush?.();
13910
+ logger.debug("sync", `study scope ${repoFilter ? repoFilter.join(", ") || "none" : "all repos"}: ${sessions.length} of ${scanned.length} sessions in scope`);
13556
13911
  ({ ready, open } = gateSessions(sessions, state.watermark, now()));
13557
13912
  logGateResult(ready, open.length, state.watermark);
13558
13913
  } catch (err) {
@@ -13611,10 +13966,11 @@ async function runKnowledgeSync(options = {}) {
13611
13966
  } else if (isIncognito(candidate)) {
13612
13967
  incognito += 1;
13613
13968
  logger.debug("sync", `skipping incognito session ${candidate.harness}/${candidate.id}`);
13614
- } else if (worthStudying(candidate)) {
13615
- batch.push(candidate);
13616
- } else {
13969
+ } else if (!worthStudying(candidate)) {
13617
13970
  trivial += 1;
13971
+ } else {
13972
+ const branch = candidate.repo ? branchOf(candidate) : null;
13973
+ batch.push(branch ? { ...candidate, branch } : candidate);
13618
13974
  }
13619
13975
  }
13620
13976
  const skippedNote = `${trivial} trivial, ${incognito} incognito${alreadyStudied > 0 ? `, ${alreadyStudied} already studied` : ""} skipped`;
@@ -13742,7 +14098,7 @@ var init_sync = __esm(() => {
13742
14098
  });
13743
14099
 
13744
14100
  // src/learner/conflicts.ts
13745
- import { existsSync as existsSync13, readFileSync as readFileSync15 } from "node:fs";
14101
+ import { existsSync as existsSync14, readFileSync as readFileSync16 } from "node:fs";
13746
14102
  function managedSettingsPaths(platform = process.platform) {
13747
14103
  switch (platform) {
13748
14104
  case "darwin":
@@ -13771,11 +14127,11 @@ function conflictingKeysIn(settings) {
13771
14127
  function detectSettingsConflicts(paths = managedSettingsPaths()) {
13772
14128
  const conflicts = [];
13773
14129
  for (const file of paths) {
13774
- if (!existsSync13(file))
14130
+ if (!existsSync14(file))
13775
14131
  continue;
13776
14132
  let settings;
13777
14133
  try {
13778
- settings = JSON.parse(readFileSync15(file, "utf8"));
14134
+ settings = JSON.parse(readFileSync16(file, "utf8"));
13779
14135
  } catch {
13780
14136
  conflicts.push({ file, keys: [UNREADABLE_SETTINGS_KEY] });
13781
14137
  continue;
@@ -13800,11 +14156,11 @@ var init_conflicts = __esm(() => {
13800
14156
  });
13801
14157
 
13802
14158
  // src/telemetry/debug-id.ts
13803
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "097dc848-8855-154b-6475-6e2164756e21";
14159
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "3b9a1619-fdbd-ebdd-6475-6e2164756e21";
13804
14160
 
13805
14161
  // src/telemetry/telemetry.ts
13806
14162
  import { randomUUID as randomUUID2 } from "node:crypto";
13807
- import { existsSync as existsSync14 } from "node:fs";
14163
+ import { existsSync as existsSync15 } from "node:fs";
13808
14164
  import { request as httpRequest2 } from "node:http";
13809
14165
  import { request as httpsRequest } from "node:https";
13810
14166
  import { isAbsolute, relative, resolve as resolve2, sep } from "node:path";
@@ -13942,7 +14298,7 @@ function parseOwnedStackLine(originalLine, packageRoot) {
13942
14298
  return;
13943
14299
  }
13944
14300
  try {
13945
- if (!existsSync14(resolvedPath))
14301
+ if (!existsSync15(resolvedPath))
13946
14302
  return;
13947
14303
  } catch {
13948
14304
  return;
@@ -14825,9 +15181,9 @@ var init_agent_select = __esm(() => {
14825
15181
  });
14826
15182
 
14827
15183
  // src/incognito/agents.ts
14828
- import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync2, writeFileSync as writeFileSync10 } from "node:fs";
15184
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync17, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
14829
15185
  import { homedir as homedir4 } from "node:os";
14830
- import { dirname as dirname5, join as join13 } from "node:path";
15186
+ import { dirname as dirname5, join as join14 } from "node:path";
14831
15187
  function withFrontmatter(body) {
14832
15188
  return `---
14833
15189
  description: ${DESCRIPTION}
@@ -14836,10 +15192,10 @@ description: ${DESCRIPTION}
14836
15192
  ${body}`;
14837
15193
  }
14838
15194
  function claudeConfigDir2() {
14839
- return process.env.CLAUDE_CONFIG_DIR || join13(homedir4(), ".claude");
15195
+ return process.env.CLAUDE_CONFIG_DIR || join14(homedir4(), ".claude");
14840
15196
  }
14841
15197
  function codexHome2() {
14842
- return process.env.CODEX_HOME || join13(homedir4(), ".codex");
15198
+ return process.env.CODEX_HOME || join14(homedir4(), ".codex");
14843
15199
  }
14844
15200
  function fileAgent(options) {
14845
15201
  const { commandPath, content } = options;
@@ -14850,29 +15206,29 @@ function fileAgent(options) {
14850
15206
  commandPath,
14851
15207
  isEnabled: () => {
14852
15208
  const path = commandPath();
14853
- if (!existsSync15(path))
15209
+ if (!existsSync16(path))
14854
15210
  return false;
14855
15211
  try {
14856
- return readFileSync16(path, "utf-8").includes(INCOGNITO_MARKER);
15212
+ return readFileSync17(path, "utf-8").includes(INCOGNITO_MARKER);
14857
15213
  } catch {
14858
15214
  return false;
14859
15215
  }
14860
15216
  },
14861
15217
  enable: () => {
14862
15218
  const path = commandPath();
14863
- if (existsSync15(path)) {
14864
- if (readFileSync16(path, "utf-8") === content)
15219
+ if (existsSync16(path)) {
15220
+ if (readFileSync17(path, "utf-8") === content)
14865
15221
  return "unchanged";
14866
- writeFileSync10(path, content, "utf-8");
15222
+ writeFileSync11(path, content, "utf-8");
14867
15223
  return "updated";
14868
15224
  }
14869
- mkdirSync9(dirname5(path), { recursive: true });
14870
- writeFileSync10(path, content, "utf-8");
15225
+ mkdirSync10(dirname5(path), { recursive: true });
15226
+ writeFileSync11(path, content, "utf-8");
14871
15227
  return "created";
14872
15228
  },
14873
15229
  disable: () => {
14874
15230
  const path = commandPath();
14875
- if (!existsSync15(path))
15231
+ if (!existsSync16(path))
14876
15232
  return "not_found";
14877
15233
  unlinkSync2(path);
14878
15234
  return "removed";
@@ -14885,21 +15241,21 @@ function allIncognitoAgents() {
14885
15241
  id: "claude",
14886
15242
  name: "Claude Code",
14887
15243
  detectPath: claudeConfigDir2,
14888
- commandPath: () => join13(claudeConfigDir2(), "commands", FILE_NAME),
15244
+ commandPath: () => join14(claudeConfigDir2(), "commands", FILE_NAME),
14889
15245
  content: withFrontmatter(INCOGNITO_COMMAND_BODY)
14890
15246
  }),
14891
15247
  fileAgent({
14892
15248
  id: "cursor",
14893
15249
  name: "Cursor",
14894
- detectPath: () => join13(homedir4(), ".cursor"),
14895
- commandPath: () => join13(homedir4(), ".cursor", "commands", FILE_NAME),
15250
+ detectPath: () => join14(homedir4(), ".cursor"),
15251
+ commandPath: () => join14(homedir4(), ".cursor", "commands", FILE_NAME),
14896
15252
  content: INCOGNITO_COMMAND_BODY
14897
15253
  }),
14898
15254
  fileAgent({
14899
15255
  id: "codex",
14900
15256
  name: "Codex",
14901
15257
  detectPath: codexHome2,
14902
- commandPath: () => join13(codexHome2(), "prompts", FILE_NAME),
15258
+ commandPath: () => join14(codexHome2(), "prompts", FILE_NAME),
14903
15259
  content: withFrontmatter(INCOGNITO_COMMAND_BODY)
14904
15260
  })
14905
15261
  ];
@@ -14983,7 +15339,7 @@ var init_knowledge_incognito = __esm(() => {
14983
15339
 
14984
15340
  // src/statusline/agents.ts
14985
15341
  import { homedir as homedir5 } from "node:os";
14986
- import { join as join14 } from "node:path";
15342
+ import { join as join15 } from "node:path";
14987
15343
  function statuslineCommand(agentId) {
14988
15344
  if (process.env.DOSU_DEV !== "true")
14989
15345
  return `dosu ${RENDER_ARGS} ${agentId}`;
@@ -14993,7 +15349,7 @@ function isDosuStatuslineCommand(command) {
14993
15349
  return typeof command === "string" && command.includes(RENDER_ARGS);
14994
15350
  }
14995
15351
  function claudeConfigDir3() {
14996
- return process.env.CLAUDE_CONFIG_DIR || join14(homedir5(), ".claude");
15352
+ return process.env.CLAUDE_CONFIG_DIR || join15(homedir5(), ".claude");
14997
15353
  }
14998
15354
  function statuslineOf(config) {
14999
15355
  const value = config.statusLine;
@@ -15034,7 +15390,7 @@ function allStatuslineAgents() {
15034
15390
  id: "claude",
15035
15391
  name: "Claude Code",
15036
15392
  detectPath: claudeConfigDir3,
15037
- configPath: () => join14(claudeConfigDir3(), "settings.json")
15393
+ configPath: () => join15(claudeConfigDir3(), "settings.json")
15038
15394
  }),
15039
15395
  configAgent({
15040
15396
  id: "cursor",
@@ -15299,12 +15655,12 @@ var init_backfill_run = __esm(() => {
15299
15655
  });
15300
15656
 
15301
15657
  // src/learner/config-dir.ts
15302
- import { mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync11 } from "node:fs";
15658
+ import { mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync12 } from "node:fs";
15303
15659
  import { tmpdir as tmpdir2 } from "node:os";
15304
- import { join as join15 } from "node:path";
15660
+ import { join as join16 } from "node:path";
15305
15661
  function createRunConfigDir() {
15306
- const path = mkdtempSync(join15(tmpdir2(), "dosu-learner-"));
15307
- writeFileSync11(join15(path, ".claude.json"), JSON.stringify({ hasCompletedOnboarding: true }));
15662
+ const path = mkdtempSync(join16(tmpdir2(), "dosu-learner-"));
15663
+ writeFileSync12(join16(path, ".claude.json"), JSON.stringify({ hasCompletedOnboarding: true }));
15308
15664
  return {
15309
15665
  path,
15310
15666
  cleanup() {
@@ -15352,10 +15708,10 @@ var init_env = __esm(() => {
15352
15708
  });
15353
15709
 
15354
15710
  // src/learner/executable.ts
15355
- import { accessSync, constants as constants2, existsSync as existsSync16 } from "node:fs";
15711
+ import { accessSync, constants as constants2, existsSync as existsSync17 } from "node:fs";
15356
15712
  import { createRequire as createRequire3 } from "node:module";
15357
15713
  import { homedir as homedir6 } from "node:os";
15358
- import { delimiter as delimiter2, dirname as dirname6, join as join16 } from "node:path";
15714
+ import { delimiter as delimiter2, dirname as dirname6, join as join17 } from "node:path";
15359
15715
  function binaryNames(platform = process.platform) {
15360
15716
  return platform === "win32" ? ["claude.exe", "claude.cmd"] : ["claude"];
15361
15717
  }
@@ -15364,7 +15720,7 @@ function sdkNativeBinaryExists() {
15364
15720
  const requireRuntime = createRequire3(import.meta.url);
15365
15721
  const pkg = `@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}`;
15366
15722
  const pkgDir = dirname6(requireRuntime.resolve(`${pkg}/package.json`));
15367
- return binaryNames().some((name) => existsSync16(join16(pkgDir, name)));
15723
+ return binaryNames().some((name) => existsSync17(join17(pkgDir, name)));
15368
15724
  } catch {
15369
15725
  return false;
15370
15726
  }
@@ -15380,10 +15736,10 @@ function isExecutable(path) {
15380
15736
  function findSystemClaude(env = process.env, homeDir = homedir6()) {
15381
15737
  const names = binaryNames();
15382
15738
  const dirs = (env.PATH ?? "").split(delimiter2).filter(Boolean);
15383
- dirs.push(join16(homeDir, ".local", "bin"), join16(homeDir, ".claude", "local"));
15739
+ dirs.push(join17(homeDir, ".local", "bin"), join17(homeDir, ".claude", "local"));
15384
15740
  for (const dir of dirs) {
15385
15741
  for (const name of names) {
15386
- const candidate = join16(dir, name);
15742
+ const candidate = join17(dir, name);
15387
15743
  if (isExecutable(candidate))
15388
15744
  return candidate;
15389
15745
  }
@@ -15477,9 +15833,8 @@ note cap are the volume guards.
15477
15833
  5. Title is a noun-phrase topic (like "page_version UniqueViolation race"), not a sentence.
15478
15834
  Content is a self-contained observation in plain language; include file/path pointers when
15479
15835
  useful.
15480
- 6. Only pass repo/branch to write_knowledge when the session itself verifies them (an explicit
15481
- cwd, git remote, or branch mentioned in the transcript). Never infer or guess a repo. When not
15482
- verified, omit both.
15836
+ 6. Never pass repo or branch to write_knowledge; the client attaches each note's repo from the
15837
+ session it came from.
15483
15838
  7. Never quote credentials, tokens, or secrets — even redacted placeholders — and never include
15484
15839
  long verbatim transcript spans. Summarize in your own words.
15485
15840
  8. A trivial session with no real user query is normal: skip it silently.`;
@@ -58494,6 +58849,8 @@ async function runLearner(options) {
58494
58849
  let currentSession;
58495
58850
  const readsSinceWrite = new Set;
58496
58851
  const sessionKeys = new Map(options.sessions.map((s) => [s.id, `${s.harness}/${s.id}`]));
58852
+ const sessionRepos = new Map(options.sessions.map((s) => [s.id, s.repo]));
58853
+ const sessionBranches = new Map(options.sessions.map((s) => [s.id, s.branch]));
58497
58854
  const notedSessions = new Set;
58498
58855
  const pendingNotes = new Map;
58499
58856
  let turns = 0;
@@ -58572,15 +58929,32 @@ async function runLearner(options) {
58572
58929
  message: "Write each session's notes right after reading THAT session, before reading the next. You have read multiple sessions without writing, so a note cannot be attributed to one. Re-read only the session this note is about, then write it."
58573
58930
  };
58574
58931
  }
58932
+ const noted = currentSession && sessionKeys.get(currentSession);
58933
+ if (!currentSession || !noted) {
58934
+ return {
58935
+ behavior: "deny",
58936
+ message: "Read the session this note is about with read_session first, then write it."
58937
+ };
58938
+ }
58575
58939
  notesWritten += 1;
58576
58940
  readsSinceWrite.clear();
58577
- const noted = currentSession && sessionKeys.get(currentSession);
58578
- if (noted)
58579
- pendingNotes.set(toolUseID, noted);
58580
- const { transcript_id: _authoredByModel, ...clean } = input;
58941
+ pendingNotes.set(toolUseID, noted);
58942
+ const {
58943
+ transcript_id: _transcriptByModel,
58944
+ repo: _repoByModel,
58945
+ branch: _branchByModel,
58946
+ ...clean
58947
+ } = input;
58948
+ const repo = sessionRepos.get(currentSession);
58949
+ const branch = repo && sessionBranches.get(currentSession);
58581
58950
  return {
58582
58951
  behavior: "allow",
58583
- updatedInput: currentSession ? { ...clean, transcript_id: currentSession } : clean
58952
+ updatedInput: {
58953
+ ...clean,
58954
+ transcript_id: currentSession,
58955
+ ...repo ? { repo } : {},
58956
+ ...branch ? { branch } : {}
58957
+ }
58584
58958
  };
58585
58959
  }
58586
58960
  return { behavior: "allow", updatedInput: input };
@@ -58669,9 +59043,8 @@ var init_runner = __esm(() => {
58669
59043
  });
58670
59044
 
58671
59045
  // src/commands/knowledge.ts
58672
- import { existsSync as existsSync18 } from "node:fs";
58673
- import { homedir as homedir7 } from "node:os";
58674
- import { delimiter as delimiter4, join as join21 } from "node:path";
59046
+ import { existsSync as existsSync19 } from "node:fs";
59047
+ import { delimiter as delimiter4, join as join22 } from "node:path";
58675
59048
  function requireConfig7() {
58676
59049
  const cfg = requireLoginConfig();
58677
59050
  if (!cfg.active_account?.target?.org_id || !cfg.active_account?.target?.space_id) {
@@ -58791,6 +59164,7 @@ ${results.length - opts.limit} more results not shown.`));
58791
59164
  return;
58792
59165
  }
58793
59166
  if (opts.detach) {
59167
+ await captureHookSession();
58794
59168
  const spawned = spawnDetachedSelf([
58795
59169
  "knowledge",
58796
59170
  "sync",
@@ -58938,10 +59312,11 @@ function printSyncStatus(status, now = new Date) {
58938
59312
  }
58939
59313
  const wm = status.state.watermark;
58940
59314
  console.log(` Studied through: ${wm ? `${wm} (${formatAge(wm, now)})` : "nothing studied yet"}`);
58941
- if (status.state.project_filter?.length) {
58942
- const home = homedir7();
58943
- const scope = status.state.project_filter.map((dir) => dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir).join(", ");
58944
- console.log(` Study scope: ${scope}`);
59315
+ const repoFilter = status.state.repo_filter;
59316
+ if (repoFilter) {
59317
+ console.log(` Study scope: ${repoFilter.length ? repoFilter.map(displayRepo).join(", ") : "no repos"}`);
59318
+ } else if (status.state.project_filter?.length) {
59319
+ console.log(` Study scope: ${status.state.project_filter.length} folders (converted to repos on the next sync)`);
58945
59320
  }
58946
59321
  if ((status.state.total_notes ?? 0) > 0) {
58947
59322
  const tokens = status.state.total_learning_tokens ?? 0;
@@ -59094,7 +59469,7 @@ function reportHookFailure(agent, err) {
59094
59469
  }
59095
59470
  function dosuOnPath() {
59096
59471
  const bin = process.platform === "win32" ? "dosu.cmd" : "dosu";
59097
- return (process.env.PATH ?? "").split(delimiter4).some((dir) => dir !== "" && existsSync18(join21(dir, bin)));
59472
+ return (process.env.PATH ?? "").split(delimiter4).some((dir) => dir !== "" && existsSync19(join22(dir, bin)));
59098
59473
  }
59099
59474
  var import_picocolors21;
59100
59475
  var init_knowledge = __esm(() => {
@@ -59104,6 +59479,8 @@ var init_knowledge = __esm(() => {
59104
59479
  init_agents();
59105
59480
  init_formats();
59106
59481
  init_generate();
59482
+ init_capture();
59483
+ init_repo();
59107
59484
  init_backlog();
59108
59485
  init_detach();
59109
59486
  init_status();
@@ -59558,7 +59935,7 @@ var init_time_range = __esm(() => {
59558
59935
  });
59559
59936
 
59560
59937
  // src/commands/review.ts
59561
- import { readFileSync as readFileSync18 } from "node:fs";
59938
+ import { readFileSync as readFileSync19 } from "node:fs";
59562
59939
  function requireConfig10() {
59563
59940
  return requireLoginConfig();
59564
59941
  }
@@ -59746,7 +60123,7 @@ function reviewCommand() {
59746
60123
  let body = opts.body;
59747
60124
  if (opts.bodyFile) {
59748
60125
  try {
59749
- body = readFileSync18(opts.bodyFile, "utf-8");
60126
+ body = readFileSync19(opts.bodyFile, "utf-8");
59750
60127
  } catch (err) {
59751
60128
  console.error(import_picocolors25.default.red(`Failed to read --body-file: ${err.message}`));
59752
60129
  process.exit(1);
@@ -60666,16 +61043,16 @@ The coding agent performs triage; Dosu cloud generates docs and opens the PR.
60666
61043
  // src/commands/skill.ts
60667
61044
  import {
60668
61045
  cpSync,
60669
- existsSync as existsSync19,
61046
+ existsSync as existsSync20,
60670
61047
  lstatSync as lstatSync2,
60671
- mkdirSync as mkdirSync11,
60672
- readFileSync as readFileSync19,
61048
+ mkdirSync as mkdirSync12,
61049
+ readFileSync as readFileSync20,
60673
61050
  rmSync as rmSync5,
60674
61051
  symlinkSync,
60675
- writeFileSync as writeFileSync12
61052
+ writeFileSync as writeFileSync13
60676
61053
  } from "node:fs";
60677
- import { homedir as homedir8 } from "node:os";
60678
- import { dirname as dirname10, join as join22, relative as relative3 } from "node:path";
61054
+ import { homedir as homedir7 } from "node:os";
61055
+ import { dirname as dirname10, join as join23, relative as relative3 } from "node:path";
60679
61056
  function skillAgentIDsForProviders(providerIDs) {
60680
61057
  return [
60681
61058
  ...new Set(providerIDs.map((providerID) => SKILL_AGENT_BY_PROVIDER[providerID]).filter((agent) => Boolean(agent)))
@@ -60685,15 +61062,15 @@ function isSkillAgentID(agent) {
60685
61062
  return SUPPORTED_SKILL_AGENTS.includes(agent);
60686
61063
  }
60687
61064
  function universalSkillsDir() {
60688
- return join22(homedir8(), ".agents", "skills");
61065
+ return join23(homedir7(), ".agents", "skills");
60689
61066
  }
60690
61067
  function linkedSkillsDir(agent) {
60691
61068
  if (agent === "claude-code") {
60692
- const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join22(homedir8(), ".claude");
60693
- return join22(claudeConfigDir, "skills");
61069
+ const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join23(homedir7(), ".claude");
61070
+ return join23(claudeConfigDir, "skills");
60694
61071
  }
60695
61072
  if (agent === "windsurf")
60696
- return join22(homedir8(), ".codeium", "windsurf", "skills");
61073
+ return join23(homedir7(), ".codeium", "windsurf", "skills");
60697
61074
  return null;
60698
61075
  }
60699
61076
  function skillInstallTargetForProvider(providerID) {
@@ -60702,18 +61079,18 @@ function skillInstallTargetForProvider(providerID) {
60702
61079
  return null;
60703
61080
  const linked = linkedSkillsDir(agentID);
60704
61081
  if (linked)
60705
- return { path: join22(linked, SKILL_NAME), symlink: true };
60706
- return { path: join22(universalSkillsDir(), SKILL_NAME), symlink: false };
61082
+ return { path: join23(linked, SKILL_NAME), symlink: true };
61083
+ return { path: join23(universalSkillsDir(), SKILL_NAME), symlink: false };
60707
61084
  }
60708
61085
  function installStatePath() {
60709
- return join22(getConfigDir(), INSTALL_STATE_FILENAME);
61086
+ return join23(getConfigDir(), INSTALL_STATE_FILENAME);
60710
61087
  }
60711
61088
  function readSkillInstallState() {
60712
61089
  try {
60713
61090
  const path = installStatePath();
60714
- if (!existsSync19(path))
61091
+ if (!existsSync20(path))
60715
61092
  return null;
60716
- const data = JSON.parse(readFileSync19(path, "utf-8"));
61093
+ const data = JSON.parse(readFileSync20(path, "utf-8"));
60717
61094
  if (typeof data?.version === "string" && Array.isArray(data.agents) && data.agents.every((agent) => typeof agent === "string") && typeof data.installedAt === "number") {
60718
61095
  return { version: data.version, agents: data.agents, installedAt: data.installedAt };
60719
61096
  }
@@ -60725,9 +61102,9 @@ function readSkillInstallState() {
60725
61102
  function writeSkillInstallState(state) {
60726
61103
  try {
60727
61104
  const dir = getConfigDir();
60728
- if (!existsSync19(dir))
60729
- mkdirSync11(dir, { recursive: true, mode: 448 });
60730
- writeFileSync12(installStatePath(), JSON.stringify(state), { mode: 384 });
61105
+ if (!existsSync20(dir))
61106
+ mkdirSync12(dir, { recursive: true, mode: 448 });
61107
+ writeFileSync13(installStatePath(), JSON.stringify(state), { mode: 384 });
60731
61108
  } catch (err) {
60732
61109
  logger.debug("skill", `Could not record skill install state: ${err}`);
60733
61110
  }
@@ -60736,11 +61113,11 @@ function clearSkillInstallState() {
60736
61113
  rmSync5(installStatePath(), { force: true });
60737
61114
  }
60738
61115
  function pruneLegacySkillLock() {
60739
- const lockPath = join22(homedir8(), ".agents", ".skill-lock.json");
61116
+ const lockPath = join23(homedir7(), ".agents", ".skill-lock.json");
60740
61117
  try {
60741
- if (!existsSync19(lockPath))
61118
+ if (!existsSync20(lockPath))
60742
61119
  return [];
60743
- const lock = JSON.parse(readFileSync19(lockPath, "utf-8"));
61120
+ const lock = JSON.parse(readFileSync20(lockPath, "utf-8"));
60744
61121
  const skills = lock?.skills;
60745
61122
  if (!skills || typeof skills !== "object")
60746
61123
  return [];
@@ -60749,7 +61126,7 @@ function pruneLegacySkillLock() {
60749
61126
  return [];
60750
61127
  for (const name of legacy)
60751
61128
  delete skills[name];
60752
- writeFileSync12(lockPath, `${JSON.stringify(lock, null, 2)}
61129
+ writeFileSync13(lockPath, `${JSON.stringify(lock, null, 2)}
60753
61130
  `);
60754
61131
  logger.debug("skill", `Removed legacy lock entries: ${legacy.join(", ")}`);
60755
61132
  return legacy;
@@ -60769,13 +61146,13 @@ function pathExists(path) {
60769
61146
  function writeSkillDir(skill, dir) {
60770
61147
  rmSync5(dir, { recursive: true, force: true });
60771
61148
  for (const file of skill.files) {
60772
- const target = join22(dir, ...file.path.split("/"));
60773
- mkdirSync11(dirname10(target), { recursive: true });
60774
- writeFileSync12(target, file.content, { mode: file.executable ? 493 : 420 });
61149
+ const target = join23(dir, ...file.path.split("/"));
61150
+ mkdirSync12(dirname10(target), { recursive: true });
61151
+ writeFileSync13(target, file.content, { mode: file.executable ? 493 : 420 });
60775
61152
  }
60776
61153
  }
60777
61154
  function linkSkillDir(linkPath, targetDir) {
60778
- mkdirSync11(dirname10(linkPath), { recursive: true });
61155
+ mkdirSync12(dirname10(linkPath), { recursive: true });
60779
61156
  rmSync5(linkPath, { recursive: true, force: true });
60780
61157
  try {
60781
61158
  symlinkSync(relative3(dirname10(linkPath), targetDir), linkPath, "dir");
@@ -60808,15 +61185,15 @@ function installBundledSkills(agentIDs) {
60808
61185
  if (bundledNames.has(name))
60809
61186
  continue;
60810
61187
  for (const dir of [universalSkillsDir(), ...linkDirs])
60811
- removeSkillDir(join22(dir, name));
61188
+ removeSkillDir(join23(dir, name));
60812
61189
  }
60813
61190
  const paths = [];
60814
61191
  for (const skill of BUNDLED_SKILLS) {
60815
- const universal = join22(universalSkillsDir(), skill.name);
61192
+ const universal = join23(universalSkillsDir(), skill.name);
60816
61193
  writeSkillDir(skill, universal);
60817
61194
  paths.push(universal);
60818
61195
  for (const dir of linkDirs) {
60819
- const linkPath = join22(dir, skill.name);
61196
+ const linkPath = join23(dir, skill.name);
60820
61197
  linkSkillDir(linkPath, universal);
60821
61198
  paths.push(linkPath);
60822
61199
  }
@@ -60827,7 +61204,7 @@ function installBundledSkills(agentIDs) {
60827
61204
  agents: [...new Set([...previous?.agents ?? [], ...agents])],
60828
61205
  installedAt: Date.now()
60829
61206
  });
60830
- rmSync5(join22(getConfigDir(), LEGACY_CACHE_FILENAME), { force: true });
61207
+ rmSync5(join23(getConfigDir(), LEGACY_CACHE_FILENAME), { force: true });
60831
61208
  logger.info("skill", `Installed bundled skills v${VERSION} for ${agents.join(", ")}`);
60832
61209
  return { success: true, version: VERSION, paths };
60833
61210
  } catch (err) {
@@ -60849,13 +61226,13 @@ function removeSkills() {
60849
61226
  const removed = [];
60850
61227
  for (const dir of dirs) {
60851
61228
  for (const name of names) {
60852
- const path = join22(dir, name);
61229
+ const path = join23(dir, name);
60853
61230
  if (removeSkillDir(path))
60854
61231
  removed.push(path);
60855
61232
  }
60856
61233
  }
60857
61234
  clearSkillInstallState();
60858
- rmSync5(join22(getConfigDir(), LEGACY_CACHE_FILENAME), { force: true });
61235
+ rmSync5(join23(getConfigDir(), LEGACY_CACHE_FILENAME), { force: true });
60859
61236
  return removed;
60860
61237
  }
60861
61238
  function printPaths(paths) {
@@ -61210,17 +61587,17 @@ var init_sources = __esm(() => {
61210
61587
  // src/telemetry/settings.ts
61211
61588
  import { randomUUID as randomUUID4 } from "node:crypto";
61212
61589
  import {
61213
- existsSync as existsSync20,
61590
+ existsSync as existsSync21,
61214
61591
  lstatSync as lstatSync3,
61215
- mkdirSync as mkdirSync12,
61216
- readFileSync as readFileSync20,
61217
- renameSync as renameSync5,
61592
+ mkdirSync as mkdirSync13,
61593
+ readFileSync as readFileSync21,
61594
+ renameSync as renameSync6,
61218
61595
  unlinkSync as unlinkSync4,
61219
- writeFileSync as writeFileSync13
61596
+ writeFileSync as writeFileSync14
61220
61597
  } from "node:fs";
61221
- import { join as join23 } from "node:path";
61598
+ import { join as join24 } from "node:path";
61222
61599
  function getTelemetrySettingsPath() {
61223
- return join23(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
61600
+ return join24(getConfigDir(), TELEMETRY_SETTINGS_FILENAME);
61224
61601
  }
61225
61602
  function loadTelemetrySettings() {
61226
61603
  return readTelemetrySettings().settings;
@@ -61288,7 +61665,7 @@ function readTelemetrySettings() {
61288
61665
  }
61289
61666
  let content;
61290
61667
  try {
61291
- content = readFileSync20(path, "utf-8");
61668
+ content = readFileSync21(path, "utf-8");
61292
61669
  } catch {
61293
61670
  return { status: "error", settings: disabledTelemetrySettings() };
61294
61671
  }
@@ -61320,14 +61697,14 @@ function writeTelemetrySettings(settings) {
61320
61697
  const dir = getConfigDir();
61321
61698
  const temporaryPath = `${path}.${process.pid}.${randomUUID4()}.tmp`;
61322
61699
  try {
61323
- if (!existsSync20(dir))
61324
- mkdirSync12(dir, { recursive: true, mode: 448 });
61325
- writeFileSync13(temporaryPath, `${JSON.stringify(settings, null, 2)}
61700
+ if (!existsSync21(dir))
61701
+ mkdirSync13(dir, { recursive: true, mode: 448 });
61702
+ writeFileSync14(temporaryPath, `${JSON.stringify(settings, null, 2)}
61326
61703
  `, {
61327
61704
  flag: "wx",
61328
61705
  mode: 384
61329
61706
  });
61330
- renameSync5(temporaryPath, path);
61707
+ renameSync6(temporaryPath, path);
61331
61708
  return true;
61332
61709
  } catch {
61333
61710
  try {
@@ -61708,7 +62085,7 @@ var init_antigravity = __esm(() => {
61708
62085
  });
61709
62086
 
61710
62087
  // src/mcp/providers/claude.ts
61711
- import { join as join24 } from "node:path";
62088
+ import { join as join25 } from "node:path";
61712
62089
  var ClaudeProvider = () => createJSONProvider({
61713
62090
  providerName: "Claude Code",
61714
62091
  providerID: "claude",
@@ -61718,24 +62095,24 @@ var ClaudeProvider = () => createJSONProvider({
61718
62095
  globalPath: "~/.claude.json",
61719
62096
  topKey: "mcpServers",
61720
62097
  buildServer: ({ url, headers }) => ({ type: "http", url, headers, alwaysLoad: true }),
61721
- localConfigPath: (cwd) => join24(cwd, ".mcp.json")
62098
+ localConfigPath: (cwd) => join25(cwd, ".mcp.json")
61722
62099
  });
61723
62100
  var init_claude = __esm(() => {
61724
62101
  init_base();
61725
62102
  });
61726
62103
 
61727
62104
  // src/mcp/providers/claude-desktop.ts
61728
- import { join as join25 } from "node:path";
62105
+ import { join as join26 } from "node:path";
61729
62106
  function configPath() {
61730
- return join25(appSupportDir(), "Claude", "claude_desktop_config.json");
62107
+ return join26(appSupportDir(), "Claude", "claude_desktop_config.json");
61731
62108
  }
61732
62109
  var ClaudeDesktopProvider = () => ({
61733
62110
  name: () => "Claude Desktop",
61734
62111
  id: () => "claude-desktop",
61735
62112
  supportsLocal: () => false,
61736
62113
  priority: () => 2,
61737
- detectPaths: () => [join25(appSupportDir(), "Claude")],
61738
- isInstalled: () => isInstalled([join25(appSupportDir(), "Claude")]),
62114
+ detectPaths: () => [join26(appSupportDir(), "Claude")],
62115
+ isInstalled: () => isInstalled([join26(appSupportDir(), "Claude")]),
61739
62116
  globalConfigPath: () => configPath(),
61740
62117
  isConfigured: () => isJSONKeyConfigured(configPath(), "mcpServers"),
61741
62118
  install(cfg, global2) {
@@ -61762,14 +62139,14 @@ var init_claude_desktop = __esm(() => {
61762
62139
  });
61763
62140
 
61764
62141
  // src/mcp/providers/cline.ts
61765
- import { join as join26 } from "node:path";
61766
- var extensionDir = () => join26(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
62142
+ import { join as join27 } from "node:path";
62143
+ var extensionDir = () => join27(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
61767
62144
  providerName: "Cline",
61768
62145
  providerID: "cline",
61769
62146
  local: false,
61770
62147
  priorityValue: 11,
61771
62148
  paths: [extensionDir()],
61772
- globalPath: join26(extensionDir(), "settings", "cline_mcp_settings.json"),
62149
+ globalPath: join27(extensionDir(), "settings", "cline_mcp_settings.json"),
61773
62150
  topKey: "mcpServers",
61774
62151
  buildServer: ({ url, headers }) => ({
61775
62152
  url,
@@ -61784,7 +62161,7 @@ var init_cline = __esm(() => {
61784
62161
  });
61785
62162
 
61786
62163
  // src/mcp/providers/cline-cli.ts
61787
- import { join as join27 } from "node:path";
62164
+ import { join as join28 } from "node:path";
61788
62165
  function clineDir() {
61789
62166
  return process.env.CLINE_DIR ?? expandHome("~/.cline");
61790
62167
  }
@@ -61794,7 +62171,7 @@ var ClineCliProvider = () => createJSONProvider({
61794
62171
  local: false,
61795
62172
  priorityValue: 12,
61796
62173
  paths: [clineDir()],
61797
- globalPath: join27(clineDir(), "data", "settings", "cline_mcp_settings.json"),
62174
+ globalPath: join28(clineDir(), "data", "settings", "cline_mcp_settings.json"),
61798
62175
  topKey: "mcpServers",
61799
62176
  buildServer: ({ url, headers }) => ({
61800
62177
  url,
@@ -61809,20 +62186,20 @@ var init_cline_cli = __esm(() => {
61809
62186
  });
61810
62187
 
61811
62188
  // src/mcp/providers/codex.ts
61812
- import { existsSync as existsSync21, readFileSync as readFileSync21 } from "node:fs";
61813
- import { dirname as dirname11, join as join28 } from "node:path";
62189
+ import { existsSync as existsSync22, readFileSync as readFileSync22 } from "node:fs";
62190
+ import { dirname as dirname11, join as join29 } from "node:path";
61814
62191
  function codexHome3() {
61815
62192
  return process.env.CODEX_HOME ?? expandHome("~/.codex");
61816
62193
  }
61817
62194
  function getConfigPath2(global2) {
61818
62195
  if (global2)
61819
- return join28(codexHome3(), "config.toml");
61820
- return join28(process.cwd(), ".codex", "config.toml");
62196
+ return join29(codexHome3(), "config.toml");
62197
+ return join29(process.cwd(), ".codex", "config.toml");
61821
62198
  }
61822
62199
  function readTOML(path) {
61823
- if (!existsSync21(path))
62200
+ if (!existsSync22(path))
61824
62201
  return "";
61825
- return readFileSync21(path, "utf-8");
62202
+ return readFileSync22(path, "utf-8");
61826
62203
  }
61827
62204
  function writeTOML(path, content) {
61828
62205
  writeSecureFile(path, content);
@@ -61897,17 +62274,17 @@ function projectConfigPaths() {
61897
62274
  const chain = [];
61898
62275
  for (let dir = cwd;; ) {
61899
62276
  chain.push(dir);
61900
- if (existsSync21(join28(dir, ".git")))
62277
+ if (existsSync22(join29(dir, ".git")))
61901
62278
  break;
61902
62279
  const parent = dirname11(dir);
61903
62280
  if (parent === dir)
61904
- return [join28(cwd, ".codex", "config.toml")];
62281
+ return [join29(cwd, ".codex", "config.toml")];
61905
62282
  dir = parent;
61906
62283
  }
61907
- return chain.reverse().map((dir) => join28(dir, ".codex", "config.toml"));
62284
+ return chain.reverse().map((dir) => join29(dir, ".codex", "config.toml"));
61908
62285
  }
61909
62286
  function pruneLegacyRemoteEntry(path) {
61910
- if (!existsSync21(path))
62287
+ if (!existsSync22(path))
61911
62288
  return;
61912
62289
  const content = readTOML(path);
61913
62290
  if (!hasRemoteHTTPForm(content))
@@ -61921,9 +62298,9 @@ var REMOTE_HTTP_KEY, CodexProvider = () => ({
61921
62298
  priority: () => 8,
61922
62299
  detectPaths: () => ["~/.codex"],
61923
62300
  isInstalled: () => isInstalled(["~/.codex"]),
61924
- globalConfigPath: () => join28(codexHome3(), "config.toml"),
62301
+ globalConfigPath: () => join29(codexHome3(), "config.toml"),
61925
62302
  isConfigured: () => {
61926
- const content = readTOML(join28(codexHome3(), "config.toml"));
62303
+ const content = readTOML(join29(codexHome3(), "config.toml"));
61927
62304
  return content.includes("[mcp_servers.dosu]");
61928
62305
  },
61929
62306
  install(cfg, global2) {
@@ -61954,10 +62331,10 @@ var init_codex = __esm(() => {
61954
62331
  });
61955
62332
 
61956
62333
  // src/mcp/providers/copilot.ts
61957
- import { join as join29 } from "node:path";
62334
+ import { join as join30 } from "node:path";
61958
62335
  function globalPath() {
61959
62336
  if (process.env.XDG_CONFIG_HOME) {
61960
- return join29(process.env.XDG_CONFIG_HOME, "mcp-config.json");
62337
+ return join30(process.env.XDG_CONFIG_HOME, "mcp-config.json");
61961
62338
  }
61962
62339
  return expandHome("~/.copilot/mcp-config.json");
61963
62340
  }
@@ -61981,7 +62358,7 @@ var CopilotProvider = () => ({
61981
62358
  };
61982
62359
  installJSONServer(globalPath(), "mcpServers", server);
61983
62360
  } else {
61984
- const configPath = join29(process.cwd(), ".vscode", "mcp.json");
62361
+ const configPath = join30(process.cwd(), ".vscode", "mcp.json");
61985
62362
  const server = {
61986
62363
  type: "http",
61987
62364
  url,
@@ -61994,7 +62371,7 @@ var CopilotProvider = () => ({
61994
62371
  if (global2) {
61995
62372
  removeJSONServer(globalPath(), "mcpServers");
61996
62373
  } else {
61997
- const configPath = join29(process.cwd(), ".vscode", "mcp.json");
62374
+ const configPath = join30(process.cwd(), ".vscode", "mcp.json");
61998
62375
  removeJSONServer(configPath, "servers");
61999
62376
  }
62000
62377
  }
@@ -62005,7 +62382,7 @@ var init_copilot = __esm(() => {
62005
62382
  });
62006
62383
 
62007
62384
  // src/mcp/providers/cursor.ts
62008
- import { join as join30 } from "node:path";
62385
+ import { join as join31 } from "node:path";
62009
62386
  var CursorProvider = () => createJSONProvider({
62010
62387
  providerName: "Cursor",
62011
62388
  providerID: "cursor",
@@ -62018,14 +62395,14 @@ var CursorProvider = () => createJSONProvider({
62018
62395
  url,
62019
62396
  headers
62020
62397
  }),
62021
- localConfigPath: (cwd) => join30(cwd, ".cursor", "mcp.json")
62398
+ localConfigPath: (cwd) => join31(cwd, ".cursor", "mcp.json")
62022
62399
  });
62023
62400
  var init_cursor = __esm(() => {
62024
62401
  init_base();
62025
62402
  });
62026
62403
 
62027
62404
  // src/mcp/providers/factory.ts
62028
- import { join as join31 } from "node:path";
62405
+ import { join as join32 } from "node:path";
62029
62406
  var FactoryProvider = () => createJSONProvider({
62030
62407
  providerName: "Factory",
62031
62408
  providerID: "factory",
@@ -62034,14 +62411,14 @@ var FactoryProvider = () => createJSONProvider({
62034
62411
  paths: ["~/.factory"],
62035
62412
  globalPath: "~/.factory/mcp.json",
62036
62413
  topKey: "mcpServers",
62037
- localConfigPath: (cwd) => join31(cwd, ".factory", "mcp.json")
62414
+ localConfigPath: (cwd) => join32(cwd, ".factory", "mcp.json")
62038
62415
  });
62039
62416
  var init_factory = __esm(() => {
62040
62417
  init_base();
62041
62418
  });
62042
62419
 
62043
62420
  // src/mcp/providers/gemini.ts
62044
- import { join as join32 } from "node:path";
62421
+ import { join as join33 } from "node:path";
62045
62422
  var GeminiProvider = () => createJSONProvider({
62046
62423
  providerName: "Gemini CLI",
62047
62424
  providerID: "gemini",
@@ -62050,7 +62427,7 @@ var GeminiProvider = () => createJSONProvider({
62050
62427
  paths: ["~/.gemini"],
62051
62428
  globalPath: "~/.gemini/settings.json",
62052
62429
  topKey: "mcpServers",
62053
- localConfigPath: (cwd) => join32(cwd, ".gemini", "settings.json")
62430
+ localConfigPath: (cwd) => join33(cwd, ".gemini", "settings.json")
62054
62431
  });
62055
62432
  var init_gemini = __esm(() => {
62056
62433
  init_base();
@@ -62092,14 +62469,14 @@ var init_manual = __esm(() => {
62092
62469
  });
62093
62470
 
62094
62471
  // src/mcp/providers/mcporter.ts
62095
- import { existsSync as existsSync22 } from "node:fs";
62096
- import { join as join33 } from "node:path";
62472
+ import { existsSync as existsSync23 } from "node:fs";
62473
+ import { join as join34 } from "node:path";
62097
62474
  function resolveGlobalConfigPath() {
62098
62475
  const jsonPath = expandHome("~/.mcporter/mcporter.json");
62099
- if (existsSync22(jsonPath))
62476
+ if (existsSync23(jsonPath))
62100
62477
  return jsonPath;
62101
62478
  const jsoncPath = expandHome("~/.mcporter/mcporter.jsonc");
62102
- if (existsSync22(jsoncPath))
62479
+ if (existsSync23(jsoncPath))
62103
62480
  return jsoncPath;
62104
62481
  return jsonPath;
62105
62482
  }
@@ -62113,7 +62490,7 @@ var MCPorterProvider = () => ({
62113
62490
  globalConfigPath: () => resolveGlobalConfigPath(),
62114
62491
  isConfigured: () => isJSONKeyConfigured(resolveGlobalConfigPath(), "mcpServers"),
62115
62492
  install(cfg, global2) {
62116
- const configPath = global2 ? resolveGlobalConfigPath() : join33(process.cwd(), "config", "mcporter.json");
62493
+ const configPath = global2 ? resolveGlobalConfigPath() : join34(process.cwd(), "config", "mcporter.json");
62117
62494
  const server = {
62118
62495
  type: "http",
62119
62496
  url: mcpEndpoint(cfg),
@@ -62122,7 +62499,7 @@ var MCPorterProvider = () => ({
62122
62499
  installJSONServer(configPath, "mcpServers", server);
62123
62500
  },
62124
62501
  remove(global2) {
62125
- const configPath = global2 ? resolveGlobalConfigPath() : join33(process.cwd(), "config", "mcporter.json");
62502
+ const configPath = global2 ? resolveGlobalConfigPath() : join34(process.cwd(), "config", "mcporter.json");
62126
62503
  removeJSONServer(configPath, "mcpServers");
62127
62504
  }
62128
62505
  });
@@ -62132,7 +62509,7 @@ var init_mcporter = __esm(() => {
62132
62509
  });
62133
62510
 
62134
62511
  // src/mcp/providers/opencode.ts
62135
- import { join as join34 } from "node:path";
62512
+ import { join as join35 } from "node:path";
62136
62513
  var OpenCodeProvider = () => createJSONProvider({
62137
62514
  providerName: "OpenCode",
62138
62515
  providerID: "opencode",
@@ -62147,23 +62524,23 @@ var OpenCodeProvider = () => createJSONProvider({
62147
62524
  enabled: true,
62148
62525
  headers
62149
62526
  }),
62150
- localConfigPath: (cwd) => join34(cwd, "opencode.json")
62527
+ localConfigPath: (cwd) => join35(cwd, "opencode.json")
62151
62528
  });
62152
62529
  var init_opencode = __esm(() => {
62153
62530
  init_base();
62154
62531
  });
62155
62532
 
62156
62533
  // src/mcp/providers/vscode.ts
62157
- import { join as join35 } from "node:path";
62534
+ import { join as join36 } from "node:path";
62158
62535
  var VSCodeProvider = () => createJSONProvider({
62159
62536
  providerName: "VS Code",
62160
62537
  providerID: "vscode",
62161
62538
  local: true,
62162
62539
  priorityValue: 6,
62163
- paths: [join35(appSupportDir(), "Code")],
62164
- globalPath: join35(appSupportDir(), "Code", "User", "mcp.json"),
62540
+ paths: [join36(appSupportDir(), "Code")],
62541
+ globalPath: join36(appSupportDir(), "Code", "User", "mcp.json"),
62165
62542
  topKey: "servers",
62166
- localConfigPath: (cwd) => join35(cwd, ".vscode", "mcp.json")
62543
+ localConfigPath: (cwd) => join36(cwd, ".vscode", "mcp.json")
62167
62544
  });
62168
62545
  var init_vscode = __esm(() => {
62169
62546
  init_detect();
@@ -62171,15 +62548,15 @@ var init_vscode = __esm(() => {
62171
62548
  });
62172
62549
 
62173
62550
  // src/mcp/providers/windsurf.ts
62174
- import { homedir as homedir9 } from "node:os";
62175
- import { join as join36 } from "node:path";
62551
+ import { homedir as homedir8 } from "node:os";
62552
+ import { join as join37 } from "node:path";
62176
62553
  var WindsurfProvider = () => createJSONProvider({
62177
62554
  providerName: "Windsurf",
62178
62555
  providerID: "windsurf",
62179
62556
  local: false,
62180
62557
  priorityValue: 9,
62181
- paths: [join36(homedir9(), ".codeium", "windsurf")],
62182
- globalPath: join36(homedir9(), ".codeium", "windsurf", "mcp_config.json"),
62558
+ paths: [join37(homedir8(), ".codeium", "windsurf")],
62559
+ globalPath: join37(homedir8(), ".codeium", "windsurf", "mcp_config.json"),
62183
62560
  topKey: "mcpServers"
62184
62561
  });
62185
62562
  var init_windsurf = __esm(() => {
@@ -62188,26 +62565,26 @@ var init_windsurf = __esm(() => {
62188
62565
 
62189
62566
  // src/mcp/providers/zed.ts
62190
62567
  import { rmSync as rmSync6 } from "node:fs";
62191
- import { homedir as homedir10, platform as platform3 } from "node:os";
62192
- import { join as join37 } from "node:path";
62568
+ import { homedir as homedir9, platform as platform3 } from "node:os";
62569
+ import { join as join38 } from "node:path";
62193
62570
  function zedConfigDir() {
62194
62571
  const os = platform3();
62195
62572
  if (os === "win32")
62196
- return join37(appSupportDir(), "Zed");
62573
+ return join38(appSupportDir(), "Zed");
62197
62574
  if (os === "darwin")
62198
- return join37(homedir10(), ".config", "zed");
62199
- return join37(appSupportDir(), "zed");
62575
+ return join38(homedir9(), ".config", "zed");
62576
+ return join38(appSupportDir(), "zed");
62200
62577
  }
62201
62578
  function zedDataDir() {
62202
62579
  const os = platform3();
62203
62580
  if (os === "darwin")
62204
- return join37(appSupportDir(), "Zed");
62581
+ return join38(appSupportDir(), "Zed");
62205
62582
  if (os === "win32")
62206
- return join37(process.env.LOCALAPPDATA ?? "", "Zed");
62207
- return join37(process.env.XDG_DATA_HOME ?? join37(homedir10(), ".local", "share"), "zed");
62583
+ return join38(process.env.LOCALAPPDATA ?? "", "Zed");
62584
+ return join38(process.env.XDG_DATA_HOME ?? join38(homedir9(), ".local", "share"), "zed");
62208
62585
  }
62209
62586
  function legacyDarwinSettingsPath() {
62210
- return platform3() === "darwin" ? join37(appSupportDir(), "Zed", "settings.json") : null;
62587
+ return platform3() === "darwin" ? join38(appSupportDir(), "Zed", "settings.json") : null;
62211
62588
  }
62212
62589
  function removeLegacyDosuEntry(path) {
62213
62590
  let cfg;
@@ -62233,10 +62610,10 @@ var ZedProvider = (legacyPath = legacyDarwinSettingsPath()) => {
62233
62610
  local: true,
62234
62611
  priorityValue: 10,
62235
62612
  paths: [zedConfigDir(), zedDataDir()],
62236
- globalPath: join37(zedConfigDir(), "settings.json"),
62613
+ globalPath: join38(zedConfigDir(), "settings.json"),
62237
62614
  topKey: "context_servers",
62238
62615
  buildServer: ({ url, headers }) => ({ url, headers }),
62239
- localConfigPath: (cwd) => join37(cwd, ".zed", "settings.json")
62616
+ localConfigPath: (cwd) => join38(cwd, ".zed", "settings.json")
62240
62617
  });
62241
62618
  if (!legacyPath)
62242
62619
  return provider;
@@ -62344,29 +62721,29 @@ var init_refresh = __esm(() => {
62344
62721
  import { spawn as spawn3 } from "node:child_process";
62345
62722
  import {
62346
62723
  closeSync as closeSync6,
62347
- existsSync as existsSync23,
62348
- mkdirSync as mkdirSync13,
62724
+ existsSync as existsSync24,
62725
+ mkdirSync as mkdirSync14,
62349
62726
  openSync as openSync6,
62350
- readFileSync as readFileSync22,
62727
+ readFileSync as readFileSync23,
62351
62728
  rmSync as rmSync7,
62352
62729
  statSync as statSync8,
62353
- writeFileSync as writeFileSync14,
62730
+ writeFileSync as writeFileSync15,
62354
62731
  writeSync
62355
62732
  } from "node:fs";
62356
- import { homedir as homedir11 } from "node:os";
62357
- import { join as join38 } from "node:path";
62733
+ import { homedir as homedir10 } from "node:os";
62734
+ import { join as join39 } from "node:path";
62358
62735
  function statePath() {
62359
- return join38(getConfigDir(), STATE_FILENAME2);
62736
+ return join39(getConfigDir(), STATE_FILENAME2);
62360
62737
  }
62361
62738
  function lockPath2() {
62362
- return join38(getConfigDir(), LOCK_FILENAME2);
62739
+ return join39(getConfigDir(), LOCK_FILENAME2);
62363
62740
  }
62364
62741
  function isValidVersion(value) {
62365
62742
  return typeof value === "string" && VERSION_PATTERN.test(value);
62366
62743
  }
62367
62744
  function readState() {
62368
62745
  try {
62369
- const raw = JSON.parse(readFileSync22(statePath(), "utf-8"));
62746
+ const raw = JSON.parse(readFileSync23(statePath(), "utf-8"));
62370
62747
  if (typeof raw !== "object" || raw === null || Array.isArray(raw))
62371
62748
  return {};
62372
62749
  const data = raw;
@@ -62385,9 +62762,9 @@ function readState() {
62385
62762
  function writeState(state) {
62386
62763
  try {
62387
62764
  const dir = getConfigDir();
62388
- if (!existsSync23(dir))
62389
- mkdirSync13(dir, { recursive: true, mode: 448 });
62390
- writeFileSync14(statePath(), `${JSON.stringify(state, null, 2)}
62765
+ if (!existsSync24(dir))
62766
+ mkdirSync14(dir, { recursive: true, mode: 448 });
62767
+ writeFileSync15(statePath(), `${JSON.stringify(state, null, 2)}
62391
62768
  `, { mode: 384 });
62392
62769
  return true;
62393
62770
  } catch {
@@ -62440,7 +62817,7 @@ function lockIsFresh(now) {
62440
62817
  }
62441
62818
  function claimLock(version, now) {
62442
62819
  try {
62443
- mkdirSync13(getConfigDir(), { recursive: true, mode: 448 });
62820
+ mkdirSync14(getConfigDir(), { recursive: true, mode: 448 });
62444
62821
  if (!lockIsFresh(now))
62445
62822
  rmSync7(lockPath2(), { force: true });
62446
62823
  const fd = openSync6(lockPath2(), "wx", 384);
@@ -62461,7 +62838,7 @@ function releaseLock() {
62461
62838
  }
62462
62839
  function readLockVersion() {
62463
62840
  try {
62464
- const version = readFileSync22(lockPath2(), "utf-8").trim();
62841
+ const version = readFileSync23(lockPath2(), "utf-8").trim();
62465
62842
  return isValidVersion(version) ? version : undefined;
62466
62843
  } catch {
62467
62844
  return;
@@ -62488,7 +62865,7 @@ function startAutoUpdate(version, options = {}) {
62488
62865
  return claim === "held" ? "in_progress" : "unavailable";
62489
62866
  try {
62490
62867
  const child = spawn3(invocation.command, invocation.args, {
62491
- cwd: homedir11(),
62868
+ cwd: homedir10(),
62492
62869
  detached: true,
62493
62870
  stdio: "ignore",
62494
62871
  windowsHide: true,
@@ -62535,8 +62912,8 @@ var init_auto_update = __esm(() => {
62535
62912
  });
62536
62913
 
62537
62914
  // src/version/update-check.ts
62538
- import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync15 } from "node:fs";
62539
- import { join as join39 } from "node:path";
62915
+ import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
62916
+ import { join as join40 } from "node:path";
62540
62917
  function isValidVersion2(value) {
62541
62918
  return typeof value === "string" && SEMVER_PATTERN.test(value);
62542
62919
  }
@@ -62558,14 +62935,14 @@ function isNewerVersion(latest, current) {
62558
62935
  return false;
62559
62936
  }
62560
62937
  function getCachePath2() {
62561
- return join39(getConfigDir(), CACHE_FILENAME3);
62938
+ return join40(getConfigDir(), CACHE_FILENAME3);
62562
62939
  }
62563
62940
  function readCache() {
62564
62941
  try {
62565
62942
  const path = getCachePath2();
62566
- if (!existsSync24(path))
62943
+ if (!existsSync25(path))
62567
62944
  return null;
62568
- const data = JSON.parse(readFileSync23(path, "utf-8"));
62945
+ const data = JSON.parse(readFileSync24(path, "utf-8"));
62569
62946
  if (typeof data.lastCheck === "number" && isValidVersion2(data.latestVersion)) {
62570
62947
  return data;
62571
62948
  }
@@ -62577,10 +62954,10 @@ function readCache() {
62577
62954
  function writeCache(cache) {
62578
62955
  try {
62579
62956
  const dir = getConfigDir();
62580
- if (!existsSync24(dir)) {
62581
- mkdirSync14(dir, { recursive: true, mode: 448 });
62957
+ if (!existsSync25(dir)) {
62958
+ mkdirSync15(dir, { recursive: true, mode: 448 });
62582
62959
  }
62583
- writeFileSync15(getCachePath2(), JSON.stringify(cache), { mode: 384 });
62960
+ writeFileSync16(getCachePath2(), JSON.stringify(cache), { mode: 384 });
62584
62961
  } catch {}
62585
62962
  }
62586
62963
  async function fetchLatestVersion() {
@@ -62708,8 +63085,8 @@ var init_update_check = __esm(() => {
62708
63085
  });
62709
63086
 
62710
63087
  // src/version/mcp-refresh-check.ts
62711
- import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "node:fs";
62712
- import { join as join40 } from "node:path";
63088
+ import { existsSync as existsSync26, mkdirSync as mkdirSync16, readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
63089
+ import { join as join41 } from "node:path";
62713
63090
  function needsMcpRefresh(previous, current) {
62714
63091
  if (previous === null)
62715
63092
  return true;
@@ -62719,14 +63096,14 @@ function needsMcpRefresh(previous, current) {
62719
63096
  return MCP_FORMAT_CHANGES.some((change) => isNewerVersion(change, older) && !isNewerVersion(change, newer));
62720
63097
  }
62721
63098
  function getCachePath3() {
62722
- return join40(getConfigDir(), CACHE_FILENAME4);
63099
+ return join41(getConfigDir(), CACHE_FILENAME4);
62723
63100
  }
62724
63101
  function readMcpRefreshCache() {
62725
63102
  try {
62726
63103
  const path = getCachePath3();
62727
- if (!existsSync25(path))
63104
+ if (!existsSync26(path))
62728
63105
  return null;
62729
- const data = JSON.parse(readFileSync24(path, "utf-8"));
63106
+ const data = JSON.parse(readFileSync25(path, "utf-8"));
62730
63107
  if (typeof data?.version === "string")
62731
63108
  return { version: data.version };
62732
63109
  return null;
@@ -62737,10 +63114,10 @@ function readMcpRefreshCache() {
62737
63114
  function writeMcpRefreshCache(cache) {
62738
63115
  try {
62739
63116
  const dir = getConfigDir();
62740
- if (!existsSync25(dir)) {
62741
- mkdirSync15(dir, { recursive: true, mode: 448 });
63117
+ if (!existsSync26(dir)) {
63118
+ mkdirSync16(dir, { recursive: true, mode: 448 });
62742
63119
  }
62743
- writeFileSync16(getCachePath3(), JSON.stringify(cache), { mode: 384 });
63120
+ writeFileSync17(getCachePath3(), JSON.stringify(cache), { mode: 384 });
62744
63121
  } catch {}
62745
63122
  }
62746
63123
  function canRefreshMcp(cfg) {
@@ -62888,15 +63265,15 @@ function createLogFollower(path, emit) {
62888
63265
  var init_follow = () => {};
62889
63266
 
62890
63267
  // src/sessions/session-title.ts
62891
- import { existsSync as existsSync26, mkdirSync as mkdirSync16, readFileSync as readFileSync25, renameSync as renameSync6, statSync as statSync10, writeFileSync as writeFileSync17 } from "node:fs";
62892
- import { homedir as homedir12 } from "node:os";
62893
- import { join as join41 } from "node:path";
63268
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync26, renameSync as renameSync7, statSync as statSync10, writeFileSync as writeFileSync18 } from "node:fs";
63269
+ import { homedir as homedir11 } from "node:os";
63270
+ import { join as join42 } from "node:path";
62894
63271
  function cachePath2(configDir) {
62895
- return join41(configDir, CACHE_FILENAME5);
63272
+ return join42(configDir, CACHE_FILENAME5);
62896
63273
  }
62897
63274
  function loadCacheFile2(configDir) {
62898
63275
  try {
62899
- const raw = JSON.parse(readFileSync25(cachePath2(configDir), "utf-8"));
63276
+ const raw = JSON.parse(readFileSync26(cachePath2(configDir), "utf-8"));
62900
63277
  if (raw.schema_version !== CACHE_SCHEMA_VERSION2 || typeof raw.entries !== "object")
62901
63278
  return {};
62902
63279
  return raw.entries;
@@ -62906,13 +63283,13 @@ function loadCacheFile2(configDir) {
62906
63283
  }
62907
63284
  function saveCacheFile2(configDir, entries) {
62908
63285
  try {
62909
- if (!existsSync26(configDir))
62910
- mkdirSync16(configDir, { recursive: true, mode: 448 });
63286
+ if (!existsSync27(configDir))
63287
+ mkdirSync17(configDir, { recursive: true, mode: 448 });
62911
63288
  const path = cachePath2(configDir);
62912
63289
  const tmp = `${path}.${process.pid}.tmp`;
62913
63290
  const file = { schema_version: CACHE_SCHEMA_VERSION2, entries };
62914
- writeFileSync17(tmp, JSON.stringify(file), { mode: 384 });
62915
- renameSync6(tmp, path);
63291
+ writeFileSync18(tmp, JSON.stringify(file), { mode: 384 });
63292
+ renameSync7(tmp, path);
62916
63293
  } catch {}
62917
63294
  }
62918
63295
  function extractUserQuery(text) {
@@ -62944,15 +63321,15 @@ function claudeSummaryFromHead(text) {
62944
63321
  }
62945
63322
  return null;
62946
63323
  }
62947
- function reconstructSession(harness, id, slug, home = homedir12(), exists = existsSync26) {
63324
+ function reconstructSession(harness, id, slug, home = homedir11(), exists = existsSync27) {
62948
63325
  if (!slug)
62949
63326
  return null;
62950
63327
  const candidates = [];
62951
63328
  if (harness === "claude") {
62952
- candidates.push(join41(home, ".claude", "projects", slug, `${id}.jsonl`));
63329
+ candidates.push(join42(home, ".claude", "projects", slug, `${id}.jsonl`));
62953
63330
  } else if (harness === "cursor") {
62954
- const project = join41(home, ".cursor", "projects", slug);
62955
- candidates.push(join41(project, "agent-transcripts", id, `${id}.jsonl`), join41(project, "agent-transcripts", `${id}.jsonl`));
63331
+ const project = join42(home, ".cursor", "projects", slug);
63332
+ candidates.push(join42(project, "agent-transcripts", id, `${id}.jsonl`), join42(project, "agent-transcripts", `${id}.jsonl`));
62956
63333
  } else {
62957
63334
  return null;
62958
63335
  }
@@ -62964,7 +63341,7 @@ function reconstructSession(harness, id, slug, home = homedir12(), exists = exis
62964
63341
  }
62965
63342
  function readHead2(path) {
62966
63343
  try {
62967
- return readFileSync25(path, "utf-8").slice(0, 128 * 1024);
63344
+ return readFileSync26(path, "utf-8").slice(0, 128 * 1024);
62968
63345
  } catch {
62969
63346
  return null;
62970
63347
  }
@@ -63044,8 +63421,8 @@ var init_alt_screen = __esm(() => {
63044
63421
  });
63045
63422
 
63046
63423
  // src/tui/activity-view.ts
63047
- import { existsSync as existsSync27, readFileSync as readFileSync26 } from "node:fs";
63048
- import { basename as basename5 } from "node:path";
63424
+ import { existsSync as existsSync28, readFileSync as readFileSync27 } from "node:fs";
63425
+ import { basename as basename6 } from "node:path";
63049
63426
  function reduceActivityViewKey(key) {
63050
63427
  if (key === "q" || key === ESC7 || key === CTRL_C4)
63051
63428
  return "back";
@@ -63365,12 +63742,12 @@ function createRowNamer() {
63365
63742
  names.titles[key] = t;
63366
63743
  };
63367
63744
  for (const s of [...backlog.queued, ...backlog.open]) {
63368
- if (!existsSync27(s.path))
63745
+ if (!existsSync28(s.path))
63369
63746
  continue;
63370
63747
  const key = `${s.harness}/${s.id}`;
63371
63748
  const dir = dirs.resolve(s);
63372
63749
  if (dir)
63373
- names.projects[key] = basename5(dir);
63750
+ names.projects[key] = basename6(dir);
63374
63751
  title(key, s);
63375
63752
  resolved = true;
63376
63753
  }
@@ -63379,7 +63756,7 @@ function createRowNamer() {
63379
63756
  if (!names.projects[key]) {
63380
63757
  const dir = dirs.cached(key) ?? (r.project ? fromSlug(r.project) : null);
63381
63758
  if (dir)
63382
- names.projects[key] = basename5(dir);
63759
+ names.projects[key] = basename6(dir);
63383
63760
  }
63384
63761
  if (!names.titles[key]) {
63385
63762
  const hit = titles.cached(key);
@@ -63402,7 +63779,7 @@ function createRowNamer() {
63402
63779
  }
63403
63780
  function defaultReadLog2() {
63404
63781
  try {
63405
- return readFileSync26(logger.getLogPath(), "utf-8");
63782
+ return readFileSync27(logger.getLogPath(), "utf-8");
63406
63783
  } catch {
63407
63784
  return "";
63408
63785
  }
@@ -63619,14 +63996,14 @@ var init_activity_view = __esm(() => {
63619
63996
  });
63620
63997
 
63621
63998
  // src/rules/installer.ts
63622
- import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync27, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "node:fs";
63623
- import { homedir as homedir13 } from "node:os";
63624
- import { dirname as dirname12, join as join42 } from "node:path";
63999
+ import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync28, unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "node:fs";
64000
+ import { homedir as homedir12 } from "node:os";
64001
+ import { dirname as dirname12, join as join43 } from "node:path";
63625
64002
  function claudeConfigDir4() {
63626
- return process.env.CLAUDE_CONFIG_DIR || join42(homedir13(), ".claude");
64003
+ return process.env.CLAUDE_CONFIG_DIR || join43(homedir12(), ".claude");
63627
64004
  }
63628
64005
  function codexHome4() {
63629
- return process.env.CODEX_HOME || join42(homedir13(), ".codex");
64006
+ return process.env.CODEX_HOME || join43(homedir12(), ".codex");
63630
64007
  }
63631
64008
  function isRuleAgent(agent) {
63632
64009
  return Object.hasOwn(RULE_TARGETS, agent);
@@ -63652,17 +64029,17 @@ async function fetchDosuRule(fetchImpl = globalThis.fetch) {
63652
64029
  return normalizeRule(FALLBACK_DOSU_RULE);
63653
64030
  }
63654
64031
  function ensureParent(path) {
63655
- mkdirSync17(dirname12(path), { recursive: true });
64032
+ mkdirSync18(dirname12(path), { recursive: true });
63656
64033
  }
63657
64034
  function writeIfChanged(path, content) {
63658
- if (!existsSync28(path)) {
64035
+ if (!existsSync29(path)) {
63659
64036
  ensureParent(path);
63660
- writeFileSync18(path, content, "utf-8");
64037
+ writeFileSync19(path, content, "utf-8");
63661
64038
  return "created";
63662
64039
  }
63663
- if (readFileSync27(path, "utf-8") === content)
64040
+ if (readFileSync28(path, "utf-8") === content)
63664
64041
  return "unchanged";
63665
- writeFileSync18(path, content, "utf-8");
64042
+ writeFileSync19(path, content, "utf-8");
63666
64043
  return "updated";
63667
64044
  }
63668
64045
  function findSection(content) {
@@ -63688,14 +64065,14 @@ function buildSection(content, lineEnding = `
63688
64065
  return `${DOSU_RULE_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_RULE_SECTION_END}`;
63689
64066
  }
63690
64067
  function upsertSection(path, content) {
63691
- if (!existsSync28(path)) {
64068
+ if (!existsSync29(path)) {
63692
64069
  const section = buildSection(content);
63693
64070
  ensureParent(path);
63694
- writeFileSync18(path, `${section}
64071
+ writeFileSync19(path, `${section}
63695
64072
  `, "utf-8");
63696
64073
  return "created";
63697
64074
  }
63698
- const existing = readFileSync27(path, "utf-8");
64075
+ const existing = readFileSync28(path, "utf-8");
63699
64076
  const lineEnding = lineEndingFor(existing);
63700
64077
  const section = buildSection(content, lineEnding);
63701
64078
  const location = findSection(existing);
@@ -63708,7 +64085,7 @@ function upsertSection(path, content) {
63708
64085
  }
63709
64086
  if (next === existing)
63710
64087
  return "unchanged";
63711
- writeFileSync18(path, next, "utf-8");
64088
+ writeFileSync19(path, next, "utf-8");
63712
64089
  return "updated";
63713
64090
  }
63714
64091
  function installRuleForAgent(agent, content) {
@@ -63725,13 +64102,13 @@ function removeRuleForAgent(agent) {
63725
64102
  return null;
63726
64103
  const target = RULE_TARGETS[agent];
63727
64104
  const path = target.path();
63728
- if (!existsSync28(path))
64105
+ if (!existsSync29(path))
63729
64106
  return { agent, path, action: "not_found" };
63730
64107
  if (target.kind === "file") {
63731
64108
  unlinkSync5(path);
63732
64109
  return { agent, path, action: "removed" };
63733
64110
  }
63734
- const existing = readFileSync27(path, "utf-8");
64111
+ const existing = readFileSync28(path, "utf-8");
63735
64112
  const lineEnding = lineEndingFor(existing);
63736
64113
  const location = findSection(existing);
63737
64114
  if (!location)
@@ -63740,7 +64117,7 @@ function removeRuleForAgent(agent) {
63740
64117
  if (!next) {
63741
64118
  unlinkSync5(path);
63742
64119
  } else {
63743
- writeFileSync18(path, `${next}${lineEnding}`, "utf-8");
64120
+ writeFileSync19(path, `${next}${lineEnding}`, "utf-8");
63744
64121
  }
63745
64122
  return { agent, path, action: "removed" };
63746
64123
  }
@@ -63768,36 +64145,36 @@ var init_installer = __esm(() => {
63768
64145
  RULE_TARGETS = {
63769
64146
  claude: {
63770
64147
  kind: "file",
63771
- path: () => join42(claudeConfigDir4(), "rules", "dosu.md")
64148
+ path: () => join43(claudeConfigDir4(), "rules", "dosu.md")
63772
64149
  },
63773
64150
  cursor: {
63774
64151
  kind: "file",
63775
- path: () => join42(homedir13(), ".cursor", "rules", "dosu.mdc"),
64152
+ path: () => join43(homedir12(), ".cursor", "rules", "dosu.mdc"),
63776
64153
  cursorFrontmatter: true
63777
64154
  },
63778
64155
  codex: {
63779
64156
  kind: "section",
63780
- path: () => join42(codexHome4(), "AGENTS.md")
64157
+ path: () => join43(codexHome4(), "AGENTS.md")
63781
64158
  },
63782
64159
  opencode: {
63783
64160
  kind: "section",
63784
- path: () => join42(homedir13(), ".config", "opencode", "AGENTS.md")
64161
+ path: () => join43(homedir12(), ".config", "opencode", "AGENTS.md")
63785
64162
  },
63786
64163
  gemini: {
63787
64164
  kind: "section",
63788
- path: () => join42(homedir13(), ".gemini", "GEMINI.md")
64165
+ path: () => join43(homedir12(), ".gemini", "GEMINI.md")
63789
64166
  },
63790
64167
  antigravity: {
63791
64168
  kind: "section",
63792
- path: () => join42(homedir13(), ".gemini", "GEMINI.md")
64169
+ path: () => join43(homedir12(), ".gemini", "GEMINI.md")
63793
64170
  }
63794
64171
  };
63795
64172
  });
63796
64173
 
63797
64174
  // src/setup/agents-md-step.ts
63798
64175
  import { execSync as execSync2 } from "node:child_process";
63799
- import { existsSync as existsSync29, readFileSync as readFileSync28, writeFileSync as writeFileSync19 } from "node:fs";
63800
- import { join as join43 } from "node:path";
64176
+ import { existsSync as existsSync30, readFileSync as readFileSync29, writeFileSync as writeFileSync20 } from "node:fs";
64177
+ import { join as join44 } from "node:path";
63801
64178
  function inGitWorkTree(cwd = process.cwd()) {
63802
64179
  try {
63803
64180
  const stdout = execSync2("git rev-parse --is-inside-work-tree", {
@@ -63811,10 +64188,10 @@ function inGitWorkTree(cwd = process.cwd()) {
63811
64188
  }
63812
64189
  function dosuAgentsSectionState(cwd = process.cwd()) {
63813
64190
  try {
63814
- const path = join43(cwd, "AGENTS.md");
63815
- if (!existsSync29(path))
64191
+ const path = join44(cwd, "AGENTS.md");
64192
+ if (!existsSync30(path))
63816
64193
  return "missing";
63817
- const content = readFileSync28(path, "utf-8");
64194
+ const content = readFileSync29(path, "utf-8");
63818
64195
  const startMatch = content.match(SECTION_START_RE);
63819
64196
  if (!startMatch || !content.includes(DOSU_SECTION_END))
63820
64197
  return "missing";
@@ -63849,14 +64226,14 @@ function findSection2(content) {
63849
64226
  return { start, end };
63850
64227
  }
63851
64228
  function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
63852
- const path = join43(cwd, "AGENTS.md");
63853
- if (!existsSync29(path)) {
64229
+ const path = join44(cwd, "AGENTS.md");
64230
+ if (!existsSync30(path)) {
63854
64231
  const section = buildDosuAgentsSection(content);
63855
- writeFileSync19(path, `${section}
64232
+ writeFileSync20(path, `${section}
63856
64233
  `);
63857
64234
  return { path, action: "created" };
63858
64235
  }
63859
- const existing = readFileSync28(path, "utf-8");
64236
+ const existing = readFileSync29(path, "utf-8");
63860
64237
  const lineEnding = lineEndingFor2(existing);
63861
64238
  const section = renderDosuAgentsSection(content, lineEnding);
63862
64239
  const location = findSection2(existing);
@@ -63868,7 +64245,7 @@ function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RU
63868
64245
  }
63869
64246
  if (next === existing)
63870
64247
  return { path, action: "unchanged" };
63871
- writeFileSync19(path, next);
64248
+ writeFileSync20(path, next);
63872
64249
  return { path, action: "updated" };
63873
64250
  }
63874
64251
  async function stepUpdateAgentsMd(cwd = process.cwd(), content) {
@@ -64642,9 +65019,6 @@ async function runSetupFlow(opts = {}) {
64642
65019
  if (cfg.mode !== MODE_OSS) {
64643
65020
  await stepShowLibrary(cfg);
64644
65021
  }
64645
- if (cfg.mode !== MODE_OSS) {
64646
- await stepOfferGithubConnect(cfg);
64647
- }
64648
65022
  const apiKey = await stepMintAPIKey(apiClient, cfg);
64649
65023
  if (!apiKey) {
64650
65024
  trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
@@ -64968,46 +65342,6 @@ async function stepSetupHandshake(cfg, onboardingRunID) {
64968
65342
  return false;
64969
65343
  }
64970
65344
  }
64971
- async function stepOfferGithubConnect(cfg) {
64972
- const target = cfg.active_account?.target;
64973
- if (!target?.org_id || !target?.space_id)
64974
- return;
64975
- try {
64976
- await Promise.resolve().then(() => init_trpc());
64977
- const trpc = createTypedClient(cfg);
64978
- if (await spaceHasGithubSource(trpc, target.space_id))
64979
- return;
64980
- } catch (err) {
64981
- const msg = err instanceof Error ? err.message : String(err);
64982
- logger.warn("setup", `GitHub source check failed, skipping offer: ${msg}`);
64983
- return;
64984
- }
64985
- logger.info("setup", "Step: offer GitHub connect (no GitHub source in the MCP's Library)");
64986
- log2.warn("No GitHub repos are connected to this MCP yet, so it can't answer from your code.");
64987
- const connectNow = await confirm2({
64988
- message: "Connect a GitHub repo now?",
64989
- active: "Connect now",
64990
- inactive: "Skip for now",
64991
- initialValue: true
64992
- });
64993
- if (isCancel2(connectNow) || !connectNow) {
64994
- log2.info(`Skipped. Connect later at ${info(`${getWebAppURL()}/libraries`)} or re-run ${info("dosu setup")}.`);
64995
- return;
64996
- }
64997
- await stepConnectGitHubRepo(cfg);
64998
- }
64999
- async function spaceHasGithubSource(trpc, spaceID) {
65000
- try {
65001
- const sources = await trpc.libraries.sourcesList.query(spaceID);
65002
- return (sources ?? []).some((source) => source.provider_slug === "github");
65003
- } catch (err) {
65004
- const missingProcedure = isTRPCClientError(err) && err.data?.code === "NOT_FOUND";
65005
- if (!missingProcedure)
65006
- throw err;
65007
- const spaceDeployments = await trpc.workspaces.listForSpace.query(spaceID);
65008
- return (spaceDeployments ?? []).some((d) => d.provider_slug === "github");
65009
- }
65010
- }
65011
65345
  async function resolveCloudSetupContext(cfg) {
65012
65346
  try {
65013
65347
  await Promise.resolve().then(() => init_trpc());
@@ -65540,7 +65874,6 @@ ${dim(wrapLog("Run it inside a session to keep that session out of studying. Rem
65540
65874
  }
65541
65875
  var import_picocolors34, OAUTH_ANALYTICS_REASONS, SETUP_HANDSHAKE_TIMEOUT_MS = 1800000, LIBRARY_SELECT_CANCELLED;
65542
65876
  var init_flow2 = __esm(() => {
65543
- init_dist();
65544
65877
  init_errors3();
65545
65878
  init_client();
65546
65879
  init_skill();
@@ -65560,7 +65893,6 @@ var init_flow2 = __esm(() => {
65560
65893
  init_mcp_refresh_check();
65561
65894
  init_agents_md_step();
65562
65895
  init_analytics2();
65563
- init_github_step();
65564
65896
  init_rules_step();
65565
65897
  init_styles();
65566
65898
  import_picocolors34 = __toESM(require_picocolors(), 1);
@@ -65580,7 +65912,7 @@ var init_flow2 = __esm(() => {
65580
65912
  // src/commands/upgrade.ts
65581
65913
  import { spawnSync } from "node:child_process";
65582
65914
  import { realpathSync as realpathSync2 } from "node:fs";
65583
- import { homedir as homedir14 } from "node:os";
65915
+ import { homedir as homedir13 } from "node:os";
65584
65916
  import { posix, win32 as win322 } from "node:path";
65585
65917
  function isAbsoluteCommandProcessor(value) {
65586
65918
  return Boolean(value && win322.isAbsolute(value) && win322.basename(value).toLowerCase() === "cmd.exe");
@@ -65634,7 +65966,7 @@ function packageRoots(manager, platform, comSpec, env, cwd) {
65634
65966
  manager === "npm" ? path.join(lines[0], "@dosu", "cli") : path.join(lines[0], "node_modules", "@dosu", "cli")
65635
65967
  ];
65636
65968
  }
65637
- function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir14()) {
65969
+ function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir13()) {
65638
65970
  const path = platform === "win32" ? win322 : posix;
65639
65971
  if (!entrypoint || !path.isAbsolute(entrypoint))
65640
65972
  return null;
@@ -65687,7 +66019,7 @@ Or install Dosu globally with your package manager:`);
65687
66019
  function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
65688
66020
  const platform = options.platform ?? process.platform;
65689
66021
  const env = options.env ?? process.env;
65690
- const cwd = options.cwd ?? homedir14();
66022
+ const cwd = options.cwd ?? homedir13();
65691
66023
  let manager = null;
65692
66024
  if (channel === "npm") {
65693
66025
  if (isNpxInvocation(channel, env)) {
@@ -65754,7 +66086,7 @@ function finishWithNewBinary(channel, options) {
65754
66086
  return;
65755
66087
  }
65756
66088
  const result = spawnSync(invocation.command, invocation.args, {
65757
- cwd: options.cwd ?? homedir14(),
66089
+ cwd: options.cwd ?? homedir13(),
65758
66090
  shell: false,
65759
66091
  stdio: "inherit"
65760
66092
  });
@@ -66552,8 +66884,7 @@ var init_pages_view = __esm(() => {
66552
66884
  });
66553
66885
 
66554
66886
  // src/tui/tui.ts
66555
- import { homedir as homedir15 } from "node:os";
66556
- import { basename as basename6 } from "node:path";
66887
+ import { basename as basename7 } from "node:path";
66557
66888
  async function probeSession(cfg) {
66558
66889
  if (!isAuthenticated(cfg) || !isTokenExpired(cfg))
66559
66890
  return { expired: false };
@@ -66580,7 +66911,7 @@ function bannerContext(cfg, session) {
66580
66911
  return {
66581
66912
  version: getVersionString(),
66582
66913
  webAppHost,
66583
- directory: basename6(process.cwd()),
66914
+ directory: basename7(process.cwd()),
66584
66915
  signedIn: isAuthenticated(cfg),
66585
66916
  sessionExpired: session.expired,
66586
66917
  deploymentName: cfg.active_account?.target?.deployment_name,
@@ -66781,8 +67112,9 @@ async function runSettings(cfg) {
66781
67112
  while (true) {
66782
67113
  const target = cfg.active_account?.target;
66783
67114
  const library = target?.library_name ?? target?.deployment_name ?? "not configured";
66784
- const filter = loadSyncState().project_filter;
66785
- const scope = !filter?.length ? "all projects" : filter.length <= 2 ? filter.map((dir) => dir === UNKNOWN_PROJECT ? "unknown" : basename6(dir)).join(", ") : `${filter.length} projects`;
67115
+ const sync = loadSyncState();
67116
+ const filter = sync.repo_filter;
67117
+ const scope = !filter ? sync.project_filter?.length ? `${sync.project_filter.length} folders (legacy)` : "all repos" : filter.length === 0 ? "no repos" : filter.length <= 2 ? filter.map(displayRepo).join(", ") : `${filter.length} repos`;
66786
67118
  const action = await menuSelect("settings", [
66787
67119
  { label: "switch organization", hint: target?.org_name, value: "switch-org" },
66788
67120
  { label: "switch library", hint: library, value: "switch-library" },
@@ -66816,45 +67148,43 @@ async function runSettings(cfg) {
66816
67148
  }
66817
67149
  }
66818
67150
  }
66819
- function displayDir(dir) {
66820
- const home = homedir15();
66821
- return dir === home ? "~" : dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir;
66822
- }
66823
- function discoverProjectDirs() {
67151
+ function discoverSessionRepos(current) {
66824
67152
  const counts = new Map;
66825
67153
  try {
66826
67154
  const resolver = createProjectDirResolver();
66827
67155
  for (const session of scanAgentSessions({})) {
66828
- const key = resolver.resolve(session) ?? UNKNOWN_PROJECT;
66829
- counts.set(key, (counts.get(key) ?? 0) + 1);
67156
+ const repo = resolver.resolveRepo(session);
67157
+ if (repo)
67158
+ counts.set(repo, (counts.get(repo) ?? 0) + 1);
66830
67159
  }
66831
67160
  resolver.flush();
66832
67161
  } catch {}
66833
- return [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([dir]) => dir);
67162
+ for (const repo of current ?? [])
67163
+ if (!counts.has(repo))
67164
+ counts.set(repo, 0);
67165
+ return [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([repo]) => repo);
66834
67166
  }
66835
67167
  async function runStudyingProjectsSetting() {
66836
- const dirs = discoverProjectDirs();
66837
- if (dirs.length === 0) {
66838
- log2.info("No local agent sessions found yet; nothing to scope.");
67168
+ const state = loadSyncState();
67169
+ const current = studyRepoFilter(state, () => scanAgentSessions({}), createProjectDirResolver());
67170
+ const repos = discoverSessionRepos(current);
67171
+ if (repos.length === 0) {
67172
+ log2.info("No agent sessions inside a git repo found yet; nothing to scope.");
66839
67173
  return;
66840
67174
  }
66841
- const current = loadSyncState().project_filter;
66842
67175
  const selected = await multiselect2({
66843
- message: "Study sessions from which folders?",
66844
- options: dirs.map((dir) => ({
66845
- label: dir === UNKNOWN_PROJECT ? "(unknown folder)" : displayDir(dir),
66846
- value: dir
66847
- })),
66848
- initialValues: current?.length ? current : dirs,
66849
- summary: (picked) => picked.length === dirs.length ? "all folders · new ones included automatically" : `${picked.length} of ${dirs.length} folders · subfolders included`,
66850
- validate: (picked) => picked.length === 0 ? "Select at least one folder." : undefined
67176
+ message: "Study sessions from which repos?",
67177
+ options: repos.map((repo) => ({ label: displayRepo(repo), hint: repo, value: repo })),
67178
+ initialValues: current ?? repos,
67179
+ summary: (picked) => picked.length === repos.length ? "all repos · new ones included automatically" : `${picked.length} of ${repos.length} repos`,
67180
+ validate: (picked) => picked.length === 0 ? "Select at least one repo." : undefined
66851
67181
  });
66852
67182
  if (isCancel2(selected))
66853
67183
  return;
66854
- const { project_filter: _previous, ...state } = loadSyncState();
66855
- const all = selected.length === dirs.length;
66856
- saveSyncState(all ? state : { ...state, project_filter: [...selected] });
66857
- const scope = all ? "all folders" : selected.map(displayDir).join(", ");
67184
+ const { repo_filter: _repos, project_filter: _folders, ...fresh } = loadSyncState();
67185
+ const all = selected.length === repos.length;
67186
+ saveSyncState(all ? fresh : { ...fresh, repo_filter: [...selected] });
67187
+ const scope = all ? "all repos" : selected.map(displayRepo).join(", ");
66858
67188
  log2.success(`Study scope ${dim(`· ${scope}`)}`);
66859
67189
  }
66860
67190
  async function handleAuthenticate(cfg) {
@@ -66907,6 +67237,7 @@ var init_tui = __esm(() => {
66907
67237
  init_providers();
66908
67238
  init_generate();
66909
67239
  init_project_dir();
67240
+ init_repo();
66910
67241
  init_scan();
66911
67242
  init_agents_md_step();
66912
67243
  init_flow2();
@@ -67527,7 +67858,7 @@ var init_flow3 = __esm(() => {
67527
67858
  });
67528
67859
 
67529
67860
  // src/cli/cli.ts
67530
- import { readFileSync as readFileSync29, unlinkSync as unlinkSync6 } from "node:fs";
67861
+ import { readFileSync as readFileSync30, unlinkSync as unlinkSync6 } from "node:fs";
67531
67862
  function shouldRunBackgroundChecks(actionName) {
67532
67863
  return actionName !== "upgrade";
67533
67864
  }
@@ -67973,7 +68304,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
67973
68304
  }
67974
68305
  if (opts.follow) {
67975
68306
  try {
67976
- const lines = readFileSync29(logPath, "utf-8").split(`
68307
+ const lines = readFileSync30(logPath, "utf-8").split(`
67977
68308
  `);
67978
68309
  if (lines.at(-1) === "")
67979
68310
  lines.pop();
@@ -67989,7 +68320,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
67989
68320
  if (opts.tail !== undefined) {
67990
68321
  const n = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
67991
68322
  try {
67992
- const content = readFileSync29(logPath, "utf-8");
68323
+ const content = readFileSync30(logPath, "utf-8");
67993
68324
  const lines = content.split(`
67994
68325
  `);
67995
68326
  console.log(lines.slice(-n).join(`
@@ -68115,4 +68446,4 @@ main().catch((err) => {
68115
68446
  process.exit(1);
68116
68447
  });
68117
68448
 
68118
- //# debugId=097dc848-8855-154b-6475-6e2164756e21
68449
+ //# debugId=3b9a1619-fdbd-ebdd-6475-6e2164756e21