clawcontainer 1.0.0

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.
Files changed (150) hide show
  1. package/CONTRIBUTING.md +76 -0
  2. package/DOCS.md +370 -0
  3. package/LICENSE +21 -0
  4. package/README.md +147 -0
  5. package/black_logo.png +0 -0
  6. package/dist/assets/abap-DLDM7-KI.js +1 -0
  7. package/dist/assets/apex-DNDY2TF8.js +1 -0
  8. package/dist/assets/azcli-Y6nb8tq_.js +1 -0
  9. package/dist/assets/bat-BwHxbl9M.js +1 -0
  10. package/dist/assets/bicep-CFznDFnq.js +2 -0
  11. package/dist/assets/cameligo-Bf6VGUru.js +1 -0
  12. package/dist/assets/clojure-Dnu-v4kV.js +1 -0
  13. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  14. package/dist/assets/coffee-Bd8akH9Z.js +1 -0
  15. package/dist/assets/cpp-BbWJElDN.js +1 -0
  16. package/dist/assets/csharp-Co3qMtFm.js +1 -0
  17. package/dist/assets/csp-D-4FJmMZ.js +1 -0
  18. package/dist/assets/css-DdJfP1eB.js +3 -0
  19. package/dist/assets/css.worker-GxEd3MMM.js +93 -0
  20. package/dist/assets/cssMode-DM_ONlf-.js +1 -0
  21. package/dist/assets/cypher-cTPe9QuQ.js +1 -0
  22. package/dist/assets/dart-BOtBlQCF.js +1 -0
  23. package/dist/assets/dockerfile-BG73LgW2.js +1 -0
  24. package/dist/assets/ecl-BEgZUVRK.js +1 -0
  25. package/dist/assets/elixir-BkW5O-1t.js +1 -0
  26. package/dist/assets/flow9-BeJ5waoc.js +1 -0
  27. package/dist/assets/freemarker2-VbwzOQPq.js +3 -0
  28. package/dist/assets/fsharp-PahG7c26.js +1 -0
  29. package/dist/assets/go-acbASCJo.js +1 -0
  30. package/dist/assets/graphql-BxJiqAUM.js +1 -0
  31. package/dist/assets/handlebars-DLvQ802u.js +1 -0
  32. package/dist/assets/hcl-DtV1sZF8.js +1 -0
  33. package/dist/assets/html-DuEPBzmS.js +1 -0
  34. package/dist/assets/html.worker-lU17Tx2m.js +470 -0
  35. package/dist/assets/htmlMode-BfeYTJaB.js +1 -0
  36. package/dist/assets/index-BnBKg8GZ.js +1291 -0
  37. package/dist/assets/index-Dq3FlPWe.css +32 -0
  38. package/dist/assets/ini-Kd9XrMLS.js +1 -0
  39. package/dist/assets/java-CXBNlu9o.js +1 -0
  40. package/dist/assets/javascript-DQO1Leza.js +1 -0
  41. package/dist/assets/json.worker-CUJs-dtA.js +58 -0
  42. package/dist/assets/jsonMode--qsURhHr.js +7 -0
  43. package/dist/assets/julia-cl7-CwDS.js +1 -0
  44. package/dist/assets/kotlin-s7OhZKlX.js +1 -0
  45. package/dist/assets/less-9HpZscsL.js +2 -0
  46. package/dist/assets/lexon-OrD6JF1K.js +1 -0
  47. package/dist/assets/liquid-PL6MZtM8.js +1 -0
  48. package/dist/assets/lspLanguageFeatures-Cy5rDFeq.js +4 -0
  49. package/dist/assets/lua-Cyyb5UIc.js +1 -0
  50. package/dist/assets/m3-B8OfTtLu.js +1 -0
  51. package/dist/assets/markdown-BFxVWTOG.js +1 -0
  52. package/dist/assets/mdx-Cb3Jy14X.js +1 -0
  53. package/dist/assets/mips-CiqrrVzr.js +1 -0
  54. package/dist/assets/msdax-DmeGPVcC.js +1 -0
  55. package/dist/assets/mysql-C_tMU-Nz.js +1 -0
  56. package/dist/assets/objective-c-BDtDVThU.js +1 -0
  57. package/dist/assets/pascal-vHIfCaH5.js +1 -0
  58. package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
  59. package/dist/assets/perl-Ub6l9XKa.js +1 -0
  60. package/dist/assets/pgsql-BlNEE0v7.js +1 -0
  61. package/dist/assets/php-BBUBE1dy.js +1 -0
  62. package/dist/assets/pla-DSh2-awV.js +1 -0
  63. package/dist/assets/postiats-CocnycG-.js +1 -0
  64. package/dist/assets/powerquery-tScXyioY.js +1 -0
  65. package/dist/assets/powershell-COWaemsV.js +1 -0
  66. package/dist/assets/protobuf-Brw8urJB.js +2 -0
  67. package/dist/assets/pug-8SOpv6rk.js +1 -0
  68. package/dist/assets/python-Usm4OUwq.js +1 -0
  69. package/dist/assets/qsharp-Bw9ernYp.js +1 -0
  70. package/dist/assets/r-j7ic8hl3.js +1 -0
  71. package/dist/assets/razor-BIOole7a.js +1 -0
  72. package/dist/assets/redis-Bu5POkcn.js +1 -0
  73. package/dist/assets/redshift-Bs9aos_-.js +1 -0
  74. package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
  75. package/dist/assets/ruby-zBfavPgS.js +1 -0
  76. package/dist/assets/rust-BzKRNQWT.js +1 -0
  77. package/dist/assets/sb-BBc9UKZt.js +1 -0
  78. package/dist/assets/scala-D9hQfWCl.js +1 -0
  79. package/dist/assets/scheme-BPhDTwHR.js +1 -0
  80. package/dist/assets/scss-CBJaRo0y.js +3 -0
  81. package/dist/assets/shell-DiJ1NA_G.js +1 -0
  82. package/dist/assets/solidity-Db0IVjzk.js +1 -0
  83. package/dist/assets/sophia-CnS9iZB_.js +1 -0
  84. package/dist/assets/sparql-CJmd_6j2.js +1 -0
  85. package/dist/assets/sql-ClhHkBeG.js +1 -0
  86. package/dist/assets/st-CHwy0fLd.js +1 -0
  87. package/dist/assets/swift-Bqt4WxQ4.js +3 -0
  88. package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
  89. package/dist/assets/tcl-Dm6ycUr_.js +1 -0
  90. package/dist/assets/ts.worker-Dy9lDQQT.js +67731 -0
  91. package/dist/assets/tsMode-CDjF3DWK.js +11 -0
  92. package/dist/assets/twig-Csy3S7wG.js +1 -0
  93. package/dist/assets/typescript-CJR4sLnG.js +1 -0
  94. package/dist/assets/typespec-Btyra-wh.js +1 -0
  95. package/dist/assets/vb-Db0cS2oM.js +1 -0
  96. package/dist/assets/wgsl-DumH7NcR.js +298 -0
  97. package/dist/assets/xml-CJZS3uh7.js +1 -0
  98. package/dist/assets/yaml-DB88cW5z.js +1 -0
  99. package/dist/audit.d.ts +48 -0
  100. package/dist/container.d.ts +100 -0
  101. package/dist/event-emitter.d.ts +7 -0
  102. package/dist/favicon.png +0 -0
  103. package/dist/git-service.d.ts +31 -0
  104. package/dist/index.html +188 -0
  105. package/dist/logo-sm.png +0 -0
  106. package/dist/logo.png +0 -0
  107. package/dist/main.d.ts +1 -0
  108. package/dist/monaco-editor.d.ts +11 -0
  109. package/dist/monacoeditorwork/css.worker.bundle.js +54264 -0
  110. package/dist/monacoeditorwork/editor.worker.bundle.js +14317 -0
  111. package/dist/monacoeditorwork/html.worker.bundle.js +30449 -0
  112. package/dist/monacoeditorwork/json.worker.bundle.js +22085 -0
  113. package/dist/monacoeditorwork/ts.worker.bundle.js +225552 -0
  114. package/dist/net-intercept.d.ts +2 -0
  115. package/dist/network-hook.d.ts +1 -0
  116. package/dist/plugin.d.ts +20 -0
  117. package/dist/policy.d.ts +58 -0
  118. package/dist/sdk.d.ts +61 -0
  119. package/dist/tab-manager.d.ts +11 -0
  120. package/dist/templates.d.ts +46 -0
  121. package/dist/terminal.d.ts +19 -0
  122. package/dist/types.d.ts +109 -0
  123. package/dist/ui.d.ts +81 -0
  124. package/dist/workspace.d.ts +16 -0
  125. package/index.html +159 -0
  126. package/logo.png +0 -0
  127. package/package.json +31 -0
  128. package/public/favicon.png +0 -0
  129. package/public/logo-sm.png +0 -0
  130. package/public/logo.png +0 -0
  131. package/src/audit.ts +196 -0
  132. package/src/container.ts +723 -0
  133. package/src/event-emitter.ts +28 -0
  134. package/src/git-service.ts +202 -0
  135. package/src/main.ts +9 -0
  136. package/src/monaco-editor.ts +111 -0
  137. package/src/net-intercept.ts +74 -0
  138. package/src/network-hook.ts +248 -0
  139. package/src/plugin.ts +63 -0
  140. package/src/policy.ts +403 -0
  141. package/src/sdk.ts +355 -0
  142. package/src/style.css +432 -0
  143. package/src/tab-manager.ts +30 -0
  144. package/src/templates.ts +271 -0
  145. package/src/terminal.ts +78 -0
  146. package/src/types.ts +113 -0
  147. package/src/ui.ts +1266 -0
  148. package/src/workspace.ts +107 -0
  149. package/tsconfig.json +20 -0
  150. package/vite.config.ts +52 -0
