gws-axi 0.3.0 → 0.4.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/README.md CHANGED
@@ -12,26 +12,68 @@ Designed for use by AI agents. Every response is structured, every error names a
12
12
  - A Google account (personal or Workspace)
13
13
  - `gcloud` CLI (optional — speeds up initial setup, not required)
14
14
 
15
- ## Install
15
+ ## Getting started
16
+
17
+ ### 1. Install
16
18
 
17
19
  ```bash
18
20
  npm install -g gws-axi
19
21
  ```
20
22
 
21
- ## First-run setup
23
+ ### 2. Let an agent walk you through setup
24
+
25
+ `gws-axi` is designed to be driven by an AI coding agent (Claude Code, Cursor, anything that can run shell commands). The setup flow is progressive — the CLI emits structured TOON output telling the agent what to do next, and the agent coordinates with you through the handful of Google Cloud Console steps that can't be automated.
26
+
27
+ Start a fresh agent session and paste a prompt like:
28
+
29
+ ```
30
+ Run `gws-axi auth setup` and walk me through the progressive setup
31
+ flow it describes. The CLI's output will tell you exactly what to do
32
+ at each step — relay the instructions to me, and run follow-up
33
+ commands as you go.
34
+
35
+ I want to authenticate the following Google accounts:
36
+ - you@example.com
37
+ - personal@gmail.com
38
+ ```
39
+
40
+ The explicit `gws-axi auth setup` in the prompt matters: this is your very first session, so the agent doesn't yet have any ambient context about `gws-axi`. Naming the first command gets the agent into the structured flow, where the CLI's output takes over. Every subsequent session auto-loads a compact `gws-axi` status line via a session-start hook (installed on first invocation) — so after this one, you can skip the command and just say "use gws-axi to ..." and the agent knows.
41
+
42
+ Expect ~10 minutes end-to-end for a fresh Google Cloud project; ~3 minutes if you already have one you want to reuse.
22
43
 
23
- `gws-axi` uses a **bring-your-own OAuth client** model: you create your own Google Cloud project with OAuth credentials, and tokens live locally at `~/.config/gws-axi/`. This avoids verification/CASA overhead for public apps and keeps the blast radius of any token revocation scoped to you.
44
+ **What happens during setup:** you create your own Google Cloud project with OAuth credentials, enable the Workspace APIs, configure the consent screen, and add your Google accounts as test users. This is the [**bring-your-own OAuth client**](docs/shared-client-future.md) model — avoids public-app verification overhead and keeps the blast radius of any token revocation scoped to you. Tokens live locally at `~/.config/gws-axi/`.
24
45
 
25
- The setup is progressive — run `gws-axi auth setup` repeatedly and each invocation walks you through the next step:
46
+ The CLI generates an auto-refreshing HTML helper page (`~/.config/gws-axi/setup.html`) with clickable Console deep-links — so you never copy long URLs from terminal to browser and you stay in the right browser profile throughout.
47
+
48
+ ### 3. Check it works
26
49
 
27
50
  ```bash
28
- gws-axi auth setup # start or continue — 7 steps, mostly automated
29
- gws-axi doctor # check setup + live API health at any time
51
+ gws-axi doctor # setup + live API health
52
+ gws-axi calendar events # upcoming 7 days on your primary calendar
30
53
  ```
31
54
 
