vibe-coding-master 0.0.9 → 0.0.10

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.
@@ -17,7 +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
- - Task creation creates one `feature/<task>` branch and one `.ai/vcm/worktrees/<task>` git worktree.
20
+ - Task creation creates one `feature/<task>` branch and one `.ai/vcm/worktrees/<task>` git worktree by default; users may clear `Create worktree and branch` to create an inline task in the connected repository/current branch.
21
21
 
22
22
  ## 2. Package And Build
23
23
 
@@ -187,16 +187,16 @@ Defines:
187
187
  - `TaskRecord`
188
188
  - `CreateTaskRequest`
189
189
 
190
- Current UI sends only `taskSlug`, although the API type still permits optional `title` and `specPath`.
190
+ Current UI sends `taskSlug` and `createWorktree`; the API type still permits optional `title` and `specPath`.
191
191
 
192
192
  Worktree fields:
193
193
 
194
- - `worktreePath: string`
195
- - `branch: feature/<taskSlug>`
194
+ - `worktreePath?: string`
195
+ - `branch: feature/<taskSlug>` when worktree creation is selected, otherwise the connected repo's current branch
196
196
  - `cleanupStatus?: "active" | "cleaned"`
197
197
  - `cleanedAt?: string`
198
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.
199
+ `CreateTaskRequest` supports `createWorktree?: boolean`. It creates a worktree and branch by default, and skips both when `createWorktree === false`.
200
200
 
201
201
  ### `src/shared/types/session.ts`
202
202
 
@@ -244,7 +244,10 @@ Defines:
244
244
  - `SendTranslatedInputRequest`
245
245
  - `TranslationProviderTestResult`
246
246
  - `TranslationPromptPreview`
247
- - `TranslationWsMessage`
247
+ - `TranslationSessionStatus`
248
+ - `TranslationSessionEvent`
249
+ - `StartTranslationSessionResult`
250
+ - `PollTranslationSessionResult`
248
251
 
249
252
  Prompt keys:
250
253
 
@@ -520,39 +523,41 @@ Create flow:
520
523
  ```text
521
524
  createTask(baseRepoRoot, { taskSlug })
522
525
  -> assertValidTaskSlug(taskSlug)
523
- -> branch = feature/<taskSlug>
524
- -> worktreePath = <baseRepoRoot>/.ai/vcm/worktrees/<taskSlug>
525
526
  -> 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 })
527
+ -> if createWorktree is not false:
528
+ -> branch = feature/<taskSlug>
529
+ -> worktreePath = <baseRepoRoot>/.ai/vcm/worktrees/<taskSlug>
530
+ -> assert base repo has no uncommitted changes
531
+ -> assert branch does not exist
532
+ -> assert worktree path does not exist
533
+ -> git.createWorktree({ baseRepoRoot, branch, worktreePath, baseRef: HEAD })
534
+ -> taskRepoRoot = worktreePath
535
+ -> otherwise:
536
+ -> branch = current base repo branch
537
+ -> worktreePath = undefined
538
+ -> taskRepoRoot = baseRepoRoot
539
+ -> artifactService.ensureHandoffStructure({ repoRoot: taskRepoRoot, handoffDir })
540
+ -> artifactService.createArtifactTemplates({ repoRoot: taskRepoRoot, handoffDir })
541
+ -> ensure task runtime state dirs under <taskRepoRoot>/.ai/vcm/
532
542
  -> write central task record under <baseRepoRoot>/.ai/vcm/tasks/<task>.json
533
543
  ```
534
544
 
535
- Cleanup flow:
545
+ Close Task flow:
536
546
 
537
547
  ```text
538
548
  cleanupTask(baseRepoRoot, taskSlug, options)
539
- -> require all role sessions stopped
540
549
  -> 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
550
+ -> if worktreePath exists, verify it is under <baseRepoRoot>/.ai/vcm/worktrees/
551
+ -> if worktreePath exists, git.removeWorktree(baseRepoRoot, worktreePath, force=true)
552
+ -> if worktreePath exists, git.deleteBranch(baseRepoRoot, task.branch, force=true) by default
553
+ -> delete <baseRepoRoot>/.ai/vcm/tasks/<task>.json
554
+ -> delete <taskRepoRoot>/.ai/vcm/sessions/<task>.json
555
+ -> delete <taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
556
+ -> delete <taskRepoRoot>/.ai/vcm/orchestration/<task>.json
557
+ -> delete <taskRepoRoot>/.ai/vcm/translation/<task>/
549
558
  ```
