@dosu/cli 0.53.0-beta.7 → 0.53.0-beta.9
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 +164 -8
- 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.9", INSTALL_CHANNEL = "npm";
|
|
5022
5022
|
|
|
5023
5023
|
// src/debug/logger.ts
|
|
5024
5024
|
import {
|
|
@@ -5156,7 +5156,7 @@ var init_logger = __esm(() => {
|
|
|
5156
5156
|
});
|
|
5157
5157
|
|
|
5158
5158
|
// src/client/contract.ts
|
|
5159
|
-
var CLI_CONTRACT_HASH = "
|
|
5159
|
+
var CLI_CONTRACT_HASH = "d7c6f0f0e8d0";
|
|
5160
5160
|
|
|
5161
5161
|
// src/client/trpc.ts
|
|
5162
5162
|
var exports_trpc = {};
|
|
@@ -10678,6 +10678,134 @@ var init_sync = __esm(() => {
|
|
|
10678
10678
|
init_watermark();
|
|
10679
10679
|
});
|
|
10680
10680
|
|
|
10681
|
+
// src/report/backfill.ts
|
|
10682
|
+
function noteTime2(at) {
|
|
10683
|
+
const parsed = Date.parse(at ?? "");
|
|
10684
|
+
return Number.isNaN(parsed) ? Number.NaN : parsed;
|
|
10685
|
+
}
|
|
10686
|
+
function correlateBackfill(input) {
|
|
10687
|
+
const batches = new Map;
|
|
10688
|
+
for (const e of input.ledger) {
|
|
10689
|
+
const members = batches.get(e.at) ?? [];
|
|
10690
|
+
members.push(e.session);
|
|
10691
|
+
batches.set(e.at, members);
|
|
10692
|
+
}
|
|
10693
|
+
const batchTimes = [...batches.keys()].map((at) => ({ at, t: Date.parse(at) })).filter((b2) => !Number.isNaN(b2.t));
|
|
10694
|
+
const sessionByKey = new Map(input.sessions.map((s) => [`${s.harness}/${s.id}`, s]));
|
|
10695
|
+
const cyclesCache = new Map;
|
|
10696
|
+
const cyclesFor = (session) => {
|
|
10697
|
+
let cycles = cyclesCache.get(session.id);
|
|
10698
|
+
if (!cycles) {
|
|
10699
|
+
cycles = sessionCycles(sessionToDigest(session).turns);
|
|
10700
|
+
cyclesCache.set(session.id, cycles);
|
|
10701
|
+
}
|
|
10702
|
+
return cycles;
|
|
10703
|
+
};
|
|
10704
|
+
const mappings = [];
|
|
10705
|
+
let ambiguous = 0;
|
|
10706
|
+
let noBatch = 0;
|
|
10707
|
+
for (const note of input.notes) {
|
|
10708
|
+
const time = noteTime2(note.at);
|
|
10709
|
+
if (Number.isNaN(time)) {
|
|
10710
|
+
noBatch += 1;
|
|
10711
|
+
continue;
|
|
10712
|
+
}
|
|
10713
|
+
let batchAt;
|
|
10714
|
+
let bestD = Number.POSITIVE_INFINITY;
|
|
10715
|
+
for (const b2 of batchTimes) {
|
|
10716
|
+
const d = Math.abs(b2.t - time);
|
|
10717
|
+
if (d <= BATCH_TOLERANCE_MS && d < bestD) {
|
|
10718
|
+
bestD = d;
|
|
10719
|
+
batchAt = b2.at;
|
|
10720
|
+
}
|
|
10721
|
+
}
|
|
10722
|
+
if (!batchAt) {
|
|
10723
|
+
noBatch += 1;
|
|
10724
|
+
continue;
|
|
10725
|
+
}
|
|
10726
|
+
const members = (batches.get(batchAt) ?? []).map((k) => sessionByKey.get(k)).filter((s) => s !== undefined);
|
|
10727
|
+
if (members.length === 0) {
|
|
10728
|
+
noBatch += 1;
|
|
10729
|
+
continue;
|
|
10730
|
+
}
|
|
10731
|
+
const words = noteWords(note);
|
|
10732
|
+
let best;
|
|
10733
|
+
let second = 0;
|
|
10734
|
+
for (const session of members) {
|
|
10735
|
+
let score = 0;
|
|
10736
|
+
for (const cycle of cyclesFor(session)) {
|
|
10737
|
+
const s = cycleMatchScore(words, cycle.text);
|
|
10738
|
+
if (s > score)
|
|
10739
|
+
score = s;
|
|
10740
|
+
}
|
|
10741
|
+
if (!best || score > best.score) {
|
|
10742
|
+
second = best?.score ?? 0;
|
|
10743
|
+
best = { session, score };
|
|
10744
|
+
} else if (score > second) {
|
|
10745
|
+
second = score;
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10748
|
+
if (!best || best.score < MIN_SCORE || second > 0 && best.score < second * CLEAR_WIN_RATIO) {
|
|
10749
|
+
ambiguous += 1;
|
|
10750
|
+
continue;
|
|
10751
|
+
}
|
|
10752
|
+
mappings.push({ note_id: note.id, transcript_id: best.session.id });
|
|
10753
|
+
}
|
|
10754
|
+
return { mappings, ambiguous, noBatch };
|
|
10755
|
+
}
|
|
10756
|
+
var BATCH_TOLERANCE_MS, CLEAR_WIN_RATIO = 1.5, MIN_SCORE = 3;
|
|
10757
|
+
var init_backfill = __esm(() => {
|
|
10758
|
+
init_digest();
|
|
10759
|
+
init_notes();
|
|
10760
|
+
BATCH_TOLERANCE_MS = 30 * 60 * 1000;
|
|
10761
|
+
});
|
|
10762
|
+
|
|
10763
|
+
// src/report/backfill-run.ts
|
|
10764
|
+
var exports_backfill_run = {};
|
|
10765
|
+
__export(exports_backfill_run, {
|
|
10766
|
+
runBackfill: () => runBackfill
|
|
10767
|
+
});
|
|
10768
|
+
async function defaultFetchUnattributed(cfg) {
|
|
10769
|
+
const orgId = cfg.active_account?.target?.org_id;
|
|
10770
|
+
if (!orgId || !cfg.active_account?.session.access_token) {
|
|
10771
|
+
throw new Error("Not signed in. Run `dosu setup` to connect an account first.");
|
|
10772
|
+
}
|
|
10773
|
+
const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
|
|
10774
|
+
const client = createTypedClient2(cfg);
|
|
10775
|
+
const { notes } = await client.notes.listMine.query({ org_id: orgId, limit: 500 });
|
|
10776
|
+
return notes.filter((n2) => !n2.transcript_id).map((n2) => ({ id: n2.id, title: n2.title, content: n2.body, at: n2.created_at }));
|
|
10777
|
+
}
|
|
10778
|
+
async function defaultApply(cfg, mappings) {
|
|
10779
|
+
const { createTypedClient: createTypedClient2 } = await Promise.resolve().then(() => (init_trpc(), exports_trpc));
|
|
10780
|
+
const client = createTypedClient2(cfg);
|
|
10781
|
+
let updated = 0;
|
|
10782
|
+
for (let i2 = 0;i2 < mappings.length; i2 += MUTATION_CHUNK) {
|
|
10783
|
+
const chunk = mappings.slice(i2, i2 + MUTATION_CHUNK);
|
|
10784
|
+
const res = await client.notes.attributeTranscripts.mutate({ mappings: chunk });
|
|
10785
|
+
updated += res.updated;
|
|
10786
|
+
}
|
|
10787
|
+
return updated;
|
|
10788
|
+
}
|
|
10789
|
+
async function runBackfill(deps = {}) {
|
|
10790
|
+
const cfg = (deps.loadCfg ?? loadConfig)();
|
|
10791
|
+
const notes = await (deps.fetchUnattributed ?? defaultFetchUnattributed)(cfg);
|
|
10792
|
+
if (notes.length === 0) {
|
|
10793
|
+
return { candidates: 0, mappings: [], ambiguous: 0, noBatch: 0, updated: 0 };
|
|
10794
|
+
}
|
|
10795
|
+
const ledger = (deps.ledger ?? (() => loadSyncState().mined_sessions ?? []))();
|
|
10796
|
+
const sessions = (deps.scan ?? scanAgentSessions)();
|
|
10797
|
+
const { mappings, ambiguous, noBatch } = correlateBackfill({ notes, ledger, sessions });
|
|
10798
|
+
const updated = mappings.length > 0 ? await (deps.apply ?? defaultApply)(cfg, mappings) : 0;
|
|
10799
|
+
return { candidates: notes.length, mappings, ambiguous, noBatch, updated };
|
|
10800
|
+
}
|
|
10801
|
+
var MUTATION_CHUNK = 500;
|
|
10802
|
+
var init_backfill_run = __esm(() => {
|
|
10803
|
+
init_config();
|
|
10804
|
+
init_scan();
|
|
10805
|
+
init_watermark();
|
|
10806
|
+
init_backfill();
|
|
10807
|
+
});
|
|
10808
|
+
|
|
10681
10809
|
// src/miner/config-dir.ts
|
|
10682
10810
|
import { mkdtempSync, rmSync as rmSync3, writeFileSync as writeFileSync10 } from "node:fs";
|
|
10683
10811
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
@@ -10850,7 +10978,7 @@ function buildMinerPrompt(sessions) {
|
|
|
10850
10978
|
|
|
10851
10979
|
${list}
|
|
10852
10980
|
|
|
10853
|
-
|
|
10981
|
+
Work through them ONE AT A TIME: read a single session with read_session, decide what (if anything) is durable per your rules, dedupe against read_knowledge, and write that session's notes with write_knowledge BEFORE moving on to the next session. Each note is attributed to the session you read just before writing it, so do not read the next session until you have written this one's notes. When you are done, reply with a one-line summary: how many sessions you read and how many notes you wrote.`;
|
|
10854
10982
|
}
|
|
10855
10983
|
|
|
10856
10984
|
// src/miner/prompt-core.ts
|
|
@@ -72798,7 +72926,8 @@ async function runMiner(options) {
|
|
|
72798
72926
|
const abort = new AbortController;
|
|
72799
72927
|
const timer = setTimeout(() => abort.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS2);
|
|
72800
72928
|
let notesWritten = 0;
|
|
72801
|
-
let
|
|
72929
|
+
let currentSession;
|
|
72930
|
+
const readsSinceWrite = new Set;
|
|
72802
72931
|
let turns = 0;
|
|
72803
72932
|
const env = buildMinerEnv({
|
|
72804
72933
|
apiKey: options.apiKey,
|
|
@@ -72843,7 +72972,11 @@ async function runMiner(options) {
|
|
|
72843
72972
|
};
|
|
72844
72973
|
}
|
|
72845
72974
|
if (toolName === `mcp__${SESSIONS_SERVER_NAME}__read_session`) {
|
|
72846
|
-
|
|
72975
|
+
const id2 = sessionIdFromReadInput(input2);
|
|
72976
|
+
if (id2) {
|
|
72977
|
+
currentSession = id2;
|
|
72978
|
+
readsSinceWrite.add(id2);
|
|
72979
|
+
}
|
|
72847
72980
|
}
|
|
72848
72981
|
if (toolName === `mcp__${KNOWLEDGE_SERVER_NAME}__write_knowledge`) {
|
|
72849
72982
|
if (notesWritten >= maxNotes) {
|
|
@@ -72852,10 +72985,20 @@ async function runMiner(options) {
|
|
|
72852
72985
|
message: `Note cap reached (${maxNotes} per run); stop writing and summarize.`
|
|
72853
72986
|
};
|
|
72854
72987
|
}
|
|
72988
|
+
if (readsSinceWrite.size > 1) {
|
|
72989
|
+
readsSinceWrite.clear();
|
|
72990
|
+
currentSession = undefined;
|
|
72991
|
+
return {
|
|
72992
|
+
behavior: "deny",
|
|
72993
|
+
message: "Write each session's notes right after reading THAT session, before reading the next. You have read multiple sessions without writing, so a note cannot be attributed to one. Re-read only the session this note is about, then write it."
|
|
72994
|
+
};
|
|
72995
|
+
}
|
|
72855
72996
|
notesWritten += 1;
|
|
72997
|
+
readsSinceWrite.clear();
|
|
72998
|
+
const { transcript_id: _authoredByModel, ...clean } = input2;
|
|
72856
72999
|
return {
|
|
72857
73000
|
behavior: "allow",
|
|
72858
|
-
updatedInput:
|
|
73001
|
+
updatedInput: currentSession ? { ...clean, transcript_id: currentSession } : clean
|
|
72859
73002
|
};
|
|
72860
73003
|
}
|
|
72861
73004
|
return { behavior: "allow", updatedInput: input2 };
|
|
@@ -73376,7 +73519,7 @@ var init_settings = __esm(() => {
|
|
|
73376
73519
|
});
|
|
73377
73520
|
|
|
73378
73521
|
// src/telemetry/debug-id.ts
|
|
73379
|
-
var BUNDLE_DEBUG_ID_PLACEHOLDER = "
|
|
73522
|
+
var BUNDLE_DEBUG_ID_PLACEHOLDER = "971484cf-da0f-e0c4-6475-6e2164756e21";
|
|
73380
73523
|
|
|
73381
73524
|
// src/telemetry/telemetry.ts
|
|
73382
73525
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -82309,6 +82452,19 @@ ${results.length - opts.limit} more results not shown.`));
|
|
|
82309
82452
|
}
|
|
82310
82453
|
console.log(`Wrote ${path3}`);
|
|
82311
82454
|
});
|
|
82455
|
+
cmd.command("backfill-transcripts").description("One-shot: attribute pre-existing notes to the local sessions that produced them, so the report can show their traces").option("--json", "Output the result as JSON").action(async (opts) => {
|
|
82456
|
+
const { runBackfill: runBackfill2 } = await Promise.resolve().then(() => (init_backfill_run(), exports_backfill_run));
|
|
82457
|
+
const result = await runBackfill2();
|
|
82458
|
+
if (opts.json) {
|
|
82459
|
+
printResult(result, opts);
|
|
82460
|
+
return;
|
|
82461
|
+
}
|
|
82462
|
+
if (result.candidates === 0) {
|
|
82463
|
+
console.log("All your notes already have a transcript — nothing to backfill.");
|
|
82464
|
+
return;
|
|
82465
|
+
}
|
|
82466
|
+
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.`);
|
|
82467
|
+
});
|
|
82312
82468
|
cmd.addCommand(hooksCommand());
|
|
82313
82469
|
return cmd;
|
|
82314
82470
|
}
|
|
@@ -84272,4 +84428,4 @@ execute().catch((err) => {
|
|
|
84272
84428
|
process.exit(1);
|
|
84273
84429
|
});
|
|
84274
84430
|
|
|
84275
|
-
//# debugId=
|
|
84431
|
+
//# debugId=971484cf-da0f-e0c4-6475-6e2164756e21
|