@dosu/cli 0.65.1 → 0.66.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 +14 -11
  2. package/bin/dosu.js +395 -295
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -178,19 +178,22 @@ session. `dosu setup` installs both alongside the hook; they can also be managed
178
178
 
179
179
  ```bash
180
180
  dosu knowledge statusline enable|disable [claude|cursor] # status-bar line in Claude Code / Cursor CLI
181
- dosu knowledge incognito enable|disable [claude|cursor|codex] # the /dosu-incognito slash command
181
+ dosu knowledge incognito on|off [claude|cursor|codex] # stop/resume studying an agent's sessions
182
+ dosu knowledge incognito status # which agents are incognito
182
183
  ```
183
184
 
184
- The status line shows one of `📚 Dosu studying…`, `👻 Dosu incognito`, `⚪ Dosu paused`,
185
- `⚪ Dosu not studying this repo`, or `⚪ Dosu off`. Every session is studied unless you limit
186
- studying to picked repos under `dosu` → settings → study scope. Notes from a session with a known
187
- repo and branch are anchored to that branch; the rest are unanchored and reach topics immediately.
188
- Neither setup nor `enable` replaces a status line you already have; they print the one-liner to add
189
- to your own script instead.
190
-
191
- Running `/dosu-incognito` inside a session marks that session's transcript so studying skips it
192
- (the whole session, and for the rest of it — start a new session to turn Dosu back on) and tells the
193
- model not to use Dosu tools. See [docs/studying.md](docs/studying.md).
185
+ The status line shows one of `📚 Dosu studying…` (a sync run is live), `📚 Dosu on`,
186
+ `👻 Dosu incognito`, `⚪ Dosu paused`, `⚪ Dosu not studying this repo`, or `⚪ Dosu off`. Every
187
+ session is studied unless you limit studying to picked repos under `dosu` → settings → study
188
+ scope. Notes from a session with a known repo and branch are anchored to that branch; the rest are
189
+ unanchored and reach topics immediately. Neither setup nor `enable` replaces a status line you
190
+ already have; they print the one-liner to add to your own script instead.
191
+
192
+ `incognito on` is a saved per-agent setting: none of that agent's sessions are studied until you
193
+ turn it off. To keep a single chat out instead, type `/dosu-incognito` in it; setup installs that
194
+ command with the hook. It marks the session's transcript so studying skips it (the whole session,
195
+ and for the rest of it — start a new session to turn Dosu back on) and tells the model not to use
196
+ Dosu tools. See [docs/studying.md](docs/studying.md).
194
197
 
195
198
  ### Telemetry and privacy
196
199
 
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.65.1", INSTALL_CHANNEL = "npm";
1086
+ var VERSION = "0.66.0", INSTALL_CHANNEL = "npm";
1087
1087
 
1088
1088
  // src/debug/logger.ts
