@dosu/cli 0.53.0-beta.12 → 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.
- package/bin/dosu.js +98 -65
- 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.
|
|
5021
|
+
var VERSION = "0.53.0-beta.13", INSTALL_CHANNEL = "npm";
|
|
5022
5022
|
|
|
5023
5023
|
// src/debug/logger.ts
|
|
5024
5024
|
import {
|
|
@@ -8595,6 +8595,17 @@ function setSyncPaused(paused, configDir = getConfigDir()) {
|
|
|
8595
8595
|
delete state.paused;
|
|
8596
8596
|
saveSyncState(state, configDir);
|
|
8597
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
|
+
}
|
|
8598
8609
|
function saveSyncState(state, configDir = getConfigDir()) {
|
|
8599
8610
|
if (!existsSync10(configDir))
|
|
8600
8611
|
mkdirSync6(configDir, { recursive: true, mode: 448 });
|
|
@@ -9256,7 +9267,7 @@ function buildReportHtml(options) {
|
|
|
9256
9267
|
const org = options.orgName || "Your team";
|
|
9257
9268
|
const repo = options.repo || inventory.cwd || "—";
|
|
9258
9269
|
const branch = options.branch || "—";
|
|
9259
|
-
const summary = options.summary || "Local agent session logs were
|
|
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.";
|
|
9260
9271
|
const generated = `${(options.generatedAt ?? new Date).toISOString().replace("T", " ").slice(0, 16)} UTC`;
|
|
9261
9272
|
const derived = tokenTotalsFromCandidates(candidates, inventory);
|
|
9262
9273
|
const [notesHeading, notesLede, footerTitle, footerBody] = notesSectionCopy(candidates);
|
|
@@ -9318,7 +9329,7 @@ function buildReportHtml(options) {
|
|
|
9318
9329
|
<p class="muted">No rediscovery estimates on the notes yet — each candidate needs <code>approx_rediscovery_tokens</code>.</p>
|
|
9319
9330
|
</section>`;
|
|
9320
9331
|
}
|
|
9321
|
-
const notesBody = candidateRows.join("") || '<p class="muted">No write_knowledge payloads yet. Run knowledge sync so
|
|
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>';
|
|
9322
9333
|
const lede = notesLede ? `<p class="lede">${esc(notesLede)}</p>` : "";
|
|
9323
9334
|
return `<!DOCTYPE html>
|
|
9324
9335
|
<html lang="en">
|
|
@@ -10508,7 +10519,7 @@ async function runKnowledgeSync(options = {}) {
|
|
|
10508
10519
|
const state = loadState();
|
|
10509
10520
|
if (options.quiet) {
|
|
10510
10521
|
if (state.paused) {
|
|
10511
|
-
logger.debug("sync", "skipping quiet sync:
|
|
10522
|
+
logger.debug("sync", "skipping quiet sync: studying is paused");
|
|
10512
10523
|
return { status: "skipped-paused", readySessions: 0, inFlightSessions: 0, sessions: [] };
|
|
10513
10524
|
}
|
|
10514
10525
|
const retryAt = backoffUntil(state);
|
|
@@ -10518,7 +10529,7 @@ async function runKnowledgeSync(options = {}) {
|
|
|
10518
10529
|
}
|
|
10519
10530
|
} else if (state.paused) {
|
|
10520
10531
|
delete state.paused;
|
|
10521
|
-
logger.debug("sync", "manual sync resumes paused
|
|
10532
|
+
logger.debug("sync", "manual sync resumes paused studying");
|
|
10522
10533
|
}
|
|
10523
10534
|
let ready;
|
|
10524
10535
|
let open2;
|
|
@@ -10608,12 +10619,12 @@ async function runKnowledgeSync(options = {}) {
|
|
|
10608
10619
|
trivialSessions: trivial
|
|
10609
10620
|
};
|
|
10610
10621
|
}
|
|
10611
|
-
logger.debug("sync", `
|
|
10622
|
+
logger.debug("sync", `studying ${batch.length} of ${ready.length} ready sessions (${trivial} trivial skipped)`);
|
|
10612
10623
|
const miner = await deps.mine(batch);
|
|
10613
10624
|
switch (miner.outcome) {
|
|
10614
10625
|
case "completed": {
|
|
10615
10626
|
for (const s of batch) {
|
|
10616
|
-
logger.debug("sync", `
|
|
10627
|
+
logger.debug("sync", `studied session ${s.harness}/${s.id}`);
|
|
10617
10628
|
}
|
|
10618
10629
|
const minedAt = now().toISOString();
|
|
10619
10630
|
const history = [
|
|
@@ -10640,7 +10651,7 @@ async function runKnowledgeSync(options = {}) {
|
|
|
10640
10651
|
total_learning_tokens: (state.total_learning_tokens ?? 0) + batchTokens,
|
|
10641
10652
|
last_refusal: undefined
|
|
10642
10653
|
});
|
|
10643
|
-
logger.debug("sync", `
|
|
10654
|
+
logger.debug("sync", `studied ${batch.length} sessions, ${miner.notesWritten} suggested pages; watermark → ${watermark}`);
|
|
10644
10655
|
return {
|
|
10645
10656
|
status: "mined",
|
|
10646
10657
|
...base,
|
|
@@ -10660,10 +10671,10 @@ async function runKnowledgeSync(options = {}) {
|
|
|
10660
10671
|
last_refusal: {
|
|
10661
10672
|
at,
|
|
10662
10673
|
outcome: miner.outcome,
|
|
10663
|
-
message: miner.message ?? "
|
|
10674
|
+
message: miner.message ?? "Studying unavailable right now."
|
|
10664
10675
|
}
|
|
10665
10676
|
});
|
|
10666
|
-
logger.debug("sync", `
|
|
10677
|
+
logger.debug("sync", `studying skipped by gateway: ${miner.outcome}`);
|
|
10667
10678
|
return { status: "skipped-gateway", ...base, minedSessions: 0, miner };
|
|
10668
10679
|
}
|
|
10669
10680
|
default: {
|
|
@@ -10672,7 +10683,7 @@ async function runKnowledgeSync(options = {}) {
|
|
|
10672
10683
|
last_attempt_at: now().toISOString(),
|
|
10673
10684
|
consecutive_failures: state.consecutive_failures + 1
|
|
10674
10685
|
});
|
|
10675
|
-
logger.debug("sync", `
|
|
10686
|
+
logger.debug("sync", `studying failed: ${miner.outcome}; ${miner.message ?? ""}`);
|
|
10676
10687
|
return {
|
|
10677
10688
|
status: "mine-failed",
|
|
10678
10689
|
...base,
|
|
@@ -72919,7 +72930,7 @@ async function runMiner(options) {
|
|
|
72919
72930
|
outcome: "settings_conflict",
|
|
72920
72931
|
notesWritten: 0,
|
|
72921
72932
|
turns: 0,
|
|
72922
|
-
message: `Refusing to run: conflicting Claude Code settings would override the
|
|
72933
|
+
message: `Refusing to run: conflicting Claude Code settings would override the study run's auth (${detail})`
|
|
72923
72934
|
};
|
|
72924
72935
|
}
|
|
72925
72936
|
const gatewayURL = options.gatewayURL ?? getLlmGatewayURL();
|
|
@@ -72986,7 +72997,7 @@ async function runMiner(options) {
|
|
|
72986
72997
|
if (!allowed.has(toolName)) {
|
|
72987
72998
|
return {
|
|
72988
72999
|
behavior: "deny",
|
|
72989
|
-
message: `Tool ${toolName} is not permitted in
|
|
73000
|
+
message: `Tool ${toolName} is not permitted in study runs.`
|
|
72990
73001
|
};
|
|
72991
73002
|
}
|
|
72992
73003
|
if (toolName === `mcp__${SESSIONS_SERVER_NAME}__read_session`) {
|
|
@@ -73043,7 +73054,7 @@ async function runMiner(options) {
|
|
|
73043
73054
|
outcome: "error",
|
|
73044
73055
|
notesWritten,
|
|
73045
73056
|
turns,
|
|
73046
|
-
message: "
|
|
73057
|
+
message: "Study run failed; see debug log for details."
|
|
73047
73058
|
};
|
|
73048
73059
|
}
|
|
73049
73060
|
logger.debug("miner", `run ${runID} completed: ${turns} turns, ${notesWritten} suggested pages`);
|
|
@@ -73054,7 +73065,7 @@ async function runMiner(options) {
|
|
|
73054
73065
|
outcome: "error",
|
|
73055
73066
|
notesWritten,
|
|
73056
73067
|
turns,
|
|
73057
|
-
message: "
|
|
73068
|
+
message: "Study run ended without a result."
|
|
73058
73069
|
};
|
|
73059
73070
|
} catch (error61) {
|
|
73060
73071
|
const text = error61 instanceof Error ? error61.message : String(error61);
|
|
@@ -73067,7 +73078,7 @@ async function runMiner(options) {
|
|
|
73067
73078
|
outcome: "error",
|
|
73068
73079
|
notesWritten,
|
|
73069
73080
|
turns,
|
|
73070
|
-
message: abort.signal.aborted ? "
|
|
73081
|
+
message: abort.signal.aborted ? "Study run timed out and was aborted." : "Study run failed; see debug log for details."
|
|
73071
73082
|
};
|
|
73072
73083
|
} finally {
|
|
73073
73084
|
clearTimeout(timer);
|
|
@@ -73537,7 +73548,7 @@ var init_settings = __esm(() => {
|
|
|
73537
73548
|
});
|
|
73538
73549
|
|
|
73539
73550
|
// src/telemetry/debug-id.ts
|
|
73540
|
-
var BUNDLE_DEBUG_ID_PLACEHOLDER = "
|
|
73551
|
+
var BUNDLE_DEBUG_ID_PLACEHOLDER = "6b750395-441b-6515-6475-6e2164756e21";
|
|
73541
73552
|
|
|
73542
73553
|
// src/telemetry/telemetry.ts
|
|
73543
73554
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -75452,6 +75463,8 @@ function reduceActivityViewKey(key) {
|
|
|
75452
75463
|
return "sync";
|
|
75453
75464
|
if (key === "f")
|
|
75454
75465
|
return "full";
|
|
75466
|
+
if (key === "c")
|
|
75467
|
+
return "clear";
|
|
75455
75468
|
return "none";
|
|
75456
75469
|
}
|
|
75457
75470
|
function cycleTab(tab, delta = 1) {
|
|
@@ -75542,12 +75555,12 @@ function foldRunProgress(progress, chunk) {
|
|
|
75542
75555
|
let current = progress;
|
|
75543
75556
|
for (const line of chunk.split(`
|
|
75544
75557
|
`)) {
|
|
75545
|
-
const start = line.match(/\[sync\] mining (\d+) of \d+ ready sessions/);
|
|
75558
|
+
const start = line.match(/\[sync\] (?:studying|mining) (\d+) of \d+ ready sessions/);
|
|
75546
75559
|
if (start) {
|
|
75547
75560
|
current = { batch: Number.parseInt(start[1], 10), read: new Set, notes: 0 };
|
|
75548
75561
|
continue;
|
|
75549
75562
|
}
|
|
75550
|
-
if (/\[sync\] (mined \d+ sessions|mining failed|
|
|
75563
|
+
if (/\[sync\] (?:studied|mined) \d+ sessions|\[sync\] (?:studying|mining) (?:failed|skipped)/.test(line)) {
|
|
75551
75564
|
current = null;
|
|
75552
75565
|
continue;
|
|
75553
75566
|
}
|
|
@@ -75572,15 +75585,15 @@ function statusLine(status) {
|
|
|
75572
75585
|
if (status.running) {
|
|
75573
75586
|
const since = status.startedAt ? ` · since ${localTime(status.startedAt)}` : "";
|
|
75574
75587
|
const pid = status.pid !== undefined ? ` (pid ${status.pid})` : "";
|
|
75575
|
-
return
|
|
75588
|
+
return `\uD83D\uDCDA ${import_picocolors30.default.bold(brand("Studying sessions..."))}${import_picocolors30.default.dim(`${pid}${since}`)}`;
|
|
75576
75589
|
}
|
|
75577
75590
|
if (status.state.paused) {
|
|
75578
|
-
return `${import_picocolors30.default.yellow("○")} ${import_picocolors30.default.bold("Paused")} ${import_picocolors30.default.dim("·
|
|
75591
|
+
return `${import_picocolors30.default.yellow("○")} ${import_picocolors30.default.bold("Paused")} ${import_picocolors30.default.dim("· studying stays off until you resume")}`;
|
|
75579
75592
|
}
|
|
75580
75593
|
if (status.staleLock) {
|
|
75581
75594
|
return `${import_picocolors30.default.yellow("○")} ${import_picocolors30.default.bold("Not running")} ${import_picocolors30.default.dim("· a previous run exited without cleaning up")}`;
|
|
75582
75595
|
}
|
|
75583
|
-
return `${import_picocolors30.default.dim("○")} ${import_picocolors30.default.bold("Idle")} ${import_picocolors30.default.dim("· hooks
|
|
75596
|
+
return `${import_picocolors30.default.dim("○")} ${import_picocolors30.default.bold("Idle")} ${import_picocolors30.default.dim("· hooks study new sessions automatically")}`;
|
|
75584
75597
|
}
|
|
75585
75598
|
function progressLine(done, ready, width, notes = 0) {
|
|
75586
75599
|
const total = done + ready;
|
|
@@ -75592,12 +75605,12 @@ function progressLine(done, ready, width, notes = 0) {
|
|
|
75592
75605
|
const bar = brand("█".repeat(filled)) + import_picocolors30.default.dim("░".repeat(cells - filled));
|
|
75593
75606
|
const pct = Math.floor(ratio * 100);
|
|
75594
75607
|
const suffix = notes > 0 ? ` · ${notes} suggested page${notes === 1 ? "" : "s"}` : "";
|
|
75595
|
-
return `${bar} ${done}/${total}
|
|
75608
|
+
return `${bar} ${done}/${total} studied · ${pct}%${suffix}`;
|
|
75596
75609
|
}
|
|
75597
75610
|
function tabBar(tab, queuedCount, openCount, minedCount, width) {
|
|
75598
75611
|
return tabStrip([
|
|
75599
75612
|
["activity", "Activity"],
|
|
75600
|
-
["mined", `
|
|
75613
|
+
["mined", `Studied (${minedCount})`],
|
|
75601
75614
|
["queued", `Queued (${queuedCount})`],
|
|
75602
75615
|
["open", `Open (${openCount})`]
|
|
75603
75616
|
], tab, width);
|
|
@@ -75621,10 +75634,11 @@ function wrapLine(text, width, indent = " ") {
|
|
|
75621
75634
|
return out;
|
|
75622
75635
|
}
|
|
75623
75636
|
function confirmBox(queuedCount, backlog, width, mode = "start") {
|
|
75624
|
-
const inFlight = backlog && backlog.inFlight > 0 ? ` (+${backlog.inFlight} open
|
|
75625
|
-
const
|
|
75626
|
-
const
|
|
75627
|
-
const
|
|
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";
|
|
75628
75642
|
const maxInner = Math.max(20, Math.min(width, contentWidth()) - 4);
|
|
75629
75643
|
const rows = [
|
|
75630
75644
|
import_picocolors30.default.bold(brand(title)),
|
|
@@ -75641,7 +75655,7 @@ function confirmBox(queuedCount, backlog, width, mode = "start") {
|
|
|
75641
75655
|
];
|
|
75642
75656
|
}
|
|
75643
75657
|
function renderActivityFrame(status, activity, width, backlog = null, pane = DEFAULT_PANE, queued = [], minedBeforeRun = 0, open5 = [], runProgress = null) {
|
|
75644
|
-
const mined = status.state.watermark ? `
|
|
75658
|
+
const mined = status.state.watermark ? `Studied sessions up to ${localTime(status.state.watermark)}` : "Nothing studied yet";
|
|
75645
75659
|
const queueDetail = [];
|
|
75646
75660
|
if (status.backoffUntil) {
|
|
75647
75661
|
queueDetail.push(`retrying after ${localTime(status.backoffUntil)} · s syncs now`);
|
|
@@ -75653,14 +75667,14 @@ function renderActivityFrame(status, activity, width, backlog = null, pane = DEF
|
|
|
75653
75667
|
progress = progressLine(minedDelta + stepDone, Math.max(0, backlog.ready - stepDone), width, runProgress?.notes ?? 0);
|
|
75654
75668
|
}
|
|
75655
75669
|
const refusal = !status.running && status.state.last_refusal;
|
|
75656
|
-
const refusalLines = refusal ? wrapLine(`!
|
|
75670
|
+
const refusalLines = refusal ? wrapLine(`! Studying paused: ${refusal.message} (${localTime(refusal.at)})`, width).map((line) => import_picocolors30.default.yellow(line)) : [];
|
|
75657
75671
|
const fullRows = Boolean(pane.fullRows);
|
|
75658
75672
|
const minedRows = (status.state.mined_sessions ?? []).map((record2) => fullRows ? formatMinedRow(record2, true) : formatActivityLine(formatMinedRow(record2), width));
|
|
75659
75673
|
const sessionRow = (session) => fullRows ? formatQueuedRow(session, true) : formatActivityLine(formatQueuedRow(session), width);
|
|
75660
75674
|
const queuedRows = queued.map(sessionRow);
|
|
75661
75675
|
const openRows = open5.map(sessionRow);
|
|
75662
75676
|
const source = pane.tab === "activity" ? activity.map((line) => formatActivityLine(line, width, fullRows)) : pane.tab === "queued" ? queuedRows : pane.tab === "open" ? openRows : minedRows;
|
|
75663
|
-
const emptyMined = status.state.watermark ? "No sessions recorded yet. History starts with the next
|
|
75677
|
+
const emptyMined = status.state.watermark ? "No sessions recorded yet. History starts with the next study run." : "No studied sessions yet.";
|
|
75664
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;
|
|
75665
75679
|
const height = fullRows ? ACTIVITY_VIEW_FULL_LIST_ROWS : ACTIVITY_VIEW_LIST_LINES;
|
|
75666
75680
|
const { visible, above, below } = windowList(source, pane.scroll, height);
|
|
@@ -75685,13 +75699,14 @@ function renderActivityFrame(status, activity, width, backlog = null, pane = DEF
|
|
|
75685
75699
|
...scrollParts.length > 0 ? [import_picocolors30.default.dim(clip(scrollParts.join(" · "), width))] : [],
|
|
75686
75700
|
"",
|
|
75687
75701
|
...pane.confirm ? centerBlock(confirmBox(queued.length, backlog, width, pane.confirm), width) : [
|
|
75688
|
-
|
|
75702
|
+
...wrapLine([
|
|
75689
75703
|
"tab switch",
|
|
75690
75704
|
"↑↓ scroll",
|
|
75691
75705
|
fullRows ? "f clip" : "f full rows",
|
|
75692
75706
|
status.running ? "s stop" : status.state.paused ? "s resume" : "s sync now",
|
|
75707
|
+
...!status.running && status.state.watermark ? ["c clear"] : [],
|
|
75693
75708
|
"esc back"
|
|
75694
|
-
].join(" · "))
|
|
75709
|
+
].join(" · "), width, "").map((line) => import_picocolors30.default.dim(line))
|
|
75695
75710
|
]
|
|
75696
75711
|
];
|
|
75697
75712
|
return lines.join(`
|
|
@@ -75715,6 +75730,7 @@ function runActivityView(io2 = {}) {
|
|
|
75715
75730
|
const startSync = io2.startSync ?? (() => spawnDetachedSelf(["knowledge", "sync", "--bootstrap"]));
|
|
75716
75731
|
const stopSync = io2.stopSync ?? stopSyncRun;
|
|
75717
75732
|
const setPaused = io2.setPaused ?? setSyncPaused;
|
|
75733
|
+
const clearHistory = io2.clearHistory ?? resetSyncState;
|
|
75718
75734
|
const listBacklog = io2.listBacklog ?? listSessionBacklog;
|
|
75719
75735
|
const pollMs = io2.pollMs ?? ACTIVITY_VIEW_POLL_MS;
|
|
75720
75736
|
const seed = readLog();
|
|
@@ -75761,7 +75777,7 @@ function runActivityView(io2 = {}) {
|
|
|
75761
75777
|
queuedWatermark = status.state.watermark;
|
|
75762
75778
|
sessions = listBacklog();
|
|
75763
75779
|
}
|
|
75764
|
-
if (
|
|
75780
|
+
if (confirmSync !== null && confirmSync !== "stop" && status.running)
|
|
75765
75781
|
confirmSync = null;
|
|
75766
75782
|
if (confirmSync === "stop" && !status.running)
|
|
75767
75783
|
confirmSync = null;
|
|
@@ -75813,11 +75829,15 @@ ${CLEAR_BELOW}`);
|
|
|
75813
75829
|
const mode = confirmSync;
|
|
75814
75830
|
confirmSync = null;
|
|
75815
75831
|
let note;
|
|
75816
|
-
if (mode === "
|
|
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") {
|
|
75817
75837
|
const ok2 = status.pid !== undefined && stopSync(status.pid);
|
|
75818
75838
|
if (ok2)
|
|
75819
75839
|
setPaused(true);
|
|
75820
|
-
note = ok2 ? "[sync]
|
|
75840
|
+
note = ok2 ? "[sync] studying stopped · paused until you resume" : "[sync] could not stop the run · it may have just finished";
|
|
75821
75841
|
} else {
|
|
75822
75842
|
if (mode === "resume")
|
|
75823
75843
|
setPaused(false);
|
|
@@ -75841,6 +75861,11 @@ ${CLEAR_BELOW}`);
|
|
|
75841
75861
|
if (action === "sync") {
|
|
75842
75862
|
confirmSync = syncConfirmMode(status);
|
|
75843
75863
|
draw();
|
|
75864
|
+
} else if (action === "clear") {
|
|
75865
|
+
if (!status.running && status.state.watermark) {
|
|
75866
|
+
confirmSync = "clear";
|
|
75867
|
+
draw();
|
|
75868
|
+
}
|
|
75844
75869
|
} else if (action === "tab" || action === "tab-back") {
|
|
75845
75870
|
tab = cycleTab(tab, action === "tab" ? 1 : -1);
|
|
75846
75871
|
scroll = 0;
|
|
@@ -76726,23 +76751,31 @@ async function stepOfferInitialSync(cfg) {
|
|
|
76726
76751
|
s.start("Checking for recent agent sessions...");
|
|
76727
76752
|
const outcome = await runKnowledgeSync({ bootstrap: true });
|
|
76728
76753
|
if (outcome.status !== "backlog" || outcome.readySessions === 0) {
|
|
76729
|
-
s.stop("No
|
|
76754
|
+
s.stop("No past agent sessions to study. Dosu will learn from new ones as you work.");
|
|
76730
76755
|
return;
|
|
76731
76756
|
}
|
|
76732
76757
|
const n5 = outcome.readySessions;
|
|
76733
|
-
|
|
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
|
+
`));
|
|
76734
76767
|
const mineNow = await confirm2({
|
|
76735
|
-
message: `
|
|
76736
|
-
active: "
|
|
76737
|
-
inactive: "Skip",
|
|
76768
|
+
message: `Study ${them} now?`,
|
|
76769
|
+
active: "Study now \uD83D\uDCDA",
|
|
76770
|
+
inactive: "Skip for now",
|
|
76738
76771
|
initialValue: true
|
|
76739
76772
|
});
|
|
76740
76773
|
if (isCancel2(mineNow) || !mineNow) {
|
|
76741
|
-
log2.info(`Skipped. Dosu
|
|
76774
|
+
log2.info(`Skipped. Dosu studies new sessions in the background as you work; run ${info("dosu knowledge sync")} anytime to study these too.`);
|
|
76742
76775
|
return;
|
|
76743
76776
|
}
|
|
76744
76777
|
if (spawnDetachedSelf(["knowledge", "sync", "--quiet", "--bootstrap"])) {
|
|
76745
|
-
log2.success("
|
|
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.`);
|
|
76746
76779
|
const watch = await confirm2({
|
|
76747
76780
|
message: "What next?",
|
|
76748
76781
|
active: "Watch it work",
|
|
@@ -77572,7 +77605,7 @@ function overviewRows(state) {
|
|
|
77572
77605
|
const tokens = state.total_learning_tokens ?? 0;
|
|
77573
77606
|
if (minedTotal === 0 && notes === 0)
|
|
77574
77607
|
return [];
|
|
77575
|
-
const rows = [`${label("Sessions
|
|
77608
|
+
const rows = [`${label("Sessions studied")}${minedTotal}`, `${label("Suggested pages")}${notes}`];
|
|
77576
77609
|
if (tokens > 0) {
|
|
77577
77610
|
rows.push(`${label("Investigation distilled")}${formatTokenCount(tokens)} tokens`);
|
|
77578
77611
|
}
|
|
@@ -77621,7 +77654,7 @@ function analyticsTabRows(tab, state, pageStats) {
|
|
|
77621
77654
|
function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending = false, width = contentWidth()) {
|
|
77622
77655
|
const rows = analyticsTabRows(tab, state, pageStats);
|
|
77623
77656
|
const { visible, above, below } = windowReport(rows, scroll);
|
|
77624
|
-
const empty = tab === "overview" ? "No analytics yet. They appear after the first
|
|
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.";
|
|
77625
77658
|
const listRows = visible.length > 0 ? visible.map((row) => import_picocolors32.default.dim(row)) : [import_picocolors32.default.dim(empty)];
|
|
77626
77659
|
const scrollParts = [];
|
|
77627
77660
|
if (above > 0)
|
|
@@ -77800,7 +77833,7 @@ function checklistRows(ctx) {
|
|
|
77800
77833
|
if (ctx.mining) {
|
|
77801
77834
|
rows.push([
|
|
77802
77835
|
"sync",
|
|
77803
|
-
|
|
77836
|
+
`\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors33.default.dim(`${DOT3} see Activity`)}`
|
|
77804
77837
|
]);
|
|
77805
77838
|
}
|
|
77806
77839
|
if (ctx.update) {
|
|
@@ -78344,7 +78377,7 @@ async function runMainMenu() {
|
|
|
78344
78377
|
const mining = isMining();
|
|
78345
78378
|
return [
|
|
78346
78379
|
{
|
|
78347
|
-
label: mining ? `Activity
|
|
78380
|
+
label: mining ? `Activity \uD83D\uDCDA ${brand("studying sessions...")}` : "Activity",
|
|
78348
78381
|
value: "sync"
|
|
78349
78382
|
},
|
|
78350
78383
|
{ label: "Knowledge report", hint: "(opens in browser)", value: "report" },
|
|
@@ -78424,7 +78457,7 @@ async function runSettings(cfg) {
|
|
|
78424
78457
|
const action = await menuSelect("Settings", [
|
|
78425
78458
|
{ label: "Switch organization", hint: target?.org_name, value: "switch-org" },
|
|
78426
78459
|
{ label: "Switch Library", hint: library, value: "switch-library" },
|
|
78427
|
-
{ label: "
|
|
78460
|
+
{ label: "Study scope", hint: scope, value: "projects" },
|
|
78428
78461
|
{ label: "Run setup", hint: "rerun the setup wizard", value: "setup" },
|
|
78429
78462
|
{ label: "Log out", hint: "clear stored credentials", value: "logout" },
|
|
78430
78463
|
{ label: "Back", value: "back" }
|
|
@@ -78478,7 +78511,7 @@ async function runMiningProjectsSetting() {
|
|
|
78478
78511
|
}
|
|
78479
78512
|
const current = loadSyncState().project_filter;
|
|
78480
78513
|
const selected = await multiselect2({
|
|
78481
|
-
message: "
|
|
78514
|
+
message: "Study sessions from which folders?",
|
|
78482
78515
|
options: dirs.map((dir) => ({
|
|
78483
78516
|
label: dir === UNKNOWN_PROJECT ? "(unknown folder)" : displayDir(dir),
|
|
78484
78517
|
value: dir
|
|
@@ -78493,7 +78526,7 @@ async function runMiningProjectsSetting() {
|
|
|
78493
78526
|
const all = selected.length === dirs.length;
|
|
78494
78527
|
saveSyncState(all ? state : { ...state, project_filter: [...selected] });
|
|
78495
78528
|
const scope = all ? "all folders" : selected.map(displayDir).join(", ");
|
|
78496
|
-
log2.success(`
|
|
78529
|
+
log2.success(`Study scope ${dim(`· ${scope}`)}`);
|
|
78497
78530
|
}
|
|
78498
78531
|
async function handleAuthenticate(cfg) {
|
|
78499
78532
|
const shouldLogin = await confirm2({ message: "Open browser to log in?" });
|
|
@@ -82399,7 +82432,7 @@ ${results.length - opts.limit} more results not shown.`));
|
|
|
82399
82432
|
console.log(` ID: ${store.id}`);
|
|
82400
82433
|
console.log(` Space ID: ${store.space_id}`);
|
|
82401
82434
|
});
|
|
82402
|
-
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
|
|
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) => {
|
|
82403
82436
|
const all = !opts.queued && !opts.open && !opts.mined;
|
|
82404
82437
|
const wantQueued = all || Boolean(opts.queued);
|
|
82405
82438
|
const wantOpen = all || Boolean(opts.open);
|
|
@@ -82440,10 +82473,10 @@ ${results.length - opts.limit} more results not shown.`));
|
|
|
82440
82473
|
section("Open", sessionRows(backlog.open), "Updated", "No open sessions. Live agent sessions sit here until they go quiet.");
|
|
82441
82474
|
}
|
|
82442
82475
|
if (wantMined) {
|
|
82443
|
-
section("
|
|
82476
|
+
section("Studied", minedRows, "Studied at", "No studied sessions recorded yet.");
|
|
82444
82477
|
}
|
|
82445
82478
|
});
|
|
82446
|
-
cmd.command("sync").description("Scan local agent session history and report the
|
|
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) => {
|
|
82447
82480
|
if (opts.status) {
|
|
82448
82481
|
const status = getSyncStatus();
|
|
82449
82482
|
if (opts.json) {
|
|
@@ -82529,7 +82562,7 @@ ${results.length - opts.limit} more results not shown.`));
|
|
|
82529
82562
|
console.log("All your notes already have a transcript — nothing to backfill.");
|
|
82530
82563
|
return;
|
|
82531
82564
|
}
|
|
82532
|
-
console.log(`Attributed ${result.updated} of ${result.candidates} notes (${result.ambiguous} ambiguous, ${result.noBatch} without a local
|
|
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.`);
|
|
82533
82566
|
});
|
|
82534
82567
|
cmd.addCommand(hooksCommand());
|
|
82535
82568
|
return cmd;
|
|
@@ -82570,14 +82603,14 @@ function printSyncStatus(status, now = new Date) {
|
|
|
82570
82603
|
console.log("○ No sync running.");
|
|
82571
82604
|
}
|
|
82572
82605
|
if (status.state.paused) {
|
|
82573
|
-
console.log(import_picocolors18.default.yellow("
|
|
82606
|
+
console.log(import_picocolors18.default.yellow(" Studying paused: stopped by you. Resume from the Activity screen or run 'dosu knowledge sync'."));
|
|
82574
82607
|
}
|
|
82575
82608
|
const wm2 = status.state.watermark;
|
|
82576
|
-
console.log(`
|
|
82609
|
+
console.log(` Studied through: ${wm2 ? `${wm2} (${formatAge(wm2, now)})` : "nothing studied yet"}`);
|
|
82577
82610
|
if (status.state.project_filter?.length) {
|
|
82578
82611
|
const home = homedir5();
|
|
82579
82612
|
const scope = status.state.project_filter.map((dir) => dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir).join(", ");
|
|
82580
|
-
console.log(`
|
|
82613
|
+
console.log(` Study scope: ${scope}`);
|
|
82581
82614
|
}
|
|
82582
82615
|
if ((status.state.total_notes ?? 0) > 0) {
|
|
82583
82616
|
const tokens = status.state.total_learning_tokens ?? 0;
|
|
@@ -82592,7 +82625,7 @@ function printSyncStatus(status, now = new Date) {
|
|
|
82592
82625
|
console.log(import_picocolors18.default.yellow(` Backing off after ${n5} failure${n5 === 1 ? "" : "s"}; background syncs retry after ${status.backoffUntil}.`));
|
|
82593
82626
|
}
|
|
82594
82627
|
if (status.state.last_refusal) {
|
|
82595
|
-
console.log(import_picocolors18.default.yellow(`
|
|
82628
|
+
console.log(import_picocolors18.default.yellow(` Studying paused: ${status.state.last_refusal.message} (${formatAge(status.state.last_refusal.at, now)})`));
|
|
82596
82629
|
}
|
|
82597
82630
|
if (status.recentActivity.length > 0) {
|
|
82598
82631
|
console.log(`
|
|
@@ -82608,25 +82641,25 @@ function printSyncOutcome(outcome) {
|
|
|
82608
82641
|
switch (outcome.status) {
|
|
82609
82642
|
case "backlog": {
|
|
82610
82643
|
const inFlight = outcome.inFlightSessions > 0 ? import_picocolors18.default.dim(` (${outcome.inFlightSessions} more still in progress)`) : "";
|
|
82611
|
-
console.log(`✓ Scanned. ${outcome.readySessions} new session${outcome.readySessions === 1 ? "" : "s"} ready to
|
|
82612
|
-
console.log(import_picocolors18.default.dim("Sign in with 'dosu setup' to enable
|
|
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."));
|
|
82613
82646
|
break;
|
|
82614
82647
|
}
|
|
82615
82648
|
case "mined": {
|
|
82616
82649
|
const notes = outcome.miner?.notesWritten ?? 0;
|
|
82617
82650
|
const remaining = outcome.readySessions - (outcome.minedSessions ?? 0);
|
|
82618
|
-
console.log(`✓
|
|
82651
|
+
console.log(`✓ Studied ${outcome.minedSessions} session${outcome.minedSessions === 1 ? "" : "s"}, ${notes} suggested page${notes === 1 ? "" : "s"} created.`);
|
|
82619
82652
|
if (remaining > 0) {
|
|
82620
82653
|
console.log(import_picocolors18.default.dim(`${remaining} more in the backlog; run sync again to continue.`));
|
|
82621
82654
|
}
|
|
82622
82655
|
break;
|
|
82623
82656
|
}
|
|
82624
82657
|
case "skipped-gateway": {
|
|
82625
|
-
console.log(import_picocolors18.default.yellow(outcome.miner?.message ?? "
|
|
82658
|
+
console.log(import_picocolors18.default.yellow(outcome.miner?.message ?? "Studying unavailable right now."));
|
|
82626
82659
|
break;
|
|
82627
82660
|
}
|
|
82628
82661
|
case "mine-failed": {
|
|
82629
|
-
console.error(import_picocolors18.default.red(outcome.miner?.message ?? "
|
|
82662
|
+
console.error(import_picocolors18.default.red(outcome.miner?.message ?? "Study run failed."));
|
|
82630
82663
|
process.exitCode = 1;
|
|
82631
82664
|
break;
|
|
82632
82665
|
}
|
|
@@ -82649,7 +82682,7 @@ function printSyncOutcome(outcome) {
|
|
|
82649
82682
|
break;
|
|
82650
82683
|
}
|
|
82651
82684
|
case "skipped-paused": {
|
|
82652
|
-
console.log(import_picocolors18.default.dim("Skipped:
|
|
82685
|
+
console.log(import_picocolors18.default.dim("Skipped: studying is paused. Run 'dosu knowledge sync' to resume."));
|
|
82653
82686
|
break;
|
|
82654
82687
|
}
|
|
82655
82688
|
}
|
|
@@ -84654,4 +84687,4 @@ execute().catch((err) => {
|
|
|
84654
84687
|
process.exit(1);
|
|
84655
84688
|
});
|
|
84656
84689
|
|
|
84657
|
-
//# debugId=
|
|
84690
|
+
//# debugId=6b750395-441b-6515-6475-6e2164756e21
|