@yeseh/cortex-cli 0.6.8 → 0.6.10

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 (74) hide show
  1. package/dist/program.js +1538 -5
  2. package/dist/program.js.map +32 -3
  3. package/dist/run.d.ts +0 -1
  4. package/dist/run.d.ts.map +1 -1
  5. package/dist/run.js +3 -4
  6. package/dist/run.js.map +3 -3
  7. package/package.json +4 -6
  8. package/dist/chunk-dsfj4baj.js +0 -1543
  9. package/dist/chunk-dsfj4baj.js.map +0 -38
  10. package/src/category/commands/create.spec.ts +0 -139
  11. package/src/category/commands/create.ts +0 -119
  12. package/src/category/index.ts +0 -24
  13. package/src/commands/init.spec.ts +0 -203
  14. package/src/commands/init.ts +0 -301
  15. package/src/context.spec.ts +0 -60
  16. package/src/context.ts +0 -170
  17. package/src/errors.spec.ts +0 -264
  18. package/src/errors.ts +0 -105
  19. package/src/memory/commands/add.spec.ts +0 -169
  20. package/src/memory/commands/add.ts +0 -158
  21. package/src/memory/commands/definitions.spec.ts +0 -80
  22. package/src/memory/commands/list.spec.ts +0 -123
  23. package/src/memory/commands/list.ts +0 -269
  24. package/src/memory/commands/move.spec.ts +0 -85
  25. package/src/memory/commands/move.ts +0 -119
  26. package/src/memory/commands/remove.spec.ts +0 -79
  27. package/src/memory/commands/remove.ts +0 -108
  28. package/src/memory/commands/show.spec.ts +0 -71
  29. package/src/memory/commands/show.ts +0 -165
  30. package/src/memory/commands/test-helpers.spec.ts +0 -127
  31. package/src/memory/commands/update.spec.ts +0 -86
  32. package/src/memory/commands/update.ts +0 -230
  33. package/src/memory/index.spec.ts +0 -59
  34. package/src/memory/index.ts +0 -44
  35. package/src/memory/parsing.spec.ts +0 -105
  36. package/src/memory/parsing.ts +0 -22
  37. package/src/observability.spec.ts +0 -126
  38. package/src/observability.ts +0 -82
  39. package/src/output.spec.ts +0 -835
  40. package/src/output.ts +0 -119
  41. package/src/program.spec.ts +0 -46
  42. package/src/program.ts +0 -75
  43. package/src/run.spec.ts +0 -31
  44. package/src/run.ts +0 -9
  45. package/src/store/commands/add.spec.ts +0 -131
  46. package/src/store/commands/add.ts +0 -231
  47. package/src/store/commands/init.spec.ts +0 -220
  48. package/src/store/commands/init.ts +0 -272
  49. package/src/store/commands/list.spec.ts +0 -175
  50. package/src/store/commands/list.ts +0 -102
  51. package/src/store/commands/prune.spec.ts +0 -120
  52. package/src/store/commands/prune.ts +0 -152
  53. package/src/store/commands/reindexs.spec.ts +0 -94
  54. package/src/store/commands/reindexs.ts +0 -97
  55. package/src/store/commands/remove.spec.ts +0 -97
  56. package/src/store/commands/remove.ts +0 -189
  57. package/src/store/index.spec.ts +0 -60
  58. package/src/store/index.ts +0 -49
  59. package/src/store/utils/resolve-store-name.spec.ts +0 -62
  60. package/src/store/utils/resolve-store-name.ts +0 -79
  61. package/src/test-helpers.spec.ts +0 -430
  62. package/src/tests/cli.integration.spec.ts +0 -1306
  63. package/src/toon.spec.ts +0 -183
  64. package/src/toon.ts +0 -462
  65. package/src/utils/git.spec.ts +0 -95
  66. package/src/utils/git.ts +0 -51
  67. package/src/utils/input.spec.ts +0 -326
  68. package/src/utils/input.ts +0 -150
  69. package/src/utils/paths.spec.ts +0 -235
  70. package/src/utils/paths.ts +0 -75
  71. package/src/utils/prompts.spec.ts +0 -23
  72. package/src/utils/prompts.ts +0 -88
  73. package/src/utils/resolve-default-store.spec.ts +0 -135
  74. package/src/utils/resolve-default-store.ts +0 -74
