Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
330 commits
Select commit Hold shift + click to select a range
c459cc4
style(arcade): wrap the widened outcome type argument as biome wants it
mxmzb Oct 12, 2026
1c72665
test(arcade): await the render the directory test releases, so the fi…
mxmzb Oct 12, 2026
630dce9
test(arcade): pin that the account-mode switch ends sibling apps, and…
mxmzb Oct 12, 2026
bd117d3
fix(arcade): removing an app ends and audits the siblings the vendor …
mxmzb Oct 12, 2026
edeb317
feat(arcade): GET /servers/:id/grants answers what an account holds, …
mxmzb Oct 12, 2026
77fa17c
test(arcade): the three person-site assertions pin the exact unconfig…
mxmzb Oct 12, 2026
f34a660
docs(arcade): broker.ts's header no longer claims its crossing import…
mxmzb Oct 12, 2026
9733060
feat(arcade): GET /servers/:id/connection/siblings names what a disco…
mxmzb Oct 12, 2026
bb458f0
feat(arcade): the pre-redirect consent copy names the permission and …
mxmzb Oct 12, 2026
bb6ce4f
feat(arcade): the connected-account page names the sibling apps a dis…
mxmzb Oct 12, 2026
3665183
fix(arcade): the admin app-detail page tells its brokered rows which …
mxmzb Oct 12, 2026
14dd925
docs(arcade): operator page for the Arcade broker
mxmzb Oct 12, 2026
e53289c
docs(arcade): name the key, provider choice, startup refusals, admin …
mxmzb Oct 12, 2026
bdd6d07
feat(arcade): the connected-account page lists grants by GrantState, …
mxmzb Oct 12, 2026
465570d
test(arcade): BROKERED_PROFILE's exhaustive expectation carries envVar
mxmzb Oct 12, 2026
420fb31
test(arcade): the whole deployment, from the picker to the disconnect…
mxmzb Oct 13, 2026
36b4283
chore(test): commit the sharded server-suite runner the gates depend on
mxmzb Oct 13, 2026
8634670
fix(app): make provider required on BrokeredAccountRow and accountSen…
mxmzb Oct 13, 2026
f279476
test(arcade): journey suite uses the shared TEST_POOL and records thr…
mxmzb Oct 13, 2026
352dc5c
perf(arcade): one auth-provider resolution per toolkit for a whole re…
mxmzb Oct 13, 2026
070498c
fix(arcade): the grant list shows unauthorized actions without a search
mxmzb Oct 13, 2026
feea10f
test(arcade): the live suite, written and never run
mxmzb Oct 13, 2026
ae74c00
fix(plugins): gate the grant list on a declared capability, not the v…
mxmzb Oct 13, 2026
c9f9f4a
fix(arcade): land a deployment-held consent where a screen reads it
mxmzb Oct 13, 2026
6676ee0
refactor(plugins): one grant-state ordering table, shared by the sort…
mxmzb Oct 13, 2026
4b7185f
fix(arcade): stop the authorize route encoding the refuted deployment…
mxmzb Oct 13, 2026
f4c5e87
fix(arcade): open the verifier's blanket try before its first store read
mxmzb Oct 13, 2026
96528ad
docs(arcade): the refusal set's docblock says eleventh, which is what…
mxmzb Oct 13, 2026
9fa2d6e
docs(arcade): say why two brokered_connections reads carry no provide…
mxmzb Oct 13, 2026
28b13e4
fix(arcade): match a connection on the provider INSTANCE, not the pro…
mxmzb Oct 13, 2026
de98696
docs(arcade): say which object a `provider_id` is on, and record the …
mxmzb Oct 13, 2026
ffef56d
test(arcade): correct the live suite against what the first real run …
mxmzb Oct 13, 2026
9c615eb
merge: bring `main` into the Arcade branch, renumbering the migrations
mxmzb Oct 13, 2026
75614fb
test(memory): name the broker the defaults fixtures already use
mxmzb Oct 13, 2026
5b2ed4c
test(arcade): give back the pools these files open
mxmzb Oct 13, 2026
50aae80
test(arcade): ask the trail for its order instead of assuming one
mxmzb Oct 13, 2026
b057bd2
fix(arcade): read every listing to its end, and tell an absent total …
mxmzb Oct 13, 2026
6d6fd20
fix(db): refuse to migrate a database that cannot reach every migration
mxmzb Oct 13, 2026
ffacc92
merge: C3 — read every Arcade listing to its end (bucket (a), round 1…
mxmzb Oct 13, 2026
047766f
merge: F1 — refuse a database that cannot reach every migration (buck…
mxmzb Oct 13, 2026
62d5cb7
fix(arcade): cancel the authorization the path names, not whatever th…
mxmzb Oct 13, 2026
8b0f380
fix(broker): a key of nothing is no key, decided where "configured" i…
mxmzb Oct 13, 2026
7cc00a7
fix(broker): refuse an activation count that is not a count
mxmzb Oct 13, 2026
3a8554b
fix(plugins): refuse a provider configuration this deployment cannot …
mxmzb Oct 13, 2026
9a17c14
test(arcade): search a logged value for a credential instead of flatt…
mxmzb Oct 13, 2026
4dc77e3
test(plugins): spell the vendor column as production does and prove b…
mxmzb Oct 13, 2026
437a9ec
fix(arcade): name an authorization attempt by an instant, not by a mi…
mxmzb Oct 13, 2026
69a2cc9
fix(arcade): read a string with no text in it as no text at all
mxmzb Oct 13, 2026
c23644c
fix(arcade): read a listing's items off the body Arcade sent, not the…
mxmzb Oct 13, 2026
cfdf85b
merge: D1-cancel-by-id (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
d05242c
merge: A4-assert-activatable (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
2ef8a25
fix(arcade): read a connection's own connection_status before calling…
mxmzb Oct 13, 2026
2255cbe
merge: A2-empty-key-configured (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
2b4b2cb
fix(db): hold pending_authorizations to the unions it declares
mxmzb Oct 13, 2026
b2bc33f
merge: A3-provider-wiring-fails-open (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
f7de92f
fix(broker): name the active vendor in a refused return address, and …
mxmzb Oct 13, 2026
15b2a8d
fix(app): look a notice code up in a map that holds only what was put…
mxmzb Oct 13, 2026
e2d9757
merge: C1-malformed-listing (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
31bed92
merge: C4-connection-status (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
d4e173d
merge: C6-account-name-shadowing (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
224c8e2
fix(arcade): answer a mint this deployment could not record, and free…
mxmzb Oct 13, 2026
c39f76b
merge: D7-created-at-precision (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
75c865e
merge: F2-pending-auth-checks (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
22c5481
merge: B1-return-url-vendor (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
302acac
merge: E1-authorized-prototype-keys (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
e362167
merge: B3-fixture-vendor (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
cfb771e
merge: E2-credential-gate-flattening (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
e095ea2
fix(plugins): remove a server at the broker that minted it, not the c…
mxmzb Oct 13, 2026
1893c49
merge: D2-mint-record-guard (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
5603ce9
merge: G1-remove-server-provenance (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
9c7dab8
fix(plugins): name the broker this deployment actually runs
mxmzb Oct 13, 2026
eaff90b
merge: B2-vendor-strings (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
17f7dc9
fix(plugins): never read an undecided provider as Composio
mxmzb Oct 13, 2026
9cc1af5
merge: A1-provider-flattening (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
a116c75
chore: untrack agent-mastra/bun.lock, swept in by a merge resolution
mxmzb Oct 13, 2026
a02edde
fix(arcade): a failed clean-up must not replace the refusal with a bo…
mxmzb Oct 13, 2026
51b79bb
fix(arcade): cap the text callTool puts in a model's context and the …
mxmzb Oct 13, 2026
c0bd415
fix(arcade): refuse a confirmed return that carries no authorization id
mxmzb Oct 13, 2026
994ed1b
merge: D3-discard-refusal (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
2d89e24
fix(app): make the consent resume leg actually leave the app
mxmzb Oct 13, 2026
f65c338
fix(arcade): read the status Arcade answered the mint with
mxmzb Oct 13, 2026
fc386cb
merge: C10-result-text-cap (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
94c22e6
merge: D6-confirm-return-id (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
b65bd8c
merge: D8-sign-resume-redirect (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
a6a55c9
merge: C9-authorize-status (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
1cc6c6c
fix(plugins): offboarding must not file an ended sibling as never ask…
mxmzb Oct 13, 2026
fcb7add
fix(arcade): an empty vendor structure is not a vendor answer
mxmzb Oct 13, 2026
1fd5661
fix(arcade): refuse an attempt that cannot say whose account it is for
mxmzb Oct 13, 2026
e7ef88f
test(db): make the schema guards fail when a CHECK is mutated
mxmzb Oct 13, 2026
8b860c7
merge: G2-retire-siblings (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
fe601cd
fix(tests): make the D24 pairing guard able to fail
mxmzb Oct 13, 2026
4457cb6
merge: C11-empty-behavior (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
5ac5eba
fix(app): read search parameters as text, so a numeric handle is not …
mxmzb Oct 13, 2026
5b6a860
fix(arcade): read an app's connection kind off the listing instead of…
mxmzb Oct 13, 2026
f527d43
fix(arcade): bound every outbound broker call, not just how many time…
mxmzb Oct 13, 2026
245fe84
merge: D4-attempt-holder (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
88993c4
merge: H3-check-mutation (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
8d3ffdf
merge: H2-pairing-guard (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
232b040
merge: C7-consent-kind (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
ceefa4d
test(server): close the test suite's egress so no case can dial a vendor
mxmzb Oct 13, 2026
226abda
merge: D9-search-coercion (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
346babd
test(arcade): see the listing defects the engine fixtures still could…
mxmzb Oct 13, 2026
1d64fa2
fix(arcade): refuse in this deployment's own sentence, not the vendor…
mxmzb Oct 13, 2026
8225e7d
test(app): pin the callbackURL a sign-in is given, not just its default
mxmzb Oct 13, 2026
9a98762
merge: H5-live-vendor-call (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
107ec2f
merge: H1-adapter-test-blindness (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
31c74c4
merge: C12-vendor-error-bodies (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
60467a0
merge: D5-poll-timeout (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
b95b503
merge: H4-app-mutation-survivors (bucket (a), round 1 fix cycle)
mxmzb Oct 13, 2026
334d805
fix(arcade): read the auth provider off the WHOLE action listing, not…
mxmzb Oct 13, 2026
54e5ba6
merge: C13-auth-provider-paging (bucket (a), wave 3 — surfaced by a s…
mxmzb Oct 13, 2026
8d75881
fix(plugins): read a stored holder/user-id pair as the account it nam…
mxmzb Oct 13, 2026
ff7f396
merge: D10-store-account-ref (bucket (a), wave 3 — surfaced by a same…
mxmzb Oct 13, 2026
922d4ec
fix(test): type arcade-verify's broker bag as a BrokerProvider, not a…
mxmzb Oct 13, 2026
419ce70
fix(plugins): account for the apps a retired identity's revoke also ends
mxmzb Oct 13, 2026
cfd0db8
Merge branch 'fix/G3-retired-identity-siblings' into arcade-provider
mxmzb Oct 13, 2026
727b0e1
test(arcade): state revoke's outcome invariant over seven vendor resp…
mxmzb Oct 14, 2026
3dd4582
test(arcade): refuse a stub vendor that never bound a port
mxmzb Oct 14, 2026
1be64c6
test(support): one shared source scanner, and the contract test for i…
mxmzb Oct 14, 2026
73b3954
test(ci): type-check server/tests against a frozen baseline of its ex…
mxmzb Oct 14, 2026
061a77b
test(contract): one home per named decision, and the keyed lookup ext…
mxmzb Oct 14, 2026
332631c
test(guards): the six assertion shapes that cannot fail, read off the…
mxmzb Oct 14, 2026
d9b7079
merge: lever-cl3 (convergence-audit lever)
mxmzb Oct 14, 2026
c93b9aa
merge: lever-cl1 (convergence-audit lever)
mxmzb Oct 14, 2026
4bac9df
merge: lever-cl4 (convergence-audit lever)
mxmzb Oct 14, 2026
ebd819e
merge: lever-cl6 (convergence-audit lever)
mxmzb Oct 14, 2026
c040190
merge: cl5-revoke-invariant (convergence-audit lever)
mxmzb Oct 14, 2026
1d80c6a
style(arcade): biome format the revoke-invariant harness
mxmzb Oct 14, 2026
598f9a3
test(arcade): make the disconnect guards see the vendor side
mxmzb Oct 14, 2026
d942c52
fix(arcade): an unattributable toolkit refuses instead of answering "…
mxmzb Oct 14, 2026
bbabc97
fix(arcade): an unreadable listing body is not an empty page
mxmzb Oct 14, 2026
83a9e25
fix(arcade): read a vendor total_count the cross-check can use, or re…
mxmzb Oct 14, 2026
293d4f1
fix(arcade): refuse a vendor body this deployment cannot read, instea…
mxmzb Oct 14, 2026
01f8ca5
merge: fix-A4-disconnect-guard (round 2 fix cycle, wave 0)
mxmzb Oct 14, 2026
3fb7289
merge: fix-A1-authprovider-null (round 2 fix cycle, wave 0)
mxmzb Oct 14, 2026
2b8f874
merge: fix-A3-nonjson-fallback (round 2 fix cycle, wave 0)
mxmzb Oct 14, 2026
2f75aa0
merge: fix-A9-totalcount-string (round 2 fix cycle, wave 0)
mxmzb Oct 14, 2026
076677e
merge: fix-A10-accidental-greens (round 2 fix cycle, wave 0)
mxmzb Oct 14, 2026
af911ed
test(arcade): cover connectionIsLive in the file its three paths live in
mxmzb Oct 14, 2026
5dbb877
test(arcade): pin the connection listing to the vendor identity
mxmzb Oct 14, 2026
36a9625
fix(plugins): record who consented on an Arcade-completed Shared conn…
mxmzb Oct 14, 2026
faca7c7
Hold the completed_at/outcome pairing in the database, not in a comment
mxmzb Oct 14, 2026
4887aac
fix(plugins): resolve the attempt before the app on authorize-cancel …
mxmzb Oct 14, 2026
1169d21
fix(plugins): refuse a late callback that would reopen a settled auth…
mxmzb Oct 14, 2026
dd00908
test(composio): make the grantsFor suite able to see the isolation it…
mxmzb Oct 14, 2026
e925cd2
fix(plugins): one place for the three rules a cascade delete obeys
mxmzb Oct 14, 2026
3d029bb
fix(app): drop every consumed one-shot parameter from Connected accou…
mxmzb Oct 14, 2026
046f05a
fix(plugins): tell the truth about a completion /arcade/verify could …
mxmzb Oct 14, 2026
538c87d
Key `pending_authorizations` to the people it names, and index its keys
mxmzb Oct 14, 2026
b534b35
Settle account_mode on every brokered app that has an account
mxmzb Oct 14, 2026
c3a08f8
merge: fix-A5-disconnect-sibling (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
add4faa
merge: fix-A6-identity-scoping (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
6c745d2
merge: fix-A7-connection-liveness (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
96d51d1
merge: fix-A8-grantsfor-isolation (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
ac8da96
merge: fix-B2-close-attempt-guard (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
756ef7a
merge: fix-B3-connectedby (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
bc3c3ca
merge: fix-B5-cancel-removed-app (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
037bb98
merge: fix-B6-verify-catch (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
4f19170
merge: fix-B8-param-replay (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
d49b390
merge: fix-B1-attempt-pairing (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
e0cb295
merge: fix-B7-0057-keys (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
b6c5a29
merge: fix-B4-account-mode (round 2 fix cycle, wave 1)
mxmzb Oct 14, 2026
aa87758
fix(tests): await the person/actor helpers B7 made async
mxmzb Oct 14, 2026
e7d12e1
fix(db): read the migrations journal from the table the migrator writes
mxmzb Oct 14, 2026
c569568
fix(migrate): keep the out-of-reach refusal when releasing the connec…
mxmzb Oct 14, 2026
163822a
fix(plugins): clear the vendor deadline when the call throws synchron…
mxmzb Oct 14, 2026
6d349ef
fix(arcade): read a missing authorization block one way, as needing none
mxmzb Oct 14, 2026
783e2f6
fix(db): pick the migrator's high-water mark the way drizzle picks it
mxmzb Oct 14, 2026
e5bc7ce
fix(tests): resolve every type-only import in server/tests that point…
mxmzb Oct 14, 2026
e1f7a0e
fix(db): serialise the reach check and the migrate under one lock
mxmzb Oct 14, 2026
2d9e233
fix(tests): close every egress path the test network guard left open …
mxmzb Oct 14, 2026
88573c9
Merge branch 'fix-C1-deadline-timer-leak' into arcade-provider
mxmzb Oct 14, 2026
67db1ed
Merge branch 'fix-C2-grantstate-noauth' into arcade-provider
mxmzb Oct 14, 2026
75b278c
Merge branch 'fix-C5-client-end-masks' into arcade-provider
mxmzb Oct 14, 2026
1254d72
Merge branch 'fix-C7-network-guard' into arcade-provider
mxmzb Oct 14, 2026
ca6ea39
Merge branch 'fix-C8-constraints-import' into arcade-provider
mxmzb Oct 14, 2026
a0c1ebf
Merge branch 'fix-C4-migrations-table-hardcode' into arcade-provider
mxmzb Oct 14, 2026
c6d7ba2
Merge branch 'fix-C6-reach-serialise' into arcade-provider
mxmzb Oct 14, 2026
450e54b
Merge branch 'fix-C3-migration-reach-max' into arcade-provider
mxmzb Oct 14, 2026
944e526
fix(db): carry a NULL created_at from the journal into the reach check
mxmzb Oct 14, 2026
398df1b
fix(plugins): route removeServer's sibling cascade through clearEnded…
mxmzb Oct 14, 2026
edfcd09
test(arcade): make the configs() stub honour the query it is handed (…
mxmzb Oct 14, 2026
ba948cb
fix(arcade): make recordAuthorizationMint write-once and never after …
mxmzb Oct 14, 2026
9a5101a
test(arcade): exercise cancel under a broker with no authorization fl…
mxmzb Oct 14, 2026
111af38
fix(app): drop ?action= from an app's page after one read, keeping th…
mxmzb Oct 14, 2026
d143fba
fix(arcade): refuse an authorization block the provider read cannot p…
mxmzb Oct 14, 2026
85eacff
fix(composio): report the scopes of the config a connection was minte…
mxmzb Oct 14, 2026
fce3a58
fix(plugins): refuse to discard a settled authorization attempt (B2a)
mxmzb Oct 14, 2026
2844ce2
fix(arcade): file mcp.authorization_cancelled when a person retracts …
mxmzb Oct 14, 2026
7fa121b
fix(plugins): carry vendor_user_id and skill origin through their con…
mxmzb Oct 14, 2026
0557dab
fix(plugins): log a context-changed withdrawal whose outcome is unknown
mxmzb Oct 14, 2026
2a42273
test(broker): complete the two enable-path broker stubs, and record a…
mxmzb Oct 14, 2026
8c8ee84
test(broker): complete the third enable-path broker stub in plugin-store
mxmzb Oct 14, 2026
42e8e25
fix(grants): count only what an approval covers in "approves all N"
mxmzb Oct 14, 2026
d735179
fix(db): name the journal the check read in the refusal's repair SQL
mxmzb Oct 14, 2026
9784073
test(composio): make the adapter suite's vendor doubles honour the qu…
mxmzb Oct 14, 2026
de6a700
Merge branch 'fix-C4m-refusal-literal-table' into arcade-provider
mxmzb Oct 14, 2026
58fbd7a
Merge branch 'fix-B8a-action-param-strip' into arcade-provider
mxmzb Oct 14, 2026
859862b
Merge branch 'fix-A5a-removeserver-key-sibling' into arcade-provider
mxmzb Oct 14, 2026
4aedd0d
Merge branch 'fix-A6a-configs-stub-options' into arcade-provider
mxmzb Oct 14, 2026
ef7d748
Merge branch 'fix-B2b-mint-rewrite-guard' into arcade-provider
mxmzb Oct 14, 2026
e5dc438
Merge branch 'fix-B4a-conflict-arm-columns' into arcade-provider
mxmzb Oct 14, 2026
b5c67a5
Merge branch 'fix-B2a-discard-state-guard' into arcade-provider
mxmzb Oct 14, 2026
7f80695
Merge branch 'fix-B5a-cancel-composio-coverage' into arcade-provider
mxmzb Oct 14, 2026
46cd67d
Merge branch 'fix-B5b-cancel-audit-row' into arcade-provider
mxmzb Oct 14, 2026
4b07e1e
Merge branch 'fix-B6a-composio-revoke-catch' into arcade-provider
mxmzb Oct 14, 2026
6db827b
Merge branch 'fix-C2b-authproviders-unreadable' into arcade-provider
mxmzb Oct 14, 2026
3e7cc9c
Merge branch 'fix-A8a-composio-fixture-blindness' into arcade-provider
mxmzb Oct 14, 2026
0142f1c
Merge branch 'fix-C8a-broker-stub-revoke' into arcade-provider
mxmzb Oct 14, 2026
281d886
Merge branch 'fix-G14-grantsfor-config-scope' into arcade-provider
mxmzb Oct 14, 2026
81f1769
Merge branch 'fix-C2a-approval-count-copy' into arcade-provider
mxmzb Oct 14, 2026
f4f6974
fix(tests): carry C2a's authorization field into G14's and B8a's gran…
mxmzb Oct 14, 2026
c995b68
test(fixtures): pin local id and vendor id distinct in account fixtur…
mxmzb Oct 14, 2026
8c4febb
test: add a mutation register that plants known defects and requires …
mxmzb Oct 14, 2026
d161617
test(arcade): L2 contract table over how every vendor-field reader tr…
mxmzb Oct 14, 2026
f9c72c3
test(sole-definition): pin K5 second spellings — journal, sibling wal…
mxmzb Oct 14, 2026
0c4859f
test(L3): ratchet casts past the broker type; add a throw-by-default …
mxmzb Oct 14, 2026
dab76a5
test(L4): ledger every pending_authorizations write against its audit…
mxmzb Oct 14, 2026
3274448
Merge branch 'lever-L1-mutation-register' into arcade-provider
mxmzb Oct 14, 2026
5397157
Merge branch 'lever-L1b-fixture-identity' into arcade-provider
mxmzb Oct 14, 2026
6cc095a
Merge branch 'lever-L2-vendor-field-contract' into arcade-provider
mxmzb Oct 14, 2026
eb85e42
Merge branch 'lever-L3-stub-ratchet' into arcade-provider
mxmzb Oct 14, 2026
718295a
Merge branch 'lever-L4-authorization-trail-ledger' into arcade-provider
mxmzb Oct 14, 2026
5aa60d7
Merge branch 'lever-L5-sole-definition-entries' into arcade-provider
mxmzb Oct 14, 2026
a54ba3a
test(levers): let two existing guards see the stubBroker factory
mxmzb Oct 14, 2026
1686607
merge: main (#784 server split, #789) — STRUCTURE ONLY, arcade work n…
mxmzb Oct 14, 2026
c78fe76
rehome(1/2): arcade store methods and shared contracts into main's sp…
mxmzb Oct 14, 2026
c870ccd
rehome(2/2): arcade routes into main's route-group layout
mxmzb Oct 14, 2026
b59a40b
Merge commit 'c870ccd4' into arcade-provider
mxmzb Oct 14, 2026
b4e48c7
test(compose): assert the migrator compose actually runs
mxmzb Oct 14, 2026
695fdc8
fix(test-guard): judge raw sockets by the address they reach; assert …
mxmzb Oct 14, 2026
e6ee9a7
Merge branch 'fix-ci-network-guard' into arcade-provider
mxmzb Oct 14, 2026
df1c682
fix(plugins): log an authorization mint whose outcome is unknown
mxmzb Oct 14, 2026
445259c
docs(accounts): say why a person's vendor id is their local id, and m…
mxmzb Oct 14, 2026
180d2dc
fix(plugins): one judgement for what the trail says about a key app (…
mxmzb Oct 14, 2026
1d4e779
fix(L4-b): an attempt dies only with the person who started it
mxmzb Oct 14, 2026
962137a
fix(arcade): do not hand out a consent url the mint could not bind (B5d)
mxmzb Oct 14, 2026
1a9728a
fix(arcade): one absent/unreadable/read reading for every vendor auth…
mxmzb Oct 14, 2026
84b9974
Merge branch 'fix-L1ba-accountref-identity' into arcade-provider
mxmzb Oct 14, 2026
f189b46
Merge branch 'fix-L4b-cascade-cross-actor' into arcade-provider
mxmzb Oct 14, 2026
497afc1
Merge branch 'fix-K5-retire-connections-rules' into arcade-provider
mxmzb Oct 14, 2026
7301015
Merge branch 'fix-K2-fail-open-reads' into arcade-provider
mxmzb Oct 14, 2026
5aa731c
Merge branch 'fix-L4a-unknown-vendor-outcome' into arcade-provider
mxmzb Oct 14, 2026
922c21a
Merge branch 'fix-B5d-ignored-mint-result' into arcade-provider
mxmzb Oct 14, 2026
3469999
fix(arcade): load the app directory inside the vendor deadline
mxmzb Oct 14, 2026
1b396d4
Merge branch 'fix-arcade-directory-deadline' into arcade-provider
mxmzb Oct 14, 2026
6b25d8c
fix(arcade): read a large toolkit's action listing inside the vendor …
mxmzb Oct 14, 2026
a1ecf38
Merge branch 'fix-arcade-toolkit-listing-deadline' into arcade-provider
mxmzb Oct 14, 2026
6c82062
Merge remote-tracking branch 'origin/main' into arcade-provider
mxmzb Oct 14, 2026
e5f0db1
test(types): take main's #790 debt into the baseline, deliberately
mxmzb Oct 14, 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
19 changes: 16 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ jobs:
- run: bun run format:check
- run: bun run lint
- run: bun run typecheck
# `typecheck` is `bun run --filter '*' typecheck`, and each workspace's `tsc --noEmit` reads
# its own tsconfig, none of which includes a test tree. The suite is therefore the one part
# of this repository that no type-checker has ever read: bun erases types rather than
# checking them, so a test could pass an options object where a connection string belongs,
# or import a type from a path that does not exist and silently get `any`, and every check
# here stayed green. This reads `server/tests` under the server's own compiler options and
# fails on any error that is not in `server/tests/typecheck-baseline.txt` — the errors that
# were already there when the check was turned on. New ones are new defects.
- name: server/tests types (baselined)
run: bun run typecheck:tests
- name: Desktop version tracks the release version
run: bun desktop/scripts/desktop-version.ts check
# The chart's default image tag is its appVersion, and a release must move both together. They
Expand Down Expand Up @@ -349,9 +359,12 @@ jobs:
# pinned by the desktop lockfile rather than the root one.
- run: bun install --frozen-lockfile
working-directory: desktop
# Not the db:migrate script: that one loads ../.env, which does not exist in CI. DATABASE_URL
# comes from the job env instead, which drizzle.config.ts already reads.
- run: bunx drizzle-kit migrate --config=drizzle.config.ts
# The same migrator a deployment runs, rather than `drizzle-kit migrate`: it is the one that
# refuses a database holding a stamp newer than the migrations it is about to walk past
# (server/src/db/migration-reach.ts), and a CI database that is ever reused rather than
# recreated is one of the places that can happen. Not the db:migrate script, which loads
# ../.env; that file does not exist in CI, and DATABASE_URL comes from the job env instead.
- run: bun scripts/migrate.ts
working-directory: server
# A passing job must include the expected test floor. Import-time failures can otherwise skip
# files before their tests are registered.
Expand Down
894 changes: 894 additions & 0 deletions agent-mastra/bun.lock

Large diffs are not rendered by default.

25 changes: 18 additions & 7 deletions app/src/components/gallery/activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { callComponentFunction } from "@/lib/components/queries";
import { useActiveBotId } from "@/lib/copilot/active-bot";
import { useConversation } from "@/lib/copilot/conversation";
import type { GalleryComponent } from "@/lib/copilot/gallery-registry";
import { keyedLookup } from "@/lib/lookup";
import { GalleryFrame } from "./frame";
import { seriesColour } from "./palette";

Expand Down Expand Up @@ -33,11 +34,19 @@ export const ActivityReportProps = z.object({

type ActivityArgs = z.infer<typeof ActivityReportProps>;

/** Which server-side function each report reads. Not the model's choice. */
const FUNCTION_FOR: Record<string, string> = {
activity: "botActivity",
refusals: "recentRefusals",
};
/**
* Which server-side function each report reads. Not the model's choice.
*
* A Map, read through `keyedLookup`, because the key is a string somebody else chose: an object
* lookup answers `toString` or `constructor` with a member inherited from `Object.prototype`,
* which is truthy and so walks straight past the `functionName ?` guards below — handing a
* function to the grant check as the data function this component reads, and to
* `callComponentFunction` as a function name.
*/
const FUNCTION_FOR: ReadonlyMap<string, string> = new Map([
["activity", "botActivity"],
["refusals", "recentRefusals"],
]);

type ActivityRow = { bot: string; actions: number };
type RefusalRow = {
Expand All @@ -61,7 +70,7 @@ export function ActivityReportCard({
const conversation = useConversation();
const [state, setState] = useState<State>({ status: "reading" });

const functionName = report ? FUNCTION_FOR[report] : undefined;
const functionName = report ? keyedLookup(FUNCTION_FOR, report) : undefined;

useEffect(() => {
// Nothing to read until the arguments have finished streaming in.
Expand Down Expand Up @@ -284,7 +293,9 @@ export const GALLERY: GalleryComponent[] = [
"The report is on screen for the person, filled with figures read from this deployment. You were not given the figures.",
reads: (args) => {
const report = typeof args.report === "string" ? args.report : undefined;
const functionName = report ? FUNCTION_FOR[report] : undefined;
const functionName = report
? keyedLookup(FUNCTION_FOR, report)
: undefined;
return functionName ? [functionName] : [];
},
},
Expand Down
251 changes: 251 additions & 0 deletions app/src/components/plugins/broker-directory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import { IconPlug } from "@tabler/icons-react";
import { useMutation, useQuery } from "@tanstack/react-query";
import * as React from "react";
import {
PageEmpty,
PageRows,
PageSection,
PageShell,
} from "@/components/layout/page-shell";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemMedia,
ItemTitle,
} from "@/components/ui/item";
import { Separator } from "@/components/ui/separator";
import {
consentBreadth,
coverageWarning,
matchingApps,
} from "@/lib/plugins/enablement-notes";
import {
enableComposioAppMutationOptions,
invalidatePlugins,
} from "@/lib/plugins/mutations";
import {
directoryReadFailure,
type PluginsProvider,
providerVocabulary,
} from "@/lib/plugins/provider-vocabulary";
import {
type ComposioApp,
composioAppsQueryOptions,
} from "@/lib/plugins/queries";
import { queryClient } from "@/query-client";

/**
* The active broker's directory, searched rather than listed.
*
* The catalogue on the previous screen is a reviewed handful, and every entry there is a decision
* somebody made about a vendor. This is a directory nobody here has reviewed, which is why it is a
* search field and not a list: the only sensible entry point into a directory that size is the name
* of the app you already came looking for.
*
* Adding one is account-wide, and it still reads nothing. Every app here is reached as whoever is
* asking, so a person's own connection is what makes their own mail or messages readable — which is
* made on their settings page, not here.
*
* A COMPONENT AND NOT A ROUTE, so both directory routes are the same screen rather than two that
* drift. A route file importing another route file is how that drift starts, so neither does. Every
* vendor word is read from {@link providerVocabulary}; nothing here spells a vendor, and nothing
* here branches on which one it is — a `provider === "composio"` test inside a screen is the same
* mistake wearing a conditional.
*/
export function BrokerDirectory({ provider }: { provider: PluginsProvider }) {
const { name, directoryLabel } = providerVocabulary(provider);
const [search, setSearch] = React.useState("");
/*
* Debounced, as on People, and for a stronger reason: every distinct term is a cache key of its
* own and a request to the vendor, so typing a name un-debounced is a round trip per keystroke
* against somebody else's rate limit.
*/
const [query, setQuery] = React.useState("");
React.useEffect(() => {
const timer = setTimeout(() => setQuery(search), 250);
return () => clearTimeout(timer);
}, [search]);

const apps = useQuery(composioAppsQueryOptions(query, provider));
/*
* WHAT A FAILED ADD SAID, KEPT WHERE A SECOND ADD CANNOT ERASE IT.
*
* ONE OBSERVER SERVES EVERY BUTTON, which is what `enable.variables` below is already written
* around — and the same fact makes `enable.error` unusable as the place a refusal lives.
* `MutationObserver.mutate` does `this.#currentMutation?.removeObserver(this)` and rebuilds, so
* `error`, `isPending` and `variables` describe ONLY the most recent press. An admin pressing Add
* on Slack and then, a beat later, on Gmail watched Slack's row revert from "Adding…" to "Add"
* with its request still in flight — and when Slack came back 409, or 503, or carrying the
* vendor's own sentence about a bad key, the banner never showed it, because `enable.error` was
* Gmail's and Gmail's was null. What was left was a row saying "Add" and no record of a failure.
*
* THE MUTATION-LEVEL `onError` STILL FIRES AFTER `removeObserver`, which is why this works and
* reading the observer does not. It is the shape the sibling grant screen already uses
* (`$key_.bots.$agentId.tsx`), arriving at the one screen that was reading the observer instead.
*/
const [enableError, setEnableError] = React.useState<string | null>(null);
/*
* AND WHICH ROWS ARE IN FLIGHT, FOR THE SAME REASON AND OUT OF THE SAME HOOKS.
*
* `enable.isPending && enable.variables?.slug === entry.slug` is the observer again: it names the
* most recent press and no other, so pressing Add on a second app put the FIRST row back to "Add"
* with its request still open — an invitation to press it again, which asks the server to enable
* an app it is already enabling. A set of slugs is what survives the rebuild, added in `onMutate`
* and removed in `onSettled` so it drains on a refusal exactly as it does on a success.
*/
const [adding, setAdding] = React.useState<ReadonlySet<string>>(new Set());
const enable = useMutation({
...enableComposioAppMutationOptions(queryClient),
onMutate: (input: { slug: string }) => {
setEnableError(null);
setAdding((held) => new Set(held).add(input.slug));
},
onError: (thrown: Error) => setEnableError(thrown.message),
/*
* SPELLED OUT RATHER THAN INHERITED, because the spread above carries an `onSettled` of its own
* — `invalidatePlugins` — and a second one here replaces it rather than running beside it. The
* refetch is what turns the added row into "Added", so dropping it would leave the list claiming
* the app is still addable until something else invalidated.
*/
onSettled: (_data, _error, input) => {
setAdding((held) => {
const left = new Set(held);
left.delete(input.slug);
return left;
});
return invalidatePlugins(queryClient);
},
});
const listed = matchingApps(apps.data?.apps ?? []);

return (
<PageShell
backButton={{ label: "Plugins", linkProps: { to: "/admin/plugins" } }}
description={`${name}'s own directory. Adding an app makes its tools available to grant; each person still connects their own account before any of them reads anything.`}
title={directoryLabel}
>
<PageSection
description="Search by name. The directory is too long to read, and nothing here has been reviewed by this deployment."
title="Apps"
>
{enableError ? (
<p className="mt-4 text-destructive text-sm" role="alert">
{enableError}
</p>
) : null}

<Input
aria-label={`Search ${name} apps`}
className="mt-4"
onChange={(event) => setSearch(event.target.value)}
placeholder="Search by app name"
value={search}
/>

{/* Pending, error, empty, rows — pending first, so no sentence asserts anything mid-fetch. */}
{apps.isPending ? null : apps.error ? (
<p className="mt-4 text-destructive text-sm" role="alert">
{/*
* The server's own sentence, as the enable failure above already does. A keyless
* deployment is refused with one naming the key's environment variable, and that name is
* the single thing an operator who reached this URL needs to read; the derived line
* stays as the fallback for a failure that arrived carrying no message of its own.
*/}
{apps.error.message || directoryReadFailure(provider)}
</p>
) : listed.length === 0 ? (
<PageEmpty>
{query
? `Nothing in ${name}'s directory matches "${query}".`
: `${name} returned no apps.`}
</PageEmpty>
) : (
<PageRows>
{listed.map((entry, index) => {
// One mutation serves every row, so which rows are mid-request is tracked beside it
// rather than read off it. See `adding` above.
const isAdding = adding.has(entry.slug);

return (
<React.Fragment key={entry.slug}>
{/* The test id names the screen, not the vendor: this module draws whichever
broker is active, and the id is not user-visible. */}
<Item data-testid={`directory-${entry.slug}`} size="sm">
{/* The vendor's own mark where the broker supplies one, and a plug where it does
not, so a list of third parties still has a fixed left edge. */}
<ItemMedia variant={entry.logo ? "image" : "icon"}>
{entry.logo ? (
<img alt="" src={entry.logo} />
) : (
<IconPlug />
)}
</ItemMedia>
<ItemContent>
<ItemTitle>{entry.name}</ItemTitle>
<ItemDescription>{entry.description}</ItemDescription>
{entry.enabled ? null : <CoverageNote app={entry} />}
{entry.enabled ? null : <BreadthNote app={entry} />}
</ItemContent>
<ItemActions>
{/* The size of the decision, stated before it is made: an app is not one
tool, and "167 actions" is what says so. */}
<span className="text-muted-foreground text-xs">
{entry.actionCount} actions
</span>
{/*
* An app this deployment already has says so rather than offering Add again.
* A second Add would ask the server to record a connector it already holds,
* and there is nothing on the row to suggest that would be harmless.
*/}
{entry.enabled ? (
<span className="text-muted-foreground text-xs">
Added
</span>
) : (
<Button
disabled={isAdding}
onClick={() => enable.mutate({ slug: entry.slug })}
size="sm"
variant="outline"
>
{isAdding ? "Adding…" : "Add"}
</Button>
)}
</ItemActions>
</Item>
{index !== listed.length - 1 && <Separator />}
</React.Fragment>
);
})}
</PageRows>
)}
</PageSection>
</PageShell>
);
}

/** The warning on a row, shown before Add is pressed. Draws nothing when there is none. */
export function CoverageNote({ app }: { app: ComposioApp }) {
const warning = coverageWarning(app);
if (!warning) return null;
return (
<p className="text-muted-foreground text-xs" data-testid="coverage-warning">
{warning}
</p>
);
}

/** The breadth line on a row, shown before Add is pressed. Draws nothing when there is none. */
export function BreadthNote({ app }: { app: ComposioApp }) {
const breadth = consentBreadth(app);
if (!breadth) return null;
return (
<p className="text-muted-foreground text-xs" data-testid="breadth-note">
{breadth}
</p>
);
}
Loading
Loading