550
559
 
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
560
+ The UI labels this operation `Close Task`, styles it as a red destructive action, and shows a browser confirmation that names the worktree, branch, and metadata that will be deleted. VCM does not check running sessions or uncommitted changes before closing. Tasks created without a worktree remove VCM metadata only.
556
561
 
557
562
  ### `src/backend/services/artifact-service.ts`
558
563
 
@@ -621,7 +626,7 @@ Responsibilities:
621
626
  Persistence:
622
627
 
623
628
  ```text
624
- <baseRepoRoot>/.ai/vcm/sessions/<task>.json
629
+ <taskRepoRoot>/.ai/vcm/sessions/<task>.json
625
630
  ```
626
631
 
627
632
  Environment passed to Claude Code:
@@ -634,7 +639,7 @@ Environment passed to Claude Code:
634
639
  In task-worktree mode:
635
640
 
636
641
  - session cwd is `task.worktreePath`
637
- - session persistence remains central under `baseRepoRoot/.ai/vcm/sessions`
642
+ - session persistence is written under `task.worktreePath/.ai/vcm/sessions`
638
643
  - raw logs and handoff artifacts are written under the task worktree
639
644
 
640
645
  ### `src/backend/services/message-service.ts`
@@ -658,7 +663,8 @@ Responsibilities:
658
663
 
659
664
  In task-worktree mode:
660
665
 
661
- - message snapshots remain central under `baseRepoRoot/.ai/vcm/messages`
666
+ - message snapshots live under `task.worktreePath/.ai/vcm/messages`
667
+ - orchestration state lives under `task.worktreePath/.ai/vcm/orchestration`
662
668
  - message body files live under `task.worktreePath/.ai/handoffs/<task>/messages`
663
669
  - terminal delivery uses the runtime session for the role, whose cwd is the task worktree
664
670
 
@@ -700,6 +706,12 @@ Exports:
700
706
  - `AppSettingsServiceDeps`
701
707
  - `createAppSettingsService(deps)`
702
708
 
709
+ Settings responsibilities:
710
+
711
+ - persist UI theme mode: `system`, `light`, or `dark`
712
+ - persist translation settings and translation secrets
713
+ - persist up to five recent repository paths
714
+
703
715
  Storage:
704
716
 
