@dosu/cli 0.65.0 → 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 +15 -12
  2. package/bin/dosu.js +397 -323
  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.65.0", 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") {
@@ -11684,30 +11857,6 @@ ${page.body}`);
11684
11857
  }
11685
11858
  console.log(import_picocolors16.default.green(`Document restored to version ${opts.revision}.`));
11686
11859
  });
11687
- cmd.command("generate").description("Generate a document using AI").requiredOption("--title <title>", "Document title").option("--instructions <text>", "Custom generation instructions").option("--json", "Output as JSON").action(async (opts) => {
11688
- const cfg = requireConfig5();
11689
- const client = createTypedClient(cfg);
11690
- const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
11691
- const result = await backendPost2("/doc/generate", requireAPIKey(cfg), {
11692
- knowledge_store_id: ksId,
11693
- title: opts.title,
11694
- instructions: opts.instructions
11695
- });
11696
- if (opts.json) {
11697
- printResult(result, opts);
11698
- return;
11699
- }
11700
- console.log(import_picocolors16.default.green("Document generation started."));
11701
- });
11702
- cmd.command("auto-tag").description("Auto-tag a document using AI").argument("<id>", "Page ID").option("--json", "Output as JSON").action(async (id, opts) => {
11703
- const cfg = requireConfig5();
11704
- const result = await backendPost2("/doc/auto-tag", requireAPIKey(cfg), { page_id: id });
11705
- if (opts.json) {
11706
- printResult(result, opts);
11707
- return;
11708
- }
11709
- console.log(import_picocolors16.default.green("Auto-tagging started."));
11710
- });
11711
11860
  cmd.command("import").description("Import documents from an external platform").addArgument(new Argument("<platform>", "Import platform").choices([...IMPORT_PLATFORMS])).requiredOption("--files <ids>", "Comma-separated file/page IDs to import").option("--json", "Output as JSON").action(async (platform, opts) => {
11712
11861
  const cfg = requireConfig5();
11713
11862
  const client = createTypedClient(cfg);
@@ -12173,21 +12322,21 @@ var init_branch = __esm(() => {
12173
12322
  });
12174
12323
 
12175
12324
  // src/sessions/capture.ts
12176
- import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync3, writeFileSync as writeFileSync7 } from "node:fs";
12177
- 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";
12178
12327
  function capturePath(configDir, key) {
12179
12328
  const [harness, id, ...rest] = key.split("/");
12180
12329
  if (rest.length > 0 || !SAFE_SEGMENT.test(harness ?? "") || !SAFE_SEGMENT.test(id ?? "")) {
12181
12330
  return null;
12182
12331
  }
12183
- return join10(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
12332
+ return join11(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
12184
12333
  }
12185
12334
  function readCapturedSession(key, configDir = getConfigDir()) {
12186
12335
  const path = capturePath(configDir, key);
12187
12336
  if (!path)
12188
12337
  return null;
12189
12338
  try {
12190
- const raw = JSON.parse(readFileSync11(path, "utf-8"));
12339
+ const raw = JSON.parse(readFileSync13(path, "utf-8"));
12191
12340
  return {
12192
12341
  ...typeof raw.dir === "string" ? { dir: raw.dir } : {},
12193
12342
  ...typeof raw.branch === "string" ? { branch: raw.branch } : {},
@@ -12210,11 +12359,11 @@ function recordCapturedSession(key, update, configDir = getConfigDir(), now = ne
12210
12359
  at: now.toISOString()
12211
12360
  };
12212
12361
  try {
12213
- const parent = join10(path, "..");
12214
- if (!existsSync11(parent))
12362
+ const parent = join11(path, "..");
12363
+ if (!existsSync12(parent))
12215
12364
  mkdirSync7(parent, { recursive: true, mode: 448 });
12216
12365
  const tmp = `${path}.${process.pid}.tmp`;
12217
- writeFileSync7(tmp, JSON.stringify(record), { mode: 384 });
12366
+ writeFileSync8(tmp, JSON.stringify(record), { mode: 384 });
12218
12367
  renameSync3(tmp, path);
12219
12368
  return true;
12220
12369
  } catch (err) {
@@ -12295,22 +12444,22 @@ var init_capture = __esm(() => {
12295
12444
  // src/sessions/project-dir.ts
12296
12445
  import {
12297
12446
  closeSync as closeSync4,
12298
- existsSync as existsSync12,
12447
+ existsSync as existsSync13,
12299
12448
  mkdirSync as mkdirSync8,
12300
12449
  openSync as openSync4,
12301
- readFileSync as readFileSync12,
12450
+ readFileSync as readFileSync14,
12302
12451
  readSync as readSync3,
12303
12452
  renameSync as renameSync4,
12304
- statSync as statSync4,
12305
- writeFileSync as writeFileSync8
12453
+ statSync as statSync6,
12454
+ writeFileSync as writeFileSync9
12306
12455
  } from "node:fs";
12307
- import { join as join11 } from "node:path";
12456
+ import { join as join12 } from "node:path";
12308
12457
  function cachePath(configDir) {
12309
- return join11(configDir, CACHE_FILENAME2);
12458
+ return join12(configDir, CACHE_FILENAME2);
12310
12459
  }
12311
12460
  function loadCacheFile(configDir) {
12312
12461
  try {
12313
- const raw = JSON.parse(readFileSync12(cachePath(configDir), "utf-8"));
12462
+ const raw = JSON.parse(readFileSync14(cachePath(configDir), "utf-8"));
12314
12463
  if (raw.schema_version !== CACHE_SCHEMA_VERSION || typeof raw.entries !== "object")
12315
12464
  return {};
12316
12465
  return raw.entries;
@@ -12320,12 +12469,12 @@ function loadCacheFile(configDir) {
12320
12469
  }
12321
12470
  function saveCacheFile(configDir, entries) {
12322
12471
  try {
12323
- if (!existsSync12(configDir))
12472
+ if (!existsSync13(configDir))
12324
12473
  mkdirSync8(configDir, { recursive: true, mode: 448 });
12325
12474
  const path = cachePath(configDir);
12326
12475
  const tmp = `${path}.${process.pid}.tmp`;
12327
12476
  const file = { schema_version: CACHE_SCHEMA_VERSION, entries };
12328
- writeFileSync8(tmp, JSON.stringify(file), { mode: 384 });
12477
+ writeFileSync9(tmp, JSON.stringify(file), { mode: 384 });
12329
12478
  renameSync4(tmp, path);
12330
12479
  } catch {}
12331
12480
  }
@@ -12360,7 +12509,7 @@ function cwdFromJsonlHead(text) {
12360
12509
  }
12361
12510
  return null;
12362
12511
  }
12363
- function unmungeSlug(slug, exists = existsSync12) {
12512
+ function unmungeSlug(slug, exists = existsSync13) {
12364
12513
  const tokens = slug.replace(/^-/, "").split("-");
12365
12514
  if (tokens.length === 0 || tokens[0] === "")
12366
12515
  return null;
@@ -12379,20 +12528,20 @@ function unmungeSlug(slug, exists = existsSync12) {
12379
12528
  }
12380
12529
  function readWholeFile(path) {
12381
12530
  try {
12382
- return readFileSync12(path, "utf-8");
12531
+ return readFileSync14(path, "utf-8");
12383
12532
  } catch {
12384
12533
  return null;
12385
12534
  }
12386
12535
  }
12387
12536
  function fileMtime(path) {
12388
12537
  try {
12389
- return statSync4(path).mtime.toISOString();
12538
+ return statSync6(path).mtime.toISOString();
12390
12539
  } catch {
12391
12540
  return "";
12392
12541
  }
12393
12542
  }
12394
12543
  function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
12395
- const exists = deps.exists ?? existsSync12;
12544
+ const exists = deps.exists ?? existsSync13;
12396
12545
  const head = deps.readHead ?? readHead;
12397
12546
  const mtime = deps.mtime ?? fileMtime;
12398
12547
  const captured = deps.captured ?? ((key) => readCapturedSession(key, configDir));
@@ -13243,7 +13392,7 @@ var init_queries = __esm(() => {
13243
13392
  });
13244
13393
 
13245
13394
  // src/report/digest.ts
13246
- import { readFileSync as readFileSync13 } from "node:fs";
13395
+ import { readFileSync as readFileSync15 } from "node:fs";
13247
13396
  function asRecord2(value) {
13248
13397
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
13249
13398
  }
@@ -13474,11 +13623,11 @@ function sessionToDigest(session) {
13474
13623
  try {
13475
13624
  switch (session.harness) {
13476
13625
  case "claude":
13477
- return { turns: digestClaude(readFileSync13(session.path, "utf8")) };
13626
+ return { turns: digestClaude(readFileSync15(session.path, "utf8")) };
13478
13627
  case "cursor":
13479
- return { turns: digestCursor(readFileSync13(session.path, "utf8")) };
13628
+ return { turns: digestCursor(readFileSync15(session.path, "utf8")) };
13480
13629
  case "codex":
13481
- return { turns: digestCodex(readFileSync13(session.path, "utf8")) };
13630
+ return { turns: digestCodex(readFileSync15(session.path, "utf8")) };
13482
13631
  case "opencode": {
13483
13632
  const turns = readSessionTurns(session).map((turn, index) => ({
13484
13633
  role: turn.role,
@@ -13699,17 +13848,17 @@ var init_notes = __esm(() => {
13699
13848
  });
13700
13849
 
13701
13850
  // src/report/write.ts
13702
- import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "node:fs";
13851
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "node:fs";
13703
13852
  import { tmpdir } from "node:os";
13704
- 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";
13705
13854
  import { pathToFileURL } from "node:url";
13706
13855
  function defaultReportPath() {
13707
- return join12(tmpdir(), "dosu-knowledge-report.html");
13856
+ return join13(tmpdir(), "dosu-knowledge-report.html");
13708
13857
  }
13709
13858
  async function writeAndOpenReport(options) {
13710
13859
  const out = resolve2(options.out ?? defaultReportPath());
13711
13860
  mkdirSync9(dirname4(out), { recursive: true });
13712
- writeFileSync9(out, options.html, "utf8");
13861
+ writeFileSync10(out, options.html, "utf8");
13713
13862
  if (options.open !== false) {
13714
13863
  const url = pathToFileURL(out).href;
13715
13864
  if (options.openUrl) {
@@ -13792,7 +13941,8 @@ function listSessionBacklog() {
13792
13941
  const sessions = filterSessionsByRepo(scanned, filter, resolver.resolveRepo);
13793
13942
  resolver.flush();
13794
13943
  const gate = gateSessions(sessions, state.watermark);
13795
- 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));
13796
13946
  return { queued: kept.reverse(), open: gate.open.reverse(), incognito: skipped.reverse() };
13797
13947
  } catch {
13798
13948
  return { queued: [], open: [], incognito: [] };
@@ -13805,155 +13955,6 @@ var init_backlog = __esm(() => {
13805
13955
  init_watermark();
13806
13956
  });
13807
13957
 
13808
- // src/sync/lock.ts
13809
- import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
13810
- import { join as join13 } from "node:path";
13811
- function processAlive(pid) {
13812
- try {
13813
- process.kill(pid, 0);
13814
- return true;
13815
- } catch (err) {
13816
- return err.code === "EPERM";
13817
- }
13818
- }
13819
- function lockPath(configDir = getConfigDir()) {
13820
- return join13(configDir, LOCK_FILENAME);
13821
- }
13822
- function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
13823
- if (!Number.isInteger(pid) || pid <= 0)
13824
- return false;
13825
- let killed = false;
13826
- try {
13827
- kill(-pid, "SIGTERM");
13828
- killed = true;
13829
- } catch {
13830
- try {
13831
- kill(pid, "SIGTERM");
13832
- killed = true;
13833
- } catch {}
13834
- }
13835
- try {
13836
- const path = lockPath(configDir);
13837
- if (existsSync13(path) && readFileSync14(path, "utf8") === String(pid)) {
13838
- rmSync2(path, { force: true });
13839
- }
13840
- } catch {}
13841
- return killed;
13842
- }
13843
- function fileLock(configDir = getConfigDir(), now = () => new Date) {
13844
- const path = lockPath(configDir);
13845
- let held = false;
13846
- const tryCreate = () => {
13847
- try {
13848
- writeFileSync10(path, String(process.pid), { flag: "wx" });
13849
- return true;
13850
- } catch {
13851
- return false;
13852
- }
13853
- };
13854
- return {
13855
- acquire() {
13856
- if (tryCreate()) {
13857
- held = true;
13858
- return true;
13859
- }
13860
- try {
13861
- const age = now().getTime() - statSync5(path).mtimeMs;
13862
- const holder = Number.parseInt(readFileSync14(path, "utf8"), 10);
13863
- const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
13864
- if (age > STALE_LOCK_MS || holderDead) {
13865
- rmSync2(path, { force: true });
13866
- held = tryCreate();
13867
- return held;
13868
- }
13869
- } catch {}
13870
- return false;
13871
- },
13872
- release() {
13873
- if (!held)
13874
- return;
13875
- held = false;
13876
- try {
13877
- if (existsSync13(path) && readFileSync14(path, "utf8") === String(process.pid)) {
13878
- rmSync2(path, { force: true });
13879
- }
13880
- } catch {}
13881
- }
13882
- };
13883
- }
13884
- var LOCK_FILENAME = "knowledge-sync.lock", STALE_LOCK_MS;
13885
- var init_lock = __esm(() => {
13886
- init_config();
13887
- STALE_LOCK_MS = 15 * 60 * 1000;
13888
- });
13889
-
13890
- // src/sync/status.ts
13891
- import { readFileSync as readFileSync15, statSync as statSync6 } from "node:fs";
13892
- function formatTokenCount(tokens) {
13893
- if (tokens < 1000)
13894
- return String(tokens);
13895
- if (tokens < 1e6) {
13896
- const k = tokens / 1000;
13897
- return `~${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\.0$/, "")}k`;
13898
- }
13899
- const m = tokens / 1e6;
13900
- return `~${m >= 100 ? Math.round(m) : m.toFixed(1).replace(/\.0$/, "")}M`;
13901
- }
13902
- function defaultIsProcessAlive2(pid) {
13903
- if (!Number.isInteger(pid) || pid <= 0)
13904
- return false;
13905
- try {
13906
- process.kill(pid, 0);
13907
- return true;
13908
- } catch (err) {
13909
- return err.code === "EPERM";
13910
- }
13911
- }
13912
- function defaultReadLog() {
13913
- try {
13914
- return readFileSync15(logger.getLogPath(), "utf-8");
13915
- } catch {
13916
- return "";
13917
- }
13918
- }
13919
- function readLockFile(configDir) {
13920
- const path = lockPath(configDir);
13921
- try {
13922
- const pid = Number.parseInt(readFileSync15(path, "utf-8"), 10);
13923
- return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync6(path).mtime };
13924
- } catch {
13925
- return null;
13926
- }
13927
- }
13928
- function recentSyncActivity(log) {
13929
- return log.split(`
13930
- `).filter((line) => line.includes("[sync]") || line.includes("[learner]")).slice(-ACTIVITY_LINES).map((line) => line.replace(/ \[(DEBUG|INFO|WARN|ERROR)\]/, ""));
13931
- }
13932
- function getSyncStatus(deps = {}) {
13933
- const configDir = deps.configDir ?? getConfigDir();
13934
- const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive2;
13935
- const readLog = deps.readLog ?? defaultReadLog;
13936
- const lock = readLockFile(configDir);
13937
- const running = lock !== null && isProcessAlive(lock.pid);
13938
- const state = loadSyncState(configDir);
13939
- const retryAt = backoffUntil(state);
13940
- return {
13941
- running,
13942
- ...lock ? { pid: lock.pid, startedAt: lock.mtime.toISOString() } : {},
13943
- ...lock && !running ? { staleLock: true } : {},
13944
- state,
13945
- ...retryAt ? { backoffUntil: retryAt.toISOString() } : {},
13946
- recentActivity: recentSyncActivity(readLog())
13947
- };
13948
- }
13949
- var ACTIVITY_LINES = 10;
13950
- var init_status = __esm(() => {
13951
- init_config();
13952
- init_logger();
13953
- init_lock();
13954
- init_watermark();
13955
- });
13956
-
13957
13958
  // src/sync/sync.ts
13958
13959
  function logGateResult(ready, inFlight, watermark) {
13959
13960
  const preview = ready.slice(0, LOG_PREVIEW_LIMIT).map((s) => `${s.harness}/${s.id}`).join(", ");
@@ -14079,7 +14080,9 @@ async function runKnowledgeSync(options = {}) {
14079
14080
  };
14080
14081
  }
14081
14082
  const worthStudying = deps.worthStudying ?? isWorthStudying;
14082
- 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);
14083
14086
  const studiedSnapshot = lastStudiedSnapshot(state.mined_sessions);
14084
14087
  const examined = [];
14085
14088
  const batch = [];
@@ -14286,7 +14289,7 @@ var init_conflicts = __esm(() => {
14286
14289
  });
14287
14290
 
14288
14291
  // src/telemetry/debug-id.ts
14289
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "a31208d6-6e9d-91e6-6475-6e2164756e21";
14292
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "8627229c-9519-9318-6475-6e2164756e21";
14290
14293
 
14291
14294
  // src/telemetry/telemetry.ts
14292
14295
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -15407,14 +15410,43 @@ Acknowledge in one line: "Dosu incognito: this session will not be studied."
15407
15410
  });
15408
15411
 
15409
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
+ }
15410
15440
  function incognitoCommand() {
15411
- const cmd = new Command("incognito").description(`Manage the /${INCOGNITO_COMMAND_NAME} slash command that turns Dosu off for one session`);
15412
- 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 ?? []);
15413
15444
  const rows = allIncognitoAgents().map((agent) => ({
15414
15445
  agent: agent.id(),
15415
15446
  name: agent.name(),
15416
15447
  installed: agent.isInstalled(),
15417
- enabled: agent.isEnabled(),
15448
+ incognito: incognitoAgents.has(agent.id()),
15449
+ command_installed: agent.isEnabled(),
15418
15450
  command_path: agent.commandPath()
15419
15451
  }));
15420
15452
  if (opts.json) {
@@ -15422,49 +15454,33 @@ function incognitoCommand() {
15422
15454
  return;
15423
15455
  }
15424
15456
  for (const row of rows) {
15425
- const state = !row.installed ? import_picocolors20.default.dim("not installed") : row.enabled ? import_picocolors20.default.green("enabled") : "disabled";
15426
- 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}`);
15427
15460
  }
