@dosu/cli 0.67.0-beta.1 → 0.67.0-beta.10

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 +40 -73
  2. package/bin/dosu.js +596 -634
  3. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -450,7 +450,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
450
450
  function getVersionString() {
451
451
  return `v${VERSION}`;
452
452
  }
453
- var VERSION = "0.67.0-beta.1", INSTALL_CHANNEL = "npm";
453
+ var VERSION = "0.67.0-beta.10", INSTALL_CHANNEL = "npm";
454
454
 
455
455
  // src/debug/logger.ts
456
456
  import {
@@ -602,22 +602,6 @@ function expandHome(path) {
602
602
  return path;
603
603
  return join3(homedir2(), path.slice(1));
604
604
  }
605
- function appSupportDir() {
606
- switch (platform()) {
607
- case "darwin": {
608
- return join3(homedir2(), "Library", "Application Support");
609
- }
610
- case "win32": {
611
- return process.env.APPDATA ?? "";
612
- }
613
- default: {
614
- const xdg = process.env.XDG_CONFIG_HOME;
615
- if (xdg)
616
- return xdg;
617
- return join3(homedir2(), ".config");
618
- }
619
- }
620
- }
621
605
  function allOnPath(name) {
622
606
  return (process.env.PATH ?? "").split(delimiter).filter(Boolean).map((dir) => join3(dir, name)).filter((candidate) => existsSync3(candidate));
623
607
  }
@@ -1087,7 +1071,7 @@ function getSupabaseURL() {
1087
1071
  return process.env.SUPABASE_URL_OVERRIDE ?? "https://wldmetsoicvieidlsqrb.supabase.co" ?? "";
1088
1072
  }
1089
1073
  function getSupabaseAnonKey() {
1090
- return process.env.SUPABASE_ANON_KEY_OVERRIDE ?? "sb_publishable_NePQHMbqqlFOp1aaHbp5Bg_zyA-kYd6" ?? "";
1074
+ return process.env.SUPABASE_ANON_KEY_OVERRIDE ?? "sb_publishable_zbUf8qAI35-w42udlAJ6LQ_01-ZZtln" ?? "";
1091
1075
  }
1092
1076
  function isAbsoluteHttpUrl(value) {
1093
1077
  try {
@@ -3486,6 +3470,7 @@ function redactSecrets2(text) {
3486
3470
  if (kvAssignmentNearby(lower)) {
3487
3471
  const kvRepl = (m) => `${m[1]}${m[2]}${m[3]}[redacted:credential]${closingQuote(m[3], m[5])}`;
3488
3472
  s = replaceSubmatch(s, genericKVRE, "credential", counts, kvRepl);
3473
+ s = replaceSubmatch(s, authTokenKVRE, "credential", counts, kvRepl);
3489
3474
  s = replaceSubmatch(s, envKeyRE, "credential", counts, kvRepl);
3490
3475
  s = replaceSubmatch(s, genericKVIntlRE, "credential", counts, kvRepl);
3491
3476
  }
@@ -3626,18 +3611,19 @@ function redactEntropy(s, counts) {
3626
3611
  return s;
3627
3612
  return out + s.slice(last);
3628
3613
  }
3629
- var REDACTION_MARKER = "[redacted:", awsAccessKeyRE, awsSecretRE, genericKVRE, envKeyRE, genericKVIntlRE, bearerRE, quotedSecretRE, pemPrivateRE, providerRE, jwtRE, connURLRE, kvHints, providerHints, entropyMinBits = 4.5, entropyMinAssign = 20, entropyMinStandalone = 28, stopWords;
3614
+ var REDACTION_MARKER = "[redacted:", awsAccessKeyRE, awsSecretRE, genericKVRE, authTokenKVRE, envKeyRE, genericKVIntlRE, bearerRE, quotedSecretRE, pemPrivateRE, providerRE, jwtRE, connURLRE, kvHints, providerHints, entropyMinBits = 4.5, entropyMinAssign = 20, entropyMinStandalone = 28, stopWords;
3630
3615
  var init_redact = __esm(() => {
3631
3616
  awsAccessKeyRE = /A(?:KIA|SIA)[0-9A-Z]{16}/g;
3632
3617
  awsSecretRE = /\b(aws[_-]?secret[_-]?access[_-]?key)(\\*['"]?\s*[:=]\s*)(\\*['"]?)([A-Za-z0-9/+=_-]{32,})(\\*['"]?)/gi;
3633
3618
  genericKVRE = /\b([\w.-]{0,64}?(?:api[_-]?key|secret|token|passwd|password|authorization))(\\*['"]?\s*[:=]\s*)(\\*['"]?)([A-Za-z0-9/+=._-]{16,})(\\*['"]?)/gi;
3619
+ authTokenKVRE = /\b([\w.-]{0,64}?(?:access|refresh|id)[_-]?token)(\\*['"]?\s*[:=]\s*)(\\*['"]?)([A-Za-z0-9/+=._-]{8,})(\\*['"]?)/gi;
3634
3620
  envKeyRE = /\b([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*_KEY)(\\*['"]?\s*[:=]\s*)(\\*['"]?)([A-Za-z0-9/+=._-]{16,})(\\*['"]?)/g;
3635
3621
  genericKVIntlRE = /(парол[ьяею]|токен[ауы]?|секрет[ауы]?|ключ[аеиуом]?|contraseña|senha|passwort|密码|密碼|パスワード|비밀번호)(\\*['"]?\s*[:=]\s*)(\\*['"]?)([A-Za-z0-9/+=._-]{16,})(\\*['"]?)/gi;
3636
3622
  bearerRE = /\b(Bearer|Basic)(\s+)([A-Za-z0-9._~+/=-]{16,})/gi;
3637
3623
  quotedSecretRE = /\b(password|passwd|pwd|secret|token|api[_-]?key)(\s+(?:is\s+|was\s+|for\s+)?)(\\*["'`])([^"'`\n]{6,80})(\\*["'`])/gi;
3638
3624
  pemPrivateRE = /-----BEGIN [A-Z0-9 ]*PRIVATE KEY[A-Z0-9 ]*-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY[A-Z0-9 ]*-----/g;
3639
- providerRE = /\b(gh[opsur]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,}|glpat-[A-Za-z0-9_-]{20,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}|sk_user_[A-Za-z0-9]{8,}|sk-[A-Za-z0-9_-]*[A-Za-z0-9]{20,}|gsk_[A-Za-z0-9]{20,}|xai-[A-Za-z0-9]{20,}|hf_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{30,}|xox[bpcs]-[A-Za-z0-9-]{10,}|AIza[0-9A-Za-z_-]{30,})\b/g;
3640
- jwtRE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\b/g;
3625
+ providerRE = /\b(gh[opsur]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,}|glpat-[A-Za-z0-9_-]{20,}|(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}|sk_user_[A-Za-z0-9_-]{8,}|sk-[A-Za-z0-9_-]*[A-Za-z0-9]{20,}|gsk_[A-Za-z0-9]{20,}|xai-[A-Za-z0-9]{20,}|hf_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{30,}|xox[bpcs]-[A-Za-z0-9-]{10,}|AIza[0-9A-Za-z_-]{30,})\b/g;
3626
+ jwtRE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}\b|(?<=(?:^|[^A-Za-z0-9_-])[A-Za-z0-9_-]{1,8})eyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]{4,}/g;
3641
3627
  connURLRE = /\b([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^\s/@:]*):([^\s]+)@([^\s]+)/g;
3642
3628
  kvHints = [
3643
3629
  "key",
@@ -7688,6 +7674,10 @@ function saveSyncState(state, configDir = getConfigDir()) {
7688
7674
  writeFileSync3(tmp, JSON.stringify(state, null, 2), { mode: 384 });
7689
7675
  renameSync2(tmp, path);
7690
7676
  }
7677
+ function saveRepoFilter(repos, configDir = getConfigDir()) {
7678
+ const { repo_filter: _repos, project_filter: _folders, ...rest } = loadSyncState(configDir);
7679
+ saveSyncState(repos ? { ...rest, repo_filter: [...repos] } : rest, configDir);
7680
+ }
7691
7681
  function setSyncPaused(paused, configDir = getConfigDir()) {
7692
7682
  const state = loadSyncState(configDir);
7693
7683
  if (paused)
@@ -9411,18 +9401,26 @@ function groupedAgent(options) {
9411
9401
  }
9412
9402
  function cursorAgent() {
9413
9403
  const configPath = () => expandHome("~/.cursor/hooks.json");
9404
+ const has = (event) => hasCursorHook(readHookConfig(configPath()), event);
9414
9405
  return {
9415
9406
  id: () => "cursor",
9416
9407
  name: () => "Cursor",
9417
9408
  isInstalled: () => isInstalled(["~/.cursor"]),
9418
9409
  configPath,
9419
- isEnabled: () => hasCursorHook(readHookConfig(configPath()), CURSOR_EVENT),
9410
+ isEnabled: () => has(CURSOR_EVENT),
9420
9411
  enable: () => {
9421
- writeHookConfig(configPath(), addCursorHook(readHookConfig(configPath()), CURSOR_EVENT));
9412
+ let config = readHookConfig(configPath());
9413
+ config = addCursorHook(config, CURSOR_EVENT);
9414
+ config = addCursorHook(config, CURSOR_END_EVENT);
9415
+ writeHookConfig(configPath(), config);
9422
9416
  },
9423
9417
  disable: () => {
9424
- writeHookConfig(configPath(), removeCursorHook(readHookConfig(configPath()), CURSOR_EVENT));
9425
- }
9418
+ let config = readHookConfig(configPath());
9419
+ config = removeCursorHook(config, CURSOR_EVENT);
9420
+ config = removeCursorHook(config, CURSOR_END_EVENT);
9421
+ writeHookConfig(configPath(), config);
9422
+ },
9423
+ statusNote: () => has(CURSOR_END_EVENT) ? "" : "The sessionEnd hook is missing, so sessions ship only once quiet; 'dosu knowledge hooks enable cursor' adds it."
9426
9424
  };
9427
9425
  }
9428
9426
  function claudeAgent() {
@@ -9499,7 +9497,7 @@ function refreshEnabledHooks() {
9499
9497
  }
9500
9498
  return refreshed;
9501
9499
  }
9502
- var CURSOR_EVENT = "stop";
9500
+ var CURSOR_EVENT = "stop", CURSOR_END_EVENT = "sessionEnd";
9503
9501
  var init_agents2 = __esm(() => {
9504
9502
  init_logger();
9505
9503
  init_agents();
@@ -9582,14 +9580,18 @@ function headReflogOfDir(dir, timeout = 5000) {
9582
9580
  function displayRepo(repo) {
9583
9581
  return repo.split("/").slice(1).join("/") || repo;
9584
9582
  }
9585
- var GIT_LOCATION_ENV, GIT_TIMED_OUT;
9583
+ function githubSlugOfRepo(repo) {
9584
+ return repo === null ? null : GITHUB_SLUG.exec(repo)?.[1] ?? null;
9585
+ }
9586
+ var GIT_LOCATION_ENV, GIT_TIMED_OUT, GITHUB_SLUG;
9586
9587
  var init_repo = __esm(() => {
9587
9588
  GIT_LOCATION_ENV = ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"];
9588
9589
  GIT_TIMED_OUT = Symbol("git timed out");
9590
+ GITHUB_SLUG = /^github\.com\/([a-z0-9-]+\/[a-z0-9._-]+)$/;
9589
9591
  });
9590
9592
 
9591
9593
  // src/sync/lock.ts
9592
- import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync6 } from "node:fs";
9594
+ import { existsSync as existsSync12, readFileSync as readFileSync15, rmSync as rmSync2, statSync as statSync5, utimesSync, writeFileSync as writeFileSync6 } from "node:fs";
9593
9595
  import { join as join15 } from "node:path";
9594
9596
  function processAlive(pid) {
9595
9597
  try {
@@ -9652,6 +9654,16 @@ function fileLock(configDir = getConfigDir(), now = () => new Date) {
9652
9654
  } catch {}
9653
9655
  return false;
9654
9656
  },
9657
+ refresh() {
9658
+ if (!held)
9659
+ return;
9660
+ try {
9661
+ if (readFileSync15(path, "utf8") === String(process.pid)) {
9662
+ const at = now();
9663
+ utimesSync(path, at, at);
9664
+ }
9665
+ } catch {}
9666
+ },
9655
9667
  release() {
9656
9668
  if (!held)
9657
9669
  return;
@@ -16186,77 +16198,10 @@ var init_ask = __esm(() => {
16186
16198
  import_picocolors7 = __toESM(require_picocolors(), 1);
16187
16199
  });
16188
16200
 
16189
- // src/setup/styles.ts
16190
- import { stripVTControlCharacters as stripVTControlCharacters4 } from "node:util";
16191
- function hasTruecolor() {
16192
- return /truecolor|24bit/i.test(process.env.COLORTERM ?? "");
16193
- }
16194
- function brand(msg) {
16195
- if (!import_picocolors8.default.isColorSupported)
16196
- return msg;
16197
- return hasTruecolor() ? `${BRAND_FG}${msg}${RESET_FG}` : import_picocolors8.default.green(msg);
16198
- }
16199
- function brandBadge(msg) {
16200
- if (!import_picocolors8.default.isColorSupported)
16201
- return `[ ${msg} ]`;
16202
- const label = import_picocolors8.default.bold(` ${msg} `);
16203
- return hasTruecolor() ? `${BRAND_BG}${INK_FG}${label}${RESET_FG}${RESET_BG}` : import_picocolors8.default.bgGreen(import_picocolors8.default.black(label));
16204
- }
16205
- function dim(msg) {
16206
- return import_picocolors8.default.dim(msg);
16207
- }
16208
- function formatSetupSummary(title, items, marker = IconAdd) {
16209
- const styled = marker === IconRemove ? import_picocolors8.default.red(marker) : brand(marker);
16210
- const lines = items.map((item) => {
16211
- const path = `${item.path}${item.status ? ` (${item.status})` : ""}`;
16212
- return item.label ? `${styled} ${item.label}
16213
- ${dim(path)}` : `${styled} ${dim(path)}`;
16214
- });
16215
- return `${title}
16216
- ${lines.join(`
16217
- `)}`;
16218
- }
16219
- function browserFallbackHint(url) {
16220
- return dim(`If your browser doesn't open automatically, visit:
16221
- ${url}`);
16222
- }
16223
- function info(msg) {
16224
- return import_picocolors8.default.cyan(msg);
16225
- }
16226
- function visibleWidth(text) {
16227
- return stripVTControlCharacters4(text).length;
16228
- }
16229
- function wrapLog(text, columns = process.stdout.columns || 80) {
16230
- const width = Math.max(20, columns - LOG_GUTTER);
16231
- const out = [];
16232
- for (const paragraph of text.split(`
16233
- `)) {
16234
- if (visibleWidth(paragraph) <= width) {
16235
- out.push(paragraph);
16236
- continue;
16237
- }
16238
- let line = "";
16239
- for (const word of paragraph.split(" ")) {
16240
- if (line === "") {
16241
- line = word;
16242
- } else if (visibleWidth(line) + 1 + visibleWidth(word) <= width) {
16243
- line = `${line} ${word}`;
16244
- } else {
16245
- out.push(line);
16246
- line = word;
16247
- }
16248
- }
16249
- out.push(line);
16250
- }
16251
- return out.join(`
16252
- `);
16253
- }
16254
- var import_picocolors8, IconAdd = "✔", IconRemove = "-", BRAND_FG = "\x1B[38;2;82;164;15m", BRAND_BG = "\x1B[48;2;82;164;15m", INK_FG = "\x1B[38;2;14;14;14m", RESET_FG = "\x1B[39m", RESET_BG = "\x1B[49m", LOG_GUTTER = 4;
16255
- var init_styles = __esm(() => {
16256
- import_picocolors8 = __toESM(require_picocolors(), 1);
16257
- });
16258
-
16259
16201
  // src/tui/layout.ts
16202
+ function activeLayoutMargin() {
16203
+ return activeMargin;
16204
+ }
16260
16205
  function contentWidth(columns = process.stdout.columns ?? 80) {
16261
16206
  return Math.min(columns, CONTENT_WIDTH);
16262
16207
  }
@@ -16275,9 +16220,9 @@ function breadcrumb(segments, width = contentWidth()) {
16275
16220
  const trailWidth = head.reduce((total, segment) => total + segment.length + 3, 0);
16276
16221
  const room = Math.max(8, width - trailWidth);
16277
16222
  const clipped = leaf.length <= room ? leaf : `${leaf.slice(0, room - 1)}…`;
16278
- return head.map((segment) => import_picocolors9.default.dim(`${segment} › `)).join("") + import_picocolors9.default.bold(clipped);
16223
+ return head.map((segment) => import_picocolors8.default.dim(`${segment} › `)).join("") + import_picocolors8.default.bold(clipped);
16279
16224
  }
16280
- function visibleWidth2(text) {
16225
+ function visibleWidth(text) {
16281
16226
  return text.replace(ANSI_PATTERN2, "").length;
16282
16227
  }
16283
16228
  function tabStrip(labels, active, width, { spread = true } = {}) {
@@ -16288,8 +16233,8 @@ function tabStrip(labels, active, width, { spread = true } = {}) {
16288
16233
  for (const [id, label] of labels) {
16289
16234
  const left = Math.floor((cellW - label.length) / 2);
16290
16235
  const cell = " ".repeat(left) + label + " ".repeat(cellW - label.length - left);
16291
- row += id === active ? brand(import_picocolors9.default.bold(cell)) : import_picocolors9.default.dim(cell);
16292
- rule += id === active ? brand("━".repeat(cellW)) : import_picocolors9.default.dim("─".repeat(cellW));
16236
+ row += id === active ? brand(import_picocolors8.default.bold(cell)) : import_picocolors8.default.dim(cell);
16237
+ rule += id === active ? brand("━".repeat(cellW)) : import_picocolors8.default.dim("─".repeat(cellW));
16293
16238
  }
16294
16239
  return [row, rule];
16295
16240
  }
@@ -16312,18 +16257,18 @@ function tabStrip(labels, active, width, { spread = true } = {}) {
16312
16257
  if (id === active) {
16313
16258
  activeStart = col;
16314
16259
  activeLen = label.length;
16315
- row += brand(import_picocolors9.default.bold(label));
16260
+ row += brand(import_picocolors8.default.bold(label));
16316
16261
  } else {
16317
- row += import_picocolors9.default.dim(label);
16262
+ row += import_picocolors8.default.dim(label);
16318
16263
  }
16319
16264
  col += label.length;
16320
16265
  });
16321
16266
  const tail = Math.max(0, width - activeStart - activeLen);
16322
- const rule = import_picocolors9.default.dim("─".repeat(activeStart)) + brand("━".repeat(activeLen)) + import_picocolors9.default.dim("─".repeat(tail));
16267
+ const rule = import_picocolors8.default.dim("─".repeat(activeStart)) + brand("━".repeat(activeLen)) + import_picocolors8.default.dim("─".repeat(tail));
16323
16268
  return [row, rule];
16324
16269
  }
16325
16270
  function centerBlock(lines, width) {
16326
- const blockWidth = Math.max(...lines.map(visibleWidth2));
16271
+ const blockWidth = Math.max(...lines.map(visibleWidth));
16327
16272
  const pad = " ".repeat(Math.max(0, Math.floor((width - blockWidth) / 2)));
16328
16273
  return lines.map((line) => pad + line);
16329
16274
  }
@@ -16364,6 +16309,7 @@ function installCenteredLayout(stream = process.stdout) {
16364
16309
  if (margin === 0)
16365
16310
  return () => {};
16366
16311
  active = true;
16312
+ activeMargin = margin;
16367
16313
  const pad = " ".repeat(margin);
16368
16314
  const original = stream.write;
16369
16315
  const state = { atLineStart: true };
@@ -16376,12 +16322,13 @@ function installCenteredLayout(stream = process.stdout) {
16376
16322
  return () => {
16377
16323
  stream.write = original;
16378
16324
  active = false;
16325
+ activeMargin = 0;
16379
16326
  };
16380
16327
  }
16381
- var import_picocolors9, ESC2, CONTENT_WIDTH = 64, TOKEN_PATTERN, COLUMN_RESET_FINALS, active = false, ANSI_PATTERN2, TAB_CELL_PAD = 2;
16328
+ var import_picocolors8, ESC2, CONTENT_WIDTH = 64, TOKEN_PATTERN, COLUMN_RESET_FINALS, active = false, activeMargin = 0, ANSI_PATTERN2, TAB_CELL_PAD = 2;
16382
16329
  var init_layout = __esm(() => {
16383
16330
  init_styles();
16384
- import_picocolors9 = __toESM(require_picocolors(), 1);
16331
+ import_picocolors8 = __toESM(require_picocolors(), 1);
16385
16332
  ESC2 = String.fromCharCode(27);
16386
16333
  TOKEN_PATTERN = new RegExp(`(\r
16387
16334
  |\r|
@@ -16390,6 +16337,73 @@ var init_layout = __esm(() => {
16390
16337
  ANSI_PATTERN2 = new RegExp(`${ESC2}\\[[0-9;?]*[A-Za-z]`, "g");
16391
16338
  });
16392
16339
 
16340
+ // src/setup/styles.ts
16341
+ function hasTruecolor() {
16342
+ return /truecolor|24bit/i.test(process.env.COLORTERM ?? "");
16343
+ }
16344
+ function brand(msg) {
16345
+ if (!import_picocolors9.default.isColorSupported)
16346
+ return msg;
16347
+ return hasTruecolor() ? `${BRAND_FG}${msg}${RESET_FG}` : import_picocolors9.default.green(msg);
16348
+ }
16349
+ function brandBadge(msg) {
16350
+ if (!import_picocolors9.default.isColorSupported)
16351
+ return `[ ${msg} ]`;
16352
+ const label = import_picocolors9.default.bold(` ${msg} `);
16353
+ return hasTruecolor() ? `${BRAND_BG}${INK_FG}${label}${RESET_FG}${RESET_BG}` : import_picocolors9.default.bgGreen(import_picocolors9.default.black(label));
16354
+ }
16355
+ function dim(msg) {
16356
+ return import_picocolors9.default.dim(msg);
16357
+ }
16358
+ function formatSetupSummary(title, items, marker = IconAdd) {
16359
+ const styled = marker === IconRemove ? import_picocolors9.default.red(marker) : brand(marker);
16360
+ const lines = items.map((item) => {
16361
+ const path = `${item.path}${item.status ? ` (${item.status})` : ""}`;
16362
+ return item.label ? `${styled} ${item.label}
16363
+ ${dim(path)}` : `${styled} ${dim(path)}`;
16364
+ });
16365
+ return `${title}
16366
+ ${lines.join(`
16367
+ `)}`;
16368
+ }
16369
+ function browserFallbackHint(url) {
16370
+ return dim(`If your browser doesn't open automatically, visit:
16371
+ ${url}`);
16372
+ }
16373
+ function info(msg) {
16374
+ return import_picocolors9.default.cyan(msg);
16375
+ }
16376
+ function wrapLog(text, columns = process.stdout.columns || 80) {
16377
+ const width = Math.max(20, contentWidth(columns) - LOG_GUTTER);
16378
+ const out = [];
16379
+ for (const paragraph of text.split(`
16380
+ `)) {
16381
+ if (visibleWidth(paragraph) <= width) {
16382
+ out.push(paragraph);
16383
+ continue;
16384
+ }
16385
+ let line = "";
16386
+ for (const word of paragraph.split(" ")) {
16387
+ if (line === "") {
16388
+ line = word;
16389
+ } else if (visibleWidth(line) + 1 + visibleWidth(word) <= width) {
16390
+ line = `${line} ${word}`;
16391
+ } else {
16392
+ out.push(line);
16393
+ line = word;
16394
+ }
16395
+ }
16396
+ out.push(line);
16397
+ }
16398
+ return out.join(`
16399
+ `);
16400
+ }
16401
+ var import_picocolors9, IconAdd = "✔", IconRemove = "-", BRAND_FG = "\x1B[38;2;82;164;15m", BRAND_BG = "\x1B[48;2;82;164;15m", INK_FG = "\x1B[38;2;14;14;14m", RESET_FG = "\x1B[39m", RESET_BG = "\x1B[49m", LOG_GUTTER = 4;
16402
+ var init_styles = __esm(() => {
16403
+ init_layout();
16404
+ import_picocolors9 = __toESM(require_picocolors(), 1);
16405
+ });
16406
+
16393
16407
  // src/tui/menu.ts
16394
16408
  function parseKeys(chunk) {
16395
16409
  const keys = [];
@@ -16427,9 +16441,9 @@ function reduceMenuKey(key, selected, count) {
16427
16441
  return { type: "none" };
16428
16442
  }
16429
16443
  function renderMenuFrame(message, options, selected) {
16430
- const labelWidth = Math.max(...options.map((option) => visibleWidth2(option.label)));
16444
+ const labelWidth = Math.max(...options.map((option) => visibleWidth(option.label)));
16431
16445
  const rows = options.map((option, index) => {
16432
- const label = option.label + " ".repeat(labelWidth - visibleWidth2(option.label));
16446
+ const label = option.label + " ".repeat(labelWidth - visibleWidth(option.label));
16433
16447
  const hint = option.hint ? ` ${import_picocolors10.default.dim(option.hint)}` : "";
16434
16448
  return index === selected ? `${brand(POINTER)} ${import_picocolors10.default.bold(label)}${hint}` : ` ${import_picocolors10.default.dim(label)}${hint}`;
16435
16449
  });
@@ -16603,15 +16617,18 @@ function runInteractive(controller, io = {}) {
16603
16617
  output.write(`${ESC4}[${frameLines}A${ESC4}[0J`);
16604
16618
  frameLines = 0;
16605
16619
  };
16620
+ const rowsFor = (line) => {
16621
+ const columns = output.columns || 80;
16622
+ return Math.max(1, Math.ceil((activeLayoutMargin() + visibleWidth(line)) / columns));
16623
+ };
16606
16624
  const draw = () => {
16607
- const frame = controller.render().flatMap((line) => line.split(`
16608
- `)).map((line) => `${brand(BAR)} ${line}`).join(`
16609
- `);
16625
+ const lines = controller.render().flatMap((line) => line.split(`
16626
+ `)).map((line) => `${brand(BAR)} ${line}`);
16610
16627
  erase();
16611
- output.write(`${frame}
16628
+ output.write(`${lines.join(`
16629
+ `)}
16612
16630
  `);
16613
- frameLines = frame.split(`
16614
- `).length;
16631
+ frameLines = lines.reduce((total, line) => total + rowsFor(line), 0);
16615
16632
  };
16616
16633
  output.write(HIDE_CURSOR2);
16617
16634
  draw();
@@ -16721,7 +16738,11 @@ function multiselect2(opts, io = {}) {
16721
16738
  let top = 0;
16722
16739
  let error;
16723
16740
  const picked = new Set(opts.initialValues ?? []);
16724
- const maxLabel = Math.max(16, contentWidth(output.columns || 80) - 8);
16741
+ const suffixWidth = Math.max(0, ...opts.options.map((option) => {
16742
+ const texts = opts.statusFor ? [opts.statusFor(option.value, true), opts.statusFor(option.value, false)] : [option.hint];
16743
+ return Math.max(0, ...texts.map((text) => text ? visibleWidth(text) + 3 : 0));
16744
+ }));
16745
+ const maxLabel = Math.max(16, contentWidth(output.columns || 80) - 8 - suffixWidth);
16725
16746
  const clipLabel = (text) => text.length <= maxLabel ? text : `…${text.slice(text.length - maxLabel + 1)}`;
16726
16747
  const labelWidth = Math.max(...opts.options.map((o) => clipLabel(optionLabel(o)).length));
16727
16748
  const pickedValues = () => opts.options.filter((option) => picked.has(option.value)).map((option) => option.value);
@@ -18346,7 +18367,7 @@ async function stepConnectGitHubRepo(cfg, detected = detectGitRepo(), opts = {})
18346
18367
  }
18347
18368
  repos = refresh.repos;
18348
18369
  if (!refresh.foundNew) {
18349
- log2.warn("GitHub may still be syncing. Pick 'Refresh list' in a moment to re-check; sync usually completes within a minute.");
18370
+ log2.warn(wrapLog("GitHub may still be syncing. Pick 'Refresh list' in a moment to re-check; sync usually completes within a minute."));
18350
18371
  }
18351
18372
  continue;
18352
18373
  }
@@ -19806,14 +19827,18 @@ function recordCapturedSession(key, update, configDir = getConfigDir(), now = ne
19806
19827
  return false;
19807
19828
  }
19808
19829
  }
19830
+ function cursorSessionId(hook) {
19831
+ const id = typeof hook.transcript_path === "string" && hook.transcript_path.endsWith(".jsonl") ? basename7(hook.transcript_path, ".jsonl") : hook.conversation_id;
19832
+ return typeof id === "string" ? id : null;
19833
+ }
19809
19834
  function captureCursorStop(payload, deps = {}) {
19810
19835
  if (typeof payload !== "object" || payload === null)
19811
19836
  return false;
19812
19837
  const hook = payload;
19813
19838
  if (hook.cursor_version === undefined)
19814
19839
  return false;
19815
- const id = typeof hook.transcript_path === "string" && hook.transcript_path.endsWith(".jsonl") ? basename7(hook.transcript_path, ".jsonl") : hook.conversation_id;
19816
- if (typeof id !== "string")
19840
+ const id = cursorSessionId(hook);
19841
+ if (id === null)
19817
19842
  return false;
19818
19843
  const roots = hook.workspace_roots;
19819
19844
  const dir = Array.isArray(roots) && typeof roots[0] === "string" ? roots[0] : undefined;
@@ -19894,6 +19919,17 @@ function piSessionShutdown(hook) {
19894
19919
  return null;
19895
19920
  return { harness: "pi", id, path };
19896
19921
  }
19922
+ function cursorSessionEnd(hook) {
19923
+ if (hook.hook_event_name !== "sessionEnd" || hook.cursor_version === undefined)
19924
+ return null;
19925
+ const path = hook.transcript_path;
19926
+ if (typeof path !== "string" || !path.startsWith("/") || !path.endsWith(".jsonl"))
19927
+ return null;
19928
+ const id = basename7(path, ".jsonl");
19929
+ if (!SAFE_SEGMENT.test(id))
19930
+ return null;
19931
+ return { harness: "cursor", id, path };
19932
+ }
19897
19933
  function endedSessionOf(payload) {
19898
19934
  if (typeof payload !== "object" || payload === null)
19899
19935
  return null;
@@ -19947,6 +19983,7 @@ var init_capture = __esm(() => {
19947
19983
  END_EVENT_READERS = [
19948
19984
  claudeSessionEnd,
19949
19985
  codexSessionEnd,
19986
+ cursorSessionEnd,
19950
19987
  piSessionShutdown
19951
19988
  ];
19952
19989
  ENDED_VALUE = /^([a-z]+):([A-Za-z0-9._-]+)(?:=(\/.*))?$/s;
@@ -21945,7 +21982,8 @@ async function runKnowledgeSync(options = {}) {
21945
21982
  offRecord = gate.ready.filter((s) => agentOff(s) && isUnanswered(s, state.sessions[sessionKey(s)]));
21946
21983
  const gatedReady = gate.ready.filter((s) => !agentOff(s));
21947
21984
  const gatedOpen = gate.open.filter((s) => !agentOff(s));
21948
- const inScope = (sessions) => filterSessionsByRepo(sessions, repoFilter, (s) => locator.resolveRepo(s));
21985
+ const scope = options.everyRepo && !deps.ship ? null : repoFilter;
21986
+ const inScope = (sessions) => filterSessionsByRepo(sessions, scope, (s) => locator.resolveRepo(s));
21949
21987
  ready = inScope(holdBack === "backoff" ? gatedReady.filter(isEnded) : gatedReady);
21950
21988
  open = inScope(gatedOpen);
21951
21989
  if (holdBack === "backoff")
@@ -22019,22 +22057,47 @@ async function runKnowledgeSync(options = {}) {
22019
22057
  failed: 0
22020
22058
  };
22021
22059
  const rank = (s) => ended.some((e) => namesSession(e, s)) ? 0 : isEnded(s) ? 1 : 2;
22022
- const ordered = [...todo].sort((a, b) => rank(a) - rank(b) || Date.parse(a.updated) - Date.parse(b.updated));
22023
- const batch = ordered.slice(0, Math.max(SHIP_BATCH_LIMIT, ordered.filter(isEnded).length));
22024
- logger.debug("sync", `shipping ${batch.length} of ${todo.length} ready sessions`);
22060
+ const batch = [...todo].sort((a, b) => rank(a) - rank(b) || Date.parse(a.updated) - Date.parse(b.updated));
22061
+ logger.debug("sync", `shipping ${batch.length} ready sessions`);
22025
22062
  const hold = (s) => {
22026
22063
  const current = loadState();
22027
22064
  if (!isShippingEnabled(current))
22028
22065
  return "stop";
22029
22066
  return isAgentIncognito(current, s, lineage) ? "agent" : null;
22030
22067
  };
22068
+ const saved = new Map;
22069
+ const reported = [];
22070
+ let savedShipped = 0;
22071
+ const settle = (result) => {
22072
+ reported.push(result);
22073
+ lock.refresh?.();
22074
+ const key = sessionKey(result.session);
22075
+ const entry = ledgerEntry(result, locked.sessions[key], now().toISOString(), cliVersion);
22076
+ if (!entry)
22077
+ return;
22078
+ saved.set(key, entry);
22079
+ try {
22080
+ const counted = result.outcome === "shipped" && !result.session.parentId ? 1 : 0;
22081
+ const next = loadState();
22082
+ next.sessions[key] = entry;
22083
+ next.total_shipped = (next.total_shipped ?? 0) + counted;
22084
+ next.run = run;
22085
+ saveState(next);
22086
+ savedShipped += counted;
22087
+ } catch {}
22088
+ };
22031
22089
  let results = [];
22032
22090
  if (batch.length > 0) {
22033
22091
  try {
22034
- results = await deps.ship(batch, (s) => shippedPrefix(locked.sessions[sessionKey(s)]), hold);
22092
+ results = await deps.ship(batch, (s) => shippedPrefix(locked.sessions[sessionKey(s)]), hold, settle);
22035
22093
  } catch (err) {
22036
22094
  const message = err instanceof Error ? err.message : String(err);
22037
- results = [{ session: batch[0], outcome: "failed", message }];
22095
+ const answered = new Set(reported.map((r) => sessionKey(r.session)));
22096
+ const next = batch.find((s) => !answered.has(sessionKey(s)));
22097
+ results = [
22098
+ ...reported,
22099
+ ...next ? [{ session: next, outcome: "failed", message }] : []
22100
+ ];
22038
22101
  }
22039
22102
  }
22040
22103
  const resultOf = new Map(results.map((r) => [sessionKey(r.session), r]));
@@ -22050,7 +22113,7 @@ async function runKnowledgeSync(options = {}) {
22050
22113
  counts[result.outcome] += 1;
22051
22114
  else
22052
22115
  counts.subagents[result.outcome] += 1;
22053
- const entry = ledgerEntry(result, locked.sessions[key], at, cliVersion);
22116
+ const entry = saved.get(key) ?? ledgerEntry(result, locked.sessions[key], at, cliVersion);
22054
22117
  if (!entry) {
22055
22118
  error = result.message ?? "unknown error";
22056
22119
  logger.debug("sync", `shipping failed at ${key}: ${error}`);
@@ -22077,7 +22140,7 @@ async function runKnowledgeSync(options = {}) {
22077
22140
  if (batch.length > 0) {
22078
22141
  next.last_attempt_at = at;
22079
22142
  next.consecutive_failures = counts.failed > 0 ? next.consecutive_failures + 1 : 0;
22080
- next.total_shipped = (next.total_shipped ?? 0) + counts.shipped;
22143
+ next.total_shipped = (next.total_shipped ?? 0) + counts.shipped - savedShipped;
22081
22144
  next.run = run;
22082
22145
  }
22083
22146
  if (resumes)
@@ -22097,7 +22160,7 @@ async function runKnowledgeSync(options = {}) {
22097
22160
  lock.release();
22098
22161
  }
22099
22162
  }
22100
- var SCAN_WINDOW_DAYS = 30, LEDGER_GRACE_DAYS = 7, SHIP_BATCH_LIMIT = 20, DAY_MS, ENDED_LOCK_WAIT_MS, LOCK_POLL_MS = 2000, LOG_PREVIEW_LIMIT = 10;
22163
+ var SCAN_WINDOW_DAYS = 30, LEDGER_GRACE_DAYS = 7, DAY_MS, ENDED_LOCK_WAIT_MS, LOCK_POLL_MS = 2000, LOG_PREVIEW_LIMIT = 10;
22101
22164
  var init_sync = __esm(() => {
22102
22165
  init_logger();
22103
22166
  init_lineage();
@@ -22178,7 +22241,7 @@ var init_backlog = __esm(() => {
22178
22241
  });
22179
22242
 
22180
22243
  // src/telemetry/debug-id.ts
22181
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "32ee4cf3-5398-61c9-6475-6e2164756e21";
22244
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "38c8fa6e-6a2c-1ace-6475-6e2164756e21";
22182
22245
 
22183
22246
  // src/telemetry/telemetry.ts
22184
22247
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -23147,10 +23210,6 @@ function isDirectory(path) {
23147
23210
  return false;
23148
23211
  }
23149
23212
  }
23150
- function saveScope(repos) {
23151
- const { repo_filter: _repos, project_filter: _folders, ...rest } = loadSyncState();
23152
- saveSyncState(repos ? { ...rest, repo_filter: repos } : rest);
23153
- }
23154
23213
  function scopeCommand() {
23155
23214
  const cmd = new Command("scope").description("Show or set which repos' sessions ship to Dosu memory (the TUI's sync scope)");
23156
23215
  cmd.command("show").description("Show the repos whose sessions ship").option("--json", "Output as JSON").action((opts) => {
@@ -23180,11 +23239,11 @@ function scopeCommand() {
23180
23239
  repos.add(repo);
23181
23240
  }
23182
23241
  const sorted = [...repos].sort();
23183
- saveScope(sorted);
23242
+ saveRepoFilter(sorted);
23184
23243
  console.log(`✓ Sessions ship only from ${sorted.join(", ")}.`);
23185
23244
  });
23186
23245
  cmd.command("clear").description("Ship sessions from every repo, and sessions outside any repo").action(() => {
23187
- saveScope(null);
23246
+ saveRepoFilter(null);
23188
23247
  console.log("✓ Sessions from every repo ship, and sessions outside any repo.");
23189
23248
  });
23190
23249
  return cmd;
@@ -23484,6 +23543,152 @@ var init_session_start = __esm(() => {
23484
23543
  init_normalize();
23485
23544
  });
23486
23545
 
23546
+ // src/shipper/usage.ts
23547
+ import { readFileSync as readFileSync25 } from "node:fs";
23548
+ function isObject7(value) {
23549
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23550
+ }
23551
+ function str2(value) {
23552
+ return typeof value === "string" && value !== "" ? value : null;
23553
+ }
23554
+ function int(value) {
23555
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : 0;
23556
+ }
23557
+ function parseLines(transcript) {
23558
+ const lines = [];
23559
+ for (const line of transcript.split(`
23560
+ `)) {
23561
+ if (line.trim() === "")
23562
+ continue;
23563
+ try {
23564
+ const value = JSON.parse(line);
23565
+ if (isObject7(value))
23566
+ lines.push(value);
23567
+ } catch {}
23568
+ }
23569
+ return lines;
23570
+ }
23571
+ function billed(request) {
23572
+ return request.input + request.output + request.cache_read + request.cache_write > 0 || request.tool_call_ids.length > 0;
23573
+ }
23574
+ function claudeUsage(transcript) {
23575
+ const requests = new Map;
23576
+ for (const line of parseLines(transcript)) {
23577
+ if (line.type !== "assistant" || !isObject7(line.message))
23578
+ continue;
23579
+ const message = line.message;
23580
+ const usage = message.usage;
23581
+ const id = str2(line.requestId) ?? str2(message.id) ?? str2(line.uuid);
23582
+ if (!isObject7(usage) || id === null)
23583
+ continue;
23584
+ const toolCallIds = Array.isArray(message.content) ? message.content.filter((block) => isObject7(block) && block.type === "tool_use").map((block) => str2(block.id)).filter((toolId) => toolId !== null) : [];
23585
+ const cacheCreation = isObject7(usage.cache_creation) ? usage.cache_creation : {};
23586
+ const entry = {
23587
+ id,
23588
+ model: str2(message.model),
23589
+ timestamp: str2(line.timestamp),
23590
+ input: int(usage.input_tokens),
23591
+ output: int(usage.output_tokens),
23592
+ cache_read: int(usage.cache_read_input_tokens),
23593
+ cache_write: int(usage.cache_creation_input_tokens),
23594
+ cache_write_1h: int(cacheCreation.ephemeral_1h_input_tokens),
23595
+ speed: str2(usage.speed),
23596
+ tool_call_ids: toolCallIds
23597
+ };
23598
+ const previous = requests.get(id);
23599
+ if (previous === undefined) {
23600
+ requests.set(id, entry);
23601
+ continue;
23602
+ }
23603
+ const latest = entry.output >= previous.output ? entry : previous;
23604
+ requests.set(id, {
23605
+ ...latest,
23606
+ timestamp: entry.timestamp ?? previous.timestamp,
23607
+ tool_call_ids: [...new Set([...previous.tool_call_ids, ...entry.tool_call_ids])]
23608
+ });
23609
+ }
23610
+ return [...requests.values()].filter(billed);
23611
+ }
23612
+ function codexUsage(transcript) {
23613
+ const requests = [];
23614
+ let model = null;
23615
+ let ownSessionId = null;
23616
+ let historyStart = null;
23617
+ let lastTotal = null;
23618
+ let toolCallIds = [];
23619
+ for (const line of parseLines(transcript)) {
23620
+ const payload = isObject7(line.payload) ? line.payload : {};
23621
+ const ordinal = typeof line.ordinal === "number" ? line.ordinal : null;
23622
+ if (historyStart !== null && ordinal !== null && ordinal < historyStart)
23623
+ continue;
23624
+ if (line.type === "session_meta") {
23625
+ const metaId = str2(payload.id);
23626
+ if (ownSessionId === null) {
23627
+ ownSessionId = metaId;
23628
+ if (str2(payload.forked_from_id) !== null) {
23629
+ const start = payload.subagent_history_start_ordinal;
23630
+ historyStart = typeof start === "number" ? start : null;
23631
+ }
23632
+ }
23633
+ } else if (line.type === "turn_context") {
23634
+ model = str2(payload.model) ?? model;
23635
+ } else if (line.type === "response_item") {
23636
+ const callId = str2(payload.call_id);
23637
+ if (callId !== null && typeof payload.type === "string" && payload.type.endsWith("_call")) {
23638
+ toolCallIds.push(callId);
23639
+ }
23640
+ } else if (line.type === "event_msg" && payload.type === "token_count") {
23641
+ const info = isObject7(payload.info) ? payload.info : null;
23642
+ const last = info && isObject7(info.last_token_usage) ? info.last_token_usage : null;
23643
+ const total = info && isObject7(info.total_token_usage) ? info.total_token_usage : null;
23644
+ if (last === null || total === null)
23645
+ continue;
23646
+ const runningTotal = int(total.total_tokens);
23647
+ if (runningTotal === lastTotal)
23648
+ continue;
23649
+ lastTotal = runningTotal;
23650
+ const input = int(last.input_tokens);
23651
+ const cached = int(last.cached_input_tokens);
23652
+ const cacheWrite = int(last.cache_write_input_tokens);
23653
+ const disjoint = cached + cacheWrite <= input;
23654
+ const request = {
23655
+ id: `codex:${runningTotal}`,
23656
+ model,
23657
+ timestamp: str2(line.timestamp),
23658
+ input: Math.max(0, input - cached - (disjoint ? cacheWrite : 0)),
23659
+ output: int(last.output_tokens),
23660
+ cache_read: cached,
23661
+ cache_write: disjoint ? cacheWrite : 0,
23662
+ cache_write_1h: 0,
23663
+ speed: null,
23664
+ tool_call_ids: toolCallIds
23665
+ };
23666
+ toolCallIds = [];
23667
+ if (billed(request))
23668
+ requests.push(request);
23669
+ }
23670
+ }
23671
+ return requests;
23672
+ }
23673
+ function readSessionUsage(session) {
23674
+ const reader = READERS[session.harness];
23675
+ if (!reader)
23676
+ return null;
23677
+ try {
23678
+ const requests = reader(readFileSync25(session.path, "utf8"));
23679
+ return requests.length > 0 ? { requests } : null;
23680
+ } catch {
23681
+ return null;
23682
+ }
23683
+ }
23684
+ var READERS;
23685
+ var init_usage = __esm(() => {
23686
+ READERS = {
23687
+ claude: claudeUsage,
23688
+ codex: codexUsage
23689
+ };
23690
+ });
23691
+
23487
23692
  // src/shipper/worthiness.ts
23488
23693
  function isTrivialTrajectory(records) {
23489
23694
  let asked = false;
@@ -23513,6 +23718,7 @@ function createShipStep(options) {
23513
23718
  const fetchImpl = options.fetchImpl ?? fetch;
23514
23719
  const isIncognito = options.isIncognito ?? isIncognitoSession;
23515
23720
  const normalize = options.normalize ?? normalizeSessionRecords;
23721
+ const readUsage = options.readUsage ?? readSessionUsage;
23516
23722
  async function shipOne(session, shipped, resolve, hold) {
23517
23723
  const held = hold(session);
23518
23724
  if (held === "stop")
@@ -23542,18 +23748,21 @@ function createShipStep(options) {
23542
23748
  const start = sessionStartOf(records, copied);
23543
23749
  const branch = start.recorded ?? resolve.resolveBranch(session, start.firstPromptAt);
23544
23750
  const parentSessionId = session.parentId ?? session.forkOf?.id;
23751
+ const repo = githubSlugOfRepo(resolve.resolveRepo(session));
23752
+ const usage = readUsage(session);
23545
23753
  const body = JSON.stringify({
23546
23754
  records: plan.records,
23547
23755
  metadata: {
23548
23756
  deployment_id: options.deploymentId,
23549
23757
  project,
23550
- repo: project,
23758
+ ...repo ? { repo } : {},
23551
23759
  agent: trajectorySourceOf(session.harness) ?? session.harness,
23552
23760
  session_id: session.id,
23553
23761
  ...branch ? { branch } : {},
23554
23762
  ...parentSessionId ? { parent_session_id: parentSessionId } : {},
23555
23763
  ...plan.continuation ? { continuation: plan.continuation } : {}
23556
- }
23764
+ },
23765
+ ...usage ? { usage } : {}
23557
23766
  });
23558
23767
  const late = hold(session);
23559
23768
  if (late === "stop")
@@ -23598,11 +23807,12 @@ function createShipStep(options) {
23598
23807
  }
23599
23808
  return async (sessions, shippedOf = () => {
23600
23809
  return;
23601
- }, hold = () => null) => {
23602
- const resolver = options.resolveProject && options.resolveBranch ? undefined : createProjectDirResolver();
23810
+ }, hold = () => null, settled = () => {}) => {
23811
+ const resolver = options.resolveProject && options.resolveBranch && options.resolveRepo ? undefined : createProjectDirResolver();
23603
23812
  const resolve = {
23604
23813
  resolveProject: options.resolveProject ?? ((session) => resolver?.resolveProject(session) ?? null),
23605
- resolveBranch: options.resolveBranch ?? ((session, at) => resolver?.resolveBranch(session, at) ?? null)
23814
+ resolveBranch: options.resolveBranch ?? ((session, at) => resolver?.resolveBranch(session, at) ?? null),
23815
+ resolveRepo: options.resolveRepo ?? ((session) => resolver?.resolveRepo(session) ?? null)
23606
23816
  };
23607
23817
  const results = [];
23608
23818
  for (const session of sessions) {
@@ -23610,6 +23820,7 @@ function createShipStep(options) {
23610
23820
  if (!result)
23611
23821
  break;
23612
23822
  results.push(result);
23823
+ settled(result);
23613
23824
  if (result.outcome === "failed")
23614
23825
  break;
23615
23826
  }
@@ -23620,16 +23831,18 @@ function createShipStep(options) {
23620
23831
  var REJECTED_STATUSES, REQUEST_TIMEOUT_MS2 = 60000;
23621
23832
  var init_runner = __esm(() => {
23622
23833
  init_project_dir();
23834
+ init_repo();
23623
23835
  init_incognito();
23624
23836
  init_continuation();
23625
23837
  init_normalize();
23626
23838
  init_session_start();
23839
+ init_usage();
23627
23840
  REJECTED_STATUSES = new Set([400, 413, 422]);
23628
23841
  });
23629
23842
 
23630
23843
  // src/memory/context-hook.ts
23631
23844
  import { basename as basename10 } from "node:path";
23632
- function str2(value) {
23845
+ function str3(value) {
23633
23846
  return typeof value === "string" && value.length > 0 ? value : null;
23634
23847
  }
23635
23848
  function harnessOf(agent) {
@@ -23667,10 +23880,10 @@ function incognitoCheckOf(agent) {
23667
23880
  return transcriptHasIncognitoMarker;
23668
23881
  }
23669
23882
  function sessionIdOf(payload, format) {
23670
- const transcript = str2(payload.transcript_path);
23883
+ const transcript = str3(payload.transcript_path);
23671
23884
  if (format === "codex" && transcript?.endsWith(".jsonl"))
23672
23885
  return basename10(transcript, ".jsonl");
23673
- return str2(payload.session_id);
23886
+ return str3(payload.session_id);
23674
23887
  }
23675
23888
  function claudeCaller(id, transcript, agentId) {
23676
23889
  if (!agentId)
@@ -23689,7 +23902,7 @@ function outsideIncognitoSession(stdin, options) {
23689
23902
  const id = sessionIdOf(payload, options.format ?? "claude");
23690
23903
  if (!id)
23691
23904
  return null;
23692
- const stored = storedSession2({ harness, id, transcript: str2(payload.transcript_path) });
23905
+ const stored = storedSession2({ harness, id, transcript: str3(payload.transcript_path) });
23693
23906
  if (!stored || scannedEverywhere(harness, stored.path))
23694
23907
  return null;
23695
23908
  return options.incognito.sessions[`${harness}/${id}`]?.by_agent ? null : stored;
@@ -23709,16 +23922,16 @@ function denial(reason) {
23709
23922
  function memoryToolHookOutput(payload, isIncognito, incognito) {
23710
23923
  if (typeof payload.tool_name !== "string" || !MEMORY_TOOL.test(payload.tool_name))
23711
23924
  return "";
23712
- const transcript = str2(payload.transcript_path);
23713
- const id = str2(payload.session_id);
23925
+ const transcript = str3(payload.transcript_path);
23926
+ const id = str3(payload.session_id);
23714
23927
  const how = incognito ? agentSwitchOf(incognito, { harness: "claude", id }, () => id && transcript ? sessionAtPath("claude", id, transcript) : null) : null;
23715
23928
  if (how)
23716
23929
  return denial(agentSwitchMessage(how, "claude", TOOLS_UNAVAILABLE));
23717
23930
  if (transcript && isIncognito(transcript))
23718
23931
  return denial(INCOGNITO_DENIAL);
23719
- const toolUseId = str2(payload.tool_use_id);
23932
+ const toolUseId = str3(payload.tool_use_id);
23720
23933
  if (toolUseId && id) {
23721
- recordClaudeToolCall(toolUseId, claudeCaller(id, transcript, str2(payload.agent_id)));
23934
+ recordClaudeToolCall(toolUseId, claudeCaller(id, transcript, str3(payload.agent_id)));
23722
23935
  }
23723
23936
  return "";
23724
23937
  }
@@ -23736,7 +23949,7 @@ async function contextHookOutput(stdin, options) {
23736
23949
  }
23737
23950
  if (format !== "plain" && payload.hook_event_name !== "UserPromptSubmit")
23738
23951
  return "";
23739
- const prompt = str2(payload.prompt);
23952
+ const prompt = str3(payload.prompt);
23740
23953
  if (!prompt || NOTIFICATION_PROMPT.test(prompt))
23741
23954
  return "";
23742
23955
  if (textHasIncognitoMarker(prompt) || promptRunsIncognito(prompt))
@@ -23744,14 +23957,14 @@ async function contextHookOutput(stdin, options) {
23744
23957
  const agent = options.agent ?? CLAUDE_CODE_AGENT;
23745
23958
  const harness = harnessOf(agent);
23746
23959
  const sessionId = sessionIdOf(payload, format);
23747
- const transcript = str2(payload.transcript_path);
23960
+ const transcript = str3(payload.transcript_path);
23748
23961
  const switchedOff = harness && options.incognito ? agentSwitchOf(options.incognito, { harness, id: sessionId }, () => sessionId ? storedSession2({ harness, id: sessionId, transcript }) : null) : null;
23749
23962
  if (switchedOff)
23750
23963
  return "";
23751
23964
  const isIncognito = options.isIncognito ?? incognitoCheckOf(agent);
23752
23965
  if (transcript && isIncognito(transcript))
23753
23966
  return "";
23754
- const cwd = str2(payload.cwd);
23967
+ const cwd = str3(payload.cwd);
23755
23968
  const fetchImpl = options.fetchImpl ?? fetch;
23756
23969
  const budgetMs = options.timeoutMs ?? CONTEXT_TIMEOUT_MS;
23757
23970
  const startedAt = Date.now();
@@ -23779,9 +23992,9 @@ async function contextHookOutput(stdin, options) {
23779
23992
  return "";
23780
23993
  }
23781
23994
  const body = await response.json();
23782
- const digest = str2(body.digest);
23995
+ const digest = str3(body.digest);
23783
23996
  if (!digest) {
23784
- note(`no digest, ${str2(body.reason) ?? "none"}`);
23997
+ note(`no digest, ${str3(body.reason) ?? "none"}`);
23785
23998
  return "";
23786
23999
  }
23787
24000
  const count = Array.isArray(body.memory_ids) ? body.memory_ids.length : 0;
@@ -23813,7 +24026,7 @@ var init_context_hook = __esm(() => {
23813
24026
  });
23814
24027
 
23815
24028
  // src/commands/knowledge.ts
23816
- import { readFileSync as readFileSync25 } from "node:fs";
24029
+ import { readFileSync as readFileSync26 } from "node:fs";
23817
24030
  function collectValues(value, previous = []) {
23818
24031
  return [...previous, value];
23819
24032
  }
@@ -23999,21 +24212,11 @@ ${results.length - opts.limit} more results not shown.`));
23999
24212
  ...opts.retryRejected ? { retryRejectedBefore: new Date } : {},
24000
24213
  deps
24001
24214
  };
24002
- let outcome = await runKnowledgeSync(syncOptions);
24003
- let sessionsShipped = outcome.counts?.shipped ?? 0;
24004
- if ((opts.bootstrap || opts.flush) && deps.ship) {
24005
- const maxRounds = Math.ceil(outcome.readySessions / SHIP_BATCH_LIMIT) + 2;
24006
- for (let round = 1;outcome.status === "shipped" && (outcome.settledSessions ?? 0) > 0 && (outcome.settledSessions ?? 0) < outcome.readySessions && round < maxRounds; round++) {
24007
- if (!opts.quiet && !opts.json)
24008
- printSyncOutcome(outcome);
24009
- outcome = await runKnowledgeSync(syncOptions);
24010
- sessionsShipped += outcome.counts?.shipped ?? 0;
24011
- }
24012
- }
24215
+ const outcome = await runKnowledgeSync(syncOptions);
24013
24216
  recordCommandFacets({
24014
24217
  sync_trigger: trigger,
24015
24218
  sync_status: outcome.status,
24016
- sessions_shipped: sessionsShipped
24219
+ sessions_shipped: outcome.counts?.shipped ?? 0
24017
24220
  });
24018
24221
  if (opts.quiet)
24019
24222
  return;
@@ -24080,7 +24283,7 @@ function buildShipper() {
24080
24283
  };
24081
24284
  }
24082
24285
  function readStdin3() {
24083
- return readFileSync25(0, "utf-8");
24286
+ return readFileSync26(0, "utf-8");
24084
24287
  }
24085
24288
  function contextCommand2() {
24086
24289
  return new Command("context").description("Prompt-submit hook: add task memory to the agent's context").option("--agent <source>", "Trajectory source the session ships as", "claude-code").option("--format <format>", "Output: claude or codex hook JSON, or plain digest text", "claude").action(async (opts) => {
@@ -24345,9 +24548,9 @@ function printSyncOutcome(outcome) {
24345
24548
  process.exitCode = 1;
24346
24549
  break;
24347
24550
  }
24348
- const remaining = outcome.readySessions - (outcome.settledSessions ?? 0);
24349
- if (remaining > 0) {
24350
- console.log(import_picocolors23.default.dim(`${remaining} more in the backlog; run sync again to continue.`));
24551
+ if (outcome.inFlightSessions > 0) {
24552
+ const n = outcome.inFlightSessions;
24553
+ console.log(import_picocolors23.default.dim(`${n} session${plural(n)} still in progress will ship once ${n === 1 ? "it ends" : "they end"}.`));
24351
24554
  }
24352
24555
  break;
24353
24556
  }
@@ -24804,17 +25007,17 @@ var init_members = __esm(() => {
24804
25007
  });
24805
25008
 
24806
25009
  // src/mcp/relay.ts
24807
- function isObject7(value) {
25010
+ function isObject8(value) {
24808
25011
  return typeof value === "object" && value !== null && !Array.isArray(value);
24809
25012
  }
24810
25013
  function messagesOf(value) {
24811
25014
  return Array.isArray(value) ? value : [value];
24812
25015
  }
24813
25016
  function requestIds(message) {
24814
- return messagesOf(message).flatMap((m) => isObject7(m) && typeof m.method === "string" && (typeof m.id === "string" || typeof m.id === "number") ? [m.id] : []);
25017
+ return messagesOf(message).flatMap((m) => isObject8(m) && typeof m.method === "string" && (typeof m.id === "string" || typeof m.id === "number") ? [m.id] : []);
24815
25018
  }
24816
25019
  function responseIds(message) {
24817
- return messagesOf(message).flatMap((m) => isObject7(m) && (typeof m.id === "string" || typeof m.id === "number") && (("result" in m) || ("error" in m)) ? [m.id] : []);
25020
+ return messagesOf(message).flatMap((m) => isObject8(m) && (typeof m.id === "string" || typeof m.id === "number") && (("result" in m) || ("error" in m)) ? [m.id] : []);
24818
25021
  }
24819
25022
  function transportError(id, message) {
24820
25023
  return { jsonrpc: "2.0", id, error: { code: TRANSPORT_ERROR, message } };
@@ -24822,9 +25025,9 @@ function transportError(id, message) {
24822
25025
  function errorDetail(body) {
24823
25026
  try {
24824
25027
  const parsed = JSON.parse(body);
24825
- if (isObject7(parsed)) {
25028
+ if (isObject8(parsed)) {
24826
25029
  const { error, error_description, detail } = parsed;
24827
- if (isObject7(error) && typeof error.message === "string")
25030
+ if (isObject8(error) && typeof error.message === "string")
24828
25031
  return error.message;
24829
25032
  if (typeof error_description === "string")
24830
25033
  return error_description;
@@ -24839,7 +25042,7 @@ function errorDetail(body) {
24839
25042
  function jsonRpcErrorBody(body, ids) {
24840
25043
  try {
24841
25044
  const parsed = JSON.parse(body);
24842
- if (isObject7(parsed) && isObject7(parsed.error) && ids.includes(parsed.id)) {
25045
+ if (isObject8(parsed) && isObject8(parsed.error) && ids.includes(parsed.id)) {
24843
25046
  return parsed;
24844
25047
  }
24845
25048
  } catch {}
@@ -24933,9 +25136,9 @@ function createMcpRelay(options) {
24933
25136
  return out;
24934
25137
  }
24935
25138
  function noteInitialized(sent, reply) {
24936
- const initializeIds = messagesOf(sent).flatMap((m) => isObject7(m) && m.method === "initialize" ? [m.id] : []);
25139
+ const initializeIds = messagesOf(sent).flatMap((m) => isObject8(m) && m.method === "initialize" ? [m.id] : []);
24937
25140
  for (const m of messagesOf(reply)) {
24938
- if (!isObject7(m) || !initializeIds.includes(m.id) || !isObject7(m.result))
25141
+ if (!isObject8(m) || !initializeIds.includes(m.id) || !isObject8(m.result))
24939
25142
  continue;
24940
25143
  if (typeof m.result.protocolVersion === "string")
24941
25144
  protocolVersion = m.result.protocolVersion;
@@ -25060,13 +25263,13 @@ function openSession(options) {
25060
25263
  function proxyRelay(options = {}) {
25061
25264
  return openSession(options).relay;
25062
25265
  }
25063
- function isObject8(value) {
25266
+ function isObject9(value) {
25064
25267
  return typeof value === "object" && value !== null && !Array.isArray(value);
25065
25268
  }
25066
25269
  function firstRootDir(answer) {
25067
- const roots = isObject8(answer.result) ? answer.result.roots : undefined;
25270
+ const roots = isObject9(answer.result) ? answer.result.roots : undefined;
25068
25271
  for (const root of Array.isArray(roots) ? roots : []) {
25069
- if (!isObject8(root) || typeof root.uri !== "string" || !root.uri.startsWith("file:"))
25272
+ if (!isObject9(root) || typeof root.uri !== "string" || !root.uri.startsWith("file:"))
25070
25273
  continue;
25071
25274
  try {
25072
25275
  return fileURLToPath3(root.uri);
@@ -25100,10 +25303,10 @@ async function serveStdio(session, input, write) {
25100
25303
  emit({ jsonrpc: "2.0", id: ROOTS_REQUEST_ID, method: "roots/list" });
25101
25304
  };
25102
25305
  const screen = (message) => {
25103
- const call = isObject8(message) && message.method === "tools/call" ? message : null;
25306
+ const call = isObject9(message) && message.method === "tools/call" ? message : null;
25104
25307
  if (!call)
25105
25308
  return { callSession: null, refusal: null };
25106
- const callSession = isObject8(call.params) ? takeCallSession(call.params, session.client) : null;
25309
+ const callSession = isObject9(call.params) ? takeCallSession(call.params, session.client) : null;
25107
25310
  const text = callRefusal(session.client, callSession ? [callSession] : []);
25108
25311
  if (!text)
25109
25312
  return { callSession, refusal: null };
@@ -25128,14 +25331,14 @@ async function serveStdio(session, input, write) {
25128
25331
  emit(PARSE_ERROR);
25129
25332
  return;
25130
25333
  }
25131
- const method = isObject8(message) ? message.method : undefined;
25132
- if (takeRoots && isObject8(message) && message.id === ROOTS_REQUEST_ID && !method) {
25334
+ const method = isObject9(message) ? message.method : undefined;
25335
+ if (takeRoots && isObject9(message) && message.id === ROOTS_REQUEST_ID && !method) {
25133
25336
  takeRoots(message);
25134
25337
  return;
25135
25338
  }
25136
- if (method === "initialize" && isObject8(message)) {
25137
- const params = isObject8(message.params) ? message.params : {};
25138
- agentOffersRoots = isObject8(params.capabilities) && isObject8(params.capabilities.roots);
25339
+ if (method === "initialize" && isObject9(message)) {
25340
+ const params = isObject9(message.params) ? message.params : {};
25341
+ agentOffersRoots = isObject9(params.capabilities) && isObject9(params.capabilities.roots);
25139
25342
  }
25140
25343
  let outgoing = message;
25141
25344
  let named = null;
@@ -25375,12 +25578,12 @@ var init_org = __esm(() => {
25375
25578
  });
25376
25579
 
25377
25580
  // src/sessions/project-links.ts
25378
- import { existsSync as existsSync19, readFileSync as readFileSync26 } from "node:fs";
25581
+ import { existsSync as existsSync19, readFileSync as readFileSync27 } from "node:fs";
25379
25582
  function readLinksFile(configDir) {
25380
25583
  const path = projectLinksPath(configDir);
25381
25584
  if (!existsSync19(path))
25382
25585
  return { links: [] };
25383
- const raw = readFileSync26(path, "utf-8").trim();
25586
+ const raw = readFileSync27(path, "utf-8").trim();
25384
25587
  if (!raw)
25385
25588
  return { links: [] };
25386
25589
  let parsed;
@@ -25829,7 +26032,7 @@ var init_time_range = __esm(() => {
25829
26032
  });
25830
26033
 
25831
26034
  // src/commands/review.ts
25832
- import { readFileSync as readFileSync27 } from "node:fs";
26035
+ import { readFileSync as readFileSync28 } from "node:fs";
25833
26036
  function requireConfig10() {
25834
26037
  return requireLoginConfig();
25835
26038
  }
@@ -26067,7 +26270,7 @@ function reviewCommand() {
26067
26270
  let body = opts.body;
26068
26271
  if (opts.bodyFile) {
26069
26272
  try {
26070
- body = readFileSync27(opts.bodyFile, "utf-8");
26273
+ body = readFileSync28(opts.bodyFile, "utf-8");
26071
26274
  } catch (err) {
26072
26275
  throw invalidArgument(`Failed to read --body-file: ${err.message}`);
26073
26276
  }
@@ -27011,7 +27214,7 @@ import {
27011
27214
  existsSync as existsSync20,
27012
27215
  lstatSync,
27013
27216
  mkdirSync as mkdirSync12,
27014
- readFileSync as readFileSync28,
27217
+ readFileSync as readFileSync29,
27015
27218
  rmSync as rmSync4,
27016
27219
  symlinkSync,
27017
27220
  writeFileSync as writeFileSync13
@@ -27034,8 +27237,6 @@ function linkedSkillsDir(agent) {
27034
27237
  const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join24(homedir9(), ".claude");
27035
27238
  return join24(claudeConfigDir, "skills");
27036
27239
  }
27037
- if (agent === "windsurf")
27038
- return join24(homedir9(), ".codeium", "windsurf", "skills");
27039
27240
  return null;
27040
27241
  }
27041
27242
  function skillInstallTargetForProvider(providerID) {
@@ -27055,7 +27256,7 @@ function readSkillInstallState() {
27055
27256
  const path = installStatePath();
27056
27257
  if (!existsSync20(path))
27057
27258
  return null;
27058
- const data = JSON.parse(readFileSync28(path, "utf-8"));
27259
+ const data = JSON.parse(readFileSync29(path, "utf-8"));
27059
27260
  if (typeof data?.version === "string" && Array.isArray(data.agents) && data.agents.every((agent) => typeof agent === "string") && typeof data.installedAt === "number") {
27060
27261
  return { version: data.version, agents: data.agents, installedAt: data.installedAt };
27061
27262
  }
@@ -27082,7 +27283,7 @@ function pruneLegacySkillLock() {
27082
27283
  try {
27083
27284
  if (!existsSync20(lockPath))
27084
27285
  return [];
27085
- const lock = JSON.parse(readFileSync28(lockPath, "utf-8"));
27286
+ const lock = JSON.parse(readFileSync29(lockPath, "utf-8"));
27086
27287
  const skills = lock?.skills;
27087
27288
  if (!skills || typeof skills !== "object")
27088
27289
  return [];
@@ -27186,7 +27387,10 @@ function removeSkills() {
27186
27387
  const names = new Set([...BUNDLED_SKILLS.map((skill) => skill.name), ...legacy]);
27187
27388
  const dirs = [
27188
27389
  universalSkillsDir(),
27189
- ...new Set(SUPPORTED_SKILL_AGENTS.map(linkedSkillsDir).filter((dir) => !!dir))
27390
+ ...new Set([
27391
+ ...SUPPORTED_SKILL_AGENTS.map(linkedSkillsDir).filter((dir) => !!dir),
27392
+ ...LEGACY_LINKED_SKILLS_DIRS.map((dir) => dir())
27393
+ ])
27190
27394
  ];
27191
27395
  const removed = [];
27192
27396
  for (const dir of dirs) {
@@ -27252,7 +27456,7 @@ Failed to update skill.`));
27252
27456
  });
27253
27457
  return cmd;
27254
27458
  }
27255
- var import_picocolors31, SKILL_NAME = "dosu", LEGACY_SKILL_SOURCE = "dosu-ai/dosu-skill", INSTALL_STATE_FILENAME = "skill-install.json", LEGACY_CACHE_FILENAME = "skill-update-check.json", SUPPORTED_SKILL_AGENTS, SKILL_AGENT_BY_PROVIDER;
27459
+ var import_picocolors31, SKILL_NAME = "dosu", LEGACY_SKILL_SOURCE = "dosu-ai/dosu-skill", INSTALL_STATE_FILENAME = "skill-install.json", LEGACY_CACHE_FILENAME = "skill-update-check.json", SUPPORTED_SKILL_AGENTS, SKILL_AGENT_BY_PROVIDER, LEGACY_LINKED_SKILLS_DIRS;
27256
27460
  var init_skill = __esm(() => {
27257
27461
  init_commander();
27258
27462
  init_config();
@@ -27264,27 +27468,20 @@ var init_skill = __esm(() => {
27264
27468
  "cursor",
27265
27469
  "gemini-cli",
27266
27470
  "codex",
27267
- "windsurf",
27268
- "zed",
27269
- "cline",
27270
27471
  "github-copilot",
27271
- "opencode",
27272
- "antigravity"
27472
+ "opencode"
27273
27473
  ];
27274
27474
  SKILL_AGENT_BY_PROVIDER = {
27275
27475
  claude: "claude-code",
27276
27476
  cursor: "cursor",
27277
- vscode: "github-copilot",
27278
27477
  gemini: "gemini-cli",
27279
27478
  codex: "codex",
27280
- windsurf: "windsurf",
27281
- zed: "zed",
27282
- cline: "cline",
27283
- "cline-cli": "cline",
27284
27479
  copilot: "github-copilot",
27285
- opencode: "opencode",
27286
- antigravity: "antigravity"
27480
+ opencode: "opencode"
27287
27481
  };
27482
+ LEGACY_LINKED_SKILLS_DIRS = [
27483
+ () => join24(homedir9(), ".codeium", "windsurf", "skills")
27484
+ ];
27288
27485
  });
27289
27486
 
27290
27487
  // src/commands/sources.ts
@@ -27555,7 +27752,7 @@ import {
27555
27752
  existsSync as existsSync21,
27556
27753
  lstatSync as lstatSync2,
27557
27754
  mkdirSync as mkdirSync13,
27558
- readFileSync as readFileSync29,
27755
+ readFileSync as readFileSync30,
27559
27756
  renameSync as renameSync5,
27560
27757
  unlinkSync as unlinkSync6,
27561
27758
  writeFileSync as writeFileSync14
@@ -27630,7 +27827,7 @@ function readTelemetrySettings() {
27630
27827
  }
27631
27828
  let content;
27632
27829
  try {
27633
- content = readFileSync29(path, "utf-8");
27830
+ content = readFileSync30(path, "utf-8");
27634
27831
  } catch {
27635
27832
  return { status: "error", settings: disabledTelemetrySettings() };
27636
27833
  }
@@ -28114,24 +28311,6 @@ var init_base = __esm(() => {
28114
28311
  init_shape();
28115
28312
  });
28116
28313
 
28117
- // src/mcp/providers/antigravity.ts
28118
- var AntigravityProvider = () => createJSONProvider({
28119
- providerName: "Antigravity",
28120
- providerID: "antigravity",
28121
- local: false,
28122
- priorityValue: 15,
28123
- paths: ["~/.gemini"],
28124
- globalPath: "~/.gemini/antigravity/mcp_config.json",
28125
- topKey: "mcpServers",
28126
- buildServer: ({ url, headers }) => ({
28127
- serverUrl: url,
28128
- headers
28129
- })
28130
- });
28131
- var init_antigravity = __esm(() => {
28132
- init_base();
28133
- });
28134
-
28135
28314
  // src/mcp/providers/claude.ts
28136
28315
  import { join as join26 } from "node:path";
28137
28316
  var ClaudeProvider = () => ({
@@ -28155,116 +28334,21 @@ var init_claude = __esm(() => {
28155
28334
  init_base();
28156
28335
  });
28157
28336
 
28158
- // src/mcp/providers/claude-desktop.ts
28159
- import { join as join27 } from "node:path";
28160
- function configPath2() {
28161
- return join27(appSupportDir(), "Claude", "claude_desktop_config.json");
28162
- }
28163
- var ClaudeDesktopProvider = () => ({
28164
- name: () => "Claude Desktop",
28165
- id: () => "claude-desktop",
28166
- supportsLocal: () => false,
28167
- priority: () => 2,
28168
- detectPaths: () => [join27(appSupportDir(), "Claude")],
28169
- isInstalled: () => isInstalled([join27(appSupportDir(), "Claude")]),
28170
- globalConfigPath: () => configPath2(),
28171
- isConfigured: () => isJSONKeyConfigured(configPath2(), "mcpServers"),
28172
- isCurrent: (cfg) => {
28173
- const proxy = proxyCommandShape("claude-desktop");
28174
- return entryHasShape(proxy ? stdioServer(proxy) : npxRemoteEntry(shapeEndpoint(cfg), ANY, ANY, ANY), readJSONServer(configPath2(), "mcpServers"));
28175
- },
28176
- install(cfg, global) {
28177
- if (!global)
28178
- throw new Error("Claude Desktop does not support local installation");
28179
- const url = mcpEndpoint(cfg);
28180
- const proxy = proxyCommand("claude-desktop");
28181
- if (proxy) {
28182
- mcpHeaders(cfg.active_account?.target?.api_key);
28183
- installJSONServer(configPath2(), "mcpServers", stdioServer(proxy));
28184
- return;
28185
- }
28186
- const npx = findNpx();
28187
- installJSONServer(configPath2(), "mcpServers", npxRemoteEntry(url, cfg.active_account?.target?.api_key, npx, launcherPathEnv(npx)));
28188
- },
28189
- remove(global) {
28190
- if (!global)
28191
- throw new Error("Claude Desktop does not support local removal");
28192
- removeJSONServer(configPath2(), "mcpServers");
28193
- }
28194
- });
28195
- var init_claude_desktop = __esm(() => {
28196
- init_config_helpers();
28197
- init_detect();
28198
- init_proxy_entry();
28199
- init_shape();
28200
- });
28201
-
28202
- // src/mcp/providers/cline.ts
28203
- import { join as join28 } from "node:path";
28204
- var extensionDir = () => join28(appSupportDir(), "Code", "User", "globalStorage", "saoudrizwan.claude-dev"), ClineProvider = () => createJSONProvider({
28205
- providerName: "Cline",
28206
- providerID: "cline",
28207
- local: false,
28208
- priorityValue: 11,
28209
- paths: [extensionDir()],
28210
- globalPath: join28(extensionDir(), "settings", "cline_mcp_settings.json"),
28211
- topKey: "mcpServers",
28212
- buildStdioServer: (proxy) => ({ type: "stdio", ...stdioServer(proxy), disabled: false }),
28213
- buildServer: ({ url, headers }) => ({
28214
- url,
28215
- type: "streamableHttp",
28216
- disabled: false,
28217
- headers
28218
- })
28219
- });
28220
- var init_cline = __esm(() => {
28221
- init_detect();
28222
- init_proxy_entry();
28223
- init_base();
28224
- });
28225
-
28226
- // src/mcp/providers/cline-cli.ts
28227
- import { join as join29 } from "node:path";
28228
- function clineDir() {
28229
- return process.env.CLINE_DIR ?? expandHome("~/.cline");
28230
- }
28231
- var ClineCliProvider = () => createJSONProvider({
28232
- providerName: "Cline CLI",
28233
- providerID: "cline-cli",
28234
- local: false,
28235
- priorityValue: 12,
28236
- paths: [clineDir()],
28237
- globalPath: join29(clineDir(), "data", "settings", "cline_mcp_settings.json"),
28238
- topKey: "mcpServers",
28239
- buildStdioServer: (proxy) => ({ type: "stdio", ...stdioServer(proxy), disabled: false }),
28240
- buildServer: ({ url, headers }) => ({
28241
- url,
28242
- type: "streamableHttp",
28243
- disabled: false,
28244
- headers
28245
- })
28246
- });
28247
- var init_cline_cli = __esm(() => {
28248
- init_detect();
28249
- init_proxy_entry();
28250
- init_base();
28251
- });
28252
-
28253
28337
  // src/mcp/providers/codex.ts
28254
- import { existsSync as existsSync22, readFileSync as readFileSync30 } from "node:fs";
28255
- import { dirname as dirname9, join as join30 } from "node:path";
28338
+ import { existsSync as existsSync22, readFileSync as readFileSync31 } from "node:fs";
28339
+ import { dirname as dirname9, join as join27 } from "node:path";
28256
28340
  function codexHome4() {
28257
28341
  return process.env.CODEX_HOME || expandHome("~/.codex");
28258
28342
  }
28259
28343
  function getConfigPath2(global) {
28260
28344
  if (global)
28261
- return join30(codexHome4(), "config.toml");
28262
- return join30(process.cwd(), ".codex", "config.toml");
28345
+ return join27(codexHome4(), "config.toml");
28346
+ return join27(process.cwd(), ".codex", "config.toml");
28263
28347
  }
28264
28348
  function readTOML(path) {
28265
28349
  if (!existsSync22(path))
28266
28350
  return "";
28267
- return readFileSync30(path, "utf-8");
28351
+ return readFileSync31(path, "utf-8");
28268
28352
  }
28269
28353
  function writeTOML(path, content) {
28270
28354
  writeSecureFile(path, content);
@@ -28459,14 +28543,14 @@ function projectConfigPaths() {
28459
28543
  const chain = [];
28460
28544
  for (let dir = cwd;; ) {
28461
28545
  chain.push(dir);
28462
- if (existsSync22(join30(dir, ".git")))
28546
+ if (existsSync22(join27(dir, ".git")))
28463
28547
  break;
28464
28548
  const parent = dirname9(dir);
28465
28549
  if (parent === dir)
28466
- return [join30(cwd, ".codex", "config.toml")];
28550
+ return [join27(cwd, ".codex", "config.toml")];
28467
28551
  dir = parent;
28468
28552
  }
28469
- return chain.reverse().map((dir) => join30(dir, ".codex", "config.toml"));
28553
+ return chain.reverse().map((dir) => join27(dir, ".codex", "config.toml"));
28470
28554
  }
28471
28555
  function pruneLegacyRemoteEntry(path) {
28472
28556
  if (!existsSync22(path))
@@ -28483,12 +28567,12 @@ var FORWARDED_ENV, DOSU_TABLE = "mcp_servers.dosu", REMOTE_HTTP_KEY, CodexProvid
28483
28567
  priority: () => 8,
28484
28568
  detectPaths: () => ["~/.codex"],
28485
28569
  isInstalled: codexInstalled,
28486
- globalConfigPath: () => join30(codexHome4(), "config.toml"),
28570
+ globalConfigPath: () => join27(codexHome4(), "config.toml"),
28487
28571
  isConfigured: () => {
28488
- const content = readTOML(join30(codexHome4(), "config.toml"));
28572
+ const content = readTOML(join27(codexHome4(), "config.toml"));
28489
28573
  return content.includes("[mcp_servers.dosu]");
28490
28574
  },
28491
- isCurrent: (cfg) => entryHasShape(codexServer(cfg, true), readDosuEntry(readTOML(join30(codexHome4(), "config.toml")))),
28575
+ isCurrent: (cfg) => entryHasShape(codexServer(cfg, true), readDosuEntry(readTOML(join27(codexHome4(), "config.toml")))),
28492
28576
  install(cfg, global) {
28493
28577
  if (cfg.mode !== MODE_OSS && !cfg.active_account?.target?.deployment_id)
28494
28578
  throw new Error("deployment ID is required");
@@ -28521,7 +28605,7 @@ var init_codex3 = __esm(() => {
28521
28605
  });
28522
28606
 
28523
28607
  // src/mcp/providers/copilot.ts
28524
- import { join as join31 } from "node:path";
28608
+ import { join as join28 } from "node:path";
28525
28609
  function globalServer(url, apiKey, proxy) {
28526
28610
  if (proxy)
28527
28611
  return { type: "local", ...stdioServer(proxy), tools: ["*"] };
@@ -28529,7 +28613,7 @@ function globalServer(url, apiKey, proxy) {
28529
28613
  }
28530
28614
  function globalPath() {
28531
28615
  if (process.env.XDG_CONFIG_HOME) {
28532
- return join31(process.env.XDG_CONFIG_HOME, "mcp-config.json");
28616
+ return join28(process.env.XDG_CONFIG_HOME, "mcp-config.json");
28533
28617
  }
28534
28618
  return expandHome("~/.copilot/mcp-config.json");
28535
28619
  }
@@ -28550,7 +28634,7 @@ var CopilotProvider = () => ({
28550
28634
  if (global) {
28551
28635
  installJSONServer(globalPath(), "mcpServers", globalServer(url, cfg.active_account?.target?.api_key, proxy));
28552
28636
  } else {
28553
- const configPath = join31(process.cwd(), ".vscode", "mcp.json");
28637
+ const configPath = join28(process.cwd(), ".vscode", "mcp.json");
28554
28638
  const server = proxy ? { type: "stdio", ...stdioServer(proxy) } : { type: "http", url, headers };
28555
28639
  installJSONServer(configPath, "servers", server);
28556
28640
  }
@@ -28559,7 +28643,7 @@ var CopilotProvider = () => ({
28559
28643
  if (global) {
28560
28644
  removeJSONServer(globalPath(), "mcpServers");
28561
28645
  } else {
28562
- const configPath = join31(process.cwd(), ".vscode", "mcp.json");
28646
+ const configPath = join28(process.cwd(), ".vscode", "mcp.json");
28563
28647
  removeJSONServer(configPath, "servers");
28564
28648
  }
28565
28649
  }
@@ -28572,7 +28656,7 @@ var init_copilot = __esm(() => {
28572
28656
  });
28573
28657
 
28574
28658
  // src/mcp/providers/cursor.ts
28575
- import { join as join32 } from "node:path";
28659
+ import { join as join29 } from "node:path";
28576
28660
  var CursorProvider = () => createJSONProvider({
28577
28661
  providerName: "Cursor",
28578
28662
  providerID: "cursor",
@@ -28585,14 +28669,14 @@ var CursorProvider = () => createJSONProvider({
28585
28669
  url,
28586
28670
  headers
28587
28671
  }),
28588
- localConfigPath: (cwd) => join32(cwd, ".cursor", "mcp.json")
28672
+ localConfigPath: (cwd) => join29(cwd, ".cursor", "mcp.json")
28589
28673
  });
28590
28674
  var init_cursor2 = __esm(() => {
28591
28675
  init_base();
28592
28676
  });
28593
28677
 
28594
28678
  // src/mcp/providers/factory.ts
28595
- import { join as join33 } from "node:path";
28679
+ import { join as join30 } from "node:path";
28596
28680
  var FactoryProvider = () => createJSONProvider({
28597
28681
  providerName: "Factory",
28598
28682
  providerID: "factory",
@@ -28602,7 +28686,7 @@ var FactoryProvider = () => createJSONProvider({
28602
28686
  globalPath: "~/.factory/mcp.json",
28603
28687
  topKey: "mcpServers",
28604
28688
  buildStdioServer: (proxy) => ({ type: "stdio", ...stdioServer(proxy) }),
28605
- localConfigPath: (cwd) => join33(cwd, ".factory", "mcp.json")
28689
+ localConfigPath: (cwd) => join30(cwd, ".factory", "mcp.json")
28606
28690
  });
28607
28691
  var init_factory = __esm(() => {
28608
28692
  init_proxy_entry();
@@ -28610,7 +28694,7 @@ var init_factory = __esm(() => {
28610
28694
  });
28611
28695
 
28612
28696
  // src/mcp/providers/gemini.ts
28613
- import { join as join34 } from "node:path";
28697
+ import { join as join31 } from "node:path";
28614
28698
  var GeminiProvider = () => createJSONProvider({
28615
28699
  providerName: "Gemini CLI",
28616
28700
  providerID: "gemini",
@@ -28619,7 +28703,7 @@ var GeminiProvider = () => createJSONProvider({
28619
28703
  paths: ["~/.gemini"],
28620
28704
  globalPath: "~/.gemini/settings.json",
28621
28705
  topKey: "mcpServers",
28622
- localConfigPath: (cwd) => join34(cwd, ".gemini", "settings.json")
28706
+ localConfigPath: (cwd) => join31(cwd, ".gemini", "settings.json")
28623
28707
  });
28624
28708
  var init_gemini = __esm(() => {
28625
28709
  init_base();
@@ -28664,53 +28748,8 @@ var init_manual = __esm(() => {
28664
28748
  init_config_helpers();
28665
28749
  });
28666
28750
 
28667
- // src/mcp/providers/mcporter.ts
28668
- import { existsSync as existsSync23 } from "node:fs";
28669
- import { join as join35 } from "node:path";
28670
- function server(url, apiKey, proxy) {
28671
- if (proxy)
28672
- return stdioServer(proxy);
28673
- return { type: "http", url, headers: mcpHeaders(apiKey) };
28674
- }
28675
- function resolveGlobalConfigPath() {
28676
- const jsonPath = expandHome("~/.mcporter/mcporter.json");
28677
- if (existsSync23(jsonPath))
28678
- return jsonPath;
28679
- const jsoncPath = expandHome("~/.mcporter/mcporter.jsonc");
28680
- if (existsSync23(jsoncPath))
28681
- return jsoncPath;
28682
- return jsonPath;
28683
- }
28684
- var MCPorterProvider = () => ({
28685
- name: () => "MCPorter",
28686
- id: () => "mcporter",
28687
- supportsLocal: () => true,
28688
- priority: () => 16,
28689
- detectPaths: () => ["~/.mcporter"],
28690
- isInstalled: () => isInstalled(["~/.mcporter"]),
28691
- globalConfigPath: () => resolveGlobalConfigPath(),
28692
- isConfigured: () => isJSONKeyConfigured(resolveGlobalConfigPath(), "mcpServers"),
28693
- isCurrent: (cfg) => entryHasShape(server(shapeEndpoint(cfg), ANY, proxyCommandShape("mcporter")), readJSONServer(resolveGlobalConfigPath(), "mcpServers")),
28694
- install(cfg, global) {
28695
- const configPath = global ? resolveGlobalConfigPath() : join35(process.cwd(), "config", "mcporter.json");
28696
- const url = mcpEndpoint(cfg);
28697
- const proxy = proxyCommand("mcporter");
28698
- installJSONServer(configPath, "mcpServers", server(url, cfg.active_account?.target?.api_key, proxy));
28699
- },
28700
- remove(global) {
28701
- const configPath = global ? resolveGlobalConfigPath() : join35(process.cwd(), "config", "mcporter.json");
28702
- removeJSONServer(configPath, "mcpServers");
28703
- }
28704
- });
28705
- var init_mcporter = __esm(() => {
28706
- init_config_helpers();
28707
- init_detect();
28708
- init_proxy_entry();
28709
- init_shape();
28710
- });
28711
-
28712
28751
  // src/mcp/providers/opencode.ts
28713
- import { join as join36 } from "node:path";
28752
+ import { join as join32 } from "node:path";
28714
28753
  var jsonProvider = () => createJSONProvider({
28715
28754
  providerName: "OpenCode",
28716
28755
  providerID: "opencode",
@@ -28731,7 +28770,7 @@ var jsonProvider = () => createJSONProvider({
28731
28770
  enabled: true,
28732
28771
  headers
28733
28772
  }),
28734
- localConfigPath: (cwd) => join36(cwd, "opencode.json")
28773
+ localConfigPath: (cwd) => join32(cwd, "opencode.json")
28735
28774
  }), OpenCodeProvider = () => {
28736
28775
  const provider = jsonProvider();
28737
28776
  return { ...provider, isInstalled: () => provider.isInstalled() || isOnPath("opencode") };
@@ -28765,133 +28804,15 @@ var init_pi4 = __esm(() => {
28765
28804
  init_pi3();
28766
28805
  });
28767
28806
 
28768
- // src/mcp/providers/vscode.ts
28769
- import { join as join37 } from "node:path";
28770
- var VSCodeProvider = () => createJSONProvider({
28771
- providerName: "VS Code",
28772
- providerID: "vscode",
28773
- local: true,
28774
- priorityValue: 6,
28775
- paths: [join37(appSupportDir(), "Code")],
28776
- globalPath: join37(appSupportDir(), "Code", "User", "mcp.json"),
28777
- topKey: "servers",
28778
- buildStdioServer: (proxy) => ({ type: "stdio", ...stdioServer(proxy) }),
28779
- localConfigPath: (cwd) => join37(cwd, ".vscode", "mcp.json")
28780
- });
28781
- var init_vscode = __esm(() => {
28782
- init_detect();
28783
- init_proxy_entry();
28784
- init_base();
28785
- });
28786
-
28787
- // src/mcp/providers/windsurf.ts
28788
- import { homedir as homedir10 } from "node:os";
28789
- import { join as join38 } from "node:path";
28790
- var WindsurfProvider = () => createJSONProvider({
28791
- providerName: "Windsurf",
28792
- providerID: "windsurf",
28793
- local: false,
28794
- priorityValue: 9,
28795
- paths: [join38(homedir10(), ".codeium", "windsurf")],
28796
- globalPath: join38(homedir10(), ".codeium", "windsurf", "mcp_config.json"),
28797
- topKey: "mcpServers"
28798
- });
28799
- var init_windsurf = __esm(() => {
28800
- init_base();
28801
- });
28802
-
28803
- // src/mcp/providers/zed.ts
28804
- import { rmSync as rmSync5 } from "node:fs";
28805
- import { homedir as homedir11, platform as platform4 } from "node:os";
28806
- import { join as join39 } from "node:path";
28807
- function zedConfigDir() {
28808
- const os = platform4();
28809
- if (os === "win32")
28810
- return join39(appSupportDir(), "Zed");
28811
- if (os === "darwin")
28812
- return join39(homedir11(), ".config", "zed");
28813
- return join39(appSupportDir(), "zed");
28814
- }
28815
- function zedDataDir() {
28816
- const os = platform4();
28817
- if (os === "darwin")
28818
- return join39(appSupportDir(), "Zed");
28819
- if (os === "win32")
28820
- return join39(process.env.LOCALAPPDATA ?? "", "Zed");
28821
- return join39(process.env.XDG_DATA_HOME ?? join39(homedir11(), ".local", "share"), "zed");
28822
- }
28823
- function legacyDarwinSettingsPath() {
28824
- return platform4() === "darwin" ? join39(appSupportDir(), "Zed", "settings.json") : null;
28825
- }
28826
- function removeLegacyDosuEntry(path) {
28827
- let cfg;
28828
- try {
28829
- cfg = readJSONConfig(path);
28830
- } catch {
28831
- return;
28832
- }
28833
- const servers = cfg.context_servers;
28834
- if (typeof servers !== "object" || servers === null || !("dosu" in servers))
28835
- return;
28836
- delete servers.dosu;
28837
- const nothingElse = Object.keys(cfg).length === 1 && Object.keys(servers).length === 0;
28838
- if (nothingElse)
28839
- rmSync5(path, { force: true });
28840
- else
28841
- saveJSONConfig(path, cfg);
28842
- }
28843
- var ZedProvider = (legacyPath = legacyDarwinSettingsPath()) => {
28844
- const provider = createJSONProvider({
28845
- providerName: "Zed",
28846
- providerID: "zed",
28847
- local: true,
28848
- priorityValue: 10,
28849
- paths: [zedConfigDir(), zedDataDir()],
28850
- globalPath: join39(zedConfigDir(), "settings.json"),
28851
- topKey: "context_servers",
28852
- buildServer: ({ url, headers }) => ({ url, headers }),
28853
- localConfigPath: (cwd) => join39(cwd, ".zed", "settings.json")
28854
- });
28855
- if (!legacyPath)
28856
- return provider;
28857
- return {
28858
- ...provider,
28859
- isCurrent: (cfg) => provider.isCurrent(cfg) && readJSONServer(legacyPath, "context_servers") === undefined,
28860
- install(cfg, global) {
28861
- provider.install(cfg, global);
28862
- if (global)
28863
- removeLegacyDosuEntry(legacyPath);
28864
- },
28865
- remove(global) {
28866
- provider.remove(global);
28867
- if (global)
28868
- removeLegacyDosuEntry(legacyPath);
28869
- }
28870
- };
28871
- };
28872
- var init_zed = __esm(() => {
28873
- init_config_helpers();
28874
- init_detect();
28875
- init_base();
28876
- });
28877
-
28878
28807
  // src/mcp/providers.ts
28879
28808
  function allProviders() {
28880
28809
  return [
28881
28810
  ClaudeProvider(),
28882
- ClaudeDesktopProvider(),
28883
28811
  CursorProvider(),
28884
- VSCodeProvider(),
28885
28812
  GeminiProvider(),
28886
28813
  CodexProvider(),
28887
- WindsurfProvider(),
28888
- ZedProvider(),
28889
- ClineProvider(),
28890
- ClineCliProvider(),
28891
28814
  CopilotProvider(),
28892
28815
  OpenCodeProvider(),
28893
- AntigravityProvider(),
28894
- MCPorterProvider(),
28895
28816
  FactoryProvider(),
28896
28817
  PiProvider(),
28897
28818
  ManualProvider()
@@ -28908,23 +28829,15 @@ function getProvider(toolID) {
28908
28829
  return provider;
28909
28830
  }
28910
28831
  var init_providers = __esm(() => {
28911
- init_antigravity();
28912
28832
  init_claude();
28913
- init_claude_desktop();
28914
- init_cline();
28915
- init_cline_cli();
28916
28833
  init_codex3();
28917
28834
  init_copilot();
28918
28835
  init_cursor2();
28919
28836
  init_factory();
28920
28837
  init_gemini();
28921
28838
  init_manual();
28922
- init_mcporter();
28923
28839
  init_opencode4();
28924
28840
  init_pi4();
28925
- init_vscode();
28926
- init_windsurf();
28927
- init_zed();
28928
28841
  });
28929
28842
 
28930
28843
  // src/mcp/refresh.ts
@@ -28973,29 +28886,29 @@ var init_refresh = __esm(() => {
28973
28886
  import { spawn as spawn2 } from "node:child_process";
28974
28887
  import {
28975
28888
  closeSync as closeSync8,
28976
- existsSync as existsSync24,
28889
+ existsSync as existsSync23,
28977
28890
  mkdirSync as mkdirSync14,
28978
28891
  openSync as openSync8,
28979
- readFileSync as readFileSync31,
28980
- rmSync as rmSync6,
28892
+ readFileSync as readFileSync32,
28893
+ rmSync as rmSync5,
28981
28894
  statSync as statSync11,
28982
28895
  writeFileSync as writeFileSync15,
28983
28896
  writeSync
28984
28897
  } from "node:fs";
28985
- import { homedir as homedir12 } from "node:os";
28986
- import { join as join40 } from "node:path";
28898
+ import { homedir as homedir10 } from "node:os";
28899
+ import { join as join33 } from "node:path";
28987
28900
  function statePath() {
28988
- return join40(getConfigDir(), STATE_FILENAME2);
28901
+ return join33(getConfigDir(), STATE_FILENAME2);
28989
28902
  }
28990
28903
  function lockPath2() {
28991
- return join40(getConfigDir(), LOCK_FILENAME2);
28904
+ return join33(getConfigDir(), LOCK_FILENAME2);
28992
28905
  }
28993
28906
  function isValidVersion(value) {
28994
28907
  return typeof value === "string" && VERSION_PATTERN.test(value);
28995
28908
  }
28996
28909
  function readState() {
28997
28910
  try {
28998
- const raw = JSON.parse(readFileSync31(statePath(), "utf-8"));
28911
+ const raw = JSON.parse(readFileSync32(statePath(), "utf-8"));
28999
28912
  if (typeof raw !== "object" || raw === null || Array.isArray(raw))
29000
28913
  return {};
29001
28914
  const data = raw;
@@ -29014,7 +28927,7 @@ function readState() {
29014
28927
  function writeState(state) {
29015
28928
  try {
29016
28929
  const dir = getConfigDir();
29017
- if (!existsSync24(dir))
28930
+ if (!existsSync23(dir))
29018
28931
  mkdirSync14(dir, { recursive: true, mode: 448 });
29019
28932
  writeFileSync15(statePath(), `${JSON.stringify(state, null, 2)}
29020
28933
  `, { mode: 384 });
@@ -29071,7 +28984,7 @@ function claimLock(version, now) {
29071
28984
  try {
29072
28985
  mkdirSync14(getConfigDir(), { recursive: true, mode: 448 });
29073
28986
  if (!lockIsFresh(now))
29074
- rmSync6(lockPath2(), { force: true });
28987
+ rmSync5(lockPath2(), { force: true });
29075
28988
  const fd = openSync8(lockPath2(), "wx", 384);
29076
28989
  try {
29077
28990
  writeSync(fd, version);
@@ -29085,12 +28998,12 @@ function claimLock(version, now) {
29085
28998
  }
29086
28999
  function releaseLock() {
29087
29000
  try {
29088
- rmSync6(lockPath2(), { force: true });
29001
+ rmSync5(lockPath2(), { force: true });
29089
29002
  } catch {}
29090
29003
  }
29091
29004
  function readLockVersion() {
29092
29005
  try {
29093
- const version = readFileSync31(lockPath2(), "utf-8").trim();
29006
+ const version = readFileSync32(lockPath2(), "utf-8").trim();
29094
29007
  return isValidVersion(version) ? version : undefined;
29095
29008
  } catch {
29096
29009
  return;
@@ -29117,7 +29030,7 @@ function startAutoUpdate(version, options = {}) {
29117
29030
  return claim === "held" ? "in_progress" : "unavailable";
29118
29031
  try {
29119
29032
  const child = spawn2(invocation.command, invocation.args, {
29120
- cwd: homedir12(),
29033
+ cwd: homedir10(),
29121
29034
  detached: true,
29122
29035
  stdio: "ignore",
29123
29036
  windowsHide: true,
@@ -29164,17 +29077,17 @@ var init_auto_update = __esm(() => {
29164
29077
  });
29165
29078
 
29166
29079
  // src/version/mcp-refresh-check.ts
29167
- import { existsSync as existsSync25, mkdirSync as mkdirSync15, readFileSync as readFileSync32, writeFileSync as writeFileSync16 } from "node:fs";
29168
- import { join as join41 } from "node:path";
29080
+ import { existsSync as existsSync24, mkdirSync as mkdirSync15, readFileSync as readFileSync33, writeFileSync as writeFileSync16 } from "node:fs";
29081
+ import { join as join34 } from "node:path";
29169
29082
  function getCachePath2() {
29170
- return join41(getConfigDir(), CACHE_FILENAME3);
29083
+ return join34(getConfigDir(), CACHE_FILENAME3);
29171
29084
  }
29172
29085
  function readMcpRefreshCache() {
29173
29086
  try {
29174
29087
  const path = getCachePath2();
29175
- if (!existsSync25(path))
29088
+ if (!existsSync24(path))
29176
29089
  return null;
29177
- const data = JSON.parse(readFileSync32(path, "utf-8"));
29090
+ const data = JSON.parse(readFileSync33(path, "utf-8"));
29178
29091
  if (typeof data?.version === "string")
29179
29092
  return { version: data.version };
29180
29093
  return null;
@@ -29185,7 +29098,7 @@ function readMcpRefreshCache() {
29185
29098
  function writeMcpRefreshCache(cache) {
29186
29099
  try {
29187
29100
  const dir = getConfigDir();
29188
- if (!existsSync25(dir)) {
29101
+ if (!existsSync24(dir)) {
29189
29102
  mkdirSync15(dir, { recursive: true, mode: 448 });
29190
29103
  }
29191
29104
  writeFileSync16(getCachePath2(), JSON.stringify(cache), { mode: 384 });
@@ -29328,15 +29241,15 @@ function createLogFollower(path, emit) {
29328
29241
  var init_follow = () => {};
29329
29242
 
29330
29243
  // src/sessions/session-title.ts
29331
- import { existsSync as existsSync26, mkdirSync as mkdirSync16, readFileSync as readFileSync33, renameSync as renameSync6, statSync as statSync13, writeFileSync as writeFileSync17 } from "node:fs";
29332
- import { homedir as homedir13 } from "node:os";
29333
- import { join as join42 } from "node:path";
29244
+ import { existsSync as existsSync25, mkdirSync as mkdirSync16, readFileSync as readFileSync34, renameSync as renameSync6, statSync as statSync13, writeFileSync as writeFileSync17 } from "node:fs";
29245
+ import { homedir as homedir11 } from "node:os";
29246
+ import { join as join35 } from "node:path";
29334
29247
  function cachePath2(configDir) {
29335
- return join42(configDir, CACHE_FILENAME4);
29248
+ return join35(configDir, CACHE_FILENAME4);
29336
29249
  }
29337
29250
  function loadCacheFile2(configDir) {
29338
29251
  try {
29339
- const raw = JSON.parse(readFileSync33(cachePath2(configDir), "utf-8"));
29252
+ const raw = JSON.parse(readFileSync34(cachePath2(configDir), "utf-8"));
29340
29253
  if (raw.schema_version !== CACHE_SCHEMA_VERSION2 || typeof raw.entries !== "object")
29341
29254
  return {};
29342
29255
  return raw.entries;
@@ -29346,7 +29259,7 @@ function loadCacheFile2(configDir) {
29346
29259
  }
29347
29260
  function saveCacheFile2(configDir, entries) {
29348
29261
  try {
29349
- if (!existsSync26(configDir))
29262
+ if (!existsSync25(configDir))
29350
29263
  mkdirSync16(configDir, { recursive: true, mode: 448 });
29351
29264
  const path = cachePath2(configDir);
29352
29265
  const tmp = `${path}.${process.pid}.tmp`;
@@ -29384,15 +29297,15 @@ function claudeSummaryFromHead(text) {
29384
29297
  }
29385
29298
  return null;
29386
29299
  }
29387
- function reconstructSession(harness, id, slug, home = homedir13(), exists = existsSync26) {
29300
+ function reconstructSession(harness, id, slug, home = homedir11(), exists = existsSync25) {
29388
29301
  if (!slug)
29389
29302
  return null;
29390
29303
  const candidates = [];
29391
29304
  if (harness === "claude") {
29392
- candidates.push(join42(home, ".claude", "projects", slug, `${id}.jsonl`));
29305
+ candidates.push(join35(home, ".claude", "projects", slug, `${id}.jsonl`));
29393
29306
  } else if (harness === "cursor") {
29394
- const project = join42(home, ".cursor", "projects", slug);
29395
- candidates.push(join42(project, "agent-transcripts", id, `${id}.jsonl`), join42(project, "agent-transcripts", `${id}.jsonl`));
29307
+ const project = join35(home, ".cursor", "projects", slug);
29308
+ candidates.push(join35(project, "agent-transcripts", id, `${id}.jsonl`), join35(project, "agent-transcripts", `${id}.jsonl`));
29396
29309
  } else {
29397
29310
  return null;
29398
29311
  }
@@ -29404,7 +29317,7 @@ function reconstructSession(harness, id, slug, home = homedir13(), exists = exis
29404
29317
  }
29405
29318
  function readHead3(path) {
29406
29319
  try {
29407
- return readFileSync33(path, "utf-8").slice(0, 128 * 1024);
29320
+ return readFileSync34(path, "utf-8").slice(0, 128 * 1024);
29408
29321
  } catch {
29409
29322
  return null;
29410
29323
  }
@@ -29484,7 +29397,7 @@ var init_alt_screen = __esm(() => {
29484
29397
  });
29485
29398
 
29486
29399
  // src/tui/activity-view.ts
29487
- import { existsSync as existsSync27, readFileSync as readFileSync34 } from "node:fs";
29400
+ import { existsSync as existsSync26, readFileSync as readFileSync35 } from "node:fs";
29488
29401
  import { basename as basename11 } from "node:path";
29489
29402
  function reduceActivityViewKey(key) {
29490
29403
  if (key === "q" || key === ESC7 || key === CTRL_C4)
@@ -29659,8 +29572,8 @@ function confirmBox(queuedCount, backlog, width, mode = "start") {
29659
29572
  "",
29660
29573
  `${import_picocolors37.default.bold("enter")} ${verb} · ${import_picocolors37.default.bold("esc")} cancel`
29661
29574
  ];
29662
- const inner = Math.min(maxInner, Math.max(...rows.map(visibleWidth2)));
29663
- const pad = (row) => row + " ".repeat(Math.max(0, inner - visibleWidth2(row)));
29575
+ const inner = Math.min(maxInner, Math.max(...rows.map(visibleWidth)));
29576
+ const pad = (row) => row + " ".repeat(Math.max(0, inner - visibleWidth(row)));
29664
29577
  return [
29665
29578
  import_picocolors37.default.dim(`╭${"─".repeat(inner + 2)}╮`),
29666
29579
  ...rows.map((row) => `${import_picocolors37.default.dim("│")} ${pad(row)} ${import_picocolors37.default.dim("│")}`),
@@ -29771,7 +29684,7 @@ function createRowNamer() {
29771
29684
  names.titles[key] = t;
29772
29685
  };
29773
29686
  for (const s of [...backlog.queued, ...backlog.open]) {
29774
- if (!existsSync27(s.path))
29687
+ if (!existsSync26(s.path))
29775
29688
  continue;
29776
29689
  const key = `${s.harness}/${s.id}`;
29777
29690
  const dir = dirs.resolve(s);
@@ -29808,7 +29721,7 @@ function createRowNamer() {
29808
29721
  }
29809
29722
  function defaultReadLog2() {
29810
29723
  try {
29811
- return readFileSync34(logger.getLogPath(), "utf-8");
29724
+ return readFileSync35(logger.getLogPath(), "utf-8");
29812
29725
  } catch {
29813
29726
  return "";
29814
29727
  }
@@ -30028,14 +29941,14 @@ var init_activity_view = __esm(() => {
30028
29941
  });
30029
29942
 
30030
29943
  // src/rules/installer.ts
30031
- import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync35, unlinkSync as unlinkSync7, writeFileSync as writeFileSync18 } from "node:fs";
30032
- import { homedir as homedir14 } from "node:os";
30033
- import { dirname as dirname10, join as join43 } from "node:path";
29944
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync36, unlinkSync as unlinkSync7, writeFileSync as writeFileSync18 } from "node:fs";
29945
+ import { homedir as homedir12 } from "node:os";
29946
+ import { dirname as dirname10, join as join36 } from "node:path";
30034
29947
  function claudeConfigDir4() {
30035
- return process.env.CLAUDE_CONFIG_DIR || join43(homedir14(), ".claude");
29948
+ return process.env.CLAUDE_CONFIG_DIR || join36(homedir12(), ".claude");
30036
29949
  }
30037
29950
  function codexHome5() {
30038
- return process.env.CODEX_HOME || join43(homedir14(), ".codex");
29951
+ return process.env.CODEX_HOME || join36(homedir12(), ".codex");
30039
29952
  }
30040
29953
  function isRuleAgent(agent) {
30041
29954
  return Object.hasOwn(RULE_TARGETS, agent);
@@ -30064,12 +29977,12 @@ function ensureParent(path) {
30064
29977
  mkdirSync17(dirname10(path), { recursive: true });
30065
29978
  }
30066
29979
  function writeIfChanged2(path, content) {
30067
- if (!existsSync28(path)) {
29980
+ if (!existsSync27(path)) {
30068
29981
  ensureParent(path);
30069
29982
  writeFileSync18(path, content, "utf-8");
30070
29983
  return "created";
30071
29984
  }
30072
- if (readFileSync35(path, "utf-8") === content)
29985
+ if (readFileSync36(path, "utf-8") === content)
30073
29986
  return "unchanged";
30074
29987
  writeFileSync18(path, content, "utf-8");
30075
29988
  return "updated";
@@ -30097,14 +30010,14 @@ function buildSection(content, lineEnding = `
30097
30010
  return `${DOSU_RULE_SECTION_START}${lineEnding}${body}${lineEnding}${DOSU_RULE_SECTION_END}`;
30098
30011
  }
30099
30012
  function upsertSection(path, content) {
30100
- if (!existsSync28(path)) {
30013
+ if (!existsSync27(path)) {
30101
30014
  const section = buildSection(content);
30102
30015
  ensureParent(path);
30103
30016
  writeFileSync18(path, `${section}
30104
30017
  `, "utf-8");
30105
30018
  return "created";
30106
30019
  }
30107
- const existing = readFileSync35(path, "utf-8");
30020
+ const existing = readFileSync36(path, "utf-8");
30108
30021
  const lineEnding = lineEndingFor(existing);
30109
30022
  const section = buildSection(content, lineEnding);
30110
30023
  const location = findSection(existing);
@@ -30134,13 +30047,13 @@ function removeRuleForAgent(agent) {
30134
30047
  return null;
30135
30048
  const target = RULE_TARGETS[agent];
30136
30049
  const path = target.path();
30137
- if (!existsSync28(path))
30050
+ if (!existsSync27(path))
30138
30051
  return { agent, path, action: "not_found" };
30139
30052
  if (target.kind === "file") {
30140
30053
  unlinkSync7(path);
30141
30054
  return { agent, path, action: "removed" };
30142
30055
  }
30143
- const existing = readFileSync35(path, "utf-8");
30056
+ const existing = readFileSync36(path, "utf-8");
30144
30057
  const lineEnding = lineEndingFor(existing);
30145
30058
  const location = findSection(existing);
30146
30059
  if (!location)
@@ -30177,36 +30090,32 @@ var init_installer = __esm(() => {
30177
30090
  RULE_TARGETS = {
30178
30091
  claude: {
30179
30092
  kind: "file",
30180
- path: () => join43(claudeConfigDir4(), "rules", "dosu.md")
30093
+ path: () => join36(claudeConfigDir4(), "rules", "dosu.md")
30181
30094
  },
30182
30095
  cursor: {
30183
30096
  kind: "file",
30184
- path: () => join43(homedir14(), ".cursor", "rules", "dosu.mdc"),
30097
+ path: () => join36(homedir12(), ".cursor", "rules", "dosu.mdc"),
30185
30098
  cursorFrontmatter: true
30186
30099
  },
30187
30100
  codex: {
30188
30101
  kind: "section",
30189
- path: () => join43(codexHome5(), "AGENTS.md")
30102
+ path: () => join36(codexHome5(), "AGENTS.md")
30190
30103
  },
30191
30104
  opencode: {
30192
30105
  kind: "section",
30193
- path: () => join43(homedir14(), ".config", "opencode", "AGENTS.md")
30106
+ path: () => join36(homedir12(), ".config", "opencode", "AGENTS.md")
30194
30107
  },
30195
30108
  gemini: {
30196
30109
  kind: "section",
30197
- path: () => join43(homedir14(), ".gemini", "GEMINI.md")
30198
- },
30199
- antigravity: {
30200
- kind: "section",
30201
- path: () => join43(homedir14(), ".gemini", "GEMINI.md")
30110
+ path: () => join36(homedir12(), ".gemini", "GEMINI.md")
30202
30111
  }
30203
30112
  };
30204
30113
  });
30205
30114
 
30206
30115
  // src/setup/agents-md-step.ts
30207
30116
  import { execSync as execSync2 } from "node:child_process";
30208
- import { existsSync as existsSync29, readFileSync as readFileSync36, writeFileSync as writeFileSync19 } from "node:fs";
30209
- import { join as join44 } from "node:path";
30117
+ import { existsSync as existsSync28, readFileSync as readFileSync37, writeFileSync as writeFileSync19 } from "node:fs";
30118
+ import { join as join37 } from "node:path";
30210
30119
  function inGitWorkTree(cwd = process.cwd()) {
30211
30120
  try {
30212
30121
  const stdout = execSync2("git rev-parse --is-inside-work-tree", {
@@ -30220,10 +30129,10 @@ function inGitWorkTree(cwd = process.cwd()) {
30220
30129
  }
30221
30130
  function dosuAgentsSectionState(cwd = process.cwd()) {
30222
30131
  try {
30223
- const path = join44(cwd, "AGENTS.md");
30224
- if (!existsSync29(path))
30132
+ const path = join37(cwd, "AGENTS.md");
30133
+ if (!existsSync28(path))
30225
30134
  return "missing";
30226
- const content = readFileSync36(path, "utf-8");
30135
+ const content = readFileSync37(path, "utf-8");
30227
30136
  const startMatch = content.match(SECTION_START_RE);
30228
30137
  if (!startMatch || !content.includes(DOSU_SECTION_END))
30229
30138
  return "missing";
@@ -30258,14 +30167,14 @@ function findSection2(content) {
30258
30167
  return { start, end };
30259
30168
  }
30260
30169
  function upsertDosuAgentsSection(cwd = process.cwd(), content = FALLBACK_DOSU_RULE) {
30261
- const path = join44(cwd, "AGENTS.md");
30262
- if (!existsSync29(path)) {
30170
+ const path = join37(cwd, "AGENTS.md");
30171
+ if (!existsSync28(path)) {
30263
30172
  const section = buildDosuAgentsSection(content);
30264
30173
  writeFileSync19(path, `${section}
30265
30174
  `);
30266
30175
  return { path, action: "created" };
30267
30176
  }
30268
- const existing = readFileSync36(path, "utf-8");
30177
+ const existing = readFileSync37(path, "utf-8");
30269
30178
  const lineEnding = lineEndingFor2(existing);
30270
30179
  const section = renderDosuAgentsSection(content, lineEnding);
30271
30180
  const location = findSection2(existing);
@@ -30566,6 +30475,58 @@ var init_rules_step = __esm(() => {
30566
30475
  init_styles();
30567
30476
  });
30568
30477
 
30478
+ // src/setup/scope-step.ts
30479
+ function scopeCandidates(sessions, current) {
30480
+ const byRepo = new Map;
30481
+ for (const { repo, updated } of sessions) {
30482
+ if (!repo)
30483
+ continue;
30484
+ const candidate = byRepo.get(repo);
30485
+ if (!candidate)
30486
+ byRepo.set(repo, { repo, sessions: 1, updated });
30487
+ else {
30488
+ candidate.sessions += 1;
30489
+ if (updated > candidate.updated)
30490
+ candidate.updated = updated;
30491
+ }
30492
+ }
30493
+ for (const repo of current ?? []) {
30494
+ if (!byRepo.has(repo))
30495
+ byRepo.set(repo, { repo, sessions: 0, updated: "" });
30496
+ }
30497
+ return [...byRepo.values()].sort((a, b) => b.sessions - a.sessions || b.updated.localeCompare(a.updated) || a.repo.localeCompare(b.repo));
30498
+ }
30499
+ function canPickScope(candidates) {
30500
+ return process.stdin.isTTY === true && candidates.length > 1;
30501
+ }
30502
+ async function stepPickSyncScope(candidates, current) {
30503
+ const repos = candidates.map((candidate) => candidate.repo);
30504
+ const plural = (n) => n === 1 ? "" : "s";
30505
+ const selected = await multiselect2({
30506
+ message: "Ship sessions to Dosu memory from which repos?",
30507
+ options: candidates.map(({ repo, sessions }) => ({
30508
+ value: repo,
30509
+ label: displayRepo(repo),
30510
+ hint: sessions > 0 ? `${sessions} session${plural(sessions)}` : "no recent sessions"
30511
+ })),
30512
+ initialValues: current ?? repos,
30513
+ summary: (picked) => picked.length === repos.length ? "all repos · new ones included automatically" : `${picked.length} of ${repos.length} repos`,
30514
+ validate: (picked) => picked.length === 0 ? "Select at least one repo." : undefined
30515
+ });
30516
+ if (isCancel2(selected))
30517
+ return current;
30518
+ const scope = selected.length === repos.length ? null : selected;
30519
+ saveRepoFilter(scope);
30520
+ log2.success(`Sync scope ${dim(`· ${scope ? scope.map(displayRepo).join(", ") : "all repos"}`)}`);
30521
+ return scope;
30522
+ }
30523
+ var init_scope_step = __esm(() => {
30524
+ init_repo();
30525
+ init_state();
30526
+ init_prompts();
30527
+ init_styles();
30528
+ });
30529
+
30569
30530
  // src/auth/server.ts
30570
30531
  function escapeHtml(value) {
30571
30532
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
@@ -31030,7 +30991,7 @@ async function runSetupFlow(opts = {}) {
31030
30991
  return;
31031
30992
  }
31032
30993
  if (!refreshed.finishedOnboarding) {
31033
- log2.warn("Your account still needs onboarding. Finish it in the browser at the Dosu app, then re-run `dosu setup`.");
30994
+ log2.warn(wrapLog("Your account still needs onboarding. Finish it in the browser at the Dosu app, then re-run `dosu setup`."));
31034
30995
  trackInBackground(trackCliOnboardingEvent(cfg, onboardingRunID, "cli_onboarding_failed", {
31035
30996
  reason: "onboarding_incomplete_after_handshake"
31036
30997
  }));
@@ -31130,17 +31091,32 @@ async function stepOfferInitialSync(cfg) {
31130
31091
  logger.info("setup", "Step: offer initial knowledge sync");
31131
31092
  const s = spinner2();
31132
31093
  s.start("Checking for agent sessions from the last 30 days...");
31133
- const outcome = await runKnowledgeSync();
31134
- const backlog = outcome.status === "backlog" ? unsettledSessions(outcome.sessions, state) : [];
31094
+ const outcome = await runKnowledgeSync({ everyRepo: true });
31095
+ const storedScope = loadSyncState().repo_filter ?? null;
31096
+ const everyBacklog = outcome.status === "backlog" ? unsettledSessions(outcome.sessions, state) : [];
31135
31097
  const lineage = sessionLineage(outcome.sessions);
31136
- const n = withoutSubagents(backlog).filter((session) => !isAgentIncognito(state, session, lineage)).length;
31098
+ const offered = (sessions) => withoutSubagents(sessions).filter((session) => !isAgentIncognito(state, session, lineage));
31099
+ const inScope = (scope) => filterSessionsByRepo(everyBacklog, scope, (session) => session.repo ?? null);
31100
+ const candidates = scopeCandidates(offered(everyBacklog), storedScope);
31101
+ const pickScope = canPickScope(candidates);
31102
+ let backlog = pickScope ? everyBacklog : inScope(storedScope);
31103
+ let n = offered(backlog).length;
31137
31104
  if (n === 0) {
31138
31105
  s.stop("No recent agent sessions. Dosu memory learns from new ones as you work.");
31139
31106
  recordCommandFacets({ backfill_offer: "not-offered" });
31140
31107
  return;
31141
31108
  }
31142
- const them = n === 1 ? "it" : "them";
31143
31109
  s.stop(`Found ${n} agent session${n === 1 ? "" : "s"} from the last 30 days on this machine.`);
31110
+ if (pickScope) {
31111
+ backlog = inScope(await stepPickSyncScope(candidates, storedScope));
31112
+ n = offered(backlog).length;
31113
+ if (n === 0) {
31114
+ log2.info(wrapLog("No sessions from those repos are waiting. Dosu memory learns from new ones."));
31115
+ recordCommandFacets({ backfill_offer: "not-offered" });
31116
+ return;
31117
+ }
31118
+ }
31119
+ const them = n === 1 ? "it" : "them";
31144
31120
  const incognito = installedIncognitoCommands();
31145
31121
  log2.message(wrapLog([
31146
31122
  "Dosu memory learns from finished agent sessions: where things live, commands that work, approaches that failed, so the next agent starts from what the last one learned.",
@@ -31922,6 +31898,7 @@ var init_flow2 = __esm(() => {
31922
31898
  init_agents_md_step();
31923
31899
  init_analytics2();
31924
31900
  init_rules_step();
31901
+ init_scope_step();
31925
31902
  init_styles();
31926
31903
  import_picocolors38 = __toESM(require_picocolors(), 1);
31927
31904
  OAUTH_ANALYTICS_REASONS = new Set([
@@ -31940,7 +31917,7 @@ var init_flow2 = __esm(() => {
31940
31917
  // src/commands/upgrade.ts
31941
31918
  import { spawnSync as spawnSync2 } from "node:child_process";
31942
31919
  import { realpathSync as realpathSync4 } from "node:fs";
31943
- import { homedir as homedir15 } from "node:os";
31920
+ import { homedir as homedir13 } from "node:os";
31944
31921
  import { posix, win32 } from "node:path";
31945
31922
  function installSpec(version = VERSION) {
31946
31923
  return `${PACKAGE_NAME}@${releaseTag(version)}`;
@@ -31997,7 +31974,7 @@ function packageRoots(manager, platform, comSpec, env, cwd) {
31997
31974
  manager === "npm" ? path.join(lines[0], "@dosu", "cli") : path.join(lines[0], "node_modules", "@dosu", "cli")
31998
31975
  ];
31999
31976
  }
32000
- function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir15()) {
31977
+ function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir13()) {
32001
31978
  const path = platform === "win32" ? win32 : posix;
32002
31979
  if (!entrypoint || !path.isAbsolute(entrypoint))
32003
31980
  return null;
@@ -32055,7 +32032,7 @@ function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
32055
32032
  }
32056
32033
  const platform = options.platform ?? process.platform;
32057
32034
  const env = options.env ?? process.env;
32058
- const cwd = options.cwd ?? homedir15();
32035
+ const cwd = options.cwd ?? homedir13();
32059
32036
  let manager = null;
32060
32037
  if (channel === "npm") {
32061
32038
  if (isNpxInvocation(channel, env)) {
@@ -32122,7 +32099,7 @@ function finishWithNewBinary(channel, options) {
32122
32099
  return;
32123
32100
  }
32124
32101
  const result = spawnSync2(invocation.command, invocation.args, {
32125
- cwd: options.cwd ?? homedir15(),
32102
+ cwd: options.cwd ?? homedir13(),
32126
32103
  shell: false,
32127
32104
  stdio: "inherit"
32128
32105
  });
@@ -32240,14 +32217,14 @@ var init_upgrade = __esm(() => {
32240
32217
  });
32241
32218
 
32242
32219
  // src/version/incognito-backfill-check.ts
32243
- import { existsSync as existsSync30, mkdirSync as mkdirSync18, writeFileSync as writeFileSync20 } from "node:fs";
32244
- import { join as join45 } from "node:path";
32220
+ import { existsSync as existsSync29, mkdirSync as mkdirSync18, writeFileSync as writeFileSync20 } from "node:fs";
32221
+ import { join as join38 } from "node:path";
32245
32222
  function markerPath() {
32246
- return join45(getConfigDir(), MARKER_FILENAME);
32223
+ return join38(getConfigDir(), MARKER_FILENAME);
32247
32224
  }
32248
32225
  function writeMarker() {
32249
32226
  const dir = getConfigDir();
32250
- if (!existsSync30(dir))
32227
+ if (!existsSync29(dir))
32251
32228
  mkdirSync18(dir, { recursive: true, mode: 448 });
32252
32229
  writeFileSync20(markerPath(), JSON.stringify({ done: true }), { mode: 384 });
32253
32230
  }
@@ -32260,7 +32237,7 @@ ${import_picocolors40.default.green(`✓ Dosu: added the incognito command to ${
32260
32237
  function checkForIncognitoBackfill(options = {}) {
32261
32238
  const notify = options.notify ?? true;
32262
32239
  try {
32263
- if (existsSync30(markerPath()))
32240
+ if (existsSync29(markerPath()))
32264
32241
  return;
32265
32242
  const added = [];
32266
32243
  let failed = false;
@@ -32297,8 +32274,8 @@ var init_incognito_backfill_check = __esm(() => {
32297
32274
  });
32298
32275
 
32299
32276
  // src/version/update-check.ts
32300
- import { existsSync as existsSync31, mkdirSync as mkdirSync19, readFileSync as readFileSync37, writeFileSync as writeFileSync21 } from "node:fs";
32301
- import { join as join46 } from "node:path";
32277
+ import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync38, writeFileSync as writeFileSync21 } from "node:fs";
32278
+ import { join as join39 } from "node:path";
32302
32279
  function isValidVersion2(value) {
32303
32280
  return typeof value === "string" && SEMVER_PATTERN.test(value);
32304
32281
  }
@@ -32351,14 +32328,14 @@ function isNewerRelease(candidate, current) {
32351
32328
  return false;
32352
32329
  }
32353
32330
  function getCachePath3() {
32354
- return join46(getConfigDir(), CACHE_FILENAME5);
32331
+ return join39(getConfigDir(), CACHE_FILENAME5);
32355
32332
  }
32356
32333
  function readCache() {
32357
32334
  try {
32358
32335
  const path = getCachePath3();
32359
- if (!existsSync31(path))
32336
+ if (!existsSync30(path))
32360
32337
  return null;
32361
- const data = JSON.parse(readFileSync37(path, "utf-8"));
32338
+ const data = JSON.parse(readFileSync38(path, "utf-8"));
32362
32339
  if (typeof data.lastCheck === "number" && isValidVersion2(data.latestVersion)) {
32363
32340
  return data;
32364
32341
  }
@@ -32370,7 +32347,7 @@ function readCache() {
32370
32347
  function writeCache(cache) {
32371
32348
  try {
32372
32349
  const dir = getConfigDir();
32373
- if (!existsSync31(dir)) {
32350
+ if (!existsSync30(dir)) {
32374
32351
  mkdirSync19(dir, { recursive: true, mode: 448 });
32375
32352
  }
32376
32353
  writeFileSync21(getCachePath3(), JSON.stringify(cache), { mode: 384 });
@@ -32406,9 +32383,9 @@ function styleHint(hint) {
32406
32383
  return [before && import_picocolors41.default.dim(before), import_picocolors41.default.cyan(command), after && import_picocolors41.default.dim(after)].filter(Boolean).join("");
32407
32384
  }
32408
32385
  function framedNotice(content, width) {
32409
- const innerWidth = Math.max(...content.map(visibleWidth2)) + BOX_PADDING * 2;
32386
+ const innerWidth = Math.max(...content.map(visibleWidth)) + BOX_PADDING * 2;
32410
32387
  const framed = (line) => {
32411
- const pad = innerWidth - visibleWidth2(line);
32388
+ const pad = innerWidth - visibleWidth(line);
32412
32389
  const left = Math.floor(pad / 2);
32413
32390
  return `${import_picocolors41.default.yellow("│")}${" ".repeat(left)}${line}${" ".repeat(pad - left)}${import_picocolors41.default.yellow("│")}`;
32414
32391
  };
@@ -32826,7 +32803,7 @@ function wrapValue(text, room) {
32826
32803
  const append = (piece, sep) => {
32827
32804
  if (current === "")
32828
32805
  current = piece;
32829
- else if (visibleWidth2(current) + sep.length + visibleWidth2(piece) <= room) {
32806
+ else if (visibleWidth(current) + sep.length + visibleWidth(piece) <= room) {
32830
32807
  current += sep + piece;
32831
32808
  } else {
32832
32809
  lines.push(current);
@@ -32834,7 +32811,7 @@ function wrapValue(text, room) {
32834
32811
  }
32835
32812
  };
32836
32813
  for (const item of text.split(LIST_SEP)) {
32837
- const pieces = visibleWidth2(item) <= room ? [item] : item.split(" ");
32814
+ const pieces = visibleWidth(item) <= room ? [item] : item.split(" ");
32838
32815
  pieces.forEach((piece, i) => {
32839
32816
  append(piece, i === 0 ? LIST_SEP : " ");
32840
32817
  });
@@ -33534,43 +33511,27 @@ async function runSettings(cfg) {
33534
33511
  }
33535
33512
  }
33536
33513
  function discoverSessionRepos(current) {
33537
- const counts = new Map;
33514
+ const inRepos = [];
33538
33515
  try {
33539
33516
  const resolver = createProjectDirResolver();
33540
33517
  for (const session of scanAgentSessions({})) {
33541
33518
  const repo = resolver.resolveRepo(session);
33542
33519
  if (repo)
33543
- counts.set(repo, (counts.get(repo) ?? 0) + 1);
33520
+ inRepos.push({ ...session, repo });
33544
33521
  }
33545
33522
  resolver.flush();
33546
33523
  } catch {}
33547
- for (const repo of current ?? [])
33548
- if (!counts.has(repo))
33549
- counts.set(repo, 0);
33550
- return [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([repo]) => repo);
33524
+ return scopeCandidates(inRepos, current);
33551
33525
  }
33552
33526
  async function runStudyingProjectsSetting() {
33553
33527
  const state = loadSyncState();
33554
33528
  const current = studyRepoFilter(state, () => scanAgentSessions({}), createProjectDirResolver());
33555
- const repos = discoverSessionRepos(current);
33556
- if (repos.length === 0) {
33529
+ const candidates = discoverSessionRepos(current);
33530
+ if (candidates.length === 0) {
33557
33531
  log2.info("No agent sessions inside a git repo found yet; nothing to scope.");
33558
33532
  return;
33559
33533
  }
33560
- const selected = await multiselect2({
33561
- message: "Ship sessions to Dosu memory from which repos?",
33562
- options: repos.map((repo) => ({ label: displayRepo(repo), hint: repo, value: repo })),
33563
- initialValues: current ?? repos,
33564
- summary: (picked) => picked.length === repos.length ? "all repos · new ones included automatically" : `${picked.length} of ${repos.length} repos`,
33565
- validate: (picked) => picked.length === 0 ? "Select at least one repo." : undefined
33566
- });
33567
- if (isCancel2(selected))
33568
- return;
33569
- const { repo_filter: _repos, project_filter: _folders, ...fresh } = loadSyncState();
33570
- const all = selected.length === repos.length;
33571
- saveSyncState(all ? fresh : { ...fresh, repo_filter: [...selected] });
33572
- const scope = all ? "all repos" : selected.map(displayRepo).join(", ");
33573
- log2.success(`Sync scope ${dim(`· ${scope}`)}`);
33534
+ await stepPickSyncScope(candidates, current);
33574
33535
  }
33575
33536
  async function handleAuthenticate(cfg) {
33576
33537
  const shouldLogin = await confirm2({ message: "Open browser to log in?" });
@@ -33626,6 +33587,7 @@ var init_tui = __esm(() => {
33626
33587
  init_scan();
33627
33588
  init_agents_md_step();
33628
33589
  init_flow2();
33590
+ init_scope_step();
33629
33591
  init_styles();
33630
33592
  init_state();
33631
33593
  init_status();
@@ -34244,7 +34206,7 @@ var init_flow3 = __esm(() => {
34244
34206
  });
34245
34207
 
34246
34208
  // src/cli/cli.ts
34247
- import { readFileSync as readFileSync38, unlinkSync as unlinkSync8 } from "node:fs";
34209
+ import { readFileSync as readFileSync39, unlinkSync as unlinkSync8 } from "node:fs";
34248
34210
  function shouldRunBackgroundChecks(command) {
34249
34211
  return !NO_BACKGROUND_CHECKS.has(command);
34250
34212
  }
@@ -34698,7 +34660,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
34698
34660
  }
34699
34661
  if (opts.follow) {
34700
34662
  try {
34701
- const lines = readFileSync38(logPath, "utf-8").split(`
34663
+ const lines = readFileSync39(logPath, "utf-8").split(`
34702
34664
  `);
34703
34665
  if (lines.at(-1) === "")
34704
34666
  lines.pop();
@@ -34714,7 +34676,7 @@ Use 'dosu mcp add <agent>' to add Dosu MCP to a tool.`);
34714
34676
  if (opts.tail !== undefined) {
34715
34677
  const n = typeof opts.tail === "string" ? parseInt(opts.tail, 10) || 50 : 50;
34716
34678
  try {
34717
- const content = readFileSync38(logPath, "utf-8");
34679
+ const content = readFileSync39(logPath, "utf-8");
34718
34680
  const lines = content.split(`
34719
34681
  `);
34720
34682
  console.log(lines.slice(-n).join(`
@@ -34900,4 +34862,4 @@ main().catch((err) => {
34900
34862
  process.exit(1);
34901
34863
  });
34902
34864
 
34903
- //# debugId=32ee4cf3-5398-61c9-6475-6e2164756e21
34865
+ //# debugId=38c8fa6e-6a2c-1ace-6475-6e2164756e21