@dosu/cli 0.62.1 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/bin/dosu.js +228 -117
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -182,7 +182,8 @@ dosu knowledge incognito enable|disable [claude|cursor|codex] # the /dosu-incog
|
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
The status line shows one of `📚 Dosu studying…`, `👻 Dosu incognito`, `⚪ Dosu paused`,
|
|
185
|
-
`⚪ Dosu not studying this
|
|
185
|
+
`⚪ Dosu not studying this repo`, or `⚪ Dosu off`. Only sessions inside a git repo are studied;
|
|
186
|
+
pick which repos under `dosu` → settings → study scope. Neither setup nor `enable` replaces a status
|
|
186
187
|
line you already have; they print the one-liner to add to your own script instead.
|
|
187
188
|
|
|
188
189
|
Running `/dosu-incognito` inside a session marks that session's transcript so studying skips it
|
package/bin/dosu.js
CHANGED
|
@@ -1083,7 +1083,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
|
|
|
1083
1083
|
function getVersionString() {
|
|
1084
1084
|
return `v${VERSION}`;
|
|
1085
1085
|
}
|
|
1086
|
-
var VERSION = "0.
|
|
1086
|
+
var VERSION = "0.63.0", INSTALL_CHANNEL = "npm";
|
|
1087
1087
|
|
|
1088
1088
|
// src/debug/logger.ts
|
|
1089
1089
|
import {
|
|
@@ -1472,6 +1472,59 @@ var init_agents = __esm(() => {
|
|
|
1472
1472
|
init_formats();
|
|
1473
1473
|
});
|
|
1474
1474
|
|
|
1475
|
+
// src/sessions/repo.ts
|
|
1476
|
+
import { execFileSync } from "node:child_process";
|
|
1477
|
+
function normalizeRepoRemote(remote) {
|
|
1478
|
+
const value = remote.trim();
|
|
1479
|
+
if (!value)
|
|
1480
|
+
return null;
|
|
1481
|
+
let host;
|
|
1482
|
+
let path;
|
|
1483
|
+
const scp = value.includes("://") ? null : /^(?:[^@/]+@)?([^:/]+):(.+)$/.exec(value);
|
|
1484
|
+
if (scp) {
|
|
1485
|
+
host = scp[1];
|
|
1486
|
+
path = scp[2];
|
|
1487
|
+
} else {
|
|
1488
|
+
try {
|
|
1489
|
+
const url = new URL(value);
|
|
1490
|
+
if (url.protocol === "file:")
|
|
1491
|
+
return null;
|
|
1492
|
+
host = url.hostname;
|
|
1493
|
+
path = url.pathname;
|
|
1494
|
+
} catch {
|
|
1495
|
+
return null;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
path = path.replace(/^\/+|\/+$/g, "").replace(/\.git$/, "");
|
|
1499
|
+
if (!host || !path.includes("/"))
|
|
1500
|
+
return null;
|
|
1501
|
+
const lowerHost = host.toLowerCase();
|
|
1502
|
+
return `${lowerHost}/${lowerHost === "github.com" ? path.toLowerCase() : path}`;
|
|
1503
|
+
}
|
|
1504
|
+
function originRepoOfDir(dir) {
|
|
1505
|
+
const env = { ...process.env };
|
|
1506
|
+
for (const name of GIT_LOCATION_ENV)
|
|
1507
|
+
delete env[name];
|
|
1508
|
+
try {
|
|
1509
|
+
const out = execFileSync("git", ["-C", dir, "remote", "get-url", "origin"], {
|
|
1510
|
+
encoding: "utf-8",
|
|
1511
|
+
env,
|
|
1512
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
1513
|
+
timeout: 1000
|
|
1514
|
+
});
|
|
1515
|
+
return normalizeRepoRemote(out);
|
|
1516
|
+
} catch {
|
|
1517
|
+
return null;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
function displayRepo(repo) {
|
|
1521
|
+
return repo.split("/").slice(1).join("/") || repo;
|
|
1522
|
+
}
|
|
1523
|
+
var GIT_LOCATION_ENV;
|
|
1524
|
+
var init_repo = __esm(() => {
|
|
1525
|
+
GIT_LOCATION_ENV = ["GIT_DIR", "GIT_WORK_TREE", "GIT_COMMON_DIR", "GIT_INDEX_FILE"];
|
|
1526
|
+
});
|
|
1527
|
+
|
|
1475
1528
|
// src/sessions/scan.ts
|
|
1476
1529
|
import { existsSync as existsSync6, readdirSync, statSync as statSync2 } from "node:fs";
|
|
1477
1530
|
import { createRequire as createRequire2 } from "node:module";
|
|
@@ -1919,6 +1972,9 @@ import { join as join6 } from "node:path";
|
|
|
1919
1972
|
function syncStatePath(configDir = getConfigDir()) {
|
|
1920
1973
|
return join6(configDir, STATE_FILENAME);
|
|
1921
1974
|
}
|
|
1975
|
+
function stringsOf(values) {
|
|
1976
|
+
return values.filter((v) => typeof v === "string");
|
|
1977
|
+
}
|
|
1922
1978
|
function loadSyncState(configDir = getConfigDir()) {
|
|
1923
1979
|
const empty = {
|
|
1924
1980
|
schema_version: STATE_SCHEMA_VERSION,
|
|
@@ -1954,9 +2010,8 @@ function loadSyncState(configDir = getConfigDir()) {
|
|
|
1954
2010
|
...lastRefusal ? { last_refusal: lastRefusal } : {},
|
|
1955
2011
|
...run ? { run } : {},
|
|
1956
2012
|
...raw.paused === true ? { paused: true } : {},
|
|
1957
|
-
...Array.isArray(raw.
|
|
1958
|
-
|
|
1959
|
-
} : {}
|
|
2013
|
+
...Array.isArray(raw.repo_filter) ? { repo_filter: stringsOf(raw.repo_filter) } : {},
|
|
2014
|
+
...Array.isArray(raw.project_filter) ? { project_filter: stringsOf(raw.project_filter) } : {}
|
|
1960
2015
|
};
|
|
1961
2016
|
} catch {
|
|
1962
2017
|
return empty;
|
|
@@ -1976,6 +2031,7 @@ function resetSyncState(configDir = getConfigDir()) {
|
|
|
1976
2031
|
schema_version: STATE_SCHEMA_VERSION,
|
|
1977
2032
|
watermark: null,
|
|
1978
2033
|
consecutive_failures: 0,
|
|
2034
|
+
...previous.repo_filter ? { repo_filter: previous.repo_filter } : {},
|
|
1979
2035
|
...previous.project_filter ? { project_filter: previous.project_filter } : {},
|
|
1980
2036
|
...previous.paused ? { paused: true } : {}
|
|
1981
2037
|
};
|
|
@@ -2002,17 +2058,31 @@ function isUnderDir(dir, base) {
|
|
|
2002
2058
|
const root = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
2003
2059
|
return dir === root || dir.startsWith(`${root}/`);
|
|
2004
2060
|
}
|
|
2005
|
-
function
|
|
2006
|
-
if (
|
|
2007
|
-
return
|
|
2008
|
-
const
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2061
|
+
function studyRepoFilter(state, listSessions, locator) {
|
|
2062
|
+
if (state.repo_filter)
|
|
2063
|
+
return state.repo_filter;
|
|
2064
|
+
const folders = state.project_filter;
|
|
2065
|
+
if (!folders?.length)
|
|
2066
|
+
return null;
|
|
2067
|
+
const repos = new Set;
|
|
2068
|
+
for (const session of listSessions()) {
|
|
2069
|
+
const dir = locator.resolve(session);
|
|
2070
|
+
if (!dir || !folders.some((base) => isUnderDir(dir, base)))
|
|
2071
|
+
continue;
|
|
2072
|
+
const repo = locator.resolveRepo(session);
|
|
2073
|
+
if (repo)
|
|
2074
|
+
repos.add(repo);
|
|
2075
|
+
}
|
|
2076
|
+
return [...repos].sort();
|
|
2077
|
+
}
|
|
2078
|
+
function filterSessionsByRepo(sessions, filter, resolveRepo) {
|
|
2079
|
+
const kept = [];
|
|
2080
|
+
for (const session of sessions) {
|
|
2081
|
+
const repo = resolveRepo(session);
|
|
2082
|
+
if (repo !== null && (filter === null || filter.includes(repo)))
|
|
2083
|
+
kept.push({ ...session, repo });
|
|
2084
|
+
}
|
|
2085
|
+
return kept;
|
|
2016
2086
|
}
|
|
2017
2087
|
function gateSessions(sessions, watermark, now = new Date, quietPeriodMs = DEFAULT_QUIET_PERIOD_MS) {
|
|
2018
2088
|
const watermarkMs = watermark ? Date.parse(watermark) : Number.NEGATIVE_INFINITY;
|
|
@@ -2031,7 +2101,7 @@ function gateSessions(sessions, watermark, now = new Date, quietPeriodMs = DEFAU
|
|
|
2031
2101
|
}
|
|
2032
2102
|
return { ready, open };
|
|
2033
2103
|
}
|
|
2034
|
-
var STATE_FILENAME = "knowledge-sync.json", STATE_SCHEMA_VERSION = 1, DEFAULT_QUIET_PERIOD_MS, BACKOFF_BASE_MS, BACKOFF_MAX_MS, STUDIED_HISTORY_LIMIT = 500
|
|
2104
|
+
var STATE_FILENAME = "knowledge-sync.json", STATE_SCHEMA_VERSION = 1, DEFAULT_QUIET_PERIOD_MS, BACKOFF_BASE_MS, BACKOFF_MAX_MS, STUDIED_HISTORY_LIMIT = 500;
|
|
2035
2105
|
var init_watermark = __esm(() => {
|
|
2036
2106
|
init_config();
|
|
2037
2107
|
DEFAULT_QUIET_PERIOD_MS = 5 * 60 * 1000;
|
|
@@ -2067,12 +2137,18 @@ function defaultHookEnabled(agentId) {
|
|
|
2067
2137
|
return false;
|
|
2068
2138
|
}
|
|
2069
2139
|
}
|
|
2070
|
-
function cwdIsStudied(cwd,
|
|
2071
|
-
if (!filter || filter.length === 0)
|
|
2072
|
-
return true;
|
|
2140
|
+
function cwdIsStudied(cwd, state, repoOfDir) {
|
|
2073
2141
|
if (!cwd)
|
|
2074
|
-
return
|
|
2075
|
-
|
|
2142
|
+
return false;
|
|
2143
|
+
const repo = repoOfDir(cwd);
|
|
2144
|
+
if (!repo)
|
|
2145
|
+
return false;
|
|
2146
|
+
if (state.repo_filter)
|
|
2147
|
+
return state.repo_filter.includes(repo);
|
|
2148
|
+
if (state.project_filter?.length) {
|
|
2149
|
+
return state.project_filter.some((base) => isUnderDir(cwd, base));
|
|
2150
|
+
}
|
|
2151
|
+
return true;
|
|
2076
2152
|
}
|
|
2077
2153
|
function resolveStatuslineState(payload, agentId, deps = {}) {
|
|
2078
2154
|
const hookEnabled = deps.hookEnabled ?? defaultHookEnabled;
|
|
@@ -2085,7 +2161,7 @@ function resolveStatuslineState(payload, agentId, deps = {}) {
|
|
|
2085
2161
|
const state = (deps.loadState ?? loadSyncState)();
|
|
2086
2162
|
if (state.paused)
|
|
2087
2163
|
return "paused";
|
|
2088
|
-
if (!cwdIsStudied(payload.cwd, state.
|
|
2164
|
+
if (!cwdIsStudied(payload.cwd, state, deps.repoOfDir ?? originRepoOfDir))
|
|
2089
2165
|
return "not-studied";
|
|
2090
2166
|
return "on";
|
|
2091
2167
|
}
|
|
@@ -2099,13 +2175,14 @@ function renderStatusline(raw, agentId, deps = {}) {
|
|
|
2099
2175
|
var STATUSLINE_LABELS;
|
|
2100
2176
|
var init_render = __esm(() => {
|
|
2101
2177
|
init_agents();
|
|
2178
|
+
init_repo();
|
|
2102
2179
|
init_incognito();
|
|
2103
2180
|
init_watermark();
|
|
2104
2181
|
STATUSLINE_LABELS = {
|
|
2105
2182
|
on: "\uD83D\uDCDA Dosu studying…",
|
|
2106
2183
|
incognito: "\uD83D\uDC7B Dosu incognito",
|
|
2107
2184
|
paused: "⚪ Dosu paused",
|
|
2108
|
-
"not-studied": "⚪ Dosu not studying this
|
|
2185
|
+
"not-studied": "⚪ Dosu not studying this repo",
|
|
2109
2186
|
off: "⚪ Dosu off"
|
|
2110
2187
|
};
|
|
2111
2188
|
});
|
|
@@ -9863,7 +9940,7 @@ var init_default_browser_id = __esm(() => {
|
|
|
9863
9940
|
// node_modules/run-applescript/index.js
|
|
9864
9941
|
import process6 from "node:process";
|
|
9865
9942
|
import { promisify as promisify4 } from "node:util";
|
|
9866
|
-
import { execFile as execFile4, execFileSync } from "node:child_process";
|
|
9943
|
+
import { execFile as execFile4, execFileSync as execFileSync2 } from "node:child_process";
|
|
9867
9944
|
async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
|
|
9868
9945
|
if (process6.platform !== "darwin") {
|
|
9869
9946
|
throw new Error("macOS only");
|
|
@@ -12000,20 +12077,39 @@ function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
|
|
|
12000
12077
|
return null;
|
|
12001
12078
|
}
|
|
12002
12079
|
};
|
|
12080
|
+
const repoOfDir = deps.repoOfDir ?? originRepoOfDir;
|
|
12081
|
+
const repoByDir = new Map;
|
|
12082
|
+
const resolve = (session) => {
|
|
12083
|
+
const key = `${session.harness}/${session.id}`;
|
|
12084
|
+
const cached = entries[key];
|
|
12085
|
+
if (cached && (cached.dir !== null || cached.mtime === mtime(session.path))) {
|
|
12086
|
+
return cached.dir;
|
|
12087
|
+
}
|
|
12088
|
+
const dir = compute(session);
|
|
12089
|
+
entries[key] = { dir, mtime: mtime(session.path) };
|
|
12090
|
+
dirty = true;
|
|
12091
|
+
return dir;
|
|
12092
|
+
};
|
|
12003
12093
|
return {
|
|
12004
12094
|
cached(key) {
|
|
12005
12095
|
return entries[key]?.dir ?? null;
|
|
12006
12096
|
},
|
|
12007
|
-
resolve
|
|
12008
|
-
|
|
12009
|
-
const
|
|
12010
|
-
if (
|
|
12011
|
-
return
|
|
12012
|
-
}
|
|
12013
|
-
|
|
12014
|
-
|
|
12097
|
+
resolve,
|
|
12098
|
+
resolveRepo(session) {
|
|
12099
|
+
const dir = resolve(session);
|
|
12100
|
+
if (dir === null)
|
|
12101
|
+
return null;
|
|
12102
|
+
const entry = entries[`${session.harness}/${session.id}`];
|
|
12103
|
+
if (entry.repo !== undefined && (entry.repo !== null || entry.mtime === mtime(session.path))) {
|
|
12104
|
+
return entry.repo;
|
|
12105
|
+
}
|
|
12106
|
+
if (!repoByDir.has(dir))
|
|
12107
|
+
repoByDir.set(dir, repoOfDir(dir));
|
|
12108
|
+
const repo = repoByDir.get(dir) ?? null;
|
|
12109
|
+
entry.repo = repo;
|
|
12110
|
+
entry.mtime = mtime(session.path);
|
|
12015
12111
|
dirty = true;
|
|
12016
|
-
return
|
|
12112
|
+
return repo;
|
|
12017
12113
|
},
|
|
12018
12114
|
flush() {
|
|
12019
12115
|
if (!dirty)
|
|
@@ -12026,6 +12122,7 @@ function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
|
|
|
12026
12122
|
var CACHE_FILENAME2 = "project-dirs.json", CACHE_SCHEMA_VERSION = 1, HEAD_BYTES, HEAD_LINES = 50;
|
|
12027
12123
|
var init_project_dir = __esm(() => {
|
|
12028
12124
|
init_config();
|
|
12125
|
+
init_repo();
|
|
12029
12126
|
HEAD_BYTES = 128 * 1024;
|
|
12030
12127
|
});
|
|
12031
12128
|
|
|
@@ -13309,12 +13406,11 @@ var init_generate = __esm(() => {
|
|
|
13309
13406
|
function listSessionBacklog() {
|
|
13310
13407
|
try {
|
|
13311
13408
|
const state = loadSyncState();
|
|
13312
|
-
|
|
13313
|
-
|
|
13314
|
-
|
|
13315
|
-
|
|
13316
|
-
|
|
13317
|
-
}
|
|
13409
|
+
const scanned = scanAgentSessions({});
|
|
13410
|
+
const resolver = createProjectDirResolver();
|
|
13411
|
+
const filter = studyRepoFilter(state, () => scanned, resolver);
|
|
13412
|
+
const sessions = filterSessionsByRepo(scanned, filter, resolver.resolveRepo);
|
|
13413
|
+
resolver.flush();
|
|
13318
13414
|
const gate = gateSessions(sessions, state.watermark);
|
|
13319
13415
|
const { kept, skipped } = partitionIncognitoSessions(gate.ready);
|
|
13320
13416
|
return { queued: kept.reverse(), open: gate.open.reverse(), incognito: skipped.reverse() };
|
|
@@ -13540,19 +13636,24 @@ async function runKnowledgeSync(options = {}) {
|
|
|
13540
13636
|
since: new Date(now().getTime() - GATE_WINDOW_DAYS * 24 * 60 * 60 * 1000),
|
|
13541
13637
|
limit: GATE_WINDOW
|
|
13542
13638
|
}));
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13639
|
+
const scanned = await listSessions();
|
|
13640
|
+
let flush;
|
|
13641
|
+
let locator = deps.locator;
|
|
13642
|
+
if (!locator) {
|
|
13643
|
+
const resolver = createProjectDirResolver();
|
|
13644
|
+
locator = resolver;
|
|
13645
|
+
flush = resolver.flush;
|
|
13646
|
+
}
|
|
13647
|
+
const repoFilter = studyRepoFilter(state, () => scanAgentSessions({}), locator);
|
|
13648
|
+
if (state.project_filter) {
|
|
13649
|
+
delete state.project_filter;
|
|
13650
|
+
if (repoFilter)
|
|
13651
|
+
state.repo_filter = repoFilter;
|
|
13652
|
+
logger.debug("sync", `folder scope converted to repos: ${repoFilter?.join(", ") || "none"}`);
|
|
13653
|
+
}
|
|
13654
|
+
const sessions = filterSessionsByRepo(scanned, repoFilter, (s) => locator.resolveRepo(s));
|
|
13655
|
+
flush?.();
|
|
13656
|
+
logger.debug("sync", `study scope ${repoFilter ? repoFilter.join(", ") || "none" : "all repos"}: ${sessions.length} of ${scanned.length} sessions in scope`);
|
|
13556
13657
|
({ ready, open } = gateSessions(sessions, state.watermark, now()));
|
|
13557
13658
|
logGateResult(ready, open.length, state.watermark);
|
|
13558
13659
|
} catch (err) {
|
|
@@ -13800,7 +13901,7 @@ var init_conflicts = __esm(() => {
|
|
|
13800
13901
|
});
|
|
13801
13902
|
|
|
13802
13903
|
// src/telemetry/debug-id.ts
|
|
13803
|
-
var BUNDLE_DEBUG_ID_PLACEHOLDER = "
|
|
13904
|
+
var BUNDLE_DEBUG_ID_PLACEHOLDER = "01f74cf6-cdbb-b296-6475-6e2164756e21";
|
|
13804
13905
|
|
|
13805
13906
|
// src/telemetry/telemetry.ts
|
|
13806
13907
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -15477,9 +15578,8 @@ note cap are the volume guards.
|
|
|
15477
15578
|
5. Title is a noun-phrase topic (like "page_version UniqueViolation race"), not a sentence.
|
|
15478
15579
|
Content is a self-contained observation in plain language; include file/path pointers when
|
|
15479
15580
|
useful.
|
|
15480
|
-
6.
|
|
15481
|
-
|
|
15482
|
-
verified, omit both.
|
|
15581
|
+
6. Never pass repo or branch to write_knowledge; the client attaches each note's repo from the
|
|
15582
|
+
session it came from.
|
|
15483
15583
|
7. Never quote credentials, tokens, or secrets — even redacted placeholders — and never include
|
|
15484
15584
|
long verbatim transcript spans. Summarize in your own words.
|
|
15485
15585
|
8. A trivial session with no real user query is normal: skip it silently.`;
|
|
@@ -58494,6 +58594,7 @@ async function runLearner(options) {
|
|
|
58494
58594
|
let currentSession;
|
|
58495
58595
|
const readsSinceWrite = new Set;
|
|
58496
58596
|
const sessionKeys = new Map(options.sessions.map((s) => [s.id, `${s.harness}/${s.id}`]));
|
|
58597
|
+
const sessionRepos = new Map(options.sessions.map((s) => [s.id, s.repo]));
|
|
58497
58598
|
const notedSessions = new Set;
|
|
58498
58599
|
const pendingNotes = new Map;
|
|
58499
58600
|
let turns = 0;
|
|
@@ -58577,10 +58678,20 @@ async function runLearner(options) {
|
|
|
58577
58678
|
const noted = currentSession && sessionKeys.get(currentSession);
|
|
58578
58679
|
if (noted)
|
|
58579
58680
|
pendingNotes.set(toolUseID, noted);
|
|
58580
|
-
const {
|
|
58681
|
+
const {
|
|
58682
|
+
transcript_id: _transcriptByModel,
|
|
58683
|
+
repo: _repoByModel,
|
|
58684
|
+
branch: _branchByModel,
|
|
58685
|
+
...clean
|
|
58686
|
+
} = input;
|
|
58687
|
+
const repo = currentSession && sessionRepos.get(currentSession);
|
|
58581
58688
|
return {
|
|
58582
58689
|
behavior: "allow",
|
|
58583
|
-
updatedInput:
|
|
58690
|
+
updatedInput: {
|
|
58691
|
+
...clean,
|
|
58692
|
+
...currentSession ? { transcript_id: currentSession } : {},
|
|
58693
|
+
...repo ? { repo } : {}
|
|
58694
|
+
}
|
|
58584
58695
|
};
|
|
58585
58696
|
}
|
|
58586
58697
|
return { behavior: "allow", updatedInput: input };
|
|
@@ -58670,7 +58781,6 @@ var init_runner = __esm(() => {
|
|
|
58670
58781
|
|
|
58671
58782
|
// src/commands/knowledge.ts
|
|
58672
58783
|
import { existsSync as existsSync18 } from "node:fs";
|
|
58673
|
-
import { homedir as homedir7 } from "node:os";
|
|
58674
58784
|
import { delimiter as delimiter4, join as join21 } from "node:path";
|
|
58675
58785
|
function requireConfig7() {
|
|
58676
58786
|
const cfg = requireLoginConfig();
|
|
@@ -58938,10 +59048,11 @@ function printSyncStatus(status, now = new Date) {
|
|
|
58938
59048
|
}
|
|
58939
59049
|
const wm = status.state.watermark;
|
|
58940
59050
|
console.log(` Studied through: ${wm ? `${wm} (${formatAge(wm, now)})` : "nothing studied yet"}`);
|
|
58941
|
-
|
|
58942
|
-
|
|
58943
|
-
|
|
58944
|
-
|
|
59051
|
+
const repoFilter = status.state.repo_filter;
|
|
59052
|
+
if (repoFilter) {
|
|
59053
|
+
console.log(` Study scope: ${repoFilter.length ? repoFilter.map(displayRepo).join(", ") : "no repos"}`);
|
|
59054
|
+
} else if (status.state.project_filter?.length) {
|
|
59055
|
+
console.log(` Study scope: ${status.state.project_filter.length} folders (converted to repos on the next sync)`);
|
|
58945
59056
|
}
|
|
58946
59057
|
if ((status.state.total_notes ?? 0) > 0) {
|
|
58947
59058
|
const tokens = status.state.total_learning_tokens ?? 0;
|
|
@@ -59104,6 +59215,7 @@ var init_knowledge = __esm(() => {
|
|
|
59104
59215
|
init_agents();
|
|
59105
59216
|
init_formats();
|
|
59106
59217
|
init_generate();
|
|
59218
|
+
init_repo();
|
|
59107
59219
|
init_backlog();
|
|
59108
59220
|
init_detach();
|
|
59109
59221
|
init_status();
|
|
@@ -60674,7 +60786,7 @@ import {
|
|
|
60674
60786
|
symlinkSync,
|
|
60675
60787
|
writeFileSync as writeFileSync12
|
|
60676
60788
|
} from "node:fs";
|
|
60677
|
-
import { homedir as
|
|
60789
|
+
import { homedir as homedir7 } from "node:os";
|
|
60678
60790
|
import { dirname as dirname10, join as join22, relative as relative3 } from "node:path";
|
|
60679
60791
|
function skillAgentIDsForProviders(providerIDs) {
|
|
60680
60792
|
return [
|
|
@@ -60685,15 +60797,15 @@ function isSkillAgentID(agent) {
|
|
|
60685
60797
|
return SUPPORTED_SKILL_AGENTS.includes(agent);
|
|
60686
60798
|
}
|
|
60687
60799
|
function universalSkillsDir() {
|
|
60688
|
-
return join22(
|
|
60800
|
+
return join22(homedir7(), ".agents", "skills");
|
|
60689
60801
|
}
|
|
60690
60802
|
function linkedSkillsDir(agent) {
|
|
60691
60803
|
if (agent === "claude-code") {
|
|
60692
|
-
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join22(
|
|
60804
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join22(homedir7(), ".claude");
|
|
60693
60805
|
return join22(claudeConfigDir, "skills");
|
|
60694
60806
|
}
|
|
60695
60807
|
if (agent === "windsurf")
|
|
60696
|
-
return join22(
|
|
60808
|
+
return join22(homedir7(), ".codeium", "windsurf", "skills");
|
|
60697
60809
|
return null;
|
|
60698
60810
|
}
|
|
60699
60811
|
function skillInstallTargetForProvider(providerID) {
|
|
@@ -60736,7 +60848,7 @@ function clearSkillInstallState() {
|
|
|
60736
60848
|
rmSync5(installStatePath(), { force: true });
|
|
60737
60849
|
}
|
|
60738
60850
|
function pruneLegacySkillLock() {
|
|
60739
|
-
const lockPath = join22(
|
|
60851
|
+
const lockPath = join22(homedir7(), ".agents", ".skill-lock.json");
|
|
60740
60852
|
try {
|
|
60741
60853
|
if (!existsSync19(lockPath))
|
|
60742
60854
|
return [];
|
|
@@ -62171,15 +62283,15 @@ var init_vscode = __esm(() => {
|
|
|
62171
62283
|
});
|
|
62172
62284
|
|
|
62173
62285
|
// src/mcp/providers/windsurf.ts
|
|
62174
|
-
import { homedir as
|
|
62286
|
+
import { homedir as homedir8 } from "node:os";
|
|
62175
62287
|
import { join as join36 } from "node:path";
|
|
62176
62288
|
var WindsurfProvider = () => createJSONProvider({
|
|
62177
62289
|
providerName: "Windsurf",
|
|
62178
62290
|
providerID: "windsurf",
|
|
62179
62291
|
local: false,
|
|
62180
62292
|
priorityValue: 9,
|
|
62181
|
-
paths: [join36(
|
|
62182
|
-
globalPath: join36(
|
|
62293
|
+
paths: [join36(homedir8(), ".codeium", "windsurf")],
|
|
62294
|
+
globalPath: join36(homedir8(), ".codeium", "windsurf", "mcp_config.json"),
|
|
62183
62295
|
topKey: "mcpServers"
|
|
62184
62296
|
});
|
|
62185
62297
|
var init_windsurf = __esm(() => {
|
|
@@ -62188,14 +62300,14 @@ var init_windsurf = __esm(() => {
|
|
|
62188
62300
|
|
|
62189
62301
|
// src/mcp/providers/zed.ts
|
|
62190
62302
|
import { rmSync as rmSync6 } from "node:fs";
|
|
62191
|
-
import { homedir as
|
|
62303
|
+
import { homedir as homedir9, platform as platform3 } from "node:os";
|
|
62192
62304
|
import { join as join37 } from "node:path";
|
|
62193
62305
|
function zedConfigDir() {
|
|
62194
62306
|
const os = platform3();
|
|
62195
62307
|
if (os === "win32")
|
|
62196
62308
|
return join37(appSupportDir(), "Zed");
|
|
62197
62309
|
if (os === "darwin")
|
|
62198
|
-
return join37(
|
|
62310
|
+
return join37(homedir9(), ".config", "zed");
|
|
62199
62311
|
return join37(appSupportDir(), "zed");
|
|
62200
62312
|
}
|
|
62201
62313
|
function zedDataDir() {
|
|
@@ -62204,7 +62316,7 @@ function zedDataDir() {
|
|
|
62204
62316
|
return join37(appSupportDir(), "Zed");
|
|
62205
62317
|
if (os === "win32")
|
|
62206
62318
|
return join37(process.env.LOCALAPPDATA ?? "", "Zed");
|
|
62207
|
-
return join37(process.env.XDG_DATA_HOME ?? join37(
|
|
62319
|
+
return join37(process.env.XDG_DATA_HOME ?? join37(homedir9(), ".local", "share"), "zed");
|
|
62208
62320
|
}
|
|
62209
62321
|
function legacyDarwinSettingsPath() {
|
|
62210
62322
|
return platform3() === "darwin" ? join37(appSupportDir(), "Zed", "settings.json") : null;
|
|
@@ -62353,7 +62465,7 @@ import {
|
|
|
62353
62465
|
writeFileSync as writeFileSync14,
|
|
62354
62466
|
writeSync
|
|
62355
62467
|
} from "node:fs";
|
|
62356
|
-
import { homedir as
|
|
62468
|
+
import { homedir as homedir10 } from "node:os";
|
|
62357
62469
|
import { join as join38 } from "node:path";
|
|
62358
62470
|
function statePath() {
|
|
62359
62471
|
return join38(getConfigDir(), STATE_FILENAME2);
|
|
@@ -62488,7 +62600,7 @@ function startAutoUpdate(version, options = {}) {
|
|
|
62488
62600
|
return claim === "held" ? "in_progress" : "unavailable";
|
|
62489
62601
|
try {
|
|
62490
62602
|
const child = spawn3(invocation.command, invocation.args, {
|
|
62491
|
-
cwd:
|
|
62603
|
+
cwd: homedir10(),
|
|
62492
62604
|
detached: true,
|
|
62493
62605
|
stdio: "ignore",
|
|
62494
62606
|
windowsHide: true,
|
|
@@ -62889,7 +63001,7 @@ var init_follow = () => {};
|
|
|
62889
63001
|
|
|
62890
63002
|
// src/sessions/session-title.ts
|
|
62891
63003
|
import { existsSync as existsSync26, mkdirSync as mkdirSync16, readFileSync as readFileSync25, renameSync as renameSync6, statSync as statSync10, writeFileSync as writeFileSync17 } from "node:fs";
|
|
62892
|
-
import { homedir as
|
|
63004
|
+
import { homedir as homedir11 } from "node:os";
|
|
62893
63005
|
import { join as join41 } from "node:path";
|
|
62894
63006
|
function cachePath2(configDir) {
|
|
62895
63007
|
return join41(configDir, CACHE_FILENAME5);
|
|
@@ -62944,7 +63056,7 @@ function claudeSummaryFromHead(text) {
|
|
|
62944
63056
|
}
|
|
62945
63057
|
return null;
|
|
62946
63058
|
}
|
|
62947
|
-
function reconstructSession(harness, id, slug, home =
|
|
63059
|
+
function reconstructSession(harness, id, slug, home = homedir11(), exists = existsSync26) {
|
|
62948
63060
|
if (!slug)
|
|
62949
63061
|
return null;
|
|
62950
63062
|
const candidates = [];
|
|
@@ -63620,13 +63732,13 @@ var init_activity_view = __esm(() => {
|
|
|
63620
63732
|
|
|
63621
63733
|
// src/rules/installer.ts
|
|
63622
63734
|
import { existsSync as existsSync28, mkdirSync as mkdirSync17, readFileSync as readFileSync27, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "node:fs";
|
|
63623
|
-
import { homedir as
|
|
63735
|
+
import { homedir as homedir12 } from "node:os";
|
|
63624
63736
|
import { dirname as dirname12, join as join42 } from "node:path";
|
|
63625
63737
|
function claudeConfigDir4() {
|
|
63626
|
-
return process.env.CLAUDE_CONFIG_DIR || join42(
|
|
63738
|
+
return process.env.CLAUDE_CONFIG_DIR || join42(homedir12(), ".claude");
|
|
63627
63739
|
}
|
|
63628
63740
|
function codexHome4() {
|
|
63629
|
-
return process.env.CODEX_HOME || join42(
|
|
63741
|
+
return process.env.CODEX_HOME || join42(homedir12(), ".codex");
|
|
63630
63742
|
}
|
|
63631
63743
|
function isRuleAgent(agent) {
|
|
63632
63744
|
return Object.hasOwn(RULE_TARGETS, agent);
|
|
@@ -63772,7 +63884,7 @@ var init_installer = __esm(() => {
|
|
|
63772
63884
|
},
|
|
63773
63885
|
cursor: {
|
|
63774
63886
|
kind: "file",
|
|
63775
|
-
path: () => join42(
|
|
63887
|
+
path: () => join42(homedir12(), ".cursor", "rules", "dosu.mdc"),
|
|
63776
63888
|
cursorFrontmatter: true
|
|
63777
63889
|
},
|
|
63778
63890
|
codex: {
|
|
@@ -63781,15 +63893,15 @@ var init_installer = __esm(() => {
|
|
|
63781
63893
|
},
|
|
63782
63894
|
opencode: {
|
|
63783
63895
|
kind: "section",
|
|
63784
|
-
path: () => join42(
|
|
63896
|
+
path: () => join42(homedir12(), ".config", "opencode", "AGENTS.md")
|
|
63785
63897
|
},
|
|
63786
63898
|
gemini: {
|
|
63787
63899
|
kind: "section",
|
|
63788
|
-
path: () => join42(
|
|
63900
|
+
path: () => join42(homedir12(), ".gemini", "GEMINI.md")
|
|
63789
63901
|
},
|
|
63790
63902
|
antigravity: {
|
|
63791
63903
|
kind: "section",
|
|
63792
|
-
path: () => join42(
|
|
63904
|
+
path: () => join42(homedir12(), ".gemini", "GEMINI.md")
|
|
63793
63905
|
}
|
|
63794
63906
|
};
|
|
63795
63907
|
});
|
|
@@ -65580,7 +65692,7 @@ var init_flow2 = __esm(() => {
|
|
|
65580
65692
|
// src/commands/upgrade.ts
|
|
65581
65693
|
import { spawnSync } from "node:child_process";
|
|
65582
65694
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
65583
|
-
import { homedir as
|
|
65695
|
+
import { homedir as homedir13 } from "node:os";
|
|
65584
65696
|
import { posix, win32 as win322 } from "node:path";
|
|
65585
65697
|
function isAbsoluteCommandProcessor(value) {
|
|
65586
65698
|
return Boolean(value && win322.isAbsolute(value) && win322.basename(value).toLowerCase() === "cmd.exe");
|
|
@@ -65634,7 +65746,7 @@ function packageRoots(manager, platform, comSpec, env, cwd) {
|
|
|
65634
65746
|
manager === "npm" ? path.join(lines[0], "@dosu", "cli") : path.join(lines[0], "node_modules", "@dosu", "cli")
|
|
65635
65747
|
];
|
|
65636
65748
|
}
|
|
65637
|
-
function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd =
|
|
65749
|
+
function owningPackageManager(entrypoint, platform, comSpec, env = process.env, cwd = homedir13()) {
|
|
65638
65750
|
const path = platform === "win32" ? win322 : posix;
|
|
65639
65751
|
if (!entrypoint || !path.isAbsolute(entrypoint))
|
|
65640
65752
|
return null;
|
|
@@ -65687,7 +65799,7 @@ Or install Dosu globally with your package manager:`);
|
|
|
65687
65799
|
function runUpgrade(channel = INSTALL_CHANNEL, options = {}) {
|
|
65688
65800
|
const platform = options.platform ?? process.platform;
|
|
65689
65801
|
const env = options.env ?? process.env;
|
|
65690
|
-
const cwd = options.cwd ??
|
|
65802
|
+
const cwd = options.cwd ?? homedir13();
|
|
65691
65803
|
let manager = null;
|
|
65692
65804
|
if (channel === "npm") {
|
|
65693
65805
|
if (isNpxInvocation(channel, env)) {
|
|
@@ -65754,7 +65866,7 @@ function finishWithNewBinary(channel, options) {
|
|
|
65754
65866
|
return;
|
|
65755
65867
|
}
|
|
65756
65868
|
const result = spawnSync(invocation.command, invocation.args, {
|
|
65757
|
-
cwd: options.cwd ??
|
|
65869
|
+
cwd: options.cwd ?? homedir13(),
|
|
65758
65870
|
shell: false,
|
|
65759
65871
|
stdio: "inherit"
|
|
65760
65872
|
});
|
|
@@ -66552,7 +66664,6 @@ var init_pages_view = __esm(() => {
|
|
|
66552
66664
|
});
|
|
66553
66665
|
|
|
66554
66666
|
// src/tui/tui.ts
|
|
66555
|
-
import { homedir as homedir15 } from "node:os";
|
|
66556
66667
|
import { basename as basename6 } from "node:path";
|
|
66557
66668
|
async function probeSession(cfg) {
|
|
66558
66669
|
if (!isAuthenticated(cfg) || !isTokenExpired(cfg))
|
|
@@ -66781,8 +66892,9 @@ async function runSettings(cfg) {
|
|
|
66781
66892
|
while (true) {
|
|
66782
66893
|
const target = cfg.active_account?.target;
|
|
66783
66894
|
const library = target?.library_name ?? target?.deployment_name ?? "not configured";
|
|
66784
|
-
const
|
|
66785
|
-
const
|
|
66895
|
+
const sync = loadSyncState();
|
|
66896
|
+
const filter = sync.repo_filter;
|
|
66897
|
+
const scope = !filter ? sync.project_filter?.length ? `${sync.project_filter.length} folders (legacy)` : "all repos" : filter.length === 0 ? "no repos" : filter.length <= 2 ? filter.map(displayRepo).join(", ") : `${filter.length} repos`;
|
|
66786
66898
|
const action = await menuSelect("settings", [
|
|
66787
66899
|
{ label: "switch organization", hint: target?.org_name, value: "switch-org" },
|
|
66788
66900
|
{ label: "switch library", hint: library, value: "switch-library" },
|
|
@@ -66816,45 +66928,43 @@ async function runSettings(cfg) {
|
|
|
66816
66928
|
}
|
|
66817
66929
|
}
|
|
66818
66930
|
}
|
|
66819
|
-
function
|
|
66820
|
-
const home = homedir15();
|
|
66821
|
-
return dir === home ? "~" : dir.startsWith(`${home}/`) ? `~${dir.slice(home.length)}` : dir;
|
|
66822
|
-
}
|
|
66823
|
-
function discoverProjectDirs() {
|
|
66931
|
+
function discoverSessionRepos(current) {
|
|
66824
66932
|
const counts = new Map;
|
|
66825
66933
|
try {
|
|
66826
66934
|
const resolver = createProjectDirResolver();
|
|
66827
66935
|
for (const session of scanAgentSessions({})) {
|
|
66828
|
-
const
|
|
66829
|
-
|
|
66936
|
+
const repo = resolver.resolveRepo(session);
|
|
66937
|
+
if (repo)
|
|
66938
|
+
counts.set(repo, (counts.get(repo) ?? 0) + 1);
|
|
66830
66939
|
}
|
|
66831
66940
|
resolver.flush();
|
|
66832
66941
|
} catch {}
|
|
66833
|
-
|
|
66942
|
+
for (const repo of current ?? [])
|
|
66943
|
+
if (!counts.has(repo))
|
|
66944
|
+
counts.set(repo, 0);
|
|
66945
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([repo]) => repo);
|
|
66834
66946
|
}
|
|
66835
66947
|
async function runStudyingProjectsSetting() {
|
|
66836
|
-
const
|
|
66837
|
-
|
|
66838
|
-
|
|
66948
|
+
const state = loadSyncState();
|
|
66949
|
+
const current = studyRepoFilter(state, () => scanAgentSessions({}), createProjectDirResolver());
|
|
66950
|
+
const repos = discoverSessionRepos(current);
|
|
66951
|
+
if (repos.length === 0) {
|
|
66952
|
+
log2.info("No agent sessions inside a git repo found yet; nothing to scope.");
|
|
66839
66953
|
return;
|
|
66840
66954
|
}
|
|
66841
|
-
const current = loadSyncState().project_filter;
|
|
66842
66955
|
const selected = await multiselect2({
|
|
66843
|
-
message: "Study sessions from which
|
|
66844
|
-
options:
|
|
66845
|
-
|
|
66846
|
-
|
|
66847
|
-
|
|
66848
|
-
initialValues: current?.length ? current : dirs,
|
|
66849
|
-
summary: (picked) => picked.length === dirs.length ? "all folders · new ones included automatically" : `${picked.length} of ${dirs.length} folders · subfolders included`,
|
|
66850
|
-
validate: (picked) => picked.length === 0 ? "Select at least one folder." : undefined
|
|
66956
|
+
message: "Study sessions from which repos?",
|
|
66957
|
+
options: repos.map((repo) => ({ label: displayRepo(repo), hint: repo, value: repo })),
|
|
66958
|
+
initialValues: current ?? repos,
|
|
66959
|
+
summary: (picked) => picked.length === repos.length ? "all repos · new ones included automatically" : `${picked.length} of ${repos.length} repos`,
|
|
66960
|
+
validate: (picked) => picked.length === 0 ? "Select at least one repo." : undefined
|
|
66851
66961
|
});
|
|
66852
66962
|
if (isCancel2(selected))
|
|
66853
66963
|
return;
|
|
66854
|
-
const { project_filter:
|
|
66855
|
-
const all = selected.length ===
|
|
66856
|
-
saveSyncState(all ?
|
|
66857
|
-
const scope = all ? "all
|
|
66964
|
+
const { repo_filter: _repos, project_filter: _folders, ...fresh } = loadSyncState();
|
|
66965
|
+
const all = selected.length === repos.length;
|
|
66966
|
+
saveSyncState(all ? fresh : { ...fresh, repo_filter: [...selected] });
|
|
66967
|
+
const scope = all ? "all repos" : selected.map(displayRepo).join(", ");
|
|
66858
66968
|
log2.success(`Study scope ${dim(`· ${scope}`)}`);
|
|
66859
66969
|
}
|
|
66860
66970
|
async function handleAuthenticate(cfg) {
|
|
@@ -66907,6 +67017,7 @@ var init_tui = __esm(() => {
|
|
|
66907
67017
|
init_providers();
|
|
66908
67018
|
init_generate();
|
|
66909
67019
|
init_project_dir();
|
|
67020
|
+
init_repo();
|
|
66910
67021
|
init_scan();
|
|
66911
67022
|
init_agents_md_step();
|
|
66912
67023
|
init_flow2();
|
|
@@ -68115,4 +68226,4 @@ main().catch((err) => {
|
|
|
68115
68226
|
process.exit(1);
|
|
68116
68227
|
});
|
|
68117
68228
|
|
|
68118
|
-
//# debugId=
|
|
68229
|
+
//# debugId=01f74cf6-cdbb-b296-6475-6e2164756e21
|