psyclaw 0.29.10 → 0.29.12
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 +4 -4
- package/dist/apps/panel/index.html +643 -273
- package/dist/src/adapters/pi/extension.js +40 -1
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/adapters/pi/rpc.js +1 -1
- package/dist/src/adapters/pi/rpc.js.map +1 -1
- package/dist/src/ars/mode-editor.d.ts +1 -5
- package/dist/src/ars/mode-editor.js +1 -9
- package/dist/src/ars/mode-editor.js.map +1 -1
- package/dist/src/branding.d.ts +4 -3
- package/dist/src/branding.js +8 -5
- package/dist/src/branding.js.map +1 -1
- package/dist/src/chat.d.ts +9 -0
- package/dist/src/chat.js +26 -3
- package/dist/src/chat.js.map +1 -1
- package/dist/src/cli-args.d.ts +1 -0
- package/dist/src/cli-args.js +1 -0
- package/dist/src/cli-args.js.map +1 -1
- package/dist/src/cli.js +12 -7
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/literature/knowledge-map.d.ts +4 -0
- package/dist/src/literature/knowledge-map.js +4 -0
- package/dist/src/literature/knowledge-map.js.map +1 -1
- package/dist/src/network-routing.js +6 -3
- package/dist/src/network-routing.js.map +1 -1
- package/dist/src/panel/server.js +1 -106
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/project/bootstrap.js +0 -2
- package/dist/src/project/bootstrap.js.map +1 -1
- package/dist/src/research/choice.d.ts +16 -0
- package/dist/src/research/choice.js +25 -0
- package/dist/src/research/choice.js.map +1 -0
- package/dist/src/session/continuously-work.d.ts +16 -0
- package/dist/src/session/continuously-work.js +44 -0
- package/dist/src/session/continuously-work.js.map +1 -0
- package/dist/src/session/help.js +39 -22
- package/dist/src/session/help.js.map +1 -1
- package/dist/src/style/cli-ui.js +1 -0
- package/dist/src/style/cli-ui.js.map +1 -1
- package/dist/src/verify/checklist.d.ts +2 -0
- package/dist/src/verify/checklist.js +36 -9
- package/dist/src/verify/checklist.js.map +1 -1
- package/dist/src/wake-options/runtime.d.ts +1 -0
- package/dist/src/wake-options/runtime.js +11 -1
- package/dist/src/wake-options/runtime.js.map +1 -1
- package/package.json +1 -1
- package/scripts/psyclaw.mjs +6 -2
|
@@ -160,20 +160,29 @@
|
|
|
160
160
|
display: grid;
|
|
161
161
|
grid-template-columns: 210px minmax(0, 1fr);
|
|
162
162
|
min-height: 0;
|
|
163
|
+
transition: grid-template-columns 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
164
|
+
}
|
|
165
|
+
.layout.nav-collapsed {
|
|
166
|
+
grid-template-columns: 58px minmax(0, 1fr);
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
.nav {
|
|
166
|
-
padding:
|
|
170
|
+
padding: 14px 8px;
|
|
167
171
|
background: var(--bg-sidebar);
|
|
168
172
|
border-right: 1px solid var(--border-subtle);
|
|
169
173
|
display: flex;
|
|
170
174
|
flex-direction: column;
|
|
171
175
|
justify-content: space-between;
|
|
176
|
+
overflow: hidden;
|
|
177
|
+
transition: padding 0.2s ease;
|
|
178
|
+
position: relative;
|
|
172
179
|
}
|
|
173
|
-
.nav-
|
|
180
|
+
.nav-header {
|
|
174
181
|
display: flex;
|
|
175
|
-
|
|
176
|
-
|
|
182
|
+
align-items: center;
|
|
183
|
+
justify-content: space-between;
|
|
184
|
+
padding: 4px 6px 8px;
|
|
185
|
+
margin-bottom: 4px;
|
|
177
186
|
}
|
|
178
187
|
.nav-label {
|
|
179
188
|
font-size: 10.5px;
|
|
@@ -181,26 +190,67 @@
|
|
|
181
190
|
color: var(--text-tertiary);
|
|
182
191
|
letter-spacing: 0.05em;
|
|
183
192
|
text-transform: uppercase;
|
|
184
|
-
|
|
185
|
-
|
|
193
|
+
white-space: nowrap;
|
|
194
|
+
overflow: hidden;
|
|
195
|
+
text-overflow: ellipsis;
|
|
196
|
+
transition: opacity 0.15s ease;
|
|
197
|
+
}
|
|
198
|
+
.nav-toggle-btn {
|
|
199
|
+
width: 26px;
|
|
200
|
+
height: 26px;
|
|
201
|
+
display: grid;
|
|
202
|
+
place-items: center;
|
|
203
|
+
border-radius: var(--radius-sm);
|
|
204
|
+
color: var(--text-muted);
|
|
205
|
+
background: transparent;
|
|
206
|
+
cursor: pointer;
|
|
207
|
+
transition: all 0.15s ease;
|
|
208
|
+
flex-shrink: 0;
|
|
209
|
+
}
|
|
210
|
+
.nav-toggle-btn:hover {
|
|
211
|
+
background: var(--bg-surface-subtle);
|
|
212
|
+
color: var(--text-main);
|
|
213
|
+
}
|
|
214
|
+
.layout.nav-collapsed .nav-header {
|
|
215
|
+
justify-content: center;
|
|
216
|
+
padding: 2px 0 10px;
|
|
217
|
+
}
|
|
218
|
+
.layout.nav-collapsed .nav-label {
|
|
219
|
+
display: none;
|
|
220
|
+
}
|
|
221
|
+
.layout.nav-collapsed .nav-toggle-btn svg {
|
|
222
|
+
transform: rotate(180deg);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.nav-group {
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: column;
|
|
228
|
+
gap: 4px;
|
|
186
229
|
}
|
|
187
230
|
.nav button {
|
|
188
231
|
width: 100%;
|
|
189
232
|
display: flex;
|
|
190
233
|
align-items: center;
|
|
191
|
-
gap:
|
|
192
|
-
padding:
|
|
234
|
+
gap: 10px;
|
|
235
|
+
padding: 9px 10px;
|
|
193
236
|
border-radius: var(--radius-sm);
|
|
194
237
|
color: var(--text-secondary);
|
|
195
238
|
font-weight: 500;
|
|
196
239
|
font-size: 12.5px;
|
|
197
240
|
text-align: left;
|
|
198
|
-
transition:
|
|
241
|
+
transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
|
|
199
242
|
position: relative;
|
|
243
|
+
white-space: nowrap;
|
|
244
|
+
}
|
|
245
|
+
.nav button .nav-btn-text {
|
|
246
|
+
flex: 1;
|
|
247
|
+
overflow: hidden;
|
|
248
|
+
text-overflow: ellipsis;
|
|
249
|
+
transition: opacity 0.15s ease;
|
|
200
250
|
}
|
|
201
251
|
.nav button svg {
|
|
202
|
-
width:
|
|
203
|
-
height:
|
|
252
|
+
width: 17px;
|
|
253
|
+
height: 17px;
|
|
204
254
|
color: var(--text-muted);
|
|
205
255
|
flex-shrink: 0;
|
|
206
256
|
transition: color 0.15s ease;
|
|
@@ -222,12 +272,29 @@
|
|
|
222
272
|
.nav button.active svg {
|
|
223
273
|
color: var(--brand-primary);
|
|
224
274
|
}
|
|
275
|
+
|
|
276
|
+
/* Collapsed Nav Styles */
|
|
277
|
+
.layout.nav-collapsed .nav {
|
|
278
|
+
padding: 12px 6px;
|
|
279
|
+
}
|
|
280
|
+
.layout.nav-collapsed .nav button {
|
|
281
|
+
justify-content: center;
|
|
282
|
+
padding: 9px 0;
|
|
283
|
+
}
|
|
284
|
+
.layout.nav-collapsed .nav button .nav-btn-text {
|
|
285
|
+
display: none;
|
|
286
|
+
}
|
|
287
|
+
.layout.nav-collapsed .nav-footer {
|
|
288
|
+
display: none;
|
|
289
|
+
}
|
|
290
|
+
|
|
225
291
|
.nav-footer {
|
|
226
292
|
padding: 12px 10px;
|
|
227
293
|
border-top: 1px solid var(--border-subtle);
|
|
228
294
|
font-size: 11px;
|
|
229
295
|
color: var(--text-muted);
|
|
230
296
|
line-height: 1.4;
|
|
297
|
+
transition: opacity 0.15s ease;
|
|
231
298
|
}
|
|
232
299
|
.nav-footer code {
|
|
233
300
|
font-family: var(--font-mono);
|
|
@@ -939,89 +1006,47 @@
|
|
|
939
1006
|
background: var(--brand-primary-hover);
|
|
940
1007
|
}
|
|
941
1008
|
|
|
942
|
-
/*
|
|
943
|
-
.console-fab {
|
|
944
|
-
position: fixed;
|
|
945
|
-
bottom: 24px;
|
|
946
|
-
right: 28px;
|
|
947
|
-
z-index: 100;
|
|
948
|
-
display: flex;
|
|
949
|
-
align-items: center;
|
|
950
|
-
gap: 8px;
|
|
951
|
-
padding: 10px 18px;
|
|
952
|
-
background: var(--bg-surface);
|
|
953
|
-
color: var(--brand-primary);
|
|
954
|
-
border: 1px solid var(--brand-primary-border);
|
|
955
|
-
border-radius: var(--radius-lg);
|
|
956
|
-
font-size: 13px;
|
|
957
|
-
font-weight: 600;
|
|
958
|
-
cursor: pointer;
|
|
959
|
-
box-shadow: var(--shadow-md);
|
|
960
|
-
transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
|
|
961
|
-
}
|
|
962
|
-
.console-fab:hover {
|
|
963
|
-
background: var(--brand-primary-light);
|
|
964
|
-
border-color: var(--brand-primary);
|
|
965
|
-
transform: translateY(-1px);
|
|
966
|
-
}
|
|
1009
|
+
/* In-page chat: Modern Codex / Gemini style */
|
|
967
1010
|
.console-drawer {
|
|
968
|
-
position:
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
height: 560px;
|
|
974
|
-
max-height: calc(100vh - 80px);
|
|
1011
|
+
position: relative;
|
|
1012
|
+
width: 100%;
|
|
1013
|
+
height: 100%;
|
|
1014
|
+
min-height: 72vh;
|
|
1015
|
+
flex: 1;
|
|
975
1016
|
background: var(--bg-surface);
|
|
976
1017
|
color: var(--text-main);
|
|
977
|
-
border:
|
|
978
|
-
border-bottom: 0;
|
|
979
|
-
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
|
980
|
-
box-shadow: var(--shadow-md);
|
|
1018
|
+
border: none;
|
|
981
1019
|
display: flex;
|
|
982
1020
|
flex-direction: column;
|
|
983
|
-
z-index: 1000;
|
|
984
|
-
transform: translateY(105%);
|
|
985
|
-
transition: transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
|
|
986
1021
|
font-family: var(--font-sans);
|
|
987
1022
|
}
|
|
988
|
-
.console-drawer.open {
|
|
989
|
-
transform: translateY(0);
|
|
990
|
-
}
|
|
991
|
-
.console-drawer.embedded {
|
|
992
|
-
border: none;
|
|
993
|
-
border-radius: 0;
|
|
994
|
-
box-shadow: none;
|
|
995
|
-
transform: none;
|
|
996
|
-
}
|
|
997
1023
|
.console-header {
|
|
998
1024
|
display: flex;
|
|
999
1025
|
align-items: center;
|
|
1000
1026
|
justify-content: space-between;
|
|
1001
|
-
padding: 12px
|
|
1027
|
+
padding: 12px 20px;
|
|
1002
1028
|
border-bottom: 1px solid var(--border-subtle);
|
|
1003
1029
|
background: var(--bg-surface);
|
|
1004
|
-
border-radius: var(--radius-lg) var(--radius-lg) 0 0;
|
|
1005
|
-
}
|
|
1006
|
-
.console-drawer.embedded .console-header {
|
|
1007
|
-
border-radius: 0;
|
|
1008
1030
|
}
|
|
1009
1031
|
.console-title {
|
|
1010
|
-
font-size:
|
|
1032
|
+
font-size: 13.5px;
|
|
1011
1033
|
font-weight: 650;
|
|
1012
1034
|
color: var(--text-main);
|
|
1013
1035
|
display: flex;
|
|
1014
1036
|
align-items: center;
|
|
1015
|
-
gap:
|
|
1037
|
+
gap: 9px;
|
|
1016
1038
|
}
|
|
1017
1039
|
.console-status-tag {
|
|
1018
|
-
font-size:
|
|
1040
|
+
font-size: 10.5px;
|
|
1019
1041
|
font-weight: 600;
|
|
1020
|
-
padding: 1px
|
|
1021
|
-
border-radius:
|
|
1042
|
+
padding: 1px 7px;
|
|
1043
|
+
border-radius: 999px;
|
|
1022
1044
|
background: var(--ok-bg);
|
|
1023
1045
|
color: var(--ok-text);
|
|
1024
1046
|
border: 1px solid var(--ok-border);
|
|
1047
|
+
display: inline-flex;
|
|
1048
|
+
align-items: center;
|
|
1049
|
+
gap: 4px;
|
|
1025
1050
|
}
|
|
1026
1051
|
.console-actions {
|
|
1027
1052
|
display: flex;
|
|
@@ -1033,140 +1058,372 @@
|
|
|
1033
1058
|
border: none;
|
|
1034
1059
|
color: var(--text-muted);
|
|
1035
1060
|
cursor: pointer;
|
|
1036
|
-
padding:
|
|
1061
|
+
padding: 5px;
|
|
1037
1062
|
border-radius: var(--radius-sm);
|
|
1038
1063
|
display: flex;
|
|
1064
|
+
align-items: center;
|
|
1065
|
+
justify-content: center;
|
|
1066
|
+
transition: all 0.15s ease;
|
|
1039
1067
|
}
|
|
1040
1068
|
.console-btn-icon:hover {
|
|
1041
1069
|
color: var(--text-main);
|
|
1042
1070
|
background: var(--bg-surface-subtle);
|
|
1043
1071
|
}
|
|
1044
|
-
|
|
1045
|
-
display: flex;
|
|
1046
|
-
align-items: center;
|
|
1047
|
-
gap: 6px;
|
|
1048
|
-
padding: 8px 14px;
|
|
1049
|
-
background: var(--bg-surface-subtle);
|
|
1050
|
-
border-bottom: 1px solid var(--border-subtle);
|
|
1051
|
-
overflow-x: auto;
|
|
1052
|
-
}
|
|
1053
|
-
.chip {
|
|
1054
|
-
font-family: var(--font-mono);
|
|
1055
|
-
font-size: 11px;
|
|
1056
|
-
background: var(--bg-surface);
|
|
1057
|
-
color: var(--text-secondary);
|
|
1058
|
-
border: 1px solid var(--border-default);
|
|
1059
|
-
padding: 3px 8px;
|
|
1060
|
-
border-radius: var(--radius-sm);
|
|
1061
|
-
cursor: pointer;
|
|
1062
|
-
white-space: nowrap;
|
|
1063
|
-
transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
|
|
1064
|
-
}
|
|
1065
|
-
.chip:hover {
|
|
1066
|
-
background: var(--brand-primary-light);
|
|
1067
|
-
border-color: var(--brand-primary-border);
|
|
1068
|
-
color: var(--brand-primary);
|
|
1069
|
-
}
|
|
1072
|
+
|
|
1070
1073
|
.console-log {
|
|
1071
1074
|
flex: 1;
|
|
1072
1075
|
overflow-y: auto;
|
|
1073
|
-
padding:
|
|
1076
|
+
padding: 24px 20px;
|
|
1074
1077
|
font-family: var(--font-sans);
|
|
1075
|
-
font-size:
|
|
1076
|
-
line-height: 1.
|
|
1078
|
+
font-size: 13.5px;
|
|
1079
|
+
line-height: 1.6;
|
|
1077
1080
|
display: flex;
|
|
1078
1081
|
flex-direction: column;
|
|
1079
|
-
gap:
|
|
1082
|
+
gap: 18px;
|
|
1080
1083
|
background: var(--bg-app);
|
|
1084
|
+
scroll-behavior: smooth;
|
|
1081
1085
|
}
|
|
1086
|
+
|
|
1087
|
+
/* Message Rows */
|
|
1082
1088
|
.log-entry {
|
|
1083
1089
|
display: flex;
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1090
|
+
width: 100%;
|
|
1091
|
+
max-width: 860px;
|
|
1092
|
+
margin: 0 auto;
|
|
1093
|
+
gap: 12px;
|
|
1094
|
+
animation: fadeIn 0.18s ease;
|
|
1087
1095
|
}
|
|
1088
1096
|
.log-entry.user {
|
|
1089
|
-
|
|
1090
|
-
align-items: flex-end;
|
|
1097
|
+
justify-content: flex-end;
|
|
1091
1098
|
}
|
|
1092
1099
|
.log-entry.agent,
|
|
1093
1100
|
.log-entry.sys {
|
|
1094
|
-
|
|
1095
|
-
|
|
1101
|
+
justify-content: flex-start;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/* User Message Bubble */
|
|
1105
|
+
.log-user-wrap {
|
|
1106
|
+
max-width: 82%;
|
|
1107
|
+
display: flex;
|
|
1108
|
+
flex-direction: column;
|
|
1109
|
+
align-items: flex-end;
|
|
1110
|
+
gap: 4px;
|
|
1096
1111
|
}
|
|
1097
1112
|
.log-user {
|
|
1098
|
-
color: #
|
|
1099
|
-
font-weight:
|
|
1100
|
-
background:
|
|
1101
|
-
padding: 10px
|
|
1102
|
-
border-radius:
|
|
1113
|
+
color: #ffffff;
|
|
1114
|
+
font-weight: 450;
|
|
1115
|
+
background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
|
|
1116
|
+
padding: 10px 15px;
|
|
1117
|
+
border-radius: 16px 16px 4px 16px;
|
|
1103
1118
|
white-space: pre-wrap;
|
|
1104
1119
|
word-break: break-word;
|
|
1105
|
-
box-shadow: var(--shadow-
|
|
1120
|
+
box-shadow: var(--shadow-sm);
|
|
1121
|
+
line-height: 1.55;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
/* Agent Message: Codex/Gemini open conversational layout */
|
|
1125
|
+
.agent-avatar {
|
|
1126
|
+
width: 32px;
|
|
1127
|
+
height: 32px;
|
|
1128
|
+
border-radius: 50%;
|
|
1129
|
+
background: linear-gradient(135deg, #0d766e 0%, #0284c7 100%);
|
|
1130
|
+
color: #ffffff;
|
|
1131
|
+
display: grid;
|
|
1132
|
+
place-items: center;
|
|
1133
|
+
font-weight: 700;
|
|
1134
|
+
font-size: 15px;
|
|
1135
|
+
flex-shrink: 0;
|
|
1136
|
+
box-shadow: 0 2px 4px rgba(13, 118, 110, 0.2);
|
|
1137
|
+
}
|
|
1138
|
+
.agent-content-wrap {
|
|
1139
|
+
flex: 1;
|
|
1140
|
+
min-width: 0;
|
|
1141
|
+
display: flex;
|
|
1142
|
+
flex-direction: column;
|
|
1143
|
+
gap: 5px;
|
|
1144
|
+
}
|
|
1145
|
+
.agent-meta {
|
|
1146
|
+
display: flex;
|
|
1147
|
+
align-items: center;
|
|
1148
|
+
gap: 8px;
|
|
1149
|
+
font-size: 12px;
|
|
1150
|
+
font-weight: 600;
|
|
1151
|
+
color: var(--text-secondary);
|
|
1152
|
+
}
|
|
1153
|
+
.agent-role-pill {
|
|
1154
|
+
font-size: 10px;
|
|
1155
|
+
font-weight: 550;
|
|
1156
|
+
background: var(--brand-primary-light);
|
|
1157
|
+
color: var(--brand-primary);
|
|
1158
|
+
border: 1px solid var(--brand-primary-border);
|
|
1159
|
+
padding: 0 5px;
|
|
1160
|
+
border-radius: 4px;
|
|
1106
1161
|
}
|
|
1107
1162
|
.log-agent {
|
|
1108
1163
|
color: var(--text-main);
|
|
1109
1164
|
background: var(--bg-surface);
|
|
1110
|
-
padding:
|
|
1111
|
-
border-radius:
|
|
1165
|
+
padding: 14px 18px;
|
|
1166
|
+
border-radius: 4px 16px 16px 16px;
|
|
1112
1167
|
border: 1px solid var(--border-subtle);
|
|
1113
|
-
white-space: pre-wrap;
|
|
1114
1168
|
word-break: break-word;
|
|
1115
|
-
box-shadow: var(--shadow-
|
|
1169
|
+
box-shadow: var(--shadow-card);
|
|
1170
|
+
line-height: 1.65;
|
|
1171
|
+
}
|
|
1172
|
+
.log-agent > :first-child { margin-top: 0; }
|
|
1173
|
+
.log-agent > :last-child { margin-bottom: 0; }
|
|
1174
|
+
.log-agent p { margin: 8px 0; }
|
|
1175
|
+
.log-agent h1, .log-agent h2, .log-agent h3 {
|
|
1176
|
+
margin: 14px 0 6px;
|
|
1177
|
+
color: var(--text-main);
|
|
1178
|
+
font-weight: 650;
|
|
1179
|
+
}
|
|
1180
|
+
.log-agent h1 { font-size: 16px; }
|
|
1181
|
+
.log-agent h2 { font-size: 14.5px; }
|
|
1182
|
+
.log-agent h3 { font-size: 13.5px; }
|
|
1183
|
+
.log-agent ul, .log-agent ol {
|
|
1184
|
+
margin: 6px 0 6px 20px;
|
|
1185
|
+
padding: 0;
|
|
1186
|
+
}
|
|
1187
|
+
.log-agent li { margin: 3px 0; }
|
|
1188
|
+
.log-agent blockquote {
|
|
1189
|
+
border-left: 3px solid var(--brand-primary);
|
|
1190
|
+
background: var(--brand-primary-light);
|
|
1191
|
+
padding: 6px 12px;
|
|
1192
|
+
margin: 8px 0;
|
|
1193
|
+
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
|
1194
|
+
color: var(--text-secondary);
|
|
1195
|
+
}
|
|
1196
|
+
.log-agent table {
|
|
1197
|
+
width: 100%;
|
|
1198
|
+
border-collapse: collapse;
|
|
1199
|
+
margin: 10px 0;
|
|
1200
|
+
font-size: 12.5px;
|
|
1201
|
+
}
|
|
1202
|
+
.log-agent th, .log-agent td {
|
|
1203
|
+
padding: 6px 10px;
|
|
1204
|
+
border: 1px solid var(--border-subtle);
|
|
1205
|
+
text-align: left;
|
|
1206
|
+
}
|
|
1207
|
+
.log-agent th {
|
|
1208
|
+
background: var(--bg-surface-subtle);
|
|
1209
|
+
font-weight: 600;
|
|
1116
1210
|
}
|
|
1211
|
+
|
|
1212
|
+
/* Code Blocks with Copy Header */
|
|
1213
|
+
.code-container {
|
|
1214
|
+
position: relative;
|
|
1215
|
+
margin: 10px 0;
|
|
1216
|
+
border-radius: var(--radius-md);
|
|
1217
|
+
overflow: hidden;
|
|
1218
|
+
background: #0f172a;
|
|
1219
|
+
border: 1px solid #1e293b;
|
|
1220
|
+
}
|
|
1221
|
+
.code-header {
|
|
1222
|
+
display: flex;
|
|
1223
|
+
align-items: center;
|
|
1224
|
+
justify-content: space-between;
|
|
1225
|
+
padding: 5px 12px;
|
|
1226
|
+
background: #1e293b;
|
|
1227
|
+
color: #94a3b8;
|
|
1228
|
+
font-size: 11px;
|
|
1229
|
+
font-family: var(--font-mono);
|
|
1230
|
+
user-select: none;
|
|
1231
|
+
}
|
|
1232
|
+
.code-copy-btn {
|
|
1233
|
+
display: inline-flex;
|
|
1234
|
+
align-items: center;
|
|
1235
|
+
gap: 4px;
|
|
1236
|
+
font-size: 11px;
|
|
1237
|
+
color: #cbd5e1;
|
|
1238
|
+
background: transparent;
|
|
1239
|
+
border: none;
|
|
1240
|
+
padding: 2px 6px;
|
|
1241
|
+
border-radius: 4px;
|
|
1242
|
+
cursor: pointer;
|
|
1243
|
+
transition: background 0.12s ease, color 0.12s ease;
|
|
1244
|
+
}
|
|
1245
|
+
.code-copy-btn:hover {
|
|
1246
|
+
background: #334155;
|
|
1247
|
+
color: #ffffff;
|
|
1248
|
+
}
|
|
1249
|
+
.log-agent pre {
|
|
1250
|
+
margin: 0;
|
|
1251
|
+
padding: 12px 14px;
|
|
1252
|
+
overflow-x: auto;
|
|
1253
|
+
font-family: var(--font-mono);
|
|
1254
|
+
font-size: 12px;
|
|
1255
|
+
line-height: 1.5;
|
|
1256
|
+
color: #f1f5f9;
|
|
1257
|
+
background: transparent;
|
|
1258
|
+
}
|
|
1259
|
+
.log-agent code {
|
|
1260
|
+
font-family: var(--font-mono);
|
|
1261
|
+
font-size: 12px;
|
|
1262
|
+
}
|
|
1263
|
+
.log-agent p code, .log-agent li code {
|
|
1264
|
+
background: var(--bg-surface-subtle);
|
|
1265
|
+
color: #0f766e;
|
|
1266
|
+
border: 1px solid var(--border-subtle);
|
|
1267
|
+
padding: 1px 5px;
|
|
1268
|
+
border-radius: 4px;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/* Shimmering Pulsing Dots for Streaming */
|
|
1272
|
+
.agent-typing-indicator {
|
|
1273
|
+
display: inline-flex;
|
|
1274
|
+
align-items: center;
|
|
1275
|
+
gap: 5px;
|
|
1276
|
+
padding: 6px 12px;
|
|
1277
|
+
background: var(--bg-surface);
|
|
1278
|
+
border: 1px solid var(--border-subtle);
|
|
1279
|
+
border-radius: 12px;
|
|
1280
|
+
margin-top: 4px;
|
|
1281
|
+
width: fit-content;
|
|
1282
|
+
}
|
|
1283
|
+
.typing-dot {
|
|
1284
|
+
width: 6px;
|
|
1285
|
+
height: 6px;
|
|
1286
|
+
border-radius: 50%;
|
|
1287
|
+
background: var(--brand-primary);
|
|
1288
|
+
animation: pulseDot 1.4s infinite ease-in-out both;
|
|
1289
|
+
}
|
|
1290
|
+
.typing-dot:nth-child(1) { animation-delay: -0.32s; }
|
|
1291
|
+
.typing-dot:nth-child(2) { animation-delay: -0.16s; }
|
|
1292
|
+
.typing-dot:nth-child(3) { animation-delay: 0s; }
|
|
1293
|
+
@keyframes pulseDot {
|
|
1294
|
+
0%, 80%, 100% { transform: scale(0.6); opacity: 0.35; }
|
|
1295
|
+
40% { transform: scale(1.1); opacity: 1; }
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/* System & Info Messages */
|
|
1117
1299
|
.log-sys {
|
|
1118
1300
|
color: var(--text-muted);
|
|
1119
|
-
font-style: normal;
|
|
1120
1301
|
font-size: 12px;
|
|
1121
|
-
background:
|
|
1122
|
-
|
|
1302
|
+
background: var(--bg-surface-subtle);
|
|
1303
|
+
border: 1px dashed var(--border-default);
|
|
1304
|
+
padding: 8px 12px;
|
|
1305
|
+
border-radius: var(--radius-sm);
|
|
1306
|
+
text-align: center;
|
|
1307
|
+
width: 100%;
|
|
1123
1308
|
}
|
|
1124
|
-
.
|
|
1125
|
-
|
|
1309
|
+
.wake-checklist-card {
|
|
1310
|
+
background: var(--bg-surface);
|
|
1311
|
+
border: 1px solid var(--brand-primary-border);
|
|
1312
|
+
border-left: 3px solid var(--brand-primary);
|
|
1313
|
+
border-radius: var(--radius-sm);
|
|
1314
|
+
padding: 10px 14px;
|
|
1315
|
+
text-align: left;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/* Quick Action Chips */
|
|
1319
|
+
.console-quick-chips {
|
|
1320
|
+
display: flex;
|
|
1321
|
+
align-items: center;
|
|
1322
|
+
gap: 6px;
|
|
1323
|
+
padding: 8px 16px;
|
|
1324
|
+
background: var(--bg-surface);
|
|
1325
|
+
border-top: 1px solid var(--border-subtle);
|
|
1326
|
+
overflow-x: auto;
|
|
1327
|
+
max-width: 860px;
|
|
1328
|
+
margin: 0 auto;
|
|
1329
|
+
width: 100%;
|
|
1330
|
+
}
|
|
1331
|
+
.chip {
|
|
1332
|
+
font-family: var(--font-mono);
|
|
1333
|
+
font-size: 11px;
|
|
1334
|
+
background: var(--bg-surface-subtle);
|
|
1335
|
+
color: var(--text-secondary);
|
|
1336
|
+
border: 1px solid var(--border-subtle);
|
|
1337
|
+
padding: 3px 9px;
|
|
1338
|
+
border-radius: 999px;
|
|
1339
|
+
cursor: pointer;
|
|
1340
|
+
white-space: nowrap;
|
|
1341
|
+
transition: all 0.15s ease;
|
|
1342
|
+
display: inline-flex;
|
|
1343
|
+
align-items: center;
|
|
1344
|
+
gap: 4px;
|
|
1345
|
+
}
|
|
1346
|
+
.chip:hover {
|
|
1347
|
+
background: var(--brand-primary-light);
|
|
1348
|
+
border-color: var(--brand-primary-border);
|
|
1349
|
+
color: var(--brand-primary);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/* Modern Textarea Input Box (Gemini / Codex Style) */
|
|
1353
|
+
.console-input-wrap {
|
|
1126
1354
|
background: var(--bg-surface);
|
|
1127
1355
|
border-top: 1px solid var(--border-subtle);
|
|
1356
|
+
padding: 12px 16px 14px;
|
|
1357
|
+
}
|
|
1358
|
+
.console-input-container {
|
|
1359
|
+
max-width: 860px;
|
|
1360
|
+
margin: 0 auto;
|
|
1128
1361
|
display: flex;
|
|
1362
|
+
flex-direction: column;
|
|
1363
|
+
gap: 6px;
|
|
1364
|
+
}
|
|
1365
|
+
.console-input-box {
|
|
1366
|
+
background: var(--bg-surface-subtle);
|
|
1367
|
+
border: 1.5px solid var(--border-default);
|
|
1368
|
+
border-radius: var(--radius-lg);
|
|
1369
|
+
padding: 8px 12px;
|
|
1370
|
+
display: flex;
|
|
1371
|
+
align-items: flex-end;
|
|
1129
1372
|
gap: 8px;
|
|
1373
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
|
|
1130
1374
|
}
|
|
1131
|
-
.console-input {
|
|
1375
|
+
.console-input-box:focus-within {
|
|
1376
|
+
background: var(--bg-surface);
|
|
1377
|
+
border-color: var(--brand-primary);
|
|
1378
|
+
box-shadow: 0 0 0 3px var(--brand-primary-border);
|
|
1379
|
+
}
|
|
1380
|
+
.console-textarea {
|
|
1132
1381
|
flex: 1;
|
|
1133
|
-
background:
|
|
1134
|
-
border:
|
|
1135
|
-
color: var(--text-main);
|
|
1136
|
-
padding: 10px 12px;
|
|
1137
|
-
font-size: 13px;
|
|
1138
|
-
border-radius: var(--radius-md);
|
|
1382
|
+
background: transparent;
|
|
1383
|
+
border: none;
|
|
1139
1384
|
outline: none;
|
|
1385
|
+
resize: none;
|
|
1140
1386
|
font-family: var(--font-sans);
|
|
1387
|
+
font-size: 13.5px;
|
|
1388
|
+
line-height: 1.5;
|
|
1389
|
+
color: var(--text-main);
|
|
1390
|
+
min-height: 24px;
|
|
1391
|
+
max-height: 160px;
|
|
1392
|
+
padding: 4px 0;
|
|
1141
1393
|
}
|
|
1142
|
-
.console-
|
|
1143
|
-
|
|
1144
|
-
background: var(--bg-surface);
|
|
1145
|
-
box-shadow: 0 0 0 3px var(--brand-primary-border);
|
|
1394
|
+
.console-textarea::placeholder {
|
|
1395
|
+
color: var(--text-muted);
|
|
1146
1396
|
}
|
|
1147
1397
|
.console-send-btn {
|
|
1148
1398
|
background: var(--brand-primary);
|
|
1149
|
-
color: #
|
|
1399
|
+
color: #ffffff;
|
|
1150
1400
|
border: none;
|
|
1151
|
-
|
|
1401
|
+
width: 32px;
|
|
1402
|
+
height: 32px;
|
|
1152
1403
|
border-radius: var(--radius-md);
|
|
1153
|
-
font-size: 13px;
|
|
1154
|
-
font-weight: 600;
|
|
1155
1404
|
cursor: pointer;
|
|
1156
|
-
display:
|
|
1157
|
-
|
|
1158
|
-
|
|
1405
|
+
display: grid;
|
|
1406
|
+
place-items: center;
|
|
1407
|
+
flex-shrink: 0;
|
|
1408
|
+
transition: background 0.15s ease, transform 0.1s ease;
|
|
1409
|
+
margin-bottom: 2px;
|
|
1159
1410
|
}
|
|
1160
|
-
.console-send-btn:hover {
|
|
1411
|
+
.console-send-btn:hover:not(:disabled) {
|
|
1161
1412
|
background: var(--brand-primary-hover);
|
|
1413
|
+
transform: translateY(-1px);
|
|
1162
1414
|
}
|
|
1163
|
-
.
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1415
|
+
.console-send-btn:disabled {
|
|
1416
|
+
opacity: 0.45;
|
|
1417
|
+
cursor: not-allowed;
|
|
1418
|
+
}
|
|
1419
|
+
.console-input-footer {
|
|
1420
|
+
display: flex;
|
|
1421
|
+
align-items: center;
|
|
1422
|
+
justify-content: space-between;
|
|
1423
|
+
padding: 0 4px;
|
|
1424
|
+
font-size: 11px;
|
|
1425
|
+
color: var(--text-muted);
|
|
1168
1426
|
}
|
|
1169
|
-
@keyframes blink { 50% { opacity: 0; } }
|
|
1170
1427
|
.wake-option-list {
|
|
1171
1428
|
display: grid;
|
|
1172
1429
|
gap: 8px;
|
|
@@ -1280,7 +1537,6 @@
|
|
|
1280
1537
|
.viewer { min-height: 480px; }
|
|
1281
1538
|
.provider-grid, .cost-metrics { grid-template-columns: 1fr; }
|
|
1282
1539
|
.topbar { padding: 0 14px; }
|
|
1283
|
-
.console-drawer { width: 100vw; right: 0; }
|
|
1284
1540
|
}
|
|
1285
1541
|
</style>
|
|
1286
1542
|
</head>
|
|
@@ -1320,32 +1576,37 @@
|
|
|
1320
1576
|
<!-- 主体工作区 Layout -->
|
|
1321
1577
|
<div class="layout">
|
|
1322
1578
|
<!-- 侧边导航栏 Sidebar -->
|
|
1323
|
-
<nav class="nav" aria-label="Panel 导航">
|
|
1579
|
+
<nav class="nav" id="workbench-nav" aria-label="Panel 导航">
|
|
1324
1580
|
<div class="nav-group">
|
|
1325
|
-
<div class="nav-
|
|
1326
|
-
|
|
1581
|
+
<div class="nav-header">
|
|
1582
|
+
<div class="nav-label">工作台导航</div>
|
|
1583
|
+
<button id="nav-toggle-btn" class="nav-toggle-btn" title="折叠/展开导航栏" aria-label="折叠导航栏">
|
|
1584
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"/></svg>
|
|
1585
|
+
</button>
|
|
1586
|
+
</div>
|
|
1587
|
+
<button class="active" data-view="project" title="项目文件">
|
|
1327
1588
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/><polyline points="14 2 14 8 20 8"/></svg>
|
|
1328
|
-
|
|
1589
|
+
<span class="nav-btn-text">项目文件</span>
|
|
1329
1590
|
</button>
|
|
1330
|
-
<button data-view="ecosystem">
|
|
1591
|
+
<button data-view="ecosystem" title="能力生态">
|
|
1331
1592
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>
|
|
1332
|
-
|
|
1593
|
+
<span class="nav-btn-text">能力生态</span>
|
|
1333
1594
|
</button>
|
|
1334
|
-
<button data-view="provider">
|
|
1595
|
+
<button data-view="provider" title="模型与成本">
|
|
1335
1596
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
|
1336
|
-
|
|
1597
|
+
<span class="nav-btn-text">模型与成本</span>
|
|
1337
1598
|
</button>
|
|
1338
|
-
<button data-view="help">
|
|
1599
|
+
<button data-view="help" title="使用速览">
|
|
1339
1600
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
|
|
1340
|
-
|
|
1601
|
+
<span class="nav-btn-text">使用速览</span>
|
|
1341
1602
|
</button>
|
|
1342
|
-
<button data-view="checklist">
|
|
1603
|
+
<button data-view="checklist" title="核对清单">
|
|
1343
1604
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
|
|
1344
|
-
|
|
1605
|
+
<span class="nav-btn-text">核对清单</span>
|
|
1345
1606
|
</button>
|
|
1346
|
-
<button data-view="chat">
|
|
1607
|
+
<button data-view="chat" title="对话">
|
|
1347
1608
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>
|
|
1348
|
-
|
|
1609
|
+
<span class="nav-btn-text">对话</span>
|
|
1349
1610
|
</button>
|
|
1350
1611
|
</div>
|
|
1351
1612
|
<div class="nav-footer">
|
|
@@ -1560,7 +1821,7 @@
|
|
|
1560
1821
|
<ol id="help-steps" class="help-steps"></ol>
|
|
1561
1822
|
</div>
|
|
1562
1823
|
<div class="help-block">
|
|
1563
|
-
<h2
|
|
1824
|
+
<h2>可用命令</h2>
|
|
1564
1825
|
<div id="help-commands" class="help-commands"></div>
|
|
1565
1826
|
</div>
|
|
1566
1827
|
<div class="help-block">
|
|
@@ -1593,62 +1854,79 @@
|
|
|
1593
1854
|
</section>
|
|
1594
1855
|
|
|
1595
1856
|
<section id="view-chat" class="view">
|
|
1596
|
-
<div class="page-head">
|
|
1857
|
+
<div class="page-head" style="margin-bottom: 12px;">
|
|
1597
1858
|
<div>
|
|
1598
1859
|
<h1>交互对话</h1>
|
|
1599
|
-
<p
|
|
1860
|
+
<p>提问将接入当前 PsyClaw 会话;助手回复经 SSE 流式同步,支持学术指令与「唤醒选项」决策。</p>
|
|
1600
1861
|
</div>
|
|
1601
1862
|
</div>
|
|
1602
|
-
<div id="chat-console-host" class="panel section" style="min-height:
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
<
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
</
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
<
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
<span>对话</span>
|
|
1620
|
-
<span id="console-status-badge" class="console-status-tag">已连接</span>
|
|
1621
|
-
</div>
|
|
1622
|
-
<div class="console-actions">
|
|
1623
|
-
<button id="console-clear-btn" class="console-btn-icon" title="清空对话">
|
|
1624
|
-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
1625
|
-
</button>
|
|
1626
|
-
<button id="console-close-btn" class="console-btn-icon" title="最小化">
|
|
1627
|
-
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
1628
|
-
</button>
|
|
1629
|
-
</div>
|
|
1630
|
-
</div>
|
|
1863
|
+
<div id="chat-console-host" class="panel section" style="min-height:74vh;padding:0;overflow:hidden;display:flex;flex-direction:column;border-radius:var(--radius-md);">
|
|
1864
|
+
<div id="console-drawer" class="console-drawer">
|
|
1865
|
+
<div class="console-header">
|
|
1866
|
+
<div class="console-title">
|
|
1867
|
+
<span class="agent-avatar" style="width:24px;height:24px;font-size:12px">ψ</span>
|
|
1868
|
+
<span>PsyClaw Research Assistant</span>
|
|
1869
|
+
<span id="console-status-badge" class="console-status-tag">
|
|
1870
|
+
<span class="pulse-dot" style="width:5px;height:5px;"></span>
|
|
1871
|
+
已连接
|
|
1872
|
+
</span>
|
|
1873
|
+
</div>
|
|
1874
|
+
<div class="console-actions">
|
|
1875
|
+
<button id="console-clear-btn" class="console-btn-icon" title="清空对话记录">
|
|
1876
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
|
|
1877
|
+
</button>
|
|
1878
|
+
</div>
|
|
1879
|
+
</div>
|
|
1631
1880
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1881
|
+
<div id="console-log" class="console-log">
|
|
1882
|
+
<div class="log-entry sys">
|
|
1883
|
+
<div class="log-sys">
|
|
1884
|
+
💡 <strong>对话已就绪</strong>:与 PsyClaw 智能体及底层学术插件安全连接。支持 <code>/init</code>、<code>/plan</code>、<code>/grill</code>、<code>/verify</code> 等研究指令;随时探讨研究设想或分析数据。
|
|
1885
|
+
</div>
|
|
1886
|
+
</div>
|
|
1887
|
+
</div>
|
|
1639
1888
|
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1889
|
+
<div class="console-quick-chips">
|
|
1890
|
+
<span class="chip" data-cmd="/plan status">
|
|
1891
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
|
|
1892
|
+
/plan status
|
|
1893
|
+
</span>
|
|
1894
|
+
<span class="chip" data-cmd="/verify list">
|
|
1895
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/></svg>
|
|
1896
|
+
/verify list
|
|
1897
|
+
</span>
|
|
1898
|
+
<span class="chip" data-cmd="/grill">
|
|
1899
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/></svg>
|
|
1900
|
+
/grill 压力追问
|
|
1901
|
+
</span>
|
|
1902
|
+
<span class="chip" data-cmd="/review">
|
|
1903
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/></svg>
|
|
1904
|
+
/review 评审
|
|
1905
|
+
</span>
|
|
1906
|
+
<span class="chip" data-cmd="/agents">
|
|
1907
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/></svg>
|
|
1908
|
+
/agents 角色
|
|
1909
|
+
</span>
|
|
1910
|
+
</div>
|
|
1645
1911
|
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1912
|
+
<div class="console-input-wrap">
|
|
1913
|
+
<div class="console-input-container">
|
|
1914
|
+
<div class="console-input-box">
|
|
1915
|
+
<textarea id="console-input" class="console-textarea" placeholder="输入研究问题或指令(Enter 发送,Shift+Enter 换行)…" rows="1"></textarea>
|
|
1916
|
+
<button id="console-send-btn" class="console-send-btn" title="发送消息 (Enter)">
|
|
1917
|
+
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
|
|
1918
|
+
</button>
|
|
1919
|
+
</div>
|
|
1920
|
+
<div class="console-input-footer">
|
|
1921
|
+
<span>支持 Markdown 与学术指令</span>
|
|
1922
|
+
<span>PsyClaw 本地隔离环境</span>
|
|
1923
|
+
</div>
|
|
1924
|
+
</div>
|
|
1925
|
+
</div>
|
|
1926
|
+
</div>
|
|
1927
|
+
</div>
|
|
1928
|
+
</section>
|
|
1929
|
+
</main>
|
|
1652
1930
|
</div>
|
|
1653
1931
|
</div>
|
|
1654
1932
|
|
|
@@ -1750,8 +2028,7 @@ function setView(view) {
|
|
|
1750
2028
|
if (view === "provider") loadProvider();
|
|
1751
2029
|
if (view === "checklist") loadChecklist();
|
|
1752
2030
|
if (view === "help") loadHelp();
|
|
1753
|
-
if (view === "chat")
|
|
1754
|
-
else restoreConsoleDrawer();
|
|
2031
|
+
if (view === "chat") queueMicrotask(() => $("console-input")?.focus());
|
|
1755
2032
|
}
|
|
1756
2033
|
|
|
1757
2034
|
async function loadHelp() {
|
|
@@ -1775,37 +2052,6 @@ async function loadHelp() {
|
|
|
1775
2052
|
}
|
|
1776
2053
|
}
|
|
1777
2054
|
|
|
1778
|
-
function mountConsoleInChat() {
|
|
1779
|
-
const host = $("chat-console-host");
|
|
1780
|
-
const drawer = $("console-drawer");
|
|
1781
|
-
if (!host || !drawer) return;
|
|
1782
|
-
host.appendChild(drawer);
|
|
1783
|
-
drawer.classList.add("open", "embedded");
|
|
1784
|
-
drawer.style.position = "relative";
|
|
1785
|
-
drawer.style.inset = "auto";
|
|
1786
|
-
drawer.style.width = "100%";
|
|
1787
|
-
drawer.style.height = "100%";
|
|
1788
|
-
drawer.style.minHeight = "58vh";
|
|
1789
|
-
drawer.style.boxShadow = "none";
|
|
1790
|
-
drawer.style.borderRadius = "0";
|
|
1791
|
-
drawer.style.transform = "none";
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
function restoreConsoleDrawer() {
|
|
1795
|
-
const drawer = $("console-drawer");
|
|
1796
|
-
if (!drawer || drawer.parentElement === document.body) return;
|
|
1797
|
-
document.body.appendChild(drawer);
|
|
1798
|
-
drawer.classList.remove("embedded");
|
|
1799
|
-
drawer.style.position = "";
|
|
1800
|
-
drawer.style.inset = "";
|
|
1801
|
-
drawer.style.width = "";
|
|
1802
|
-
drawer.style.height = "";
|
|
1803
|
-
drawer.style.minHeight = "";
|
|
1804
|
-
drawer.style.boxShadow = "";
|
|
1805
|
-
drawer.style.borderRadius = "";
|
|
1806
|
-
drawer.style.transform = "";
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
2055
|
async function loadChecklist() {
|
|
1810
2056
|
const body = $("checklist-body");
|
|
1811
2057
|
if (!body) return;
|
|
@@ -1854,7 +2100,7 @@ $("skip-checklist")?.addEventListener("click", async () => {
|
|
|
1854
2100
|
await loadChecklist();
|
|
1855
2101
|
});
|
|
1856
2102
|
|
|
1857
|
-
document.querySelectorAll(".nav button").forEach(button => {
|
|
2103
|
+
document.querySelectorAll(".nav button[data-view]").forEach(button => {
|
|
1858
2104
|
button.addEventListener("click", () => setView(button.dataset.view));
|
|
1859
2105
|
});
|
|
1860
2106
|
|
|
@@ -1873,16 +2119,20 @@ function inlineMarkdown(text) {
|
|
|
1873
2119
|
|
|
1874
2120
|
function renderMarkdown(markdown) {
|
|
1875
2121
|
const lines = String(markdown).replace(/\r\n/g, "\n").split("\n"), out = [];
|
|
1876
|
-
let i = 0, inCode = false, code = [];
|
|
2122
|
+
let i = 0, inCode = false, codeLang = "", code = [];
|
|
1877
2123
|
while (i < lines.length) {
|
|
1878
2124
|
const line = lines[i], trim = line.trim();
|
|
1879
2125
|
if (trim.startsWith("```")) {
|
|
1880
2126
|
if (inCode) {
|
|
1881
|
-
|
|
2127
|
+
const rawCode = code.join("\n");
|
|
2128
|
+
const langDisplay = codeLang || "code";
|
|
2129
|
+
out.push(`<div class="code-container"><div class="code-header"><span>${esc(langDisplay)}</span><button type="button" class="code-copy-btn" data-code="${esc(rawCode)}"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><span>复制</span></button></div><pre><code>${esc(rawCode)}</code></pre></div>`);
|
|
1882
2130
|
code = [];
|
|
2131
|
+
codeLang = "";
|
|
1883
2132
|
inCode = false;
|
|
1884
2133
|
} else {
|
|
1885
2134
|
inCode = true;
|
|
2135
|
+
codeLang = trim.slice(3).trim();
|
|
1886
2136
|
}
|
|
1887
2137
|
i++;
|
|
1888
2138
|
continue;
|
|
@@ -1942,7 +2192,11 @@ function renderMarkdown(markdown) {
|
|
|
1942
2192
|
}
|
|
1943
2193
|
out.push(`<p>${inlineMarkdown(para.join(" "))}</p>`);
|
|
1944
2194
|
}
|
|
1945
|
-
if (inCode)
|
|
2195
|
+
if (inCode) {
|
|
2196
|
+
const rawCode = code.join("\n");
|
|
2197
|
+
const langDisplay = codeLang || "code";
|
|
2198
|
+
out.push(`<div class="code-container"><div class="code-header"><span>${esc(langDisplay)}</span><button type="button" class="code-copy-btn" data-code="${esc(rawCode)}"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><span>复制</span></button></div><pre><code>${esc(rawCode)}</code></pre></div>`);
|
|
2199
|
+
}
|
|
1946
2200
|
return out.join("");
|
|
1947
2201
|
}
|
|
1948
2202
|
|
|
@@ -2343,8 +2597,6 @@ document.querySelectorAll(".step-item").forEach(item => {
|
|
|
2343
2597
|
});
|
|
2344
2598
|
|
|
2345
2599
|
/* --- 交互对话 + SSE + 唤醒选项 --- */
|
|
2346
|
-
const consoleDrawer = $("console-drawer");
|
|
2347
|
-
const consoleFab = $("console-fab");
|
|
2348
2600
|
const consoleLog = $("console-log");
|
|
2349
2601
|
const consoleInput = $("console-input");
|
|
2350
2602
|
const streamBubbles = new Map();
|
|
@@ -2352,12 +2604,8 @@ let lastLocalUserText = "";
|
|
|
2352
2604
|
let wakeState = null;
|
|
2353
2605
|
|
|
2354
2606
|
function openConsole() {
|
|
2355
|
-
|
|
2356
|
-
consoleInput
|
|
2357
|
-
}
|
|
2358
|
-
|
|
2359
|
-
function closeConsole() {
|
|
2360
|
-
consoleDrawer.classList.remove("open");
|
|
2607
|
+
setView("chat");
|
|
2608
|
+
queueMicrotask(() => consoleInput?.focus());
|
|
2361
2609
|
}
|
|
2362
2610
|
|
|
2363
2611
|
function openConsoleWithMessage(text) {
|
|
@@ -2369,9 +2617,22 @@ function appendLog(role, text) {
|
|
|
2369
2617
|
const entry = document.createElement("div");
|
|
2370
2618
|
entry.className = `log-entry ${role}`;
|
|
2371
2619
|
if (role === "user") {
|
|
2372
|
-
entry.innerHTML =
|
|
2620
|
+
entry.innerHTML = `
|
|
2621
|
+
<div class="log-user-wrap">
|
|
2622
|
+
<div class="log-user">${esc(text)}</div>
|
|
2623
|
+
</div>
|
|
2624
|
+
`;
|
|
2373
2625
|
} else if (role === "agent") {
|
|
2374
|
-
entry.innerHTML =
|
|
2626
|
+
entry.innerHTML = `
|
|
2627
|
+
<div class="agent-avatar">ψ</div>
|
|
2628
|
+
<div class="agent-content-wrap">
|
|
2629
|
+
<div class="agent-meta">
|
|
2630
|
+
<span>PsyClaw Assistant</span>
|
|
2631
|
+
<span class="agent-role-pill">Core</span>
|
|
2632
|
+
</div>
|
|
2633
|
+
<div class="log-agent">${renderMarkdown(text)}</div>
|
|
2634
|
+
</div>
|
|
2635
|
+
`;
|
|
2375
2636
|
} else {
|
|
2376
2637
|
entry.innerHTML = `<div class="log-sys">${esc(text)}</div>`;
|
|
2377
2638
|
}
|
|
@@ -2386,7 +2647,21 @@ function ensureStreamBubble(messageId) {
|
|
|
2386
2647
|
entry = document.createElement("div");
|
|
2387
2648
|
entry.className = "log-entry agent";
|
|
2388
2649
|
entry.dataset.messageId = messageId;
|
|
2389
|
-
entry.innerHTML =
|
|
2650
|
+
entry.innerHTML = `
|
|
2651
|
+
<div class="agent-avatar">ψ</div>
|
|
2652
|
+
<div class="agent-content-wrap">
|
|
2653
|
+
<div class="agent-meta">
|
|
2654
|
+
<span>PsyClaw Assistant</span>
|
|
2655
|
+
<span class="agent-role-pill">Streaming</span>
|
|
2656
|
+
</div>
|
|
2657
|
+
<div class="log-agent" style="display:none"></div>
|
|
2658
|
+
<div class="agent-typing-indicator">
|
|
2659
|
+
<span class="typing-dot"></span>
|
|
2660
|
+
<span class="typing-dot"></span>
|
|
2661
|
+
<span class="typing-dot"></span>
|
|
2662
|
+
</div>
|
|
2663
|
+
</div>
|
|
2664
|
+
`;
|
|
2390
2665
|
consoleLog.appendChild(entry);
|
|
2391
2666
|
streamBubbles.set(messageId, entry);
|
|
2392
2667
|
consoleLog.scrollTop = consoleLog.scrollHeight;
|
|
@@ -2396,9 +2671,24 @@ function ensureStreamBubble(messageId) {
|
|
|
2396
2671
|
function updateStreamBubble(messageId, text, done) {
|
|
2397
2672
|
const entry = ensureStreamBubble(messageId);
|
|
2398
2673
|
const bubble = entry.querySelector(".log-agent");
|
|
2674
|
+
const indicator = entry.querySelector(".agent-typing-indicator");
|
|
2675
|
+
const pill = entry.querySelector(".agent-role-pill");
|
|
2399
2676
|
if (!bubble) return;
|
|
2400
|
-
|
|
2401
|
-
|
|
2677
|
+
|
|
2678
|
+
if (text) {
|
|
2679
|
+
bubble.style.display = "block";
|
|
2680
|
+
bubble.innerHTML = renderMarkdown(text);
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
if (done) {
|
|
2684
|
+
if (indicator) indicator.remove();
|
|
2685
|
+
if (pill) pill.textContent = "Answered";
|
|
2686
|
+
bubble.style.display = "block";
|
|
2687
|
+
} else {
|
|
2688
|
+
if (text && indicator) {
|
|
2689
|
+
indicator.style.display = "none";
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2402
2692
|
consoleLog.scrollTop = consoleLog.scrollHeight;
|
|
2403
2693
|
}
|
|
2404
2694
|
|
|
@@ -2450,7 +2740,10 @@ function connectAssistantStream() {
|
|
|
2450
2740
|
es.addEventListener("wake_options", (ev) => {
|
|
2451
2741
|
try {
|
|
2452
2742
|
const data = JSON.parse(ev.data);
|
|
2453
|
-
if (data.prompt)
|
|
2743
|
+
if (data.prompt) {
|
|
2744
|
+
appendWakeChecklist(data.prompt);
|
|
2745
|
+
showWakeModal(data.prompt, { switchChecklist: false });
|
|
2746
|
+
}
|
|
2454
2747
|
} catch { /* ignore */ }
|
|
2455
2748
|
});
|
|
2456
2749
|
es.addEventListener("wake_options_resolved", (ev) => {
|
|
@@ -2466,8 +2759,32 @@ function connectAssistantStream() {
|
|
|
2466
2759
|
es.onerror = () => setConsoleStatus("重连中", false);
|
|
2467
2760
|
}
|
|
2468
2761
|
|
|
2469
|
-
function
|
|
2470
|
-
|
|
2762
|
+
function appendWakeChecklist(prompt) {
|
|
2763
|
+
if (!prompt || prompt.mode !== "checklist") return;
|
|
2764
|
+
const existing = document.querySelector(`[data-wake-checklist-id="${CSS.escape(prompt.id)}"]`);
|
|
2765
|
+
if (existing) return;
|
|
2766
|
+
const entry = document.createElement("div");
|
|
2767
|
+
entry.className = "log-entry sys";
|
|
2768
|
+
entry.dataset.wakeChecklistId = prompt.id;
|
|
2769
|
+
const items = (prompt.options || []).map(option => `
|
|
2770
|
+
<li data-option-id="${esc(option.id)}"><span class="wake-checklist-mark">${option.checked ? "[x]" : "[ ]"}</span> <span>${esc(option.label)}</span>${option.description ? `<small>${esc(option.description)}</small>` : ""}</li>
|
|
2771
|
+
`).join("");
|
|
2772
|
+
entry.innerHTML = `<div class="log-sys wake-checklist-card"><strong>${esc(prompt.title || "交叉核验清单")}</strong>${prompt.prompt ? `<p>${esc(prompt.prompt)}</p>` : ""}<ul>${items}</ul><span class="wake-checklist-hint">请在当前对话中的弹窗完成勾选。</span></div>`;
|
|
2773
|
+
consoleLog.appendChild(entry);
|
|
2774
|
+
consoleLog.scrollTop = consoleLog.scrollHeight;
|
|
2775
|
+
}
|
|
2776
|
+
|
|
2777
|
+
function updateWakeChecklist(promptId, selectedIds) {
|
|
2778
|
+
const entry = document.querySelector(`[data-wake-checklist-id="${CSS.escape(promptId)}"]`);
|
|
2779
|
+
if (!entry) return;
|
|
2780
|
+
const selected = new Set(selectedIds || []);
|
|
2781
|
+
entry.querySelectorAll("li[data-option-id]").forEach(item => {
|
|
2782
|
+
const mark = item.querySelector(".wake-checklist-mark");
|
|
2783
|
+
if (mark) mark.textContent = selected.has(item.dataset.optionId) ? "[x]" : "[ ]";
|
|
2784
|
+
});
|
|
2785
|
+
}
|
|
2786
|
+
|
|
2787
|
+
function showWakeModal(prompt) {
|
|
2471
2788
|
wakeState = {
|
|
2472
2789
|
id: prompt.id,
|
|
2473
2790
|
mode: prompt.mode,
|
|
@@ -2502,13 +2819,12 @@ function showWakeModal(prompt, { switchChecklist = true } = {}) {
|
|
|
2502
2819
|
} else {
|
|
2503
2820
|
wakeState.selected.add(option.id);
|
|
2504
2821
|
}
|
|
2505
|
-
showWakeModal(prompt
|
|
2822
|
+
showWakeModal(prompt);
|
|
2506
2823
|
});
|
|
2507
2824
|
list.appendChild(btn);
|
|
2508
2825
|
}
|
|
2509
2826
|
$("wake-modal").classList.remove("hidden");
|
|
2510
2827
|
openConsole();
|
|
2511
|
-
if (firstOpen && switchChecklist && prompt.mode === "checklist") setView("checklist");
|
|
2512
2828
|
}
|
|
2513
2829
|
|
|
2514
2830
|
function hideWakeModal() {
|
|
@@ -2527,8 +2843,8 @@ async function submitWake(cancel = false) {
|
|
|
2527
2843
|
body: JSON.stringify({ promptId, selectedIds, cancel: Boolean(cancel) }),
|
|
2528
2844
|
});
|
|
2529
2845
|
hideWakeModal();
|
|
2846
|
+
updateWakeChecklist(promptId, selectedIds);
|
|
2530
2847
|
appendLog("sys", cancel ? "已取消唤醒选项" : `已提交选择:${selectedIds.join(", ") || "(空)"}`);
|
|
2531
|
-
await loadChecklist().catch(() => {});
|
|
2532
2848
|
} catch (err) {
|
|
2533
2849
|
appendLog("sys", `[唤醒选项] ${err.message}`);
|
|
2534
2850
|
}
|
|
@@ -2538,23 +2854,55 @@ $("wake-modal-close")?.addEventListener("click", () => submitWake(true));
|
|
|
2538
2854
|
$("wake-cancel-btn")?.addEventListener("click", () => submitWake(true));
|
|
2539
2855
|
$("wake-submit-btn")?.addEventListener("click", () => submitWake(false));
|
|
2540
2856
|
|
|
2541
|
-
consoleFab.addEventListener("click", () => {
|
|
2542
|
-
if (consoleDrawer.classList.contains("open")) closeConsole();
|
|
2543
|
-
else openConsole();
|
|
2544
|
-
});
|
|
2545
|
-
$("console-close-btn").addEventListener("click", closeConsole);
|
|
2546
2857
|
$("console-clear-btn").addEventListener("click", () => {
|
|
2547
2858
|
consoleLog.innerHTML = `<div class="log-entry sys"><div class="log-sys">对话已清空。输入问题或 /help 即可继续。</div></div>`;
|
|
2548
2859
|
streamBubbles.clear();
|
|
2549
2860
|
});
|
|
2550
2861
|
|
|
2862
|
+
// 自适应高度调整函数
|
|
2863
|
+
function autoResizeConsoleInput() {
|
|
2864
|
+
if (!consoleInput) return;
|
|
2865
|
+
consoleInput.style.height = "auto";
|
|
2866
|
+
const nextHeight = Math.min(Math.max(consoleInput.scrollHeight, 24), 160);
|
|
2867
|
+
consoleInput.style.height = `${nextHeight}px`;
|
|
2868
|
+
}
|
|
2869
|
+
|
|
2870
|
+
consoleInput.addEventListener("input", autoResizeConsoleInput);
|
|
2871
|
+
|
|
2872
|
+
// 代码块全局点击复制事件代理
|
|
2873
|
+
document.addEventListener("click", async (e) => {
|
|
2874
|
+
const btn = e.target.closest(".code-copy-btn");
|
|
2875
|
+
if (!btn) return;
|
|
2876
|
+
const rawCode = btn.dataset.code;
|
|
2877
|
+
if (!rawCode) return;
|
|
2878
|
+
try {
|
|
2879
|
+
await navigator.clipboard.writeText(rawCode);
|
|
2880
|
+
const textSpan = btn.querySelector("span");
|
|
2881
|
+
if (textSpan) {
|
|
2882
|
+
const originalText = textSpan.textContent;
|
|
2883
|
+
textSpan.textContent = "已复制";
|
|
2884
|
+
btn.style.color = "var(--ok-text)";
|
|
2885
|
+
setTimeout(() => {
|
|
2886
|
+
textSpan.textContent = originalText;
|
|
2887
|
+
btn.style.color = "";
|
|
2888
|
+
}, 1800);
|
|
2889
|
+
}
|
|
2890
|
+
} catch {
|
|
2891
|
+
alert("无法写入剪贴板,请手动选中文本复制。");
|
|
2892
|
+
}
|
|
2893
|
+
});
|
|
2894
|
+
|
|
2551
2895
|
async function sendConsoleMessage(msg) {
|
|
2552
2896
|
const text = (msg || consoleInput.value).trim();
|
|
2553
2897
|
if (!text) return;
|
|
2554
2898
|
consoleInput.value = "";
|
|
2899
|
+
autoResizeConsoleInput();
|
|
2555
2900
|
lastLocalUserText = text;
|
|
2556
2901
|
appendLog("user", text);
|
|
2557
2902
|
|
|
2903
|
+
const sendBtn = $("console-send-btn");
|
|
2904
|
+
if (sendBtn) sendBtn.disabled = true;
|
|
2905
|
+
|
|
2558
2906
|
try {
|
|
2559
2907
|
const res = await json("/api/assistant", {
|
|
2560
2908
|
method: "POST",
|
|
@@ -2565,6 +2913,8 @@ async function sendConsoleMessage(msg) {
|
|
|
2565
2913
|
if (res.text) appendLog("sys", res.text);
|
|
2566
2914
|
} catch (err) {
|
|
2567
2915
|
appendLog("sys", `[提示] ${err.message}`);
|
|
2916
|
+
} finally {
|
|
2917
|
+
if (sendBtn) sendBtn.disabled = false;
|
|
2568
2918
|
}
|
|
2569
2919
|
}
|
|
2570
2920
|
|
|
@@ -2583,11 +2933,31 @@ document.querySelectorAll(".chip").forEach(chip => {
|
|
|
2583
2933
|
const cmd = chip.dataset.cmd;
|
|
2584
2934
|
if (cmd) {
|
|
2585
2935
|
consoleInput.value = cmd;
|
|
2936
|
+
autoResizeConsoleInput();
|
|
2586
2937
|
sendConsoleMessage(cmd);
|
|
2587
2938
|
}
|
|
2588
2939
|
});
|
|
2589
2940
|
});
|
|
2590
2941
|
|
|
2942
|
+
/* --- 侧边栏折叠与展开交互 --- */
|
|
2943
|
+
const layoutEl = document.querySelector(".layout");
|
|
2944
|
+
const navToggleBtn = $("nav-toggle-btn");
|
|
2945
|
+
|
|
2946
|
+
function initNavCollapse() {
|
|
2947
|
+
const saved = localStorage.getItem("psyclaw_nav_collapsed");
|
|
2948
|
+
if (saved === "true") {
|
|
2949
|
+
layoutEl?.classList.add("nav-collapsed");
|
|
2950
|
+
}
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
navToggleBtn?.addEventListener("click", () => {
|
|
2954
|
+
if (!layoutEl) return;
|
|
2955
|
+
const isCollapsed = layoutEl.classList.toggle("nav-collapsed");
|
|
2956
|
+
localStorage.setItem("psyclaw_nav_collapsed", isCollapsed ? "true" : "false");
|
|
2957
|
+
});
|
|
2958
|
+
|
|
2959
|
+
initNavCollapse();
|
|
2960
|
+
|
|
2591
2961
|
/* --- 顶栏快捷命令 Quick Actions --- */
|
|
2592
2962
|
const initModal = $("init-modal");
|
|
2593
2963
|
const initParadigm = $("init-paradigm");
|