Skip to content

feat: edit a registered member's project dir from the app - #581

Open
otsune wants to merge 1 commit into
fujibee:mainfrom
otsune:feat/edit-project-dir
Open

feat: edit a registered member's project dir from the app#581
otsune wants to merge 1 commit into
fujibee:mainfrom
otsune:feat/edit-project-dir

Conversation

@otsune

@otsune otsune commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

join.sh only ever adds a registration, so a team or agent whose project dir was mistyped (or whose repo moved) could only be fixed by leaving and re-joining. This PR adds a sanctioned way to repoint registrations in place, and surfaces it in the desktop app.

  • core: new scripts/set-project.sh <team> <agent_id> <new_project> [--type <type>] — rewrites the matching registrations' project (all of them, or one type via --type). Follows join.sh's per-team locking (Team registry read-modify-write updates lose concurrent changes #141) and SQL-literal escaping (Harden SQLite query construction and parameter handling #87) conventions; normalizes legacy {type,project} records via full-replacement (a json_patch merge would leave the old top-level keys behind); collapses registrations that land on an existing identical one.
  • api.sh: get teams <team> members now also emits a registrations: [{type, project}] array (existing name/types/project fields unchanged), so consumers can read a specific type's project instead of the first registration's.
  • app: "Change project directory…" context-menu items on team rows and member rows, opening a small modal (current value + Browse). The team-row flow always pins --type agmsg-app and takes its current value from the app-user registration — never Member.project (first registration) — so a same-named agent's other registrations can't be dragged along with the team dir (found in adversarial review). Member rows deliberately move all of that agent's registrations (others already excludes the app-user type). Both items are feature-gated on the installed core actually having set-project.sh, so an older core never shows an action that would fail. i18n keys added to all 9 locales.

Tests

  • 18 new bats cases in test_team.bats (repoint, --type scoping, the agmsg-app + claude-code cross-type scenario, dedup, single-quote names/paths, lock release on success and failure paths, whoami resolution at the new path) + 1 in test_api.bats — full suites pass (85/85, 19/19)
  • 2 Windows-gated Rust regression tests for the Title: Windows app: MSYS-style registration path used verbatim as spawn cwd — agents run #315 MSYS→native path handling in agmsg_set_projectcargo test 60 passed
  • vitest 183 passed, tsc/vite build clean
  • Verified end-to-end in a dev build on Windows: menu → modal shows the app-user registration's dir; native menu untouched on cores without the script

Note: the app-side feature stays dormant until a core release ships set-project.sh and app/AGMSG_CORE_REF is bumped accordingly.

Co-Authored-By: Claude noreply@anthropic.com

join.sh only ever ADDS a registration, so a team or agent whose project
dir was mistyped (or whose repo moved) could only be fixed by leaving
and re-joining. Add scripts/set-project.sh to repoint registrations in
place (all of them, or one type via --type), and surface it in the
desktop app as a "Change project directory..." context-menu item on
team rows and member rows.

- core: set-project.sh follows join.sh's locking (fujibee#141) and SQL-literal
  escaping (fujibee#87) conventions; normalizes legacy {type,project} records
  via full-replacement (json_patch would leave the old top-level keys
  behind) and collapses registrations that land on an existing
  identical one
- api.sh: get_members now also emits a registrations [{type,project}]
  array so the app can read a specific type's project instead of the
  first registration's
- app: the team-row flow always pins --type agmsg-app and takes its
  current value from the app-user registration, never Member.project
  (first registration) - moving a same-named agent's other
  registrations along with the team dir was flagged in adversarial
  review. Member rows deliberately move all of that agent's
  registrations. Both items are feature-gated on the installed core
  having set-project.sh
- tests: 18 bats cases (incl. the agmsg-app + claude-code cross-type
  scenario), 2 Windows-gated Rust regression tests for the fujibee#315
  MSYS-path handling

Co-Authored-By: Claude <noreply@anthropic.com>
@fujibee

fujibee commented Aug 1, 2026

Copy link
Copy Markdown
Owner

@otsune

Thank you for this, and for the write-up — the summary states the part that matters before anyone has to go looking for it.

When we talked on X I had this filed as an app-side change. Reading the PR, the core half is the substantive one, and your first line is why: join.sh only ever adds. Between join, leave and reset, core today has "register" and "unregister" and nothing that edits an existing registration. set-project.sh would be the first operation that rewrites one in place.

That is worth being deliberate about, because a registration's project is not just a stored path — it is the key identity resolution runs on. whoami resolves an agent from (project, type), the watcher's subscription is derived from it, and run/ state hangs off the result. Adding or removing a registration changes which mappings exist; rewriting one changes a mapping that live sessions may already be standing on. Nothing in your patch looks careless about that — pinning --type agmsg-app on the team row rather than trusting Member.project is exactly the right instinct, and the failure-path lock-release tests are the kind we ask of ourselves — but it is a shape core has not had before, so we would rather look at it properly than merge it quickly.

So: we are reviewing it as a core change, not an app one. I am not going to attach a date to that, because a date I cannot keep is worse than no date. If we come back with anything it will be specific.

The api.sh half reads as straightforwardly additive and separable, for what that is worth.

@fujibee

fujibee commented Aug 1, 2026

Copy link
Copy Markdown
Owner

@otsune

Following up with what the read turned up, because it changed our view of the problem rather than of the patch.

What repointing touches beyond the config. project is not only stored in the team config — several pieces of runtime state derive from it independently, and none of them go through the config to do it:

Your tests pin the config-level behaviour well — including the failure path leaving the config untouched, which is the one we would have asked for. The gap is not in them; it is that the state which would need to move alongside does not live in the config at all.

The part we think is actually ours. Following that through, project is carrying two jobs in one field: it is the working directory an agent runs in, and it is the input whoami resolves an identity from. What you wanted — a directory that was mistyped or has moved — is the first. It cannot be changed without also changing the second, and the runtime state above keys off the path a third time, independently.

The same conflation runs into the app: what the New Team dialog presents as the team's project dir is the app-user's registration (--type agmsg-app), because core has no team-level path at all. Pinning that type on the team row rather than trusting Member.project is exactly right, and it is right because of this — the two rows are the same operation on different registrations.

So: we think the project concept in agmsg needs revisiting, not that this patch got it wrong. As it stands the operation would need to carry every piece of runtime state with it, which is a lot to ask of one script; if project were an attribute of an identity rather than the key that resolves it, this would be a small and obviously safe change instead.

We do not have an answer to that yet and are not going to invent one in a hurry. Meanwhile the api.sh half stands on its own and is not entangled in any of this.

Thank you for the push — the design question was sitting there before your PR, and it took your PR to make anyone look at it.

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