Skip to content

feat(docker): support project-specific Dockerfiles#63

Open
ASRagab wants to merge 13 commits intojohannesjo:mainfrom
ASRagab:feat/per-project-dockerfile
Open

feat(docker): support project-specific Dockerfiles#63
ASRagab wants to merge 13 commits intojohannesjo:mainfrom
ASRagab:feat/per-project-dockerfile

Conversation

@ASRagab
Copy link
Copy Markdown
Contributor

@ASRagab ASRagab commented Apr 7, 2026

Summary

  • detect and build project-specific Dockerfiles from .parallel-code/Dockerfile
  • pass an explicit project build context into Docker builds instead of inferring from the Dockerfile directory
  • track Docker source explicitly (default | project | custom) instead of inferring UI state from image-tag prefixes
  • harden Docker image checks for unreadable custom Dockerfiles and clean up the new-task / Docker UI flow
  • ignore repo-local .worktrees/** in Electron Vite dev mode so task creation does not trigger renderer reloads

Validation

  • npm run compile
  • npm run lint
  • npm test
  • npm run typecheck

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support for project-specific Dockerfiles by detecting .parallel-code/Dockerfile, building with an explicit project build context, and persisting an explicit Docker source (default | project | custom) so the UI no longer infers state from image-tag prefixes.

Changes:

  • Introduces DockerSource metadata on tasks and persistence migration to infer it for legacy tasks.
  • Adds project Dockerfile resolution + deterministic project image tagging and updates Docker image existence/build flows to accept custom Dockerfile/build-context inputs.
  • Prevents Electron Vite dev server from reloading when repo-local .worktrees/** changes.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/store/types.ts Persists dockerSource on Task and PersistedTask.
src/store/tasks.ts Threads dockerSource through task creation options into stored task state.
src/store/persistence.ts Saves/loads dockerSource and infers it for legacy persisted tasks.
src/lib/docker.ts Adds shared Docker constants + docker source inference and UI label helpers.
src/lib/docker.test.ts Adds label tests for docker display helpers.
src/components/TaskTitleBar.tsx Shows Docker badge label derived from dockerSource and adds image title tooltip.
src/components/TaskAITerminal.tsx Refactors InfoBar status logic and updates Docker overlay label from dockerSource.
src/components/SettingsDialog.tsx Uses shared default image constant and documents project Dockerfile behavior.
src/components/NewTaskDialog.tsx Detects project Dockerfile via IPC, adjusts image checks/build args, and persists docker source/image appropriately.
eslint.config.js Ignores Electron Vite config test file for linting.
electron/vite.config.electron.ts Ignores **/.worktrees/** in dev watch to avoid renderer reloads during task creation.
electron/vite.config.electron.test.ts Tests that Vite watch ignores nested .worktrees directories.
electron/tsconfig.json Excludes Electron Vite config + its test from Electron TS config compilation.
electron/preload.cjs Allows new resolve_project_dockerfile IPC channel.
electron/ipc/register.ts Adds IPC handlers/arg validation for resolving project Dockerfiles and for docker image checks/builds with optional inputs.
electron/ipc/pty.ts Adds project dockerfile resolution + hashing/tagging; extends docker image checks/builds; updates container HOME to /tmp.
electron/ipc/pty.test.ts Adds/extends tests for docker HOME behavior and new dockerfile/hash/build context helpers.
electron/ipc/channels.ts Defines ResolveProjectDockerfile IPC channel.
.prettierignore Ignores additional repo-local files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/>
</div>
>
<span>📁</span>
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The folder emoji is rendered as a literal character. For better accessibility/screen-reader behavior, consider using a real icon component or marking the emoji aria-hidden and providing an accessible text label.

Suggested change
<span>📁</span>
<span aria-hidden="true">📁</span>

Copilot uses AI. Check for mistakes.
Merge upstream/main, resolve conflict in NewTaskDialog.tsx, and address
Copilot review feedback: cross-platform path splitting, file-type check
in resolveProjectDockerfile, inferDockerSource test coverage, and
aria-hidden on emoji span.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ASRagab
Copy link
Copy Markdown
Contributor Author

ASRagab commented Apr 9, 2026

Resolved the merge conflict with upstream/main and addressed all review comments:

  1. fileNameFromPath cross-platform split — now splits on both / and \ via /[\\/]/
  2. resolveProjectDockerfile file-type check — uses statSync().isFile() instead of bare existsSync to reject directories and non-regular files
  3. inferDockerSource test coverage — added cases for default image, project prefix, custom tag, and undefined
  4. Emoji accessibility — added aria-hidden="true" to the folder emoji span

@johannesjo
Copy link
Copy Markdown
Owner

Thank you very much! <3

@johannesjo
Copy link
Copy Markdown
Owner

Reviewed the diff including the follow-up addressing all 4 Copilot comments (cross-platform path split, statSync().isFile(), inferDockerSource test coverage, aria-hidden). Those are all correctly resolved.

One new issue worth flagging:

One-way Docker ratchet in NewTaskDialog

createEffect(() => {
  if (skipPermissions() && store.dockerAvailable) {
    setDockerMode(true);
  }
});

This auto-enables Docker when "skip permissions" is checked, but has no inverse — unchecking skip-permissions leaves Docker mode on. The user would have to manually uncheck Docker mode. If this is intentional (i.e. skip-permissions always implies Docker), a comment would clarify the intent. If unintentional, the effect should also handle the reverse:

createEffect(() => {
  if (skipPermissions() && store.dockerAvailable) {
    setDockerMode(true);
  } else if (!skipPermissions()) {
    setDockerMode(false);
  }
});

(Or drop the effect entirely and rely on the existing "Enable Docker" suggestion UI that was already shown when skip-permissions was active.)

Everything else looks good — the buildDockerImage deduplication logic, IPC validation, dockerSource persistence migration, and cleanup handling in createEffect are all solid.

Copy link
Copy Markdown
Owner

@johannesjo johannesjo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All four original Copilot review comments were correctly addressed. One UX issue before merge:

One-way Docker ratchet — in NewTaskDialog, a createEffect auto-enables Docker when 'skip permissions' is checked, but there is no inverse: unchecking 'skip permissions' leaves Docker enabled. This can silently enable Docker mode for users who toggle that checkbox and then change their mind. Consider adding the inverse side-effect, or making the coupling explicit in the UI. Details in the review comment.

The rest of the PR (Dockerfile detection, DockerSource migration, Vite watch fix) is well-implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants