Skip to content

fix(app): list draft projects from every connected Environment - #402

Merged
oxwen11 merged 18 commits into
mainfrom
fix/draft-projects-per-environment
Oct 6, 2026
Merged

oxwen11 merged 18 commits into
mainfrom
fix/draft-projects-per-environment

Conversation

@oxwen11

@oxwen11 oxwen11 commented Sep 25, 2026

Copy link
Copy Markdown
Owner

What

The draft picker only listed the active Environment's projects, so a linked host's projects were invisible until its Environment became the draft target. The picker now:

  • fans project.list across every connected Environment — same prefixed cache keys the sidebar and catalog worker use, so it subscribes to warm caches;
  • groups the list per Environment and labels each group with its Environment title when more than one has projects (single Environment stays unlabeled, unchanged DOM);
  • writes the owning Environment's environmentId into ?environmentId= when a project is picked.

Non-project chats stay local (~/Pie allocation is local-only, per CONTEXT.md): clearing the project drops the environmentId hint, and a linked host's picker hides every path back to null — no clear (X), no Choose project item, no Don't work in a project. A stale /draft?environmentId=<remote> URL with no project disables send instead of allocating remotely.

The empty-import draft state now appears only when every connected Environment has no imported projects; a remote-only catalog is enough to compose.

Verification

  • pnpm exec vitest run --config apps/app/vitest.browser.config.ts src/features/projects/project-select.test.tsx — 3 tests in real Chromium: local null mode keeps clear + Don't-work button; requireProject hides every path back to null; multi-Environment popup renders both labels and picking a remote project emits the owning environmentId.
  • pnpm --filter @getpie/app test — 199 passed.
  • turbo run typecheck lint:check --filter=@getpie/app + oxfmt --check — clean; react-doctor --scope changed --blocking warning 100/100.
  • Gap: no live screenshot/video. Ports 4180/4190 are held by another worktree's active pie-verify web run (Vite is strictPort), and no SSH Environment is connected here, so the grouped popup was proven via the browser test rather than a driven UI. Happy to attach runtime captures once 4190 frees up.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit 0c1e7e5.

@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
npx https://pkg.pr.new/oxwen11/pie/@getpie/cli@402

commit: 0c1e7e5

@oxwen11

oxwen11 commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head 060d5c6ebc71b4d0c5aab27c00aac1da995c7985 — required CI green (Check, react-doctor, both Publish @getpie/cli preview), MERGEABLE (BEHIND).

out of .agents/rules/auto-merge-pr.md allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect now fans out across every connected Environment (useQueries / grouped ProjectGroup), writes ?environmentId= with the pick, and adds requireProject control flow that disables clear / "Don't work in a project" / send-without-project on linked hosts
  • not presentation-only: new selection type + onChange contract, CONTEXT.md glossary drift, verify skill behavior change

needs human review (multi-Environment draft path).

@oxwen11

oxwen11 commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner Author

Runtime proof

Isolated desktop verify (CDP 9333, separate PIE_HOME). Web 4180/4190 were held by another worktree, so this run did not touch them.

Drive: draft picker on the isolated sample project.

  • before: Choose project
  • open: sample project and path
  • pick: URL becomes /draft?projectId=…&environmentId=… (owning Environment is written)
  • reopen: Don't work in a project
  • clear: both projectId and environmentId drop; back to /draft

recording-001.webm is that drive. SSH to the laptop refused with a version mismatch, so the multi-Environment group labels were not on this live window. Those labels are covered by the Chromium component test.

draft-picker-before

draft-picker-open

draft-picker-selected

draft-picker-dont-work

draft-picker-cleared

recording-001.webm

@oxwen11

oxwen11 commented Sep 25, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head def1124d128867423f375c85d862560a4ccaf1a5 — required CI green (Check, react-doctor, both Publish @getpie/cli preview), MERGEABLE (CLEAN). Prior no was on 060d5c6…; re-reviewed this updated head.

out of .agents/rules/auto-merge-pr.md allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect fans out across every connected Environment (useQueries / grouped ProjectGroup), writes ?environmentId= with the pick, and adds requireProject control flow that disables clear / "Don't work in a project" / send-without-project on linked hosts
  • non-presentational product + routing/query changes in draft.tsx, draft-composer.tsx, project-select.tsx (plus verify skill / CONTEXT docs and new browser tests for that behavior)

