agentikit 0.0.12 → 0.0.13

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 CHANGED
@@ -35,11 +35,24 @@ When you search or open an asset, the working stash takes priority. This
35
35
  means you can install a kit and override individual assets by cloning them
36
36
  into your working stash.
37
37
 
38
+ ## Prerequisites
39
+
40
+ Agent-i-Kit requires [Bun](https://bun.sh) (v1.0+) as its runtime. It uses
41
+ Bun-specific APIs (`bun:sqlite`) that are not available in Node.js.
42
+
43
+ ```sh
44
+ # Install Bun if you don't have it
45
+ curl -fsSL https://bun.sh/install | bash
46
+ ```
47
+
48
+ > **Don't want to install Bun?** Use the [standalone binary](#standalone-binary)
49
+ > instead -- it has no runtime dependencies.
50
+
38
51
  ## Quick Start
39
52
 
40
53
  ```sh
41
54
  # Install
42
- npm install -g agentikit
55
+ bun install -g agentikit
43
56
 
44
57
  # Initialize your stash
45
58
  akm init
@@ -59,6 +72,9 @@ akm search "lint" --source both
59
72
 
60
73
  ### Standalone Binary
61
74
 
75
+ The standalone binary bundles everything it needs and does **not** require Bun
76
+ or Node.js.
77
+
62
78
  ```sh
63
79
  # macOS / Linux
64
80
  curl -fsSL https://raw.githubusercontent.com/itlackey/agentikit/main/install.sh | bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentikit",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "description": "CLI tool to search, open, and run extension assets from an agentikit stash directory.",
6
6
  "keywords": [
@@ -1,211 +0,0 @@
1
- export class TfIdfAdapter {
2
- documents = [];
3
- idf = new Map();
4
- entries = [];
5
- buildIndex(entries) {
6
- this.entries = entries;
7
- const docCount = entries.length;
8
- if (docCount === 0)
9
- return;
10
- // Compute term frequencies per document
11
- const docFreqs = new Map();
12
- this.documents = entries.map((entry) => {
13
- const tokens = tokenize(entry.text);
14
- const termFreqs = new Map();
15
- for (const token of tokens) {
16
- termFreqs.set(token, (termFreqs.get(token) || 0) + 1);
17
- }
18
- // Track document frequency for IDF
19
- for (const term of termFreqs.keys()) {
20
- docFreqs.set(term, (docFreqs.get(term) || 0) + 1);
21
- }
22
- return { entry, termFreqs, magnitude: 0 };
23
- });
24
- // Compute IDF: log(N / df)
25
- this.idf = new Map();
26
- for (const [term, df] of docFreqs) {
27
- this.idf.set(term, Math.log(docCount / df));
28
- }
29
- // Compute document magnitudes for cosine similarity
30
- for (const doc of this.documents) {
31
- let sumSq = 0;
32
- for (const [term, tf] of doc.termFreqs) {
33
- const idf = this.idf.get(term) || 0;
34
- const tfidf = tf * idf;
35
- sumSq += tfidf * tfidf;
36
- }
37
- doc.magnitude = Math.sqrt(sumSq);
38
- }
39
- }
40
- search(query, limit, typeFilter) {
41
- if (this.documents.length === 0)
42
- return [];
43
- const queryTokens = tokenize(query.toLowerCase());
44
- if (queryTokens.length === 0) {
45
- // Empty query: return all, sorted by type
46
- return this.documents
47
- .filter((d) => !typeFilter || typeFilter === "any" || d.entry.entry.type === typeFilter)
48
- .slice(0, limit)
49
- .map((d) => ({
50
- entry: d.entry.entry,
51
- path: d.entry.path,
52
- score: 1,
53
- }));
54
- }
55
- // Build query TF-IDF vector
56
- const queryTermFreqs = new Map();
57
- for (const token of queryTokens) {
58
- queryTermFreqs.set(token, (queryTermFreqs.get(token) || 0) + 1);
59
- }
60
- let queryMagnitude = 0;
61
- const queryVector = new Map();
62
- for (const [term, tf] of queryTermFreqs) {
63
- const idf = this.idf.get(term) || 0;
64
- const tfidf = tf * idf;
65
- queryVector.set(term, tfidf);
66
- queryMagnitude += tfidf * tfidf;
67
- }
68
- queryMagnitude = Math.sqrt(queryMagnitude);
69
- if (queryMagnitude === 0) {
70
- // All query terms are unknown — fallback to substring match
71
- return this.substringFallback(query, limit, typeFilter);
72
- }
73
- const results = [];
74
- const querySet = new Set(queryTokens);
75
- for (const doc of this.documents) {
76
- if (typeFilter && typeFilter !== "any" && doc.entry.entry.type !== typeFilter)
77
- continue;
78
- // Cosine similarity
79
- let dotProduct = 0;
80
- for (const [term, queryTfidf] of queryVector) {
81
- const docTf = doc.termFreqs.get(term) || 0;
82
- if (docTf === 0)
83
- continue;
84
- const docIdf = this.idf.get(term) || 0;
85
- dotProduct += queryTfidf * (docTf * docIdf);
86
- }
87
- let score = doc.magnitude > 0 && queryMagnitude > 0
88
- ? dotProduct / (doc.magnitude * queryMagnitude)
89
- : 0;
90
- // Boost: tag exact match
91
- const tags = doc.entry.entry.tags || [];
92
- for (const tag of tags) {
93
- if (querySet.has(tag.toLowerCase())) {
94
- score += 0.15;
95
- }
96
- }
97
- // Boost: intent phrase contains query token
98
- const intents = doc.entry.entry.intents || [];
99
- for (const intent of intents) {
100
- const intentLower = intent.toLowerCase();
101
- for (const token of queryTokens) {
102
- if (intentLower.includes(token)) {
103
- score += 0.12;
104
- break; // one boost per intent phrase
105
- }
106
- }
107
- }
108
- // Boost: name contains query token
109
- const nameLower = doc.entry.entry.name.toLowerCase().replace(/[-_]/g, " ");
110
- for (const token of queryTokens) {
111
- if (nameLower.includes(token)) {
112
- score += 0.1;
113
- break;
114
- }
115
- }
116
- if (score > 0) {
117
- results.push({
118
- entry: doc.entry.entry,
119
- path: doc.entry.path,
120
- score: Math.round(score * 1000) / 1000,
121
- });
122
- }
123
- }
124
- results.sort((a, b) => b.score - a.score);
125
- return results.slice(0, limit);
126
- }
127
- serialize() {
128
- const idf = {};
129
- for (const [term, val] of this.idf) {
130
- idf[term] = val;
131
- }
132
- const docs = this.documents.map((d) => {
133
- const termFreqs = {};
134
- for (const [term, tf] of d.termFreqs) {
135
- termFreqs[term] = tf;
136
- }
137
- return { id: d.entry.id, termFreqs, magnitude: d.magnitude };
138
- });
139
- return { idf, docs };
140
- }
141
- static deserialize(data, entries) {
142
- const adapter = new TfIdfAdapter();
143
- adapter.entries = entries;
144
- adapter.idf = new Map(Object.entries(data.idf));
145
- const entryMap = new Map(entries.map((e) => [e.id, e]));
146
- adapter.documents = data.docs
147
- .map((d) => {
148
- const entry = entryMap.get(d.id);
149
- if (!entry)
150
- return null;
151
- return {
152
- entry,
153
- termFreqs: new Map(Object.entries(d.termFreqs)),
154
- magnitude: d.magnitude,
155
- };
156
- })
157
- .filter((d) => d !== null);
158
- return adapter;
159
- }
160
- substringFallback(query, limit, typeFilter) {
161
- const q = query.toLowerCase();
162
- const tokens = tokenize(q);
163
- return this.documents
164
- .map((d) => {
165
- if (typeFilter && typeFilter !== "any" && d.entry.entry.type !== typeFilter)
166
- return null;
167
- // Check if any query token matches the document text or name
168
- const text = d.entry.text;
169
- const name = d.entry.entry.name.toLowerCase();
170
- let matchCount = 0;
171
- for (const token of tokens) {
172
- if (text.includes(token) || name.includes(token))
173
- matchCount++;
174
- }
175
- // Also check full substring match
176
- if (text.includes(q) || name.includes(q))
177
- matchCount = Math.max(matchCount, tokens.length);
178
- if (matchCount === 0)
179
- return null;
180
- return {
181
- entry: d.entry.entry,
182
- path: d.entry.path,
183
- score: Math.round((matchCount / Math.max(tokens.length, 1)) * 500) / 1000,
184
- };
185
- })
186
- .filter((d) => d !== null)
187
- .sort((a, b) => b.score - a.score)
188
- .slice(0, limit);
189
- }
190
- }
191
- // ── Tokenization ────────────────────────────────────────────────────────────
192
- const STOP_WORDS = new Set([
193
- "a", "an", "the", "is", "are", "was", "were", "be", "been", "being",
194
- "have", "has", "had", "do", "does", "did", "will", "would", "could",
195
- "should", "may", "might", "shall", "can", "need", "dare", "ought",
196
- "to", "of", "in", "for", "on", "with", "at", "by", "from", "as",
197
- "into", "through", "during", "before", "after", "above", "below",
198
- "and", "but", "or", "nor", "not", "so", "yet", "both", "either",
199
- "neither", "each", "every", "all", "any", "few", "more", "most",
200
- "other", "some", "such", "no", "only", "own", "same", "than",
201
- "too", "very", "just", "because", "if", "when", "where", "how",
202
- "what", "which", "who", "whom", "this", "that", "these", "those",
203
- "it", "its",
204
- ]);
205
- function tokenize(text) {
206
- return text
207
- .toLowerCase()
208
- .replace(/[^a-z0-9]+/g, " ")
209
- .split(/\s+/)
210
- .filter((t) => t.length > 1 && !STOP_WORDS.has(t));
211
- }