@vpxa/kb 0.1.1 → 0.1.2
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/package.json +1 -1
- package/packages/analyzers/dist/blast-radius-analyzer.js +13 -114
- package/packages/analyzers/dist/dependency-analyzer.js +11 -425
- package/packages/analyzers/dist/diagram-generator.js +4 -86
- package/packages/analyzers/dist/entry-point-analyzer.js +5 -239
- package/packages/analyzers/dist/index.js +1 -23
- package/packages/analyzers/dist/knowledge-producer.js +24 -113
- package/packages/analyzers/dist/pattern-analyzer.js +5 -359
- package/packages/analyzers/dist/regex-call-graph.js +1 -428
- package/packages/analyzers/dist/structure-analyzer.js +4 -258
- package/packages/analyzers/dist/symbol-analyzer.js +13 -442
- package/packages/analyzers/dist/ts-call-graph.js +1 -160
- package/packages/analyzers/dist/types.js +0 -1
- package/packages/chunker/dist/call-graph-extractor.js +1 -90
- package/packages/chunker/dist/chunker-factory.js +1 -36
- package/packages/chunker/dist/chunker.interface.js +0 -1
- package/packages/chunker/dist/code-chunker.js +14 -134
- package/packages/chunker/dist/generic-chunker.js +5 -72
- package/packages/chunker/dist/index.js +1 -21
- package/packages/chunker/dist/markdown-chunker.js +7 -119
- package/packages/chunker/dist/treesitter-chunker.js +8 -234
- package/packages/cli/dist/commands/analyze.js +3 -112
- package/packages/cli/dist/commands/context-cmds.js +1 -155
- package/packages/cli/dist/commands/environment.js +2 -204
- package/packages/cli/dist/commands/execution.js +1 -137
- package/packages/cli/dist/commands/graph.js +7 -81
- package/packages/cli/dist/commands/init.js +9 -87
- package/packages/cli/dist/commands/knowledge.js +1 -139
- package/packages/cli/dist/commands/search.js +8 -267
- package/packages/cli/dist/commands/system.js +4 -241
- package/packages/cli/dist/commands/workspace.js +2 -388
- package/packages/cli/dist/context.js +1 -14
- package/packages/cli/dist/helpers.js +3 -458
- package/packages/cli/dist/index.js +3 -69
- package/packages/cli/dist/kb-init.js +1 -82
- package/packages/cli/dist/types.js +0 -1
- package/packages/core/dist/constants.js +1 -43
- package/packages/core/dist/content-detector.js +1 -79
- package/packages/core/dist/errors.js +1 -40
- package/packages/core/dist/index.js +1 -9
- package/packages/core/dist/logger.js +1 -34
- package/packages/core/dist/types.js +0 -1
- package/packages/embeddings/dist/embedder.interface.js +0 -1
- package/packages/embeddings/dist/index.js +1 -5
- package/packages/embeddings/dist/onnx-embedder.js +1 -82
- package/packages/indexer/dist/file-hasher.js +1 -13
- package/packages/indexer/dist/filesystem-crawler.js +1 -125
- package/packages/indexer/dist/graph-extractor.js +1 -111
- package/packages/indexer/dist/incremental-indexer.js +1 -278
- package/packages/indexer/dist/index.js +1 -14
- package/packages/server/dist/api.js +1 -9
- package/packages/server/dist/config.js +1 -75
- package/packages/server/dist/curated-manager.js +9 -356
- package/packages/server/dist/index.js +1 -134
- package/packages/server/dist/replay-interceptor.js +1 -38
- package/packages/server/dist/resources/resources.js +2 -40
- package/packages/server/dist/server.js +1 -247
- package/packages/server/dist/tools/analyze.tools.js +1 -288
- package/packages/server/dist/tools/forge.tools.js +11 -499
- package/packages/server/dist/tools/forget.tool.js +3 -39
- package/packages/server/dist/tools/graph.tool.js +5 -110
- package/packages/server/dist/tools/list.tool.js +5 -53
- package/packages/server/dist/tools/lookup.tool.js +8 -51
- package/packages/server/dist/tools/onboard.tool.js +2 -112
- package/packages/server/dist/tools/produce.tool.js +4 -74
- package/packages/server/dist/tools/read.tool.js +4 -47
- package/packages/server/dist/tools/reindex.tool.js +2 -70
- package/packages/server/dist/tools/remember.tool.js +3 -42
- package/packages/server/dist/tools/replay.tool.js +6 -88
- package/packages/server/dist/tools/search.tool.js +17 -327
- package/packages/server/dist/tools/status.tool.js +3 -68
- package/packages/server/dist/tools/toolkit.tools.js +20 -1673
- package/packages/server/dist/tools/update.tool.js +3 -39
- package/packages/server/dist/tools/utility.tools.js +19 -456
- package/packages/store/dist/graph-store.interface.js +0 -1
- package/packages/store/dist/index.js +1 -9
- package/packages/store/dist/lance-store.js +1 -258
- package/packages/store/dist/sqlite-graph-store.js +8 -309
- package/packages/store/dist/store-factory.js +1 -14
- package/packages/store/dist/store.interface.js +0 -1
- package/packages/tools/dist/batch.js +1 -45
- package/packages/tools/dist/changelog.js +2 -112
- package/packages/tools/dist/check.js +2 -59
- package/packages/tools/dist/checkpoint.js +2 -43
- package/packages/tools/dist/codemod.js +2 -69
- package/packages/tools/dist/compact.js +3 -60
- package/packages/tools/dist/data-transform.js +1 -124
- package/packages/tools/dist/dead-symbols.js +2 -71
- package/packages/tools/dist/delegate.js +3 -128
- package/packages/tools/dist/diff-parse.js +3 -153
- package/packages/tools/dist/digest.js +7 -242
- package/packages/tools/dist/encode.js +1 -46
- package/packages/tools/dist/env-info.js +1 -58
- package/packages/tools/dist/eval.js +3 -79
- package/packages/tools/dist/evidence-map.js +3 -203
- package/packages/tools/dist/file-summary.js +2 -106
- package/packages/tools/dist/file-walk.js +1 -75
- package/packages/tools/dist/find-examples.js +3 -48
- package/packages/tools/dist/find.js +1 -120
- package/packages/tools/dist/forge-classify.js +2 -319
- package/packages/tools/dist/forge-ground.js +1 -184
- package/packages/tools/dist/git-context.js +3 -46
- package/packages/tools/dist/graph-query.js +1 -194
- package/packages/tools/dist/health.js +1 -118
- package/packages/tools/dist/http-request.js +1 -58
- package/packages/tools/dist/index.js +1 -273
- package/packages/tools/dist/lane.js +7 -227
- package/packages/tools/dist/measure.js +2 -119
- package/packages/tools/dist/onboard.js +42 -1136
- package/packages/tools/dist/parse-output.js +2 -158
- package/packages/tools/dist/process-manager.js +1 -69
- package/packages/tools/dist/queue.js +2 -126
- package/packages/tools/dist/regex-test.js +1 -39
- package/packages/tools/dist/rename.js +2 -70
- package/packages/tools/dist/replay.js +6 -108
- package/packages/tools/dist/schema-validate.js +1 -141
- package/packages/tools/dist/scope-map.js +1 -72
- package/packages/tools/dist/snippet.js +1 -80
- package/packages/tools/dist/stash.js +2 -60
- package/packages/tools/dist/stratum-card.js +5 -238
- package/packages/tools/dist/symbol.js +3 -87
- package/packages/tools/dist/test-run.js +2 -55
- package/packages/tools/dist/text-utils.js +2 -31
- package/packages/tools/dist/time-utils.js +1 -135
- package/packages/tools/dist/trace.js +2 -114
- package/packages/tools/dist/truncation.js +10 -41
- package/packages/tools/dist/watch.js +1 -61
- package/packages/tools/dist/web-fetch.js +9 -244
- package/packages/tools/dist/web-search.js +1 -46
- package/packages/tools/dist/workset.js +2 -77
- package/packages/tui/dist/App.js +260 -52468
- package/packages/tui/dist/index.js +286 -54551
- package/packages/tui/dist/panels/CuratedPanel.js +211 -34291
- package/packages/tui/dist/panels/LogPanel.js +259 -51703
- package/packages/tui/dist/panels/SearchPanel.js +212 -34824
- package/packages/tui/dist/panels/StatusPanel.js +211 -34304
|
@@ -1,141 +1 @@
|
|
|
1
|
-
function
|
|
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
|
|
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},k=await h.search(f,S),o=new Map;for(const e of k){const t=e.record.sourcePath,r=o.get(t);r?(r.chunks.push(e),r.totalChars+=e.record.content.length,r.maxScore=Math.max(r.maxScore,e.score)):o.set(t,{chunks:[e],totalChars:e.record.content.length,maxScore:e.score})}const s=[...o.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],x=i.record.headingPath?`Matches: ${i.record.headingPath}`:`Contains relevant ${i.record.contentType} content`;return{path:e,reason:x,estimatedTokens:0,relevance:r,focusRanges:a}});for(const e of s){const t=o.get(e.path);t&&(e.estimatedTokens=M(t.chunks.map(r=>r.record.content).join("")))}const y=s.reduce((e,t)=>e+t.estimatedTokens,0),b=[...s].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:s,totalEstimatedTokens:y,readingOrder:b}}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
|
|
2
|
-
|
|
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
|
|
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 X}from"./file-summary.js";import{cosineSimilarity as j,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 X({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
|
-
${
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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:j(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};
|