@yeseh/cortex-cli 0.6.7 → 0.6.9
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/dist/program.js +1538 -5
- package/dist/program.js.map +32 -3
- package/dist/run.d.ts +0 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +3 -4
- package/dist/run.js.map +3 -3
- package/package.json +4 -6
- package/dist/chunk-tgrm2cc9.js +0 -1543
- package/dist/chunk-tgrm2cc9.js.map +0 -38
- package/src/category/commands/create.spec.ts +0 -139
- package/src/category/commands/create.ts +0 -119
- package/src/category/index.ts +0 -24
- package/src/commands/init.spec.ts +0 -203
- package/src/commands/init.ts +0 -301
- package/src/context.spec.ts +0 -60
- package/src/context.ts +0 -170
- package/src/errors.spec.ts +0 -264
- package/src/errors.ts +0 -105
- package/src/memory/commands/add.spec.ts +0 -169
- package/src/memory/commands/add.ts +0 -158
- package/src/memory/commands/definitions.spec.ts +0 -80
- package/src/memory/commands/list.spec.ts +0 -123
- package/src/memory/commands/list.ts +0 -269
- package/src/memory/commands/move.spec.ts +0 -85
- package/src/memory/commands/move.ts +0 -119
- package/src/memory/commands/remove.spec.ts +0 -79
- package/src/memory/commands/remove.ts +0 -108
- package/src/memory/commands/show.spec.ts +0 -71
- package/src/memory/commands/show.ts +0 -165
- package/src/memory/commands/test-helpers.spec.ts +0 -127
- package/src/memory/commands/update.spec.ts +0 -86
- package/src/memory/commands/update.ts +0 -230
- package/src/memory/index.spec.ts +0 -59
- package/src/memory/index.ts +0 -44
- package/src/memory/parsing.spec.ts +0 -105
- package/src/memory/parsing.ts +0 -22
- package/src/observability.spec.ts +0 -126
- package/src/observability.ts +0 -82
- package/src/output.spec.ts +0 -835
- package/src/output.ts +0 -119
- package/src/program.spec.ts +0 -46
- package/src/program.ts +0 -75
- package/src/run.spec.ts +0 -31
- package/src/run.ts +0 -9
- package/src/store/commands/add.spec.ts +0 -131
- package/src/store/commands/add.ts +0 -231
- package/src/store/commands/init.spec.ts +0 -220
- package/src/store/commands/init.ts +0 -272
- package/src/store/commands/list.spec.ts +0 -175
- package/src/store/commands/list.ts +0 -102
- package/src/store/commands/prune.spec.ts +0 -120
- package/src/store/commands/prune.ts +0 -152
- package/src/store/commands/reindexs.spec.ts +0 -94
- package/src/store/commands/reindexs.ts +0 -97
- package/src/store/commands/remove.spec.ts +0 -97
- package/src/store/commands/remove.ts +0 -189
- package/src/store/index.spec.ts +0 -60
- package/src/store/index.ts +0 -49
- package/src/store/utils/resolve-store-name.spec.ts +0 -62
- package/src/store/utils/resolve-store-name.ts +0 -79
- package/src/test-helpers.spec.ts +0 -430
- package/src/tests/cli.integration.spec.ts +0 -1306
- package/src/toon.spec.ts +0 -183
- package/src/toon.ts +0 -462
- package/src/utils/git.spec.ts +0 -95
- package/src/utils/git.ts +0 -51
- package/src/utils/input.spec.ts +0 -326
- package/src/utils/input.ts +0 -150
- package/src/utils/paths.spec.ts +0 -235
- package/src/utils/paths.ts +0 -75
- package/src/utils/prompts.spec.ts +0 -23
- package/src/utils/prompts.ts +0 -88
- package/src/utils/resolve-default-store.spec.ts +0 -135
- package/src/utils/resolve-default-store.ts +0 -74
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the handleAdd command handler.
|
|
3
|
-
*
|
|
4
|
-
* @module cli/memory/commands/add.spec
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { describe, it, expect, afterEach, beforeEach } from 'bun:test';
|
|
8
|
-
import { CommanderError, InvalidArgumentError } from '@commander-js/extra-typings';
|
|
9
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
10
|
-
import { tmpdir } from 'node:os';
|
|
11
|
-
import { join } from 'node:path';
|
|
12
|
-
import { PassThrough } from 'node:stream';
|
|
13
|
-
import {
|
|
14
|
-
ok,
|
|
15
|
-
type AdapterFactory,
|
|
16
|
-
} from '@yeseh/cortex-core';
|
|
17
|
-
import { handleAdd } from './add.ts';
|
|
18
|
-
import {
|
|
19
|
-
createCaptureStream,
|
|
20
|
-
createMemoryCommandContext,
|
|
21
|
-
createMockMemoryCommandAdapter,
|
|
22
|
-
} from './test-helpers.spec.ts';
|
|
23
|
-
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
// Local helpers
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
|
|
28
|
-
// ---------------------------------------------------------------------------
|
|
29
|
-
// Tests
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
describe('handleAdd', () => {
|
|
33
|
-
let tempDir: string;
|
|
34
|
-
|
|
35
|
-
beforeEach(async () => {
|
|
36
|
-
tempDir = await mkdtemp(join(tmpdir(), 'cortex-add-'));
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
afterEach(async () => {
|
|
40
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should create a memory and write success message to stdout', async () => {
|
|
44
|
-
const capture = createCaptureStream();
|
|
45
|
-
const ctx = createMemoryCommandContext({
|
|
46
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
47
|
-
storePath: tempDir,
|
|
48
|
-
stdout: capture.stream,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
await handleAdd(ctx, undefined, 'project/notes', { content: 'Hello world' });
|
|
52
|
-
|
|
53
|
-
const out = capture.getOutput();
|
|
54
|
-
expect(out).toContain('Added memory');
|
|
55
|
-
expect(out).toContain('project/notes');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should pass tags from options', async () => {
|
|
59
|
-
const capture = createCaptureStream();
|
|
60
|
-
const ctx = createMemoryCommandContext({
|
|
61
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
62
|
-
storePath: tempDir,
|
|
63
|
-
stdout: capture.stream,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
await handleAdd(ctx, undefined, 'project/tagged', {
|
|
67
|
-
content: 'Tagged memory',
|
|
68
|
-
tags: ['foo', 'bar'],
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
expect(capture.getOutput()).toContain('Added memory');
|
|
72
|
-
expect(capture.getOutput()).toContain('project/tagged');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should pass expiresAt from options', async () => {
|
|
76
|
-
const capture = createCaptureStream();
|
|
77
|
-
const ctx = createMemoryCommandContext({
|
|
78
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
79
|
-
storePath: tempDir,
|
|
80
|
-
stdout: capture.stream,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
await handleAdd(ctx, undefined, 'project/expiring', {
|
|
84
|
-
content: 'Expires soon',
|
|
85
|
-
expiresAt: '2030-12-31T00:00:00Z',
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
expect(capture.getOutput()).toContain('Added memory');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should pass citations from options', async () => {
|
|
92
|
-
const capture = createCaptureStream();
|
|
93
|
-
const ctx = createMemoryCommandContext({
|
|
94
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
95
|
-
storePath: tempDir,
|
|
96
|
-
stdout: capture.stream,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
await handleAdd(ctx, undefined, 'project/cited', {
|
|
100
|
-
content: 'Cited memory',
|
|
101
|
-
citations: ['https://example.com/source'],
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
expect(capture.getOutput()).toContain('Added memory');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should throw CommanderError when store not found', async () => {
|
|
108
|
-
const failingFactory = (() => undefined) as unknown as AdapterFactory;
|
|
109
|
-
|
|
110
|
-
const stdin = new PassThrough();
|
|
111
|
-
const ctx = createMemoryCommandContext({
|
|
112
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
113
|
-
storePath: tempDir,
|
|
114
|
-
stdin,
|
|
115
|
-
adapterFactory: failingFactory,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
await expect(
|
|
119
|
-
handleAdd(ctx, 'nonexistent', 'project/notes', { content: 'test' })
|
|
120
|
-
).rejects.toThrow(CommanderError);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('should throw InvalidArgumentError for MISSING_CONTENT when no content provided', async () => {
|
|
124
|
-
const stdin = new PassThrough();
|
|
125
|
-
stdin.end(); // EOF with no data → empty content → MISSING_CONTENT
|
|
126
|
-
const ctx = createMemoryCommandContext({
|
|
127
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
128
|
-
storePath: tempDir,
|
|
129
|
-
stdin,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
await expect(handleAdd(ctx, undefined, 'project/notes', {})).rejects.toThrow(
|
|
133
|
-
InvalidArgumentError
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should throw CommanderError when memory create fails due to missing category', async () => {
|
|
138
|
-
const ctx = createMemoryCommandContext({
|
|
139
|
-
adapter: createMockMemoryCommandAdapter({
|
|
140
|
-
categories: {
|
|
141
|
-
exists: async () => ok(false), // category absent → CATEGORY_NOT_FOUND
|
|
142
|
-
},
|
|
143
|
-
}),
|
|
144
|
-
storePath: tempDir,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
await expect(
|
|
148
|
-
handleAdd(ctx, undefined, 'project/notes', { content: 'test' })
|
|
149
|
-
).rejects.toThrow(CommanderError);
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
it('should use stdin when no content option is provided', async () => {
|
|
153
|
-
const stdin = new PassThrough();
|
|
154
|
-
stdin.end('Content from stdin');
|
|
155
|
-
const capture = createCaptureStream();
|
|
156
|
-
const ctx = createMemoryCommandContext({
|
|
157
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
158
|
-
storePath: tempDir,
|
|
159
|
-
stdin,
|
|
160
|
-
stdout: capture.stream,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
await handleAdd(ctx, undefined, 'project/stdin', {});
|
|
164
|
-
|
|
165
|
-
const out = capture.getOutput();
|
|
166
|
-
expect(out).toContain('Added memory');
|
|
167
|
-
expect(out).toContain('stdin');
|
|
168
|
-
});
|
|
169
|
-
});
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memory add command implementation using Commander.js.
|
|
3
|
-
*
|
|
4
|
-
* Creates a new memory at the specified path with content from inline text,
|
|
5
|
-
* a file, or stdin.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```bash
|
|
9
|
-
* # Add memory with inline content
|
|
10
|
-
* cortex memory add project/tech-stack --content "Using TypeScript and Node.js"
|
|
11
|
-
*
|
|
12
|
-
* # Add memory from a file
|
|
13
|
-
* cortex memory add project/notes --file ./notes.md
|
|
14
|
-
*
|
|
15
|
-
* # Add memory from stdin
|
|
16
|
-
* echo "My notes" | cortex memory add project/notes
|
|
17
|
-
*
|
|
18
|
-
* # Add memory with tags and expiration
|
|
19
|
-
* cortex memory add project/temp --content "Temporary note" \
|
|
20
|
-
* --tags "temp,cleanup" --expires-at "2025-12-31T00:00:00Z"
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
import { Command } from '@commander-js/extra-typings';
|
|
25
|
-
import { throwCliError } from '../../errors.ts';
|
|
26
|
-
import { type CortexContext } from '@yeseh/cortex-core';
|
|
27
|
-
import { resolveInput as resolveCliContent } from '../../utils/input.ts';
|
|
28
|
-
import { parseExpiresAt, parseTags } from '../parsing.ts';
|
|
29
|
-
import { createCliCommandContext } from '../../context.ts';
|
|
30
|
-
import { serializeOutput, type OutputFormat } from '../../output.ts';
|
|
31
|
-
import { resolveDefaultStore } from '../../utils/resolve-default-store.ts';
|
|
32
|
-
|
|
33
|
-
/** Options parsed by Commander for the add command */
|
|
34
|
-
export interface AddCommandOptions {
|
|
35
|
-
content?: string;
|
|
36
|
-
file?: string;
|
|
37
|
-
tags?: string[];
|
|
38
|
-
expiresAt?: string;
|
|
39
|
-
citations?: string[];
|
|
40
|
-
format?: string;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Handler for the memory add command.
|
|
44
|
-
* Exported for direct testing without Commander parsing.
|
|
45
|
-
*
|
|
46
|
-
* @param path - Memory path (e.g., "project/tech-stack")
|
|
47
|
-
* @param options - Command options from Commander
|
|
48
|
-
* @param storeName - Optional store name from parent command
|
|
49
|
-
* @param deps - Injectable dependencies for testing
|
|
50
|
-
*/
|
|
51
|
-
export async function handleAdd(
|
|
52
|
-
ctx: CortexContext,
|
|
53
|
-
storeName: string | undefined,
|
|
54
|
-
path: string,
|
|
55
|
-
options: AddCommandOptions
|
|
56
|
-
): Promise<void> {
|
|
57
|
-
const content = await resolveCliContent({
|
|
58
|
-
content: options.content,
|
|
59
|
-
filePath: options.file,
|
|
60
|
-
stream: ctx.stdin,
|
|
61
|
-
// `memory add` accepts stdin by default (when piped).
|
|
62
|
-
stdinRequested: options.content === undefined && options.file === undefined,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (!content.ok()) {
|
|
66
|
-
throwCliError(content.error);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!content.value.content) {
|
|
70
|
-
throwCliError({
|
|
71
|
-
code: 'MISSING_CONTENT',
|
|
72
|
-
message: 'Memory content is required via --content, --file, or stdin.',
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const { content: memoryContent, source } = content.value;
|
|
77
|
-
const tags = parseTags(options.tags);
|
|
78
|
-
const expiresAt = parseExpiresAt(options.expiresAt);
|
|
79
|
-
const citations = options.citations ?? [];
|
|
80
|
-
|
|
81
|
-
const storeResult = ctx.cortex.getStore(resolveDefaultStore(ctx, storeName));
|
|
82
|
-
if (!storeResult.ok()) {
|
|
83
|
-
throwCliError(storeResult.error);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const store = storeResult.value;
|
|
87
|
-
const timestamp = ctx.now() ?? new Date();
|
|
88
|
-
const memoryClient = store.getMemory(path);
|
|
89
|
-
const memoryResult = await memoryClient.create({
|
|
90
|
-
content: memoryContent!,
|
|
91
|
-
metadata: {
|
|
92
|
-
tags,
|
|
93
|
-
source,
|
|
94
|
-
createdAt: timestamp,
|
|
95
|
-
updatedAt: timestamp,
|
|
96
|
-
expiresAt,
|
|
97
|
-
citations,
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
if (!memoryResult.ok()) {
|
|
102
|
-
throwCliError(memoryResult.error);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const memory = memoryResult.value;
|
|
106
|
-
const out = ctx.stdout ?? process.stdout;
|
|
107
|
-
|
|
108
|
-
const rawFormat = options.format;
|
|
109
|
-
if (!rawFormat) {
|
|
110
|
-
out.write(`Added memory ${memory.path} (${source}).\n`);
|
|
111
|
-
} else {
|
|
112
|
-
const format = rawFormat as OutputFormat;
|
|
113
|
-
const serialized = serializeOutput(
|
|
114
|
-
{
|
|
115
|
-
kind: 'memory',
|
|
116
|
-
value: {
|
|
117
|
-
path: memory.path.toString(),
|
|
118
|
-
metadata: memory.metadata,
|
|
119
|
-
content: memory.content,
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
format
|
|
123
|
-
);
|
|
124
|
-
if (!serialized.ok()) {
|
|
125
|
-
throwCliError({ code: 'SERIALIZE_FAILED', message: serialized.error.message });
|
|
126
|
-
}
|
|
127
|
-
out.write(serialized.value + '\n');
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* The `memory add` subcommand.
|
|
133
|
-
*
|
|
134
|
-
* Creates a new memory at the specified path. Content can be provided via:
|
|
135
|
-
* - `--content` flag for inline text
|
|
136
|
-
* - `--file` flag to read from a file
|
|
137
|
-
* - stdin when piped
|
|
138
|
-
*
|
|
139
|
-
* The `--store` option is inherited from the parent `memory` command.
|
|
140
|
-
*/
|
|
141
|
-
export const addCommand = new Command('add')
|
|
142
|
-
.description('Create a new memory')
|
|
143
|
-
.argument('<path>', 'Memory path (e.g., project/tech-stack)')
|
|
144
|
-
.option('-c, --content <text>', 'Memory content as inline text')
|
|
145
|
-
.option('-f, --file <filepath>', 'Read content from a file')
|
|
146
|
-
.option('-t, --tags <value...>', 'Tags (can be repeated or comma-separated)')
|
|
147
|
-
.option('-e, --expires-at <date>', 'Expiration date (ISO 8601)')
|
|
148
|
-
.option('--citation <value...>', 'Citation references (file paths or URLs)')
|
|
149
|
-
.option('-o, --format <format>', 'Output format (yaml, json, toon)')
|
|
150
|
-
.action(async (path, options, command) => {
|
|
151
|
-
const parentOpts = command.parent?.opts() as { store?: string } | undefined;
|
|
152
|
-
const context = await createCliCommandContext();
|
|
153
|
-
if (!context.ok()) {
|
|
154
|
-
throwCliError(context.error);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
await handleAdd(context.value, parentOpts?.store, path, options);
|
|
158
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for memory command definitions.
|
|
3
|
-
*
|
|
4
|
-
* Verifies that memory subcommands expose the expected names,
|
|
5
|
-
* arguments, and options.
|
|
6
|
-
*
|
|
7
|
-
* @module cli/memory/commands/definitions.spec
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { describe, expect, it } from 'bun:test';
|
|
11
|
-
|
|
12
|
-
import { listCommand } from './list.ts';
|
|
13
|
-
import { moveCommand } from './move.ts';
|
|
14
|
-
import { removeCommand } from './remove.ts';
|
|
15
|
-
import { showCommand } from './show.ts';
|
|
16
|
-
import { updateCommand } from './update.ts';
|
|
17
|
-
|
|
18
|
-
const getLongOptions = (command: { options: ReadonlyArray<{ long?: string }> }): string[] =>
|
|
19
|
-
command.options.map((option) => option.long ?? '').filter(Boolean);
|
|
20
|
-
|
|
21
|
-
describe('memory command definitions', () => {
|
|
22
|
-
describe('listCommand', () => {
|
|
23
|
-
it('should expose expected command name and usage', () => {
|
|
24
|
-
expect(listCommand.name()).toBe('list');
|
|
25
|
-
expect(listCommand.usage()).toContain('[category]');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('should register expected options', () => {
|
|
29
|
-
const options = getLongOptions(listCommand);
|
|
30
|
-
expect(options).toContain('--store');
|
|
31
|
-
expect(options).toContain('--include-expired');
|
|
32
|
-
expect(options).toContain('--format');
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
describe('moveCommand', () => {
|
|
37
|
-
it('should expose expected command name and usage', () => {
|
|
38
|
-
expect(moveCommand.name()).toBe('move');
|
|
39
|
-
expect(moveCommand.usage()).toContain('<from>');
|
|
40
|
-
expect(moveCommand.usage()).toContain('<to>');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('removeCommand', () => {
|
|
45
|
-
it('should expose expected command name and usage', () => {
|
|
46
|
-
expect(removeCommand.name()).toBe('remove');
|
|
47
|
-
expect(removeCommand.usage()).toContain('<path>');
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
describe('showCommand', () => {
|
|
52
|
-
it('should expose expected command name and usage', () => {
|
|
53
|
-
expect(showCommand.name()).toBe('show');
|
|
54
|
-
expect(showCommand.usage()).toContain('<path>');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should register expected options', () => {
|
|
58
|
-
const options = getLongOptions(showCommand);
|
|
59
|
-
expect(options).toContain('--include-expired');
|
|
60
|
-
expect(options).toContain('--format');
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
describe('updateCommand', () => {
|
|
65
|
-
it('should expose expected command name and usage', () => {
|
|
66
|
-
expect(updateCommand.name()).toBe('update');
|
|
67
|
-
expect(updateCommand.usage()).toContain('<path>');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should register expected options', () => {
|
|
71
|
-
const options = getLongOptions(updateCommand);
|
|
72
|
-
expect(options).toContain('--content');
|
|
73
|
-
expect(options).toContain('--file');
|
|
74
|
-
expect(options).toContain('--tags');
|
|
75
|
-
expect(options).toContain('--expires-at');
|
|
76
|
-
expect(options).toContain('--no-expires-at');
|
|
77
|
-
expect(options).toContain('--citation');
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
});
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
|
2
|
-
import { CommanderError, InvalidArgumentError } from '@commander-js/extra-typings';
|
|
3
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
4
|
-
import { tmpdir } from 'node:os';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
import {
|
|
7
|
-
CategoryPath,
|
|
8
|
-
MemoryPath,
|
|
9
|
-
ok,
|
|
10
|
-
type AdapterFactory,
|
|
11
|
-
type Category,
|
|
12
|
-
} from '@yeseh/cortex-core';
|
|
13
|
-
|
|
14
|
-
import { handleList } from './list.ts';
|
|
15
|
-
import {
|
|
16
|
-
createCaptureStream,
|
|
17
|
-
createMemoryCommandContext,
|
|
18
|
-
createMemoryFixture,
|
|
19
|
-
createMockMemoryCommandAdapter,
|
|
20
|
-
} from './test-helpers.spec.ts';
|
|
21
|
-
|
|
22
|
-
describe('handleList', () => {
|
|
23
|
-
let tempDir: string;
|
|
24
|
-
|
|
25
|
-
beforeEach(async () => {
|
|
26
|
-
tempDir = await mkdtemp(join(tmpdir(), 'cortex-cli-memory-list-'));
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
afterEach(async () => {
|
|
30
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should throw InvalidArgumentError for invalid category paths', async () => {
|
|
34
|
-
const ctx = createMemoryCommandContext({
|
|
35
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
36
|
-
storePath: tempDir,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
await expect(handleList(ctx, undefined, '/ /', { format: 'yaml' })).rejects.toThrow(
|
|
40
|
-
InvalidArgumentError,
|
|
41
|
-
);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('should throw CommanderError when the adapter factory returns nothing', async () => {
|
|
45
|
-
const nullFactory = (() => undefined) as unknown as AdapterFactory;
|
|
46
|
-
const ctx = createMemoryCommandContext({
|
|
47
|
-
adapter: createMockMemoryCommandAdapter(),
|
|
48
|
-
storePath: tempDir,
|
|
49
|
-
adapterFactory: nullFactory,
|
|
50
|
-
stores: {
|
|
51
|
-
global: {
|
|
52
|
-
kind: 'filesystem',
|
|
53
|
-
properties: { path: tempDir },
|
|
54
|
-
categories: {},
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
await expect(handleList(ctx, 'missing-store', undefined, {})).rejects.toThrow(
|
|
60
|
-
CommanderError,
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should write serialized list output', async () => {
|
|
65
|
-
const memoryPath = MemoryPath.fromString('project/one');
|
|
66
|
-
if (!memoryPath.ok()) {
|
|
67
|
-
throw new Error('Test setup failed to create memory path.');
|
|
68
|
-
}
|
|
69
|
-
const memory = createMemoryFixture('project/one');
|
|
70
|
-
|
|
71
|
-
const rootCategory: Category = {
|
|
72
|
-
memories: [],
|
|
73
|
-
subcategories: [
|
|
74
|
-
{
|
|
75
|
-
path: CategoryPath.fromString('project').unwrap(),
|
|
76
|
-
memoryCount: 1,
|
|
77
|
-
description: 'Project memories',
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const projectCategory: Category = {
|
|
83
|
-
memories: [
|
|
84
|
-
{
|
|
85
|
-
path: memoryPath.value,
|
|
86
|
-
tokenEstimate: 42,
|
|
87
|
-
},
|
|
88
|
-
],
|
|
89
|
-
subcategories: [],
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const adapter = createMockMemoryCommandAdapter({
|
|
93
|
-
indexes: {
|
|
94
|
-
load: async (path: CategoryPath) => {
|
|
95
|
-
if (path.isRoot) {
|
|
96
|
-
return ok(rootCategory);
|
|
97
|
-
}
|
|
98
|
-
if (path.toString() === 'project') {
|
|
99
|
-
return ok(projectCategory);
|
|
100
|
-
}
|
|
101
|
-
return ok(null);
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
memories: {
|
|
105
|
-
load: async () => ok(memory),
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const capture = createCaptureStream();
|
|
110
|
-
const ctx = createMemoryCommandContext({
|
|
111
|
-
adapter,
|
|
112
|
-
storePath: tempDir,
|
|
113
|
-
stdout: capture.stream,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
await handleList(ctx, undefined, undefined, { format: 'json' });
|
|
117
|
-
|
|
118
|
-
const output = JSON.parse(capture.getOutput());
|
|
119
|
-
expect(output.memories).toHaveLength(1);
|
|
120
|
-
expect(output.memories[0].path).toBe('project/one');
|
|
121
|
-
expect(output.subcategories[0].path).toBe('project');
|
|
122
|
-
});
|
|
123
|
-
});
|