15428
15461
  console.log(import_picocolors20.default.dim(`
15429
- Use 'dosu knowledge incognito enable|disable [agent...]' to change these.
15430
- ` + `Inside a session, run /${INCOGNITO_COMMAND_NAME} to keep that session out of studying.`));
15431
- });
15432
- cmd.command("enable [agents...]").description("Install the slash command for agents (default: all detected)").action((ids) => {
15433
- for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
15434
- try {
15435
- const action = agent.enable();
15436
- const verb = action === "unchanged" ? "already installed" : "installed";
15437
- console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb} (${agent.commandPath()})`);
15438
- } catch (err) {
15439
- reportFailure(agent.name(), err);
15440
- }
15441
- }
15442
- });
15443
- cmd.command("disable [agents...]").description("Remove the slash command from agents (default: all detected)").action((ids) => {
15444
- for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
15445
- try {
15446
- const action = agent.disable();
15447
- const verb = action === "removed" ? "removed" : "was not installed";
15448
- console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb}`);
15449
- } catch (err) {
15450
- reportFailure(agent.name(), err);
15451
- }
15452
- }
15462
+ Use 'dosu knowledge incognito on|off [agent...]' to change these.
15463
+ ` + `To keep a single chat out instead, type ${SLASH} in it.`));
15453
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));
15454
15467
  return cmd;
15455
15468
  }
15456
- function reportFailure(agentName, err) {
15457
- 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}`));
15458
15472
  process.exitCode = 1;
