caveat-cli 0.4.0 → 0.6.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # caveat-cli
2
2
 
3
- External spec gotcha knowledge base CLI — markdown + SQLite FTS5 + MCP server + Claude Code hooks.
3
+ External spec gotcha knowledge base CLI — markdown + SQLite FTS5 + MCP server + Claude Code hooks, with a shared community knowledge DB out of the box.
4
4
 
5
5
  **Source / full docs**: https://github.com/kitepon-rgb/Caveat
6
6
 
@@ -11,22 +11,48 @@ npm install -g caveat-cli
11
11
  caveat init
12
12
  ```
13
13
 
14
- `caveat init` creates `~/.caveat/`, registers the MCP server with Claude Code (via `claude mcp add --scope user`), and merges `UserPromptSubmit` / `Stop` hooks into `~/.claude/settings.json`. Existing hook entries are preserved; the settings file is backed up before any write. Run `caveat init --dry-run` to preview, or `caveat init --skip-claude` to skip Claude Code wiring.
14
+ `caveat init` (idempotent, `--dry-run` supported) does 4 things:
15
+
16
+ 1. Scaffolds `~/.caveat/own/` (your personal knowledge repo) + `~/.caveat/index/caveat.db`
17
+ 2. **Subscribes you to the shared community DB** (`kitepon-rgb/Caveat` by default) — shallow-clones into `~/.caveat/community/Caveat/` and indexes so other users' caveats are immediately searchable
18
+ 3. Registers the MCP server with Claude Code (`claude mcp add --scope user`)
19
+ 4. Merges `UserPromptSubmit` / `Stop` hooks into `~/.claude/settings.json` (existing entries preserved, backup written before any change)
20
+
21
+ Opt-out flags: `--skip-claude`, `--skip-shared`. `caveat uninstall` reverses the Claude Code changes without touching `~/.caveat/`.
15
22
 
16
23
  ## Basic usage
17
24
 
18
25
  ```sh
19
- caveat search "rtx" # FTS against your knowledge repo
26
+ caveat search "rtx" # FTS across your own entries + the shared community DB
20
27
  caveat list # recent entries
28
+ caveat pull # fetch new community contributions + re-index
29
+ caveat push <entry-id> # contribute your entry via fork + PR (requires gh CLI)
21
30
  caveat serve # http://localhost:4242 read-only portal
22
- caveat community add <url> # shallow-clone another user's caveats repo
31
+ caveat community add <url> # subscribe to an additional community repo
23
32
  caveat uninstall # reverse `caveat init` Claude integration
