gogcli-mcp 2.8.0 → 2.18.1
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 +20218 -19700
- package/dist/lib.js +15845 -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 +28 -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 +84 -46
- 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,15 +94,15 @@ 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 },
|
|
@@ -105,8 +112,8 @@ describe('gog_docs_write', () => {
|
|
|
105
112
|
// gog 0.25.0
|
|
106
113
|
it('appends to a persisted batch via --batch', async () => {
|
|
107
114
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
108
|
-
const
|
|
109
|
-
await
|
|
115
|
+
const harness = await setupHandlers();
|
|
116
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'T', batch: 'b1' });
|
|
110
117
|
expect(runner.run).toHaveBeenCalledWith(
|
|
111
118
|
['docs', 'write', 'abc', '--text=T', '--batch=b1'],
|
|
112
119
|
{ account: undefined },
|
|
@@ -116,8 +123,8 @@ describe('gog_docs_write', () => {
|
|
|
116
123
|
// gog 0.24.0
|
|
117
124
|
it('adds --check-orphans when checkOrphans is true', async () => {
|
|
118
125
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
119
|
-
const
|
|
120
|
-
await
|
|
126
|
+
const harness = await setupHandlers();
|
|
127
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'Rewrite', checkOrphans: true });
|
|
121
128
|
expect(runner.run).toHaveBeenCalledWith(
|
|
122
129
|
['docs', 'write', 'abc', '--text=Rewrite', '--check-orphans'],
|
|
123
130
|
{ account: undefined },
|
|
@@ -126,15 +133,46 @@ describe('gog_docs_write', () => {
|
|
|
126
133
|
|
|
127
134
|
it('omits --append flag when append is false', async () => {
|
|
128
135
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
129
|
-
const
|
|
130
|
-
await
|
|
136
|
+
const harness = await setupHandlers();
|
|
137
|
+
await harness.callTool('gog_docs_write', { docId: 'abc', text: 'text', append: false });
|
|
131
138
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'write', 'abc', '--text=text'], { account: undefined });
|
|
132
139
|
});
|
|
133
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
|
+
|
|
134
172
|
it('returns error text on failure', async () => {
|
|
135
173
|
vi.mocked(runner.run).mockRejectedValue(new Error('Write failed'));
|
|
136
|
-
const
|
|
137
|
-
const result = await
|
|
174
|
+
const harness = await setupHandlers();
|
|
175
|
+
const result = await harness.callTool('gog_docs_write', { docId: 'bad', text: 'x' });
|
|
138
176
|
expect(result.content[0].text).toBe('Error: Write failed');
|
|
139
177
|
});
|
|
140
178
|
});
|
|
@@ -142,15 +180,15 @@ describe('gog_docs_write', () => {
|
|
|
142
180
|
describe('gog_docs_find_replace', () => {
|
|
143
181
|
it('calls run with find and replace args', async () => {
|
|
144
182
|
vi.mocked(runner.run).mockResolvedValue('{"occurrencesChanged":2}');
|
|
145
|
-
const
|
|
146
|
-
await
|
|
183
|
+
const harness = await setupHandlers();
|
|
184
|
+
await harness.callTool('gog_docs_find_replace', { docId: 'abc', find: 'foo', replace: 'bar' });
|
|
147
185
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'find-replace', 'abc', 'foo', 'bar'], { account: undefined });
|
|
148
186
|
});
|
|
149
187
|
|
|
150
188
|
it('returns error text on failure', async () => {
|
|
151
189
|
vi.mocked(runner.run).mockRejectedValue(new Error('Replace failed'));
|
|
152
|
-
const
|
|
153
|
-
const result = await
|
|
190
|
+
const harness = await setupHandlers();
|
|
191
|
+
const result = await harness.callTool('gog_docs_find_replace', { docId: 'bad', find: 'x', replace: 'y' });
|
|
154
192
|
expect(result.content[0].text).toBe('Error: Replace failed');
|
|
155
193
|
});
|
|
156
194
|
});
|
|
@@ -158,16 +196,16 @@ describe('gog_docs_find_replace', () => {
|
|
|
158
196
|
describe('gog_docs_structure', () => {
|
|
159
197
|
it('calls run with correct args', async () => {
|
|
160
198
|
vi.mocked(runner.run).mockResolvedValue('[1] Heading\n[2] Paragraph');
|
|
161
|
-
const
|
|
162
|
-
const result = await
|
|
199
|
+
const harness = await setupHandlers();
|
|
200
|
+
const result = await harness.callTool('gog_docs_structure', { docId: 'abc' });
|
|
163
201
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'structure', 'abc'], { account: undefined });
|
|
164
202
|
expect(result.content[0].text).toContain('Heading');
|
|
165
203
|
});
|
|
166
204
|
|
|
167
205
|
it('returns error text on failure', async () => {
|
|
168
206
|
vi.mocked(runner.run).mockRejectedValue(new Error('Structure failed'));
|
|
169
|
-
const
|
|
170
|
-
const result = await
|
|
207
|
+
const harness = await setupHandlers();
|
|
208
|
+
const result = await harness.callTool('gog_docs_structure', { docId: 'bad' });
|
|
171
209
|
expect(result.content[0].text).toBe('Error: Structure failed');
|
|
172
210
|
});
|
|
173
211
|
});
|
|
@@ -175,22 +213,22 @@ describe('gog_docs_structure', () => {
|
|
|
175
213
|
describe('gog_docs_run', () => {
|
|
176
214
|
it('passes raw subcommand and args to runner', async () => {
|
|
177
215
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
178
|
-
const
|
|
179
|
-
await
|
|
216
|
+
const harness = await setupHandlers();
|
|
217
|
+
await harness.callTool('gog_docs_run', { subcommand: 'copy', args: ['abc', 'My Copy'] });
|
|
180
218
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'copy', 'abc', 'My Copy'], { account: undefined });
|
|
181
219
|
});
|
|
182
220
|
|
|
183
221
|
it('works with empty args array', async () => {
|
|
184
222
|
vi.mocked(runner.run).mockResolvedValue('{}');
|
|
185
|
-
const
|
|
186
|
-
await
|
|
223
|
+
const harness = await setupHandlers();
|
|
224
|
+
await harness.callTool('gog_docs_run', { subcommand: 'clear', args: [] });
|
|
187
225
|
expect(runner.run).toHaveBeenCalledWith(['docs', 'clear'], { account: undefined });
|
|
188
226
|
});
|
|
189
227
|
|
|
190
228
|
it('returns error text on failure', async () => {
|
|
191
229
|
vi.mocked(runner.run).mockRejectedValue(new Error('Run failed'));
|
|
192
|
-
const
|
|
193
|
-
const result = await
|
|
230
|
+
const harness = await setupHandlers();
|
|
231
|
+
const result = await harness.callTool('gog_docs_run', { subcommand: 'clear', args: [] });
|
|
194
232
|
expect(result.content[0].text).toBe('Error: Run failed');
|
|
195
233
|
});
|
|
196
234
|
});
|