705
717
  ```text
@@ -770,10 +782,12 @@ Responsibilities:
770
782
  - load/update translation settings
771
783
  - expose prompt previews
772
784
  - test provider
785
+ - start backend transcript listening for a role session
786
+ - poll cached translation events by cursor
773
787
  - translate user input
774
788
  - send English text to active terminal
775
- - subscribe to session translation events
776
- - clear session entries
789
+ - clear session entries and cached events
790
+ - stop session/task translation listeners
777
791
  - retry failed output translation
778
792
  - subscribe to Claude transcript service
779
793
  - translate prose output and preserve tool output
@@ -792,17 +806,17 @@ Exports:
792
806
  - `createDefaultServerDeps(options)`
793
807
  - `getDefaultStaticDir()`
794
808
 
795
- Registers all routes and WebSockets.
809
+ Registers HTTP routes and the terminal WebSocket.
796
810
 
797
811
  ### Route files
798
812
 
799
813
  - `src/backend/api/project-routes.ts`: health, recent paths, connect/current project
800
814
  - `src/backend/api/harness-routes.ts`: harness status/apply
801
- - `src/backend/api/task-routes.ts`: tasks, task status, task cleanup
815
+ - `src/backend/api/task-routes.ts`: tasks, task status, and Close Task cleanup endpoint
802
816
  - `src/backend/api/session-routes.ts`: session lifecycle and dispatch compatibility endpoint
803
817
  - `src/backend/api/artifact-routes.ts`: artifact, role command, and log reads/writes
804
818
  - `src/backend/api/message-routes.ts`: messages and orchestration
805
- - `src/backend/api/translation-routes.ts`: settings, prompt previews, provider test, input/send, clear/retry
819
+ - `src/backend/api/translation-routes.ts`: settings, prompt previews, provider test, start/poll, input/send, clear/retry
806
820
 
807
821
  Worktree task API:
808
822
 
@@ -815,11 +829,10 @@ Do not add a "switch task worktree" endpoint. Worktree assignment happens only d
815
829
  ### WebSocket files
816
830
 
817
831
  - `src/backend/ws/terminal-ws.ts`
818
- - `src/backend/ws/translation-ws.ts`
819
832
 
820
833
  Terminal WebSocket forwards PTY output/input/resize.
821
834
 
822
- Translation WebSocket subscribes to translation entries/status for a runtime session id.
835
+ Translation does not use WebSocket. The backend writes cached translation events under `<taskRepoRoot>/.ai/vcm/translation/<task>/<role>/<session-id>.jsonl`; the frontend polls `GET /api/translation/sessions/:sessionId/events?after=<cursor>`. The cursor is the next expected seq, so `after=18` means seq `1..17` can be removed and seq `18+` should be returned.
823
836
 
824
837
  ## 10. Backend Templates
825
838
 
@@ -931,9 +944,9 @@ Responsibilities:
931
944
  - messages modal
932
945
  - events modal
933
946
  - harness panel
934
- - task creation with one task-name field, checked non-optional worktree/branch indicator, branch preview, and worktree path preview
947
+ - task creation with one task-name field, `Create worktree and branch` checkbox selected by default, branch preview, and worktree path preview
935
948
  - task navigation
936
- - completed-task cleanup action
949
+ - red `Close Task` action with destructive confirmation
937
950
 
938
951
  ### `src/frontend/routes/task-workspace.tsx`
939
952
 
@@ -1068,6 +1081,7 @@ Important current behavior:
1068
1081
  - no `Original` buttons
1069
1082
  - tool output is preserved, dim, one-line
1070
1083
  - prose source is replaced by translated text after completion
1084
+ - prose renders Markdown with GFM support
1071
1085
  - no separate translated-English textarea
1072
1086
 
1073
1087
  ### `src/frontend/components/translation-settings-modal.tsx`
@@ -1079,18 +1093,15 @@ Exports:
1079
1093
 
1080
1094
  Settings:
1081
1095
 
1082
- - enable translation
1083
1096
  - base URL
1084
1097
  - API key as text input
1085
1098
  - model
1086
1099
  - target language
1087
- - input mode
1088
1100
  - context
1089
- - translate output
1090
- - translate user input
1091
1101
  - timeout
1092
1102
  - temperature
1093
- - prompt slot overrides
1103
+ - direct editors for `zh-to-en`, `zh-to-en-with-context`, and `en-to-zh`
1104
+ - reset prompts to built-in defaults
1094
1105
  - provider test
1095
1106
 
1096
1107
  ### `src/frontend/components/status-badge.tsx`
@@ -1114,7 +1125,8 @@ Sidebar:
1114
1125
 
1115
1126
  - all groups default collapsed
1116
1127
  - `Repository Path` default open only when no task is selected
1117
- - `Settings` includes `Messages`, `Events`, and `Auto orchestration`
1128
+ - `Settings` includes `Theme`, `Messages`, `Events`, and `Auto orchestration`
1129
+ - `Theme` cycles through `System`, `Light`, and `Dark`; `System` follows the browser/OS color-scheme preference
1118
1130
 
1119
1131
  Task workspace:
1120
1132
 
@@ -1139,6 +1151,8 @@ App settings:
1139
1151
  ~/.vcm/settings.json
1140
1152
  ```
1141
1153
 
1154
+ Contains UI theme preference, translation settings/secrets, and recent repository paths.
1155
+
1142
1156
  Project config:
1143
1157
 
1144
1158
  ```text
@@ -1149,26 +1163,32 @@ Project config:
1149
1163
  Task state:
1150
1164
 
1151
1165
  ```text
1152
- .ai/vcm/tasks/<task>.json
1166
+ <baseRepoRoot>/.ai/vcm/tasks/<task>.json
1153
1167
  ```
1154
1168
 
1155
1169
  Session state:
1156
1170
 
1157
1171
  ```text
