@dosu/cli 0.65.0 → 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 +15 -12
- package/bin/dosu.js +397 -323
- 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.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") {
|
|
@@ -11684,30 +11857,6 @@ ${page.body}`);
|
|
|
11684
11857
|
}
|
|
11685
11858
|
console.log(import_picocolors16.default.green(`Document restored to version ${opts.revision}.`));
|
|
11686
11859
|
});
|
|
11687
|
-
cmd.command("generate").description("Generate a document using AI").requiredOption("--title <title>", "Document title").option("--instructions <text>", "Custom generation instructions").option("--json", "Output as JSON").action(async (opts) => {
|
|
11688
|
-
const cfg = requireConfig5();
|
|
11689
|
-
const client = createTypedClient(cfg);
|
|
11690
|
-
const ksId = await getKnowledgeStoreId(client, cfg.active_account.target.space_id);
|
|
11691
|
-
const result = await backendPost2("/doc/generate", requireAPIKey(cfg), {
|
|
11692
|
-
knowledge_store_id: ksId,
|
|
11693
|
-
title: opts.title,
|
|
11694
|
-
instructions: opts.instructions
|
|
11695
|
-
});
|
|
11696
|
-
if (opts.json) {
|
|
11697
|
-
printResult(result, opts);
|
|
11698
|
-
return;
|
|
11699
|
-
}
|
|
11700
|
-
console.log(import_picocolors16.default.green("Document generation started."));
|
|
11701
|
-
});
|
|
11702
|
-
cmd.command("auto-tag").description("Auto-tag a document using AI").argument("<id>", "Page ID").option("--json", "Output as JSON").action(async (id, opts) => {
|
|
11703
|
-
const cfg = requireConfig5();
|
|
11704
|
-
const result = await backendPost2("/doc/auto-tag", requireAPIKey(cfg), { page_id: id });
|
|
11705
|
-
if (opts.json) {
|
|
11706
|
-
printResult(result, opts);
|
|
11707
|
-
return;
|
|
11708
|
-
}
|
|
11709
|
-
console.log(import_picocolors16.default.green("Auto-tagging started."));
|
|
11710
|
-
});
|
|
11711
11860
|
cmd.command("import").description("Import documents from an external platform").addArgument(new Argument("<platform>", "Import platform").choices([...IMPORT_PLATFORMS])).requiredOption("--files <ids>", "Comma-separated file/page IDs to import").option("--json", "Output as JSON").action(async (platform, opts) => {
|
|
11712
11861
|
const cfg = requireConfig5();
|
|
11713
11862
|
const client = createTypedClient(cfg);
|
|
@@ -12173,21 +12322,21 @@ var init_branch = __esm(() => {
|
|
|
12173
12322
|
});
|
|
12174
12323
|
|
|
12175
12324
|
// src/sessions/capture.ts
|
|
12176
|
-
import { existsSync as
|
|
12177
|
-
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";
|
|
12178
12327
|
function capturePath(configDir, key) {
|
|
12179
12328
|
const [harness, id, ...rest] = key.split("/");
|
|
12180
12329
|
if (rest.length > 0 || !SAFE_SEGMENT.test(harness ?? "") || !SAFE_SEGMENT.test(id ?? "")) {
|
|
12181
12330
|
return null;
|
|
12182
12331
|
}
|
|
12183
|
-
return
|
|
12332
|
+
return join11(configDir, CAPTURE_DIRNAME, harness, `${id}.json`);
|
|
12184
12333
|
}
|
|
12185
12334
|
function readCapturedSession(key, configDir = getConfigDir()) {
|
|
12186
12335
|
const path = capturePath(configDir, key);
|
|
12187
12336
|
if (!path)
|
|
12188
12337
|
return null;
|
|
12189
12338
|
try {
|
|
12190
|
-
const raw = JSON.parse(
|
|
12339
|
+
const raw = JSON.parse(readFileSync13(path, "utf-8"));
|
|
12191
12340
|
return {
|
|
12192
12341
|
...typeof raw.dir === "string" ? { dir: raw.dir } : {},
|
|
12193
12342
|
...typeof raw.branch === "string" ? { branch: raw.branch } : {},
|
|
@@ -12210,11 +12359,11 @@ function recordCapturedSession(key, update, configDir = getConfigDir(), now = ne
|
|
|
12210
12359
|
at: now.toISOString()
|
|
12211
12360
|
};
|
|
12212
12361
|
try {
|
|
12213
|
-
const parent =
|
|
12214
|
-
if (!
|
|
12362
|
+
const parent = join11(path, "..");
|
|
12363
|
+
if (!existsSync12(parent))
|
|
12215
12364
|
mkdirSync7(parent, { recursive: true, mode: 448 });
|
|
12216
12365
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
12217
|
-
|
|
12366
|
+
writeFileSync8(tmp, JSON.stringify(record), { mode: 384 });
|
|
12218
12367
|
renameSync3(tmp, path);
|
|
12219
12368
|
return true;
|
|
12220
12369
|
} catch (err) {
|
|
@@ -12295,22 +12444,22 @@ var init_capture = __esm(() => {
|
|
|
12295
12444
|
// src/sessions/project-dir.ts
|
|
12296
12445
|
import {
|
|
12297
12446
|
closeSync as closeSync4,
|
|
12298
|
-
existsSync as
|
|
12447
|
+
existsSync as existsSync13,
|
|
12299
12448
|
mkdirSync as mkdirSync8,
|
|
12300
12449
|
openSync as openSync4,
|
|
12301
|
-
readFileSync as
|
|
12450
|
+
readFileSync as readFileSync14,
|
|
12302
12451
|
readSync as readSync3,
|
|
12303
12452
|
renameSync as renameSync4,
|
|
12304
|
-
statSync as
|
|
12305
|
-
writeFileSync as
|
|
12453
|
+
statSync as statSync6,
|
|
12454
|
+
writeFileSync as writeFileSync9
|
|
12306
12455
|
} from "node:fs";
|
|
12307
|
-
import { join as
|
|
12456
|
+
import { join as join12 } from "node:path";
|
|
12308
12457
|
function cachePath(configDir) {
|
|
12309
|
-
return
|
|
12458
|
+
return join12(configDir, CACHE_FILENAME2);
|
|
12310
12459
|
}
|
|
12311
12460
|
function loadCacheFile(configDir) {
|
|
12312
12461
|
try {
|
|
12313
|
-
const raw = JSON.parse(
|
|
12462
|
+
const raw = JSON.parse(readFileSync14(cachePath(configDir), "utf-8"));
|
|
12314
12463
|
if (raw.schema_version !== CACHE_SCHEMA_VERSION || typeof raw.entries !== "object")
|
|
12315
12464
|
return {};
|
|
12316
12465
|
return raw.entries;
|
|
@@ -12320,12 +12469,12 @@ function loadCacheFile(configDir) {
|
|
|
12320
12469
|
}
|
|
12321
12470
|
function saveCacheFile(configDir, entries) {
|
|
12322
12471
|
try {
|
|
12323
|
-
if (!
|
|
12472
|
+
if (!existsSync13(configDir))
|
|
12324
12473
|
mkdirSync8(configDir, { recursive: true, mode: 448 });
|
|
12325
12474
|
const path = cachePath(configDir);
|
|
12326
12475
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
12327
12476
|
const file = { schema_version: CACHE_SCHEMA_VERSION, entries };
|
|
12328
|
-
|
|
12477
|
+
writeFileSync9(tmp, JSON.stringify(file), { mode: 384 });
|
|
12329
12478
|
renameSync4(tmp, path);
|
|
12330
12479
|
} catch {}
|
|
12331
12480
|
}
|
|
@@ -12360,7 +12509,7 @@ function cwdFromJsonlHead(text) {
|
|
|
12360
12509
|
}
|
|
12361
12510
|
return null;
|
|
12362
12511
|
}
|
|
12363
|
-
function unmungeSlug(slug, exists =
|
|
12512
|
+
function unmungeSlug(slug, exists = existsSync13) {
|
|
12364
12513
|
const tokens = slug.replace(/^-/, "").split("-");
|
|
12365
12514
|
if (tokens.length === 0 || tokens[0] === "")
|
|
12366
12515
|
return null;
|
|
@@ -12379,20 +12528,20 @@ function unmungeSlug(slug, exists = existsSync12) {
|
|
|
12379
12528
|
}
|
|
12380
12529
|
function readWholeFile(path) {
|
|
12381
12530
|
try {
|
|
12382
|
-
return
|
|
12531
|
+
return readFileSync14(path, "utf-8");
|
|
12383
12532
|
} catch {
|
|
12384
12533
|
return null;
|
|
12385
12534
|
}
|
|
12386
12535
|
}
|
|
12387
12536
|
function fileMtime(path) {
|
|
12388
12537
|
try {
|
|
12389
|
-
return
|
|
12538
|
+
return statSync6(path).mtime.toISOString();
|
|
12390
12539
|
} catch {
|
|
12391
12540
|
return "";
|
|
12392
12541
|
}
|
|
12393
12542
|
}
|
|
12394
12543
|
function createProjectDirResolver(configDir = getConfigDir(), deps = {}) {
|
|
12395
|
-
const exists = deps.exists ??
|
|
12544
|
+
const exists = deps.exists ?? existsSync13;
|
|
12396
12545
|
const head = deps.readHead ?? readHead;
|
|
12397
12546
|
const mtime = deps.mtime ?? fileMtime;
|
|
12398
12547
|
const captured = deps.captured ?? ((key) => readCapturedSession(key, configDir));
|
|
@@ -13243,7 +13392,7 @@ var init_queries = __esm(() => {
|
|
|
13243
13392
|
});
|
|
13244
13393
|
|
|
13245
13394
|
// src/report/digest.ts
|
|
13246
|
-
import { readFileSync as
|
|
13395
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
13247
13396
|
function asRecord2(value) {
|
|
13248
13397
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
13249
13398
|
}
|
|
@@ -13474,11 +13623,11 @@ function sessionToDigest(session) {
|
|
|
13474
13623
|
try {
|
|
13475
13624
|
switch (session.harness) {
|
|
13476
13625
|
case "claude":
|
|
13477
|
-
return { turns: digestClaude(
|
|
13626
|
+
return { turns: digestClaude(readFileSync15(session.path, "utf8")) };
|
|
13478
13627
|
case "cursor":
|
|
13479
|
-
return { turns: digestCursor(
|
|
13628
|
+
return { turns: digestCursor(readFileSync15(session.path, "utf8")) };
|
|
13480
13629
|
case "codex":
|
|
13481
|
-
return { turns: digestCodex(
|
|
13630
|
+
return { turns: digestCodex(readFileSync15(session.path, "utf8")) };
|
|
13482
13631
|
case "opencode": {
|
|
13483
13632
|
const turns = readSessionTurns(session).map((turn, index) => ({
|
|
13484
13633
|
role: turn.role,
|
|
@@ -13699,17 +13848,17 @@ var init_notes = __esm(() => {
|
|
|
13699
13848
|
});
|
|
13700
13849
|
|
|
13701
13850
|
// src/report/write.ts
|
|
13702
|
-
import { mkdirSync as mkdirSync9, writeFileSync as
|
|
13851
|
+
import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync10 } from "node:fs";
|
|
13703
13852
|
import { tmpdir } from "node:os";
|
|
13704
|
-
import { dirname as dirname4, join as
|
|
13853
|
+
import { dirname as dirname4, join as join13, resolve as resolve2 } from "node:path";
|
|
13705
13854
|
import { pathToFileURL } from "node:url";
|
|
13706
13855
|
function defaultReportPath() {
|
|
13707
|
-
return
|
|
13856
|
+
return join13(tmpdir(), "dosu-knowledge-report.html");
|
|
13708
13857
|
}
|
|
13709
13858
|
async function writeAndOpenReport(options) {
|
|
13710
13859
|
const out = resolve2(options.out ?? defaultReportPath());
|
|
13711
13860
|
mkdirSync9(dirname4(out), { recursive: true });
|
|
13712
|
-
|
|
13861
|
+
writeFileSync10(out, options.html, "utf8");
|
|
13713
13862
|
if (options.open !== false) {
|
|
13714
13863
|
const url = pathToFileURL(out).href;
|
|
13715
13864
|
if (options.openUrl) {
|
|
@@ -13792,7 +13941,8 @@ function listSessionBacklog() {
|
|
|
13792
13941
|
const sessions = filterSessionsByRepo(scanned, filter, resolver.resolveRepo);
|
|
13793
13942
|
resolver.flush();
|
|
13794
13943
|
const gate = gateSessions(sessions, state.watermark);
|
|
13795
|
-
const
|
|
13944
|
+
const incognitoAgents = new Set(state.incognito_agents ?? []);
|
|
13945
|
+
const { kept, skipped } = partitionIncognitoSessions(gate.ready, (session) => incognitoAgents.has(session.harness) || isIncognitoSession(session));
|
|
13796
13946
|
return { queued: kept.reverse(), open: gate.open.reverse(), incognito: skipped.reverse() };
|
|
13797
13947
|
} catch {
|
|
13798
13948
|
return { queued: [], open: [], incognito: [] };
|
|
@@ -13805,155 +13955,6 @@ var init_backlog = __esm(() => {
|
|
|
13805
13955
|
init_watermark();
|
|
13806
13956
|
});
|
|
13807
13957
|
|
|
13808
|
-
// src/sync/lock.ts
|
|
13809
|
-
import { existsSync as existsSync13, readFileSync as readFileSync14, rmSync as rmSync2, statSync as statSync5, writeFileSync as writeFileSync10 } from "node:fs";
|
|
13810
|
-
import { join as join13 } from "node:path";
|
|
13811
|
-
function processAlive(pid) {
|
|
13812
|
-
try {
|
|
13813
|
-
process.kill(pid, 0);
|
|
13814
|
-
return true;
|
|
13815
|
-
} catch (err) {
|
|
13816
|
-
return err.code === "EPERM";
|
|
13817
|
-
}
|
|
13818
|
-
}
|
|
13819
|
-
function lockPath(configDir = getConfigDir()) {
|
|
13820
|
-
return join13(configDir, LOCK_FILENAME);
|
|
13821
|
-
}
|
|
13822
|
-
function stopSyncRun(pid, configDir = getConfigDir(), kill = process.kill.bind(process)) {
|
|
13823
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
13824
|
-
return false;
|
|
13825
|
-
let killed = false;
|
|
13826
|
-
try {
|
|
13827
|
-
kill(-pid, "SIGTERM");
|
|
13828
|
-
killed = true;
|
|
13829
|
-
} catch {
|
|
13830
|
-
try {
|
|
13831
|
-
kill(pid, "SIGTERM");
|
|
13832
|
-
killed = true;
|
|
13833
|
-
} catch {}
|
|
13834
|
-
}
|
|
13835
|
-
try {
|
|
13836
|
-
const path = lockPath(configDir);
|
|
13837
|
-
if (existsSync13(path) && readFileSync14(path, "utf8") === String(pid)) {
|
|
13838
|
-
rmSync2(path, { force: true });
|
|
13839
|
-
}
|
|
13840
|
-
} catch {}
|
|
13841
|
-
return killed;
|
|
13842
|
-
}
|
|
13843
|
-
function fileLock(configDir = getConfigDir(), now = () => new Date) {
|
|
13844
|
-
const path = lockPath(configDir);
|
|
13845
|
-
let held = false;
|
|
13846
|
-
const tryCreate = () => {
|
|
13847
|
-
try {
|
|
13848
|
-
writeFileSync10(path, String(process.pid), { flag: "wx" });
|
|
13849
|
-
return true;
|
|
13850
|
-
} catch {
|
|
13851
|
-
return false;
|
|
13852
|
-
}
|
|
13853
|
-
};
|
|
13854
|
-
return {
|
|
13855
|
-
acquire() {
|
|
13856
|
-
if (tryCreate()) {
|
|
13857
|
-
held = true;
|
|
13858
|
-
return true;
|
|
13859
|
-
}
|
|
13860
|
-
try {
|
|
13861
|
-
const age = now().getTime() - statSync5(path).mtimeMs;
|
|
13862
|
-
const holder = Number.parseInt(readFileSync14(path, "utf8"), 10);
|
|
13863
|
-
const holderDead = Number.isInteger(holder) && holder > 0 && !processAlive(holder);
|
|
13864
|
-
if (age > STALE_LOCK_MS || holderDead) {
|
|
13865
|
-
rmSync2(path, { force: true });
|
|
13866
|
-
held = tryCreate();
|
|
13867
|
-
return held;
|
|
13868
|
-
}
|
|
13869
|
-
} catch {}
|
|
13870
|
-
return false;
|
|
13871
|
-
},
|
|
13872
|
-
release() {
|
|
13873
|
-
if (!held)
|
|
13874
|
-
return;
|
|
13875
|
-
held = false;
|
|
13876
|
-
try {
|
|
13877
|
-
if (existsSync13(path) && readFileSync14(path, "utf8") === String(process.pid)) {
|
|
13878
|
-
rmSync2(path, { force: true });
|
|
13879
|
-
}
|
|
13880
|
-
} catch {}
|
|
13881
|
-
}
|
|
13882
|
-
};
|
|
13883
|
-
}
|
|
13884
|
-
var LOCK_FILENAME = "knowledge-sync.lock", STALE_LOCK_MS;
|
|
13885
|
-
var init_lock = __esm(() => {
|
|
13886
|
-
init_config();
|
|
13887
|
-
STALE_LOCK_MS = 15 * 60 * 1000;
|
|
13888
|
-
});
|
|
13889
|
-
|
|
13890
|
-
// src/sync/status.ts
|
|
13891
|
-
import { readFileSync as readFileSync15, statSync as statSync6 } from "node:fs";
|
|
13892
|
-
function formatTokenCount(tokens) {
|
|
13893
|
-
if (tokens < 1000)
|
|
13894
|
-
return String(tokens);
|
|
13895
|
-
if (tokens < 1e6) {
|
|
13896
|
-
const k = tokens / 1000;
|
|
13897
|
-
return `~${k >= 100 ? Math.round(k) : k.toFixed(1).replace(/\.0$/, "")}k`;
|
|
13898
|
-
}
|
|
13899
|
-
const m = tokens / 1e6;
|
|
13900
|
-
return `~${m >= 100 ? Math.round(m) : m.toFixed(1).replace(/\.0$/, "")}M`;
|
|
13901
|
-
}
|
|
13902
|
-
function defaultIsProcessAlive2(pid) {
|
|
13903
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
13904
|
-
return false;
|
|
13905
|
-
try {
|
|
13906
|
-
process.kill(pid, 0);
|
|
13907
|
-
return true;
|
|
13908
|
-
} catch (err) {
|
|
13909
|
-
return err.code === "EPERM";
|
|
13910
|
-
}
|
|
13911
|
-
}
|
|
13912
|
-
function defaultReadLog() {
|
|
13913
|
-
try {
|
|
13914
|
-
return readFileSync15(logger.getLogPath(), "utf-8");
|
|
13915
|
-
} catch {
|
|
13916
|
-
return "";
|
|
13917
|
-
}
|
|
13918
|
-
}
|
|
13919
|
-
function readLockFile(configDir) {
|
|
13920
|
-
const path = lockPath(configDir);
|
|
13921
|
-
try {
|
|
13922
|
-
const pid = Number.parseInt(readFileSync15(path, "utf-8"), 10);
|
|
13923
|
-
return { pid: Number.isNaN(pid) ? -1 : pid, mtime: statSync6(path).mtime };
|
|
13924
|
-
} catch {
|
|
13925
|
-
return null;
|
|
13926
|
-
}
|
|
13927
|
-
}
|
|
13928
|
-
function recentSyncActivity(log) {
|
|
13929
|
-
return log.split(`
|
|
13930
|
-
`).filter((line) => line.includes("[sync]") || line.includes("[learner]")).slice(-ACTIVITY_LINES).map((line) => line.replace(/ \[(DEBUG|INFO|WARN|ERROR)\]/, ""));
|
|
13931
|
-
}
|
|
13932
|
-
function getSyncStatus(deps = {}) {
|
|
13933
|
-
const configDir = deps.configDir ?? getConfigDir();
|
|
13934
|
-
const isProcessAlive = deps.isProcessAlive ?? defaultIsProcessAlive2;
|
|
13935
|
-
const readLog = deps.readLog ?? defaultReadLog;
|
|
13936
|
-
const lock = readLockFile(configDir);
|
|
13937
|
-
const running = lock !== null && isProcessAlive(lock.pid);
|
|
13938
|
-
const state = loadSyncState(configDir);
|
|
13939
|
-
const retryAt = backoffUntil(state);
|
|
13940
|
-
return {
|
|
13941
|
-
running,
|
|
13942
|
-
...lock ? { pid: lock.pid, startedAt: lock.mtime.toISOString() } : {},
|
|
13943
|
-
...lock && !running ? { staleLock: true } : {},
|
|
13944
|
-
state,
|
|
13945
|
-
...retryAt ? { backoffUntil: retryAt.toISOString() } : {},
|
|
13946
|
-
recentActivity: recentSyncActivity(readLog())
|
|
13947
|
-
};
|
|
13948
|
-
}
|
|
13949
|
-
var ACTIVITY_LINES = 10;
|
|
13950
|
-
var init_status = __esm(() => {
|
|
13951
|
-
init_config();
|
|
13952
|
-
init_logger();
|
|
13953
|
-
init_lock();
|
|
13954
|
-
init_watermark();
|
|
13955
|
-
});
|
|
13956
|
-
|
|
13957
13958
|
// src/sync/sync.ts
|
|
13958
13959
|
function logGateResult(ready, inFlight, watermark) {
|
|
13959
13960
|
const preview = ready.slice(0, LOG_PREVIEW_LIMIT).map((s) => `${s.harness}/${s.id}`).join(", ");
|
|
@@ -14079,7 +14080,9 @@ async function runKnowledgeSync(options = {}) {
|
|
|
14079
14080
|
};
|
|
14080
14081
|
}
|
|
14081
14082
|
const worthStudying = deps.worthStudying ?? isWorthStudying;
|
|
14082
|
-
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);
|
|
14083
14086
|
const studiedSnapshot = lastStudiedSnapshot(state.mined_sessions);
|
|
14084
14087
|
const examined = [];
|
|
14085
14088
|
const batch = [];
|
|
@@ -14286,7 +14289,7 @@ var init_conflicts = __esm(() => {
|
|
|
14286
14289
|
});
|
|
14287
14290
|
|
|
14288
14291
|
// src/telemetry/debug-id.ts
|
|
14289
|
-
var BUNDLE_DEBUG_ID_PLACEHOLDER = "
|
|
14292
|
+
var BUNDLE_DEBUG_ID_PLACEHOLDER = "8627229c-9519-9318-6475-6e2164756e21";
|
|
14290
14293
|
|
|
14291
14294
|
// src/telemetry/telemetry.ts
|
|
14292
14295
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -15407,14 +15410,43 @@ Acknowledge in one line: "Dosu incognito: this session will not be studied."
|
|
|
15407
15410
|
});
|
|
15408
15411
|
|
|
15409
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
|
+
}
|
|
15410
15440
|
function incognitoCommand() {
|
|
15411
|
-
const cmd = new Command("incognito").description(
|
|
15412
|
-
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 ?? []);
|
|
15413
15444
|
const rows = allIncognitoAgents().map((agent) => ({
|
|
15414
15445
|
agent: agent.id(),
|
|
15415
15446
|
name: agent.name(),
|
|
15416
15447
|
installed: agent.isInstalled(),
|
|
15417
|
-
|
|
15448
|
+
incognito: incognitoAgents.has(agent.id()),
|
|
15449
|
+
command_installed: agent.isEnabled(),
|
|
15418
15450
|
command_path: agent.commandPath()
|
|
15419
15451
|
}));
|
|
15420
15452
|
if (opts.json) {
|
|
@@ -15422,49 +15454,33 @@ function incognitoCommand() {
|
|
|
15422
15454
|
return;
|
|
15423
15455
|
}
|
|
15424
15456
|
for (const row of rows) {
|
|
15425
|
-
const state = !row.installed ? import_picocolors20.default.dim("not
|
|
15426
|
-
|
|
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}`);
|
|
15427
15460
|
}
|
|
15428
15461
|
console.log(import_picocolors20.default.dim(`
|
|
15429
|
-
Use 'dosu knowledge incognito
|
|
15430
|
-
` + `
|
|
15431
|
-
});
|
|
15432
|
-
cmd.command("enable [agents...]").description("Install the slash command for agents (default: all detected)").action((ids) => {
|
|
15433
|
-
for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
|
|
15434
|
-
try {
|
|
15435
|
-
const action = agent.enable();
|
|
15436
|
-
const verb = action === "unchanged" ? "already installed" : "installed";
|
|
15437
|
-
console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb} (${agent.commandPath()})`);
|
|
15438
|
-
} catch (err) {
|
|
15439
|
-
reportFailure(agent.name(), err);
|
|
15440
|
-
}
|
|
15441
|
-
}
|
|
15442
|
-
});
|
|
15443
|
-
cmd.command("disable [agents...]").description("Remove the slash command from agents (default: all detected)").action((ids) => {
|
|
15444
|
-
for (const agent of resolveAgents(ids, allIncognitoAgents, getIncognitoAgent)) {
|
|
15445
|
-
try {
|
|
15446
|
-
const action = agent.disable();
|
|
15447
|
-
const verb = action === "removed" ? "removed" : "was not installed";
|
|
15448
|
-
console.log(`✓ ${agent.name()} · /${INCOGNITO_COMMAND_NAME} ${verb}`);
|
|
15449
|
-
} catch (err) {
|
|
15450
|
-
reportFailure(agent.name(), err);
|
|
15451
|
-
}
|
|
15452
|
-
}
|
|
15462
|
+
Use 'dosu knowledge incognito on|off [agent...]' to change these.
|
|
15463
|
+
` + `To keep a single chat out instead, type ${SLASH} in it.`));
|
|
15453
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));
|
|
15454
15467
|
return cmd;
|
|
15455
15468
|
}
|
|
15456
|
-
function reportFailure(
|
|
15457
|
-
|
|
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}`));
|
|
15458
15472
|
process.exitCode = 1;
|
|
15459
15473
|
}
|
|
15460
|
-
var import_picocolors20;
|
|
15474
|
+
var import_picocolors20, SLASH;
|
|
15461
15475
|
var init_knowledge_incognito = __esm(() => {
|
|
15462
15476
|
init_commander();
|
|
15463
15477
|
init_agents3();
|
|
15464
15478
|
init_incognito();
|
|
15479
|
+
init_watermark();
|
|
15465
15480
|
init_agent_select();
|
|
15466
15481
|
init_output();
|
|
15467
15482
|
import_picocolors20 = __toESM(require_picocolors(), 1);
|
|
15483
|
+
SLASH = `/${INCOGNITO_COMMAND_NAME}`;
|
|
15468
15484
|
});
|
|
15469
15485
|
|
|
15470
15486
|
// src/statusline/agents.ts
|
|
@@ -60643,7 +60659,7 @@ Operate Dosu through \`dosu\`. Prefer structured output and let the CLI and App
|
|
|
60643
60659
|
|
|
60644
60660
|
- \`dosu login\` supplies the JWT used by tRPC-backed commands.
|
|
60645
60661
|
- \`dosu setup\` selects an organization, Library context, and MCP deployment, creates an API key, and can configure an agent tool.
|
|
60646
|
-
- \`dosu ask\` needs an API key. \`docs
|
|
60662
|
+
- \`dosu ask\` needs an API key. \`docs publish\` needs both JWT login and the API key. Other platform commands generally need JWT login; commands scoped to an organization or current Library also need the corresponding setup selection.
|
|
60647
60663
|
- For coding-agent setup, follow the nonblocking \`dosu setup --agent --tool <id>\` workflow in [workflows.md](references/workflows.md). Relay its URL and execute its returned \`resume_command\`; never invent ticket commands.
|
|
60648
60664
|
|
|
60649
60665
|
## Use current product terms
|
|
@@ -61044,8 +61060,6 @@ dosu docs unarchive <id> [--json]
|
|
|
61044
61060
|
dosu docs delete <id> [--json]
|
|
61045
61061
|
dosu docs versions <id> [--json]
|
|
61046
61062
|
dosu docs restore <id> --revision <positive-int> [--json]
|
|
61047
|
-
dosu docs generate --title <title> [--instructions <text>] [--json]
|
|
61048
|
-
dosu docs auto-tag <id> [--json]
|
|
61049
61063
|
dosu docs import <platform> --files <comma-separated-ids> [--json]
|
|
61050
61064
|
dosu docs import-status <task-id> [--json]
|
|
61051
61065
|
dosu docs publish <id> --to <platform> [target flags] [--json]
|
|
@@ -61055,7 +61069,7 @@ dosu docs sync-back <id> [--json]
|
|
|
61055
61069
|
- Document list defaults to 20. \`create\` and \`update\` reject combining \`--body\` with \`--body-file\`; \`update\` requires at least one field.
|
|
61056
61070
|
- Import platforms: \`github\`, \`gitlab\`, \`azure_devops\`, \`confluence\`, \`notion\`, \`coda\`.
|
|
61057
61071
|
- Publish platforms: the same six. Target flags are \`--repo-id\`, \`--project-id\`, \`--parent-page-id\`, \`--doc-id\`, \`--directory\`, and \`--data-source-id\`; Azure DevOps requires \`--data-source-id\`. Other target validation may occur in the backend.
|
|
61058
|
-
-
|
|
61072
|
+
- Import, publish, and sync operations may be asynchronous. Use the returned task/status identifiers rather than assuming completion.
|
|
61059
61073
|
|
|
61060
61074
|
## Review
|
|
61061
61075
|
|
|
@@ -66216,7 +66230,7 @@ ${dim(wrapLog("Dosu scans finished agent sessions in the background. Disable any
|
|
|
66216
66230
|
const statuslines = installed.flatMap((r) => r.statusline ? [r.statusline] : []);
|
|
66217
66231
|
if (statuslines.length > 0) {
|
|
66218
66232
|
log2.success(`${formatSetupSummary(`Status line enabled for ${statuslines.length} agent(s):`, statuslines.map((item) => ({ label: item.name, path: item.path })))}
|
|
66219
|
-
${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'."))}`);
|
|
66220
66234
|
}
|
|
66221
66235
|
for (const result of installed) {
|
|
66222
66236
|
if (result.statuslineSuggestion) {
|
|
@@ -66227,7 +66241,7 @@ ${dim(wrapLog("Shows \uD83D\uDCDA Dosu studying…, \uD83D\uDC7B Dosu incognito,
|
|
|
66227
66241
|
const incognitos = installed.flatMap((r) => r.incognito ? [r.incognito] : []);
|
|
66228
66242
|
if (incognitos.length > 0) {
|
|
66229
66243
|
log2.success(`${formatSetupSummary(`/dosu-incognito installed for ${incognitos.length} agent(s):`, incognitos.map((item) => ({ label: item.name, path: item.path })))}
|
|
66230
|
-
${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>'."))}`);
|
|
66231
66245
|
}
|
|
66232
66246
|
if (removed.length > 0) {
|
|
66233
66247
|
log2.info(formatSetupSummary(`Removed from ${removed.length} agent(s):`, removed.map((result) => ({
|
|
@@ -66568,6 +66582,64 @@ var init_upgrade = __esm(() => {
|
|
|
66568
66582
|
SEMVER = /^\d+\.\d+\.\d+/;
|
|
66569
66583
|
});
|
|
66570
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
|
+
|
|
66571
66643
|
// src/tui/analytics-view.ts
|
|
66572
66644
|
function analyticsListHeight(rows) {
|
|
66573
66645
|
const room = frameMaxLines(rows) - ANALYTICS_VIEW_CHROME_LINES;
|
|
@@ -66686,7 +66758,7 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
|
|
|
66686
66758
|
const rows = analyticsTabRows(tab, state, pageStats);
|
|
66687
66759
|
const { visible, above, below } = windowReport(rows, scroll, height);
|
|
66688
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.";
|
|
66689
|
-
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)];
|
|
66690
66762
|
const scrollParts = [];
|
|
66691
66763
|
if (above > 0)
|
|
66692
66764
|
scrollParts.push(`↑ ${above} earlier`);
|
|
@@ -66702,9 +66774,9 @@ function renderAnalyticsFrame(state, tab, scroll, pageStats = null, pagesPending
|
|
|
66702
66774
|
], tab, width, { spread: false }),
|
|
66703
66775
|
"",
|
|
66704
66776
|
...listRows,
|
|
66705
|
-
...scrollParts.length > 0 ? [
|
|
66777
|
+
...scrollParts.length > 0 ? [import_picocolors39.default.dim(scrollParts.join(" · "))] : [],
|
|
66706
66778
|
"",
|
|
66707
|
-
|
|
66779
|
+
import_picocolors39.default.dim("tab switch · ↑↓ scroll · esc back")
|
|
66708
66780
|
];
|
|
66709
66781
|
return lines.join(`
|
|
66710
66782
|
`);
|
|
@@ -66801,7 +66873,7 @@ ${CLEAR_BELOW2}`);
|
|
|
66801
66873
|
input.on("data", onData);
|
|
66802
66874
|
});
|
|
66803
66875
|
}
|
|
66804
|
-
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);
|
|
66805
66877
|
var init_analytics_view = __esm(() => {
|
|
66806
66878
|
init_trpc();
|
|
66807
66879
|
init_config();
|
|
@@ -66809,7 +66881,7 @@ var init_analytics_view = __esm(() => {
|
|
|
66809
66881
|
init_alt_screen();
|
|
66810
66882
|
init_layout();
|
|
66811
66883
|
init_menu();
|
|
66812
|
-
|
|
66884
|
+
import_picocolors39 = __toESM(require_picocolors(), 1);
|
|
66813
66885
|
ESC8 = String.fromCharCode(27);
|
|
66814
66886
|
HIDE_CURSOR4 = `${ESC8}[?25l`;
|
|
66815
66887
|
SHOW_CURSOR4 = `${ESC8}[?25h`;
|
|
@@ -66827,7 +66899,7 @@ var init_analytics_view = __esm(() => {
|
|
|
66827
66899
|
// src/tui/banner.ts
|
|
66828
66900
|
function paintLogoRow(row) {
|
|
66829
66901
|
return row.map(([tone, art]) => {
|
|
66830
|
-
if (!
|
|
66902
|
+
if (!import_picocolors40.default.isColorSupported)
|
|
66831
66903
|
return art;
|
|
66832
66904
|
const { fg, fallback } = LOGO_TONES[tone];
|
|
66833
66905
|
return hasTruecolor() ? `${fg}${art}\x1B[39m` : fallback(art);
|
|
@@ -66835,14 +66907,14 @@ function paintLogoRow(row) {
|
|
|
66835
66907
|
}
|
|
66836
66908
|
function checklistRows(ctx) {
|
|
66837
66909
|
const on = brand(CHECK2);
|
|
66838
|
-
const off =
|
|
66910
|
+
const off = import_picocolors40.default.dim(CIRCLE);
|
|
66839
66911
|
const rows = [["workspace", ctx.directory]];
|
|
66840
66912
|
rows.push([
|
|
66841
66913
|
"account",
|
|
66842
|
-
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`)}`
|
|
66843
66915
|
]);
|
|
66844
66916
|
const missing = new Set(ctx.setupMissing ?? []);
|
|
66845
|
-
const warnRow = `${off} ${
|
|
66917
|
+
const warnRow = `${off} ${import_picocolors40.default.yellow("not configured")} ${import_picocolors40.default.dim(`${DOT3} run Setup`)}`;
|
|
66846
66918
|
if (missing.has("MCP"))
|
|
66847
66919
|
rows.push(["mcp", warnRow]);
|
|
66848
66920
|
else if (ctx.deploymentName)
|
|
@@ -66854,7 +66926,7 @@ function checklistRows(ctx) {
|
|
|
66854
66926
|
if (ctx.repoAgentsMd) {
|
|
66855
66927
|
rows.push([
|
|
66856
66928
|
"repo",
|
|
66857
|
-
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`)}`
|
|
66858
66930
|
]);
|
|
66859
66931
|
}
|
|
66860
66932
|
if (missing.has("agents"))
|
|
@@ -66866,24 +66938,24 @@ function checklistRows(ctx) {
|
|
|
66866
66938
|
if (ctx.studying) {
|
|
66867
66939
|
rows.push([
|
|
66868
66940
|
"sync",
|
|
66869
|
-
`\uD83D\uDCDA ${brand("studying sessions...")} ${
|
|
66941
|
+
`\uD83D\uDCDA ${brand("studying sessions...")} ${import_picocolors40.default.dim(`${DOT3} see activity`)}`
|
|
66870
66942
|
]);
|
|
66871
66943
|
}
|
|
66872
66944
|
if (ctx.update) {
|
|
66873
66945
|
rows.push([
|
|
66874
66946
|
"update",
|
|
66875
|
-
`${
|
|
66947
|
+
`${import_picocolors40.default.yellow(`↑ ${ctx.update.version} available`)} ${import_picocolors40.default.dim(`${DOT3} ${ctx.update.hint}`)}`
|
|
66876
66948
|
]);
|
|
66877
66949
|
}
|
|
66878
66950
|
const labelWidth = Math.max(...rows.map(([label]) => label.length));
|
|
66879
|
-
return rows.map(([label, value]) => `${
|
|
66951
|
+
return rows.map(([label, value]) => `${import_picocolors40.default.dim(label.padEnd(labelWidth))} ${value}`);
|
|
66880
66952
|
}
|
|
66881
66953
|
function renderBanner(ctx) {
|
|
66882
66954
|
const logo = LOGO_ROWS.map(paintLogoRow);
|
|
66883
66955
|
const text = [
|
|
66884
66956
|
...checklistRows(ctx),
|
|
66885
66957
|
"",
|
|
66886
|
-
`${brandBadge("dosu-cli")} ${
|
|
66958
|
+
`${brandBadge("dosu-cli")} ${import_picocolors40.default.dim(`${ctx.version} ${DOT3} ${ctx.webAppHost}`)}`
|
|
66887
66959
|
];
|
|
66888
66960
|
const height = Math.max(logo.length, text.length);
|
|
66889
66961
|
const combined = [];
|
|
@@ -66896,10 +66968,10 @@ function renderBanner(ctx) {
|
|
|
66896
66968
|
return ["", ...combined, ""].join(`
|
|
66897
66969
|
`);
|
|
66898
66970
|
}
|
|
66899
|
-
var
|
|
66971
|
+
var import_picocolors40, CHECK2 = "✔", CIRCLE = "○", DOT3 = "·", LOGO_ROWS, LOGO_MARK, LOGO_WIDTH, LOGO_TONES, COLUMN_GAP = " ";
|
|
66900
66972
|
var init_banner = __esm(() => {
|
|
66901
66973
|
init_styles();
|
|
66902
|
-
|
|
66974
|
+
import_picocolors40 = __toESM(require_picocolors(), 1);
|
|
66903
66975
|
LOGO_ROWS = [
|
|
66904
66976
|
[["sage", "▄▄▄▄▄▄"]],
|
|
66905
66977
|
[["sage", "██ ▀▄"]],
|
|
@@ -66910,8 +66982,8 @@ var init_banner = __esm(() => {
|
|
|
66910
66982
|
LOGO_MARK = LOGO_ROWS.map((row) => row.map(([, art]) => art).join(""));
|
|
66911
66983
|
LOGO_WIDTH = Math.max(...LOGO_MARK.map((row) => row.length));
|
|
66912
66984
|
LOGO_TONES = {
|
|
66913
|
-
sage: { fg: "\x1B[38;2;180;187;145m", fallback:
|
|
66914
|
-
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)) }
|
|
66915
66987
|
};
|
|
66916
66988
|
});
|
|
66917
66989
|
|
|
@@ -67023,16 +67095,16 @@ function renderPagesFrame(model, width, selected) {
|
|
|
67023
67095
|
const body = [];
|
|
67024
67096
|
let scrollHint = "";
|
|
67025
67097
|
if (model.phase === "loading") {
|
|
67026
|
-
body.push(
|
|
67098
|
+
body.push(import_picocolors41.default.dim("Loading pages…"));
|
|
67027
67099
|
} else if (model.phase === "error") {
|
|
67028
|
-
body.push(
|
|
67100
|
+
body.push(import_picocolors41.default.yellow(clip3(model.message, width)));
|
|
67029
67101
|
} else if (model.pages.length === 0) {
|
|
67030
|
-
body.push(
|
|
67102
|
+
body.push(import_picocolors41.default.dim("No pages in this Library yet."));
|
|
67031
67103
|
} else {
|
|
67032
67104
|
const rows = pageRows2(model.pages, width - 2);
|
|
67033
67105
|
const { start, above } = windowSelection(rows.length, selected);
|
|
67034
67106
|
const visible = rows.slice(start, start + PAGES_VIEW_LINES);
|
|
67035
|
-
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)}`));
|
|
67036
67108
|
const below = Math.max(0, Math.max(model.total, rows.length) - start - PAGES_VIEW_LINES);
|
|
67037
67109
|
const parts = [];
|
|
67038
67110
|
if (above > 0)
|
|
@@ -67041,14 +67113,14 @@ function renderPagesFrame(model, width, selected) {
|
|
|
67041
67113
|
parts.push(`↓ ${below} more`);
|
|
67042
67114
|
scrollHint = parts.join(" · ");
|
|
67043
67115
|
}
|
|
67044
|
-
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})`)}` : "";
|
|
67045
67117
|
const lines = [
|
|
67046
67118
|
`${breadcrumb(["home", "pages"], width)}${count}`,
|
|
67047
67119
|
"",
|
|
67048
67120
|
...body,
|
|
67049
|
-
...scrollHint ? [
|
|
67121
|
+
...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
|
|
67050
67122
|
"",
|
|
67051
|
-
|
|
67123
|
+
import_picocolors41.default.dim("↑↓ move · enter open · esc back")
|
|
67052
67124
|
];
|
|
67053
67125
|
return lines.join(`
|
|
67054
67126
|
`);
|
|
@@ -67057,9 +67129,9 @@ function renderPageFrame(page, content, width, scroll) {
|
|
|
67057
67129
|
const body = [];
|
|
67058
67130
|
let scrollHint = "";
|
|
67059
67131
|
if (content.phase === "loading") {
|
|
67060
|
-
body.push(
|
|
67132
|
+
body.push(import_picocolors41.default.dim("Loading page…"));
|
|
67061
67133
|
} else if (content.phase === "error") {
|
|
67062
|
-
body.push(
|
|
67134
|
+
body.push(import_picocolors41.default.yellow(clip3(content.message, width)));
|
|
67063
67135
|
} else {
|
|
67064
67136
|
const rows = wrapBody(content.body, width);
|
|
67065
67137
|
const { visible, above, below } = windowReport(rows, scroll, PAGE_BODY_LINES);
|
|
@@ -67074,12 +67146,12 @@ function renderPageFrame(page, content, width, scroll) {
|
|
|
67074
67146
|
const meta = `${page.type} · ${page.published ? "published" : "draft"} · updated ${page.updated_at.slice(0, 10)}`;
|
|
67075
67147
|
const lines = [
|
|
67076
67148
|
breadcrumb(["home", "pages", page.title], width),
|
|
67077
|
-
|
|
67149
|
+
import_picocolors41.default.dim(clip3(meta, width)),
|
|
67078
67150
|
"",
|
|
67079
67151
|
...body,
|
|
67080
|
-
...scrollHint ? [
|
|
67152
|
+
...scrollHint ? [import_picocolors41.default.dim(scrollHint)] : [],
|
|
67081
67153
|
"",
|
|
67082
|
-
|
|
67154
|
+
import_picocolors41.default.dim("↑↓ scroll · esc back to pages")
|
|
67083
67155
|
];
|
|
67084
67156
|
return lines.join(`
|
|
67085
67157
|
`);
|
|
@@ -67228,7 +67300,7 @@ ${CLEAR_BELOW3}`);
|
|
|
67228
67300
|
input.on("data", onData);
|
|
67229
67301
|
});
|
|
67230
67302
|
}
|
|
67231
|
-
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;
|
|
67232
67304
|
var init_pages_view = __esm(() => {
|
|
67233
67305
|
init_trpc();
|
|
67234
67306
|
init_config();
|
|
@@ -67238,7 +67310,7 @@ var init_pages_view = __esm(() => {
|
|
|
67238
67310
|
init_analytics_view();
|
|
67239
67311
|
init_layout();
|
|
67240
67312
|
init_menu();
|
|
67241
|
-
|
|
67313
|
+
import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
67242
67314
|
ESC9 = String.fromCharCode(27);
|
|
67243
67315
|
HIDE_CURSOR5 = `${ESC9}[?25l`;
|
|
67244
67316
|
SHOW_CURSOR5 = `${ESC9}[?25h`;
|
|
@@ -67351,7 +67423,7 @@ function isSetUp(cfg) {
|
|
|
67351
67423
|
}
|
|
67352
67424
|
function setupHint(cfg) {
|
|
67353
67425
|
const started = Boolean(cfg.active_account?.target);
|
|
67354
|
-
return
|
|
67426
|
+
return import_picocolors42.default.yellow(started ? `incomplete · missing ${missingSetupSteps(cfg).join(" + ")}` : "not set up yet");
|
|
67355
67427
|
}
|
|
67356
67428
|
function isStudying() {
|
|
67357
67429
|
try {
|
|
@@ -67596,7 +67668,7 @@ function handleLogout(cfg) {
|
|
|
67596
67668
|
saveConfig(cfg);
|
|
67597
67669
|
log2.success("Credentials cleared.");
|
|
67598
67670
|
}
|
|
67599
|
-
var
|
|
67671
|
+
var import_picocolors42, ESC10, CLEAR_SCREEN;
|
|
67600
67672
|
var init_tui = __esm(() => {
|
|
67601
67673
|
init_client();
|
|
67602
67674
|
init_config();
|
|
@@ -67620,7 +67692,7 @@ var init_tui = __esm(() => {
|
|
|
67620
67692
|
init_menu();
|
|
67621
67693
|
init_pages_view();
|
|
67622
67694
|
init_prompts();
|
|
67623
|
-
|
|
67695
|
+
import_picocolors42 = __toESM(require_picocolors(), 1);
|
|
67624
67696
|
ESC10 = String.fromCharCode(27);
|
|
67625
67697
|
CLEAR_SCREEN = `${ESC10}[2J${ESC10}[H`;
|
|
67626
67698
|
});
|
|
@@ -68339,6 +68411,7 @@ function createProgram(options = {}) {
|
|
|
68339
68411
|
checkForReadyTasks();
|
|
68340
68412
|
if (shouldRunMcpRefreshCheck(actionCommand)) {
|
|
68341
68413
|
checkForMcpRefresh({ notify: !launchesTUI });
|
|
68414
|
+
checkForIncognitoBackfill({ notify: !launchesTUI });
|
|
68342
68415
|
}
|
|
68343
68416
|
}
|
|
68344
68417
|
const command = commandTelemetryName(actionCommand);
|
|
@@ -68769,6 +68842,7 @@ var init_cli = __esm(() => {
|
|
|
68769
68842
|
init_styles();
|
|
68770
68843
|
init_settings();
|
|
68771
68844
|
init_telemetry();
|
|
68845
|
+
init_incognito_backfill_check();
|
|
68772
68846
|
init_mcp_refresh_check();
|
|
68773
68847
|
init_pending_tasks_check();
|
|
68774
68848
|
init_skill_update_check();
|
|
@@ -68807,4 +68881,4 @@ main().catch((err) => {
|
|
|
68807
68881
|
process.exit(1);
|
|
68808
68882
|
});
|
|
68809
68883
|
|
|
68810
|
-
//# debugId=
|
|
68884
|
+
//# debugId=8627229c-9519-9318-6475-6e2164756e21
|