gogcli-mcp 2.7.1 → 2.18.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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +20220 -19700
- package/dist/lib.js +15847 -23331
- package/manifest.json +33 -1
- package/package.json +7 -6
- package/server.json +2 -2
- package/src/connector-auth.ts +46 -0
- package/src/connector-runtime.ts +177 -0
- package/src/index.ts +7 -5
- package/src/lib.ts +8 -7
- package/src/runner.ts +225 -30
- package/src/server.ts +21 -25
- package/src/tools/api.ts +65 -0
- package/src/tools/auth.ts +112 -15
- package/src/tools/calendar.ts +24 -9
- package/src/tools/docs.ts +30 -3
- package/src/tools/drive.ts +124 -1
- package/src/tools/gmail.ts +7 -3
- package/src/tools/sheets.ts +6 -3
- package/src/tools/slides.ts +9 -4
- package/src/tools/tasks.ts +3 -1
- package/src/tools/utils.ts +163 -27
- package/src/worker.ts +99 -0
- package/tests/connector-auth.test.ts +28 -0
- package/tests/connector-runtime.test.ts +474 -0
- package/tests/runner-file-args-failure.test.ts +94 -0
- package/tests/runner-file-args.test.ts +232 -0
- package/tests/runner.test.ts +221 -13
- package/tests/server.test.ts +28 -28
- package/tests/tools/api.test.ts +107 -0
- package/tests/tools/auth.test.ts +187 -31
- package/tests/tools/calendar.test.ts +115 -52
- package/tests/tools/classroom.test.ts +77 -77
- package/tests/tools/contacts.test.ts +24 -24
- package/tests/tools/docs.test.ts +93 -44
- package/tests/tools/drive.test.ts +226 -55
- package/tests/tools/gmail.test.ts +61 -28
- package/tests/tools/sheets.test.ts +81 -70
- package/tests/tools/slides.test.ts +56 -36
- package/tests/tools/tasks.test.ts +33 -33
- package/tests/tools/utils.test.ts +116 -2
- package/tests/worker.test.ts +142 -0
- package/tsconfig.json +4 -1
- package/vitest.config.ts +33 -2
- package/tests/helpers/test-harness.ts +0 -27
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { registerContactsTools } from '../../src/tools/contacts.js';
|
|
3
3
|
import * as runner from '../../src/runner.js';
|
|
4
|
-
import {
|
|
4
|
+
import { createTestHarness } from '@chrischall/mcp-utils/test';
|
|
5
5
|
|
|
6
6
|
vi.mock('../../src/runner.js');
|
|
7
7
|
|
|
8
|
-
const setupHandlers = () =>
|
|
8
|
+
const setupHandlers = () => createTestHarness(registerContactsTools);
|
|
9
9
|
|
|
10
10
|
beforeEach(() => vi.clearAllMocks());
|
|
11
11
|
|
|
12
12
|
describe('gog_contacts_search', () => {
|
|
13
13
|
it('calls run with query', async () => {
|
|
14
14
|
vi.mocked(runner.run).mockResolvedValue('{"connections":[]}');
|
|
15
|
-
const
|
|
16
|
-
await
|
|
15
|
+
const harness = await setupHandlers();
|
|
16
|
+
await harness.callTool('gog_contacts_search', { query: 'alice' });
|
|
17
17
|
expect(runner.run).toHaveBeenCalledWith(['contacts', 'search', 'alice'], { account: undefined });
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it('returns error text on failure', async () => {
|
|
21
21
|
vi.mocked(runner.run).mockRejectedValue(new Error('Search failed'));
|
|
22
|
-
const
|
|
23
|
-
const result = await
|
|
22
|
+
const harness = await setupHandlers();
|
|
23
|
+
const result = await harness.callTool('gog_contacts_search', { query: 'x' });
|
|
24
24
|
expect(result.content[0].text).toBe('Error: Search failed');
|
|
25
25
|
});
|
|
26
26
|
});
|
|
@@ -28,15 +28,15 @@ describe('gog_contacts_search', () => {
|
|
|
28
28
|
describe('gog_contacts_list', () => {
|
|
29
29
|
it('calls run with contacts list', async () => {
|
|
30
30
|
vi.mocked(runner.run).mockResolvedValue('{"connections":[]}');
|
|
31
|
-
const
|
|
32
|
-
await
|
|
31
|
+
const harness = await setupHandlers();
|
|
32
|
+
await harness.callTool('gog_contacts_list', {});
|
|
33
33
|
expect(runner.run).toHaveBeenCalledWith(['contacts', 'list'], { account: undefined });
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
it('returns error text on failure', async () => {
|
|
37
37
|
vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
|
|
38
|
-
const
|
|
39
|
-
const result = await
|
|
38
|
+
const harness = await setupHandlers();
|
|
39
|
+
const result = await harness.callTool('gog_contacts_list', {});
|
|
40
40
|
expect(result.content[0].text).toBe('Error: List failed');
|
|
41
41
|
});
|
|
42
42
|
});
|
|
@@ -44,15 +44,15 @@ describe('gog_contacts_list', () => {
|
|
|
44
44
|
describe('gog_contacts_get', () => {
|
|
45
45
|
it('calls run with resourceName', async () => {
|
|
46
46
|
vi.mocked(runner.run).mockResolvedValue('{"resourceName":"people/c123"}');
|
|
47
|
-
const
|
|
48
|
-
await
|
|
47
|
+
const harness = await setupHandlers();
|
|
48
|
+
await harness.callTool('gog_contacts_get', { resourceName: 'people/c123' });
|
|
49
49
|
expect(runner.run).toHaveBeenCalledWith(['contacts', 'get', 'people/c123'], { account: undefined });
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
it('returns error text on failure', async () => {
|
|
53
53
|
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
54
|
-
const
|
|
55
|
-
const result = await
|
|
54
|
+
const harness = await setupHandlers();
|
|
55
|
+
const result = await harness.callTool('gog_contacts_get', { resourceName: 'bad' });
|
|
56
56
|
expect(result.content[0].text).toBe('Error: Not found');
|
|
57
57
|
});
|
|
58
58
|
});
|
|
@@ -60,15 +60,15 @@ describe('gog_contacts_get', () => {
|
|
|
60
60
|
describe('gog_contacts_create', () => {
|
|
61
61
|
it('calls run with required givenName', async () => {
|
|
62
62
|
vi.mocked(runner.run).mockResolvedValue('{"resourceName":"people/c456"}');
|
|
63
|
-
const
|
|
64
|
-
await
|
|
63
|
+
const harness = await setupHandlers();
|
|
64
|
+
await harness.callTool('gog_contacts_create', { givenName: 'Alice' });
|
|
65
65
|
expect(runner.run).toHaveBeenCalledWith(['contacts', 'create', '--given=Alice'], { account: undefined });
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it('appends optional fields when provided', async () => {
|
|
69
69
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
70
|
-
const
|
|
71
|
-
await
|
|
70
|
+
const harness = await setupHandlers();
|
|
71
|
+
await harness.callTool('gog_contacts_create', {
|
|
72
72
|
givenName: 'Alice',
|
|
73
73
|
familyName: 'Smith',
|
|
74
74
|
email: 'alice@example.com',
|
|
@@ -88,8 +88,8 @@ describe('gog_contacts_create', () => {
|
|
|
88
88
|
|
|
89
89
|
it('returns error text on failure', async () => {
|
|
90
90
|
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
91
|
-
const
|
|
92
|
-
const result = await
|
|
91
|
+
const harness = await setupHandlers();
|
|
92
|
+
const result = await harness.callTool('gog_contacts_create', { givenName: 'Bad' });
|
|
93
93
|
expect(result.content[0].text).toBe('Error: Create failed');
|
|
94
94
|
});
|
|
95
95
|
});
|
|
@@ -97,15 +97,15 @@ describe('gog_contacts_create', () => {
|
|
|
97
97
|
describe('gog_contacts_run', () => {
|
|
98
98
|
it('passes subcommand and args to runner', async () => {
|
|
99
99
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
100
|
-
const
|
|
101
|
-
await
|
|
100
|
+
const harness = await setupHandlers();
|
|
101
|
+
await harness.callTool('gog_contacts_run', { subcommand: 'delete', args: ['people/c123'] });
|
|
102
102
|
expect(runner.run).toHaveBeenCalledWith(['contacts', 'delete', 'people/c123'], { account: undefined });
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
it('returns error text on failure', async () => {
|
|
106
106
|
vi.mocked(runner.run).mockRejectedValue(new Error('Run failed'));
|
|
107
|
-
const
|
|
108
|
-
const result = await
|
|
107
|
+
const harness = await setupHandlers();
|
|
108
|
+
const result = await harness.callTool('gog_contacts_run', { subcommand: 'update', args: [] });
|
|
109
109
|
expect(result.content[0].text).toBe('Error: Run failed');
|
|
110
110
|
});
|
|
111
111
|
});
|
package/tests/tools/docs.test.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
2
|
import { registerDocsTools } from '../../src/tools/docs.js';
|
|
3
3
|
import * as runner from '../../src/runner.js';
|
|
4
|
-
import {
|
|
4
|
+
import { createTestHarness } from '@chrischall/mcp-utils/test';
|
|
5
5
|
|
|
6
6
|
vi.mock('../../src/runner.js');
|
|
7
7
|
|
|
8
|
-
const setupHandlers = () =>
|
|
8
|
+
const setupHandlers = () => createTestHarness(registerDocsTools);
|
|
9
9
|
|
|
10
10
|
beforeEach(() => vi.clearAllMocks());
|
|
11
11
|
|
|
12
12
|
describe('gog_docs_info', () => {
|
|
13
13
|
it('calls run with correct args', async () => {
|
|
14
14
|
vi.mocked(runner.run).mockResolvedValue('{"title":"My Doc","docId":"abc"}');
|
|
15
|
-
const
|
|
16
|
-
const result = await
|
|
15
|
+
const harness = await setupHandlers();
|
|
16
|
+
const result = await harness.callTool('gog_docs_info', { docId: 'abc' });
|
|
17
17
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'info', 'abc'], { account: undefined });
|
|
18
18
|
expect(result.content[0].text).toContain('My Doc');
|
|
19
19
|
});
|
|
@@ -22,15 +22,15 @@ describe('gog_docs_info', () => {
|
|
|
22
22
|
vi.mocked(runner.run)
|
|
23
23
|
.mockRejectedValueOnce(new Error('Doc not found'))
|
|
24
24
|
.mockResolvedValueOnce('user@gmail.com');
|
|
25
|
-
const
|
|
26
|
-
const result = await
|
|
25
|
+
const harness = await setupHandlers();
|
|
26
|
+
const result = await harness.callTool('gog_docs_info', { docId: 'bad' });
|
|
27
27
|
expect(result.content[0].text).toBe('Error: Doc not found\n\nConfigured accounts:\nuser@gmail.com');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
it('returns plain error text when auth list also fails', async () => {
|
|
31
31
|
vi.mocked(runner.run).mockRejectedValue(new Error('Doc not found'));
|
|
32
|
-
const
|
|
33
|
-
const result = await
|
|
32
|
+
const harness = await setupHandlers();
|
|
33
|
+
const result = await harness.callTool('gog_docs_info', { docId: 'bad' });
|
|
34
34
|
expect(result.content[0].text).toBe('Error: Doc not found');
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -38,8 +38,8 @@ describe('gog_docs_info', () => {
|
|
|
38
38
|
vi.mocked(runner.run)
|
|
39
39
|
.mockRejectedValueOnce('raw error string')
|
|
40
40
|
.mockRejectedValueOnce(new Error('auth list failed'));
|
|
41
|
-
const
|
|
42
|
-
const result = await
|
|
41
|
+
const harness = await setupHandlers();
|
|
42
|
+
const result = await harness.callTool('gog_docs_info', { docId: 'bad' });
|
|
43
43
|
expect(result.content[0].text).toBe('raw error string');
|
|
44
44
|
});
|
|
45
45
|
});
|
|
@@ -47,23 +47,30 @@ describe('gog_docs_info', () => {
|
|
|
47
47
|
describe('gog_docs_cat', () => {
|
|
48
48
|
it('calls run with correct args', async () => {
|
|
49
49
|
vi.mocked(runner.run).mockResolvedValue('Hello world');
|
|
50
|
-
const
|
|
51
|
-
const result = await
|
|
50
|
+
const harness = await setupHandlers();
|
|
51
|
+
const result = await harness.callTool('gog_docs_cat', { docId: 'abc' });
|
|
52
52
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'cat', 'abc'], { account: undefined });
|
|
53
53
|
expect(result.content[0].text).toBe('Hello world');
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
it('forwards account override', async () => {
|
|
57
57
|
vi.mocked(runner.run).mockResolvedValue('text');
|
|
58
|
-
const
|
|
59
|
-
await
|
|
58
|
+
const harness = await setupHandlers();
|
|
59
|
+
await harness.callTool('gog_docs_cat', { docId: 'abc', account: 'other@gmail.com' });
|
|
60
60
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'cat', 'abc'], { account: 'other@gmail.com' });
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
it('appends --chips when requested', async () => {
|
|
64
|
+
vi.mocked(runner.run).mockResolvedValue('Hello @person');
|
|
65
|
+
const harness = await setupHandlers();
|
|
66
|
+
await harness.callTool('gog_docs_cat', { docId: 'abc', chips: true });
|
|
67
|
+
expect(runner.run).toHaveBeenCalledWith(['docs', 'cat', 'abc', '--chips'], { account: undefined });
|
|
68
|
+
});
|
|
69
|
+
|
|
63
70
|
it('returns error text on failure', async () => {
|
|
64
71
|
vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
|
|
65
|
-
const
|
|
66
|
-
const result = await
|
|
72
|
+
const harness = await setupHandlers();
|
|
73
|
+
const result = await harness.callTool('gog_docs_cat', { docId: 'bad' });
|
|
67
74
|
expect(result.content[0].text).toBe('Error: Not found');
|
|
68
75
|
});
|
|
69
76
|
});
|
|
@@ -71,15 +78,15 @@ describe('gog_docs_cat', () => {
|
|
|
71
78
|
describe('gog_docs_create', () => {
|
|
72
79
|
it('calls run with title', async () => {
|
|
73
80
|
vi.mocked(runner.run).mockResolvedValue('{"docId":"newid","title":"Meeting Notes"}');
|
|
74
|
-
const
|
|
75
|
-
await
|
|
81
|
+
const harness = await setupHandlers();
|
|
82
|
+
await harness.callTool('gog_docs_create', { title: 'Meeting Notes' });
|
|
76
83
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'create', 'Meeting Notes'], { account: undefined });
|
|
77
84
|
});
|
|
78
85
|
|
|
79
86
|
it('returns error text on failure', async () => {
|
|
80
87
|
vi.mocked(runner.run).mockRejectedValue(new Error('Create failed'));
|
|
81
|
-
const
|
|
82
|
-
const result = await
|
|
88
|
+
const harness = await setupHandlers();
|
|
89
|
+
const result = await harness.callTool('gog_docs_create', { title: 'Bad' });
|
|
83
90
|
expect(result.content[0].text).toBe('Error: Create failed');
|
|
84
91
|
});
|
|
85
92
|
});
|
|
@@ -87,26 +94,37 @@ describe('gog_docs_create', () => {
|
|
|
87
94
|
describe('gog_docs_write', () => {
|
|
88
95
|
it('calls run with text flag', async () => {
|
|
89
96
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
90
|
-
const
|
|
91
|
-
await
|
|
97
|
+
const harness = await setupHandlers();
|
|
98
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'Hello world' });
|
|
92
99
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'write', 'abc', '--text=Hello world'], { account: undefined });
|
|
93
100
|
});
|
|
94
101
|
|
|
95
102
|
it('adds --append flag when append is true', async () => {
|
|
96
103
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
97
|
-
const
|
|
98
|
-
await
|
|
104
|
+
const harness = await setupHandlers();
|
|
105
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'More text', append: true });
|
|
99
106
|
expect(runner.run).toHaveBeenCalledWith(
|
|
100
107
|
['docs', 'write', 'abc', '--text=More text', '--append'],
|
|
101
108
|
{ account: undefined },
|
|
102
109
|
);
|
|
103
110
|
});
|
|
104
111
|
|
|
112
|
+
// gog 0.25.0
|
|
113
|
+
it('appends to a persisted batch via --batch', async () => {
|
|
114
|
+
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
115
|
+
const harness = await setupHandlers();
|
|
116
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'T', batch: 'b1' });
|
|
117
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
118
|
+
['docs', 'write', 'abc', '--text=T', '--batch=b1'],
|
|
119
|
+
{ account: undefined },
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
105
123
|
// gog 0.24.0
|
|
106
124
|
it('adds --check-orphans when checkOrphans is true', async () => {
|
|
107
125
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
108
|
-
const
|
|
109
|
-
await
|
|
126
|
+
const harness = await setupHandlers();
|
|
127
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'Rewrite', checkOrphans: true });
|
|
110
128
|
expect(runner.run).toHaveBeenCalledWith(
|
|
111
129
|
['docs', 'write', 'abc', '--text=Rewrite', '--check-orphans'],
|
|
112
130
|
{ account: undefined },
|
|
@@ -115,15 +133,46 @@ describe('gog_docs_write', () => {
|
|
|
115
133
|
|
|
116
134
|
it('omits --append flag when append is false', async () => {
|
|
117
135
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
118
|
-
const
|
|
119
|
-
await
|
|
136
|
+
const harness = await setupHandlers();
|
|
137
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'text', append: false });
|
|
120
138
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'write', 'abc', '--text=text'], { account: undefined });
|
|
121
139
|
});
|
|
122
140
|
|
|
141
|
+
// gog 0.30.0 paragraph list / indentation / spacing / keep controls
|
|
142
|
+
it('adds bullets, numbering, indentation, spacing and keep flags (keep=true)', async () => {
|
|
143
|
+
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
144
|
+
const harness = await setupHandlers();
|
|
145
|
+
await harness.callTool('gog_docs_write', {
|
|
146
|
+
docId: 'abc', text: 'List', bullets: true, bulletPreset: 'BULLET_DISC_CIRCLE_SQUARE',
|
|
147
|
+
indentStart: 18, indentEnd: 6, indentFirstLine: 36, spaceAbove: 4, spaceBelow: 8,
|
|
148
|
+
keepLinesTogether: true, keepWithNext: true,
|
|
149
|
+
});
|
|
150
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
151
|
+
['docs', 'write', 'abc', '--text=List', '--bullets', '--bullet-preset=BULLET_DISC_CIRCLE_SQUARE',
|
|
152
|
+
'--indent-start=18', '--indent-end=6', '--indent-first-line=36', '--space-above=4', '--space-below=8',
|
|
153
|
+
'--keep-lines-together', '--keep-with-next'],
|
|
154
|
+
{ account: undefined },
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('uses numbered list and negated keep flags (keep=false)', async () => {
|
|
159
|
+
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
160
|
+
const harness = await setupHandlers();
|
|
161
|
+
await harness.callTool('gog_docs_write', {
|
|
162
|
+
docId: 'abc', text: 'Steps', ordered: true, noBullets: true,
|
|
163
|
+
keepLinesTogether: false, keepWithNext: false,
|
|
164
|
+
});
|
|
165
|
+
expect(runner.run).toHaveBeenCalledWith(
|
|
166
|
+
['docs', 'write', 'abc', '--text=Steps', '--ordered', '--no-bullets',
|
|
167
|
+
'--no-keep-lines-together', '--no-keep-with-next'],
|
|
168
|
+
{ account: undefined },
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
123
172
|
it('returns error text on failure', async () => {
|
|
124
173
|
vi.mocked(runner.run).mockRejectedValue(new Error('Write failed'));
|
|
125
|
-
const
|
|
126
|
-
const result = await
|
|
174
|
+
const harness = await setupHandlers();
|
|
175
|
+
const result = await harness.callTool('gog_docs_write', { docId: 'bad', text: 'x' });
|
|
127
176
|
expect(result.content[0].text).toBe('Error: Write failed');
|
|
128
177
|
});
|
|
129
178
|
});
|
|
@@ -131,15 +180,15 @@ describe('gog_docs_write', () => {
|
|
|
131
180
|
describe('gog_docs_find_replace', () => {
|
|
132
181
|
it('calls run with find and replace args', async () => {
|
|
133
182
|
vi.mocked(runner.run).mockResolvedValue('{"occurrencesChanged":2}');
|
|
134
|
-
const
|
|
135
|
-
await
|
|
183
|
+
const harness = await setupHandlers();
|
|
184
|
+
await harness.callTool('gog_docs_find_replace', { docId: 'abc', find: 'foo', replace: 'bar' });
|
|
136
185
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'find-replace', 'abc', 'foo', 'bar'], { account: undefined });
|
|
137
186
|
});
|
|
138
187
|
|
|
139
188
|
it('returns error text on failure', async () => {
|
|
140
189
|
vi.mocked(runner.run).mockRejectedValue(new Error('Replace failed'));
|
|
141
|
-
const
|
|
142
|
-
const result = await
|
|
190
|
+
const harness = await setupHandlers();
|
|
191
|
+
const result = await harness.callTool('gog_docs_find_replace', { docId: 'bad', find: 'x', replace: 'y' });
|
|
143
192
|
expect(result.content[0].text).toBe('Error: Replace failed');
|
|
144
193
|
});
|
|
145
194
|
});
|
|
@@ -147,16 +196,16 @@ describe('gog_docs_find_replace', () => {
|
|
|
147
196
|
describe('gog_docs_structure', () => {
|
|
148
197
|
it('calls run with correct args', async () => {
|
|
149
198
|
vi.mocked(runner.run).mockResolvedValue('[1] Heading\n[2] Paragraph');
|
|
150
|
-
const
|
|
151
|
-
const result = await
|
|
199
|
+
const harness = await setupHandlers();
|
|
200
|
+
const result = await harness.callTool('gog_docs_structure', { docId: 'abc' });
|
|
152
201
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'structure', 'abc'], { account: undefined });
|
|
153
202
|
expect(result.content[0].text).toContain('Heading');
|
|
154
203
|
});
|
|
155
204
|
|
|
156
205
|
it('returns error text on failure', async () => {
|
|
157
206
|
vi.mocked(runner.run).mockRejectedValue(new Error('Structure failed'));
|
|
158
|
-
const
|
|
159
|
-
const result = await
|
|
207
|
+
const harness = await setupHandlers();
|
|
208
|
+
const result = await harness.callTool('gog_docs_structure', { docId: 'bad' });
|
|
160
209
|
expect(result.content[0].text).toBe('Error: Structure failed');
|
|
161
210
|
});
|
|
162
211
|
});
|
|
@@ -164,22 +213,22 @@ describe('gog_docs_structure', () => {
|
|
|
164
213
|
describe('gog_docs_run', () => {
|
|
165
214
|
it('passes raw subcommand and args to runner', async () => {
|
|
166
215
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
167
|
-
const
|
|
168
|
-
await
|
|
216
|
+
const harness = await setupHandlers();
|
|
217
|
+
await harness.callTool('gog_docs_run', { subcommand: 'copy', args: ['abc', 'My Copy'] });
|
|
169
218
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'copy', 'abc', 'My Copy'], { account: undefined });
|
|
170
219
|
});
|
|
171
220
|
|
|
172
221
|
it('works with empty args array', async () => {
|
|
173
222
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
174
|
-
const
|
|
175
|
-
await
|
|
223
|
+
const harness = await setupHandlers();
|
|
224
|
+
await harness.callTool('gog_docs_run', { subcommand: 'clear', args: [] });
|
|
176
225
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'clear'], { account: undefined });
|
|
177
226
|
});
|
|
178
227
|
|
|
179
228
|
it('returns error text on failure', async () => {
|
|
180
229
|
vi.mocked(runner.run).mockRejectedValue(new Error('Run failed'));
|
|
181
|
-
const
|
|
182
|
-
const result = await
|
|
230
|
+
const harness = await setupHandlers();
|
|
231
|
+
const result = await harness.callTool('gog_docs_run', { subcommand: 'clear', args: [] });
|
|
183
232
|
expect(result.content[0].text).toBe('Error: Run failed');
|
|
184
233
|
});
|
|
185
234
|
});
|