vibe-coding-master 0.0.9 → 0.0.11
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 +38 -25
- package/dist/backend/api/app-settings-routes.js +8 -0
- package/dist/backend/api/message-routes.js +3 -1
- package/dist/backend/api/session-routes.js +7 -1
- package/dist/backend/api/task-routes.js +12 -10
- package/dist/backend/api/translation-routes.js +21 -3
- package/dist/backend/runtime/terminal-submit.js +20 -0
- package/dist/backend/server.js +9 -4
- package/dist/backend/services/app-settings-service.js +28 -0
- package/dist/backend/services/claude-transcript-service.js +12 -8
- package/dist/backend/services/command-dispatcher.js +2 -1
- package/dist/backend/services/message-service.js +10 -6
- package/dist/backend/services/project-service.js +0 -3
- package/dist/backend/services/session-service.js +7 -4
- package/dist/backend/services/task-service.js +65 -56
- package/dist/backend/services/translation-service.js +264 -77
- package/dist/shared/types/app-settings.js +1 -0
- package/dist-frontend/assets/index-Bi4X3GSR.css +32 -0
- package/dist-frontend/assets/index-DaHXq14j.js +88 -0
- package/dist-frontend/index.html +2 -2
- package/docs/cc-best-practices.md +4 -4
- package/docs/product-design.md +71 -33
- package/docs/v1-architecture-design.md +92 -60
- package/docs/v1-implementation-plan.md +101 -61
- package/package.json +3 -1
- package/dist/backend/ws/translation-ws.js +0 -35
- package/dist-frontend/assets/index-CuiNNOzj.css +0 -32
- package/dist-frontend/assets/index-D59GuHCR.js +0 -58
|
@@ -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
|
|
|
@@ -28,7 +28,7 @@ File:
|
|
|
28
28
|
Current package facts:
|
|
29
29
|
|
|
30
30
|
- package name: `vibe-coding-master`
|
|
31
|
-
- current version: `0.0.
|
|
31
|
+
- current version: `0.0.10`
|
|
32
32
|
- type: ESM
|
|
33
33
|
- `bin.vcm`: `dist/main.js`
|
|
34
34
|
- `bin.vcmctl`: `dist/cli/vcmctl.js`
|
|
@@ -179,6 +179,20 @@ Important fields:
|
|
|
179
179
|
- `claudeCommand`
|
|
180
180
|
- `isDirty`
|
|
181
181
|
|
|
182
|
+
### `src/shared/types/app-settings.ts`
|
|
183
|
+
|
|
184
|
+
Defines:
|
|
185
|
+
|
|
186
|
+
- `ThemeMode`
|
|
187
|
+
- `AppPreferences`
|
|
188
|
+
- `UpdateAppPreferencesRequest`
|
|
189
|
+
|
|
190
|
+
Theme modes:
|
|
191
|
+
|
|
192
|
+
- `system`
|
|
193
|
+
- `light`
|
|
194
|
+
- `dark`
|
|
195
|
+
|
|
182
196
|
### `src/shared/types/task.ts`
|
|
183
197
|
|
|
184
198
|
Defines:
|
|
@@ -187,16 +201,16 @@ Defines:
|
|
|
187
201
|
- `TaskRecord`
|
|
188
202
|
- `CreateTaskRequest`
|
|
189
203
|
|
|
190
|
-
Current UI sends
|
|
204
|
+
Current UI sends `taskSlug` and `createWorktree`; the API type still permits optional `title` and `specPath`.
|
|
191
205
|
|
|
192
206
|
Worktree fields:
|
|
193
207
|
|
|
194
|
-
- `worktreePath
|
|
195
|
-
- `branch: feature/<taskSlug>`
|
|
208
|
+
- `worktreePath?: string`
|
|
209
|
+
- `branch: feature/<taskSlug>` when worktree creation is selected, otherwise the connected repo's current branch
|
|
196
210
|
- `cleanupStatus?: "active" | "cleaned"`
|
|
197
211
|
- `cleanedAt?: string`
|
|
198
212
|
|
|
199
|
-
`CreateTaskRequest` creates a worktree and branch by default
|
|
213
|
+
`CreateTaskRequest` supports `createWorktree?: boolean`. It creates a worktree and branch by default, and skips both when `createWorktree === false`.
|
|
200
214
|
|
|
201
215
|
### `src/shared/types/session.ts`
|
|
202
216
|
|
|
@@ -244,7 +258,10 @@ Defines:
|
|
|
244
258
|
- `SendTranslatedInputRequest`
|
|
245
259
|
- `TranslationProviderTestResult`
|
|
246
260
|
- `TranslationPromptPreview`
|
|
247
|
-
- `
|
|
261
|
+
- `TranslationSessionStatus`
|
|
262
|
+
- `TranslationSessionEvent`
|
|
263
|
+
- `StartTranslationSessionResult`
|
|
264
|
+
- `PollTranslationSessionResult`
|
|
248
265
|
|
|
249
266
|
Prompt keys:
|
|
250
267
|
|
|
@@ -396,8 +413,8 @@ Worktree methods:
|
|
|
396
413
|
Required safety:
|
|
397
414
|
|
|
398
415
|
- all Git commands keep command-scoped `safe.directory`
|
|
399
|
-
-
|
|
400
|
-
-
|
|
416
|
+
- `TaskService` verifies Close Task worktree paths are under `<baseRepoRoot>/.ai/vcm/worktrees/`
|
|
417
|
+
- VCM-created task branches are derived from validated task slugs as `feature/<taskSlug>`
|
|
401
418
|
|
|
402
419
|
### `src/backend/adapters/claude-adapter.ts`
|
|
403
420
|
|
|
@@ -520,39 +537,44 @@ Create flow:
|
|
|
520
537
|
```text
|
|
521
538
|
createTask(baseRepoRoot, { taskSlug })
|
|
522
539
|
-> assertValidTaskSlug(taskSlug)
|
|
523
|
-
-> branch = feature/<taskSlug>
|
|
524
|
-
-> worktreePath = <baseRepoRoot>/.ai/vcm/worktrees/<taskSlug>
|
|
525
540
|
-> assert .ai/vcm/ is ignored
|
|
526
|
-
->
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
541
|
+
-> if createWorktree is not false:
|
|
542
|
+
-> branch = feature/<taskSlug>
|
|
543
|
+
-> worktreePath = <baseRepoRoot>/.ai/vcm/worktrees/<taskSlug>
|
|
544
|
+
-> assert base repo has no uncommitted changes
|
|
545
|
+
-> assert branch does not exist
|
|
546
|
+
-> assert worktree path does not exist
|
|
547
|
+
-> git.createWorktree({ baseRepoRoot, branch, worktreePath, baseRef: HEAD })
|
|
548
|
+
-> taskRepoRoot = worktreePath
|
|
549
|
+
-> otherwise:
|
|
550
|
+
-> branch = current base repo branch
|
|
551
|
+
-> worktreePath = undefined
|
|
552
|
+
-> taskRepoRoot = baseRepoRoot
|
|
553
|
+
-> artifactService.ensureHandoffStructure({ repoRoot: taskRepoRoot, handoffDir })
|
|
554
|
+
-> artifactService.createArtifactTemplates({ repoRoot: taskRepoRoot, handoffDir })
|
|
555
|
+
-> ensure task runtime state dirs under <taskRepoRoot>/.ai/vcm/
|
|
532
556
|
-> write central task record under <baseRepoRoot>/.ai/vcm/tasks/<task>.json
|
|
533
557
|
```
|
|
534
558
|
|
|
535
|
-
|
|
559
|
+
Close Task flow:
|
|
536
560
|
|
|
537
561
|
```text
|
|
538
562
|
cleanupTask(baseRepoRoot, taskSlug, options)
|
|
539
|
-
-> require all role sessions stopped
|
|
540
563
|
-> load central task record
|
|
541
|
-
->
|
|
542
|
-
->
|
|
543
|
-
->
|
|
544
|
-
->
|
|
545
|
-
->
|
|
546
|
-
->
|
|
547
|
-
-> delete
|
|
548
|
-
-> delete
|
|
564
|
+
-> route layer lists role sessions
|
|
565
|
+
-> route layer stops each VCM-managed role session with status running
|
|
566
|
+
-> route layer stops translation tailers and clears task translation cache
|
|
567
|
+
-> if worktreePath exists, verify it is under <baseRepoRoot>/.ai/vcm/worktrees/
|
|
568
|
+
-> if worktreePath exists, git.removeWorktree(baseRepoRoot, worktreePath, force=true)
|
|
569
|
+
-> if worktreePath exists, git.deleteBranch(baseRepoRoot, task.branch, force=true) by default
|
|
570
|
+
-> delete <baseRepoRoot>/.ai/vcm/tasks/<task>.json
|
|
571
|
+
-> delete <taskRepoRoot>/.ai/vcm/sessions/<task>.json
|
|
572
|
+
-> delete <taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
|
|
573
|
+
-> delete <taskRepoRoot>/.ai/vcm/orchestration/<task>.json
|
|
574
|
+
-> delete <taskRepoRoot>/.ai/vcm/translation/<task>/
|
|
549
575
|
```
|
|
550
576
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
- keep `feature/<taskSlug>` by default
|
|
554
|
-
- optional `deleteBranch` only with explicit confirmation
|
|
555
|
-
- prefer requiring merged branch unless force-confirmed
|
|
577
|
+
The UI labels this operation `Close Task`, styles it as a red destructive action, and shows a browser confirmation that names running role-session shutdown, the worktree, branch, and metadata that will be deleted. VCM actively stops VCM-managed running role sessions, but it does not preflight running sessions or uncommitted changes before closing. Tasks created without a worktree remove VCM metadata only.
|
|
556
578
|
|
|
557
579
|
### `src/backend/services/artifact-service.ts`
|
|
558
580
|
|
|
@@ -621,7 +643,7 @@ Responsibilities:
|
|
|
621
643
|
Persistence:
|
|
622
644
|
|
|
623
645
|
```text
|
|
624
|
-
<
|
|
646
|
+
<taskRepoRoot>/.ai/vcm/sessions/<task>.json
|
|
625
647
|
```
|
|
626
648
|
|
|
627
649
|
Environment passed to Claude Code:
|
|
@@ -634,7 +656,7 @@ Environment passed to Claude Code:
|
|
|
634
656
|
In task-worktree mode:
|
|
635
657
|
|
|
636
658
|
- session cwd is `task.worktreePath`
|
|
637
|
-
- session persistence
|
|
659
|
+
- session persistence is written under `task.worktreePath/.ai/vcm/sessions`
|
|
638
660
|
- raw logs and handoff artifacts are written under the task worktree
|
|
639
661
|
|
|
640
662
|
### `src/backend/services/message-service.ts`
|
|
@@ -658,7 +680,8 @@ Responsibilities:
|
|
|
658
680
|
|
|
659
681
|
In task-worktree mode:
|
|
660
682
|
|
|
661
|
-
- message snapshots
|
|
683
|
+
- message snapshots live under `task.worktreePath/.ai/vcm/messages`
|
|
684
|
+
- orchestration state lives under `task.worktreePath/.ai/vcm/orchestration`
|
|
662
685
|
- message body files live under `task.worktreePath/.ai/handoffs/<task>/messages`
|
|
663
686
|
- terminal delivery uses the runtime session for the role, whose cwd is the task worktree
|
|
664
687
|
|
|
@@ -700,6 +723,12 @@ Exports:
|
|
|
700
723
|
- `AppSettingsServiceDeps`
|
|
701
724
|
- `createAppSettingsService(deps)`
|
|
702
725
|
|
|
726
|
+
Settings responsibilities:
|
|
727
|
+
|
|
728
|
+
- persist UI theme mode: `system`, `light`, or `dark`
|
|
729
|
+
- persist translation settings and translation secrets
|
|
730
|
+
- persist up to five recent repository paths
|
|
731
|
+
|
|
703
732
|
Storage:
|
|
704
733
|
|
|
705
734
|
```text
|
|
@@ -763,21 +792,24 @@ Exports:
|
|
|
763
792
|
- `TranslationEventListener`
|
|
764
793
|
- `TranslationServiceDeps`
|
|
765
794
|
- `createTranslationService(deps)`
|
|
766
|
-
- `formatTerminalSubmit(text)`
|
|
767
795
|
|
|
768
796
|
Responsibilities:
|
|
769
797
|
|
|
770
798
|
- load/update translation settings
|
|
771
799
|
- expose prompt previews
|
|
772
800
|
- test provider
|
|
801
|
+
- start backend transcript listening for a role session
|
|
802
|
+
- poll cached translation events by cursor
|
|
773
803
|
- translate user input
|
|
774
804
|
- send English text to active terminal
|
|
775
|
-
-
|
|
776
|
-
-
|
|
805
|
+
- clear session entries and cached events
|
|
806
|
+
- stop session/task translation listeners
|
|
777
807
|
- retry failed output translation
|
|
778
808
|
- subscribe to Claude transcript service
|
|
779
809
|
- translate prose output and preserve tool output
|
|
780
810
|
|
|
811
|
+
Terminal submission is delegated to `src/backend/runtime/terminal-submit.ts`, which bracket-pastes text, waits briefly, then sends Enter separately.
|
|
812
|
+
|
|
781
813
|
## 9. Backend API
|
|
782
814
|
|
|
783
815
|
### `src/backend/server.ts`
|
|
@@ -792,17 +824,18 @@ Exports:
|
|
|
792
824
|
- `createDefaultServerDeps(options)`
|
|
793
825
|
- `getDefaultStaticDir()`
|
|
794
826
|
|
|
795
|
-
Registers
|
|
827
|
+
Registers HTTP routes and the terminal WebSocket.
|
|
796
828
|
|
|
797
829
|
### Route files
|
|
798
830
|
|
|
831
|
+
- `src/backend/api/app-settings-routes.ts`: UI preferences
|
|
799
832
|
- `src/backend/api/project-routes.ts`: health, recent paths, connect/current project
|
|
800
833
|
- `src/backend/api/harness-routes.ts`: harness status/apply
|
|
801
|
-
- `src/backend/api/task-routes.ts`: tasks, task status, task cleanup
|
|
834
|
+
- `src/backend/api/task-routes.ts`: tasks, task status, and Close Task cleanup endpoint; Close Task stops running role sessions before translation/task cleanup
|
|
802
835
|
- `src/backend/api/session-routes.ts`: session lifecycle and dispatch compatibility endpoint
|
|
803
836
|
- `src/backend/api/artifact-routes.ts`: artifact, role command, and log reads/writes
|
|
804
837
|
- `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
|
|
838
|
+
- `src/backend/api/translation-routes.ts`: settings, prompt previews, provider test, start/poll, input/send, clear/retry
|
|
806
839
|
|
|
807
840
|
Worktree task API:
|
|
808
841
|
|
|
@@ -815,11 +848,10 @@ Do not add a "switch task worktree" endpoint. Worktree assignment happens only d
|
|
|
815
848
|
### WebSocket files
|
|
816
849
|
|
|
817
850
|
- `src/backend/ws/terminal-ws.ts`
|
|
818
|
-
- `src/backend/ws/translation-ws.ts`
|
|
819
851
|
|
|
820
852
|
Terminal WebSocket forwards PTY output/input/resize.
|
|
821
853
|
|
|
822
|
-
Translation WebSocket
|
|
854
|
+
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
855
|
|
|
824
856
|
## 10. Backend Templates
|
|
825
857
|
|
|
@@ -878,12 +910,12 @@ It calls:
|
|
|
878
910
|
- orchestration endpoints
|
|
879
911
|
- translation endpoints
|
|
880
912
|
|
|
881
|
-
|
|
913
|
+
Implemented task cleanup method:
|
|
882
914
|
|
|
883
|
-
- `listGitWorktrees()`
|
|
884
|
-
- `listGitBranches()`
|
|
885
915
|
- `cleanupTask(taskSlug, options)`
|
|
886
916
|
|
|
917
|
+
There are no branch/worktree switching APIs in the current frontend client.
|
|
918
|
+
|
|
887
919
|
### `src/frontend/state/app-store.ts`
|
|
888
920
|
|
|
889
921
|
Exports:
|
|
@@ -931,9 +963,8 @@ Responsibilities:
|
|
|
931
963
|
- messages modal
|
|
932
964
|
- events modal
|
|
933
965
|
- harness panel
|
|
934
|
-
- task creation with one task-name field,
|
|
966
|
+
- task creation with one task-name field, `Create worktree and branch` checkbox selected by default, branch preview, and worktree path preview
|
|
935
967
|
- task navigation
|
|
936
|
-
- completed-task cleanup action
|
|
937
968
|
|
|
938
969
|
### `src/frontend/routes/task-workspace.tsx`
|
|
939
970
|
|
|
@@ -945,6 +976,7 @@ Exports:
|
|
|
945
976
|
Responsibilities:
|
|
946
977
|
|
|
947
978
|
- task header with role tabs and refresh
|
|
979
|
+
- red `Close Task` action with destructive confirmation
|
|
948
980
|
- show branch and immutable worktree path for the active task
|
|
949
981
|
- status/message/orchestration refresh
|
|
950
982
|
- periodic polling
|
|
@@ -1003,7 +1035,7 @@ Exports:
|
|
|
1003
1035
|
- `getMessageCounts(messages)`
|
|
1004
1036
|
- `MessageTimeline(props)`
|
|
1005
1037
|
|
|
1006
|
-
Used inside the Messages modal.
|
|
1038
|
+
Used inside the Messages modal. Current UI rows show sequence, timestamp, route, type, status, body preview, body path, and a `Copy` button. Stage/approve/reject backend APIs remain compatibility paths, but those buttons are not displayed in the current modal.
|
|
1007
1039
|
|
|
1008
1040
|
### `src/frontend/components/event-log.tsx`
|
|
1009
1041
|
|
|
@@ -1068,6 +1100,8 @@ Important current behavior:
|
|
|
1068
1100
|
- no `Original` buttons
|
|
1069
1101
|
- tool output is preserved, dim, one-line
|
|
1070
1102
|
- prose source is replaced by translated text after completion
|
|
1103
|
+
- prose renders Markdown with GFM support
|
|
1104
|
+
- user-input translation entries add a thick divider and larger top spacing to mark question/answer boundaries
|
|
1071
1105
|
- no separate translated-English textarea
|
|
1072
1106
|
|
|
1073
1107
|
### `src/frontend/components/translation-settings-modal.tsx`
|
|
@@ -1079,18 +1113,15 @@ Exports:
|
|
|
1079
1113
|
|
|
1080
1114
|
Settings:
|
|
1081
1115
|
|
|
1082
|
-
- enable translation
|
|
1083
1116
|
- base URL
|
|
1084
1117
|
- API key as text input
|
|
1085
1118
|
- model
|
|
1086
1119
|
- target language
|
|
1087
|
-
- input mode
|
|
1088
1120
|
- context
|
|
1089
|
-
- translate output
|
|
1090
|
-
- translate user input
|
|
1091
1121
|
- timeout
|
|
1092
1122
|
- temperature
|
|
1093
|
-
-
|
|
1123
|
+
- direct editors for `zh-to-en`, `zh-to-en-with-context`, and `en-to-zh`
|
|
1124
|
+
- reset prompts to built-in defaults
|
|
1094
1125
|
- provider test
|
|
1095
1126
|
|
|
1096
1127
|
### `src/frontend/components/status-badge.tsx`
|
|
@@ -1114,7 +1145,8 @@ Sidebar:
|
|
|
1114
1145
|
|
|
1115
1146
|
- all groups default collapsed
|
|
1116
1147
|
- `Repository Path` default open only when no task is selected
|
|
1117
|
-
- `Settings` includes `Messages`, `Events`, and `Auto orchestration`
|
|
1148
|
+
- `Settings` includes `Theme`, `Messages`, `Events`, and `Auto orchestration`
|
|
1149
|
+
- `Theme` cycles through `System`, `Light`, and `Dark`; `System` follows the browser/OS color-scheme preference
|
|
1118
1150
|
|
|
1119
1151
|
Task workspace:
|
|
1120
1152
|
|
|
@@ -1139,6 +1171,8 @@ App settings:
|
|
|
1139
1171
|
~/.vcm/settings.json
|
|
1140
1172
|
```
|
|
1141
1173
|
|
|
1174
|
+
Contains UI theme preference, translation settings/secrets, and recent repository paths.
|
|
1175
|
+
|
|
1142
1176
|
Project config:
|
|
1143
1177
|
|
|
1144
1178
|
```text
|
|
@@ -1149,26 +1183,32 @@ Project config:
|
|
|
1149
1183
|
Task state:
|
|
1150
1184
|
|
|
1151
1185
|
```text
|
|
1152
|
-
|
|
1186
|
+
<baseRepoRoot>/.ai/vcm/tasks/<task>.json
|
|
1153
1187
|
```
|
|
1154
1188
|
|
|
1155
1189
|
Session state:
|
|
1156
1190
|
|
|
1157
1191
|
```text
|
|
1158
|
-
|
|
1192
|
+
<taskRepoRoot>/.ai/vcm/sessions/<task>.json
|
|
1159
1193
|
```
|
|
1160
1194
|
|
|
1161
1195
|
Messages:
|
|
1162
1196
|
|
|
1163
1197
|
```text
|
|
1164
|
-
|
|
1165
|
-
|
|
1198
|
+
<taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
|
|
1199
|
+
<taskRepoRoot>/.ai/handoffs/<task>/messages/<message-id>.md
|
|
1166
1200
|
```
|
|
1167
1201
|
|
|
1168
1202
|
Orchestration:
|
|
1169
1203
|
|
|
1170
1204
|
```text
|
|
1171
|
-
|
|
1205
|
+
<taskRepoRoot>/.ai/vcm/orchestration/<task>.json
|
|
1206
|
+
```
|
|
1207
|
+
|
|
1208
|
+
Translation cache:
|
|
1209
|
+
|
|
1210
|
+
```text
|
|
1211
|
+
<taskRepoRoot>/.ai/vcm/translation/<task>/
|
|
1172
1212
|
```
|
|
1173
1213
|
|
|
1174
1214
|
Task worktrees:
|
|
@@ -1217,7 +1257,7 @@ For frontend layout changes, also verify manually:
|
|
|
1217
1257
|
- Auto orchestration toggles on/off
|
|
1218
1258
|
- `Enter` in translation composer translates/sends
|
|
1219
1259
|
- `Shift+Enter` inserts newline
|
|
1220
|
-
-
|
|
1260
|
+
- close a worktree-backed task and verify it stops running role sessions, removes the worktree, deletes the task branch, and removes central task metadata
|
|
1221
1261
|
|
|
1222
1262
|
## 17. V1 Boundaries To Preserve
|
|
1223
1263
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-coding-master",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
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%}}
|