refactor(projects): share safe dashboard and CLI operations by salmonumbrella · Pull Request #602 · runkids/skillshare · GitHub
Skip to content

refactor(projects): share safe dashboard and CLI operations - #602

Merged
runkids merged 1 commit into
runkids:mainfrom
salmonumbrella:feat/project-cli-core
Oct 22, 2026
Merged

runkids merged 1 commit into
runkids:mainfrom
salmonumbrella:feat/project-cli-core

Conversation

@salmonumbrella

@salmonumbrella salmonumbrella commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What changed

  • Move the dashboard's project list, save and remove into a shared internal/projects service, with the detach and bounded sync execution the CLI in part 2 builds on. This PR holds only what the dashboard uses today.
  • Validate the actual project YAML candidate before writing. Ordinary Config.Save() callers keep their existing path.
  • Serialize dashboard project mutations with gofrs/flock and reload after acquisition. The lock lives in the state dir, like the MCP and hooks locks, so it never lands in a pushed config folder.
  • Saving a project still only validates and writes. Remove still detaches every project target under the root, including agents-only projects with a leftover skills manifest.

Deliberate behavior changes:

  • On a partial failure, remove keeps local files, surviving target ownership and the detach work already done, and reports them.
  • SkillsPathKeptBy compares paths with PathsEqual. On Windows a case-different spelling is the same folder, so target remove keeps it for the other target instead of unlinking it.

Why

Repository and worktree setup currently needs a YAML edit or the dashboard to register a global project. This prepares the shared operations the CLI needs while keeping the existing dashboard contracts.

Usage

No usage change.

Part 1 of the two-PR implementation approved in #591 and proposed in #592. Part 2 is #603, which adds all six commands, edit-time detach, completions, docs and end-to-end coverage.

Type

  • Small improvement (shared extraction with project safety fixes)

Linked Issue

Refs #591 and #592.

Checklist

  • I've read CONTRIBUTING.md
  • Tests included and passing (make check): focused runs below, CI for the rest
  • No unrelated changes in the diff
  • Scope is focused: only operations the dashboard uses today

Focused project, config, sync, sourcefs and server tests pass in the devcontainer, along with Windows cross-vet. The git-backed check and web-ref tests fail there on the base commit too, because a linked worktree's git dir isn't mounted, so CI covers them. A local Roborev review of the final commit is clean.

@salmonumbrella
salmonumbrella force-pushed the feat/project-cli-core branch 2 times, most recently from eddb3e3 to d8b4b7c Compare October 21, 2026 17:42
@salmonumbrella
salmonumbrella marked this pull request as ready for review October 21, 2026 19:03
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

@runkids

runkids commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Thanks for splitting this so carefully, and for keeping the safeguards from #591 intact. The lock coverage, read-only loading and partial-failure reporting all held up when I traced them. A few things before this can land:

Needs a change

  1. Lock file ends up in git. internal/projects/lock.go:21 creates config.yaml.projects.lock next to the config and never removes it. With git_root: root, WriteScopeGitignore only ignores config.yaml, so the next skillshare push (git add -A) commits the lock file. The MCP and hooks services keep their locks in the state dir (internal/mcp/service.go:172, internal/hooks/service.go:364). Could this follow the same pattern?
  2. Dashboard save now detaches folders. handleSaveProject → Service.Put → detachDeparting (internal/projects/service.go:172). On main, saving a project only validated and wrote config; only remove detached. Unticking a target in the dashboard editor now removes its manifest and copies links back. That matches the proposal's edit-detach behavior, but the PR describes itself as behavior-preserving apart from two deliberate fixes. Please either list it as a third deliberate change (with a test) or move it to feat(project): manage global registrations from the CLI #603.
  3. CLI-only code in the shared layer. At this commit the dashboard calls List, Put and Remove. Service.Sync, Show, Find and StoredKey are only used by feat(project): manage global registrations from the CLI #603. Service.Sync (about 85 lines) also re-implements validation, backup and discovery, while skillshare sync keeps its own path. The scope note on Manage global project registrations from the CLI #591 asked to extract only what both interfaces need and to reuse the existing sync orchestration where practical. Could these move into feat(project): manage global registrations from the CLI #603, ideally reusing the CLI sync flow?
  4. SkillsPathKeptBy now uses PathsEqual (internal/config/path_overlap.go:96). target remove also calls it, so on Windows a case-different skills path is now treated as shared and kept. Possibly right, but it is a global change not listed in the PR description.

Please double-check

  1. Remove now only detaches targets in enabledSkillTargets (service.go:196-201, 241-250). For an agents-only project (skills: null) whose skills-path targets were synced with exclude: ["*"], the manifest and any leftover links seem to stay behind. main removed them. I have only read this, not reproduced it.

Optional

  • save_candidate.go:50-98 adds another temp-file-and-rename writer. writeFileAtomic in internal/server/handler_skill_content.go already does this.
  • The oracle in root_fuzz_test.go is the function's own spec, and it skips the risky inputs (~user, drive-relative paths). The table tests may be enough.

Happy to talk through any of these. If one of them is intentional, a short note in the description is fine.

@salmonumbrella

Copy link
Copy Markdown
Contributor Author

@runkids runkids left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for the quick turnaround. I checked all five against 0fa2d6d2:

  1. The lock is now in <state>/projects/, and lock_test.go checks that nothing gets created next to the config.
  2. Service.Put no longer detaches, so saving from the dashboard behaves as it does on main.
  3. The CLI-only surface is gone. ExecuteTargets now has a single caller, the dashboard, and is the dashboard's existing flow moved into internal/sync.
  4. Your reasoning on PathsEqual holds, and having it listed as deliberate with a Windows test is exactly what I was hoping for.
  5. Agents-only remove matches main again, and the safeguards_test.go case covers it.

Keeping the save_candidate.go writer separate is fine. Preserving the mode and honoring the umask on first create is a real difference.

Approving. For #603: once it's rebased on this commit and project sync reuses the skillshare sync flow, I'll review it again along with the points from my earlier comment there. Thanks again for the careful work.

@runkids
runkids merged commit d23a44a into runkids:main Oct 22, 2026
8 checks passed
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.

2 participants