not presentation-only; leave for human review.

@oxwen11

oxwen11 commented Sep 28, 2026

Copy link
Copy Markdown
Owner Author

Runtime proof

Isolated web verify at http://localhost:4190/ (single Environment: this device).

Drive: draft project picker.

  • before: Choose project
  • open: verify-pie-sample and its path. One Environment, so no group label.
  • pick: URL becomes /draft?projectId=…&environmentId=…
  • reopen: Don't work in a project
  • clear: both search params drop, back to /draft

recording-001.webm is that drive. Group labels need a second connected Environment; this run had none, so that split is covered by the Chromium component test, not this window.

draft-picker-before

draft-picker-open

draft-picker-selected

draft-picker-dont-work

draft-picker-cleared

recording-001.webm

@oxwen11

oxwen11 commented Sep 28, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head 32aff8699a6a5de60a0b45cfa65053636adb3ced — required CI green (Check, react-doctor, both Publish @getpie/cli preview), MERGEABLE (BEHIND). Prior no was on def1124d128867423f375c85d862560a4ccaf1a5; re-reviewed this updated head.

out of .agents/rules/auto-merge-pr.md allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect fans out across every connected Environment (useQueries / grouped ProjectGroup), writes ?environmentId= with the pick, and adds requireProject control flow that disables clear / "Don't work in a project" / send-without-project on linked hosts
  • non-presentational product + routing/query changes in draft.tsx, draft-composer.tsx, project-select.tsx (plus verify skill / CONTEXT docs and new browser tests for that behavior)

not presentation-only; leave for human review.

@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Review-and-merge gate record — not merged

  • Head: 32aff8699a6a5de60a0b45cfa65053636adb3ced.
  • Current target main and trusted rules commit: d7f4b7a95588e5de2aeefbe790e65111e89195f6.
  • Policy: trusted PR workflow, with review, security and acceptance rules from that base (not PR-proposed or retired rules).
  • Context: fix(app): list draft projects from every connected Environment. Same-repository, author oxwen11, open, non-draft.

Required CI observed for this head

Blocking gate and conclusion

  • GitHub reports CONFLICTING / DIRTY against main.
  • Comparison to current main shows the head is behind by 8 commits; historical green checks do not satisfy the current-base gate.

Stopped before code review and independent verification; not merged. These are gate observations, not an implementation-quality verdict. No branch update, conflict resolution, CI rerun, protection bypass or fix-and-merge was performed.

Revisit only after a relevant change resolves the recorded blocker: an author-provided head containing current main with no conflict where necessary, and every required check present, executed and successful for the candidate version. The next eligible version starts again at CI; unchanged blockers need no duplicate review/comment.

@oxwen11
oxwen11 force-pushed the fix/draft-projects-per-environment branch from 32aff86 to d19b36f Compare September 30, 2026 14:20
@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

本轮审查入口检查:等待 CI

  • Head:d19b36f38ed80f171a45184693dde6cc3edd6d8b
  • Base / 可信规则 commit:c7c4138afdafaf951349be57cb8acc990a07e0aa
  • 依据:仓库 PR 规则

当前 GitHub 状态为 MERGEABLE / BLOCKED,必需检查尚未全部完成:

本轮停止在入口检查,未进行代码审查或独立验收,未合并;这不是对实现质量的结论。前次评论针对旧 head 的门禁状态不代表当前版本。

下一轮条件:当前候选版本的所有 required checks 均实际成功,且保持非 Draft、无冲突、不落后于 base。届时从 CI 开始审查;不因未变化的等待状态重复评论。本轮未更新分支、解决冲突或重跑 CI。

@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head d19b36f38ed80f171a45184693dde6cc3edd6d8b — required CI green (Check, react-doctor, both Publish @getpie/cli preview, Continuous Releases, React Doctor), MERGEABLE (BEHIND). Prior no was on 32aff8699a6a5de60a0b45cfa65053636adb3ced; re-reviewed this updated head.

