Skip to content
Merged
Show file tree
Hide file tree
Changes from 183 commits
Commits
Show all changes
257 commits
Select commit Hold shift + click to select a range
52f1a87
refactor(mcp): correct update_records idempotency hint + clarify reco…
ARHAEEM Jun 15, 2026
3ac79e5
chore(tool-sync): register record-write tools across mirror + counts
ARHAEEM Jun 15, 2026
8d2b2b9
feat(mcp): gate record deletes behind new record-destructive category…
ARHAEEM Jun 16, 2026
66268f8
test(mcp): cover viewId fallback, id guards, and attachment soft-fail…
ARHAEEM Jun 16, 2026
eec14e8
feat(sync): add schema snapshot/normalize for plan engine
ARHAEEM Jun 16, 2026
71900d5
feat(sync): add idmap name-matching + sync-state persistence
ARHAEEM Jun 16, 2026
cf01096
feat(sync): add computed-field canonicalization for ref-stable diffing
ARHAEEM Jun 16, 2026
0f4ff23
chore(mcp): recurse test glob to include test/sync suites
ARHAEEM Jun 16, 2026
019e24c
feat(sync): add schema diff -> ordered plan (create/update/orphan, re…
ARHAEEM Jun 16, 2026
0a9444b
fix(sync): canonical typeOptions diff for computed fields + ordering …
ARHAEEM Jun 16, 2026
168ce62
feat(sync): add plan report + orchestrator with dest fingerprint
ARHAEEM Jun 16, 2026
679868b
feat(mcp): add sync_base tool (mode=plan) in new sync category
ARHAEEM Jun 16, 2026
b645f2c
chore(tool-sync): register sync category + sync_base across mirror + …
ARHAEEM Jun 16, 2026
0532e5b
feat(sync): capture link foreign-table deps + document source-id cont…
ARHAEEM Jun 16, 2026
a72b4ac
feat(sync): carry sourcePrimaryFieldId + field description in plan ac…
ARHAEEM Jun 16, 2026
9b2faa9
feat(sync): add remapRefs source->dest rewrite + writable computed op…
ARHAEEM Jun 16, 2026
dc141ef
test(sync): lock brace-aware remapRefs (string-literal safety)
ARHAEEM Jun 16, 2026
dad6371
feat(sync): add resumable apply journal + loadPlan
ARHAEEM Jun 16, 2026
e4b9388
test(sync): add deterministic stateful mock client for apply tests
ARHAEEM Jun 16, 2026
17686d0
feat(sync): apply skeleton -- createTable (scaffolding-delete) + prim…
ARHAEEM Jun 16, 2026
8e69e3f
feat(sync): apply scalar createField with existence-skip idempotency
ARHAEEM Jun 16, 2026
b64fec8
feat(sync): apply computed createField -- writable shape, validate, s…
ARHAEEM Jun 16, 2026
1d0dd90
feat(sync): apply foreignKey link createField with reciprocal-once ad…
ARHAEEM Jun 16, 2026
87fccdb
feat(sync): apply updateField -- safe changes, select-merge, retype d…
ARHAEEM Jun 16, 2026
a91a538
test(sync): prove apply journal-resume + run-twice idempotency
ARHAEEM Jun 16, 2026
f3f364c
feat(sync): apply orchestrator with drift guard + journal/idmap persi…
ARHAEEM Jun 16, 2026
384b0e6
feat(mcp): sync_base mode=apply (execute saved plan, drift-guarded)
ARHAEEM Jun 16, 2026
f9e666a
docs(sync): document sync_base mode=apply across CLAUDE.md, CHANGELOG…
ARHAEEM Jun 16, 2026
a6ba2a4
fix(sync): skip computed field with unresolvable refs instead of halt…
ARHAEEM Jun 16, 2026
4fac816
fix(sync): apply updateField computed writable shape + continue-on-fa…
ARHAEEM Jun 16, 2026
cc7e7d9
fix(sync): converge plan — select choices are superset-equal, skip em…
ARHAEEM Jun 16, 2026
0c3ed54
feat(sync): add remapViewConfig + canonicalizeViewConfig for view sync
ARHAEEM Jun 16, 2026
e9bd5b2
feat(sync): snapshot collaborative views + live config (sortSet unwra…
ARHAEEM Jun 16, 2026
2596d41
feat(sync): match collaborative views by name in idmap
ARHAEEM Jun 16, 2026
c420b3b
feat(sync): diff emits createView + applyViewConfig (convergent, afte…
ARHAEEM Jun 16, 2026
9f2b909
feat(sync): apply createView (adopt-by-name) + mock view state
ARHAEEM Jun 16, 2026
9a85799
fix(sync): createTable index entry includes viewsByName so same-run c…
ARHAEEM Jun 16, 2026
4d17b2d
feat(sync): apply applyViewConfig -- facets, anchor validation (kanba…
ARHAEEM Jun 16, 2026
a5bbc73
feat(sync): view-aware fingerprint + count view actions in plan report
ARHAEEM Jun 16, 2026
ba4179a
docs(sync): document collaborative view sync in sync_base
ARHAEEM Jun 16, 2026
814e61a
fix(client): setViewColumns verify-readback + retry (bulk under-apply…
ARHAEEM Jun 16, 2026
f434620
fix(sync): converge view columns -- canonical compares visible order …
ARHAEEM Jun 17, 2026
fe9b032
fix(sync): converge view columns on visible/hidden SET, not order (or…
ARHAEEM Jun 17, 2026
a0172af
fix(sync): exclude record-based colorConfig (colorDefinitions) from v…
ARHAEEM Jun 17, 2026
5295e49
fix(sync): clear stray dest view facets source lacks (filters/sorts/g…
ARHAEEM Jun 17, 2026
c96e192
fix(sync): strip+report record-referencing view filters (no dangling …
ARHAEEM Jun 17, 2026
7bb4974
feat(sync): record snapshot via queryRecords summary.rows
ARHAEEM Jun 17, 2026
7977d00
feat(sync): persist records map in idmap
ARHAEEM Jun 17, 2026
695e041
feat(sync): cells.js pass-1 scalar/select coercion + writable gate
ARHAEEM Jun 17, 2026
9d75144
feat(sync): cells.js link partition (resolved/unresolved)
ARHAEEM Jun 17, 2026
a0f14fa
feat(sync): ratelimit token-bucket + transient retry
ARHAEEM Jun 17, 2026
0ec4768
feat(sync): records journal file (distinct from schema journal)
ARHAEEM Jun 17, 2026
d1d9f2b
fix(test): expand records-journal test — distinct filename, env clean…
ARHAEEM Jun 17, 2026
3283b80
feat(sync): records Pass 1 (scalar/select upsert + fill record map)
ARHAEEM Jun 17, 2026
90009f4
feat(sync): records Pass 2 link cells via addLinkItems (idempotent)
ARHAEEM Jun 17, 2026
0290dc0
fix(sync): harden link-cell shape handling in records Pass 1 & 2
ARHAEEM Jun 17, 2026
02ce8f1
feat(sync): record attachments (download/upload/verify/dedupe, non-bl…
ARHAEEM Jun 17, 2026
ecab2db
feat(sync): reapplyViewFilters — remap record-ref filters once record…
ARHAEEM Jun 17, 2026
950db47
feat(sync): wire records phase into apply + reconcile mode + pre-flight
ARHAEEM Jun 17, 2026
96d21f9
feat(sync): sync_base mode=reconcile; apply now syncs records; record…
ARHAEEM Jun 17, 2026
b7d5788
fix(auth): bound session init/recovery with a timeout (records apply …
ARHAEEM Jun 17, 2026
78a254d
perf(sync): records phase uses schema-only snapshot (eliminate getVie…
ARHAEEM Jun 17, 2026
9a46f27
feat(sync): run the records phase as a background job (non-blocking a…
ARHAEEM Jun 17, 2026
0038d4a
docs(sync): document M3-records (background record sync, mode=status,…
ARHAEEM Jun 17, 2026
6c191e1
fix(sync): final-review fixes — preserve records map across applies (…
ARHAEEM Jun 17, 2026
88a0c19
feat(sync): server-side cross-base attachment copy (fast-path)
ARHAEEM Jun 17, 2026
8a55c9d
fix(auth): circuit-breaker for a dead session (stop the 403→recover→4…
ARHAEEM Jun 17, 2026
9dca92b
fix(auth): back off on 403/429 (don't relaunch) — stop amplifying the…
ARHAEEM Jun 18, 2026
44e5248
feat(sync): fold resolvable links into row/create (kills most of Pass 2)
ARHAEEM Jun 18, 2026
cd15864
feat(sync): proactively pace the records phase under ~5 req/s
ARHAEEM Jun 18, 2026
8c81b55
fix(sync): pace records POSTs via a phase-local gate, not the shared …
ARHAEEM Jun 18, 2026
8934a05
feat(sync): AIRTABLE_SYNC_RPS knob for the records-phase limiter
ARHAEEM Jun 18, 2026
dce82e2
feat(sync): capture view sections in normalizeSchema (no extra API call)
ARHAEEM Jun 19, 2026
1111950
feat(sync): compare.js classification map
ARHAEEM Jun 19, 2026
0275d26
feat(sync): compareFields with drift + best-effort field order
ARHAEEM Jun 19, 2026
18f3647
fix(sync): compareFields — guard choices on type-match; track matched…
ARHAEEM Jun 19, 2026
63ea942
feat(sync): compareTable/Views incl. sections + order
ARHAEEM Jun 19, 2026
77ae232
test(sync): pin frozen/rowHeight DiffEntry contract; document sort-or…
ARHAEEM Jun 19, 2026
ec22fe4
feat(sync): top-level compare() + identical/converged verdicts
ARHAEEM Jun 19, 2026
e69f2d3
fix(sync): converged must account for onlyInSource (missing) items, n…
ARHAEEM Jun 19, 2026
837f6a8
feat(sync): saveDiff/loadDiff/latestDiffId
ARHAEEM Jun 19, 2026
c768a67
feat(sync): renderDiff digest + drill-in
ARHAEEM Jun 19, 2026
96a6b35
feat(sync): add diff() + diffDetail() engine functions
ARHAEEM Jun 19, 2026
15559b0
feat(sync): sync_base mode=diff (digest + detail drill-in)
ARHAEEM Jun 19, 2026
4b6edf2
feat(sync): stable changeId + class + apply flag on plan actions
ARHAEEM Jun 19, 2026
bd0cab5
feat(sync): changeset digest + direction in plan()
ARHAEEM Jun 19, 2026
997ab90
feat(sync): journal-safe selective apply (skip-list + apply:false)
ARHAEEM Jun 19, 2026
c7098fc
feat(sync): thread skip-list through apply() + sync_base
ARHAEEM Jun 19, 2026
06f970a
docs(sync): compare/changeset/selective-apply
ARHAEEM Jun 19, 2026
b05f0ac
chore(sync): drop dead import; document to-source apply base-swap
ARHAEEM Jun 19, 2026
7c96c75
fix(sync): compare canonicalizes cross-base computed/link refs (no fa…
ARHAEEM Jun 19, 2026
7754291
fix(sync): strip read-only maxUsedAutoNumber so autoNumber fields create
ARHAEEM Jun 19, 2026
3fe3de5
fix(sync): count fields emit internal relationColumnId (not public re…
ARHAEEM Jun 19, 2026
818ba6c
docs(sync): changelog — autoNumber + count field-create fixes
ARHAEEM Jun 19, 2026
c871bb4
fix(sync): canonicalize empty-predicate filter operators (no false vi…
ARHAEEM Jun 19, 2026
c52118e
fix(sync): delete createTable scaffolding rows for a clean mirror
ARHAEEM Jun 20, 2026
0360193
docs(sync): changelog — createTable scaffolding-row cleanup
ARHAEEM Jun 20, 2026
5790df3
feat(sync): policy presets + resolvePolicy + isDeleting
ARHAEEM Jun 20, 2026
ddf069a
feat(sync): validateFieldMappings (fail-fast, 6 codes) + resolve to f…
ARHAEEM Jun 20, 2026
7cf8eeb
fix(sync): add multipleSelects to ARRAY_SOURCE_TYPES hardening
ARHAEEM Jun 20, 2026
02a0321
feat(sync): coerceMappedValue — scalar source->dest injection
ARHAEEM Jun 20, 2026
6e50a8f
feat(sync): Pass1 honors conflict policy (dest-wins preserves dest ed…
ARHAEEM Jun 20, 2026
f57539c
feat(sync): Pass1 injects resolved field mappings (source value -> de…
ARHAEEM Jun 20, 2026
dd20332
feat(sync): pruneRecords — delete dest-only orphans under mirror (gated)
ARHAEEM Jun 20, 2026
a87c337
fix(sync): result accumulator guards in pruneRecords
ARHAEEM Jun 20, 2026
bb54df6
feat(sync): runRecords core — pre-flight mapping validation + prune; …
ARHAEEM Jun 20, 2026
e046ad4
fix(sync): surface deleted in records job-status + relocate applyReco…
ARHAEEM Jun 20, 2026
af8a7f1
feat(sync): sync_base policy/fieldMappings params + plan-mode mapping…
ARHAEEM Jun 20, 2026
450cef6
fix(sync): synchronous fieldMappings pre-flight in apply() + dead DEL…
ARHAEEM Jun 20, 2026
0fefde6
docs(sync): document reconciliation policy + custom field mappings
ARHAEEM Jun 20, 2026
03ed538
fix(docs): clarify createTable scaffolding-row clearing is unconditional
ARHAEEM Jun 20, 2026
ab1fd2f
fix(sync): pruneRecords — snapshot-derived orphan detection, M3 scopi…
ARHAEEM Jun 20, 2026
772df21
chore: WIP auth/daemon/webview changes (separated from records-policy)
ARHAEEM Jun 20, 2026
80aa327
feat(sync): matchByNaturalKeys — add-only, ambiguity-safe record matc…
ARHAEEM Jun 21, 2026
0ff6d60
feat(sync): reconcile performs natural-key matching (removes stub)
ARHAEEM Jun 21, 2026
0d1e26b
feat(sync): runRecords natural-key pre-pass + thread naturalKeys thro…
ARHAEEM Jun 21, 2026
fa8a57e
feat(sync): sync_base passes naturalKeys to apply + surfaces matched …
ARHAEEM Jun 21, 2026
3f912d5
docs(sync): document natural-key record matching
ARHAEEM Jun 21, 2026
3418339
docs: fix accuracy (reconcile natural-key stale text + add naturalKey…
ARHAEEM Jun 21, 2026
059e1cb
docs: fix stale comment on reconcile natural-key matching
ARHAEEM Jun 21, 2026
6c433cf
feat(sync): pruneSchema — delete dest-only fields/views/tables under …
ARHAEEM Jun 21, 2026
e4e3fcc
feat(sync): apply() runs pruneSchema after applyPlan (threads confirm…
ARHAEEM Jun 21, 2026
0606069
feat(sync): sync_base confirmTableDeletions param + surface schema-de…
ARHAEEM Jun 21, 2026
bc29bd8
docs(sync): document schema-orphan deletion under mirror
ARHAEEM Jun 21, 2026
87b1e05
docs(changelog): fix stale deferred-follow-ups sentence
ARHAEEM Jun 21, 2026
40d5643
fix(sync): guard pruneSchema with aborted check
ARHAEEM Jun 21, 2026
5e5860f
feat(sync): apply scalar field retypes under confirmRetypes (was RETY…
ARHAEEM Jun 21, 2026
2f3c500
feat(sync): sync_base confirmRetypes param + surface retyped count
ARHAEEM Jun 21, 2026
3c0fe98
docs(sync): document scalar field retypes under confirmRetypes
ARHAEEM Jun 21, 2026
2d9e397
fix(sync): pruneRecords skips truncated tables (>1000 rows) to preven…
ARHAEEM Jun 21, 2026
505125f
feat(sync): runRecords flags truncated tables + warns; thread guard i…
ARHAEEM Jun 21, 2026
27d4682
feat(sync): capture view-section id in snapshot; compare sections by …
ARHAEEM Jun 21, 2026
81d59a1
feat(sync): delete dest-only view-section orphans under mirror (prune…
ARHAEEM Jun 21, 2026
a34996e
docs(sync): prune-schema header comment lists sections + deletion order
ARHAEEM Jun 21, 2026
70f308d
fix(security): stop logging CSRF token prefix; drop daemon port from …
ARHAEEM Jun 22, 2026
7ea117f
fix(sync): recognize INTERNAL array type spellings in cells + fieldMa…
ARHAEEM Jul 4, 2026
50bfe7b
fix(sync): preserve persisted idmap.records/attachments across plan/diff
ARHAEEM Jul 4, 2026
fbaefab
fix(sync): defer ALL array-shaped cells on the Pass-1 update path
ARHAEEM Jul 4, 2026
24b9b0f
fix(sync): guard mode=apply with a per-pair lock file
ARHAEEM Jul 4, 2026
ac370e0
fix(sync): use escaped separator in arrayCellEquals (drop raw NUL byte)
ARHAEEM Jul 4, 2026
fc00f3d
fix(sync): make journal resume reachable past the drift guard
ARHAEEM Jul 4, 2026
3537158
fix(sync): propagate cells cleared on source as explicit nulls (sourc…
ARHAEEM Jul 4, 2026
385547c
fix(sync): harden apply engine — exact reverse-link adoption, retryab…
ARHAEEM Jul 4, 2026
a7b9d27
fix(sync): skip update rows with an empty cell map
ARHAEEM Jul 4, 2026
571f002
fix(sync): compare matched link fields canonically — no phantom updat…
ARHAEEM Jul 4, 2026
1205974
fix(sync): compare writable display-format options on computed fields
ARHAEEM Jul 4, 2026
dd9a0aa
fix(sync): pass collaborator usr ids through view-filter remap verbatim
ARHAEEM Jul 4, 2026
8d34ab3
fix(sync): match views by (name, type) — cross-type same-name views a…
ARHAEEM Jul 4, 2026
79ba83d
fix(sync): never emit the dest primary field as a deletable orphan
ARHAEEM Jul 4, 2026
f2cce19
fix(sync): guard reconcile existence-prune against truncated dest sna…
ARHAEEM Jul 4, 2026
cef92c5
fix(sync): truncation detection counts fetched rows, not folded synth…
ARHAEEM Jul 4, 2026
81009ad
fix(sync): mirror prune propagates source record deletions (stale idm…
ARHAEEM Jul 4, 2026
f98710c
fix(sync): Pass 2 links + Pass 3 attachments honor conflicts=dest-wins
ARHAEEM Jul 4, 2026
3004f7d
fix(sync): scope attachment-fallback dedupe key to the destination cell
ARHAEEM Jul 4, 2026
bcf2c72
fix(sync): filter restore survives per-view getView failures; never b…
ARHAEEM Jul 4, 2026
fb15ffc
fix(sync): record snapshots avoid filtered views; partial reads block…
ARHAEEM Jul 4, 2026
b08f1ea
fix(sync): mode=status detects a records job whose process died mid-run
ARHAEEM Jul 4, 2026
8d80a98
fix(sync): createField registers the real select choice map for the s…
ARHAEEM Jul 4, 2026
de9f9b5
fix(sync): records seams — computed-dest clear skip, resume-durable c…
ARHAEEM Jul 4, 2026
b6fa5f9
fix(sync): apply-engine seams — (name,type) view adoption, deferred c…
ARHAEEM Jul 4, 2026
c98f5ab
docs: update tool count to 71, document upload_attachment and daemon …
ARHAEEM Jul 4, 2026
fe5807b
feat(transport): route Airtable API calls through direct node HTTP
ARHAEEM Jul 4, 2026
91e22a5
test(transport): cover HttpTransport + auth direct-HTTP seam
ARHAEEM Jul 4, 2026
9af6601
refactor(auth): drop blocking secretSocketId nav-capture (live-proven…
ARHAEEM Jul 4, 2026
da34bd1
feat(auth): AIRTABLE_AUTH_MODE=byo — cookie-only credentials, no browser
ARHAEEM Jul 4, 2026
36e977e
feat(auth): AIRTABLE_AUTH_MODE=direct-login — browser-free login via …
ARHAEEM Jul 4, 2026
3921af7
fix(auth): recover from a locked Chrome profile (exit 21) by killing …
ARHAEEM Jul 4, 2026
eefd80e
feat(sync): run plan + apply as background jobs (mode=status phases)
ARHAEEM Jul 4, 2026
d56f556
docs: document transport modes (direct-HTTP + auth-mode + http-client…
ARHAEEM Jul 4, 2026
3ea20d2
fix(sync): harden applyJob terminal write + document apply() throw co…
ARHAEEM Jul 4, 2026
2803eac
feat(mcp): re-provision stdio MCP servers when authMode/httpClient ch…
ARHAEEM Jul 4, 2026
0e0d0e4
feat(daemon): inject byo/direct-login credentials via a bearer-authed…
ARHAEEM Jul 4, 2026
8abaecf
feat(auth): byo + direct-login credential handling in extension (keyc…
ARHAEEM Jul 7, 2026
2d04354
fix(formula): resolve field names in downloads + normalize legacy ref…
ARHAEEM Jul 9, 2026
d3204b1
feat(mcp): idle park Chromium, PageScheduler, process-tree, tool labels
ARHAEEM Jul 22, 2026
ae481e1
fix(mcp): share auth for pageBusy; update multiSelect on records
ARHAEEM Jul 22, 2026
ace1e42
fix(mcp): address PR #19 review — CI lockfile, auth/daemon lifecycle,…
ARHAEEM Jul 22, 2026
cf4e987
fix(build): keep impit external in the MCP bundle + vendor it for pac…
ARHAEEM Jul 22, 2026
da0c5b4
test(mcp): make process-tree + idmap tests deterministic across OSes
ARHAEEM Jul 22, 2026
c0a9010
fix(auth): single-flight _doInit so a watchdog timeout can't double-l…
ARHAEEM Jul 22, 2026
8673e04
fix(daemon): fail clearly if listenAvoidingBlockedPorts exhausts all …
ARHAEEM Jul 22, 2026
352b29c
fix(mcp): address PR #19 review — dead code, test engines, tracer red…
ARHAEEM Jul 24, 2026
35b389a
fix(extension): propagate transport-setting edits from settings.json …
ARHAEEM Jul 24, 2026
905ed73
docs(tooling): fix CLAUDE.md tool/category counts and guard them in c…
ARHAEEM Jul 24, 2026
e473cdb
fix(mcp): remove sync from safe-write; stop custom profiles gaining n…
ARHAEEM Jul 24, 2026
0e51c20
fix(mcp): correct toggle notifications for absent-key tools; make new…
ARHAEEM Jul 24, 2026
6634c24
fix(mcp): mark sync_base destructive; retire "read-only plan mode" wo…
ARHAEEM Jul 24, 2026
f677127
fix(extension): scope the orphan sweep to processes this install prov…
ARHAEEM Jul 24, 2026
39f4c55
fix(extension): require the daemon-start shape for path-based sweep o…
ARHAEEM Jul 24, 2026
032f01f
docs: fix stale 66-tool counts and sync scope claims in published REA…
ARHAEEM Jul 24, 2026
4545a4a
docs(assets): fix stale 66-tool/13-category text baked into banner/ar…
ARHAEEM Jul 24, 2026
e1675b6
fix(mcp-server): sanitize real account identifiers in sync test fixture
ARHAEEM Jul 24, 2026
ff8dba9
fix(mcp-server): give sync fixture's avatar/attachment hashes distinc…
ARHAEEM Jul 24, 2026
e6924b6
test(direct-login): pin CSRF reuse across 2FA — Seer stale-token find…
ARHAEEM Jul 24, 2026
3b71a39
fix(build): vendor impit's per-platform napi binary into the VSIX
ARHAEEM Jul 24, 2026
e88b3f7
fix(build): generalize the napi-binary vendoring fix to @ngrok/ngrok …
ARHAEEM Jul 24, 2026
0ca34c7
fix(auth): clear the dead-session breaker on re-authentication (8b)
ARHAEEM Jul 25, 2026
9c319f5
fix(extension): make every logout path actually drop the daemon sessi…
ARHAEEM Jul 25, 2026
b89963d
fix(mcp-server): honour HTTP(S)_PROXY/NO_PROXY and unwrap "fetch fail…
ARHAEEM Jul 25, 2026
28cb407
fix(auth): only un-latch the breaker, never zero a partial streak (8b…
ARHAEEM Jul 25, 2026
9fea048
fix(extension): logout must not report success it cannot confirm (8c/F1)
ARHAEEM Jul 25, 2026
8f85a77
fix(extension): a profile left on disk is not a completed logout (8c/F3)
ARHAEEM Jul 25, 2026
ba745ab
docs(changelog): document pre-merge pass scope + retroactively docume…
ARHAEEM Jul 25, 2026
0d67323
fix(mcp-server): correct serverInfo.description tool count and guard it
ARHAEEM Jul 25, 2026
58e5efd
fix(extension): logout must not let a vacuous release mask a failed drop
ARHAEEM Jul 25, 2026
eb87f60
fix(extension): fail closed on the recordDestructive/sync setting fal…
ARHAEEM Jul 25, 2026
853179e
fix(mcp-server): match getView column-visibility semantics; inject CS…
ARHAEEM Jul 25, 2026
1bb90dd
feat(packaging): define the VSIX target matrix and vendor foreign nat…
ARHAEEM Jul 25, 2026
68e8bf5
feat(packaging): assert every VSIX carries its own platform's binarie…
ARHAEEM Jul 25, 2026
634286b
feat(packaging): build one verified VSIX per target; drop untargeted …
ARHAEEM Jul 25, 2026
462886c
ci(release): publish 8 platform-specific VSIXes, no untargeted fallba…
ARHAEEM Jul 25, 2026
cf92b97
docs: correct the "fully self-contained" VSIX claim; document the pla…
ARHAEEM Jul 25, 2026
d016d0b
ci(release): bound the Open VSX index-verification wait across 8 targets
ARHAEEM Jul 25, 2026
455bfda
fix(mcp-server): guard CSRF spread against non-plain bodies; unify co…
ARHAEEM Jul 25, 2026
6e31e66
fix(packaging): verify native binaries by magic number, not just by n…
ARHAEEM Jul 25, 2026
bb0a636
ci(release): bound Open VSX verification by wall clock; fix the build…
ARHAEEM Jul 25, 2026
67999ce
fix(packaging): report vendor failures without an unhandled-rejection…
ARHAEEM Jul 25, 2026
119c9ea
docs: narrow tool-profile allowlist claim; document column-visibility…
ARHAEEM Jul 25, 2026
be862c3
fix(packaging): verify native binaries by exact digest, not by OS mag…
ARHAEEM Jul 25, 2026
5d1538d
fix(packaging): revalidate the vendor cache and guard foreign symlink…
ARHAEEM Jul 25, 2026
96daeed
docs: call these eight target artifact packaging/assertion smokes (18d)
ARHAEEM Jul 25, 2026
e8ee2fc
fix(extension): the orphan sweep must not kill by profile-path mentio…
ARHAEEM Jul 25, 2026
becd274
fix(packaging): reject unpinned .node files in the artifact, not just…
ARHAEEM Jul 25, 2026
5dd032b
fix(packaging): diff pins not prose; guard the generator's extraction…
ARHAEEM Jul 25, 2026
2e5c702
ci: verify native-binary digest pins at release and on dependency PRs
ARHAEEM Jul 25, 2026
a5c80ce
ci: widen the pin-check trigger; record that the PR job is advisory, …
ARHAEEM Jul 25, 2026
ec11ec6
fix(extension): make the sweep's image test actually mean argv[0] (17…
ARHAEEM Jul 25, 2026
26cfa0f
fix(mcp-server): only kill positively-attributable browsers on POSIX …
ARHAEEM Jul 25, 2026
2d77844
fix(mcp-server): replace too-loose plain-object test in the CSRF spre…
ARHAEEM Jul 25, 2026
05b54aa
fix(extension): resolve argv[0] by enumeration, not by patched exampl…
ARHAEEM Jul 25, 2026
427a3c7
fix(mcp-server): unify process attribution behind one shared, test-en…
ARHAEEM Jul 25, 2026
40a61a7
fix(mcp-server): pin the win32 PowerShell invocation to the reference…
ARHAEEM Jul 25, 2026
18c8614
fix(attribution): make the argv boundary symmetric and the bundle mar…
ARHAEEM Jul 25, 2026
fbd9487
fix(attribution): drop the `=` widening and give the quoted branch th…
ARHAEEM Jul 25, 2026
05917bd
fix(build): parameterize the symlink policy so verify-pins survives n…
ARHAEEM Jul 25, 2026
fb11377
fix(attribution): parse argv instead of matching quoted substrings (23)
ARHAEEM Jul 25, 2026
fe12bb2
docs: specify native Airtable workbench redesign
ARHAEEM Jul 25, 2026
0b444db
fix(sync): sort fields before hashing in fingerprintSchema (27)
ARHAEEM Jul 25, 2026
0ecff7f
docs: plan native Airtable workbench implementation
ARHAEEM Jul 25, 2026
08274e3
fix(auth): report user id only when known, never invent it from API r…
ARHAEEM Jul 30, 2026
47fcd17
fix(daemon): start daemon on MCP request, harden idle park and config…
ARHAEEM Jul 30, 2026
af507bb
docs(release): document manage_daemon tool, daemon auto-start, login/…
ARHAEEM Jul 30, 2026
1e85024
fix(release): bump server.json alongside package.json in mcp-server r…
ARHAEEM Jul 30, 2026
3c5befd
docs(sync): document drift guard hardening — fingerprint now covers f…
ARHAEEM Jul 30, 2026
ab6749a
docs(sync): document drift guard second-round fixes — typeOptions key…
ARHAEEM Jul 30, 2026
61c8df8
docs(sync): document drift guard third-round fix — strip autoNumber r…
ARHAEEM Jul 30, 2026
1169b81
fix(test): sandbox tool-config tests away from the live ~/.airtable-u…
ARHAEEM Jul 30, 2026
c1755a7
fix(sync): mode=diff detail echoes the resolved diffId, not the calle…
ARHAEEM Jul 30, 2026
c34efd8
fix(sync): strip maxUsedAutoNumber on the updateField options path too
ARHAEEM Jul 30, 2026
a5d5f43
docs(sync): changelog for diff-detail id echo, autoNumber update-path…
ARHAEEM Jul 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@
**/PLAN.md
packages/mcp-server/.chrome-profile/
packages/mcp-server/dev-tools/
packages/extension/README.md
packages/extension/README.md
packages/webview/.ds-css/
packages/webview/.ds-src/
56 changes: 56 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,62 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

## [Unreleased]

### Formula round-trip + daemon upload fixes (2026-07-09)

#### Fixed
- **MCP server — formula downloads emit real field names.** `download_base_formulas` / `download_formula_field` used to write Airtable's internal `{column_value_fldXXX}` refs verbatim — unreadable, and rejected by Airtable on re-upload ("Unknown field names"). Refs are now resolved to `{Field Name}` (native syntax); unknown ids fall back to `{fldXXX}`, which the API accepts. Non-field placeholders (`{FOO_PLACEHOLDER}`) pass through untouched.
- **MCP server — formula writes normalize legacy refs.** All formula write paths (`create_formula_field`, `update_formula_field`, `update_field_config`, `validate_formula`) convert `{column_value_fldXXX}` → `{fldXXX}` before sending, so previously-downloaded files round-trip without manual rewriting.
- **Extension — "Upload formula" no longer fails with HTTP 406.** The right-click upload/download commands' daemon HTTP client now sends the MCP-spec-required `Accept: application/json, text/event-stream` header, and parses both JSON and SSE-framed responses (older daemons). The daemon side now answers stateless `/mcp` POSTs as plain JSON (`enableJsonResponse`).
- **MCP server — `list_fields` lightweight by default**: returns `{ id, name, type }`; full `typeOptions` is opt-in via `includeOptions: true` (previously ~350K chars on a wide table). The installed AI-skill template and `server.json` tool listing were updated to match.
- **Language services — field names with special characters no longer produce false errors.** With downloads now emitting real `{Field Name}` refs, names containing apostrophes (`{Owner's List}`), parentheses (`{Total (USD)}`), or smart quotes (`{Owner’s List}`, common via Airtable UI autocorrect) used to trigger spurious `Unclosed quote` / `Missing closing parenthesis` / `Smart quote` Errors in the `.formula` editor — and the smart-quote quick fix would rename the ref into a dangling reference. The paren/bracket/quote/smart-quote checkers now skip `{…}` field-ref bodies (real errors outside refs still report; an unclosed `{` still reports).

### MCP server — sync_base schema-orphan deletion under mirror (2026-06-21)

#### Added
- `sync_base mode=apply` — **schema-orphan deletion** (`pruneSchema`): under `policy=mirror`, dest-only fields/views/tables that have no counterpart in the source are deleted from the destination after `applyPlan` completes. Two independent gates: `confirmDeletions:true` is required to delete dest-only **fields and views** (same flag as `pruneRecords`); the new `confirmTableDeletions:true` is required to drop dest-only **tables** — `confirmDeletions` alone never deletes an entire table. Without each gate the operation is a dry-count only (`DELETION_GATED` for fields/views, `TABLE_DELETION_GATED` for tables). Deletion is dependency-safe: fields are deleted without `force` (so no matched field is ever cascade-deleted), orphan→orphan formula dependencies are resolved by retry-until-stable, and a field blocked by a matched-field dependency is kept and reported as `SCHEMA_DELETE_BLOCKED`. Deletion order: views first (no dependents), then fields, then tables (after their content). Applied counts are surfaced in the result as `schemaDeleted` (fields + views) and `tablesDeleted`; failures are continue-on-failure warnings (`SCHEMA_DELETE_FAILED`). Per-table `policyOverrides` are respected — `overlay`/`preserve` tables are never pruned. Module: `src/sync/prune-schema.js`. Deferred: retypes, view-section orphan deletion, attachment-strip (M4).

### MCP server — sync_base natural-key record matching (2026-06-21)

#### Added
- `sync_base` — **natural-key record matching** (`naturalKeys: { [tableName]: fieldName }`): matches dest↔source records by a shared key field's value (resolved by name per base) and grows `idmap.records` without any write to either base. Add-only + ambiguity-safe: existing mappings are never overwritten, already-mapped dest records are never re-claimed, and ambiguous/duplicate key values are skipped with a `NATURAL_KEY_AMBIGUOUS` warning; a missing key field emits `NATURAL_KEY_FIELD_MISSING`. Runs in two places: (1) **`mode=reconcile`** — after the existence-prune, snapshots source records and calls the matcher, then saves the updated idmap; (2) **`mode=apply` auto pre-pass** — runs before Pass 1 and before `pruneRecords`, so records `mirror` no longer treats real-but-unmapped dest records as orphans and re-syncs no longer duplicate them. The key field must be stable across bases (autoNumber renumbers → bad key; name/email/injected `InjectID` → good key). Single-field keys only; composite keys and value normalization are deferred. A `matched` count is returned in the result.

### MCP server — sync_base reconciliation policy + custom field mappings (2026-06-20)

#### Added
- `sync_base mode=apply` — **records reconciliation policy**: new `policy` param (`mirror` | `overlay` | `preserve`, default `overlay`) controls two independent axes — **extras** (keep or remove dest-only records) and **conflicts** (source-wins or dest-wins when both bases hold the record). Presets: `mirror` = {remove, source-wins} (make dest identical to source), `overlay` = {keep, source-wins} (default — today's existing behavior), `preserve` = {keep, dest-wins} (never overwrite dest edits). `policyOverrides` (`{ [tableName]: preset }`) overrides the global preset per table.
- `sync_base mode=apply` — **deletion gate** (`confirmDeletions`): under `mirror` policy (or any table override that removes extras), dest-only orphan records are not deleted unless `confirmDeletions: true`. Without it, `pruneRecords` reports a `DELETION_GATED` warning with the would-delete count and does nothing — poll `mode=status` to see counts, then re-run with `confirmDeletions:true` to apply. Separately, `createTable` unconditionally clears the ~3 blank scaffolding rows it seeds (best-effort; `SCAFFOLDING_ROWS_KEPT` warning if the deletion attempt fails); `pruneRecords` under `mirror`+`confirmDeletions` additionally removes any leftover dest-only blank rows as part of the ordinary orphan prune. Attachment-strip under mirror remains a deferred follow-up (schema-orphan deletion and natural-key matching shipped separately).
- `sync_base` — **custom field mappings** (`fieldMappings: { [tableName]: { sourceFieldName: destFieldName } }`): inject a source field's value (including computed fields like `autoNumber` or formula) into a different writable scalar dest field during record sync. Classic use: inject a source `autoNumber` field (`Code`) into a writable dest text field (`InjectID`) so a dest primary-key formula can reconstruct original identity across bases. Fail-fast pre-flight validation aborts `mode=apply` synchronously on any error (`FIELD_MAP_INVALID`); `mode=plan` and `mode=diff` run the same validation as a dry check and return errors in `fieldMappingErrors` (machine output). Validation codes: `FIELD_MAP_TABLE_MISSING`, `FIELD_MAP_SOURCE_MISSING`, `FIELD_MAP_TARGET_MISSING`, `FIELD_MAP_TARGET_COMPUTED` (dest must be writable scalar), `FIELD_MAP_TYPE_INCOMPATIBLE` (array-typed source/dest rejected), `FIELD_MAP_COLLISION` (two sources targeting the same dest).

### MCP server — sync_base compare, curatable changeset, selective apply (2026-06-19)

#### Added
- `sync_base mode=diff` (read-only): comprehensive schema comparison of two bases via a new pure `src/sync/compare.js`. Every difference is classified as **drift** (sync enforces it — table/field/view existence, field type/options/choices, view filters/sorts/groups content, column visibility, colors/cover/frozen/rowHeight, primary, form), **best-effort** (sync applies but doesn't guarantee — field/view/column order, sort/group clause order), or **not-synced** (view sections, now captured by the snapshot). Two verdicts: `identical` (zero diffs) and `converged` (zero drift; best-effort/not-synced may remain). The full diff is persisted to `~/.airtable-user-mcp/sync/<src>__<dest>/diff-<id>.json`; the tool returns a token-budgeted DIGEST (verdicts + class counts + per-table count rollup + a capped driftSample, ≤25). Drill into one table via `mode=diff detail="<table>"` (params: `detail`, `diffId`, `offset`, `limit`).
- `sync_base mode=plan` now emits a curatable **changeset**: each action carries a stable name-based `changeId` (`<op>|<table>|<target>`), a `class`, and an `apply:true` flag; the digest includes a `sample` + an `editHint`. New `direction` param (`to-dest` default | `to-source`) targets either base as the destination.
- `sync_base mode=apply` accepts a `skip:[changeId]` list (and honors `apply:false` on changeset entries) → applies everything except the removed changes. Journal-safe; skipped dependencies degrade gracefully to UNRESOLVABLE_REF.

#### Fixed
- `sync_base mode=apply` field creation — **autoNumber** fields now create. The read-only runtime counter `maxUsedAutoNumber` is stripped from `typeOptions` before `createField` (the internal API rejected it with 422 "options not valid").
- `sync_base mode=apply` field creation — **count** fields now create. `toWritableComputedOptions` emitted the public-REST key `recordLinkFieldId`, but internal-API snapshots store a count's link under `relationColumnId` (like rollup) and the count create path passes `typeOptions` through untranslated — so every count field 422'd "options not valid". It now reads/emits the internal `relationColumnId`. (Both fixes validated live by converging a full base copy: 5 autoNumber + 3 count fields that previously failed now create cleanly.)
- `sync_base mode=apply` — **createTable scaffolding rows are now removed** (clean mirror). A new table is seeded with ~3 blank rows (like the 6 default fields); apply already deleted the scaffolding fields but left the rows, so every synced table carried blank rows. The rows are now cleared right after create (best-effort; `SCAFFOLDING_ROWS_KEPT` warning on failure). Live-confirmed: createTable → 3 rows → 0.
- `sync_base mode=diff` / view convergence — **empty-predicate filter representations no longer report false drift.** Airtable's internal API stores the same emptiness check two equivalent ways (`isNotEmpty`/null ≡ `!=`/"" and `isEmpty`/null ≡ `=`/""): a source base holds the named-operator form, the dest holds the `=`/`!=` form after the sync applied it. `canonFilterSet` now normalizes these (only when the value is genuinely empty — `0`/`false` are preserved), so semantically-equal filters compare equal in the diff report and stop re-emitting `applyViewConfig` every apply.

### MCP server — sync_base record sync (2026-06-17)

#### Added
- `sync_base mode=apply`: after schema + view sync, launches a **background** record sync and returns a `jobId` immediately. Two-pass: Pass 1 creates/updates scalar + single/multi-select cells (computed fields + computed primary are never written) and fills a persisted `idmap.records` (rec→rec map); Pass 2 writes linked-record cells (remapped via record map, unresolved targets reported). Attachments are then downloaded from source and re-uploaded to dest (deduped by filename+size). Record-referencing view filters that were stripped during view sync are restored once records exist. Throttling is handled by per-request 429 backoff in the auth queue; resumable (records journal, per-chunk persist) and continue-on-failure (per-record errors are warnings, not aborts).
- `sync_base mode=status`: poll a background record job by planId — returns running/done/failed plus live records-mapped count.
- `sync_base mode=reconcile`: **prune** dead record-map entries (existence-prune). Per-table natural-key re-match is planned (not yet implemented); reconcile does not de-duplicate records.

### MCP server — sync_base collaborative view sync (2026-06-17)

#### Added
- `sync_base`: full collaborative-view sync — create views + mirror filters, sorts, group levels, field visibility + column order, frozen columns, color config, cover, calendar date columns, form metadata, and row height, with source→dest field+choice ID remapping, per-view-type anchor validation + grid fallback, applied after fields. Idempotent (convergent canonical compare). Personal views skipped; orphan views reported (not deleted).

### MCP server — sync_base mode=apply (2026-06-16)

#### Added
- `sync_base mode=apply`: execute a saved base-to-base schema plan against the destination — creates tables, reconciles the primary, creates scalar/link/computed fields (source→dest reference remapping + dest-space formula validation), and applies non-destructive field updates. Drift-guarded (aborts if the destination changed since the plan) and resumable via an on-disk journal. Type-changing retypes, deletions, records, and views are out of scope for this release.

### LSP server — fix runtime startup + CI bin-link warning (2026-06-12)

- **`airtable-user-lsp` was runtime-broken when executed with Node directly**
Expand Down
8 changes: 6 additions & 2 deletions CLAUDE.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ Manage Airtable bases with capabilities **not available through the official RES
| **Form Metadata** | 2 | Description, redirect URL, attribution, copy-to-respondent, branding (legacy form views) |
| **Extension Management** | 7 | Create, install, enable/disable, rename, duplicate, remove extensions |
| **Tool Management** | 1 | List profiles, switch profile, toggle tools/categories (meta-tool, always enabled) |
| **Base Sync** | 1 | `sync_base` — copy a base's schema to another base. `mode=plan` produces a diff report; `mode=apply` executes it (creates tables/fields with ref remapping, drift-guarded, resumable via journal) and also syncs collaborative views (filters, sorts, groups, column order, frozen, color, cover, calendar, form, row height). Retypes, deletions, and records are out of scope. |

See the full tool reference in [`packages/mcp-server/README.md`](packages/mcp-server/README.md).

Expand Down
Loading
Loading