@teammates/recall 0.6.2 → 0.6.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.
package/src/cli.test.ts CHANGED
@@ -1,324 +1,324 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- // parseArgs is not exported, so we re-implement the parsing logic for testing.
4
- // This validates that the arg parsing contract is correct.
5
-
6
- interface Args {
7
- command: string;
8
- query: string;
9
- file: string;
10
- dir: string;
11
- teammate?: string;
12
- results: number;
13
- maxChunks?: number;
14
- maxTokens?: number;
15
- recencyDepth?: number;
16
- typedMemoryBoost?: number;
17
- model?: string;
18
- json: boolean;
19
- sync: boolean;
20
- }
21
-
22
- function parseArgs(argv: string[]): Args {
23
- const args: Args = {
24
- command: "",
25
- query: "",
26
- file: "",
27
- dir: "./.teammates",
28
- results: 5,
29
- json: false,
30
- sync: true,
31
- };
32
-
33
- let i = 0;
34
- while (
35
- i < argv.length &&
36
- (argv[i].includes("node") ||
37
- argv[i].includes("teammates-recall") ||
38
- argv[i].endsWith(".js"))
39
- ) {
40
- i++;
41
- }
42
-
43
- if (i < argv.length && !argv[i].startsWith("-")) {
44
- args.command = argv[i++];
45
- }
46
-
47
- if (
48
- args.command === "search" &&
49
- i < argv.length &&
50
- !argv[i].startsWith("-")
51
- ) {
52
- args.query = argv[i++];
53
- } else if (
54
- args.command === "add" &&
55
- i < argv.length &&
56
- !argv[i].startsWith("-")
57
- ) {
58
- args.file = argv[i++];
59
- }
60
-
61
- while (i < argv.length) {
62
- const arg = argv[i++];
63
- switch (arg) {
64
- case "--dir":
65
- args.dir = argv[i++];
66
- break;
67
- case "--teammate":
68
- args.teammate = argv[i++];
69
- break;
70
- case "--results":
71
- args.results = parseInt(argv[i++], 10);
72
- break;
73
- case "--model":
74
- args.model = argv[i++];
75
- break;
76
- case "--max-chunks":
77
- args.maxChunks = parseInt(argv[i++], 10);
78
- break;
79
- case "--max-tokens":
80
- args.maxTokens = parseInt(argv[i++], 10);
81
- break;
82
- case "--recency-depth":
83
- args.recencyDepth = parseInt(argv[i++], 10);
84
- break;
85
- case "--typed-memory-boost":
86
- args.typedMemoryBoost = parseFloat(argv[i++]);
87
- break;
88
- case "--no-sync":
89
- args.sync = false;
90
- break;
91
- case "--json":
92
- args.json = true;
93
- break;
94
- }
95
- }
96
-
97
- return args;
98
- }
99
-
100
- describe("parseArgs", () => {
101
- it("parses search command with query", () => {
102
- const args = parseArgs(["node", "cli.js", "search", "hello world"]);
103
- expect(args.command).toBe("search");
104
- expect(args.query).toBe("hello world");
105
- });
106
-
107
- it("parses add command with file path", () => {
108
- const args = parseArgs([
109
- "node",
110
- "cli.js",
111
- "add",
112
- "memory/foo.md",
113
- "--teammate",
114
- "beacon",
115
- ]);
116
- expect(args.command).toBe("add");
117
- expect(args.file).toBe("memory/foo.md");
118
- expect(args.teammate).toBe("beacon");
119
- });
120
-
121
- it("parses index command", () => {
122
- const args = parseArgs(["node", "cli.js", "index"]);
123
- expect(args.command).toBe("index");
124
- });
125
-
126
- it("parses sync command", () => {
127
- const args = parseArgs(["node", "cli.js", "sync"]);
128
- expect(args.command).toBe("sync");
129
- });
130
-
131
- it("parses status command", () => {
132
- const args = parseArgs(["node", "cli.js", "status"]);
133
- expect(args.command).toBe("status");
134
- });
135
-
136
- it("parses watch command", () => {
137
- const args = parseArgs(["node", "cli.js", "watch"]);
138
- expect(args.command).toBe("watch");
139
- });
140
-
141
- it("defaults dir to ./.teammates", () => {
142
- const args = parseArgs(["node", "cli.js", "index"]);
143
- expect(args.dir).toBe("./.teammates");
144
- });
145
-
146
- it("parses --dir flag", () => {
147
- const args = parseArgs([
148
- "node",
149
- "cli.js",
150
- "index",
151
- "--dir",
152
- "/path/to/.teammates",
153
- ]);
154
- expect(args.dir).toBe("/path/to/.teammates");
155
- });
156
-
157
- it("parses --teammate flag", () => {
158
- const args = parseArgs([
159
- "node",
160
- "cli.js",
161
- "search",
162
- "query",
163
- "--teammate",
164
- "scribe",
165
- ]);
166
- expect(args.teammate).toBe("scribe");
167
- });
168
-
169
- it("parses --results flag", () => {
170
- const args = parseArgs([
171
- "node",
172
- "cli.js",
173
- "search",
174
- "query",
175
- "--results",
176
- "10",
177
- ]);
178
- expect(args.results).toBe(10);
179
- });
180
-
181
- it("parses --model flag", () => {
182
- const args = parseArgs([
183
- "node",
184
- "cli.js",
185
- "index",
186
- "--model",
187
- "custom/model",
188
- ]);
189
- expect(args.model).toBe("custom/model");
190
- });
191
-
192
- it("parses --json flag", () => {
193
- const args = parseArgs(["node", "cli.js", "status", "--json"]);
194
- expect(args.json).toBe(true);
195
- });
196
-
197
- it("defaults json to false", () => {
198
- const args = parseArgs(["node", "cli.js", "status"]);
199
- expect(args.json).toBe(false);
200
- });
201
-
202
- it("parses --no-sync flag", () => {
203
- const args = parseArgs(["node", "cli.js", "search", "query", "--no-sync"]);
204
- expect(args.sync).toBe(false);
205
- });
206
-
207
- it("defaults sync to true", () => {
208
- const args = parseArgs(["node", "cli.js", "search", "query"]);
209
- expect(args.sync).toBe(true);
210
- });
211
-
212
- it("defaults results to 5", () => {
213
- const args = parseArgs(["node", "cli.js", "search", "query"]);
214
- expect(args.results).toBe(5);
215
- });
216
-
217
- it("returns empty command for no args", () => {
218
- const args = parseArgs(["node", "cli.js"]);
219
- expect(args.command).toBe("");
220
- });
221
-
222
- it("handles multiple flags together", () => {
223
- const args = parseArgs([
224
- "node",
225
- "cli.js",
226
- "search",
227
- "my query",
228
- "--dir",
229
- "/tmp/.teammates",
230
- "--teammate",
231
- "beacon",
232
- "--results",
233
- "3",
234
- "--json",
235
- "--no-sync",
236
- ]);
237
- expect(args.command).toBe("search");
238
- expect(args.query).toBe("my query");
239
- expect(args.dir).toBe("/tmp/.teammates");
240
- expect(args.teammate).toBe("beacon");
241
- expect(args.results).toBe(3);
242
- expect(args.json).toBe(true);
243
- expect(args.sync).toBe(false);
244
- });
245
-
246
- it("parses --max-chunks flag", () => {
247
- const args = parseArgs([
248
- "node",
249
- "cli.js",
250
- "search",
251
- "query",
252
- "--max-chunks",
253
- "7",
254
- ]);
255
- expect(args.maxChunks).toBe(7);
256
- });
257
-
258
- it("parses --max-tokens flag", () => {
259
- const args = parseArgs([
260
- "node",
261
- "cli.js",
262
- "search",
263
- "query",
264
- "--max-tokens",
265
- "1000",
266
- ]);
267
- expect(args.maxTokens).toBe(1000);
268
- });
269
-
270
- it("parses --recency-depth flag", () => {
271
- const args = parseArgs([
272
- "node",
273
- "cli.js",
274
- "search",
275
- "query",
276
- "--recency-depth",
277
- "4",
278
- ]);
279
- expect(args.recencyDepth).toBe(4);
280
- });
281
-
282
- it("parses --typed-memory-boost flag", () => {
283
- const args = parseArgs([
284
- "node",
285
- "cli.js",
286
- "search",
287
- "query",
288
- "--typed-memory-boost",
289
- "1.5",
290
- ]);
291
- expect(args.typedMemoryBoost).toBe(1.5);
292
- });
293
-
294
- it("handles multiple new search flags together", () => {
295
- const args = parseArgs([
296
- "node",
297
- "cli.js",
298
- "search",
299
- "my query",
300
- "--max-chunks",
301
- "5",
302
- "--max-tokens",
303
- "800",
304
- "--recency-depth",
305
- "3",
306
- "--typed-memory-boost",
307
- "2.0",
308
- ]);
309
- expect(args.command).toBe("search");
310
- expect(args.query).toBe("my query");
311
- expect(args.maxChunks).toBe(5);
312
- expect(args.maxTokens).toBe(800);
313
- expect(args.recencyDepth).toBe(3);
314
- expect(args.typedMemoryBoost).toBe(2.0);
315
- });
316
-
317
- it("leaves new flags undefined when not provided", () => {
318
- const args = parseArgs(["node", "cli.js", "search", "query"]);
319
- expect(args.maxChunks).toBeUndefined();
320
- expect(args.maxTokens).toBeUndefined();
321
- expect(args.recencyDepth).toBeUndefined();
322
- expect(args.typedMemoryBoost).toBeUndefined();
323
- });
324
- });
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ // parseArgs is not exported, so we re-implement the parsing logic for testing.
4
+ // This validates that the arg parsing contract is correct.
5
+
6
+ interface Args {
7
+ command: string;
8
+ query: string;
9
+ file: string;
10
+ dir: string;
11
+ teammate?: string;
12
+ results: number;
13
+ maxChunks?: number;
14
+ maxTokens?: number;
15
+ recencyDepth?: number;
16
+ typedMemoryBoost?: number;
17
+ model?: string;
18
+ json: boolean;
19
+ sync: boolean;
20
+ }
21
+
22
+ function parseArgs(argv: string[]): Args {
23
+ const args: Args = {
24
+ command: "",
25
+ query: "",
26
+ file: "",
27
+ dir: "./.teammates",
28
+ results: 5,
29
+ json: false,
30
+ sync: true,
31
+ };
32
+
33
+ let i = 0;
34
+ while (
35
+ i < argv.length &&
36
+ (argv[i].includes("node") ||
37
+ argv[i].includes("teammates-recall") ||
38
+ argv[i].endsWith(".js"))
39
+ ) {
40
+ i++;
41
+ }
42
+
43
+ if (i < argv.length && !argv[i].startsWith("-")) {
44
+ args.command = argv[i++];
45
+ }
46
+
47
+ if (
48
+ args.command === "search" &&
49
+ i < argv.length &&
50
+ !argv[i].startsWith("-")
51
+ ) {
52
+ args.query = argv[i++];
53
+ } else if (
54
+ args.command === "add" &&
55
+ i < argv.length &&
56
+ !argv[i].startsWith("-")
57
+ ) {
58
+ args.file = argv[i++];
59
+ }
60
+
61
+ while (i < argv.length) {
62
+ const arg = argv[i++];
63
+ switch (arg) {
64
+ case "--dir":
65
+ args.dir = argv[i++];
66
+ break;
67
+ case "--teammate":
68
+ args.teammate = argv[i++];
69
+ break;
70
+ case "--results":
71
+ args.results = parseInt(argv[i++], 10);
72
+ break;
73
+ case "--model":
74
+ args.model = argv[i++];
75
+ break;
76
+ case "--max-chunks":
77
+ args.maxChunks = parseInt(argv[i++], 10);
78
+ break;
79
+ case "--max-tokens":
80
+ args.maxTokens = parseInt(argv[i++], 10);
81
+ break;
82
+ case "--recency-depth":
83
+ args.recencyDepth = parseInt(argv[i++], 10);
84
+ break;
85
+ case "--typed-memory-boost":
86
+ args.typedMemoryBoost = parseFloat(argv[i++]);
87
+ break;
88
+ case "--no-sync":
89
+ args.sync = false;
90
+ break;
91
+ case "--json":
92
+ args.json = true;
93
+ break;
94
+ }
95
+ }
96
+
97
+ return args;
98
+ }
99
+
100
+ describe("parseArgs", () => {
101
+ it("parses search command with query", () => {
102
+ const args = parseArgs(["node", "cli.js", "search", "hello world"]);
103
+ expect(args.command).toBe("search");
104
+ expect(args.query).toBe("hello world");
105
+ });
106
+
107
+ it("parses add command with file path", () => {
108
+ const args = parseArgs([
109
+ "node",
110
+ "cli.js",
111
+ "add",
112
+ "memory/foo.md",
113
+ "--teammate",
114
+ "beacon",
115
+ ]);
116
+ expect(args.command).toBe("add");
117
+ expect(args.file).toBe("memory/foo.md");
118
+ expect(args.teammate).toBe("beacon");
119
+ });
120
+
121
+ it("parses index command", () => {
122
+ const args = parseArgs(["node", "cli.js", "index"]);
123
+ expect(args.command).toBe("index");
124
+ });
125
+
126
+ it("parses sync command", () => {
127
+ const args = parseArgs(["node", "cli.js", "sync"]);
128
+ expect(args.command).toBe("sync");
129
+ });
130
+
131
+ it("parses status command", () => {
132
+ const args = parseArgs(["node", "cli.js", "status"]);
133
+ expect(args.command).toBe("status");
134
+ });
135
+
136
+ it("parses watch command", () => {
137
+ const args = parseArgs(["node", "cli.js", "watch"]);
138
+ expect(args.command).toBe("watch");
139
+ });
140
+
141
+ it("defaults dir to ./.teammates", () => {
142
+ const args = parseArgs(["node", "cli.js", "index"]);
143
+ expect(args.dir).toBe("./.teammates");
144
+ });
145
+
146
+ it("parses --dir flag", () => {
147
+ const args = parseArgs([
148
+ "node",
149
+ "cli.js",
150
+ "index",
151
+ "--dir",
152
+ "/path/to/.teammates",
153
+ ]);
154
+ expect(args.dir).toBe("/path/to/.teammates");
155
+ });
156
+
157
+ it("parses --teammate flag", () => {
158
+ const args = parseArgs([
159
+ "node",
160
+ "cli.js",
161
+ "search",
162
+ "query",
163
+ "--teammate",
164
+ "scribe",
165
+ ]);
166
+ expect(args.teammate).toBe("scribe");
167
+ });
168
+
169
+ it("parses --results flag", () => {
170
+ const args = parseArgs([
171
+ "node",
172
+ "cli.js",
173
+ "search",
174
+ "query",
175
+ "--results",
176
+ "10",
177
+ ]);
178
+ expect(args.results).toBe(10);
179
+ });
180
+
181
+ it("parses --model flag", () => {
182
+ const args = parseArgs([
183
+ "node",
184
+ "cli.js",
185
+ "index",
186
+ "--model",
187
+ "custom/model",
188
+ ]);
189
+ expect(args.model).toBe("custom/model");
190
+ });
191
+
192
+ it("parses --json flag", () => {
193
+ const args = parseArgs(["node", "cli.js", "status", "--json"]);
194
+ expect(args.json).toBe(true);
195
+ });
196
+
197
+ it("defaults json to false", () => {
198
+ const args = parseArgs(["node", "cli.js", "status"]);
199
+ expect(args.json).toBe(false);
200
+ });
201
+
202
+ it("parses --no-sync flag", () => {
203
+ const args = parseArgs(["node", "cli.js", "search", "query", "--no-sync"]);
204
+ expect(args.sync).toBe(false);
205
+ });
206
+
207
+ it("defaults sync to true", () => {
208
+ const args = parseArgs(["node", "cli.js", "search", "query"]);
209
+ expect(args.sync).toBe(true);
210
+ });
211
+
212
+ it("defaults results to 5", () => {
213
+ const args = parseArgs(["node", "cli.js", "search", "query"]);
214
+ expect(args.results).toBe(5);
215
+ });
216
+
217
+ it("returns empty command for no args", () => {
218
+ const args = parseArgs(["node", "cli.js"]);
219
+ expect(args.command).toBe("");
220
+ });
221
+
222
+ it("handles multiple flags together", () => {
223
+ const args = parseArgs([
224
+ "node",
225
+ "cli.js",
226
+ "search",
227
+ "my query",
228
+ "--dir",
229
+ "/tmp/.teammates",
230
+ "--teammate",
231
+ "beacon",
232
+ "--results",
233
+ "3",
234
+ "--json",
235
+ "--no-sync",
236
+ ]);
237
+ expect(args.command).toBe("search");
238
+ expect(args.query).toBe("my query");
239
+ expect(args.dir).toBe("/tmp/.teammates");
240
+ expect(args.teammate).toBe("beacon");
241
+ expect(args.results).toBe(3);
242
+ expect(args.json).toBe(true);
243
+ expect(args.sync).toBe(false);
244
+ });
245
+
246
+ it("parses --max-chunks flag", () => {
247
+ const args = parseArgs([
248
+ "node",
249
+ "cli.js",
250
+ "search",
251
+ "query",
252
+ "--max-chunks",
253
+ "7",
254
+ ]);
255
+ expect(args.maxChunks).toBe(7);
256
+ });
257
+
258
+ it("parses --max-tokens flag", () => {
259
+ const args = parseArgs([
260
+ "node",
261
+ "cli.js",
262
+ "search",
263
+ "query",
264
+ "--max-tokens",
265
+ "1000",
266
+ ]);
267
+ expect(args.maxTokens).toBe(1000);
268
+ });
269
+
270
+ it("parses --recency-depth flag", () => {
271
+ const args = parseArgs([
272
+ "node",
273
+ "cli.js",
274
+ "search",
275
+ "query",
276
+ "--recency-depth",
277
+ "4",
278
+ ]);
279
+ expect(args.recencyDepth).toBe(4);
280
+ });
281
+
282
+ it("parses --typed-memory-boost flag", () => {
283
+ const args = parseArgs([
284
+ "node",
285
+ "cli.js",
286
+ "search",
287
+ "query",
288
+ "--typed-memory-boost",
289
+ "1.5",
290
+ ]);
291
+ expect(args.typedMemoryBoost).toBe(1.5);
292
+ });
293
+
294
+ it("handles multiple new search flags together", () => {
295
+ const args = parseArgs([
296
+ "node",
297
+ "cli.js",
298
+ "search",
299
+ "my query",
300
+ "--max-chunks",
301
+ "5",
302
+ "--max-tokens",
303
+ "800",
304
+ "--recency-depth",
305
+ "3",
306
+ "--typed-memory-boost",
307
+ "2.0",
308
+ ]);
309
+ expect(args.command).toBe("search");
310
+ expect(args.query).toBe("my query");
311
+ expect(args.maxChunks).toBe(5);
312
+ expect(args.maxTokens).toBe(800);
313
+ expect(args.recencyDepth).toBe(3);
314
+ expect(args.typedMemoryBoost).toBe(2.0);
315
+ });
316
+
317
+ it("leaves new flags undefined when not provided", () => {
318
+ const args = parseArgs(["node", "cli.js", "search", "query"]);
319
+ expect(args.maxChunks).toBeUndefined();
320
+ expect(args.maxTokens).toBeUndefined();
321
+ expect(args.recencyDepth).toBeUndefined();
322
+ expect(args.typedMemoryBoost).toBeUndefined();
323
+ });
324
+ });