15459
15473
  }
15460
- var import_picocolors20;
15474
+ var import_picocolors20, SLASH;
15461
15475
  var init_knowledge_incognito = __esm(() => {
15462
15476
  init_commander();
15463
15477
  init_agents3();
15464
15478
  init_incognito();
15479
+ init_watermark();
15465
15480
  init_agent_select();
15466
15481
  init_output();
15467
15482
  import_picocolors20 = __toESM(require_picocolors(), 1);
15483
+ SLASH = `/${INCOGNITO_COMMAND_NAME}`;
15468
15484
  });
15469
15485
 
15470
15486
  // src/statusline/agents.ts
@@ -60643,7 +60659,7 @@ Operate Dosu through \`dosu\`. Prefer structured output and let the CLI and App
60643
60659
 
60644
60660
  - \`dosu login\` supplies the JWT used by tRPC-backed commands.
60645
60661
  - \`dosu setup\` selects an organization, Library context, and MCP deployment, creates an API key, and can configure an agent tool.
60646
- - \`dosu ask\` needs an API key. \`docs generate\`, \`docs auto-tag\`, and \`docs publish\` need both JWT login and the API key. Other platform commands generally need JWT login; commands scoped to an organization or current Library also need the corresponding setup selection.
60662
+ - \`dosu ask\` needs an API key. \`docs publish\` needs both JWT login and the API key. Other platform commands generally need JWT login; commands scoped to an organization or current Library also need the corresponding setup selection.
60647
60663
  - For coding-agent setup, follow the nonblocking \`dosu setup --agent --tool <id>\` workflow in [workflows.md](references/workflows.md). Relay its URL and execute its returned \`resume_command\`; never invent ticket commands.
60648
60664
 
60649
60665
  ## Use current product terms
@@ -61044,8 +61060,6 @@ dosu docs unarchive <id> [--json]
61044
61060
  dosu docs delete <id> [--json]
61045
61061
  dosu docs versions <id> [--json]
61046
61062
  dosu docs restore <id> --revision <positive-int> [--json]
61047
- dosu docs generate --title <title> [--instructions <text>] [--json]
61048
- dosu docs auto-tag <id> [--json]
61049
61063
  dosu docs import <platform> --files <comma-separated-ids> [--json]
61050
61064
  dosu docs import-status <task-id> [--json]
61051
61065
  dosu docs publish <id> --to <platform> [target flags] [--json]
@@ -61055,7 +61069,7 @@ dosu docs sync-back <id> [--json]
61055
61069
  - Document list defaults to 20. \`create\` and \`update\` reject combining \`--body\` with \`--body-file\`; \`update\` requires at least one field.
61056
61070
  - Import platforms: \`github\`, \`gitlab\`, \`azure_devops\`, \`confluence\`, \`notion\`, \`coda\`.
61057
61071
  - Publish platforms: the same six. Target flags are \`--repo-id\`, \`--project-id\`, \`--parent-page-id\`, \`--doc-id\`, \`--directory\`, and \`--data-source-id\`; Azure DevOps requires \`--data-source-id\`. Other target validation may occur in the backend.
61058
- - \`generate\`, \`auto-tag\`, import, publish, and sync operations may be asynchronous. Use the returned task/status identifiers rather than assuming completion.
61072
+ - Import, publish, and sync operations may be asynchronous. Use the returned task/status identifiers rather than assuming completion.
61059
61073
 
61060
61074
  ## Review
61061
61075
 
@@ -66216,7 +66230,7 @@ ${dim(wrapLog("Dosu scans finished agent sessions in the background. Disable any
66216
66230
  const statuslines = installed.flatMap((r) => r.statusline ? [r.statusline] : []);
66217
66231
  if (statuslines.length > 0) {
66218
66232
  log2.success(`${formatSetupSummary(`Status line enabled for ${statuslines.length} agent(s):`, statuslines.map((item) => ({ label: item.name, path: item.path })))}
