From fd1b73f9176907b47d56f44245de891810ab7925 Mon Sep 17 00:00:00 2001 From: "A.R" Date: Wed, 24 Sep 2025 21:37:24 +0300 Subject: [PATCH 1/6] @ --- .gitignore | 52 - .vscode-test.mjs | 5 + .vscode/extensions.json | 5 + .vscode/launch.json | 21 + .vscode/settings.json | 13 + .vscode/tasks.json | 64 + .vscodeignore | 14 + CHANGELOG.md | 313 -- README.md | 313 -- esbuild.js | 98 + eslint.config.mjs | 29 + images/gallery-banner.png | Bin 0 -> 380593 bytes images/icon.png | Bin 0 -> 3589 bytes package.json | 25 - pnpm-lock.yaml | 6785 ------------------------------ src/extension.ts | 292 ++ src/test/extension.test.ts | 15 + src/vendor/formula-beautifier.js | 1021 +++++ src/vendor/formula-minifier.js | 659 +++ tsconfig.json | 16 + vsc-extension-quickstart.md | 48 + 21 files changed, 2300 insertions(+), 7488 deletions(-) delete mode 100644 .gitignore create mode 100644 .vscode-test.mjs create mode 100644 .vscode/extensions.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 .vscodeignore delete mode 100644 CHANGELOG.md delete mode 100644 README.md create mode 100644 esbuild.js create mode 100644 eslint.config.mjs create mode 100644 images/gallery-banner.png create mode 100644 images/icon.png delete mode 100644 package.json delete mode 100644 pnpm-lock.yaml create mode 100644 src/extension.ts create mode 100644 src/test/extension.test.ts create mode 100644 src/vendor/formula-beautifier.js create mode 100644 src/vendor/formula-minifier.js create mode 100644 tsconfig.json create mode 100644 vsc-extension-quickstart.md diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 8b6fd9f..0000000 --- a/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# ============================================================ -# WHITELIST .gitignore -# Ignore everything, then allow only public project files. -# New files are private-by-default — you must opt-in below. -# ============================================================ - -# 1. Ignore everything -* - -# 2. Allow top-level config & docs -!.gitignore -!.npmrc -!package.json -!pnpm-lock.yaml -!pnpm-workspace.yaml -!README.md -!CHANGELOG.md -!LICENSE -!glama.json - -# 4. Allow GitHub config -!.github/ -!.github/** - -# 4. Allow scripts -!scripts/ -!scripts/** - -# 5. Allow packages directory structure -!packages/ -!packages/extension/ -!packages/extension/** -!packages/language-services/ -!packages/language-services/** -!packages/lsp-server/ -!packages/lsp-server/** -!packages/mcp-server/ -!packages/mcp-server/** -!packages/shared/ -!packages/shared/** -!packages/webview/ -!packages/webview/** - -# 6. Re-ignore planning directory, build artifacts, deps & private files inside allowed dirs -.planning/ -**/node_modules/ -**/dist/ -*.vsix -**/PLAN.md -packages/mcp-server/.chrome-profile/ -packages/mcp-server/dev-tools/ -packages/extension/README.md \ No newline at end of file diff --git a/.vscode-test.mjs b/.vscode-test.mjs new file mode 100644 index 0000000..b62ba25 --- /dev/null +++ b/.vscode-test.mjs @@ -0,0 +1,5 @@ +import { defineConfig } from '@vscode/test-cli'; + +export default defineConfig({ + files: 'out/test/**/*.test.js', +}); diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..d7a3ca1 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": ["dbaeumer.vscode-eslint", "connor4312.esbuild-problem-matchers", "ms-vscode.extension-test-runner"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c42edc0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "${defaultBuildTask}" + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5c5ac48 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "out": false, // set this to true to hide the "out" folder with the compiled JS files + "dist": false // set this to true to hide the "dist" folder with the compiled JS files + }, + "search.exclude": { + "out": true, // set this to false to include "out" folder in search results + "dist": true // set this to false to include "dist" folder in search results + }, + // Turn off tsc task auto detection since we have the necessary tasks as npm scripts + "typescript.tsc.autoDetect": "off" +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..3cf99c3 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,64 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "2.0.0", + "tasks": [ + { + "label": "watch", + "dependsOn": [ + "npm: watch:tsc", + "npm: watch:esbuild" + ], + "presentation": { + "reveal": "never" + }, + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "type": "npm", + "script": "watch:esbuild", + "group": "build", + "problemMatcher": "$esbuild-watch", + "isBackground": true, + "label": "npm: watch:esbuild", + "presentation": { + "group": "watch", + "reveal": "never" + } + }, + { + "type": "npm", + "script": "watch:tsc", + "group": "build", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "label": "npm: watch:tsc", + "presentation": { + "group": "watch", + "reveal": "never" + } + }, + { + "type": "npm", + "script": "watch-tests", + "problemMatcher": "$tsc-watch", + "isBackground": true, + "presentation": { + "reveal": "never", + "group": "watchers" + }, + "group": "build" + }, + { + "label": "tasks: watch-tests", + "dependsOn": [ + "npm: watch", + "npm: watch-tests" + ], + "problemMatcher": [] + } + ] +} diff --git a/.vscodeignore b/.vscodeignore new file mode 100644 index 0000000..159277f --- /dev/null +++ b/.vscodeignore @@ -0,0 +1,14 @@ +.vscode/** +.vscode-test/** +out/** +node_modules/** +src/** +.gitignore +.yarnrc +esbuild.js +vsc-extension-quickstart.md +**/tsconfig.json +**/eslint.config.mjs +**/*.map +**/*.ts +**/.vscode-test.* diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index c60b4cd..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,313 +0,0 @@ -# Change Log - -All notable changes to the "airtable-formula" extension will be documented in this file. - -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. - -## [Unreleased] - -### MCP Server 2.5.0 — Record Templates (9 new tools) + round-4 user-report fixes (2026-05-01) - -Promotes record templates to a first-class MCP capability. Templates are -the saved row scaffolds that Airtable surfaces under the "+ Add record" -flyout and inside the row-create extension — previously not addressable -through any public or internal API client we had. Discovered by capturing -the rowTemplate endpoints with `pnpm capture:cdp:mutations` while the -reporter exercised every template UI path. - -**New tools (9):** - -| Tool | Category | Purpose | -|:-----|:---------|:--------| -| `list_record_templates` | read | List record templates for a table | -| `create_record_template` | table-write | Create a template (client-side `rtp...` ID like view sections use `vsc...`) | -| `rename_record_template` | table-write | Rename a template | -| `update_record_template_description` | table-write | Set or clear a template's description | -| `set_record_template_cell` | table-write | Set a cell value in a template (static, linked rows, or linked templates) | -| `set_record_template_visible_columns` | table-write | Choose which columns the template surfaces in its UI | -| `duplicate_record_template` | table-write | Clone an existing template | -| `apply_record_template` | table-write | Apply a template — creates a new record using the template's cell defaults | -| `delete_record_template` | table-destructive | Delete a template | - -**Round-4 fixes (carried into 2.5.0 from interim 2.4.4 work):** - -- `set_view_columns` now filters the primary column out of the move step - before calling `moveVisibleColumns` — Airtable rejects any move that - displaces the pinned primary at index 0. -- `reorder_view_fields` `mergePartialFieldOrder` protects the primary - column at index 0; user-requested moves to index 0 are clamped to 1. -- `update_view_group_levels` always sends `emptyGroupState: 'hidden'`; - Airtable's API rejects `'visible'` with INVALID_REQUEST. -- `list_tables` now reads `data.tableById` as a fallback when - `tableSchemas` / `tables` / `tableDatas` are absent (matches the shape - the reporter saw). -- `update_view_filters` `isWithin` corrected: requires `timeZone` (IANA) - and `shouldUseCorrectTimeZoneForFormulaicColumn: true`, no `exactDate`, - modes are `thisCalendarMonth` / `thisCalendarYear` (not `thisMonth` / - `thisYear`). Tool description and AI skill template updated. - -**Counts:** 52 → **61 tools**. `read-only` profile: 8 → 9. `safe-write` -profile: 39 → 47. `full` profile: 52 → 61. - -mcp-server: 2.4.4 → 2.5.0. - -### MCP Server 2.4.3 — `list_view_sections` full fix (carry-over from 2.4.2) - -Probed the schema read response with a fresh patchright session against -a base that has sections (`packages/mcp-server/dev-tools/debug-sections.js`, -new `pnpm probe:sections` script). Found that sidebar sections live at -`data.tableSchemas[N].viewSectionsById` — NOT `viewSections` like the -WebSocket realtime delta model uses. 2.4.0 + 2.4.1 read the wrong key, -which is why the sections array came back empty. - -`listViewSections` now reads from `viewSectionsById` first, falls back -to `viewSections` for fixture/test compatibility, falls back to the -2.4.2 ID-only-from-tableViewOrder path if both are absent. The rich -shape (`name`, `viewOrder`, `pinnedForUserId`, `createdByUserId`) is -fully restored on real bases. - -mcp-server: 2.4.2 → 2.4.3. - -### MCP Server 2.4.2 — User follow-up bugs (report 2026-05-01) - -After upgrading to 2.4.0 and running real end-to-end view-rollout work, -the reporter surfaced two bugs in the new tooling. Both fixed here. - -**Bug 1 — `set_view_columns` orchestration 422'd at the move step** (P1). -The internal step 3 looped per-id `moveVisibleColumns([id], i)` starting -at index 0. That fails reliably because grid views pin the primary -column at visible index 0 (you can't move anything else there) and -per-id moves of an already-correctly-positioned column also fail. -Steps 1 and 2 (hide-all + show-the-set) succeeded, so visibility was -correct but column order was untouched. - -Fix: replace the loop with one batched `moveVisibleColumns(visibleColumnIds, 1)` -call — the entire ordered list is inserted starting at visible index 1, -after the pinned primary. Verified by the reporter's workaround snippet -on 11 grid views (100% success rate). Test updated to match. - -**Bug 2 — `list_view_sections` returned empty `sections`** (P2, partial fix). -On the reporter's base, `table.viewSections` is absent from the cached -`application/{appId}/read` response even when `tableViewOrder` clearly -contains `vsc...` IDs. The full fix needs a network capture from a base -with sections to discover where the section objects actually live in -the schema response (none of our existing captures cover this — they -were either mutations-only or pre-section). - -Partial fix shipped here: when `viewSections` is empty but -`tableViewOrder` contains `vsc...` IDs, surface them as bare-id entries -with `name: null`, `viewOrder: null`, `partial: true`, and a top-level -`introspectionPartial: true` flag with a `introspectionNote` explaining -the limitation. The agent at least knows which section IDs exist and -can pass them to `move_view_to_section` / `rename_view_section` / -`delete_view_section` (all of which still work for side effects). - -mcp-server: 2.4.1 → 2.4.2. - -### MCP Server 2.4.1 — Hotfix: bundled server crashed on startup - -Released hours after 2.4.0. The bundled extension copy of the MCP -server crashed immediately on every spawn with `MODULE_NOT_FOUND` for -`../package.json`, surfacing in MCP clients as `transport error: -transport closed`. No tool ever ran from the bundled launcher. - -Root cause: `index.js` resolved its own version with -`require('../package.json')`. That works when running from source -(`packages/mcp-server/src/index.js` → `packages/mcp-server/package.json`) -but fails when bundled to `packages/extension/dist/mcp/index.mjs` — -`../package.json` resolves to a non-existent -`packages/extension/dist/package.json`. - -Fix: read `version.json` (which `bundle-mcp.mjs` writes alongside the -bundle) first, fall back to `../package.json` for source/npx runs, fall -back to `'unknown'` if both fail. Verified end-to-end against the bundled -launcher with a real `initialize` handshake. - -Anyone whose MCP entries pointed at the bundled launcher -(`~/.airtable-user-mcp/start.mjs` → `dist/mcp/index.mjs`) was affected. -Standalone npx runs (`npx -y airtable-user-mcp`) were not — that path -keeps `package.json` adjacent. mcp-server: 2.4.0 → 2.4.1. - -### MCP Server 2.4.0 — Sidebar sections, view setup, non-grid metadata, user-report bug fixes (user report 2026-04-30) - -**16 net-new tools (52 total, was 36).** All endpoints captured against Airtable's internal API on 2026-04-30 with `pnpm capture:cdp:mutations`. - -#### New features (user report §1.3, §1.4, §3.1) - -**View sections (sidebar grouping) — new `view-section` category, defaults on in `safe-write`:** -- `list_view_sections` — read all sections in a table with their view membership and the table-level mixed `viewOrder` (mixes view IDs and section IDs) -- `create_view_section` — generate a `vsc...` ID and create a section -- `rename_view_section` — change a section's name -- `move_view_to_section` — single tool covering four user actions: move view INTO section, move view OUT to ungrouped, reorder sections among each other, reorder views within a section. Maps to one Airtable endpoint (`moveViewOrViewSection`) -- `delete_view_section` — destroy a section. Verified behavior: views inside the section are NOT deleted — Airtable auto-promotes them into the table-level `viewOrder` at the position the section used to occupy. Lives in the new `view-section-destructive` category, gated to `full` profile - -**View column setup — extend `view-write`:** -- `set_view_columns` — one-shot tool that hides every column, shows only `visibleColumnIds`, places them in left-to-right order, and optionally sets `frozenColumnCount`. Solves the user report's §1.4 "new views show all 168 fields, unusable until manually trimmed" problem in a single call -- `show_or_hide_all_columns` — bulk on/off. Closes the §3.2 doc-promised-but-missing tool -- `move_visible_columns` — move columns to a target index in the *visible-only* ordering -- `move_overall_columns` — same, but in the *overall* (visible + hidden) ordering. Distinct from existing `reorder_view_fields` (which writes the full map) and from `move_visible_columns` (different index space) -- `update_frozen_column_count` — set the frozen-column divider position - -**View presentation (Kanban / Gallery / Calendar) — extend `view-write`:** -- `set_view_cover` — set or clear the cover-image field and choose `fit` vs `crop`. Same endpoints work for both Kanban and Gallery (verified) -- `set_view_color_config` — apply a color config. Currently supports `type: "selectColumn"` (cards colored by a single-select field's choice colors); other types pass through for forward compatibility -- `set_view_cell_wrap` — toggle whether long values wrap (multi-line) or truncate (single-line) -- `set_calendar_date_columns` — set `dateColumnRanges`. Each entry is `{ startColumnId }` for single-point events or `{ startColumnId, endColumnId }` for ranges; the array form lets a Calendar overlay multiple date series at once - -**Form metadata (legacy form views only) — new `form-write` category, opt-in (gated to `full` profile since changes are visible to anyone with the form URL):** -- `set_form_metadata` — bundled tool that fans out to atomic Airtable endpoints for `description`, `afterSubmitMessage`, `redirectUrl`, `refreshAfterSubmit`, `shouldAllowRequestCopyOfResponse`, `shouldAttributeResponses`, `isAirtableBrandingRemoved`. Unset properties are not touched -- `set_form_submission_notification` — per-user email-on-submit toggle (separate because it's per-user, not per-form) - -Note on builder forms: Airtable's "Interfaces" / page-based forms (`page/{pageId}/*` endpoints, layout-engine element trees) are intentionally out of scope — they're a separate product surface that warrants a dedicated tool family. Filed as a follow-up. - -**Categories now in `safe-write`:** `read`, `table-write`, `field-write`, `view-write`, `view-section`. Categories opt-in only via `full` or `custom`: `*-destructive`, `view-section-destructive`, `form-write`, `extension`. - -#### Bug fixes (user report §1.2, §2.x, §4.3) - -- **`isEmpty` / `isNotEmpty` on text + formula(text) + lookup/rollup(text) fields** — auto-rewritten to `=` / `!=` `""` before sending. The internal API rejects the documented operators with `FAILED_STATE_CHECK` on these field types; the rewrite happens client-side using the cached table schema (§2.1, §2.2) -- **`isEmpty` / `isNotEmpty` on linked-record (foreignKey) fields** — now throws a clear error pointing at the helper-formula workaround instead of letting Airtable's opaque `422` through (§2.3) -- **3-level nested filter rejection** — `updateViewFilters` errors now annotate the depth, the leaf operators that failed, and the recommended flatten pattern (`(A AND B) OR (A AND C)` instead of `A AND (B OR C)`) (§2.4, §2.5) -- **`reorder_view_fields` accepts partial maps** — pass only the field IDs you want to move; the tool reads the current `columnOrder`, applies moves in ascending target-position order, and sends the complete map. Avoids the `FAILED_STATE_CHECK` Airtable's internal API returns for single-key payloads (§2.6) -- **`manage_tools` discoverability** — `ListTools` response now includes a dynamic description on `manage_tools` listing every tool hidden by the active profile (e.g. `delete_table` / `delete_field` / `delete_view` in `safe-write`). `get_tool_status` also returns a `disabledByCategory` summary so an LLM can show the user what to enable (root-cause behind §1.2 — the delete tools always existed, they were just filtered) -- **Tool docstring audit** — corrected `update_view_filters`, `show_or_hide_view_columns`, and `reorder_view_fields` descriptions to match actual behavior (§4.3) - -### Fixed (Audit Round 3) -- **Formatter version setting was inert** — Dashboard's "Formatter version" dropdown now actually switches engines. Extension consolidated on `airtableFormula.formula.formatterVersion` and reads this key from all four load sites; legacy `beautifierVersion` / `minifierVersion` remain as fallback for user settings migrated from prior versions -- **Browser-choice changes didn't propagate to IDE MCP configs** — Selecting a different browser (or picking a custom path) now re-writes the MCP entry for every already-configured IDE, so the new `AIRTABLE_BROWSER_CHANNEL` / `AIRTABLE_BROWSER_PATH` env vars take effect immediately instead of staying stale until the next Setup -- **Toggle MCP Tool Category command couldn't toggle table categories** — Added `tableWrite` and `tableDestructive` to the command palette quick-pick; also fixed mis-mapped `fieldWrite` / `viewWrite` file keys that were breaking the label and tool-count display for those rows -- **Formatter commands missing from command palette** — `beautify`, `minify`, `beautifyWithStyle`, `minifyWithLevel`, and `formatWithPreset` are now contributed in `package.json`, with `.formula` language enablement. `beautifyFile` / `minifyFile` added to the explorer context menu for `.formula` files -- **Webview action cards weren't keyboard-accessible** — All clickable `.action-card` divs are now `