Repository navigation
feat(mcp-worker): forest-tracked AI-workspace I/O (putFlat/getFlat/listFilesFromForest) - #68
Merged
Merged
Conversation
…stFilesFromForest) The hosted MCP Worker stored AI files with putEncryptedWithType — a raw encrypted- object PUT that never registers the object in the bucket's private-forest index. Result: AI files were readable by exact key but NOT enumerable, so they never appeared in FxFiles (or the AI's own fula_list_files). See functionland/fula-api#82. Switch every workspace I/O path to the forest-tracked bindings (the same ones the FxFiles app already uses): - storeFile + applyTaggingToDoc putEncryptedWithType -> putFlat (upsert + flush) - readFile + tag-doc read getDecrypted -> getFlat (forest + CID read) - listFiles + search listDecrypted -> listFilesFromForest (listFiles' category narrowing moves to the post-filter; the raw listDecrypted prefix-filtered the OBFUSCATED storage keys and returned nothing for this bucket.) Concurrency: put_object_flat flushes the forest with a conditional PUT; a concurrent writer makes it 412 (ConcurrentModification). The wasm flush is single-attempt, so withWorkspaceClient now retries on 412 — re-creating the client drops the stale forest cache so the next attempt reloads the winner's forest and re-applies the write (bounded + jittered; read-only bodies never 412). Requires @functionland/fula-client ^0.6.17 (the build that exports putFlat/getFlat/ listFilesFromForest). Verified: tsc clean + a workerd (vitest-pool-workers) integration test driving putFlat -> listFilesFromForest -> getFlat against the prod gateway, in the Worker runtime, round-trips byte-exact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0161UGEJmTpM6DM2cVZyV6Ev
ehsan6sha
added a commit
to functionland/FxFiles
that referenced
this pull request
Jun 25, 2026
…rol (1.i/1.ii/1.iii) (#93) After the Worker writes AI files forest-indexed (functionland/pinning-service#68 + functionland/fula-api#82), FxFiles can see + move them. Three parts: P1 (1.i) category map: the MCP writes SINGULAR category segments (ai/document/, ai/note/, ai/image/ …); FxFiles' category views are PLURAL. _mergeAiWorkspaceInto now maps them (images<-image+screenshot, documents<-document+note+link, other<-file+other) and folds the AI categories with no FileCategory of their own into the closest view. A view with no AI mapping (downloads/archives/starred) short-circuits. P2 (1.i) cloud-files: the bucket view routes fula-ai-workspace through the workspace client (workspace secret) instead of the master-KEK listObjects, so the AI files decrypt + list, tagged sourceBucket for correct open/move routing. P3 (1.ii/1.iii) move-as-access-control: moving a file INTO the AI bucket re-encrypts it under the workspace secret + forest-indexes it (grant AI read) under an ai/<category>/<name> key; moving OUT re-encrypts under the master KEK and removes the workspace copy (revoke). The revoke is VERIFIED: the re-encrypted master copy must decrypt BEFORE the AI copy is deleted, then the AI copy is verified gone — "revoke incomplete" is surfaced loudly otherwise. All re-keying is client-side (the KEK never leaves FxFiles). New primitives: uploadWorkspaceObject (putFlat), deleteWorkspaceObject (deleteFlat, which removes the forest entry too). The move orchestration is factored into a UI-free aiAwareMove() so the security- critical revoke is unit-tested (grant / verified-revoke / abort-without-delete-on- failed-verify / normal-move). flutter analyze clean (0 errors); 25 AI unit tests green. Claude-Session: https://claude.ai/code/session_0161UGEJmTpM6DM2cVZyV6Ev Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The hosted MCP Worker stored AI-workspace files with
putEncryptedWithType— a raw encrypted-object PUT that writes the blob but never registers it in the bucket's private-forest index. So AI files were readable by exact key but not enumerable → invisible to FxFiles and to the AI's ownfula_list_files. (Root cause + the new bindings: functionland/fula-api#82.)Change
Switch every workspace I/O path to the forest-tracked bindings — the same ones the FxFiles app already uses for every file:
storeFile,applyTaggingToDocputEncryptedWithTypeputFlat(upsert + flush_forest)readFile, tag-doc readgetDecryptedgetFlat(forest + CID-aware)listFiles,searchlistDecryptedlistFilesFromForestlistFilescategory narrowing moves to the post-filter (the rawlistDecryptedprefix-filtered the obfuscated storage keys → returned nothing).put_object_flatflushes via a conditional PUT → a concurrent writer 412s (ConcurrentModification); the wasm flush is single-attempt, sowithWorkspaceClientnow retries on 412 (re-creating the client drops the stale forest cache → reload the winner's forest → re-apply; bounded + jittered; read-only bodies never 412).Requires
@functionland/fula-client ^0.6.17(the build exportingputFlat/getFlat/listFilesFromForest). Not yet published — deploy is gated on the publish. No deploy-on-merge CI, so merging is safe.Test
tsc --noEmitclean (zero errors in the changed files).@cloudflare/vitest-pool-workers):putFlat→listFilesFromForest→getFlatagainst the prod gateway, inside the Worker runtime → round-trips byte-exact. ✅🤖 Generated with Claude Code