@saasontools/strauss-kb 0.1.3 → 0.1.4
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 +25 -1
- package/dist/{chunk-HYNAEAPM.js → chunk-EDH43Z7J.js} +67 -13
- package/dist/chunk-EDH43Z7J.js.map +1 -0
- package/dist/{chunk-FSI4Q2FD.js → chunk-TS26G7TL.js} +2 -2
- package/dist/{chunk-QLTB77W4.js → chunk-Y5C7Z2HG.js} +2 -2
- package/dist/cli-main.cjs +66 -12
- package/dist/cli-main.cjs.map +1 -1
- package/dist/cli-main.js +2 -2
- package/dist/index.cjs +66 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +3 -3
- package/dist/mcp-main.cjs +66 -12
- package/dist/mcp-main.cjs.map +1 -1
- package/dist/mcp-main.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-HYNAEAPM.js.map +0 -1
- /package/dist/{chunk-FSI4Q2FD.js.map → chunk-TS26G7TL.js.map} +0 -0
- /package/dist/{chunk-QLTB77W4.js.map → chunk-Y5C7Z2HG.js.map} +0 -0
package/dist/cli-main.cjs
CHANGED
|
@@ -213,7 +213,7 @@ var composeInputSchema = import_zod2.z.object({
|
|
|
213
213
|
/** Concept ids this record relates to; rendered as body links. */
|
|
214
214
|
relatedConceptIds: import_zod2.z.array(kbConceptIdSchema).optional(),
|
|
215
215
|
/** Concept ids this record replaces. The store settles the backlinks. */
|
|
216
|
-
supersedes: import_zod2.z.array(kbConceptIdSchema).optional(),
|
|
216
|
+
supersedes: import_zod2.z.array(kbConceptIdSchema).max(32).optional(),
|
|
217
217
|
materiality: import_zod2.z.enum(KB_MATERIALITIES).optional(),
|
|
218
218
|
confidence: import_zod2.z.enum(KB_CONFIDENCES).optional(),
|
|
219
219
|
owner: import_zod2.z.string().min(1).optional()
|
|
@@ -1601,7 +1601,11 @@ var writeCommand = define({
|
|
|
1601
1601
|
composeRecord(type, input, actor, now()),
|
|
1602
1602
|
actor
|
|
1603
1603
|
);
|
|
1604
|
-
return {
|
|
1604
|
+
return {
|
|
1605
|
+
conceptId: record.conceptId,
|
|
1606
|
+
action: record.action,
|
|
1607
|
+
supersededIds: record.supersededIds
|
|
1608
|
+
};
|
|
1605
1609
|
}
|
|
1606
1610
|
});
|
|
1607
1611
|
|
|
@@ -1631,7 +1635,11 @@ var writeDecisionCommand = define({
|
|
|
1631
1635
|
composeDecisionRecord(input, actor, now()),
|
|
1632
1636
|
actor
|
|
1633
1637
|
);
|
|
1634
|
-
return {
|
|
1638
|
+
return {
|
|
1639
|
+
conceptId: record.conceptId,
|
|
1640
|
+
action: record.action,
|
|
1641
|
+
supersededIds: record.supersededIds
|
|
1642
|
+
};
|
|
1635
1643
|
}
|
|
1636
1644
|
});
|
|
1637
1645
|
|
|
@@ -1722,7 +1730,7 @@ var KbRecordAlreadyExistsError = class extends BaseError {
|
|
|
1722
1730
|
fault: "User" /* User */,
|
|
1723
1731
|
retriable: false,
|
|
1724
1732
|
reportToUser: true,
|
|
1725
|
-
details: { conceptId: conceptId2 }
|
|
1733
|
+
details: { conceptId: conceptId2, action: "refused" }
|
|
1726
1734
|
});
|
|
1727
1735
|
this.conceptId = conceptId2;
|
|
1728
1736
|
}
|
|
@@ -1902,13 +1910,27 @@ var KbStore = class {
|
|
|
1902
1910
|
conceptId: conceptId2,
|
|
1903
1911
|
by: actor
|
|
1904
1912
|
});
|
|
1913
|
+
const targets = new Set(frontmatter.strauss_supersedes ?? []);
|
|
1914
|
+
targets.delete(conceptId2);
|
|
1915
|
+
const supersededIds = [];
|
|
1916
|
+
for (const old of targets) {
|
|
1917
|
+
if (await this.markSupersededRetrying(bundlePath2, old, conceptId2, actor)) {
|
|
1918
|
+
supersededIds.push(old);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1905
1921
|
this.logger.info?.({
|
|
1906
1922
|
operation: "kb.write",
|
|
1907
1923
|
bundlePath: root,
|
|
1908
1924
|
conceptId: conceptId2,
|
|
1909
1925
|
anchors: frontmatter.strauss_anchors?.length ?? 0
|
|
1910
1926
|
});
|
|
1911
|
-
return {
|
|
1927
|
+
return {
|
|
1928
|
+
conceptId: conceptId2,
|
|
1929
|
+
frontmatter,
|
|
1930
|
+
body: input.body,
|
|
1931
|
+
action: supersededIds.length ? "superseded-prior" : "created",
|
|
1932
|
+
supersededIds
|
|
1933
|
+
};
|
|
1912
1934
|
}
|
|
1913
1935
|
/** One record by concept id, or null when it does not exist. */
|
|
1914
1936
|
async read(bundlePath2, conceptId2) {
|
|
@@ -1972,15 +1994,11 @@ var KbStore = class {
|
|
|
1972
1994
|
async supersede(bundlePath2, conceptId2, replacementId, actor = "unknown") {
|
|
1973
1995
|
const replacement = await this.read(bundlePath2, replacementId);
|
|
1974
1996
|
if (!replacement) throw new KbRecordNotFoundError(replacementId);
|
|
1975
|
-
const superseded = await this.
|
|
1997
|
+
const superseded = await this.markSuperseded(
|
|
1976
1998
|
bundlePath2,
|
|
1977
1999
|
conceptId2,
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
strauss_status: "superseded",
|
|
1981
|
-
strauss_superseded_by: replacementId
|
|
1982
|
-
}),
|
|
1983
|
-
{ operation: "supersede", by: actor, target: replacementId }
|
|
2000
|
+
replacementId,
|
|
2001
|
+
actor
|
|
1984
2002
|
);
|
|
1985
2003
|
await this.mutate(
|
|
1986
2004
|
bundlePath2,
|
|
@@ -2144,6 +2162,42 @@ ${answer}
|
|
|
2144
2162
|
}
|
|
2145
2163
|
return result;
|
|
2146
2164
|
}
|
|
2165
|
+
/**
|
|
2166
|
+
* `markSuperseded`, tolerant of the two ways it legitimately doesn't land:
|
|
2167
|
+
* a missing target (a broken link, legal per compose.ts) or a CAS conflict
|
|
2168
|
+
* from a concurrent writer touching the same target. A conflict is retried
|
|
2169
|
+
* a bounded number of times — each attempt re-reads the target fresh — and
|
|
2170
|
+
* on the last, `false` reports "not marked" rather than throwing: the
|
|
2171
|
+
* caller's own record is already published, so failing here would leave
|
|
2172
|
+
* that publish unreported instead of undone. kb_validate's existing
|
|
2173
|
+
* "not marked superseded" check is what surfaces the residue.
|
|
2174
|
+
*/
|
|
2175
|
+
async markSupersededRetrying(bundlePath2, conceptId2, replacementId, actor, retries = 3) {
|
|
2176
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
2177
|
+
try {
|
|
2178
|
+
await this.markSuperseded(bundlePath2, conceptId2, replacementId, actor);
|
|
2179
|
+
return true;
|
|
2180
|
+
} catch (error) {
|
|
2181
|
+
if (error instanceof KbRecordNotFoundError) return false;
|
|
2182
|
+
if (!(error instanceof KbWriteConflictError)) throw error;
|
|
2183
|
+
if (attempt === retries) return false;
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
return false;
|
|
2187
|
+
}
|
|
2188
|
+
/** The one-directional half of `supersede`: marks `conceptId` superseded. */
|
|
2189
|
+
async markSuperseded(bundlePath2, conceptId2, replacementId, actor) {
|
|
2190
|
+
return this.mutate(
|
|
2191
|
+
bundlePath2,
|
|
2192
|
+
conceptId2,
|
|
2193
|
+
(frontmatter) => ({
|
|
2194
|
+
...frontmatter,
|
|
2195
|
+
strauss_status: "superseded",
|
|
2196
|
+
strauss_superseded_by: replacementId
|
|
2197
|
+
}),
|
|
2198
|
+
{ operation: "supersede", by: actor, target: replacementId }
|
|
2199
|
+
);
|
|
2200
|
+
}
|
|
2147
2201
|
async mutate(bundlePath2, conceptId2, change, entry, changeBody = (body) => body) {
|
|
2148
2202
|
const target = this.recordPath(bundlePath2, conceptId2);
|
|
2149
2203
|
const before = await (0, import_promises4.readFile)(target, "utf8").catch(() => null);
|