@dosu/cli 0.65.1 → 0.66.1
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 +430 -299
- package/package.json +1 -1
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.1", 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 = "0891ed1f-f060-16b6-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,22 +66899,45 @@ 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);
|
|
66808
66906
|
}).join("");
|
|
66809
66907
|
}
|
|
66810
|
-
function
|
|
66908
|
+
function wrapValue(text, room) {
|
|
66909
|
+
const lines = [];
|
|
66910
|
+
let current = "";
|
|
66911
|
+
const append = (piece, sep) => {
|
|
66912
|
+
if (current === "")
|
|
66913
|
+
current = piece;
|
|
66914
|
+
else if (visibleWidth2(current) + sep.length + visibleWidth2(piece) <= room) {
|
|
66915
|
+
current += sep + piece;
|
|
66916
|
+
} else {
|
|
66917
|
+
lines.push(current);
|
|
66918
|
+
current = piece;
|
|
66919
|
+
}
|
|
66920
|
+
};
|
|
66921
|
+
for (const item of text.split(LIST_SEP)) {
|
|
66922
|
+
const pieces = visibleWidth2(item) <= room ? [item] : item.split(" ");
|
|
66923
|
+
pieces.forEach((piece, i) => {
|
|
66924
|
+
append(piece, i === 0 ? LIST_SEP : " ");
|
|
66925
|
+
});
|
|
66926
|
+
}
|
|
66927
|
+
if (current !== "")
|
|
66928
|
+
lines.push(current);
|
|
66929
|
+
return lines.length > 0 ? lines : [text];
|
|
66930
|
+
}
|
|
66931
|
+
function checklistRows(ctx, width) {
|
|
66811
66932
|
const on = brand(CHECK2);
|
|
66812
|
-
const off =
|
|
66933
|
+
const off = import_picocolors40.default.dim(CIRCLE);
|
|
66813
66934
|
const rows = [["workspace", ctx.directory]];
|
|
66814
66935
|
rows.push([
|
|
66815
66936
|
"account",
|
|
66816
|
-
ctx.sessionExpired ? `${off} ${
|
|
66937
|
+
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
66938
|
]);
|
|
66818
66939
|
const missing = new Set(ctx.setupMissing ?? []);
|
|
66819
|
-
const warnRow = `${off} ${
|
|
66940
|
+
const warnRow = `${off} ${import_picocolors40.default.yellow("not configured")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`;
|
|
66820
66941
|
if (missing.has("MCP"))
|
|
66821
66942
|
rows.push(["mcp", warnRow]);
|
|
66822
66943
|
else if (ctx.deploymentName)
|
|
@@ -66828,36 +66949,42 @@ function checklistRows(ctx) {
|
|
|
66828
66949
|
if (ctx.repoAgentsMd) {
|
|
66829
66950
|
rows.push([
|
|
66830
66951
|
"repo",
|
|
66831
|
-
ctx.repoAgentsMd === "current" ? `${on} AGENTS.md has the Dosu section` : `${off} ${
|
|
66952
|
+
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
66953
|
]);
|
|
66833
66954
|
}
|
|
66834
66955
|
if (missing.has("agents"))
|
|
66835
66956
|
rows.push(["agents", warnRow]);
|
|
66836
66957
|
else if (ctx.agents.length > 0)
|
|
66837
|
-
rows.push(["agents", `${on} ${ctx.agents.join(
|
|
66958
|
+
rows.push(["agents", `${on} ${ctx.agents.join(LIST_SEP)}`]);
|
|
66838
66959
|
if (missing.has("hooks"))
|
|
66839
66960
|
rows.push(["hooks", warnRow]);
|
|
66840
66961
|
if (ctx.studying) {
|
|
66841
66962
|
rows.push([
|
|
66842
66963
|
"sync",
|
|
66843
|
-
`\uD83D\uDCDA ${brand("studying sessions...")} ${
|
|
66964
|
+
`\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors40.default.dim(`${DOT3} see activity`)}`
|
|
66844
66965
|
]);
|
|
66845
66966
|
}
|
|
66846
66967
|
if (ctx.update) {
|
|
66847
66968
|
rows.push([
|
|
66848
66969
|
"update",
|
|
66849
|
-
`${
|
|
66970
|
+
`${import_picocolors40.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors40.default.dim(`${DOT3} ${ctx.update.hint}`)}`
|
|
66850
66971
|
]);
|
|
66851
66972
|
}
|
|
66852
66973
|
const labelWidth = Math.max(...rows.map(([label]) => label.length));
|
|
66853
|
-
|
|
66974
|
+
const valueColumn = LOGO_WIDTH + COLUMN_GAP.length + labelWidth + LABEL_GAP.length;
|
|
66975
|
+
const room = Math.max(1, width - valueColumn);
|
|
66976
|
+
const indent = " ".repeat(labelWidth + LABEL_GAP.length);
|
|
66977
|
+
return rows.flatMap(([label, value]) => wrapValue(value, room).map((line, i) => i === 0 ? `${import_picocolors40.default.dim(label.padEnd(labelWidth))}${LABEL_GAP}${line}` : `${indent}${line}`));
|
|
66978
|
+
}
|
|
66979
|
+
function bannerWidth(columns = process.stdout.columns ?? 80) {
|
|
66980
|
+
return columns - layoutMargin(columns) - 1;
|
|
66854
66981
|
}
|
|
66855
|
-
function renderBanner(ctx) {
|
|
66982
|
+
function renderBanner(ctx, width = bannerWidth()) {
|
|
66856
66983
|
const logo = LOGO_ROWS.map(paintLogoRow);
|
|
66857
66984
|
const text = [
|
|
66858
|
-
...checklistRows(ctx),
|
|
66985
|
+
...checklistRows(ctx, width),
|
|
66859
66986
|
"",
|
|
66860
|
-
`${brandBadge("dosu-cli")} ${
|
|
66987
|
+
`${brandBadge("dosu-cli")} ${import_picocolors40.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
|
|
66861
66988
|
];
|
|
66862
66989
|
const height = Math.max(logo.length, text.length);
|
|
66863
66990
|
const combined = [];
|
|
@@ -66870,10 +66997,11 @@ function renderBanner(ctx) {
|
|
|
66870
66997
|
return ["", ...combined, ""].join(`
|
|
66871
66998
|
`);
|
|
66872
66999
|
}
|
|
66873
|
-
var
|
|
67000
|
+
var import_picocolors40, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ", LABEL_GAP = " ", LIST_SEP;
|
|
66874
67001
|
var init_banner = __esm(() => {
|
|
66875
67002
|
init_styles();
|
|
66876
|
-
|
|
67003
|
+
init_layout();
|
|
67004
|
+
import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
66877
67005
|
LOGO_ROWS = [
|
|
66878
67006
|
[["sage", "▄▄▄▄▄▄"]],
|
|
66879
67007
|
[["sage", "██ ▀▄"]],
|
|
@@ -66884,9 +67012,10 @@ var init_banner = __esm(() => {
|
|
|
66884
67012
|
LOGO_MARK = LOGO_ROWS.map((row) => row.map(([, art]) => art).join(""));
|
|
66885
67013
|
LOGO_WIDTH = Math.max(...LOGO_MARK.map((row) => row.length));
|
|
66886
67014
|
LOGO_TONES = {
|
|
66887
|
-
sage: { fg: "\x1B[38;2;180;187;145m", fallback:
|
|
66888
|
-
moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) =>
|
|
67015
|
+
sage: { fg: "\x1B[38;2;180;187;145m", fallback: import_picocolors40.default.green },
|
|
67016
|
+
moss: { fg: "\x1B[38;2;119;133;97m", fallback: (art) => import_picocolors40.default.dim(import_picocolors40.default.green(art)) }
|
|
66889
67017
|
};
|
|
67018
|
+
LIST_SEP = ` ${DOT3} `;
|
|
66890
67019
|
});
|
|
66891
67020
|
|
|
66892
67021
|
// src/tui/pages-view.ts
|
|
@@ -66997,16 +67126,16 @@ function renderPagesFrame(model, width, selected) {
|
|
|
66997
67126
|
const body = [];
|
|
66998
67127
|
let scrollHint = "";
|
|
66999
67128
|
if (model.phase === "loading") {
|
|
67000
|
-
body.push(
|
|
67129
|
+
body.push(import_picocolors41.default.dim("Loading pages…"));
|
|
67001
67130
|
} else if (model.phase === "error") {
|
|
67002
|
-
body.push(
|
|
67131
|
+
body.push(import_picocolors41.default.yellow(clip3(model.message, width)));
|
|
67003
67132
|
} else if (model.pages.length === 0) {
|
|
67004
|
-
body.push(
|
|
67133
|
+
body.push(import_picocolors41.default.dim("No pages in this Library yet."));
|
|
67005
67134
|
} else {
|
|
67006
67135
|
const rows = pageRows2(model.pages, width - 2);
|
|
67007
67136
|
const { start, above } = windowSelection(rows.length, selected);
|
|
67008
67137
|
const visible = rows.slice(start, start + PAGES_VIEW_LINES);
|
|
67009
|
-
body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${
|
|
67138
|
+
body.push(...visible.map((row, i) => start + i === selected ? `${brand("▸")} ${import_picocolors41.default.bold(row)}` : ` ${import_picocolors41.default.dim(row)}`));
|
|
67010
67139
|
const below = Math.max(0, Math.max(model.total, rows.length) - start - PAGES_VIEW_LINES);
|
|
67011
67140
|
const parts = [];
|
|
67012
67141
|
if (above > 0)
|
|
@@ -67015,14 +67144,14 @@ function renderPagesFrame(model, width, selected) {
|
|
|
67015
67144
|
parts.push(`↓ ${below} more`);
|
|
67016
67145
|
scrollHint = parts.join(" · ");
|
|
67017
67146
|
}
|
|
67018
|
-
const count = model.phase === "ready" ? ` ${
|
|
67147
|
+
const count = model.phase === "ready" ? ` ${import_picocolors41.default.dim(model.pages.length < model.total ? `(${model.pages.length} of ${model.total})` : `(${model.pages.length})`)}` : "";
|
|
67019
67148
|
const lines = [
|
|
67020
67149
|
`${breadcrumb(["home", "pages"], width)}${count}`,
|
|
67021
67150
|
"",
|
|
67022
67151
|
...body,
|
|
67023
|
-
...scrollHint ? [
|
|
67152
|
+
...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
|
|
67024
67153
|
"",
|
|
67025
|
-
|
|
67154
|
+
import_picocolors41.default.dim("↑↓ move · enter open · esc back")
|
|
67026
67155
|
];
|
|
67027
67156
|
return lines.join(`
|
|
67028
67157
|
`);
|
|
@@ -67031,9 +67160,9 @@ function renderPageFrame(page, content, width, scroll) {
|
|
|
67031
67160
|
const body = [];
|
|
67032
67161
|
let scrollHint = "";
|
|
67033
67162
|
if (content.phase === "loading") {
|
|
67034
|
-
body.push(
|
|
67163
|
+
body.push(import_picocolors41.default.dim("Loading page…"));
|
|
67035
67164
|
} else if (content.phase === "error") {
|
|
67036
|
-
body.push(
|
|
67165
|
+
body.push(import_picocolors41.default.yellow(clip3(content.message, width)));
|
|
67037
67166
|
} else {
|
|
67038
67167
|
const rows = wrapBody(content.body, width);
|
|
67039
67168
|
const { visible, above, below } = windowReport(rows, scroll, PAGE_BODY_LINES);
|
|
@@ -67048,12 +67177,12 @@ function renderPageFrame(page, content, width, scroll) {
|
|
|
67048
67177
|
const meta = `${page.type} · ${page.published ? "published" : "draft"} · updated ${page.updated_at.slice(0, 10)}`;
|
|
67049
67178
|
const lines = [
|
|
67050
67179
|
breadcrumb(["home", "pages", page.title], width),
|
|
67051
|
-
|
|
67180
|
+
import_picocolors41.default.dim(clip3(meta, width)),
|
|
67052
67181
|
"",
|
|
67053
67182
|
...body,
|
|
67054
|
-
...scrollHint ? [
|
|
67183
|
+
...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
|
|
67055
67184
|
"",
|
|
67056
|
-
|
|
67185
|
+
import_picocolors41.default.dim("↑↓ scroll · esc back to pages")
|
|
67057
67186
|
];
|
|
67058
67187
|
return lines.join(`
|
|
67059
67188
|
`);
|
|
@@ -67202,7 +67331,7 @@ ${CLEAR_BELOW3}`);
|
|
|
67202
67331
|
input.on("data", onData);
|
|
67203
67332
|
});
|
|
67204
67333
|
}
|
|
67205
|
-
var
|
|
67334
|
+
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
67335
|
var init_pages_view = __esm(() => {
|
|
67207
67336
|
init_trpc();
|
|
67208
67337
|
init_config();
|
|
@@ -67212,7 +67341,7 @@ var init_pages_view = __esm(() => {
|
|
|
67212
67341
|
init_analytics_view();
|
|
67213
67342
|
init_layout();
|
|
67214
67343
|
init_menu();
|
|
67215
|
-
|
|
67344
|
+
import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
67216
67345
|
ESC9 = String.fromCharCode(27);
|
|
67217
67346
|
HIDE_CURSOR5 = `${ESC9}[?25l`;
|
|
67218
67347
|
SHOW_CURSOR5 = `${ESC9}[?25h`;
|
|
@@ -67325,7 +67454,7 @@ function isSetUp(cfg) {
|
|
|
67325
67454
|
}
|
|
67326
67455
|
function setupHint(cfg) {
|
|
67327
67456
|
const started = Boolean(cfg.active_account?.target);
|
|
67328
|
-
return
|
|
67457
|
+
return import_picocolors42.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
|
|
67329
67458
|
}
|
|
67330
67459
|
function isStudying() {
|
|
67331
67460
|
try {
|
|
@@ -67570,7 +67699,7 @@ function handleLogout(cfg) {
|
|
|
67570
67699
|
saveConfig(cfg);
|
|
67571
67700
|
log2.success("Credentials cleared.");
|
|
67572
67701
|
}
|
|
67573
|
-
var
|
|
67702
|
+
var import_picocolors42, ESC10, CLEAR_SCREEN;
|
|
67574
67703
|
var init_tui = __esm(() => {
|
|
67575
67704
|
init_client();
|
|
67576
67705
|
init_config();
|
|
@@ -67594,7 +67723,7 @@ var init_tui = __esm(() => {
|
|
|
67594
67723
|
init_menu();
|
|
67595
67724
|
init_pages_view();
|
|
67596
67725
|
init_prompts();
|
|
67597
|
-
|
|
67726
|
+
import_picocolors42 = __toESM(require_picocolors(), 1);
|
|
67598
67727
|
ESC10 = String.fromCharCode(27);
|
|
67599
67728
|
CLEAR_SCREEN = `${ESC10}[2J${ESC10}[H`;
|
|
67600
67729
|
});
|
|
@@ -68313,6 +68442,7 @@ function createProgram(options = {}) {
|
|
|
68313
68442
|
checkForReadyTasks();
|
|
68314
68443
|
if (shouldRunMcpRefreshCheck(actionCommand)) {
|
|
68315
68444
|
checkForMcpRefresh({ notify: !launchesTUI });
|
|
68445
|
+
checkForIncognitoBackfill({ notify: !launchesTUI });
|
|
68316
68446
|
}
|
|
68317
68447
|
}
|
|
68318
68448
|
const command = commandTelemetryName(actionCommand);
|
|
@@ -68743,6 +68873,7 @@ var init_cli = __esm(() => {
|
|
|
68743
68873
|
init_styles();
|
|
68744
68874
|
init_settings();
|
|
68745
68875
|
init_telemetry();
|
|
68876
|
+
init_incognito_backfill_check();
|
|
68746
68877
|
init_mcp_refresh_check();
|
|
68747
68878
|
init_pending_tasks_check();
|
|
68748
68879
|
init_skill_update_check();
|
|
@@ -68781,4 +68912,4 @@ main().catch((err) => {
|
|
|
68781
68912
|
process.exit(1);
|
|
68782
68913
|
});
|
|
68783
68914
|
|
|
68784
|
-
//# debugId=
|
|
68915
|
+
//# debugId=0891ed1f-f060-16b6-6475-6e2164756e21
|