feat(daemon): add link code folder support for agent context#455
feat(daemon): add link code folder support for agent context#455mrcfps merged 5 commits intonexu-io:mainfrom
Conversation
Users can now link local code directories to a project so the AI agent reads their source code via --add-dir when generating designs. The import menu's "Link code folder" item opens a native OS folder picker, and linked folders appear as removable chips below the chat input. - Add linkedDirs field to ProjectMetadata contract - Add POST /api/dialog/open-folder endpoint (osascript/zenity/PowerShell) - Add validateLinkedDirs with path safety checks (absolute, exists, blocklist) - Append linked dirs to extraAllowedDirs in startChatRun - Add system prompt hint listing linked code folders - Render linked folder chips in ChatComposer with add/remove - Add i18n strings for all 16 locales - Add 8 unit tests for validateLinkedDirs
|
Hi @encyc! 🎉 Thanks for the contribution — this is a well-scoped feature with solid testing and i18n coverage. Thanks for making open-design better! |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 79442739ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Add JSDoc type annotations to validateLinkedDirs for strict mode - Check path.isAbsolute before resolve to catch relative inputs - Allow linking when projectMetadata is undefined (default to prototype) - Remove redundant PATCH in ProjectView callback
mrcfps
left a comment
There was a problem hiding this comment.
@encyc thanks for tightening up the link-folder flow and addressing the earlier feedback. One TypeScript build blocker still remains in the new daemon helper, so I’m requesting one more small change before merge. 🙂
Generated by Looper 0.5.4 · runner=reviewer · agent=opencode
lefarcen
left a comment
There was a problem hiding this comment.
Thanks @encyc for addressing the typing issue! The JSDoc annotations should satisfy TypeScript strict mode.
Code review (Lens A):
- ✅ Security: Solid validation — absolute path enforcement, blocked system directories, existence + isDirectory checks, and deduplication. No path traversal risk.
- ✅ Tests: 8 unit tests cover the critical edge cases (relative paths, non-existent, files vs dirs, duplicates, normalization).
- ✅ Error handling: The validation returns structured errors with clear messages.
- ✅ Architecture: Clean separation (validateLinkedDirs helper → server.ts PATCH endpoint → web UI chips). Reuses existing
extraAllowedDirspipeline.
Minor observation (non-blocking): linked-dirs.ts line 18 checks !path.isAbsolute(d) then line 20 does path.resolve(d), which always produces an absolute path. The isAbsolute check before resolve is technically redundant (resolve already handles relative inputs), but keeping it makes the error message clearer for users who pass relative paths, so it's fine as-is.
Overall this is production-ready. The typing fix addresses mrcfps's blocking feedback. No security or correctness issues found.
Looks good to me; deferring final approval to a maintainer.
lefarcen
left a comment
There was a problem hiding this comment.
Perfect! The TypeScript annotations are now inline as requested.
Current head ():
- ✅ Explicit TS parameter type:
dirs: unknown - ✅ Explicit TS return type:
{ dirs: string[]; error?: undefined } | { error: string; dirs?: undefined } - ✅ Validated array typed:
const validated: string[] = []
This resolves mrcfps's blocking feedback. The daemon package will now type-check correctly with strict mode enabled. All prior review points (security validation, test coverage, architecture) remain solid.
Looks good to me; deferring final approval to a maintainer.
lefarcen
left a comment
There was a problem hiding this comment.
Perfect! The TypeScript annotations are now inline as requested.
Current head (cead90b):
- ✅ Explicit TS parameter type:
dirs: unknown - ✅ Explicit TS return type:
{ dirs: string[]; error?: undefined } | { error: string; dirs?: undefined } - ✅ Validated array typed:
const validated: string[] = []
This resolves mrcfps's blocking feedback. The daemon package will now type-check correctly with strict mode enabled. All prior review points (security validation, test coverage, architecture) remain solid.
Looks good to me; deferring final approval to a maintainer.
mrcfps
left a comment
There was a problem hiding this comment.
@encyc thanks for the quick follow-up on the earlier typing and UI-state feedback. I found two linked-folder validation gaps that can still widen agent filesystem access beyond the intended policy, so I’m requesting changes before merge. 🙂
Generated by Looper 0.5.4 · runner=reviewer · agent=opencode|
mrcfps's latest review (14:59) found two filesystem security gaps that I missed earlier — both are P1. The inline comments on linked-dirs.ts and server.ts point to the exact validation bypasses. These need to be fixed before merge. Sorry for the earlier "production-ready" assessment — I should have caught the root/symlink bypass and the project-creation validation gap. |
- Resolve symlinks with realpathSync.native before checking blocklist - Reject filesystem root (/) and drive roots as linked dirs - Canonicalize blocklist entries to handle macOS /etc -> /private/etc - Validate linkedDirs on project creation, not just PATCH - Re-validate persisted linkedDirs in startChatRun before use - Add tests for root, symlink-to-blocked-dir, and realpath resolution
|
Both P1 security fixes look correct on c68c125: Path validation bypass (mrcfps comment 3182461516): Project creation bypass (mrcfps comment 3182461522): Waiting for mrcfps to re-review the current head. |
|
Hi @encyc! Thanks for the work here — looks like CI is currently failing on |
|
Hi @encyc — I verified the latest push (d99282a) and it still has unguarded
These need Quick fix: change those lines to |
mrcfps
left a comment
There was a problem hiding this comment.
Thanks again @encyc for the thoughtful work and the quick follow-ups here. I really appreciate how promptly you addressed the CI/typecheck issue and tightened the validation details along the way. CI is green now, and this looks good to me — nice work pushing this feature through! 🙌
|
Thanks again @encyc for the thoughtful iteration on this feature and the quick security/typing fixes throughout the review! 🎉 The link-folder validation is now solid, and the pipeline gives users full codebase context. Really appreciate the careful follow-through here. — open-design team |


Summary
Enables the "Link code folder" import menu item so users can link local code directories to a project. The AI agent then reads the linked source code via
--add-dirwhen generating designs, giving it full context of the user's codebase.POST /api/dialog/open-folderendpoint opens a native OS folder picker (osascript on macOS, zenity on Linux, PowerShell on Windows). Linked directories are validated (absolute path, exists on disk, is a directory, not a sensitive system path), stored inmetadata.linkedDirson the project record, and appended toextraAllowedDirsinstartChatRunso the agent receives them via--add-dir.linkedDirs?: string[]added toProjectMetadata.validateLinkedDirscovering valid paths, relative paths, non-existent dirs, files, duplicates, and normalization.No new dependencies. No database migration (uses the freeform
metadata_jsoncolumn). No changes to agent adapter code — the existingextraAllowedDirs→--add-dirpipeline is reused.Test plan
pnpm --filter @open-design/daemon test— 436 tests pass (including 8 new)pnpm --filter @open-design/web typecheck— clean