@wafflebase/cli 0.4.9 → 0.5.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 (83) hide show
  1. package/dist/bin.js +99988 -11
  2. package/package.json +7 -6
  3. package/dist/bin.d.ts +0 -2
  4. package/dist/client/dry-run.d.ts +0 -5
  5. package/dist/client/dry-run.js +0 -16
  6. package/dist/client/http-client.d.ts +0 -59
  7. package/dist/client/http-client.js +0 -178
  8. package/dist/commands/api-keys.d.ts +0 -2
  9. package/dist/commands/api-keys.js +0 -54
  10. package/dist/commands/cells.d.ts +0 -2
  11. package/dist/commands/cells.js +0 -108
  12. package/dist/commands/ctx.d.ts +0 -5
  13. package/dist/commands/ctx.js +0 -56
  14. package/dist/commands/docs.d.ts +0 -3
  15. package/dist/commands/docs.js +0 -320
  16. package/dist/commands/login.d.ts +0 -2
  17. package/dist/commands/login.js +0 -220
  18. package/dist/commands/logout.d.ts +0 -2
  19. package/dist/commands/logout.js +0 -10
  20. package/dist/commands/root.d.ts +0 -18
  21. package/dist/commands/root.js +0 -37
  22. package/dist/commands/schema.d.ts +0 -2
  23. package/dist/commands/schema.js +0 -28
  24. package/dist/commands/sheets-export.d.ts +0 -2
  25. package/dist/commands/sheets-export.js +0 -52
  26. package/dist/commands/sheets-import.d.ts +0 -2
  27. package/dist/commands/sheets-import.js +0 -88
  28. package/dist/commands/sheets.d.ts +0 -2
  29. package/dist/commands/sheets.js +0 -17
  30. package/dist/commands/slides.d.ts +0 -3
  31. package/dist/commands/slides.js +0 -227
  32. package/dist/commands/status.d.ts +0 -2
  33. package/dist/commands/status.js +0 -22
  34. package/dist/commands/tabs.d.ts +0 -2
  35. package/dist/commands/tabs.js +0 -20
  36. package/dist/config/config.d.ts +0 -38
  37. package/dist/config/config.js +0 -135
  38. package/dist/config/session.d.ts +0 -49
  39. package/dist/config/session.js +0 -74
  40. package/dist/docs/content.d.ts +0 -37
  41. package/dist/docs/content.js +0 -90
  42. package/dist/docs/docx-export.d.ts +0 -23
  43. package/dist/docs/docx-export.js +0 -14
  44. package/dist/docs/docx-import.d.ts +0 -36
  45. package/dist/docs/docx-import.js +0 -70
  46. package/dist/docs/dom-polyfill.d.ts +0 -1
  47. package/dist/docs/dom-polyfill.js +0 -29
  48. package/dist/docs/fontkit-measurer.d.ts +0 -41
  49. package/dist/docs/fontkit-measurer.js +0 -64
  50. package/dist/docs/image-fetcher.d.ts +0 -37
  51. package/dist/docs/image-fetcher.js +0 -38
  52. package/dist/docs/import.d.ts +0 -72
  53. package/dist/docs/import.js +0 -146
  54. package/dist/docs/page-range.d.ts +0 -29
  55. package/dist/docs/page-range.js +0 -74
  56. package/dist/docs/page-slice.d.ts +0 -45
  57. package/dist/docs/page-slice.js +0 -61
  58. package/dist/docs/paginate.d.ts +0 -13
  59. package/dist/docs/paginate.js +0 -19
  60. package/dist/docs/pdf-export.d.ts +0 -47
  61. package/dist/docs/pdf-export.js +0 -95
  62. package/dist/output/binary.d.ts +0 -37
  63. package/dist/output/binary.js +0 -47
  64. package/dist/output/csv.d.ts +0 -4
  65. package/dist/output/csv.js +0 -25
  66. package/dist/output/formatter.d.ts +0 -4
  67. package/dist/output/formatter.js +0 -41
  68. package/dist/output/json.d.ts +0 -1
  69. package/dist/output/json.js +0 -3
  70. package/dist/output/table.d.ts +0 -4
  71. package/dist/output/table.js +0 -14
  72. package/dist/schema/registry.d.ts +0 -42
  73. package/dist/schema/registry.js +0 -375
  74. package/dist/slides/content.d.ts +0 -41
  75. package/dist/slides/content.js +0 -122
  76. package/dist/slides/import.d.ts +0 -82
  77. package/dist/slides/import.js +0 -170
  78. package/dist/slides/pptx-export.d.ts +0 -6
  79. package/dist/slides/pptx-export.js +0 -10
  80. package/dist/slides/pptx-import.d.ts +0 -35
  81. package/dist/slides/pptx-import.js +0 -49
  82. package/dist/util/csv-parse.d.ts +0 -21
  83. package/dist/util/csv-parse.js +0 -99