package/src/style.css ADDED
@@ -0,0 +1,432 @@
1
+ /* ─── Reset & base ─────────────────────────────────────────────── */
2
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
3
+
4
+ :root {
5
+ --bg: #0d1117;
6
+ --bg2: #161b22;
7
+ --bg3: #21262d;
8
+ --border: #30363d;
9
+ --text: #e6edf3;
10
+ --text-dim: #8b949e;
11
+ --accent: #f78166;
12
+ --green: #3fb950;
13
+ --yellow: #d29922;
14
+ --blue: #58a6ff;
15
+ --filetree-w: 240px;
16
+ --sidebar-w: 300px;
17
+ --topbar-h: 44px;
18
+ }
19
+
20
+ html, body { height: 100%; background: var(--bg); color: var(--text);
21
+ font-family: 'SF Mono','Fira Code','Cascadia Code',Menlo,monospace;
22
+ font-size: 13px; overflow: hidden; }
23
+
24
+ /* ─── Loading overlay ───────────────────────────────────────────── */
25
+ #loading-overlay {
26
+ position: fixed; inset: 0; background: var(--bg);
27
+ display: flex; align-items: center; justify-content: center;
28
+ z-index: 1000; transition: opacity 0.4s ease;
29
+ }
30
+ #loading-overlay.fade-out { opacity: 0; pointer-events: none; }
31
+ .loading-inner { text-align: center; display: flex; flex-direction: column;
32
+ align-items: center; gap: 12px; }
33
+ .claw-logo { animation: pulse 1.5s ease-in-out infinite;
34
+ display: flex; align-items: center; justify-content: center; }
35
+ .loading-logo { display: block; }
36
+ @keyframes pulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.1)} }
37
+ .loading-inner h2 { font-size: 22px; color: var(--accent); letter-spacing: 1px; }
38
+ #loading-status { color: var(--text-dim); font-size: 12px; min-height: 18px; }
39
+ .progress-bar { width: 240px; height: 3px; background: var(--bg3);
40
+ border-radius: 2px; overflow: hidden; }
41
+ #progress-fill { height: 100%; width: 0%; background: var(--accent);
42
+ transition: width 0.3s ease; }
43
+
44
+ /* ─── App shell ─────────────────────────────────────────────────── */
45
+ #app { display: flex; flex-direction: column; height: 100vh; }
46
+
47
+ #bottom-bar {
48
+ height: 24px; flex-shrink: 0;
49
+ background: var(--bg2); border-top: 1px solid var(--border);
50
+ display: flex; align-items: center; padding: 0 12px;
51
+ font-size: 11px; gap: 6px;
52
+ }
53
+ .bottom-bar-text { color: var(--text); font-weight: 600; }
54
+ .bottom-bar-sep { color: var(--text-dim); }
55
+ .bottom-bar-desc { color: var(--text-dim); }
56
+
57
+ /* ─── Topbar ────────────────────────────────────────────────────── */
58
+ #topbar {
59
+ height: var(--topbar-h); background: var(--bg2);
60
+ border-bottom: 1px solid var(--border);
61
+ display: flex; align-items: center; justify-content: space-between;
62
+ padding: 0 14px; flex-shrink: 0;
63
+ }
64
+ .topbar-left { display: flex; align-items: center; gap: 10px; }
65
+ .topbar-right { display: flex; align-items: center; gap: 4px; }
66
+ .logo { font-size: 15px; font-weight: 600; color: var(--accent);
67
+ display: flex; align-items: center; gap: 6px; }
68
+ .logo svg, .icon-logo, .topbar-logo { vertical-align: middle; flex-shrink: 0; }
69
+
70
+ .topbar-sep { color: var(--text-dim); font-size: 12px; }
71
+ .topbar-gitagent {
72
+ font-size: 11px; color: var(--text-dim); white-space: nowrap;
73
+ }
74
+ .topbar-gitagent a {
75
+ color: var(--blue); text-decoration: none; font-weight: 600;
76
+ }
77
+ .topbar-gitagent a:hover { text-decoration: underline; }
78
+
79
+ .status-badge { font-size: 11px; padding: 2px 8px; border-radius: 10px;
80
+ font-weight: 500; letter-spacing: 0.3px; }
81
+ .status-booting { background: #2d2e1e; color: var(--yellow); }
82
+ .status-ready { background: #1a2e1a; color: var(--green); }
83
+ .status-error { background: #2e1a1a; color: var(--accent); }
84
+ .status-install { background: #1a1e2e; color: var(--blue); }
85
+
86
+ /* ─── Topbar center (repo controls) ──────────────────────────── */
87
+ .topbar-center {
88
+ display: flex; align-items: center; gap: 6px;
89
+ max-width: 500px; flex: 1; margin: 0 12px;
90
+ }
91
+ #repo-url-input {
92
+ flex: 1; background: var(--bg); color: var(--text);
93
+ border: 1px solid var(--border); border-radius: 4px;
94
+ padding: 4px 8px; font-size: 12px; font-family: inherit;
95
+ outline: none; min-width: 0;
96
+ }
97
+ #repo-url-input:focus { border-color: var(--blue); }
98
+ #repo-url-input::placeholder { color: var(--text-dim); }
99
+
100
+ .auto-sync-toggle {
101
+ display: flex; align-items: center; gap: 4px;
102
+ font-size: 11px; color: var(--text-dim); cursor: pointer;
103
+ white-space: nowrap; user-select: none;
104
+ }
105
+ .auto-sync-toggle input[type="checkbox"] {
106
+ width: 14px; height: 14px; accent-color: var(--accent); cursor: pointer;
107
+ }
108
+
109
+ .btn-icon.syncing svg {
110
+ animation: spin-sync 1s linear infinite;
111
+ }
112
+ @keyframes spin-sync {
113
+ from { transform: rotate(0deg); }
114
+ to { transform: rotate(360deg); }
115
+ }
116
+
117
+ .btn-icon { background: none; border: 1px solid transparent; color: var(--text-dim);
118
+ cursor: pointer; padding: 4px 8px; border-radius: 6px; font-size: 15px;
119
+ transition: all 0.15s; display: inline-flex; align-items: center; justify-content: center; }
120
+ .btn-icon svg { display: block; }
121
+ .btn-icon:hover { border-color: var(--border); color: var(--text); background: var(--bg3); }
122
+ .btn-icon.active { border-color: var(--accent); color: var(--accent); background: var(--bg3); }
123
+
124
+ /* ─── Body ──────────────────────────────────────────────────────── */
125
+ #body { display: flex; flex: 1; min-height: 0; overflow: hidden; }
126
+
127
+ /* ─── Main content (editor + terminal vertical split) ──────────── */
128
+ #main-content { flex: 1; min-width: 0; display: flex; flex-direction: column; }
129
+
130
+ /* ─── Editor panel ─────────────────────────────────────────────── */
131
+ #editor-panel {
132
+ display: flex; flex-direction: column; flex: 0 0 auto; height: 60%;
133
+ min-height: 80px; overflow: hidden;
134
+ }
135
+ #editor-panel.hidden { display: none; }
136
+
137
+ #tab-bar {
138
+ display: flex; align-items: stretch; height: 32px; flex-shrink: 0;
139
+ background: var(--bg); border-bottom: 1px solid var(--border);
140
+ overflow-x: auto; overflow-y: hidden;
141
+ }
142
+ #tab-bar::-webkit-scrollbar { height: 0; }
143
+
144
+ .tab {
145
+ display: flex; align-items: center; gap: 6px;
146
+ padding: 0 12px; font-size: 11px; color: var(--text-dim);
147
+ background: var(--bg); border-right: 1px solid var(--border);
148
+ cursor: pointer; white-space: nowrap; user-select: none;
149
+ transition: background 0.1s, color 0.1s;
150
+ }
151
+ .tab:hover { background: var(--bg2); color: var(--text); }
152
+ .tab.active {
153
+ background: var(--bg2); color: var(--text);
154
+ box-shadow: inset 0 2px 0 var(--accent);
155
+ }
156
+ .tab .tab-close {
157
+ display: inline-flex; align-items: center; justify-content: center;
158
+ width: 16px; height: 16px; border-radius: 3px;
159
+ background: none; border: none; color: var(--text-dim);
160
+ font-size: 12px; cursor: pointer; line-height: 1;
161
+ opacity: 0; transition: opacity 0.1s, background 0.1s;
162
+ }
163
+ .tab:hover .tab-close, .tab.active .tab-close { opacity: 1; }
164
+ .tab .tab-close:hover { background: var(--bg3); color: var(--accent); }
165
+
166
+ #editor-container { flex: 1; overflow: hidden; }
167
+ #editor-container.hidden { display: none; }
168
+
169
+ #preview-container { flex: 1; overflow: hidden; display: flex; flex-direction: column; }
170
+ #preview-container.hidden { display: none; }
171
+
172
+ #preview-toolbar {
173
+ display: flex; align-items: center; gap: 4px;
174
+ padding: 4px 8px; background: var(--bg2);
175
+ border-bottom: 1px solid var(--border); flex-shrink: 0;
176
+ z-index: 2;
177
+ }
178
+ .preview-nav-btn {
179
+ background: none; border: none; color: var(--text-dim);
180
+ font-size: 16px; cursor: pointer; padding: 2px 6px;
181
+ border-radius: 4px; line-height: 1;
182
+ }
183
+ .preview-nav-btn:hover { background: var(--bg3); color: var(--text); }
184
+ #preview-url {
185
+ flex: 1; background: var(--bg); color: var(--text);
186
+ border: 1px solid var(--border); border-radius: 4px;
187
+ padding: 4px 8px; font-size: 12px; font-family: inherit; outline: none;
188
+ }
189
+ #preview-url:focus { border-color: var(--blue); }
190
+
191
+ #preview-viewport { flex: 1; position: relative; overflow: hidden; }
192
+ #preview-iframe { width: 100%; height: 100%; border: none; background: #fff; }
193
+ #preview-loading {
194
+ position: absolute; inset: 0; display: flex;
195
+ align-items: center; justify-content: center;
196
+ background: var(--bg); color: var(--text-dim); font-size: 12px;
197
+ z-index: 1;
198
+ }
199
+ #preview-loading.hidden { display: none; }
200
+
201
+ /* ─── Terminal panel ────────────────────────────────────────────── */
202
+ #terminal-panel { flex: 1; min-width: 0; min-height: 80px; display: flex;
203
+ flex-direction: column; background: var(--bg); padding: 8px; }
204
+ #terminal-container { flex: 1; min-height: 0; }
205
+ .xterm { height: 100%; }
206
+ .xterm-viewport { overflow-y: auto !important; }
207
+
208
+ /* ─── Always-on File Tree ───────────────────────────────────────── */
209
+ #filetree {
210
+ width: var(--filetree-w);
211
+ background: var(--bg2);
212
+ border-right: 1px solid var(--border);
213
+ display: flex;
214
+ flex-direction: column;
215
+ flex-shrink: 0;
216
+ overflow: hidden;
217
+ }
218
+
219
+ .filetree-header {
220
+ display: flex; align-items: center; justify-content: space-between;
221
+ padding: 8px 12px; border-bottom: 1px solid var(--border);
222
+ font-size: 10px; font-weight: 700; letter-spacing: 1px;
223
+ color: var(--text-dim); flex-shrink: 0;
224
+ }
225
+ .filetree-header button {
226
+ background: none; border: none; color: var(--text-dim); cursor: pointer;
227
+ font-size: 14px; padding: 0 4px; transition: color 0.15s;
228
+ }
229
+ .filetree-header button:hover { color: var(--text); }
230
+
231
+ #filetree-list { flex: 1; overflow-y: auto; padding: 4px 0; }
232
+
233
+ .ft-item {
234
+ display: flex; align-items: center; gap: 6px;
235
+ padding: 4px 12px; cursor: pointer; font-size: 12px;
236
+ color: var(--text-dim); white-space: nowrap; overflow: hidden;
237
+ text-overflow: ellipsis; transition: background 0.1s, color 0.1s;
238
+ user-select: none;
239
+ }
240
+ .ft-item:hover { background: var(--bg3); color: var(--text); }
241
+ .ft-item.is-dir { color: var(--blue); cursor: default; font-weight: 500; }
242
+ .ft-item.is-dir:hover { background: transparent; }
243
+ .ft-item .ft-icon { font-size: 13px; flex-shrink: 0; display: inline-flex; align-items: center; }
244
+ .ft-item .ft-icon svg { display: block; }
245
+ .ft-item .ft-name { overflow: hidden; text-overflow: ellipsis; }
246
+ .ft-item .ft-badge {
247
+ margin-left: auto; font-size: 9px; padding: 1px 5px;
248
+ border-radius: 3px; flex-shrink: 0;
249
+ }
250
+ .ft-badge-dl { background: #1a2e1a; color: var(--green); }
251
+
252
+ /* depth indent */
253
+ .ft-item[data-depth="1"] { padding-left: 24px; }
254
+ .ft-item[data-depth="2"] { padding-left: 36px; }
255
+ .ft-item[data-depth="3"] { padding-left: 48px; }
256
+
257
+ /* ─── Config / Agent Sidebar ────────────────────────────────────── */
258
+ #sidebar {
259
+ width: var(--sidebar-w); background: var(--bg2);
260
+ border-left: 1px solid var(--border);
261
+ overflow-y: auto; flex-shrink: 0;
262
+ transition: width 0.2s ease, opacity 0.2s ease;
263
+ }
264
+ #sidebar.sidebar-hidden { width: 0; opacity: 0; overflow: hidden; }
265
+
266
+ .panel { padding: 16px; border-bottom: 1px solid var(--border); }
267
+ .panel h3 { font-size: 12px; font-weight: 600; text-transform: uppercase;
268
+ letter-spacing: 0.8px; color: var(--text-dim); margin-bottom: 14px; }
269
+ .panel label { display: block; font-size: 11px; color: var(--text-dim);
270
+ margin-bottom: 4px; margin-top: 10px; }
271
+ .panel input, .panel select, .panel textarea {
272
+ width: 100%; background: var(--bg3); border: 1px solid var(--border);
273
+ color: var(--text); border-radius: 6px; padding: 7px 10px;
274
+ font-family: inherit; font-size: 12px; outline: none; transition: border-color 0.15s;
275
+ }
276
+ .panel input:focus, .panel select:focus, .panel textarea:focus { border-color: var(--blue); }
277
+ .panel select option { background: var(--bg3); }
278
+ #policy-yaml-editor { height: 260px; resize: vertical; font-size: 11px; line-height: 1.5; }
279
+
280
+ .panel-hint { font-size: 11px; color: var(--text-dim); margin-bottom: 10px; }
281
+
282
+ .btn-primary {
283
+ margin-top: 12px; width: 100%; padding: 8px;
284
+ background: var(--accent); color: #fff; border: none; border-radius: 6px;
285
+ font-family: inherit; font-size: 12px; font-weight: 600;
286
+ cursor: pointer; transition: opacity 0.15s;
287
+ }
288
+ .btn-primary:hover { opacity: 0.85; }
289
+ .btn-primary:active { opacity: 0.7; }
290
+ .btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }
291
+
292
+ .btn-secondary {
293
+ margin-top: 8px; width: 100%; padding: 8px;
294
+ background: transparent; color: var(--text-dim);
295
+ border: 1px solid var(--border); border-radius: 6px;
296
+ font-family: inherit; font-size: 12px; font-weight: 600;
297
+ cursor: pointer; transition: all 0.15s;
298
+ }
299
+ .btn-secondary:hover { border-color: var(--text-dim); color: var(--text); }
300
+
301
+ .env-section { margin-top: 12px; }
302
+ .env-section > label { margin-bottom: 8px; }
303
+ .env-row {
304
+ display: flex; gap: 4px; margin-bottom: 4px; align-items: center;
305
+ }
306
+ .env-row input.env-key {
307
+ width: 40%; flex-shrink: 0; font-size: 11px; font-family: var(--mono, monospace);
308
+ }
309
+ .env-row input.env-val {
310
+ flex: 1; font-size: 11px;
311
+ }
312
+ .env-row .btn-remove-env {
313
+ background: none; border: none; color: var(--text-dim); cursor: pointer;
314
+ font-size: 14px; padding: 0 4px; line-height: 1; flex-shrink: 0;
315
+ }
316
+ .env-row .btn-remove-env:hover { color: var(--accent); }
317
+
318
+ .message { margin-top: 8px; font-size: 11px; min-height: 16px; }
319
+ .message.success { color: var(--green); }
320
+ .message.error { color: var(--accent); }
321
+ .message.info { color: var(--blue); }
322
+
323
+ /* ─── Resize handles ───────────────────────────────────────────── */
324
+ .resize-handle {
325
+ flex-shrink: 0; background: var(--border); position: relative; z-index: 10;
326
+ transition: background 0.15s;
327
+ }
328
+ .resize-handle:hover, .resize-handle.active { background: var(--accent); }
329
+
330
+ .resize-h {
331
+ width: 4px; cursor: col-resize;
332
+ }
333
+ .resize-v {
334
+ height: 4px; cursor: row-resize;
335
+ }
336
+
337
+ body.resizing-col { cursor: col-resize !important; }
338
+ body.resizing-col * { cursor: col-resize !important; user-select: none !important; pointer-events: none !important; }
339
+ body.resizing-row { cursor: row-resize !important; }
340
+ body.resizing-row * { cursor: row-resize !important; user-select: none !important; pointer-events: none !important; }
341
+
342
+ #editor-panel.hidden ~ #resize-editor-terminal { display: none; }
343
+
344
+ /* ─── Audit Log Viewer ─────────────────────────────────────────── */
345
+ #audit-container { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
346
+ #audit-container.hidden { display: none; }
347
+
348
+ #policy-container { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
349
+ #policy-container.hidden { display: none; }
350
+ .policy-editor-wrap { display: flex; flex-direction: column; flex: 1; padding: 12px; overflow: hidden; }
351
+ .policy-editor-wrap .panel-hint { margin: 0 0 8px; }
352
+ .policy-editor-wrap textarea {
353
+ flex: 1; width: 100%; background: var(--bg3); border: 1px solid var(--border);
354
+ color: var(--text); border-radius: 6px; padding: 10px; resize: none;
355
+ font-family: var(--mono, monospace); font-size: 12px; line-height: 1.5; outline: none;
356
+ }
357
+ .policy-editor-wrap textarea:focus { border-color: var(--blue); }
358
+ .policy-actions { display: flex; gap: 8px; margin-top: 8px; }
359
+ .policy-actions .btn-primary, .policy-actions .btn-secondary { flex: 1; }
360
+
361
+ #audit-toolbar {
362
+ display: flex; gap: 6px; padding: 6px 10px; align-items: center;
363
+ background: var(--bg2); border-bottom: 1px solid var(--border);
364
+ flex-shrink: 0; flex-wrap: wrap;
365
+ }
366
+ #audit-toolbar input, #audit-toolbar select {
367
+ background: var(--bg); color: var(--text); border: 1px solid var(--border);
368
+ border-radius: 4px; padding: 3px 8px; font-size: 12px; font-family: inherit;
369
+ outline: none;
370
+ }
371
+ #audit-toolbar input:focus, #audit-toolbar select:focus { border-color: var(--blue); }
372
+ #audit-toolbar select option { background: var(--bg); }
373
+ #audit-search { flex: 1; min-width: 120px; }
374
+ #audit-toolbar input[type="datetime-local"] { max-width: 170px; }
375
+
376
+ #audit-log-list {
377
+ flex: 1; overflow-y: auto; padding: 4px 0; font-size: 12px;
378
+ }
379
+ .audit-row {
380
+ display: flex; gap: 8px; padding: 2px 10px; align-items: baseline;
381
+ white-space: nowrap;
382
+ }
383
+ .audit-row:hover { background: var(--bg2); }
384
+ .audit-ts { color: var(--text-dim); min-width: 90px; }
385
+ .audit-level { min-width: 40px; font-weight: 600; text-transform: uppercase; }
386
+ .audit-level-info { color: var(--text-dim); }
387
+ .audit-level-warn { color: var(--yellow); }
388
+ .audit-level-error { color: var(--accent); }
389
+ .audit-source { color: var(--blue); min-width: 55px; }
390
+ .audit-event { color: var(--text); min-width: 120px; }
391
+ .audit-detail { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; }
392
+ .audit-meta { color: var(--text-dim); opacity: 0.7; font-size: 11px; }
393
+
394
+ /* ─── Cloud Browser ────────────────────────────────────────────── */
395
+ #cloud-browser-container { flex: 1; overflow: hidden; display: flex; flex-direction: column; }
396
+ #cloud-browser-container.hidden { display: none; }
397
+
398
+ #cloud-browser-toolbar {
399
+ display: flex; align-items: center; gap: 4px;
400
+ padding: 4px 8px; background: var(--bg2);
401
+ border-bottom: 1px solid var(--border); flex-shrink: 0;
402
+ }
403
+ #cloud-browser-url {
404
+ flex: 1; background: var(--bg); color: var(--text);
405
+ border: 1px solid var(--border); border-radius: 4px;
406
+ padding: 4px 8px; font-size: 12px; font-family: inherit; outline: none;
407
+ }
408
+ #cloud-browser-url:focus { border-color: var(--blue); }
409
+ #cloud-browser-toolbar .btn-primary {
410
+ width: auto; margin-top: 0; padding: 4px 12px;
411
+ }
412
+ #cloud-browser-status {
413
+ font-size: 11px; color: var(--text-dim); margin-left: 4px; white-space: nowrap;
414
+ }
415
+
416
+ #cloud-browser-viewport { flex: 1; position: relative; overflow: hidden; }
417
+ #cloud-browser-iframe {
418
+ border: none; background: #fff;
419
+ /* Set to remote browser resolution; JS will scale via transform to fit viewport */
420
+ width: 1920px; height: 1080px;
421
+ transform-origin: 0 0;
422
+ }
423
+ #cloud-browser-loading {
424
+ position: absolute; inset: 0; display: flex;
425
+ align-items: center; justify-content: center;
426
+ background: var(--bg); color: var(--text-dim); font-size: 12px;
427
+ z-index: 1;
428
+ }
429
+ #cloud-browser-loading.hidden { display: none; }
430
+
431
+ /* ─── Util ──────────────────────────────────────────────────────── */
432
+ .hidden { display: none !important; }
@@ -0,0 +1,30 @@
1
+ // ─── Custom Tab Manager ─────────────────────────────────────────────────────
2
+
3
+ import type { TabDefinition } from './types.js';
4
+ import type { UIManager } from './ui.js';
5
+
6
+ export class TabManager {
7
+ private ui: UIManager;
8
+ private customTabs = new Map<string, { tabEl: HTMLElement; contentEl: HTMLDivElement }>();
9
+
10
+ constructor(ui: UIManager) {
11
+ this.ui = ui;
12
+ }
13
+
14
+ /** Add a custom tab to the UI. Delegates to UIManager's addCustomTab. */
15
+ addTab(def: TabDefinition): void {
16
+ this.ui.addCustomTab(def);
17
+ // Track the elements so we can remove them later
18
+ const contentEl = document.getElementById(`custom-tab-${def.id}`) as HTMLDivElement | null;
19
+ const tabEl = document.querySelector(`[data-custom-tab-id="${def.id}"]`) as HTMLElement | null;
20
+ if (contentEl && tabEl) {
21
+ this.customTabs.set(def.id, { tabEl, contentEl });
22
+ }
23
+ }
24
+
25
+ /** Remove a custom tab from the UI. */
26
+ removeTab(id: string): void {
27
+ this.ui.removeCustomTab(id);
28
+ this.customTabs.delete(id);
29
+ }
30
+ }