@saasontools/strauss-kb 0.1.13 → 0.1.14

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-ZICKDZGY.js";
5
- import "./chunk-XALWG3EZ.js";
4
+ } from "./chunk-MBXNCZ4V.js";
5
+ import "./chunk-43KALLFU.js";
6
6
 
7
7
  // src/cli-main.ts
8
8
  runKbCli(process.argv.slice(2)).catch((error) => {
package/dist/index.cjs CHANGED
@@ -3778,7 +3778,7 @@ var answerCommand = define({
3778
3778
  name: "answer",
3779
3779
  tool: "kb_answer",
3780
3780
  usage: "answer <concept-id> <answer...>",
3781
- description: "Resolve an open question: sets the status, stamps who answered and when, and appends an Answer section. If the answer overturns an assumption or a decision, that is a supersession \u2014 do it explicitly.",
3781
+ description: "Resolve an open question: set status, stamp who and when, append an Answer section. If the answer overturns a decision or assumption, supersede that record explicitly.",
3782
3782
  input: import_zod9.z.object({ bundlePath, conceptId, answer: import_zod9.z.string().min(1) }),
3783
3783
  fromArgv: (argv, path) => ({
3784
3784
  bundlePath: path,
@@ -3873,7 +3873,7 @@ var contextCommand = define({
3873
3873
  name: "context",
3874
3874
  tool: "kb_context",
3875
3875
  usage: "context [--profile NAME] [--budget N] [--full-under N] [--format json] [--event NAME]",
3876
- description: "The pinned-base index block, for injection at every context birth \u2014 startup, clear, resume, and after compaction. An index, not the content: concept ids, titles and standing, with the bodies left behind kb_load at the point of use. Emits nothing when nothing is pinned. Refuses with the list of bases and their sizes rather than truncating past its budget. Budgets resolve most-specific-first: explicit flags, then the workspace manifests' `context` tables (per profile, over their `default`), then the built-in profile (session-start, compact, turn), then package defaults \u2014 so a repo tunes its own numbers in .strauss/kb-pins.json without touching hook commands. Like kb_schema and kb_types this takes no bundlePath \u2014 it reads the workspace pin manifests, because which bases a session should see is workspace state, not a property of one base.",
3876
+ 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.",
3877
3877
  input: import_zod12.z.object({
3878
3878
  budgetTokens: import_zod12.z.number().int().positive().optional().describe(
3879
3879
  "Ceiling on the whole emitted block; past it the command refuses with a list of bases rather than truncating. Defaults to 4000."
@@ -4059,7 +4059,7 @@ var listCommand = define({
4059
4059
  name: "list",
4060
4060
  tool: "kb_list",
4061
4061
  usage: "list [type]",
4062
- description: "Every record, optionally narrowed to one type. Use kb_query when you have a question; this is for enumerating.",
4062
+ description: "Every record, optionally one type. For enumerating; use kb_query for a question.",
4063
4063
  input: import_zod15.z.object({ bundlePath, type: import_zod15.z.enum(KB_RECORD_TYPES).optional() }),
4064
4064
  fromArgv: (argv, path) => ({ bundlePath: path, type: argv[1] }),
4065
4065
  run: async ({ store }, { bundlePath: path, type }) => (await store.list(path, type)).map((record) => ({
@@ -4077,7 +4077,7 @@ var loadCommand = define({
4077
4077
  name: "load",
4078
4078
  tool: "kb_load",
4079
4079
  usage: "load [type] [--budget N | --all] [--repo-root PATH]",
4080
- description: "Loads the whole knowledge base at once, each record with its standing. Superseded records arrive as stubs; rejected and open records arrive whole. Refuses past the token budget \u2014 call kb_catalog, kb_pack on it; `all` bypasses the budget. Never read record files directly. Cache-stable; `digest` is the base's content stamp \u2014 hooks use it to tell you when to reload.",
4080
+ description: "Load the whole base, each record with its standing \u2014 call it first, at the point of use, since compaction drops it. Superseded records arrive as stubs; kb_trace has the history. Over budget it refuses: kb_catalog, then kb_pack, or narrow with `type`; `all` bypasses. Never read record files directly \u2014 only kb_* tools resolve supersession. `digest` stamps the base's content, so hooks know when to reload.",
4081
4081
  input: import_zod16.z.object({
4082
4082
  bundlePath,
4083
4083
  type: import_zod16.z.enum(KB_RECORD_TYPES).optional(),
@@ -4129,7 +4129,7 @@ var logCommand = define({
4129
4129
  name: "log",
4130
4130
  tool: "kb_log",
4131
4131
  usage: "log",
4132
- description: "What touched what, and when. The only artifact here that cannot be reconstructed from the records, so malformed lines are reported rather than repaired.",
4132
+ description: "Who touched what, and when. Append-only; malformed lines are reported, never repaired.",
4133
4133
  input: import_zod17.z.object({ bundlePath }),
4134
4134
  fromArgv: (_argv, path) => ({ bundlePath: path }),
4135
4135
  run: ({ store }, { bundlePath: path }) => store.readLog(path)
@@ -4141,7 +4141,7 @@ var noDecisionCommand = define({
4141
4141
  name: "no-decision",
4142
4142
  tool: "kb_no_decision",
4143
4143
  usage: "no-decision <reason...>",
4144
- description: 'Claim in one sentence that there was nothing to decide. Gating on "did you write a decision?" rewards writing a junk one; gating on "did you answer?" does not, so silence has to be expressible. Idempotent \u2014 restating it is not a collision.',
4144
+ description: "Record in one sentence that a piece of work had nothing to decide. Idempotent.",
4145
4145
  input: import_zod18.z.object({ bundlePath, reason: import_zod18.z.string().min(1) }),
4146
4146
  fromArgv: (argv, path) => ({
4147
4147
  bundlePath: path,
@@ -4164,7 +4164,7 @@ var packCommand = define({
4164
4164
  name: "pack",
4165
4165
  tool: "kb_pack",
4166
4166
  usage: "pack <conceptId> [--hops N] [--max-nodes N] [--budget N]",
4167
- description: "The bounded neighbourhood around one record: everything within `hops` of the root, ranked and cut to `maxNodes`, with every cut record named under Excluded \u2014 a named gap is knowable, a silent one is not. Prefer this over kb_load when the base is too large to hold whole and the work centres on one record; prefer it over kb_query when the question needs the governed neighbourhood \u2014 what was settled and what binds near this record \u2014 rather than a lookup by wording. Superseded records arrive as name, replacement and date stubs exactly as kb_load emits them: their bodies no longer hold, and kb_trace has the history. Refuses outright rather than truncating when the pack would exceed its token budget \u2014 a partial pack is indistinguishable from a complete one \u2014 reporting the record count and every already-cut id so the caller can lower hops or maxNodes, or raise the budget. The header carries the bundle, root, budget and a timestamp; everything below the header is byte-identical across runs over an unchanged base, so two packs can be diffed and a changed byte means changed knowledge. This tool (with kb_load, kb_query and kb_trace) is the only supported way to read a base; a raw file read bypasses supersession resolution and returns replaced records as if current.",
4167
+ description: "Bounded neighbourhood around one record: within `hops`, ranked, cut to `maxNodes`, with every cut record named under Excluded. Use when the base is over kb_load's budget and the work centres on a record you can name. Refuses over budget rather than truncating. Everything below the header is byte-stable across runs. Resolves supersession like kb_load.",
4168
4168
  input: import_zod19.z.object({
4169
4169
  bundlePath,
4170
4170
  conceptId,
@@ -4264,7 +4264,7 @@ var pinCommand = define({
4264
4264
  name: "pin",
4265
4265
  tool: "kb_pin",
4266
4266
  usage: "pin [bundle-path] [--mode full|index] [--profiles a,b] [--local|--user] [--frozen|--unfreeze]",
4267
- description: "Pin a base into a workspace pin manifest, so `context` surfaces it at every context birth. Three layers, nearest wins: the committed project manifest (.strauss/kb-pins.json, the default), `--local` (.strauss/kb-pins.local.json, personal and gitignored), and `--user` (~/.strauss/kb-pins.json, every workspace). Idempotent \u2014 re-pinning changes nothing unless --mode, --profiles, or --frozen/--unfreeze are given, which update just those fields. `--mode full` preloads the whole base into the block regardless of the full-under threshold; `--mode index` never upgrades. `--profiles` scopes the pin to named context profiles. `--frozen` marks the base concluded: write commands against it refuse and `context` labels it read-only. A path with no records yet succeeds with a warning; bases are routinely pinned before they are populated. Pins are workspace state: the pinned base itself is never touched.",
4267
+ description: "Pin a base into a workspace manifest so kb_context surfaces it. Layers, nearest wins: project `.strauss/kb-pins.json` (default), `--local` (personal, gitignored), `--user` (`~/.strauss`). Idempotent; `--mode full|index`, `--profiles`, `--frozen`/`--unfreeze` update only those fields. A path with no records pins with a warning. Never touches the base itself.",
4268
4268
  input: import_zod20.z.object({
4269
4269
  bundlePath,
4270
4270
  mode: import_zod20.z.enum(["full", "index"]).optional().describe(
@@ -4308,7 +4308,7 @@ var pinsCommand = define({
4308
4308
  name: "pins",
4309
4309
  tool: "kb_pins",
4310
4310
  usage: "pins",
4311
- description: "Every pinned base across the manifest layers, each with its layer and whether it currently resolves to readable records. Reads the workspace manifests rather than any one base, like kb_context.",
4311
+ description: "Every pinned base across the manifest layers, with its layer and whether it resolves to records. Takes no bundlePath.",
4312
4312
  input: import_zod21.z.object({}),
4313
4313
  fromArgv: () => ({}),
4314
4314
  run: ({ store }) => listPins(store, process.cwd())
@@ -4362,7 +4362,7 @@ var readIndexCommand = define({
4362
4362
  name: "index",
4363
4363
  tool: "kb_index",
4364
4364
  usage: "index",
4365
- description: "The index, rebuilt if it disagrees with the records. One call gives the whole shape of the base: title, type, status, and description per record. The cheap re-orientation call after compaction or deep in a long session \u2014 a few hundred tokens; call it (or kb_context, when bases are pinned) first, then kb_load or fetch by concept id.",
4365
+ description: "The index \u2014 title, type, status, description per record \u2014 rebuilt if stale. Cheapest re-orientation after compaction: call it (or kb_context) first, then kb_load or fetch by id.",
4366
4366
  input: import_zod23.z.object({ bundlePath }),
4367
4367
  fromArgv: (_argv, path) => ({ bundlePath: path }),
4368
4368
  run: ({ store }, { bundlePath: path }) => store.readIndex(path)
@@ -4374,7 +4374,7 @@ var schemaCommand = define({
4374
4374
  name: "schema",
4375
4375
  tool: "kb_schema",
4376
4376
  usage: "schema",
4377
- description: "JSON Schema for the frontmatter, the write input, and log entries \u2014 generated from the code that enforces them, so it cannot drift from what a write will accept.",
4377
+ description: "JSON Schema for frontmatter, write input, and log entries, generated from the enforcing code.",
4378
4378
  input: import_zod24.z.object({}),
4379
4379
  fromArgv: () => ({}),
4380
4380
  run: () => Promise.resolve(kbJsonSchemas())
@@ -4386,7 +4386,7 @@ var statusCommand = define({
4386
4386
  name: "status",
4387
4387
  tool: "kb_status",
4388
4388
  usage: "status <concept-id> <status>",
4389
- description: "Move a record's status, leaving everything else alone. Uses a compare-and-swap, so a concurrent change fails loudly rather than being overwritten.",
4389
+ description: "Move a record's status. Compare-and-swap: a concurrent change fails instead of being overwritten.",
4390
4390
  input: import_zod25.z.object({
4391
4391
  bundlePath,
4392
4392
  conceptId,
@@ -4410,7 +4410,7 @@ var supersedeCommand = define({
4410
4410
  name: "supersede",
4411
4411
  tool: "kb_supersede",
4412
4412
  usage: "supersede <concept-id> <replacement-id>",
4413
- description: "Mark a record superseded by another, linking both directions. Use this rather than editing a record whose meaning changed \u2014 a record that quietly becomes something else invalidates every reference to it, and the earlier understanding is what a later trace needs.",
4413
+ description: "Mark a record superseded by another, linked in both directions. Use instead of editing a record whose meaning changed.",
4414
4414
  input: import_zod26.z.object({ bundlePath, conceptId, replacementId: conceptId }),
4415
4415
  fromArgv: (argv, path) => ({
4416
4416
  bundlePath: path,
@@ -4429,7 +4429,7 @@ var import_zod27 = require("zod");
4429
4429
  var syncInstructionsCommand = define({
4430
4430
  name: "sync-instructions",
4431
4431
  usage: "sync-instructions <file> [--profile NAME] [--budget N] [--full-under N]",
4432
- description: "Idempotently plant the `context` block between sentinel comments in an instruction file (AGENTS.md, CLAUDE.md), creating the block when absent and leaving everything outside the sentinels alone. CLI-only: this is file plumbing for runtimes whose instruction files are re-read where their conversations are not, not an agent capability \u2014 the capability is kb_context.",
4432
+ description: "CLI-only: plant the kb_context block between sentinel comments in AGENTS.md or CLAUDE.md, idempotently.",
4433
4433
  input: import_zod27.z.object({
4434
4434
  file: import_zod27.z.string().min(1).describe("The instruction file to edit in place."),
4435
4435
  budgetTokens: import_zod27.z.number().int().positive().optional(),
@@ -4465,7 +4465,7 @@ var traceCommand = define({
4465
4465
  name: "trace",
4466
4466
  tool: "kb_trace",
4467
4467
  usage: "trace <concept-id> [edges...]",
4468
- description: 'How a position was arrived at, as a timeline ordered by when each record was written. Deliberately includes rejected, draft, and superseded records \u2014 in a history those are the content, not noise. Follows supersession, shared code anchors, and shared sources. Use when the question is "why is this the way it is" rather than "what do we hold now". This tool (with kb_load and kb_query) is the only supported way to read a base; a raw file read bypasses supersession resolution and returns replaced records as if current.',
4468
+ description: 'Timeline of how a position was reached, ordered by write time, following supersession, shared anchors and shared sources. Includes rejected, draft and superseded records \u2014 in a history they are the content. For "why is it like this"; kb_load answers "what holds now".',
4469
4469
  input: import_zod28.z.object({
4470
4470
  bundlePath,
4471
4471
  conceptId,
@@ -4509,7 +4509,7 @@ var unpinCommand = define({
4509
4509
  name: "unpin",
4510
4510
  tool: "kb_unpin",
4511
4511
  usage: "unpin [bundle-path]",
4512
- description: "Remove a base from every pin manifest layer that holds it \u2014 project, local, and user \u2014 because unpinned means gone, not still injected from another file. Reports which layers were touched.",
4512
+ description: "Remove a base from every manifest layer that holds it. Reports the layers touched.",
4513
4513
  input: import_zod30.z.object({ bundlePath }),
4514
4514
  fromArgv: (argv, path) => ({ bundlePath: argv[1] ?? path }),
4515
4515
  run: (_ctx, { bundlePath: path }) => unpinBase(process.cwd(), path)
@@ -4537,7 +4537,7 @@ var verifyCommand = define({
4537
4537
  name: "verify",
4538
4538
  tool: "kb_verify",
4539
4539
  usage: "verify <concept-id> --note <text>",
4540
- description: "Append one verified[] event \u2014 who checked the record, when, and what the check found. Appends only; prior events are never rewritten. A record's own generator is refused unless the actor is human: re-reading your own output is not an independent check.",
4540
+ description: "Append a verified[] event: who checked, when, and what was found. Append-only. A record's own generator is refused unless the actor is `human:`-prefixed.",
4541
4541
  input: import_zod32.z.object({
4542
4542
  bundlePath,
4543
4543
  conceptId,
@@ -4566,15 +4566,7 @@ var writeCommand = define({
4566
4566
  name: "write",
4567
4567
  tool: "kb_write",
4568
4568
  usage: "write <type> < record.json",
4569
- description: [
4570
- "Write one record. Search first \u2014 the same knowledge filed twice under different slugs is how a base rots, and a duplicate concept id is rejected rather than overwritten. Call kb_types for the sections each type accepts.",
4571
- "",
4572
- "Judgment the tool cannot enforce for you:",
4573
- "- An unsourced claim is an `assumption` record with assumption: true, never a `fact` with a vague source. The distinction is what lets a later reader separate what was established from what was guessed.",
4574
- "- When two records conflict, say so in a `risk`, an `open-question`, or a superseding `decision`. Quietly picking a winner destroys the disagreement, which is usually the useful part.",
4575
- "- Prefer a new record over overloading an existing one, and keep each short. A record nobody finishes reading is not durable memory.",
4576
- "- Records are never deleted; supersede instead, so the earlier reasoning stays inspectable."
4577
- ].join("\n"),
4569
+ description: "Write one record. Search first \u2014 a duplicate concept id is rejected, not overwritten; kb_types lists each type's sections. An unsourced claim is an `assumption` with assumption: true, never a vague `fact`. Conflicting records get a `risk`, `open-question`, or superseding `decision`. Prefer a new short record over overloading one. Never delete; supersede.",
4578
4570
  input: import_zod33.z.object({
4579
4571
  bundlePath,
4580
4572
  type: import_zod33.z.enum(KB_RECORD_TYPES),
@@ -4606,14 +4598,7 @@ var writeDecisionCommand = define({
4606
4598
  name: "write-decision",
4607
4599
  tool: "kb_write_decision",
4608
4600
  usage: "write-decision < decision.json",
4609
- description: [
4610
- "Write a decision. Takes `alternative` and `impact` as fields rather than free sections, because what was rejected is the part a later reader cannot reconstruct from the code \u2014 a heading is too easy to leave empty.",
4611
- "",
4612
- "What belongs in one:",
4613
- '- Record a decision when a later reader would otherwise "simplify" the constraint away. If the diff already answers the question, there is nothing here to write.',
4614
- "- `alternative` is what you turned down and why, not a list of everything considered.",
4615
- "- A reference to material you read goes in `sources`; a reference to code goes in `anchors`; a reference to another record goes in `relatedConceptIds`."
4616
- ].join("\n"),
4601
+ description: "Write a decision, with `alternative` (what was rejected and why) and `impact` as fields. Record one when a later reader would otherwise simplify the constraint away; skip when the diff already answers it. `sources` for material read, `anchors` for code, `relatedConceptIds` for records.",
4617
4602
  input: import_zod34.z.object({ bundlePath, input: decisionInputSchema }),
4618
4603
  fromArgv: async (_argv, path, stdin) => ({
4619
4604
  bundlePath: path,
@@ -4673,7 +4658,7 @@ var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
4673
4658
  var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
4674
4659
 
4675
4660
  // src/version.ts
4676
- var VERSION = true ? "0.1.13" : "0.0.0-dev";
4661
+ var VERSION = true ? "0.1.14" : "0.0.0-dev";
4677
4662
 
4678
4663
  // src/mcp.ts
4679
4664
  function createKbMcpServer() {