vibe-coding-master 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -11
- package/dist/backend/adapters/filesystem.js +13 -0
- package/dist/backend/adapters/git-adapter.js +79 -1
- package/dist/backend/api/artifact-routes.js +13 -7
- package/dist/backend/api/message-routes.js +2 -0
- package/dist/backend/api/task-routes.js +14 -0
- package/dist/backend/server.js +2 -1
- package/dist/backend/services/command-dispatcher.js +4 -2
- package/dist/backend/services/harness-service.js +22 -4
- package/dist/backend/services/message-service.js +1 -1
- package/dist/backend/services/project-service.js +46 -9
- package/dist/backend/services/session-service.js +7 -5
- package/dist/backend/services/status-service.js +3 -1
- package/dist/backend/services/task-service.js +118 -4
- package/dist/backend/templates/harness/gitignore.js +9 -0
- package/dist-frontend/assets/index-CuiNNOzj.css +32 -0
- package/dist-frontend/assets/{index-Bp49_End.js → index-D59GuHCR.js} +18 -18
- package/dist-frontend/index.html +2 -2
- package/docs/cc-best-practices.md +16 -4
- package/docs/product-design.md +105 -14
- package/docs/v1-architecture-design.md +163 -29
- package/docs/v1-implementation-plan.md +131 -15
- package/package.json +1 -1
- package/dist-frontend/assets/index-BNASqKEK.css +0 -32
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# V1 Implementation Plan And File Map
|
|
2
2
|
|
|
3
|
-
Last updated: 2026-05-
|
|
3
|
+
Last updated: 2026-05-31
|
|
4
4
|
|
|
5
|
-
This document is the current implementation map for VCM V1.
|
|
5
|
+
This document is the current implementation map for VCM V1.
|
|
6
6
|
|
|
7
7
|
## 1. Current Status
|
|
8
8
|
|
|
@@ -17,8 +17,7 @@ V1 is implemented as a local GUI app with:
|
|
|
17
17
|
- API-driven message bus.
|
|
18
18
|
- Translation panel based on Claude transcript JSONL tailing.
|
|
19
19
|
- npm packaging with built `dist` and `dist-frontend` output.
|
|
20
|
-
|
|
21
|
-
The implementation still has planned improvement space, but this file only describes code that exists now.
|
|
20
|
+
- Task creation creates one `feature/<task>` branch and one `.ai/vcm/worktrees/<task>` git worktree.
|
|
22
21
|
|
|
23
22
|
## 2. Package And Build
|
|
24
23
|
|
|
@@ -29,7 +28,7 @@ File:
|
|
|
29
28
|
Current package facts:
|
|
30
29
|
|
|
31
30
|
- package name: `vibe-coding-master`
|
|
32
|
-
- current version: `0.0.
|
|
31
|
+
- current version: `0.0.7`
|
|
33
32
|
- type: ESM
|
|
34
33
|
- `bin.vcm`: `dist/main.js`
|
|
35
34
|
- `bin.vcmctl`: `dist/cli/vcmctl.js`
|
|
@@ -190,6 +189,15 @@ Defines:
|
|
|
190
189
|
|
|
191
190
|
Current UI sends only `taskSlug`, although the API type still permits optional `title` and `specPath`.
|
|
192
191
|
|
|
192
|
+
Worktree fields:
|
|
193
|
+
|
|
194
|
+
- `worktreePath: string`
|
|
195
|
+
- `branch: feature/<taskSlug>`
|
|
196
|
+
- `cleanupStatus?: "active" | "cleaned"`
|
|
197
|
+
- `cleanedAt?: string`
|
|
198
|
+
|
|
199
|
+
`CreateTaskRequest` creates a worktree and branch by default. The UI shows a checked `Create worktree and branch` indicator, but task worktree creation is the normal VCM task path and does not require a separate later action or a user-visible off switch.
|
|
200
|
+
|
|
193
201
|
### `src/shared/types/session.ts`
|
|
194
202
|
|
|
195
203
|
Defines:
|
|
@@ -376,6 +384,21 @@ Important behavior:
|
|
|
376
384
|
- accepts `.git` pointer files
|
|
377
385
|
- passes per-command `safe.directory`
|
|
378
386
|
|
|
387
|
+
Worktree methods:
|
|
388
|
+
|
|
389
|
+
- `branchExists(repoRoot, branch): Promise<boolean>`
|
|
390
|
+
- `createWorktree(input): Promise<void>`
|
|
391
|
+
- `removeWorktree(repoRoot, worktreePath, options): Promise<void>`
|
|
392
|
+
- `deleteBranch(repoRoot, branch, options): Promise<void>`
|
|
393
|
+
- `getStatusPorcelain(repoRoot): Promise<string>`
|
|
394
|
+
- `isIgnored(repoRoot, repoRelativePath): Promise<boolean>`
|
|
395
|
+
|
|
396
|
+
Required safety:
|
|
397
|
+
|
|
398
|
+
- all Git commands keep command-scoped `safe.directory`
|
|
399
|
+
- refuse worktree paths outside `<baseRepoRoot>/.ai/vcm/worktrees/`
|
|
400
|
+
- refuse branch names that do not match `feature/<taskSlug>` for VCM-created tasks
|
|
401
|
+
|
|
379
402
|
### `src/backend/adapters/claude-adapter.ts`
|
|
380
403
|
|
|
381
404
|
Exports:
|
|
@@ -461,8 +484,12 @@ Responsibilities:
|
|
|
461
484
|
- connect repo
|
|
462
485
|
- store current project in process memory
|
|
463
486
|
- record recent repo paths in app settings
|
|
464
|
-
- create `.vcm/config.json`
|
|
487
|
+
- create `.ai/vcm/config.json`
|
|
465
488
|
- ensure base state directories
|
|
489
|
+
- ensure `.ai/vcm/` is ignored by Git before task-worktree creation
|
|
490
|
+
- expose base repo as the project control root
|
|
491
|
+
|
|
492
|
+
Repository connect should keep connecting to the base repo. Task worktrees are managed under that base repo and should not be treated as separate projects in the normal task list.
|
|
466
493
|
|
|
467
494
|
### `src/backend/services/task-service.ts`
|
|
468
495
|
|
|
@@ -479,13 +506,54 @@ Responsibilities:
|
|
|
479
506
|
- load task
|
|
480
507
|
- save task
|
|
481
508
|
- update task status
|
|
509
|
+
- create task branch and worktree
|
|
510
|
+
- clean up completed task worktree and task metadata
|
|
482
511
|
|
|
483
512
|
Task files:
|
|
484
513
|
|
|
485
514
|
```text
|
|
486
|
-
|
|
515
|
+
<baseRepoRoot>/.ai/vcm/tasks/<task>.json
|
|
487
516
|
```
|
|
488
517
|
|
|
518
|
+
Create flow:
|
|
519
|
+
|
|
520
|
+
```text
|
|
521
|
+
createTask(baseRepoRoot, { taskSlug })
|
|
522
|
+
-> assertValidTaskSlug(taskSlug)
|
|
523
|
+
-> branch = feature/<taskSlug>
|
|
524
|
+
-> worktreePath = <baseRepoRoot>/.ai/vcm/worktrees/<taskSlug>
|
|
525
|
+
-> assert .ai/vcm/ is ignored
|
|
526
|
+
-> assert base repo has no uncommitted changes
|
|
527
|
+
-> assert branch does not exist
|
|
528
|
+
-> assert worktree path does not exist
|
|
529
|
+
-> git.createWorktree({ baseRepoRoot, branch, worktreePath, baseRef: HEAD })
|
|
530
|
+
-> artifactService.ensureHandoffStructure({ repoRoot: worktreePath, handoffDir })
|
|
531
|
+
-> artifactService.createArtifactTemplates({ repoRoot: worktreePath, handoffDir })
|
|
532
|
+
-> write central task record under <baseRepoRoot>/.ai/vcm/tasks/<task>.json
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Cleanup flow:
|
|
536
|
+
|
|
537
|
+
```text
|
|
538
|
+
cleanupTask(baseRepoRoot, taskSlug, options)
|
|
539
|
+
-> require all role sessions stopped
|
|
540
|
+
-> load central task record
|
|
541
|
+
-> verify worktreePath is under <baseRepoRoot>/.ai/vcm/worktrees/
|
|
542
|
+
-> inspect git status in worktree
|
|
543
|
+
-> refuse uncommitted changes unless options.force
|
|
544
|
+
-> git.removeWorktree(baseRepoRoot, worktreePath)
|
|
545
|
+
-> delete .ai/vcm/tasks/<task>.json
|
|
546
|
+
-> delete .ai/vcm/sessions/<task>.json
|
|
547
|
+
-> delete .ai/vcm/messages/<task>.jsonl
|
|
548
|
+
-> delete .ai/vcm/orchestration/<task>.json
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
Branch cleanup:
|
|
552
|
+
|
|
553
|
+
- keep `feature/<taskSlug>` by default
|
|
554
|
+
- optional `deleteBranch` only with explicit confirmation
|
|
555
|
+
- prefer requiring merged branch unless force-confirmed
|
|
556
|
+
|
|
489
557
|
### `src/backend/services/artifact-service.ts`
|
|
490
558
|
|
|
491
559
|
Exports:
|
|
@@ -504,6 +572,8 @@ Responsibilities:
|
|
|
504
572
|
- read/save role commands
|
|
505
573
|
- append role logs
|
|
506
574
|
|
|
575
|
+
In task-worktree mode, artifact paths are still repo-relative, but `repoRoot` must be the task worktree path, not the base repo path.
|
|
576
|
+
|
|
507
577
|
Primary role command path:
|
|
508
578
|
|
|
509
579
|
```text
|
|
@@ -551,7 +621,7 @@ Responsibilities:
|
|
|
551
621
|
Persistence:
|
|
552
622
|
|
|
553
623
|
```text
|
|
554
|
-
|
|
624
|
+
<baseRepoRoot>/.ai/vcm/sessions/<task>.json
|
|
555
625
|
```
|
|
556
626
|
|
|
557
627
|
Environment passed to Claude Code:
|
|
@@ -561,6 +631,12 @@ Environment passed to Claude Code:
|
|
|
561
631
|
- `VCM_TASK_SLUG`
|
|
562
632
|
- `VCM_ROLE`
|
|
563
633
|
|
|
634
|
+
In task-worktree mode:
|
|
635
|
+
|
|
636
|
+
- session cwd is `task.worktreePath`
|
|
637
|
+
- session persistence remains central under `baseRepoRoot/.ai/vcm/sessions`
|
|
638
|
+
- raw logs and handoff artifacts are written under the task worktree
|
|
639
|
+
|
|
564
640
|
### `src/backend/services/message-service.ts`
|
|
565
641
|
|
|
566
642
|
Exports:
|
|
@@ -580,6 +656,12 @@ Responsibilities:
|
|
|
580
656
|
- write message body markdown
|
|
581
657
|
- write staged or delivered messages to target terminal
|
|
582
658
|
|
|
659
|
+
In task-worktree mode:
|
|
660
|
+
|
|
661
|
+
- message snapshots remain central under `baseRepoRoot/.ai/vcm/messages`
|
|
662
|
+
- message body files live under `task.worktreePath/.ai/handoffs/<task>/messages`
|
|
663
|
+
- terminal delivery uses the runtime session for the role, whose cwd is the task worktree
|
|
664
|
+
|
|
583
665
|
### `src/backend/services/command-dispatcher.ts`
|
|
584
666
|
|
|
585
667
|
Exports:
|
|
@@ -603,6 +685,7 @@ Exports:
|
|
|
603
685
|
Responsibilities:
|
|
604
686
|
|
|
605
687
|
- inspect harness files
|
|
688
|
+
- manage `.gitignore` entries for VCM local state
|
|
606
689
|
- plan create/insert/update/ok
|
|
607
690
|
- apply VCM managed blocks
|
|
608
691
|
- preserve user content outside managed blocks
|
|
@@ -722,12 +805,20 @@ Registers all routes and WebSockets.
|
|
|
722
805
|
|
|
723
806
|
- `src/backend/api/project-routes.ts`: health, recent paths, connect/current project
|
|
724
807
|
- `src/backend/api/harness-routes.ts`: harness status/apply
|
|
725
|
-
- `src/backend/api/task-routes.ts`: tasks
|
|
808
|
+
- `src/backend/api/task-routes.ts`: tasks, task status, task cleanup
|
|
726
809
|
- `src/backend/api/session-routes.ts`: session lifecycle and dispatch compatibility endpoint
|
|
727
810
|
- `src/backend/api/artifact-routes.ts`: artifact, role command, and log reads/writes
|
|
728
811
|
- `src/backend/api/message-routes.ts`: messages and orchestration
|
|
729
812
|
- `src/backend/api/translation-routes.ts`: settings, prompt previews, provider test, input/send, clear/retry
|
|
730
813
|
|
|
814
|
+
Worktree task API:
|
|
815
|
+
|
|
816
|
+
```text
|
|
817
|
+
POST /api/tasks/:taskSlug/cleanup
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
Do not add a "switch task worktree" endpoint. Worktree assignment happens only during task creation.
|
|
821
|
+
|
|
731
822
|
### WebSocket files
|
|
732
823
|
|
|
733
824
|
- `src/backend/ws/terminal-ws.ts`
|
|
@@ -769,6 +860,7 @@ Auto delivery envelope is submitted with Enter.
|
|
|
769
860
|
### Harness templates
|
|
770
861
|
|
|
771
862
|
- `src/backend/templates/harness/claude-root.ts`
|
|
863
|
+
- `src/backend/templates/harness/gitignore.ts`
|
|
772
864
|
- `src/backend/templates/harness/project-manager-agent.ts`
|
|
773
865
|
- `src/backend/templates/harness/architect-agent.ts`
|
|
774
866
|
- `src/backend/templates/harness/coder-agent.ts`
|
|
@@ -793,6 +885,12 @@ It calls:
|
|
|
793
885
|
- orchestration endpoints
|
|
794
886
|
- translation endpoints
|
|
795
887
|
|
|
888
|
+
Target additions:
|
|
889
|
+
|
|
890
|
+
- `listGitWorktrees()`
|
|
891
|
+
- `listGitBranches()`
|
|
892
|
+
- `cleanupTask(taskSlug, options)`
|
|
893
|
+
|
|
796
894
|
### `src/frontend/state/app-store.ts`
|
|
797
895
|
|
|
798
896
|
Exports:
|
|
@@ -840,8 +938,9 @@ Responsibilities:
|
|
|
840
938
|
- messages modal
|
|
841
939
|
- events modal
|
|
842
940
|
- harness panel
|
|
843
|
-
- one-field
|
|
941
|
+
- task creation with one task-name field, checked non-optional worktree/branch indicator, branch preview, and worktree path preview
|
|
844
942
|
- task navigation
|
|
943
|
+
- completed-task cleanup action
|
|
845
944
|
|
|
846
945
|
### `src/frontend/routes/task-workspace.tsx`
|
|
847
946
|
|
|
@@ -853,6 +952,7 @@ Exports:
|
|
|
853
952
|
Responsibilities:
|
|
854
953
|
|
|
855
954
|
- task header with role tabs and refresh
|
|
955
|
+
- show branch and immutable worktree path for the active task
|
|
856
956
|
- status/message/orchestration refresh
|
|
857
957
|
- periodic polling
|
|
858
958
|
- session lifecycle actions
|
|
@@ -882,6 +982,8 @@ Layout:
|
|
|
882
982
|
- path input row
|
|
883
983
|
- recent select plus connect button row
|
|
884
984
|
|
|
985
|
+
This form connects the base repository. It is not used to switch an existing task to another worktree.
|
|
986
|
+
|
|
885
987
|
### `src/frontend/components/harness-panel.tsx`
|
|
886
988
|
|
|
887
989
|
Exports:
|
|
@@ -1047,32 +1149,38 @@ App settings:
|
|
|
1047
1149
|
Project config:
|
|
1048
1150
|
|
|
1049
1151
|
```text
|
|
1050
|
-
.vcm/config.json
|
|
1152
|
+
.ai/vcm/config.json
|
|
1051
1153
|
```
|
|
1052
1154
|
|
|
1053
1155
|
Task state:
|
|
1054
1156
|
|
|
1055
1157
|
```text
|
|
1056
|
-
.vcm/tasks/<task>.json
|
|
1158
|
+
.ai/vcm/tasks/<task>.json
|
|
1057
1159
|
```
|
|
1058
1160
|
|
|
1059
1161
|
Session state:
|
|
1060
1162
|
|
|
1061
1163
|
```text
|
|
1062
|
-
.vcm/sessions/<task>.json
|
|
1164
|
+
.ai/vcm/sessions/<task>.json
|
|
1063
1165
|
```
|
|
1064
1166
|
|
|
1065
1167
|
Messages:
|
|
1066
1168
|
|
|
1067
1169
|
```text
|
|
1068
|
-
.vcm/messages/<task>.jsonl
|
|
1170
|
+
.ai/vcm/messages/<task>.jsonl
|
|
1069
1171
|
.ai/handoffs/<task>/messages/<message-id>.md
|
|
1070
1172
|
```
|
|
1071
1173
|
|
|
1072
1174
|
Orchestration:
|
|
1073
1175
|
|
|
1074
1176
|
```text
|
|
1075
|
-
.vcm/orchestration/<task>.json
|
|
1177
|
+
.ai/vcm/orchestration/<task>.json
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
Task worktrees:
|
|
1181
|
+
|
|
1182
|
+
```text
|
|
1183
|
+
.ai/vcm/worktrees/<task>/
|
|
1076
1184
|
```
|
|
1077
1185
|
|
|
1078
1186
|
Handoff artifacts:
|
|
@@ -1101,7 +1209,11 @@ npm run verify:package
|
|
|
1101
1209
|
For frontend layout changes, also verify manually:
|
|
1102
1210
|
|
|
1103
1211
|
- connect repository
|
|
1212
|
+
- confirm `.ai/vcm/` is ignored before creating a task worktree
|
|
1213
|
+
- create task and verify branch `feature/<task>` is created
|
|
1214
|
+
- verify worktree path is `<baseRepoRoot>/.ai/vcm/worktrees/<task>`
|
|
1104
1215
|
- open task
|
|
1216
|
+
- verify role sessions start with cwd set to the task worktree
|
|
1105
1217
|
- role tabs stay in header
|
|
1106
1218
|
- sidebar sections collapse/open correctly
|
|
1107
1219
|
- embedded terminal remains visible after role switch
|
|
@@ -1111,6 +1223,7 @@ For frontend layout changes, also verify manually:
|
|
|
1111
1223
|
- Auto orchestration toggles on/off
|
|
1112
1224
|
- `Enter` in translation composer translates/sends
|
|
1113
1225
|
- `Shift+Enter` inserts newline
|
|
1226
|
+
- mark task complete and verify cleanup removes the worktree and central task metadata
|
|
1114
1227
|
|
|
1115
1228
|
## 17. V1 Boundaries To Preserve
|
|
1116
1229
|
|
|
@@ -1126,3 +1239,6 @@ Do not reintroduce these into V1 docs or UI unless the product direction changes
|
|
|
1126
1239
|
- optional title input in New Task
|
|
1127
1240
|
- `Dirty: yes/no` sidebar label
|
|
1128
1241
|
- role command dispatch as the primary orchestration path
|
|
1242
|
+
- per-role worktrees
|
|
1243
|
+
- switching a task to another branch/worktree after creation
|
|
1244
|
+
- a separate `Create task worktree` button outside task creation
|
package/package.json
CHANGED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
3
|
-
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
4
|
-
* https://github.com/chjj/term.js
|
|
5
|
-
* @license MIT
|
|
6
|
-
*
|
|
7
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
-
* in the Software without restriction, including without limitation the rights
|
|
10
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
-
* furnished to do so, subject to the following conditions:
|
|
13
|
-
*
|
|
14
|
-
* The above copyright notice and this permission notice shall be included in
|
|
15
|
-
* all copies or substantial portions of the Software.
|
|
16
|
-
*
|
|
17
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
23
|
-
* THE SOFTWARE.
|
|
24
|
-
*
|
|
25
|
-
* Originally forked from (with the author's permission):
|
|
26
|
-
* Fabrice Bellard's javascript vt100 for jslinux:
|
|
27
|
-
* http://bellard.org/jslinux/
|
|
28
|
-
* Copyright (c) 2011 Fabrice Bellard
|
|
29
|
-
* The original design remains. The terminal itself
|
|
30
|
-
* has been extended to include xterm CSI codes, among
|
|
31
|
-
* other features.
|
|
32
|
-
*/.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}:root{color-scheme:light;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;background:#f5f2ea;color:#1c2024;line-height:1.5}html,body,#root{height:100%}*{box-sizing:border-box}body{margin:0;min-width:320px;min-height:100vh;background:#f5f2ea}button,input,select,textarea{font:inherit}button{border:1px solid #9ba6ad;background:#f8f7f2;color:#1d252b;border-radius:6px;min-height:34px;padding:6px 10px;cursor:pointer}button:hover:not(:disabled){background:#eef4f2;border-color:#607d74}button:disabled{cursor:not-allowed;opacity:.55}input,select,textarea:not(.xterm-helper-textarea){width:100%;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:8px 10px}textarea:not(.xterm-helper-textarea){min-height:240px;resize:vertical;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}h1,h2,p{margin-top:0}h1{margin-bottom:4px;font-size:26px;line-height:1.15}h2{margin-bottom:10px;font-size:14px;letter-spacing:0}.app-shell{display:grid;grid-template-columns:minmax(280px,320px) minmax(0,1fr);height:100vh;min-height:0;overflow:hidden}.app-shell.is-sidebar-collapsed{grid-template-columns:46px minmax(0,1fr)}.app-sidebar{position:relative;min-width:0;border-right:1px solid #d3c9b8;background:#fbfaf6;padding:14px;overflow:auto}.app-shell.is-sidebar-collapsed .app-sidebar{overflow:hidden;padding:8px}.sidebar-toggle{position:absolute;top:10px;right:10px;z-index:2;display:grid;place-items:center;width:28px;min-height:28px;padding:0;background:#fffdf8}.sidebar-toggle:before{width:8px;height:8px;border-color:currentColor;border-style:solid;border-width:0 2px 2px 0;content:"";transform:translate(2px) rotate(135deg)}.app-shell.is-sidebar-collapsed .sidebar-toggle{left:9px;right:auto}.app-shell.is-sidebar-collapsed .sidebar-toggle:before{transform:translate(-2px) rotate(-45deg)}.sidebar-content{min-width:0}.app-shell.is-sidebar-collapsed .sidebar-content{width:0;opacity:0;pointer-events:none}.app-main{min-width:0;height:100%;padding:14px 16px;overflow:auto}.brand-header{display:flex;gap:12px;align-items:baseline;margin-bottom:10px;padding-right:34px}.brand-header strong{font-size:18px}.brand-header span,.muted,.workspace-branch{color:#667071;font-size:13px}.sidebar-section{margin-bottom:8px;border:1px solid #e0d6c7;border-radius:8px;background:#fffdfa;overflow:hidden}.sidebar-section-toggle{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;min-height:34px;border:0;border-radius:0;background:transparent;color:#1c2024;font-size:13px;font-weight:750;text-align:left}.sidebar-section-toggle:hover{background:#f5f1e8}.sidebar-section-toggle[aria-expanded=true]{border-bottom:1px solid #ece5d9}.sidebar-section-chevron{width:8px;height:8px;border-color:currentColor;border-style:solid;border-width:0 2px 2px 0;transform:rotate(45deg)}.sidebar-section-toggle[aria-expanded=true] .sidebar-section-chevron{transform:rotate(-135deg)}.sidebar-section-content{padding:8px}.repo-connect,.project-summary,.harness-panel,.task-create{margin:0}.inline-form{display:grid;grid-template-columns:minmax(0,1fr);gap:8px}.inline-form.has-recent-paths{grid-template-columns:minmax(0,1fr) auto}.inline-form>input{grid-column:1 / -1}.inline-form>button{justify-self:end}.inline-form.has-recent-paths>button{justify-self:auto}.repo-recent-select{min-width:0;max-width:none}.project-summary dl{display:grid;gap:8px;margin:0}.project-summary div{min-width:0}.project-summary dt{color:#6c6255;font-size:12px}.project-summary dd{margin:0;overflow-wrap:anywhere;font-size:13px}.warnings,.error-banner{border:1px solid #c87b54;background:#fff4ed;color:#6f3218;border-radius:6px;padding:10px 12px}.warnings{margin:12px 0 0;padding-left:26px;font-size:13px}.harness-panel{display:grid;gap:8px}.harness-panel-header{display:flex;justify-content:space-between;gap:8px;align-items:center}.harness-panel-header h2,.harness-panel-header p,.harness-result p{margin-bottom:0}.harness-actions{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.harness-file-list{display:grid;gap:6px;margin:0;padding:0;list-style:none}.harness-file-list li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;border:1px solid #ece5d9;border-radius:6px;padding:6px 8px;background:#fffdfa}.harness-file-list span{overflow:hidden;font-size:12px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.harness-changes,.harness-result{border:1px solid #e0d6c7;border-radius:6px;padding:8px;background:#f8f7f2;font-size:12px}.harness-changes h3{margin:0 0 4px;font-size:12px}.harness-changes ul,.harness-result ul{margin:0;padding-left:18px}.task-create form,.task-nav{display:grid;gap:8px}.task-nav-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;text-align:left}.task-nav-item.is-active,.role-tab.is-active{border-color:#2f6f73;background:#e8f1ef}.sidebar-settings{display:grid;gap:8px}.sidebar-settings button{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;text-align:left}.sidebar-settings .settings-toggle.is-active{border-color:#2f6f73;background:#e8f1ef}.workspace-header{display:grid;grid-template-columns:minmax(180px,auto) minmax(420px,1fr) auto;gap:16px;align-items:center;margin-bottom:6px}.workspace-title-line{display:flex;flex-wrap:wrap;gap:10px;align-items:baseline;min-width:0}.workspace-title-line h1{margin-bottom:0;font-size:18px;line-height:1.15}.workspace-branch{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.eyebrow{color:#7a5c2f;font-size:12px;font-weight:700;text-transform:uppercase}.role-tabs{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;margin-bottom:8px;min-width:0}.workspace-header .role-tabs{margin-bottom:0}.role-tab{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;align-items:center;min-height:30px;padding:4px 8px;text-align:left}.workflow-panel{display:grid;gap:8px;margin:0}.workflow-summary p{margin-bottom:0}.workflow-summary p{color:#4f5558;font-size:13px}.workflow-steps{display:grid;grid-template-columns:minmax(0,1fr);gap:6px;margin:0;padding:0;list-style:none}.workflow-steps li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:6px;align-items:center;min-height:28px;border:1px solid #ece5d9;border-radius:6px;padding:4px 6px;background:#fffdfa}.workflow-steps li.is-current{border-color:#2f6f73;background:#e8f1ef}.workflow-steps span{overflow:hidden;color:#394246;font-size:12px;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.workspace-grid{display:grid;grid-template-columns:minmax(0,1fr);flex:1;gap:10px;align-items:stretch;min-height:0}.workspace-main{min-width:0;min-height:0;display:flex;flex-direction:column;gap:8px}.role-console-stack{min-width:0;min-height:0;flex:1;display:flex;flex-direction:column}.role-console-panel{min-width:0;min-height:0;flex:1;display:none}.role-console-panel.is-active{display:flex;flex-direction:column}.session-console,.message-panel,.event-log,.empty-workspace{border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:10px}.task-workspace{display:flex;flex-direction:column;gap:8px;height:100%;min-height:0}.session-console{display:grid;grid-template-rows:auto minmax(0,1fr);gap:8px;flex:1;min-height:0}.session-console-top{display:flex;gap:10px;align-items:center;justify-content:space-between}.session-controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between;margin:0 0 8px}.permission-mode-field{display:grid;grid-template-columns:auto minmax(180px,260px);gap:8px;align-items:center;width:fit-content;max-width:100%}.permission-mode-field span{color:#5f6a6c;font-size:13px;font-weight:650}.permission-mode-field small{display:block;color:#7b8587;font-size:11px;font-weight:500;line-height:1.2}.permission-mode-field select{width:100%;min-height:30px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:4px 8px}.session-toolbar{display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.session-toolbar button{min-height:30px;padding:4px 9px}.translation-toggle{display:inline-flex;align-items:center;justify-content:center;min-height:28px;border:1px solid #b5bec4;border-radius:6px;background:#fffefa;color:#4f5558;font-size:12px;font-weight:650;padding:3px 10px;white-space:nowrap}.translation-toggle.is-active{border-color:#2f7e84;background:#e8f4f2;color:#145e64}.translation-settings-grid input[type=checkbox]{width:auto}.session-console-body{min-width:0;min-height:0;height:100%}.session-console-body.has-translation{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:10px;align-items:stretch}.terminal-pane,.translation-pane{min-width:0;min-height:0}.terminal-frame,.terminal-empty{height:100%;min-height:0;border-radius:6px;overflow:hidden;background:#111316}.terminal-empty{display:grid;place-items:center;align-content:center;gap:8px;color:#d6d0c6;border:1px solid #292d31}.translation-panel{display:grid;grid-template-rows:auto minmax(0,1fr) auto;gap:8px;height:100%;min-height:0;border:1px solid #292d31;border-radius:6px;background:#0d1117;color:#d6deeb;padding:8px;min-width:0;width:100%;overflow:hidden;font-family:Menlo,Monaco,Consolas,monospace}.translation-panel-header{display:grid;gap:3px}.translation-panel-titlebar,.translation-panel-actions{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:space-between}.translation-panel-header h2,.translation-panel-header p{margin-bottom:0}.translation-panel-titlebar h2{font-size:16px}.translation-panel-header p,.translation-composer span{color:#8b949e;font-size:12px}.translation-panel-actions button{border-color:#3a4149;background:#161b22;color:#d6deeb;min-height:26px;padding:2px 8px;font-size:12px}.translation-panel-actions button:hover:not(:disabled),.translation-composer-actions button:hover:not(:disabled){border-color:#58a6ff;background:#1f2937}.translation-panel-actions .auto-send-toggle.is-active{border-color:#56d364;background:#12261a;color:#d6deeb}.translation-panel-actions{justify-content:flex-end}.translation-entry-list{display:grid;align-content:start;gap:8px;min-height:0;min-width:0;overflow-x:hidden;overflow-y:auto;scrollbar-color:#4b5563 #0d1117}.translation-entry{border:0;border-radius:0;background:transparent;min-width:0;max-width:100%;padding:0}.translation-entry pre{box-sizing:border-box;margin:0;max-height:none;max-width:100%;min-width:0;overflow:visible;white-space:pre-wrap;overflow-wrap:anywhere;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px;line-height:1.45;color:#d6deeb}.translation-entry.is-tool-output pre{display:block;overflow:hidden;color:#7d8590;text-overflow:ellipsis;white-space:nowrap;width:100%}.translation-warning{color:#ffab70;margin-bottom:6px}.translation-composer{display:grid;gap:6px;border-top:1px solid #292d31;padding-top:8px}.translation-composer-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:stretch}.translation-composer textarea{width:100%;min-height:38px;max-height:88px;border-color:#3a4149;background:#0d1117;color:#d6deeb;font-family:inherit;font-size:12px;line-height:1.35;resize:vertical}.translation-composer textarea::placeholder{color:#7d8590}.translation-composer textarea::selection{background:#8b949e59;color:#fff}.translation-composer textarea:focus,.translation-composer textarea:focus-visible{border-color:#4b5563;outline:none;box-shadow:none}.translation-composer-actions{display:grid;align-content:start;gap:6px;min-width:104px}.translation-composer-actions button{border-color:#3a4149;background:#161b22;color:#d6deeb;width:100%;min-height:38px;padding:4px 9px;font-size:12px}.translation-panel .muted{color:#8b949e}.translation-panel .error-banner{border-color:#da7b72;background:#2d1518;color:#ffdcd7}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:20;display:grid;place-items:center;background:#181c1f61;padding:18px}.translation-settings-modal{display:grid;gap:12px;width:min(760px,100%);max-height:min(760px,92vh);overflow:auto;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:14px}.message-modal,.event-modal{display:grid;grid-template-rows:auto minmax(0,1fr);gap:12px;width:min(980px,100%);max-height:min(760px,92vh);overflow:hidden;border:1px solid #d6d0c6;border-radius:8px;background:#fffdf8;padding:14px}.translation-settings-modal header,.message-modal header,.event-modal header,.translation-settings-modal footer{display:flex;gap:8px;align-items:center;justify-content:space-between}.translation-prompt-settings{display:grid;gap:10px;border-top:1px solid #ece5d9;padding-top:12px}.translation-prompt-settings header{display:flex;gap:10px;align-items:end;justify-content:space-between}.translation-prompt-settings h3,.translation-prompt-settings p{margin-bottom:0}.translation-prompt-settings h3{font-size:13px}.translation-prompt-settings textarea{min-height:120px;max-height:260px;font-family:Menlo,Monaco,Consolas,monospace;font-size:12px}.translation-prompt-editor-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.translation-settings-modal h2,.message-modal h2,.message-modal p,.event-modal h2,.event-modal p,.translation-settings-modal p{margin-bottom:0}.translation-settings-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.translation-settings-grid label{display:grid;gap:4px}.translation-settings-grid span{color:#4f5558;font-size:12px;font-weight:650}.translation-settings-grid select,.translation-prompt-settings select{min-height:34px;border:1px solid #b9b0a1;border-radius:6px;background:#fffdf8;color:#202326;padding:6px 10px}.translation-test-result{border-radius:6px;padding:8px;font-size:13px}.translation-test-result.is-ok{border:1px solid #6ea77e;background:#e6f3e9;color:#245334}.translation-test-result.is-error{border:1px solid #c46e5f;background:#fae9e6;color:#6f2b21}.message-panel{display:grid;gap:8px}.message-modal .message-panel,.event-modal .event-log{min-height:0;overflow:auto;border:0;background:transparent;padding:0}.message-panel-header{display:flex;justify-content:space-between;gap:12px;align-items:center}.message-panel-header h2,.message-panel-header p{margin-bottom:0}.message-controls,.message-mode-toggle,.message-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.message-mode-toggle{color:#4f5558;font-size:13px;font-weight:650}.message-mode-toggle input{width:auto}.message-list{display:grid;gap:8px;margin:0;padding:0;list-style:none}.message-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:start;border:1px solid #ece5d9;border-radius:6px;padding:8px;background:#fffdfa}.message-meta{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:4px}.message-meta span:not(.status-badge),.message-path{color:#667071;font-size:12px}.message-item p{display:-webkit-box;margin-bottom:4px;overflow:hidden;-webkit-box-orient:vertical;-webkit-line-clamp:2}.message-path{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.event-log ol{margin:0;padding-left:22px;font-size:13px}.event-log{max-height:92px;overflow:auto}.event-log h2{margin-bottom:4px;font-size:13px}.event-log p{margin-bottom:0}.event-log li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.status-badge{display:inline-flex;align-items:center;justify-content:center;min-width:66px;min-height:20px;border-radius:999px;padding:2px 8px;border:1px solid #c7c1b8;background:#f2eee7;color:#4f5558;font-size:11px;white-space:nowrap}.status-running,.status-ok{border-color:#6ea77e;background:#e6f3e9;color:#245334}.status-blocked,.status-crashed,.status-missing,.status-empty{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-waiting,.status-starting,.status-incomplete{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-exited,.status-done,.status-resumable,.status-staged,.status-delivered,.status-acknowledged{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.status-pending_approval,.status-queued,.status-translating,.status-ready,.status-create,.status-insert,.status-update{border-color:#c4a34e;background:#f7efcf;color:#604e16}.status-rejected,.status-failed,.status-cancelled,.status-blocked{border-color:#c46e5f;background:#fae9e6;color:#6f2b21}.status-pending{border-color:#c7c1b8;background:#f2eee7;color:#4f5558}.status-translated,.status-preserved{border-color:#7b98b8;background:#e9f0f8;color:#2e4e70}.empty-workspace{max-width:680px}@media(max-width:980px){.app-shell,.workspace-grid{grid-template-columns:1fr}.app-sidebar{border-right:0;border-bottom:1px solid #d3c9b8}.role-tabs{grid-template-columns:repeat(2,minmax(0,1fr))}.workflow-panel,.workflow-steps,.session-console-body.has-translation,.translation-settings-grid,.translation-prompt-editor-grid{grid-template-columns:1fr}}@media(max-width:560px){.app-main,.app-sidebar{padding:12px}.workspace-header,.inline-form,.inline-form.has-recent-paths{grid-template-columns:1fr;display:grid}.role-tabs{grid-template-columns:1fr}.terminal-frame,.terminal-empty{min-height:300px;height:54vh}.permission-mode-field{grid-template-columns:1fr;width:100%}}
|