slates 0.0.2 → 1.0.0-rc.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.
Files changed (34) hide show
  1. package/example/google-sheets/auth.ts +317 -0
  2. package/example/google-sheets/config.ts +9 -0
  3. package/example/google-sheets/docs/abc.md +1 -0
  4. package/example/google-sheets/docs/readme.md +1 -0
  5. package/example/google-sheets/index.ts +42 -0
  6. package/example/google-sheets/lib/client.ts +717 -0
  7. package/example/google-sheets/lib/types.ts +1674 -0
  8. package/example/google-sheets/readme.md +1 -0
  9. package/example/google-sheets/slate.json +4 -0
  10. package/example/google-sheets/spec.ts +13 -0
  11. package/example/google-sheets/tools/append-values.ts +74 -0
  12. package/example/google-sheets/tools/clear-values.ts +45 -0
  13. package/example/google-sheets/tools/copy-paste.ts +99 -0
  14. package/example/google-sheets/tools/create-spreadsheet.ts +72 -0
  15. package/example/google-sheets/tools/find-replace.ts +68 -0
  16. package/example/google-sheets/tools/format-cells.ts +137 -0
  17. package/example/google-sheets/tools/get-spreadsheet.ts +108 -0
  18. package/example/google-sheets/tools/index.ts +15 -0
  19. package/example/google-sheets/tools/manage-rows-columns.ts +160 -0
  20. package/example/google-sheets/tools/manage-sheets.ts +183 -0
  21. package/example/google-sheets/tools/merge-cells.ts +76 -0
  22. package/example/google-sheets/tools/named-ranges.ts +82 -0
  23. package/example/google-sheets/tools/protect-range.ts +100 -0
  24. package/example/google-sheets/tools/read-values.ts +94 -0
  25. package/example/google-sheets/tools/sort-range.ts +78 -0
  26. package/example/google-sheets/tools/write-values.ts +91 -0
  27. package/example/google-sheets/triggers/index.ts +1 -0
  28. package/example/google-sheets/triggers/spreadsheet-changed.ts +108 -0
  29. package/example/out.zip.b64 +1 -0
  30. package/package.json +30 -20
  31. package/src/index.ts +1 -0
  32. package/tsconfig.json +8 -0
  33. package/bin/slates.js +0 -8
  34. package/readme.md +0 -9
