@aaronsb/google-workspace-mcp 2.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +193 -0
  3. package/build/__helpers__/testSetup.d.ts +1 -0
  4. package/build/__helpers__/testSetup.js +6 -0
  5. package/build/__helpers__/testSetup.js.map +1 -0
  6. package/build/__tests__/accounts/credentials.test.d.ts +1 -0
  7. package/build/__tests__/accounts/credentials.test.js +129 -0
  8. package/build/__tests__/accounts/credentials.test.js.map +1 -0
  9. package/build/__tests__/accounts/registry.test.d.ts +1 -0
  10. package/build/__tests__/accounts/registry.test.js +74 -0
  11. package/build/__tests__/accounts/registry.test.js.map +1 -0
  12. package/build/__tests__/executor/errors.test.d.ts +1 -0
  13. package/build/__tests__/executor/errors.test.js +42 -0
  14. package/build/__tests__/executor/errors.test.js.map +1 -0
  15. package/build/__tests__/executor/gws.test.d.ts +1 -0
  16. package/build/__tests__/executor/gws.test.js +178 -0
  17. package/build/__tests__/executor/gws.test.js.map +1 -0
  18. package/build/__tests__/executor/paths.test.d.ts +1 -0
  19. package/build/__tests__/executor/paths.test.js +60 -0
  20. package/build/__tests__/executor/paths.test.js.map +1 -0
  21. package/build/__tests__/executor/workspace.test.d.ts +1 -0
  22. package/build/__tests__/executor/workspace.test.js +117 -0
  23. package/build/__tests__/executor/workspace.test.js.map +1 -0
  24. package/build/__tests__/factory/generator.test.d.ts +1 -0
  25. package/build/__tests__/factory/generator.test.js +178 -0
  26. package/build/__tests__/factory/generator.test.js.map +1 -0
  27. package/build/__tests__/factory/patch-coverage.test.d.ts +10 -0
  28. package/build/__tests__/factory/patch-coverage.test.js +148 -0
  29. package/build/__tests__/factory/patch-coverage.test.js.map +1 -0
  30. package/build/__tests__/factory/safety.test.d.ts +1 -0
  31. package/build/__tests__/factory/safety.test.js +107 -0
  32. package/build/__tests__/factory/safety.test.js.map +1 -0
  33. package/build/__tests__/integration/executor.test.d.ts +5 -0
  34. package/build/__tests__/integration/executor.test.js +46 -0
  35. package/build/__tests__/integration/executor.test.js.map +1 -0
  36. package/build/__tests__/integration/handlers.test.d.ts +6 -0
  37. package/build/__tests__/integration/handlers.test.js +95 -0
  38. package/build/__tests__/integration/handlers.test.js.map +1 -0
  39. package/build/__tests__/integration/setup.d.ts +19 -0
  40. package/build/__tests__/integration/setup.js +61 -0
  41. package/build/__tests__/integration/setup.js.map +1 -0
  42. package/build/__tests__/server/formatting/markdown.test.d.ts +1 -0
  43. package/build/__tests__/server/formatting/markdown.test.js +149 -0
  44. package/build/__tests__/server/formatting/markdown.test.js.map +1 -0
  45. package/build/__tests__/server/formatting/next-steps.test.d.ts +1 -0
  46. package/build/__tests__/server/formatting/next-steps.test.js +42 -0
  47. package/build/__tests__/server/formatting/next-steps.test.js.map +1 -0
  48. package/build/__tests__/server/handler.test.d.ts +1 -0
  49. package/build/__tests__/server/handler.test.js +97 -0
  50. package/build/__tests__/server/handler.test.js.map +1 -0
  51. package/build/__tests__/server/handlers/__mocks__/executor.d.ts +147 -0
  52. package/build/__tests__/server/handlers/__mocks__/executor.js +114 -0
  53. package/build/__tests__/server/handlers/__mocks__/executor.js.map +1 -0
  54. package/build/__tests__/server/handlers/accounts.test.d.ts +1 -0
  55. package/build/__tests__/server/handlers/accounts.test.js +127 -0
  56. package/build/__tests__/server/handlers/accounts.test.js.map +1 -0
  57. package/build/__tests__/server/handlers/calendar.test.d.ts +1 -0
  58. package/build/__tests__/server/handlers/calendar.test.js +95 -0
  59. package/build/__tests__/server/handlers/calendar.test.js.map +1 -0
  60. package/build/__tests__/server/handlers/drive.test.d.ts +1 -0
  61. package/build/__tests__/server/handlers/drive.test.js +81 -0
  62. package/build/__tests__/server/handlers/drive.test.js.map +1 -0
  63. package/build/__tests__/server/handlers/email.test.d.ts +1 -0
  64. package/build/__tests__/server/handlers/email.test.js +99 -0
  65. package/build/__tests__/server/handlers/email.test.js.map +1 -0
  66. package/build/__tests__/server/handlers/validate.test.d.ts +1 -0
  67. package/build/__tests__/server/handlers/validate.test.js +88 -0
  68. package/build/__tests__/server/handlers/validate.test.js.map +1 -0
  69. package/build/__tests__/server/queue.test.d.ts +1 -0
  70. package/build/__tests__/server/queue.test.js +194 -0
  71. package/build/__tests__/server/queue.test.js.map +1 -0
  72. package/build/__tests__/server/server.test.d.ts +7 -0
  73. package/build/__tests__/server/server.test.js +135 -0
  74. package/build/__tests__/server/server.test.js.map +1 -0
  75. package/build/__tests__/server/tools.test.d.ts +1 -0
  76. package/build/__tests__/server/tools.test.js +91 -0
  77. package/build/__tests__/server/tools.test.js.map +1 -0
  78. package/build/accounts/auth.d.ts +24 -0
  79. package/build/accounts/auth.js +118 -0
  80. package/build/accounts/auth.js.map +1 -0
  81. package/build/accounts/credentials.d.ts +11 -0
  82. package/build/accounts/credentials.js +52 -0
  83. package/build/accounts/credentials.js.map +1 -0
  84. package/build/accounts/index.d.ts +6 -0
  85. package/build/accounts/index.js +4 -0
  86. package/build/accounts/index.js.map +1 -0
  87. package/build/accounts/registry.d.ts +11 -0
  88. package/build/accounts/registry.js +62 -0
  89. package/build/accounts/registry.js.map +1 -0
  90. package/build/executor/errors.d.ts +15 -0
  91. package/build/executor/errors.js +37 -0
  92. package/build/executor/errors.js.map +1 -0
  93. package/build/executor/file-output.d.ts +23 -0
  94. package/build/executor/file-output.js +67 -0
  95. package/build/executor/file-output.js.map +1 -0
  96. package/build/executor/gws.d.ts +23 -0
  97. package/build/executor/gws.js +144 -0
  98. package/build/executor/gws.js.map +1 -0
  99. package/build/executor/index.d.ts +4 -0
  100. package/build/executor/index.js +4 -0
  101. package/build/executor/index.js.map +1 -0
  102. package/build/executor/paths.d.ts +6 -0
  103. package/build/executor/paths.js +25 -0
  104. package/build/executor/paths.js.map +1 -0
  105. package/build/executor/workspace.d.ts +38 -0
  106. package/build/executor/workspace.js +146 -0
  107. package/build/executor/workspace.js.map +1 -0
  108. package/build/factory/defaults.d.ts +8 -0
  109. package/build/factory/defaults.js +101 -0
  110. package/build/factory/defaults.js.map +1 -0
  111. package/build/factory/generator.d.ts +23 -0
  112. package/build/factory/generator.js +253 -0
  113. package/build/factory/generator.js.map +1 -0
  114. package/build/factory/manifest.yaml +852 -0
  115. package/build/factory/patches.d.ts +6 -0
  116. package/build/factory/patches.js +13 -0
  117. package/build/factory/patches.js.map +1 -0
  118. package/build/factory/registry.d.ts +12 -0
  119. package/build/factory/registry.js +18 -0
  120. package/build/factory/registry.js.map +1 -0
  121. package/build/factory/safety.d.ts +68 -0
  122. package/build/factory/safety.js +157 -0
  123. package/build/factory/safety.js.map +1 -0
  124. package/build/factory/types.d.ts +102 -0
  125. package/build/factory/types.js +6 -0
  126. package/build/factory/types.js.map +1 -0
  127. package/build/factory/yaml.d.ts +2 -0
  128. package/build/factory/yaml.js +3 -0
  129. package/build/factory/yaml.js.map +1 -0
  130. package/build/index.d.ts +2 -0
  131. package/build/index.js +14 -0
  132. package/build/index.js.map +1 -0
  133. package/build/server/formatting/markdown.d.ts +21 -0
  134. package/build/server/formatting/markdown.js +324 -0
  135. package/build/server/formatting/markdown.js.map +1 -0
  136. package/build/server/formatting/next-steps.d.ts +9 -0
  137. package/build/server/formatting/next-steps.js +123 -0
  138. package/build/server/formatting/next-steps.js.map +1 -0
  139. package/build/server/handler.d.ts +3 -0
  140. package/build/server/handler.js +24 -0
  141. package/build/server/handler.js.map +1 -0
  142. package/build/server/handlers/accounts.d.ts +2 -0
  143. package/build/server/handlers/accounts.js +181 -0
  144. package/build/server/handlers/accounts.js.map +1 -0
  145. package/build/server/handlers/calendar.d.ts +2 -0
  146. package/build/server/handlers/calendar.js +93 -0
  147. package/build/server/handlers/calendar.js.map +1 -0
  148. package/build/server/handlers/drive.d.ts +2 -0
  149. package/build/server/handlers/drive.js +74 -0
  150. package/build/server/handlers/drive.js.map +1 -0
  151. package/build/server/handlers/email.d.ts +2 -0
  152. package/build/server/handlers/email.js +115 -0
  153. package/build/server/handlers/email.js.map +1 -0
  154. package/build/server/handlers/validate.d.ts +3 -0
  155. package/build/server/handlers/validate.js +22 -0
  156. package/build/server/handlers/validate.js.map +1 -0
  157. package/build/server/handlers/workspace.d.ts +9 -0
  158. package/build/server/handlers/workspace.js +110 -0
  159. package/build/server/handlers/workspace.js.map +1 -0
  160. package/build/server/index.d.ts +4 -0
  161. package/build/server/index.js +4 -0
  162. package/build/server/index.js.map +1 -0
  163. package/build/server/queue.d.ts +11 -0
  164. package/build/server/queue.js +141 -0
  165. package/build/server/queue.js.map +1 -0
  166. package/build/server/server.d.ts +3 -0
  167. package/build/server/server.js +214 -0
  168. package/build/server/server.js.map +1 -0
  169. package/build/server/tools.d.ts +13 -0
  170. package/build/server/tools.js +99 -0
  171. package/build/server/tools.js.map +1 -0
  172. package/build/services/calendar/patch.d.ts +11 -0
  173. package/build/services/calendar/patch.js +116 -0
  174. package/build/services/calendar/patch.js.map +1 -0
  175. package/build/services/drive/patch.d.ts +10 -0
  176. package/build/services/drive/patch.js +131 -0
  177. package/build/services/drive/patch.js.map +1 -0
  178. package/build/services/gmail/attachments.d.ts +19 -0
  179. package/build/services/gmail/attachments.js +90 -0
  180. package/build/services/gmail/attachments.js.map +1 -0
  181. package/build/services/gmail/patch.d.ts +10 -0
  182. package/build/services/gmail/patch.js +226 -0
  183. package/build/services/gmail/patch.js.map +1 -0
  184. package/package.json +34 -0