32
- The CLI generates a styled, auto-refreshing HTML helper page at `~/.config/gws-axi/setup.html` with clickable Console deep-links — so you never copy long URLs from terminal to browser and you stay in the right browser profile throughout.
55
+ ### 4. Make gws-axi your agent's default for Google Workspace
56
+
57
+ On first invocation (which already happened during step 2), `gws-axi` auto-installed a **SessionStart hook** into your agent's config (Claude Code's `~/.claude/settings.json`, Codex's `~/.codex/hooks.json`). From now on, every new agent session will see a compact `gws-axi` status line in ambient context — authenticated accounts, write-protection status, setup health — with no extra wiring. Nothing for you to configure.
58
+
59
+ To make sure agents reach for `gws-axi` instead of stale alternatives, also consider:
60
+
61
+ - **Remove existing Google Workspace MCP servers and skills.** If you already have Gmail / Calendar / Drive / Docs / Slides integrations installed (community MCP servers, bespoke skills, etc.), disable them. Keeping both creates ambiguity — agents may pick whichever they noticed first, and the tools have different auth models, flag names, and output shapes. Typical candidates to disable: `google-calendar-mcp`, `gmail-mcp`, `google-docs-mcp`, any `@modelcontextprotocol/server-google-*`, and skills with similar names.
62
+
63
+ - **Add a directive to your `CLAUDE.md`.** A short note in your project-level (`.claude/CLAUDE.md`) or user-level (`~/.claude/CLAUDE.md`) file nudges agents to consistently use `gws-axi`. Example:
64
+
65
+ ```markdown
66
+ ## Google Workspace
67
+
68
+ Use `gws-axi` for ALL Google Calendar, Gmail, Docs, Drive, and Slides
69
+ interactions. Check the SessionStart `gws-axi` line for current auth
70
+ state; run `gws-axi --help` for the command surface. Prefer this over
71
+ any other Google integrations.
72
+ ```
73
+
74
+ ### Prefer to drive it manually?
33
75
 
34
- Typical flow: set project → enable APIs → create OAuth client → download JSON → configure consent screen → add test users → authenticate. See the in-CLI guidance as you go; every step tells you exactly what to do next.
76
+ The CLI works fine without an agent — each `gws-axi auth setup` invocation prints its own instructions and updates `setup.html`. Run it repeatedly as you complete each step; no state is lost between invocations.
35
77
 
36
78
  ## Usage
37
79
 
package/dist/src/cli.js CHANGED
@@ -7,7 +7,7 @@ import { authCommand, AUTH_HELP } from "./commands/auth.js";
7
7
  import { doctorCommand, DOCTOR_HELP } from "./commands/doctor.js";
8
8
  import { calendarCommand } from "./commands/calendar.js";
9
9
  import { gmailCommand, GMAIL_HELP } from "./commands/gmail.js";
10
- import { docsCommand, DOCS_HELP } from "./commands/docs.js";
10
+ import { docsCommand } from "./commands/docs.js";
11
11
  import { driveCommand, DRIVE_HELP } from "./commands/drive.js";
12
12
  import { slidesCommand, SLIDES_HELP } from "./commands/slides.js";
13
13
  const DESCRIPTION = "Agent ergonomic CLI for Google Workspace. Unified interface for Gmail, Calendar, Docs, Drive, and Slides with agent-guided OAuth setup.";
