From a5449ab91cb2f81e58552649db0e58b841687cfe Mon Sep 17 00:00:00 2001 From: toki Date: Sun, 7 Jun 2026 04:18:22 +0900 Subject: [PATCH] =?UTF-8?q?test(workbench):=20=EC=9B=8C=ED=81=AC=EB=B2=A4?= =?UTF-8?q?=EC=B9=98=20=EA=B2=80=EC=A6=9D=EA=B3=BC=20=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=EB=A7=B5=20=EC=83=81=ED=83=9C=EB=A5=BC=20=EB=8F=99=EA=B8=B0?= =?UTF-8?q?=ED=99=94=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 현재 마일스톤의 project-config 진행 상태와 workbench-shell 검증 근거를 로드맵에 반영한다. --- .../agent-ops-mcp-control-plane/PHASE.md | 2 +- .../milestone-work-item-creation-sync.md | 19 ++++---- .../workbench-provider-slot-composition.md | 9 ++-- apps/client/test/widget_test.dart | 48 +++++++++++++++++++ 4 files changed, 64 insertions(+), 14 deletions(-) diff --git a/agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md b/agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md index 726ae1b..28d3c10 100644 --- a/agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md +++ b/agent-roadmap/phase/agent-ops-mcp-control-plane/PHASE.md @@ -14,7 +14,7 @@ 완료, 검토중, 진행중, 계획, 스케치 순서로 두어 아래로 갈수록 미래 작업에 가까워지게 정렬한다. 스케치 Milestone은 아직 구현 가능한 계획이 아니므로 계획 Milestone보다 아래에 둔다. -- [계획] Milestone Work Item Creation Sync +- [진행중] Milestone Work Item Creation Sync - 경로: `agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md` - 요약: Plane-origin 방식으로 Milestone을 생성하고 Plane Todo 티켓까지 동기화한 뒤 멈추는 계획 후보다. Workspace agent 실행은 IOP CLI 1차 통로를 선행으로 두며, Agent chat/IDE-origin 생성 projection은 이번 범위에서 제외한다. diff --git a/agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md b/agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md index 43ce8ac..4aa579d 100644 --- a/agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md +++ b/agent-roadmap/phase/agent-ops-mcp-control-plane/milestones/milestone-work-item-creation-sync.md @@ -11,7 +11,7 @@ Plane-origin 경로로 Milestone을 생성하고, `develop` branch의 agent-road ## 상태 -[계획] +[진행중] ## 구현 잠금 @@ -47,14 +47,14 @@ Plane-origin 경로로 Milestone을 생성하고, `develop` branch의 agent-road Plane project 단위로 Milestone sync에 필요한 기본 설정을 저장하고 이후 UI/UX가 소비할 project settings 경계를 만든다. -- [ ] [project-model] Plane project 단위 sync 설정 모델을 정의한다. 검증: 설정 모델이 provider project target, git remote URL, source-of-truth branch, workspace id/path를 필수 필드로 갖는다. -- [ ] [project-store] Project sync 설정을 Core DB에 저장하는 persistence 경계를 정한다. 검증: Plane project별로 하나의 active sync 설정을 찾을 수 있고, Milestone 생성 동기화가 이 설정 없이는 진행되지 않는 기준이 문서화되어 있다. -- [ ] [project-bind] Plane-origin 생성 동기화가 project sync 설정을 통해 Plane project, git repository, 작업 workspace를 해석하도록 한다. 검증: 같은 Plane project 안의 티켓은 같은 git/workspace 설정을 사용하며, 다른 Plane project와 섞이지 않는다. -- [ ] [workspace-layout] NomadCode host 기준 workspace 경로 규칙을 정의한다. 검증: `workspace_base_path=/home/user/workspace`, `repo_dir_name=nomadcode`이면 project workspace root는 `/home/user/workspace/nomadcode`이고 실제 작업 slot path는 `/home/user/workspace/nomadcode/000`처럼 계산된다. -- [ ] [workspace-slot] 병렬 운용을 위한 workspace slot index 모델을 정의한다. 검증: 기본 작업공간은 `000`이고, 병렬 요청이 들어오면 `001`, `002`처럼 3자리 zero-padded index를 증가시키며 각 slot이 독립 작업공간으로 예약된다. -- [ ] [workspace-slot-state] Workspace slot의 사용중 상태 모델을 정의한다. 검증: 각 slot은 `available`, `in_use`, `dirty`, `error` 같은 상태 후보를 갖고, 새 작업은 `available` slot만 선택하며, 동시에 들어온 요청이 같은 slot을 잡지 않도록 DB에서 원자적으로 `in_use`로 전환하는 기준이 있다. -- [ ] [workspace-checkout] Git repository checkout 정책을 project sync 설정과 연결한다. 검증: git remote는 project sync 설정에서 읽고, 안정성을 우선해 각 slot은 같은 remote의 독립 checkout을 기본으로 확보하며, 일반 단일 운용에서는 `000`만 사용한다. -- [ ] [settings-ui] Project sync 설정을 이후 프로젝트 설정 UI/UX에서 관리해야 하는 후보로 남긴다. 검증: 이번 마일스톤에서는 UI 구현을 하지 않고, 후속 Project settings 화면이 provider project target, git remote, workspace를 표시/수정해야 한다는 요구가 남아 있다. +- [x] [project-model] Plane project 단위 sync 설정 모델을 정의한다. 검증: 설정 모델이 provider project target, git remote URL, source-of-truth branch, workspace id/path를 필수 필드로 갖는다. +- [x] [project-store] Project sync 설정을 Core DB에 저장하는 persistence 경계를 정한다. 검증: Plane project별로 하나의 active sync 설정을 찾을 수 있고, Milestone 생성 동기화가 이 설정 없이는 진행되지 않는 기준이 문서화되어 있다. +- [x] [project-bind] Plane-origin 생성 동기화가 project sync 설정을 통해 Plane project, git repository, 작업 workspace를 해석하도록 한다. 검증: 같은 Plane project 안의 티켓은 같은 git/workspace 설정을 사용하며, 다른 Plane project와 섞이지 않는다. +- [x] [workspace-layout] NomadCode host 기준 workspace 경로 규칙을 정의한다. 검증: `workspace_base_path=/home/user/workspace`, `repo_dir_name=nomadcode`이면 project workspace root는 `/home/user/workspace/nomadcode`이고 실제 작업 slot path는 `/home/user/workspace/nomadcode/000`처럼 계산된다. +- [x] [workspace-slot] 병렬 운용을 위한 workspace slot index 모델을 정의한다. 검증: 기본 작업공간은 `000`이고, 병렬 요청이 들어오면 `001`, `002`처럼 3자리 zero-padded index를 증가시키며 각 slot이 독립 작업공간으로 예약된다. +- [x] [workspace-slot-state] Workspace slot의 사용중 상태 모델을 정의한다. 검증: 각 slot은 `available`, `in_use`, `dirty`, `error` 같은 상태 후보를 갖고, 새 작업은 `available` slot만 선택하며, 동시에 들어온 요청이 같은 slot을 잡지 않도록 DB에서 원자적으로 `in_use`로 전환하는 기준이 있다. +- [x] [workspace-checkout] Git repository checkout 정책을 project sync 설정과 연결한다. 검증: git remote는 project sync 설정에서 읽고, 안정성을 우선해 각 slot은 같은 remote의 독립 checkout을 기본으로 확보하며, 일반 단일 운용에서는 `000`만 사용한다. +- [x] [settings-ui] Project sync 설정을 이후 프로젝트 설정 UI/UX에서 관리해야 하는 후보로 남긴다. 검증: 이번 마일스톤에서는 UI 구현을 하지 않고, 후속 Project settings 화면이 provider project target, git remote, workspace를 표시/수정해야 한다는 요구가 남아 있다. ### Epic: [agent-bridge] Workspace agent IOP CLI bridge @@ -120,6 +120,7 @@ Plane-origin 생성 경로를 `develop` agent-roadmap 기준의 `Todo` 검토 - Slot 사용 상태: slot은 Core DB에서 `available` 또는 `in_use` 같은 사용 상태를 추적한다. 여기서 사용 상태는 해당 slot이 현재 작업에 배정되어 다른 병렬 작업이 잡으면 안 되는지를 나타낸다. - Checkout 기준: 안정성을 우선해 각 slot은 같은 git remote를 기준으로 독립 checkout을 갖는 작업공간으로 둔다. 초기 slot 생성 때 clone 비용이 들지만 이후 branch 이동과 일반 작업은 해당 slot 안에서 처리하므로 운영 비용을 낮춘다. - 후속 UI/UX: project settings 화면에서 Plane project target, git remote, workspace 설정을 확인하고 수정하는 UX가 필요하다. +- 완료 근거(2026-06-07): `[project-config]`는 `services/core/internal/projectsync/`, `services/core/migrations/00004_create_project_sync_settings.sql`, `services/core/migrations/00005_create_workspace_slots.sql`, `services/core/queries/project_sync_settings.sql`, `services/core/queries/workspace_slots.sql`, `packages/contracts/notes/flutter-core-api-candidates.md`의 모델/저장/slot/UI 후보 경계와 테스트로 확인했다. 검증: `cd services/core && go test ./...` PASS. - 중지 지점: Plane-origin 생성이 Plane `Todo` 상위 티켓과 `develop` agent-roadmap Milestone identity로 연결된 상태다. - 루프 확인: Plane `Backlog + AGENT assignee` -> IOP CLI로 workspace agent authoring run 실행 -> agent가 Milestone 파일 작성/갱신 후 `develop` push -> sync layer가 push 완료 또는 roadmap scan을 감지 -> Plane 원문 댓글 보존/본문 치환/제목 변경/`Todo` 이동 -> 사용자가 확인 후 `In Progress`로 이동하는 지점까지다. `In Progress` 이후 실행은 후속 잠금 범위다. - 후속 잠금: `Todo -> In Progress` 이후 실행 lifecycle은 사용자가 명시적으로 잠금을 해제할 때까지 진행하지 않는다. diff --git a/agent-roadmap/phase/project-workspace-management-ux/milestones/workbench-provider-slot-composition.md b/agent-roadmap/phase/project-workspace-management-ux/milestones/workbench-provider-slot-composition.md index 853f9b3..a465282 100644 --- a/agent-roadmap/phase/project-workspace-management-ux/milestones/workbench-provider-slot-composition.md +++ b/agent-roadmap/phase/project-workspace-management-ux/milestones/workbench-provider-slot-composition.md @@ -33,10 +33,10 @@ NomadCode Flutter 앱의 상단 titlebar와 우측 icon rail 기반 workbench sh NomadCode는 여러 도메인 관리 화면을 우측 icon rail과 중앙 content host로 전환하는 제품 shell을 소유한다. -- [ ] [titlebar] NomadCode shell은 상단 titlebar 영역을 제공하고, 앱/워크스페이스/현재 컨텍스트 상태를 이 영역에서 표현한다. -- [ ] [right-rail] NomadCode shell은 VS Code activity bar처럼 아이콘만 있는 우측 rail을 제공한다. -- [ ] [center-content] 우측 rail item 선택에 따라 중앙 content가 Agent, Workflow, Web Context, Settings, provider slot 등으로 전환된다. -- [ ] [layout-shape] 상단 titlebar와 우측 rail이 ㄱ자 구조를 만들고, 중앙 content는 host 도메인 화면을 침범 없이 표시한다. 검증: narrow/wide layout에서 titlebar, rail, center content가 겹치지 않는다. +- [x] [titlebar] NomadCode shell은 상단 titlebar 영역을 제공하고, 앱/워크스페이스/현재 컨텍스트 상태를 이 영역에서 표현한다. +- [x] [right-rail] NomadCode shell은 VS Code activity bar처럼 아이콘만 있는 우측 rail을 제공한다. +- [x] [center-content] 우측 rail item 선택에 따라 중앙 content가 Agent, Workflow, Web Context, Settings, provider slot 등으로 전환된다. +- [x] [layout-shape] 상단 titlebar와 우측 rail이 ㄱ자 구조를 만들고, 중앙 content는 host 도메인 화면을 침범 없이 표시한다. 검증: narrow/wide layout에서 titlebar, rail, center content가 겹치지 않는다. ### Epic: [provider-slots] Provider slot registry @@ -89,6 +89,7 @@ IOP와 OTO 관리는 webview나 별도 앱이 아니라 각 repository의 embedd - 표준선(선택): NomadCode shell은 상단 titlebar + 우측 icon rail + center content 구조를 소유한다. - 표준선(선택): 외부 제품 UI는 provider adapter/composition layer에서만 import하고, default build는 외부 제품 package 없이 빌드 가능해야 한다. - 표준선(선택): Agent shell은 공통 package, NomadCode/IOP/OTO는 각각 capability pack으로 조립한다. +- 완료 근거(2026-06-07): `[workbench-shell]`은 `apps/client/lib/src/app/nomadcode_workbench_shell.dart`와 `apps/client/test/widget_test.dart`의 right rail, Agent dock, IOP/Workflow section 전환, narrow/wide layout rect 검증으로 확인했다. 검증: `cd apps/client && flutter test` PASS. - 선행 작업: Client Integration Standardization, Project Workspace Management UX - 선행 확인 대상: `../iop/packages/flutter/iop_console/`, `../oto/packages/flutter/oto_console/` - 후속 작업: 실제 desktop/mobile project workspace 화면 구현, workflow/provider 관리 탭별 세부 content 구현 diff --git a/apps/client/test/widget_test.dart b/apps/client/test/widget_test.dart index 63bddc7..2132170 100644 --- a/apps/client/test/widget_test.dart +++ b/apps/client/test/widget_test.dart @@ -133,6 +133,54 @@ void main() { expect(find.textContaining('Optional IOP console package'), findsOneWidget); }); + testWidgets('Workbench separates titlebar, right rail, and content', ( + WidgetTester tester, + ) async { + addTearDown(() { + tester.view.resetPhysicalSize(); + tester.view.resetDevicePixelRatio(); + }); + + for (final size in const [Size(390, 800), Size(1280, 900)]) { + tester.view.physicalSize = size; + tester.view.devicePixelRatio = 1; + await tester.pumpWidget(const NomadCodeClientApp()); + await tester.pump(); + + final titleRect = tester.getRect(find.text('NomadCode Console')); + final workflowRailRect = tester.getRect(find.byTooltip('Workflow')); + + expect(titleRect.bottom, lessThanOrEqualTo(workflowRailRect.top)); + + await tester.tap(find.byTooltip('Workflow')); + await tester.pump(); + + final workflowContentRect = tester.getRect( + find.text('Workflow management surface will mount here.'), + ); + + expect(workflowContentRect.top, greaterThan(titleRect.bottom)); + expect( + workflowContentRect.right, + lessThanOrEqualTo(workflowRailRect.left), + ); + + await tester.tap(find.byTooltip('Agent')); + await tester.pump(); + + final agentRailRect = tester.getRect(find.byTooltip('Agent')); + final agentContentRect = tester.getRect( + find.text('Ask the workspace agent'), + ); + + expect(agentContentRect.top, greaterThan(titleRect.bottom)); + expect(agentContentRect.right, lessThanOrEqualTo(agentRailRect.left)); + + await tester.pumpWidget(const SizedBox.shrink()); + await tester.pump(); + } + }); + testWidgets('WorkspaceHomePage triggers launcher callback on button tap', ( WidgetTester tester, ) async {