caveat-cli 0.6.0 → 0.6.2
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/dist/caveat.js +0 -0
- package/dist/index.js +135 -81
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/dist/caveat.js
CHANGED
|
File without changes
|
package/dist/index.js
CHANGED
|
@@ -16095,7 +16095,11 @@ function resolvePaths(caveatHome, knowledgeRepo, userHome) {
|
|
|
16095
16095
|
knowledgeRepo: resolved,
|
|
16096
16096
|
dbPath: join5(caveatHome, "index", "caveat.db"),
|
|
16097
16097
|
entriesDir: join5(resolved, "entries"),
|
|
16098
|
-
|
|
16098
|
+
// community/ lives at caveatHome level, NOT inside knowledgeRepo. Community
|
|
16099
|
+
// clones are external knowledge caches — not semantically "owned" by the
|
|
16100
|
+
// user — and they embed their own .git dirs which would otherwise nest
|
|
16101
|
+
// inside the user's git-tracked knowledge repo.
|
|
16102
|
+
communityDir: join5(caveatHome, "community")
|
|
16099
16103
|
};
|
|
16100
16104
|
}
|
|
16101
16105
|
|
|
@@ -21233,6 +21237,12 @@ async function pushEntry(opts) {
|
|
|
21233
21237
|
detail: `entry id=${opts.id} not found under ${opts.entriesDir}`
|
|
21234
21238
|
};
|
|
21235
21239
|
}
|
|
21240
|
+
if (owned.visibility === "private") {
|
|
21241
|
+
return {
|
|
21242
|
+
status: "visibility-private",
|
|
21243
|
+
detail: `entry id=${opts.id} has visibility: private and cannot be pushed to the public community DB. Update the entry to visibility: public first (the user declared this entry local-only).`
|
|
21244
|
+
};
|
|
21245
|
+
}
|
|
21236
21246
|
const ghUser = resolveGhUser();
|
|
21237
21247
|
if (!ghUser) {
|
|
21238
21248
|
return { status: "failed", detail: "gh api user failed" };
|
|
@@ -21253,16 +21263,16 @@ async function pushEntry(opts) {
|
|
|
21253
21263
|
const stagingDir = forkStagingDir(opts.caveatHome);
|
|
21254
21264
|
ensureStagingClone(stagingDir, ghUser, sharedName, sharedOwner);
|
|
21255
21265
|
const branch = `caveat-push-${owned.id}-${Date.now().toString(36)}`;
|
|
21256
|
-
|
|
21266
|
+
runOrThrow("git", ["checkout", "-b", branch], { cwd: stagingDir });
|
|
21257
21267
|
const destPath = join7(stagingDir, "entries", owned.relPath);
|
|
21258
21268
|
mkdirSync3(dirname4(destPath), { recursive: true });
|
|
21259
21269
|
copyFileSync(owned.absPath, destPath);
|
|
21260
|
-
|
|
21270
|
+
runOrThrow("git", ["add", join7("entries", owned.relPath)], { cwd: stagingDir });
|
|
21261
21271
|
const isUpdate = upstreamAlreadyHas(stagingDir, "entries/" + owned.relPath);
|
|
21262
21272
|
const verb = isUpdate ? "update" : "add";
|
|
21263
21273
|
const commitMsg = `${verb}: ${owned.title}`;
|
|
21264
|
-
|
|
21265
|
-
|
|
21274
|
+
runOrThrow("git", ["commit", "-m", commitMsg], { cwd: stagingDir });
|
|
21275
|
+
runOrThrow("git", ["push", "--set-upstream", "origin", branch], { cwd: stagingDir });
|
|
21266
21276
|
const prTitle = `${verb}: ${owned.title}`;
|
|
21267
21277
|
const prBody = [
|
|
21268
21278
|
`Contribution of caveat \`${owned.id}\` via \`caveat push\`.`,
|
|
@@ -21272,7 +21282,7 @@ async function pushEntry(opts) {
|
|
|
21272
21282
|
"",
|
|
21273
21283
|
"Merged PRs will appear in subscribers' repos on their next `caveat pull`."
|
|
21274
21284
|
].join("\n");
|
|
21275
|
-
const pr =
|
|
21285
|
+
const pr = runCapture(
|
|
21276
21286
|
"gh",
|
|
21277
21287
|
[
|
|
21278
21288
|
"pr",
|
|
@@ -21288,16 +21298,15 @@ async function pushEntry(opts) {
|
|
|
21288
21298
|
"--body",
|
|
21289
21299
|
prBody
|
|
21290
21300
|
],
|
|
21291
|
-
{ cwd: stagingDir
|
|
21301
|
+
{ cwd: stagingDir }
|
|
21292
21302
|
);
|
|
21293
21303
|
if (pr.status !== 0) {
|
|
21294
21304
|
return {
|
|
21295
21305
|
status: "failed",
|
|
21296
|
-
detail: (
|
|
21306
|
+
detail: (pr.stderr || "gh pr create failed").trim()
|
|
21297
21307
|
};
|
|
21298
21308
|
}
|
|
21299
|
-
|
|
21300
|
-
return { status: "ok", prUrl };
|
|
21309
|
+
return { status: "ok", prUrl: pr.stdout.trim() };
|
|
21301
21310
|
} catch (err) {
|
|
21302
21311
|
return {
|
|
21303
21312
|
status: "failed",
|
|
@@ -21305,21 +21314,41 @@ async function pushEntry(opts) {
|
|
|
21305
21314
|
};
|
|
21306
21315
|
}
|
|
21307
21316
|
}
|
|
21317
|
+
function shellQuote(s) {
|
|
21318
|
+
if (!/[\s&|<>^()"`$!*?\[\]{}\\]/.test(s)) return s;
|
|
21319
|
+
return `"${s.replace(/"/g, '""')}"`;
|
|
21320
|
+
}
|
|
21321
|
+
function runCapture(command, args, opts = {}) {
|
|
21322
|
+
const line = [command, ...args].map(shellQuote).join(" ");
|
|
21323
|
+
const r2 = spawnSync(line, {
|
|
21324
|
+
encoding: "utf-8",
|
|
21325
|
+
cwd: opts.cwd,
|
|
21326
|
+
shell: true
|
|
21327
|
+
});
|
|
21328
|
+
return {
|
|
21329
|
+
status: r2.status,
|
|
21330
|
+
stdout: typeof r2.stdout === "string" ? r2.stdout : "",
|
|
21331
|
+
stderr: typeof r2.stderr === "string" ? r2.stderr : ""
|
|
21332
|
+
};
|
|
21333
|
+
}
|
|
21334
|
+
function runOrThrow(command, args, opts = {}) {
|
|
21335
|
+
const r2 = runCapture(command, args, opts);
|
|
21336
|
+
if (r2.status !== 0) {
|
|
21337
|
+
throw new Error(
|
|
21338
|
+
`${command} ${args.join(" ")} failed: ${(r2.stderr || r2.stdout || "unknown").trim()}`
|
|
21339
|
+
);
|
|
21340
|
+
}
|
|
21341
|
+
}
|
|
21308
21342
|
function checkGhAvailable() {
|
|
21309
|
-
|
|
21310
|
-
return r2.status === 0;
|
|
21343
|
+
return runCapture("gh", ["--version"]).status === 0;
|
|
21311
21344
|
}
|
|
21312
21345
|
function checkGhAuthed() {
|
|
21313
|
-
|
|
21314
|
-
return r2.status === 0;
|
|
21346
|
+
return runCapture("gh", ["auth", "status"]).status === 0;
|
|
21315
21347
|
}
|
|
21316
21348
|
function resolveGhUser() {
|
|
21317
|
-
const r2 =
|
|
21318
|
-
encoding: "utf-8",
|
|
21319
|
-
shell: true
|
|
21320
|
-
});
|
|
21349
|
+
const r2 = runCapture("gh", ["api", "user", "--jq", ".login"]);
|
|
21321
21350
|
if (r2.status !== 0) return void 0;
|
|
21322
|
-
return
|
|
21351
|
+
return r2.stdout.trim() || void 0;
|
|
21323
21352
|
}
|
|
21324
21353
|
function parseOwnerRepo(url) {
|
|
21325
21354
|
const m = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(\.git)?\/?$/.exec(url);
|
|
@@ -21339,7 +21368,13 @@ function findOwnedEntry(entriesDir, id) {
|
|
|
21339
21368
|
const parsed = parseMarkdown(raw2);
|
|
21340
21369
|
if (parsed.frontmatter.id === id) {
|
|
21341
21370
|
const relPath = relative2(entriesDir, absPath).replace(/\\/g, "/");
|
|
21342
|
-
return {
|
|
21371
|
+
return {
|
|
21372
|
+
id,
|
|
21373
|
+
title: parsed.frontmatter.title,
|
|
21374
|
+
absPath,
|
|
21375
|
+
relPath,
|
|
21376
|
+
visibility: parsed.frontmatter.visibility
|
|
21377
|
+
};
|
|
21343
21378
|
}
|
|
21344
21379
|
} catch {
|
|
21345
21380
|
}
|
|
@@ -21351,44 +21386,28 @@ function forkStagingDir(caveatHome) {
|
|
|
21351
21386
|
return join7(caveatHome, "push-fork");
|
|
21352
21387
|
}
|
|
21353
21388
|
function ensureFork(owner, repo) {
|
|
21354
|
-
|
|
21355
|
-
"gh",
|
|
21356
|
-
["repo", "fork", `${owner}/${repo}`, "--clone=false", "--remote=false"],
|
|
21357
|
-
{ encoding: "utf-8", shell: true }
|
|
21358
|
-
);
|
|
21389
|
+
runCapture("gh", ["repo", "fork", `${owner}/${repo}`, "--clone=false", "--remote=false"]);
|
|
21359
21390
|
}
|
|
21360
21391
|
function ensureStagingClone(stagingDir, ghUser, sharedName, upstreamOwner) {
|
|
21361
21392
|
if (!existsSync7(stagingDir)) {
|
|
21362
21393
|
mkdirSync3(dirname4(stagingDir), { recursive: true });
|
|
21363
21394
|
const forkUrl = `https://github.com/${ghUser}/${sharedName}.git`;
|
|
21364
|
-
|
|
21365
|
-
|
|
21395
|
+
runOrThrow("git", ["clone", "--depth", "30", forkUrl, stagingDir]);
|
|
21396
|
+
runOrThrow(
|
|
21366
21397
|
"git",
|
|
21367
21398
|
["remote", "add", "upstream", `https://github.com/${upstreamOwner}/${sharedName}.git`],
|
|
21368
21399
|
{ cwd: stagingDir }
|
|
21369
21400
|
);
|
|
21370
21401
|
} else {
|
|
21371
|
-
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
|
|
21402
|
+
runOrThrow("git", ["checkout", "main"], { cwd: stagingDir });
|
|
21403
|
+
runOrThrow("git", ["fetch", "upstream", "main"], { cwd: stagingDir });
|
|
21404
|
+
runOrThrow("git", ["reset", "--hard", "upstream/main"], { cwd: stagingDir });
|
|
21405
|
+
runOrThrow("git", ["push", "origin", "main", "--force-with-lease"], { cwd: stagingDir });
|
|
21375
21406
|
}
|
|
21376
21407
|
}
|
|
21377
21408
|
function upstreamAlreadyHas(stagingDir, relFromRoot) {
|
|
21378
21409
|
return existsSync7(join7(stagingDir, relFromRoot));
|
|
21379
21410
|
}
|
|
21380
|
-
function run(command, args, opts = {}) {
|
|
21381
|
-
const r2 = spawnSync(command, args, {
|
|
21382
|
-
encoding: "utf-8",
|
|
21383
|
-
cwd: opts.cwd,
|
|
21384
|
-
shell: true
|
|
21385
|
-
});
|
|
21386
|
-
if (r2.status !== 0) {
|
|
21387
|
-
const stderr = typeof r2.stderr === "string" ? r2.stderr : String(r2.stderr ?? "");
|
|
21388
|
-
const stdout = typeof r2.stdout === "string" ? r2.stdout : String(r2.stdout ?? "");
|
|
21389
|
-
throw new Error(`${command} ${args.join(" ")} failed: ${(stderr || stdout || "unknown").trim()}`);
|
|
21390
|
-
}
|
|
21391
|
-
}
|
|
21392
21411
|
|
|
21393
21412
|
// ../../packages/core/dist/pullShared.js
|
|
21394
21413
|
import { existsSync as existsSync8, readdirSync as readdirSync5 } from "node:fs";
|
|
@@ -21435,6 +21454,21 @@ function buildContext(logger, overrides = {}) {
|
|
|
21435
21454
|
return { caveatHome, userHome, userConfigPath, config: config3, paths, logger };
|
|
21436
21455
|
}
|
|
21437
21456
|
|
|
21457
|
+
// src/version.ts
|
|
21458
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
21459
|
+
import { dirname as dirname5, join as join10 } from "node:path";
|
|
21460
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
21461
|
+
function resolveVersion() {
|
|
21462
|
+
try {
|
|
21463
|
+
const here2 = dirname5(fileURLToPath3(import.meta.url));
|
|
21464
|
+
const pkg = JSON.parse(readFileSync6(join10(here2, "..", "package.json"), "utf-8"));
|
|
21465
|
+
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
21466
|
+
} catch {
|
|
21467
|
+
return "0.0.0";
|
|
21468
|
+
}
|
|
21469
|
+
}
|
|
21470
|
+
var CAVEAT_VERSION = resolveVersion();
|
|
21471
|
+
|
|
21438
21472
|
// src/logger.ts
|
|
21439
21473
|
var stdoutLogger = {
|
|
21440
21474
|
info: (m) => process.stdout.write(`[caveat] ${m}
|
|
@@ -21446,13 +21480,13 @@ var stdoutLogger = {
|
|
|
21446
21480
|
};
|
|
21447
21481
|
|
|
21448
21482
|
// src/commands/init.ts
|
|
21449
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync6, writeFileSync as writeFileSync5 } from "node:fs";
|
|
21450
|
-
import { join as
|
|
21483
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync6, renameSync, rmdirSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
21484
|
+
import { join as join12 } from "node:path";
|
|
21451
21485
|
|
|
21452
21486
|
// src/claudeInstall.ts
|
|
21453
21487
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
21454
|
-
import { copyFileSync as copyFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as
|
|
21455
|
-
import { dirname as
|
|
21488
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
21489
|
+
import { dirname as dirname6, join as join11 } from "node:path";
|
|
21456
21490
|
var EVENT_USER_PROMPT_SUBMIT = "UserPromptSubmit";
|
|
21457
21491
|
var EVENT_STOP = "Stop";
|
|
21458
21492
|
function quote(p2) {
|
|
@@ -21487,10 +21521,10 @@ function removeHook(settings, event, command) {
|
|
|
21487
21521
|
}
|
|
21488
21522
|
function readSettings(path) {
|
|
21489
21523
|
if (!existsSync9(path)) return {};
|
|
21490
|
-
return JSON.parse(
|
|
21524
|
+
return JSON.parse(readFileSync7(path, "utf-8"));
|
|
21491
21525
|
}
|
|
21492
21526
|
function writeSettings(path, settings) {
|
|
21493
|
-
const dir =
|
|
21527
|
+
const dir = dirname6(path);
|
|
21494
21528
|
if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
|
|
21495
21529
|
let backupPath = "";
|
|
21496
21530
|
if (existsSync9(path)) {
|
|
@@ -21501,11 +21535,11 @@ function writeSettings(path, settings) {
|
|
|
21501
21535
|
return backupPath;
|
|
21502
21536
|
}
|
|
21503
21537
|
var CLAUDE_BIN = "claude";
|
|
21504
|
-
function
|
|
21538
|
+
function shellQuote2(s) {
|
|
21505
21539
|
return /[\s&|<>^()]/.test(s) ? `"${s}"` : s;
|
|
21506
21540
|
}
|
|
21507
21541
|
function runClaude(args) {
|
|
21508
|
-
const line = [CLAUDE_BIN, ...args].map(
|
|
21542
|
+
const line = [CLAUDE_BIN, ...args].map(shellQuote2).join(" ");
|
|
21509
21543
|
return spawnSync2(line, { shell: true, encoding: "utf-8" });
|
|
21510
21544
|
}
|
|
21511
21545
|
function registerMcp(nodePath, cliScriptPath, dryRun, logger) {
|
|
@@ -21556,7 +21590,7 @@ function unregisterMcp(dryRun, logger) {
|
|
|
21556
21590
|
return { action: "skipped", detail: "not registered or removal failed" };
|
|
21557
21591
|
}
|
|
21558
21592
|
function installClaudeIntegration(opts) {
|
|
21559
|
-
const settingsPath =
|
|
21593
|
+
const settingsPath = join11(opts.claudeDir, "settings.json");
|
|
21560
21594
|
const settings = readSettings(settingsPath);
|
|
21561
21595
|
const usCmd = hookCommand(opts.nodePath, opts.cliScriptPath, "user-prompt-submit");
|
|
21562
21596
|
const stopCmd = hookCommand(opts.nodePath, opts.cliScriptPath, "stop");
|
|
@@ -21575,7 +21609,7 @@ function installClaudeIntegration(opts) {
|
|
|
21575
21609
|
return { mcp, hooks: { userPromptSubmit, stop }, backupPath };
|
|
21576
21610
|
}
|
|
21577
21611
|
function uninstallClaudeIntegration(opts) {
|
|
21578
|
-
const settingsPath =
|
|
21612
|
+
const settingsPath = join11(opts.claudeDir, "settings.json");
|
|
21579
21613
|
const settings = readSettings(settingsPath);
|
|
21580
21614
|
const usCmd = hookCommand(opts.nodePath, opts.cliScriptPath, "user-prompt-submit");
|
|
21581
21615
|
const stopCmd = hookCommand(opts.nodePath, opts.cliScriptPath, "stop");
|
|
@@ -21605,11 +21639,6 @@ var KNOWLEDGE_GITIGNORE = [
|
|
|
21605
21639
|
"",
|
|
21606
21640
|
"# Obsidian per-user config: workspace layout, theme, plugin state, cache.",
|
|
21607
21641
|
".obsidian/",
|
|
21608
|
-
"",
|
|
21609
|
-
"# community/ is a local cache of shallow-cloned third-party caveat repos",
|
|
21610
|
-
"# (populated by `caveat community add`). Each contains its own .git and is not",
|
|
21611
|
-
"# part of this repo's tracked knowledge.",
|
|
21612
|
-
"community/",
|
|
21613
21642
|
""
|
|
21614
21643
|
].join("\n");
|
|
21615
21644
|
async function runInit(ctx, opts = { skipClaude: false, skipShared: false, dryRun: false }) {
|
|
@@ -21622,7 +21651,8 @@ async function runInit(ctx, opts = { skipClaude: false, skipShared: false, dryRu
|
|
|
21622
21651
|
} else {
|
|
21623
21652
|
ctx.logger.info(`knowledge repo: ${ctx.paths.knowledgeRepo}`);
|
|
21624
21653
|
}
|
|
21625
|
-
|
|
21654
|
+
migrateLegacyCommunityDir(ctx);
|
|
21655
|
+
const gitignorePath = join12(ctx.paths.knowledgeRepo, ".gitignore");
|
|
21626
21656
|
if (!existsSync10(gitignorePath)) {
|
|
21627
21657
|
writeFileSync5(gitignorePath, KNOWLEDGE_GITIGNORE, "utf-8");
|
|
21628
21658
|
ctx.logger.info(`.gitignore created: ${gitignorePath}`);
|
|
@@ -21650,7 +21680,7 @@ async function runInit(ctx, opts = { skipClaude: false, skipShared: false, dryRu
|
|
|
21650
21680
|
return;
|
|
21651
21681
|
}
|
|
21652
21682
|
const result = installClaudeIntegration({
|
|
21653
|
-
claudeDir:
|
|
21683
|
+
claudeDir: join12(ctx.userHome, ".claude"),
|
|
21654
21684
|
cliScriptPath,
|
|
21655
21685
|
nodePath: process.execPath,
|
|
21656
21686
|
dryRun: opts.dryRun,
|
|
@@ -21658,6 +21688,28 @@ async function runInit(ctx, opts = { skipClaude: false, skipShared: false, dryRu
|
|
|
21658
21688
|
});
|
|
21659
21689
|
reportInstallResult(ctx, result, opts.dryRun);
|
|
21660
21690
|
}
|
|
21691
|
+
function migrateLegacyCommunityDir(ctx) {
|
|
21692
|
+
const legacy = join12(ctx.paths.knowledgeRepo, "community");
|
|
21693
|
+
const current = ctx.paths.communityDir;
|
|
21694
|
+
if (legacy === current) return;
|
|
21695
|
+
if (!existsSync10(legacy)) return;
|
|
21696
|
+
if (existsSync10(current)) {
|
|
21697
|
+
ctx.logger.warn(
|
|
21698
|
+
`legacy community dir still exists at ${legacy} \u2014 remove manually (new location in use)`
|
|
21699
|
+
);
|
|
21700
|
+
return;
|
|
21701
|
+
}
|
|
21702
|
+
mkdirSync5(current, { recursive: true });
|
|
21703
|
+
for (const entry of readdirSync6(legacy, { withFileTypes: true })) {
|
|
21704
|
+
if (!entry.isDirectory()) continue;
|
|
21705
|
+
renameSync(join12(legacy, entry.name), join12(current, entry.name));
|
|
21706
|
+
}
|
|
21707
|
+
try {
|
|
21708
|
+
rmdirSync(legacy);
|
|
21709
|
+
} catch {
|
|
21710
|
+
}
|
|
21711
|
+
ctx.logger.info(`migrated legacy community/ \u2192 ${current}`);
|
|
21712
|
+
}
|
|
21661
21713
|
async function subscribeSharedRepo(ctx, db) {
|
|
21662
21714
|
const url = ctx.config.sharedRepo;
|
|
21663
21715
|
const validation = validateCommunityUrl(url);
|
|
@@ -21668,7 +21720,7 @@ async function subscribeSharedRepo(ctx, db) {
|
|
|
21668
21720
|
return;
|
|
21669
21721
|
}
|
|
21670
21722
|
const handle = validation.handle;
|
|
21671
|
-
const target =
|
|
21723
|
+
const target = join12(ctx.paths.communityDir, handle);
|
|
21672
21724
|
if (!existsSync10(target)) {
|
|
21673
21725
|
if (!existsSync10(ctx.paths.communityDir)) {
|
|
21674
21726
|
mkdirSync5(ctx.paths.communityDir, { recursive: true });
|
|
@@ -21697,7 +21749,7 @@ async function subscribeSharedRepo(ctx, db) {
|
|
|
21697
21749
|
for (const entry of readdirSync6(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
21698
21750
|
if (!entry.isDirectory()) continue;
|
|
21699
21751
|
const source = `community/${entry.name}`;
|
|
21700
|
-
const root =
|
|
21752
|
+
const root = join12(ctx.paths.communityDir, entry.name, "entries");
|
|
21701
21753
|
if (!existsSync10(root)) continue;
|
|
21702
21754
|
const result = scanSource({ db, source, entriesRoot: root });
|
|
21703
21755
|
ctx.logger.info(`indexed ${source}: +${result.added}`);
|
|
@@ -21711,7 +21763,7 @@ function runUninstall(ctx, opts) {
|
|
|
21711
21763
|
process.exit(1);
|
|
21712
21764
|
}
|
|
21713
21765
|
const result = uninstallClaudeIntegration({
|
|
21714
|
-
claudeDir:
|
|
21766
|
+
claudeDir: join12(ctx.userHome, ".claude"),
|
|
21715
21767
|
cliScriptPath,
|
|
21716
21768
|
nodePath: process.execPath,
|
|
21717
21769
|
dryRun: opts.dryRun,
|
|
@@ -21749,9 +21801,9 @@ function reportInstallResult(ctx, result, dryRun) {
|
|
|
21749
21801
|
|
|
21750
21802
|
// src/commands/indexCmd.ts
|
|
21751
21803
|
import { existsSync as existsSync11, readdirSync as readdirSync7, mkdirSync as mkdirSync6 } from "node:fs";
|
|
21752
|
-
import { dirname as
|
|
21804
|
+
import { dirname as dirname7, join as join13 } from "node:path";
|
|
21753
21805
|
function runIndex(ctx, opts) {
|
|
21754
|
-
const dbDir =
|
|
21806
|
+
const dbDir = dirname7(ctx.paths.dbPath);
|
|
21755
21807
|
if (!existsSync11(dbDir)) mkdirSync6(dbDir, { recursive: true });
|
|
21756
21808
|
const db = openDb({ path: ctx.paths.dbPath, logger: ctx.logger });
|
|
21757
21809
|
try {
|
|
@@ -21769,7 +21821,7 @@ function runIndex(ctx, opts) {
|
|
|
21769
21821
|
for (const entry of readdirSync7(ctx.paths.communityDir, { withFileTypes: true })) {
|
|
21770
21822
|
if (!entry.isDirectory()) continue;
|
|
21771
21823
|
const source = `community/${entry.name}`;
|
|
21772
|
-
const root =
|
|
21824
|
+
const root = join13(ctx.paths.communityDir, entry.name, "entries");
|
|
21773
21825
|
if (!existsSync11(root)) continue;
|
|
21774
21826
|
const result = scanSource({ db, source, entriesRoot: root });
|
|
21775
21827
|
ctx.logger.info(`${source}: +${result.added} ~${result.updated} -${result.deleted}`);
|
|
@@ -22544,11 +22596,11 @@ var serve = (options2, listeningListener) => {
|
|
|
22544
22596
|
|
|
22545
22597
|
// ../web/dist/context.js
|
|
22546
22598
|
import { homedir as homedir2 } from "node:os";
|
|
22547
|
-
import { join as
|
|
22599
|
+
import { join as join14 } from "node:path";
|
|
22548
22600
|
function buildWebContext(overrides = {}) {
|
|
22549
22601
|
const userHome = overrides.userHome ?? homedir2();
|
|
22550
22602
|
const caveatHome = overrides.caveatHome ?? findCaveatHome(userHome);
|
|
22551
|
-
const userConfigPath =
|
|
22603
|
+
const userConfigPath = join14(userHome, ".caveatrc.json");
|
|
22552
22604
|
const logger = overrides.logger ?? stderrLogger;
|
|
22553
22605
|
const config3 = loadConfig(userConfigPath);
|
|
22554
22606
|
const paths = resolvePaths(caveatHome, config3.knowledgeRepo, userHome);
|
|
@@ -30276,13 +30328,13 @@ function createDetailRoute(ctx) {
|
|
|
30276
30328
|
|
|
30277
30329
|
// ../web/dist/routes/community.js
|
|
30278
30330
|
import { existsSync as existsSync12, readdirSync as readdirSync8, statSync as statSync4 } from "node:fs";
|
|
30279
|
-
import { join as
|
|
30331
|
+
import { join as join15 } from "node:path";
|
|
30280
30332
|
function listCommunity(communityDir, db) {
|
|
30281
30333
|
if (!existsSync12(communityDir)) return [];
|
|
30282
30334
|
const handles = [];
|
|
30283
30335
|
for (const entry of readdirSync8(communityDir, { withFileTypes: true })) {
|
|
30284
30336
|
if (!entry.isDirectory()) continue;
|
|
30285
|
-
const handlePath =
|
|
30337
|
+
const handlePath = join15(communityDir, entry.name);
|
|
30286
30338
|
const countRow = db.prepare("SELECT COUNT(*) AS n FROM entries WHERE source = ?").get(`community/${entry.name}`);
|
|
30287
30339
|
handles.push({
|
|
30288
30340
|
handle: entry.name,
|
|
@@ -44580,11 +44632,11 @@ var StdioServerTransport = class {
|
|
|
44580
44632
|
|
|
44581
44633
|
// ../mcp/dist/context.js
|
|
44582
44634
|
import { homedir as homedir3 } from "node:os";
|
|
44583
|
-
import { join as
|
|
44635
|
+
import { join as join16 } from "node:path";
|
|
44584
44636
|
function buildMcpContext(overrides = {}) {
|
|
44585
44637
|
const userHome = overrides.userHome ?? homedir3();
|
|
44586
44638
|
const caveatHome = overrides.caveatHome ?? findCaveatHome(userHome);
|
|
44587
|
-
const userConfigPath =
|
|
44639
|
+
const userConfigPath = join16(userHome, ".caveatrc.json");
|
|
44588
44640
|
const logger = overrides.logger ?? stderrLogger;
|
|
44589
44641
|
const config3 = loadConfig(userConfigPath);
|
|
44590
44642
|
const paths = resolvePaths(caveatHome, config3.knowledgeRepo, userHome);
|
|
@@ -44640,7 +44692,9 @@ var recordInputShape = {
|
|
|
44640
44692
|
context: external_exports.string().optional(),
|
|
44641
44693
|
confidence: confidenceSchema2.optional(),
|
|
44642
44694
|
outcome: outcomeSchema.optional(),
|
|
44643
|
-
visibility: visibilitySchema.
|
|
44695
|
+
visibility: visibilitySchema.describe(
|
|
44696
|
+
'REQUIRED. Ask the user "public (share to community) or private (keep local only)?" before calling \u2014 never auto-classify. The user owns the knowledge; they decide its reach.'
|
|
44697
|
+
),
|
|
44644
44698
|
tags: external_exports.array(external_exports.string()).optional(),
|
|
44645
44699
|
environment: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
44646
44700
|
category: external_exports.string().optional().describe("Directory under entries/ (e.g., gpu, claude-code). Default: misc")
|
|
@@ -44748,7 +44802,7 @@ function registerAllTools(server, ctx) {
|
|
|
44748
44802
|
"caveat_search",
|
|
44749
44803
|
{
|
|
44750
44804
|
title: "caveat_search",
|
|
44751
|
-
description: "
|
|
44805
|
+
description: 'Search the "caveats" knowledge base \u2014 records of time-wasting traps in EXTERNAL specs (GPU/driver/CUDA versions, native-module builds, IDE/shell quirks, platform-specific behavior, library version incompatibilities) that someone already diagnosed. Call this FIRST when a problem smells environmental rather than a logic bug \u2014 before reading stack traces top-to-bottom or trying fixes. Query: 3+ chars, plain tokens only (no OR/NEAR/other FTS5 operators). Returns summary rows including `{id, source}` \u2014 pass BOTH to caveat_get for the full body.',
|
|
44752
44806
|
inputSchema: searchInputShape
|
|
44753
44807
|
},
|
|
44754
44808
|
async (args) => jsonResult(handleSearch(ctx, args))
|
|
@@ -44757,7 +44811,7 @@ function registerAllTools(server, ctx) {
|
|
|
44757
44811
|
"caveat_get",
|
|
44758
44812
|
{
|
|
44759
44813
|
title: "caveat_get",
|
|
44760
|
-
description:
|
|
44814
|
+
description: 'Fetch the full body (frontmatter + H2 sections + text) of a caveat by id. IMPORTANT: when the id came from caveat_search, you MUST pass the `source` field from that same result (e.g., "community/Caveat"). The default source is "own" only; omitting source for a community entry returns not-found.',
|
|
44761
44815
|
inputSchema: getInputShape
|
|
44762
44816
|
},
|
|
44763
44817
|
async (args) => jsonResult(handleGet(ctx, args))
|
|
@@ -44766,7 +44820,7 @@ function registerAllTools(server, ctx) {
|
|
|
44766
44820
|
"caveat_record",
|
|
44767
44821
|
{
|
|
44768
44822
|
title: "caveat_record",
|
|
44769
|
-
description: "Create a new caveat
|
|
44823
|
+
description: "Create a new caveat: a record of an external-spec trap that wasted real time (wrong driver, version mismatch, platform bug, IDE quirk, native-module issue, etc.) so future sessions can find it via caveat_search. REQUIRED BEFORE CALLING: (1) run caveat_search first to avoid duplicates, (2) ASK THE USER whether this should be `public` (shareable to the community DB) or `private` (kept local only) \u2014 never auto-classify visibility; the user owns the knowledge and decides its reach. Qualifies: specific symptom + diagnosed cause (or `outcome: impossible` verdict) + environment fingerprint. Does NOT qualify: project-internal bugs, user preferences, session summaries, ephemeral task notes. Auto-fills source_session and environment defaults; source_project is left null by design (shared knowledge must not leak per-user project names).",
|
|
44770
44824
|
inputSchema: recordInputShape
|
|
44771
44825
|
},
|
|
44772
44826
|
async (args) => jsonResult(handleRecord(ctx, args))
|
|
@@ -44775,7 +44829,7 @@ function registerAllTools(server, ctx) {
|
|
|
44775
44829
|
"caveat_update",
|
|
44776
44830
|
{
|
|
44777
44831
|
title: "caveat_update",
|
|
44778
|
-
description: "Patch an existing caveat. Frontmatter shallow-merges (
|
|
44832
|
+
description: "Patch an existing caveat \u2014 use when newer evidence extends or corrects one that already exists. Frontmatter shallow-merges, but array fields (tags etc.) REPLACE rather than append \u2014 to add one tag, read the current list first, then patch with the full new array. Sections match by case-insensitive H2 heading. Immutable keys: id, created_at, source_session, source_project. Common uses: bump `last_verified` after re-confirming, add a resolution when it was `tentative`, flip `outcome` to `impossible`.",
|
|
44779
44833
|
inputSchema: updateInputShape
|
|
44780
44834
|
},
|
|
44781
44835
|
async (args) => jsonResult(handleUpdate(ctx, args))
|
|
@@ -44784,7 +44838,7 @@ function registerAllTools(server, ctx) {
|
|
|
44784
44838
|
"caveat_list_recent",
|
|
44785
44839
|
{
|
|
44786
44840
|
title: "caveat_list_recent",
|
|
44787
|
-
description: "List caveats by updated_at DESC.",
|
|
44841
|
+
description: "List caveats ordered by updated_at DESC. Use for browsing recent additions \u2014 e.g., showing the user what is new after caveat_pull. Not for search; use caveat_search when you have a query.",
|
|
44788
44842
|
inputSchema: listRecentInputShape
|
|
44789
44843
|
},
|
|
44790
44844
|
async (args) => jsonResult(handleListRecent(ctx, args))
|
|
@@ -44793,7 +44847,7 @@ function registerAllTools(server, ctx) {
|
|
|
44793
44847
|
"caveat_pull",
|
|
44794
44848
|
{
|
|
44795
44849
|
title: "caveat_pull",
|
|
44796
|
-
description: "git-pull
|
|
44850
|
+
description: "git-pull the subscribed community caveat repos (the shared knowledge DB + any user-added remotes) and re-index. Call when: (a) the user explicitly asks about others' knowledge on a topic, or (b) caveat_search returned empty for a query that feels like it should have hits and the DB might be stale. Do NOT call reflexively at session start \u2014 it is cheap but not free, and stale-by-minutes is acceptable. Safe and idempotent.",
|
|
44797
44851
|
inputSchema: pullInputShape
|
|
44798
44852
|
},
|
|
44799
44853
|
async (args) => jsonResult(await handlePull(ctx, args))
|
|
@@ -44802,7 +44856,7 @@ function registerAllTools(server, ctx) {
|
|
|
44802
44856
|
"caveat_push",
|
|
44803
44857
|
{
|
|
44804
44858
|
title: "caveat_push",
|
|
44805
|
-
description: "Contribute a user-owned caveat to the shared
|
|
44859
|
+
description: "Contribute a user-owned caveat to the public shared DB via fork + PR on GitHub. This is a PUBLIC, externally-visible action (the PR appears on GitHub and is hard to fully retract). Confirm with the user before calling without dry_run \u2014 or call with dry_run=true first to show the plan. Only push entries that document a trap genuinely reusable by others (not project-specific ties, not duplicated by existing community entries). Entries with `visibility: private` are rejected (`status=visibility-private`) \u2014 the user has declared them local-only. Requires `gh` CLI authenticated; returns `status=gh-missing` / `gh-unauthed` on failure.",
|
|
44806
44860
|
inputSchema: pushInputShape
|
|
44807
44861
|
},
|
|
44808
44862
|
async (args) => jsonResult(await handlePush(ctx, args))
|
|
@@ -45022,7 +45076,7 @@ function runCommunityList(ctx) {
|
|
|
45022
45076
|
|
|
45023
45077
|
// src/index.ts
|
|
45024
45078
|
var program = new Command();
|
|
45025
|
-
program.name("caveat").description("External spec gotcha knowledge base CLI").version(
|
|
45079
|
+
program.name("caveat").description("External spec gotcha knowledge base CLI").version(CAVEAT_VERSION);
|
|
45026
45080
|
program.command("init").description(
|
|
45027
45081
|
"Initialize ~/.caveatrc.json, ~/.caveat/, subscribe to the shared community DB, and register Claude Code integration"
|
|
45028
45082
|
).option("--skip-claude", "skip Claude Code MCP + hook registration", false).option("--skip-shared", "skip subscribing to the shared community DB", false).option("--dry-run", "show planned changes without writing", false).action(async (opts) => {
|