@@ -30,7 +30,6 @@ const COMMAND_HELP = {
30
30
  auth: AUTH_HELP,
31
31
  doctor: DOCTOR_HELP,
32
32
  gmail: GMAIL_HELP,
33
- docs: DOCS_HELP,
34
33
  drive: DRIVE_HELP,
35
34
  slides: SLIDES_HELP,
36
35
  };
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAElE,MAAM,WAAW,GACf,yIAAyI,CAAC;AAE5I,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;AAErC,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;CAUvB,CAAC;AAEF,0EAA0E;AAC1E,0EAA0E;AAC1E,iEAAiE;AACjE,MAAM,YAAY,GAA2B;IAC3C,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,WAAW;IACnB,KAAK,EAAE,UAAU;IACjB,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,WAAW;CACpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,MAAM,SAAS,CAAC;QACd,WAAW,EAAE,WAAW;QACxB,OAAO,EAAE,OAAO;QAChB,YAAY,EAAE,QAAQ;QACtB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,WAAW,EAAE;QAC/B,QAAQ,EAAE;YACR,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE,eAAe;YACzB,KAAK,EAAE,YAAY;YACnB,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,aAAa;SACtB;QACD,cAAc,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC;KACnD,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAErD,KAAK,MAAM,SAAS,IAAI;QACtB,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;KACvC,EAAE,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAEzD,CAAC;QACF,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpE,OAAO,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const COMMENTS_HELP = "usage: gws-axi docs comments <documentId> [flags]\nargs[1]:\n <documentId> The Google Doc ID (from the URL after /d/)\nflags[4]:\n --include-resolved Also show comments that have been resolved\n --full Don't truncate comment/reply bodies (default cap: 500 chars)\n --limit <n> Max comments to return (default: 50)\n --account <email> Account override when 2+ are configured\nexamples:\n gws-axi docs comments 1BxAbc...\n gws-axi docs comments 1BxAbc... --include-resolved --full\noutput:\n A `comments[N]{id,author,created,resolved,quoted_content,body,reply_count}`\n list and (when any comment has replies) a sibling `replies[N]{comment,author,created,body}`\n table keyed by parent comment id. Bodies and quoted_content are truncated\n at 500 chars unless --full is passed.\nnotes:\n `quoted_content` is the exact text in the doc that the comment is anchored\n to \u2014 important for agents to know what the comment is *about*. Comments\n without an anchor (overall-document comments) will have an empty value.\n";
2
+ export declare function docsCommentsCommand(account: string, args: string[]): Promise<string>;
@@ -0,0 +1,172 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ import { driveClient, translateGoogleError } from "../../google/client.js";
3
+ import { field, joinBlocks, renderHelp, renderList, renderObject, } from "../../output/index.js";
4
+ export const COMMENTS_HELP = `usage: gws-axi docs comments <documentId> [flags]
5
+ args[1]:
6
+ <documentId> The Google Doc ID (from the URL after /d/)
7
+ flags[4]:
8
+ --include-resolved Also show comments that have been resolved
9
+ --full Don't truncate comment/reply bodies (default cap: 500 chars)
10
+ --limit <n> Max comments to return (default: 50)
11
+ --account <email> Account override when 2+ are configured
12
+ examples:
13
+ gws-axi docs comments 1BxAbc...
14
+ gws-axi docs comments 1BxAbc... --include-resolved --full
15
+ output:
16
+ A \`comments[N]{id,author,created,resolved,quoted_content,body,reply_count}\`
17
+ list and (when any comment has replies) a sibling \`replies[N]{comment,author,created,body}\`
18
+ table keyed by parent comment id. Bodies and quoted_content are truncated
19
+ at 500 chars unless --full is passed.
20
+ notes:
21
+ \`quoted_content\` is the exact text in the doc that the comment is anchored
22
+ to — important for agents to know what the comment is *about*. Comments
23
+ without an anchor (overall-document comments) will have an empty value.
24
+ `;
25
+ const DEFAULT_LIMIT = 50;
26
+ const BODY_TRUNCATE = 500;
27
+ function parseFlags(args) {
28
+ let documentId;
29
+ let includeResolved = false;
30
+ let full = false;
31
+ let limit = DEFAULT_LIMIT;
32
+ for (let i = 0; i < args.length; i++) {
33
+ const arg = args[i];
34
+ const next = args[i + 1];
35
+ switch (arg) {
36
+ case "--include-resolved":
37
+ includeResolved = true;
38
+ break;
39
+ case "--full":
40
+ full = true;
41
+ break;
42
+ case "--limit":
43
+ limit = Math.max(1, Math.min(100, parseInt(next, 10) || DEFAULT_LIMIT));
44
+ i++;
45
+ break;
46
+ default:
47
+ if (!arg.startsWith("--") && documentId === undefined) {
48
+ documentId = arg;
49
+ }
50
+ }
51
+ }
52
+ if (!documentId) {
53
+ throw new AxiError("Missing documentId argument", "VALIDATION_ERROR", ["Usage: gws-axi docs comments <documentId>"]);
54
+ }
55
+ return { documentId, includeResolved, full, limit };
56
+ }
57
+ function truncate(value, max) {
58
+ if (!value)
59
+ return "";
60
+ if (value.length <= max)
61
+ return value;
62
+ return `${value.slice(0, max - 1)}…`;
63
+ }
64
+ function commentSchema(truncateAt) {
65
+ return [
66
+ field("id"),
67
+ field("author"),
68
+ field("created"),
69
+ field("resolved"),
70
+ {
71
+ name: "quoted_content",
72
+ extract: (item) => truncate(item.quoted_content, truncateAt),
73
+ },
74
+ {
75
+ name: "body",
76
+ extract: (item) => truncate(item.body, truncateAt),
77
+ },
78
+ field("reply_count"),
79
+ ];
80
+ }
81
+ function replySchema(truncateAt) {
82
+ return [
83
+ field("comment"),
84
+ field("author"),
85
+ field("created"),
86
+ {
87
+ name: "body",
88
+ extract: (item) => truncate(item.body, truncateAt),
89
+ },
90
+ ];
91
+ }
92
+ export async function docsCommentsCommand(account, args) {
93
+ const flags = parseFlags(args);
94
+ const api = await driveClient(account);
95
+ let data;
96
+ try {
97
+ const res = await api.comments.list({
98
+ fileId: flags.documentId,
99
+ includeDeleted: false,
100
+ pageSize: Math.min(100, flags.limit),
101
+ // Request every field we surface. Drive requires explicit `fields`
102
+ // projection on comments.list — the default response omits replies.
103
+ fields: "comments(id,content,quotedFileContent,author(displayName,emailAddress),createdTime,modifiedTime,resolved,anchor,replies(id,content,author(displayName,emailAddress),createdTime))",
104
+ });
105
+ data = res.data;
106
+ }
107
+ catch (err) {
108
+ const translated = translateGoogleError(err, {
109
+ account,
110
+ operation: "drive.comments.list",
111
+ });
112
+ if (translated.code === "NOT_FOUND") {
113
+ throw new AxiError(`Document '${flags.documentId}' not found (or ${account} doesn't have access)`, "DOCUMENT_NOT_FOUND", [
114
+ `Verify the document ID is correct (the portion of the URL after /d/)`,
115
+ `Confirm ${account} has at least view access to the document`,
116
+ ]);
117
+ }
118
+ throw translated;
119
+ }
120
+ const raw = data.comments ?? [];
121
+ const filtered = flags.includeResolved
122
+ ? raw
123
+ : raw.filter((c) => !c.resolved);
124
+ const truncateAt = flags.full ? Number.POSITIVE_INFINITY : BODY_TRUNCATE;
125
+ const commentRows = filtered.map((c) => ({
126
+ id: c.id ?? "",
127
+ author: c.author?.displayName ?? c.author?.emailAddress ?? "",
128
+ created: c.createdTime ?? "",
129
+ resolved: c.resolved ?? false,
130
+ quoted_content: c.quotedFileContent?.value ?? "",
131
+ body: c.content ?? "",
132
+ reply_count: c.replies?.length ?? 0,
133
+ }));
134
+ const replyRows = filtered.flatMap((c) => (c.replies ?? []).map((r) => ({
135
+ comment: c.id ?? "",
136
+ author: r.author?.displayName ?? r.author?.emailAddress ?? "",
137
+ created: r.createdTime ?? "",
138
+ body: r.content ?? "",
139
+ })));
140
+ const blocks = [];
141
+ blocks.push(renderObject({ account, document: flags.documentId }));
142
+ if (commentRows.length === 0) {
143
+ blocks.push(renderObject({ comments: [] }));
144
+ blocks.push(renderObject({
145
+ message: flags.includeResolved
146
+ ? "no comments on this document"
147
+ : "no open comments (pass --include-resolved to include resolved)",
148
+ }));
149
+ }
150
+ else {
151
+ blocks.push(renderList("comments", commentRows, commentSchema(truncateAt)));
152
+ if (replyRows.length > 0) {
153
+ blocks.push(renderList("replies", replyRows, replySchema(truncateAt)));
154
+ }
155
+ }
156
+ const suggestions = [];
157
+ const resolvedHidden = raw.length - filtered.length;
158
+ if (!flags.includeResolved && resolvedHidden > 0) {
159
+ suggestions.push(`${resolvedHidden} resolved comment${resolvedHidden === 1 ? "" : "s"} hidden — add --include-resolved to see them`);
160
+ }
161
+ if (commentRows.length > 0 && !flags.full) {
162
+ const someTruncated = commentRows.some((r) => (typeof r.body === "string" && r.body.length > BODY_TRUNCATE) ||
163
+ (typeof r.quoted_content === "string" && r.quoted_content.length > BODY_TRUNCATE));
164
+ if (someTruncated) {
165
+ suggestions.push(`Add --full to see complete bodies / quoted content`);
166
+ }
167
+ }
168
+ if (suggestions.length > 0)
169
+ blocks.push(renderHelp(suggestions));
170
+ return joinBlocks(...blocks);
171
+ }
172
+ //# sourceMappingURL=comments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.js","sourceRoot":"","sources":["../../../../src/commands/docs/comments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const DOWNLOAD_HELP = "usage: gws-axi docs download <documentId> [flags]\nargs[1]:\n <documentId> The Google Doc / Drive file ID (from the URL after /d/)\nflags[3]:\n --out <path> Where to save (default: ./<sanitized file name>; pass a\n directory to save inside with the native name)\n --as <mime> Export format for native Google files (default: docx for\n Docs, xlsx for Sheets, pptx for Slides, png for Drawings).\n Ignored for uploaded files (they download as-is).\n --account <email> Account override when 2+ are configured\nexamples:\n gws-axi docs download 1RxHZ...\n gws-axi docs download 1RxHZ... --out /tmp/source.docx\n gws-axi docs download 1Native... --as application/pdf --out ./spec.pdf\nnotes:\n Works on any Drive file, not just docs. Native Google files are exported\n on the server side (via Drive files.export); uploaded files (.docx, .pdf,\n images, etc.) are downloaded as-is. After download, agents can inspect\n the file with tools like `file`, `pandoc`, `textutil -convert html`,\n or language-specific parsers for the file's format.\n";
2
+ export declare function docsDownloadCommand(account: string, args: string[]): Promise<string>;
@@ -0,0 +1,213 @@
1
+ import { writeFile, mkdir } from "node:fs/promises";
2
+ import { basename, dirname, extname } from "node:path";
3
+ import { AxiError } from "axi-sdk-js";
4
+ import { driveClient, translateGoogleError } from "../../google/client.js";
5
+ import { joinBlocks, renderHelp, renderObject } from "../../output/index.js";
6
+ import { resolveOutputPath } from "./paths.js";
7
+ export const DOWNLOAD_HELP = `usage: gws-axi docs download <documentId> [flags]
8
+ args[1]:
9
+ <documentId> The Google Doc / Drive file ID (from the URL after /d/)
10
+ flags[3]:
11
+ --out <path> Where to save (default: ./<sanitized file name>; pass a
12
+ directory to save inside with the native name)
13
+ --as <mime> Export format for native Google files (default: docx for
14
+ Docs, xlsx for Sheets, pptx for Slides, png for Drawings).
15
+ Ignored for uploaded files (they download as-is).
16
+ --account <email> Account override when 2+ are configured
17
+ examples:
18
+ gws-axi docs download 1RxHZ...
19
+ gws-axi docs download 1RxHZ... --out /tmp/source.docx
20
+ gws-axi docs download 1Native... --as application/pdf --out ./spec.pdf
21
+ notes:
22
+ Works on any Drive file, not just docs. Native Google files are exported
23
+ on the server side (via Drive files.export); uploaded files (.docx, .pdf,
24
+ images, etc.) are downloaded as-is. After download, agents can inspect
25
+ the file with tools like \`file\`, \`pandoc\`, \`textutil -convert html\`,
26
+ or language-specific parsers for the file's format.
27
+ `;
28
+ // Default export mime types for native Google file types.
29
+ const NATIVE_EXPORT_DEFAULTS = {
30
+ "application/vnd.google-apps.document": {
31
+ mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
32
+ extension: ".docx",
33
+ },
34
+ "application/vnd.google-apps.spreadsheet": {
35
+ mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
36
+ extension: ".xlsx",
37
+ },
38
+ "application/vnd.google-apps.presentation": {
39
+ mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
40
+ extension: ".pptx",
41
+ },
42
+ "application/vnd.google-apps.drawing": {
43
+ mime: "image/png",
44
+ extension: ".png",
45
+ },
46
+ };
47
+ // When the user passes --as, try to guess a file extension from the mime.
48
+ const EXTENSION_BY_MIME = {
49
+ "application/pdf": ".pdf",
50
+ "text/plain": ".txt",
51
+ "text/markdown": ".md",
52
+ "text/html": ".html",
53
+ "text/csv": ".csv",
54
+ "application/rtf": ".rtf",
55
+ "image/png": ".png",
56
+ "image/jpeg": ".jpg",
57
+ "image/svg+xml": ".svg",
58
+ "application/epub+zip": ".epub",
59
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx",
60
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx",
61
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx",
62
+ "application/vnd.oasis.opendocument.text": ".odt",
63
+ };
64
+ function parseFlags(args) {
65
+ let documentId;
66
+ let out;
67
+ let as;
68
+ for (let i = 0; i < args.length; i++) {
69
+ const arg = args[i];
70
+ const next = args[i + 1];
71
+ switch (arg) {
72
+ case "--out":
73
+ out = next;
74
+ i++;
75
+ break;
76
+ case "--as":
77
+ as = next;
78
+ i++;
79
+ break;
80
+ default:
81
+ if (!arg.startsWith("--") && documentId === undefined) {
82
+ documentId = arg;
83
+ }
84
+ }
85
+ }
86
+ if (!documentId) {
87
+ throw new AxiError("Missing documentId argument", "VALIDATION_ERROR", ["Usage: gws-axi docs download <documentId>"]);
88
+ }
89
+ return { documentId, out, as };
90
+ }
91
+ export async function docsDownloadCommand(account, args) {
92
+ const flags = parseFlags(args);
93
+ const api = await driveClient(account);
94
+ // Step 1: metadata — we need name, mimeType, and size to decide whether
95
+ // to export or media-download and to build a useful response.
96
+ let meta;
97
+ try {
98
+ const res = await api.files.get({
99
+ fileId: flags.documentId,
100
+ fields: "id,name,mimeType,size",
101
+ supportsAllDrives: true,
102
+ });
103
+ meta = {
104
+ name: res.data.name ?? "download",
105
+ mimeType: res.data.mimeType ?? "application/octet-stream",
106
+ size: res.data.size ?? undefined,
107
+ };
108
+ }
109
+ catch (err) {
110
+ const translated = translateGoogleError(err, {
111
+ account,
112
+ operation: "drive.files.get",
113
+ });
114
+ if (translated.code === "NOT_FOUND") {
115
+ throw new AxiError(`File '${flags.documentId}' not found (or ${account} doesn't have access)`, "FILE_NOT_FOUND", [
116
+ `Verify the file ID is correct (the portion of the URL after /d/)`,
117
+ `Confirm ${account} has at least view access to the file`,
118
+ ]);
119
+ }
120
+ throw translated;
121
+ }
122
+ const isNative = meta.mimeType.startsWith("application/vnd.google-apps.");
123
+ const nativeDefault = NATIVE_EXPORT_DEFAULTS[meta.mimeType];
124
+ if (isNative && !nativeDefault && !flags.as) {
125
+ throw new AxiError(`No default export format for native mime type ${meta.mimeType}`, "EXPORT_FORMAT_REQUIRED", [
126
+ "Pass --as <mime> to choose an export format",
127
+ "Common options: application/pdf, text/plain, text/html",
128
+ ]);
129
+ }
130
+ // Step 2: fetch bytes.
131
+ let bytes;
132
+ let effectiveMime;
133
+ let extension;
134
+ if (isNative) {
135
+ effectiveMime = flags.as ?? nativeDefault.mime;
136
+ extension = EXTENSION_BY_MIME[effectiveMime] ?? nativeDefault?.extension ?? "";
137
+ try {
138
+ const res = await api.files.export({ fileId: flags.documentId, mimeType: effectiveMime }, { responseType: "arraybuffer" });
139
+ bytes = Buffer.from(res.data);
140
+ }
141
+ catch (err) {
142
+ throw translateGoogleError(err, {
143
+ account,
144
+ operation: "drive.files.export",
145
+ });
146
+ }
147
+ }
148
+ else {
149
+ if (flags.as) {
150
+ throw new AxiError(`--as is only valid for native Google files; this is ${meta.mimeType}`, "VALIDATION_ERROR", [
151
+ "Drop --as to download the file as-is",
152
+ `The file will be saved with its original mime type (${meta.mimeType})`,
153
+ ]);
154
+ }
155
+ effectiveMime = meta.mimeType;
156
+ extension = extname(meta.name) || EXTENSION_BY_MIME[effectiveMime] || "";
157
+ try {
158
+ const res = await api.files.get({ fileId: flags.documentId, alt: "media", supportsAllDrives: true }, { responseType: "arraybuffer" });
159
+ bytes = Buffer.from(res.data);
160
+ }
161
+ catch (err) {
162
+ throw translateGoogleError(err, {
163
+ account,
164
+ operation: "drive.files.get(alt=media)",
165
+ });
166
+ }
167
+ }
168
+ // Step 3: compute output path. For native files we might need to append
169
+ // the extension because meta.name doesn't carry one for Google-native
170
+ // files (e.g., "My Doc" rather than "My Doc.docx").
171
+ let baseName = meta.name;
172
+ if (isNative && extension && !baseName.toLowerCase().endsWith(extension.toLowerCase())) {
173
+ baseName += extension;
174
+ }
175
+ const outPath = await resolveOutputPath(flags.out, baseName);
176
+ await mkdir(dirname(outPath), { recursive: true });
177
+ await writeFile(outPath, bytes);
178
+ // Step 4: response.
179
+ const blocks = [];
180
+ blocks.push(renderObject({ account }));
181
+ blocks.push(renderObject({
182
+ file: {
183
+ id: flags.documentId,
184
+ name: meta.name,
185
+ source_mime_type: meta.mimeType,
186
+ saved_mime_type: effectiveMime,
187
+ size_bytes: bytes.length,
188
+ },
189
+ }));
190
+ blocks.push(renderObject({ saved: outPath }));
191
+ const suggestions = [];
192
+ if (effectiveMime === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") {
193
+ suggestions.push(`This is a .docx — extract text with \`pandoc "${basename(outPath)}" -t plain\` or \`textutil -convert txt "${basename(outPath)}"\``);
194
+ }
195
+ else if (effectiveMime === "application/pdf") {
196
+ suggestions.push(`This is a PDF — inspect with \`pdftotext "${basename(outPath)}" -\` or open in Preview`);
197
+ }
198
+ else if (effectiveMime.startsWith("text/")) {
199
+ suggestions.push(`Text file — \`cat "${outPath}"\` to view`);
200
+ }
201
+ else if (effectiveMime.startsWith("image/")) {
202
+ suggestions.push(`Image file — open with \`open "${outPath}"\` on macOS`);
203
+ }
204
+ else {
205
+ suggestions.push(`Inspect with \`file "${outPath}"\` to identify the format`);
206
+ }
207
+ if (isNative) {
208
+ suggestions.push(`Native Google file exported as ${effectiveMime} — use --as <mime> to pick a different format (e.g. application/pdf, text/plain)`);
209
+ }
210
+ blocks.push(renderHelp(suggestions));
211
+ return joinBlocks(...blocks);
212
+ }
213
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../../../src/commands/docs/download.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const FIND_HELP = "usage: gws-axi docs find <documentId> --query <text> [flags]\nargs[1]:\n <documentId> The Google Doc ID (from the URL after /d/)\nflags[4]:\n --query <text> Text to search for (case-insensitive; required)\n --tab <id> Tab to search within (default: first tab)\n --limit <n> Max matches to return (default: 50)\n --account <email> Account override when 2+ are configured\nexamples:\n gws-axi docs find 1BxAbc... --query \"sprint goal\"\n gws-axi docs find 1BxAbc... --query foo --tab t.1 --limit 10\noutput:\n A `matches[N]{ref,paragraph,start,end,context}` table. The `ref`\n column holds compact `@N` handles that future mutation subcommands\n (insert-text, delete-range) will accept as shorthand for the matched\n range. `start` and `end` are raw Docs API character offsets.\nnotes:\n Search is restricted to one tab per call \u2014 v1 does not fan out across\n sibling tabs. Use `gws-axi docs read <id>` (no --tab) to see the tabs\n list and pick one.\n";
2
+ export declare function docsFindCommand(account: string, args: string[]): Promise<string>;