@saasontools/strauss-kb 0.1.20 → 0.1.21
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 +5 -7
- package/dist/{chunk-XDH6J6CH.js → chunk-VXWN62HT.js} +2 -2
- package/dist/{chunk-EXZQZJU2.js → chunk-WVJULVGY.js} +2 -2
- package/dist/{chunk-QQLPJO4R.js → chunk-XBZ7G5R5.js} +78 -49
- package/dist/chunk-XBZ7G5R5.js.map +1 -0
- package/dist/cli-main.cjs +75 -48
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.js +2 -2
- package/dist/index.cjs +77 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -3
- package/dist/mcp-main.cjs +75 -48
- package/dist/mcp-main.cjs.map +1 -1
- package/dist/mcp-main.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-QQLPJO4R.js.map +0 -1
- /package/dist/{chunk-XDH6J6CH.js.map → chunk-VXWN62HT.js.map} +0 -0
- /package/dist/{chunk-EXZQZJU2.js.map → chunk-WVJULVGY.js.map} +0 -0
package/README.md
CHANGED
|
@@ -222,11 +222,12 @@ end of it. Six optional fields extend it:
|
|
|
222
222
|
them; `repo` and `ref` are **author-owned identity** and a resolution pass
|
|
223
223
|
never writes them.
|
|
224
224
|
|
|
225
|
-
`anchor-resolve <concept-id>` (`kb_anchor_resolve`)
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
`anchor-resolve <concept-id>` (`kb_anchor_resolve`) checks the anchored code
|
|
226
|
+
against the working tree (`--repo-root` when the base is not inside it) and
|
|
227
|
+
never writes `verified[]`; `--check` writes nothing at all. Per anchor:
|
|
228
228
|
|
|
229
|
-
- **stamped** — no hash yet; hash, line count, and timestamp are written
|
|
229
|
+
- **stamped** — no hash yet; hash, line count, and timestamp are written
|
|
230
|
+
(`unstamped` under `--check`, which writes none).
|
|
230
231
|
- **match** — unchanged; nothing written. `--restamp` re-dates on purpose.
|
|
231
232
|
- **drifted** — hash changed. Baseline kept unless `--rebaseline`.
|
|
232
233
|
- **unresolved** — not comparable, with a reason. A finding, not an error.
|
|
@@ -245,9 +246,6 @@ and again on the real path after symlinks.
|
|
|
245
246
|
Exit code is non-zero on **drifted**, or on **unresolved** for an anchor that
|
|
246
247
|
carries a hash; unstamped anchors and unreachable remotes never fail.
|
|
247
248
|
|
|
248
|
-
A fully clean run — every anchor checked and `match`, none stamped this run —
|
|
249
|
-
appends a `verified[]` event.
|
|
250
|
-
|
|
251
249
|
Symbols resolve tree-sitter first — the 20 language packs that have both a
|
|
252
250
|
grammar and a definitions query, pinned together by `pnpm grammars pin` from
|
|
253
251
|
`grammars/packs.json` and proved at pin time — then the regex heuristic for
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
KB_DIR,
|
|
5
5
|
KbStore,
|
|
6
6
|
VERSION
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XBZ7G5R5.js";
|
|
8
8
|
|
|
9
9
|
// src/cli.ts
|
|
10
10
|
import { join } from "path";
|
|
@@ -121,4 +121,4 @@ function usage() {
|
|
|
121
121
|
export {
|
|
122
122
|
runKbCli
|
|
123
123
|
};
|
|
124
|
-
//# sourceMappingURL=chunk-
|
|
124
|
+
//# sourceMappingURL=chunk-VXWN62HT.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
KB_COMMANDS,
|
|
3
3
|
KbStore,
|
|
4
4
|
VERSION
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XBZ7G5R5.js";
|
|
6
6
|
|
|
7
7
|
// src/mcp.ts
|
|
8
8
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -46,4 +46,4 @@ export {
|
|
|
46
46
|
createKbMcpServer,
|
|
47
47
|
runKbMcpServer
|
|
48
48
|
};
|
|
49
|
-
//# sourceMappingURL=chunk-
|
|
49
|
+
//# sourceMappingURL=chunk-WVJULVGY.js.map
|
|
@@ -2235,6 +2235,8 @@ var Fault = /* @__PURE__ */ ((Fault2) => {
|
|
|
2235
2235
|
var ErrorTypes = /* @__PURE__ */ ((ErrorTypes2) => {
|
|
2236
2236
|
ErrorTypes2["KbRecordAlreadyExists"] = "KbRecordAlreadyExists";
|
|
2237
2237
|
ErrorTypes2["KbClassifyInput"] = "KbClassifyInput";
|
|
2238
|
+
ErrorTypes2["KbFlagConflict"] = "KbFlagConflict";
|
|
2239
|
+
ErrorTypes2["KbInvalidActor"] = "KbInvalidActor";
|
|
2238
2240
|
ErrorTypes2["KbInvalidConceptId"] = "KbInvalidConceptId";
|
|
2239
2241
|
ErrorTypes2["KbMatchInput"] = "KbMatchInput";
|
|
2240
2242
|
ErrorTypes2["KbMissingFlagValue"] = "KbMissingFlagValue";
|
|
@@ -2335,6 +2337,38 @@ var KbSelfVerificationError = class extends BaseError {
|
|
|
2335
2337
|
actor;
|
|
2336
2338
|
generatedBy;
|
|
2337
2339
|
};
|
|
2340
|
+
var KbInvalidActorError = class extends BaseError {
|
|
2341
|
+
constructor(actor, reason) {
|
|
2342
|
+
super({
|
|
2343
|
+
message: `kb: actor ${JSON.stringify(actor)} ${reason} \u2014 set STRAUSS_KB_ACTOR, e.g. human:alice or agent:reviewer`,
|
|
2344
|
+
errorType: "KbInvalidActor" /* KbInvalidActor */,
|
|
2345
|
+
code: 400,
|
|
2346
|
+
fault: "User" /* User */,
|
|
2347
|
+
retriable: false,
|
|
2348
|
+
reportToUser: true,
|
|
2349
|
+
details: { actor, reason, action: "refused" }
|
|
2350
|
+
});
|
|
2351
|
+
this.actor = actor;
|
|
2352
|
+
this.reason = reason;
|
|
2353
|
+
}
|
|
2354
|
+
actor;
|
|
2355
|
+
reason;
|
|
2356
|
+
};
|
|
2357
|
+
var KbFlagConflictError = class extends BaseError {
|
|
2358
|
+
constructor(flags) {
|
|
2359
|
+
super({
|
|
2360
|
+
message: `kb: ${flags.join(" and ")} cannot be combined`,
|
|
2361
|
+
errorType: "KbFlagConflict" /* KbFlagConflict */,
|
|
2362
|
+
code: 400,
|
|
2363
|
+
fault: "User" /* User */,
|
|
2364
|
+
retriable: false,
|
|
2365
|
+
reportToUser: true,
|
|
2366
|
+
details: { flags }
|
|
2367
|
+
});
|
|
2368
|
+
this.flags = flags;
|
|
2369
|
+
}
|
|
2370
|
+
flags;
|
|
2371
|
+
};
|
|
2338
2372
|
var KbPackBudgetExceededError = class extends BaseError {
|
|
2339
2373
|
constructor(recordCount, approxTokens2, budgetTokens, excluded) {
|
|
2340
2374
|
super({
|
|
@@ -4978,19 +5012,11 @@ function byGeneratedAt(left, right) {
|
|
|
4978
5012
|
|
|
4979
5013
|
// src/commands/anchor-resolve.ts
|
|
4980
5014
|
import { z as z10 } from "zod";
|
|
4981
|
-
function resolverSummary(results) {
|
|
4982
|
-
const names = [
|
|
4983
|
-
...new Set(
|
|
4984
|
-
results.flatMap((entry) => entry.resolver ? [entry.resolver] : [])
|
|
4985
|
-
)
|
|
4986
|
-
].sort();
|
|
4987
|
-
return names.length ? `${names.join(" + ")} resolver` : "whole-file";
|
|
4988
|
-
}
|
|
4989
5015
|
var anchorResolveCommand = define({
|
|
4990
5016
|
name: "anchor-resolve",
|
|
4991
5017
|
tool: "kb_anchor_resolve",
|
|
4992
|
-
usage: "anchor-resolve <concept-id> [--repo-root <path>] [--offline] [--rebaseline] [--restamp]",
|
|
4993
|
-
description: "Resolve a record's anchors: stamp a hash onto anchors that lack one, report drift where the code moved. An anchor naming another repository is read from that remote through a bare cache; --offline uses the cache only.
|
|
5018
|
+
usage: "anchor-resolve <concept-id> [--repo-root <path>] [--offline] [--rebaseline] [--restamp] [--check]",
|
|
5019
|
+
description: "Resolve a record's anchors: stamp a hash onto anchors that lack one, report drift where the code moved. An anchor naming another repository is read from that remote through a bare cache; --offline uses the cache only. Never writes verified[]; a judgment is kb_verify. Exits non-zero on drift.",
|
|
4994
5020
|
input: z10.object({
|
|
4995
5021
|
bundlePath,
|
|
4996
5022
|
conceptId,
|
|
@@ -5003,6 +5029,9 @@ var anchorResolveCommand = define({
|
|
|
5003
5029
|
),
|
|
5004
5030
|
restamp: z10.boolean().optional().describe(
|
|
5005
5031
|
"Refresh `resolved_at` on anchors that already match. Off by default, so a green run writes nothing."
|
|
5032
|
+
),
|
|
5033
|
+
check: z10.boolean().optional().describe(
|
|
5034
|
+
"Resolve and report only: no hash, no `resolved_at`, no log entry."
|
|
5006
5035
|
)
|
|
5007
5036
|
}),
|
|
5008
5037
|
fromArgv: (argv, path) => ({
|
|
@@ -5011,9 +5040,24 @@ var anchorResolveCommand = define({
|
|
|
5011
5040
|
repoRoot: argvFlag(argv, "--repo-root"),
|
|
5012
5041
|
offline: argv.includes("--offline"),
|
|
5013
5042
|
rebaseline: argv.includes("--rebaseline"),
|
|
5014
|
-
restamp: argv.includes("--restamp")
|
|
5043
|
+
restamp: argv.includes("--restamp"),
|
|
5044
|
+
check: argv.includes("--check")
|
|
5015
5045
|
}),
|
|
5016
|
-
run: async ({ store, actor, now }, {
|
|
5046
|
+
run: async ({ store, actor, now }, {
|
|
5047
|
+
bundlePath: path,
|
|
5048
|
+
conceptId: id,
|
|
5049
|
+
repoRoot,
|
|
5050
|
+
offline,
|
|
5051
|
+
rebaseline,
|
|
5052
|
+
restamp,
|
|
5053
|
+
check
|
|
5054
|
+
}) => {
|
|
5055
|
+
if (check && (rebaseline || restamp)) {
|
|
5056
|
+
throw new KbFlagConflictError([
|
|
5057
|
+
"check",
|
|
5058
|
+
rebaseline ? "rebaseline" : "restamp"
|
|
5059
|
+
]);
|
|
5060
|
+
}
|
|
5017
5061
|
const root = repoRoot ?? process.cwd();
|
|
5018
5062
|
const record = await store.read(path, id);
|
|
5019
5063
|
if (!record) throw new KbRecordNotFoundError(id);
|
|
@@ -5022,7 +5066,6 @@ var anchorResolveCommand = define({
|
|
|
5022
5066
|
return {
|
|
5023
5067
|
conceptId: id,
|
|
5024
5068
|
results: [],
|
|
5025
|
-
verified: false,
|
|
5026
5069
|
note: "record has no anchors"
|
|
5027
5070
|
};
|
|
5028
5071
|
}
|
|
@@ -5080,7 +5123,7 @@ var anchorResolveCommand = define({
|
|
|
5080
5123
|
if (!anchor.hash) {
|
|
5081
5124
|
results.push({
|
|
5082
5125
|
...base2,
|
|
5083
|
-
state: "stamped",
|
|
5126
|
+
state: check ? "unstamped" : "stamped",
|
|
5084
5127
|
currentHash: stampedHash,
|
|
5085
5128
|
hashKind: stampedKind,
|
|
5086
5129
|
...producedBy ? { resolver: producedBy } : {}
|
|
@@ -5132,7 +5175,7 @@ var anchorResolveCommand = define({
|
|
|
5132
5175
|
if (refresh) dirty = true;
|
|
5133
5176
|
}
|
|
5134
5177
|
let frozen = false;
|
|
5135
|
-
if (dirty) {
|
|
5178
|
+
if (dirty && !check) {
|
|
5136
5179
|
try {
|
|
5137
5180
|
await assertBaseNotFrozen(process.cwd(), path);
|
|
5138
5181
|
} catch (error) {
|
|
@@ -5147,42 +5190,11 @@ var anchorResolveCommand = define({
|
|
|
5147
5190
|
const unreachable = results.filter(
|
|
5148
5191
|
(entry) => isUncheckedReason(entry.reason)
|
|
5149
5192
|
).length;
|
|
5150
|
-
const checked = results.length - unreachable;
|
|
5151
5193
|
const matches3 = results.filter((entry) => entry.state === "match").length;
|
|
5152
|
-
const note = `${matches3}/${
|
|
5153
|
-
const clean = checked > 0 && matches3 === checked && unreachable === 0;
|
|
5154
|
-
if (clean) {
|
|
5155
|
-
try {
|
|
5156
|
-
await store.verify(
|
|
5157
|
-
path,
|
|
5158
|
-
id,
|
|
5159
|
-
`anchor-resolve: ${note} (${resolverSummary(results)})`,
|
|
5160
|
-
actor,
|
|
5161
|
-
now()
|
|
5162
|
-
);
|
|
5163
|
-
} catch (error) {
|
|
5164
|
-
if (!(error instanceof KbSelfVerificationError)) throw error;
|
|
5165
|
-
return {
|
|
5166
|
-
conceptId: id,
|
|
5167
|
-
results,
|
|
5168
|
-
verified: false,
|
|
5169
|
-
verifyRefused: "self-verification",
|
|
5170
|
-
...frozenNote,
|
|
5171
|
-
...hintNote
|
|
5172
|
-
};
|
|
5173
|
-
}
|
|
5174
|
-
return {
|
|
5175
|
-
conceptId: id,
|
|
5176
|
-
results,
|
|
5177
|
-
verified: true,
|
|
5178
|
-
...frozenNote,
|
|
5179
|
-
...hintNote
|
|
5180
|
-
};
|
|
5181
|
-
}
|
|
5194
|
+
const note = `${matches3}/${results.length - unreachable} anchors match, ${unreachable} unreachable`;
|
|
5182
5195
|
return {
|
|
5183
5196
|
conceptId: id,
|
|
5184
5197
|
results,
|
|
5185
|
-
verified: false,
|
|
5186
5198
|
...unreachable ? { note } : {},
|
|
5187
5199
|
...frozenNote,
|
|
5188
5200
|
...hintNote
|
|
@@ -7581,6 +7593,7 @@ var KbStore = class {
|
|
|
7581
7593
|
* its contents.
|
|
7582
7594
|
*/
|
|
7583
7595
|
async write(bundlePath2, input, actor = "unknown") {
|
|
7596
|
+
assertActor(actor);
|
|
7584
7597
|
if (!KB_SLUG_PATTERN.test(input.slug)) {
|
|
7585
7598
|
throw new KbInvalidConceptIdError("slug must be kebab-case", {
|
|
7586
7599
|
slug: input.slug
|
|
@@ -7682,6 +7695,7 @@ var KbStore = class {
|
|
|
7682
7695
|
* timeouts.
|
|
7683
7696
|
*/
|
|
7684
7697
|
async setStatus(bundlePath2, conceptId2, status, actor = "unknown") {
|
|
7698
|
+
assertActor(actor);
|
|
7685
7699
|
return this.mutate(
|
|
7686
7700
|
bundlePath2,
|
|
7687
7701
|
conceptId2,
|
|
@@ -7700,6 +7714,7 @@ var KbStore = class {
|
|
|
7700
7714
|
* the frontmatter must not be published back out under an actor stamp.
|
|
7701
7715
|
*/
|
|
7702
7716
|
async updateAnchors(bundlePath2, conceptId2, anchors, actor = "unknown") {
|
|
7717
|
+
assertActor(actor);
|
|
7703
7718
|
const checked = anchors.map((anchor) => kbAnchorWriteSchema.parse(anchor));
|
|
7704
7719
|
return this.mutate(
|
|
7705
7720
|
bundlePath2,
|
|
@@ -7720,6 +7735,7 @@ var KbStore = class {
|
|
|
7720
7735
|
* logs what it publishes.
|
|
7721
7736
|
*/
|
|
7722
7737
|
async verify(bundlePath2, conceptId2, note, actor = "unknown", at2 = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
7738
|
+
assertActor(actor, { named: true });
|
|
7723
7739
|
const event = kbVerifiedEventSchema.parse({ by: actor, at: at2, note });
|
|
7724
7740
|
const existing = await this.read(bundlePath2, conceptId2);
|
|
7725
7741
|
if (!existing) throw new KbRecordNotFoundError(conceptId2);
|
|
@@ -7750,6 +7766,7 @@ var KbStore = class {
|
|
|
7750
7766
|
* in normal use, and validation drops to catching hand-edits.
|
|
7751
7767
|
*/
|
|
7752
7768
|
async supersede(bundlePath2, conceptId2, replacementId, actor = "unknown") {
|
|
7769
|
+
assertActor(actor);
|
|
7753
7770
|
const replacement = await this.read(bundlePath2, replacementId);
|
|
7754
7771
|
if (!replacement) throw new KbRecordNotFoundError(replacementId);
|
|
7755
7772
|
const superseded = await this.markSuperseded(
|
|
@@ -7773,6 +7790,7 @@ var KbStore = class {
|
|
|
7773
7790
|
}
|
|
7774
7791
|
/** Resolves an open question, stamping who answered and when. */
|
|
7775
7792
|
async answer(bundlePath2, conceptId2, answer, actor = "unknown", at2 = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
7793
|
+
assertActor(actor);
|
|
7776
7794
|
return this.mutate(
|
|
7777
7795
|
bundlePath2,
|
|
7778
7796
|
conceptId2,
|
|
@@ -7799,6 +7817,7 @@ ${answer}
|
|
|
7799
7817
|
* terminal status since the caller listed it is reported, not removed.
|
|
7800
7818
|
*/
|
|
7801
7819
|
async deleteRecord(bundlePath2, conceptId2, expected, actor = "unknown") {
|
|
7820
|
+
assertActor(actor);
|
|
7802
7821
|
const target = this.recordPath(bundlePath2, conceptId2);
|
|
7803
7822
|
const witness = await this.read(bundlePath2, conceptId2);
|
|
7804
7823
|
if (!witness) throw new KbRecordNotFoundError(conceptId2);
|
|
@@ -8102,6 +8121,7 @@ ${answer}
|
|
|
8102
8121
|
* base too, where nothing was written.
|
|
8103
8122
|
*/
|
|
8104
8123
|
async note(bundlePath2, entry) {
|
|
8124
|
+
assertActor(entry.by);
|
|
8105
8125
|
await this.record(this.root(bundlePath2), entry);
|
|
8106
8126
|
}
|
|
8107
8127
|
/**
|
|
@@ -8359,6 +8379,15 @@ function normalizeActor(id) {
|
|
|
8359
8379
|
if (colon === -1) return id.toLowerCase();
|
|
8360
8380
|
return id.slice(0, colon + 1).toLowerCase() + id.slice(colon + 1);
|
|
8361
8381
|
}
|
|
8382
|
+
var KB_ACTOR_PATTERN = /^[A-Za-z][\w-]*(?::[\p{L}\p{M}\p{N}_.@+/-]+)?$/u;
|
|
8383
|
+
function assertActor(actor, { named = false } = {}) {
|
|
8384
|
+
if (!KB_ACTOR_PATTERN.test(actor)) {
|
|
8385
|
+
throw new KbInvalidActorError(actor, "is not kind or kind:name");
|
|
8386
|
+
}
|
|
8387
|
+
if (named && normalizeActor(actor) === "unknown") {
|
|
8388
|
+
throw new KbInvalidActorError(actor, "cannot verify: name who checked");
|
|
8389
|
+
}
|
|
8390
|
+
}
|
|
8362
8391
|
|
|
8363
8392
|
// src/pack.ts
|
|
8364
8393
|
var DEFAULT_PACK_HOPS = 2;
|
|
@@ -8445,7 +8474,7 @@ function typeRank(record) {
|
|
|
8445
8474
|
}
|
|
8446
8475
|
|
|
8447
8476
|
// src/version.ts
|
|
8448
|
-
var VERSION = true ? "0.1.
|
|
8477
|
+
var VERSION = true ? "0.1.21" : "0.0.0-dev";
|
|
8449
8478
|
|
|
8450
8479
|
export {
|
|
8451
8480
|
kbSourceSchema,
|
|
@@ -8593,4 +8622,4 @@ export {
|
|
|
8593
8622
|
KbStore,
|
|
8594
8623
|
VERSION
|
|
8595
8624
|
};
|
|
8596
|
-
//# sourceMappingURL=chunk-
|
|
8625
|
+
//# sourceMappingURL=chunk-XBZ7G5R5.js.map
|