1089
1089
  import {
@@ -1977,11 +1977,93 @@ var init_incognito = __esm(() => {
1977
1977
  MAX_SCAN_BYTES = 64 * 1024 * 1024;
1978
1978
  });
1979
1979
 
1980
- // src/sync/watermark.ts
1981
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
1980
+ // src/sync/lock.ts
1981
+ import { existsSync as existsSync7, readFileSync as readFileSync6, rmSync, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
1982
1982
  import { join as join6 } from "node:path";
1983
+ function processAlive(pid) {
1984
+ try {
1985
+ process.kill(pid, 0);
1986
+ return true;
1987
+ } catch (err) {
1988
+ return err.code === "EPERM";
1989
+ }
1990
+ }
1991
+ function lockPath(configDir = getConfigDir()) {
1992
+ return join6(configDir, LOCK_FILENAME);
1993
+ }
1994
+ function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
1995
+ if (!Number.isInteger(pid) || pid <= 0)
1996
+ return false;
1997
+ let killed = false;
1998
+ try {
1999
+ kill(-pid, "SIGTERM");
2000
+ killed = true;
2001
+ } catch {
2002
+ try {
2003
+ kill(pid, "SIGTERM");
2004
+ killed = true;
2005
+ } catch {}
2006
+ }
2007
+ try {
2008
+ const path = lockPath(configDir);
2009
+ if (existsSync7(path) && readFileSync6(path, "utf8") === String(pid)) {
2010
+ rmSync(path, { force: true });
2011
+ }
2012
+ } catch {}
2013
+ return killed;
2014
+ }
2015
+ function fileLock(configDir = getConfigDir(), now = () => new Date) {
2016
+ const path = lockPath(configDir);
2017
+ let held = false;
2018
+ const tryCreate = () => {
2019
+ try {
2020
+ writeFileSync3(path, String(process.pid), { flag: "wx" });
2021
+ return true;
2022
+ } catch {
2023
+ return false;
2024
+ }
2025
+ };
2026
+ return {
2027
+ acquire() {
2028
+ if (tryCreate()) {
2029
+ held = true;
2030
+ return true;
2031
+ }
2032
+ try {
2033
+ const age = now().getTime() - statSync3(path).mtimeMs;
2034
+ const holder = Number.parseInt(readFileSync6(path, "utf8"), 10);
2035
+ const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
2036
+ if (age > STALE_LOCK_MS || holderDead) {
2037
+ rmSync(path, { force: true });
2038
+ held = tryCreate();
2039
+ return held;
2040
+ }
2041
+ } catch {}
2042
+ return false;
2043
+ },
2044
+ release() {
2045
+ if (!held)
2046
+ return;
2047
+ held = false;
2048
+ try {
2049
+ if (existsSync7(path) && readFileSync6(path, "utf8") === String(process.pid)) {
2050
+ rmSync(path, { force: true });
2051
+ }
2052
+ } catch {}
2053
+ }
2054
+ };
2055
+ }
2056
+ var LOCK_FILENAME = "knowledge-sync.lock", STALE_LOCK_MS;
2057
+ var init_lock = __esm(() => {
2058
+ init_config();
2059
+ STALE_LOCK_MS = 15 * 60 * 1000;
2060
+ });
2061
+
2062
+ // src/sync/watermark.ts
2063
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
2064
+ import { join as join7 } from "node:path";
1983
2065
  function syncStatePath(configDir = getConfigDir()) {
1984
- return join6(configDir, STATE_FILENAME);
2066
+ return join7(configDir, STATE_FILENAME);
1985
2067
  }
1986
2068
  function stringsOf(values) {
1987
2069
  return values.filter((v) => typeof v === "string");
@@ -1993,10 +2075,10 @@ function loadSyncState(configDir = getConfigDir()) {
1993
2075
  consecutive_failures: 0
1994
2076
  };
1995
2077
  const path = syncStatePath(configDir);
1996
- if (!existsSync7(path))
2078
+ if (!existsSync8(path))
1997
2079
  return empty;
1998
2080
  try {
1999
- const raw = JSON.parse(readFileSync6(path, "utf-8"));
2081
+ const raw = JSON.parse(readFileSync7(path, "utf-8"));
2000
2082
  if (raw.schema_version !== STATE_SCHEMA_VERSION)
2001
2083
  return empty;
2002
2084
  const studiedSessions = Array.isArray(raw.mined_sessions) ? raw.mined_sessions.filter((record) => typeof record === "object" && record !== null && typeof record.at === "string" && typeof record.session === "string").map((record) => ({
@@ -2021,6 +2103,7 @@ function loadSyncState(configDir = getConfigDir()) {
2021
2103
  ...lastRefusal ? { last_refusal: lastRefusal } : {},
2022
2104
  ...run ? { run } : {},
2023
2105
  ...raw.paused === true ? { paused: true } : {},
2106
+ ...Array.isArray(raw.incognito_agents) ? { incognito_agents: stringsOf(raw.incognito_agents) } : {},
2024
2107
  ...Array.isArray(raw.repo_filter) ? { repo_filter: stringsOf(raw.repo_filter) } : {},
2025
2108
  ...Array.isArray(raw.project_filter) ? { project_filter: stringsOf(raw.project_filter) } : {}
2026
2109
  };
@@ -2036,6 +2119,21 @@ function setSyncPaused(paused, configDir = getConfigDir()) {
2036
2119
  delete state.paused;
2037
2120
  saveSyncState(state, configDir);
2038
2121
  }
2122
+ function setAgentsIncognito(agentIds, incognito, configDir = getConfigDir()) {
2123
+ const state = loadSyncState(configDir);
2124
+ const current = new Set(state.incognito_agents ?? []);
2125
+ for (const id of agentIds) {
2126
+ if (incognito)
2127
+ current.add(id);
2128
+ else
2129
+ current.delete(id);
2130
+ }
2131
+ if (current.size > 0)
2132
+ state.incognito_agents = [...current].sort();
2133
+ else
2134
+ delete state.incognito_agents;
2135
+ saveSyncState(state, configDir);
2136
+ }
2039
2137
  function resetSyncState(configDir = getConfigDir()) {
2040
2138
  const previous = loadSyncState(configDir);
2041
2139
  const fresh = {
@@ -2044,16 +2142,17 @@ function resetSyncState(configDir = getConfigDir()) {
2044
2142
  consecutive_failures: 0,
2045
2143
  ...previous.repo_filter ? { repo_filter: previous.repo_filter } : {},
2046
2144
  ...previous.project_filter ? { project_filter: previous.project_filter } : {},
2047
- ...previous.paused ? { paused: true } : {}
2145
+ ...previous.paused ? { paused: true } : {},
2146
+ ...previous.incognito_agents ? { incognito_agents: previous.incognito_agents } : {}
2048
2147
  };
2049
2148
  saveSyncState(fresh, configDir);
2050
2149
  }
2051
2150
  function saveSyncState(state, configDir = getConfigDir()) {
2052
- if (!existsSync7(configDir))
2151
+ if (!existsSync8(configDir))
2053
2152
  mkdirSync4(configDir, { recursive: true, mode: 448 });
2054
2153
  const path = syncStatePath(configDir);
2055
2154
  const tmp = `${path}.${process.pid}.tmp`;
2056
- writeFileSync3(tmp, JSON.stringify(state, null, 2), { mode: 384 });
2155
+ writeFileSync4(tmp, JSON.stringify(state, null, 2), { mode: 384 });
2057
2156
  renameSync2(tmp, path);
2058
2157
  }
2059
2158
  function backoffUntil(state) {
@@ -2123,6 +2222,73 @@ var init_watermark = __esm(() => {
2123
2222
  BACKOFF_MAX_MS = 24 * 60 * 60 * 1000;
2124
2223
  });
2125
2224
 
2225
+ // src/sync/status.ts
2226
+ import { readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
2227
+ function formatTokenCount(tokens) {
2228
+ if (tokens < 1000)
2229
+ return String(tokens);
2230
+ if (tokens < 1e6) {
2231
+ const k = tokens / 1000;
2232
+ return `~${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\.0$/, "")}k`;
2233
+ }
2234
+ const m = tokens / 1e6;
2235
+ return `~${m >= 100 ? Math.round(m) : m.toFixed(1).replace(/\.0$/, "")}M`;
2236
+ }
2237
+ function defaultIsProcessAlive(pid) {
2238
+ if (!Number.isInteger(pid) || pid <= 0)
2239
+ return false;
2240
+ try {
2241
+ process.kill(pid, 0);
2242
+ return true;
2243
+ } catch (err) {
2244
+ return err.code === "EPERM";
2245
+ }
2246
+ }
2247
+ function defaultReadLog() {
2248
+ try {
2249
+ return readFileSync8(logger.getLogPath(), "utf-8");
2250
+ } catch {
2251
+ return "";
2252
+ }
2253
+ }
2254
+ function readLockFile(configDir) {
2255
+ const path = lockPath(configDir);
2256
+ try {
2257
+ const pid = Number.parseInt(readFileSync8(path, "utf-8"), 10);
2258
+ return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync4(path).mtime };
2259
+ } catch {
2260
+ return null;
2261
+ }
2262
+ }
2263
+ function recentSyncActivity(log) {
2264
+ return log.split(`
2265
+ `).filter((line) => line.includes("[sync]") || line.includes("[learner]")).slice(-ACTIVITY_LINES).map((line) => line.replace(/ \[(DEBUG|INFO|WARN|ERROR)\]/, ""));
2266
+ }
2267
+ function getSyncStatus(deps = {}) {
2268
+ const configDir = deps.configDir ?? getConfigDir();
2269
+ const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive;
2270
+ const readLog = deps.readLog ?? defaultReadLog;
2271
+ const lock = readLockFile(configDir);
2272
+ const running = lock !== null && isProcessAlive(lock.pid);
2273
+ const state = loadSyncState(configDir);
2274
+ const retryAt = backoffUntil(state);
2275
+ return {
2276
+ running,
2277
+ ...lock ? { pid: lock.pid, startedAt: lock.mtime.toISOString() } : {},
2278
+ ...lock && !running ? { staleLock: true } : {},
2279
+ state,
2280
+ ...retryAt ? { backoffUntil: retryAt.toISOString() } : {},
2281
+ recentActivity: recentSyncActivity(readLog())
2282
+ };
2283
+ }
2284
+ var ACTIVITY_LINES = 10;
2285
+ var init_status = __esm(() => {
2286
+ init_config();
2287
+ init_logger();
2288
+ init_lock();
2289
+ init_watermark();
2290
+ });
2291
+
2126
2292
  // src/statusline/render.ts
2127
2293
  function asString(value) {
2128
2294
  return typeof value === "string" && value !== "" ? value : undefined;
@@ -2151,6 +2317,9 @@ function defaultHookEnabled(agentId) {
2151
2317
  return false;
2152
2318
  }
2153
2319
  }
2320
+ function defaultSyncRunning() {
2321
+ return getSyncStatus({ readLog: () => "" }).running;
2322
+ }
2154
2323
  function cwdIsStudied(cwd, state, repoOfDir) {
2155
2324
  if (state.repo_filter) {
2156
2325
  const repo = cwd ? repoOfDir(cwd) : null;
@@ -2165,16 +2334,18 @@ function resolveStatuslineState(payload, agentId, deps = {}) {
2165
2334
  const hookEnabled = deps.hookEnabled ?? defaultHookEnabled;
2166
2335
  if (!hookEnabled(agentId))
2167
2336
  return "off";
2337
+ const state = (deps.loadState ?? loadSyncState)();
2338
+ if (state.incognito_agents?.includes(agentId))
2339
+ return "incognito";
2168
2340
  const transcriptIsIncognito = deps.transcriptIsIncognito ?? transcriptHasIncognitoMarker;
2169
2341
  if (payload.transcript_path && transcriptIsIncognito(payload.transcript_path)) {
2170
2342
  return "incognito";
2171
2343
  }
2172
- const state = (deps.loadState ?? loadSyncState)();
2173
2344
  if (state.paused)
2174
2345
  return "paused";
2175
2346
  if (!cwdIsStudied(payload.cwd, state, deps.repoOfDir ?? originRepoOfDir))
2176
2347
  return "not-studied";
2177
- return "on";
2348
+ return (deps.syncRunning ?? defaultSyncRunning)() ? "studying" : "on";
2178
2349
  }
2179
2350
  function renderStatusline(raw, agentId, deps = {}) {
2180
2351
  try {
@@ -2188,9 +2359,11 @@ var init_render = __esm(() => {
2188
2359
  init_agents();
2189
2360
  init_repo();
2190
2361
  init_incognito();
2362
+ init_status();
2191
2363
  init_watermark();
2192
2364
  STATUSLINE_LABELS = {
2193
- on: "\uD83D\uDCDA Dosu studying…",
2365
+ studying: "\uD83D\uDCDA Dosu studying…",
2366
+ on: "\uD83D\uDCDA Dosu on",
2194
2367
  incognito: "\uD83D\uDC7B Dosu incognito",
2195
2368
  paused: "⚪ Dosu paused",
2196
2369
  "not-studied": "⚪ Dosu not studying this repo",
@@ -4327,16 +4500,16 @@ var init_session_errors = __esm(() => {
4327
4500
  import { randomUUID } from "node:crypto";
4328
4501
  import {
4329
4502
  closeSync as closeSync3,
4330
- existsSync as existsSync8,
4503
+ existsSync as existsSync9,
4331
4504
  linkSync,
4332
4505
  mkdirSync as mkdirSync5,
4333
4506
  openSync as openSync3,
4334
- readFileSync as readFileSync7,
4335
- statSync as statSync3,
4507
+ readFileSync as readFileSync9,
4508
+ statSync as statSync5,
4336
4509
  unlinkSync,
4337
- writeFileSync as writeFileSync4
4510
+ writeFileSync as writeFileSync5
4338
4511
  } from "node:fs";
4339
- import { join as join7 } from "node:path";
4512
+ import { join as join8 } from "node:path";
4340
4513
  async function withConfigRefreshLock(task, options = {}) {
4341
4514
  const release = await acquireConfigRefreshLock(options);
4342
4515
  try {
@@ -4351,12 +4524,12 @@ async function acquireConfigRefreshLock(options) {
4351
4524
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
4352
4525
  const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
4353
4526
  const staleAgeMs = options.staleAgeMs ?? DEFAULT_STALE_AGE_MS;
4354
- const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive;
4527
+ const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive2;
4355
4528
  const ownerId = options.ownerId ?? randomUUID();
4356
4529
  const configDir = getConfigDir();
4357
- const lockPath = join7(configDir, CONFIG_REFRESH_LOCK_FILENAME);
4530
+ const lockPath = join8(configDir, CONFIG_REFRESH_LOCK_FILENAME);
4358
4531
  try {
4359
- if (!existsSync8(configDir))
4532
+ if (!existsSync9(configDir))
4360
4533
  mkdirSync5(configDir, { recursive: true, mode: 448 });
4361
4534
  } catch (cause) {
4362
4535
  throw new SessionPersistenceError({ cause });
@@ -4385,7 +4558,7 @@ async function acquireConfigRefreshLock(options) {
4385
4558
  function createLockFile(lockPath, metadata) {
4386
4559
  const fd = openSync3(lockPath, "wx", 384);
4387
4560
  try {
4388
- writeFileSync4(fd, JSON.stringify(metadata));
4561
+ writeFileSync5(fd, JSON.stringify(metadata));
4389
4562
  } catch (cause) {
4390
4563
  try {
4391
4564
  closeSync3(fd);
@@ -4419,12 +4592,12 @@ function claimAndRemoveStaleLock(lockPath, staleAgeMs, now, isProcessAlive, owne
4419
4592
  if (metadata && Number.isInteger(metadata.pid) && metadata.pid > 0) {
4420
4593
  stale = !isProcessAlive(metadata.pid);
4421
4594
  } else {
4422
- stale = now - statSync3(claimPath).mtimeMs >= staleAgeMs;
4595
+ stale = now - statSync5(claimPath).mtimeMs >= staleAgeMs;
4423
4596
  }
4424
4597
  if (!stale)
4425
4598
  return false;
4426
- const current = statSync3(lockPath);
4427
- const claimed = statSync3(claimPath);
4599
+ const current = statSync5(lockPath);
4600
+ const claimed = statSync5(claimPath);
4428
4601
  if (current.dev !== claimed.dev || current.ino !== claimed.ino)
4429
4602
  return false;
4430
4603
  unlinkSync(lockPath);
@@ -4439,7 +4612,7 @@ function claimAndRemoveStaleLock(lockPath, staleAgeMs, now, isProcessAlive, owne
4439
4612
  }
4440
4613
  function readLockMetadata(lockPath) {
4441
4614
  try {
4442
- const parsed = JSON.parse(readFileSync7(lockPath, "utf8"));
4615
+ const parsed = JSON.parse(readFileSync9(lockPath, "utf8"));
4443
4616
  if (!isRecord3(parsed))
4444
4617
  return;
4445
4618
  if (typeof parsed.owner_id !== "string" || typeof parsed.pid !== "number" || typeof parsed.created_at !== "number") {
@@ -4454,7 +4627,7 @@ function readLockMetadata(lockPath) {
4454
4627
  return;
4455
4628
  }
4456
4629
  }
4457
- function defaultIsProcessAlive(pid) {
4630
+ function defaultIsProcessAlive2(pid) {
4458
4631
  try {
4459
4632
  process.kill(pid, 0);
4460
4633
  return true;
@@ -10814,17 +10987,17 @@ var init_github_step = __esm(() => {
10814
10987
  });
10815
10988
 
10816
10989
  // src/version/pending-tasks-check.ts
10817
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
10818
- import { join as join8 } from "node:path";
10990
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "node:fs";
10991
+ import { join as join9 } from "node:path";
10819
10992
  function getCachePath() {
10820
- return join8(getConfigDir(), CACHE_FILENAME);
10993
+ return join9(getConfigDir(), CACHE_FILENAME);
10821
10994
  }
10822
10995
  function readPendingTasks() {
10823
10996
  try {
10824
10997
  const path = getCachePath();
10825
- if (!existsSync9(path))
10998
+ if (!existsSync10(path))
10826
10999
  return { tasks: [] };
10827
- const data = JSON.parse(readFileSync8(path, "utf-8"));
11000
+ const data = JSON.parse(readFileSync10(path, "utf-8"));
10828
11001
  if (Array.isArray(data?.tasks)) {
10829
11002
  return { tasks: data.tasks };
10830
11003
  }
@@ -10836,10 +11009,10 @@ function readPendingTasks() {
10836
11009
  function writePendingTasks(cache) {
10837
11010
  try {
10838
11011
  const dir = getConfigDir();
10839
- if (!existsSync9(dir)) {
11012
+ if (!existsSync10(dir)) {
10840
11013
  mkdirSync6(dir, { recursive: true, mode: 448 });
10841
11014
  }
10842
- writeFileSync5(getCachePath(), JSON.stringify(cache), { mode: 384 });
11015
+ writeFileSync6(getCachePath(), JSON.stringify(cache), { mode: 384 });
10843
11016
  } catch {}
10844
11017
  }
10845
11018
  function addPendingTask(task) {
@@ -10946,8 +11119,8 @@ var init_pending_tasks_check = __esm(() => {
10946
11119
  });
10947
11120
 
10948
11121
  // src/commands/audit.ts
10949
- import { existsSync as existsSync10, readFileSync as readFileSync9, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
10950
- import { dirname as dirname3, join as join9 } from "node:path";
11122
+ import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
11123
+ import { dirname as dirname3, join as join10 } from "node:path";
10951
11124
  function requireConfig3() {
10952
11125
  const cfg = requireLoginConfig();
10953
11126
  if (!cfg.active_account?.target?.api_key) {
@@ -11084,12 +11257,12 @@ function loadFindings(findingsPath) {
11084
11257
  console.error(import_picocolors14.default.red("Run the Dosu audit in your coding agent first (it writes .dosu/audit.json)."));
11085
11258
  process.exit(1);
11086
11259
  };
11087
- if (!existsSync10(findingsPath)) {
11260
+ if (!existsSync11(findingsPath)) {
11088
11261
  fail();
11089
11262
  }
11090
11263
  let parsed;
11091
11264
  try {
11092
- parsed = JSON.parse(readFileSync9(findingsPath, "utf-8"));
11265
+ parsed = JSON.parse(readFileSync11(findingsPath, "utf-8"));
11093
11266
  } catch {
11094
11267
  fail();
11095
11268
  }
@@ -11099,25 +11272,25 @@ function loadFindings(findingsPath) {
11099
11272
  return parsed;
11100
11273
  }
11101
11274
  function cleanupFindings(findingsPath, cwd = process.cwd()) {
11102
- const gitignorePath = join9(cwd, ".gitignore");
11275
+ const gitignorePath = join10(cwd, ".gitignore");
11103
11276
  try {
11104
- const content = existsSync10(gitignorePath) ? readFileSync9(gitignorePath, "utf-8") : "";
11277
+ const content = existsSync11(gitignorePath) ? readFileSync11(gitignorePath, "utf-8") : "";
11105
11278
  const hasEntry = content.split(/\r?\n/).some((line) => /^\.dosu\/?$/.test(line.trim()));
11106
11279
  if (!hasEntry) {
11107
11280
  const sep = content === "" || content.endsWith(`
11108
11281
  `) ? "" : `
11109
11282
  `;
11110
- writeFileSync6(gitignorePath, `${content}${sep}.dosu/
11283
+ writeFileSync7(gitignorePath, `${content}${sep}.dosu/
11111
11284
  `);
11112
11285
  }
11113
11286
  } catch (err) {
11114
11287
  logger.warn("audit", `could not update .gitignore: ${errText(err)}`);
11115
11288
  }
11116
- const defaultDir = join9(cwd, ".dosu");
11289
+ const defaultDir = join10(cwd, ".dosu");
11117
11290
  if (dirname3(findingsPath) !== defaultDir)
11118
11291
  return;
11119
11292
  try {
11120
- rmSync(defaultDir, { recursive: true, force: true });
11293
+ rmSync2(defaultDir, { recursive: true, force: true });
11121
11294
  } catch (err) {
11122
11295
  logger.warn("audit", `could not remove ${defaultDir}: ${errText(err)}`);
11123
11296
  }
@@ -11156,7 +11329,7 @@ function auditCommand() {
11156
11329
  const nonInteractive = Boolean(opts.tasks);
11157
11330
  const client = createTypedClient(cfg);
11158
11331
  const dataSourceId = await ensureSyncedRepo(cfg, client, detected, opts.dataSourceId, nonInteractive);
11159
- const findingsPath = opts.findings ?? join9(process.cwd(), ".dosu", "audit.json");
11332
+ const findingsPath = opts.findings ?? join10(process.cwd(), ".dosu", "audit.json");
11160
11333
  const findings = loadFindings(findingsPath);
11161
11334
  if (!opts.dataSourceId && findings.repo?.slug && findings.repo.slug !== detected.slug) {
11162
11335
  console.error(import_picocolors14.default.red(`Audit was run on ${findings.repo.slug}, but the current repo is ${detected.slug}. ` + `Run 'dosu audit' from ${findings.repo.slug} so the PR targets the audited repo.`));
@@ -11427,7 +11600,7 @@ var init_doc_import = __esm(() => {
11427
11600
  });
11428
11601
 
11429
11602
  // src/commands/docs.ts
11430
- import { readFileSync as readFileSync10 } from "node:fs";
11603
+ import { readFileSync as readFileSync12 } from "node:fs";
11431
11604
  import { resolve } from "node:path";
11432
11605
  function requireConfig5() {
11433
11606
  const cfg = requireLoginConfig();
@@ -11452,7 +11625,7 @@ function readBody(opts) {
11452
11625
  return opts.body;
11453
11626
  const path = opts.bodyFile;
11454
11627
  try {
11455
- return readFileSync10(path, "utf-8");
11628
+ return readFileSync12(path, "utf-8");
11456
11629
  } catch (err) {
11457
11630
  const code = err.code;
11458
11631
  if (code === "ENOENT") {
@@ -12149,21 +12322,21 @@ var init_branch = __esm(() => {
12149
12322
  });
12150
12323
 
12151
12324
  // src/sessions/capture.ts
12152
- import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync3, writeFileSync as writeFileSync7 } from "node:fs";
12153
- import { basename as basename2, join as join10 } from "node:path";
12325
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync13, renameSync as renameSync3, writeFileSync as writeFileSync8 } from "node:fs";
12326
+ import { basename as basename2, join as join11 } from "node:path";
12154
12327
  function capturePath(configDir, key) {
12155
12328
  const [harness, id, ...rest] = key.split("/");
12156
12329
  if (rest.length > 0 || !SAFE_SEGMENT.test(harness ?? "") || !SAFE_SEGMENT.test(id ?? "")) {
12157
12330
  return null;
12158
12331
  }
12159
- return join10(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
12332
+ return join11(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
12160
12333
  }
12161
12334
  function readCapturedSession(key, configDir = getConfigDir()) {
12162
12335
  const path = capturePath(configDir, key);
12163
12336
  if (!path)
12164
12337
  return null;
12165
12338
  try {
12166
- const raw = JSON.parse(readFileSync11(path, "utf-8"));
12339
+ const raw = JSON.parse(readFileSync13(path, "utf-8"));
12167
12340
  return {
12168
12341
  ...typeof raw.dir === "string" ? { dir: raw.dir } : {},
12169
12342
  ...typeof raw.branch === "string" ? { branch: raw.branch } : {},
@@ -12186,11 +12359,11 @@ function recordCapturedSession(key, update, configDir = getConfigDir(), now = ne
12186
12359
  at: now.toISOString()
12187
12360
  };
12188
12361
  try {
12189
- const parent = join10(path, "..");
12190
- if (!existsSync11(parent))
12362
+ const parent = join11(path, "..");
12363
+ if (!existsSync12(parent))
12191
12364
  mkdirSync7(parent, { recursive: true, mode: 448 });
12192
12365
  const tmp = `${path}.${process.pid}.tmp`;
12193
- writeFileSync7(tmp, JSON.stringify(record), { mode: 384 });
12366
+ writeFileSync8(tmp, JSON.stringify(record), { mode: 384 });
12194
12367
  renameSync3(tmp, path);
12195
12368
  return true;
12196
12369
  } catch (err) {
@@ -12271,22 +12444,22 @@ var init_capture = __esm(() => {
12271
12444
  // src/sessions/project-dir.ts
12272
12445
  import {
12273
12446
  closeSync as closeSync4,
12274
- existsSync as existsSync12,
12447
+ existsSync as existsSync13,
12275
12448
  mkdirSync as mkdirSync8,
12276
12449
  openSync as openSync4,
12277
- readFileSync as readFileSync12,
12450
+ readFileSync as readFileSync14,
12278
12451
  readSync as readSync3,
12279
12452
  renameSync as renameSync4,
12280
- statSync as statSync4,
12281
- writeFileSync as writeFileSync8
12453
+ statSync as statSync6,
12454
+ writeFileSync as writeFileSync9
12282
12455
  } from "node:fs";
12283
- import { join as join11 } from "node:path";
12456
+ import { join as join12 } from "node:path";
12284
12457
  function cachePath(configDir) {
12285
- return join11(configDir, CACHE_FILENAME2);
12458
+ return join12(configDir, CACHE_FILENAME2);
12286
12459
  }
12287
12460
  function loadCacheFile(configDir) {
12288
12461
  try {
12289
- const raw = JSON.parse(readFileSync12(cachePath(configDir), "utf-8"));
12462
+ const raw = JSON.parse(readFileSync14(cachePath(configDir), "utf-8"));
12290
12463
  if (raw.schema_version !== CACHE_SCHEMA_VERSION || typeof raw.entries !== "object")
12291
12464
  return {};
12292
12465
  return raw.entries;
@@ -12296,12 +12469,12 @@ function loadCacheFile(configDir) {
12296
12469
  }
12297
12470
  function saveCacheFile(configDir, entries) {
12298
12471
  try {
12299
- if (!existsSync12(configDir))
12472
+ if (!existsSync13(configDir))
12300
12473
  mkdirSync8(configDir, { recursive: true, mode: 448 });
12301
12474
  const path = cachePath(configDir);
12302
12475
  const tmp = `${path}.${process.pid}.tmp`;
12303
12476
  const file = { schema_version: CACHE_SCHEMA_VERSION, entries };
12304
- writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
12477
+ writeFileSync9(tmp, JSON.stringify(file), { mode: 384 });
12305
12478
  renameSync4(tmp, path);
12306
12479
  } catch {}
12307
12480
  }
@@ -12336,7 +12509,7 @@ function cwdFromJsonlHead(text) {
12336
12509
  }
12337
12510
  return null;
12338
12511
  }
12339
- function unmungeSlug(slug, exists = existsSync12) {
12512
+ function unmungeSlug(slug, exists = existsSync13) {
12340
12513
  const tokens = slug.replace(/^-/, "").split("-");
12341
12514
  if (tokens.length === 0 || tokens[0] === "")
12342
12515
  return null;
@@ -12355,20 +12528,20 @@ function unmungeSlug(slug, exists = existsSync12) {
12355
12528
  }
12356
12529
  function readWholeFile(path) {
12357
12530
  try {
12358
- return readFileSync12(path, "utf-8");
12531
+ return readFileSync14(path, "utf-8");
12359
12532
  } catch {
12360
12533
  return null;
12361
12534
  }
12362
12535
  }
12363
12536
  function fileMtime(path) {
12364
12537
  try {
12365
- return statSync4(path).mtime.toISOString();
12538
+ return statSync6(path).mtime.toISOString();
12366
12539
  } catch {
12367
12540
  return "";
12368
12541
  }
12369
12542
  }
12370
12543
  function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
12371
- const exists = deps.exists ?? existsSync12;
12544
+ const exists = deps.exists ?? existsSync13;
12372
12545
  const head = deps.readHead ?? readHead;
12373
12546
  const mtime = deps.mtime ?? fileMtime;
12374
12547
  const captured = deps.captured ?? ((key) => readCapturedSession(key, configDir));
@@ -13219,7 +13392,7 @@ var init_queries = __esm(() => {
13219
13392
  });
13220
13393
 
13221
13394
  // src/report/digest.ts
13222
- import { readFileSync as readFileSync13 } from "node:fs";
13395
+ import { readFileSync as readFileSync15 } from "node:fs";
13223
13396
  function asRecord2(value) {
13224
13397
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
13225
13398
  }
@@ -13450,11 +13623,11 @@ function sessionToDigest(session) {
13450
13623
  try {
13451
13624
  switch (session.harness) {
13452
13625
  case "claude":
13453
- return { turns: digestClaude(readFileSync13(session.path, "utf8")) };
13626
+ return { turns: digestClaude(readFileSync15(session.path, "utf8")) };
13454
13627
  case "cursor":
13455
- return { turns: digestCursor(readFileSync13(session.path, "utf8")) };
13628
+ return { turns: digestCursor(readFileSync15(session.path, "utf8")) };
13456
13629
  case "codex":
13457
- return { turns: digestCodex(readFileSync13(session.path, "utf8")) };
13630
+ return { turns: digestCodex(readFileSync15(session.path, "utf8")) };
13458
13631
  case "opencode": {
13459
13632
  const turns = readSessionTurns(session).map((turn, index) => ({
13460
13633
  role: turn.role,
@@ -13675,17 +13848,17 @@ var init_notes = __esm(() => {
13675
13848
  });
13676
13849
 
13677
13850
  // src/report/write.ts
13678
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "node:fs";
13851
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "node:fs";
13679
13852
  import { tmpdir } from "node:os";
13680
- import { dirname as dirname4, join as join12, resolve as resolve2 } from "node:path";
13853
+ import { dirname as dirname4, join as join13, resolve as resolve2 } from "node:path";
13681
13854
  import { pathToFileURL } from "node:url";
13682
13855
  function defaultReportPath() {
13683
- return join12(tmpdir(), "dosu-knowledge-report.html");
13856
+ return join13(tmpdir(), "dosu-knowledge-report.html");
13684
13857
  }
13685
13858
  async function writeAndOpenReport(options) {
13686
13859
  const out = resolve2(options.out ?? defaultReportPath());
13687
13860
  mkdirSync9(dirname4(out), { recursive: true });
13688
- writeFileSync9(out, options.html, "utf8");
13861
+ writeFileSync10(out, options.html, "utf8");
13689
13862
  if (options.open !== false) {
13690
13863
  const url = pathToFileURL(out).href;
13691
13864
  if (options.openUrl) {
@@ -13768,7 +13941,8 @@ function listSessionBacklog() {
13768
13941
  const sessions = filterSessionsByRepo(scanned, filter, resolver.resolveRepo);
13769
13942
  resolver.flush();
13770
13943
  const gate = gateSessions(sessions, state.watermark);
13771
- const { kept, skipped } = partitionIncognitoSessions(gate.ready);
13944
+ const incognitoAgents = new Set(state.incognito_agents ?? []);
13945
+ const { kept, skipped } = partitionIncognitoSessions(gate.ready, (session) => incognitoAgents.has(session.harness) || isIncognitoSession(session));
13772
13946
  return { queued: kept.reverse(), open: gate.open.reverse(), incognito: skipped.reverse() };
13773
13947
  } catch {
13774
13948
  return { queued: [], open: [], incognito: [] };
@@ -13781,155 +13955,6 @@ var init_backlog = __esm(() => {
13781
13955
  init_watermark();
13782
13956
  });
13783
13957
 
13784
- // src/sync/lock.ts
13785
- import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
13786
- import { join as join13 } from "node:path";
13787
- function processAlive(pid) {
13788
- try {
13789
- process.kill(pid, 0);
13790
- return true;
13791
- } catch (err) {
13792
- return err.code === "EPERM";
13793
- }
13794
- }
13795
- function lockPath(configDir = getConfigDir()) {
13796
- return join13(configDir, LOCK_FILENAME);
13797
- }
13798
- function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
13799
- if (!Number.isInteger(pid) || pid <= 0)
13800
- return false;
13801
- let killed = false;
13802
- try {
13803
- kill(-pid, "SIGTERM");
13804
- killed = true;
13805
- } catch {
13806
- try {
13807
- kill(pid, "SIGTERM");
13808
- killed = true;
13809
- } catch {}
13810
- }
13811
- try {
13812
- const path = lockPath(configDir);
13813
- if (existsSync13(path) && readFileSync14(path, "utf8") === String(pid)) {
13814
- rmSync2(path, { force: true });
13815
- }
13816
- } catch {}
13817
- return killed;
13818
- }
13819
- function fileLock(configDir = getConfigDir(), now = () => new Date) {
13820
- const path = lockPath(configDir);
13821
- let held = false;
13822
- const tryCreate = () => {
13823
- try {
13824
- writeFileSync10(path, String(process.pid), { flag: "wx" });
13825
- return true;
13826
- } catch {
13827
- return false;
13828
- }
13829
- };
13830
- return {
13831
- acquire() {
13832
- if (tryCreate()) {
13833
- held = true;
13834
- return true;
13835
- }
13836
- try {
13837
- const age = now().getTime() - statSync5(path).mtimeMs;
13838
- const holder = Number.parseInt(readFileSync14(path, "utf8"), 10);
13839
- const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
13840
- if (age > STALE_LOCK_MS || holderDead) {
13841
- rmSync2(path, { force: true });
13842
- held = tryCreate();
13843
- return held;
13844
- }
13845
- } catch {}
13846
- return false;
13847
- },
13848
- release() {
13849
- if (!held)
13850
- return;
13851
- held = false;
13852
- try {
13853
- if (existsSync13(path) && readFileSync14(path, "utf8") === String(process.pid)) {
13854
- rmSync2(path, { force: true });
13855
- }
13856
- } catch {}
13857
- }
13858
- };
13859
- }
13860
- var LOCK_FILENAME = "knowledge-sync.lock", STALE_LOCK_MS;
13861
- var init_lock = __esm(() => {
13862
- init_config();
13863
- STALE_LOCK_MS = 15 * 60 * 1000;
13864
- });
13865
-
13866
- // src/sync/status.ts
13867
- import { readFileSync as readFileSync15, statSync as statSync6 } from "node:fs";
13868
- function formatTokenCount(tokens) {
13869
- if (tokens < 1000)
13870
- return String(tokens);
13871
- if (tokens < 1e6) {
13872
- const k = tokens / 1000;
13873
- return `~${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\.0$/, "")}k`;
13874
- }
13875
- const m = tokens / 1e6;
13876
- return `~${m >= 100 ? Math.round(m) : m.toFixed(1).replace(/\.0$/, "")}M`;
13877
- }
13878
- function defaultIsProcessAlive2(pid) {
13879
- if (!Number.isInteger(pid) || pid <= 0)
13880
- return false;
13881
- try {
13882
- process.kill(pid, 0);
13883
- return true;
13884
- } catch (err) {
13885
- return err.code === "EPERM";
13886
- }
13887
- }
13888
- function defaultReadLog() {
13889
- try {
13890
- return readFileSync15(logger.getLogPath(), "utf-8");
13891
- } catch {
13892
- return "";
13893
- }
13894
- }
13895
- function readLockFile(configDir) {
13896
- const path = lockPath(configDir);
13897
- try {
13898
- const pid = Number.parseInt(readFileSync15(path, "utf-8"), 10);
13899
- return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync6(path).mtime };
13900
- } catch {
13901
- return null;
13902
- }
13903
- }
13904
- function recentSyncActivity(log) {
13905
- return log.split(`
13906
- `).filter((line) => line.includes("[sync]") || line.includes("[learner]")).slice(-ACTIVITY_LINES).map((line) => line.replace(/ \[(DEBUG|INFO|WARN|ERROR)\]/, ""));
13907
- }
13908
- function getSyncStatus(deps = {}) {
13909
- const configDir = deps.configDir ?? getConfigDir();
13910
- const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive2;
13911
- const readLog = deps.readLog ?? defaultReadLog;
13912
- const lock = readLockFile(configDir);
13913
- const running = lock !== null && isProcessAlive(lock.pid);
13914
- const state = loadSyncState(configDir);
13915
- const retryAt = backoffUntil(state);
13916
- return {
13917
- running,
13918
- ...lock ? { pid: lock.pid, startedAt: lock.mtime.toISOString() } : {},
13919
- ...lock && !running ? { staleLock: true } : {},
13920
- state,
13921
- ...retryAt ? { backoffUntil: retryAt.toISOString() } : {},
13922
- recentActivity: recentSyncActivity(readLog())
13923
- };
13924
- }
13925
- var ACTIVITY_LINES = 10;
13926
- var init_status = __esm(() => {
13927
- init_config();
13928
- init_logger();
13929
- init_lock();
13930
- init_watermark();
13931
- });
13932
-
13933
13958
  // src/sync/sync.ts
13934
13959
  function logGateResult(ready, inFlight, watermark) {
13935
13960
  const preview = ready.slice(0, LOG_PREVIEW_LIMIT).map((s) => `${s.harness}/${s.id}`).join(", ");
@@ -14055,7 +14080,9 @@ async function runKnowledgeSync(options = {}) {
14055
14080
  };
14056
14081
  }
14057
14082
  const worthStudying = deps.worthStudying ?? isWorthStudying;
14058
- const isIncognito = deps.isIncognito ?? isIncognitoSession;
14083
+ const isIncognitoChat = deps.isIncognito ?? isIncognitoSession;
14084
+ const incognitoAgents = new Set(state.incognito_agents ?? []);
14085
+ const isIncognito = (session) => incognitoAgents.has(session.harness) || isIncognitoChat(session);
14059
14086
  const studiedSnapshot = lastStudiedSnapshot(state.mined_sessions);
14060
14087
  const examined = [];
14061
14088
  const batch = [];
@@ -14262,7 +14289,7 @@ var init_conflicts = __esm(() => {
14262
14289
  });
14263
14290
 
14264
14291
  // src/telemetry/debug-id.ts
14265
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "274ecbf7-23f0-dedc-6475-6e2164756e21";
14292
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "8627229c-9519-9318-6475-6e2164756e21";
14266
14293
 
14267
14294
  // src/telemetry/telemetry.ts
14268
14295
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -15383,14 +15410,43 @@ Acknowledge in one line: "Dosu incognito: this session will not be studied."
15383
15410
  });
15384
15411
 
15385
15412
  // src/commands/knowledge-incognito.ts
15413
+ function ensureSlashCommand(agent) {
15414
+ try {
15415
+ agent.enable();
15416
+ } catch (err) {
15417
+ reportFailure(agent.name(), err, `could not install ${SLASH}`);
15418
+ }
15419
+ }
15420
+ function switchAction(incognito) {
15421
+ return (ids) => {
15422
+ const agents = resolveAgents(ids, allIncognitoAgents, getIncognitoAgent);
15423
+ if (agents.length === 0)
15424
+ return;
15425
+ try {
15426
+ setAgentsIncognito(agents.map((agent) => agent.id()), incognito);
15427
+ } catch (err) {
15428
+ reportFailure("Dosu", err, "could not save the setting");
15429
+ return;
15430
+ }
15431
+ for (const agent of agents) {
15432
+ ensureSlashCommand(agent);
15433
+ console.log(incognito ? `\uD83D\uDC7B ${agent.name()} is incognito: its sessions will not be studied` : `\uD83D\uDCDA ${agent.name()} is studied again`);
15434
+ }
15435
+ if (!incognito) {
15436
+ console.log(import_picocolors20.default.dim("Sessions that finished while incognito stay unstudied."));
15437
+ }
15438
+ };
15439
+ }
15386
15440
  function incognitoCommand() {
15387
- const cmd = new Command("incognito").description(`Manage the /${INCOGNITO_COMMAND_NAME} slash command that turns Dosu off for one session`);
15388
- cmd.command("status").description("Show whether the slash command is installed for each supported agent").option("--json", "Output as JSON").action((opts) => {
15441
+ const cmd = new Command("incognito").description("Keep a coding agent's sessions out of Dosu studying");
15442
+ cmd.command("status").description("Show which agents are incognito").option("--json", "Output as JSON").action((opts) => {
15443
+ const incognitoAgents = new Set(loadSyncState().incognito_agents ?? []);
15389
15444
  const rows = allIncognitoAgents().map((agent) => ({
15390
15445
  agent: agent.id(),
15391
15446
  name: agent.name(),
15392
15447
  installed: agent.isInstalled(),
15393
- enabled: agent.isEnabled(),
15448
+ incognito: incognitoAgents.has(agent.id()),
15449
+ command_installed: agent.isEnabled(),
15394
15450
  command_path: agent.commandPath()
15395
15451
  }));
15396
15452
  if (opts.json) {
@@ -15398,49 +15454,33 @@ function incognitoCommand() {
15398
15454
  return;
15399
15455
  }
15400
15456
  for (const row of rows) {
15401
- const state = !row.installed ? import_picocolors20.default.dim("not installed") : row.enabled ? import_picocolors20.default.green("enabled") : "disabled";
15402
- console.log(` ${row.agent.padEnd(8)} ${row.name.padEnd(14)} ${state}`);
15457
+ const state = !row.installed ? import_picocolors20.default.dim("agent not found") : row.incognito ? "\uD83D\uDC7B incognito (not studied)" : import_picocolors20.default.green("\uD83D\uDCDA studied");
15458
+ const missing = row.installed && !row.command_installed ? import_picocolors20.default.dim(` (${SLASH} missing)`) : "";
15459
+ console.log(` ${row.agent.padEnd(8)} ${row.name.padEnd(14)} ${state}${missing}`);
15403
15460
  }
15404
15461
  console.log(import_picocolors20.default.dim(`
15405
- Use 'dosu knowledge incognito enable|disable [agent...]' to change these.
15406
- ` + `Inside a session, run /${INCOGNITO_COMMAND_NAME} to keep that session out of studying.`));
15407
- });
15408
- cmd.command("enable [agents...]").description("Install the slash command for agents (default: all detected)").action((ids) => {
15409
- for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
15410
- try {
15411
- const action = agent.enable();
15412
- const verb = action === "unchanged" ? "already installed" : "installed";
15413
- console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb} (${agent.commandPath()})`);
15414
- } catch (err) {
15415
- reportFailure(agent.name(), err);
15416
- }
15417
- }
15418
- });
15419
- cmd.command("disable [agents...]").description("Remove the slash command from agents (default: all detected)").action((ids) => {
15420
- for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
15421
- try {
15422
- const action = agent.disable();
15423
- const verb = action === "removed" ? "removed" : "was not installed";
15424
- console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb}`);
15425
- } catch (err) {
15426
- reportFailure(agent.name(), err);
15427
- }
15428
- }
15462
+ Use 'dosu knowledge incognito on|off [agent...]' to change these.
15463
+ ` + `To keep a single chat out instead, type ${SLASH} in it.`));
15429
15464
  });
15465
+ cmd.command("on [agents...]").description("Stop studying these agents' sessions (default: all detected)").action(switchAction(true));
15466
+ cmd.command("off [agents...]").description("Study these agents' sessions again (default: all detected)").action(switchAction(false));
15430
15467
  return cmd;
15431
15468
  }
15432
- function reportFailure(agentName, err) {
15433
- console.error(import_picocolors20.default.red(`✗ ${agentName}: ${err instanceof Error ? err.message : String(err)}`));
15469
+ function reportFailure(label, err, what) {
15470
+ const message = err instanceof Error ? err.message : String(err);
15471
+ console.error(import_picocolors20.default.red(`✗ ${label}: ${what}: ${message}`));
15434
15472
  process.exitCode = 1;
15435
15473
  }
15436
- var import_picocolors20;
15474
+ var import_picocolors20, SLASH;
15437
15475
  var init_knowledge_incognito = __esm(() => {
15438
15476
  init_commander();
15439
15477
  init_agents3();
15440
15478
  init_incognito();
15479
+ init_watermark();
15441
15480
  init_agent_select();
15442
15481
  init_output();
15443
15482
  import_picocolors20 = __toESM(require_picocolors(), 1);
15483
+ SLASH = `/${INCOGNITO_COMMAND_NAME}`;
15444
15484
  });
15445
15485
 
15446
15486
  // src/statusline/agents.ts
@@ -66190,7 +66230,7 @@ ${dim(wrapLog("Dosu scans finished agent sessions in the background. Disable any
66190
66230
  const statuslines = installed.flatMap((r) => r.statusline ? [r.statusline] : []);
66191
66231
  if (statuslines.length > 0) {
66192
66232
  log2.success(`${formatSetupSummary(`Status line enabled for ${statuslines.length} agent(s):`, statuslines.map((item) => ({ label: item.name, path: item.path })))}
66193
- ${dim(wrapLog("Shows \uD83D\uDCDA Dosu studying…, \uD83D\uDC7B Dosu incognito, or ⚪ Dosu off/paused. Remove with 'dosu knowledge statusline disable'."))}`);
66233
+ ${dim(wrapLog("Shows \uD83D\uDCDA Dosu on/studying…, \uD83D\uDC7B Dosu incognito, or ⚪ Dosu off/paused. Remove with 'dosu knowledge statusline disable'."))}`);
66194
66234
  }
66195
66235
  for (const result of installed) {
66196
66236
  if (result.statuslineSuggestion) {
@@ -66201,7 +66241,7 @@ ${dim(wrapLog("Shows \uD83D\uDCDA Dosu studying…, \uD83D\uDC7B Dosu incognito,
66201
66241
  const incognitos = installed.flatMap((r) => r.incognito ? [r.incognito] : []);
66202
66242
  if (incognitos.length > 0) {
66203
66243
  log2.success(`${formatSetupSummary(`/dosu-incognito installed for ${incognitos.length} agent(s):`, incognitos.map((item) => ({ label: item.name, path: item.path })))}
66204
- ${dim(wrapLog("Run it inside a session to keep that session out of studying. Remove with 'dosu knowledge incognito disable'."))}`);
66244
+ ${dim(wrapLog("Type it in a chat to keep that chat out of Dosu. To keep a whole agent out, run 'dosu knowledge incognito on <agent>'."))}`);
66205
66245
  }
66206
66246
  if (removed.length > 0) {
66207
66247
  log2.info(formatSetupSummary(`Removed from ${removed.length} agent(s):`, removed.map((result) => ({
@@ -66542,6 +66582,64 @@ var init_upgrade = __esm(() => {
66542
66582
  SEMVER = /^\d+\.\d+\.\d+/;
66543
66583
  });
66544
66584
 
66585
+ // src/version/incognito-backfill-check.ts
66586
+ import { existsSync as existsSync31, mkdirSync as mkdirSync19, writeFileSync as writeFileSync21 } from "node:fs";
66587
+ import { join as join45 } from "node:path";
66588
+ function markerPath() {
66589
+ return join45(getConfigDir(), MARKER_FILENAME);
66590
+ }
66591
+ function writeMarker() {
66592
+ const dir = getConfigDir();
66593
+ if (!existsSync31(dir))
66594
+ mkdirSync19(dir, { recursive: true, mode: 448 });
66595
+ writeFileSync21(markerPath(), JSON.stringify({ done: true }), { mode: 384 });
66596
+ }
66597
+ function displayNotice3(names) {
66598
+ console.error(`
66599
+ ${import_picocolors38.default.green(`✓ Dosu: added the /${INCOGNITO_COMMAND_NAME} command to ${names.join(", ")}`)}
66600
+ ` + `${import_picocolors38.default.dim(` Type /${INCOGNITO_COMMAND_NAME} in a chat to keep that chat out of Dosu.`)}
66601
+ `);
66602
+ }
66603
+ function checkForIncognitoBackfill(options = {}) {
66604
+ const notify = options.notify ?? true;
66605
+ try {
66606
+ if (existsSync31(markerPath()))
66607
+ return;
66608
+ const added = [];
66609
+ let failed = false;
66610
+ for (const hook of allHookAgents()) {
66611
+ const agent = getIncognitoAgent(hook.id());
66612
+ if (!agent || !hook.isEnabled() || agent.isEnabled())
66613
+ continue;
66614
+ try {
66615
+ agent.enable();
66616
+ added.push(agent.name());
66617
+ } catch (err) {
66618
+ failed = true;
66619
+ logger.warn("incognito-backfill", `Install failed for ${agent.id()}: ${err}`);
66620
+ }
66621
+ }
66622
+ if (!failed)
66623
+ writeMarker();
66624
+ if (added.length > 0) {
66625
+ logger.info("incognito-backfill", `Installed /${INCOGNITO_COMMAND_NAME} for ${added}`);
66626
+ if (notify)
66627
+ displayNotice3(added);
66628
+ }
66629
+ } catch (err) {
66630
+ logger.error("incognito-backfill", `Incognito backfill failed: ${err}`);
66631
+ }
66632
+ }
66633
+ var import_picocolors38, MARKER_FILENAME = "incognito-backfill.json";
66634
+ var init_incognito_backfill_check = __esm(() => {
66635
+ init_config();
66636
+ init_logger();
66637
+ init_agents();
66638
+ init_agents3();
66639
+ init_incognito();
66640
+ import_picocolors38 = __toESM(require_picocolors(), 1);
66641
+ });
66642
+
66545
66643
  // src/tui/analytics-view.ts
66546
66644
  function analyticsListHeight(rows) {
66547
66645
  const room = frameMaxLines(rows) - ANALYTICS_VIEW_CHROME_LINES;
@@ -66660,7 +66758,7 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
66660
66758
  const rows = analyticsTabRows(tab, state, pageStats);
66661
66759
  const { visible, above, below } = windowReport(rows, scroll, height);
66662
66760
  const empty = tab === "overview" ? "No analytics yet. They appear after the first study run." : tab === "projects" ? "No per-project history yet. It fills in as sessions are studied." : pagesPending ? "Loading page analytics..." : "No page analytics yet.";
66663
- const listRows = visible.length > 0 ? visible.map((row) => import_picocolors38.default.dim(row)) : [import_picocolors38.default.dim(empty)];
66761
+ const listRows = visible.length > 0 ? visible.map((row) => import_picocolors39.default.dim(row)) : [import_picocolors39.default.dim(empty)];
66664
66762
  const scrollParts = [];
66665
66763
  if (above > 0)
66666
66764
  scrollParts.push(`↑ ${above} earlier`);
@@ -66676,9 +66774,9 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
66676
66774
  ], tab, width, { spread: false }),
66677
66775
  "",
66678
66776
  ...listRows,
66679
- ...scrollParts.length > 0 ? [import_picocolors38.default.dim(scrollParts.join(" · "))] : [],
66777
+ ...scrollParts.length > 0 ? [import_picocolors39.default.dim(scrollParts.join(" · "))] : [],
66680
66778
  "",
66681
- import_picocolors38.default.dim("tab switch · ↑↓ scroll · esc back")
66779
+ import_picocolors39.default.dim("tab switch · ↑↓ scroll · esc back")
66682
66780
  ];
66683
66781
  return lines.join(`
66684
66782
  `);
@@ -66775,7 +66873,7 @@ ${CLEAR_BELOW2}`);
66775
66873
  input.on("data", onData);
66776
66874
  });
66777
66875
  }
66778
- var import_picocolors38, ESC8, HIDE_CURSOR4, SHOW_CURSOR4, CTRL_C5, KEY_UP5, KEY_DOWN5, KEY_RIGHT4, KEY_LEFT4, CURSOR_HOME2, CLEAR_BELOW2, CLEAR_EOL2, ANALYTICS_VIEW_POLL_MS = 1000, ANALYTICS_VIEW_LINES = 14, ANALYTICS_VIEW_CHROME_LINES = 8, ANALYTICS_VIEW_TABS, TOP_PAGES_LIMIT = 5, TOP_CITED_DAYS = 30, label = (text) => text.padEnd(26);
66876
+ var import_picocolors39, ESC8, HIDE_CURSOR4, SHOW_CURSOR4, CTRL_C5, KEY_UP5, KEY_DOWN5, KEY_RIGHT4, KEY_LEFT4, CURSOR_HOME2, CLEAR_BELOW2, CLEAR_EOL2, ANALYTICS_VIEW_POLL_MS = 1000, ANALYTICS_VIEW_LINES = 14, ANALYTICS_VIEW_CHROME_LINES = 8, ANALYTICS_VIEW_TABS, TOP_PAGES_LIMIT = 5, TOP_CITED_DAYS = 30, label = (text) => text.padEnd(26);
66779
66877
  var init_analytics_view = __esm(() => {
66780
66878
  init_trpc();
66781
66879
  init_config();
@@ -66783,7 +66881,7 @@ var init_analytics_view = __esm(() => {
66783
66881
  init_alt_screen();
66784
66882
  init_layout();
66785
66883
  init_menu();
66786
- import_picocolors38 = __toESM(require_picocolors(), 1);
66884
+ import_picocolors39 = __toESM(require_picocolors(), 1);
66787
66885
  ESC8 = String.fromCharCode(27);
66788
66886
  HIDE_CURSOR4 = `${ESC8}[?25l`;
66789
66887
  SHOW_CURSOR4 = `${ESC8}[?25h`;
@@ -66801,7 +66899,7 @@ var init_analytics_view = __esm(() => {
66801
66899
  // src/tui/banner.ts
66802
66900
  function paintLogoRow(row) {
66803
66901
  return row.map(([tone, art]) => {
66804
- if (!import_picocolors39.default.isColorSupported)
66902
+ if (!import_picocolors40.default.isColorSupported)
66805
66903
  return art;
66806
66904
  const { fg, fallback } = LOGO_TONES[tone];
66807
66905
  return hasTruecolor() ? `${fg}${art}\x1B[39m` : fallback(art);
@@ -66809,14 +66907,14 @@ function paintLogoRow(row) {
66809
66907
  }
66810
66908
  function checklistRows(ctx) {
66811
66909
  const on = brand(CHECK2);
66812
- const off = import_picocolors39.default.dim(CIRCLE);
66910
+ const off = import_picocolors40.default.dim(CIRCLE);
66813
66911
  const rows = [["workspace", ctx.directory]];
66814
66912
  rows.push([
66815
66913
  "account",
66816
- ctx.sessionExpired ? `${off} ${import_picocolors39.default.yellow("session expired")} ${import_picocolors39.default.dim(`${DOT3} run Log in`)}` : ctx.signedIn ? `${on} signed in` : `${off} ${import_picocolors39.default.dim(`not signed in ${DOT3} run Setup`)}`
66914
+ ctx.sessionExpired ? `${off} ${import_picocolors40.default.yellow("session expired")} ${import_picocolors40.default.dim(`${DOT3} run Log in`)}` : ctx.signedIn ? `${on} signed in` : `${off} ${import_picocolors40.default.dim(`not signed in ${DOT3} run Setup`)}`
66817
66915
  ]);
66818
66916
  const missing = new Set(ctx.setupMissing ?? []);
66819
- const warnRow = `${off} ${import_picocolors39.default.yellow("not configured")} ${import_picocolors39.default.dim(`${DOT3} run Setup`)}`;
66917
+ const warnRow = `${off} ${import_picocolors40.default.yellow("not configured")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`;
66820
66918
  if (missing.has("MCP"))
66821
66919
  rows.push(["mcp", warnRow]);
66822
66920
  else if (ctx.deploymentName)
@@ -66828,7 +66926,7 @@ function checklistRows(ctx) {
66828
66926
  if (ctx.repoAgentsMd) {
66829
66927
  rows.push([
66830
66928
  "repo",
66831
- ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${import_picocolors39.default.yellow(ctx.repoAgentsMd === "outdated" ? "AGENTS.md Dosu section outdated" : "AGENTS.md missing the Dosu section")} ${import_picocolors39.default.dim(`${DOT3} run Setup`)}`
66929
+ ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${import_picocolors40.default.yellow(ctx.repoAgentsMd === "outdated" ? "AGENTS.md Dosu section outdated" : "AGENTS.md missing the Dosu section")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`
66832
66930
  ]);
66833
66931
  }
66834
66932
  if (missing.has("agents"))
@@ -66840,24 +66938,24 @@ function checklistRows(ctx) {
66840
66938
  if (ctx.studying) {
66841
66939
  rows.push([
66842
66940
  "sync",
66843
- `\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors39.default.dim(`${DOT3} see activity`)}`
66941
+ `\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors40.default.dim(`${DOT3} see activity`)}`
66844
66942
  ]);
66845
66943
  }
66846
66944
  if (ctx.update) {
66847
66945
  rows.push([
66848
66946
  "update",
66849
- `${import_picocolors39.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors39.default.dim(`${DOT3} ${ctx.update.hint}`)}`
66947
+ `${import_picocolors40.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors40.default.dim(`${DOT3} ${ctx.update.hint}`)}`
66850
66948
  ]);
66851
66949
  }
66852
66950
  const labelWidth = Math.max(...rows.map(([label]) => label.length));
66853
- return rows.map(([label, value]) => `${import_picocolors39.default.dim(label.padEnd(labelWidth))} ${value}`);
66951
+ return rows.map(([label, value]) => `${import_picocolors40.default.dim(label.padEnd(labelWidth))} ${value}`);
66854
66952
  }
66855
66953
  function renderBanner(ctx) {
66856
66954
  const logo = LOGO_ROWS.map(paintLogoRow);
66857
66955
  const text = [
66858
66956
  ...checklistRows(ctx),
66859
66957
  "",
66860
- `${brandBadge("dosu-cli")} ${import_picocolors39.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
66958
+ `${brandBadge("dosu-cli")} ${import_picocolors40.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
66861
66959
  ];
66862
66960
  const height = Math.max(logo.length, text.length);
66863
66961
  const combined = [];
@@ -66870,10 +66968,10 @@ function renderBanner(ctx) {
66870
66968
  return ["", ...combined, ""].join(`
66871
66969
  `);
66872
66970
  }
66873
- var import_picocolors39, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ";
66971
+ var import_picocolors40, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ";
66874
66972
  var init_banner = __esm(() => {
66875
66973
  init_styles();
66876
- import_picocolors39 = __toESM(require_picocolors(), 1);
66974
+ import_picocolors40 = __toESM(require_picocolors(), 1);
66877
66975
  LOGO_ROWS = [
66878
66976
  [["sage", "▄▄▄▄▄▄"]],
66879
66977
  [["sage", "██ ▀▄"]],
@@ -66884,8 +66982,8 @@ var init_banner = __esm(() => {
66884
66982
  LOGO_MARK = LOGO_ROWS.map((row) => row.map(([, art]) => art).join(""));
66885
66983
  LOGO_WIDTH = Math.max(...LOGO_MARK.map((row) => row.length));
66886
66984
  LOGO_TONES = {
66887
- sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors39.default.green },
66888
- moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) => import_picocolors39.default.dim(import_picocolors39.default.green(art)) }
66985
+ sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors40.default.green },
66986
+ moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) => import_picocolors40.default.dim(import_picocolors40.default.green(art)) }
66889
66987
  };
66890
66988
  });
66891
66989
 
@@ -66997,16 +67095,16 @@ function renderPagesFrame(model, width, selected) {
66997
67095
  const body = [];
66998
67096
  let scrollHint = "";
66999
67097
  if (model.phase === "loading") {
67000
- body.push(import_picocolors40.default.dim("Loading pages…"));
67098
+ body.push(import_picocolors41.default.dim("Loading pages…"));
67001
67099
  } else if (model.phase === "error") {
67002
- body.push(import_picocolors40.default.yellow(clip3(model.message, width)));
67100
+ body.push(import_picocolors41.default.yellow(clip3(model.message, width)));
67003
67101
  } else if (model.pages.length === 0) {
67004
- body.push(import_picocolors40.default.dim("No pages in this Library yet."));
67102
+ body.push(import_picocolors41.default.dim("No pages in this Library yet."));
67005
67103
  } else {
67006
67104
  const rows = pageRows2(model.pages, width - 2);
67007
67105
  const { start, above } = windowSelection(rows.length, selected);
67008
67106
  const visible = rows.slice(start, start + PAGES_VIEW_LINES);
67009
- body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${import_picocolors40.default.bold(row)}` : ` ${import_picocolors40.default.dim(row)}`));
67107
+ body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${import_picocolors41.default.bold(row)}` : ` ${import_picocolors41.default.dim(row)}`));
67010
67108
  const below = Math.max(0, Math.max(model.total, rows.length) - start - PAGES_VIEW_LINES);
67011
67109
  const parts = [];
67012
67110
  if (above > 0)
@@ -67015,14 +67113,14 @@ function renderPagesFrame(model, width, selected) {
67015
67113
  parts.push(`↓ ${below} more`);
67016
67114
  scrollHint = parts.join(" · ");
67017
67115
  }
67018
- const count = model.phase === "ready" ? ` ${import_picocolors40.default.dim(model.pages.length < model.total ? `(${model.pages.length} of ${model.total})` : `(${model.pages.length})`)}` : "";
67116
+ const count = model.phase === "ready" ? ` ${import_picocolors41.default.dim(model.pages.length < model.total ? `(${model.pages.length} of ${model.total})` : `(${model.pages.length})`)}` : "";
67019
67117
  const lines = [
67020
67118
  `${breadcrumb(["home", "pages"], width)}${count}`,
67021
67119
  "",
67022
67120
  ...body,
67023
- ...scrollHint ? [import_picocolors40.default.dim(scrollHint)] : [],
67121
+ ...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
67024
67122
  "",
67025
- import_picocolors40.default.dim("↑↓ move · enter open · esc back")
67123
+ import_picocolors41.default.dim("↑↓ move · enter open · esc back")
67026
67124
  ];
67027
67125
  return lines.join(`
67028
67126
  `);
@@ -67031,9 +67129,9 @@ function renderPageFrame(page, content, width, scroll) {
67031
67129
  const body = [];
67032
67130
  let scrollHint = "";
67033
67131
  if (content.phase === "loading") {
67034
- body.push(import_picocolors40.default.dim("Loading page…"));
67132
+ body.push(import_picocolors41.default.dim("Loading page…"));
67035
67133
  } else if (content.phase === "error") {
67036
- body.push(import_picocolors40.default.yellow(clip3(content.message, width)));
67134
+ body.push(import_picocolors41.default.yellow(clip3(content.message, width)));
67037
67135
  } else {
67038
67136
  const rows = wrapBody(content.body, width);
67039
67137
  const { visible, above, below } = windowReport(rows, scroll, PAGE_BODY_LINES);
@@ -67048,12 +67146,12 @@ function renderPageFrame(page, content, width, scroll) {
67048
67146
  const meta = `${page.type} · ${page.published ? "published" : "draft"} · updated ${page.updated_at.slice(0, 10)}`;
67049
67147
  const lines = [
67050
67148
  breadcrumb(["home", "pages", page.title], width),
67051
- import_picocolors40.default.dim(clip3(meta, width)),
67149
+ import_picocolors41.default.dim(clip3(meta, width)),
67052
67150
  "",
67053
67151
  ...body,
67054
- ...scrollHint ? [import_picocolors40.default.dim(scrollHint)] : [],
67152
+ ...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
67055
67153
  "",
67056
- import_picocolors40.default.dim("↑↓ scroll · esc back to pages")
67154
+ import_picocolors41.default.dim("↑↓ scroll · esc back to pages")
67057
67155
  ];
67058
67156
  return lines.join(`
67059
67157
  `);
@@ -67202,7 +67300,7 @@ ${CLEAR_BELOW3}`);
67202
67300
  input.on("data", onData);
67203
67301
  });
67204
67302
  }
67205
- var import_picocolors40, ESC9, HIDE_CURSOR5, SHOW_CURSOR5, CTRL_C6, KEY_UP6, KEY_DOWN6, CURSOR_HOME3, CLEAR_BELOW3, CLEAR_EOL3, PAGES_VIEW_LINES = 12, PAGE_BODY_LINES = 14, PAGES_FETCH_BATCH = 100;
67303
+ var import_picocolors41, ESC9, HIDE_CURSOR5, SHOW_CURSOR5, CTRL_C6, KEY_UP6, KEY_DOWN6, CURSOR_HOME3, CLEAR_BELOW3, CLEAR_EOL3, PAGES_VIEW_LINES = 12, PAGE_BODY_LINES = 14, PAGES_FETCH_BATCH = 100;
67206
67304
  var init_pages_view = __esm(() => {
67207
67305
  init_trpc();
67208
67306
  init_config();
@@ -67212,7 +67310,7 @@ var init_pages_view = __esm(() => {
67212
67310
  init_analytics_view();
67213
67311
  init_layout();
67214
67312
  init_menu();
67215
- import_picocolors40 = __toESM(require_picocolors(), 1);
67313
+ import_picocolors41 = __toESM(require_picocolors(), 1);
67216
67314
  ESC9 = String.fromCharCode(27);
67217
67315
  HIDE_CURSOR5 = `${ESC9}[?25l`;
67218
67316
  SHOW_CURSOR5 = `${ESC9}[?25h`;
@@ -67325,7 +67423,7 @@ function isSetUp(cfg) {
67325
67423
  }
67326
67424
  function setupHint(cfg) {
67327
67425
  const started = Boolean(cfg.active_account?.target);
67328
- return import_picocolors41.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
67426
+ return import_picocolors42.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
67329
67427
  }
67330
67428
  function isStudying() {
67331
67429
  try {
@@ -67570,7 +67668,7 @@ function handleLogout(cfg) {
67570
67668
  saveConfig(cfg);
67571
67669
  log2.success("Credentials cleared.");
67572
67670
  }
67573
- var import_picocolors41, ESC10, CLEAR_SCREEN;
67671
+ var import_picocolors42, ESC10, CLEAR_SCREEN;
67574
67672
  var init_tui = __esm(() => {
67575
67673
  init_client();
67576
67674
  init_config();
@@ -67594,7 +67692,7 @@ var init_tui = __esm(() => {
67594
67692
  init_menu();
67595
67693
  init_pages_view();
67596
67694
  init_prompts();
67597
- import_picocolors41 = __toESM(require_picocolors(), 1);
67695
+ import_picocolors42 = __toESM(require_picocolors(), 1);
67598
67696
  ESC10 = String.fromCharCode(27);
67599
67697
  CLEAR_SCREEN = `${ESC10}[2J${ESC10}[H`;
67600
67698
  });
@@ -68313,6 +68411,7 @@ function createProgram(options = {}) {
68313
68411
  checkForReadyTasks();
68314
68412
  if (shouldRunMcpRefreshCheck(actionCommand)) {
68315
68413
  checkForMcpRefresh({ notify: !launchesTUI });
68414
+ checkForIncognitoBackfill({ notify: !launchesTUI });
68316
68415
  }
68317
68416
  }
68318
68417
  const command = commandTelemetryName(actionCommand);
@@ -68743,6 +68842,7 @@ var init_cli = __esm(() => {
68743
68842
  init_styles();
68744
68843
  init_settings();
68745
68844
  init_telemetry();
68845
+ init_incognito_backfill_check();
68746
68846
  init_mcp_refresh_check();
68747
68847
  init_pending_tasks_check();
68748
68848
  init_skill_update_check();
@@ -68781,4 +68881,4 @@ main().catch((err) => {
68781
68881
  process.exit(1);
68782
68882
  });
68783
68883
 
68784
- //# debugId=274ecbf7-23f0-dedc-6475-6e2164756e21
68884
+ //# debugId=8627229c-9519-9318-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.65.1",
3
+ "version": "0.66.0",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Set up Dosu MCP for AI tools and work with Dosu Libraries, docs, and reviews",
6
6
  "license": "MIT",