@@ -1,430 +0,0 @@
1
- /**
2
- * Shared test helpers for CLI package unit tests.
3
- *
4
- * Exports reusable primitives for result construction, stream capture,
5
- * clock fixtures, CLI error assertions, and mock adapter/context factories.
6
- * All other spec files in this package import from this module.
7
- *
8
- * @module cli/_test-helpers
9
- */
10
-
11
- import { describe, expect, it } from 'bun:test';
12
- import { PassThrough } from 'node:stream';
13
- import { InvalidArgumentError, CommanderError } from '@commander-js/extra-typings';
14
- import type {
15
- StorageAdapter,
16
- MemoryStorage,
17
- IndexStorage,
18
- CategoryStorage,
19
- ConfigStores,
20
- CortexContext,
21
- } from '@yeseh/cortex-core';
22
- import { testContext } from '@yeseh/cortex-core';
23
-
24
- // ============================================================================
25
- // 2.1 Result helpers
26
- // ============================================================================
27
-
28
- /**
29
- * Constructs a minimal ok-shaped result for use in mock return values.
30
- *
31
- * @param value - The success value
32
- * @returns A plain object compatible with ok result checks
33
- *
34
- * @example
35
- * ```typescript
36
- * const result = okResult('hello');
37
- * expect(result.ok()).toBe(true);
38
- * expect(result.value).toBe('hello');
39
- * ```
40
- */
41
- export const okResult = <T>(value: T): { ok: () => true; value: T } => ({
42
- ok: () => true as const,
43
- value,
44
- });
45
-
46
- /**
47
- * Constructs a minimal err-shaped result for use in mock return values.
48
- *
49
- * @param error - The error value
50
- * @returns A plain object compatible with err result checks
51
- *
52
- * @example
53
- * ```typescript
54
- * const result = errResult({ code: 'NOT_FOUND', message: 'not found' });
55
- * expect(result.ok()).toBe(false);
56
- * ```
57
- */
58
- export const errResult = <E>(error: E): { ok: () => false; error: E } => ({
59
- ok: () => false as const,
60
- error,
61
- });
62
-
63
- // ============================================================================
64
- // 2.2 Stream and output helpers
65
- // ============================================================================
66
-
67
- /**
68
- * Creates a writable PassThrough stream and a helper to capture written text.
69
- *
70
- * @returns An object containing the stream and a `getOutput` function
71
- *
72
- * @example
73
- * ```typescript
74
- * const { stream, getOutput } = createWritableCapture();
75
- * stream.write('hello');
76
- * expect(getOutput()).toBe('hello');
77
- * ```
78
- */
79
- export function createWritableCapture(): { stream: PassThrough; getOutput: () => string } {
80
- const stream = new PassThrough();
81
- let output = '';
82
- stream.on('data', (chunk: Buffer | string) => {
83
- output += chunk.toString();
84
- });
85
- return { stream, getOutput: () => output };
86
- }
87
-
88
- /**
89
- * Creates a readable PassThrough stream pre-loaded with text.
90
- *
91
- * @param text - The text to pre-load into the stream
92
- * @returns A PassThrough stream with the given text already written
93
- *
94
- * @example
95
- * ```typescript
96
- * const stream = createReadableFromText('user input\n');
97
- * ```
98
- */
99
- export function createReadableFromText(text: string): PassThrough {
100
- const stream = new PassThrough();
101
- stream.end(text);
102
- return stream;
103
- }
104
-
105
- // ============================================================================
106
- // 2.3 Clock helpers
107
- // ============================================================================
108
-
109
- /** ISO 8601 string for the fixed test clock date */
110
- export const FIXED_NOW_ISO = '2025-06-01T12:00:00.000Z';
111
-
112
- /** Fixed Date instance for use in tests */
113
- export const FIXED_NOW = new Date(FIXED_NOW_ISO);
114
-
115
- /**
116
- * Returns a `now` function that always returns the given ISO date.
117
- *
118
- * @param iso - ISO 8601 string (defaults to {@link FIXED_NOW_ISO})
119
- * @returns A zero-argument function returning the fixed Date
120
- *
121
- * @example
122
- * ```typescript
123
- * const ctx = createMockContext({ now: fixedNow('2025-01-01T00:00:00.000Z') });
124
- * ```
125
- */
126
- export const fixedNow =
127
- (iso: string = FIXED_NOW_ISO): (() => Date) =>
128
- () =>
129
- new Date(iso);
130
-
131
- // ============================================================================
132
- // 2.4 CLI error assertion helpers
133
- // ============================================================================
134
-
135
- /**
136
- * Asserts that the given function throws an `InvalidArgumentError`.
137
- *
138
- * @param fn - Sync or async function expected to throw
139
- * @param messagePart - Optional substring the error message must contain
140
- *
141
- * @example
142
- * ```typescript
143
- * await expectInvalidArgumentError(
144
- * () => parseMemoryPath(''),
145
- * 'must not be empty',
146
- * );
147
- * ```
148
- */
149
- export async function expectInvalidArgumentError(
150
- fn: () => Promise<unknown> | unknown,
151
- messagePart?: string
152
- ): Promise<void> {
153
- let threw = false;
154
- try {
155
- await fn();
156
- } catch (e) {
157
- threw = true;
158
- expect(e).toBeInstanceOf(InvalidArgumentError);
159
- if (messagePart) {
160
- expect((e as Error).message).toContain(messagePart);
161
- }
162
- }
163
- if (!threw) {
164
- throw new Error('Expected InvalidArgumentError to be thrown but it was not');
165
- }
166
- }
167
-
168
- /**
169
- * Asserts that the given function throws a `CommanderError`.
170
- *
171
- * @param fn - Sync or async function expected to throw
172
- * @param codePart - Optional substring the error's `.code` must contain
173
- * @param messagePart - Optional substring the error message must contain
174
- *
175
- * @example
176
- * ```typescript
177
- * await expectCommanderError(
178
- * () => handleAdd(ctx, args, 'missing-store'),
179
- * 'commander.storeNotFound',
180
- * );
181
- * ```
182
- */
183
- export async function expectCommanderError(
184
- fn: () => Promise<unknown> | unknown,
185
- codePart?: string,
186
- messagePart?: string
187
- ): Promise<void> {
188
- let threw = false;
189
- try {
190
- await fn();
191
- } catch (e) {
192
- threw = true;
193
- expect(e).toBeInstanceOf(CommanderError);
194
- if (codePart) {
195
- expect((e as CommanderError).code).toContain(codePart);
196
- }
197
- if (messagePart) {
198
- expect((e as Error).message).toContain(messagePart);
199
- }
200
- }
201
- if (!threw) {
202
- throw new Error('Expected CommanderError to be thrown but it was not');
203
- }
204
- }
205
-
206
- // ============================================================================
207
- // 2.5 Mock adapter factories
208
- // ============================================================================
209
-
210
- /**
211
- * Creates a minimal mock MemoryStorage with sensible defaults.
212
- *
213
- * @param overrides - Partial overrides for individual methods
214
- * @returns A fully-typed MemoryStorage mock
215
- *
216
- * @example
217
- * ```typescript
218
- * const memories = createMockMemoryStorage({
219
- * load: async () => ok(sampleMemory),
220
- * });
221
- * ```
222
- */
223
- export function createMockMemoryStorage(overrides: Partial<MemoryStorage> = {}): MemoryStorage {
224
- return {
225
- load: async () => ({
226
- ok: () => false as const,
227
- error: { code: 'MEMORY_NOT_FOUND', message: 'not found' },
228
- }),
229
- save: async () => ({ ok: () => true as const, value: undefined }),
230
- add: async () => ({ ok: () => true as const, value: undefined }),
231
- remove: async () => ({ ok: () => true as const, value: undefined }),
232
- move: async () => ({ ok: () => true as const, value: undefined }),
233
- ...overrides,
234
- } as unknown as MemoryStorage;
235
- }
236
-
237
- /**
238
- * Creates a minimal mock IndexStorage with sensible defaults.
239
- *
240
- * @param overrides - Partial overrides for individual methods
241
- * @returns A fully-typed IndexStorage mock
242
- *
243
- * @example
244
- * ```typescript
245
- * const indexes = createMockIndexStorage({
246
- * load: async () => ok({ memories: [], subcategories: [] }),
247
- * });
248
- * ```
249
- */
250
- export function createMockIndexStorage(overrides: Partial<IndexStorage> = {}): IndexStorage {
251
- return {
252
- load: async () => ({ ok: () => true as const, value: { memories: [], subcategories: [] } }),
253
- write: async () => ({ ok: () => true as const, value: undefined }),
254
- reindex: async () => ({ ok: () => true as const, value: { warnings: [] } }),
255
- updateAfterMemoryWrite: async () => ({ ok: () => true as const, value: undefined }),
256
- ...overrides,
257
- } as unknown as IndexStorage;
258
- }
259
-
260
- /**
261
- * Creates a minimal mock CategoryStorage with sensible defaults.
262
- *
263
- * @param overrides - Partial overrides for individual methods
264
- * @returns A fully-typed CategoryStorage mock
265
- *
266
- * @example
267
- * ```typescript
268
- * const categories = createMockCategoryStorage({
269
- * exists: async () => ok(true),
270
- * });
271
- * ```
272
- */
273
- export function createMockCategoryStorage(
274
- overrides: Partial<CategoryStorage> = {}
275
- ): CategoryStorage {
276
- return {
277
- exists: async () => ({ ok: () => true as const, value: false }),
278
- ensure: async () => ({ ok: () => true as const, value: undefined }),
279
- delete: async () => ({ ok: () => true as const, value: undefined }),
280
- setDescription: async () => ({ ok: () => true as const, value: undefined }),
281
- ...overrides,
282
- } as unknown as CategoryStorage;
283
- }
284
-
285
- /**
286
- * Creates a minimal mock StorageAdapter composed of mock sub-adapters.
287
- *
288
- * @param overrides - Partial overrides for individual sub-adapters
289
- * @returns A fully-typed StorageAdapter mock
290
- *
291
- * @example
292
- * ```typescript
293
- * const adapter = createMockStorageAdapter({
294
- * memories: createMockMemoryStorage({ load: async () => ok(null) }),
295
- * });
296
- * ```
297
- */
298
- export function createMockStorageAdapter(overrides: Partial<StorageAdapter> = {}): StorageAdapter {
299
- return {
300
- memories: createMockMemoryStorage(),
301
- indexes: createMockIndexStorage(),
302
- categories: createMockCategoryStorage(),
303
- config: {
304
- path: '/tmp/cortex-test-config.yaml',
305
- data: null,
306
- stores: null,
307
- settings: null,
308
- initializeConfig: async () => ({ ok: () => true as const, value: undefined }),
309
- getSettings: async () => ({ ok: () => true as const, value: {} }),
310
- getStores: async () => ({ ok: () => true as const, value: {} }),
311
- getStore: async () => ({ ok: () => true as const, value: null }),
312
- saveStore: async () => ({ ok: () => true as const, value: undefined }),
313
- },
314
- ...overrides,
315
- } as unknown as StorageAdapter;
316
- }
317
-
318
- /** Options for {@link createMockContext} */
319
- export interface MockContextOptions {
320
- /** Override the storage adapter (defaults to {@link createMockStorageAdapter}) */
321
- adapter?: StorageAdapter;
322
- /** Override the store configuration (defaults to a single in-memory mock store) */
323
- stores?: ConfigStores;
324
- /** Override the clock (defaults to {@link fixedNow}) */
325
- now?: () => Date;
326
- /** Override the current working directory */
327
- cwd?: string;
328
- }
329
-
330
- /** Result of {@link createMockContext} */
331
- export interface MockContextResult {
332
- ctx: CortexContext;
333
- stdout: PassThrough;
334
- stdin: PassThrough;
335
- }
336
-
337
- /**
338
- * Creates a {@link CortexContext} backed by a real Cortex.init() with a mock adapter.
339
- *
340
- * @param overrides - Optional overrides for adapter, stores, clock, and cwd
341
- * @returns An object with the context and the raw stdout/stdin PassThrough streams
342
- *
343
- * @example
344
- * ```typescript
345
- * const { ctx, stdout } = createMockContext();
346
- * await handleAdd(ctx, args, 'global', {});
347
- * expect(captureOutput(stdout)).toContain('Memory added');
348
- * ```
349
- */
350
- export function createMockContext(overrides?: MockContextOptions): MockContextResult {
351
- const stdout = new PassThrough();
352
- const stdin = new PassThrough();
353
- const adapter = overrides?.adapter ?? createMockStorageAdapter();
354
- const stores: ConfigStores = overrides?.stores ?? {
355
- global: {
356
- kind: 'filesystem',
357
- categoryMode: 'free',
358
- categories: {},
359
- properties: { path: '/mock/store' },
360
- },
361
- };
362
-
363
- const ctx = testContext({
364
- adapter,
365
- storePath: '/mock/store',
366
- stdout,
367
- stdin,
368
- stores,
369
- now: overrides?.now ?? fixedNow(),
370
- });
371
-
372
- if (overrides?.cwd) {
373
- (ctx as unknown as Record<string, unknown>).cwd = overrides.cwd;
374
- }
375
-
376
- return { ctx, stdout, stdin };
377
- }
378
-
379
- // ============================================================================
380
- // 2.6 Output capture helper
381
- // ============================================================================
382
-
383
- /**
384
- * Reads all buffered output from a PassThrough stream synchronously.
385
- *
386
- * Drains already-buffered data without consuming future writes.
387
- * Useful for asserting output after a handler has finished writing.
388
- *
389
- * @param stream - The PassThrough stream to drain
390
- * @returns The concatenated string of all buffered chunks
391
- *
392
- * @example
393
- * ```typescript
394
- * const { ctx, stdout } = createMockContext();
395
- * await handleList(ctx, {}, 'global', {});
396
- * expect(captureOutput(stdout)).toContain('No memories found');
397
- * ```
398
- */
399
- export function captureOutput(stream: PassThrough): string {
400
- const chunks: Buffer[] = [];
401
- let chunk: Buffer | null;
402
- while ((chunk = stream.read()) !== null) {
403
- chunks.push(chunk);
404
- }
405
- return Buffer.concat(chunks).toString();
406
- }
407
-
408
- // ============================================================================
409
- // Smoke test — validates all helpers are exported and callable
410
- // ============================================================================
411
-
412
- describe('test-helpers', () => {
413
- it('should export all helpers', () => {
414
- expect(typeof okResult).toBe('function');
415
- expect(typeof errResult).toBe('function');
416
- expect(typeof createWritableCapture).toBe('function');
417
- expect(typeof createReadableFromText).toBe('function');
418
- expect(typeof FIXED_NOW_ISO).toBe('string');
419
- expect(FIXED_NOW).toBeInstanceOf(Date);
420
- expect(typeof fixedNow).toBe('function');
421
- expect(typeof expectInvalidArgumentError).toBe('function');
422
- expect(typeof expectCommanderError).toBe('function');
423
- expect(typeof createMockMemoryStorage).toBe('function');
424
- expect(typeof createMockIndexStorage).toBe('function');
425
- expect(typeof createMockCategoryStorage).toBe('function');
426
- expect(typeof createMockStorageAdapter).toBe('function');
427
- expect(typeof createMockContext).toBe('function');
428
- expect(typeof captureOutput).toBe('function');
429
- });
430
- });