clipy-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/auth.d.ts +53 -0
- package/dist/auth.js +314 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +160 -0
- package/dist/color.d.ts +12 -0
- package/dist/color.js +19 -0
- package/dist/colors.d.ts +6 -0
- package/dist/colors.js +26 -0
- package/dist/host/doctor.d.ts +17 -0
- package/dist/host/doctor.js +54 -0
- package/dist/host/help.d.ts +20 -0
- package/dist/host/help.js +142 -0
- package/dist/host/setup.d.ts +16 -0
- package/dist/host/setup.js +93 -0
- package/dist/http.d.ts +14 -0
- package/dist/http.js +53 -0
- package/dist/ids.d.ts +2 -0
- package/dist/ids.js +21 -0
- package/dist/json-input.d.ts +4 -0
- package/dist/json-input.js +34 -0
- package/dist/lib/format.d.ts +14 -0
- package/dist/lib/format.js +73 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.js +6 -0
- package/dist/lib/ops.d.ts +460 -0
- package/dist/lib/ops.js +475 -0
- package/dist/lib/table.d.ts +14 -0
- package/dist/lib/table.js +67 -0
- package/dist/lib/types.d.ts +26 -0
- package/dist/lib/types.js +1 -0
- package/dist/output.d.ts +37 -0
- package/dist/output.js +67 -0
- package/dist/plugins/catalog.d.ts +11 -0
- package/dist/plugins/catalog.js +31 -0
- package/dist/plugins/sheet/plugin.d.ts +2 -0
- package/dist/plugins/sheet/plugin.js +8 -0
- package/dist/plugins/sheet/register.d.ts +2 -0
- package/dist/plugins/sheet/register.js +529 -0
- package/dist/plugins/sheet/specs.d.ts +20 -0
- package/dist/plugins/sheet/specs.js +291 -0
- package/dist/plugins/types.d.ts +7 -0
- package/dist/plugins/types.js +1 -0
- package/dist/ranges.d.ts +20 -0
- package/dist/ranges.js +77 -0
- package/dist/run.d.ts +353 -0
- package/dist/run.js +36 -0
- package/dist/specs.d.ts +1 -0
- package/dist/specs.js +1 -0
- package/package.json +50 -0
- package/skills/clipy/SKILL.md +38 -0
- package/skills/clipy-sheet/SKILL.md +71 -0
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
export type Globals = {
|
|
3
|
+
pretty: boolean;
|
|
4
|
+
account?: string;
|
|
5
|
+
spreadsheet?: string;
|
|
6
|
+
dryRun: boolean;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function takeGlobals(cmd: Command): Globals;
|
|
10
|
+
export declare function opsFor(account?: string): {
|
|
11
|
+
getSpreadsheet: (id: string, fields?: string) => Promise<import("./lib/types.js").Spreadsheet>;
|
|
12
|
+
findSpreadsheets: (name: string, limit?: number) => Promise<{
|
|
13
|
+
query: string;
|
|
14
|
+
files: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
url: string;
|
|
18
|
+
}[];
|
|
19
|
+
}>;
|
|
20
|
+
info: (id: string) => Promise<{
|
|
21
|
+
spreadsheetId: string;
|
|
22
|
+
title: string | undefined;
|
|
23
|
+
url: string | undefined;
|
|
24
|
+
tabs: {
|
|
25
|
+
sheetId: number | undefined;
|
|
26
|
+
title: string | undefined;
|
|
27
|
+
index: number | undefined;
|
|
28
|
+
rows: number | undefined;
|
|
29
|
+
columns: number | undefined;
|
|
30
|
+
}[];
|
|
31
|
+
}>;
|
|
32
|
+
listTabs: (id: string) => Promise<{
|
|
33
|
+
title: string | undefined;
|
|
34
|
+
tabs: {
|
|
35
|
+
sheetId: number | undefined;
|
|
36
|
+
title: string | undefined;
|
|
37
|
+
index: number | undefined;
|
|
38
|
+
rows: number | undefined;
|
|
39
|
+
columns: number | undefined;
|
|
40
|
+
}[];
|
|
41
|
+
}>;
|
|
42
|
+
readTable: (id: string, opts: import("./lib/ops.js").ReadOpts) => Promise<{
|
|
43
|
+
range: string;
|
|
44
|
+
values: unknown[][];
|
|
45
|
+
} | {
|
|
46
|
+
headers: string[];
|
|
47
|
+
rows: Record<string, unknown>[];
|
|
48
|
+
headerRow: number;
|
|
49
|
+
range: string;
|
|
50
|
+
values?: undefined;
|
|
51
|
+
}>;
|
|
52
|
+
readRange: (id: string, range: string) => Promise<{
|
|
53
|
+
range: string;
|
|
54
|
+
values: unknown[][];
|
|
55
|
+
}>;
|
|
56
|
+
append: (id: string, opts: import("./lib/ops.js").WriteTableOpts) => Promise<{
|
|
57
|
+
dryRun: boolean;
|
|
58
|
+
tab: string;
|
|
59
|
+
headers: string[];
|
|
60
|
+
rows: number;
|
|
61
|
+
bootstrap: boolean;
|
|
62
|
+
result?: undefined;
|
|
63
|
+
} | {
|
|
64
|
+
tab: string;
|
|
65
|
+
headers: string[];
|
|
66
|
+
rows: number;
|
|
67
|
+
bootstrap: boolean;
|
|
68
|
+
result: unknown;
|
|
69
|
+
dryRun?: undefined;
|
|
70
|
+
} | {
|
|
71
|
+
dryRun: boolean;
|
|
72
|
+
tab: string;
|
|
73
|
+
headers: string[];
|
|
74
|
+
rows: number;
|
|
75
|
+
bootstrap?: undefined;
|
|
76
|
+
result?: undefined;
|
|
77
|
+
} | {
|
|
78
|
+
tab: string;
|
|
79
|
+
headers: string[];
|
|
80
|
+
rows: number;
|
|
81
|
+
result: unknown;
|
|
82
|
+
dryRun?: undefined;
|
|
83
|
+
bootstrap?: undefined;
|
|
84
|
+
}>;
|
|
85
|
+
update: (id: string, opts: import("./lib/ops.js").UpdateOpts) => Promise<{
|
|
86
|
+
dryRun: boolean;
|
|
87
|
+
matchedRows: unknown[];
|
|
88
|
+
set: Record<string, unknown>;
|
|
89
|
+
updated?: undefined;
|
|
90
|
+
result?: undefined;
|
|
91
|
+
} | {
|
|
92
|
+
matchedRows: unknown[];
|
|
93
|
+
updated: number;
|
|
94
|
+
result: unknown;
|
|
95
|
+
dryRun?: undefined;
|
|
96
|
+
set?: undefined;
|
|
97
|
+
}>;
|
|
98
|
+
upsert: (id: string, opts: import("./lib/ops.js").UpsertOpts) => Promise<{
|
|
99
|
+
updated: number;
|
|
100
|
+
inserted: number;
|
|
101
|
+
updatedRows: unknown[];
|
|
102
|
+
appendResult: unknown;
|
|
103
|
+
}>;
|
|
104
|
+
setRange: (id: string, opts: import("./lib/ops.js").SetOpts) => Promise<{
|
|
105
|
+
dryRun: boolean;
|
|
106
|
+
range: string;
|
|
107
|
+
values: unknown[][];
|
|
108
|
+
result?: undefined;
|
|
109
|
+
} | {
|
|
110
|
+
range: string;
|
|
111
|
+
result: unknown;
|
|
112
|
+
dryRun?: undefined;
|
|
113
|
+
values?: undefined;
|
|
114
|
+
}>;
|
|
115
|
+
clear: (id: string, range: string, dryRun?: boolean) => Promise<{
|
|
116
|
+
dryRun: boolean;
|
|
117
|
+
range: string;
|
|
118
|
+
result?: undefined;
|
|
119
|
+
} | {
|
|
120
|
+
range: string;
|
|
121
|
+
result: unknown;
|
|
122
|
+
dryRun?: undefined;
|
|
123
|
+
}>;
|
|
124
|
+
batch: (id: string, ops: import("./lib/ops.js").BatchOp[], dryRun?: boolean) => Promise<{
|
|
125
|
+
count: number;
|
|
126
|
+
results: ({
|
|
127
|
+
op: "append";
|
|
128
|
+
result: {
|
|
129
|
+
dryRun: boolean;
|
|
130
|
+
tab: string;
|
|
131
|
+
headers: string[];
|
|
132
|
+
rows: number;
|
|
133
|
+
bootstrap: boolean;
|
|
134
|
+
result?: undefined;
|
|
135
|
+
} | {
|
|
136
|
+
tab: string;
|
|
137
|
+
headers: string[];
|
|
138
|
+
rows: number;
|
|
139
|
+
bootstrap: boolean;
|
|
140
|
+
result: unknown;
|
|
141
|
+
dryRun?: undefined;
|
|
142
|
+
} | {
|
|
143
|
+
dryRun: boolean;
|
|
144
|
+
tab: string;
|
|
145
|
+
headers: string[];
|
|
146
|
+
rows: number;
|
|
147
|
+
bootstrap?: undefined;
|
|
148
|
+
result?: undefined;
|
|
149
|
+
} | {
|
|
150
|
+
tab: string;
|
|
151
|
+
headers: string[];
|
|
152
|
+
rows: number;
|
|
153
|
+
result: unknown;
|
|
154
|
+
dryRun?: undefined;
|
|
155
|
+
bootstrap?: undefined;
|
|
156
|
+
};
|
|
157
|
+
} | {
|
|
158
|
+
op: "updateKey";
|
|
159
|
+
result: {
|
|
160
|
+
dryRun: boolean;
|
|
161
|
+
matchedRows: unknown[];
|
|
162
|
+
set: Record<string, unknown>;
|
|
163
|
+
updated?: undefined;
|
|
164
|
+
result?: undefined;
|
|
165
|
+
} | {
|
|
166
|
+
matchedRows: unknown[];
|
|
167
|
+
updated: number;
|
|
168
|
+
result: unknown;
|
|
169
|
+
dryRun?: undefined;
|
|
170
|
+
set?: undefined;
|
|
171
|
+
};
|
|
172
|
+
} | {
|
|
173
|
+
op: "updateRow";
|
|
174
|
+
result: {
|
|
175
|
+
dryRun: boolean;
|
|
176
|
+
row: number;
|
|
177
|
+
set: Record<string, unknown>;
|
|
178
|
+
result?: undefined;
|
|
179
|
+
} | {
|
|
180
|
+
row: number;
|
|
181
|
+
result: unknown;
|
|
182
|
+
dryRun?: undefined;
|
|
183
|
+
set?: undefined;
|
|
184
|
+
};
|
|
185
|
+
} | {
|
|
186
|
+
op: "setRange";
|
|
187
|
+
result: {
|
|
188
|
+
dryRun: boolean;
|
|
189
|
+
range: string;
|
|
190
|
+
values: unknown[][];
|
|
191
|
+
result?: undefined;
|
|
192
|
+
} | {
|
|
193
|
+
range: string;
|
|
194
|
+
result: unknown;
|
|
195
|
+
dryRun?: undefined;
|
|
196
|
+
values?: undefined;
|
|
197
|
+
};
|
|
198
|
+
} | {
|
|
199
|
+
op: "clear";
|
|
200
|
+
result: {
|
|
201
|
+
dryRun: boolean;
|
|
202
|
+
range: string;
|
|
203
|
+
result?: undefined;
|
|
204
|
+
} | {
|
|
205
|
+
range: string;
|
|
206
|
+
result: unknown;
|
|
207
|
+
dryRun?: undefined;
|
|
208
|
+
};
|
|
209
|
+
})[];
|
|
210
|
+
}>;
|
|
211
|
+
create: (opts: import("./lib/ops.js").CreateOpts) => Promise<{
|
|
212
|
+
properties: {
|
|
213
|
+
title: string;
|
|
214
|
+
};
|
|
215
|
+
sheets: {
|
|
216
|
+
properties: {
|
|
217
|
+
title: string;
|
|
218
|
+
index: number;
|
|
219
|
+
};
|
|
220
|
+
}[];
|
|
221
|
+
dryRun: boolean;
|
|
222
|
+
spreadsheetId?: undefined;
|
|
223
|
+
url?: undefined;
|
|
224
|
+
title?: undefined;
|
|
225
|
+
tabs?: undefined;
|
|
226
|
+
} | {
|
|
227
|
+
spreadsheetId: string;
|
|
228
|
+
url: string;
|
|
229
|
+
title: string | undefined;
|
|
230
|
+
tabs: string[];
|
|
231
|
+
}>;
|
|
232
|
+
tabAdd: (id: string, opts: import("./lib/ops.js").TabAddOpts) => Promise<{
|
|
233
|
+
title: string;
|
|
234
|
+
result: unknown;
|
|
235
|
+
}>;
|
|
236
|
+
tabRename: (id: string, opts: import("./lib/ops.js").TabRenameOpts) => Promise<{
|
|
237
|
+
from: string;
|
|
238
|
+
title: string;
|
|
239
|
+
result: unknown;
|
|
240
|
+
}>;
|
|
241
|
+
tabDelete: (id: string, opts: {
|
|
242
|
+
tab: string;
|
|
243
|
+
dryRun?: boolean;
|
|
244
|
+
}) => Promise<{
|
|
245
|
+
tab: string;
|
|
246
|
+
sheetId: number;
|
|
247
|
+
result: unknown;
|
|
248
|
+
}>;
|
|
249
|
+
tabDuplicate: (id: string, opts: import("./lib/ops.js").TabDupOpts) => Promise<{
|
|
250
|
+
tab: string;
|
|
251
|
+
title: string | undefined;
|
|
252
|
+
result: unknown;
|
|
253
|
+
}>;
|
|
254
|
+
format: (id: string, opts: import("./lib/ops.js").FormatOpts) => Promise<{
|
|
255
|
+
dryRun: boolean;
|
|
256
|
+
range: string;
|
|
257
|
+
requests: Record<string, unknown>[];
|
|
258
|
+
result?: undefined;
|
|
259
|
+
} | {
|
|
260
|
+
range: string;
|
|
261
|
+
result: unknown;
|
|
262
|
+
dryRun?: undefined;
|
|
263
|
+
requests?: undefined;
|
|
264
|
+
}>;
|
|
265
|
+
formatHeader: (id: string, opts: import("./lib/ops.js").HeaderFormatOpts) => Promise<{
|
|
266
|
+
tab: string;
|
|
267
|
+
freeze: boolean;
|
|
268
|
+
result: unknown;
|
|
269
|
+
}>;
|
|
270
|
+
freeze: (id: string, opts: import("./lib/ops.js").FreezeOpts) => Promise<{
|
|
271
|
+
tab: string;
|
|
272
|
+
rows: number;
|
|
273
|
+
columns: number | undefined;
|
|
274
|
+
result: unknown;
|
|
275
|
+
}>;
|
|
276
|
+
numberFormat: (id: string, opts: import("./lib/ops.js").NumberFormatOpts) => Promise<{
|
|
277
|
+
dryRun: boolean;
|
|
278
|
+
range: string;
|
|
279
|
+
requests: Record<string, unknown>[];
|
|
280
|
+
result?: undefined;
|
|
281
|
+
} | {
|
|
282
|
+
range: string;
|
|
283
|
+
result: unknown;
|
|
284
|
+
dryRun?: undefined;
|
|
285
|
+
requests?: undefined;
|
|
286
|
+
}>;
|
|
287
|
+
formula: (id: string, opts: import("./lib/ops.js").FormulaOpts) => Promise<{
|
|
288
|
+
dryRun: boolean;
|
|
289
|
+
cell: string;
|
|
290
|
+
expr: string;
|
|
291
|
+
result?: undefined;
|
|
292
|
+
} | {
|
|
293
|
+
cell: string;
|
|
294
|
+
expr: string;
|
|
295
|
+
result: unknown;
|
|
296
|
+
dryRun?: undefined;
|
|
297
|
+
}>;
|
|
298
|
+
fillDown: (id: string, opts: import("./lib/ops.js").FillDownOpts) => Promise<{
|
|
299
|
+
dryRun: boolean;
|
|
300
|
+
range: string;
|
|
301
|
+
expr: string;
|
|
302
|
+
rows: number;
|
|
303
|
+
result?: undefined;
|
|
304
|
+
} | {
|
|
305
|
+
range: string;
|
|
306
|
+
expr: string;
|
|
307
|
+
rows: number;
|
|
308
|
+
result: unknown;
|
|
309
|
+
dryRun?: undefined;
|
|
310
|
+
}>;
|
|
311
|
+
share: (id: string, opts: import("./lib/ops.js").ShareOpts) => Promise<{
|
|
312
|
+
dryRun: boolean;
|
|
313
|
+
email: string;
|
|
314
|
+
role: string;
|
|
315
|
+
result?: undefined;
|
|
316
|
+
} | {
|
|
317
|
+
email: string;
|
|
318
|
+
role: string;
|
|
319
|
+
result: unknown;
|
|
320
|
+
dryRun?: undefined;
|
|
321
|
+
}>;
|
|
322
|
+
unshare: (id: string, email: string, dryRun?: boolean) => Promise<{
|
|
323
|
+
dryRun: boolean;
|
|
324
|
+
email: string;
|
|
325
|
+
permissionId: string;
|
|
326
|
+
removed?: undefined;
|
|
327
|
+
} | {
|
|
328
|
+
email: string;
|
|
329
|
+
removed: string;
|
|
330
|
+
dryRun?: undefined;
|
|
331
|
+
permissionId?: undefined;
|
|
332
|
+
}>;
|
|
333
|
+
permissions: (id: string) => Promise<{
|
|
334
|
+
permissions: {
|
|
335
|
+
id: string;
|
|
336
|
+
role: string | undefined;
|
|
337
|
+
type: string | undefined;
|
|
338
|
+
email: string | undefined;
|
|
339
|
+
name: string | undefined;
|
|
340
|
+
}[];
|
|
341
|
+
}>;
|
|
342
|
+
api: (method: string, id: string | undefined, json: unknown) => Promise<{
|
|
343
|
+
method: string;
|
|
344
|
+
result: unknown;
|
|
345
|
+
}>;
|
|
346
|
+
};
|
|
347
|
+
export declare function idOf(positional: string | undefined, g: Globals): string;
|
|
348
|
+
export declare function run(cmdName: string, pretty: boolean, fn: () => Promise<{
|
|
349
|
+
result: unknown;
|
|
350
|
+
spreadsheetId?: string;
|
|
351
|
+
sheet?: string;
|
|
352
|
+
}>): Promise<void>;
|
|
353
|
+
export declare function need(value: string | undefined, flag: string): string;
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { getAccessToken } from './auth.js';
|
|
2
|
+
import { GoogleClient } from './http.js';
|
|
3
|
+
import { resolveSpreadsheetId } from './ids.js';
|
|
4
|
+
import { createOps } from './lib/ops.js';
|
|
5
|
+
import { CliError, envelopeErr, envelopeOk, exitCodeFor, stringifyEnvelope } from './output.js';
|
|
6
|
+
export function takeGlobals(cmd) {
|
|
7
|
+
const opts = cmd.optsWithGlobals();
|
|
8
|
+
return {
|
|
9
|
+
pretty: Boolean(opts.pretty),
|
|
10
|
+
account: opts.account,
|
|
11
|
+
spreadsheet: opts.spreadsheet,
|
|
12
|
+
dryRun: Boolean(opts.dryRun),
|
|
13
|
+
json: Boolean(opts.json),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function opsFor(account) {
|
|
17
|
+
return createOps(new GoogleClient(() => getAccessToken(account)));
|
|
18
|
+
}
|
|
19
|
+
export function idOf(positional, g) {
|
|
20
|
+
return resolveSpreadsheetId(positional, g.spreadsheet);
|
|
21
|
+
}
|
|
22
|
+
export async function run(cmdName, pretty, fn) {
|
|
23
|
+
try {
|
|
24
|
+
const out = await fn();
|
|
25
|
+
process.stdout.write(stringifyEnvelope(envelopeOk(cmdName, out.result, out), pretty) + '\n');
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
process.stdout.write(stringifyEnvelope(envelopeErr(cmdName, err), pretty) + '\n');
|
|
29
|
+
process.exitCode = exitCodeFor(err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function need(value, flag) {
|
|
33
|
+
if (!value)
|
|
34
|
+
throw new CliError('VALIDATION_ERROR', `${flag} is required`);
|
|
35
|
+
return value;
|
|
36
|
+
}
|
package/dist/specs.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { COMMANDS, findSpec } from './plugins/sheet/specs.js';
|
package/dist/specs.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { COMMANDS, findSpec } from './plugins/sheet/specs.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clipy-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Clipy (clp): local intent CLI for humans and agents. Google Sheets plugin first; JSON stdout, CLI login, no rewritten API code.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"clp": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/lib/index.d.ts",
|
|
12
|
+
"import": "./dist/lib/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"skills",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"clp": "tsx src/cli.ts",
|
|
24
|
+
"test": "tsx --test test/*.test.ts",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"cli",
|
|
33
|
+
"agent-skills",
|
|
34
|
+
"google-sheets",
|
|
35
|
+
"clipy",
|
|
36
|
+
"clp",
|
|
37
|
+
"clipy-kit"
|
|
38
|
+
],
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"commander": "^13.1.0",
|
|
42
|
+
"google-auth-library": "^9.15.1",
|
|
43
|
+
"picocolors": "^1.1.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^22.13.10",
|
|
47
|
+
"tsx": "^4.19.3",
|
|
48
|
+
"typescript": "^5.8.2"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: clipy
|
|
3
|
+
description: >-
|
|
4
|
+
Clipy host CLI (binary: clp). Use when installing or diagnosing clipy,
|
|
5
|
+
listing plugins, or when the user mentions Clipy, clp setup, clp
|
|
6
|
+
doctor, or adding sheet/jira/linear tools. Never write OAuth or API client
|
|
7
|
+
code — run clp commands. For Google Sheets details, also read the clipy-sheet skill.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# clp — Clipy
|
|
11
|
+
|
|
12
|
+
One PATH binary for humans and agents. JSON on stdout for data commands.
|
|
13
|
+
|
|
14
|
+
## If `clp` is missing
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm i -g clipy-kit
|
|
18
|
+
clp setup
|
|
19
|
+
clp doctor --json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Do not edit PATH by hand and do not generate a wrapper script.
|
|
23
|
+
|
|
24
|
+
## Host commands
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
clp --help --json
|
|
28
|
+
clp doctor --json
|
|
29
|
+
clp setup
|
|
30
|
+
clp plugin list --json
|
|
31
|
+
clp plugin add sheet
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`plugin list` includes **planned** names (linear, github, jira, …). Do not call those plugins; they are not shipped.
|
|
35
|
+
|
|
36
|
+
## Plugins
|
|
37
|
+
|
|
38
|
+
Delegate to `clp <plugin> …`. Sheets: `clp sheet --help --json`. Never write `googleapis`, MCP payloads, or login code. If `AUTH_REQUIRED`, run `clp sheet auth login`.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: clipy-sheet
|
|
3
|
+
description: >-
|
|
4
|
+
Read, write, format, and share Google Sheets via `clp sheet`. Use when the
|
|
5
|
+
user mentions Google Sheets, spreadsheets, Drive tabs, or tabular data in a
|
|
6
|
+
Google spreadsheet. Never write googleapis, OAuth, or Apps Script — run
|
|
7
|
+
clp sheet commands.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# clp sheet
|
|
11
|
+
|
|
12
|
+
Intent-level Google Sheets plugin. JSON on stdout. Do not generate Google client or login code.
|
|
13
|
+
|
|
14
|
+
## Auth (CLI only)
|
|
15
|
+
|
|
16
|
+
If a command returns `AUTH_REQUIRED`, run login and wait — do not write OAuth.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
clp sheet auth status
|
|
20
|
+
clp sheet auth login
|
|
21
|
+
clp sheet auth login --credentials ./client_secret.json
|
|
22
|
+
clp sheet auth login --service-account ./sa.json
|
|
23
|
+
clp sheet auth login --token "$GOOGLE_TOKEN"
|
|
24
|
+
clp sheet auth login --adc
|
|
25
|
+
clp sheet auth logout
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Workflow
|
|
29
|
+
|
|
30
|
+
`clp sheet auth status` → login if needed → read → `--dry-run` → apply. Prefer `upsert` / `update --key-col`. Check `ok`.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
clp sheet --help --json
|
|
34
|
+
clp sheet format --help --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`--spreadsheet` accepts a full URL.
|
|
38
|
+
|
|
39
|
+
## Commands
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
clp sheet find --name "HPP"
|
|
43
|
+
clp sheet info <id-or-url>
|
|
44
|
+
clp sheet tabs list <id>
|
|
45
|
+
clp sheet read <id> --tab "Sheet1" --limit 100
|
|
46
|
+
clp sheet read range <id> --range 'Sheet1!A1:C10'
|
|
47
|
+
clp sheet append <id> --tab "Sheet1" --rows '[{"Name":"A"}]' --dry-run
|
|
48
|
+
clp sheet update <id> --tab "Sheet1" --key-col Name --key A --set '{"Status":"Done"}'
|
|
49
|
+
clp sheet upsert <id> --tab "Sheet1" --key-col Name --rows '[{"Name":"A","Status":"Done"}]'
|
|
50
|
+
clp sheet set <id> --range 'Sheet1!A1:B2' --values '[["A","B"],["1","2"]]'
|
|
51
|
+
clp sheet clear <id> --range 'Sheet1!A2:Z'
|
|
52
|
+
clp sheet batch <id> --ops '[{"op":"append","sheet":"Sheet1","values":{"Name":"B"}}]'
|
|
53
|
+
clp sheet create --title "Recipes" --tabs "Minuman,Makanan"
|
|
54
|
+
clp sheet tab add <id> --title "Snack"
|
|
55
|
+
clp sheet format <id> --range 'Sheet1!A1:Z1' --bold --bg navy --fg white --align center
|
|
56
|
+
clp sheet format header <id> --tab Sheet1
|
|
57
|
+
clp sheet freeze <id> --tab Sheet1 --rows 1
|
|
58
|
+
clp sheet number-format <id> --range 'Sheet1!B:B' --pattern 'Rp#,##0'
|
|
59
|
+
clp sheet formula <id> --cell 'Sheet1!D2' --expr '=B2+C2'
|
|
60
|
+
clp sheet share <id> --email user@example.com --role writer
|
|
61
|
+
clp sheet permissions <id>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Rules
|
|
65
|
+
|
|
66
|
+
- Never write `googleapis`, gviz, Apps Script, or token-exchange code.
|
|
67
|
+
- Never host an OAuth callback — `clp sheet auth login` owns the browser flow.
|
|
68
|
+
- Prefer key columns; `read` returns `_row` if you need a row index.
|
|
69
|
+
- `clp sheet api <method> --json @file.json` only when `--help --json` has no intent command.
|
|
70
|
+
|
|
71
|
+
Success: `{ "ok": true, "cmd": "...", "result": ... }`. Exit 20 = auth.
|