1158
- .ai/vcm/sessions/<task>.json
1172
+ <taskRepoRoot>/.ai/vcm/sessions/<task>.json
1159
1173
  ```
1160
1174
 
1161
1175
  Messages:
1162
1176
 
1163
1177
  ```text
1164
- .ai/vcm/messages/<task>.jsonl
1165
- .ai/handoffs/<task>/messages/<message-id>.md
1178
+ <taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
1179
+ <taskRepoRoot>/.ai/handoffs/<task>/messages/<message-id>.md
1166
1180
  ```
1167
1181
 
1168
1182
  Orchestration:
1169
1183
 
1170
1184
  ```text
1171
- .ai/vcm/orchestration/<task>.json
1185
+ <taskRepoRoot>/.ai/vcm/orchestration/<task>.json
1186
+ ```
1187
+
1188
+ Translation cache:
1189
+
1190
+ ```text
1191
+ <taskRepoRoot>/.ai/vcm/translation/<task>/
1172
1192
  ```
1173
1193
 
1174
1194
  Task worktrees:
@@ -1217,7 +1237,7 @@ For frontend layout changes, also verify manually:
1217
1237
  - Auto orchestration toggles on/off
1218
1238
  - `Enter` in translation composer translates/sends
1219
1239
  - `Shift+Enter` inserts newline
1220
- - mark task complete and verify cleanup removes the worktree and central task metadata
1240
+ - close a worktree-backed task and verify it removes the worktree, deletes the task branch, and removes central task metadata
1221
1241
 
1222
1242
  ## 17. V1 Boundaries To Preserve
1223
1243
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-coding-master",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "Local GUI session cockpit for Claude Code role sessions.",
5
5
  "type": "module",
6
6
  "files": [
@@ -44,6 +44,8 @@
44
44
  "node-pty": "^1.0.0",
45
45
  "react": "^19.1.0",
46
46
  "react-dom": "^19.1.0",
47
+ "react-markdown": "^10.1.0",
48
+ "remark-gfm": "^4.0.1",
47
49
  "ws": "^8.18.2",
48
50
  "zod": "^3.25.28"
49
51
  },
@@ -1,35 +0,0 @@
1
- import { WebSocketServer } from "ws";
2
- import { toVcmError } from "../errors.js";
3
- export function registerTranslationWs(app, deps) {
4
- const wss = new WebSocketServer({ noServer: true });
5
- app.server.on("upgrade", (request, socket, head) => {
6
- const url = new URL(request.url ?? "/", "http://localhost");
7
- const match = /^\/ws\/translation\/([^/]+)$/.exec(url.pathname);
8
- if (!match) {
9
- return;
10
- }
11
- wss.handleUpgrade(request, socket, head, (ws) => {
12
- bindTranslationSocket(ws, decodeURIComponent(match[1] ?? ""), deps.translationService);
13
- });
14
- });
15
- }
16
- function bindTranslationSocket(ws, sessionId, translationService) {
17
- let unsubscribe = () => { };
18
- try {
19
- unsubscribe = translationService.subscribeToSession(sessionId, (message) => send(ws, message));
20
- }
21
- catch (error) {
22
- const vcmError = toVcmError(error);
23
- send(ws, { type: "translation-error", message: vcmError.message });
24
- ws.close();
25
- return;
26
- }
27
- ws.on("close", () => {
28
- unsubscribe();
29
- });
30
- }
31
- function send(ws, message) {
32
- if (ws.readyState === ws.OPEN) {
33
- ws.send(JSON.stringify(message));
34
- }
35
- }
@@ -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,.workspace-worktree{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{display:grid;gap:8px}.task-create-preview{display:grid;gap:2px;border:1px solid #e0d6c7;border-radius:6px;background:#f8f7f2;padding:6px 8px}.task-create-preview span{color:#255f3d;font-size:12px;font-weight:700}.task-create-preview small{overflow:hidden;color:#687273;font-size:11px;text-overflow:ellipsis;white-space:nowrap}.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 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}.workspace-worktree{max-width:260px;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%}}