@vpxa/kb 0.1.1 → 0.1.3

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.
Files changed (138) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/packages/analyzers/dist/blast-radius-analyzer.js +13 -114
  4. package/packages/analyzers/dist/dependency-analyzer.js +11 -425
  5. package/packages/analyzers/dist/diagram-generator.js +4 -86
  6. package/packages/analyzers/dist/entry-point-analyzer.js +5 -239
  7. package/packages/analyzers/dist/index.js +1 -23
  8. package/packages/analyzers/dist/knowledge-producer.js +24 -113
  9. package/packages/analyzers/dist/pattern-analyzer.js +5 -359
  10. package/packages/analyzers/dist/regex-call-graph.js +1 -428
  11. package/packages/analyzers/dist/structure-analyzer.js +4 -258
  12. package/packages/analyzers/dist/symbol-analyzer.js +13 -442
  13. package/packages/analyzers/dist/ts-call-graph.js +1 -160
  14. package/packages/analyzers/dist/types.js +0 -1
  15. package/packages/chunker/dist/call-graph-extractor.js +1 -90
  16. package/packages/chunker/dist/chunker-factory.js +1 -36
  17. package/packages/chunker/dist/chunker.interface.js +0 -1
  18. package/packages/chunker/dist/code-chunker.js +14 -134
  19. package/packages/chunker/dist/generic-chunker.js +5 -72
  20. package/packages/chunker/dist/index.js +1 -21
  21. package/packages/chunker/dist/markdown-chunker.js +7 -119
  22. package/packages/chunker/dist/treesitter-chunker.js +8 -234
  23. package/packages/cli/dist/commands/analyze.js +3 -112
  24. package/packages/cli/dist/commands/context-cmds.js +1 -155
  25. package/packages/cli/dist/commands/environment.js +2 -204
  26. package/packages/cli/dist/commands/execution.js +1 -137
  27. package/packages/cli/dist/commands/graph.js +7 -81
  28. package/packages/cli/dist/commands/init.js +9 -87
  29. package/packages/cli/dist/commands/knowledge.js +1 -139
  30. package/packages/cli/dist/commands/search.js +8 -267
  31. package/packages/cli/dist/commands/system.js +4 -241
  32. package/packages/cli/dist/commands/workspace.js +2 -388
  33. package/packages/cli/dist/context.js +1 -14
  34. package/packages/cli/dist/helpers.js +3 -458
  35. package/packages/cli/dist/index.d.ts +1 -1
  36. package/packages/cli/dist/index.js +3 -69
  37. package/packages/cli/dist/kb-init.js +1 -82
  38. package/packages/cli/dist/types.js +0 -1
  39. package/packages/core/dist/constants.js +1 -43
  40. package/packages/core/dist/content-detector.js +1 -79
  41. package/packages/core/dist/errors.js +1 -40
  42. package/packages/core/dist/index.js +1 -9
  43. package/packages/core/dist/logger.js +1 -34
  44. package/packages/core/dist/types.js +0 -1
  45. package/packages/embeddings/dist/embedder.interface.js +0 -1
  46. package/packages/embeddings/dist/index.js +1 -5
  47. package/packages/embeddings/dist/onnx-embedder.js +1 -82
  48. package/packages/indexer/dist/file-hasher.js +1 -13
  49. package/packages/indexer/dist/filesystem-crawler.js +1 -125
  50. package/packages/indexer/dist/graph-extractor.js +1 -111
  51. package/packages/indexer/dist/incremental-indexer.js +1 -278
  52. package/packages/indexer/dist/index.js +1 -14
  53. package/packages/server/dist/api.js +1 -9
  54. package/packages/server/dist/config.js +1 -75
  55. package/packages/server/dist/curated-manager.js +9 -356
  56. package/packages/server/dist/index.js +1 -134
  57. package/packages/server/dist/replay-interceptor.js +1 -38
  58. package/packages/server/dist/resources/resources.js +2 -40
  59. package/packages/server/dist/server.js +1 -247
  60. package/packages/server/dist/tools/analyze.tools.js +1 -288
  61. package/packages/server/dist/tools/forge.tools.js +11 -499
  62. package/packages/server/dist/tools/forget.tool.js +3 -39
  63. package/packages/server/dist/tools/graph.tool.js +5 -110
  64. package/packages/server/dist/tools/list.tool.js +5 -53
  65. package/packages/server/dist/tools/lookup.tool.js +8 -51
  66. package/packages/server/dist/tools/onboard.tool.js +2 -112
  67. package/packages/server/dist/tools/produce.tool.js +4 -74
  68. package/packages/server/dist/tools/read.tool.js +4 -47
  69. package/packages/server/dist/tools/reindex.tool.js +2 -70
  70. package/packages/server/dist/tools/remember.tool.js +3 -42
  71. package/packages/server/dist/tools/replay.tool.js +6 -88
  72. package/packages/server/dist/tools/search.tool.js +17 -327
  73. package/packages/server/dist/tools/status.tool.js +3 -68
  74. package/packages/server/dist/tools/toolkit.tools.js +20 -1673
  75. package/packages/server/dist/tools/update.tool.js +3 -39
  76. package/packages/server/dist/tools/utility.tools.js +19 -456
  77. package/packages/store/dist/graph-store.interface.js +0 -1
  78. package/packages/store/dist/index.js +1 -9
  79. package/packages/store/dist/lance-store.js +1 -258
  80. package/packages/store/dist/sqlite-graph-store.js +8 -309
  81. package/packages/store/dist/store-factory.js +1 -14
  82. package/packages/store/dist/store.interface.js +0 -1
  83. package/packages/tools/dist/batch.js +1 -45
  84. package/packages/tools/dist/changelog.js +2 -112
  85. package/packages/tools/dist/check.js +2 -59
  86. package/packages/tools/dist/checkpoint.js +2 -43
  87. package/packages/tools/dist/codemod.js +2 -69
  88. package/packages/tools/dist/compact.js +3 -60
  89. package/packages/tools/dist/data-transform.js +1 -124
  90. package/packages/tools/dist/dead-symbols.js +2 -71
  91. package/packages/tools/dist/delegate.js +3 -128
  92. package/packages/tools/dist/diff-parse.js +3 -153
  93. package/packages/tools/dist/digest.js +7 -242
  94. package/packages/tools/dist/encode.js +1 -46
  95. package/packages/tools/dist/env-info.js +1 -58
  96. package/packages/tools/dist/eval.js +3 -79
  97. package/packages/tools/dist/evidence-map.js +3 -203
  98. package/packages/tools/dist/file-summary.js +2 -106
  99. package/packages/tools/dist/file-walk.js +1 -75
  100. package/packages/tools/dist/find-examples.js +3 -48
  101. package/packages/tools/dist/find.js +1 -120
  102. package/packages/tools/dist/forge-classify.js +2 -319
  103. package/packages/tools/dist/forge-ground.js +1 -184
  104. package/packages/tools/dist/git-context.js +3 -46
  105. package/packages/tools/dist/graph-query.js +1 -194
  106. package/packages/tools/dist/health.js +1 -118
  107. package/packages/tools/dist/http-request.js +1 -58
  108. package/packages/tools/dist/index.js +1 -273
  109. package/packages/tools/dist/lane.js +7 -227
  110. package/packages/tools/dist/measure.js +2 -119
  111. package/packages/tools/dist/onboard.js +42 -1136
  112. package/packages/tools/dist/parse-output.js +2 -158
  113. package/packages/tools/dist/process-manager.js +1 -69
  114. package/packages/tools/dist/queue.js +2 -126
  115. package/packages/tools/dist/regex-test.js +1 -39
  116. package/packages/tools/dist/rename.js +2 -70
  117. package/packages/tools/dist/replay.js +6 -108
  118. package/packages/tools/dist/schema-validate.js +1 -141
  119. package/packages/tools/dist/scope-map.js +1 -72
  120. package/packages/tools/dist/snippet.js +1 -80
  121. package/packages/tools/dist/stash.js +2 -60
  122. package/packages/tools/dist/stratum-card.js +5 -238
  123. package/packages/tools/dist/symbol.js +3 -87
  124. package/packages/tools/dist/test-run.js +2 -55
  125. package/packages/tools/dist/text-utils.js +2 -31
  126. package/packages/tools/dist/time-utils.js +1 -135
  127. package/packages/tools/dist/trace.js +2 -114
  128. package/packages/tools/dist/truncation.js +10 -41
  129. package/packages/tools/dist/watch.js +1 -61
  130. package/packages/tools/dist/web-fetch.js +9 -244
  131. package/packages/tools/dist/web-search.js +1 -46
  132. package/packages/tools/dist/workset.js +2 -77
  133. package/packages/tui/dist/App.js +260 -52468
  134. package/packages/tui/dist/index.js +286 -54551
  135. package/packages/tui/dist/panels/CuratedPanel.js +211 -34291
  136. package/packages/tui/dist/panels/LogPanel.js +259 -51703
  137. package/packages/tui/dist/panels/SearchPanel.js +212 -34824
  138. package/packages/tui/dist/panels/StatusPanel.js +211 -34304
