@mndrk/memx 0.3.2 → 0.3.4
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/README.md +98 -77
- package/coverage/clover.xml +1160 -0
- package/coverage/coverage-final.json +3 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +131 -0
- package/coverage/lcov-report/index.js.html +7255 -0
- package/coverage/lcov-report/mcp.js.html +1009 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +2017 -0
- package/index.js +651 -243
- package/package.json +24 -2
- package/test/additional.test.js +373 -0
- package/test/branches.test.js +247 -0
- package/test/commands.test.js +663 -0
- package/test/context.test.js +185 -0
- package/test/coverage.test.js +366 -0
- package/test/dispatch.test.js +220 -0
- package/test/edge-coverage.test.js +250 -0
- package/test/edge.test.js +434 -0
- package/test/final-coverage.test.js +316 -0
- package/test/final-edges.test.js +199 -0
- package/test/init-local.test.js +316 -0
- package/test/init.test.js +122 -0
- package/test/interactive.test.js +229 -0
- package/test/main-dispatch.test.js +164 -0
- package/test/main-full.test.js +590 -0
- package/test/main.test.js +197 -0
- package/test/mcp-server.test.js +320 -0
- package/test/mcp.test.js +288 -0
- package/test/more.test.js +312 -0
- package/test/new.test.js +175 -0
- package/test/skill.test.js +247 -0
- package/test/tasks-interactive.test.js +243 -0
- package/test/utils.test.js +367 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for main function dispatcher
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
|
|
9
|
+
// Mock child_process before requiring index.js
|
|
10
|
+
jest.mock('child_process', () => ({
|
|
11
|
+
execSync: jest.fn(),
|
|
12
|
+
spawnSync: jest.fn(() => ({ status: 0, stdout: '', stderr: '' })),
|
|
13
|
+
spawn: jest.fn()
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
// Mock readline
|
|
17
|
+
jest.mock('readline', () => ({
|
|
18
|
+
createInterface: jest.fn(() => ({
|
|
19
|
+
question: jest.fn((q, cb) => cb('')),
|
|
20
|
+
close: jest.fn(),
|
|
21
|
+
on: jest.fn()
|
|
22
|
+
}))
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
main,
|
|
27
|
+
showHelp,
|
|
28
|
+
showMCPConfig,
|
|
29
|
+
cmdTasks,
|
|
30
|
+
cmdDone,
|
|
31
|
+
handleSkillCommand,
|
|
32
|
+
CENTRAL_MEM,
|
|
33
|
+
writeMemFile,
|
|
34
|
+
loadIndex,
|
|
35
|
+
saveIndex,
|
|
36
|
+
} = require('../index.js');
|
|
37
|
+
|
|
38
|
+
const { spawnSync, execSync } = require('child_process');
|
|
39
|
+
|
|
40
|
+
const testDir = path.join(os.tmpdir(), 'memx-test-main-dispatch-' + Date.now());
|
|
41
|
+
let memDir;
|
|
42
|
+
let originalArgv;
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
memDir = path.join(testDir, '.mem');
|
|
46
|
+
fs.mkdirSync(memDir, { recursive: true });
|
|
47
|
+
fs.mkdirSync(path.join(memDir, '.git'), { recursive: true });
|
|
48
|
+
spawnSync.mockReset();
|
|
49
|
+
spawnSync.mockReturnValue({ status: 0, stdout: '', stderr: '' });
|
|
50
|
+
execSync.mockClear();
|
|
51
|
+
originalArgv = process.argv;
|
|
52
|
+
jest.spyOn(console, 'log').mockImplementation();
|
|
53
|
+
jest.spyOn(console, 'error').mockImplementation();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
process.argv = originalArgv;
|
|
58
|
+
if (fs.existsSync(testDir)) {
|
|
59
|
+
fs.rmSync(testDir, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
jest.restoreAllMocks();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('showHelp', () => {
|
|
65
|
+
test('displays help information', () => {
|
|
66
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
67
|
+
showHelp();
|
|
68
|
+
|
|
69
|
+
const output = consoleSpy.mock.calls.map(c => c[0]).join('\n');
|
|
70
|
+
expect(output).toContain('mem');
|
|
71
|
+
expect(output).toContain('status');
|
|
72
|
+
expect(output).toContain('goal');
|
|
73
|
+
expect(output).toContain('learn');
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('showMCPConfig', () => {
|
|
78
|
+
test('displays MCP configuration', () => {
|
|
79
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
80
|
+
showMCPConfig();
|
|
81
|
+
|
|
82
|
+
const output = consoleSpy.mock.calls.map(c => c[0]).join('\n');
|
|
83
|
+
expect(output).toContain('mcp');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('cmdTasks edge cases', () => {
|
|
88
|
+
test('shows no tasks when only main branch', () => {
|
|
89
|
+
spawnSync
|
|
90
|
+
.mockReturnValueOnce({ status: 0, stdout: 'main', stderr: '' })
|
|
91
|
+
.mockReturnValueOnce({ status: 0, stdout: '* main', stderr: '' });
|
|
92
|
+
|
|
93
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
94
|
+
cmdTasks([], memDir);
|
|
95
|
+
|
|
96
|
+
expect(consoleSpy.mock.calls[0][0]).toContain('No tasks');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('lists tasks when task branches exist', () => {
|
|
100
|
+
// Mock isTTY to false for non-interactive mode
|
|
101
|
+
Object.defineProperty(process.stdin, 'isTTY', { value: false, writable: true });
|
|
102
|
+
|
|
103
|
+
spawnSync
|
|
104
|
+
.mockReturnValueOnce({ status: 0, stdout: 'task/first', stderr: '' })
|
|
105
|
+
.mockReturnValueOnce({ status: 0, stdout: ' main\n* task/first\n task/second', stderr: '' });
|
|
106
|
+
|
|
107
|
+
// Create state files for task branches
|
|
108
|
+
writeMemFile(memDir, 'state.md', '---\nstatus: active\n---\n\n');
|
|
109
|
+
writeMemFile(memDir, 'goal.md', '---\ntask: first\n---\n\n# Goal\n\nTest goal\n\n## Progress: 50%');
|
|
110
|
+
|
|
111
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
112
|
+
cmdTasks([], memDir);
|
|
113
|
+
|
|
114
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('handleSkillCommand', () => {
|
|
119
|
+
test('shows skill status', () => {
|
|
120
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
121
|
+
handleSkillCommand(['skill']);
|
|
122
|
+
|
|
123
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('handles install command', () => {
|
|
127
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
128
|
+
// This will try to install but may fail if Claude.ai not configured
|
|
129
|
+
handleSkillCommand(['skill', 'install']);
|
|
130
|
+
|
|
131
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('handles install with claude target', () => {
|
|
135
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
136
|
+
handleSkillCommand(['skill', 'install', 'claude']);
|
|
137
|
+
|
|
138
|
+
expect(consoleSpy).toHaveBeenCalled();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('loadIndex and saveIndex with central mem', () => {
|
|
143
|
+
test('saves and loads index correctly', () => {
|
|
144
|
+
const testIndex = {
|
|
145
|
+
'/test/project': 'task/feature',
|
|
146
|
+
'/another/project': 'task/other'
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
saveIndex(testIndex);
|
|
150
|
+
const loaded = loadIndex();
|
|
151
|
+
|
|
152
|
+
expect(loaded['/test/project']).toBe('task/feature');
|
|
153
|
+
expect(loaded['/another/project']).toBe('task/other');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('cmdDone edge cases', () => {
|
|
158
|
+
test('shows warning for null memDir', async () => {
|
|
159
|
+
const consoleSpy = jest.spyOn(console, 'log');
|
|
160
|
+
await cmdDone(null);
|
|
161
|
+
|
|
162
|
+
expect(consoleSpy.mock.calls[0][0]).toContain('No .mem repo');
|
|
163
|
+
});
|
|
164
|
+
});
|