clawvault 3.4.0 → 3.5.0

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 (37) hide show
  1. package/CHANGELOG.md +543 -0
  2. package/LICENSE +21 -0
  3. package/README.md +26 -26
  4. package/SKILL.md +369 -0
  5. package/dist/{chunk-X3SPPUFG.js → chunk-JI7VUQV7.js} +118 -132
  6. package/dist/{chunk-QYQAGBTM.js → chunk-QUFQBAHP.js} +148 -125
  7. package/dist/cli/index.js +1 -1
  8. package/dist/commands/compat.js +1 -1
  9. package/dist/commands/observe.js +1 -1
  10. package/dist/commands/status.js +4 -4
  11. package/dist/index.js +11 -8
  12. package/dist/openclaw-plugin.js +6 -1
  13. package/docs/clawhub-security-release-playbook.md +75 -0
  14. package/docs/getting-started/installation.md +99 -0
  15. package/docs/openclaw-plugin-usage.md +152 -0
  16. package/openclaw.plugin.json +1 -1
  17. package/package.json +26 -8
  18. package/bin/command-registration.test.js +0 -179
  19. package/bin/command-runtime.test.js +0 -154
  20. package/bin/help-contract.test.js +0 -55
  21. package/bin/register-config-route-commands.test.js +0 -121
  22. package/bin/register-core-commands.test.js +0 -80
  23. package/bin/register-kanban-commands.test.js +0 -83
  24. package/bin/register-project-commands.test.js +0 -206
  25. package/bin/register-query-commands.test.js +0 -80
  26. package/bin/register-resilience-commands.test.js +0 -81
  27. package/bin/register-task-commands.test.js +0 -69
  28. package/bin/register-template-commands.test.js +0 -87
  29. package/bin/test-helpers/cli-command-fixtures.js +0 -120
  30. package/dashboard/lib/graph-diff.test.js +0 -75
  31. package/dashboard/lib/vault-parser.test.js +0 -254
  32. package/hooks/clawvault/HOOK.md +0 -130
  33. package/hooks/clawvault/handler.js +0 -1696
  34. package/hooks/clawvault/handler.test.js +0 -576
  35. package/hooks/clawvault/integrity.js +0 -112
  36. package/hooks/clawvault/integrity.test.js +0 -32
  37. package/hooks/clawvault/openclaw.plugin.json +0 -190