24
33
  ```
25
34
 
35
+ ## MCP tools (7)
36
+
37
+ Exposed to Claude Code via the MCP server that `caveat init` registers:
38
+
39
+ `caveat_search`, `caveat_get`, `caveat_record`, `caveat_update`, `caveat_list_recent`, `caveat_pull`, `caveat_push`.
40
+
41
+ Claude can autonomously pull community updates (safe, idempotent) and push your recorded caveats (gated by Claude Code's tool permission prompt for user consent — contribution is a public action).
42
+
43
+ ## Pointing at a different shared DB
44
+
45
+ For an internal/enterprise shared knowledge pool, override in `~/.caveatrc.json`:
46
+
47
+ ```json
48
+ { "sharedRepo": "https://github.com/your-org/your-caveats" }
49
+ ```
50
+
26
51
  ## Requirements
27
52
 
28
53
  - Node 22.5+ (for built-in `node:sqlite`)
29
- - Optional: Claude Code installed for MCP / hooks integration. Without it, `caveat init --skip-claude` still provisions the local knowledge repo + index.
54
+ - `gh` CLI authenticated (`gh auth login`) if you want to use `caveat push`
55
+ - Claude Code installed if you want MCP / hooks integration. Without it, `caveat init --skip-claude` still provisions local state + shared DB
30
56
 
31
57
  ## License
32
58
 
package/dist/index.js CHANGED
@@ -15948,8 +15948,7 @@ function recordEntry(input, opts) {
15948
15948
  source_session: generateSourceSession(now),
15949
15949
  created_at: ymd,
15950
15950
  updated_at: ymd,
15951
- last_verified: ymd,
15952
- ...input.brief_id !== void 0 ? { brief_id: input.brief_id } : {}
15951
+ last_verified: ymd
15953
15952
  };
15954
15953
  const sections = {};
15955
15954
  if (input.context !== void 0) sections["Context"] = input.context;
@@ -15996,8 +15995,7 @@ var IMMUTABLE_KEYS = /* @__PURE__ */ new Set([
15996
15995
  "id",
15997
15996
  "created_at",
15998
15997
  "source_session",
15999
- "source_project",
16000
- "brief_id"
15998
+ "source_project"
16001
15999
  ]);
16002
16000
  function updateEntry(id, patch, opts) {
16003
16001
  const source = opts.source ?? "own";
@@ -16035,9 +16033,6 @@ function updateEntry(id, patch, opts) {
16035
16033
  if (patch.frontmatter?.tags !== void 0) {
16036
16034
  mergedFrontmatter.tags = patch.frontmatter.tags;
16037
16035
  }
16038
- if (parsed.frontmatter.brief_id !== void 0) {
16039
- mergedFrontmatter.brief_id = parsed.frontmatter.brief_id;
16040
- }
16041
16036
  const mergedSections = { ...parsed.sections };
16042
16037
  if (patch.sections) {
16043
16038
  for (const [heading2, content] of Object.entries(patch.sections)) {
@@ -16077,39 +16072,6 @@ function formatYmd2(d) {
16077
16072
  return `${yyyy}-${mm}-${dd}`;
16078
16073
  }
16079
16074
 
16080
- // ../../packages/core/dist/brief.js
16081
- function generateBrief(db, topic, limit = 10) {
16082
- const related = topic.trim().length > 0 ? search(db, { query: topic, limit }) : [];
16083
- const brief_id = `brf-${Date.now().toString(36)}-${randomHex(8)}`;
16084
- const lines = [];
16085
- lines.push(`# \u8ABF\u67FB\u4F9D\u983C: ${topic}`);
16086
- lines.push("");
16087
- lines.push("## \u4F9D\u983C\u306E\u80CC\u666F");
16088
- lines.push(
16089
- `\u4EE5\u4E0B\u306E\u8A71\u984C\u306B\u3064\u3044\u3066\u3001\u4E00\u6B21\u30BD\u30FC\u30B9\u4E2D\u5FC3\u3067\u8ABF\u67FB\u3057\u3066\u304F\u3060\u3055\u3044: ${topic}`
16090
- );
16091
- lines.push("");
16092
- if (related.length > 0) {
16093
- lines.push("## \u65E2\u5B58\u306E\u95A2\u9023 caveat\uFF08\u53C2\u8003\uFF09");
16094
- for (const r2 of related) {
16095
- lines.push(`- \`${r2.id}\` (${r2.confidence}) ${r2.title}`);
16096
- }
16097
- lines.push("");
16098
- }
16099
- lines.push("## \u6C42\u3081\u305F\u3044\u60C5\u5831");
16100
- lines.push("1. \u516C\u5F0F\u4ED5\u69D8 (RFC / \u4ED5\u69D8\u66F8 / \u30D9\u30F3\u30C0\u30FC\u516C\u5F0F\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8) \u2014 \u30D0\u30FC\u30B8\u30E7\u30F3\u660E\u8A18");
16101
- lines.push("2. \u65E2\u77E5\u306E\u843D\u3068\u3057\u7A74 (\u30D0\u30FC\u30B8\u30E7\u30F3\u4F9D\u5B58\u3001\u30D7\u30E9\u30C3\u30C8\u30D5\u30A9\u30FC\u30E0\u5DEE\u7570\u3001\u65E2\u5831\u306E\u4E0D\u5177\u5408)");
16102
- lines.push("3. \u56DE\u907F\u7B56\u3068\u4EE3\u66FF\u624B\u6BB5\uFF08\u52B9\u679C\u306E\u88CF\u53D6\u308A\u3064\u304D\uFF09");
16103
- lines.push("4. \u4E00\u6B21\u30BD\u30FC\u30B9 URL\u3002\u4E8C\u6B21\u30BD\u30FC\u30B9\uFF08\u30D6\u30ED\u30B0\u7B49\uFF09\u306F\u533A\u5225\u3057\u3066\u8A18\u8F09");
16104
- lines.push("");
16105
- lines.push("## \u51FA\u529B\u306E\u5F62");
16106
- lines.push("Symptom / Cause / Resolution / Evidence \u306E 4 \u30BB\u30AF\u30B7\u30E7\u30F3\u3067\u3001\u5F8C\u7D9A\u306E `ingest_research` \u306B\u6E21\u305B\u308B\u5F62\u5F0F\u3067\u8FD4\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
16107
- lines.push("");
16108
- lines.push("---");
16109
- lines.push(`brief_id: ${brief_id}`);
16110
- return { brief_id, text: lines.join("\n") };
16111
- }
16112
-
16113
16075
  // ../../packages/core/dist/paths.js
16114
16076
  import { existsSync as existsSync4 } from "node:fs";
16115
16077
  import { dirname as dirname3, isAbsolute, join as join5, resolve } from "node:path";
