@saasontools/strauss-kb 0.1.18 → 0.1.19

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/cli-main.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runKbCli
4
- } from "./chunk-IOIUS26S.js";
5
- import "./chunk-GSOTMWZZ.js";
4
+ } from "./chunk-CQBLH7CE.js";
5
+ import "./chunk-MNQNHYWL.js";
6
6
 
7
7
  // src/cli-main.ts
8
8
  runKbCli(process.argv.slice(2)).catch((error) => {
package/dist/index.cjs CHANGED
@@ -123,6 +123,7 @@ __export(index_exports, {
123
123
  listPins: () => listPins,
124
124
  loadQmd: () => loadQmd,
125
125
  matchToDiff: () => matchToDiff,
126
+ matchesTags: () => matchesTags,
126
127
  mergedContextBudgets: () => mergedContextBudgets,
127
128
  neighbours: () => neighbours,
128
129
  pack: () => pack,
@@ -2733,6 +2734,13 @@ function typeRank(record) {
2733
2734
  return index2 === -1 ? TYPE_PRIORITY.length : index2;
2734
2735
  }
2735
2736
 
2737
+ // src/kb-tags.ts
2738
+ function matchesTags(record, filter) {
2739
+ if (!filter.tags?.length && !filter.excludeTags?.length) return true;
2740
+ const carried = new Set(record.frontmatter.tags ?? []);
2741
+ return (filter.tags ?? []).every((tag) => carried.has(tag)) && !(filter.excludeTags ?? []).some((tag) => carried.has(tag));
2742
+ }
2743
+
2736
2744
  // src/catalog.ts
2737
2745
  var EMPTY_STANDINGS = {
2738
2746
  current: 0,
@@ -2743,7 +2751,7 @@ var EMPTY_STANDINGS = {
2743
2751
  };
2744
2752
  function catalog(bundle, options = {}) {
2745
2753
  const wanted = options.type ? bundle.filter((record) => record.frontmatter.type === options.type) : bundle;
2746
- const entries = adjudicate(wanted, bundle, options.now ?? /* @__PURE__ */ new Date()).map((hit) => ({
2754
+ const entries = adjudicate(wanted, bundle, options.now ?? /* @__PURE__ */ new Date()).filter((hit) => matchesTags(hit.record, options)).map((hit) => ({
2747
2755
  conceptId: hit.record.conceptId,
2748
2756
  type: hit.record.frontmatter.type,
2749
2757
  title: hit.record.frontmatter.title ?? null,
@@ -3016,13 +3024,16 @@ var KbStore = class {
3016
3024
  return this.parse(conceptId2, raw);
3017
3025
  }
3018
3026
  /**
3019
- * Every record in the bundle, optionally narrowed to one type.
3027
+ * Every record in the bundle, optionally narrowed to one type and to the
3028
+ * records carrying every tag in `filter.tags`. Selection only — `excludeTags`
3029
+ * is not taken here, because `query`, `catalog` and `load` read through this
3030
+ * and must adjudicate over the whole base.
3020
3031
  *
3021
3032
  * A file that fails to parse is skipped and logged rather than thrown: one
3022
3033
  * malformed record — hand-edited, or written by a producer we don't know —
3023
3034
  * must not make the whole bundle unreadable.
3024
3035
  */
3025
- async list(bundlePath2, type) {
3036
+ async list(bundlePath2, type, filter = {}) {
3026
3037
  const root = this.root(bundlePath2);
3027
3038
  let names;
3028
3039
  try {
@@ -3036,7 +3047,9 @@ var KbStore = class {
3036
3047
  DEFAULT_IO_CONCURRENCY,
3037
3048
  async ({ name, conceptId: conceptId2 }) => this.parse(conceptId2, await (0, import_promises6.readFile)((0, import_node_path7.join)(root, name), "utf8"))
3038
3049
  );
3039
- return records.filter((record) => record !== null);
3050
+ return records.filter(
3051
+ (record) => record !== null && matchesTags(record, filter)
3052
+ );
3040
3053
  }
3041
3054
  /**
3042
3055
  * Moves a record's status, preserving everything else.
@@ -3176,9 +3189,10 @@ ${answer}
3176
3189
  /* @__PURE__ */ new Date(),
3177
3190
  await this.detectDrift(narrowed, options.repoRoot)
3178
3191
  );
3179
- if (options.includeNonCurrent) return adjudicated;
3180
- const present = new Set(adjudicated.map((hit) => hit.record.conceptId));
3181
- return adjudicated.filter(
3192
+ const kept = adjudicated.filter((hit) => matchesTags(hit.record, options));
3193
+ if (options.includeNonCurrent) return kept;
3194
+ const present = new Set(kept.map((hit) => hit.record.conceptId));
3195
+ return kept.filter(
3182
3196
  (hit) => hit.standing !== "superseded" || !hit.heads.some((head) => present.has(head.conceptId))
3183
3197
  );
3184
3198
  }
@@ -3281,14 +3295,17 @@ ${answer}
3281
3295
  /* @__PURE__ */ new Date(),
3282
3296
  await this.detectDrift(wanted, options.repoRoot)
3283
3297
  );
3284
- const records = adjudicated.filter((hit) => hit.standing !== "superseded");
3285
- const superseded = adjudicated.filter((hit) => hit.standing === "superseded").map(stub);
3298
+ const kept = adjudicated.filter(
3299
+ (hit) => matchesTags(hit.record, { excludeTags: options.excludeTags })
3300
+ );
3301
+ const records = kept.filter((hit) => hit.standing !== "superseded");
3302
+ const superseded = kept.filter((hit) => hit.standing === "superseded").map(stub);
3286
3303
  const approxTokens2 = records.reduce((total, hit) => total + estimateTokens(hit.record), 0) + superseded.reduce((total, entry) => total + estimateStubTokens(entry), 0);
3287
3304
  const bundleDigestValue = bundleDigest(records, superseded);
3288
3305
  if (!options.all && approxTokens2 > budgetTokens) {
3289
3306
  return {
3290
3307
  loaded: false,
3291
- recordCount: wanted.length,
3308
+ recordCount: kept.length,
3292
3309
  approxTokens: approxTokens2,
3293
3310
  budgetTokens,
3294
3311
  message: refusalMessage({
@@ -3301,7 +3318,7 @@ ${answer}
3301
3318
  }
3302
3319
  return {
3303
3320
  loaded: true,
3304
- recordCount: wanted.length,
3321
+ recordCount: kept.length,
3305
3322
  tokensLoaded: approxTokens2,
3306
3323
  budgetTokens: options.all ? null : budgetTokens,
3307
3324
  records,
@@ -3788,14 +3805,17 @@ function asBudgets(value) {
3788
3805
  if (value === null || typeof value !== "object") return {};
3789
3806
  const table2 = value;
3790
3807
  const pick = (key2, min) => {
3791
- const raw = table2[key2];
3792
- return typeof raw === "number" && Number.isInteger(raw) && raw >= min ? raw : void 0;
3808
+ const raw2 = table2[key2];
3809
+ return typeof raw2 === "number" && Number.isInteger(raw2) && raw2 >= min ? raw2 : void 0;
3793
3810
  };
3794
3811
  const budgetTokens = pick("budgetTokens", 1);
3795
3812
  const fullUnderTokens = pick("fullUnderTokens", 0);
3813
+ const raw = table2["excludeTags"];
3814
+ const excludeTags = Array.isArray(raw) ? raw.filter((tag) => typeof tag === "string" && tag !== "") : void 0;
3796
3815
  return {
3797
3816
  ...budgetTokens ? { budgetTokens } : {},
3798
- ...fullUnderTokens !== void 0 ? { fullUnderTokens } : {}
3817
+ ...fullUnderTokens !== void 0 ? { fullUnderTokens } : {},
3818
+ ...excludeTags ? { excludeTags } : {}
3799
3819
  };
3800
3820
  }
3801
3821
  function contextProfileBudgets(manifest, profile) {
@@ -4111,7 +4131,7 @@ function preamble() {
4111
4131
  "tokens."
4112
4132
  ].join("\n");
4113
4133
  }
4114
- async function renderBase(store, path, absolutePath, fullUnderTokens, pinMode, budgetTokens) {
4134
+ async function renderBase(store, path, absolutePath, fullUnderTokens, pinMode, budgetTokens, excludeTags) {
4115
4135
  const bundle = await store.list(absolutePath);
4116
4136
  if (bundle.length === 0) {
4117
4137
  return {
@@ -4125,7 +4145,8 @@ async function renderBase(store, path, absolutePath, fullUnderTokens, pinMode, b
4125
4145
  let degradedFrom;
4126
4146
  if (fullCap > 0) {
4127
4147
  const full = await store.load(absolutePath, {
4128
- budgetTokens: fullCap
4148
+ budgetTokens: fullCap,
4149
+ excludeTags
4129
4150
  });
4130
4151
  if (!full.loaded && pinMode === "full") {
4131
4152
  degradedFrom = { approxTokens: full.approxTokens };
@@ -4155,7 +4176,9 @@ async function renderBase(store, path, absolutePath, fullUnderTokens, pinMode, b
4155
4176
  };
4156
4177
  }
4157
4178
  }
4158
- const adjudicated = adjudicate(bundle, bundle);
4179
+ const adjudicated = adjudicate(bundle, bundle).filter(
4180
+ (hit) => matchesTags(hit.record, { excludeTags })
4181
+ );
4159
4182
  const lines = adjudicated.filter((hit) => hit.standing !== "superseded").map((hit) => renderIndexLine(hit.record));
4160
4183
  const superseded = adjudicated.filter((hit) => hit.standing === "superseded").map(
4161
4184
  (hit) => `- \`${hit.record.conceptId}\` \u2192 superseded by ${hit.heads.map((head) => `\`${head.conceptId}\``).join(", ") || "(missing replacement)"}`
@@ -4176,6 +4199,7 @@ async function buildContext(store, workspaceDir, options = {}) {
4176
4199
  const fromManifest = mergedContextBudgets(merged, options.profile);
4177
4200
  budgetTokens = options.budgetTokens ?? fromManifest.budgetTokens ?? builtin.budgetTokens ?? DEFAULT_CONTEXT_BUDGET;
4178
4201
  fullUnderTokens = options.fullUnderTokens ?? fromManifest.fullUnderTokens ?? builtin.fullUnderTokens ?? 0;
4202
+ const excludeTags = options.excludeTags ?? fromManifest.excludeTags ?? builtin.excludeTags ?? [];
4179
4203
  const pins = merged.pins.filter(
4180
4204
  (pin) => !pin.profiles?.length || !options.profile || pin.profiles.includes(options.profile)
4181
4205
  );
@@ -4196,7 +4220,8 @@ async function buildContext(store, workspaceDir, options = {}) {
4196
4220
  pin.absolutePath,
4197
4221
  fullUnderTokens,
4198
4222
  pin.mode,
4199
- budgetTokens
4223
+ budgetTokens,
4224
+ excludeTags
4200
4225
  ),
4201
4226
  frozen: pin.frozen === true
4202
4227
  }))
@@ -4857,6 +4882,9 @@ var import_zod9 = require("zod");
4857
4882
  var import_zod8 = require("zod");
4858
4883
  var bundlePath = import_zod8.z.string().min(1).describe("Absolute path to the knowledge base directory.");
4859
4884
  var conceptId = import_zod8.z.string().min(1).describe("e.g. decision.cursor-v2");
4885
+ var TAGS = import_zod8.z.array(import_zod8.z.string().min(1)).optional().describe(
4886
+ "Keep only records carrying every one of these frontmatter tags. Matched exactly."
4887
+ );
4860
4888
  var REPO_ROOT = import_zod8.z.string().min(1).optional().describe(
4861
4889
  "Where the anchored source lives, for the drift check. Defaults to the working directory."
4862
4890
  );
@@ -4878,6 +4906,41 @@ function argvFlag(argv, name) {
4878
4906
  }
4879
4907
  return value;
4880
4908
  }
4909
+ function argvFlags(argv, name) {
4910
+ const values = [];
4911
+ for (const [at2, arg] of argv.entries()) {
4912
+ if (arg.startsWith(`${name}=`)) {
4913
+ const value = arg.slice(name.length + 1);
4914
+ if (!value) throw new KbMissingFlagValueError(name);
4915
+ values.push(value);
4916
+ } else if (arg === name) {
4917
+ const value = argv[at2 + 1];
4918
+ if (value === void 0 || value.startsWith("--")) {
4919
+ throw new KbMissingFlagValueError(name);
4920
+ }
4921
+ values.push(value);
4922
+ }
4923
+ }
4924
+ return values;
4925
+ }
4926
+ function argvWithout(argv, ...names) {
4927
+ const kept = [];
4928
+ for (let at2 = 0; at2 < argv.length; at2 += 1) {
4929
+ const arg = argv[at2];
4930
+ if (names.some((name) => arg.startsWith(`${name}=`))) continue;
4931
+ if (names.includes(arg)) {
4932
+ at2 += 1;
4933
+ continue;
4934
+ }
4935
+ kept.push(arg);
4936
+ }
4937
+ return kept;
4938
+ }
4939
+ function argvPositional(argv, ...names) {
4940
+ return argvWithout(argv.slice(1), ...names).find(
4941
+ (arg) => !arg.startsWith("--")
4942
+ );
4943
+ }
4881
4944
 
4882
4945
  // src/commands/anchor-resolve.ts
4883
4946
  function resolverSummary(results) {
@@ -5194,25 +5257,39 @@ var import_zod12 = require("zod");
5194
5257
  var catalogCommand = define({
5195
5258
  name: "catalog",
5196
5259
  tool: "kb_catalog",
5197
- usage: "catalog [type]",
5260
+ usage: "catalog [type] [--tag T]...",
5198
5261
  description: "Lists every record as one line \u2014 concept id, type, title, standing, and a stale flag \u2014 at roughly thirty tokens each. Pick this over kb_load once kb_load refuses: kb_catalog never refuses. Superseded records show only their replacement; fetch bodies with kb_load, kb_pack, kb_query, or kb_trace.",
5199
5262
  input: import_zod12.z.object({
5200
5263
  bundlePath,
5201
- type: import_zod12.z.enum(KB_RECORD_TYPES).optional()
5202
- }),
5203
- fromArgv: (argv, path) => ({
5204
- bundlePath: path,
5205
- ...argv[1] && !argv[1].startsWith("--") ? { type: argv[1] } : {}
5264
+ type: import_zod12.z.enum(KB_RECORD_TYPES).optional(),
5265
+ tags: TAGS
5206
5266
  }),
5207
- run: async ({ store }, { bundlePath: path, type }) => render(
5208
- await store.catalog(path, { ...type ? { type } : {} }),
5267
+ fromArgv: (argv, path) => {
5268
+ const tags = argvFlags(argv, "--tag");
5269
+ const type = argvPositional(argv, "--tag");
5270
+ return {
5271
+ bundlePath: path,
5272
+ ...type ? { type } : {},
5273
+ ...tags.length ? { tags } : {}
5274
+ };
5275
+ },
5276
+ run: async ({ store }, { bundlePath: path, type, tags }) => render(
5277
+ await store.catalog(path, {
5278
+ ...type ? { type } : {},
5279
+ ...tags ? { tags } : {}
5280
+ }),
5209
5281
  path,
5210
- type
5282
+ type,
5283
+ tags
5211
5284
  )
5212
5285
  });
5213
- function render(result, bundle, type) {
5286
+ function render(result, bundle, type, tags) {
5287
+ const narrowed = [
5288
+ ...type ? [type] : [],
5289
+ ...tags?.length ? [`tags: ${tags.join(", ")}`] : []
5290
+ ].join(" \xB7 ");
5214
5291
  const lines = [
5215
- `# KB Catalog${type ? ` \u2014 ${type}` : ""}`,
5292
+ `# KB Catalog${narrowed ? ` \u2014 ${narrowed}` : ""}`,
5216
5293
  `bundle: ${bundle}`,
5217
5294
  `${count(result.recordCount, "record")}: ${standingCounts(result)}`
5218
5295
  ];
@@ -5224,7 +5301,7 @@ function render(result, bundle, type) {
5224
5301
  lines.push("");
5225
5302
  if (!result.entries.length) {
5226
5303
  lines.push(
5227
- type ? `(no records of type ${type})` : "(no records \u2014 this base is empty)"
5304
+ narrowed ? `(no records matching ${narrowed})` : "(no records \u2014 this base is empty)"
5228
5305
  );
5229
5306
  } else {
5230
5307
  for (const entry of result.entries) lines.push(renderCatalogLine(entry));
@@ -5257,7 +5334,7 @@ var import_zod13 = require("zod");
5257
5334
  var contextCommand = define({
5258
5335
  name: "context",
5259
5336
  tool: "kb_context",
5260
- usage: "context [--profile NAME] [--budget N] [--full-under N] [--format json] [--event NAME]",
5337
+ usage: "context [--profile NAME] [--budget N] [--full-under N] [--exclude-tag T]... [--format json] [--event NAME]",
5261
5338
  description: "Index block of pinned bases (ids, titles, standing) for injection at context birth. Takes no bundlePath \u2014 reads the workspace pin manifests. Empty when nothing is pinned; refuses over budget rather than truncating. Budget precedence: flags, then the manifest `context[profile]` over `context.default`, then the built-in profile, then package defaults.",
5262
5339
  input: import_zod13.z.object({
5263
5340
  budgetTokens: import_zod13.z.number().int().positive().optional().describe(
@@ -5269,6 +5346,9 @@ var contextCommand = define({
5269
5346
  profile: import_zod13.z.string().optional().describe(
5270
5347
  "Named budget set: built-ins are session-start (full-under 1500), compact and turn (budget 2500); the manifests' `context` tables override per repo. Unknown names fall through to defaults rather than failing."
5271
5348
  ),
5349
+ excludeTags: import_zod13.z.array(import_zod13.z.string().min(1)).optional().describe(
5350
+ "Frontmatter tags whose records stay out of the block. The base stays pinned and stays readable by tool; resolved like the budgets."
5351
+ ),
5272
5352
  format: import_zod13.z.enum(["markdown", "json"]).optional().describe(
5273
5353
  "CLI envelope for hook protocols that require strict JSON on stdout. MCP callers omit this \u2014 the block itself is identical."
5274
5354
  ),
@@ -5282,19 +5362,22 @@ var contextCommand = define({
5282
5362
  const profile = argvFlag(argv, "--profile");
5283
5363
  const format = argvFlag(argv, "--format");
5284
5364
  const event = argvFlag(argv, "--event");
5365
+ const excludeTags = argvFlags(argv, "--exclude-tag");
5285
5366
  return {
5286
5367
  ...budget ? { budgetTokens: Number(budget) } : {},
5287
5368
  ...fullUnder ? { fullUnderTokens: Number(fullUnder) } : {},
5288
5369
  ...profile ? { profile } : {},
5370
+ ...excludeTags.length ? { excludeTags } : {},
5289
5371
  ...format ? { format } : {},
5290
5372
  ...event ? { event } : {}
5291
5373
  };
5292
5374
  },
5293
- run: async ({ store }, { budgetTokens, fullUnderTokens, profile, format, event }) => {
5375
+ run: async ({ store }, { budgetTokens, fullUnderTokens, profile, excludeTags, format, event }) => {
5294
5376
  const result = await buildContext(store, process.cwd(), {
5295
5377
  ...budgetTokens ? { budgetTokens } : {},
5296
5378
  ...fullUnderTokens ? { fullUnderTokens } : {},
5297
5379
  ...profile ? { profile } : {},
5380
+ ...excludeTags ? { excludeTags } : {},
5298
5381
  // Degradations — a full pin that could not fit, a refused block — go
5299
5382
  // to stderr as well as into the block itself: stderr is diagnostics on
5300
5383
  // both surfaces (hooks discard it, MCP logs it), so an operator can
@@ -6095,17 +6178,31 @@ var import_zod17 = require("zod");
6095
6178
  var listCommand = define({
6096
6179
  name: "list",
6097
6180
  tool: "kb_list",
6098
- usage: "list [type]",
6099
- description: "Every record, optionally one type. For enumerating; use kb_query for a question.",
6100
- input: import_zod17.z.object({ bundlePath, type: import_zod17.z.enum(KB_RECORD_TYPES).optional() }),
6101
- fromArgv: (argv, path) => ({ bundlePath: path, type: argv[1] }),
6102
- run: async ({ store }, { bundlePath: path, type }) => (await store.list(path, type)).map((record) => ({
6103
- conceptId: record.conceptId,
6104
- title: record.frontmatter.title ?? null,
6105
- description: record.frontmatter.description ?? null,
6106
- status: record.frontmatter.strauss_status,
6107
- anchors: record.frontmatter.strauss_anchors ?? []
6108
- }))
6181
+ usage: "list [type] [--tag T]...",
6182
+ description: "Every record, optionally one type or tag. For enumerating; use kb_query for a question.",
6183
+ input: import_zod17.z.object({
6184
+ bundlePath,
6185
+ type: import_zod17.z.enum(KB_RECORD_TYPES).optional(),
6186
+ tags: TAGS
6187
+ }),
6188
+ fromArgv: (argv, path) => {
6189
+ const tags = argvFlags(argv, "--tag");
6190
+ const type = argvPositional(argv, "--tag");
6191
+ return {
6192
+ bundlePath: path,
6193
+ ...type ? { type } : {},
6194
+ ...tags.length ? { tags } : {}
6195
+ };
6196
+ },
6197
+ run: async ({ store }, { bundlePath: path, type, tags }) => (await store.list(path, type, { ...tags ? { tags } : {} })).map(
6198
+ (record) => ({
6199
+ conceptId: record.conceptId,
6200
+ title: record.frontmatter.title ?? null,
6201
+ description: record.frontmatter.description ?? null,
6202
+ status: record.frontmatter.strauss_status,
6203
+ anchors: record.frontmatter.strauss_anchors ?? []
6204
+ })
6205
+ )
6109
6206
  });
6110
6207
 
6111
6208
  // src/commands/load.ts
@@ -6356,31 +6453,33 @@ var import_zod24 = require("zod");
6356
6453
  var queryCommand = define({
6357
6454
  name: "query",
6358
6455
  tool: "kb_query",
6359
- usage: "query <text...> [--repo-root PATH]",
6456
+ usage: "query <text...> [--tag T]... [--repo-root PATH]",
6360
6457
  description: "Search; every hit carries its standing. Flagged, never filtered: a superseded hit returns with its replacement, a rejected one is marked. Prefer kb_load when the base fits its budget \u2014 a full read beats search. Results are volatile: place them at the tail, not the cached prefix. Never read record files directly.",
6361
6458
  input: import_zod24.z.object({
6362
6459
  bundlePath,
6363
6460
  text: import_zod24.z.string().optional(),
6364
6461
  type: import_zod24.z.enum(KB_RECORD_TYPES).optional(),
6365
6462
  includeNonCurrent: import_zod24.z.boolean().optional(),
6463
+ tags: TAGS,
6366
6464
  repoRoot: REPO_ROOT
6367
6465
  }),
6368
- // `--repo-root` is a flag, so its value must not fall into the search text.
6466
+ // Both are flags, so neither's value may fall into the search text.
6369
6467
  fromArgv: (argv, path) => {
6370
6468
  const repoRoot = argvFlag(argv, "--repo-root");
6371
- const words = argv.slice(1);
6372
- const flag = words.indexOf("--repo-root");
6373
- if (flag !== -1) words.splice(flag, 2);
6469
+ const tags = argvFlags(argv, "--tag");
6470
+ const words = argvWithout(argv.slice(1), "--repo-root", "--tag");
6374
6471
  return {
6375
6472
  bundlePath: path,
6376
6473
  text: words.join(" ").trim(),
6377
6474
  includeNonCurrent: true,
6475
+ ...tags.length ? { tags } : {},
6378
6476
  ...repoRoot !== void 0 ? { repoRoot } : {}
6379
6477
  };
6380
6478
  },
6381
- run: async ({ store }, { bundlePath: path, text, type, includeNonCurrent, repoRoot }) => (await store.query(path, text ?? "", {
6479
+ run: async ({ store }, { bundlePath: path, text, type, includeNonCurrent, tags, repoRoot }) => (await store.query(path, text ?? "", {
6382
6480
  ...type ? { type } : {},
6383
6481
  includeNonCurrent: includeNonCurrent === true,
6482
+ ...tags ? { tags } : {},
6384
6483
  ...repoRoot !== void 0 ? { repoRoot } : {}
6385
6484
  })).map((hit) => ({
6386
6485
  conceptId: hit.record.conceptId,
@@ -6795,7 +6894,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
6795
6894
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
6796
6895
 
6797
6896
  // src/version.ts
6798
- var VERSION = true ? "0.1.18" : "0.0.0-dev";
6897
+ var VERSION = true ? "0.1.19" : "0.0.0-dev";
6799
6898
 
6800
6899
  // src/mcp.ts
6801
6900
  function createKbMcpServer() {
@@ -7039,6 +7138,7 @@ function usage() {
7039
7138
  listPins,
7040
7139
  loadQmd,
7041
7140
  matchToDiff,
7141
+ matchesTags,
7042
7142
  mergedContextBudgets,
7043
7143
  neighbours,
7044
7144
  pack,