ghagga 2.0.1 → 2.2.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.
- package/README.md +90 -19
- package/dist/commands/hooks/index.d.ts +9 -0
- package/dist/commands/hooks/index.d.ts.map +1 -0
- package/dist/commands/hooks/index.js +16 -0
- package/dist/commands/hooks/index.js.map +1 -0
- package/dist/commands/hooks/install.d.ts +13 -0
- package/dist/commands/hooks/install.d.ts.map +1 -0
- package/dist/commands/hooks/install.js +64 -0
- package/dist/commands/hooks/install.js.map +1 -0
- package/dist/commands/hooks/install.test.d.ts +11 -0
- package/dist/commands/hooks/install.test.d.ts.map +1 -0
- package/dist/commands/hooks/install.test.js +157 -0
- package/dist/commands/hooks/install.test.js.map +1 -0
- package/dist/commands/hooks/status.d.ts +12 -0
- package/dist/commands/hooks/status.d.ts.map +1 -0
- package/dist/commands/hooks/status.js +38 -0
- package/dist/commands/hooks/status.js.map +1 -0
- package/dist/commands/hooks/status.test.d.ts +11 -0
- package/dist/commands/hooks/status.test.d.ts.map +1 -0
- package/dist/commands/hooks/status.test.js +123 -0
- package/dist/commands/hooks/status.test.js.map +1 -0
- package/dist/commands/hooks/uninstall.d.ts +12 -0
- package/dist/commands/hooks/uninstall.d.ts.map +1 -0
- package/dist/commands/hooks/uninstall.js +44 -0
- package/dist/commands/hooks/uninstall.js.map +1 -0
- package/dist/commands/hooks/uninstall.test.d.ts +10 -0
- package/dist/commands/hooks/uninstall.test.d.ts.map +1 -0
- package/dist/commands/hooks/uninstall.test.js +120 -0
- package/dist/commands/hooks/uninstall.test.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +17 -14
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/login.test.d.ts +9 -0
- package/dist/commands/login.test.d.ts.map +1 -0
- package/dist/commands/login.test.js +138 -0
- package/dist/commands/login.test.js.map +1 -0
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +4 -3
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/logout.test.d.ts +8 -0
- package/dist/commands/logout.test.d.ts.map +1 -0
- package/dist/commands/logout.test.js +61 -0
- package/dist/commands/logout.test.js.map +1 -0
- package/dist/commands/memory/clear.d.ts +11 -0
- package/dist/commands/memory/clear.d.ts.map +1 -0
- package/dist/commands/memory/clear.js +45 -0
- package/dist/commands/memory/clear.js.map +1 -0
- package/dist/commands/memory/clear.test.d.ts +11 -0
- package/dist/commands/memory/clear.test.d.ts.map +1 -0
- package/dist/commands/memory/clear.test.js +178 -0
- package/dist/commands/memory/clear.test.js.map +1 -0
- package/dist/commands/memory/delete.d.ts +11 -0
- package/dist/commands/memory/delete.d.ts.map +1 -0
- package/dist/commands/memory/delete.js +38 -0
- package/dist/commands/memory/delete.js.map +1 -0
- package/dist/commands/memory/delete.test.d.ts +11 -0
- package/dist/commands/memory/delete.test.d.ts.map +1 -0
- package/dist/commands/memory/delete.test.js +176 -0
- package/dist/commands/memory/delete.test.js.map +1 -0
- package/dist/commands/memory/index.d.ts +10 -0
- package/dist/commands/memory/index.d.ts.map +1 -0
- package/dist/commands/memory/index.js +23 -0
- package/dist/commands/memory/index.js.map +1 -0
- package/dist/commands/memory/list.d.ts +11 -0
- package/dist/commands/memory/list.d.ts.map +1 -0
- package/dist/commands/memory/list.js +47 -0
- package/dist/commands/memory/list.js.map +1 -0
- package/dist/commands/memory/list.test.d.ts +10 -0
- package/dist/commands/memory/list.test.d.ts.map +1 -0
- package/dist/commands/memory/list.test.js +135 -0
- package/dist/commands/memory/list.test.js.map +1 -0
- package/dist/commands/memory/search.d.ts +12 -0
- package/dist/commands/memory/search.d.ts.map +1 -0
- package/dist/commands/memory/search.js +44 -0
- package/dist/commands/memory/search.js.map +1 -0
- package/dist/commands/memory/search.test.d.ts +11 -0
- package/dist/commands/memory/search.test.d.ts.map +1 -0
- package/dist/commands/memory/search.test.js +122 -0
- package/dist/commands/memory/search.test.js.map +1 -0
- package/dist/commands/memory/show.d.ts +10 -0
- package/dist/commands/memory/show.d.ts.map +1 -0
- package/dist/commands/memory/show.js +51 -0
- package/dist/commands/memory/show.js.map +1 -0
- package/dist/commands/memory/show.test.d.ts +11 -0
- package/dist/commands/memory/show.test.d.ts.map +1 -0
- package/dist/commands/memory/show.test.js +156 -0
- package/dist/commands/memory/show.test.js.map +1 -0
- package/dist/commands/memory/stats.d.ts +11 -0
- package/dist/commands/memory/stats.d.ts.map +1 -0
- package/dist/commands/memory/stats.js +63 -0
- package/dist/commands/memory/stats.js.map +1 -0
- package/dist/commands/memory/stats.test.d.ts +10 -0
- package/dist/commands/memory/stats.test.d.ts.map +1 -0
- package/dist/commands/memory/stats.test.js +122 -0
- package/dist/commands/memory/stats.test.js.map +1 -0
- package/dist/commands/memory/utils.d.ts +44 -0
- package/dist/commands/memory/utils.d.ts.map +1 -0
- package/dist/commands/memory/utils.js +90 -0
- package/dist/commands/memory/utils.js.map +1 -0
- package/dist/commands/memory/utils.test.d.ts +10 -0
- package/dist/commands/memory/utils.test.d.ts.map +1 -0
- package/dist/commands/memory/utils.test.js +93 -0
- package/dist/commands/memory/utils.test.js.map +1 -0
- package/dist/commands/review-commit-msg.d.ts +28 -0
- package/dist/commands/review-commit-msg.d.ts.map +1 -0
- package/dist/commands/review-commit-msg.js +126 -0
- package/dist/commands/review-commit-msg.js.map +1 -0
- package/dist/commands/review-commit-msg.test.d.ts +11 -0
- package/dist/commands/review-commit-msg.test.d.ts.map +1 -0
- package/dist/commands/review-commit-msg.test.js +126 -0
- package/dist/commands/review-commit-msg.test.js.map +1 -0
- package/dist/commands/review.d.ts +7 -0
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +138 -103
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/review.test.js +267 -1
- package/dist/commands/review.test.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +12 -11
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status.test.d.ts +8 -0
- package/dist/commands/status.test.d.ts.map +1 -0
- package/dist/commands/status.test.js +106 -0
- package/dist/commands/status.test.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +48 -16
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/config.test.d.ts +9 -0
- package/dist/lib/config.test.d.ts.map +1 -0
- package/dist/lib/config.test.js +181 -0
- package/dist/lib/config.test.js.map +1 -0
- package/dist/lib/git-hooks.d.ts +19 -0
- package/dist/lib/git-hooks.d.ts.map +1 -0
- package/dist/lib/git-hooks.js +129 -0
- package/dist/lib/git-hooks.js.map +1 -0
- package/dist/lib/git-hooks.test.d.ts +11 -0
- package/dist/lib/git-hooks.test.d.ts.map +1 -0
- package/dist/lib/git-hooks.test.js +178 -0
- package/dist/lib/git-hooks.test.js.map +1 -0
- package/dist/lib/git.d.ts +33 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +85 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/git.test.d.ts +2 -0
- package/dist/lib/git.test.d.ts.map +1 -0
- package/dist/lib/git.test.js +65 -0
- package/dist/lib/git.test.js.map +1 -0
- package/dist/lib/hook-templates.d.ts +12 -0
- package/dist/lib/hook-templates.d.ts.map +1 -0
- package/dist/lib/hook-templates.js +52 -0
- package/dist/lib/hook-templates.js.map +1 -0
- package/dist/lib/hook-templates.test.d.ts +11 -0
- package/dist/lib/hook-templates.test.d.ts.map +1 -0
- package/dist/lib/hook-templates.test.js +76 -0
- package/dist/lib/hook-templates.test.js.map +1 -0
- package/dist/lib/hooks-types.d.ts +30 -0
- package/dist/lib/hooks-types.d.ts.map +1 -0
- package/dist/lib/hooks-types.js +9 -0
- package/dist/lib/hooks-types.js.map +1 -0
- package/dist/lib/oauth.test.d.ts +8 -0
- package/dist/lib/oauth.test.d.ts.map +1 -0
- package/dist/lib/oauth.test.js +212 -0
- package/dist/lib/oauth.test.js.map +1 -0
- package/dist/ui/__tests__/format.test.d.ts +7 -0
- package/dist/ui/__tests__/format.test.d.ts.map +1 -0
- package/dist/ui/__tests__/format.test.js +220 -0
- package/dist/ui/__tests__/format.test.js.map +1 -0
- package/dist/ui/__tests__/theme.test.d.ts +7 -0
- package/dist/ui/__tests__/theme.test.d.ts.map +1 -0
- package/dist/ui/__tests__/theme.test.js +79 -0
- package/dist/ui/__tests__/theme.test.js.map +1 -0
- package/dist/ui/__tests__/tui.test.d.ts +9 -0
- package/dist/ui/__tests__/tui.test.d.ts.map +1 -0
- package/dist/ui/__tests__/tui.test.js +222 -0
- package/dist/ui/__tests__/tui.test.js.map +1 -0
- package/dist/ui/format.d.ts +38 -0
- package/dist/ui/format.d.ts.map +1 -0
- package/dist/ui/format.js +136 -0
- package/dist/ui/format.js.map +1 -0
- package/dist/ui/theme.d.ts +26 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +63 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/tui.d.ts +44 -0
- package/dist/ui/tui.d.ts.map +1 -0
- package/dist/ui/tui.js +121 -0
- package/dist/ui/tui.js.map +1 -0
- package/package.json +4 -2
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `ghagga memory show` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Mocks ghagga-core (SqliteMemoryStorage) and node:fs.
|
|
5
|
+
* Tests happy path field display, not found (exit 1),
|
|
6
|
+
* invalid ID (exit 1), and no DB file (exit 0).
|
|
7
|
+
*
|
|
8
|
+
* @see T7.4, S13–S16
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
11
|
+
import { Command } from 'commander';
|
|
12
|
+
// ─── Mocks ──────────────────────────────────────────────────────
|
|
13
|
+
const { mockGetObservation, mockClose } = vi.hoisted(() => ({
|
|
14
|
+
mockGetObservation: vi.fn(),
|
|
15
|
+
mockClose: vi.fn(),
|
|
16
|
+
}));
|
|
17
|
+
vi.mock('ghagga-core', () => ({
|
|
18
|
+
SqliteMemoryStorage: {
|
|
19
|
+
create: vi.fn().mockResolvedValue({
|
|
20
|
+
getObservation: (...args) => mockGetObservation(...args),
|
|
21
|
+
close: (...args) => mockClose(...args),
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
vi.mock('node:fs', () => ({
|
|
26
|
+
existsSync: vi.fn().mockReturnValue(true),
|
|
27
|
+
}));
|
|
28
|
+
vi.mock('../../lib/config.js', () => ({
|
|
29
|
+
getConfigDir: vi.fn().mockReturnValue('/mock-config'),
|
|
30
|
+
}));
|
|
31
|
+
import { existsSync } from 'node:fs';
|
|
32
|
+
import { registerShowCommand } from './show.js';
|
|
33
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
34
|
+
// ─── Helpers ────────────────────────────────────────────────────
|
|
35
|
+
/** Sentinel thrown by the process.exit mock to halt execution. */
|
|
36
|
+
class ProcessExitError extends Error {
|
|
37
|
+
code;
|
|
38
|
+
constructor(code) {
|
|
39
|
+
super(`process.exit(${code})`);
|
|
40
|
+
this.code = code;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function makeDetail(overrides = {}) {
|
|
44
|
+
return {
|
|
45
|
+
id: 42,
|
|
46
|
+
type: 'pattern',
|
|
47
|
+
title: 'OAuth token refresh patterns',
|
|
48
|
+
content: 'OAuth token refresh must handle 401 responses.',
|
|
49
|
+
filePaths: ['src/auth.ts', 'lib/token.ts'],
|
|
50
|
+
severity: null,
|
|
51
|
+
project: 'acme/widgets',
|
|
52
|
+
topicKey: 'auth-token-refresh',
|
|
53
|
+
revisionCount: 3,
|
|
54
|
+
createdAt: '2025-03-01T14:22:05Z',
|
|
55
|
+
updatedAt: '2025-03-04T09:15:32Z',
|
|
56
|
+
...overrides,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
async function runShowCommand(args = []) {
|
|
60
|
+
const parent = new Command('memory');
|
|
61
|
+
registerShowCommand(parent);
|
|
62
|
+
try {
|
|
63
|
+
await parent.parseAsync(['show', ...args], { from: 'user' });
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (!(err instanceof ProcessExitError))
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// ─── Setup ──────────────────────────────────────────────────────
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
+
let logSpy;
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
74
|
+
let exitSpy;
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
vi.clearAllMocks();
|
|
77
|
+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
78
|
+
exitSpy = vi
|
|
79
|
+
.spyOn(process, 'exit')
|
|
80
|
+
.mockImplementation(((code) => {
|
|
81
|
+
throw new ProcessExitError(code);
|
|
82
|
+
}));
|
|
83
|
+
mockExistsSync.mockReturnValue(true);
|
|
84
|
+
});
|
|
85
|
+
afterEach(() => {
|
|
86
|
+
logSpy.mockRestore();
|
|
87
|
+
exitSpy.mockRestore();
|
|
88
|
+
});
|
|
89
|
+
// ─── Tests ──────────────────────────────────────────────────────
|
|
90
|
+
describe('ghagga memory show', () => {
|
|
91
|
+
it('displays all fields with correct labels on happy path', async () => {
|
|
92
|
+
const obs = makeDetail();
|
|
93
|
+
mockGetObservation.mockResolvedValue(obs);
|
|
94
|
+
await runShowCommand(['42']);
|
|
95
|
+
const output = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
96
|
+
expect(output).toContain('ID:');
|
|
97
|
+
expect(output).toContain('42');
|
|
98
|
+
expect(output).toContain('Type:');
|
|
99
|
+
expect(output).toContain('pattern');
|
|
100
|
+
expect(output).toContain('Title:');
|
|
101
|
+
expect(output).toContain('OAuth token refresh patterns');
|
|
102
|
+
expect(output).toContain('Project:');
|
|
103
|
+
expect(output).toContain('acme/widgets');
|
|
104
|
+
expect(output).toContain('Topic Key:');
|
|
105
|
+
expect(output).toContain('auth-token-refresh');
|
|
106
|
+
expect(output).toContain('Revision Count:');
|
|
107
|
+
expect(output).toContain('3');
|
|
108
|
+
expect(output).toContain('Created:');
|
|
109
|
+
expect(output).toContain('Updated:');
|
|
110
|
+
expect(output).toContain('File Paths:');
|
|
111
|
+
expect(output).toContain('src/auth.ts, lib/token.ts');
|
|
112
|
+
expect(output).toContain('Content:');
|
|
113
|
+
expect(output).toContain('OAuth token refresh must handle 401 responses.');
|
|
114
|
+
});
|
|
115
|
+
it('shows (none) for null topicKey', async () => {
|
|
116
|
+
mockGetObservation.mockResolvedValue(makeDetail({ topicKey: null }));
|
|
117
|
+
await runShowCommand(['42']);
|
|
118
|
+
const output = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
119
|
+
expect(output).toContain('(none)');
|
|
120
|
+
});
|
|
121
|
+
it('shows (none) for null filePaths', async () => {
|
|
122
|
+
mockGetObservation.mockResolvedValue(makeDetail({ filePaths: null }));
|
|
123
|
+
await runShowCommand(['42']);
|
|
124
|
+
const output = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
125
|
+
expect(output).toMatch(/File Paths:.*\(none\)/);
|
|
126
|
+
});
|
|
127
|
+
it('shows (none) for empty filePaths array', async () => {
|
|
128
|
+
mockGetObservation.mockResolvedValue(makeDetail({ filePaths: [] }));
|
|
129
|
+
await runShowCommand(['42']);
|
|
130
|
+
const output = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
131
|
+
expect(output).toMatch(/File Paths:.*\(none\)/);
|
|
132
|
+
});
|
|
133
|
+
it('prints error and exits 1 when observation is not found', async () => {
|
|
134
|
+
mockGetObservation.mockResolvedValue(null);
|
|
135
|
+
await runShowCommand(['999']);
|
|
136
|
+
expect(logSpy).toHaveBeenCalledWith('Observation not found: 999');
|
|
137
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
138
|
+
});
|
|
139
|
+
it('prints error and exits 1 for invalid ID "abc"', async () => {
|
|
140
|
+
await runShowCommand(['abc']);
|
|
141
|
+
expect(logSpy).toHaveBeenCalledWith('Invalid observation ID: "abc". Expected a number.');
|
|
142
|
+
expect(exitSpy).toHaveBeenCalledWith(1);
|
|
143
|
+
});
|
|
144
|
+
it('prints no-DB message and exits 0 when database file is missing', async () => {
|
|
145
|
+
mockExistsSync.mockReturnValue(false);
|
|
146
|
+
await runShowCommand(['42']);
|
|
147
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('No memory database found'));
|
|
148
|
+
expect(exitSpy).toHaveBeenCalledWith(0);
|
|
149
|
+
});
|
|
150
|
+
it('closes storage after execution', async () => {
|
|
151
|
+
mockGetObservation.mockResolvedValue(makeDetail());
|
|
152
|
+
await runShowCommand(['42']);
|
|
153
|
+
expect(mockClose).toHaveBeenCalled();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
//# sourceMappingURL=show.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.test.js","sourceRoot":"","sources":["../../../src/commands/memory/show.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ghagga memory stats` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Displays aggregate statistics about the memory database including
|
|
5
|
+
* observation counts by type and project, file size, and date range.
|
|
6
|
+
*
|
|
7
|
+
* @see R11, S25–S27
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
export declare function registerStatsCommand(parent: Command): void;
|
|
11
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/commands/memory/stats.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAmD1D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ghagga memory stats` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Displays aggregate statistics about the memory database including
|
|
5
|
+
* observation counts by type and project, file size, and date range.
|
|
6
|
+
*
|
|
7
|
+
* @see R11, S25–S27
|
|
8
|
+
*/
|
|
9
|
+
import { statSync } from 'node:fs';
|
|
10
|
+
import { openMemoryOrExit, formatSize } from './utils.js';
|
|
11
|
+
import * as tui from '../../ui/tui.js';
|
|
12
|
+
export function registerStatsCommand(parent) {
|
|
13
|
+
parent
|
|
14
|
+
.command('stats')
|
|
15
|
+
.description('Show memory database statistics')
|
|
16
|
+
.action(async () => {
|
|
17
|
+
const { storage, dbPath } = await openMemoryOrExit();
|
|
18
|
+
try {
|
|
19
|
+
const stats = await storage.getStats();
|
|
20
|
+
const fileSize = statSync(dbPath).size;
|
|
21
|
+
tui.log.info('Memory Database Statistics');
|
|
22
|
+
tui.log.message('\u2500'.repeat(26));
|
|
23
|
+
tui.log.message('');
|
|
24
|
+
tui.log.message(`Database: ${dbPath}`);
|
|
25
|
+
tui.log.message(`File Size: ${formatSize(fileSize)}`);
|
|
26
|
+
tui.log.message(`Observations: ${stats.totalObservations} total`);
|
|
27
|
+
tui.log.message('');
|
|
28
|
+
const oldest = stats.oldestObservation
|
|
29
|
+
? stats.oldestObservation.slice(0, 10)
|
|
30
|
+
: '(none)';
|
|
31
|
+
const newest = stats.newestObservation
|
|
32
|
+
? stats.newestObservation.slice(0, 10)
|
|
33
|
+
: '(none)';
|
|
34
|
+
tui.log.message(`Date Range: ${oldest} \u2014 ${newest}`);
|
|
35
|
+
tui.log.message('');
|
|
36
|
+
tui.log.message('By Type:');
|
|
37
|
+
const typeEntries = Object.entries(stats.byType);
|
|
38
|
+
if (typeEntries.length === 0) {
|
|
39
|
+
tui.log.message(' (none)');
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
for (const [type, count] of typeEntries) {
|
|
43
|
+
tui.log.message(` ${type.padEnd(14)}${count}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
tui.log.message('');
|
|
47
|
+
tui.log.message('By Project:');
|
|
48
|
+
const projectEntries = Object.entries(stats.byProject);
|
|
49
|
+
if (projectEntries.length === 0) {
|
|
50
|
+
tui.log.message(' (none)');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
for (const [project, count] of projectEntries) {
|
|
54
|
+
tui.log.message(` ${project.padEnd(14)}${count}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
await storage.close();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/commands/memory/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `ghagga memory stats` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Mocks ghagga-core (SqliteMemoryStorage) and node:fs (existsSync, statSync).
|
|
5
|
+
* Tests happy path full output, empty DB, and no DB file.
|
|
6
|
+
*
|
|
7
|
+
* @see T7.6, S25–S27
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=stats.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.test.d.ts","sourceRoot":"","sources":["../../../src/commands/memory/stats.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `ghagga memory stats` subcommand.
|
|
3
|
+
*
|
|
4
|
+
* Mocks ghagga-core (SqliteMemoryStorage) and node:fs (existsSync, statSync).
|
|
5
|
+
* Tests happy path full output, empty DB, and no DB file.
|
|
6
|
+
*
|
|
7
|
+
* @see T7.6, S25–S27
|
|
8
|
+
*/
|
|
9
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
// ─── Mocks ──────────────────────────────────────────────────────
|
|
12
|
+
const { mockGetStats, mockClose } = vi.hoisted(() => ({
|
|
13
|
+
mockGetStats: vi.fn(),
|
|
14
|
+
mockClose: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
vi.mock('ghagga-core', () => ({
|
|
17
|
+
SqliteMemoryStorage: {
|
|
18
|
+
create: vi.fn().mockResolvedValue({
|
|
19
|
+
getStats: (...args) => mockGetStats(...args),
|
|
20
|
+
close: (...args) => mockClose(...args),
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
23
|
+
}));
|
|
24
|
+
vi.mock('node:fs', () => ({
|
|
25
|
+
existsSync: vi.fn().mockReturnValue(true),
|
|
26
|
+
statSync: vi.fn().mockReturnValue({ size: 2457600 }),
|
|
27
|
+
}));
|
|
28
|
+
vi.mock('../../lib/config.js', () => ({
|
|
29
|
+
getConfigDir: vi.fn().mockReturnValue('/mock-config'),
|
|
30
|
+
}));
|
|
31
|
+
import { existsSync, statSync } from 'node:fs';
|
|
32
|
+
import { registerStatsCommand } from './stats.js';
|
|
33
|
+
const mockExistsSync = vi.mocked(existsSync);
|
|
34
|
+
const mockStatSync = vi.mocked(statSync);
|
|
35
|
+
// ─── Helpers ────────────────────────────────────────────────────
|
|
36
|
+
function makeStats(overrides = {}) {
|
|
37
|
+
return {
|
|
38
|
+
totalObservations: 147,
|
|
39
|
+
byType: { pattern: 68, bugfix: 42, learning: 21 },
|
|
40
|
+
byProject: { 'acme/widgets': 89, 'acme/gadgets': 45, 'acme/platform': 13 },
|
|
41
|
+
oldestObservation: '2025-01-15T00:00:00Z',
|
|
42
|
+
newestObservation: '2025-03-06T00:00:00Z',
|
|
43
|
+
...overrides,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
async function runStatsCommand() {
|
|
47
|
+
const parent = new Command('memory');
|
|
48
|
+
registerStatsCommand(parent);
|
|
49
|
+
await parent.parseAsync(['stats'], { from: 'user' });
|
|
50
|
+
}
|
|
51
|
+
// ─── Setup ──────────────────────────────────────────────────────
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
+
let logSpy;
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
let exitSpy;
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
vi.clearAllMocks();
|
|
58
|
+
logSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
59
|
+
exitSpy = vi.spyOn(process, 'exit').mockImplementation((() => { }));
|
|
60
|
+
mockExistsSync.mockReturnValue(true);
|
|
61
|
+
mockStatSync.mockReturnValue({ size: 2457600 });
|
|
62
|
+
});
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
logSpy.mockRestore();
|
|
65
|
+
exitSpy.mockRestore();
|
|
66
|
+
});
|
|
67
|
+
// ─── Tests ──────────────────────────────────────────────────────
|
|
68
|
+
describe('ghagga memory stats', () => {
|
|
69
|
+
it('displays full statistics on happy path', async () => {
|
|
70
|
+
mockGetStats.mockResolvedValue(makeStats());
|
|
71
|
+
await runStatsCommand();
|
|
72
|
+
const output = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
73
|
+
// Header
|
|
74
|
+
expect(output).toContain('Memory Database Statistics');
|
|
75
|
+
expect(output).toContain('──────────');
|
|
76
|
+
// DB info
|
|
77
|
+
expect(output).toContain('/mock-config');
|
|
78
|
+
expect(output).toContain('2.3 MB');
|
|
79
|
+
// Totals
|
|
80
|
+
expect(output).toContain('147 total');
|
|
81
|
+
// Date range
|
|
82
|
+
expect(output).toContain('2025-01-15');
|
|
83
|
+
expect(output).toContain('2025-03-06');
|
|
84
|
+
// By type
|
|
85
|
+
expect(output).toContain('By Type:');
|
|
86
|
+
expect(output).toContain('pattern');
|
|
87
|
+
expect(output).toContain('68');
|
|
88
|
+
expect(output).toContain('bugfix');
|
|
89
|
+
expect(output).toContain('42');
|
|
90
|
+
// By project
|
|
91
|
+
expect(output).toContain('By Project:');
|
|
92
|
+
expect(output).toContain('acme/widgets');
|
|
93
|
+
expect(output).toContain('89');
|
|
94
|
+
});
|
|
95
|
+
it('displays (none) for date range and sections when DB is empty', async () => {
|
|
96
|
+
mockGetStats.mockResolvedValue(makeStats({
|
|
97
|
+
totalObservations: 0,
|
|
98
|
+
byType: {},
|
|
99
|
+
byProject: {},
|
|
100
|
+
oldestObservation: null,
|
|
101
|
+
newestObservation: null,
|
|
102
|
+
}));
|
|
103
|
+
await runStatsCommand();
|
|
104
|
+
const output = logSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
105
|
+
expect(output).toContain('0 total');
|
|
106
|
+
// (none) for empty sections
|
|
107
|
+
const noneCount = (output.match(/\(none\)/g) || []).length;
|
|
108
|
+
expect(noneCount).toBeGreaterThanOrEqual(3); // date range (none) — (none), byType (none), byProject (none)
|
|
109
|
+
});
|
|
110
|
+
it('prints no-DB message and exits 0 when database file is missing', async () => {
|
|
111
|
+
mockExistsSync.mockReturnValue(false);
|
|
112
|
+
await runStatsCommand();
|
|
113
|
+
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('No memory database found'));
|
|
114
|
+
expect(exitSpy).toHaveBeenCalledWith(0);
|
|
115
|
+
});
|
|
116
|
+
it('closes storage after execution', async () => {
|
|
117
|
+
mockGetStats.mockResolvedValue(makeStats());
|
|
118
|
+
await runStatsCommand();
|
|
119
|
+
expect(mockClose).toHaveBeenCalled();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
//# sourceMappingURL=stats.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.test.js","sourceRoot":"","sources":["../../../src/commands/memory/stats.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for the `ghagga memory` command group.
|
|
3
|
+
*
|
|
4
|
+
* Provides database lifecycle management, confirmation prompts,
|
|
5
|
+
* and plain-text formatting helpers used by all subcommands.
|
|
6
|
+
*/
|
|
7
|
+
import { SqliteMemoryStorage } from 'ghagga-core';
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the DB path, check existence, and open storage.
|
|
10
|
+
* Prints a message and exits 0 if the DB file doesn't exist.
|
|
11
|
+
* Returns the storage instance and resolved dbPath.
|
|
12
|
+
*/
|
|
13
|
+
export declare function openMemoryOrExit(): Promise<{
|
|
14
|
+
storage: SqliteMemoryStorage;
|
|
15
|
+
dbPath: string;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Handle confirmation flow for destructive operations.
|
|
19
|
+
*
|
|
20
|
+
* - force=true: returns immediately (no prompt)
|
|
21
|
+
* - Non-TTY without force: prints error, exits 1
|
|
22
|
+
* - TTY without force: prompts, exits 0 on cancel
|
|
23
|
+
*/
|
|
24
|
+
export declare function confirmOrExit(message: string, force: boolean): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Format a plain-text table with headers, separator, and padded columns.
|
|
27
|
+
* No ANSI colors — plain text only (CC3).
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatTable(headers: string[], rows: string[][], widths: number[]): string;
|
|
30
|
+
/**
|
|
31
|
+
* Format bytes as human-readable size (AD8).
|
|
32
|
+
* < 1024: "N bytes", < 1MB: "N.N KB", else "N.N MB"
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatSize(bytes: number): string;
|
|
35
|
+
/**
|
|
36
|
+
* Format observation ID as 8-char zero-padded string (AD5, CC5).
|
|
37
|
+
* ID 42 -> "00000042"
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatId(id: number): string;
|
|
40
|
+
/**
|
|
41
|
+
* Truncate a string to maxLen characters, appending "..." if truncated.
|
|
42
|
+
*/
|
|
43
|
+
export declare function truncate(str: string, maxLen: number): string;
|
|
44
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/commands/memory/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAelD;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC;IAChD,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAWD;AAID;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,IAAI,CAAC,CAuBf;AAKD;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,MAAM,EAAE,EAAE,EAChB,MAAM,EAAE,MAAM,EAAE,GACf,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5D"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for the `ghagga memory` command group.
|
|
3
|
+
*
|
|
4
|
+
* Provides database lifecycle management, confirmation prompts,
|
|
5
|
+
* and plain-text formatting helpers used by all subcommands.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { createInterface } from 'node:readline/promises';
|
|
10
|
+
import { SqliteMemoryStorage } from 'ghagga-core';
|
|
11
|
+
import { getConfigDir } from '../../lib/config.js';
|
|
12
|
+
import * as tui from '../../ui/tui.js';
|
|
13
|
+
import { formatTable as _formatTable, formatSize as _formatSize, formatId as _formatId, truncate as _truncate, } from '../../ui/format.js';
|
|
14
|
+
// ─── Database Lifecycle ─────────────────────────────────────────
|
|
15
|
+
const NO_DB_MESSAGE = 'No memory database found. Run "ghagga review" first to build memory.';
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the DB path, check existence, and open storage.
|
|
18
|
+
* Prints a message and exits 0 if the DB file doesn't exist.
|
|
19
|
+
* Returns the storage instance and resolved dbPath.
|
|
20
|
+
*/
|
|
21
|
+
export async function openMemoryOrExit() {
|
|
22
|
+
const configDir = getConfigDir();
|
|
23
|
+
const dbPath = join(configDir, 'memory.db');
|
|
24
|
+
if (!existsSync(dbPath)) {
|
|
25
|
+
tui.log.info(NO_DB_MESSAGE);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
}
|
|
28
|
+
const storage = await SqliteMemoryStorage.create(dbPath);
|
|
29
|
+
return { storage, dbPath };
|
|
30
|
+
}
|
|
31
|
+
// ─── Confirmation ───────────────────────────────────────────────
|
|
32
|
+
/**
|
|
33
|
+
* Handle confirmation flow for destructive operations.
|
|
34
|
+
*
|
|
35
|
+
* - force=true: returns immediately (no prompt)
|
|
36
|
+
* - Non-TTY without force: prints error, exits 1
|
|
37
|
+
* - TTY without force: prompts, exits 0 on cancel
|
|
38
|
+
*/
|
|
39
|
+
export async function confirmOrExit(message, force) {
|
|
40
|
+
if (force)
|
|
41
|
+
return;
|
|
42
|
+
if (!process.stdin.isTTY) {
|
|
43
|
+
tui.log.error('Error: Destructive operation requires --force in non-interactive mode.');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const rl = createInterface({
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stdout,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
const answer = await rl.question(message);
|
|
52
|
+
if (answer.trim().toLowerCase() !== 'y') {
|
|
53
|
+
tui.log.info('Cancelled.');
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
rl.close();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ─── Formatting Helpers ─────────────────────────────────────────
|
|
62
|
+
// Re-exported from ui/format.js — kept here for backwards compatibility.
|
|
63
|
+
/**
|
|
64
|
+
* Format a plain-text table with headers, separator, and padded columns.
|
|
65
|
+
* No ANSI colors — plain text only (CC3).
|
|
66
|
+
*/
|
|
67
|
+
export function formatTable(headers, rows, widths) {
|
|
68
|
+
return _formatTable(headers, rows, widths);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Format bytes as human-readable size (AD8).
|
|
72
|
+
* < 1024: "N bytes", < 1MB: "N.N KB", else "N.N MB"
|
|
73
|
+
*/
|
|
74
|
+
export function formatSize(bytes) {
|
|
75
|
+
return _formatSize(bytes);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Format observation ID as 8-char zero-padded string (AD5, CC5).
|
|
79
|
+
* ID 42 -> "00000042"
|
|
80
|
+
*/
|
|
81
|
+
export function formatId(id) {
|
|
82
|
+
return _formatId(id);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Truncate a string to maxLen characters, appending "..." if truncated.
|
|
86
|
+
*/
|
|
87
|
+
export function truncate(str, maxLen) {
|
|
88
|
+
return _truncate(str, maxLen);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/commands/memory/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,GAAG,MAAM,iBAAiB,CAAC;AACvC,OAAO,EACL,WAAW,IAAI,YAAY,EAC3B,UAAU,IAAI,WAAW,EACzB,QAAQ,IAAI,SAAS,EACrB,QAAQ,IAAI,SAAS,GACtB,MAAM,oBAAoB,CAAC;AAE5B,mEAAmE;AAEnE,MAAM,aAAa,GACjB,sEAAsE,CAAC;AAEzE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IAIpC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAE5C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzD,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED,mEAAmE;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,KAAc;IAEd,IAAI,KAAK;QAAE,OAAO;IAElB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACzB,GAAG,CAAC,GAAG,CAAC,KAAK,CACX,wEAAwE,CACzE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,EAAE,GAAG,eAAe,CAAC;QACzB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG,EAAE,CAAC;YACxC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,yEAAyE;AAEzE;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,OAAiB,EACjB,IAAgB,EAChB,MAAgB;IAEhB,OAAO,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,OAAO,SAAS,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAW,EAAE,MAAc;IAClD,OAAO,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../../src/commands/memory/utils.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|