66219
- ${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'."))}`);
66220
66234
  }
66221
66235
  for (const result of installed) {
66222
66236
  if (result.statuslineSuggestion) {
@@ -66227,7 +66241,7 @@ ${dim(wrapLog("Shows \uD83D\uDCDA Dosu studying…, \uD83D\uDC7B Dosu incognito,
66227
66241
  const incognitos = installed.flatMap((r) => r.incognito ? [r.incognito] : []);
66228
66242
  if (incognitos.length > 0) {
66229
66243
  log2.success(`${formatSetupSummary(`/dosu-incognito installed for ${incognitos.length} agent(s):`, incognitos.map((item) => ({ label: item.name, path: item.path })))}
66230
- ${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>'."))}`);
66231
66245
  }
66232
66246
  if (removed.length > 0) {
66233
66247
  log2.info(formatSetupSummary(`Removed from ${removed.length} agent(s):`, removed.map((result) => ({
@@ -66568,6 +66582,64 @@ var init_upgrade = __esm(() => {
66568
66582
  SEMVER = /^\d+\.\d+\.\d+/;
66569
66583
  });
66570
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
+
66571
66643
  // src/tui/analytics-view.ts
66572
66644
  function analyticsListHeight(rows) {
66573
66645
  const room = frameMaxLines(rows) - ANALYTICS_VIEW_CHROME_LINES;
@@ -66686,7 +66758,7 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
66686
66758
  const rows = analyticsTabRows(tab, state, pageStats);
66687
66759
  const { visible, above, below } = windowReport(rows, scroll, height);
66688
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.";
66689
- 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)];
66690
66762
  const scrollParts = [];
66691
66763
  if (above > 0)
66692
66764
  scrollParts.push(`↑ ${above} earlier`);
@@ -66702,9 +66774,9 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
66702
66774
  ], tab, width, { spread: false }),
66703
66775
  "",
66704
66776
  ...listRows,
66705
- ...scrollParts.length > 0 ? [import_picocolors38.default.dim(scrollParts.join(" · "))] : [],
66777
+ ...scrollParts.length > 0 ? [import_picocolors39.default.dim(scrollParts.join(" · "))] : [],
66706
66778
  "",
66707
- import_picocolors38.default.dim("tab switch · ↑↓ scroll · esc back")
66779
+ import_picocolors39.default.dim("tab switch · ↑↓ scroll · esc back")
66708
66780
  ];
66709
66781
  return lines.join(`
66710
66782
  `);
@@ -66801,7 +66873,7 @@ ${CLEAR_BELOW2}`);
66801
66873
  input.on("data", onData);
66802
66874
  });
66803
66875
  }
66804
- 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);
66805
66877
  var init_analytics_view = __esm(() => {
66806
66878
  init_trpc();
66807
66879
  init_config();
@@ -66809,7 +66881,7 @@ var init_analytics_view = __esm(() => {
66809
66881
  init_alt_screen();
66810
66882
  init_layout();
66811
66883
  init_menu();
66812
- import_picocolors38 = __toESM(require_picocolors(), 1);
66884
+ import_picocolors39 = __toESM(require_picocolors(), 1);
66813
66885
  ESC8 = String.fromCharCode(27);
66814
66886
  HIDE_CURSOR4 = `${ESC8}[?25l`;
66815
66887
  SHOW_CURSOR4 = `${ESC8}[?25h`;
@@ -66827,7 +66899,7 @@ var init_analytics_view = __esm(() => {
66827
66899
  // src/tui/banner.ts
66828
66900
  function paintLogoRow(row) {
66829
66901
  return row.map(([tone, art]) => {
66830
- if (!import_picocolors39.default.isColorSupported)
66902
+ if (!import_picocolors40.default.isColorSupported)
66831
66903
  return art;
66832
66904
  const { fg, fallback } = LOGO_TONES[tone];
66833
66905
  return hasTruecolor() ? `${fg}${art}\x1B[39m` : fallback(art);
@@ -66835,14 +66907,14 @@ function paintLogoRow(row) {
66835
66907
  }
66836
66908
  function checklistRows(ctx) {
66837
66909
  const on = brand(CHECK2);
66838
- const off = import_picocolors39.default.dim(CIRCLE);
66910
+ const off = import_picocolors40.default.dim(CIRCLE);
66839
66911
  const rows = [["workspace", ctx.directory]];
66840
66912
  rows.push([
66841
66913
  "account",
66842
- 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`)}`
66843
66915
  ]);
66844
66916
  const missing = new Set(ctx.setupMissing ?? []);
66845
- 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`)}`;
66846
66918
  if (missing.has("MCP"))
66847
66919
  rows.push(["mcp", warnRow]);
66848
66920
  else if (ctx.deploymentName)
@@ -66854,7 +66926,7 @@ function checklistRows(ctx) {
66854
66926
  if (ctx.repoAgentsMd) {
66855
66927
  rows.push([
66856
66928
  "repo",
66857
- 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`)}`
66858
66930
  ]);
66859
66931
  }
66860
66932
  if (missing.has("agents"))
@@ -66866,24 +66938,24 @@ function checklistRows(ctx) {
66866
66938
  if (ctx.studying) {
66867
66939
  rows.push([
66868
66940
  "sync",
66869
- `\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`)}`
66870
66942
  ]);
66871
66943
  }
66872
66944
  if (ctx.update) {
66873
66945
  rows.push([
66874
66946
  "update",
66875
- `${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}`)}`
66876
66948
  ]);
66877
66949
  }
66878
66950
  const labelWidth = Math.max(...rows.map(([label]) => label.length));
66879
- 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}`);
66880
66952
  }