@@ -1,55 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { registerAllCommandModules } from './test-helpers/cli-command-fixtures.js';
3
-
4
- describe('CLI help contract', () => {
5
- it('includes expected high-level command surface', () => {
6
- const help = registerAllCommandModules().helpInformation();
7
- expect(help).toContain('init');
8
- expect(help).toContain('context');
9
- expect(help).toContain('recall');
10
- expect(help).toContain('inject');
11
- expect(help).toContain('doctor');
12
- expect(help).toContain('benchmark');
13
- expect(help).toContain('maintain');
14
- expect(help).toContain('embed');
15
- expect(help).toContain('inbox');
16
- expect(help).toContain('patch');
17
- expect(help).toContain('compat');
18
- expect(help).toContain('graph');
19
- expect(help).toContain('reflect');
20
- expect(help).toContain('replay');
21
- expect(help).toContain('repair-session');
22
- expect(help).toContain('project');
23
- expect(help).toContain('template');
24
- expect(help).toContain('config');
25
- expect(help).toContain('route');
26
- expect(help).toContain('entity');
27
- });
28
-
29
- it('documents context/compat/inject/project help details', () => {
30
- const program = registerAllCommandModules();
31
- const contextHelp = program.commands.find((command) => command.name() === 'context')?.helpInformation() ?? '';
32
- const compatHelp = program.commands.find((command) => command.name() === 'compat')?.helpInformation() ?? '';
33
- const injectHelp = program.commands.find((command) => command.name() === 'inject')?.helpInformation() ?? '';
34
- const projectCommand = program.commands.find((command) => command.name() === 'project');
35
- const projectListHelp = projectCommand?.commands.find((command) => command.name() === 'list')?.helpInformation() ?? '';
36
- const projectBoardHelp = projectCommand?.commands.find((command) => command.name() === 'board')?.helpInformation() ?? '';
37
- expect(contextHelp).toContain('--profile <profile>');
38
- expect(contextHelp).toContain('auto');
39
- expect(compatHelp).toContain('--strict');
40
- expect(injectHelp).toContain('inject.maxResults');
41
- expect(injectHelp).toContain('inject.scope');
42
- expect(projectListHelp).toContain('archived projects are hidden');
43
- expect(projectBoardHelp).toContain('default: status');
44
- });
45
-
46
- it('does not advertise removed workgraph commands', () => {
47
- const program = registerAllCommandModules();
48
- const names = program.commands.map((command) => command.name());
49
-
50
- expect(names).not.toContain('wg');
51
- expect(names).not.toContain('thread');
52
- expect(names).not.toContain('primitive');
53
- expect(names).not.toContain('ledger');
54
- });
55
- });
@@ -1,121 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { Command } from 'commander';
3
- import { registerConfigCommands } from './register-config-commands.js';
4
- import { registerRouteCommands } from './register-route-commands.js';
5
- import { chalkStub } from './test-helpers/cli-command-fixtures.js';
6
-
7
- const {
8
- getConfigValueMock,
9
- setConfigValueMock,
10
- listConfigMock,
11
- resetConfigMock,
12
- addRouteRuleMock,
13
- listRouteRulesMock,
14
- removeRouteRuleMock,
15
- testRouteRuleMock
16
- } = vi.hoisted(() => ({
17
- getConfigValueMock: vi.fn(),
18
- setConfigValueMock: vi.fn(),
19
- listConfigMock: vi.fn(),
20
- resetConfigMock: vi.fn(),
21
- addRouteRuleMock: vi.fn(),
22
- listRouteRulesMock: vi.fn(),
23
- removeRouteRuleMock: vi.fn(),
24
- testRouteRuleMock: vi.fn()
25
- }));
26
-
27
- vi.mock('../dist/index.js', () => ({
28
- SUPPORTED_CONFIG_KEYS: [
29
- 'name',
30
- 'categories',
31
- 'theme',
32
- 'observe.model',
33
- 'observe.provider',
34
- 'observer.compression.provider',
35
- 'observer.compression.model',
36
- 'observer.compression.baseUrl',
37
- 'observer.compression.apiKey',
38
- 'context.maxResults',
39
- 'context.defaultProfile',
40
- 'graph.maxHops',
41
- 'inject.maxResults',
42
- 'inject.useLlm',
43
- 'inject.scope'
44
- ],
45
- getConfigValue: getConfigValueMock,
46
- setConfigValue: setConfigValueMock,
47
- listConfig: listConfigMock,
48
- resetConfig: resetConfigMock,
49
- addRouteRule: addRouteRuleMock,
50
- listRouteRules: listRouteRulesMock,
51
- removeRouteRule: removeRouteRuleMock,
52
- testRouteRule: testRouteRuleMock
53
- }));
54
-
55
- function buildProgram() {
56
- const program = new Command();
57
- const resolveVaultPath = (value) => value ?? '/vault';
58
- registerConfigCommands(program, { chalk: chalkStub, resolveVaultPath });
59
- registerRouteCommands(program, { chalk: chalkStub, resolveVaultPath });
60
- return program;
61
- }
62
-
63
- async function runCommand(args) {
64
- const program = buildProgram();
65
- await program.parseAsync(args, { from: 'user' });
66
- }
67
-
68
- beforeEach(() => {
69
- vi.clearAllMocks();
70
- getConfigValueMock.mockReturnValue('demo-vault');
71
- setConfigValueMock.mockReturnValue({ value: 'demo-vault' });
72
- listConfigMock.mockReturnValue({ name: 'demo-vault', context: { maxResults: 5 } });
73
- resetConfigMock.mockReturnValue(undefined);
74
- addRouteRuleMock.mockReturnValue({ pattern: 'Pedro', target: 'people/pedro', priority: 1 });
75
- listRouteRulesMock.mockReturnValue([{ pattern: 'Pedro', target: 'people/pedro', priority: 1 }]);
76
- removeRouteRuleMock.mockReturnValue(true);
77
- testRouteRuleMock.mockReturnValue({ pattern: 'Pedro', target: 'people/pedro', priority: 1 });
78
- });
79
-
80
- describe('config and route command registrations', () => {
81
- it('executes config get/set/list subcommands', async () => {
82
- const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
83
- try {
84
- await runCommand(['config', 'get', 'name']);
85
- expect(getConfigValueMock).toHaveBeenCalledWith('/vault', 'name');
86
-
87
- await runCommand(['config', 'set', 'categories', 'people,projects']);
88
- expect(setConfigValueMock).toHaveBeenCalledWith('/vault', 'categories', 'people,projects');
89
-
90
- await runCommand(['config', 'list']);
91
- expect(listConfigMock).toHaveBeenCalledWith('/vault');
92
-
93
- const output = logSpy.mock.calls.map((call) => call.join(' ')).join('\n');
94
- expect(output).toContain('context.maxResults');
95
- } finally {
96
- logSpy.mockRestore();
97
- }
98
- });
99
-
100
- it('executes route add/remove/test subcommands', async () => {
101
- const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
102
- try {
103
- await runCommand(['route', 'add', 'Pedro', 'people/pedro']);
104
- expect(addRouteRuleMock).toHaveBeenCalledWith('/vault', 'Pedro', 'people/pedro');
105
-
106
- await runCommand(['route', 'remove', 'Pedro']);
107
- expect(removeRouteRuleMock).toHaveBeenCalledWith('/vault', 'Pedro');
108
-
109
- await runCommand(['route', 'test', 'Talked to Pedro']);
110
- expect(testRouteRuleMock).toHaveBeenCalledWith('/vault', 'Talked to Pedro');
111
-
112
- await runCommand(['route', 'list']);
113
- expect(listRouteRulesMock).toHaveBeenCalledWith('/vault');
114
-
115
- const output = logSpy.mock.calls.map((call) => call.join(' ')).join('\n');
116
- expect(output).toContain('Route matched');
117
- } finally {
118
- logSpy.mockRestore();
119
- }
120
- });
121
- });
@@ -1,80 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { Command } from 'commander';
3
- import * as fs from 'fs';
4
- import * as path from 'path';
5
- import { registerCoreCommands } from './register-core-commands.js';
6
- import { chalkStub } from './test-helpers/cli-command-fixtures.js';
7
-
8
- function buildProgram(patchImpl) {
9
- const program = new Command();
10
- registerCoreCommands(program, {
11
- chalk: chalkStub,
12
- path,
13
- fs,
14
- createVault: async () => ({ getCategories: () => [], getQmdRoot: () => '', getQmdCollection: () => '' }),
15
- getVault: async () => ({ patch: patchImpl }),
16
- runQmd: async () => {}
17
- });
18
- return program;
19
- }
20
-
21
- describe('register-core-commands patch command', () => {
22
- it('exposes patch command mode flags', () => {
23
- const program = buildProgram(async () => ({ id: 'decisions/example', path: '/vault/decisions/example.md' }));
24
- const patchCommand = program.commands.find((command) => command.name() === 'patch');
25
- expect(patchCommand).toBeDefined();
26
- const optionFlags = patchCommand?.options.map((option) => option.flags) ?? [];
27
- expect(optionFlags).toEqual(expect.arrayContaining([
28
- '--append <text>',
29
- '--replace <text>',
30
- '--with <text>',
31
- '--section <heading>',
32
- '--content <text>',
33
- '-v, --vault <path>'
34
- ]));
35
- });
36
-
37
- it('forwards append mode payload to vault.patch', async () => {
38
- const patchMock = vi.fn(async () => ({ id: 'decisions/example', path: '/vault/decisions/example.md' }));
39
- const program = buildProgram(patchMock);
40
- const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
41
- const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
42
-
43
- try {
44
- await program.parseAsync(['patch', 'decisions/example', '--append', 'new line'], { from: 'user' });
45
- expect(patchMock).toHaveBeenCalledWith({
46
- idOrPath: 'decisions/example',
47
- mode: 'append',
48
- append: 'new line'
49
- });
50
- expect(errorSpy).not.toHaveBeenCalled();
51
- } finally {
52
- logSpy.mockRestore();
53
- errorSpy.mockRestore();
54
- }
55
- });
56
-
57
- it('forwards section/content mode payload to vault.patch', async () => {
58
- const patchMock = vi.fn(async () => ({ id: 'decisions/example', path: '/vault/decisions/example.md' }));
59
- const program = buildProgram(patchMock);
60
- const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
61
- const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
62
-
63
- try {
64
- await program.parseAsync(
65
- ['patch', 'decisions/example', '--section', 'Notes', '--content', 'updated notes'],
66
- { from: 'user' }
67
- );
68
- expect(patchMock).toHaveBeenCalledWith({
69
- idOrPath: 'decisions/example',
70
- mode: 'content',
71
- content: 'updated notes',
72
- section: 'Notes'
73
- });
74
- expect(errorSpy).not.toHaveBeenCalled();
75
- } finally {
76
- logSpy.mockRestore();
77
- errorSpy.mockRestore();
78
- }
79
- });
80
- });
@@ -1,83 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { Command } from 'commander';
3
- import { registerKanbanCommands } from './register-kanban-commands.js';
4
- import { chalkStub } from './test-helpers/cli-command-fixtures.js';
5
-
6
- const { kanbanCommandMock } = vi.hoisted(() => ({
7
- kanbanCommandMock: vi.fn()
8
- }));
9
-
10
- vi.mock('../dist/commands/kanban.js', () => ({
11
- kanbanCommand: kanbanCommandMock
12
- }));
13
-
14
- function buildProgram() {
15
- const program = new Command();
16
- registerKanbanCommands(program, {
17
- chalk: chalkStub,
18
- resolveVaultPath: (value) => value ?? '/vault'
19
- });
20
- return program;
21
- }
22
-
23
- async function runCommand(args) {
24
- const program = buildProgram();
25
- await program.parseAsync(args, { from: 'user' });
26
- }
27
-
28
- describe('register-kanban-commands', () => {
29
- beforeEach(() => {
30
- vi.clearAllMocks();
31
- });
32
-
33
- it('registers sync and import subcommands with expected options', () => {
34
- const program = buildProgram();
35
- const kanbanCommand = program.commands.find((command) => command.name() === 'kanban');
36
- expect(kanbanCommand).toBeDefined();
37
-
38
- const syncCommand = kanbanCommand?.commands.find((command) => command.name() === 'sync');
39
- expect(syncCommand).toBeDefined();
40
- const syncFlags = syncCommand?.options.map((option) => option.flags) ?? [];
41
- expect(syncFlags).toEqual(expect.arrayContaining([
42
- '--output <path>',
43
- '--group-by <field>',
44
- '--filter-project <project>',
45
- '--filter-owner <owner>',
46
- '--include-done'
47
- ]));
48
-
49
- const importCommand = kanbanCommand?.commands.find((command) => command.name() === 'import');
50
- expect(importCommand).toBeDefined();
51
- const importFlags = importCommand?.options.map((option) => option.flags) ?? [];
52
- expect(importFlags).toEqual(expect.arrayContaining(['--output <path>']));
53
- });
54
-
55
- it('dispatches sync and import actions to the kanban command handler', async () => {
56
- await runCommand([
57
- 'kanban',
58
- 'sync',
59
- '--group-by',
60
- 'priority',
61
- '--output',
62
- 'Board.md',
63
- '--filter-project',
64
- 'apollo',
65
- '--filter-owner',
66
- 'alice',
67
- '--include-done'
68
- ]);
69
-
70
- expect(kanbanCommandMock).toHaveBeenCalledWith('/vault', 'sync', {
71
- output: 'Board.md',
72
- groupBy: 'priority',
73
- filterProject: 'apollo',
74
- filterOwner: 'alice',
75
- includeDone: true
76
- });
77
-
78
- await runCommand(['kanban', 'import', '--output', 'Board.md']);
79
- expect(kanbanCommandMock).toHaveBeenCalledWith('/vault', 'import', {
80
- output: 'Board.md'
81
- });
82
- });
83
- });
@@ -1,206 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { Command } from 'commander';
3
- import { registerProjectCommands } from './register-project-commands.js';
4
- import { chalkStub } from './test-helpers/cli-command-fixtures.js';
5
-
6
- const { projectCommandMock } = vi.hoisted(() => ({
7
- projectCommandMock: vi.fn()
8
- }));
9
-
10
- vi.mock('../dist/commands/project.js', () => ({
11
- projectCommand: projectCommandMock
12
- }));
13
-
14
- function buildProgram() {
15
- const program = new Command();
16
- registerProjectCommands(program, {
17
- chalk: chalkStub,
18
- resolveVaultPath: (value) => value ?? '/vault'
19
- });
20
- return program;
21
- }
22
-
23
- async function runCommand(args) {
24
- const program = buildProgram();
25
- await program.parseAsync(args, { from: 'user' });
26
- }
27
-
28
- describe('register-project-commands', () => {
29
- beforeEach(() => {
30
- vi.clearAllMocks();
31
- });
32
-
33
- it('registers add/update/archive/list/show/tasks/board subcommands', () => {
34
- const program = buildProgram();
35
- const projectCommand = program.commands.find((command) => command.name() === 'project');
36
- expect(projectCommand).toBeDefined();
37
-
38
- const subcommandNames = projectCommand?.commands.map((command) => command.name()) ?? [];
39
- expect(subcommandNames).toEqual(expect.arrayContaining([
40
- 'add',
41
- 'update',
42
- 'archive',
43
- 'list',
44
- 'show',
45
- 'tasks',
46
- 'board'
47
- ]));
48
-
49
- const addCommand = projectCommand?.commands.find((command) => command.name() === 'add');
50
- const addFlags = addCommand?.options.map((option) => option.flags) ?? [];
51
- expect(addFlags).toEqual(expect.arrayContaining([
52
- '--owner <owner>',
53
- '--status <status>',
54
- '--team <team>',
55
- '--client <client>',
56
- '--tags <tags>',
57
- '--description <description>',
58
- '--deadline <date>',
59
- '--repo <url>',
60
- '--url <url>'
61
- ]));
62
-
63
- const listCommand = projectCommand?.commands.find((command) => command.name() === 'list');
64
- const listFlags = listCommand?.options.map((option) => option.flags) ?? [];
65
- expect(listFlags).toEqual(expect.arrayContaining([
66
- '--status <status>',
67
- '--owner <owner>',
68
- '--client <client>',
69
- '--tag <tag>',
70
- '--json'
71
- ]));
72
-
73
- const boardCommand = projectCommand?.commands.find((command) => command.name() === 'board');
74
- const boardFlags = boardCommand?.options.map((option) => option.flags) ?? [];
75
- expect(boardFlags).toEqual(expect.arrayContaining([
76
- '--output <path>',
77
- '--group-by <field>'
78
- ]));
79
-
80
- expect(listCommand?.description()).toContain('archived projects are hidden');
81
-
82
- const boardGroupByOption = boardCommand?.options.find((option) => option.flags === '--group-by <field>');
83
- expect(boardGroupByOption?.description).toContain('default: status');
84
- });
85
-
86
- it('dispatches project subcommands to project command handler', async () => {
87
- await runCommand([
88
- 'project',
89
- 'add',
90
- 'Apollo Launch',
91
- '--owner',
92
- 'alice',
93
- '--status',
94
- 'active',
95
- '--team',
96
- 'alice,bob',
97
- '--client',
98
- 'Acme',
99
- '--tags',
100
- 'platform,release',
101
- '--description',
102
- 'Launch project',
103
- '--deadline',
104
- '2026-03-01',
105
- '--repo',
106
- 'https://github.com/acme/apollo',
107
- '--url',
108
- 'https://apollo.acme.dev'
109
- ]);
110
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'add', {
111
- title: 'Apollo Launch',
112
- options: {
113
- owner: 'alice',
114
- status: 'active',
115
- team: ['alice', 'bob'],
116
- client: 'Acme',
117
- tags: ['platform', 'release'],
118
- description: 'Launch project',
119
- deadline: '2026-03-01',
120
- repo: 'https://github.com/acme/apollo',
121
- url: 'https://apollo.acme.dev'
122
- }
123
- });
124
-
125
- await runCommand([
126
- 'project',
127
- 'update',
128
- 'apollo-launch',
129
- '--status',
130
- 'paused',
131
- '--owner',
132
- 'carol',
133
- '--team',
134
- 'carol,dave',
135
- '--client',
136
- 'Acme',
137
- '--tags',
138
- 'ops',
139
- '--description',
140
- 'Paused pending review',
141
- '--deadline',
142
- '2026-03-10',
143
- '--repo',
144
- 'https://github.com/acme/apollo-v2',
145
- '--url',
146
- 'https://staging.acme.dev'
147
- ]);
148
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'update', {
149
- slug: 'apollo-launch',
150
- options: {
151
- status: 'paused',
152
- owner: 'carol',
153
- team: ['carol', 'dave'],
154
- client: 'Acme',
155
- tags: ['ops'],
156
- description: 'Paused pending review',
157
- deadline: '2026-03-10',
158
- repo: 'https://github.com/acme/apollo-v2',
159
- url: 'https://staging.acme.dev'
160
- }
161
- });
162
-
163
- await runCommand(['project', 'archive', 'apollo-launch', '--reason', 'Client offboarded']);
164
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'archive', {
165
- slug: 'apollo-launch',
166
- options: {
167
- reason: 'Client offboarded'
168
- }
169
- });
170
-
171
- await runCommand(['project', 'list', '--status', 'active', '--owner', 'alice', '--client', 'Acme', '--tag', 'platform', '--json']);
172
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'list', {
173
- options: {
174
- status: 'active',
175
- owner: 'alice',
176
- client: 'Acme',
177
- tag: 'platform',
178
- json: true
179
- }
180
- });
181
-
182
- await runCommand(['project', 'show', 'apollo-launch']);
183
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'show', {
184
- slug: 'apollo-launch',
185
- options: {
186
- json: undefined
187
- }
188
- });
189
-
190
- await runCommand(['project', 'tasks', 'apollo-launch', '--json']);
191
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'tasks', {
192
- slug: 'apollo-launch',
193
- options: {
194
- json: true
195
- }
196
- });
197
-
198
- await runCommand(['project', 'board', '--output', 'Projects-Board.md', '--group-by', 'client']);
199
- expect(projectCommandMock).toHaveBeenCalledWith('/vault', 'board', {
200
- options: {
201
- output: 'Projects-Board.md',
202
- groupBy: 'client'
203
- }
204
- });
205
- });
206
- });
@@ -1,80 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { Command } from 'commander';
3
- import { registerQueryCommands } from './register-query-commands.js';
4
- import {
5
- chalkStub,
6
- createGetVaultStub,
7
- stubResolveVaultPath
8
- } from './test-helpers/cli-command-fixtures.js';
9
-
10
- function buildProgram() {
11
- const program = new Command();
12
- registerQueryCommands(program, {
13
- chalk: chalkStub,
14
- getVault: createGetVaultStub({ find: async () => [], vsearch: async () => [] }),
15
- resolveVaultPath: stubResolveVaultPath,
16
- QmdUnavailableError: class extends Error {},
17
- printQmdMissing: () => {}
18
- });
19
- return program;
20
- }
21
-
22
- describe('register-query-commands', () => {
23
- it('registers recall command with strategy options', () => {
24
- const program = buildProgram();
25
- const recallCommand = program.commands.find((command) => command.name() === 'recall');
26
- expect(recallCommand).toBeDefined();
27
-
28
- const flags = recallCommand?.options.map((option) => option.flags) ?? [];
29
- expect(flags).toEqual(expect.arrayContaining([
30
- '-n, --limit <n>',
31
- '--strategy <strategy>',
32
- '--json',
33
- '--no-sources',
34
- '-v, --vault <path>'
35
- ]));
36
- });
37
-
38
- it('documents inject command options and config-backed defaults', () => {
39
- const program = buildProgram();
40
- const injectCommand = program.commands.find((command) => command.name() === 'inject');
41
- expect(injectCommand).toBeDefined();
42
-
43
- const injectFlags = injectCommand?.options.map((option) => option.flags) ?? [];
44
- expect(injectFlags).toEqual(expect.arrayContaining([
45
- '-n, --max-results <n>',
46
- '--scope <scope>',
47
- '--enable-llm',
48
- '--disable-llm',
49
- '--format <format>',
50
- '--model <model>',
51
- '-v, --vault <path>'
52
- ]));
53
-
54
- const maxResultsOption = injectCommand?.options.find((option) => option.flags === '-n, --max-results <n>');
55
- const scopeOption = injectCommand?.options.find((option) => option.flags === '--scope <scope>');
56
- const formatOption = injectCommand?.options.find((option) => option.flags === '--format <format>');
57
- expect(maxResultsOption?.description).toContain('inject.maxResults');
58
- expect(scopeOption?.description).toContain('inject.scope');
59
- expect(formatOption?.description).toContain('default: markdown');
60
- });
61
-
62
- it('documents observe extraction toggles and threshold defaults', () => {
63
- const program = buildProgram();
64
- const observeCommand = program.commands.find((command) => command.name() === 'observe');
65
- expect(observeCommand).toBeDefined();
66
-
67
- const observeFlags = observeCommand?.options.map((option) => option.flags) ?? [];
68
- expect(observeFlags).toEqual(expect.arrayContaining([
69
- '--extract-tasks',
70
- '--no-extract-tasks',
71
- '--threshold <n>',
72
- '--reflect-threshold <n>'
73
- ]));
74
-
75
- const thresholdOption = observeCommand?.options.find((option) => option.flags === '--threshold <n>');
76
- const reflectThresholdOption = observeCommand?.options.find((option) => option.flags === '--reflect-threshold <n>');
77
- expect(thresholdOption?.description).toContain('default: 30000');
78
- expect(reflectThresholdOption?.description).toContain('default: 40000');
79
- });
80
- });