@@ -1,320 +0,0 @@
1
- import { extname } from 'node:path';
2
- import { getGlobalOpts, getClient, getConfig } from './root.js';
3
- import { output, outputError } from '../output/formatter.js';
4
- import { printDryRun } from '../client/dry-run.js';
5
- import { parseContentFormat, runDocsContent } from '../docs/content.js';
6
- import { exportPdf } from '../docs/pdf-export.js';
7
- import { exportDocx } from '../docs/docx-export.js';
8
- import { createImageFetcher } from '../docs/image-fetcher.js';
9
- import { parsePageRange } from '../docs/page-range.js';
10
- import { writeBinary } from '../output/binary.js';
11
- import { runDocsImport } from '../docs/import.js';
12
- function parseType(value) {
13
- if (value === undefined)
14
- return undefined;
15
- if (value !== 'doc' && value !== 'sheet') {
16
- throw new Error(`Invalid --type "${value}". Use "doc" or "sheet".`);
17
- }
18
- return value;
19
- }
20
- const VALID_EXPORT_FORMATS = ['pdf', 'docx'];
21
- function detectExportFormat(file, formatFlag) {
22
- if (formatFlag) {
23
- if (!VALID_EXPORT_FORMATS.includes(formatFlag)) {
24
- throw new Error(`Invalid --format "${formatFlag}". Use one of: ${VALID_EXPORT_FORMATS.join(', ')}.`);
25
- }
26
- return formatFlag;
27
- }
28
- const ext = extname(file).toLowerCase();
29
- if (ext === '.pdf')
30
- return 'pdf';
31
- if (ext === '.docx')
32
- return 'docx';
33
- throw new Error(`Cannot infer format from "${file}". Pass --format pdf|docx, or use a .pdf/.docx extension.`);
34
- }
35
- export function registerDocsCommand(program) {
36
- const doc = program
37
- .command('docs')
38
- .alias('doc')
39
- .alias('document')
40
- .alias('documents')
41
- .description('Manage documents');
42
- doc
43
- .command('list')
44
- .description('List documents in workspace')
45
- .option('--type <type>', 'Filter by document type (doc|sheet)')
46
- .action(async function () {
47
- const opts = getGlobalOpts(this);
48
- const { type: typeStr } = this.opts();
49
- try {
50
- const filterType = parseType(typeStr);
51
- const res = await getClient(opts).listDocuments();
52
- if (!res.ok)
53
- throw new Error(`HTTP ${res.status}`);
54
- let data = res.data;
55
- if (filterType && Array.isArray(data)) {
56
- data = data.filter((d) => (d.type ?? 'sheet') === filterType);
57
- }
58
- output(data, opts.format, opts.quiet);
59
- }
60
- catch (e) {
61
- outputError(e, opts.quiet);
62
- }
63
- });
64
- doc
65
- .command('create <title>')
66
- .description('Create a new document')
67
- .option('--type <type>', 'Document type (doc|sheet)', 'sheet')
68
- .action(async function (title) {
69
- const opts = getGlobalOpts(this);
70
- const { type: typeStr } = this.opts();
71
- try {
72
- const type = parseType(typeStr) ?? 'sheet';
73
- if (opts.dryRun) {
74
- printDryRun(getConfig(opts), 'POST', '/documents', { title, type });
75
- return;
76
- }
77
- const res = await getClient(opts).createDocument(title, type);
78
- if (!res.ok)
79
- throw new Error(`HTTP ${res.status}`);
80
- output(res.data, opts.format, opts.quiet);
81
- }
82
- catch (e) {
83
- outputError(e, opts.quiet);
84
- }
85
- });
86
- doc
87
- .command('get <doc-id>')
88
- .description('Show document metadata')
89
- .action(async function (docId) {
90
- const opts = getGlobalOpts(this);
91
- try {
92
- const res = await getClient(opts).getDocument(docId);
93
- if (!res.ok)
94
- throw new Error(`HTTP ${res.status}`);
95
- output(res.data, opts.format, opts.quiet);
96
- }
97
- catch (e) {
98
- outputError(e, opts.quiet);
99
- }
100
- });
101
- doc
102
- .command('rename <doc-id> <title>')
103
- .description('Rename a document')
104
- .action(async function (docId, title) {
105
- const opts = getGlobalOpts(this);
106
- if (opts.dryRun) {
107
- printDryRun(getConfig(opts), 'PATCH', `/documents/${docId}`, { title });
108
- return;
109
- }
110
- try {
111
- const res = await getClient(opts).updateDocument(docId, title);
112
- if (!res.ok)
113
- throw new Error(`HTTP ${res.status}`);
114
- output(res.data, opts.format, opts.quiet);
115
- }
116
- catch (e) {
117
- outputError(e, opts.quiet);
118
- }
119
- });
120
- doc
121
- .command('delete <doc-id>')
122
- .description('Delete a document')
123
- .action(async function (docId) {
124
- const opts = getGlobalOpts(this);
125
- if (opts.dryRun) {
126
- printDryRun(getConfig(opts), 'DELETE', `/documents/${docId}`);
127
- return;
128
- }
129
- try {
130
- const res = await getClient(opts).deleteDocument(docId);
131
- if (!res.ok)
132
- throw new Error(`HTTP ${res.status}`);
133
- output(res.data, opts.format, opts.quiet);
134
- }
135
- catch (e) {
136
- outputError(e, opts.quiet);
137
- }
138
- });
139
- doc
140
- .command('content <doc-id>')
141
- .description('Read document content as JSON, Markdown, or plain text')
142
- // NOTE: `--format` is intentionally not redeclared here. The global
143
- // `--format` option (declared in `createProgram`) catches the user's
144
- // value because commander resolves duplicate-named flags through the
145
- // earliest parent that owns them. Reading via `opts.format` (the
146
- // merged form) keeps a single source of truth and lets
147
- // `parseContentFormat` validate that the value is one of json|md|text.
148
- .option('--pages <range>', 'Page range to include (e.g. 1-3,5)')
149
- .option('--include-header-footer', 'Include header/footer (md/text)', false)
150
- .option('--inline-images', 'Inline data: image URLs (md only)', false)
151
- .option('--out <file>', 'Output file (- for stdout)')
152
- .option('--force', 'Overwrite existing output file', false)
153
- .action(async function (docId) {
154
- const opts = getGlobalOpts(this);
155
- const local = this.opts();
156
- try {
157
- const format = parseContentFormat(opts.format);
158
- if (opts.dryRun) {
159
- printDryRun(getConfig(opts), 'GET', `/documents/${docId}/content`);
160
- return;
161
- }
162
- const res = await getClient(opts).getDocContent(docId);
163
- if (!res.ok) {
164
- const body = res.data;
165
- if (body?.error) {
166
- // Surface backend-shaped errors (e.g., TYPE_MISMATCH) verbatim
167
- // so agents reading stderr can act on the `code` field.
168
- console.error(JSON.stringify(body, null, 2));
169
- process.exitCode = 1;
170
- return;
171
- }
172
- throw new Error(`HTTP ${res.status}`);
173
- }
174
- runDocsContent({
175
- doc: res.data,
176
- format,
177
- pages: local.pages,
178
- includeHeaderFooter: local.includeHeaderFooter,
179
- inlineImages: local.inlineImages,
180
- out: local.out,
181
- force: local.force,
182
- quiet: opts.quiet,
183
- });
184
- }
185
- catch (e) {
186
- outputError(e, opts.quiet);
187
- }
188
- });
189
- doc
190
- .command('export <doc-id> <file>')
191
- .description('Export a document to PDF or DOCX')
192
- // NOTE: `--format` reuses the global option for the same reason
193
- // documented on `docs content` above; we route through `opts.format`
194
- // and use commander's `getOptionValueSourceWithGlobals` to tell a
195
- // user-supplied value from the implicit default. That keeps an
196
- // explicit `--format json` from silently falling through to the
197
- // extension — it now surfaces as the documented "invalid format"
198
- // error.
199
- .option('--pages <range>', 'Page range to export (PDF only)')
200
- .option('--include-header-footer', 'Include header/footer regions', true)
201
- .option('--force', 'Overwrite existing output file', false)
202
- .action(async function (docId, file) {
203
- const opts = getGlobalOpts(this);
204
- const local = this.opts();
205
- try {
206
- // `'cli'` source means the user typed the flag (or its alias)
207
- // on the command line; anything else (`'default'`, `'env'`,
208
- // `'config'`) is treated as "no override intended" so the
209
- // file extension wins.
210
- const formatSource = this.getOptionValueSourceWithGlobals('format');
211
- const formatOverride = formatSource === 'cli' ? opts.format : undefined;
212
- const format = detectExportFormat(file, formatOverride);
213
- if (opts.dryRun) {
214
- printDryRun(getConfig(opts), 'GET', `/documents/${docId}/content`);
215
- return;
216
- }
217
- const res = await getClient(opts).getDocContent(docId);
218
- if (!res.ok) {
219
- const body = res.data;
220
- if (body?.error) {
221
- console.error(JSON.stringify(body, null, 2));
222
- process.exitCode = 1;
223
- return;
224
- }
225
- throw new Error(`HTTP ${res.status}`);
226
- }
227
- const fetchedDoc = res.data;
228
- // Image inlines reference URLs that PdfExporter and DocxExporter
229
- // can't resolve on their own. The fetcher walks each unique
230
- // `src`, GETs it (via `globalThis.fetch`), and hands back a
231
- // Blob. Relative URLs (`/images/<id>`) resolve against the
232
- // configured server base so the same doc round-trips between
233
- // the editor (browser-relative) and the CLI.
234
- const imageFetcher = createImageFetcher({
235
- serverBase: getConfig(opts).server,
236
- });
237
- let bytes;
238
- if (format === 'pdf') {
239
- // Pagination uses the FontkitMeasurer's coarse Latin estimate
240
- // when no Korean fonts are needed; we still pre-page to know
241
- // the document's page count for `parsePageRange`. PdfExporter
242
- // does the authoritative paint-time pagination internally.
243
- let pageRange = undefined;
244
- if (local.pages) {
245
- // Resolve pages against the rendered PDF's page count
246
- // (rather than running our own paginator twice). We render
247
- // the full PDF first, then strip non-selected pages —
248
- // see `extractPages` in pdf-export.ts.
249
- const fullPdf = await exportPdf(fetchedDoc, {
250
- includeHeaderFooter: local.includeHeaderFooter,
251
- imageFetcher,
252
- });
253
- const total = await pdfPageCount(fullPdf);
254
- pageRange = parsePageRange(local.pages, total);
255
- if (!opts.quiet) {
256
- for (const w of pageRange.warnings)
257
- console.error(w);
258
- }
259
- bytes = await exportPdf(fetchedDoc, {
260
- includeHeaderFooter: local.includeHeaderFooter,
261
- pages: pageRange,
262
- imageFetcher,
263
- });
264
- }
265
- else {
266
- bytes = await exportPdf(fetchedDoc, {
267
- includeHeaderFooter: local.includeHeaderFooter,
268
- imageFetcher,
269
- });
270
- }
271
- }
272
- else {
273
- if (local.pages && !opts.quiet) {
274
- console.error('DOCX has no page concept — exporting full document, --pages ignored.');
275
- }
276
- bytes = await exportDocx(fetchedDoc, {
277
- includeHeaderFooter: local.includeHeaderFooter,
278
- imageFetcher,
279
- });
280
- }
281
- writeBinary(bytes, file, { force: local.force, quiet: opts.quiet });
282
- }
283
- catch (e) {
284
- outputError(e, opts.quiet);
285
- }
286
- });
287
- registerDocsImportCommand(doc);
288
- }
289
- async function pdfPageCount(bytes) {
290
- const { PDFDocument } = await import('pdf-lib');
291
- const pdf = await PDFDocument.load(bytes);
292
- return pdf.getPageCount();
293
- }
294
- export function registerDocsImportCommand(doc) {
295
- doc
296
- .command('import <file>')
297
- .description('Import a .docx file as a new (or replacement) document')
298
- .option('--title <title>', 'Document title (default: file basename)')
299
- .option('--replace <doc-id>', 'Replace content of an existing document')
300
- .option('--yes', 'Skip --replace confirmation prompt', false)
301
- .action(async function (file) {
302
- const opts = getGlobalOpts(this);
303
- const local = this.opts();
304
- try {
305
- const result = await runDocsImport({
306
- file,
307
- title: local.title,
308
- replace: local.replace,
309
- yes: local.yes,
310
- quiet: opts.quiet,
311
- dryRun: opts.dryRun,
312
- }, getClient(opts));
313
- if (result.exitCode !== 0)
314
- process.exitCode = result.exitCode;
315
- }
316
- catch (e) {
317
- outputError(e, opts.quiet);
318
- }
319
- });
320
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerLoginCommand(program: Command): void;
@@ -1,220 +0,0 @@
1
- import { createServer } from 'node:http';
2
- import { createInterface } from 'node:readline';
3
- import { loadSession, saveSession, decodeJwtExpiry, } from '../config/session.js';
4
- import { DEFAULT_SERVER } from '../config/config.js';
5
- export function registerLoginCommand(program) {
6
- program
7
- .command('login')
8
- .description('Log in via GitHub OAuth in the browser')
9
- .action(async function () {
10
- const parentOpts = this.optsWithGlobals();
11
- const server = (parentOpts.server ?? DEFAULT_SERVER).replace(/\/$/, '');
12
- // 1. Check existing session
13
- const existing = loadSession();
14
- if (existing) {
15
- const answer = await ask(`Logged in as ${existing.user.username}. Continue? [Y/n] `);
16
- if (answer.toLowerCase() === 'n') {
17
- console.log('Cancelled.');
18
- return;
19
- }
20
- }
21
- // 2. Start local HTTP server
22
- const { port, waitForCallback, close } = await startCallbackServer();
23
- // 3. Build OAuth URL and open browser
24
- const oauthUrl = `${server}/auth/github?mode=cli&port=${port}`;
25
- console.error(`Opening browser: ${oauthUrl}`);
26
- console.error('If the browser does not open, visit the URL above.');
27
- try {
28
- const open = (await import('open')).default;
29
- await open(oauthUrl);
30
- }
31
- catch {
32
- // Browser open failed — URL was already printed
33
- }
34
- // 4. Wait for callback
35
- let code;
36
- try {
37
- code = await waitForCallback();
38
- }
39
- finally {
40
- close();
41
- }
42
- // 5. Exchange code for tokens
43
- const exchangeRes = await fetch(`${server}/auth/cli/exchange`, {
44
- method: 'POST',
45
- headers: { 'Content-Type': 'application/json' },
46
- body: JSON.stringify({ code }),
47
- });
48
- if (!exchangeRes.ok) {
49
- console.error('Token exchange failed. Try again with `wafflebase login`.');
50
- process.exit(1);
51
- }
52
- const tokens = (await exchangeRes.json());
53
- // 6. Get user info
54
- const meRes = await fetch(`${server}/auth/me`, {
55
- headers: { Authorization: `Bearer ${tokens.accessToken}` },
56
- });
57
- if (!meRes.ok) {
58
- console.error('Failed to fetch user info.');
59
- process.exit(1);
60
- }
61
- const user = (await meRes.json());
62
- // 7. Get workspace list
63
- const wsRes = await fetch(`${server}/workspaces`, {
64
- headers: { Authorization: `Bearer ${tokens.accessToken}` },
65
- });
66
- if (!wsRes.ok) {
67
- console.error(`Failed to fetch workspaces (HTTP ${wsRes.status}). Try again with \`wafflebase login\`.`);
68
- process.exit(1);
69
- }
70
- const workspaces = (await wsRes.json());
71
- // 8. Select workspace
72
- let activeWorkspace = '';
73
- if (workspaces.length === 0) {
74
- console.log('No workspaces found.');
75
- }
76
- else if (workspaces.length === 1) {
77
- activeWorkspace = workspaces[0].id;
78
- console.log(`Workspace: ${workspaces[0].name}`);
79
- }
80
- else {
81
- console.log('Select a workspace:');
82
- workspaces.forEach((ws, i) => {
83
- console.log(` ${i + 1}. ${ws.name} (${ws.id.slice(0, 8)})`);
84
- });
85
- const choice = await ask('Enter number: ');
86
- const idx = parseInt(choice, 10) - 1;
87
- if (idx >= 0 && idx < workspaces.length) {
88
- activeWorkspace = workspaces[idx].id;
89
- }
90
- else {
91
- activeWorkspace = workspaces[0].id;
92
- console.log(`Invalid choice, using ${workspaces[0].name}.`);
93
- }
94
- }
95
- // 9. Save session
96
- const session = {
97
- server,
98
- user,
99
- accessToken: tokens.accessToken,
100
- refreshToken: tokens.refreshToken,
101
- expiresAt: decodeJwtExpiry(tokens.accessToken),
102
- activeWorkspace,
103
- workspaces,
104
- };
105
- saveSession(session);
106
- console.log(`Logged in as ${user.username}.`);
107
- });
108
- }
109
- function ask(prompt) {
110
- const rl = createInterface({ input: process.stdin, output: process.stderr });
111
- return new Promise((resolve) => {
112
- rl.question(prompt, (answer) => {
113
- rl.close();
114
- resolve(answer.trim());
115
- });
116
- });
117
- }
118
- function startCallbackServer() {
119
- return new Promise((resolve, reject) => {
120
- let settled = false;
121
- let callbackResolve;
122
- let callbackReject;
123
- const callbackPromise = new Promise((res, rej) => {
124
- callbackResolve = res;
125
- callbackReject = rej;
126
- });
127
- const srv = createServer((req, res) => {
128
- const url = new URL(req.url ?? '/', `http://127.0.0.1`);
129
- if (url.pathname !== '/callback') {
130
- res.writeHead(404);
131
- res.end('Not found');
132
- return;
133
- }
134
- const code = url.searchParams.get('code');
135
- if (!code) {
136
- res.writeHead(400);
137
- res.end('Missing code');
138
- return;
139
- }
140
- res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
141
- res.end(`<!DOCTYPE html>
142
- <html lang="en">
143
- <head>
144
- <meta charset="utf-8">
145
- <meta name="viewport" content="width=device-width, initial-scale=1">
146
- <title>Wafflebase CLI</title>
147
- <style>
148
- body {
149
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
150
- display: flex;
151
- justify-content: center;
152
- align-items: center;
153
- min-height: 100vh;
154
- margin: 0;
155
- background: #fafafa;
156
- color: #1a1a1a;
157
- }
158
- .card {
159
- text-align: center;
160
- padding: 3rem 2.5rem;
161
- background: #fff;
162
- border-radius: 12px;
163
- box-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.04);
164
- }
165
- .icon { font-size: 2.5rem; margin-bottom: 0.5rem; }
166
- h2 { margin: 0 0 0.5rem; font-size: 1.25rem; font-weight: 600; }
167
- p { margin: 0; color: #666; font-size: 0.95rem; }
168
- </style>
169
- </head>
170
- <body>
171
- <div class="card">
172
- <div class="icon">&#10003;</div>
173
- <h2>Login successful!</h2>
174
- <p>You can close this tab and return to the terminal.</p>
175
- </div>
176
- </body>
177
- </html>`);
178
- if (!settled) {
179
- settled = true;
180
- callbackResolve(code);
181
- }
182
- });
183
- const timeout = setTimeout(() => {
184
- if (!settled) {
185
- settled = true;
186
- callbackReject(new Error('Login timed out. Try again with `wafflebase login`.'));
187
- }
188
- srv.close();
189
- }, 30_000);
190
- // Try to listen on a random port (up to 3 attempts)
191
- let attempts = 0;
192
- const tryListen = () => {
193
- attempts++;
194
- srv.listen(0, '127.0.0.1', () => {
195
- const addr = srv.address();
196
- if (!addr || typeof addr === 'string') {
197
- reject(new Error('Failed to start callback server'));
198
- return;
199
- }
200
- resolve({
201
- port: addr.port,
202
- waitForCallback: () => callbackPromise,
203
- close: () => {
204
- clearTimeout(timeout);
205
- srv.close();
206
- },
207
- });
208
- });
209
- };
210
- srv.on('error', (err) => {
211
- if (err.code === 'EADDRINUSE' && attempts < 3) {
212
- tryListen();
213
- }
214
- else {
215
- reject(err);
216
- }
217
- });
218
- tryListen();
219
- });
220
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerLogoutCommand(program: Command): void;
@@ -1,10 +0,0 @@
1
- import { clearSession } from '../config/session.js';
2
- export function registerLogoutCommand(program) {
3
- program
4
- .command('logout')
5
- .description('Log out and clear session')
6
- .action(() => {
7
- clearSession();
8
- console.log('Logged out.');
9
- });
10
- }
@@ -1,18 +0,0 @@
1
- import { Command } from 'commander';
2
- import { type CliConfig } from '../config/config.js';
3
- import { HttpClient } from '../client/http-client.js';
4
- import type { OutputFormat } from '../output/formatter.js';
5
- export interface GlobalOpts {
6
- server?: string;
7
- apiKey?: string;
8
- workspace?: string;
9
- profile?: string;
10
- format: OutputFormat;
11
- quiet: boolean;
12
- verbose: boolean;
13
- dryRun: boolean;
14
- }
15
- export declare function getGlobalOpts(cmd: Command): GlobalOpts;
16
- export declare function getConfig(opts: GlobalOpts): CliConfig;
17
- export declare function getClient(opts: GlobalOpts): HttpClient;
18
- export declare function createProgram(): Command;
@@ -1,37 +0,0 @@
1
- import { createRequire } from 'node:module';
2
- import { Command } from 'commander';
3
- import { resolveConfig } from '../config/config.js';
4
- import { HttpClient } from '../client/http-client.js';
5
- const require = createRequire(import.meta.url);
6
- const { version } = require('../../package.json');
7
- export function getGlobalOpts(cmd) {
8
- const root = cmd.optsWithGlobals();
9
- return root;
10
- }
11
- export function getConfig(opts) {
12
- return resolveConfig({
13
- server: opts.server,
14
- apiKey: opts.apiKey,
15
- workspace: opts.workspace,
16
- profile: opts.profile,
17
- });
18
- }
19
- export function getClient(opts) {
20
- return new HttpClient(getConfig(opts));
21
- }
22
- export function createProgram() {
23
- const program = new Command();
24
- program
25
- .name('wafflebase')
26
- .description('CLI for Wafflebase spreadsheet API')
27
- .version(version)
28
- .option('--server <url>', 'Server URL')
29
- .option('--api-key <key>', 'API key')
30
- .option('--workspace <id>', 'Workspace ID')
31
- .option('--profile <name>', 'Config profile', 'default')
32
- .option('--format <fmt>', 'Output format (json, table, csv)', 'json')
33
- .option('--quiet', 'Suppress output', false)
34
- .option('--verbose', 'Verbose output', false)
35
- .option('--dry-run', 'Show request without executing', false);
36
- return program;
37
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerSchemaCommand(program: Command): void;
@@ -1,28 +0,0 @@
1
- import { getGlobalOpts } from './root.js';
2
- import { output } from '../output/formatter.js';
3
- import { getCommandSchema, getAllCommandSchemas } from '../schema/registry.js';
4
- export function registerSchemaCommand(program) {
5
- program
6
- .command('schema [command]')
7
- .description('Describe command parameters and response shape')
8
- .action(function (commandName) {
9
- const opts = getGlobalOpts(this);
10
- if (commandName) {
11
- const schema = getCommandSchema(commandName);
12
- if (!schema) {
13
- console.error(JSON.stringify({ error: { code: 'NOT_FOUND', message: `Unknown command: ${commandName}` } }, null, 2));
14
- process.exitCode = 1;
15
- return;
16
- }
17
- output(schema, opts.format, opts.quiet);
18
- }
19
- else {
20
- const commands = getAllCommandSchemas().map((c) => ({
21
- name: c.name,
22
- description: c.description,
23
- safety: c.safety,
24
- }));
25
- output({ commands }, opts.format, opts.quiet);
26
- }
27
- });
28
- }
@@ -1,2 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function registerSheetsExportCommand(parent: Command): void;