66881
66953
  function renderBanner(ctx) {
66882
66954
  const logo = LOGO_ROWS.map(paintLogoRow);
66883
66955
  const text = [
66884
66956
  ...checklistRows(ctx),
66885
66957
  "",
66886
- `${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}`)}`
66887
66959
  ];
66888
66960
  const height = Math.max(logo.length, text.length);
66889
66961
  const combined = [];
@@ -66896,10 +66968,10 @@ function renderBanner(ctx) {
66896
66968
  return ["", ...combined, ""].join(`
66897
66969
  `);
66898
66970
  }
66899
- 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 = " ";
66900
66972
  var init_banner = __esm(() => {
66901
66973
  init_styles();
66902
- import_picocolors39 = __toESM(require_picocolors(), 1);
66974
+ import_picocolors40 = __toESM(require_picocolors(), 1);
66903
66975
  LOGO_ROWS = [
66904
66976
  [["sage", "▄▄▄▄▄▄"]],
66905
66977
  [["sage", "██ ▀▄"]],
@@ -66910,8 +66982,8 @@ var init_banner = __esm(() => {
66910
66982
  LOGO_MARK = LOGO_ROWS.map((row) => row.map(([, art]) => art).join(""));
66911
66983
  LOGO_WIDTH = Math.max(...LOGO_MARK.map((row) => row.length));
66912
66984
  LOGO_TONES = {
66913
- sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors39.default.green },
66914
- 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)) }
66915
66987
  };
66916
66988
  });
66917
66989
 
@@ -67023,16 +67095,16 @@ function renderPagesFrame(model, width, selected) {
67023
67095
  const body = [];
67024
67096
  let scrollHint = "";
67025
67097
  if (model.phase === "loading") {
67026
- body.push(import_picocolors40.default.dim("Loading pages…"));
67098
+ body.push(import_picocolors41.default.dim("Loading pages…"));
67027
67099
  } else if (model.phase === "error") {
67028
- body.push(import_picocolors40.default.yellow(clip3(model.message, width)));
67100
+ body.push(import_picocolors41.default.yellow(clip3(model.message, width)));
67029
67101
  } else if (model.pages.length === 0) {
67030
- 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."));
67031
67103
  } else {
67032
67104
  const rows = pageRows2(model.pages, width - 2);
67033
67105
  const { start, above } = windowSelection(rows.length, selected);
67034
67106
  const visible = rows.slice(start, start + PAGES_VIEW_LINES);
67035
- 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)}`));
67036
67108
  const below = Math.max(0, Math.max(model.total, rows.length) - start - PAGES_VIEW_LINES);
