gogcli-mcp 1.0.5 → 1.0.6

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 (47) hide show
  1. package/README.md +23 -125
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +5340 -5393
  5. package/dist/lib.d.ts +6 -0
  6. package/dist/lib.d.ts.map +1 -0
  7. package/dist/lib.js +30837 -0
  8. package/dist/runner.d.ts +12 -0
  9. package/dist/runner.d.ts.map +1 -0
  10. package/dist/server.d.ts +7 -0
  11. package/dist/server.d.ts.map +1 -0
  12. package/dist/tools/auth.d.ts +3 -0
  13. package/dist/tools/auth.d.ts.map +1 -0
  14. package/dist/tools/calendar.d.ts +3 -0
  15. package/dist/tools/calendar.d.ts.map +1 -0
  16. package/dist/tools/contacts.d.ts +3 -0
  17. package/dist/tools/contacts.d.ts.map +1 -0
  18. package/dist/tools/docs.d.ts +3 -0
  19. package/dist/tools/docs.d.ts.map +1 -0
  20. package/dist/tools/drive.d.ts +3 -0
  21. package/dist/tools/drive.d.ts.map +1 -0
  22. package/dist/tools/gmail.d.ts +3 -0
  23. package/dist/tools/gmail.d.ts.map +1 -0
  24. package/dist/tools/sheets.d.ts +3 -0
  25. package/dist/tools/sheets.d.ts.map +1 -0
  26. package/dist/tools/tasks.d.ts +3 -0
  27. package/dist/tools/tasks.d.ts.map +1 -0
  28. package/dist/tools/utils.d.ts +14 -0
  29. package/dist/tools/utils.d.ts.map +1 -0
  30. package/manifest.json +1 -1
  31. package/package.json +6 -2
  32. package/src/index.ts +2 -23
  33. package/src/lib.ts +5 -0
  34. package/src/server.ts +31 -0
  35. package/src/tools/docs.ts +10 -76
  36. package/tests/tools/docs.test.ts +19 -163
  37. package/tsconfig.json +2 -8
  38. package/.github/workflows/ci.yml +0 -22
  39. package/.github/workflows/release.yml +0 -76
  40. package/.github/workflows/tag-and-bump.yml +0 -67
  41. package/.mcp.json +0 -13
  42. package/CLAUDE.md +0 -61
  43. package/docs/superpowers/plans/2026-04-12-gogcli-mcp.md +0 -758
  44. package/docs/superpowers/plans/2026-04-13-browser-auth.md +0 -450
  45. package/docs/superpowers/specs/2026-04-12-gogcli-mcp-design.md +0 -102
  46. package/docs/superpowers/specs/2026-04-13-browser-auth-design.md +0 -88
  47. package/gogcli-mcp-1.0.5.skill +0 -0
@@ -0,0 +1,12 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+ export type Spawner = (command: string, args: string[], options: {
3
+ env: NodeJS.ProcessEnv;
4
+ }) => ChildProcess;
5
+ export interface RunOptions {
6
+ account?: string;
7
+ spawner?: Spawner;
8
+ interactive?: boolean;
9
+ timeout?: number;
10
+ }
11
+ export declare function run(args: string[], options?: RunOptions): Promise<string>;
12
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,MAAM,OAAO,GAAG,CACpB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChC,YAAY,CAAC;AAElB,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA0DnF"}
@@ -0,0 +1,7 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare const VERSION: string;
3
+ export declare function createBaseServer(options?: {
4
+ name?: string;
5
+ version?: string;
6
+ }): McpServer;
7
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAYpE,eAAO,MAAM,OAAO,QAAmE,CAAC;AAExF,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAgBzF"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerAuthTools(server: McpServer): void;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/tools/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwEzD"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerCalendarTools(server: McpServer): void;
3
+ //# sourceMappingURL=calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../src/tools/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2H7D"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerContactsTools(server: McpServer): void;
3
+ //# sourceMappingURL=contacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../../src/tools/contacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkE7D"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerDocsTools(server: McpServer): void;
3
+ //# sourceMappingURL=docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../src/tools/docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAoGzD"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerDriveTools(server: McpServer): void;
3
+ //# sourceMappingURL=drive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../src/tools/drive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgH1D"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerGmailTools(server: McpServer): void;
3
+ //# sourceMappingURL=gmail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../src/tools/gmail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA8D1D"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerSheetsTools(server: McpServer): void;
3
+ //# sourceMappingURL=sheets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sheets.d.ts","sourceRoot":"","sources":["../../src/tools/sheets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuG3D"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerTasksTools(server: McpServer): void;
3
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.d.ts","sourceRoot":"","sources":["../../src/tools/tasks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsF1D"}
@@ -0,0 +1,14 @@
1
+ import { z } from 'zod';
2
+ export type ToolResult = {
3
+ content: [{
4
+ type: 'text';
5
+ text: string;
6
+ }];
7
+ };
8
+ export declare const accountParam: z.ZodOptional<z.ZodString>;
9
+ export declare function toText(output: string): ToolResult;
10
+ export declare function toError(err: unknown): ToolResult;
11
+ export declare function runOrDiagnose(args: string[], options: {
12
+ account?: string;
13
+ }): Promise<ToolResult>;
14
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/tools/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,MAAM,UAAU,GAAG;IAAE,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AAEvE,eAAO,MAAM,YAAY,4BAExB,CAAC;AAEF,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAEjD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAEhD;AAQD,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5B,OAAO,CAAC,UAAU,CAAC,CAerB"}
package/manifest.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "manifest_version": "0.3",
4
4
  "name": "gogcli-mcp",