@@ -0,0 +1 @@
1
+ Hello world
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "@w1/s1",
3
+ "version": "1.2.0"
4
+ }
@@ -0,0 +1,13 @@
1
+ import { SlateSpecification } from 'slates';
2
+ import { auth } from './auth';
3
+ import { config } from './config';
4
+
5
+ export let spec = SlateSpecification.create({
6
+ key: 'google-sheets',
7
+ name: 'Google Sheets',
8
+ description:
9
+ 'Cloud-based spreadsheet application for creating, editing, and collaborating on spreadsheets.',
10
+ metadata: {},
11
+ config,
12
+ auth
13
+ });
@@ -0,0 +1,74 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ export let appendValuesTool = SlateTool.create(spec, {
7
+ name: 'Append Values',
8
+ key: 'append_values',
9
+ description: `Appends rows of data to a table in a Google Sheets spreadsheet.
10
+ Finds the last row with data in the specified range and appends new rows below it. Ideal for adding records to a data table.`,
11
+ instructions: [
12
+ 'Specify a range that covers the table (e.g., "Sheet1!A:E" for columns A through E)',
13
+ 'New rows will be appended after the last row with data'
14
+ ],
15
+ tags: {
16
+ destructive: false,
17
+ readOnly: false
18
+ }
19
+ })
20
+ .input(
21
+ z.object({
22
+ spreadsheetId: z.string().describe('ID of the spreadsheet'),
23
+ range: z.string().describe('Range defining the table to append to (e.g., "Sheet1!A:E")'),
24
+ values: z
25
+ .array(z.array(z.union([z.string(), z.number(), z.boolean(), z.null()])))
26
+ .describe('2D array of rows to append'),
27
+ valueInputOption: z
28
+ .enum(['RAW', 'USER_ENTERED'])
29
+ .optional()
30
+ .describe('How input values should be interpreted'),
31
+ insertDataOption: z
32
+ .enum(['OVERWRITE', 'INSERT_ROWS'])
33
+ .optional()
34
+ .describe('Whether to overwrite or insert new rows')
35
+ })
36
+ )
37
+ .output(
38
+ z.object({
39
+ spreadsheetId: z.string().optional().describe('ID of the spreadsheet'),
40
+ tableRange: z.string().optional().describe('Range of the table that was appended to'),
41
+ updatedRange: z.string().optional().describe('The actual range that was written'),
42
+ updatedRows: z.number().optional().describe('Number of rows appended'),
43
+ updatedColumns: z.number().optional().describe('Number of columns in appended rows'),
44
+ updatedCells: z.number().optional().describe('Total cells written')
45
+ })
46
+ )
47
+ .handleInvocation(async ctx => {
48
+ let client = new SheetsClient({ token: ctx.auth.token });
49
+
50
+ let result = await client.appendValues(
51
+ ctx.input.spreadsheetId,
52
+ ctx.input.range,
53
+ ctx.input.values,
54
+ {
55
+ valueInputOption: ctx.input.valueInputOption || 'USER_ENTERED',
56
+ insertDataOption: ctx.input.insertDataOption
57
+ }
58
+ );
59
+
60
+ let output = {
61
+ spreadsheetId: result.spreadsheetId,
62
+ tableRange: result.tableRange,
63
+ updatedRange: result.updates?.updatedRange,
64
+ updatedRows: result.updates?.updatedRows,
65
+ updatedColumns: result.updates?.updatedColumns,
66
+ updatedCells: result.updates?.updatedCells
67
+ };
68
+
69
+ return {
70
+ output,
71
+ message: `Appended **${output.updatedRows || ctx.input.values.length}** row(s) to range \`${ctx.input.range}\`.`
72
+ };
73
+ })
74
+ .build();
@@ -0,0 +1,45 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ export let clearValuesTool = SlateTool.create(spec, {
7
+ name: 'Clear Values',
8
+ key: 'clear_values',
9
+ description: `Clears cell values from specified ranges in a Google Sheets spreadsheet.
10
+ Removes values but preserves formatting, data validation, and other cell properties.`,
11
+ tags: {
12
+ destructive: true,
13
+ readOnly: false
14
+ }
15
+ })
16
+ .input(
17
+ z.object({
18
+ spreadsheetId: z.string().describe('ID of the spreadsheet'),
19
+ ranges: z
20
+ .array(z.string())
21
+ .describe('Ranges to clear in A1 notation (e.g., ["Sheet1!A1:B10", "Sheet2!C1:D5"])')
22
+ })
23
+ )
24
+ .output(
25
+ z.object({
26
+ spreadsheetId: z.string().optional().describe('ID of the spreadsheet'),
27
+ clearedRanges: z.array(z.string()).optional().describe('Ranges that were cleared')
28
+ })
29
+ )
30
+ .handleInvocation(async ctx => {
31
+ let client = new SheetsClient({ token: ctx.auth.token });
32
+
33
+ let result = await client.batchClearValues(ctx.input.spreadsheetId, ctx.input.ranges);
34
+
35
+ let output = {
36
+ spreadsheetId: result.spreadsheetId,
37
+ clearedRanges: result.clearedRanges
38
+ };
39
+
40
+ return {
41
+ output,
42
+ message: `Cleared **${ctx.input.ranges.length}** range(s): ${ctx.input.ranges.map(r => `\`${r}\``).join(', ')}.`
43
+ };
44
+ })
45
+ .build();
@@ -0,0 +1,99 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ export let copyPasteTool = SlateTool.create(spec, {
7
+ name: 'Copy and Paste',
8
+ key: 'copy_paste',
9
+ description: `Copies a range of cells and pastes them to another location in a Google Sheets spreadsheet.
10
+ Supports various paste types including values only, format only, formulas only, and transposing data.`,
11
+ tags: {
12
+ destructive: false,
13
+ readOnly: false
14
+ }
15
+ })
16
+ .input(
17
+ z.object({
18
+ spreadsheetId: z.string().describe('ID of the spreadsheet'),
19
+ sourceSheetId: z.number().describe('Sheet ID of the source range'),
20
+ sourceStartRowIndex: z.number().describe('Source start row index (0-based)'),
21
+ sourceEndRowIndex: z.number().describe('Source end row index (exclusive)'),
22
+ sourceStartColumnIndex: z.number().describe('Source start column index (0-based)'),
23
+ sourceEndColumnIndex: z.number().describe('Source end column index (exclusive)'),
24
+ destinationSheetId: z.number().describe('Sheet ID of the destination range'),
25
+ destinationStartRowIndex: z.number().describe('Destination start row index (0-based)'),
26
+ destinationEndRowIndex: z.number().describe('Destination end row index (exclusive)'),
27
+ destinationStartColumnIndex: z
28
+ .number()
29
+ .describe('Destination start column index (0-based)'),
30
+ destinationEndColumnIndex: z
31
+ .number()
32
+ .describe('Destination end column index (exclusive)'),
33
+ pasteType: z
34
+ .enum([
35
+ 'PASTE_NORMAL',
36
+ 'PASTE_VALUES',
37
+ 'PASTE_FORMAT',
38
+ 'PASTE_NO_BORDERS',
39
+ 'PASTE_FORMULA',
40
+ 'PASTE_DATA_VALIDATION',
41
+ 'PASTE_CONDITIONAL_FORMATTING'
42
+ ])
43
+ .optional()
44
+ .describe(
45
+ 'What to paste: NORMAL (all), VALUES (values only), FORMAT (formatting only), etc.'
46
+ ),
47
+ pasteOrientation: z
48
+ .enum(['NORMAL', 'TRANSPOSE'])
49
+ .optional()
50
+ .describe('Whether to transpose rows and columns')
51
+ })
52
+ )
53
+ .output(
54
+ z.object({
55
+ operationPerformed: z.string().describe('Description of the copy/paste operation'),
56
+ sourceRange: z.string().describe('Description of the source range'),
57
+ destinationRange: z.string().describe('Description of the destination range')
58
+ })
59
+ )
60
+ .handleInvocation(async ctx => {
61
+ let client = new SheetsClient({ token: ctx.auth.token });
62
+
63
+ await client.copyPaste(
64
+ ctx.input.spreadsheetId,
65
+ {
66
+ sheetId: ctx.input.sourceSheetId,
67
+ startRowIndex: ctx.input.sourceStartRowIndex,
68
+ endRowIndex: ctx.input.sourceEndRowIndex,
69
+ startColumnIndex: ctx.input.sourceStartColumnIndex,
70
+ endColumnIndex: ctx.input.sourceEndColumnIndex
71
+ },
72
+ {
73
+ sheetId: ctx.input.destinationSheetId,
74
+ startRowIndex: ctx.input.destinationStartRowIndex,
75
+ endRowIndex: ctx.input.destinationEndRowIndex,
76
+ startColumnIndex: ctx.input.destinationStartColumnIndex,
77
+ endColumnIndex: ctx.input.destinationEndColumnIndex
78
+ },
79
+ ctx.input.pasteType,
80
+ ctx.input.pasteOrientation
81
+ );
82
+
83
+ let sourceRows = ctx.input.sourceEndRowIndex - ctx.input.sourceStartRowIndex;
84
+ let sourceCols = ctx.input.sourceEndColumnIndex - ctx.input.sourceStartColumnIndex;
85
+ let destRows = ctx.input.destinationEndRowIndex - ctx.input.destinationStartRowIndex;
86
+ let destCols = ctx.input.destinationEndColumnIndex - ctx.input.destinationStartColumnIndex;
87
+
88
+ let output = {
89
+ operationPerformed: `Copied and pasted (${ctx.input.pasteType || 'PASTE_NORMAL'}${ctx.input.pasteOrientation === 'TRANSPOSE' ? ', transposed' : ''})`,
90
+ sourceRange: `${sourceRows} row(s) x ${sourceCols} column(s)`,
91
+ destinationRange: `${destRows} row(s) x ${destCols} column(s)`
92
+ };
93
+
94
+ return {
95
+ output,
96
+ message: `Copied **${sourceRows * sourceCols}** cells and pasted to destination.`
97
+ };
98
+ })
99
+ .build();
@@ -0,0 +1,72 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ export let createSpreadsheetTool = SlateTool.create(spec, {
7
+ name: 'Create Spreadsheet',
8
+ key: 'create_spreadsheet',
9
+ description: `Creates a new Google Sheets spreadsheet with optional initial sheets.
10
+ Use this to programmatically create spreadsheets with custom titles, locales, and time zones.`,
11
+ tags: {
12
+ destructive: false,
13
+ readOnly: false
14
+ }
15
+ })
16
+ .input(
17
+ z.object({
18
+ title: z.string().describe('Title of the new spreadsheet'),
19
+ locale: z.string().optional().describe('Locale of the spreadsheet (e.g., "en_US")'),
20
+ timeZone: z
21
+ .string()
22
+ .optional()
23
+ .describe('Time zone of the spreadsheet (e.g., "America/New_York")'),
24
+ autoRecalc: z
25
+ .enum(['ON_CHANGE', 'MINUTE', 'HOUR'])
26
+ .optional()
27
+ .describe('When to recalculate formulas')
28
+ })
29
+ )
30
+ .output(
31
+ z.object({
32
+ spreadsheetId: z.string().describe('ID of the created spreadsheet'),
33
+ title: z.string().describe('Title of the spreadsheet'),
34
+ spreadsheetUrl: z.string().optional().describe('URL to open the spreadsheet'),
35
+ sheets: z
36
+ .array(
37
+ z.object({
38
+ sheetId: z.number().describe('ID of the sheet'),
39
+ title: z.string().describe('Title of the sheet'),
40
+ index: z.number().describe('Index position of the sheet')
41
+ })
42
+ )
43
+ .describe('Sheets in the spreadsheet')
44
+ })
45
+ )
46
+ .handleInvocation(async ctx => {
47
+ let client = new SheetsClient({ token: ctx.auth.token });
48
+
49
+ let result = await client.createSpreadsheet({
50
+ title: ctx.input.title,
51
+ locale: ctx.input.locale,
52
+ timeZone: ctx.input.timeZone,
53
+ autoRecalc: ctx.input.autoRecalc
54
+ });
55
+
56
+ let output = {
57
+ spreadsheetId: result.spreadsheetId,
58
+ title: result.properties.title,
59
+ spreadsheetUrl: result.spreadsheetUrl,
60
+ sheets: (result.sheets || []).map(sheet => ({
61
+ sheetId: sheet.properties.sheetId,
62
+ title: sheet.properties.title,
63
+ index: sheet.properties.index
64
+ }))
65
+ };
66
+
67
+ return {
68
+ output,
69
+ message: `Created spreadsheet **"${output.title}"** with ID \`${output.spreadsheetId}\`.`
70
+ };
71
+ })
72
+ .build();
@@ -0,0 +1,68 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ export let findReplaceTool = SlateTool.create(spec, {
7
+ name: 'Find and Replace',
8
+ key: 'find_replace',
9
+ description: `Finds and replaces text or values in a Google Sheets spreadsheet.
10
+ Supports case-sensitive matching, whole cell matching, regex patterns, and searching in formulas.`,
11
+ tags: {
12
+ destructive: false,
13
+ readOnly: false
14
+ }
15
+ })
16
+ .input(
17
+ z.object({
18
+ spreadsheetId: z.string().describe('ID of the spreadsheet'),
19
+ find: z.string().describe('Text or pattern to find'),
20
+ replacement: z.string().describe('Text to replace with'),
21
+ matchCase: z.boolean().optional().describe('Case-sensitive search'),
22
+ matchEntireCell: z.boolean().optional().describe('Match entire cell content only'),
23
+ searchByRegex: z.boolean().optional().describe('Treat find string as regex pattern'),
24
+ includeFormulas: z.boolean().optional().describe('Search within formula text'),
25
+ sheetId: z.number().optional().describe('Limit search to specific sheet'),
26
+ allSheets: z.boolean().optional().describe('Search all sheets (default behavior)')
27
+ })
28
+ )
29
+ .output(
30
+ z.object({
31
+ valuesChanged: z.number().optional().describe('Number of values changed'),
32
+ formulasChanged: z.number().optional().describe('Number of formulas changed'),
33
+ rowsChanged: z.number().optional().describe('Number of rows affected'),
34
+ sheetsChanged: z.number().optional().describe('Number of sheets affected'),
35
+ occurrencesChanged: z.number().optional().describe('Total occurrences replaced')
36
+ })
37
+ )
38
+ .handleInvocation(async ctx => {
39
+ let client = new SheetsClient({ token: ctx.auth.token });
40
+
41
+ let result = await client.findReplace(
42
+ ctx.input.spreadsheetId,
43
+ ctx.input.find,
44
+ ctx.input.replacement,
45
+ {
46
+ matchCase: ctx.input.matchCase,
47
+ matchEntireCell: ctx.input.matchEntireCell,
48
+ searchByRegex: ctx.input.searchByRegex,
49
+ includeFormulas: ctx.input.includeFormulas,
50
+ sheetId: ctx.input.sheetId,
51
+ allSheets: ctx.input.allSheets
52
+ }
53
+ );
54
+
55
+ let output = {
56
+ valuesChanged: result.valuesChanged,
57
+ formulasChanged: result.formulasChanged,
58
+ rowsChanged: result.rowsChanged,
59
+ sheetsChanged: result.sheetsChanged,
60
+ occurrencesChanged: result.occurrencesChanged
61
+ };
62
+
63
+ return {
64
+ output,
65
+ message: `Replaced **${output.occurrencesChanged || 0}** occurrence(s) of "${ctx.input.find}" with "${ctx.input.replacement}".`
66
+ };
67
+ })
68
+ .build();
@@ -0,0 +1,137 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ let colorSchema = z
7
+ .object({
8
+ red: z.number().min(0).max(1).optional().describe('Red component (0-1)'),
9
+ green: z.number().min(0).max(1).optional().describe('Green component (0-1)'),
10
+ blue: z.number().min(0).max(1).optional().describe('Blue component (0-1)'),
11
+ alpha: z.number().min(0).max(1).optional().describe('Alpha/opacity (0-1)')
12
+ })
13
+ .optional();
14
+
15
+ export let formatCellsTool = SlateTool.create(spec, {
16
+ name: 'Format Cells',
17
+ key: 'format_cells',
18
+ description: `Applies formatting to cells in a Google Sheets spreadsheet.
19
+ Supports text formatting (bold, italic, font, color), cell background, alignment, number formats, and borders.`,
20
+ instructions: [
21
+ 'Colors use RGB values from 0 to 1 (e.g., red: 1, green: 0, blue: 0 for pure red)',
22
+ 'Number format patterns follow Google Sheets format codes'
23
+ ],
24
+ tags: {
25
+ destructive: false,
26
+ readOnly: false
27
+ }
28
+ })
29
+ .input(
30
+ z.object({
31
+ spreadsheetId: z.string().describe('ID of the spreadsheet'),
32
+ sheetId: z.number().describe('ID of the sheet containing the cells'),
33
+ startRowIndex: z.number().describe('Start row index (0-based)'),
34
+ endRowIndex: z.number().describe('End row index (exclusive)'),
35
+ startColumnIndex: z.number().describe('Start column index (0-based)'),
36
+ endColumnIndex: z.number().describe('End column index (exclusive)'),
37
+ backgroundColor: colorSchema.describe('Background color'),
38
+ textFormat: z
39
+ .object({
40
+ foregroundColor: colorSchema.describe('Text color'),
41
+ fontFamily: z.string().optional().describe('Font family (e.g., "Arial")'),
42
+ fontSize: z.number().optional().describe('Font size in points'),
43
+ bold: z.boolean().optional().describe('Bold text'),
44
+ italic: z.boolean().optional().describe('Italic text'),
45
+ strikethrough: z.boolean().optional().describe('Strikethrough text'),
46
+ underline: z.boolean().optional().describe('Underlined text')
47
+ })
48
+ .optional()
49
+ .describe('Text formatting'),
50
+ horizontalAlignment: z
51
+ .enum(['LEFT', 'CENTER', 'RIGHT'])
52
+ .optional()
53
+ .describe('Horizontal alignment'),
54
+ verticalAlignment: z
55
+ .enum(['TOP', 'MIDDLE', 'BOTTOM'])
56
+ .optional()
57
+ .describe('Vertical alignment'),
58
+ wrapStrategy: z
59
+ .enum(['OVERFLOW_CELL', 'CLIP', 'WRAP'])
60
+ .optional()
61
+ .describe('Text wrapping'),
62
+ numberFormat: z
63
+ .object({
64
+ type: z
65
+ .enum([
66
+ 'TEXT',
67
+ 'NUMBER',
68
+ 'PERCENT',
69
+ 'CURRENCY',
70
+ 'DATE',
71
+ 'TIME',
72
+ 'DATE_TIME',
73
+ 'SCIENTIFIC'
74
+ ])
75
+ .describe('Format type'),
76
+ pattern: z.string().optional().describe('Format pattern (e.g., "#,##0.00")')
77
+ })
78
+ .optional()
79
+ .describe('Number format')
80
+ })
81
+ )
82
+ .output(
83
+ z.object({
84
+ formatted: z.boolean().describe('Whether formatting was applied successfully'),
85
+ range: z.string().describe('Description of the formatted range')
86
+ })
87
+ )
88
+ .handleInvocation(async ctx => {
89
+ let client = new SheetsClient({ token: ctx.auth.token });
90
+
91
+ let format: Record<string, unknown> = {};
92
+
93
+ if (ctx.input.backgroundColor) {
94
+ format.backgroundColor = ctx.input.backgroundColor;
95
+ }
96
+ if (ctx.input.textFormat) {
97
+ format.textFormat = ctx.input.textFormat;
98
+ }
99
+ if (ctx.input.horizontalAlignment) {
100
+ format.horizontalAlignment = ctx.input.horizontalAlignment;
101
+ }
102
+ if (ctx.input.verticalAlignment) {
103
+ format.verticalAlignment = ctx.input.verticalAlignment;
104
+ }
105
+ if (ctx.input.wrapStrategy) {
106
+ format.wrapStrategy = ctx.input.wrapStrategy;
107
+ }
108
+ if (ctx.input.numberFormat) {
109
+ format.numberFormat = ctx.input.numberFormat;
110
+ }
111
+
112
+ await client.formatCells(
113
+ ctx.input.spreadsheetId,
114
+ {
115
+ sheetId: ctx.input.sheetId,
116
+ startRowIndex: ctx.input.startRowIndex,
117
+ endRowIndex: ctx.input.endRowIndex,
118
+ startColumnIndex: ctx.input.startColumnIndex,
119
+ endColumnIndex: ctx.input.endColumnIndex
120
+ },
121
+ format
122
+ );
123
+
124
+ let rowCount = ctx.input.endRowIndex - ctx.input.startRowIndex;
125
+ let colCount = ctx.input.endColumnIndex - ctx.input.startColumnIndex;
126
+
127
+ let output = {
128
+ formatted: true,
129
+ range: `${rowCount} row(s) x ${colCount} column(s) starting at row ${ctx.input.startRowIndex}, column ${ctx.input.startColumnIndex}`
130
+ };
131
+
132
+ return {
133
+ output,
134
+ message: `Applied formatting to **${rowCount * colCount}** cells.`
135
+ };
136
+ })
137
+ .build();
@@ -0,0 +1,108 @@
1
+ import { SlateTool } from 'slates';
2
+ import { z } from 'zod';
3
+ import { SheetsClient } from '../lib/client';
4
+ import { spec } from '../spec';
5
+
6
+ export let getSpreadsheetTool = SlateTool.create(spec, {
7
+ name: 'Get Spreadsheet',
8
+ key: 'get_spreadsheet',
9
+ description: `Retrieves metadata and structure of a Google Sheets spreadsheet.
10
+ Returns spreadsheet properties, sheet list, and named ranges. Optionally include cell data for specific ranges.`,
11
+ tags: {
12
+ destructive: false,
13
+ readOnly: true
14
+ }
15
+ })
16
+ .input(
17
+ z.object({
18
+ spreadsheetId: z.string().describe('ID of the spreadsheet to retrieve'),
19
+ ranges: z
20
+ .array(z.string())
21
+ .optional()
22
+ .describe('Optional ranges to include grid data for (e.g., ["Sheet1!A1:B10"])'),
23
+ includeGridData: z
24
+ .boolean()
25
+ .optional()
26
+ .describe('Include cell data for specified ranges')
27
+ })
28
+ )
29
+ .output(
30
+ z.object({
31
+ spreadsheetId: z.string().describe('ID of the spreadsheet'),
32
+ title: z.string().describe('Title of the spreadsheet'),
33
+ locale: z.string().optional().describe('Locale of the spreadsheet'),
34
+ timeZone: z.string().optional().describe('Time zone of the spreadsheet'),
35
+ spreadsheetUrl: z.string().optional().describe('URL to open the spreadsheet'),
36
+ sheets: z
37
+ .array(
38
+ z.object({
39
+ sheetId: z.number().describe('ID of the sheet'),
40
+ title: z.string().describe('Title of the sheet'),
41
+ index: z.number().describe('Index position of the sheet'),
42
+ sheetType: z.string().optional().describe('Type of the sheet'),
43
+ rowCount: z.number().optional().describe('Number of rows'),
44
+ columnCount: z.number().optional().describe('Number of columns'),
45
+ frozenRowCount: z.number().optional().describe('Number of frozen rows'),
46
+ frozenColumnCount: z.number().optional().describe('Number of frozen columns'),
47
+ hidden: z.boolean().optional().describe('Whether the sheet is hidden')
48
+ })
49
+ )
50
+ .describe('Sheets in the spreadsheet'),
51
+ namedRanges: z
52
+ .array(
53
+ z.object({
54
+ namedRangeId: z.string().optional().describe('ID of the named range'),
55
+ name: z.string().optional().describe('Name of the range'),
56
+ sheetId: z.number().optional().describe('Sheet containing the range'),
57
+ startRowIndex: z.number().optional().describe('Start row (0-indexed)'),
58
+ endRowIndex: z.number().optional().describe('End row (exclusive)'),
59
+ startColumnIndex: z.number().optional().describe('Start column (0-indexed)'),
60
+ endColumnIndex: z.number().optional().describe('End column (exclusive)')
61
+ })
62
+ )
63
+ .optional()
64
+ .describe('Named ranges in the spreadsheet')
65
+ })
66
+ )
67
+ .handleInvocation(async ctx => {
68
+ let client = new SheetsClient({ token: ctx.auth.token });
69
+
70
+ let result = await client.getSpreadsheet(ctx.input.spreadsheetId, {
71
+ ranges: ctx.input.ranges,
72
+ includeGridData: ctx.input.includeGridData
73
+ });
74
+
75
+ let output = {
76
+ spreadsheetId: result.spreadsheetId,
77
+ title: result.properties.title,
78
+ locale: result.properties.locale,
79
+ timeZone: result.properties.timeZone,
80
+ spreadsheetUrl: result.spreadsheetUrl,
81
+ sheets: (result.sheets || []).map(sheet => ({
82
+ sheetId: sheet.properties.sheetId,
83
+ title: sheet.properties.title,
84
+ index: sheet.properties.index,
85
+ sheetType: sheet.properties.sheetType,
86
+ rowCount: sheet.properties.gridProperties?.rowCount,
87
+ columnCount: sheet.properties.gridProperties?.columnCount,
88
+ frozenRowCount: sheet.properties.gridProperties?.frozenRowCount,
89
+ frozenColumnCount: sheet.properties.gridProperties?.frozenColumnCount,
90
+ hidden: sheet.properties.hidden
91
+ })),
92
+ namedRanges: result.namedRanges?.map(nr => ({
93
+ namedRangeId: nr.namedRangeId,
94
+ name: nr.name,
95
+ sheetId: nr.range?.sheetId,
96
+ startRowIndex: nr.range?.startRowIndex,
97
+ endRowIndex: nr.range?.endRowIndex,
98
+ startColumnIndex: nr.range?.startColumnIndex,
99
+ endColumnIndex: nr.range?.endColumnIndex
100
+ }))
101
+ };
102
+
103
+ return {
104
+ output,
105
+ message: `Retrieved spreadsheet **"${output.title}"** with ${output.sheets.length} sheet(s).`
106
+ };
107
+ })
108
+ .build();
@@ -0,0 +1,15 @@
1
+ export * from './append-values';
2
+ export * from './clear-values';
3
+ export * from './copy-paste';
4
+ export * from './create-spreadsheet';
5
+ export * from './find-replace';
6
+ export * from './format-cells';
7
+ export * from './get-spreadsheet';
8
+ export * from './manage-rows-columns';
9
+ export * from './manage-sheets';
10
+ export * from './merge-cells';
11
+ export * from './named-ranges';
12
+ export * from './protect-range';
13
+ export * from './read-values';
14
+ export * from './sort-range';
15
+ export * from './write-values';