vibe-coding-master 0.0.7 → 0.0.9
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 +48 -11
- package/dist/backend/adapters/filesystem.js +6 -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/app-settings-service.js +90 -15
- 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 +28 -10
- 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 +6 -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 +110 -14
- package/docs/v1-architecture-design.md +168 -34
- package/docs/v1-implementation-plan.md +132 -22
- 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
|
|
487
|
+
- create `~/.vcm/projects/<project-id>/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
|
|
516
|
+
```
|
|
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
|
|
487
549
|
```
|
|
488
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
|
|
@@ -623,13 +706,6 @@ Storage:
|
|
|
623
706
|
~/.vcm/settings.json
|
|
624
707
|
```
|
|
625
708
|
|
|
626
|
-
Also migrates legacy:
|
|
627
|
-
|
|
628
|
-
```text
|
|
629
|
-
~/.vibe-coding-master/settings.json
|
|
630
|
-
~/.vibe-coding-master/translation.json
|
|
631
|
-
```
|
|
632
|
-
|
|
633
709
|
### `src/backend/services/translation-prompts.ts`
|
|
634
710
|
|
|
635
711
|
Exports:
|
|
@@ -722,12 +798,20 @@ Registers all routes and WebSockets.
|
|
|
722
798
|
|
|
723
799
|
- `src/backend/api/project-routes.ts`: health, recent paths, connect/current project
|
|
724
800
|
- `src/backend/api/harness-routes.ts`: harness status/apply
|
|
725
|
-
- `src/backend/api/task-routes.ts`: tasks
|
|
801
|
+
- `src/backend/api/task-routes.ts`: tasks, task status, task cleanup
|
|
726
802
|
- `src/backend/api/session-routes.ts`: session lifecycle and dispatch compatibility endpoint
|
|
727
803
|
- `src/backend/api/artifact-routes.ts`: artifact, role command, and log reads/writes
|
|
728
804
|
- `src/backend/api/message-routes.ts`: messages and orchestration
|
|
729
805
|
- `src/backend/api/translation-routes.ts`: settings, prompt previews, provider test, input/send, clear/retry
|
|
730
806
|
|
|
807
|
+
Worktree task API:
|
|
808
|
+
|
|
809
|
+
```text
|
|
810
|
+
POST /api/tasks/:taskSlug/cleanup
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
Do not add a "switch task worktree" endpoint. Worktree assignment happens only during task creation.
|
|
814
|
+
|
|
731
815
|
### WebSocket files
|
|
732
816
|
|
|
733
817
|
- `src/backend/ws/terminal-ws.ts`
|
|
@@ -769,6 +853,7 @@ Auto delivery envelope is submitted with Enter.
|
|
|
769
853
|
### Harness templates
|
|
770
854
|
|
|
771
855
|
- `src/backend/templates/harness/claude-root.ts`
|
|
856
|
+
- `src/backend/templates/harness/gitignore.ts`
|
|
772
857
|
- `src/backend/templates/harness/project-manager-agent.ts`
|
|
773
858
|
- `src/backend/templates/harness/architect-agent.ts`
|
|
774
859
|
- `src/backend/templates/harness/coder-agent.ts`
|
|
@@ -793,6 +878,12 @@ It calls:
|
|
|
793
878
|
- orchestration endpoints
|
|
794
879
|
- translation endpoints
|
|
795
880
|
|
|
881
|
+
Target additions:
|
|
882
|
+
|
|
883
|
+
- `listGitWorktrees()`
|
|
884
|
+
- `listGitBranches()`
|
|
885
|
+
- `cleanupTask(taskSlug, options)`
|
|
886
|
+
|
|
796
887
|
### `src/frontend/state/app-store.ts`
|
|
797
888
|
|
|
798
889
|
Exports:
|
|
@@ -840,8 +931,9 @@ Responsibilities:
|
|
|
840
931
|
- messages modal
|
|
841
932
|
- events modal
|
|
842
933
|
- harness panel
|
|
843
|
-
- one-field
|
|
934
|
+
- task creation with one task-name field, checked non-optional worktree/branch indicator, branch preview, and worktree path preview
|
|
844
935
|
- task navigation
|
|
936
|
+
- completed-task cleanup action
|
|
845
937
|
|
|
846
938
|
### `src/frontend/routes/task-workspace.tsx`
|
|
847
939
|
|
|
@@ -853,6 +945,7 @@ Exports:
|
|
|
853
945
|
Responsibilities:
|
|
854
946
|
|
|
855
947
|
- task header with role tabs and refresh
|
|
948
|
+
- show branch and immutable worktree path for the active task
|
|
856
949
|
- status/message/orchestration refresh
|
|
857
950
|
- periodic polling
|
|
858
951
|
- session lifecycle actions
|
|
@@ -882,6 +975,8 @@ Layout:
|
|
|
882
975
|
- path input row
|
|
883
976
|
- recent select plus connect button row
|
|
884
977
|
|
|
978
|
+
This form connects the base repository. It is not used to switch an existing task to another worktree.
|
|
979
|
+
|
|
885
980
|
### `src/frontend/components/harness-panel.tsx`
|
|
886
981
|
|
|
887
982
|
Exports:
|
|
@@ -1047,32 +1142,39 @@ App settings:
|
|
|
1047
1142
|
Project config:
|
|
1048
1143
|
|
|
1049
1144
|
```text
|
|
1050
|
-
|
|
1145
|
+
~/.vcm/projects/<project-id>/config.json
|
|
1146
|
+
~/.vcm/projects/index.json
|
|
1051
1147
|
```
|
|
1052
1148
|
|
|
1053
1149
|
Task state:
|
|
1054
1150
|
|
|
1055
1151
|
```text
|
|
1056
|
-
.vcm/tasks/<task>.json
|
|
1152
|
+
.ai/vcm/tasks/<task>.json
|
|
1057
1153
|
```
|
|
1058
1154
|
|
|
1059
1155
|
Session state:
|
|
1060
1156
|
|
|
1061
1157
|
```text
|
|
1062
|
-
.vcm/sessions/<task>.json
|
|
1158
|
+
.ai/vcm/sessions/<task>.json
|
|
1063
1159
|
```
|
|
1064
1160
|
|
|
1065
1161
|
Messages:
|
|
1066
1162
|
|
|
1067
1163
|
```text
|
|
1068
|
-
.vcm/messages/<task>.jsonl
|
|
1164
|
+
.ai/vcm/messages/<task>.jsonl
|
|
1069
1165
|
.ai/handoffs/<task>/messages/<message-id>.md
|
|
1070
1166
|
```
|
|
1071
1167
|
|
|
1072
1168
|
Orchestration:
|
|
1073
1169
|
|
|
1074
1170
|
```text
|
|
1075
|
-
.vcm/orchestration/<task>.json
|
|
1171
|
+
.ai/vcm/orchestration/<task>.json
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
Task worktrees:
|
|
1175
|
+
|
|
1176
|
+
```text
|
|
1177
|
+
.ai/vcm/worktrees/<task>/
|
|
1076
1178
|
```
|
|
1077
1179
|
|
|
1078
1180
|
Handoff artifacts:
|
|
@@ -1101,7 +1203,11 @@ npm run verify:package
|
|
|
1101
1203
|
For frontend layout changes, also verify manually:
|
|
1102
1204
|
|
|
1103
1205
|
- connect repository
|
|
1206
|
+
- confirm `.ai/vcm/` is ignored before creating a task worktree
|
|
1207
|
+
- create task and verify branch `feature/<task>` is created
|
|
1208
|
+
- verify worktree path is `<baseRepoRoot>/.ai/vcm/worktrees/<task>`
|
|
1104
1209
|
- open task
|
|
1210
|
+
- verify role sessions start with cwd set to the task worktree
|
|
1105
1211
|
- role tabs stay in header
|
|
1106
1212
|
- sidebar sections collapse/open correctly
|
|
1107
1213
|
- embedded terminal remains visible after role switch
|
|
@@ -1111,6 +1217,7 @@ For frontend layout changes, also verify manually:
|
|
|
1111
1217
|
- Auto orchestration toggles on/off
|
|
1112
1218
|
- `Enter` in translation composer translates/sends
|
|
1113
1219
|
- `Shift+Enter` inserts newline
|
|
1220
|
+
- mark task complete and verify cleanup removes the worktree and central task metadata
|
|
1114
1221
|
|
|
1115
1222
|
## 17. V1 Boundaries To Preserve
|
|
1116
1223
|
|
|
@@ -1126,3 +1233,6 @@ Do not reintroduce these into V1 docs or UI unless the product direction changes
|
|
|
1126
1233
|
- optional title input in New Task
|
|
1127
1234
|
- `Dirty: yes/no` sidebar label
|
|
1128
1235
|
- role command dispatch as the primary orchestration path
|
|
1236
|
+
- per-role worktrees
|
|
1237
|
+
- switching a task to another branch/worktree after creation
|
|
1238
|
+
- 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%}}
|