5
5
  "display_name": "gogcli",
6
- "version": "1.0.5",
6
+ "version": "1.0.6",
7
7
  "description": "Google Sheets (and more) for Claude via gogcli — read, write, and manage spreadsheets",
8
8
  "author": {
9
9
  "name": "Chris Hall",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gogcli-mcp",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "MCP server wrapping gogcli for Google service access",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,9 +10,13 @@
10
10
  "bin": {
11
11
  "gogcli-mcp": "dist/index.js"
12
12
  },
13
+ "exports": {
14
+ ".": "./dist/index.js",
15
+ "./lib": "./dist/lib.js"
16
+ },
13
17
  "scripts": {
14
18
  "build": "tsc --noEmit && npm run bundle",
15
- "bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js",
19
+ "bundle": "node ../../scripts/bundle.js src/index.ts dist/index.js && node ../../scripts/bundle.js src/lib.ts dist/lib.js",
16
20
  "typecheck": "tsc --noEmit",
17
21
  "test": "vitest run",
18
22
  "test:watch": "vitest",
package/src/index.ts CHANGED
@@ -1,28 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
- import { registerAuthTools } from './tools/auth.js';
5
- import { registerCalendarTools } from './tools/calendar.js';
6
- import { registerContactsTools } from './tools/contacts.js';
7
- import { registerDocsTools } from './tools/docs.js';
8
- import { registerDriveTools } from './tools/drive.js';
9
- import { registerGmailTools } from './tools/gmail.js';
10
- import { registerSheetsTools } from './tools/sheets.js';
11
- import { registerTasksTools } from './tools/tasks.js';
12
-
13
- const server = new McpServer({ name: 'gogcli', version: '1.0.5' });
14
-
15
- registerAuthTools(server);
16
- registerCalendarTools(server);
17
- registerContactsTools(server);
18
- registerDocsTools(server);
19
- registerDriveTools(server);
20
- registerGmailTools(server);
21
- registerSheetsTools(server);
22
- registerTasksTools(server);
23
-
24
- // To add more services: import registerXxxTools and call them here.
25
- // Example: registerGmailTools(server);
3
+ import { createBaseServer } from './server.js';
26
4
 
5
+ const server = createBaseServer();
27
6
  const transport = new StdioServerTransport();
28
7
  await server.connect(transport);
package/src/lib.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { createBaseServer, VERSION } from './server.js';
2
+ export { run } from './runner.js';
3
+ export type { RunOptions, Spawner } from './runner.js';
4
+ export { accountParam, runOrDiagnose, toText, toError } from './tools/utils.js';
5
+ export type { ToolResult } from './tools/utils.js';
package/src/server.ts ADDED
@@ -0,0 +1,31 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { registerAuthTools } from './tools/auth.js';
3
+ import { registerCalendarTools } from './tools/calendar.js';
4
+ import { registerContactsTools } from './tools/contacts.js';
5
+ import { registerDocsTools } from './tools/docs.js';
6
+ import { registerDriveTools } from './tools/drive.js';
7
+ import { registerGmailTools } from './tools/gmail.js';
8
+ import { registerSheetsTools } from './tools/sheets.js';
9
+ import { registerTasksTools } from './tools/tasks.js';
10
+
11
+ // Injected at build time by esbuild --define:GOGCLI_VERSION=...
12
+ declare const GOGCLI_VERSION: string;
13
+ export const VERSION = typeof GOGCLI_VERSION !== 'undefined' ? GOGCLI_VERSION : '0.0.0';
14
+
15
+ export function createBaseServer(options?: { name?: string; version?: string }): McpServer {
16
+ const server = new McpServer({
17
+ name: options?.name ?? 'gogcli',
18
+ version: options?.version ?? VERSION,
19
+ });
20
+
21
+ registerAuthTools(server);
22
+ registerCalendarTools(server);
23
+ registerContactsTools(server);
24
+ registerDocsTools(server);
25
+ registerDriveTools(server);
26
+ registerGmailTools(server);
27
+ registerSheetsTools(server);
28
+ registerTasksTools(server);
29
+
30
+ return server;
31
+ }
package/src/tools/docs.ts CHANGED
@@ -74,87 +74,21 @@ export function registerDocsTools(server: McpServer): void {
74
74
  return runOrDiagnose(['docs', 'structure', docId], { account });
75
75
  });
76
76
 
77
- // --- Comments tools ---
77
+ // --- Comments (generic escape hatch — full comment tools are in gogcli-mcp-docs) ---
78
78
 
79
- server.registerTool('gog_docs_comments_list', {
79
+ server.registerTool('gog_docs_comments', {
80
80
  description:
81
- 'List comments on a Google Doc. Returns open comments by default; set includeResolved=true to include resolved comments.',
82
- annotations: { readOnlyHint: true },
83
- inputSchema: {
84
- docId: z.string().describe('Doc ID (from the URL)'),
85
- includeResolved: z.boolean().optional().describe('Include resolved comments (default: false, open only)'),
86
- account: accountParam,
87
- },
88
- }, async ({ docId, includeResolved, account }) => {
89
- const args = ['docs', 'comments', 'list', docId];
90
- if (includeResolved) args.push('--include-resolved');
91
- return runOrDiagnose(args, { account });
92
- });
93
-
94
- server.registerTool('gog_docs_comments_get', {
95
- description: 'Get a single comment by ID, including its replies.',
96
- annotations: { readOnlyHint: true },
97
- inputSchema: {
98
- docId: z.string().describe('Doc ID (from the URL)'),
99
- commentId: z.string().describe('Comment ID'),
100
- account: accountParam,
101
- },
102
- }, async ({ docId, commentId, account }) => {
103
- return runOrDiagnose(['docs', 'comments', 'get', docId, commentId], { account });
104
- });
105
-
106
- server.registerTool('gog_docs_comments_add', {
107
- description:
108
- 'Add a comment to a Google Doc. Optionally attach quoted text that appears as the highlighted passage in the Google Docs UI.',
109
- inputSchema: {
110
- docId: z.string().describe('Doc ID (from the URL)'),
111
- content: z.string().describe('Comment text'),
112
- quoted: z.string().optional().describe('Quoted text to attach to the comment (shown in UIs when available)'),
113
- account: accountParam,
114
- },
115
- }, async ({ docId, content, quoted, account }) => {
116
- const args = ['docs', 'comments', 'add', docId, content];
117
- if (quoted) args.push(`--quoted=${quoted}`);
118
- return runOrDiagnose(args, { account });
119
- });
120
-
121
- server.registerTool('gog_docs_comments_reply', {
122
- description: 'Reply to an existing comment on a Google Doc.',
123
- inputSchema: {
124
- docId: z.string().describe('Doc ID (from the URL)'),
125
- commentId: z.string().describe('Comment ID to reply to'),
126
- content: z.string().describe('Reply text'),
127
- account: accountParam,
128
- },
129
- }, async ({ docId, commentId, content, account }) => {
130
- return runOrDiagnose(['docs', 'comments', 'reply', docId, commentId, content], { account });
131
- });
132
-
133
- server.registerTool('gog_docs_comments_resolve', {
134
- description: 'Resolve a comment (mark as done). Optionally include a closing message.',
135
- annotations: { destructiveHint: true },
81
+ 'Run a docs comments subcommand. Subcommands: list, get, add, reply, resolve, delete. ' +
82
+ 'Examples: subcommand="list", args=["<docId>"] | subcommand="add", args=["<docId>", "<text>", "--quoted=<passage>"] | ' +
83
+ 'subcommand="reply", args=["<docId>", "<commentId>", "<text>"]. ' +
84
+ 'For dedicated comment tools with full parameter validation, use the gogcli-mcp-docs package.',
136
85
  inputSchema: {
137
- docId: z.string().describe('Doc ID (from the URL)'),
138
- commentId: z.string().describe('Comment ID to resolve'),
139
- message: z.string().optional().describe('Optional message to include when resolving'),
140
- account: accountParam,
141
- },
142
- }, async ({ docId, commentId, message, account }) => {
143
- const args = ['docs', 'comments', 'resolve', docId, commentId];
144
- if (message) args.push(`--message=${message}`);
145
- return runOrDiagnose(args, { account });
146
- });
147
-
148
- server.registerTool('gog_docs_comments_delete', {
149
- description: 'Delete a comment from a Google Doc. This action is permanent.',
150
- annotations: { destructiveHint: true },
151
- inputSchema: {
152
- docId: z.string().describe('Doc ID (from the URL)'),
153
- commentId: z.string().describe('Comment ID to delete'),
86
+ subcommand: z.string().describe('Comments subcommand: list, get, add, reply, resolve, delete'),
87
+ args: z.array(z.string()).describe('Positional args and flags for the subcommand'),
154
88
  account: accountParam,
155
89
  },
156
- }, async ({ docId, commentId, account }) => {
157
- return runOrDiagnose(['docs', 'comments', 'delete', docId, commentId], { account });
90
+ }, async ({ subcommand, args, account }) => {
91
+ return runOrDiagnose(['docs', 'comments', subcommand, ...args], { account });
158
92
  });
159
93
 
160
94
  server.registerTool('gog_docs_run', {
@@ -161,190 +161,46 @@ describe('gog_docs_structure', () => {
161
161
  });
162
162
  });
163
163
 
164
- // --- Comments tools ---
164
+ // --- Comments (generic escape hatch) ---
165
165
 
166
- describe('gog_docs_comments_list', () => {
167
- it('calls run with correct args for open comments', async () => {
168
- vi.mocked(runner.run).mockResolvedValue('[{"id":"c1","content":"Fix this"}]');
166
+ describe('gog_docs_comments', () => {
167
+ it('passes subcommand and args to runner', async () => {
168
+ vi.mocked(runner.run).mockResolvedValue('[{"id":"c1"}]');
169
169
  const handlers = setupHandlers();
170
- const result = await handlers.get('gog_docs_comments_list')!({ docId: 'abc' });
170
+ const result = await handlers.get('gog_docs_comments')!({ subcommand: 'list', args: ['abc'] });
171
171
  expect(runner.run).toHaveBeenCalledWith(['docs', 'comments', 'list', 'abc'], { account: undefined });
172
- expect(result.content[0].text).toContain('Fix this');
172
+ expect(result.content[0].text).toContain('c1');
173
173
  });
174
174
 
175
- it('includes --include-resolved when set', async () => {
176
- vi.mocked(runner.run).mockResolvedValue('[]');
177
- const handlers = setupHandlers();
178
- await handlers.get('gog_docs_comments_list')!({ docId: 'abc', includeResolved: true });
179
- expect(runner.run).toHaveBeenCalledWith(
180
- ['docs', 'comments', 'list', 'abc', '--include-resolved'],
181
- { account: undefined },
182
- );
183
- });
184
-
185
- it('omits --include-resolved when false', async () => {
186
- vi.mocked(runner.run).mockResolvedValue('[]');
187
- const handlers = setupHandlers();
188
- await handlers.get('gog_docs_comments_list')!({ docId: 'abc', includeResolved: false });
189
- expect(runner.run).toHaveBeenCalledWith(['docs', 'comments', 'list', 'abc'], { account: undefined });
190
- });
191
-
192
- it('forwards account override', async () => {
193
- vi.mocked(runner.run).mockResolvedValue('[]');
194
- const handlers = setupHandlers();
195
- await handlers.get('gog_docs_comments_list')!({ docId: 'abc', account: 'other@gmail.com' });
196
- expect(runner.run).toHaveBeenCalledWith(
197
- ['docs', 'comments', 'list', 'abc'],
198
- { account: 'other@gmail.com' },
199
- );
200
- });
201
-
202
- it('returns error text on failure', async () => {
203
- vi.mocked(runner.run).mockRejectedValue(new Error('List failed'));
204
- const handlers = setupHandlers();
205
- const result = await handlers.get('gog_docs_comments_list')!({ docId: 'bad' });
206
- expect(result.content[0].text).toContain('Error: List failed');
207
- });
208
- });
209
-
210
- describe('gog_docs_comments_get', () => {
211
- it('calls run with correct args', async () => {
212
- vi.mocked(runner.run).mockResolvedValue('{"id":"c1","content":"Fix this","replies":[]}');
213
- const handlers = setupHandlers();
214
- const result = await handlers.get('gog_docs_comments_get')!({ docId: 'abc', commentId: 'c1' });
215
- expect(runner.run).toHaveBeenCalledWith(['docs', 'comments', 'get', 'abc', 'c1'], { account: undefined });
216
- expect(result.content[0].text).toContain('Fix this');
217
- });
218
-
219
- it('returns error text on failure', async () => {
220
- vi.mocked(runner.run).mockRejectedValue(new Error('Not found'));
221
- const handlers = setupHandlers();
222
- const result = await handlers.get('gog_docs_comments_get')!({ docId: 'abc', commentId: 'bad' });
223
- expect(result.content[0].text).toContain('Error: Not found');
224
- });
225
- });
226
-
227
- describe('gog_docs_comments_add', () => {
228
- it('calls run with content', async () => {
229
- vi.mocked(runner.run).mockResolvedValue('{"id":"c2"}');
230
- const handlers = setupHandlers();
231
- await handlers.get('gog_docs_comments_add')!({ docId: 'abc', content: 'Please review' });
232
- expect(runner.run).toHaveBeenCalledWith(
233
- ['docs', 'comments', 'add', 'abc', 'Please review'],
234
- { account: undefined },
235
- );
236
- });
237
-
238
- it('includes --quoted when provided', async () => {
239
- vi.mocked(runner.run).mockResolvedValue('{"id":"c2"}');
240
- const handlers = setupHandlers();
241
- await handlers.get('gog_docs_comments_add')!({
242
- docId: 'abc',
243
- content: 'Typo here',
244
- quoted: 'teh',
245
- });
246
- expect(runner.run).toHaveBeenCalledWith(
247
- ['docs', 'comments', 'add', 'abc', 'Typo here', '--quoted=teh'],
248
- { account: undefined },
249
- );
250
- });
251
-
252
- it('omits --quoted when not provided', async () => {
253
- vi.mocked(runner.run).mockResolvedValue('{"id":"c2"}');
254
- const handlers = setupHandlers();
255
- await handlers.get('gog_docs_comments_add')!({ docId: 'abc', content: 'Nice' });
256
- expect(runner.run).toHaveBeenCalledWith(
257
- ['docs', 'comments', 'add', 'abc', 'Nice'],
258
- { account: undefined },
259
- );
260
- });
261
-
262
- it('returns error text on failure', async () => {
263
- vi.mocked(runner.run).mockRejectedValue(new Error('Add failed'));
264
- const handlers = setupHandlers();
265
- const result = await handlers.get('gog_docs_comments_add')!({ docId: 'bad', content: 'x' });
266
- expect(result.content[0].text).toContain('Error: Add failed');
267
- });
268
- });
269
-
270
- describe('gog_docs_comments_reply', () => {
271
- it('calls run with correct args', async () => {
272
- vi.mocked(runner.run).mockResolvedValue('{"id":"r1"}');
273
- const handlers = setupHandlers();
274
- await handlers.get('gog_docs_comments_reply')!({ docId: 'abc', commentId: 'c1', content: 'Done' });
275
- expect(runner.run).toHaveBeenCalledWith(
276
- ['docs', 'comments', 'reply', 'abc', 'c1', 'Done'],
277
- { account: undefined },
278
- );
279
- });
280
-
281
- it('returns error text on failure', async () => {
282
- vi.mocked(runner.run).mockRejectedValue(new Error('Reply failed'));
283
- const handlers = setupHandlers();
284
- const result = await handlers.get('gog_docs_comments_reply')!({
285
- docId: 'abc', commentId: 'c1', content: 'x',
286
- });
287
- expect(result.content[0].text).toContain('Error: Reply failed');
288
- });
289
- });
290
-
291
- describe('gog_docs_comments_resolve', () => {
292
- it('calls run with correct args', async () => {
293
- vi.mocked(runner.run).mockResolvedValue('{}');
294
- const handlers = setupHandlers();
295
- await handlers.get('gog_docs_comments_resolve')!({ docId: 'abc', commentId: 'c1' });
296
- expect(runner.run).toHaveBeenCalledWith(
297
- ['docs', 'comments', 'resolve', 'abc', 'c1'],
298
- { account: undefined },
299
- );
300
- });
301
-
302
- it('includes --message when provided', async () => {
175
+ it('passes flags through args', async () => {
303
176
  vi.mocked(runner.run).mockResolvedValue('{}');
304
177
  const handlers = setupHandlers();
305
- await handlers.get('gog_docs_comments_resolve')!({
306
- docId: 'abc', commentId: 'c1', message: 'Fixed in v2',
178
+ await handlers.get('gog_docs_comments')!({
179
+ subcommand: 'add', args: ['abc', 'Nice work', '--quoted=paragraph'],
307
180
  });
308
181
  expect(runner.run).toHaveBeenCalledWith(
309
- ['docs', 'comments', 'resolve', 'abc', 'c1', '--message=Fixed in v2'],
310
- { account: undefined },
311
- );
312
- });
313
-
314
- it('omits --message when not provided', async () => {
315
- vi.mocked(runner.run).mockResolvedValue('{}');
316
- const handlers = setupHandlers();
317
- await handlers.get('gog_docs_comments_resolve')!({ docId: 'abc', commentId: 'c1' });
318
- expect(runner.run).toHaveBeenCalledWith(
319
- ['docs', 'comments', 'resolve', 'abc', 'c1'],
182
+ ['docs', 'comments', 'add', 'abc', 'Nice work', '--quoted=paragraph'],
320
183
  { account: undefined },
321
184
  );
322
185
  });
323
186
 
324
- it('returns error text on failure', async () => {
325
- vi.mocked(runner.run).mockRejectedValue(new Error('Resolve failed'));
326
- const handlers = setupHandlers();
327
- const result = await handlers.get('gog_docs_comments_resolve')!({ docId: 'abc', commentId: 'c1' });
328
- expect(result.content[0].text).toContain('Error: Resolve failed');
329
- });
330
- });
331
-
332
- describe('gog_docs_comments_delete', () => {
333
- it('calls run with correct args', async () => {
187
+ it('forwards account override', async () => {
334
188
  vi.mocked(runner.run).mockResolvedValue('{}');
335
189
  const handlers = setupHandlers();
336
- await handlers.get('gog_docs_comments_delete')!({ docId: 'abc', commentId: 'c1' });
190
+ await handlers.get('gog_docs_comments')!({
191
+ subcommand: 'list', args: ['abc'], account: 'other@gmail.com',
192
+ });
337
193
  expect(runner.run).toHaveBeenCalledWith(
338
- ['docs', 'comments', 'delete', 'abc', 'c1'],
339
- { account: undefined },
194
+ ['docs', 'comments', 'list', 'abc'],
195
+ { account: 'other@gmail.com' },
340
196
  );
341
197
  });
342
198
 
343
199
  it('returns error text on failure', async () => {
344
- vi.mocked(runner.run).mockRejectedValue(new Error('Delete failed'));
200
+ vi.mocked(runner.run).mockRejectedValue(new Error('Comments failed'));
345
201
  const handlers = setupHandlers();
346
- const result = await handlers.get('gog_docs_comments_delete')!({ docId: 'abc', commentId: 'c1' });
347
- expect(result.content[0].text).toContain('Error: Delete failed');
202
+ const result = await handlers.get('gog_docs_comments')!({ subcommand: 'list', args: ['bad'] });
203
+ expect(result.content[0].text).toContain('Error: Comments failed');
348
204
  });
349
205
  });
350
206
 
package/tsconfig.json CHANGED
@@ -1,14 +1,8 @@
1
1
  {
2
+ "extends": "../../tsconfig.base.json",
2
3
  "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
4
  "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "types": ["node"]
5
+ "rootDir": "./src"
12
6
  },
13
7
  "include": ["src/**/*"],
14
8
  "exclude": ["node_modules", "dist"]
@@ -1,22 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- workflow_call:
8
-
9
- jobs:
10
- ci:
11
- runs-on: ubuntu-latest
12
- steps:
13
- - uses: actions/checkout@v6.0.2
14
-
15
- - uses: actions/setup-node@v6.3.0
16
- with:
17
- node-version: 22
18
- cache: npm
19
-
20
- - run: npm ci
21
- - run: npm run build
22
- - run: npm test