out of .agents/rules/auto-merge-pr.md allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect fans out across every connected Environment (useQueries / grouped ProjectGroup), writes ?environmentId= with the pick, and adds requireProject control flow that disables clear / send on linked hosts with no project
  • non-presentational fix: draft route selection, composer submit gating, and navigate search rewriting change product control flow — not idle/hover/focus chrome via class/style tokens
  • ui-presentation.md rejects new interaction flows, handlers, conditions/control flow; docs/skills/CONTEXT updates accompany the feature rather than being docs-only

fail closed; no update-branch.

The draft picker only listed the active Environment's projects, so a
linked host's projects were invisible until its Environment became the
draft target. The picker now fans project.list across every connected
Environment (same prefixed cache keys the sidebar uses), groups and
labels each Environment when more than one has projects, and picking a
project writes the owning Environment's id into the draft URL.

Non-project chats stay local: clearing the project drops the
environment hint, and a linked host's picker hides every path back to
null (no clear, no Choose project, no Don't-work button) because
chat-folder allocation under ~/Pie is local-only.
A grouped project dropdown mixed every host. Pick the Environment first;
the project list is only that Environment's imported projects.
Do not pick an Environment first. The project list splits connected
hosts into labeled groups; choosing a project addresses that host.
@oxwen11
oxwen11 force-pushed the fix/draft-projects-per-environment branch from d19b36f to 4f920b7 Compare September 30, 2026 15:37
@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

审查阻塞:新增远端加载会丢失已输入的草稿

  • Head:4f920b7d46143c047c5ec31a1c6b2a10fe4b79bf
  • Base / 可信规则 commit:8f7546548ca95b7167c2261ebe87f4425806cf65
  • 本轮已确认 rebase 后包含当前 main;非 Draft、同仓库、作者 oxwen11、MERGEABLE/CLEAN。当前 required Check、react-doctor、preview 及另一项 preview 全部 SUCCESS。因此本轮进入了完整 diff 与调用链审查,不再沿用之前的 CI 等待结论或退休白名单。

P1 — 不要让其他 Environment 的首次加载卸载草稿编辑器

位置:draft.tsx L215–217。

用户已经在本地草稿输入内容时,新 SSH Environment 连接完成会加入 useConnectedEnvironments()。该 Environment 的 project.list 首次查询没有缓存、处于 pending,即使本地列表早已成功,新增的 projectLists.some(list => list.isPending) 也会返回 Loader,卸载整个 DraftComposer。

卸载不是无损隐藏:use-chat-input-controller.ts L24–40 会 dispose 编辑器,而 DraftComposer L48–64 没有提供 onDispose/initialContent 保存与恢复。远端加载结束后新建的是空编辑器,未发送文本丢失;远端慢请求也会阻塞原本可用的本地草稿。

需作者保持已挂载草稿及其输入不受无关 Environment 加载影响,并补充回归覆盖:本地输入 → 新远端首次列表 pending → resolve/reject → 本地文本仍在且本地可用。已有新增测试只覆盖 ProjectSelect 的分组和选中回调,没有覆盖此路由/编辑器生命周期。

结论与证据边界

代码审查未通过,未合并。 上述是源码与生命周期调用链确认的问题,不声称已用真实 SSH/UI 重现。按门禁顺序,未进入独立运行验收,未运行本地测试或截图/视频验收;历史作者证据不能替代新 head 的独立验收。没有修改代码或自行修复。当前身份是 PR 作者,使用此评论记录本应 Request changes 的阻塞,不替代任何必需审批。

作者修复并提交新 head 后,重新从当前 base、required CI、审查开始;通过后仍需独立 Web/Desktop 的跨 Environment、清除归属和失败路径验证及截图/视频证据。

@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head 4f920b7d46143c047c5ec31a1c6b2a10fe4b79bf — required CI green (Check, react-doctor, both Publish @getpie/cli preview, Continuous Releases, React Doctor), MERGEABLE (BEHIND). Prior no was on d19b36f38ed80f171a45184693dde6cc3edd6d8b; re-reviewed this updated head.

out of .agents/rules/auto-merge-pr.md allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect fans out across every connected Environment (useQueries / grouped ProjectGroup), writes ?environmentId= with the pick, and adds requireProject control flow that disables clear / "Don't work in a project" on linked hosts
  • interaction/state: picker selection shape, send-disable conditions, draft route wiring — not presentation-only class/style tokens
  • not docs-tooling or mechanical lint/format (skill/CONTEXT text accompanies the feature)

Din review-first: no squash-merge.

@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

Current head 0da9c48b3b2adcc3e4770167024259049725406a now includes base/trusted rules 01f864fe30b4376714547bd6bd6576b5540e3d03, and required CI passed. This removes the stale-base gate but does not resolve the existing P1 draft-input-loss review: projectLists.some(list => list.isPending) still replaces the composer with Loader. No independent acceptance or merge; the author repair requested in that review remains necessary.

@oxwen11

oxwen11 commented Sep 30, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head 0da9c48b3b2adcc3e4770167024259049725406a — required CI green (Check, react-doctor, Publish @getpie/cli preview, Continuous Releases, React Doctor), MERGEABLE (BEHIND). Prior no was on 4f920b7d46143c047c5ec31a1c6b2a10fe4b79bf; re-reviewed this updated head.

out of .agents/rules/auto-merge-pr.md allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect fans out across every connected Environment (useQueries / grouped ProjectGroup), writes ?environmentId= with ?projectId=, and adds requireProject so linked hosts cannot allocate a non-project chat (draft.tsx, draft-composer.tsx, project-select.tsx)
  • not ui-presentation-only: new types/API (ProjectSelection, selectionValue), control-flow for multi-env groups, submit disable when requireProject && selected === null
  • docs/skill updates (CONTEXT.md, draft-new-chat.md) describe the new product behavior; they do not make the PR docs-tooling-only

fail closed — comment only (Din review-first; no merge).

@oxwen11

oxwen11 commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Draft-loss repair submitted — independent acceptance still required

Repair commit 487bdc7d, based on current main 4a338cb0f5e1b22d24ca1dea46ce1ee6a50c2cd3. This is implementation work addressing the P1 finding, not reviewer self-approval.

The loading gate no longer replaces an available draft when an unrelated Environment starts its first project-list request. It still waits for the active Environment, and for unresolved catalogs when no imported projects are available. No persistence, RPC contract or shared component changes.

Added a Chromium regression at the actual draft-route/editor seam, using real TanStack queries and the real editor with controlled RPC links and an Environment feed (not a live SSH proof). Local input → remote first-load pending → remote resolve/reject must retain the same editor DOM node and exact text, with local submit still enabled. The final regression assertions failed on the old gate (editor replaced by Loader) and passed after the fix. Both outcomes plus existing project-picker cases: 4/4 passed. App typecheck, scoped formatting, commit-hook lint and React Doctor 100/100 passed. A test-placement boundary violation found by the hook was corrected by locating the test at the route composition root, not suppressing the rule.

Ordinary history-preserving push; no conflict resolution, force-push or protection bypass. New CI, independent full-PR review and real Web/Desktop cross-Environment verification with screenshots/video remain outstanding. No merge or deferred auto-merge armed.

@oxwen11

oxwen11 commented Oct 1, 2026

Copy link
Copy Markdown
Owner Author

Queue update after verified #423 merge — waiting at CI

Head 82b0845a2e4e86ddd1c3ee2f55318873109b5d59 now contains main/trusted-rules 0920277492d381b108b520b341c449bcc3e3dbd8 (behind_by=0 verified). GitHub performed a conflict-free merge update guarded by the previous exact head; no conflict resolution or source repair.

Required CI for this new head is queued/in progress at this observation, so no old-head review or acceptance is carried forward. The earlier repair/self-test record is not independent acceptance. No additional repair was made.

No merge or deferred auto-merge. Continue only after the applicable blocker is resolved and the new version passes required CI → review → independent acceptance.

@oxwen11

oxwen11 commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

auto-merge: no

head 82b0845a2e4e86ddd1c3ee2f55318873109b5d59 — required CI green (Check, react-doctor, Publish @getpie/cli preview, Continuous Releases, React Doctor), MERGEABLE (BEHIND). Prior no was on 0da9c48b3b2adcc3e4770167024259049725406a; re-reviewed this updated head.

Out of the allowed groups; hits exclusions:

  • feature / new functional product behavior: draft ProjectSelect lists projects from every connected Environment and carries the Environment with the project selection (project-select.tsx, draft.tsx, draft-composer.tsx, +68/-23, +75/-17, +28/-10).
  • not ui-presentation-only: new selection types, control flow and submit gating; new tests (project-select.test.tsx, -draft-loading.test.tsx) cover that product flow.

@oxwen11

oxwen11 commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

Merged current origin/main (c020c97c, #443) into this branch with a merge commit (de482382). No force push.

Conflict was only CONTEXT.md Project entry. Kept main's wording: Pie-owned children load and execute built-in, global, and Project extensions, and registering a Project trusts that extension code. The daemon model list still does not load extensions. Kept this PR's note on the same entry: non-project chat allocation stays local-only, and the draft picker lists imported projects from every connected Environment, grouped and labeled when more than one has projects.

@getpie/app typecheck passed. project-select.test.tsx passed (2).

@oxwen11

oxwen11 commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Review and verification record — approved, merging

  • Head 0c1e7e53f5abf3363a945846c556d8f4dee78719; base and trusted rules 9d2ea787dbc13d2a193e9e11114f1aac516c6955.
  • Required CI on this head, all success:

Review

  • The earlier P1 (the draft is replaced while another Environment loads) is fixed by 487bdc7d. The regression test lives at the draft-route/editor seam (-draft-loading.test.tsx, resolve + reject).
  • The picker fans project.list out to every connected Environment. Groups are labeled only when more than one Environment has projects. Picking a project writes the owning environmentId. Clearing the project drops it, so non-project chats stay local.
  • No persistence, RPC contract or shared-component changes. App code is unchanged since the Desktop run on fed81bba: the PR's apps/ diff against main is identical.

Independent verification

Clean worktree at this head. Locked install. Isolated PIE_HOME, ports and browser profile. Real model through the operator's Pi config; no explicit model was selected.

  • Browser tests: project-select.test.tsx + -draft-loading.test.tsx, 4 passed.
  • Web (Vite + serve, this head):
    • Picker → verify-pie-sample. The URL became /draft?projectId=…&environmentId=<local>.
    • Sent. The session route kept both parameters and the model replied in that Project.
    • Hovered and clicked X. The URL went back to /draft, with both parameters cleared.
    • Sent again. A local Chat-1 was allocated under $PIE_HOME/Pie/<date>/. The session appears under Recent and not under Projects.
  • Desktop (Electron, macOS, on fed81bba with the identical app diff):
    • Single Environment: picking writes projectId + environmentId, and clearing removes both.
    • A typed draft was kept through an attempt to add a remote.

Gaps (accepted, not blocking)

  • No live multi-Environment run.
    • An SSH Environment needs the remote daemon's compatibility key to match this build. The remote runs the published CLI, so attaching was refused (version mismatch).
    • The multi-Environment grouping, labels and owning-environmentId emission are covered by the Chromium test splits projects by Environment and emits the owning id.
  • Pre-existing, not from this PR: /draft?environmentId=<unknown id> renders the error boundary (Environment … is not connected). It comes from environmentRpc.for(), which behaves the same on main. A follow-up issue would be useful.
  • Non-blocking: the PR body still describes an earlier requireProject design. The code now groups Environments in one picker. Worth refreshing the body.

Evidence below. The local sample path in the open-picker frame and video is masked with a grey bar.

402-before-draft-picker

402-picker-open

402-project-picked

402-after-project-send

402-hover-clear

402-cleared

402-after-allocate

04-after-pick-local-project

05-after-clear-project

402-web-pick-send.webm
402-web-clear-allocate.webm

@oxwen11
oxwen11 merged commit 257f0da into main Oct 6, 2026
6 checks passed
@oxwen11
oxwen11 deleted the fix/draft-projects-per-environment branch October 6, 2026 03:44
@oxwen11

oxwen11 commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

Merged as 257f0da (squash, head guard 0c1e7e53); follows the record above.

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