@@ -0,0 +1,194 @@
1
+ import { handleQueue } from '../../server/queue.js';
2
+ // Mock handlers returning HandlerResponse { text, refs }
3
+ const handlers = {
4
+ tool_a: async (params) => ({
5
+ text: `Result A: ${params.input ?? 'default'}`,
6
+ refs: { id: 'result-a', value: params.input ?? 'default' },
7
+ }),
8
+ tool_b: async (params) => ({
9
+ text: `Result B: ref=${params.ref ?? 'none'}`,
10
+ refs: { id: 'result-b', ref: params.ref ?? 'none' },
11
+ }),
12
+ tool_fail: async () => { throw new Error('intentional failure'); },
13
+ };
14
+ describe('handleQueue', () => {
15
+ it('executes operations sequentially', async () => {
16
+ const result = await handleQueue({
17
+ operations: [
18
+ { tool: 'tool_a', args: { input: 'hello' } },
19
+ { tool: 'tool_b', args: { ref: 'world' } },
20
+ ],
21
+ }, handlers);
22
+ expect(result.text).toContain('2/2 succeeded');
23
+ expect(result.text).toContain('✓ tool_a');
24
+ expect(result.text).toContain('✓ tool_b');
25
+ expect(result.refs.succeeded).toBe(2);
26
+ });
27
+ it('resolves $N.field references from refs', async () => {
28
+ const result = await handleQueue({
29
+ operations: [
30
+ { tool: 'tool_a', args: { input: 'first' } },
31
+ { tool: 'tool_b', args: { ref: '$0.id' } },
32
+ ],
33
+ }, handlers);
34
+ // tool_b should have received ref='result-a' (from tool_a's refs.id)
35
+ expect(result.text).toContain('✓ tool_b');
36
+ expect(result.refs.succeeded).toBe(2);
37
+ });
38
+ it('bails on error by default', async () => {
39
+ const result = await handleQueue({
40
+ operations: [
41
+ { tool: 'tool_a', args: {} },
42
+ { tool: 'tool_fail', args: {} },
43
+ { tool: 'tool_b', args: {} },
44
+ ],
45
+ }, handlers);
46
+ expect(result.refs.succeeded).toBe(1);
47
+ expect(result.refs.failed).toBe(1);
48
+ expect(result.refs.skipped).toBe(1);
49
+ expect(result.text).toContain('✗ tool_fail');
50
+ expect(result.text).toContain('○ tool_b');
51
+ });
52
+ it('continues on error when onError is continue', async () => {
53
+ const result = await handleQueue({
54
+ operations: [
55
+ { tool: 'tool_a', args: {} },
56
+ { tool: 'tool_fail', args: {}, onError: 'continue' },
57
+ { tool: 'tool_b', args: {} },
58
+ ],
59
+ }, handlers);
60
+ expect(result.refs.succeeded).toBe(2);
61
+ expect(result.refs.failed).toBe(1);
62
+ expect(result.refs.skipped).toBe(0);
63
+ });
64
+ it('errors on forward references', async () => {
65
+ const result = await handleQueue({
66
+ operations: [
67
+ { tool: 'tool_a', args: { input: '$1.id' } },
68
+ { tool: 'tool_b', args: {} },
69
+ ],
70
+ }, handlers);
71
+ expect(result.text).toContain('✗ tool_a');
72
+ expect(result.text).toContain("hasn't run yet");
73
+ });
74
+ it('errors on references to failed operations', async () => {
75
+ const result = await handleQueue({
76
+ operations: [
77
+ { tool: 'tool_fail', args: {}, onError: 'continue' },
78
+ { tool: 'tool_b', args: { ref: '$0.id' } },
79
+ ],
80
+ }, handlers);
81
+ expect(result.refs.failed).toBe(2);
82
+ });
83
+ it('errors on missing field in reference', async () => {
84
+ const result = await handleQueue({
85
+ operations: [
86
+ { tool: 'tool_a', args: {} },
87
+ { tool: 'tool_b', args: { ref: '$0.nonexistent' }, onError: 'continue' },
88
+ ],
89
+ }, handlers);
90
+ expect(result.text).toContain('not found');
91
+ });
92
+ it('errors on unknown tool', async () => {
93
+ const result = await handleQueue({
94
+ operations: [
95
+ { tool: 'unknown_tool', args: {} },
96
+ ],
97
+ }, handlers);
98
+ expect(result.text).toContain('✗ unknown_tool');
99
+ expect(result.text).toContain('Unknown tool');
100
+ });
101
+ it('strips next_steps from per-operation text in summary', async () => {
102
+ const handlersWithSteps = {
103
+ tool_with_steps: async () => ({
104
+ text: 'Some result\n\n---\n**Next steps:**\n- Do something',
105
+ refs: { id: '1' },
106
+ }),
107
+ };
108
+ const result = await handleQueue({
109
+ operations: [{ tool: 'tool_with_steps', args: {} }],
110
+ }, handlersWithSteps);
111
+ // Summary line should not contain next-steps
112
+ const lines = result.text.split('\n');
113
+ const summaryLine = lines.find(l => l.includes('tool_with_steps'));
114
+ expect(summaryLine).not.toContain('Next steps');
115
+ // But consolidated next-steps from last success should be appended
116
+ expect(result.text).toContain('**Next steps:**');
117
+ });
118
+ it('rejects empty operations array', async () => {
119
+ await expect(handleQueue({ operations: [] }, handlers)).rejects.toThrow('must not be empty');
120
+ });
121
+ it('returns markdown summary', async () => {
122
+ const result = await handleQueue({
123
+ operations: [
124
+ { tool: 'tool_a', args: { input: 'test' } },
125
+ ],
126
+ }, handlers);
127
+ expect(result.text).toContain('## Queue Results');
128
+ expect(result.text).toContain('1/1 succeeded');
129
+ });
130
+ it('exposes per-operation refs in results array', async () => {
131
+ const result = await handleQueue({
132
+ operations: [
133
+ { tool: 'tool_a', args: { input: 'hello' } },
134
+ { tool: 'tool_b', args: { ref: 'world' } },
135
+ ],
136
+ }, handlers);
137
+ const opResults = result.refs.results;
138
+ expect(opResults).toHaveLength(2);
139
+ expect(opResults[0]).toMatchObject({ tool: 'tool_a', status: 'success', id: 'result-a' });
140
+ expect(opResults[1]).toMatchObject({ tool: 'tool_b', status: 'success', id: 'result-b' });
141
+ });
142
+ it('includes error status in per-operation results', async () => {
143
+ const result = await handleQueue({
144
+ operations: [
145
+ { tool: 'tool_fail', args: {}, onError: 'continue' },
146
+ { tool: 'tool_a', args: {} },
147
+ ],
148
+ }, handlers);
149
+ const opResults = result.refs.results;
150
+ expect(opResults[0]).toMatchObject({ tool: 'tool_fail', status: 'error' });
151
+ expect(opResults[1]).toMatchObject({ tool: 'tool_a', status: 'success' });
152
+ });
153
+ describe('detail: full', () => {
154
+ it('includes complete operation output below summary lines', async () => {
155
+ const result = await handleQueue({
156
+ operations: [
157
+ { tool: 'tool_a', args: { input: 'hello' } },
158
+ { tool: 'tool_b', args: { ref: 'world' } },
159
+ ],
160
+ detail: 'full',
161
+ }, handlers);
162
+ expect(result.text).toContain('## Queue Results');
163
+ // Full output should appear
164
+ expect(result.text).toContain('Result A: hello');
165
+ expect(result.text).toContain('Result B: ref=world');
166
+ });
167
+ it('does not include output for failed operations', async () => {
168
+ const result = await handleQueue({
169
+ operations: [
170
+ { tool: 'tool_a', args: {} },
171
+ { tool: 'tool_fail', args: {}, onError: 'continue' },
172
+ ],
173
+ detail: 'full',
174
+ }, handlers);
175
+ expect(result.text).toContain('Result A: default');
176
+ expect(result.text).toContain('✗ tool_fail');
177
+ // Error message appears in summary line, not as full output
178
+ });
179
+ });
180
+ describe('detail: summary (default)', () => {
181
+ it('only shows one-liner per operation, not full output blocks', async () => {
182
+ const result = await handleQueue({
183
+ operations: [
184
+ { tool: 'tool_a', args: { input: 'hello' } },
185
+ ],
186
+ }, handlers);
187
+ // Summary line contains the first content line
188
+ expect(result.text).toContain('✓ tool_a — Result A: hello');
189
+ // No blank-line-separated full output block
190
+ expect(result.text).not.toMatch(/\n\nResult A: hello\n/);
191
+ });
192
+ });
193
+ });
194
+ //# sourceMappingURL=queue.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue.test.js","sourceRoot":"","sources":["../../../src/__tests__/server/queue.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Tests for server.ts MCP wiring.
3
+ *
4
+ * We mock the MCP SDK (ESM-only) and verify that createServer
5
+ * wires handlers correctly and maps responses/errors.
6
+ */
7
+ export {};
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Tests for server.ts MCP wiring.
3
+ *
4
+ * We mock the MCP SDK (ESM-only) and verify that createServer
5
+ * wires handlers correctly and maps responses/errors.
6
+ */
7
+ // Mock registry before any server imports — avoids import.meta.url in Jest
8
+ jest.mock('../../factory/registry.js', () => {
9
+ const { loadManifest, generateTools } = jest.requireActual('../../factory/generator.js');
10
+ const { patches } = jest.requireActual('../../factory/patches.js');
11
+ const manifest = loadManifest();
12
+ return { manifest, generatedTools: generateTools(manifest, patches) };
13
+ });
14
+ const mockSetRequestHandler = jest.fn();
15
+ const mockServerConnect = jest.fn();
16
+ jest.mock('@modelcontextprotocol/sdk/server/index.js', () => ({
17
+ Server: jest.fn().mockImplementation(() => ({
18
+ setRequestHandler: mockSetRequestHandler,
19
+ connect: mockServerConnect,
20
+ })),
21
+ }));
22
+ jest.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({
23
+ StdioServerTransport: jest.fn(),
24
+ }));
25
+ jest.mock('@modelcontextprotocol/sdk/types.js', () => ({
26
+ CallToolRequestSchema: 'CallToolRequestSchema',
27
+ ListToolsRequestSchema: 'ListToolsRequestSchema',
28
+ }));
29
+ jest.mock('../../server/handler.js');
30
+ import { createServer } from '../../server/server.js';
31
+ import { handleToolCall } from '../../server/handler.js';
32
+ import { GwsError, GwsExitCode } from '../../executor/errors.js';
33
+ const mockHandleToolCall = handleToolCall;
34
+ describe('createServer', () => {
35
+ let listToolsHandler;
36
+ let callToolHandler;
37
+ beforeAll(() => {
38
+ createServer();
39
+ // Extract handlers by schema key, not registration order
40
+ for (const [schema, handler] of mockSetRequestHandler.mock.calls) {
41
+ if (schema === 'ListToolsRequestSchema')
42
+ listToolsHandler = handler;
43
+ if (schema === 'CallToolRequestSchema')
44
+ callToolHandler = handler;
45
+ }
46
+ });
47
+ beforeEach(() => {
48
+ mockHandleToolCall.mockReset();
49
+ });
50
+ it('registers ListTools and CallTool handlers', () => {
51
+ expect(listToolsHandler).toBeInstanceOf(Function);
52
+ expect(callToolHandler).toBeInstanceOf(Function);
53
+ });
54
+ describe('ListTools handler', () => {
55
+ it('returns all 5 tool schemas', async () => {
56
+ const result = await listToolsHandler({});
57
+ const names = result.tools.map((t) => t.name);
58
+ expect(names).toContain('manage_accounts');
59
+ expect(names).toContain('manage_email');
60
+ expect(names).toContain('manage_sheets');
61
+ expect(names).toContain('manage_tasks');
62
+ expect(names.length).toBeGreaterThanOrEqual(8);
63
+ });
64
+ it('each tool has name, description, and inputSchema', async () => {
65
+ const result = await listToolsHandler({});
66
+ for (const tool of result.tools) {
67
+ expect(tool).toHaveProperty('name');
68
+ expect(tool).toHaveProperty('description');
69
+ expect(tool).toHaveProperty('inputSchema');
70
+ }
71
+ });
72
+ });
73
+ describe('CallTool handler', () => {
74
+ it('returns markdown text content on success', async () => {
75
+ const response = { text: '## Messages (1)\n\nmsg-1 | alice', refs: { count: 1 } };
76
+ mockHandleToolCall.mockResolvedValue(response);
77
+ const result = await callToolHandler({
78
+ params: { name: 'manage_email', arguments: { operation: 'triage', email: 'u@t.com' } },
79
+ });
80
+ expect(result.content).toHaveLength(1);
81
+ expect(result.content[0].type).toBe('text');
82
+ expect(result.content[0].text).toBe('## Messages (1)\n\nmsg-1 | alice');
83
+ expect(result.isError).toBeUndefined();
84
+ });
85
+ it('maps GwsError to structured isError response', async () => {
86
+ mockHandleToolCall.mockRejectedValue(new GwsError('Token expired', GwsExitCode.AuthError, 'authError', 'stderr: token invalid'));
87
+ const result = await callToolHandler({
88
+ params: { name: 'manage_email', arguments: { operation: 'triage', email: 'u@t.com' } },
89
+ });
90
+ expect(result.isError).toBe(true);
91
+ const text = result.content[0].text;
92
+ // Error JSON is followed by auth remediation guidance
93
+ expect(text).toContain('"error": "Token expired"');
94
+ expect(text).toContain(`"exitCode": ${GwsExitCode.AuthError}`);
95
+ expect(text).toContain('"reason": "authError"');
96
+ // Auth error should include remediation guidance
97
+ expect(text).toContain('**Next steps:**');
98
+ expect(text).toContain('Re-authenticate');
99
+ });
100
+ it('maps generic Error to plain error message', async () => {
101
+ mockHandleToolCall.mockRejectedValue(new Error('Something broke'));
102
+ const result = await callToolHandler({
103
+ params: { name: 'manage_email', arguments: {} },
104
+ });
105
+ expect(result.isError).toBe(true);
106
+ expect(result.content[0].text).toBe('Error: Something broke');
107
+ });
108
+ it('handles non-Error thrown values', async () => {
109
+ mockHandleToolCall.mockRejectedValue('string error');
110
+ const result = await callToolHandler({
111
+ params: { name: 'manage_email', arguments: {} },
112
+ });
113
+ expect(result.isError).toBe(true);
114
+ expect(result.content[0].text).toBe('Error: string error');
115
+ });
116
+ it('passes arguments to handleToolCall', async () => {
117
+ mockHandleToolCall.mockResolvedValue({ text: 'ok', refs: {} });
118
+ await callToolHandler({
119
+ params: { name: 'manage_drive', arguments: { operation: 'search', email: 'u@t.com' } },
120
+ });
121
+ expect(mockHandleToolCall).toHaveBeenCalledWith('manage_drive', {
122
+ operation: 'search',
123
+ email: 'u@t.com',
124
+ });
125
+ });
126
+ it('defaults to empty object when arguments are undefined', async () => {
127
+ mockHandleToolCall.mockResolvedValue({ text: 'ok', refs: {} });
128
+ await callToolHandler({
129
+ params: { name: 'manage_accounts' },
130
+ });
131
+ expect(mockHandleToolCall).toHaveBeenCalledWith('manage_accounts', {});
132
+ });
133
+ });
134
+ });
135
+ //# sourceMappingURL=server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.test.js","sourceRoot":"","sources":["../../../src/__tests__/server/server.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,2EAA2E;AAC3E,IAAI,CAAC,IAAI,CAAC,2BAA2B,EAAE,GAAG,EAAE;IAC1C,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,4BAA4B,CAAC,CAAC;IACzF,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,0BAA0B,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;AACxE,CAAC,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;AACxC,MAAM,iBAAiB,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;AAEpC,IAAI,CAAC,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5D,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1C,iBAAiB,EAAE,qBAAqB;QACxC,OAAO,EAAE,iBAAiB;KAC3B,CAAC,CAAC;CACJ,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,2CAA2C,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5D,oBAAoB,EAAE,IAAI,CAAC,EAAE,EAAE;CAChC,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,oCAAoC,EAAE,GAAG,EAAE,CAAC,CAAC;IACrD,qBAAqB,EAAE,uBAAuB;IAC9C,sBAAsB,EAAE,wBAAwB;CACjD,CAAC,CAAC,CAAC;AAEJ,IAAI,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;AAErC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGjE,MAAM,kBAAkB,GAAG,cAA4D,CAAC;AAExF,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,IAAI,gBAAgD,CAAC;IACrD,IAAI,eAA+C,CAAC;IAEpD,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,EAAE,CAAC;QAEf,yDAAyD;QACzD,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACjE,IAAI,MAAM,KAAK,wBAAwB;gBAAE,gBAAgB,GAAG,OAAO,CAAC;YACpE,IAAI,MAAM,KAAK,uBAAuB;gBAAE,eAAe,GAAG,OAAO,CAAC;QACpE,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,GAAG,EAAE;QACd,kBAAkB,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,gBAAgB,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAClD,MAAM,CAAC,eAAe,CAAC,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAC;YAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YAC3C,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAC;YAC1C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAChC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;gBACpC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;gBAC3C,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;YACxD,MAAM,QAAQ,GAAoB,EAAE,IAAI,EAAE,kCAAkC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACnG,kBAAkB,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;YAE/C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;aACvF,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YACxE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC5D,kBAAkB,CAAC,iBAAiB,CAClC,IAAI,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,SAAS,EAAE,WAAW,EAAE,uBAAuB,CAAC,CAC3F,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;aACvF,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAc,CAAC;YAC9C,sDAAsD;YACtD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,eAAe,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;YAChD,iDAAiD;YACjD,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,kBAAkB,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAEnE,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;YAC/C,kBAAkB,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC;YAErD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;gBACnC,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,EAAE;aAChD,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAE/D,MAAM,eAAe,CAAC;gBACpB,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE;aACvF,CAAC,CAAC;YAEH,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,cAAc,EAAE;gBAC9D,SAAS,EAAE,QAAQ;gBACnB,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;YACrE,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YAE/D,MAAM,eAAe,CAAC;gBACpB,MAAM,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE;aACpC,CAAC,CAAC;YAEH,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,91 @@
1
+ // Mock registry before tools imports it — avoids import.meta.url in Jest
2
+ jest.mock('../../factory/registry.js', () => {
3
+ const { loadManifest, generateTools } = jest.requireActual('../../factory/generator.js');
4
+ const { patches } = jest.requireActual('../../factory/patches.js');
5
+ const manifest = loadManifest();
6
+ return { manifest, generatedTools: generateTools(manifest, patches) };
7
+ });
8
+ import { toolSchemas, getToolSchema } from '../../server/tools.js';
9
+ describe('tool registry', () => {
10
+ it('has all expected tools', () => {
11
+ const names = toolSchemas.map(t => t.name);
12
+ // Hand-coded tools
13
+ expect(names).toContain('manage_accounts');
14
+ expect(names).toContain('queue_operations');
15
+ // Factory-generated tools
16
+ expect(names).toContain('manage_email');
17
+ expect(names).toContain('manage_calendar');
18
+ expect(names).toContain('manage_drive');
19
+ expect(names).toContain('manage_sheets');
20
+ expect(names).toContain('manage_docs');
21
+ expect(names).toContain('manage_tasks');
22
+ expect(names.length).toBeGreaterThanOrEqual(8);
23
+ });
24
+ it('getToolSchema returns correct tool', () => {
25
+ const tool = getToolSchema('manage_email');
26
+ expect(tool?.name).toBe('manage_email');
27
+ });
28
+ it('getToolSchema returns undefined for unknown', () => {
29
+ expect(getToolSchema('nonexistent')).toBeUndefined();
30
+ });
31
+ it('all schemas have additionalProperties: false', () => {
32
+ for (const tool of toolSchemas) {
33
+ const schema = tool.inputSchema;
34
+ expect(schema.additionalProperties).toBe(false);
35
+ }
36
+ });
37
+ it('all domain tools require operation', () => {
38
+ const domainTools = toolSchemas.filter(t => t.name !== 'queue_operations');
39
+ for (const tool of domainTools) {
40
+ const required = tool.inputSchema.required;
41
+ expect(required).toContain('operation');
42
+ }
43
+ });
44
+ });
45
+ describe('manage_email schema', () => {
46
+ const tool = getToolSchema('manage_email');
47
+ const props = tool.inputSchema.properties;
48
+ it('has operation enum with all email operations', () => {
49
+ // Core operations present (manifest may expand)
50
+ expect(props.operation.enum).toContain('search');
51
+ expect(props.operation.enum).toContain('read');
52
+ expect(props.operation.enum).toContain('send');
53
+ expect(props.operation.enum).toContain('reply');
54
+ expect(props.operation.enum).toContain('triage');
55
+ });
56
+ it('requires email', () => {
57
+ const required = tool.inputSchema.required;
58
+ expect(required).toContain('email');
59
+ });
60
+ });
61
+ describe('manage_calendar schema', () => {
62
+ const tool = getToolSchema('manage_calendar');
63
+ const props = tool.inputSchema.properties;
64
+ it('has operation enum with calendar operations', () => {
65
+ // Core operations present (manifest may expand)
66
+ expect(props.operation.enum).toContain('list');
67
+ expect(props.operation.enum).toContain('agenda');
68
+ expect(props.operation.enum).toContain('create');
69
+ expect(props.operation.enum).toContain('get');
70
+ expect(props.operation.enum).toContain('delete');
71
+ });
72
+ });
73
+ describe('queue_operations schema', () => {
74
+ const tool = getToolSchema('queue_operations');
75
+ const props = tool.inputSchema.properties;
76
+ it('has operations array with maxItems', () => {
77
+ expect(props.operations.type).toBe('array');
78
+ expect(props.operations.maxItems).toBe(10);
79
+ });
80
+ it('operations items require tool and args', () => {
81
+ expect(props.operations.items.required).toEqual(['tool', 'args']);
82
+ });
83
+ it('tool enum includes all domain tools', () => {
84
+ const toolEnum = props.operations.items.properties.tool.enum;
85
+ expect(toolEnum).toContain('manage_email');
86
+ expect(toolEnum).toContain('manage_calendar');
87
+ expect(toolEnum).toContain('manage_drive');
88
+ expect(toolEnum).toContain('manage_accounts');
89
+ });
90
+ });
91
+ //# sourceMappingURL=tools.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.test.js","sourceRoot":"","sources":["../../../src/__tests__/server/tools.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface AuthResult {
2
+ status: 'success' | 'error';
3
+ account?: string;
4
+ credentialPath?: string;
5
+ error?: string;
6
+ }
7
+ export interface AccountStatus {
8
+ email: string;
9
+ tokenValid: boolean;
10
+ scopes: string[];
11
+ scopeCount: number;
12
+ hasRefreshToken: boolean;
13
+ }
14
+ /**
15
+ * Check account status by reading our credential file and validating
16
+ * the token via a lightweight Gmail API call.
17
+ *
18
+ * Note: `gws auth status` is single-account (keyring-based) and ignores
19
+ * GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE. We bypass it entirely and
20
+ * validate against our own per-account credential files.
21
+ */
22
+ export declare function checkAccountStatus(email: string): Promise<AccountStatus>;
23
+ export declare function authenticateAccount(clientId: string, clientSecret: string): Promise<AuthResult>;
24
+ export declare function reauthWithServices(clientId: string, clientSecret: string, services: string): Promise<AuthResult>;
@@ -0,0 +1,118 @@
1
+ import { spawn, execFile } from 'node:child_process';
2
+ import { platform } from 'node:os';
3
+ import { execute, resolveGwsBinary, resolvePackageBinDir } from '../executor/gws.js';
4
+ import { exportAndSaveCredential, readCredential, hasCredential } from './credentials.js';
5
+ /**
6
+ * Check account status by reading our credential file and validating
7
+ * the token via a lightweight Gmail API call.
8
+ *
9
+ * Note: `gws auth status` is single-account (keyring-based) and ignores
10
+ * GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE. We bypass it entirely and
11
+ * validate against our own per-account credential files.
12
+ */
13
+ export async function checkAccountStatus(email) {
14
+ const hasCred = await hasCredential(email);
15
+ if (!hasCred) {
16
+ return {
17
+ email,
18
+ tokenValid: false,
19
+ scopes: [],
20
+ scopeCount: 0,
21
+ hasRefreshToken: false,
22
+ };
23
+ }
24
+ const cred = await readCredential(email);
25
+ const hasRefreshToken = Boolean(cred.refresh_token);
26
+ // Validate the token with a lightweight API call using this account's credential
27
+ let tokenValid = false;
28
+ try {
29
+ await execute(['gmail', 'users', 'getProfile', '--params', JSON.stringify({ userId: 'me' })], { account: email });
30
+ tokenValid = true;
31
+ }
32
+ catch {
33
+ tokenValid = false;
34
+ }
35
+ // Get scopes from gws auth status. These are the scopes granted to the
36
+ // OAuth app, not per-account — gws is single-account so we can't get
37
+ // per-account scopes. But they're useful for showing what services are enabled.
38
+ let scopes = [];
39
+ if (tokenValid) {
40
+ try {
41
+ const statusResult = await execute(['auth', 'status']);
42
+ const statusData = statusResult.data;
43
+ scopes = Array.isArray(statusData.scopes) ? statusData.scopes : [];
44
+ }
45
+ catch {
46
+ // Non-critical — scopes are informational
47
+ }
48
+ }
49
+ return {
50
+ email,
51
+ tokenValid,
52
+ scopes,
53
+ scopeCount: scopes.length,
54
+ hasRefreshToken,
55
+ };
56
+ }
57
+ export async function authenticateAccount(clientId, clientSecret) {
58
+ return runAuthLogin(clientId, clientSecret, ['auth', 'login']);
59
+ }
60
+ export async function reauthWithServices(clientId, clientSecret, services) {
61
+ return runAuthLogin(clientId, clientSecret, ['auth', 'login', '-s', services]);
62
+ }
63
+ // --- Internal ---
64
+ function runAuthLogin(clientId, clientSecret, args) {
65
+ return new Promise((resolve, reject) => {
66
+ const env = {
67
+ ...process.env,
68
+ GOOGLE_WORKSPACE_CLI_CLIENT_ID: clientId,
69
+ GOOGLE_WORKSPACE_CLI_CLIENT_SECRET: clientSecret,
70
+ };
71
+ const gwsBinary = resolveGwsBinary();
72
+ env.PATH = `${resolvePackageBinDir()}:${env.PATH || ''}`;
73
+ const proc = spawn(gwsBinary, args, {
74
+ env,
75
+ stdio: ['ignore', 'pipe', 'pipe'],
76
+ });
77
+ let stdout = '';
78
+ proc.stderr.on('data', (chunk) => {
79
+ const text = chunk.toString();
80
+ const match = text.match(/https:\/\/accounts\.google\.com\S+/);
81
+ if (match)
82
+ openBrowser(match[0]);
83
+ });
84
+ proc.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
85
+ proc.on('error', (err) => {
86
+ reject(new Error(`Failed to spawn gws auth login: ${err.message}`));
87
+ });
88
+ proc.on('close', async (code) => {
89
+ if (code !== 0) {
90
+ resolve({ status: 'error', error: `gws auth login exited with code ${code}` });
91
+ return;
92
+ }
93
+ try {
94
+ const result = JSON.parse(stdout);
95
+ const email = result.account;
96
+ if (!email) {
97
+ resolve({ status: 'error', error: 'No account email in gws auth login response' });
98
+ return;
99
+ }
100
+ const credPath = await exportAndSaveCredential(email);
101
+ resolve({ status: 'success', account: email, credentialPath: credPath });
102
+ }
103
+ catch (err) {
104
+ resolve({ status: 'error', error: `Failed to process auth result: ${err.message}` });
105
+ }
106
+ });
107
+ });
108
+ }
109
+ function openBrowser(url) {
110
+ const cmd = platform() === 'darwin' ? 'open'
111
+ : platform() === 'win32' ? 'start'
112
+ : 'xdg-open';
113
+ execFile(cmd, [url], (err) => {
114
+ if (err)
115
+ process.stderr.write(`Failed to open browser: ${err.message}\n`);
116
+ });
117
+ }
118
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/accounts/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface AuthorizedUserCredential {
2
+ type: 'authorized_user';
3
+ client_id: string;
4
+ client_secret: string;
5
+ refresh_token: string;
6
+ }
7
+ export declare function hasCredential(email: string): Promise<boolean>;
8
+ export declare function exportAndSaveCredential(email: string): Promise<string>;
9
+ export declare function readCredential(email: string): Promise<AuthorizedUserCredential>;
10
+ export declare function removeCredential(email: string): Promise<void>;
11
+ export declare function listCredentials(): Promise<string[]>;