@@ -16139,7 +16101,7 @@ function resolvePaths(caveatHome, knowledgeRepo, userHome) {
16139
16101
 
16140
16102
  // ../../packages/core/dist/config.js
16141
16103
  import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
16142
- var SHARED_REPO_URL = "https://github.com/kitepon-rgb/caveats-quo";
16104
+ var SHARED_REPO_URL = "https://github.com/kitepon-rgb/Caveat";
16143
16105
  var DEFAULT_CONFIG = {
16144
16106
  knowledgeRepo: "own",
16145
16107
  semverKeys: ["driver", "cuda", "node"],
@@ -44681,8 +44643,7 @@ var recordInputShape = {
44681
44643
  visibility: visibilitySchema.optional(),
44682
44644
  tags: external_exports.array(external_exports.string()).optional(),
44683
44645
  environment: external_exports.record(external_exports.string(), external_exports.string()).optional(),
44684
- category: external_exports.string().optional().describe("Directory under entries/ (e.g., gpu, claude-code). Default: misc"),
44685
- brief_id: external_exports.string().optional()
44646
+ category: external_exports.string().optional().describe("Directory under entries/ (e.g., gpu, claude-code). Default: misc")
44686
44647
  };
44687
44648
  function handleRecord(ctx, args) {
44688
44649
  return recordEntry(args, {
@@ -44729,48 +44690,6 @@ function handleListRecent(ctx, args) {
44729
44690
  return listRecent(ctx.db, args.limit ?? 20);
44730
44691
  }
44731
44692
 
44732
- // ../mcp/dist/tools/nlmBriefFor.js
44733
- var nlmBriefForInputShape = {
44734
- topic: external_exports.string().min(1),
44735
- limit: external_exports.number().int().min(1).max(50).optional()
44736
- };
44737
- function handleNlmBriefFor(ctx, args) {
44738
- return generateBrief(ctx.db, args.topic, args.limit);
44739
- }
44740
-
44741
- // ../mcp/dist/tools/ingestResearch.js
44742
- var ingestResearchInputShape = {
44743
- title: external_exports.string().min(1),
44744
- symptom: external_exports.string().min(1),
44745
- cause: external_exports.string().optional(),
44746
- resolution: external_exports.string().optional(),
44747
- evidence: external_exports.array(external_exports.string()).optional(),
44748
- brief_id: external_exports.string().optional(),
44749
- tags: external_exports.array(external_exports.string()).optional(),
44750
- category: external_exports.string().optional()
44751
- };
44752
- function handleIngestResearch(ctx, args) {
44753
- const evidenceText = args.evidence ? args.evidence.map((line) => `- ${line}`).join("\n") : "";
44754
- return recordEntry(
44755
- {
44756
- title: args.title,
44757
- symptom: args.symptom,
44758
- cause: args.cause ?? "",
44759
- resolution: args.resolution ?? "",
44760
- evidence: evidenceText,
44761
- confidence: "tentative",
44762
- outcome: "resolved",
44763
- tags: args.tags,
44764
- category: args.category,
44765
- brief_id: args.brief_id
44766
- },
44767
- {
44768
- db: ctx.db,
44769
- entriesRoot: ctx.paths.entriesDir
44770
- }
44771
- );
44772
- }
44773
-
44774
44693
  // ../mcp/dist/tools/pull.js
44775
44694
  var pullInputShape = {};
44776
44695
  async function handlePull(ctx, _args = {}) {
@@ -44856,7 +44775,7 @@ function registerAllTools(server, ctx) {
44856
44775
  "caveat_update",
44857
44776
  {
44858
44777
  title: "caveat_update",
44859
- description: "Patch an existing caveat. Frontmatter shallow-merges (arrays replace). Sections matched by case-insensitive H2 heading. Immutable keys: id, created_at, source_session, source_project, brief_id.",
44778
+ description: "Patch an existing caveat. Frontmatter shallow-merges (arrays replace). Sections matched by case-insensitive H2 heading. Immutable keys: id, created_at, source_session, source_project.",
44860
44779
  inputSchema: updateInputShape
44861
44780
  },
44862
44781
  async (args) => jsonResult(handleUpdate(ctx, args))
@@ -44870,24 +44789,6 @@ function registerAllTools(server, ctx) {
44870
44789
  },
44871
44790
  async (args) => jsonResult(handleListRecent(ctx, args))
44872
44791
  );
44873
- server.registerTool(
44874
- "nlm_brief_for",
44875
- {
44876
- title: "nlm_brief_for",
44877
- description: "Generate a NotebookLM research brief for a topic. Returns {brief_id, text}. brief_id can be passed to ingest_research when the NLM output is ready. Stateless \u2014 brief_id is not persisted until ingest_research fires.",
44878
- inputSchema: nlmBriefForInputShape
44879
- },
44880
- async (args) => jsonResult(handleNlmBriefFor(ctx, args))
44881
- );
44882
- server.registerTool(
44883
- "ingest_research",
44884
- {
44885
- title: "ingest_research",
44886
- description: "Create a caveat from NotebookLM research output. Always records with confidence: tentative. Pass brief_id to link back to the originating brief.",
44887
- inputSchema: ingestResearchInputShape
44888
- },
44889
- async (args) => jsonResult(handleIngestResearch(ctx, args))
44890
- );
44891
44792
  server.registerTool(
44892
44793
  "caveat_pull",
44893
44794
  {
@@ -45121,7 +45022,7 @@ function runCommunityList(ctx) {
45121
45022
 
45122
45023
  // src/index.ts
45123
45024
  var program = new Command();
45124
- program.name("caveat").description("External spec gotcha knowledge base CLI").version("0.4.0");
45025
+ program.name("caveat").description("External spec gotcha knowledge base CLI").version("0.6.0");
45125
45026
  program.command("init").description(
45126
45027
  "Initialize ~/.caveatrc.json, ~/.caveat/, subscribe to the shared community DB, and register Claude Code integration"
45127
45028
  ).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) => {