@marcfargas/go-easy 0.2.0 → 0.3.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/CHANGELOG.md +76 -0
- package/README.md +48 -44
- package/dist/auth-flow.d.ts +50 -0
- package/dist/auth-flow.d.ts.map +1 -0
- package/dist/auth-flow.js +219 -0
- package/dist/auth-flow.js.map +1 -0
- package/dist/auth-server.d.ts +18 -0
- package/dist/auth-server.d.ts.map +1 -0
- package/dist/auth-server.js +327 -0
- package/dist/auth-server.js.map +1 -0
- package/dist/auth-store.d.ts +81 -0
- package/dist/auth-store.d.ts.map +1 -0
- package/dist/auth-store.js +185 -0
- package/dist/auth-store.js.map +1 -0
- package/dist/auth.d.ts +21 -15
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +90 -50
- package/dist/auth.js.map +1 -1
- package/dist/bin/calendar.js +69 -7
- package/dist/bin/calendar.js.map +1 -1
- package/dist/bin/drive.js +2 -0
- package/dist/bin/drive.js.map +1 -1
- package/dist/bin/easy.d.ts +11 -0
- package/dist/bin/easy.d.ts.map +1 -0
- package/dist/bin/easy.js +140 -0
- package/dist/bin/easy.js.map +1 -0
- package/dist/bin/gmail.d.ts +6 -1
- package/dist/bin/gmail.d.ts.map +1 -1
- package/dist/bin/gmail.js +85 -13
- package/dist/bin/gmail.js.map +1 -1
- package/dist/bin/tasks.d.ts +17 -0
- package/dist/bin/tasks.d.ts.map +1 -0
- package/dist/bin/tasks.js +190 -0
- package/dist/bin/tasks.js.map +1 -0
- package/dist/calendar/helpers.d.ts +13 -1
- package/dist/calendar/helpers.d.ts.map +1 -1
- package/dist/calendar/helpers.js +112 -3
- package/dist/calendar/helpers.js.map +1 -1
- package/dist/calendar/index.d.ts +2 -2
- package/dist/calendar/index.d.ts.map +1 -1
- package/dist/calendar/index.js +9 -1
- package/dist/calendar/index.js.map +1 -1
- package/dist/calendar/types.d.ts +84 -0
- package/dist/calendar/types.d.ts.map +1 -1
- package/dist/calendar/types.js +7 -0
- package/dist/calendar/types.js.map +1 -1
- package/dist/errors.d.ts +24 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +22 -2
- package/dist/errors.js.map +1 -1
- package/dist/gmail/helpers.d.ts +8 -1
- package/dist/gmail/helpers.d.ts.map +1 -1
- package/dist/gmail/helpers.js +31 -5
- package/dist/gmail/helpers.js.map +1 -1
- package/dist/gmail/index.d.ts +14 -5
- package/dist/gmail/index.d.ts.map +1 -1
- package/dist/gmail/index.js +90 -20
- package/dist/gmail/index.js.map +1 -1
- package/dist/gmail/markdown.d.ts +22 -0
- package/dist/gmail/markdown.d.ts.map +1 -0
- package/dist/gmail/markdown.js +30 -0
- package/dist/gmail/markdown.js.map +1 -0
- package/dist/gmail/types.d.ts +19 -3
- package/dist/gmail/types.d.ts.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/scopes.d.ts +16 -0
- package/dist/scopes.d.ts.map +1 -0
- package/dist/scopes.js +28 -0
- package/dist/scopes.js.map +1 -0
- package/dist/tasks/helpers.d.ts +10 -0
- package/dist/tasks/helpers.d.ts.map +1 -0
- package/dist/tasks/helpers.js +33 -0
- package/dist/tasks/helpers.js.map +1 -0
- package/dist/tasks/index.d.ts +63 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +253 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/types.d.ts +79 -0
- package/dist/tasks/types.d.ts.map +1 -0
- package/dist/tasks/types.js +5 -0
- package/dist/tasks/types.js.map +1 -0
- package/package.json +33 -5
- package/skills/go-easy/SKILL.md +146 -0
- package/skills/go-easy/calendar.md +366 -0
- package/skills/go-easy/drive.md +309 -0
- package/skills/go-easy/gmail.md +478 -0
- package/skills/go-easy/tasks.md +260 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,81 @@
|
|
|
1
1
|
# @marcfargas/go-easy
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`8cf8524`](https://github.com/marcfargas/go-easy/commit/8cf85243659e1151b896a69f5405534062a82899) Thanks [@marcfargas](https://github.com/marcfargas)! - Beta release — own auth system, Google Tasks, reply CLI, file-based body flags, Markdown emails.
|
|
8
|
+
|
|
9
|
+
### Auth (BREAKING)
|
|
10
|
+
|
|
11
|
+
go-easy now owns its own OAuth2 tokens at `~/.go-easy/` instead of reading from legacy CLI stores (`~/.gmcli`, `~/.gdcli`, `~/.gccli`).
|
|
12
|
+
|
|
13
|
+
- `npx go-easy auth add <email>` — agent-compatible two-phase OAuth flow (start → poll)
|
|
14
|
+
- `npx go-easy auth list` — list configured accounts and scopes
|
|
15
|
+
- `npx go-easy auth remove <email> --confirm` — remove an account
|
|
16
|
+
- One combined token per account covers Gmail + Drive + Calendar + Tasks
|
|
17
|
+
- Specific error codes with `fix` field: `AUTH_NO_ACCOUNT`, `AUTH_MISSING_SCOPE`, `AUTH_TOKEN_REVOKED`, `AUTH_NO_CREDENTIALS`
|
|
18
|
+
|
|
19
|
+
### Google Tasks (NEW)
|
|
20
|
+
|
|
21
|
+
New service module and CLI for Google Tasks API:
|
|
22
|
+
|
|
23
|
+
- `npx go-tasks <account> lists` — list task lists
|
|
24
|
+
- `npx go-tasks <account> tasks <listId>` — list tasks with pagination
|
|
25
|
+
- `npx go-tasks <account> get/add/update/complete/move/delete` — full CRUD
|
|
26
|
+
- `npx go-tasks <account> create-list/delete-list/clear` — list management
|
|
27
|
+
- Subtask support via `--parent` flag
|
|
28
|
+
- Library: `@marcfargas/go-easy/tasks` export
|
|
29
|
+
- Requires re-auth for existing accounts (`npx go-easy auth add <email>`)
|
|
30
|
+
|
|
31
|
+
### Gmail CLI
|
|
32
|
+
|
|
33
|
+
- Add `reply` command — reply and reply-all with `--reply-all` flag (DESTRUCTIVE, requires `--confirm`)
|
|
34
|
+
- Add `--in-reply-to` flag for `draft` command (thread association)
|
|
35
|
+
- Add `--cc` and `--bcc` flags for `draft` and `send` commands
|
|
36
|
+
- Add `--page-token` for `search` and `drafts` pagination
|
|
37
|
+
|
|
38
|
+
### Body Flags (BREAKING)
|
|
39
|
+
|
|
40
|
+
Replace inline `--body`, `--html`, `--md` flags with file-based alternatives:
|
|
41
|
+
|
|
42
|
+
- `--body-text-file=<path>` — read plain text body from UTF-8 file
|
|
43
|
+
- `--body-html-file=<path>` — read HTML body from UTF-8 file
|
|
44
|
+
- `--body-md-file=<path>` — read Markdown body from file (auto-converted to HTML)
|
|
45
|
+
|
|
46
|
+
This eliminates shell escaping, encoding, and multiline issues for agent use.
|
|
47
|
+
|
|
48
|
+
### Markdown Email Support
|
|
49
|
+
|
|
50
|
+
- New `markdown` option on `send`, `reply`, `forward`, and `createDraft`
|
|
51
|
+
- Auto-converts Markdown to email-safe HTML with inline styles
|
|
52
|
+
- GFM support: tables, strikethrough, code blocks, links, lists
|
|
53
|
+
- `markdownToHtml()` helper exported from `@marcfargas/go-easy/gmail`
|
|
54
|
+
|
|
55
|
+
### Forward Improvements
|
|
56
|
+
|
|
57
|
+
- Forward creates a draft by default (WRITE, no safety gate)
|
|
58
|
+
- `--send-now --confirm` to send immediately (DESTRUCTIVE)
|
|
59
|
+
- Attachment filtering: `--include=name` and `--exclude=name` (substring match)
|
|
60
|
+
- `--no-thread` to break out of the original thread
|
|
61
|
+
- Body content appears above the forwarded message
|
|
62
|
+
|
|
63
|
+
### Calendar
|
|
64
|
+
|
|
65
|
+
- Support all event types: working location, out-of-office, focus time, birthday
|
|
66
|
+
- `--page-token` for events pagination
|
|
67
|
+
- Fix `update` command: use PATCH instead of PUT to prevent data loss on partial updates
|
|
68
|
+
|
|
69
|
+
### Drive
|
|
70
|
+
|
|
71
|
+
- `--page-token` for `ls` and `search` pagination
|
|
72
|
+
|
|
73
|
+
### Fixes
|
|
74
|
+
|
|
75
|
+
- RFC 2047 encode Subject headers with non-ASCII characters
|
|
76
|
+
- Fix forward threading (keep in original thread by default)
|
|
77
|
+
- Fix auth HTML pages: add `<meta charset="utf-8">` for emoji rendering
|
|
78
|
+
|
|
3
79
|
## 0.2.0
|
|
4
80
|
|
|
5
81
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
> Google APIs made easy — Gmail, Drive & Calendar. For AI agents and humans.
|
|
4
4
|
|
|
5
5
|
Thin TypeScript wrappers over Google's individual `@googleapis/*` packages with:
|
|
6
|
-
- **
|
|
6
|
+
- **Own auth** — unified OAuth2 with combined tokens, agent-compatible two-phase flow
|
|
7
7
|
- **Agent-friendly types** — structured `GmailMessage`, `DriveFile`, `CalendarEvent`
|
|
8
8
|
- **Safety guards** — destructive operations (send, share, delete) require explicit confirmation
|
|
9
9
|
- **JSON gateways** — CLI tools that always output structured JSON
|
|
10
|
-
- **
|
|
10
|
+
- **File-based body** — email bodies read from files, not CLI args (no shell escaping issues)
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -25,41 +25,48 @@ Requires **Node.js ≥ 20**.
|
|
|
25
25
|
|
|
26
26
|
## Auth Setup
|
|
27
27
|
|
|
28
|
-
go-easy
|
|
28
|
+
go-easy manages its own OAuth2 tokens in `~/.go-easy/`.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|---|---|
|
|
32
|
-
| Gmail | `~/.gmcli/accounts.json` |
|
|
33
|
-
| Drive | `~/.gdcli/accounts.json` |
|
|
34
|
-
| Calendar | `~/.gccli/accounts.json` |
|
|
30
|
+
### Prerequisites
|
|
35
31
|
|
|
36
|
-
|
|
32
|
+
1. Create a project in [Google Cloud Console](https://console.cloud.google.com/)
|
|
33
|
+
2. Enable the Gmail, Drive, and Calendar APIs
|
|
34
|
+
3. Create OAuth2 credentials (Desktop application type)
|
|
35
|
+
4. Save credentials to `~/.go-easy/credentials.json`:
|
|
37
36
|
|
|
38
37
|
```json
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"clientId": "YOUR_CLIENT_ID.apps.googleusercontent.com",
|
|
44
|
-
"clientSecret": "YOUR_CLIENT_SECRET",
|
|
45
|
-
"refreshToken": "YOUR_REFRESH_TOKEN"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
]
|
|
38
|
+
{
|
|
39
|
+
"clientId": "YOUR_CLIENT_ID.apps.googleusercontent.com",
|
|
40
|
+
"clientSecret": "YOUR_CLIENT_SECRET"
|
|
41
|
+
}
|
|
49
42
|
```
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
### Add an account
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx go-easy auth add you@example.com
|
|
48
|
+
# → { "status": "started", "authUrl": "https://accounts.google.com/..." }
|
|
49
|
+
# Open the URL, authorize, then poll:
|
|
50
|
+
npx go-easy auth add you@example.com
|
|
51
|
+
# → { "status": "complete", "email": "you@example.com", "scopes": ["gmail", "drive", "calendar"] }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
One combined token covers Gmail + Drive + Calendar. The flow is agent-compatible — two separate CLI calls (start + poll), no streaming stdout needed.
|
|
55
|
+
|
|
56
|
+
### Manage accounts
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx go-easy auth list # List configured accounts
|
|
60
|
+
npx go-easy auth add you@example.com # Add or upgrade account
|
|
61
|
+
npx go-easy auth remove you@example.com --confirm # Remove account
|
|
62
|
+
```
|
|
57
63
|
|
|
58
64
|
## Quick Start
|
|
59
65
|
|
|
60
66
|
```ts
|
|
61
67
|
import { getAuth } from '@marcfargas/go-easy/auth';
|
|
62
68
|
import { search, send } from '@marcfargas/go-easy/gmail';
|
|
69
|
+
import { setSafetyContext } from '@marcfargas/go-easy';
|
|
63
70
|
|
|
64
71
|
const auth = await getAuth('gmail', 'you@example.com');
|
|
65
72
|
|
|
@@ -68,8 +75,6 @@ const results = await search(auth, { query: 'is:unread from:client' });
|
|
|
68
75
|
console.log(results.items);
|
|
69
76
|
|
|
70
77
|
// Send (DESTRUCTIVE — requires safety context)
|
|
71
|
-
import { setSafetyContext } from '@marcfargas/go-easy';
|
|
72
|
-
|
|
73
78
|
setSafetyContext({
|
|
74
79
|
confirm: async (op) => {
|
|
75
80
|
console.log(`⚠️ ${op.description}`);
|
|
@@ -80,7 +85,7 @@ setSafetyContext({
|
|
|
80
85
|
await send(auth, {
|
|
81
86
|
to: 'client@example.com',
|
|
82
87
|
subject: 'Invoice attached',
|
|
83
|
-
|
|
88
|
+
markdown: '# Invoice\n\nPlease find attached.',
|
|
84
89
|
attachments: ['./invoice.pdf'],
|
|
85
90
|
});
|
|
86
91
|
```
|
|
@@ -93,7 +98,8 @@ All gateway CLIs output JSON to stdout and work via `npx`:
|
|
|
93
98
|
# Gmail
|
|
94
99
|
npx go-gmail you@example.com search "is:unread" --max=10
|
|
95
100
|
npx go-gmail you@example.com get <messageId>
|
|
96
|
-
npx go-gmail you@example.com
|
|
101
|
+
npx go-gmail you@example.com reply <messageId> --body-text-file=reply.txt --confirm
|
|
102
|
+
npx go-gmail you@example.com send --to=x@y.com --subject="Hi" --body-text-file=body.txt --confirm
|
|
97
103
|
|
|
98
104
|
# Drive
|
|
99
105
|
npx go-drive you@example.com ls
|
|
@@ -106,6 +112,8 @@ npx go-calendar you@example.com create primary --summary="Meeting" --start=... -
|
|
|
106
112
|
npx go-calendar you@example.com freebusy primary --from=... --to=...
|
|
107
113
|
```
|
|
108
114
|
|
|
115
|
+
Body content is always read from files (`--body-text-file`, `--body-html-file`, `--body-md-file`), never passed inline.
|
|
116
|
+
|
|
109
117
|
Destructive operations require `--confirm`. Without it, they show what *would* happen and exit with code 2.
|
|
110
118
|
|
|
111
119
|
## Services
|
|
@@ -129,9 +137,10 @@ Destructive operations require `--confirm`. Without it, they show what *would* h
|
|
|
129
137
|
| `createDraft` | WRITE | Create a draft (no send) |
|
|
130
138
|
| `listDrafts` | READ | List existing drafts |
|
|
131
139
|
| `batchModifyLabels` | WRITE | Add/remove labels on multiple messages |
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
140
|
+
| `markdownToHtml` | — | Convert Markdown to email-safe HTML |
|
|
141
|
+
| `send` | ⚠️ DESTRUCTIVE | Send a new email (supports `markdown` option) |
|
|
142
|
+
| `reply` | ⚠️ DESTRUCTIVE | Reply / reply-all to a message |
|
|
143
|
+
| `forward` | WRITE / ⚠️ DESTRUCTIVE | Forward as draft (default) or send (`sendNow`). Attachment filtering. |
|
|
135
144
|
| `sendDraft` | ⚠️ DESTRUCTIVE | Send an existing draft |
|
|
136
145
|
|
|
137
146
|
### Drive
|
|
@@ -161,8 +170,8 @@ Destructive operations require `--confirm`. Without it, they show what *would* h
|
|
|
161
170
|
| `listEvents` | READ | List events with time range, search, pagination |
|
|
162
171
|
| `getEvent` | READ | Get a single event by ID |
|
|
163
172
|
| `queryFreeBusy` | READ | Check availability across calendars |
|
|
164
|
-
| `createEvent` | WRITE | Create an event (with attendees, all-day, location) |
|
|
165
|
-
| `updateEvent` | WRITE | Update an existing event |
|
|
173
|
+
| `createEvent` | WRITE | Create an event (with attendees, all-day, location, OOO, focus time) |
|
|
174
|
+
| `updateEvent` | WRITE | Update an existing event (full replace) |
|
|
166
175
|
| `deleteEvent` | ⚠️ DESTRUCTIVE | Delete an event (warns about attendee cancellation) |
|
|
167
176
|
|
|
168
177
|
## Safety Model
|
|
@@ -183,24 +192,23 @@ Without one, all destructive operations are blocked by default.
|
|
|
183
192
|
go-easy uses **subpath exports** — import only what you need:
|
|
184
193
|
|
|
185
194
|
```ts
|
|
186
|
-
// Subpath imports (recommended)
|
|
187
195
|
import { getAuth } from '@marcfargas/go-easy/auth';
|
|
188
196
|
import { search, send } from '@marcfargas/go-easy/gmail';
|
|
189
|
-
import { listFiles,
|
|
197
|
+
import { listFiles, uploadFile } from '@marcfargas/go-easy/drive';
|
|
190
198
|
import { listEvents, createEvent } from '@marcfargas/go-easy/calendar';
|
|
191
|
-
import { setSafetyContext } from '@marcfargas/go-easy';
|
|
199
|
+
import { setSafetyContext } from '@marcfargas/go-easy';
|
|
192
200
|
```
|
|
193
201
|
|
|
194
202
|
| Import path | What's in it |
|
|
195
203
|
|---|---|
|
|
196
204
|
| `@marcfargas/go-easy` | Safety context, errors, plus `gmail`/`drive`/`calendar` as namespaces |
|
|
197
|
-
| `@marcfargas/go-easy/auth` | `getAuth`, `listAccounts`, `clearAuthCache` |
|
|
205
|
+
| `@marcfargas/go-easy/auth` | `getAuth`, `listAccounts`, `listAllAccounts`, `clearAuthCache` |
|
|
206
|
+
| `@marcfargas/go-easy/auth-store` | `readAccountStore`, `writeAccountStore`, `findAccount`, etc. |
|
|
207
|
+
| `@marcfargas/go-easy/scopes` | `SCOPES`, `ALL_SCOPES`, `scopeToService` |
|
|
198
208
|
| `@marcfargas/go-easy/gmail` | All Gmail operations |
|
|
199
209
|
| `@marcfargas/go-easy/drive` | All Drive operations |
|
|
200
210
|
| `@marcfargas/go-easy/calendar` | All Calendar operations |
|
|
201
211
|
|
|
202
|
-
The root export also re-exports each service as a namespace, so `import { gmail } from '@marcfargas/go-easy'` works if you prefer a single import.
|
|
203
|
-
|
|
204
212
|
## Development
|
|
205
213
|
|
|
206
214
|
```bash
|
|
@@ -211,10 +219,6 @@ npm run lint # type-check without emitting
|
|
|
211
219
|
npm run dev # watch mode
|
|
212
220
|
```
|
|
213
221
|
|
|
214
|
-
## Contributing
|
|
215
|
-
|
|
216
|
-
Found a bug or have a feature request? [Open an issue](https://github.com/marcfargas/go-easy/issues).
|
|
217
|
-
|
|
218
222
|
## License
|
|
219
223
|
|
|
220
224
|
MIT
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auth-flow — Two-phase OAuth flow for agent-compatible auth.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 (start): Spawn background auth server, return URL.
|
|
5
|
+
* Phase 2 (poll): Check pending file for completion status.
|
|
6
|
+
*
|
|
7
|
+
* The agent calls `npx go-easy auth add <email>` which:
|
|
8
|
+
* - On first call: starts the server, returns { status: "started", authUrl }
|
|
9
|
+
* - On subsequent calls: polls and returns current status
|
|
10
|
+
* - When user completes auth: returns { status: "complete" }
|
|
11
|
+
*/
|
|
12
|
+
export type AuthFlowStatus = {
|
|
13
|
+
status: 'started';
|
|
14
|
+
authUrl: string;
|
|
15
|
+
expiresIn: number;
|
|
16
|
+
} | {
|
|
17
|
+
status: 'waiting';
|
|
18
|
+
authUrl: string;
|
|
19
|
+
expiresIn: number;
|
|
20
|
+
} | {
|
|
21
|
+
status: 'complete';
|
|
22
|
+
email: string;
|
|
23
|
+
scopes: string[];
|
|
24
|
+
} | {
|
|
25
|
+
status: 'partial';
|
|
26
|
+
email: string;
|
|
27
|
+
grantedScopes: string[];
|
|
28
|
+
missingScopes: string[];
|
|
29
|
+
message: string;
|
|
30
|
+
} | {
|
|
31
|
+
status: 'denied';
|
|
32
|
+
message: string;
|
|
33
|
+
} | {
|
|
34
|
+
status: 'expired';
|
|
35
|
+
message: string;
|
|
36
|
+
} | {
|
|
37
|
+
status: 'error';
|
|
38
|
+
message: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Start or poll the auth flow for an email.
|
|
42
|
+
*
|
|
43
|
+
* This is the single entry point — handles all states:
|
|
44
|
+
* - No session → start new auth server
|
|
45
|
+
* - Pending session with live server → return waiting/started
|
|
46
|
+
* - Completed session → return result, clean up
|
|
47
|
+
* - Stale session (dead pid) → clean up, restart
|
|
48
|
+
*/
|
|
49
|
+
export declare function authAdd(email: string): Promise<AuthFlowStatus>;
|
|
50
|
+
//# sourceMappingURL=auth-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-flow.d.ts","sourceRoot":"","sources":["../src/auth-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAiBH,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GACvD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvG;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAmBzC;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAyGpE"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auth-flow — Two-phase OAuth flow for agent-compatible auth.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 (start): Spawn background auth server, return URL.
|
|
5
|
+
* Phase 2 (poll): Check pending file for completion status.
|
|
6
|
+
*
|
|
7
|
+
* The agent calls `npx go-easy auth add <email>` which:
|
|
8
|
+
* - On first call: starts the server, returns { status: "started", authUrl }
|
|
9
|
+
* - On subsequent calls: polls and returns current status
|
|
10
|
+
* - When user completes auth: returns { status: "complete" }
|
|
11
|
+
*/
|
|
12
|
+
import { readFile, unlink, stat } from 'node:fs/promises';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { spawn } from 'node:child_process';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
16
|
+
import { getPendingDir, readAccountStore, readCredentials, findAccount, } from './auth-store.js';
|
|
17
|
+
import { ALL_SCOPES, scopeToService } from './scopes.js';
|
|
18
|
+
import { AuthError } from './errors.js';
|
|
19
|
+
// ─── Public API ────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* Start or poll the auth flow for an email.
|
|
22
|
+
*
|
|
23
|
+
* This is the single entry point — handles all states:
|
|
24
|
+
* - No session → start new auth server
|
|
25
|
+
* - Pending session with live server → return waiting/started
|
|
26
|
+
* - Completed session → return result, clean up
|
|
27
|
+
* - Stale session (dead pid) → clean up, restart
|
|
28
|
+
*/
|
|
29
|
+
export async function authAdd(email) {
|
|
30
|
+
// Check if already fully configured
|
|
31
|
+
const store = await readAccountStore();
|
|
32
|
+
if (store) {
|
|
33
|
+
const account = findAccount(store, email);
|
|
34
|
+
if (account?.tokens.combined) {
|
|
35
|
+
const hasAll = ALL_SCOPES.every((s) => account.tokens.combined.scopes.includes(s));
|
|
36
|
+
if (hasAll) {
|
|
37
|
+
// Clean up any stale pending file
|
|
38
|
+
await cleanupPending(email);
|
|
39
|
+
return {
|
|
40
|
+
status: 'complete',
|
|
41
|
+
email: account.email,
|
|
42
|
+
scopes: account.tokens.combined.scopes.map((s) => scopeToService(s) ?? s),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Check credentials exist
|
|
48
|
+
const creds = await readCredentials();
|
|
49
|
+
if (!creds) {
|
|
50
|
+
throw new AuthError('AUTH_NO_CREDENTIALS', {
|
|
51
|
+
message: 'OAuth client credentials not found at ~/.go-easy/credentials.json',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Check for pending session
|
|
55
|
+
const pending = await readPending(email);
|
|
56
|
+
if (pending) {
|
|
57
|
+
// Terminal states: return and clean up
|
|
58
|
+
if (pending.status === 'complete') {
|
|
59
|
+
await cleanupPending(email);
|
|
60
|
+
return {
|
|
61
|
+
status: 'complete',
|
|
62
|
+
email: pending.email ?? email,
|
|
63
|
+
scopes: pending.scopes ?? [],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (pending.status === 'partial') {
|
|
67
|
+
await cleanupPending(email);
|
|
68
|
+
return {
|
|
69
|
+
status: 'partial',
|
|
70
|
+
email: pending.email ?? email,
|
|
71
|
+
grantedScopes: pending.grantedScopes ?? [],
|
|
72
|
+
missingScopes: pending.missingScopes ?? [],
|
|
73
|
+
message: pending.message ?? 'Partial authorization',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (pending.status === 'denied') {
|
|
77
|
+
await cleanupPending(email);
|
|
78
|
+
return {
|
|
79
|
+
status: 'denied',
|
|
80
|
+
message: pending.message ?? 'User declined authorization',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (pending.status === 'expired') {
|
|
84
|
+
await cleanupPending(email);
|
|
85
|
+
return {
|
|
86
|
+
status: 'expired',
|
|
87
|
+
message: pending.message ?? 'Authorization timed out',
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (pending.status === 'error') {
|
|
91
|
+
await cleanupPending(email);
|
|
92
|
+
return {
|
|
93
|
+
status: 'error',
|
|
94
|
+
message: pending.message ?? 'Unknown error during authorization',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// Active session (waiting/started)
|
|
98
|
+
if (pending.status === 'waiting' || pending.status === 'started') {
|
|
99
|
+
// Check if the server process is still alive
|
|
100
|
+
if (pending.pid && isProcessAlive(pending.pid)) {
|
|
101
|
+
// Check if expired by time
|
|
102
|
+
if (pending.expiresAt && new Date(pending.expiresAt) < new Date()) {
|
|
103
|
+
await cleanupPending(email);
|
|
104
|
+
return {
|
|
105
|
+
status: 'expired',
|
|
106
|
+
message: 'Authorization timed out',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Still waiting — return current state
|
|
110
|
+
const expiresIn = pending.expiresAt
|
|
111
|
+
? Math.max(0, Math.floor((new Date(pending.expiresAt).getTime() - Date.now()) / 1000))
|
|
112
|
+
: 300;
|
|
113
|
+
return {
|
|
114
|
+
status: 'waiting',
|
|
115
|
+
authUrl: pending.authUrl ?? '',
|
|
116
|
+
expiresIn,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// PID is dead — stale session, clean up and restart
|
|
120
|
+
await cleanupPending(email);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Start new auth flow
|
|
124
|
+
return startAuthServer(email);
|
|
125
|
+
}
|
|
126
|
+
// ─── Internal ──────────────────────────────────────────────
|
|
127
|
+
function pendingFilePath(email) {
|
|
128
|
+
return join(getPendingDir(), `${email.toLowerCase().trim()}.json`);
|
|
129
|
+
}
|
|
130
|
+
async function readPending(email) {
|
|
131
|
+
try {
|
|
132
|
+
const raw = await readFile(pendingFilePath(email), 'utf-8');
|
|
133
|
+
return JSON.parse(raw);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function cleanupPending(email) {
|
|
140
|
+
try {
|
|
141
|
+
await unlink(pendingFilePath(email));
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Already deleted or never existed
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function isProcessAlive(pid) {
|
|
148
|
+
try {
|
|
149
|
+
process.kill(pid, 0); // Signal 0 = just check existence
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Spawn the auth-server as a fully detached background process.
|
|
158
|
+
*
|
|
159
|
+
* Uses stdio: 'ignore' so the child has no pipe ties to the parent.
|
|
160
|
+
* The child writes its startup info to the pending/<email>.json file.
|
|
161
|
+
* We poll that file briefly to get the authUrl.
|
|
162
|
+
*/
|
|
163
|
+
async function startAuthServer(email) {
|
|
164
|
+
// Resolve the auth-server script path
|
|
165
|
+
const thisDir = typeof __dirname !== 'undefined'
|
|
166
|
+
? __dirname
|
|
167
|
+
: fileURLToPath(new URL('.', import.meta.url));
|
|
168
|
+
const serverScript = join(thisDir, 'auth-server.js');
|
|
169
|
+
// Verify the script exists
|
|
170
|
+
try {
|
|
171
|
+
await stat(serverScript);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
throw new AuthError('AUTH_ERROR', {
|
|
175
|
+
message: `Auth server script not found: ${serverScript}`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Clean up any old pending file first
|
|
179
|
+
await cleanupPending(email);
|
|
180
|
+
// Spawn fully detached — no pipes, child survives parent exit
|
|
181
|
+
const child = spawn(process.execPath, // node.exe
|
|
182
|
+
[serverScript, email.toLowerCase().trim(), '0'], {
|
|
183
|
+
detached: true,
|
|
184
|
+
stdio: 'ignore',
|
|
185
|
+
windowsHide: true,
|
|
186
|
+
});
|
|
187
|
+
child.unref();
|
|
188
|
+
// Poll the pending file for the server's startup info
|
|
189
|
+
const maxWait = 10_000; // 10s
|
|
190
|
+
const pollInterval = 100; // 100ms
|
|
191
|
+
const start = Date.now();
|
|
192
|
+
while (Date.now() - start < maxWait) {
|
|
193
|
+
await sleep(pollInterval);
|
|
194
|
+
const pending = await readPending(email);
|
|
195
|
+
if (pending && pending.authUrl) {
|
|
196
|
+
return {
|
|
197
|
+
status: 'started',
|
|
198
|
+
authUrl: pending.authUrl,
|
|
199
|
+
expiresIn: pending.expiresAt
|
|
200
|
+
? Math.max(0, Math.floor((new Date(pending.expiresAt).getTime() - Date.now()) / 1000))
|
|
201
|
+
: 300,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
// If the server wrote an error/terminal state, return it
|
|
205
|
+
if (pending && pending.status === 'error') {
|
|
206
|
+
return {
|
|
207
|
+
status: 'error',
|
|
208
|
+
message: pending.message ?? 'Auth server failed to start',
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
throw new AuthError('AUTH_ERROR', {
|
|
213
|
+
message: 'Auth server did not start within 10 seconds',
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function sleep(ms) {
|
|
217
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=auth-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-flow.js","sourceRoot":"","sources":["../src/auth-flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* auth-server — Background loopback OAuth callback server.
|
|
4
|
+
*
|
|
5
|
+
* Spawned as a detached child by auth-flow.ts.
|
|
6
|
+
* Listens on 127.0.0.1:<port>, waits for Google OAuth callback,
|
|
7
|
+
* exchanges code for token, writes result to pending/<email>.json,
|
|
8
|
+
* updates accounts.json.
|
|
9
|
+
*
|
|
10
|
+
* Communicates with parent via:
|
|
11
|
+
* 1. stdout: JSON line with { port, pid, authUrl } (parent reads this, then detaches)
|
|
12
|
+
* 2. pending/<email>.json file (poll target for subsequent CLI calls)
|
|
13
|
+
*
|
|
14
|
+
* Usage (not meant to be called directly):
|
|
15
|
+
* node auth-server.js <email> <port>
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=auth-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-server.d.ts","sourceRoot":"","sources":["../src/auth-server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG"}
|