67037
67109
  const parts = [];
67038
67110
  if (above > 0)
@@ -67041,14 +67113,14 @@ function renderPagesFrame(model, width, selected) {
67041
67113
  parts.push(`↓ ${below} more`);
67042
67114
  scrollHint = parts.join(" · ");
67043
67115
  }
67044
- 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})`)}` : "";
67045
67117
  const lines = [
67046
67118
  `${breadcrumb(["home", "pages"], width)}${count}`,
67047
67119
  "",
67048
67120
  ...body,
67049
- ...scrollHint ? [import_picocolors40.default.dim(scrollHint)] : [],
67121
+ ...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
67050
67122
  "",
67051
- import_picocolors40.default.dim("↑↓ move · enter open · esc back")
67123
+ import_picocolors41.default.dim("↑↓ move · enter open · esc back")
67052
67124
  ];
67053
67125
  return lines.join(`
67054
67126
  `);
@@ -67057,9 +67129,9 @@ function renderPageFrame(page, content, width, scroll) {
67057
67129
  const body = [];
67058
67130
  let scrollHint = "";
67059
67131
  if (content.phase === "loading") {
67060
- body.push(import_picocolors40.default.dim("Loading page…"));
67132
+ body.push(import_picocolors41.default.dim("Loading page…"));
67061
67133
  } else if (content.phase === "error") {
67062
- body.push(import_picocolors40.default.yellow(clip3(content.message, width)));
67134
+ body.push(import_picocolors41.default.yellow(clip3(content.message, width)));
67063
67135
  } else {
67064
67136
  const rows = wrapBody(content.body, width);
67065
67137
  const { visible, above, below } = windowReport(rows, scroll, PAGE_BODY_LINES);
@@ -67074,12 +67146,12 @@ function renderPageFrame(page, content, width, scroll) {
67074
67146
  const meta = `${page.type} · ${page.published ? "published" : "draft"} · updated ${page.updated_at.slice(0, 10)}`;
67075
67147
  const lines = [
67076
67148
  breadcrumb(["home", "pages", page.title], width),
67077
- import_picocolors40.default.dim(clip3(meta, width)),
67149
+ import_picocolors41.default.dim(clip3(meta, width)),
67078
67150
  "",
67079
67151
  ...body,
67080
- ...scrollHint ? [import_picocolors40.default.dim(scrollHint)] : [],
67152
+ ...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
67081
67153
  "",
67082
- import_picocolors40.default.dim("↑↓ scroll · esc back to pages")
67154
+ import_picocolors41.default.dim("↑↓ scroll · esc back to pages")
67083
67155
  ];
67084
67156
  return lines.join(`
67085
67157
  `);
@@ -67228,7 +67300,7 @@ ${CLEAR_BELOW3}`);
67228
67300
  input.on("data", onData);
67229
67301
  });
67230
67302
  }
67231
- 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;
67232
67304
  var init_pages_view = __esm(() => {
67233
67305
  init_trpc();
67234
67306
  init_config();
@@ -67238,7 +67310,7 @@ var init_pages_view = __esm(() => {
67238
67310
  init_analytics_view();
67239
67311
  init_layout();
67240
67312
  init_menu();
67241
- import_picocolors40 = __toESM(require_picocolors(), 1);
67313
+ import_picocolors41 = __toESM(require_picocolors(), 1);
67242
67314
  ESC9 = String.fromCharCode(27);
67243
67315
  HIDE_CURSOR5 = `${ESC9}[?25l`;
67244
67316
  SHOW_CURSOR5 = `${ESC9}[?25h`;
@@ -67351,7 +67423,7 @@ function isSetUp(cfg) {
67351
67423
  }
67352
67424
  function setupHint(cfg) {
67353
67425
  const started = Boolean(cfg.active_account?.target);
67354
- 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");
67355
67427
  }
67356
67428
  function isStudying() {
67357
67429
  try {
@@ -67596,7 +67668,7 @@ function handleLogout(cfg) {
67596
67668
  saveConfig(cfg);
67597
67669
  log2.success("Credentials cleared.");
67598
67670
  }
67599
- var import_picocolors41, ESC10, CLEAR_SCREEN;
67671
+ var import_picocolors42, ESC10, CLEAR_SCREEN;
67600
67672
  var init_tui = __esm(() => {
67601
67673
  init_client();
67602
67674
  init_config();
@@ -67620,7 +67692,7 @@ var init_tui = __esm(() => {
67620
67692
  init_menu();
67621
67693
  init_pages_view();
67622
67694
  init_prompts();
67623
- import_picocolors41 = __toESM(require_picocolors(), 1);
67695
+ import_picocolors42 = __toESM(require_picocolors(), 1);
67624
67696
  ESC10 = String.fromCharCode(27);
67625
67697
  CLEAR_SCREEN = `${ESC10}[2J${ESC10}[H`;
67626
67698
  });
@@ -68339,6 +68411,7 @@ function createProgram(options = {}) {
68339
68411
  checkForReadyTasks();
68340
68412
  if (shouldRunMcpRefreshCheck(actionCommand)) {
68341
68413
  checkForMcpRefresh({ notify: !launchesTUI });
68414
+ checkForIncognitoBackfill({ notify: !launchesTUI });
68342
68415
  }
68343
68416
  }
68344
68417
  const command = commandTelemetryName(actionCommand);
@@ -68769,6 +68842,7 @@ var init_cli = __esm(() => {
68769
68842
  init_styles();
68770
68843
  init_settings();
68771
68844
  init_telemetry();
68845
+ init_incognito_backfill_check();
68772
68846
  init_mcp_refresh_check();
68773
68847
  init_pending_tasks_check();
68774
68848
  init_skill_update_check();
@@ -68807,4 +68881,4 @@ main().catch((err) => {
68807
68881
  process.exit(1);
68808
68882
  });
68809
68883
 
68810
- //# debugId=a31208d6-6e9d-91e6-6475-6e2164756e21
68884
+ //# debugId=8627229c-9519-9318-6475-6e2164756e21