@@ -1,141 +1 @@
1
- function schemaValidate(options) {
2
- const errors = [];
3
- validateNode(options.data, options.schema, "$", errors);
4
- return { valid: errors.length === 0, errors };
5
- }
6
- function validateNode(data, schema, path, errors) {
7
- if ("type" in schema) {
8
- const expected = schema.type;
9
- if (!checkType(data, expected)) {
10
- errors.push({
11
- path,
12
- message: `Expected type "${expected}"`,
13
- expected,
14
- received: getType(data)
15
- });
16
- return;
17
- }
18
- }
19
- if ("enum" in schema) {
20
- const allowed = schema.enum;
21
- if (!allowed.some((v) => JSON.stringify(v) === JSON.stringify(data))) {
22
- errors.push({
23
- path,
24
- message: `Must be one of: ${JSON.stringify(allowed)}`,
25
- received: JSON.stringify(data)
26
- });
27
- }
28
- }
29
- if ("const" in schema) {
30
- if (JSON.stringify(data) !== JSON.stringify(schema.const)) {
31
- errors.push({
32
- path,
33
- message: `Must equal ${JSON.stringify(schema.const)}`,
34
- received: JSON.stringify(data)
35
- });
36
- }
37
- }
38
- if (typeof data === "string") {
39
- if ("minLength" in schema && data.length < schema.minLength) {
40
- errors.push({
41
- path,
42
- message: `String too short (min: ${schema.minLength})`,
43
- received: `length ${data.length}`
44
- });
45
- }
46
- if ("maxLength" in schema && data.length > schema.maxLength) {
47
- errors.push({
48
- path,
49
- message: `String too long (max: ${schema.maxLength})`,
50
- received: `length ${data.length}`
51
- });
52
- }
53
- if ("pattern" in schema && !new RegExp(schema.pattern).test(data)) {
54
- errors.push({ path, message: `Does not match pattern: ${schema.pattern}` });
55
- }
56
- }
57
- if (typeof data === "number") {
58
- if ("minimum" in schema && data < schema.minimum) {
59
- errors.push({ path, message: `Below minimum (${schema.minimum})`, received: String(data) });
60
- }
61
- if ("maximum" in schema && data > schema.maximum) {
62
- errors.push({ path, message: `Above maximum (${schema.maximum})`, received: String(data) });
63
- }
64
- }
65
- if (Array.isArray(data)) {
66
- if ("minItems" in schema && data.length < schema.minItems) {
67
- errors.push({
68
- path,
69
- message: `Too few items (min: ${schema.minItems})`,
70
- received: `length ${data.length}`
71
- });
72
- }
73
- if ("maxItems" in schema && data.length > schema.maxItems) {
74
- errors.push({
75
- path,
76
- message: `Too many items (max: ${schema.maxItems})`,
77
- received: `length ${data.length}`
78
- });
79
- }
80
- if ("items" in schema) {
81
- for (let i = 0; i < data.length; i++) {
82
- validateNode(data[i], schema.items, `${path}[${i}]`, errors);
83
- }
84
- }
85
- }
86
- if (data && typeof data === "object" && !Array.isArray(data)) {
87
- const obj = data;
88
- if ("required" in schema) {
89
- for (const key of schema.required) {
90
- if (!(key in obj)) {
91
- errors.push({ path: `${path}.${key}`, message: "Required property missing" });
92
- }
93
- }
94
- }
95
- if ("properties" in schema) {
96
- const props = schema.properties;
97
- for (const [key, propSchema] of Object.entries(props)) {
98
- if (key in obj) {
99
- validateNode(obj[key], propSchema, `${path}.${key}`, errors);
100
- }
101
- }
102
- }
103
- if ("additionalProperties" in schema && schema.additionalProperties === false) {
104
- const defined = Object.keys(schema.properties ?? {});
105
- for (const key of Object.keys(obj)) {
106
- if (!defined.includes(key)) {
107
- errors.push({ path: `${path}.${key}`, message: "Additional property not allowed" });
108
- }
109
- }
110
- }
111
- }
112
- }
113
- function checkType(data, type) {
114
- switch (type) {
115
- case "string":
116
- return typeof data === "string";
117
- case "number":
118
- return typeof data === "number" && !Number.isNaN(data);
119
- case "integer":
120
- return typeof data === "number" && Number.isInteger(data);
121
- case "boolean":
122
- return typeof data === "boolean";
123
- case "null":
124
- return data === null;
125
- case "array":
126
- return Array.isArray(data);
127
- case "object":
128
- return data !== null && typeof data === "object" && !Array.isArray(data);
129
- default:
130
- return true;
131
- }
132
- }
133
- function getType(data) {
134
- if (data === null) return "null";
135
- if (Array.isArray(data)) return "array";
136
- return typeof data;
137
- }
138
- export {
139
- schemaValidate
140
- };
141
- //# sourceMappingURL=schema-validate.js.map
1
+ function m(e){const n=[];return u(e.data,e.schema,"$",n),{valid:n.length===0,errors:n}}function u(e,n,r,t){if("type"in n){const i=n.type;if(!f(e,i)){t.push({path:r,message:`Expected type "${i}"`,expected:i,received:l(e)});return}}if("enum"in n){const i=n.enum;i.some(o=>JSON.stringify(o)===JSON.stringify(e))||t.push({path:r,message:`Must be one of: ${JSON.stringify(i)}`,received:JSON.stringify(e)})}if("const"in n&&JSON.stringify(e)!==JSON.stringify(n.const)&&t.push({path:r,message:`Must equal ${JSON.stringify(n.const)}`,received:JSON.stringify(e)}),typeof e=="string"&&("minLength"in n&&e.length<n.minLength&&t.push({path:r,message:`String too short (min: ${n.minLength})`,received:`length ${e.length}`}),"maxLength"in n&&e.length>n.maxLength&&t.push({path:r,message:`String too long (max: ${n.maxLength})`,received:`length ${e.length}`}),"pattern"in n&&!new RegExp(n.pattern).test(e)&&t.push({path:r,message:`Does not match pattern: ${n.pattern}`})),typeof e=="number"&&("minimum"in n&&e<n.minimum&&t.push({path:r,message:`Below minimum (${n.minimum})`,received:String(e)}),"maximum"in n&&e>n.maximum&&t.push({path:r,message:`Above maximum (${n.maximum})`,received:String(e)})),Array.isArray(e)&&("minItems"in n&&e.length<n.minItems&&t.push({path:r,message:`Too few items (min: ${n.minItems})`,received:`length ${e.length}`}),"maxItems"in n&&e.length>n.maxItems&&t.push({path:r,message:`Too many items (max: ${n.maxItems})`,received:`length ${e.length}`}),"items"in n))for(let i=0;i<e.length;i++)u(e[i],n.items,`${r}[${i}]`,t);if(e&&typeof e=="object"&&!Array.isArray(e)){const i=e;if("required"in n)for(const o of n.required)o in i||t.push({path:`${r}.${o}`,message:"Required property missing"});if("properties"in n){const o=n.properties;for(const[s,g]of Object.entries(o))s in i&&u(i[s],g,`${r}.${s}`,t)}if("additionalProperties"in n&&n.additionalProperties===!1){const o=Object.keys(n.properties??{});for(const s of Object.keys(i))o.includes(s)||t.push({path:`${r}.${s}`,message:"Additional property not allowed"})}}}function f(e,n){switch(n){case"string":return typeof e=="string";case"number":return typeof e=="number"&&!Number.isNaN(e);case"integer":return typeof e=="number"&&Number.isInteger(e);case"boolean":return typeof e=="boolean";case"null":return e===null;case"array":return Array.isArray(e);case"object":return e!==null&&typeof e=="object"&&!Array.isArray(e);default:return!0}}function l(e){return e===null?"null":Array.isArray(e)?"array":typeof e}export{m as schemaValidate};
@@ -1,72 +1 @@
1
- function estimateTokens(text) {
2
- return Math.ceil(text.length / 4);
3
- }
4
- async function scopeMap(embedder, store, options) {
5
- const { task, maxFiles = 15, contentType, origin } = options;
6
- const queryVector = await embedder.embed(task);
7
- const searchOpts = {
8
- limit: maxFiles * 3,
9
- // Over-fetch to group by file
10
- contentType,
11
- origin
12
- };
13
- const results = await store.search(queryVector, searchOpts);
14
- const fileMap = /* @__PURE__ */ new Map();
15
- for (const result of results) {
16
- const path = result.record.sourcePath;
17
- const existing = fileMap.get(path);
18
- if (existing) {
19
- existing.chunks.push(result);
20
- existing.totalChars += result.record.content.length;
21
- existing.maxScore = Math.max(existing.maxScore, result.score);
22
- } else {
23
- fileMap.set(path, {
24
- chunks: [result],
25
- totalChars: result.record.content.length,
26
- maxScore: result.score
27
- });
28
- }
29
- }
30
- const entries = [...fileMap.entries()].sort(([, a], [, b]) => b.maxScore - a.maxScore).slice(0, maxFiles).map(([path, { chunks, maxScore }]) => {
31
- const focusRanges = chunks.sort((a, b) => a.record.startLine - b.record.startLine).map((c) => ({
32
- start: c.record.startLine,
33
- end: c.record.endLine,
34
- heading: c.record.headingPath
35
- }));
36
- const topChunk = chunks.sort((a, b) => b.score - a.score)[0];
37
- const reason = topChunk.record.headingPath ? `Matches: ${topChunk.record.headingPath}` : `Contains relevant ${topChunk.record.contentType} content`;
38
- return {
39
- path,
40
- reason,
41
- estimatedTokens: 0,
42
- // computed below from actual content
43
- relevance: maxScore,
44
- focusRanges
45
- };
46
- });
47
- for (const entry of entries) {
48
- const fileChunks = fileMap.get(entry.path);
49
- if (fileChunks) {
50
- entry.estimatedTokens = estimateTokens(
51
- fileChunks.chunks.map((c) => c.record.content).join("")
52
- );
53
- }
54
- }
55
- const totalEstimatedTokens = entries.reduce((sum, e) => sum + e.estimatedTokens, 0);
56
- const readingOrder = [...entries].sort((a, b) => {
57
- const aIsConfig = a.path.includes("config") || a.path.includes("types") ? -1 : 0;
58
- const bIsConfig = b.path.includes("config") || b.path.includes("types") ? -1 : 0;
59
- if (aIsConfig !== bIsConfig) return aIsConfig - bIsConfig;
60
- return b.relevance - a.relevance;
61
- }).map((e) => e.path);
62
- return {
63
- task,
64
- files: entries,
65
- totalEstimatedTokens,
66
- readingOrder
67
- };
68
- }
69
- export {
70
- scopeMap
71
- };
72
- //# sourceMappingURL=scope-map.js.map
1
+ function M(c){return Math.ceil(c.length/4)}async function T(c,h,u){const{task:d,maxFiles:m=15,contentType:l,origin:g}=u,f=await c.embed(d),S={limit:m*3,contentType:l,origin:g},x=await h.search(f,S),s=new Map;for(const e of x){const t=e.record.sourcePath,r=s.get(t);r?(r.chunks.push(e),r.totalChars+=e.record.content.length,r.maxScore=Math.max(r.maxScore,e.score)):s.set(t,{chunks:[e],totalChars:e.record.content.length,maxScore:e.score})}const o=[...s.entries()].sort(([,e],[,t])=>t.maxScore-e.maxScore).slice(0,m).map(([e,{chunks:t,maxScore:r}])=>{const a=t.sort((n,p)=>n.record.startLine-p.record.startLine).map(n=>({start:n.record.startLine,end:n.record.endLine,heading:n.record.headingPath})),i=t.sort((n,p)=>p.score-n.score)[0],b=i.record.headingPath?`Matches: ${i.record.headingPath}`:`Contains relevant ${i.record.contentType} content`;return{path:e,reason:b,estimatedTokens:0,relevance:r,focusRanges:a}});for(const e of o){const t=s.get(e.path);t&&(e.estimatedTokens=M(t.chunks.map(r=>r.record.content).join("")))}const y=o.reduce((e,t)=>e+t.estimatedTokens,0),k=[...o].sort((e,t)=>{const r=e.path.includes("config")||e.path.includes("types")?-1:0,a=t.path.includes("config")||t.path.includes("types")?-1:0;return r!==a?r-a:t.relevance-e.relevance}).map(e=>e.path);return{task:d,files:o,totalEstimatedTokens:y,readingOrder:k}}export{T as scopeMap};
@@ -1,80 +1 @@
1
- import {
2
- existsSync,
3
- mkdirSync,
4
- readdirSync,
5
- readFileSync,
6
- unlinkSync,
7
- writeFileSync
8
- } from "node:fs";
9
- import { join } from "node:path";
10
- const SNIPPETS_DIR = () => join(process.cwd(), ".kb-state", "snippets");
11
- function ensureDir() {
12
- const dir = SNIPPETS_DIR();
13
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
14
- return dir;
15
- }
16
- function safeName(name) {
17
- const safe = name.replace(/[^a-zA-Z0-9_-]/g, "_");
18
- if (!safe) throw new Error("Invalid snippet name");
19
- return safe;
20
- }
21
- function snippet(options) {
22
- switch (options.action) {
23
- case "save": {
24
- if (!options.name || !options.code) throw new Error("name and code required for save");
25
- const dir = ensureDir();
26
- const name = safeName(options.name);
27
- const filePath = join(dir, `${name}.json`);
28
- const existing = existsSync(filePath) ? JSON.parse(readFileSync(filePath, "utf8")) : null;
29
- const now = (/* @__PURE__ */ new Date()).toISOString();
30
- const entry = {
31
- name: options.name,
32
- language: options.language ?? "text",
33
- code: options.code,
34
- tags: options.tags ?? [],
35
- created: existing?.created ?? now,
36
- updated: now
37
- };
38
- writeFileSync(filePath, JSON.stringify(entry, null, 2));
39
- return entry;
40
- }
41
- case "get": {
42
- if (!options.name) throw new Error("name required for get");
43
- const filePath = join(SNIPPETS_DIR(), `${safeName(options.name)}.json`);
44
- if (!existsSync(filePath)) throw new Error(`Snippet not found: ${options.name}`);
45
- return JSON.parse(readFileSync(filePath, "utf8"));
46
- }
47
- case "list": {
48
- const dir = ensureDir();
49
- const files = readdirSync(dir).filter((f) => f.endsWith(".json"));
50
- const snippets = files.map((f) => {
51
- const data = JSON.parse(readFileSync(join(dir, f), "utf8"));
52
- return { name: data.name, language: data.language, tags: data.tags, updated: data.updated };
53
- });
54
- return { snippets };
55
- }
56
- case "search": {
57
- if (!options.query) throw new Error("query required for search");
58
- const q = options.query.toLowerCase();
59
- const dir = ensureDir();
60
- const files = readdirSync(dir).filter((f) => f.endsWith(".json"));
61
- const snippets = files.map((f) => JSON.parse(readFileSync(join(dir, f), "utf8"))).filter(
62
- (s) => s.name.toLowerCase().includes(q) || s.tags.some((t) => t.toLowerCase().includes(q)) || s.language.toLowerCase().includes(q) || s.code.toLowerCase().includes(q)
63
- ).map((s) => ({ name: s.name, language: s.language, tags: s.tags, updated: s.updated }));
64
- return { snippets };
65
- }
66
- case "delete": {
67
- if (!options.name) throw new Error("name required for delete");
68
- const filePath = join(SNIPPETS_DIR(), `${safeName(options.name)}.json`);
69
- if (!existsSync(filePath)) return { deleted: false };
70
- unlinkSync(filePath);
71
- return { deleted: true };
72
- }
73
- default:
74
- throw new Error(`Unknown action: ${options.action}`);
75
- }
76
- }
77
- export {
78
- snippet
79
- };
80
- //# sourceMappingURL=snippet.js.map
1
+ import{existsSync as p,mkdirSync as f,readdirSync as l,readFileSync as u,unlinkSync as m,writeFileSync as S}from"node:fs";import{join as a}from"node:path";const o=()=>a(process.cwd(),".kb-state","snippets");function d(){const e=o();return p(e)||f(e,{recursive:!0}),e}function g(e){const n=e.replace(/[^a-zA-Z0-9_-]/g,"_");if(!n)throw new Error("Invalid snippet name");return n}function h(e){switch(e.action){case"save":{if(!e.name||!e.code)throw new Error("name and code required for save");const n=d(),s=g(e.name),i=a(n,`${s}.json`),r=p(i)?JSON.parse(u(i,"utf8")):null,t=new Date().toISOString(),c={name:e.name,language:e.language??"text",code:e.code,tags:e.tags??[],created:r?.created??t,updated:t};return S(i,JSON.stringify(c,null,2)),c}case"get":{if(!e.name)throw new Error("name required for get");const n=a(o(),`${g(e.name)}.json`);if(!p(n))throw new Error(`Snippet not found: ${e.name}`);return JSON.parse(u(n,"utf8"))}case"list":{const n=d();return{snippets:l(n).filter(r=>r.endsWith(".json")).map(r=>{const t=JSON.parse(u(a(n,r),"utf8"));return{name:t.name,language:t.language,tags:t.tags,updated:t.updated}})}}case"search":{if(!e.query)throw new Error("query required for search");const n=e.query.toLowerCase(),s=d();return{snippets:l(s).filter(t=>t.endsWith(".json")).map(t=>JSON.parse(u(a(s,t),"utf8"))).filter(t=>t.name.toLowerCase().includes(n)||t.tags.some(c=>c.toLowerCase().includes(n))||t.language.toLowerCase().includes(n)||t.code.toLowerCase().includes(n)).map(t=>({name:t.name,language:t.language,tags:t.tags,updated:t.updated}))}}case"delete":{if(!e.name)throw new Error("name required for delete");const n=a(o(),`${g(e.name)}.json`);return p(n)?(m(n),{deleted:!0}):{deleted:!1}}default:throw new Error(`Unknown action: ${e.action}`)}}export{h as snippet};
@@ -1,60 +1,2 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname, resolve } from "node:path";
3
- const STASH_DIR = ".kb-state";
4
- const STASH_FILE = "stash.json";
5
- function stashPath(cwd) {
6
- const root = cwd ?? process.cwd();
7
- return resolve(root, STASH_DIR, STASH_FILE);
8
- }
9
- function loadStash(cwd) {
10
- const path = stashPath(cwd);
11
- if (!existsSync(path)) return {};
12
- const raw = readFileSync(path, "utf-8");
13
- return JSON.parse(raw);
14
- }
15
- function saveStash(data, cwd) {
16
- const path = stashPath(cwd);
17
- const dir = dirname(path);
18
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
19
- writeFileSync(path, `${JSON.stringify(data, null, 2)}
20
- `, "utf-8");
21
- }
22
- function stashSet(key, value, cwd) {
23
- const stash = loadStash(cwd);
24
- const entry = {
25
- key,
26
- value,
27
- type: typeof value,
28
- storedAt: (/* @__PURE__ */ new Date()).toISOString()
29
- };
30
- stash[key] = entry;
31
- saveStash(stash, cwd);
32
- return entry;
33
- }
34
- function stashGet(key, cwd) {
35
- return loadStash(cwd)[key];
36
- }
37
- function stashList(cwd) {
38
- return Object.values(loadStash(cwd));
39
- }
40
- function stashDelete(key, cwd) {
41
- const stash = loadStash(cwd);
42
- if (!(key in stash)) return false;
43
- delete stash[key];
44
- saveStash(stash, cwd);
45
- return true;
46
- }
47
- function stashClear(cwd) {
48
- const stash = loadStash(cwd);
49
- const count = Object.keys(stash).length;
50
- saveStash({}, cwd);
51
- return count;
52
- }
53
- export {
54
- stashClear,
55
- stashDelete,
56
- stashGet,
57
- stashList,
58
- stashSet
59
- };
60
- //# sourceMappingURL=stash.js.map
1
+ import{existsSync as a,mkdirSync as u,readFileSync as h,writeFileSync as S}from"node:fs";import{dirname as g,resolve as f}from"node:path";const y=".kb-state",p="stash.json";function c(t){const n=t??process.cwd();return f(n,y,p)}function e(t){const n=c(t);if(!a(n))return{};const r=h(n,"utf-8");return JSON.parse(r)}function o(t,n){const r=c(n),s=g(r);a(s)||u(s,{recursive:!0}),S(r,`${JSON.stringify(t,null,2)}
2
+ `,"utf-8")}function E(t,n,r){const s=e(r),i={key:t,value:n,type:typeof n,storedAt:new Date().toISOString()};return s[t]=i,o(s,r),i}function m(t,n){return e(n)[t]}function x(t){return Object.values(e(t))}function b(t,n){const r=e(n);return t in r?(delete r[t],o(r,n),!0):!1}function v(t){const n=e(t),r=Object.keys(n).length;return o({},t),r}export{v as stashClear,b as stashDelete,m as stashGet,x as stashList,E as stashSet};
@@ -1,239 +1,6 @@
1
- import { readFile } from "node:fs/promises";
2
- import { basename, extname, relative } from "node:path";
3
- import { fileSummary } from "./file-summary.js";
4
- import { cosineSimilarity, estimateTokens, segment } from "./text-utils.js";
5
- const DEFAULT_MAX_CONTENT_CHARS = 800;
6
- const UNKNOWN_LIMIT = 3;
7
- async function stratumCard(embedder, options) {
8
- const { files, query, tier = "T1", maxContentChars = DEFAULT_MAX_CONTENT_CHARS } = options;
9
- const queryVector = tier === "T2" ? await embedder.embedQuery(query) : null;
10
- const cards = await Promise.all(
11
- files.map(async (filePath) => {
12
- try {
13
- const content = await readFile(filePath, "utf-8");
14
- const originalTokenEstimate = estimateTokens(content);
15
- if (content.includes("\0")) {
16
- return buildErrorCard(filePath, tier, "binary", "binary file", originalTokenEstimate);
17
- }
18
- if (content.trim().length === 0) {
19
- const card2 = formatCard({
20
- displayPath: formatDisplayPath(filePath),
21
- tier,
22
- role: "empty",
23
- deps: [],
24
- exports: [],
25
- unknowns: [],
26
- riskTier: "low"
27
- });
28
- return {
29
- path: filePath,
30
- tier,
31
- card: card2,
32
- unknowns: [],
33
- riskTier: "low",
34
- tokenEstimate: estimateTokens(card2),
35
- originalTokenEstimate
36
- };
37
- }
38
- const summary = await fileSummary({ path: filePath });
39
- const role = inferRole(filePath, summary);
40
- const unknowns = detectUnknowns(content, summary);
41
- const riskTier = classifyRisk(filePath, summary);
42
- const deps = getTopDeps(summary);
43
- const exports = [...new Set(summary.exports)].slice(0, 5);
44
- let card = formatCard({
45
- displayPath: formatDisplayPath(filePath),
46
- tier,
47
- role,
48
- deps,
49
- exports,
50
- unknowns,
51
- riskTier
52
- });
53
- if (tier === "T2" && queryVector) {
54
- const context = await compressContent(embedder, queryVector, content, maxContentChars);
55
- if (context.length > 0) {
56
- card = `${card}
1
+ import{readFile as F}from"node:fs/promises";import{basename as h,extname as I,relative as A}from"node:path";import{fileSummary as j}from"./file-summary.js";import{cosineSimilarity as X,estimateTokens as y,segment as D}from"./text-utils.js";const M=800,S=3;async function B(t,e){const{files:r,query:o,tier:n="T1",maxContentChars:m=M}=e,u=n==="T2"?await t.embedQuery(o):null,l=await Promise.all(r.map(async i=>{try{const c=await F(i,"utf-8"),p=y(c);if(c.includes("\0"))return C(i,n,"binary","binary file",p);if(c.trim().length===0){const g=x({displayPath:T(i),tier:n,role:"empty",deps:[],exports:[],unknowns:[],riskTier:"low"});return{path:i,tier:n,card:g,unknowns:[],riskTier:"low",tokenEstimate:y(g),originalTokenEstimate:p}}const d=await j({path:i}),N=U(i,d),E=W(c,d),w=_(i,d),O=$(d),R=[...new Set(d.exports)].slice(0,5);let f=x({displayPath:T(i),tier:n,role:N,deps:O,exports:R,unknowns:E,riskTier:w});if(n==="T2"&&u){const g=await v(t,u,c,m);g.length>0&&(f=`${f}
57
2
  CONTEXT:
58
- ${context}`;
59
- }
60
- }
61
- return {
62
- path: filePath,
63
- tier,
64
- card,
65
- unknowns,
66
- riskTier,
67
- tokenEstimate: estimateTokens(card),
68
- originalTokenEstimate
69
- };
70
- } catch (error) {
71
- const message = error.code === "ENOENT" ? "file missing" : "unreadable file";
72
- const role = error.code === "ENOENT" ? "missing" : "unreadable";
73
- return buildErrorCard(filePath, tier, role, message, 0);
74
- }
75
- })
76
- );
77
- const totalTokenEstimate = cards.reduce((total, card) => total + card.tokenEstimate, 0);
78
- const totalOriginalTokenEstimate = cards.reduce(
79
- (total, card) => total + card.originalTokenEstimate,
80
- 0
81
- );
82
- return {
83
- cards,
84
- totalTokenEstimate,
85
- totalOriginalTokenEstimate,
86
- compressionRatio: totalOriginalTokenEstimate === 0 ? 0 : totalTokenEstimate / totalOriginalTokenEstimate
87
- };
88
- }
89
- function buildErrorCard(filePath, tier, role, unknown, originalTokenEstimate) {
90
- const card = formatCard({
91
- displayPath: formatDisplayPath(filePath),
92
- tier,
93
- role,
94
- deps: [],
95
- exports: [],
96
- unknowns: [unknown],
97
- riskTier: "low"
98
- });
99
- return {
100
- path: filePath,
101
- tier,
102
- card,
103
- unknowns: [unknown],
104
- riskTier: "low",
105
- tokenEstimate: estimateTokens(card),
106
- originalTokenEstimate
107
- };
108
- }
109
- function formatCard(input) {
110
- const { displayPath, tier, role, deps, exports, unknowns, riskTier } = input;
111
- return [
112
- `[${tier}: ${displayPath}]`,
113
- `ROLE: ${role}`,
114
- `DEPS: ${joinOrNone(deps)}`,
115
- `EXPORTS: ${joinOrNone(exports)}`,
116
- `UNKNOWNS: ${joinOrNone(unknowns, "; ")}`,
117
- `RISK: ${riskTier}`
118
- ].join("\n");
119
- }
120
- function formatDisplayPath(filePath) {
121
- const relPath = relative(process.cwd(), filePath).replace(/\\/g, "/");
122
- if (!relPath || relPath.startsWith("..")) {
123
- return basename(filePath);
124
- }
125
- return relPath;
126
- }
127
- function joinOrNone(values, separator = ", ") {
128
- return values.length > 0 ? values.join(separator) : "none";
129
- }
130
- function inferRole(path, summary) {
131
- const name = basename(path);
132
- const extension = extname(name).toLowerCase();
133
- if ([".json", ".yaml", ".yml", ".env"].includes(extension) || /config|settings/i.test(name)) {
134
- return "configuration";
135
- }
136
- if (/types?\.ts$|\.d\.ts$/i.test(name)) return "type-definitions";
137
- if (/schema/i.test(name)) return "schema";
138
- if (/test|spec/i.test(name)) return "test";
139
- if (/index\.[jt]sx?$/i.test(name)) return "barrel-export";
140
- if (/handler|controller|route/i.test(name)) return "entry-point";
141
- if (/model|entity/i.test(name)) return "data-model";
142
- if (/util|helper/i.test(name)) return "utility";
143
- if (/service|provider/i.test(name)) return "service";
144
- if (summary.classes.length > 0) return "class-module";
145
- if (summary.interfaces.length > 2) return "type-definitions";
146
- return "implementation";
147
- }
148
- function detectUnknowns(content, summary) {
149
- const unknowns = [];
150
- const seen = /* @__PURE__ */ new Set();
151
- for (const match of content.matchAll(/\/\/\s*(TODO|FIXME|HACK|XXX)\s*:?\s*(.+)?$/gm)) {
152
- const text = `${match[1]}: ${(match[2] ?? "").trim()}`.trim();
153
- addUnknown(unknowns, seen, text.replace(/:\s*$/, ""));
154
- }
155
- if (hasExportedAny(content)) {
156
- addUnknown(unknowns, seen, "exported any usage");
157
- }
158
- for (const dep of getTopDeps(summary)) {
159
- addUnknown(unknowns, seen, `cross-package import: ${dep}`);
160
- }
161
- return unknowns.slice(0, UNKNOWN_LIMIT);
162
- }
163
- function addUnknown(unknowns, seen, value) {
164
- if (unknowns.length >= UNKNOWN_LIMIT) return;
165
- if (!value || seen.has(value)) return;
166
- seen.add(value);
167
- unknowns.push(value);
168
- }
169
- function hasExportedAny(content) {
170
- const patterns = [
171
- /export\s+(?:async\s+)?function\s+\w+[^\n{;]*\bany\b/g,
172
- /export\s+interface\s+\w+[\s\S]*?\{[\s\S]*?\bany\b[\s\S]*?\}/g,
173
- /export\s+type\s+\w+\s*=.*\bany\b/g,
174
- /export\s+const\s+\w+[^\n=]*\bany\b/g
175
- ];
176
- return patterns.some((pattern) => pattern.test(content));
177
- }
178
- function classifyRisk(path, summary) {
179
- if (/auth|token|permission|secret|credential|encrypt/i.test(path)) return "high";
180
- if (/types?\.ts$|schema|contract|\.d\.ts$/i.test(basename(path))) return "medium";
181
- if (summary.exports.length > 10) return "medium";
182
- return "low";
183
- }
184
- function getTopDeps(summary) {
185
- return summary.imports.map(extractImportSpecifier).filter((specifier) => Boolean(specifier)).filter((specifier) => !specifier.startsWith("./") && !specifier.startsWith("../")).slice(0, 3);
186
- }
187
- function extractImportSpecifier(importLine) {
188
- const fromMatch = importLine.match(/from\s+['"]([^'"]+)['"]/);
189
- if (fromMatch) {
190
- return fromMatch[1];
191
- }
192
- const sideEffectMatch = importLine.match(/^import\s+['"]([^'"]+)['"]/);
193
- return sideEffectMatch ? sideEffectMatch[1] : null;
194
- }
195
- async function compressContent(embedder, queryVector, content, maxContentChars) {
196
- if (maxContentChars <= 0) {
197
- return "";
198
- }
199
- const segments = segment(content, "paragraph");
200
- if (segments.length === 0) {
201
- return "";
202
- }
203
- const scoredSegments = await Promise.all(
204
- segments.map(async (text, index) => {
205
- const embedding = await embedder.embed(text);
206
- return {
207
- index,
208
- text,
209
- score: cosineSimilarity(queryVector, embedding)
210
- };
211
- })
212
- );
213
- const selected = [];
214
- let usedChars = 0;
215
- for (const segmentInfo of scoredSegments.sort((left, right) => right.score - left.score)) {
216
- const availableChars = maxContentChars - usedChars;
217
- if (availableChars <= 0) {
218
- break;
219
- }
220
- if (segmentInfo.text.length <= availableChars) {
221
- selected.push({ index: segmentInfo.index, text: segmentInfo.text });
222
- usedChars += segmentInfo.text.length;
223
- continue;
224
- }
225
- if (selected.length === 0) {
226
- selected.push({
227
- index: segmentInfo.index,
228
- text: segmentInfo.text.slice(0, availableChars).trimEnd()
229
- });
230
- usedChars = maxContentChars;
231
- }
232
- break;
233
- }
234
- return selected.sort((left, right) => left.index - right.index).map((entry) => entry.text).filter((entry) => entry.length > 0).join("\n\n");
235
- }
236
- export {
237
- stratumCard
238
- };
239
- //# sourceMappingURL=stratum-card.js.map
3
+ ${g}`)}return{path:i,tier:n,card:f,unknowns:E,riskTier:w,tokenEstimate:y(f),originalTokenEstimate:p}}catch(c){const p=c.code==="ENOENT"?"file missing":"unreadable file",d=c.code==="ENOENT"?"missing":"unreadable";return C(i,n,d,p,0)}})),s=l.reduce((i,c)=>i+c.tokenEstimate,0),a=l.reduce((i,c)=>i+c.originalTokenEstimate,0);return{cards:l,totalTokenEstimate:s,totalOriginalTokenEstimate:a,compressionRatio:a===0?0:s/a}}function C(t,e,r,o,n){const m=x({displayPath:T(t),tier:e,role:r,deps:[],exports:[],unknowns:[o],riskTier:"low"});return{path:t,tier:e,card:m,unknowns:[o],riskTier:"low",tokenEstimate:y(m),originalTokenEstimate:n}}function x(t){const{displayPath:e,tier:r,role:o,deps:n,exports:m,unknowns:u,riskTier:l}=t;return[`[${r}: ${e}]`,`ROLE: ${o}`,`DEPS: ${k(n)}`,`EXPORTS: ${k(m)}`,`UNKNOWNS: ${k(u,"; ")}`,`RISK: ${l}`].join(`
4
+ `)}function T(t){const e=A(process.cwd(),t).replace(/\\/g,"/");return!e||e.startsWith("..")?h(t):e}function k(t,e=", "){return t.length>0?t.join(e):"none"}function U(t,e){const r=h(t),o=I(r).toLowerCase();return[".json",".yaml",".yml",".env"].includes(o)||/config|settings/i.test(r)?"configuration":/types?\.ts$|\.d\.ts$/i.test(r)?"type-definitions":/schema/i.test(r)?"schema":/test|spec/i.test(r)?"test":/index\.[jt]sx?$/i.test(r)?"barrel-export":/handler|controller|route/i.test(r)?"entry-point":/model|entity/i.test(r)?"data-model":/util|helper/i.test(r)?"utility":/service|provider/i.test(r)?"service":e.classes.length>0?"class-module":e.interfaces.length>2?"type-definitions":"implementation"}function W(t,e){const r=[],o=new Set;for(const n of t.matchAll(/\/\/\s*(TODO|FIXME|HACK|XXX)\s*:?\s*(.+)?$/gm)){const m=`${n[1]}: ${(n[2]??"").trim()}`.trim();b(r,o,m.replace(/:\s*$/,""))}K(t)&&b(r,o,"exported any usage");for(const n of $(e))b(r,o,`cross-package import: ${n}`);return r.slice(0,S)}function b(t,e,r){t.length>=S||!r||e.has(r)||(e.add(r),t.push(r))}function K(t){return[/export\s+(?:async\s+)?function\s+\w+[^\n{;]*\bany\b/g,/export\s+interface\s+\w+[\s\S]*?\{[\s\S]*?\bany\b[\s\S]*?\}/g,/export\s+type\s+\w+\s*=.*\bany\b/g,/export\s+const\s+\w+[^\n=]*\bany\b/g].some(r=>r.test(t))}function _(t,e){return/auth|token|permission|secret|credential|encrypt/i.test(t)?"high":/types?\.ts$|schema|contract|\.d\.ts$/i.test(h(t))||e.exports.length>10?"medium":"low"}function $(t){return t.imports.map(q).filter(e=>!!e).filter(e=>!e.startsWith("./")&&!e.startsWith("../")).slice(0,3)}function q(t){const e=t.match(/from\s+['"]([^'"]+)['"]/);if(e)return e[1];const r=t.match(/^import\s+['"]([^'"]+)['"]/);return r?r[1]:null}async function v(t,e,r,o){if(o<=0)return"";const n=D(r,"paragraph");if(n.length===0)return"";const m=await Promise.all(n.map(async(s,a)=>{const i=await t.embed(s);return{index:a,text:s,score:X(e,i)}})),u=[];let l=0;for(const s of m.sort((a,i)=>i.score-a.score)){const a=o-l;if(a<=0)break;if(s.text.length<=a){u.push({index:s.index,text:s.text}),l+=s.text.length;continue}u.length===0&&(u.push({index:s.index,text:s.text.slice(0,a).trimEnd()}),l=o);break}return u.sort((s,a)=>s.index-a.index).map(s=>s.text).filter(s=>s.length>0).join(`
5
+
6
+ `)}export{B as stratumCard};