@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,189 +0,0 @@
1
- /**
2
- * Store remove command for unregistering a store.
3
- *
4
- * This command removes a store from the global registry. Note that this
5
- * only unregisters the store - it does not delete the actual data.
6
- *
7
- * @example
8
- * ```bash
9
- * # Remove a store from the registry
10
- * cortex store remove work
11
- * ```
12
- */
13
-
14
- import { Command } from '@commander-js/extra-typings';
15
- import { throwCliError } from '../../errors.ts';
16
- import { getDefaultConfigPath } from '../../utils/paths.ts';
17
- import { serializeOutput, type OutputStore, type OutputFormat } from '../../output.ts';
18
- import { Slug, parseConfig, type CortexContext } from '@yeseh/cortex-core';
19
- import { createCliCommandContext } from '../../context.ts';
20
-
21
- /**
22
- * Options for the remove command.
23
- */
24
- export interface RemoveCommandOptions {
25
- /** Output format (yaml, json, toon) */
26
- format?: string;
27
- }
28
-
29
- /**
30
- * Dependencies for the remove command handler.
31
- * Allows injection for testing.
32
- */
33
- export interface RemoveHandlerDeps {
34
- /** Output stream for writing results (defaults to process.stdout) */
35
- stdout?: NodeJS.WritableStream;
36
- }
37
-
38
- /**
39
- * Validates store name input.
40
- *
41
- * @param name - The raw store name input
42
- * @returns The validated, trimmed store name
43
- * @throws {InvalidArgumentError} When the store name is empty or invalid
44
- */
45
- function validateStoreName(name: string): string {
46
- const slugResult = Slug.from(name);
47
- if (!slugResult.ok()) {
48
- throwCliError({
49
- code: 'INVALID_STORE_NAME',
50
- message: 'Store name must be a lowercase slug (letters, numbers, hyphens).',
51
- });
52
- }
53
-
54
- return slugResult.value.toString();
55
- }
56
-
57
- /**
58
- * Writes the serialized output to the output stream.
59
- *
60
- * @param output - The store output payload
61
- * @param format - The output format
62
- * @param stdout - The output stream
63
- */
64
- function writeOutput(
65
- output: OutputStore,
66
- format: OutputFormat,
67
- stdout: NodeJS.WritableStream,
68
- ): void {
69
- const serialized = serializeOutput({ kind: 'store', value: output }, format);
70
- if (!serialized.ok()) {
71
- throwCliError({ code: 'SERIALIZE_FAILED', message: serialized.error.message });
72
- }
73
- stdout.write(serialized.value + '\n');
74
- }
75
-
76
- /**
77
- * Handles the remove command execution.
78
- *
79
- * This function:
80
- * 1. Validates the store name format
81
- * 2. Checks that the store exists in context
82
- * 3. Reads current config file
83
- * 4. Removes the store from the config and saves
84
- * 5. Outputs the result
85
- *
86
- * @param ctx - The Cortex context
87
- * @param name - The store name to unregister
88
- * @param options - Command options (format)
89
- * @param deps - Optional dependencies for testing
90
- * @throws {InvalidArgumentError} When the store name is invalid
91
- * @throws {CommanderError} When the store doesn't exist or config operations fail
92
- */
93
- export async function handleRemove(
94
- ctx: CortexContext,
95
- name: string,
96
- options: RemoveCommandOptions = {},
97
- deps: RemoveHandlerDeps = {},
98
- ): Promise<void> {
99
- const stdout = deps.stdout ?? ctx.stdout ?? process.stdout;
100
- const configPath = getDefaultConfigPath();
101
-
102
- // 1. Validate store name
103
- const trimmedName = validateStoreName(name);
104
-
105
- // 2. Check if store exists in context
106
- const existingStore = ctx.stores[trimmedName];
107
- if (!existingStore) {
108
- throwCliError({
109
- code: 'STORE_NOT_FOUND',
110
- message: `Store '${trimmedName}' is not registered.`,
111
- });
112
- }
113
-
114
- // Get the path from the existing store before removing
115
- const storePath = (existingStore.properties as { path: string }).path;
116
-
117
- // 3. Read current config file
118
- const configFile = Bun.file(configPath);
119
- if (!(await configFile.exists())) {
120
- throwCliError({
121
- code: 'CONFIG_NOT_FOUND',
122
- message: `Config file not found at ${configPath}. Cannot remove store.`,
123
- });
124
- }
125
- let configContents: string;
126
- try {
127
- configContents = await configFile.text();
128
- }
129
- catch {
130
- throwCliError({
131
- code: 'CONFIG_READ_FAILED',
132
- message: `Failed to read config at ${configPath}`,
133
- });
134
- }
135
-
136
- const configResult = parseConfig(configContents);
137
- if (!configResult.ok()) {
138
- throwCliError(configResult.error);
139
- }
140
-
141
- // 4. Remove store from config
142
- const { [trimmedName]: _removed, ...remainingStores } = configResult.value.stores ?? {};
143
-
144
- const updatedConfig = {
145
- ...configResult.value,
146
- stores: remainingStores,
147
- };
148
-
149
- // 5. Write updated config
150
- const serialized = Bun.YAML.stringify(updatedConfig, null, 2);
151
- try {
152
- await Bun.write(configPath, serialized);
153
- }
154
- catch {
155
- throwCliError({
156
- code: 'CONFIG_WRITE_FAILED',
157
- message: `Failed to write config at ${configPath}`,
158
- });
159
- }
160
-
161
- // 6. Output result
162
- const output: OutputStore = { name: trimmedName, path: storePath };
163
- const format: OutputFormat = (options.format as OutputFormat) ?? 'yaml';
164
- writeOutput(output, format, stdout);
165
- }
166
-
167
- /**
168
- * The `remove` subcommand for unregistering a store.
169
- *
170
- * Removes a store from the registry. This only unregisters the store
171
- * from the global registry - it does not delete the actual data.
172
- *
173
- * @example
174
- * ```bash
175
- * cortex store remove work
176
- * cortex store remove project --format json
177
- * ```
178
- */
179
- export const removeCommand = new Command('remove')
180
- .description('Unregister a store from the registry')
181
- .argument('<name>', 'Store name to remove')
182
- .option('-o, --format <format>', 'Output format (yaml, json, toon)', 'yaml')
183
- .action(async (name, options) => {
184
- const context = await createCliCommandContext();
185
- if (!context.ok()) {
186
- throwCliError(context.error);
187
- }
188
- await handleRemove(context.value, name, options);
189
- });
@@ -1,60 +0,0 @@
1
- /**
2
- * Unit tests for store command group wiring.
3
- *
4
- * Verifies that the `store` command group is correctly configured.
5
- *
6
- * @module cli/store/index.spec
7
- */
8
-
9
- import { describe, it, expect } from 'bun:test';
10
-
11
- import { storeCommand } from './index.ts';
12
-
13
- // ── storeCommand wiring ──────────────────────────────────────────────────────
14
-
15
- describe('storeCommand', () => {
16
- it('should have name "store"', () => {
17
- expect(storeCommand.name()).toBe('store');
18
- });
19
-
20
- it('should have description', () => {
21
- expect(storeCommand.description()).toBeTruthy();
22
- });
23
-
24
- it('should have --store option', () => {
25
- const storeOption = storeCommand.options.find((o) => o.long === '--store');
26
- expect(storeOption).toBeDefined();
27
- expect(storeOption?.short).toBe('-s');
28
- });
29
-
30
- it('should have "list" subcommand', () => {
31
- const names = storeCommand.commands.map((c) => c.name());
32
- expect(names).toContain('list');
33
- });
34
-
35
- it('should have "add" subcommand', () => {
36
- const names = storeCommand.commands.map((c) => c.name());
37
- expect(names).toContain('add');
38
- });
39
-
40
- it('should have "remove" subcommand', () => {
41
- const names = storeCommand.commands.map((c) => c.name());
42
- expect(names).toContain('remove');
43
- });
44
-
45
- it('should have "init" subcommand', () => {
46
- const names = storeCommand.commands.map((c) => c.name());
47
- expect(names).toContain('init');
48
- });
49
-
50
- it('should have "prune" subcommand', () => {
51
- const names = storeCommand.commands.map((c) => c.name());
52
- expect(names).toContain('prune');
53
- });
54
-
55
- it('should have "reindex" subcommand', () => {
56
- const names = storeCommand.commands.map((c) => c.name());
57
- expect(names).toContain('reindex');
58
- });
59
- });
60
-
@@ -1,49 +0,0 @@
1
- /**
2
- * Store command group for the Cortex CLI.
3
- *
4
- * Provides store management operations including listing, adding, removing,
5
- * and initializing memory stores. Also includes maintenance commands for
6
- * pruning expired memories and reindexing stores.
7
- *
8
- * The `--store` option is defined at the group level and inherited by all
9
- * subcommands, allowing users to specify which store to operate on.
10
- *
11
- * @example
12
- * ```bash
13
- * cortex store list # List all registered stores
14
- * cortex store add <name> <path> # Register a store
15
- * cortex store remove <name> # Unregister a store
16
- * cortex store init [path] # Initialize a new store
17
- * cortex store prune # Remove expired memories
18
- * cortex store reindex # Rebuild store indexes
19
- * ```
20
- */
21
- import { Command } from '@commander-js/extra-typings';
22
-
23
- import { listCommand } from './commands/list.ts';
24
- import { addCommand } from './commands/add.ts';
25
- import { removeCommand } from './commands/remove.ts';
26
- import { initCommand } from './commands/init.ts';
27
- import { pruneCommand } from './commands/prune.ts';
28
- import { reindexCommand } from './commands/reindexs.ts';
29
-
30
- // Re-export resolveStoreName from its own utility module so callers that
31
- // previously imported it from this file continue to work.
32
- export { resolveStoreName } from './utils/resolve-store-name.ts';
33
-
34
- /**
35
- * Store command group.
36
- *
37
- * The `--store` option is inherited by all subcommands, allowing operations
38
- * to target a specific named store rather than using automatic store resolution.
39
- */
40
- export const storeCommand = new Command('store')
41
- .description('Store management')
42
- .option('-s, --store <name>', 'Use a specific named store');
43
-
44
- storeCommand.addCommand(listCommand);
45
- storeCommand.addCommand(addCommand);
46
- storeCommand.addCommand(removeCommand);
47
- storeCommand.addCommand(initCommand);
48
- storeCommand.addCommand(pruneCommand);
49
- storeCommand.addCommand(reindexCommand);
@@ -1,62 +0,0 @@
1
- import { afterEach, describe, expect, it } from 'bun:test';
2
- import { InvalidArgumentError } from '@commander-js/extra-typings';
3
- import { mkdtemp, mkdir, rm } from 'node:fs/promises';
4
- import { tmpdir } from 'node:os';
5
- import { basename, join } from 'node:path';
6
-
7
- import { runGitCommand } from '../../utils/git.ts';
8
- import { resolveStoreName } from './resolve-store-name.ts';
9
-
10
- const THIS_DIR = import.meta.dir;
11
-
12
- describe('resolveStoreName', () => {
13
- const createdDirs: string[] = [];
14
-
15
- afterEach(async () => {
16
- for (const dir of createdDirs.splice(0)) {
17
- await rm(dir, { recursive: true, force: true });
18
- }
19
- });
20
-
21
- it('should prioritize explicit name when provided', async () => {
22
- const name = await resolveStoreName('/any/path', 'My Project Store!');
23
- expect(name).toBe('my-project-store');
24
- });
25
-
26
- it('should throw InvalidArgumentError for invalid explicit name', async () => {
27
- await expect(resolveStoreName('/any/path', ' ')).rejects.toThrow(InvalidArgumentError);
28
- });
29
-
30
- it('should derive store name from git toplevel basename', async () => {
31
- const toplevelResult = await runGitCommand([
32
- 'rev-parse', '--show-toplevel',
33
- ], THIS_DIR);
34
- if (!toplevelResult.ok) {
35
- return;
36
- }
37
-
38
- const expected = basename(toplevelResult.value)
39
- .toLowerCase()
40
- .replace(/[^a-z0-9]+/g, '-')
41
- .replace(/^-|-$/g, '');
42
-
43
- const resolved = await resolveStoreName(THIS_DIR);
44
- expect(resolved).toBe(expected);
45
- });
46
-
47
- it('should fall back to folder basename when not in a git repository', async () => {
48
- const dir = await mkdtemp(join(tmpdir(), 'Resolve Name Folder '));
49
- createdDirs.push(dir);
50
-
51
- const resolved = await resolveStoreName(dir);
52
- expect(resolved).toMatch(/^resolve-name-folder-/);
53
- });
54
-
55
- it('should return an empty slug when folder basename normalizes to nothing', async () => {
56
- const dir = join(tmpdir(), '!!!');
57
- await mkdir(dir, { recursive: true });
58
- createdDirs.push(dir);
59
-
60
- await expect(resolveStoreName(dir)).resolves.toBe('');
61
- });
62
- });
@@ -1,79 +0,0 @@
1
- /**
2
- * Utility for resolving the store name using a priority-based strategy.
3
- *
4
- * Extracted into its own module to avoid a circular dependency:
5
- * store/commands/init.ts → store/index.ts → store/commands/init.ts
6
- *
7
- * @module cli/store/utils/resolve-store-name
8
- */
9
-
10
- import { Slug } from '@yeseh/cortex-core';
11
- import { basename } from 'node:path';
12
- import { detectGitRepoName } from '../../utils/git.ts';
13
- import { throwCliError } from '../../errors.ts';
14
-
15
- /**
16
- * Resolves the store name using a priority-based strategy.
17
- *
18
- * Name resolution follows this precedence:
19
- * 1. **Explicit name** - If `--name` option is provided, use it directly
20
- * 2. **Git detection** - Auto-detect from git repository directory name
21
- * 3. **Folder name** - Use the current folder name if git detection fails
22
- * 4. **Error** - Fail with guidance to use `--name` flag
23
- *
24
- * Git repository names are normalized to valid store name format:
25
- * - Converted to lowercase
26
- * - Non-alphanumeric characters replaced with hyphens
27
- * - Leading/trailing hyphens removed
28
- *
29
- * @param cwd - Current working directory
30
- * @param explicitName - Optional explicit name provided via `--name` option
31
- * @returns The validated store name
32
- * @throws {InvalidArgumentError} When the name is invalid
33
- * @throws {CommanderError} When git detection fails and no name provided
34
- */
35
- export async function resolveStoreName(cwd: string, explicitName?: string): Promise<string> {
36
- // 1. Use explicit name if provided
37
- if (explicitName) {
38
- const slugResult = Slug.from(explicitName);
39
- if (!slugResult.ok()) {
40
- throwCliError({
41
- code: 'INVALID_STORE_NAME',
42
- message: 'Store name must be a lowercase slug (letters, numbers, hyphens).',
43
- });
44
- }
45
-
46
- return slugResult.value.toString();
47
- }
48
-
49
- // 2. Try git detection
50
- const gitName = await detectGitRepoName(cwd);
51
- if (gitName) {
52
- // Convert to valid store name (lowercase slug)
53
- const normalized = gitName
54
- .toLowerCase()
55
- .replace(/[^a-z0-9]+/g, '-')
56
- .replace(/^-|-$/g, '');
57
- const slugResult = Slug.from(normalized);
58
- if (!slugResult.ok()) {
59
- throwCliError({
60
- code: 'INVALID_STORE_NAME',
61
- message: 'Could not derive valid store name from git repo.',
62
- });
63
- }
64
- return slugResult.value.toString();
65
- }
66
-
67
- // 3. Use the leaf folder name if git detection fails
68
- const folderName = basename(cwd);
69
- const slugResult = Slug.from(folderName);
70
- if (slugResult.ok()) {
71
- return slugResult.value.toString();
72
- }
73
-
74
- // 4. Error: require --name
75
- throwCliError({
76
- code: 'GIT_REPO_REQUIRED',
77
- message: 'Not in a git repository. Use --name to specify the store name.',
78
- });
79
- }