@lanes-sh/link 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 +202 -0
- package/README.md +144 -0
- package/bin/lanes +42 -0
- package/instructions/agents/lanes-link-scout.md +73 -0
- package/instructions/skills/lanes-link/SKILL.md +187 -0
- package/package.json +95 -0
- package/src/audit/chain.ts +278 -0
- package/src/audit/conformance.ts +374 -0
- package/src/audit/fanout.ts +97 -0
- package/src/audit/index.ts +218 -0
- package/src/audit/stdout.ts +60 -0
- package/src/auth/index.ts +220 -0
- package/src/auth/oauth/metadata.ts +75 -0
- package/src/auth/oauth/server.ts +385 -0
- package/src/auth/oauth/store.ts +215 -0
- package/src/auth/oidc.ts +206 -0
- package/src/auth/remote.ts +72 -0
- package/src/cli/argv.ts +94 -0
- package/src/cli/callback-page.ts +256 -0
- package/src/cli/commands/connect/accounts.ts +94 -0
- package/src/cli/commands/connect/authorise.ts +298 -0
- package/src/cli/commands/connect/client.ts +284 -0
- package/src/cli/commands/connect/index.ts +398 -0
- package/src/cli/commands/connect/outcome.ts +119 -0
- package/src/cli/commands/connect/requirements.ts +103 -0
- package/src/cli/commands/connect/scopes-gate.ts +146 -0
- package/src/cli/commands/connect/settle.ts +136 -0
- package/src/cli/commands/connect/setup.ts +276 -0
- package/src/cli/commands/mcp/assets.ts +189 -0
- package/src/cli/commands/mcp/harnesses.ts +143 -0
- package/src/cli/commands/mcp/list.ts +70 -0
- package/src/cli/commands/mcp/register.ts +199 -0
- package/src/cli/commands/mcp/stdio.ts +57 -0
- package/src/cli/commands/mcp.ts +22 -0
- package/src/cli/commands/operate/attach.ts +121 -0
- package/src/cli/commands/operate/audit.ts +119 -0
- package/src/cli/commands/operate/inspect.ts +355 -0
- package/src/cli/commands/operate/outputs.ts +206 -0
- package/src/cli/commands/operate/policy.ts +80 -0
- package/src/cli/commands/operate/serve.ts +55 -0
- package/src/cli/commands/operate/status.ts +133 -0
- package/src/cli/commands/operate/token.ts +70 -0
- package/src/cli/commands/operate.ts +27 -0
- package/src/cli/commands/owner/memory.ts +110 -0
- package/src/cli/commands/owner/shared.ts +125 -0
- package/src/cli/commands/owner/skills.ts +92 -0
- package/src/cli/commands/owner/vault.ts +140 -0
- package/src/cli/commands/owner.ts +46 -0
- package/src/cli/commands/profile/removal.ts +278 -0
- package/src/cli/commands/profile/remove.ts +315 -0
- package/src/cli/commands/profile.ts +156 -0
- package/src/cli/commands/secrets.ts +176 -0
- package/src/cli/commands/setup.ts +150 -0
- package/src/cli/commands/target.ts +310 -0
- package/src/cli/config-edit.ts +397 -0
- package/src/cli/endpoint-url.ts +77 -0
- package/src/cli/identity.ts +109 -0
- package/src/cli/lanes.ts +78 -0
- package/src/cli/main.ts +333 -0
- package/src/cli/oauth-error.ts +13 -0
- package/src/cli/oauth-exchange.ts +146 -0
- package/src/cli/oauth.ts +354 -0
- package/src/cli/output.ts +184 -0
- package/src/cli/prompt.ts +180 -0
- package/src/cli/publish.ts +185 -0
- package/src/cli/runtime/discovery.ts +123 -0
- package/src/cli/runtime/open.ts +342 -0
- package/src/cli/runtime/registry.ts +185 -0
- package/src/cli/runtime/select.ts +124 -0
- package/src/cli/runtime.ts +34 -0
- package/src/cli/scopes.ts +63 -0
- package/src/cli/usage.ts +111 -0
- package/src/cli/version.ts +25 -0
- package/src/connectivity/auth/README.md +36 -0
- package/src/connectivity/auth/api-key/index.ts +43 -0
- package/src/connectivity/auth/authorize.ts +49 -0
- package/src/connectivity/auth/basic/index.ts +68 -0
- package/src/connectivity/auth/bearer/index.ts +13 -0
- package/src/connectivity/auth/credential.ts +19 -0
- package/src/connectivity/auth/header/index.ts +18 -0
- package/src/connectivity/auth/index.ts +35 -0
- package/src/connectivity/auth/none/index.ts +12 -0
- package/src/connectivity/auth/oauth-authcode/broker.ts +261 -0
- package/src/connectivity/auth/oauth-authcode/index.ts +64 -0
- package/src/connectivity/auth/oauth-authcode/provider.ts +279 -0
- package/src/connectivity/auth/oauth-authcode/refresh.ts +118 -0
- package/src/connectivity/auth/resolve.ts +61 -0
- package/src/connectivity/auth/strategy/index.ts +14 -0
- package/src/connectivity/capability.ts +164 -0
- package/src/connectivity/connector.ts +175 -0
- package/src/connectivity/context.ts +77 -0
- package/src/connectivity/index.ts +94 -0
- package/src/connectivity/mail/attachments.ts +368 -0
- package/src/connectivity/mail/compose.ts +73 -0
- package/src/connectivity/mail/index.ts +40 -0
- package/src/connectivity/mail/message.ts +82 -0
- package/src/connectivity/mail/nodemailer.d.ts +83 -0
- package/src/connectivity/mail/staging.ts +143 -0
- package/src/connectivity/mail/url.ts +301 -0
- package/src/connectivity/manifest/auth.ts +135 -0
- package/src/connectivity/manifest/bundles.ts +23 -0
- package/src/connectivity/manifest/connector.ts +168 -0
- package/src/connectivity/manifest/credential-ref.ts +73 -0
- package/src/connectivity/manifest/identity.ts +43 -0
- package/src/connectivity/manifest/index.ts +46 -0
- package/src/connectivity/manifest/primitives.ts +20 -0
- package/src/connectivity/manifest/provider.ts +208 -0
- package/src/connectivity/manifest/requirements.ts +146 -0
- package/src/connectivity/manifest/setup.ts +55 -0
- package/src/connectivity/provider.ts +163 -0
- package/src/connectivity/transports/README.md +33 -0
- package/src/connectivity/transports/composite/index.ts +68 -0
- package/src/connectivity/transports/dav/calendar.ts +217 -0
- package/src/connectivity/transports/dav/capabilities.ts +151 -0
- package/src/connectivity/transports/dav/client.ts +226 -0
- package/src/connectivity/transports/dav/contacts.ts +75 -0
- package/src/connectivity/transports/dav/ical.ts +412 -0
- package/src/connectivity/transports/dav/index.ts +143 -0
- package/src/connectivity/transports/dav/operations.ts +43 -0
- package/src/connectivity/transports/dav/request.ts +161 -0
- package/src/connectivity/transports/dav/xml.ts +123 -0
- package/src/connectivity/transports/factory.ts +181 -0
- package/src/connectivity/transports/fs/capabilities.ts +88 -0
- package/src/connectivity/transports/fs/commands.ts +258 -0
- package/src/connectivity/transports/fs/index.ts +121 -0
- package/src/connectivity/transports/fs/operations.ts +45 -0
- package/src/connectivity/transports/fs/paths.ts +120 -0
- package/src/connectivity/transports/fs/result.ts +12 -0
- package/src/connectivity/transports/http/index.ts +255 -0
- package/src/connectivity/transports/imap/attachment.ts +166 -0
- package/src/connectivity/transports/imap/capabilities.ts +158 -0
- package/src/connectivity/transports/imap/client.ts +398 -0
- package/src/connectivity/transports/imap/commands.ts +385 -0
- package/src/connectivity/transports/imap/index.ts +152 -0
- package/src/connectivity/transports/imap/operations.ts +64 -0
- package/src/connectivity/transports/imap/parse.ts +130 -0
- package/src/connectivity/transports/imap/parser.ts +272 -0
- package/src/connectivity/transports/imap/result.ts +15 -0
- package/src/connectivity/transports/imap/send.ts +92 -0
- package/src/connectivity/transports/imap/socket.ts +111 -0
- package/src/connectivity/transports/imap/utf7.ts +136 -0
- package/src/connectivity/transports/index.ts +20 -0
- package/src/connectivity/transports/local/index.ts +173 -0
- package/src/connectivity/transports/mcp/index.ts +215 -0
- package/src/deployments/README.md +63 -0
- package/src/deployments/adapters/audit-blob.ts +203 -0
- package/src/deployments/adapters/filesystem.ts +184 -0
- package/src/deployments/adapters/gcp-secret-manager.ts +492 -0
- package/src/deployments/adapters/gcs.ts +191 -0
- package/src/deployments/adapters/otlp.ts +128 -0
- package/src/deployments/adapters/s3.ts +195 -0
- package/src/deployments/azure/README.md +21 -0
- package/src/deployments/bootstrap.ts +177 -0
- package/src/deployments/deploy.ts +290 -0
- package/src/deployments/driver.ts +157 -0
- package/src/deployments/drivers.ts +35 -0
- package/src/deployments/gcp/Dockerfile +70 -0
- package/src/deployments/gcp/cloudbuild.yaml +31 -0
- package/src/deployments/gcp/driver.ts +175 -0
- package/src/deployments/gcp/gcloud.ts +178 -0
- package/src/deployments/gcp/provision.ts +290 -0
- package/src/deployments/gcp/survey.ts +319 -0
- package/src/deployments/local/README.md +12 -0
- package/src/deployments/prepare.ts +257 -0
- package/src/deployments/steps.ts +137 -0
- package/src/deployments/target.ts +295 -0
- package/src/deployments/upload.ts +207 -0
- package/src/dispatch/context.ts +195 -0
- package/src/dispatch/dispatch.ts +350 -0
- package/src/dispatch/index.ts +32 -0
- package/src/dispatch/staging.ts +102 -0
- package/src/policy/index.ts +179 -0
- package/src/policy/limits.ts +77 -0
- package/src/profile/authorization.ts +81 -0
- package/src/profile/files.ts +71 -0
- package/src/profile/index.ts +76 -0
- package/src/profile/layout.ts +123 -0
- package/src/profile/load.ts +199 -0
- package/src/profile/primitives.ts +45 -0
- package/src/profile/schema.ts +347 -0
- package/src/profile/secret-detection.ts +162 -0
- package/src/profile/targets.ts +152 -0
- package/src/profile/workspace.ts +262 -0
- package/src/providers/custom/index.ts +21 -0
- package/src/providers/custom/load.ts +115 -0
- package/src/providers/custom/template.ts +156 -0
- package/src/providers/example/provider.ts +207 -0
- package/src/providers/google/calendar/index.ts +66 -0
- package/src/providers/google/calendar/redact.ts +40 -0
- package/src/providers/google/contacts/index.ts +50 -0
- package/src/providers/google/contacts/redact.ts +21 -0
- package/src/providers/google/docs/index.ts +45 -0
- package/src/providers/google/drive/hints.ts +28 -0
- package/src/providers/google/drive/index.ts +34 -0
- package/src/providers/google/drive/redact.ts +39 -0
- package/src/providers/google/drive-mcp/index.ts +21 -0
- package/src/providers/google/gmail/api.ts +42 -0
- package/src/providers/google/gmail/attachment.ts +142 -0
- package/src/providers/google/gmail/hints.ts +55 -0
- package/src/providers/google/gmail/index.ts +112 -0
- package/src/providers/google/gmail/redact.ts +56 -0
- package/src/providers/google/gmail/send.ts +365 -0
- package/src/providers/google/gmail-mcp/index.ts +35 -0
- package/src/providers/google/index.ts +10 -0
- package/src/providers/google/shared/oauth.ts +122 -0
- package/src/providers/google/shared/scopes.ts +99 -0
- package/src/providers/google/shared/setup.ts +80 -0
- package/src/providers/google/sheets/hints.ts +45 -0
- package/src/providers/google/sheets/index.ts +70 -0
- package/src/providers/google/sheets/redact.ts +45 -0
- package/src/providers/google/specs/calendar.v3.json +1829 -0
- package/src/providers/google/specs/docs.v1.json +381 -0
- package/src/providers/google/specs/drive.v3.json +2208 -0
- package/src/providers/google/specs/gmail.v1.json +2578 -0
- package/src/providers/google/specs/people.v1.json +506 -0
- package/src/providers/google/specs/sheets.v4.json +1269 -0
- package/src/providers/google/specs/tasks.v1.json +840 -0
- package/src/providers/google/specs/vendor.ts +661 -0
- package/src/providers/google/tasks/index.ts +53 -0
- package/src/providers/google/tasks/redact.ts +34 -0
- package/src/providers/harness.ts +95 -0
- package/src/providers/icloud/calendar/index.ts +27 -0
- package/src/providers/icloud/contacts/index.ts +17 -0
- package/src/providers/icloud/drive/index.ts +47 -0
- package/src/providers/icloud/index.ts +8 -0
- package/src/providers/icloud/mail/index.ts +37 -0
- package/src/providers/icloud/shared/setup.ts +66 -0
- package/src/providers/index.ts +93 -0
- package/src/providers/linear/index.ts +11 -0
- package/src/providers/linear/scopes.ts +7 -0
- package/src/providers/memory/provider.ts +429 -0
- package/src/providers/notion/index.ts +19 -0
- package/src/providers/owner.ts +49 -0
- package/src/providers/scopes.ts +26 -0
- package/src/providers/setup/plan.ts +141 -0
- package/src/providers/setup/provider.ts +323 -0
- package/src/providers/shared/frontmatter.ts +119 -0
- package/src/providers/skills/provider.ts +283 -0
- package/src/providers/skills/store.ts +252 -0
- package/src/providers/vault/provider.ts +194 -0
- package/src/registry/index.ts +36 -0
- package/src/registry/policy-bridge.ts +32 -0
- package/src/registry/reconcile.ts +313 -0
- package/src/registry/registry.ts +240 -0
- package/src/secrets/document.ts +293 -0
- package/src/secrets/index.ts +154 -0
- package/src/secrets/system.ts +173 -0
- package/src/secrets/vault.ts +336 -0
- package/src/server/attachments.ts +197 -0
- package/src/server/container.ts +96 -0
- package/src/server/edge.ts +53 -0
- package/src/server/endpoint.ts +352 -0
- package/src/server/generations.ts +362 -0
- package/src/server/harness.ts +400 -0
- package/src/server/index.ts +331 -0
- package/src/server/logging.ts +41 -0
- package/src/server/mcp/build.ts +68 -0
- package/src/server/mcp/icon.ts +145 -0
- package/src/server/mcp/index.ts +32 -0
- package/src/server/mcp/instructions.ts +245 -0
- package/src/server/mcp/naming.ts +39 -0
- package/src/server/mcp/prompts.ts +78 -0
- package/src/server/mcp/resources.ts +106 -0
- package/src/server/mcp/routing.ts +117 -0
- package/src/server/mcp/schema.ts +78 -0
- package/src/server/mcp/tools.ts +186 -0
- package/src/server/mcp/visibility.ts +132 -0
- package/src/server/oauth.ts +222 -0
- package/src/server/rebinding.ts +53 -0
- package/src/server/stdio.ts +192 -0
- package/src/stores/blobs/conformance.ts +223 -0
- package/src/stores/blobs/index.ts +125 -0
- package/src/stores/blobs/testing.ts +49 -0
- package/src/stores/state/index.ts +247 -0
- package/src/stores/state/keys.ts +68 -0
- package/src/stores/state/testing.ts +41 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { GOOGLE_APP } from './oauth.ts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The walkthrough every Google provider prints before asking for anything.
|
|
5
|
+
*
|
|
6
|
+
* Google requires a pre-registered OAuth client — even for Google's own MCP
|
|
7
|
+
* servers. That is their policy and no architecture avoids it, but it does not
|
|
8
|
+
* follow that *you* have to be the one to register it: since ADR-028 the client
|
|
9
|
+
* Lanes operates is the default, and this walkthrough is what `--own-client`
|
|
10
|
+
* opts into. It stays complete, because the people who need it — an
|
|
11
|
+
* organisation that forbids third-party clients, a Workspace "Internal" app —
|
|
12
|
+
* need all of it.
|
|
13
|
+
*
|
|
14
|
+
* Gmail and Drive share the `google` app, which is why `oauth_apps` exists:
|
|
15
|
+
* every connection of a vendor authorises against the same registered client,
|
|
16
|
+
* and declaring that entry is also how a profile says it has one of its own.
|
|
17
|
+
*/
|
|
18
|
+
export const googleSetup = (
|
|
19
|
+
product: string,
|
|
20
|
+
scopes: readonly string[],
|
|
21
|
+
options: { preview?: boolean; apis?: readonly string[] } = {},
|
|
22
|
+
) => {
|
|
23
|
+
// Which APIs to enable is per product, not global: telling someone connecting
|
|
24
|
+
// Gmail to enable Sheets is advice to grant more than they asked for. Sheets
|
|
25
|
+
// and Docs name Drive as well, because their `identity` block reads
|
|
26
|
+
// `drive/v3/about` — with the Drive API disabled, connecting succeeds and then
|
|
27
|
+
// fails to label the connection.
|
|
28
|
+
const apis =
|
|
29
|
+
options.apis ??
|
|
30
|
+
(options.preview
|
|
31
|
+
? [
|
|
32
|
+
'gmail.googleapis.com',
|
|
33
|
+
'gmailmcp.googleapis.com',
|
|
34
|
+
'drive.googleapis.com',
|
|
35
|
+
'drivemcp.googleapis.com',
|
|
36
|
+
]
|
|
37
|
+
: ['gmail.googleapis.com', 'drive.googleapis.com']);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
summary: `${product} signs in with Google. By default it authorises against the OAuth client Lanes operates, so there is nothing to register and no client secret on this machine — the code is exchanged for a token by the Lanes API, which holds that secret. Pass --own-client to register a client of your own instead; the steps below are that path, asked once per profile and then covering every Google account you connect.`,
|
|
41
|
+
docs: 'docs/detailed/setup/google.md',
|
|
42
|
+
docs_url: 'https://console.cloud.google.com/auth',
|
|
43
|
+
steps: [
|
|
44
|
+
...(options.preview
|
|
45
|
+
? [
|
|
46
|
+
'ENROL IN THE WORKSPACE DEVELOPER PREVIEW FIRST — https://developers.google.com/workspace/preview\n This provider proxies Google\'s MCP server, which is gated behind it. Without enrolment everything below still succeeds — consent is granted, the tool list is returned — and then every single call answers "The caller does not have permission". Enrolment needs a Google Workspace account; a personal @gmail.com cannot enrol, and should use the plain "' +
|
|
47
|
+
product.toLowerCase() +
|
|
48
|
+
'" provider instead, which talks to the REST API and has no gate.',
|
|
49
|
+
]
|
|
50
|
+
: []),
|
|
51
|
+
'Create or pick a project at https://console.cloud.google.com',
|
|
52
|
+
`Enable the APIs:\n gcloud services enable ${apis.join(' ')} --project=YOUR_PROJECT${
|
|
53
|
+
options.preview
|
|
54
|
+
? '\n Note there are TWO per product for the MCP path: the service itself and its separate MCP API. Enabling only one produces a 403 whose explanation is buried in the response body.'
|
|
55
|
+
: ''
|
|
56
|
+
}\n Without gcloud: APIs & Services → Library, and search for each by name.`,
|
|
57
|
+
'The rest is under Google Auth Platform — https://console.cloud.google.com/auth — in this order:',
|
|
58
|
+
' BRANDING — app name and a support email. Seen by nobody but you.',
|
|
59
|
+
' AUDIENCE — User type: EXTERNAL (even with a Workspace domain: "Internal" admits only that one domain, so a mix of personal and Workspace accounts needs External). Add every account you will connect under "Test users". LEAVE the status as "Testing".',
|
|
60
|
+
` DATA ACCESS — where scopes live now. Add:\n ${scopes.join('\n ')}\n Note drive.file is filed under "sensitive" rather than "restricted", so it appears in a different section of that page.`,
|
|
61
|
+
' CLIENTS — Create OAuth client → type: DESKTOP APP. Google\'s docs say "Web application" with a redirect URI for Claude or Antigravity, because they assume the agent host runs the OAuth. Here the CLI does, on a loopback port — which is also why this stays Desktop even when the server runs on Cloud Run.',
|
|
62
|
+
'Copy the client ID and secret — you are asked for them next.',
|
|
63
|
+
'Not publishing is deliberate: these are restricted scopes, and publishing them means Google verification with a CASA assessment taking months. Testing needs none. The cost is that refresh tokens expire after 7 days, so expect to re-run "lanes link connect" weekly — "lanes link doctor" says which are stale.',
|
|
64
|
+
],
|
|
65
|
+
prompts: [
|
|
66
|
+
{
|
|
67
|
+
key: 'client_id',
|
|
68
|
+
label: 'Google OAuth client ID',
|
|
69
|
+
secret: false,
|
|
70
|
+
credential_ref: `${GOOGLE_APP}/client_id`,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: 'client_secret',
|
|
74
|
+
label: 'Google OAuth client secret',
|
|
75
|
+
secret: true,
|
|
76
|
+
credential_ref: `${GOOGLE_APP}/client_secret`,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the Sheets surface stops, and what continues it.
|
|
3
|
+
*
|
|
4
|
+
* Two gaps, both of which read as missing features rather than as boundaries.
|
|
5
|
+
*
|
|
6
|
+
* There is no `spreadsheets.create` here and there will not be: its request
|
|
7
|
+
* body is a whole `Spreadsheet`, which generates a 1,133 KB input schema
|
|
8
|
+
* against a 64 KB budget — the argument is in `specs/vendor.ts`. Creating the
|
|
9
|
+
* file belongs to Drive. Nothing in a tool list says so, and "sheet has no
|
|
10
|
+
* create" is the reasonable conclusion from reading one.
|
|
11
|
+
*
|
|
12
|
+
* And `batchUpdate` is the whole structural-edit surface behind a single
|
|
13
|
+
* `requests` argument that has to stay opaque, because inlining Google's
|
|
14
|
+
* `Request` union costs 2,469 KB. Opaque means the tool cannot enumerate what
|
|
15
|
+
* it does, so the common cases are named here instead.
|
|
16
|
+
*/
|
|
17
|
+
export const SHEETS_HINTS: Record<string, string> = {
|
|
18
|
+
'spreadsheets.batchUpdate': [
|
|
19
|
+
'This is the structural-edit surface: adding, renaming, reordering, and deleting tabs,',
|
|
20
|
+
'plus formatting, frozen rows, filters, and charts.',
|
|
21
|
+
'The `requests` array takes Google\'s `Request` objects — `addSheet` to create a tab,',
|
|
22
|
+
'`updateSheetProperties` to rename one, `deleteSheet` to remove it,',
|
|
23
|
+
'`repeatCell` to format a range. Its structure is omitted from this schema because',
|
|
24
|
+
'inlining the full union costs megabytes; the shapes are at',
|
|
25
|
+
'https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request.',
|
|
26
|
+
'To change cell *values* rather than structure, use the `values_*` tools instead.',
|
|
27
|
+
'To create a whole new spreadsheet file, use `drive_files_create` with',
|
|
28
|
+
'`mimeType: "application/vnd.google-apps.spreadsheet"` — there is no create tool here.',
|
|
29
|
+
].join(' '),
|
|
30
|
+
|
|
31
|
+
// On the read too, because "how do I make one" is asked while looking at the
|
|
32
|
+
// tool that reads one, and this is the only other tool named `spreadsheets.*`
|
|
33
|
+
// that an agent scanning the list is likely to open.
|
|
34
|
+
'spreadsheets.get': [
|
|
35
|
+
'Reads an existing spreadsheet. To create one, use `drive_files_create` with',
|
|
36
|
+
'`mimeType: "application/vnd.google-apps.spreadsheet"`, then write into it with the',
|
|
37
|
+
'`values_*` tools — this provider edits spreadsheets but does not create the file.',
|
|
38
|
+
].join(' '),
|
|
39
|
+
|
|
40
|
+
'spreadsheets.sheets.copyTo': [
|
|
41
|
+
'Copies one tab into a *different* spreadsheet. To duplicate a tab within the same',
|
|
42
|
+
'file use `batchUpdate` with a `duplicateSheet` request, and to copy the whole file',
|
|
43
|
+
'use `drive_files_copy`.',
|
|
44
|
+
].join(' '),
|
|
45
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { defineProvider } from '#connectivity';
|
|
2
|
+
import { DRIVE_IDENTITY, GOOGLE_APP, GOOGLE_OAUTH, specPath } from '../shared/oauth.ts';
|
|
3
|
+
import { googleSetup } from '../shared/setup.ts';
|
|
4
|
+
import { SHEETS_HINTS } from './hints.ts';
|
|
5
|
+
import { SHEETS_REDACT } from './redact.ts';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sheets, because Drive cannot edit a spreadsheet.
|
|
9
|
+
*
|
|
10
|
+
* Drive holds the file and exports a rendering of it; nothing in Drive writes a
|
|
11
|
+
* cell. The nearest thing would be `files.update` with media, which replaces the
|
|
12
|
+
* whole file through import conversion and discards formulas, formatting, tabs,
|
|
13
|
+
* and comments in the process. Cell-level editing exists in exactly one place.
|
|
14
|
+
*
|
|
15
|
+
* Note the `base_url`: Sheets carries its version in the path
|
|
16
|
+
* (`/v4/spreadsheets/...`), where Drive carries it in the host. Copying Drive's
|
|
17
|
+
* shape here yields `/v4/v4/...` and a 404 on every call.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Editing a file someone already has, and why that costs a broad scope.
|
|
22
|
+
*
|
|
23
|
+
* `drive.readonly` and `drive.file` are held already and between them nearly
|
|
24
|
+
* cover this: reads of any spreadsheet accept `drive.readonly`, and every Sheets
|
|
25
|
+
* write accepts `drive.file`. But `drive.file` means *files this app created* —
|
|
26
|
+
* its other half, files the user picks, arrives through the Google Picker, and
|
|
27
|
+
* there is no picker on an MCP endpoint. So under those two scopes an agent can
|
|
28
|
+
* build a spreadsheet and maintain it forever, and cannot touch the one someone
|
|
29
|
+
* made in the browser last week. That second case is the request.
|
|
30
|
+
*
|
|
31
|
+
* `spreadsheets` is the only scope that reaches it, and it is the `gmail.modify`
|
|
32
|
+
* argument again, arriving at the same answer for the same reason: there is no
|
|
33
|
+
* narrower grant that does the job, so the choice is this or the feature. It is
|
|
34
|
+
* marked broad in `../shared/scopes.ts` and should stay marked. What bounds it is
|
|
35
|
+
* what bounds Gmail — the token is wide, the tool surface is eight operations,
|
|
36
|
+
* and `lanes link policy deny` narrows that further.
|
|
37
|
+
*
|
|
38
|
+
* `drive.readonly` stays alongside it. `spreadsheets` alone cannot answer
|
|
39
|
+
* `drive/v3/about`, which is how the connection gets labelled with an address.
|
|
40
|
+
*/
|
|
41
|
+
const SHEETS_SCOPES = [
|
|
42
|
+
'https://www.googleapis.com/auth/drive.readonly',
|
|
43
|
+
'https://www.googleapis.com/auth/drive.file',
|
|
44
|
+
'https://www.googleapis.com/auth/spreadsheets',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export const sheets = defineProvider({
|
|
48
|
+
id: 'sheets',
|
|
49
|
+
name: 'Google Sheets',
|
|
50
|
+
description:
|
|
51
|
+
'Read and edit spreadsheet cells — ranges, appends, and structural changes like tabs, formatting, and frozen rows — via the Sheets REST API.',
|
|
52
|
+
connector: {
|
|
53
|
+
kind: 'http',
|
|
54
|
+
base_url: 'https://sheets.googleapis.com',
|
|
55
|
+
openapi: specPath('sheets.v4.json'),
|
|
56
|
+
},
|
|
57
|
+
auth: {
|
|
58
|
+
kind: 'oauth',
|
|
59
|
+
registration: 'manual',
|
|
60
|
+
app: GOOGLE_APP,
|
|
61
|
+
scopes: SHEETS_SCOPES,
|
|
62
|
+
...GOOGLE_OAUTH,
|
|
63
|
+
},
|
|
64
|
+
identity: DRIVE_IDENTITY,
|
|
65
|
+
setup: googleSetup('Sheets', SHEETS_SCOPES, {
|
|
66
|
+
apis: ['sheets.googleapis.com', 'drive.googleapis.com'],
|
|
67
|
+
}),
|
|
68
|
+
redact: SHEETS_REDACT,
|
|
69
|
+
hints: SHEETS_HINTS,
|
|
70
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifiers and shape, never contents.
|
|
3
|
+
*
|
|
4
|
+
* The split is cleaner here than it was for mail. `values` and `data` hold the
|
|
5
|
+
* cells themselves, and `requests` holds the text of a structural edit — that is
|
|
6
|
+
* the spreadsheet, and withholding it is the whole point of the default. What is
|
|
7
|
+
* kept is where and how: which file, which range, and which write mode, without
|
|
8
|
+
* which a write log records that a spreadsheet changed and not where.
|
|
9
|
+
*
|
|
10
|
+
* Reads are listed too, unlike Gmail's block. Gmail withholds its reads because
|
|
11
|
+
* `q` is a search query and the question is the sensitive part; a Sheets read
|
|
12
|
+
* carries no query, only a file id and an A1 range, so there is nothing there to
|
|
13
|
+
* protect. A range does embed a tab name, which is the user's word — that is the
|
|
14
|
+
* one judgement call, made in favour of an audit log that can distinguish
|
|
15
|
+
* reading a cell from reading the sheet.
|
|
16
|
+
*
|
|
17
|
+
* The two writes take `pathRange`, not `range`. A `ValueRange` body carries a
|
|
18
|
+
* `range` of its own, so the generator prefixes both with where they came from,
|
|
19
|
+
* and the plain name matches neither. This block said `range` until the
|
|
20
|
+
* argument-name check in `cli/tools.test.ts` was written — which meant the one
|
|
21
|
+
* thing these entries exist to record, *where* the sheet was written, was the
|
|
22
|
+
* one thing being withheld. The reads keep the plain name because they have no
|
|
23
|
+
* body to collide with.
|
|
24
|
+
*/
|
|
25
|
+
export const SHEETS_REDACT: Record<string, string[]> = {
|
|
26
|
+
'spreadsheets.get': ['spreadsheetId', 'ranges', 'includeGridData'],
|
|
27
|
+
'spreadsheets.values.get': ['spreadsheetId', 'range', 'majorDimension'],
|
|
28
|
+
'spreadsheets.values.batchGet': ['spreadsheetId', 'ranges', 'majorDimension'],
|
|
29
|
+
'spreadsheets.values.update': ['spreadsheetId', 'pathRange', 'valueInputOption'],
|
|
30
|
+
'spreadsheets.values.batchUpdate': ['spreadsheetId'],
|
|
31
|
+
'spreadsheets.values.append': [
|
|
32
|
+
'spreadsheetId',
|
|
33
|
+
'pathRange',
|
|
34
|
+
'valueInputOption',
|
|
35
|
+
'insertDataOption',
|
|
36
|
+
],
|
|
37
|
+
'spreadsheets.values.clear': ['spreadsheetId', 'range'],
|
|
38
|
+
'spreadsheets.values.batchClear': ['spreadsheetId', 'ranges'],
|
|
39
|
+
// Every argument, because every argument is an identifier: this operation
|
|
40
|
+
// carries no cell contents at all, and the destination file is the one fact
|
|
41
|
+
// an audit log must not lose — a tab copied into the wrong workbook is the
|
|
42
|
+
// failure worth being able to trace.
|
|
43
|
+
'spreadsheets.sheets.copyTo': ['spreadsheetId', 'sheetId', 'destinationSpreadsheetId'],
|
|
44
|
+
'spreadsheets.batchUpdate': ['spreadsheetId'],
|
|
45
|
+
};
|