@dosu/cli 0.65.1 → 0.66.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 +14 -11
- package/bin/dosu.js +395 -295
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -178,19 +178,22 @@ session. `dosu setup` installs both alongside the hook; they can also be managed
|
|
|
178
178
|
|
|
179
179
|
```bash
|
|
180
180
|
dosu knowledge statusline enable|disable [claude|cursor] # status-bar line in Claude Code / Cursor CLI
|
|
181
|
-
dosu knowledge incognito
|
|
181
|
+
dosu knowledge incognito on|off [claude|cursor|codex] # stop/resume studying an agent's sessions
|
|
182
|
+
dosu knowledge incognito status # which agents are incognito
|
|
182
183
|
```
|
|
183
184
|
|
|
184
|
-
The status line shows one of `📚 Dosu studying
|
|
185
|
-
`⚪ Dosu not studying this repo`, or `⚪ Dosu off`. Every
|
|
186
|
-
studying to picked repos under `dosu` → settings → study
|
|
187
|
-
repo and branch are anchored to that branch; the rest are
|
|
188
|
-
Neither setup nor `enable` replaces a status line you
|
|
189
|
-
to your own script instead.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
185
|
+
The status line shows one of `📚 Dosu studying…` (a sync run is live), `📚 Dosu on`,
|
|
186
|
+
`👻 Dosu incognito`, `⚪ Dosu paused`, `⚪ Dosu not studying this repo`, or `⚪ Dosu off`. Every
|
|
187
|
+
session is studied unless you limit studying to picked repos under `dosu` → settings → study
|
|
188
|
+
scope. Notes from a session with a known repo and branch are anchored to that branch; the rest are
|
|
189
|
+
unanchored and reach topics immediately. Neither setup nor `enable` replaces a status line you
|
|
190
|
+
already have; they print the one-liner to add to your own script instead.
|
|
191
|
+
|
|
192
|
+
`incognito on` is a saved per-agent setting: none of that agent's sessions are studied until you
|
|
193
|
+
turn it off. To keep a single chat out instead, type `/dosu-incognito` in it; setup installs that
|
|
194
|
+
command with the hook. It marks the session's transcript so studying skips it (the whole session,
|
|
195
|
+
and for the rest of it — start a new session to turn Dosu back on) and tells the model not to use
|
|
196
|
+
Dosu tools. See [docs/studying.md](docs/studying.md).
|
|
194
197
|
|
|
195
198
|
### Telemetry and privacy
|
|
196
199
|
|
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.66.0", INSTALL_CHANNEL = "npm";
|
|
1087
1087
|
|
|
1088
1088
|
// src/debug/logger.ts
|
|
1089
1089
|
import {
|
|
@@ -1977,11 +1977,93 @@ var init_incognito = __esm(() => {
|
|
|
1977
1977
|
MAX_SCAN_BYTES = 64 * 1024 * 1024;
|
|
1978
1978
|
});
|
|
1979
1979
|
|
|
1980
|
-
// src/sync/
|
|
1981
|
-
import { existsSync as existsSync7,
|
|
1980
|
+
// src/sync/lock.ts
|
|
1981
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, rmSync, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
1982
1982
|
import { join as join6 } from "node:path";
|
|
1983
|
+
function processAlive(pid) {
|
|
1984
|
+
try {
|
|
1985
|
+
process.kill(pid, 0);
|
|
1986
|
+
return true;
|
|
1987
|
+
} catch (err) {
|
|
1988
|
+
return err.code === "EPERM";
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
function lockPath(configDir = getConfigDir()) {
|
|
1992
|
+
return join6(configDir, LOCK_FILENAME);
|
|
1993
|
+
}
|
|
1994
|
+
function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
|
|
1995
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
1996
|
+
return false;
|
|
1997
|
+
let killed = false;
|
|
1998
|
+
try {
|
|
1999
|
+
kill(-pid, "SIGTERM");
|
|
2000
|
+
killed = true;
|
|
2001
|
+
} catch {
|
|
2002
|
+
try {
|
|
2003
|
+
kill(pid, "SIGTERM");
|
|
2004
|
+
killed = true;
|
|
2005
|
+
} catch {}
|
|
2006
|
+
}
|
|
2007
|
+
try {
|
|
2008
|
+
const path = lockPath(configDir);
|
|
2009
|
+
if (existsSync7(path) && readFileSync6(path, "utf8") === String(pid)) {
|
|
2010
|
+
rmSync(path, { force: true });
|
|
2011
|
+
}
|
|
2012
|
+
} catch {}
|
|
2013
|
+
return killed;
|
|
2014
|
+
}
|
|
2015
|
+
function fileLock(configDir = getConfigDir(), now = () => new Date) {
|
|
2016
|
+
const path = lockPath(configDir);
|
|
2017
|
+
let held = false;
|
|
2018
|
+
const tryCreate = () => {
|
|
2019
|
+
try {
|
|
2020
|
+
writeFileSync3(path, String(process.pid), { flag: "wx" });
|
|
2021
|
+
return true;
|
|
2022
|
+
} catch {
|
|
2023
|
+
return false;
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
2026
|
+
return {
|
|
2027
|
+
acquire() {
|
|
2028
|
+
if (tryCreate()) {
|
|
2029
|
+
held = true;
|
|
2030
|
+
return true;
|
|
2031
|
+
}
|
|
2032
|
+
try {
|
|
2033
|
+
const age = now().getTime() - statSync3(path).mtimeMs;
|
|
2034
|
+
const holder = Number.parseInt(readFileSync6(path, "utf8"), 10);
|
|
2035
|
+
const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
|
|
2036
|
+
if (age > STALE_LOCK_MS || holderDead) {
|
|
2037
|
+
rmSync(path, { force: true });
|
|
2038
|
+
held = tryCreate();
|
|
2039
|
+
return held;
|
|
2040
|
+
}
|
|
2041
|
+
} catch {}
|
|
2042
|
+
return false;
|
|
2043
|
+
},
|
|
2044
|
+
release() {
|
|
2045
|
+
if (!held)
|
|
2046
|
+
return;
|
|
2047
|
+
held = false;
|
|
2048
|
+
try {
|
|
2049
|
+
if (existsSync7(path) && readFileSync6(path, "utf8") === String(process.pid)) {
|
|
2050
|
+
rmSync(path, { force: true });
|
|
2051
|
+
}
|
|
2052
|
+
} catch {}
|
|
2053
|
+
}
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
var LOCK_FILENAME = "knowledge-sync.lock", STALE_LOCK_MS;
|
|
2057
|
+
var init_lock = __esm(() => {
|
|
2058
|
+
init_config();
|
|
2059
|
+
STALE_LOCK_MS = 15 * 60 * 1000;
|
|
2060
|
+
});
|
|
2061
|
+
|
|
2062
|
+
// src/sync/watermark.ts
|
|
2063
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2064
|
+
import { join as join7 } from "node:path";
|
|
1983
2065
|
function syncStatePath(configDir = getConfigDir()) {
|
|
1984
|
-
return
|
|
2066
|
+
return join7(configDir, STATE_FILENAME);
|
|
1985
2067
|
}
|
|
1986
2068
|
function stringsOf(values) {
|
|
1987
2069
|
return values.filter((v) => typeof v === "string");
|
|
@@ -1993,10 +2075,10 @@ function loadSyncState(configDir = getConfigDir()) {
|
|
|
1993
2075
|
consecutive_failures: 0
|
|
1994
2076
|
};
|
|
1995
2077
|
const path = syncStatePath(configDir);
|
|
1996
|
-
if (!
|
|
2078
|
+
if (!existsSync8(path))
|
|
1997
2079
|
return empty;
|
|
1998
2080
|
try {
|
|
1999
|
-
const raw = JSON.parse(
|
|
2081
|
+
const raw = JSON.parse(readFileSync7(path, "utf-8"));
|
|
2000
2082
|
if (raw.schema_version !== STATE_SCHEMA_VERSION)
|
|
2001
2083
|
return empty;
|
|
2002
2084
|
const studiedSessions = Array.isArray(raw.mined_sessions) ? raw.mined_sessions.filter((record) => typeof record === "object" && record !== null && typeof record.at === "string" && typeof record.session === "string").map((record) => ({
|
|
@@ -2021,6 +2103,7 @@ function loadSyncState(configDir = getConfigDir()) {
|
|
|
2021
2103
|
...lastRefusal ? { last_refusal: lastRefusal } : {},
|
|
2022
2104
|
...run ? { run } : {},
|
|
2023
2105
|
...raw.paused === true ? { paused: true } : {},
|
|
2106
|
+
...Array.isArray(raw.incognito_agents) ? { incognito_agents: stringsOf(raw.incognito_agents) } : {},
|
|
2024
2107
|
...Array.isArray(raw.repo_filter) ? { repo_filter: stringsOf(raw.repo_filter) } : {},
|
|
2025
2108
|
...Array.isArray(raw.project_filter) ? { project_filter: stringsOf(raw.project_filter) } : {}
|
|
2026
2109
|
};
|
|
@@ -2036,6 +2119,21 @@ function setSyncPaused(paused, configDir = getConfigDir()) {
|
|
|
2036
2119
|
delete state.paused;
|
|
2037
2120
|
saveSyncState(state, configDir);
|
|
2038
2121
|
}
|
|
2122
|
+
function setAgentsIncognito(agentIds, incognito, configDir = getConfigDir()) {
|
|
2123
|
+
const state = loadSyncState(configDir);
|
|
2124
|
+
const current = new Set(state.incognito_agents ?? []);
|
|
2125
|
+
for (const id of agentIds) {
|
|
2126
|
+
if (incognito)
|
|
2127
|
+
current.add(id);
|
|
2128
|
+
else
|
|
2129
|
+
current.delete(id);
|
|
2130
|
+
}
|
|
2131
|
+
if (current.size > 0)
|
|
2132
|
+
state.incognito_agents = [...current].sort();
|
|
2133
|
+
else
|
|
2134
|
+
delete state.incognito_agents;
|
|
2135
|
+
saveSyncState(state, configDir);
|
|
2136
|
+
}
|
|
2039
2137
|
function resetSyncState(configDir = getConfigDir()) {
|
|
2040
2138
|
const previous = loadSyncState(configDir);
|
|
2041
2139
|
const fresh = {
|
|
@@ -2044,16 +2142,17 @@ function resetSyncState(configDir = getConfigDir()) {
|
|
|
2044
2142
|
consecutive_failures: 0,
|
|
2045
2143
|
...previous.repo_filter ? { repo_filter: previous.repo_filter } : {},
|
|
2046
2144
|
...previous.project_filter ? { project_filter: previous.project_filter } : {},
|
|
2047
|
-
...previous.paused ? { paused: true } : {}
|
|
2145
|
+
...previous.paused ? { paused: true } : {},
|
|
2146
|
+
...previous.incognito_agents ? { incognito_agents: previous.incognito_agents } : {}
|
|
2048
2147
|
};
|
|
2049
2148
|
saveSyncState(fresh, configDir);
|
|
2050
2149
|
}
|
|
2051
2150
|
function saveSyncState(state, configDir = getConfigDir()) {
|
|
2052
|
-
if (!
|
|
2151
|
+
if (!existsSync8(configDir))
|
|
2053
2152
|
mkdirSync4(configDir, { recursive: true, mode: 448 });
|
|
2054
2153
|
const path = syncStatePath(configDir);
|
|
2055
2154
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
2056
|
-
|
|
2155
|
+
writeFileSync4(tmp, JSON.stringify(state, null, 2), { mode: 384 });
|
|
2057
2156
|
renameSync2(tmp, path);
|
|
2058
2157
|
}
|
|
2059
2158
|
function backoffUntil(state) {
|
|
@@ -2123,6 +2222,73 @@ var init_watermark = __esm(() => {
|
|
|
2123
2222
|
BACKOFF_MAX_MS = 24 * 60 * 60 * 1000;
|
|
2124
2223
|
});
|
|
2125
2224
|
|
|
2225
|
+
// src/sync/status.ts
|
|
2226
|
+
import { readFileSync as readFileSync8, statSync as statSync4 } from "node:fs";
|
|
2227
|
+
function formatTokenCount(tokens) {
|
|
2228
|
+
if (tokens < 1000)
|
|
2229
|
+
return String(tokens);
|
|
2230
|
+
if (tokens < 1e6) {
|
|
2231
|
+
const k = tokens / 1000;
|
|
2232
|
+
return `~${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\.0$/, "")}k`;
|
|
2233
|
+
}
|
|
2234
|
+
const m = tokens / 1e6;
|
|
2235
|
+
return `~${m >= 100 ? Math.round(m) : m.toFixed(1).replace(/\.0$/, "")}M`;
|
|
2236
|
+
}
|
|
2237
|
+
function defaultIsProcessAlive(pid) {
|
|
2238
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
2239
|
+
return false;
|
|
2240
|
+
try {
|
|
2241
|
+
process.kill(pid, 0);
|
|
2242
|
+
return true;
|
|
2243
|
+
} catch (err) {
|
|
2244
|
+
return err.code === "EPERM";
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
function defaultReadLog() {
|
|
2248
|
+
try {
|
|
2249
|
+
return readFileSync8(logger.getLogPath(), "utf-8");
|
|
2250
|
+
} catch {
|
|
2251
|
+
return "";
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
function readLockFile(configDir) {
|
|
2255
|
+
const path = lockPath(configDir);
|
|
2256
|
+
try {
|
|
2257
|
+
const pid = Number.parseInt(readFileSync8(path, "utf-8"), 10);
|
|
2258
|
+
return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync4(path).mtime };
|
|
2259
|
+
} catch {
|
|
2260
|
+
return null;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
function recentSyncActivity(log) {
|
|
2264
|
+
return log.split(`
|
|
2265
|
+
`).filter((line) => line.includes("[sync]") || line.includes("[learner]")).slice(-ACTIVITY_LINES).map((line) => line.replace(/ \[(DEBUG|INFO|WARN|ERROR)\]/, ""));
|
|
2266
|
+
}
|
|
2267
|
+
function getSyncStatus(deps = {}) {
|
|
2268
|
+
const configDir = deps.configDir ?? getConfigDir();
|
|
2269
|
+
const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive;
|
|
2270
|
+
const readLog = deps.readLog ?? defaultReadLog;
|
|
2271
|
+
const lock = readLockFile(configDir);
|
|
2272
|
+
const running = lock !== null && isProcessAlive(lock.pid);
|
|
2273
|
+
const state = loadSyncState(configDir);
|
|
2274
|
+
const retryAt = backoffUntil(state);
|
|
2275
|
+
return {
|
|
2276
|
+
running,
|
|
2277
|
+
...lock ? { pid: lock.pid, startedAt: lock.mtime.toISOString() } : {},
|
|
2278
|
+
...lock && !running ? { staleLock: true } : {},
|
|
2279
|
+
state,
|
|
2280
|
+
...retryAt ? { backoffUntil: retryAt.toISOString() } : {},
|
|
2281
|
+
recentActivity: recentSyncActivity(readLog())
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2284
|
+
var ACTIVITY_LINES = 10;
|
|
2285
|
+
var init_status = __esm(() => {
|
|
2286
|
+
init_config();
|
|
2287
|
+
init_logger();
|
|
2288
|
+
init_lock();
|
|
2289
|
+
init_watermark();
|
|
2290
|
+
});
|
|
2291
|
+
|
|
2126
2292
|
// src/statusline/render.ts
|
|
2127
2293
|
function asString(value) {
|
|
2128
2294
|
return typeof value === "string" && value !== "" ? value : undefined;
|
|
@@ -2151,6 +2317,9 @@ function defaultHookEnabled(agentId) {
|
|
|
2151
2317
|
return false;
|
|
2152
2318
|
}
|
|
2153
2319
|
}
|
|
2320
|
+
function defaultSyncRunning() {
|
|
2321
|
+
return getSyncStatus({ readLog: () => "" }).running;
|
|
2322
|
+
}
|
|
2154
2323
|
function cwdIsStudied(cwd, state, repoOfDir) {
|
|
2155
2324
|
if (state.repo_filter) {
|
|
2156
2325
|
const repo = cwd ? repoOfDir(cwd) : null;
|
|
@@ -2165,16 +2334,18 @@ function resolveStatuslineState(payload, agentId, deps = {}) {
|
|
|
2165
2334
|
const hookEnabled = deps.hookEnabled ?? defaultHookEnabled;
|
|
2166
2335
|
if (!hookEnabled(agentId))
|
|
2167
2336
|
return "off";
|
|
2337
|
+
const state = (deps.loadState ?? loadSyncState)();
|
|
2338
|
+
if (state.incognito_agents?.includes(agentId))
|
|
2339
|
+
return "incognito";
|
|
2168
2340
|
const transcriptIsIncognito = deps.transcriptIsIncognito ?? transcriptHasIncognitoMarker;
|
|
2169
2341
|
if (payload.transcript_path && transcriptIsIncognito(payload.transcript_path)) {
|
|
2170
2342
|
return "incognito";
|
|
2171
2343
|
}
|
|
2172
|
-
const state = (deps.loadState ?? loadSyncState)();
|
|
2173
2344
|
if (state.paused)
|
|
2174
2345
|
return "paused";
|
|
2175
2346
|
if (!cwdIsStudied(payload.cwd, state, deps.repoOfDir ?? originRepoOfDir))
|
|
2176
2347
|
return "not-studied";
|
|
2177
|
-
return "on";
|
|
2348
|
+
return (deps.syncRunning ?? defaultSyncRunning)() ? "studying" : "on";
|
|
2178
2349
|
}
|
|
2179
2350
|
function renderStatusline(raw, agentId, deps = {}) {
|
|
2180
2351
|
try {
|
|
@@ -2188,9 +2359,11 @@ var init_render = __esm(() => {
|
|
|
2188
2359
|
init_agents();
|
|
2189
2360
|
init_repo();
|
|
2190
2361
|
init_incognito();
|
|
2362
|
+
init_status();
|
|
2191
2363
|
init_watermark();
|
|
2192
2364
|
STATUSLINE_LABELS = {
|
|
2193
|
-
|
|
2365
|
+
studying: "\uD83D\uDCDA Dosu studying…",
|
|
2366
|
+
on: "\uD83D\uDCDA Dosu on",
|
|
2194
2367
|
incognito: "\uD83D\uDC7B Dosu incognito",
|
|
2195
2368
|
paused: "⚪ Dosu paused",
|
|
2196
2369
|
"not-studied": "⚪ Dosu not studying this repo",
|
|
@@ -4327,16 +4500,16 @@ var init_session_errors = __esm(() => {
|
|
|
4327
4500
|
import { randomUUID } from "node:crypto";
|
|
4328
4501
|
import {
|
|
4329
4502
|
closeSync as closeSync3,
|
|
4330
|
-
existsSync as
|
|
4503
|
+
existsSync as existsSync9,
|
|
4331
4504
|
linkSync,
|
|
4332
4505
|
mkdirSync as mkdirSync5,
|
|
4333
4506
|
openSync as openSync3,
|
|
4334
|
-
readFileSync as
|
|
4335
|
-
statSync as
|
|
4507
|
+
readFileSync as readFileSync9,
|
|
4508
|
+
statSync as statSync5,
|
|
4336
4509
|
unlinkSync,
|
|
4337
|
-
writeFileSync as
|
|
4510
|
+
writeFileSync as writeFileSync5
|
|
4338
4511
|
} from "node:fs";
|
|
4339
|
-
import { join as
|
|
4512
|
+
import { join as join8 } from "node:path";
|
|
4340
4513
|
async function withConfigRefreshLock(task, options = {}) {
|
|
4341
4514
|
const release = await acquireConfigRefreshLock(options);
|
|
4342
4515
|
try {
|
|
@@ -4351,12 +4524,12 @@ async function acquireConfigRefreshLock(options) {
|
|
|
4351
4524
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
4352
4525
|
const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
4353
4526
|
const staleAgeMs = options.staleAgeMs ?? DEFAULT_STALE_AGE_MS;
|
|
4354
|
-
const isProcessAlive = options.isProcessAlive ??
|
|
4527
|
+
const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive2;
|
|
4355
4528
|
const ownerId = options.ownerId ?? randomUUID();
|
|
4356
4529
|
const configDir = getConfigDir();
|
|
4357
|
-
const lockPath =
|
|
4530
|
+
const lockPath = join8(configDir, CONFIG_REFRESH_LOCK_FILENAME);
|
|
4358
4531
|
try {
|
|
4359
|
-
if (!
|
|
4532
|
+
if (!existsSync9(configDir))
|
|
4360
4533
|
mkdirSync5(configDir, { recursive: true, mode: 448 });
|
|
4361
4534
|
} catch (cause) {
|
|
4362
4535
|
throw new SessionPersistenceError({ cause });
|
|
@@ -4385,7 +4558,7 @@ async function acquireConfigRefreshLock(options) {
|
|
|
4385
4558
|
function createLockFile(lockPath, metadata) {
|
|
4386
4559
|
const fd = openSync3(lockPath, "wx", 384);
|
|
4387
4560
|
try {
|
|
4388
|
-
|
|
4561
|
+
writeFileSync5(fd, JSON.stringify(metadata));
|
|
4389
4562
|
} catch (cause) {
|
|
4390
4563
|
try {
|
|
4391
4564
|
closeSync3(fd);
|
|
@@ -4419,12 +4592,12 @@ function claimAndRemoveStaleLock(lockPath, staleAgeMs, now, isProcessAlive, owne
|
|
|
4419
4592
|
if (metadata && Number.isInteger(metadata.pid) && metadata.pid > 0) {
|
|
4420
4593
|
stale = !isProcessAlive(metadata.pid);
|
|
4421
4594
|
} else {
|
|
4422
|
-
stale = now -
|
|
4595
|
+
stale = now - statSync5(claimPath).mtimeMs >= staleAgeMs;
|
|
4423
4596
|
}
|
|
4424
4597
|
if (!stale)
|
|
4425
4598
|
return false;
|
|
4426
|
-
const current =
|
|
4427
|
-
const claimed =
|
|
4599
|
+
const current = statSync5(lockPath);
|
|
4600
|
+
const claimed = statSync5(claimPath);
|
|
4428
4601
|
if (current.dev !== claimed.dev || current.ino !== claimed.ino)
|
|
4429
4602
|
return false;
|
|
4430
4603
|
unlinkSync(lockPath);
|
|
@@ -4439,7 +4612,7 @@ function claimAndRemoveStaleLock(lockPath, staleAgeMs, now, isProcessAlive, owne
|
|
|
4439
4612
|
}
|
|
4440
4613
|
function readLockMetadata(lockPath) {
|
|
4441
4614
|
try {
|
|
4442
|
-
const parsed = JSON.parse(
|
|
4615
|
+
const parsed = JSON.parse(readFileSync9(lockPath, "utf8"));
|
|
4443
4616
|
if (!isRecord3(parsed))
|
|
4444
4617
|
return;
|
|
4445
4618
|
if (typeof parsed.owner_id !== "string" || typeof parsed.pid !== "number" || typeof parsed.created_at !== "number") {
|
|
@@ -4454,7 +4627,7 @@ function readLockMetadata(lockPath) {
|
|
|
4454
4627
|
return;
|
|
4455
4628
|
}
|
|
4456
4629
|
}
|
|
4457
|
-
function
|
|
4630
|
+
function defaultIsProcessAlive2(pid) {
|
|
4458
4631
|
try {
|
|
4459
4632
|
process.kill(pid, 0);
|
|
4460
4633
|
return true;
|
|
@@ -10814,17 +10987,17 @@ var init_github_step = __esm(() => {
|
|
|
10814
10987
|
});
|
|
10815
10988
|
|
|
10816
10989
|
// src/version/pending-tasks-check.ts
|
|
10817
|
-
import { existsSync as
|
|
10818
|
-
import { join as
|
|
10990
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10991
|
+
import { join as join9 } from "node:path";
|
|
10819
10992
|
function getCachePath() {
|
|
10820
|
-
return
|
|
10993
|
+
return join9(getConfigDir(), CACHE_FILENAME);
|
|
10821
10994
|
}
|
|
10822
10995
|
function readPendingTasks() {
|
|
10823
10996
|
try {
|
|
10824
10997
|
const path = getCachePath();
|
|
10825
|
-
if (!
|
|
10998
|
+
if (!existsSync10(path))
|
|
10826
10999
|
return { tasks: [] };
|
|
10827
|
-
const data = JSON.parse(
|
|
11000
|
+
const data = JSON.parse(readFileSync10(path, "utf-8"));
|
|
10828
11001
|
if (Array.isArray(data?.tasks)) {
|
|
10829
11002
|
return { tasks: data.tasks };
|
|
10830
11003
|
}
|
|
@@ -10836,10 +11009,10 @@ function readPendingTasks() {
|
|
|
10836
11009
|
function writePendingTasks(cache) {
|
|
10837
11010
|
try {
|
|
10838
11011
|
const dir = getConfigDir();
|
|
10839
|
-
if (!
|
|
11012
|
+
if (!existsSync10(dir)) {
|
|
10840
11013
|
mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
10841
11014
|
}
|
|
10842
|
-
|
|
11015
|
+
writeFileSync6(getCachePath(), JSON.stringify(cache), { mode: 384 });
|
|
10843
11016
|
} catch {}
|
|
10844
11017
|
}
|
|
10845
11018
|
function addPendingTask(task) {
|
|
@@ -10946,8 +11119,8 @@ var init_pending_tasks_check = __esm(() => {
|
|
|
10946
11119
|
});
|
|
10947
11120
|
|
|
10948
11121
|
// src/commands/audit.ts
|
|
10949
|
-
import { existsSync as
|
|
10950
|
-
import { dirname as dirname3, join as
|
|
11122
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
11123
|
+
import { dirname as dirname3, join as join10 } from "node:path";
|
|
10951
11124
|
function requireConfig3() {
|
|
10952
11125
|
const cfg = requireLoginConfig();
|
|
10953
11126
|
if (!cfg.active_account?.target?.api_key) {
|
|
@@ -11084,12 +11257,12 @@ function loadFindings(findingsPath) {
|
|
|
11084
11257
|
console.error(import_picocolors14.default.red("Run the Dosu audit in your coding agent first (it writes .dosu/audit.json)."));
|
|
11085
11258
|
process.exit(1);
|
|
11086
11259
|
};
|
|
11087
|
-
if (!
|
|
11260
|
+
if (!existsSync11(findingsPath)) {
|
|
11088
11261
|
fail();
|
|
11089
11262
|
}
|
|
11090
11263
|
let parsed;
|
|
11091
11264
|
try {
|
|
11092
|
-
parsed = JSON.parse(
|
|
11265
|
+
parsed = JSON.parse(readFileSync11(findingsPath, "utf-8"));
|
|
11093
11266
|
} catch {
|
|
11094
11267
|
fail();
|
|
11095
11268
|
}
|
|
@@ -11099,25 +11272,25 @@ function loadFindings(findingsPath) {
|
|
|
11099
11272
|
return parsed;
|
|
11100
11273
|
}
|
|
11101
11274
|
function cleanupFindings(findingsPath, cwd = process.cwd()) {
|
|
11102
|
-
const gitignorePath =
|
|
11275
|
+
const gitignorePath = join10(cwd, ".gitignore");
|
|
11103
11276
|
try {
|
|
11104
|
-
const content =
|
|
11277
|
+
const content = existsSync11(gitignorePath) ? readFileSync11(gitignorePath, "utf-8") : "";
|
|
11105
11278
|
const hasEntry = content.split(/\r?\n/).some((line) => /^\.dosu\/?$/.test(line.trim()));
|
|
11106
11279
|
if (!hasEntry) {
|
|
11107
11280
|
const sep = content === "" || content.endsWith(`
|
|
11108
11281
|
`) ? "" : `
|
|
11109
11282
|
`;
|
|
11110
|
-
|
|
11283
|
+
writeFileSync7(gitignorePath, `${content}${sep}.dosu/
|
|
11111
11284
|
`);
|
|
11112
11285
|
}
|
|
11113
11286
|
} catch (err) {
|
|
11114
11287
|
logger.warn("audit", `could not update .gitignore: ${errText(err)}`);
|
|
11115
11288
|
}
|
|
11116
|
-
const defaultDir =
|
|
11289
|
+
const defaultDir = join10(cwd, ".dosu");
|
|
11117
11290
|
if (dirname3(findingsPath) !== defaultDir)
|
|
11118
11291
|
return;
|
|
11119
11292
|
try {
|
|
11120
|
-
|
|
11293
|
+
rmSync2(defaultDir, { recursive: true, force: true });
|
|
11121
11294
|
} catch (err) {
|
|
11122
11295
|
logger.warn("audit", `could not remove ${defaultDir}: ${errText(err)}`);
|
|
11123
11296
|
}
|
|
@@ -11156,7 +11329,7 @@ function auditCommand() {
|
|
|
11156
11329
|
const nonInteractive = Boolean(opts.tasks);
|
|
11157
11330
|
const client = createTypedClient(cfg);
|
|
11158
11331
|
const dataSourceId = await ensureSyncedRepo(cfg, client, detected, opts.dataSourceId, nonInteractive);
|
|
11159
|
-
const findingsPath = opts.findings ??
|
|
11332
|
+
const findingsPath = opts.findings ?? join10(process.cwd(), ".dosu", "audit.json");
|
|
11160
11333
|
const findings = loadFindings(findingsPath);
|
|
11161
11334
|
if (!opts.dataSourceId && findings.repo?.slug && findings.repo.slug !== detected.slug) {
|
|
11162
11335
|
console.error(import_picocolors14.default.red(`Audit was run on ${findings.repo.slug}, but the current repo is ${detected.slug}. ` + `Run 'dosu audit' from ${findings.repo.slug} so the PR targets the audited repo.`));
|
|
@@ -11427,7 +11600,7 @@ var init_doc_import = __esm(() => {
|
|
|
11427
11600
|
});
|
|
11428
11601
|
|
|
11429
11602
|
// src/commands/docs.ts
|
|
11430
|
-
import { readFileSync as
|
|
11603
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
11431
11604
|
import { resolve } from "node:path";
|
|
11432
11605
|
function requireConfig5() {
|
|
11433
11606
|
const cfg = requireLoginConfig();
|
|
@@ -11452,7 +11625,7 @@ function readBody(opts) {
|
|
|
11452
11625
|
return opts.body;
|
|
11453
11626
|
const path = opts.bodyFile;
|
|
11454
11627
|
try {
|
|
11455
|
-
return
|
|
11628
|
+
return readFileSync12(path, "utf-8");
|
|
11456
11629
|
} catch (err) {
|
|
11457
11630
|
const code = err.code;
|
|
11458
11631
|
if (code === "ENOENT") {
|
|
@@ -12149,21 +12322,21 @@ var init_branch = __esm(() => {
|
|
|
12149
12322
|
});
|
|
12150
12323
|
|
|
12151
12324
|
// src/sessions/capture.ts
|
|
12152
|
-
import { existsSync as
|
|
12153
|
-
import { basename as basename2, join as
|
|
12325
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync13, renameSync as renameSync3, writeFileSync as writeFileSync8 } from "node:fs";
|
|
12326
|
+
import { basename as basename2, join as join11 } from "node:path";
|
|
12154
12327
|
function capturePath(configDir, key) {
|
|
12155
12328
|
const [harness, id, ...rest] = key.split("/");
|
|
12156
12329
|
if (rest.length > 0 || !SAFE_SEGMENT.test(harness ?? "") || !SAFE_SEGMENT.test(id ?? "")) {
|
|
12157
12330
|
return null;
|
|
12158
12331
|
}
|
|
12159
|
-
return
|
|
12332
|
+
return join11(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
|
|
12160
12333
|
}
|
|
12161
12334
|
function readCapturedSession(key, configDir = getConfigDir()) {
|
|
12162
12335
|
const path = capturePath(configDir, key);
|
|
12163
12336
|
if (!path)
|
|
12164
12337
|
return null;
|
|
12165
12338
|
try {
|
|
12166
|
-
const raw = JSON.parse(
|
|
12339
|
+
const raw = JSON.parse(readFileSync13(path, "utf-8"));
|
|
12167
12340
|
return {
|
|
12168
12341
|
...typeof raw.dir === "string" ? { dir: raw.dir } : {},
|
|
12169
12342
|
...typeof raw.branch === "string" ? { branch: raw.branch } : {},
|
|
@@ -12186,11 +12359,11 @@ function recordCapturedSession(key, update, configDir = getConfigDir(), now = ne
|
|
|
12186
12359
|
at: now.toISOString()
|
|
12187
12360
|
};
|
|
12188
12361
|
try {
|
|
12189
|
-
const parent =
|
|
12190
|
-
if (!
|
|
12362
|
+
const parent = join11(path, "..");
|
|
12363
|
+
if (!existsSync12(parent))
|
|
12191
12364
|
mkdirSync7(parent, { recursive: true, mode: 448 });
|
|
12192
12365
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
12193
|
-
|
|
12366
|
+
writeFileSync8(tmp, JSON.stringify(record), { mode: 384 });
|
|
12194
12367
|
renameSync3(tmp, path);
|
|
12195
12368
|
return true;
|
|
12196
12369
|
} catch (err) {
|
|
@@ -12271,22 +12444,22 @@ var init_capture = __esm(() => {
|
|
|
12271
12444
|
// src/sessions/project-dir.ts
|
|
12272
12445
|
import {
|
|
12273
12446
|
closeSync as closeSync4,
|
|
12274
|
-
existsSync as
|
|
12447
|
+
existsSync as existsSync13,
|
|
12275
12448
|
mkdirSync as mkdirSync8,
|
|
12276
12449
|
openSync as openSync4,
|
|
12277
|
-
readFileSync as
|
|
12450
|
+
readFileSync as readFileSync14,
|
|
12278
12451
|
readSync as readSync3,
|
|
12279
12452
|
renameSync as renameSync4,
|
|
12280
|
-
statSync as
|
|
12281
|
-
writeFileSync as
|
|
12453
|
+
statSync as statSync6,
|
|
12454
|
+
writeFileSync as writeFileSync9
|
|
12282
12455
|
} from "node:fs";
|
|
12283
|
-
import { join as
|
|
12456
|
+
import { join as join12 } from "node:path";
|
|
12284
12457
|
function cachePath(configDir) {
|
|
12285
|
-
return
|
|
12458
|
+
return join12(configDir, CACHE_FILENAME2);
|
|
12286
12459
|
}
|
|
12287
12460
|
function loadCacheFile(configDir) {
|
|
12288
12461
|
try {
|
|
12289
|
-
const raw = JSON.parse(
|
|
12462
|
+
const raw = JSON.parse(readFileSync14(cachePath(configDir), "utf-8"));
|
|
12290
12463
|
if (raw.schema_version !== CACHE_SCHEMA_VERSION || typeof raw.entries !== "object")
|
|
12291
12464
|
return {};
|
|
12292
12465
|
return raw.entries;
|
|
@@ -12296,12 +12469,12 @@ function loadCacheFile(configDir) {
|
|
|
12296
12469
|
}
|
|
12297
12470
|
function saveCacheFile(configDir, entries) {
|
|
12298
12471
|
try {
|
|
12299
|
-
if (!
|
|
12472
|
+
if (!existsSync13(configDir))
|
|
12300
12473
|
mkdirSync8(configDir, { recursive: true, mode: 448 });
|
|
12301
12474
|
const path = cachePath(configDir);
|
|
12302
12475
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
12303
12476
|
const file = { schema_version: CACHE_SCHEMA_VERSION, entries };
|
|
12304
|
-
|
|
12477
|
+
writeFileSync9(tmp, JSON.stringify(file), { mode: 384 });
|
|
12305
12478
|
renameSync4(tmp, path);
|
|
12306
12479
|
} catch {}
|
|
12307
12480
|
}
|
|
@@ -12336,7 +12509,7 @@ function cwdFromJsonlHead(text) {
|
|
|
12336
12509
|
}
|
|
12337
12510
|
return null;
|
|
12338
12511
|
}
|
|
12339
|
-
function unmungeSlug(slug, exists =
|
|
12512
|
+
function unmungeSlug(slug, exists = existsSync13) {
|
|
12340
12513
|
const tokens = slug.replace(/^-/, "").split("-");
|
|
12341
12514
|
if (tokens.length === 0 || tokens[0] === "")
|
|
12342
12515
|
return null;
|
|
@@ -12355,20 +12528,20 @@ function unmungeSlug(slug, exists = existsSync12) {
|
|
|
12355
12528
|
}
|
|
12356
12529
|
function readWholeFile(path) {
|
|
12357
12530
|
try {
|
|
12358
|
-
return
|
|
12531
|
+
return readFileSync14(path, "utf-8");
|
|
12359
12532
|
} catch {
|
|
12360
12533
|
return null;
|
|
12361
12534
|
}
|
|
12362
12535
|
}
|
|
12363
12536
|
function fileMtime(path) {
|
|
12364
12537
|
try {
|
|
12365
|
-
return
|
|
12538
|
+
return statSync6(path).mtime.toISOString();
|
|
12366
12539
|
} catch {
|
|
12367
12540
|
return "";
|
|
12368
12541
|
}
|
|
12369
12542
|
}
|
|
12370
12543
|
function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
|
|
12371
|
-
const exists = deps.exists ??
|
|
12544
|
+
const exists = deps.exists ?? existsSync13;
|
|
12372
12545
|
const head = deps.readHead ?? readHead;
|
|
12373
12546
|
const mtime = deps.mtime ?? fileMtime;
|
|
12374
12547
|
const captured = deps.captured ?? ((key) => readCapturedSession(key, configDir));
|
|
@@ -13219,7 +13392,7 @@ var init_queries = __esm(() => {
|
|
|
13219
13392
|
});
|
|
13220
13393
|
|
|
13221
13394
|
// src/report/digest.ts
|
|
13222
|
-
import { readFileSync as
|
|
13395
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
13223
13396
|
function asRecord2(value) {
|
|
13224
13397
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
13225
13398
|
}
|
|
@@ -13450,11 +13623,11 @@ function sessionToDigest(session) {
|
|
|
13450
13623
|
try {
|
|
13451
13624
|
switch (session.harness) {
|
|
13452
13625
|
case "claude":
|
|
13453
|
-
return { turns: digestClaude(
|
|
13626
|
+
return { turns: digestClaude(readFileSync15(session.path, "utf8")) };
|
|
13454
13627
|
case "cursor":
|
|
13455
|
-
return { turns: digestCursor(
|
|
13628
|
+
return { turns: digestCursor(readFileSync15(session.path, "utf8")) };
|
|
13456
13629
|
case "codex":
|
|
13457
|
-
return { turns: digestCodex(
|
|
13630
|
+
return { turns: digestCodex(readFileSync15(session.path, "utf8")) };
|
|
13458
13631
|
case "opencode": {
|
|
13459
13632
|
const turns = readSessionTurns(session).map((turn, index) => ({
|
|
13460
13633
|
role: turn.role,
|
|
@@ -13675,17 +13848,17 @@ var init_notes = __esm(() => {
|
|
|
13675
13848
|
});
|
|
13676
13849
|
|
|
13677
13850
|
// src/report/write.ts
|
|
13678
|
-
import { mkdirSync as mkdirSync9, writeFileSync as
|
|
13851
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "node:fs";
|
|
13679
13852
|
import { tmpdir } from "node:os";
|
|
13680
|
-
import { dirname as dirname4, join as
|
|
13853
|
+
import { dirname as dirname4, join as join13, resolve as resolve2 } from "node:path";
|
|
13681
13854
|
import { pathToFileURL } from "node:url";
|
|
13682
13855
|
function defaultReportPath() {
|
|
13683
|
-
return
|
|
13856
|
+
return join13(tmpdir(), "dosu-knowledge-report.html");
|
|
13684
13857
|
}
|
|
13685
13858
|
async function writeAndOpenReport(options) {
|
|
13686
13859
|
const out = resolve2(options.out ?? defaultReportPath());
|
|
13687
13860
|
mkdirSync9(dirname4(out), { recursive: true });
|
|
13688
|
-
|
|
13861
|
+
writeFileSync10(out, options.html, "utf8");
|
|
13689
13862
|
if (options.open !== false) {
|
|
13690
13863
|
const url = pathToFileURL(out).href;
|
|
13691
13864
|
if (options.openUrl) {
|
|
@@ -13768,7 +13941,8 @@ function listSessionBacklog() {
|
|
|
13768
13941
|
const sessions = filterSessionsByRepo(scanned, filter, resolver.resolveRepo);
|
|
13769
13942
|
resolver.flush();
|
|
13770
13943
|
const gate = gateSessions(sessions, state.watermark);
|
|
13771
|
-
const
|
|
13944
|
+
const incognitoAgents = new Set(state.incognito_agents ?? []);
|
|
13945
|
+
const { kept, skipped } = partitionIncognitoSessions(gate.ready, (session) => incognitoAgents.has(session.harness) || isIncognitoSession(session));
|
|
13772
13946
|
return { queued: kept.reverse(), open: gate.open.reverse(), incognito: skipped.reverse() };
|
|
13773
13947
|
} catch {
|
|
13774
13948
|
return { queued: [], open: [], incognito: [] };
|
|
@@ -13781,155 +13955,6 @@ var init_backlog = __esm(() => {
|
|
|
13781
13955
|
init_watermark();
|
|
13782
13956
|
});
|
|
13783
13957
|
|
|
13784
|
-
// src/sync/lock.ts
|
|
13785
|
-
import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
|
|
13786
|
-
import { join as join13 } from "node:path";
|
|
13787
|
-
function processAlive(pid) {
|
|
13788
|
-
try {
|
|
13789
|
-
process.kill(pid, 0);
|
|
13790
|
-
return true;
|
|
13791
|
-
} catch (err) {
|
|
13792
|
-
return err.code === "EPERM";
|
|
13793
|
-
}
|
|
13794
|
-
}
|
|
13795
|
-
function lockPath(configDir = getConfigDir()) {
|
|
13796
|
-
return join13(configDir, LOCK_FILENAME);
|
|
13797
|
-
}
|
|
13798
|
-
function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
|
|
13799
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
13800
|
-
return false;
|
|
13801
|
-
let killed = false;
|
|
13802
|
-
try {
|
|
13803
|
-
kill(-pid, "SIGTERM");
|
|
13804
|
-
killed = true;
|
|
13805
|
-
} catch {
|
|
13806
|
-
try {
|
|
13807
|
-
kill(pid, "SIGTERM");
|
|
13808
|
-
killed = true;
|
|
13809
|
-
} catch {}
|
|
13810
|
-
}
|
|
13811
|
-
try {
|
|
13812
|
-
const path = lockPath(configDir);
|
|
13813
|
-
if (existsSync13(path) && readFileSync14(path, "utf8") === String(pid)) {
|
|
13814
|
-
rmSync2(path, { force: true });
|
|
13815
|
-
}
|
|
13816
|
-
} catch {}
|
|
13817
|
-
return killed;
|
|
13818
|
-
}
|
|
13819
|
-
function fileLock(configDir = getConfigDir(), now = () => new Date) {
|
|
13820
|
-
const path = lockPath(configDir);
|
|
13821
|
-
let held = false;
|
|
13822
|
-
const tryCreate = () => {
|
|
13823
|
-
try {
|
|
13824
|
-
writeFileSync10(path, String(process.pid), { flag: "wx" });
|
|
13825
|
-
return true;
|
|
13826
|
-
} catch {
|
|
13827
|
-
return false;
|
|
13828
|
-
}
|
|
13829
|
-
};
|
|
13830
|
-
return {
|
|
13831
|
-
acquire() {
|
|
13832
|
-
if (tryCreate()) {
|
|
13833
|
-
held = true;
|
|
13834
|
-
return true;
|
|
13835
|
-
}
|
|
13836
|
-
try {
|
|
13837
|
-
const age = now().getTime() - statSync5(path).mtimeMs;
|
|
13838
|
-
const holder = Number.parseInt(readFileSync14(path, "utf8"), 10);
|
|
13839
|
-
const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
|
|
13840
|
-
if (age > STALE_LOCK_MS || holderDead) {
|
|
13841
|
-
rmSync2(path, { force: true });
|
|
13842
|
-
held = tryCreate();
|
|
13843
|
-
return held;
|
|
13844
|
-
}
|
|
13845
|
-
} catch {}
|
|
13846
|
-
return false;
|
|
13847
|
-
},
|
|
13848
|
-
release() {
|
|
13849
|
-
if (!held)
|
|
13850
|
-
return;
|
|
13851
|
-
held = false;
|
|
13852
|
-
try {
|
|
13853
|
-
if (existsSync13(path) && readFileSync14(path, "utf8") === String(process.pid)) {
|
|
13854
|
-
rmSync2(path, { force: true });
|
|
13855
|
-
}
|
|
13856
|
-
} catch {}
|
|
13857
|
-
}
|
|
13858
|
-
};
|
|
13859
|
-
}
|
|
13860
|
-
var LOCK_FILENAME = "knowledge-sync.lock", STALE_LOCK_MS;
|
|
13861
|
-
var init_lock = __esm(() => {
|
|
13862
|
-
init_config();
|
|
13863
|
-
STALE_LOCK_MS = 15 * 60 * 1000;
|
|
13864
|
-
});
|
|
13865
|
-
|
|
13866
|
-
// src/sync/status.ts
|
|
13867
|
-
import { readFileSync as readFileSync15, statSync as statSync6 } from "node:fs";
|
|
13868
|
-
function formatTokenCount(tokens) {
|
|
13869
|
-
if (tokens < 1000)
|
|
13870
|
-
return String(tokens);
|
|
13871
|
-
if (tokens < 1e6) {
|
|
13872
|
-
const k = tokens / 1000;
|
|
13873
|
-
return `~${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\.0$/, "")}k`;
|
|
13874
|
-
}
|
|
13875
|
-
const m = tokens / 1e6;
|
|
13876
|
-
return `~${m >= 100 ? Math.round(m) : m.toFixed(1).replace(/\.0$/, "")}M`;
|
|
13877
|
-
}
|
|
13878
|
-
function defaultIsProcessAlive2(pid) {
|
|
13879
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
13880
|
-
return false;
|
|
13881
|
-
try {
|
|
13882
|
-
process.kill(pid, 0);
|
|
13883
|
-
return true;
|
|
13884
|
-
} catch (err) {
|
|
13885
|
-
return err.code === "EPERM";
|
|
13886
|
-
}
|
|
13887
|
-
}
|
|
13888
|
-
function defaultReadLog() {
|
|
13889
|
-
try {
|
|
13890
|
-
return readFileSync15(logger.getLogPath(), "utf-8");
|
|
13891
|
-
} catch {
|
|
13892
|
-
return "";
|
|
13893
|
-
}
|
|
13894
|
-
}
|
|
13895
|
-
function readLockFile(configDir) {
|
|
13896
|
-
const path = lockPath(configDir);
|
|
13897
|
-
try {
|
|
13898
|
-
const pid = Number.parseInt(readFileSync15(path, "utf-8"), 10);
|
|
13899
|
-
return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync6(path).mtime };
|
|
13900
|
-
} catch {
|
|
13901
|
-
return null;
|
|
13902
|
-
}
|
|
13903
|
-
}
|
|
13904
|
-
function recentSyncActivity(log) {
|
|
13905
|
-
return log.split(`
|
|
13906
|
-
`).filter((line) => line.includes("[sync]") || line.includes("[learner]")).slice(-ACTIVITY_LINES).map((line) => line.replace(/ \[(DEBUG|INFO|WARN|ERROR)\]/, ""));
|
|
13907
|
-
}
|
|
13908
|
-
function getSyncStatus(deps = {}) {
|
|
13909
|
-
const configDir = deps.configDir ?? getConfigDir();
|
|
13910
|
-
const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive2;
|
|
13911
|
-
const readLog = deps.readLog ?? defaultReadLog;
|
|
13912
|
-
const lock = readLockFile(configDir);
|
|
13913
|
-
const running = lock !== null && isProcessAlive(lock.pid);
|
|
13914
|
-
const state = loadSyncState(configDir);
|
|
13915
|
-
const retryAt = backoffUntil(state);
|
|
13916
|
-
return {
|
|
13917
|
-
running,
|
|
13918
|
-
...lock ? { pid: lock.pid, startedAt: lock.mtime.toISOString() } : {},
|
|
13919
|
-
...lock && !running ? { staleLock: true } : {},
|
|
13920
|
-
state,
|
|
13921
|
-
...retryAt ? { backoffUntil: retryAt.toISOString() } : {},
|
|
13922
|
-
recentActivity: recentSyncActivity(readLog())
|
|
13923
|
-
};
|
|
13924
|
-
}
|
|
13925
|
-
var ACTIVITY_LINES = 10;
|
|
13926
|
-
var init_status = __esm(() => {
|
|
13927
|
-
init_config();
|
|
13928
|
-
init_logger();
|
|
13929
|
-
init_lock();
|
|
13930
|
-
init_watermark();
|
|
13931
|
-
});
|
|
13932
|
-
|
|
13933
13958
|
// src/sync/sync.ts
|
|
13934
13959
|
function logGateResult(ready, inFlight, watermark) {
|
|
13935
13960
|
const preview = ready.slice(0, LOG_PREVIEW_LIMIT).map((s) => `${s.harness}/${s.id}`).join(", ");
|
|
@@ -14055,7 +14080,9 @@ async function runKnowledgeSync(options = {}) {
|
|
|
14055
14080
|
};
|
|
14056
14081
|
}
|
|
14057
14082
|
const worthStudying = deps.worthStudying ?? isWorthStudying;
|
|
14058
|
-
const
|
|
14083
|
+
const isIncognitoChat = deps.isIncognito ?? isIncognitoSession;
|
|
14084
|
+
const incognitoAgents = new Set(state.incognito_agents ?? []);
|
|
14085
|
+
const isIncognito = (session) => incognitoAgents.has(session.harness) || isIncognitoChat(session);
|
|
14059
14086
|
const studiedSnapshot = lastStudiedSnapshot(state.mined_sessions);
|
|
14060
14087
|
const examined = [];
|
|
14061
14088
|
const batch = [];
|
|
@@ -14262,7 +14289,7 @@ var init_conflicts = __esm(() => {
|
|
|
14262
14289
|
});
|
|
14263
14290
|
|
|
14264
14291
|
// src/telemetry/debug-id.ts
|
|
14265
|
-
var BUNDLE_DEBUG_ID_PLACEHOLDER = "
|
|
14292
|
+
var BUNDLE_DEBUG_ID_PLACEHOLDER = "8627229c-9519-9318-6475-6e2164756e21";
|
|
14266
14293
|
|
|
14267
14294
|
// src/telemetry/telemetry.ts
|
|
14268
14295
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -15383,14 +15410,43 @@ Acknowledge in one line: "Dosu incognito: this session will not be studied."
|
|
|
15383
15410
|
});
|
|
15384
15411
|
|
|
15385
15412
|
// src/commands/knowledge-incognito.ts
|
|
15413
|
+
function ensureSlashCommand(agent) {
|
|
15414
|
+
try {
|
|
15415
|
+
agent.enable();
|
|
15416
|
+
} catch (err) {
|
|
15417
|
+
reportFailure(agent.name(), err, `could not install ${SLASH}`);
|
|
15418
|
+
}
|
|
15419
|
+
}
|
|
15420
|
+
function switchAction(incognito) {
|
|
15421
|
+
return (ids) => {
|
|
15422
|
+
const agents = resolveAgents(ids, allIncognitoAgents, getIncognitoAgent);
|
|
15423
|
+
if (agents.length === 0)
|
|
15424
|
+
return;
|
|
15425
|
+
try {
|
|
15426
|
+
setAgentsIncognito(agents.map((agent) => agent.id()), incognito);
|
|
15427
|
+
} catch (err) {
|
|
15428
|
+
reportFailure("Dosu", err, "could not save the setting");
|
|
15429
|
+
return;
|
|
15430
|
+
}
|
|
15431
|
+
for (const agent of agents) {
|
|
15432
|
+
ensureSlashCommand(agent);
|
|
15433
|
+
console.log(incognito ? `\uD83D\uDC7B ${agent.name()} is incognito: its sessions will not be studied` : `\uD83D\uDCDA ${agent.name()} is studied again`);
|
|
15434
|
+
}
|
|
15435
|
+
if (!incognito) {
|
|
15436
|
+
console.log(import_picocolors20.default.dim("Sessions that finished while incognito stay unstudied."));
|
|
15437
|
+
}
|
|
15438
|
+
};
|
|
15439
|
+
}
|
|
15386
15440
|
function incognitoCommand() {
|
|
15387
|
-
const cmd = new Command("incognito").description(
|
|
15388
|
-
cmd.command("status").description("Show
|
|
15441
|
+
const cmd = new Command("incognito").description("Keep a coding agent's sessions out of Dosu studying");
|
|
15442
|
+
cmd.command("status").description("Show which agents are incognito").option("--json", "Output as JSON").action((opts) => {
|
|
15443
|
+
const incognitoAgents = new Set(loadSyncState().incognito_agents ?? []);
|
|
15389
15444
|
const rows = allIncognitoAgents().map((agent) => ({
|
|
15390
15445
|
agent: agent.id(),
|
|
15391
15446
|
name: agent.name(),
|
|
15392
15447
|
installed: agent.isInstalled(),
|
|
15393
|
-
|
|
15448
|
+
incognito: incognitoAgents.has(agent.id()),
|
|
15449
|
+
command_installed: agent.isEnabled(),
|
|
15394
15450
|
command_path: agent.commandPath()
|
|
15395
15451
|
}));
|
|
15396
15452
|
if (opts.json) {
|
|
@@ -15398,49 +15454,33 @@ function incognitoCommand() {
|
|
|
15398
15454
|
return;
|
|
15399
15455
|
}
|
|
15400
15456
|
for (const row of rows) {
|
|
15401
|
-
const state = !row.installed ? import_picocolors20.default.dim("not
|
|
15402
|
-
|
|
15457
|
+
const state = !row.installed ? import_picocolors20.default.dim("agent not found") : row.incognito ? "\uD83D\uDC7B incognito (not studied)" : import_picocolors20.default.green("\uD83D\uDCDA studied");
|
|
15458
|
+
const missing = row.installed && !row.command_installed ? import_picocolors20.default.dim(` (${SLASH} missing)`) : "";
|
|
15459
|
+
console.log(` ${row.agent.padEnd(8)} ${row.name.padEnd(14)} ${state}${missing}`);
|
|
15403
15460
|
}
|
|
15404
15461
|
console.log(import_picocolors20.default.dim(`
|
|
15405
|
-
Use 'dosu knowledge incognito
|
|
15406
|
-
` + `
|
|
15407
|
-
});
|
|
15408
|
-
cmd.command("enable [agents...]").description("Install the slash command for agents (default: all detected)").action((ids) => {
|
|
15409
|
-
for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
|
|
15410
|
-
try {
|
|
15411
|
-
const action = agent.enable();
|
|
15412
|
-
const verb = action === "unchanged" ? "already installed" : "installed";
|
|
15413
|
-
console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb} (${agent.commandPath()})`);
|
|
15414
|
-
} catch (err) {
|
|
15415
|
-
reportFailure(agent.name(), err);
|
|
15416
|
-
}
|
|
15417
|
-
}
|
|
15418
|
-
});
|
|
15419
|
-
cmd.command("disable [agents...]").description("Remove the slash command from agents (default: all detected)").action((ids) => {
|
|
15420
|
-
for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
|
|
15421
|
-
try {
|
|
15422
|
-
const action = agent.disable();
|
|
15423
|
-
const verb = action === "removed" ? "removed" : "was not installed";
|
|
15424
|
-
console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb}`);
|
|
15425
|
-
} catch (err) {
|
|
15426
|
-
reportFailure(agent.name(), err);
|
|
15427
|
-
}
|
|
15428
|
-
}
|
|
15462
|
+
Use 'dosu knowledge incognito on|off [agent...]' to change these.
|
|
15463
|
+
` + `To keep a single chat out instead, type ${SLASH} in it.`));
|
|
15429
15464
|
});
|
|
15465
|
+
cmd.command("on [agents...]").description("Stop studying these agents' sessions (default: all detected)").action(switchAction(true));
|
|
15466
|
+
cmd.command("off [agents...]").description("Study these agents' sessions again (default: all detected)").action(switchAction(false));
|
|
15430
15467
|
return cmd;
|
|
15431
15468
|
}
|
|
15432
|
-
function reportFailure(
|
|
15433
|
-
|
|
15469
|
+
function reportFailure(label, err, what) {
|
|
15470
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
15471
|
+
console.error(import_picocolors20.default.red(`✗ ${label}: ${what}: ${message}`));
|
|
15434
15472
|
process.exitCode = 1;
|
|
15435
15473
|
}
|
|
15436
|
-
var import_picocolors20;
|
|
15474
|
+
var import_picocolors20, SLASH;
|
|
15437
15475
|
var init_knowledge_incognito = __esm(() => {
|
|
15438
15476
|
init_commander();
|
|
15439
15477
|
init_agents3();
|
|
15440
15478
|
init_incognito();
|
|
15479
|
+
init_watermark();
|
|
15441
15480
|
init_agent_select();
|
|
15442
15481
|
init_output();
|
|
15443
15482
|
import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
15483
|
+
SLASH = `/${INCOGNITO_COMMAND_NAME}`;
|
|
15444
15484
|
});
|
|
15445
15485
|
|
|
15446
15486
|
// src/statusline/agents.ts
|
|
@@ -66190,7 +66230,7 @@ ${dim(wrapLog("Dosu scans finished agent sessions in the background. Disable any
|
|
|
66190
66230
|
const statuslines = installed.flatMap((r) => r.statusline ? [r.statusline] : []);
|
|
66191
66231
|
if (statuslines.length > 0) {
|
|
66192
66232
|
log2.success(`${formatSetupSummary(`Status line enabled for ${statuslines.length} agent(s):`, statuslines.map((item) => ({ label: item.name, path: item.path })))}
|
|
66193
|
-
${dim(wrapLog("Shows \uD83D\uDCDA Dosu studying…, \uD83D\uDC7B Dosu incognito, or ⚪ Dosu off/paused. Remove with 'dosu knowledge statusline disable'."))}`);
|
|
66233
|
+
${dim(wrapLog("Shows \uD83D\uDCDA Dosu on/studying…, \uD83D\uDC7B Dosu incognito, or ⚪ Dosu off/paused. Remove with 'dosu knowledge statusline disable'."))}`);
|
|
66194
66234
|
}
|
|
66195
66235
|
for (const result of installed) {
|
|
66196
66236
|
if (result.statuslineSuggestion) {
|
|
@@ -66201,7 +66241,7 @@ ${dim(wrapLog("Shows \uD83D\uDCDA Dosu studying…, \uD83D\uDC7B Dosu incognito,
|
|
|
66201
66241
|
const incognitos = installed.flatMap((r) => r.incognito ? [r.incognito] : []);
|
|
66202
66242
|
if (incognitos.length > 0) {
|
|
66203
66243
|
log2.success(`${formatSetupSummary(`/dosu-incognito installed for ${incognitos.length} agent(s):`, incognitos.map((item) => ({ label: item.name, path: item.path })))}
|
|
66204
|
-
${dim(wrapLog("
|
|
66244
|
+
${dim(wrapLog("Type it in a chat to keep that chat out of Dosu. To keep a whole agent out, run 'dosu knowledge incognito on <agent>'."))}`);
|
|
66205
66245
|
}
|
|
66206
66246
|
if (removed.length > 0) {
|
|
66207
66247
|
log2.info(formatSetupSummary(`Removed from ${removed.length} agent(s):`, removed.map((result) => ({
|
|
@@ -66542,6 +66582,64 @@ var init_upgrade = __esm(() => {
|
|
|
66542
66582
|
SEMVER = /^\d+\.\d+\.\d+/;
|
|
66543
66583
|
});
|
|
66544
66584
|
|
|
66585
|
+
// src/version/incognito-backfill-check.ts
|
|
66586
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync19, writeFileSync as writeFileSync21 } from "node:fs";
|
|
66587
|
+
import { join as join45 } from "node:path";
|
|
66588
|
+
function markerPath() {
|
|
66589
|
+
return join45(getConfigDir(), MARKER_FILENAME);
|
|
66590
|
+
}
|
|
66591
|
+
function writeMarker() {
|
|
66592
|
+
const dir = getConfigDir();
|
|
66593
|
+
if (!existsSync31(dir))
|
|
66594
|
+
mkdirSync19(dir, { recursive: true, mode: 448 });
|
|
66595
|
+
writeFileSync21(markerPath(), JSON.stringify({ done: true }), { mode: 384 });
|
|
66596
|
+
}
|
|
66597
|
+
function displayNotice3(names) {
|
|
66598
|
+
console.error(`
|
|
66599
|
+
${import_picocolors38.default.green(`✓ Dosu: added the /${INCOGNITO_COMMAND_NAME} command to ${names.join(", ")}`)}
|
|
66600
|
+
` + `${import_picocolors38.default.dim(` Type /${INCOGNITO_COMMAND_NAME} in a chat to keep that chat out of Dosu.`)}
|
|
66601
|
+
`);
|
|
66602
|
+
}
|
|
66603
|
+
function checkForIncognitoBackfill(options = {}) {
|
|
66604
|
+
const notify = options.notify ?? true;
|
|
66605
|
+
try {
|
|
66606
|
+
if (existsSync31(markerPath()))
|
|
66607
|
+
return;
|
|
66608
|
+
const added = [];
|
|
66609
|
+
let failed = false;
|
|
66610
|
+
for (const hook of allHookAgents()) {
|
|
66611
|
+
const agent = getIncognitoAgent(hook.id());
|
|
66612
|
+
if (!agent || !hook.isEnabled() || agent.isEnabled())
|
|
66613
|
+
continue;
|
|
66614
|
+
try {
|
|
66615
|
+
agent.enable();
|
|
66616
|
+
added.push(agent.name());
|
|
66617
|
+
} catch (err) {
|
|
66618
|
+
failed = true;
|
|
66619
|
+
logger.warn("incognito-backfill", `Install failed for ${agent.id()}: ${err}`);
|
|
66620
|
+
}
|
|
66621
|
+
}
|
|
66622
|
+
if (!failed)
|
|
66623
|
+
writeMarker();
|
|
66624
|
+
if (added.length > 0) {
|
|
66625
|
+
logger.info("incognito-backfill", `Installed /${INCOGNITO_COMMAND_NAME} for ${added}`);
|
|
66626
|
+
if (notify)
|
|
66627
|
+
displayNotice3(added);
|
|
66628
|
+
}
|
|
66629
|
+
} catch (err) {
|
|
66630
|
+
logger.error("incognito-backfill", `Incognito backfill failed: ${err}`);
|
|
66631
|
+
}
|
|
66632
|
+
}
|
|
66633
|
+
var import_picocolors38, MARKER_FILENAME = "incognito-backfill.json";
|
|
66634
|
+
var init_incognito_backfill_check = __esm(() => {
|
|
66635
|
+
init_config();
|
|
66636
|
+
init_logger();
|
|
66637
|
+
init_agents();
|
|
66638
|
+
init_agents3();
|
|
66639
|
+
init_incognito();
|
|
66640
|
+
import_picocolors38 = __toESM(require_picocolors(), 1);
|
|
66641
|
+
});
|
|
66642
|
+
|
|
66545
66643
|
// src/tui/analytics-view.ts
|
|
66546
66644
|
function analyticsListHeight(rows) {
|
|
66547
66645
|
const room = frameMaxLines(rows) - ANALYTICS_VIEW_CHROME_LINES;
|
|
@@ -66660,7 +66758,7 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
|
|
|
66660
66758
|
const rows = analyticsTabRows(tab, state, pageStats);
|
|
66661
66759
|
const { visible, above, below } = windowReport(rows, scroll, height);
|
|
66662
66760
|
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.";
|
|
66663
|
-
const listRows = visible.length > 0 ? visible.map((row) =>
|
|
66761
|
+
const listRows = visible.length > 0 ? visible.map((row) => import_picocolors39.default.dim(row)) : [import_picocolors39.default.dim(empty)];
|
|
66664
66762
|
const scrollParts = [];
|
|
66665
66763
|
if (above > 0)
|
|
66666
66764
|
scrollParts.push(`↑ ${above} earlier`);
|
|
@@ -66676,9 +66774,9 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
|
|
|
66676
66774
|
], tab, width, { spread: false }),
|
|
66677
66775
|
"",
|
|
66678
66776
|
...listRows,
|
|
66679
|
-
...scrollParts.length > 0 ? [
|
|
66777
|
+
...scrollParts.length > 0 ? [import_picocolors39.default.dim(scrollParts.join(" · "))] : [],
|
|
66680
66778
|
"",
|
|
66681
|
-
|
|
66779
|
+
import_picocolors39.default.dim("tab switch · ↑↓ scroll · esc back")
|
|
66682
66780
|
];
|
|
66683
66781
|
return lines.join(`
|
|
66684
66782
|
`);
|
|
@@ -66775,7 +66873,7 @@ ${CLEAR_BELOW2}`);
|
|
|
66775
66873
|
input.on("data", onData);
|
|
66776
66874
|
});
|
|
66777
66875
|
}
|
|
66778
|
-
var
|
|
66876
|
+
var import_picocolors39, ESC8, HIDE_CURSOR4, SHOW_CURSOR4, CTRL_C5, KEY_UP5, KEY_DOWN5, KEY_RIGHT4, KEY_LEFT4, CURSOR_HOME2, CLEAR_BELOW2, CLEAR_EOL2, ANALYTICS_VIEW_POLL_MS = 1000, ANALYTICS_VIEW_LINES = 14, ANALYTICS_VIEW_CHROME_LINES = 8, ANALYTICS_VIEW_TABS, TOP_PAGES_LIMIT = 5, TOP_CITED_DAYS = 30, label = (text) => text.padEnd(26);
|
|
66779
66877
|
var init_analytics_view = __esm(() => {
|
|
66780
66878
|
init_trpc();
|
|
66781
66879
|
init_config();
|
|
@@ -66783,7 +66881,7 @@ var init_analytics_view = __esm(() => {
|
|
|
66783
66881
|
init_alt_screen();
|
|
66784
66882
|
init_layout();
|
|
66785
66883
|
init_menu();
|
|
66786
|
-
|
|
66884
|
+
import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
66787
66885
|
ESC8 = String.fromCharCode(27);
|
|
66788
66886
|
HIDE_CURSOR4 = `${ESC8}[?25l`;
|
|
66789
66887
|
SHOW_CURSOR4 = `${ESC8}[?25h`;
|
|
@@ -66801,7 +66899,7 @@ var init_analytics_view = __esm(() => {
|
|
|
66801
66899
|
// src/tui/banner.ts
|
|
66802
66900
|
function paintLogoRow(row) {
|
|
66803
66901
|
return row.map(([tone, art]) => {
|
|
66804
|
-
if (!
|
|
66902
|
+
if (!import_picocolors40.default.isColorSupported)
|
|
66805
66903
|
return art;
|
|
66806
66904
|
const { fg, fallback } = LOGO_TONES[tone];
|
|
66807
66905
|
return hasTruecolor() ? `${fg}${art}\x1B[39m` : fallback(art);
|
|
@@ -66809,14 +66907,14 @@ function paintLogoRow(row) {
|
|
|
66809
66907
|
}
|
|
66810
66908
|
function checklistRows(ctx) {
|
|
66811
66909
|
const on = brand(CHECK2);
|
|
66812
|
-
const off =
|
|
66910
|
+
const off = import_picocolors40.default.dim(CIRCLE);
|
|
66813
66911
|
const rows = [["workspace", ctx.directory]];
|
|
66814
66912
|
rows.push([
|
|
66815
66913
|
"account",
|
|
66816
|
-
ctx.sessionExpired ? `${off} ${
|
|
66914
|
+
ctx.sessionExpired ? `${off} ${import_picocolors40.default.yellow("session expired")} ${import_picocolors40.default.dim(`${DOT3} run Log in`)}` : ctx.signedIn ? `${on} signed in` : `${off} ${import_picocolors40.default.dim(`not signed in ${DOT3} run Setup`)}`
|
|
66817
66915
|
]);
|
|
66818
66916
|
const missing = new Set(ctx.setupMissing ?? []);
|
|
66819
|
-
const warnRow = `${off} ${
|
|
66917
|
+
const warnRow = `${off} ${import_picocolors40.default.yellow("not configured")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`;
|
|
66820
66918
|
if (missing.has("MCP"))
|
|
66821
66919
|
rows.push(["mcp", warnRow]);
|
|
66822
66920
|
else if (ctx.deploymentName)
|
|
@@ -66828,7 +66926,7 @@ function checklistRows(ctx) {
|
|
|
66828
66926
|
if (ctx.repoAgentsMd) {
|
|
66829
66927
|
rows.push([
|
|
66830
66928
|
"repo",
|
|
66831
|
-
ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${
|
|
66929
|
+
ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${import_picocolors40.default.yellow(ctx.repoAgentsMd === "outdated" ? "AGENTS.md Dosu section outdated" : "AGENTS.md missing the Dosu section")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`
|
|
66832
66930
|
]);
|
|
66833
66931
|
}
|
|
66834
66932
|
if (missing.has("agents"))
|
|
@@ -66840,24 +66938,24 @@ function checklistRows(ctx) {
|
|
|
66840
66938
|
if (ctx.studying) {
|
|
66841
66939
|
rows.push([
|
|
66842
66940
|
"sync",
|
|
66843
|
-
`\uD83D\uDCDA ${brand("studying sessions...")} ${
|
|
66941
|
+
`\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors40.default.dim(`${DOT3} see activity`)}`
|
|
66844
66942
|
]);
|
|
66845
66943
|
}
|
|
66846
66944
|
if (ctx.update) {
|
|
66847
66945
|
rows.push([
|
|
66848
66946
|
"update",
|
|
66849
|
-
`${
|
|
66947
|
+
`${import_picocolors40.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors40.default.dim(`${DOT3} ${ctx.update.hint}`)}`
|
|
66850
66948
|
]);
|
|
66851
66949
|
}
|
|
66852
66950
|
const labelWidth = Math.max(...rows.map(([label]) => label.length));
|
|
66853
|
-
return rows.map(([label, value]) => `${
|
|
66951
|
+
return rows.map(([label, value]) => `${import_picocolors40.default.dim(label.padEnd(labelWidth))} ${value}`);
|
|
66854
66952
|
}
|
|
66855
66953
|
function renderBanner(ctx) {
|
|
66856
66954
|
const logo = LOGO_ROWS.map(paintLogoRow);
|
|
66857
66955
|
const text = [
|
|
66858
66956
|
...checklistRows(ctx),
|
|
66859
66957
|
"",
|
|
66860
|
-
`${brandBadge("dosu-cli")} ${
|
|
66958
|
+
`${brandBadge("dosu-cli")} ${import_picocolors40.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
|
|
66861
66959
|
];
|
|
66862
66960
|
const height = Math.max(logo.length, text.length);
|
|
66863
66961
|
const combined = [];
|
|
@@ -66870,10 +66968,10 @@ function renderBanner(ctx) {
|
|
|
66870
66968
|
return ["", ...combined, ""].join(`
|
|
66871
66969
|
`);
|
|
66872
66970
|
}
|
|
66873
|
-
var
|
|
66971
|
+
var import_picocolors40, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ";
|
|
66874
66972
|
var init_banner = __esm(() => {
|
|
66875
66973
|
init_styles();
|
|
66876
|
-
|
|
66974
|
+
import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
66877
66975
|
LOGO_ROWS = [
|
|
66878
66976
|
[["sage", "▄▄▄▄▄▄"]],
|
|
66879
66977
|
[["sage", "██ ▀▄"]],
|
|
@@ -66884,8 +66982,8 @@ var init_banner = __esm(() => {
|
|
|
66884
66982
|
LOGO_MARK = LOGO_ROWS.map((row) => row.map(([, art]) => art).join(""));
|
|
66885
66983
|
LOGO_WIDTH = Math.max(...LOGO_MARK.map((row) => row.length));
|
|
66886
66984
|
LOGO_TONES = {
|
|
66887
|
-
sage: { fg: "\x1B[38;2;180;187;145m", fallback:
|
|
66888
|
-
moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) =>
|
|
66985
|
+
sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors40.default.green },
|
|
66986
|
+
moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) => import_picocolors40.default.dim(import_picocolors40.default.green(art)) }
|
|
66889
66987
|
};
|
|
66890
66988
|
});
|
|
66891
66989
|
|
|
@@ -66997,16 +67095,16 @@ function renderPagesFrame(model, width, selected) {
|
|
|
66997
67095
|
const body = [];
|
|
66998
67096
|
let scrollHint = "";
|
|
66999
67097
|
if (model.phase === "loading") {
|
|
67000
|
-
body.push(
|
|
67098
|
+
body.push(import_picocolors41.default.dim("Loading pages…"));
|
|
67001
67099
|
} else if (model.phase === "error") {
|
|
67002
|
-
body.push(
|
|
67100
|
+
body.push(import_picocolors41.default.yellow(clip3(model.message, width)));
|
|
67003
67101
|
} else if (model.pages.length === 0) {
|
|
67004
|
-
body.push(
|
|
67102
|
+
body.push(import_picocolors41.default.dim("No pages in this Library yet."));
|
|
67005
67103
|
} else {
|
|
67006
67104
|
const rows = pageRows2(model.pages, width - 2);
|
|
67007
67105
|
const { start, above } = windowSelection(rows.length, selected);
|
|
67008
67106
|
const visible = rows.slice(start, start + PAGES_VIEW_LINES);
|
|
67009
|
-
body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${
|
|
67107
|
+
body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${import_picocolors41.default.bold(row)}` : ` ${import_picocolors41.default.dim(row)}`));
|
|
67010
67108
|
const below = Math.max(0, Math.max(model.total, rows.length) - start - PAGES_VIEW_LINES);
|
|
67011
67109
|
const parts = [];
|
|
67012
67110
|
if (above > 0)
|
|
@@ -67015,14 +67113,14 @@ function renderPagesFrame(model, width, selected) {
|
|
|
67015
67113
|
parts.push(`↓ ${below} more`);
|
|
67016
67114
|
scrollHint = parts.join(" · ");
|
|
67017
67115
|
}
|
|
67018
|
-
const count = model.phase === "ready" ? ` ${
|
|
67116
|
+
const count = model.phase === "ready" ? ` ${import_picocolors41.default.dim(model.pages.length < model.total ? `(${model.pages.length} of ${model.total})` : `(${model.pages.length})`)}` : "";
|
|
67019
67117
|
const lines = [
|
|
67020
67118
|
`${breadcrumb(["home", "pages"], width)}${count}`,
|
|
67021
67119
|
"",
|
|
67022
67120
|
...body,
|
|
67023
|
-
...scrollHint ? [
|
|
67121
|
+
...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
|
|
67024
67122
|
"",
|
|
67025
|
-
|
|
67123
|
+
import_picocolors41.default.dim("↑↓ move · enter open · esc back")
|
|
67026
67124
|
];
|
|
67027
67125
|
return lines.join(`
|
|
67028
67126
|
`);
|
|
@@ -67031,9 +67129,9 @@ function renderPageFrame(page, content, width, scroll) {
|
|
|
67031
67129
|
const body = [];
|
|
67032
67130
|
let scrollHint = "";
|
|
67033
67131
|
if (content.phase === "loading") {
|
|
67034
|
-
body.push(
|
|
67132
|
+
body.push(import_picocolors41.default.dim("Loading page…"));
|
|
67035
67133
|
} else if (content.phase === "error") {
|
|
67036
|
-
body.push(
|
|
67134
|
+
body.push(import_picocolors41.default.yellow(clip3(content.message, width)));
|
|
67037
67135
|
} else {
|
|
67038
67136
|
const rows = wrapBody(content.body, width);
|
|
67039
67137
|
const { visible, above, below } = windowReport(rows, scroll, PAGE_BODY_LINES);
|
|
@@ -67048,12 +67146,12 @@ function renderPageFrame(page, content, width, scroll) {
|
|
|
67048
67146
|
const meta = `${page.type} · ${page.published ? "published" : "draft"} · updated ${page.updated_at.slice(0, 10)}`;
|
|
67049
67147
|
const lines = [
|
|
67050
67148
|
breadcrumb(["home", "pages", page.title], width),
|
|
67051
|
-
|
|
67149
|
+
import_picocolors41.default.dim(clip3(meta, width)),
|
|
67052
67150
|
"",
|
|
67053
67151
|
...body,
|
|
67054
|
-
...scrollHint ? [
|
|
67152
|
+
...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
|
|
67055
67153
|
"",
|
|
67056
|
-
|
|
67154
|
+
import_picocolors41.default.dim("↑↓ scroll · esc back to pages")
|
|
67057
67155
|
];
|
|
67058
67156
|
return lines.join(`
|
|
67059
67157
|
`);
|
|
@@ -67202,7 +67300,7 @@ ${CLEAR_BELOW3}`);
|
|
|
67202
67300
|
input.on("data", onData);
|
|
67203
67301
|
});
|
|
67204
67302
|
}
|
|
67205
|
-
var
|
|
67303
|
+
var import_picocolors41, ESC9, HIDE_CURSOR5, SHOW_CURSOR5, CTRL_C6, KEY_UP6, KEY_DOWN6, CURSOR_HOME3, CLEAR_BELOW3, CLEAR_EOL3, PAGES_VIEW_LINES = 12, PAGE_BODY_LINES = 14, PAGES_FETCH_BATCH = 100;
|
|
67206
67304
|
var init_pages_view = __esm(() => {
|
|
67207
67305
|
init_trpc();
|
|
67208
67306
|
init_config();
|
|
@@ -67212,7 +67310,7 @@ var init_pages_view = __esm(() => {
|
|
|
67212
67310
|
init_analytics_view();
|
|
67213
67311
|
init_layout();
|
|
67214
67312
|
init_menu();
|
|
67215
|
-
|
|
67313
|
+
import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
67216
67314
|
ESC9 = String.fromCharCode(27);
|
|
67217
67315
|
HIDE_CURSOR5 = `${ESC9}[?25l`;
|
|
67218
67316
|
SHOW_CURSOR5 = `${ESC9}[?25h`;
|
|
@@ -67325,7 +67423,7 @@ function isSetUp(cfg) {
|
|
|
67325
67423
|
}
|
|
67326
67424
|
function setupHint(cfg) {
|
|
67327
67425
|
const started = Boolean(cfg.active_account?.target);
|
|
67328
|
-
return
|
|
67426
|
+
return import_picocolors42.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
|
|
67329
67427
|
}
|
|
67330
67428
|
function isStudying() {
|
|
67331
67429
|
try {
|
|
@@ -67570,7 +67668,7 @@ function handleLogout(cfg) {
|
|
|
67570
67668
|
saveConfig(cfg);
|
|
67571
67669
|
log2.success("Credentials cleared.");
|
|
67572
67670
|
}
|
|
67573
|
-
var
|
|
67671
|
+
var import_picocolors42, ESC10, CLEAR_SCREEN;
|
|
67574
67672
|
var init_tui = __esm(() => {
|
|
67575
67673
|
init_client();
|
|
67576
67674
|
init_config();
|
|
@@ -67594,7 +67692,7 @@ var init_tui = __esm(() => {
|
|
|
67594
67692
|
init_menu();
|
|
67595
67693
|
init_pages_view();
|
|
67596
67694
|
init_prompts();
|
|
67597
|
-
|
|
67695
|
+
import_picocolors42 = __toESM(require_picocolors(), 1);
|
|
67598
67696
|
ESC10 = String.fromCharCode(27);
|
|
67599
67697
|
CLEAR_SCREEN = `${ESC10}[2J${ESC10}[H`;
|
|
67600
67698
|
});
|
|
@@ -68313,6 +68411,7 @@ function createProgram(options = {}) {
|
|
|
68313
68411
|
checkForReadyTasks();
|
|
68314
68412
|
if (shouldRunMcpRefreshCheck(actionCommand)) {
|
|
68315
68413
|
checkForMcpRefresh({ notify: !launchesTUI });
|
|
68414
|
+
checkForIncognitoBackfill({ notify: !launchesTUI });
|
|
68316
68415
|
}
|
|
68317
68416
|
}
|
|
68318
68417
|
const command = commandTelemetryName(actionCommand);
|
|
@@ -68743,6 +68842,7 @@ var init_cli = __esm(() => {
|
|
|
68743
68842
|
init_styles();
|
|
68744
68843
|
init_settings();
|
|
68745
68844
|
init_telemetry();
|
|
68845
|
+
init_incognito_backfill_check();
|
|
68746
68846
|
init_mcp_refresh_check();
|
|
68747
68847
|
init_pending_tasks_check();
|
|
68748
68848
|
init_skill_update_check();
|
|
@@ -68781,4 +68881,4 @@ main().catch((err) => {
|
|
|
68781
68881
|
process.exit(1);
|
|
68782
68882
|
});
|
|
68783
68883
|
|
|
68784
|
-
//# debugId=
|
|
68884
|
+
//# debugId=8627229c-9519-9318-6475-6e2164756e21
|