@dosu/cli 0.53.0-beta.11 → 0.53.0-beta.13

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 (2) hide show
  1. package/bin/dosu.js +128 -77
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -5018,7 +5018,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
5018
5018
  function getVersionString() {
5019
5019
  return `v${VERSION}`;
5020
5020
  }
5021
- var VERSION = "0.53.0-beta.11", INSTALL_CHANNEL = "npm";
5021
+ var VERSION = "0.53.0-beta.13", INSTALL_CHANNEL = "npm";
5022
5022
 
5023
5023
  // src/debug/logger.ts
5024
5024
  import {
@@ -5712,12 +5712,34 @@ function answeredEcho(message, answer) {
5712
5712
  function optionLabel(option) {
5713
5713
  return option.label ?? String(option.value);
5714
5714
  }
5715
+ function viewport(count, cursor3, top, rows, chrome) {
5716
+ const visible = Math.min(count, Math.max(4, (rows ?? 24) - chrome));
5717
+ let next = top;
5718
+ if (cursor3 < next)
5719
+ next = cursor3;
5720
+ if (cursor3 >= next + visible)
5721
+ next = cursor3 - visible + 1;
5722
+ next = Math.max(0, Math.min(next, count - visible));
5723
+ return { top: next, visible, above: next, below: count - next - visible };
5724
+ }
5725
+ function moreAbove(n2) {
5726
+ return n2 > 0 ? [import_picocolors11.default.dim(` ↑ ${n2} more`)] : [];
5727
+ }
5728
+ function moreBelow(n2) {
5729
+ return n2 > 0 ? [import_picocolors11.default.dim(` ↓ ${n2} more`)] : [];
5730
+ }
5715
5731
  function select(opts, io = {}) {
5732
+ const { output } = resolveIO(io);
5716
5733
  let selected = 0;
5734
+ let top = 0;
5717
5735
  const labelWidth = Math.max(...opts.options.map((o2) => optionLabel(o2).length));
5718
5736
  return runInteractive({
5719
5737
  render() {
5720
- const rows = opts.options.map((option, index) => {
5738
+ const count = opts.options.length;
5739
+ const view = viewport(count, selected, top, output.rows, 8);
5740
+ top = view.top;
5741
+ const rows = opts.options.slice(top, top + view.visible).map((option, offset) => {
5742
+ const index = top + offset;
5721
5743
  const label = optionLabel(option).padEnd(labelWidth);
5722
5744
  const hint = option.hint ? ` ${import_picocolors11.default.dim(option.hint)}` : "";
5723
5745
  return index === selected ? `${brand(POINTER2)} ${import_picocolors11.default.bold(brand(label))}${hint}` : ` ${import_picocolors11.default.dim(label)}${hint}`;
@@ -5725,7 +5747,9 @@ function select(opts, io = {}) {
5725
5747
  return [
5726
5748
  import_picocolors11.default.bold(opts.message),
5727
5749
  "",
5750
+ ...moreAbove(view.above),
5728
5751
  ...rows,
5752
+ ...moreBelow(view.below),
5729
5753
  "",
5730
5754
  import_picocolors11.default.dim(`↑↓ move ${DOT} enter select ${DOT} esc cancel`)
5731
5755
  ];
@@ -5763,13 +5787,9 @@ function multiselect2(opts, io = {}) {
5763
5787
  return runInteractive({
5764
5788
  render() {
5765
5789
  const count = opts.options.length;
5766
- const visible = Math.min(count, Math.max(4, (output.rows ?? 24) - 9));
5767
- if (cursor3 < top)
5768
- top = cursor3;
5769
- if (cursor3 >= top + visible)
5770
- top = cursor3 - visible + 1;
5771
- top = Math.max(0, Math.min(top, count - visible));
5772
- const rows = opts.options.slice(top, top + visible).map((option, offset) => {
5790
+ const view = viewport(count, cursor3, top, output.rows, 9);
5791
+ top = view.top;
5792
+ const rows = opts.options.slice(top, top + view.visible).map((option, offset) => {
5773
5793
  const index = top + offset;
5774
5794
  const isPicked = picked.has(option.value);
5775
5795
  const box = isPicked ? brand(BOX_ON) : import_picocolors11.default.dim(BOX_OFF);
@@ -5778,15 +5798,13 @@ function multiselect2(opts, io = {}) {
5778
5798
  const suffix = status ? ` ${status}` : "";
5779
5799
  return index === cursor3 ? `${brand(POINTER2)} ${box} ${import_picocolors11.default.bold(brand(label))}${suffix}` : ` ${box} ${import_picocolors11.default.dim(label)}${suffix}`;
5780
5800
  });
5781
- const above = top;
5782
- const below = count - top - visible;
5783
5801
  const summary = opts.summary?.(pickedValues());
5784
5802
  return [
5785
5803
  import_picocolors11.default.bold(opts.message),
5786
5804
  "",
5787
- ...above > 0 ? [import_picocolors11.default.dim(` ↑ ${above} more`)] : [],
5805
+ ...moreAbove(view.above),
5788
5806
  ...rows,
5789
- ...below > 0 ? [import_picocolors11.default.dim(` ↓ ${below} more`)] : [],
5807
+ ...moreBelow(view.below),
5790
5808
  "",
5791
5809
  ...error ? [import_picocolors11.default.yellow(error)] : summary ? [import_picocolors11.default.dim(summary)] : [],
5792
5810
  import_picocolors11.default.dim(`↑↓ move ${DOT} space toggle ${DOT} a all ${DOT} enter confirm ${DOT} esc cancel`)
@@ -8577,6 +8595,17 @@ function setSyncPaused(paused, configDir = getConfigDir()) {
8577
8595
  delete state.paused;
8578
8596
  saveSyncState(state, configDir);
8579
8597
  }
8598
+ function resetSyncState(configDir = getConfigDir()) {
8599
+ const previous = loadSyncState(configDir);
8600
+ const fresh = {
8601
+ schema_version: STATE_SCHEMA_VERSION,
8602
+ watermark: null,
8603
+ consecutive_failures: 0,
8604
+ ...previous.project_filter ? { project_filter: previous.project_filter } : {},
8605
+ ...previous.paused ? { paused: true } : {}
8606
+ };
8607
+ saveSyncState(fresh, configDir);
8608
+ }
8580
8609
  function saveSyncState(state, configDir = getConfigDir()) {
8581
8610
  if (!existsSync10(configDir))
8582
8611
  mkdirSync6(configDir, { recursive: true, mode: 448 });
@@ -9238,7 +9267,7 @@ function buildReportHtml(options) {
9238
9267
  const org = options.orgName || "Your team";
9239
9268
  const repo = options.repo || inventory.cwd || "—";
9240
9269
  const branch = options.branch || "—";
9241
- const summary = options.summary || "Local agent session logs were mined into Dosu notes so the next task can reuse them — reducing rediscovery cost.";
9270
+ const summary = options.summary || "Local agent session logs were studied and distilled into Dosu notes so the next task can reuse them — reducing rediscovery cost.";
9242
9271
  const generated = `${(options.generatedAt ?? new Date).toISOString().replace("T", " ").slice(0, 16)} UTC`;
9243
9272
  const derived = tokenTotalsFromCandidates(candidates, inventory);
9244
9273
  const [notesHeading, notesLede, footerTitle, footerBody] = notesSectionCopy(candidates);
@@ -9300,7 +9329,7 @@ function buildReportHtml(options) {
9300
9329
  <p class="muted">No rediscovery estimates on the notes yet — each candidate needs <code>approx_rediscovery_tokens</code>.</p>
9301
9330
  </section>`;
9302
9331
  }
9303
- const notesBody = candidateRows.join("") || '<p class="muted">No write_knowledge payloads yet. Run knowledge sync so the miner extracts learnings.</p>';
9332
+ const notesBody = candidateRows.join("") || '<p class="muted">No write_knowledge payloads yet. Run knowledge sync so Dosu studies your sessions and extracts learnings.</p>';
9304
9333
  const lede = notesLede ? `<p class="lede">${esc(notesLede)}</p>` : "";
9305
9334
  return `<!DOCTYPE html>
9306
9335
  <html lang="en">
@@ -10490,7 +10519,7 @@ async function runKnowledgeSync(options = {}) {
10490
10519
  const state = loadState();
10491
10520
  if (options.quiet) {
10492
10521
  if (state.paused) {
10493
- logger.debug("sync", "skipping quiet sync: mining is paused");
10522
+ logger.debug("sync", "skipping quiet sync: studying is paused");
10494
10523
  return { status: "skipped-paused", readySessions: 0, inFlightSessions: 0, sessions: [] };
10495
10524
  }
10496
10525
  const retryAt = backoffUntil(state);
@@ -10500,7 +10529,7 @@ async function runKnowledgeSync(options = {}) {
10500
10529
  }
10501
10530
  } else if (state.paused) {
10502
10531
  delete state.paused;
10503
- logger.debug("sync", "manual sync resumes paused mining");
10532
+ logger.debug("sync", "manual sync resumes paused studying");
10504
10533
  }
10505
10534
  let ready;
10506
10535
  let open2;
@@ -10590,12 +10619,12 @@ async function runKnowledgeSync(options = {}) {
10590
10619
  trivialSessions: trivial
10591
10620
  };
10592
10621
  }
10593
- logger.debug("sync", `mining ${batch.length} of ${ready.length} ready sessions (${trivial} trivial skipped)`);
10622
+ logger.debug("sync", `studying ${batch.length} of ${ready.length} ready sessions (${trivial} trivial skipped)`);
10594
10623
  const miner = await deps.mine(batch);
10595
10624
  switch (miner.outcome) {
10596
10625
  case "completed": {
10597
10626
  for (const s of batch) {
10598
- logger.debug("sync", `mined session ${s.harness}/${s.id}`);
10627
+ logger.debug("sync", `studied session ${s.harness}/${s.id}`);
10599
10628
  }
10600
10629
  const minedAt = now().toISOString();
10601
10630
  const history = [
@@ -10622,7 +10651,7 @@ async function runKnowledgeSync(options = {}) {
10622
10651
  total_learning_tokens: (state.total_learning_tokens ?? 0) + batchTokens,
10623
10652
  last_refusal: undefined
10624
10653
  });
10625
- logger.debug("sync", `mined ${batch.length} sessions, ${miner.notesWritten} suggested pages; watermark → ${watermark}`);
10654
+ logger.debug("sync", `studied ${batch.length} sessions, ${miner.notesWritten} suggested pages; watermark → ${watermark}`);
10626
10655
  return {
10627
10656
  status: "mined",
10628
10657
  ...base,
@@ -10642,10 +10671,10 @@ async function runKnowledgeSync(options = {}) {
10642
10671
  last_refusal: {
10643
10672
  at,
10644
10673
  outcome: miner.outcome,
10645
- message: miner.message ?? "Mining unavailable right now."
10674
+ message: miner.message ?? "Studying unavailable right now."
10646
10675
  }
10647
10676
  });
10648
- logger.debug("sync", `mining skipped by gateway: ${miner.outcome}`);
10677
+ logger.debug("sync", `studying skipped by gateway: ${miner.outcome}`);
10649
10678
  return { status: "skipped-gateway", ...base, minedSessions: 0, miner };
10650
10679
  }
10651
10680
  default: {
@@ -10654,7 +10683,7 @@ async function runKnowledgeSync(options = {}) {
10654
10683
  last_attempt_at: now().toISOString(),
10655
10684
  consecutive_failures: state.consecutive_failures + 1
10656
10685
  });
10657
- logger.debug("sync", `mining failed: ${miner.outcome}; ${miner.message ?? ""}`);
10686
+ logger.debug("sync", `studying failed: ${miner.outcome}; ${miner.message ?? ""}`);
10658
10687
  return {
10659
10688
  status: "mine-failed",
10660
10689
  ...base,
@@ -72901,7 +72930,7 @@ async function runMiner(options) {
72901
72930
  outcome: "settings_conflict",
72902
72931
  notesWritten: 0,
72903
72932
  turns: 0,
72904
- message: `Refusing to run: conflicting Claude Code settings would override the miner's auth (${detail})`
72933
+ message: `Refusing to run: conflicting Claude Code settings would override the study run's auth (${detail})`
72905
72934
  };
72906
72935
  }
72907
72936
  const gatewayURL = options.gatewayURL ?? getLlmGatewayURL();
@@ -72968,7 +72997,7 @@ async function runMiner(options) {
72968
72997
  if (!allowed.has(toolName)) {
72969
72998
  return {
72970
72999
  behavior: "deny",
72971
- message: `Tool ${toolName} is not permitted in mining runs.`
73000
+ message: `Tool ${toolName} is not permitted in study runs.`
72972
73001
  };
72973
73002
  }
72974
73003
  if (toolName === `mcp__${SESSIONS_SERVER_NAME}__read_session`) {
@@ -73025,7 +73054,7 @@ async function runMiner(options) {
73025
73054
  outcome: "error",
73026
73055
  notesWritten,
73027
73056
  turns,
73028
- message: "Mining run failed; see debug log for details."
73057
+ message: "Study run failed; see debug log for details."
73029
73058
  };
73030
73059
  }
73031
73060
  logger.debug("miner", `run ${runID} completed: ${turns} turns, ${notesWritten} suggested pages`);
@@ -73036,7 +73065,7 @@ async function runMiner(options) {
73036
73065
  outcome: "error",
73037
73066
  notesWritten,
73038
73067
  turns,
73039
- message: "Mining run ended without a result."
73068
+ message: "Study run ended without a result."
73040
73069
  };
73041
73070
  } catch (error61) {
73042
73071
  const text = error61 instanceof Error ? error61.message : String(error61);
@@ -73049,7 +73078,7 @@ async function runMiner(options) {
73049
73078
  outcome: "error",
73050
73079
  notesWritten,
73051
73080
  turns,
73052
- message: abort.signal.aborted ? "Mining run timed out and was aborted." : "Mining run failed; see debug log for details."
73081
+ message: abort.signal.aborted ? "Study run timed out and was aborted." : "Study run failed; see debug log for details."
73053
73082
  };
73054
73083
  } finally {
73055
73084
  clearTimeout(timer);
@@ -73519,7 +73548,7 @@ var init_settings = __esm(() => {
73519
73548
  });
73520
73549
 
73521
73550
  // src/telemetry/debug-id.ts
73522
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "fa7cf492-7aa5-180c-6475-6e2164756e21";
73551
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "6b750395-441b-6515-6475-6e2164756e21";
73523
73552
 
73524
73553
  // src/telemetry/telemetry.ts
73525
73554
  import { randomUUID as randomUUID4 } from "node:crypto";
@@ -75434,6 +75463,8 @@ function reduceActivityViewKey(key) {
75434
75463
  return "sync";
75435
75464
  if (key === "f")
75436
75465
  return "full";
75466
+ if (key === "c")
75467
+ return "clear";
75437
75468
  return "none";
75438
75469
  }
75439
75470
  function cycleTab(tab, delta = 1) {
@@ -75524,12 +75555,12 @@ function foldRunProgress(progress, chunk) {
75524
75555
  let current = progress;
75525
75556
  for (const line of chunk.split(`
75526
75557
  `)) {
75527
- const start = line.match(/\[sync\] mining (\d+) of \d+ ready sessions/);
75558
+ const start = line.match(/\[sync\] (?:studying|mining) (\d+) of \d+ ready sessions/);
75528
75559
  if (start) {
75529
75560
  current = { batch: Number.parseInt(start[1], 10), read: new Set, notes: 0 };
75530
75561
  continue;
75531
75562
  }
75532
- if (/\[sync\] (mined \d+ sessions|mining failed|mining skipped)/.test(line)) {
75563
+ if (/\[sync\] (?:studied|mined) \d+ sessions|\[sync\] (?:studying|mining) (?:failed|skipped)/.test(line)) {
75533
75564
  current = null;
75534
75565
  continue;
75535
75566
  }
@@ -75554,15 +75585,15 @@ function statusLine(status) {
75554
75585
  if (status.running) {
75555
75586
  const since = status.startedAt ? ` · since ${localTime(status.startedAt)}` : "";
75556
75587
  const pid = status.pid !== undefined ? ` (pid ${status.pid})` : "";
75557
- return `⛏️ ${import_picocolors30.default.bold(brand("Mining sessions..."))}${import_picocolors30.default.dim(`${pid}${since}`)}`;
75588
+ return `\uD83D\uDCDA ${import_picocolors30.default.bold(brand("Studying sessions..."))}${import_picocolors30.default.dim(`${pid}${since}`)}`;
75558
75589
  }
75559
75590
  if (status.state.paused) {
75560
- return `${import_picocolors30.default.yellow("○")} ${import_picocolors30.default.bold("Paused")} ${import_picocolors30.default.dim("· mining stays off until you resume")}`;
75591
+ return `${import_picocolors30.default.yellow("○")} ${import_picocolors30.default.bold("Paused")} ${import_picocolors30.default.dim("· studying stays off until you resume")}`;
75561
75592
  }
75562
75593
  if (status.staleLock) {
75563
75594
  return `${import_picocolors30.default.yellow("○")} ${import_picocolors30.default.bold("Not running")} ${import_picocolors30.default.dim("· a previous run exited without cleaning up")}`;
75564
75595
  }
75565
- return `${import_picocolors30.default.dim("○")} ${import_picocolors30.default.bold("Idle")} ${import_picocolors30.default.dim("· hooks mine new sessions automatically")}`;
75596
+ return `${import_picocolors30.default.dim("○")} ${import_picocolors30.default.bold("Idle")} ${import_picocolors30.default.dim("· hooks study new sessions automatically")}`;
75566
75597
  }
75567
75598
  function progressLine(done, ready, width, notes = 0) {
75568
75599
  const total = done + ready;
@@ -75574,12 +75605,12 @@ function progressLine(done, ready, width, notes = 0) {
75574
75605
  const bar = brand("█".repeat(filled)) + import_picocolors30.default.dim("░".repeat(cells - filled));
75575
75606
  const pct = Math.floor(ratio * 100);
75576
75607
  const suffix = notes > 0 ? ` · ${notes} suggested page${notes === 1 ? "" : "s"}` : "";
75577
- return `${bar} ${done}/${total} mined · ${pct}%${suffix}`;
75608
+ return `${bar} ${done}/${total} studied · ${pct}%${suffix}`;
75578
75609
  }
75579
75610
  function tabBar(tab, queuedCount, openCount, minedCount, width) {
75580
75611
  return tabStrip([
75581
75612
  ["activity", "Activity"],
75582
- ["mined", `Mined (${minedCount})`],
75613
+ ["mined", `Studied (${minedCount})`],
75583
75614
  ["queued", `Queued (${queuedCount})`],
75584
75615
  ["open", `Open (${openCount})`]
75585
75616
  ], tab, width);
@@ -75603,10 +75634,11 @@ function wrapLine(text, width, indent = " ") {
75603
75634
  return out;
75604
75635
  }
75605
75636
  function confirmBox(queuedCount, backlog, width, mode = "start") {
75606
- const inFlight = backlog && backlog.inFlight > 0 ? ` (+${backlog.inFlight} open, mined once ${backlog.inFlight === 1 ? "it goes" : "they go"} quiet)` : "";
75607
- const scope = mode === "stop" ? "the run is killed mid-batch · mining stays paused until you resume" : queuedCount > 0 ? `${queuedCount} session${queuedCount === 1 ? "" : "s"} queued${inFlight} · runs in the background` : `queue empty${inFlight} · a run would only pick up sessions that finish from here`;
75608
- const title = mode === "stop" ? "Stop mining?" : mode === "resume" ? "Resume mining?" : "Start mining now?";
75609
- const verb = mode === "stop" ? "stop" : mode === "resume" ? "resume" : "start";
75637
+ const inFlight = backlog && backlog.inFlight > 0 ? ` (+${backlog.inFlight} still open; ${backlog.inFlight === 1 ? "it joins" : "they join"} once quiet)` : "";
75638
+ const sessions = `${queuedCount} session${queuedCount === 1 ? "" : "s"}`;
75639
+ const scope = mode === "clear" ? "Forgets which local sessions Dosu has already studied, so the next run reads them all again. Use this to rebuild knowledge from scratch. Notes already saved in Dosu are kept." : mode === "stop" ? "Kills the run mid-batch and pauses studying, so new sessions pile up in the queue instead of being read. Nothing is lost; press s again to resume from where it left off." : mode === "resume" ? `Studying picks up where it stopped: ${sessions} queued${inFlight}. Runs in the background; new notes appear in Dosu as each batch finishes.` : queuedCount > 0 ? `Dosu reads ${sessions}${inFlight} and distills the durable decisions and gotchas into team knowledge. Runs in the background; new notes appear in Dosu as each batch finishes.` : `Queue is empty${inFlight}. A run now would only pick up sessions that finish from here; hooks already do that automatically.`;
75640
+ const title = mode === "clear" ? "Clear study history?" : mode === "stop" ? "Stop studying?" : mode === "resume" ? "Resume studying?" : "Start studying now?";
75641
+ const verb = mode === "clear" ? "clear" : mode === "stop" ? "stop" : mode === "resume" ? "resume" : "start";
75610
75642
  const maxInner = Math.max(20, Math.min(width, contentWidth()) - 4);
75611
75643
  const rows = [
75612
75644
  import_picocolors30.default.bold(brand(title)),
@@ -75623,7 +75655,7 @@ function confirmBox(queuedCount, backlog, width, mode = "start") {
75623
75655
  ];
75624
75656
  }
75625
75657
  function renderActivityFrame(status, activity, width, backlog = null, pane = DEFAULT_PANE, queued = [], minedBeforeRun = 0, open5 = [], runProgress = null) {
75626
- const mined = status.state.watermark ? `Mined sessions up to ${localTime(status.state.watermark)}` : "Nothing mined yet";
75658
+ const mined = status.state.watermark ? `Studied sessions up to ${localTime(status.state.watermark)}` : "Nothing studied yet";
75627
75659
  const queueDetail = [];
75628
75660
  if (status.backoffUntil) {
75629
75661
  queueDetail.push(`retrying after ${localTime(status.backoffUntil)} · s syncs now`);
@@ -75635,14 +75667,14 @@ function renderActivityFrame(status, activity, width, backlog = null, pane = DEF
75635
75667
  progress = progressLine(minedDelta + stepDone, Math.max(0, backlog.ready - stepDone), width, runProgress?.notes ?? 0);
75636
75668
  }
75637
75669
  const refusal = !status.running && status.state.last_refusal;
75638
- const refusalLines = refusal ? wrapLine(`! Mining paused: ${refusal.message} (${localTime(refusal.at)})`, width).map((line) => import_picocolors30.default.yellow(line)) : [];
75670
+ const refusalLines = refusal ? wrapLine(`! Studying paused: ${refusal.message} (${localTime(refusal.at)})`, width).map((line) => import_picocolors30.default.yellow(line)) : [];
75639
75671
  const fullRows = Boolean(pane.fullRows);
75640
75672
  const minedRows = (status.state.mined_sessions ?? []).map((record2) => fullRows ? formatMinedRow(record2, true) : formatActivityLine(formatMinedRow(record2), width));
75641
75673
  const sessionRow = (session) => fullRows ? formatQueuedRow(session, true) : formatActivityLine(formatQueuedRow(session), width);
75642
75674
  const queuedRows = queued.map(sessionRow);
75643
75675
  const openRows = open5.map(sessionRow);
75644
75676
  const source = pane.tab === "activity" ? activity.map((line) => formatActivityLine(line, width, fullRows)) : pane.tab === "queued" ? queuedRows : pane.tab === "open" ? openRows : minedRows;
75645
- const emptyMined = status.state.watermark ? "No sessions recorded yet. History starts with the next mining run." : "No mined sessions yet.";
75677
+ const emptyMined = status.state.watermark ? "No sessions recorded yet. History starts with the next study run." : "No studied sessions yet.";
75646
75678
  const empty = pane.tab === "activity" ? "No sync activity in the log yet." : pane.tab === "queued" ? "Queue empty. Finished agent sessions appear here." : pane.tab === "open" ? "No open sessions. Live agent sessions sit here until they go quiet." : emptyMined;
75647
75679
  const height = fullRows ? ACTIVITY_VIEW_FULL_LIST_ROWS : ACTIVITY_VIEW_LIST_LINES;
75648
75680
  const { visible, above, below } = windowList(source, pane.scroll, height);
@@ -75667,13 +75699,14 @@ function renderActivityFrame(status, activity, width, backlog = null, pane = DEF
75667
75699
  ...scrollParts.length > 0 ? [import_picocolors30.default.dim(clip(scrollParts.join(" · "), width))] : [],
75668
75700
  "",
75669
75701
  ...pane.confirm ? centerBlock(confirmBox(queued.length, backlog, width, pane.confirm), width) : [
75670
- import_picocolors30.default.dim([
75702
+ ...wrapLine([
75671
75703
  "tab switch",
75672
75704
  "↑↓ scroll",
75673
75705
  fullRows ? "f clip" : "f full rows",
75674
75706
  status.running ? "s stop" : status.state.paused ? "s resume" : "s sync now",
75707
+ ...!status.running && status.state.watermark ? ["c clear"] : [],
75675
75708
  "esc back"
75676
- ].join(" · "))
75709
+ ].join(" · "), width, "").map((line) => import_picocolors30.default.dim(line))
75677
75710
  ]
75678
75711
  ];
75679
75712
  return lines.join(`
@@ -75697,6 +75730,7 @@ function runActivityView(io2 = {}) {
75697
75730
  const startSync = io2.startSync ?? (() => spawnDetachedSelf(["knowledge", "sync", "--bootstrap"]));
75698
75731
  const stopSync = io2.stopSync ?? stopSyncRun;
75699
75732
  const setPaused = io2.setPaused ?? setSyncPaused;
75733
+ const clearHistory = io2.clearHistory ?? resetSyncState;
75700
75734
  const listBacklog = io2.listBacklog ?? listSessionBacklog;
75701
75735
  const pollMs = io2.pollMs ?? ACTIVITY_VIEW_POLL_MS;
75702
75736
  const seed = readLog();
@@ -75743,7 +75777,7 @@ function runActivityView(io2 = {}) {
75743
75777
  queuedWatermark = status.state.watermark;
75744
75778
  sessions = listBacklog();
75745
75779
  }
75746
- if ((confirmSync === "start" || confirmSync === "resume") && status.running)
75780
+ if (confirmSync !== null && confirmSync !== "stop" && status.running)
75747
75781
  confirmSync = null;
75748
75782
  if (confirmSync === "stop" && !status.running)
75749
75783
  confirmSync = null;
@@ -75795,11 +75829,15 @@ ${CLEAR_BELOW}`);
75795
75829
  const mode = confirmSync;
75796
75830
  confirmSync = null;
75797
75831
  let note;
75798
- if (mode === "stop") {
75832
+ if (mode === "clear") {
75833
+ clearHistory();
75834
+ minedBeforeRun = null;
75835
+ note = "[sync] study history cleared · the next run reads every local session again";
75836
+ } else if (mode === "stop") {
75799
75837
  const ok2 = status.pid !== undefined && stopSync(status.pid);
75800
75838
  if (ok2)
75801
75839
  setPaused(true);
75802
- note = ok2 ? "[sync] mining stopped · paused until you resume" : "[sync] could not stop the run · it may have just finished";
75840
+ note = ok2 ? "[sync] studying stopped · paused until you resume" : "[sync] could not stop the run · it may have just finished";
75803
75841
  } else {
75804
75842
  if (mode === "resume")
75805
75843
  setPaused(false);
@@ -75823,6 +75861,11 @@ ${CLEAR_BELOW}`);
75823
75861
  if (action === "sync") {
75824
75862
  confirmSync = syncConfirmMode(status);
75825
75863
  draw();
75864
+ } else if (action === "clear") {
75865
+ if (!status.running && status.state.watermark) {
75866
+ confirmSync = "clear";
75867
+ draw();
75868
+ }
75826
75869
  } else if (action === "tab" || action === "tab-back") {
75827
75870
  tab = cycleTab(tab, action === "tab" ? 1 : -1);
75828
75871
  scroll = 0;
@@ -76708,23 +76751,31 @@ async function stepOfferInitialSync(cfg) {
76708
76751
  s.start("Checking for recent agent sessions...");
76709
76752
  const outcome = await runKnowledgeSync({ bootstrap: true });
76710
76753
  if (outcome.status !== "backlog" || outcome.readySessions === 0) {
76711
- s.stop("No unmined agent sessions found. Dosu will learn as you work.");
76754
+ s.stop("No past agent sessions to study. Dosu will learn from new ones as you work.");
76712
76755
  return;
76713
76756
  }
76714
76757
  const n5 = outcome.readySessions;
76715
- s.stop(`Found ${n5} unmined agent session${n5 === 1 ? "" : "s"} on this machine.`);
76758
+ const them = n5 === 1 ? "it" : "them";
76759
+ s.stop(`Found ${n5} past agent session${n5 === 1 ? "" : "s"} on this machine that Dosu hasn't studied.`);
76760
+ log2.message([
76761
+ `Dosu can read ${them} and pull out the durable knowledge: decisions, gotchas, and`,
76762
+ "how-things-work that your team and agents would otherwise rediscover.",
76763
+ "Only distilled notes are saved to Dosu; your session logs stay on this machine.",
76764
+ "It runs in the background a few sessions at a time; notes appear in Dosu as each batch finishes."
76765
+ ].join(`
76766
+ `));
76716
76767
  const mineNow = await confirm2({
76717
- message: `Mine ${n5 === 1 ? "it" : "them"} for team knowledge now? (runs in the background)`,
76718
- active: "Mine now ⛏️",
76719
- inactive: "Skip",
76768
+ message: `Study ${them} now?`,
76769
+ active: "Study now \uD83D\uDCDA",
76770
+ inactive: "Skip for now",
76720
76771
  initialValue: true
76721
76772
  });
76722
76773
  if (isCancel2(mineNow) || !mineNow) {
76723
- log2.info(`Skipped. Dosu picks sessions up in the background as you work, or run ${info("dosu knowledge sync")} anytime.`);
76774
+ log2.info(`Skipped. Dosu studies new sessions in the background as you work; run ${info("dosu knowledge sync")} anytime to study these too.`);
76724
76775
  return;
76725
76776
  }
76726
76777
  if (spawnDetachedSelf(["knowledge", "sync", "--quiet", "--bootstrap"])) {
76727
- log2.success("⛏️ Currently mining... Dosu is distilling your past sessions into team knowledge, a few at a time in the background.");
76778
+ log2.success(`\uD83D\uDCDA Studying ${n5} session${n5 === 1 ? "" : "s"} in the background. Watch progress on the Activity screen; when it finishes, the new notes are in Dosu and agents connected to this MCP can use them.`);
76728
76779
  const watch = await confirm2({
76729
76780
  message: "What next?",
76730
76781
  active: "Watch it work",
@@ -77554,7 +77605,7 @@ function overviewRows(state) {
77554
77605
  const tokens = state.total_learning_tokens ?? 0;
77555
77606
  if (minedTotal === 0 && notes === 0)
77556
77607
  return [];
77557
- const rows = [`${label("Sessions mined")}${minedTotal}`, `${label("Suggested pages")}${notes}`];
77608
+ const rows = [`${label("Sessions studied")}${minedTotal}`, `${label("Suggested pages")}${notes}`];
77558
77609
  if (tokens > 0) {
77559
77610
  rows.push(`${label("Investigation distilled")}${formatTokenCount(tokens)} tokens`);
77560
77611
  }
@@ -77603,7 +77654,7 @@ function analyticsTabRows(tab, state, pageStats) {
77603
77654
  function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending = false, width = contentWidth()) {
77604
77655
  const rows = analyticsTabRows(tab, state, pageStats);
77605
77656
  const { visible, above, below } = windowReport(rows, scroll);
77606
- const empty = tab === "overview" ? "No analytics yet. They appear after the first mining run." : tab === "projects" ? "No per-project history yet. It fills in as sessions are mined." : pagesPending ? "Loading page analytics..." : "No page analytics yet.";
77657
+ const empty = tab === "overview" ? "No analytics yet. They appear after the first study run." : tab === "projects" ? "No per-project history yet. It fills in as sessions are studied." : pagesPending ? "Loading page analytics..." : "No page analytics yet.";
77607
77658
  const listRows = visible.length > 0 ? visible.map((row) => import_picocolors32.default.dim(row)) : [import_picocolors32.default.dim(empty)];
77608
77659
  const scrollParts = [];
77609
77660
  if (above > 0)
@@ -77782,7 +77833,7 @@ function checklistRows(ctx) {
77782
77833
  if (ctx.mining) {
77783
77834
  rows.push([
77784
77835
  "sync",
77785
- `⛏️ ${brand("mining sessions...")} ${import_picocolors33.default.dim(`${DOT3} see Activity`)}`
77836
+ `\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors33.default.dim(`${DOT3} see Activity`)}`
77786
77837
  ]);
77787
77838
  }
77788
77839
  if (ctx.update) {
@@ -78326,7 +78377,7 @@ async function runMainMenu() {
78326
78377
  const mining = isMining();
78327
78378
  return [
78328
78379
  {
78329
- label: mining ? `Activity ⛏️ ${brand("mining sessions...")}` : "Activity",
78380
+ label: mining ? `Activity \uD83D\uDCDA ${brand("studying sessions...")}` : "Activity",
78330
78381
  value: "sync"
78331
78382
  },
78332
78383
  { label: "Knowledge report", hint: "(opens in browser)", value: "report" },
@@ -78406,7 +78457,7 @@ async function runSettings(cfg) {
78406
78457
  const action = await menuSelect("Settings", [
78407
78458
  { label: "Switch organization", hint: target?.org_name, value: "switch-org" },
78408
78459
  { label: "Switch Library", hint: library, value: "switch-library" },
78409
- { label: "Mining scope", hint: scope, value: "projects" },
78460
+ { label: "Study scope", hint: scope, value: "projects" },
78410
78461
  { label: "Run setup", hint: "rerun the setup wizard", value: "setup" },
78411
78462
  { label: "Log out", hint: "clear stored credentials", value: "logout" },
78412
78463
  { label: "Back", value: "back" }
@@ -78460,7 +78511,7 @@ async function runMiningProjectsSetting() {
78460
78511
  }
78461
78512
  const current = loadSyncState().project_filter;
78462
78513
  const selected = await multiselect2({
78463
- message: "Mine sessions from which folders?",
78514
+ message: "Study sessions from which folders?",
78464
78515
  options: dirs.map((dir) => ({
78465
78516
  label: dir === UNKNOWN_PROJECT ? "(unknown folder)" : displayDir(dir),
78466
78517
  value: dir
@@ -78475,7 +78526,7 @@ async function runMiningProjectsSetting() {
78475
78526
  const all = selected.length === dirs.length;
78476
78527
  saveSyncState(all ? state : { ...state, project_filter: [...selected] });
78477
78528
  const scope = all ? "all folders" : selected.map(displayDir).join(", ");
78478
- log2.success(`Mining scope ${dim(`· ${scope}`)}`);
78529
+ log2.success(`Study scope ${dim(`· ${scope}`)}`);
78479
78530
  }
78480
78531
  async function handleAuthenticate(cfg) {
78481
78532
  const shouldLogin = await confirm2({ message: "Open browser to log in?" });
@@ -82381,7 +82432,7 @@ ${results.length - opts.limit} more results not shown.`));
82381
82432
  console.log(` ID: ${store.id}`);
82382
82433
  console.log(` Space ID: ${store.space_id}`);
82383
82434
  });
82384
- cmd.command("sessions").description("List local agent sessions with full project and session ids (the untruncated view of the Activity screen's tabs)").option("--queued", "Only sessions queued for mining").option("--open", "Only live sessions still inside the quiet period").option("--mined", "Only recent mined-session history").option("--json", "Output as JSON").action((opts) => {
82435
+ cmd.command("sessions").description("List local agent sessions with full project and session ids (the untruncated view of the Activity screen's tabs)").option("--queued", "Only sessions queued for studying").option("--open", "Only live sessions still inside the quiet period").option("--mined", "Only recent studied-session history").option("--json", "Output as JSON").action((opts) => {
82385
82436
  const all = !opts.queued && !opts.open && !opts.mined;
82386
82437
  const wantQueued = all || Boolean(opts.queued);
82387
82438
  const wantOpen = all || Boolean(opts.open);
@@ -82422,10 +82473,10 @@ ${results.length - opts.limit} more results not shown.`));
82422
82473
  section("Open", sessionRows(backlog.open), "Updated", "No open sessions. Live agent sessions sit here until they go quiet.");
82423
82474
  }
82424
82475
  if (wantMined) {
82425
- section("Mined", minedRows, "Mined at", "No mined sessions recorded yet.");
82476
+ section("Studied", minedRows, "Studied at", "No studied sessions recorded yet.");
82426
82477
  }
82427
82478
  });
82428
- cmd.command("sync").description("Scan local agent session history and report the mining backlog").option("--quiet", "Background mode for hooks: honor backoff, exit 0, print nothing").option("--detach", "Re-spawn detached and return immediately (used by agent hooks)").option("--bootstrap", "Backfill mode: mine the full local session history regardless of age and drain the backlog (used by setup)").option("--status", "Show whether a sync is running now, plus watermark and recent activity").option("--report", "Write the same HTML harvest report as the log-to-dosu-knowledge skill and open it").option("--out <path>", "HTML report path (default: tmp/dosu-knowledge-report.html)").option("--json", "Output as JSON").action(async (opts) => {
82479
+ cmd.command("sync").description("Scan local agent session history and report the study backlog").option("--quiet", "Background mode for hooks: honor backoff, exit 0, print nothing").option("--detach", "Re-spawn detached and return immediately (used by agent hooks)").option("--bootstrap", "Backfill mode: study the full local session history regardless of age and drain the backlog (used by setup)").option("--status", "Show whether a sync is running now, plus watermark and recent activity").option("--report", "Write the same HTML harvest report as the log-to-dosu-knowledge skill and open it").option("--out <path>", "HTML report path (default: tmp/dosu-knowledge-report.html)").option("--json", "Output as JSON").action(async (opts) => {
82429
82480
  if (opts.status) {
82430
82481
  const status = getSyncStatus();
82431
82482
  if (opts.json) {
@@ -82511,7 +82562,7 @@ ${results.length - opts.limit} more results not shown.`));
82511
82562
  console.log("All your notes already have a transcript — nothing to backfill.");
82512
82563
  return;
82513
82564
  }
82514
- console.log(`Attributed ${result.updated} of ${result.candidates} notes (${result.ambiguous} ambiguous, ${result.noBatch} without a local mining batch). Run 'dosu knowledge report' to see their traces.`);
82565
+ console.log(`Attributed ${result.updated} of ${result.candidates} notes (${result.ambiguous} ambiguous, ${result.noBatch} without a local study batch). Run 'dosu knowledge report' to see their traces.`);
82515
82566
  });
82516
82567
  cmd.addCommand(hooksCommand());
82517
82568
  return cmd;
@@ -82552,14 +82603,14 @@ function printSyncStatus(status, now = new Date) {
82552
82603
  console.log("○ No sync running.");
82553
82604
  }
82554
82605
  if (status.state.paused) {
82555
- console.log(import_picocolors18.default.yellow(" Mining paused: stopped by you. Resume from the Activity screen or run 'dosu knowledge sync'."));
82606
+ console.log(import_picocolors18.default.yellow(" Studying paused: stopped by you. Resume from the Activity screen or run 'dosu knowledge sync'."));
82556
82607
  }
82557
82608
  const wm2 = status.state.watermark;
82558
- console.log(` Mined through: ${wm2 ? `${wm2} (${formatAge(wm2, now)})` : "nothing mined yet"}`);
82609
+ console.log(` Studied through: ${wm2 ? `${wm2} (${formatAge(wm2, now)})` : "nothing studied yet"}`);
82559
82610
  if (status.state.project_filter?.length) {
82560
82611
  const home = homedir5();
82561
82612
  const scope = status.state.project_filter.map((dir) => dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir).join(", ");
82562
- console.log(` Mining scope: ${scope}`);
82613
+ console.log(` Study scope: ${scope}`);
82563
82614
  }
82564
82615
  if ((status.state.total_notes ?? 0) > 0) {
82565
82616
  const tokens = status.state.total_learning_tokens ?? 0;
@@ -82574,7 +82625,7 @@ function printSyncStatus(status, now = new Date) {
82574
82625
  console.log(import_picocolors18.default.yellow(` Backing off after ${n5} failure${n5 === 1 ? "" : "s"}; background syncs retry after ${status.backoffUntil}.`));
82575
82626
  }
82576
82627
  if (status.state.last_refusal) {
82577
- console.log(import_picocolors18.default.yellow(` Mining paused: ${status.state.last_refusal.message} (${formatAge(status.state.last_refusal.at, now)})`));
82628
+ console.log(import_picocolors18.default.yellow(` Studying paused: ${status.state.last_refusal.message} (${formatAge(status.state.last_refusal.at, now)})`));
82578
82629
  }
82579
82630
  if (status.recentActivity.length > 0) {
82580
82631
  console.log(`
@@ -82590,25 +82641,25 @@ function printSyncOutcome(outcome) {
82590
82641
  switch (outcome.status) {
82591
82642
  case "backlog": {
82592
82643
  const inFlight = outcome.inFlightSessions > 0 ? import_picocolors18.default.dim(` (${outcome.inFlightSessions} more still in progress)`) : "";
82593
- console.log(`✓ Scanned. ${outcome.readySessions} new session${outcome.readySessions === 1 ? "" : "s"} ready to mine${inFlight}.`);
82594
- console.log(import_picocolors18.default.dim("Sign in with 'dosu setup' to enable mining."));
82644
+ console.log(`✓ Scanned. ${outcome.readySessions} new session${outcome.readySessions === 1 ? "" : "s"} ready to study${inFlight}.`);
82645
+ console.log(import_picocolors18.default.dim("Sign in with 'dosu setup' to enable studying."));
82595
82646
  break;
82596
82647
  }
82597
82648
  case "mined": {
82598
82649
  const notes = outcome.miner?.notesWritten ?? 0;
82599
82650
  const remaining = outcome.readySessions - (outcome.minedSessions ?? 0);
82600
- console.log(`✓ Mined ${outcome.minedSessions} session${outcome.minedSessions === 1 ? "" : "s"}, ${notes} suggested page${notes === 1 ? "" : "s"} created.`);
82651
+ console.log(`✓ Studied ${outcome.minedSessions} session${outcome.minedSessions === 1 ? "" : "s"}, ${notes} suggested page${notes === 1 ? "" : "s"} created.`);
82601
82652
  if (remaining > 0) {
82602
82653
  console.log(import_picocolors18.default.dim(`${remaining} more in the backlog; run sync again to continue.`));
82603
82654
  }
82604
82655
  break;
82605
82656
  }
82606
82657
  case "skipped-gateway": {
82607
- console.log(import_picocolors18.default.yellow(outcome.miner?.message ?? "Mining unavailable right now."));
82658
+ console.log(import_picocolors18.default.yellow(outcome.miner?.message ?? "Studying unavailable right now."));
82608
82659
  break;
82609
82660
  }
82610
82661
  case "mine-failed": {
82611
- console.error(import_picocolors18.default.red(outcome.miner?.message ?? "Mining run failed."));
82662
+ console.error(import_picocolors18.default.red(outcome.miner?.message ?? "Study run failed."));
82612
82663
  process.exitCode = 1;
82613
82664
  break;
82614
82665
  }
@@ -82631,7 +82682,7 @@ function printSyncOutcome(outcome) {
82631
82682
  break;
82632
82683
  }
82633
82684
  case "skipped-paused": {
82634
- console.log(import_picocolors18.default.dim("Skipped: mining is paused. Run 'dosu knowledge sync' to resume."));
82685
+ console.log(import_picocolors18.default.dim("Skipped: studying is paused. Run 'dosu knowledge sync' to resume."));
82635
82686
  break;
82636
82687
  }
82637
82688
  }
@@ -84636,4 +84687,4 @@ execute().catch((err) => {
84636
84687
  process.exit(1);
84637
84688
  });
84638
84689
 
84639
- //# debugId=fa7cf492-7aa5-180c-6475-6e2164756e21
84690
+ //# debugId=6b750395-441b-6515-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.53.0-beta.11",
3
+ "version": "0.53.0-beta.13",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",