psyclaw 0.29.14 → 0.29.16

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 (36) hide show
  1. package/README.md +14 -14
  2. package/dist/apps/panel/index.html +381 -141
  3. package/dist/src/adapters/pi/extension.js +145 -518
  4. package/dist/src/adapters/pi/extension.js.map +1 -1
  5. package/dist/src/agents/recommended-personas.d.ts +1 -1
  6. package/dist/src/agents/recommended-personas.js +2 -2
  7. package/dist/src/agents/recommended-personas.js.map +1 -1
  8. package/dist/src/analysis/plan.js +2 -2
  9. package/dist/src/analysis/plan.js.map +1 -1
  10. package/dist/src/analysis/stats-router.js +2 -2
  11. package/dist/src/analysis/stats-router.js.map +1 -1
  12. package/dist/src/branding.js +3 -3
  13. package/dist/src/branding.js.map +1 -1
  14. package/dist/src/orchestration/bundled-personas.d.ts +1 -1
  15. package/dist/src/orchestration/bundled-personas.js +1 -1
  16. package/dist/src/orchestration/bundled-personas.js.map +1 -1
  17. package/dist/src/orchestration/personas.js +2 -5
  18. package/dist/src/orchestration/personas.js.map +1 -1
  19. package/dist/src/panel/extension.js +3 -7
  20. package/dist/src/panel/extension.js.map +1 -1
  21. package/dist/src/panel/server.js +4 -4
  22. package/dist/src/panel/server.js.map +1 -1
  23. package/dist/src/session/help.d.ts +1 -1
  24. package/dist/src/session/help.js +26 -27
  25. package/dist/src/session/help.js.map +1 -1
  26. package/dist/src/session/modes.js +3 -3
  27. package/dist/src/session/modes.js.map +1 -1
  28. package/dist/src/skills/recommended.js +1 -1
  29. package/dist/src/skills/recommended.js.map +1 -1
  30. package/dist/src/style/cli-ui.js +14 -13
  31. package/dist/src/style/cli-ui.js.map +1 -1
  32. package/dist/src/verify/checklist.d.ts +5 -4
  33. package/dist/src/verify/checklist.js +7 -8
  34. package/dist/src/verify/checklist.js.map +1 -1
  35. package/package.json +1 -1
  36. package/skills/recommended/catalog.json +36 -3
@@ -102,15 +102,19 @@
102
102
  .brand-mark {
103
103
  display: grid;
104
104
  place-items: center;
105
- width: 28px;
106
- height: 28px;
107
- background: linear-gradient(135deg, #0f172a 0%, #0d766e 100%);
105
+ width: 30px;
106
+ height: 30px;
107
+ background: linear-gradient(135deg, #38bdf8 0%, #818cf8 50%, #a855f7 100%);
108
108
  color: #ffffff;
109
109
  border-radius: var(--radius-sm);
110
- font-weight: 700;
111
- font-size: 16px;
112
- line-height: 1;
113
- box-shadow: var(--shadow-xs);
110
+ box-shadow: 0 2px 10px rgba(129, 140, 248, 0.35);
111
+ border: 1px solid rgba(255, 255, 255, 0.25);
112
+ flex-shrink: 0;
113
+ }
114
+ .brand-mark svg {
115
+ width: 17px;
116
+ height: 17px;
117
+ fill: currentColor;
114
118
  }
115
119
  .brand-title {
116
120
  font-weight: 650;
@@ -123,18 +127,43 @@
123
127
  }
124
128
  .brand-badge {
125
129
  font-size: 10.5px;
126
- font-weight: 550;
127
- color: var(--brand-primary);
128
- background: var(--brand-primary-light);
129
- border: 1px solid var(--brand-primary-border);
130
- padding: 1px 6px;
130
+ font-weight: 600;
131
+ background: linear-gradient(135deg, rgba(56, 189, 248, 0.12) 0%, rgba(168, 85, 247, 0.12) 100%);
132
+ color: #6366f1;
133
+ border: 1px solid rgba(129, 140, 248, 0.3);
134
+ padding: 1px 7px;
131
135
  border-radius: 999px;
132
136
  letter-spacing: 0.02em;
133
137
  }
134
138
  .topbar-meta {
135
139
  display: flex;
136
140
  align-items: center;
137
- gap: 16px;
141
+ gap: 12px;
142
+ }
143
+ .github-link {
144
+ display: inline-flex;
145
+ align-items: center;
146
+ gap: 6px;
147
+ padding: 4px 10px;
148
+ font-size: 12px;
149
+ font-weight: 550;
150
+ color: var(--text-secondary);
151
+ background: var(--bg-surface-subtle);
152
+ border: 1px solid var(--border-subtle);
153
+ border-radius: var(--radius-sm);
154
+ text-decoration: none;
155
+ transition: all 0.15s ease;
156
+ }
157
+ .github-link:hover {
158
+ background: var(--bg-surface-hover);
159
+ color: var(--text-main);
160
+ border-color: rgba(129, 140, 248, 0.4);
161
+ box-shadow: 0 1px 4px rgba(129, 140, 248, 0.15);
162
+ }
163
+ .github-link svg {
164
+ width: 14px;
165
+ height: 14px;
166
+ fill: currentColor;
138
167
  }
139
168
  .local-badge {
140
169
  display: inline-flex;
@@ -593,15 +622,32 @@
593
622
 
594
623
  .workspace {
595
624
  display: grid;
596
- grid-template-columns: 260px minmax(0, 1fr);
625
+ grid-template-columns: minmax(480px, 1.25fr) 180px minmax(0, 1.6fr);
597
626
  height: calc(100vh - 130px);
598
627
  overflow: hidden;
599
628
  background: var(--bg-surface);
629
+ transition: grid-template-columns 0.22s cubic-bezier(0.4, 0, 0.2, 1);
630
+ }
631
+ .workspace.chat-collapsed {
632
+ grid-template-columns: 46px 180px minmax(0, 1fr);
633
+ }
634
+ /* 当未打开具体文件时,对话框自动铺满工作台主区域 */
635
+ .workspace.no-file-open {
636
+ grid-template-columns: minmax(0, 1fr) 180px 0px;
637
+ }
638
+ .workspace.no-file-open .viewer {
639
+ display: none !important;
640
+ }
641
+ .workspace.no-file-open.chat-collapsed {
642
+ grid-template-columns: 46px minmax(0, 1fr) 0px;
643
+ }
644
+ .workspace.no-file-open.chat-collapsed .viewer {
645
+ display: none !important;
600
646
  }
601
647
  .tree {
602
648
  border-right: 1px solid var(--border-subtle);
603
649
  overflow-y: auto;
604
- padding: 12px 8px;
650
+ padding: 10px 6px;
605
651
  background: #fafbfc;
606
652
  }
607
653
  .tree-section {
@@ -1132,40 +1178,45 @@
1132
1178
  background: var(--brand-primary-hover);
1133
1179
  }
1134
1180
 
1135
- /* In-page chat: Modern Codex / Gemini style */
1181
+ /* In-page chat: Modern Codex / Gemini style inside workspace */
1136
1182
  .console-drawer {
1137
1183
  position: relative;
1138
1184
  width: 100%;
1139
1185
  height: 100%;
1140
- min-height: 72vh;
1186
+ min-height: 0;
1141
1187
  flex: 1;
1142
1188
  background: var(--bg-surface);
1143
1189
  color: var(--text-main);
1144
- border: none;
1190
+ border-right: 1px solid var(--border-subtle);
1145
1191
  display: flex;
1146
1192
  flex-direction: column;
1147
1193
  font-family: var(--font-sans);
1194
+ overflow: hidden;
1195
+ transition: width 0.2s ease;
1148
1196
  }
1149
1197
  .console-header {
1150
1198
  display: flex;
1151
1199
  align-items: center;
1152
1200
  justify-content: space-between;
1153
- padding: 12px 20px;
1201
+ padding: 10px 14px;
1154
1202
  border-bottom: 1px solid var(--border-subtle);
1155
1203
  background: var(--bg-surface);
1204
+ min-height: 48px;
1156
1205
  }
1157
1206
  .console-title {
1158
- font-size: 13.5px;
1207
+ font-size: 13px;
1159
1208
  font-weight: 650;
1160
1209
  color: var(--text-main);
1161
1210
  display: flex;
1162
1211
  align-items: center;
1163
- gap: 9px;
1212
+ gap: 8px;
1213
+ overflow: hidden;
1214
+ white-space: nowrap;
1164
1215
  }
1165
1216
  .console-status-tag {
1166
- font-size: 10.5px;
1217
+ font-size: 10px;
1167
1218
  font-weight: 600;
1168
- padding: 1px 7px;
1219
+ padding: 1px 6px;
1169
1220
  border-radius: 999px;
1170
1221
  background: var(--ok-bg);
1171
1222
  color: var(--ok-text);
@@ -1177,7 +1228,8 @@
1177
1228
  .console-actions {
1178
1229
  display: flex;
1179
1230
  align-items: center;
1180
- gap: 8px;
1231
+ gap: 6px;
1232
+ flex-shrink: 0;
1181
1233
  }
1182
1234
  .console-btn-icon {
1183
1235
  background: transparent;
@@ -1196,6 +1248,50 @@
1196
1248
  background: var(--bg-surface-subtle);
1197
1249
  }
1198
1250
 
1251
+ /* Collapsed state for workspace chat drawer */
1252
+ .workspace.chat-collapsed .console-header {
1253
+ padding: 10px 6px;
1254
+ justify-content: center;
1255
+ }
1256
+ .workspace.chat-collapsed .console-title span,
1257
+ .workspace.chat-collapsed .console-status-tag,
1258
+ .workspace.chat-collapsed #console-clear-btn,
1259
+ .workspace.chat-collapsed .console-log,
1260
+ .workspace.chat-collapsed .console-quick-chips,
1261
+ .workspace.chat-collapsed .console-input-wrap {
1262
+ display: none !important;
1263
+ }
1264
+ .workspace.chat-collapsed #chat-collapse-btn svg {
1265
+ transform: rotate(180deg);
1266
+ }
1267
+ .workspace.chat-collapsed .console-collapsed-bar {
1268
+ display: flex !important;
1269
+ }
1270
+
1271
+ .console-collapsed-bar {
1272
+ display: none;
1273
+ flex-direction: column;
1274
+ align-items: center;
1275
+ padding: 16px 0;
1276
+ gap: 16px;
1277
+ height: 100%;
1278
+ cursor: pointer;
1279
+ background: var(--bg-surface-subtle);
1280
+ }
1281
+ .console-collapsed-bar:hover {
1282
+ background: var(--bg-surface-hover);
1283
+ }
1284
+ .console-vertical-label {
1285
+ writing-mode: vertical-rl;
1286
+ text-orientation: mixed;
1287
+ letter-spacing: 0.12em;
1288
+ font-size: 11px;
1289
+ font-weight: 650;
1290
+ color: var(--text-muted);
1291
+ text-transform: uppercase;
1292
+ user-select: none;
1293
+ }
1294
+
1199
1295
  .console-log {
1200
1296
  flex: 1;
1201
1297
  overflow-y: auto;
@@ -1249,17 +1345,21 @@
1249
1345
 
1250
1346
  /* Agent Message: Codex/Gemini open conversational layout */
1251
1347
  .agent-avatar {
1252
- width: 32px;
1253
- height: 32px;
1348
+ width: 30px;
1349
+ height: 30px;
1254
1350
  border-radius: 50%;
1255
- background: linear-gradient(135deg, #0d766e 0%, #0284c7 100%);
1351
+ background: linear-gradient(135deg, #38bdf8 0%, #818cf8 50%, #a855f7 100%);
1256
1352
  color: #ffffff;
1257
1353
  display: grid;
1258
1354
  place-items: center;
1259
- font-weight: 700;
1260
- font-size: 15px;
1261
1355
  flex-shrink: 0;
1262
- box-shadow: 0 2px 4px rgba(13, 118, 110, 0.2);
1356
+ box-shadow: 0 2px 8px rgba(129, 140, 248, 0.35);
1357
+ border: 1px solid rgba(255, 255, 255, 0.2);
1358
+ }
1359
+ .agent-avatar svg {
1360
+ width: 15px;
1361
+ height: 15px;
1362
+ fill: currentColor;
1263
1363
  }
1264
1364
  .agent-content-wrap {
1265
1365
  flex: 1;
@@ -1394,6 +1494,38 @@
1394
1494
  border-radius: 4px;
1395
1495
  }
1396
1496
 
1497
+ /* Antigravity-like clickable file jump pill in chat */
1498
+ .file-jump-pill {
1499
+ display: inline-flex;
1500
+ align-items: center;
1501
+ gap: 4px;
1502
+ padding: 1.5px 7px;
1503
+ border-radius: 4px;
1504
+ background: linear-gradient(135deg, rgba(56, 189, 248, 0.08) 0%, rgba(129, 140, 248, 0.08) 100%);
1505
+ color: #4338ca;
1506
+ border: 1px solid rgba(129, 140, 248, 0.3);
1507
+ font-family: var(--font-mono);
1508
+ font-size: 11.5px;
1509
+ font-weight: 550;
1510
+ text-decoration: none;
1511
+ cursor: pointer;
1512
+ vertical-align: baseline;
1513
+ transition: all 0.15s ease;
1514
+ }
1515
+ .file-jump-pill:hover {
1516
+ background: linear-gradient(135deg, rgba(56, 189, 248, 0.18) 0%, rgba(129, 140, 248, 0.18) 100%);
1517
+ border-color: #6366f1;
1518
+ color: #312e81;
1519
+ box-shadow: 0 1px 3px rgba(99, 102, 241, 0.15);
1520
+ transform: translateY(-0.5px);
1521
+ }
1522
+ .file-jump-pill svg {
1523
+ width: 12px;
1524
+ height: 12px;
1525
+ flex-shrink: 0;
1526
+ stroke-width: 2.2;
1527
+ }
1528
+
1397
1529
  /* Shimmering Pulsing Dots for Streaming */
1398
1530
  .agent-typing-indicator {
1399
1531
  display: inline-flex;
@@ -1659,6 +1791,8 @@
1659
1791
  .nav button { width: auto; white-space: nowrap; }
1660
1792
  .main { padding: 16px; }
1661
1793
  .workspace { grid-template-columns: 1fr; height: auto; }
1794
+ .workspace.chat-collapsed { grid-template-columns: 1fr; }
1795
+ .console-drawer { min-height: 360px; border-right: 0; border-bottom: 1px solid var(--border-subtle); }
1662
1796
  .tree { max-height: 260px; border-right: 0; border-bottom: 1px solid var(--border-subtle); }
1663
1797
  .viewer { min-height: 480px; }
1664
1798
  .provider-grid, .cost-metrics { grid-template-columns: 1fr; }
@@ -1671,7 +1805,9 @@
1671
1805
  <!-- 顶栏 Header -->
1672
1806
  <header class="topbar">
1673
1807
  <div class="brand">
1674
- <span class="brand-mark">ψ</span>
1808
+ <span class="brand-mark" title="PsyClaw Academic AI">
1809
+ <svg viewBox="0 0 24 24"><path d="M12 2v20M12 2c-3.3 0-6 2.7-6 6v3c0 3.3 2.7 6 6 6s6-2.7 6-6V8c0-3.3-2.7-6-6-6zM4 9h4M16 9h4M9 22h6"/></svg>
1810
+ </span>
1675
1811
  <div class="brand-title">
1676
1812
  PsyClaw Panel
1677
1813
  <span class="brand-badge">Academic Studio</span>
@@ -1692,6 +1828,10 @@
1692
1828
  /crosscheck
1693
1829
  </button>
1694
1830
  </div>
1831
+ <a href="https://github.com/Exekiel179/psyclaw" target="_blank" rel="noopener noreferrer" class="github-link" title="前往 PsyClaw GitHub 仓库">
1832
+ <svg viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z"/></svg>
1833
+ <span>GitHub</span>
1834
+ </a>
1695
1835
  <div class="local-badge">
1696
1836
  <span class="pulse-dot"></span>
1697
1837
  安全沙盒 · 本地隔离
@@ -1700,7 +1840,7 @@
1700
1840
  </header>
1701
1841
 
1702
1842
  <!-- 主体工作区 Layout -->
1703
- <div class="layout">
1843
+ <div class="layout nav-collapsed">
1704
1844
  <!-- 侧边导航栏 Sidebar -->
1705
1845
  <nav class="nav" id="workbench-nav" aria-label="Panel 导航">
1706
1846
  <div class="nav-group">
@@ -1710,30 +1850,26 @@
1710
1850
  <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>
1711
1851
  </button>
1712
1852
  </div>
1713
- <button class="active" data-view="project" title="项目文件">
1714
- <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>
1715
- <span class="nav-btn-text">项目文件</span>
1853
+ <button class="active" data-view="project" title="工作台与对话">
1854
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><line x1="9" y1="4" x2="9" y2="20"/><line x1="15" y1="4" x2="15" y2="20"/></svg>
1855
+ <span class="nav-btn-text">工作台与对话</span>
1716
1856
  </button>
1717
1857
  <button data-view="ecosystem" title="能力生态">
1718
- <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>
1858
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/></svg>
1719
1859
  <span class="nav-btn-text">能力生态</span>
1720
1860
  </button>
1721
1861
  <button data-view="provider" title="模型与成本">
1722
- <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>
1862
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" 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>
1723
1863
  <span class="nav-btn-text">模型与成本</span>
1724
1864
  </button>
1725
1865
  <button data-view="help" title="使用速览">
1726
- <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>
1866
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" 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>
1727
1867
  <span class="nav-btn-text">使用速览</span>
1728
1868
  </button>
1729
1869
  <button data-view="checklist" title="核对清单">
1730
- <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>
1870
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" 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>
1731
1871
  <span class="nav-btn-text">核对清单</span>
1732
1872
  </button>
1733
- <button data-view="chat" title="对话">
1734
- <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>
1735
- <span class="nav-btn-text">对话</span>
1736
- </button>
1737
1873
  </div>
1738
1874
  <div class="nav-footer">
1739
1875
  <div style="font-weight:600;margin-bottom:2px;color:var(--text-secondary)">PsyClaw 运行提示</div>
@@ -1743,13 +1879,12 @@
1743
1879
 
1744
1880
  <!-- 主面板内容区 Main -->
1745
1881
  <main class="main">
1746
- <!-- 视图 1:项目文件 -->
1882
+ <!-- 视图 1:项目工作台 (默认主界面) -->
1747
1883
  <section id="view-project" class="view active">
1748
- <!-- 科研全流程导航条 Pipeline Stepper -->
1749
- <div class="pipeline-stepper" id="pipeline-stepper">
1750
- <span class="stepper-label">ARS 科研流水线:</span>
1751
- <div class="step-item" data-stage="intake" title="探索性学术追问与目标澄清 (notes/goal.md)">
1752
- <span>① 选题与入口</span>
1884
+ <!-- 科研全流程阶段导航条 Pipeline Stepper -->
1885
+ <div class="pipeline-stepper" aria-label="科研流程阶段">
1886
+ <div class="step-item active" data-stage="intake" title="研究问题与范式目标 (notes/goal.md)">
1887
+ <span>① 课题界定</span>
1753
1888
  </div>
1754
1889
  <span class="step-arrow">➔</span>
1755
1890
  <div class="step-item" data-stage="evidence" title="证据溯源与文献账本 (notes/evidence.jsonl, claims.jsonl)">
@@ -1779,7 +1914,85 @@
1779
1914
  刷新文档
1780
1915
  </button>
1781
1916
  </div>
1782
- <div class="panel workspace">
1917
+ <div class="panel workspace no-file-open" id="project-workspace">
1918
+ <!-- 智能体交互对话抽屉(平时折叠,点击展开) -->
1919
+ <div id="console-drawer" class="console-drawer">
1920
+ <div class="console-header">
1921
+ <div class="console-title">
1922
+ <span class="agent-avatar" style="width:24px;height:24px;">
1923
+ <svg viewBox="0 0 24 24"><path d="M12 2v20M12 2c-3.3 0-6 2.7-6 6v3c0 3.3 2.7 6 6 6s6-2.7 6-6V8c0-3.3-2.7-6-6-6zM4 9h4M16 9h4M9 22h6"/></svg>
1924
+ </span>
1925
+ <span>智能体对话</span>
1926
+ <span id="console-status-badge" class="console-status-tag">
1927
+ <span class="pulse-dot" style="width:5px;height:5px;"></span>
1928
+ 已连接
1929
+ </span>
1930
+ </div>
1931
+ <div class="console-actions">
1932
+ <button id="console-clear-btn" class="console-btn-icon" title="清空对话记录">
1933
+ <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>
1934
+ </button>
1935
+ <button id="chat-collapse-btn" class="console-btn-icon" title="收起/展开对话侧栏" aria-label="收起/展开对话侧栏">
1936
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transition:transform 0.2s ease;"><polyline points="15 18 9 12 15 6"/></svg>
1937
+ </button>
1938
+ </div>
1939
+ </div>
1940
+
1941
+ <!-- 折叠时竖条提示区,点击可直接展开 -->
1942
+ <div class="console-collapsed-bar" id="console-collapsed-bar" title="点击展开智能体对话">
1943
+ <span class="agent-avatar" style="width:24px;height:24px;">
1944
+ <svg viewBox="0 0 24 24"><path d="M12 2v20M12 2c-3.3 0-6 2.7-6 6v3c0 3.3 2.7 6 6 6s6-2.7 6-6V8c0-3.3-2.7-6-6-6zM4 9h4M16 9h4M9 22h6"/></svg>
1945
+ </span>
1946
+ <span class="console-vertical-label">AI 对话</span>
1947
+ </div>
1948
+
1949
+ <div id="console-log" class="console-log">
1950
+ <div class="log-entry sys">
1951
+ <div class="log-sys">
1952
+ 💡 <strong>对话已就绪</strong>:与 PsyClaw 智能体安全连接。支持 <code>/init</code>、<code>/plan</code>、<code>/grill</code>、<code>/crosscheck</code>(AI 核验)等指令。
1953
+ </div>
1954
+ </div>
1955
+ </div>
1956
+
1957
+ <div class="console-quick-chips">
1958
+ <span class="chip" data-cmd="/plan status">
1959
+ <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>
1960
+ /plan status
1961
+ </span>
1962
+ <span class="chip" data-cmd="/crosscheck list">
1963
+ <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/></svg>
1964
+ /crosscheck
1965
+ </span>
1966
+ <span class="chip" data-cmd="/grill">
1967
+ <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>
1968
+ /grill 压力追问
1969
+ </span>
1970
+ <span class="chip" data-cmd="/review">
1971
+ <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>
1972
+ /review
1973
+ </span>
1974
+ <span class="chip" data-cmd="/agents">
1975
+ <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>
1976
+ /agents
1977
+ </span>
1978
+ </div>
1979
+
1980
+ <div class="console-input-wrap">
1981
+ <div class="console-input-container">
1982
+ <div class="console-input-box">
1983
+ <textarea id="console-input" class="console-textarea" placeholder="向智能体提问或输入指令(Enter 发送)…" rows="1"></textarea>
1984
+ <button id="console-send-btn" class="console-send-btn" title="发送消息 (Enter)">
1985
+ <svg width="14" height="14" 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>
1986
+ </button>
1987
+ </div>
1988
+ <div class="console-input-footer">
1989
+ <span>支持 Markdown 与学术指令</span>
1990
+ <span>PsyClaw 本地隔离环境</span>
1991
+ </div>
1992
+ </div>
1993
+ </div>
1994
+ </div>
1995
+
1783
1996
  <aside id="file-tree" class="tree">
1784
1997
  <div class="empty">读取项目文档中...</div>
1785
1998
  </aside>
@@ -1795,6 +2008,9 @@
1795
2008
  <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><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>
1796
2009
  复制
1797
2010
  </button>
2011
+ <button id="viewer-close-btn" class="console-btn-icon" title="关闭文件,展开对话视图" style="padding:4px;color:var(--text-muted);">
2012
+ <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>
2013
+ </button>
1798
2014
  </div>
1799
2015
  </div>
1800
2016
  <div id="viewer-body" class="viewer-body empty">
@@ -1979,80 +2195,6 @@
1979
2195
  </table>
1980
2196
  </div>
1981
2197
  </section>
1982
-
1983
- <section id="view-chat" class="view">
1984
- <div class="page-head" style="margin-bottom: 12px;">
1985
- <div>
1986
- <h1>交互对话</h1>
1987
- <p>提问将接入当前 PsyClaw 会话;助手回复经 SSE 流式同步,支持学术指令与「唤醒选项」决策。</p>
1988
- </div>
1989
- </div>
1990
- <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);">
1991
- <div id="console-drawer" class="console-drawer">
1992
- <div class="console-header">
1993
- <div class="console-title">
1994
- <span class="agent-avatar" style="width:24px;height:24px;font-size:12px">ψ</span>
1995
- <span>PsyClaw Research Assistant</span>
1996
- <span id="console-status-badge" class="console-status-tag">
1997
- <span class="pulse-dot" style="width:5px;height:5px;"></span>
1998
- 已连接
1999
- </span>
2000
- </div>
2001
- <div class="console-actions">
2002
- <button id="console-clear-btn" class="console-btn-icon" title="清空对话记录">
2003
- <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>
2004
- </button>
2005
- </div>
2006
- </div>
2007
-
2008
- <div id="console-log" class="console-log">
2009
- <div class="log-entry sys">
2010
- <div class="log-sys">
2011
- 💡 <strong>对话已就绪</strong>:与 PsyClaw 智能体安全连接。支持 <code>/init</code>、<code>/plan</code>、<code>/grill</code>、<code>/crosscheck</code>(AI 核验)等指令。
2012
- </div>
2013
- </div>
2014
- </div>
2015
-
2016
- <div class="console-quick-chips">
2017
- <span class="chip" data-cmd="/plan status">
2018
- <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>
2019
- /plan status
2020
- </span>
2021
- <span class="chip" data-cmd="/crosscheck list">
2022
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/></svg>
2023
- /crosscheck list
2024
- </span>
2025
- <span class="chip" data-cmd="/grill">
2026
- <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>
2027
- /grill 压力追问
2028
- </span>
2029
- <span class="chip" data-cmd="/review">
2030
- <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>
2031
- /review 评审
2032
- </span>
2033
- <span class="chip" data-cmd="/agents">
2034
- <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>
2035
- /agents 角色
2036
- </span>
2037
- </div>
2038
-
2039
- <div class="console-input-wrap">
2040
- <div class="console-input-container">
2041
- <div class="console-input-box">
2042
- <textarea id="console-input" class="console-textarea" placeholder="输入研究问题或指令(Enter 发送,Shift+Enter 换行)…" rows="1"></textarea>
2043
- <button id="console-send-btn" class="console-send-btn" title="发送消息 (Enter)">
2044
- <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>
2045
- </button>
2046
- </div>
2047
- <div class="console-input-footer">
2048
- <span>支持 Markdown 与学术指令</span>
2049
- <span>PsyClaw 本地隔离环境</span>
2050
- </div>
2051
- </div>
2052
- </div>
2053
- </div>
2054
- </div>
2055
- </section>
2056
2198
  </main>
2057
2199
  </div>
2058
2200
  </div>
@@ -2141,6 +2283,12 @@ async function json(url, options) {
2141
2283
  }
2142
2284
 
2143
2285
  function setView(view) {
2286
+ if (view === "chat") {
2287
+ // 对话框直接位于第一个界面(工作台),自动切换到项目视图并展开对话
2288
+ setView("project");
2289
+ expandChat();
2290
+ return;
2291
+ }
2144
2292
  state.view = view;
2145
2293
  if (location.hash.replace(/^#/, "") !== view) {
2146
2294
  history.replaceState(null, "", `#${view}`);
@@ -2155,7 +2303,6 @@ function setView(view) {
2155
2303
  if (view === "provider") loadProvider();
2156
2304
  if (view === "checklist") loadChecklist();
2157
2305
  if (view === "help") loadHelp();
2158
- if (view === "chat") queueMicrotask(() => $("console-input")?.focus());
2159
2306
  }
2160
2307
 
2161
2308
  async function loadHelp() {
@@ -2246,15 +2393,33 @@ document.querySelectorAll(".nav button[data-view]").forEach(button => {
2246
2393
  button.addEventListener("click", () => setView(button.dataset.view));
2247
2394
  });
2248
2395
 
2396
+ function renderFileJumpPill(path) {
2397
+ const cleanPath = esc(path);
2398
+ const fileName = esc(path.split("/").at(-1));
2399
+ return `<button type="button" class="file-jump-pill" data-jump-file="${cleanPath}" title="点击在工作台查看 ${cleanPath}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg><span>${fileName}</span></button>`;
2400
+ }
2401
+
2249
2402
  function inlineMarkdown(text) {
2250
2403
  let value = esc(text);
2404
+ // 解析反引号中的文件路径,如 `notes/goal.md`、`paper/draft.md`
2405
+ value = value.replace(/`((?:notes|paper|docs|outputs|analysis|\.psyclaw)\/[a-zA-Z0-9_\-./]+|\b[a-zA-Z0-9_\-]+\.(?:md|json|jsonl|txt|py|r|tex)\b)`/g, (_, path) => renderFileJumpPill(path));
2251
2406
  value = value.replace(/`([^`]+)`/g, "<code>$1</code>")
2252
2407
  .replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
2253
2408
  .replace(/\*([^*]+)\*/g, "<em>$1</em>");
2254
- value = value.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, target) =>
2255
- /^https?:\/\//i.test(target)
2256
- ? `<a href="${esc(target)}" target="_blank" rel="noreferrer" style="color:var(--brand-accent);text-decoration:none;border-bottom:1px dashed currentColor">${label}</a>`
2257
- : label
2409
+ // 解析 Markdown 链接,区分网页链接与本地文件相对路径
2410
+ value = value.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, target) => {
2411
+ if (/^https?:\/\//i.test(target)) {
2412
+ return `<a href="${esc(target)}" target="_blank" rel="noreferrer" style="color:var(--brand-accent);text-decoration:none;border-bottom:1px dashed currentColor">${label}</a>`;
2413
+ }
2414
+ // 本地文件相对链接
2415
+ if (/\.(md|json|jsonl|txt|py|r|tex)$/i.test(target) || /^(notes|paper|docs|outputs|analysis|\.psyclaw)\//.test(target)) {
2416
+ return renderFileJumpPill(target.replace(/^\.\//, ""));
2417
+ }
2418
+ return label;
2419
+ });
2420
+ // 识别未被标签包裹的独立文件相对路径
2421
+ value = value.replace(/(^|[\s((])((?:notes|paper|docs|outputs|analysis|\.psyclaw)\/[a-zA-Z0-9_\-./]+\.[a-zA-Z0-9]+)(?=[)\s,。!?,!?)]|$)/g,
2422
+ (_, prefix, path) => `${prefix}${renderFileJumpPill(path)}`
2258
2423
  );
2259
2424
  return value;
2260
2425
  }
@@ -2391,8 +2556,24 @@ function selectTree(button) {
2391
2556
  document.querySelectorAll(".tree-item").forEach(item => item.classList.toggle("active", item === button));
2392
2557
  }
2393
2558
 
2559
+ function closeFile() {
2560
+ const ws = $("project-workspace");
2561
+ if (ws) ws.classList.add("no-file-open");
2562
+ selectTree(null);
2563
+ state.currentContent = "";
2564
+ $("viewer-path").textContent = "选择左侧文件";
2565
+ $("viewer-kind").textContent = "未打开";
2566
+ $("viewer-body").className = "viewer-body empty";
2567
+ $("viewer-body").textContent = "请在文件树或对话中选择文件进行查看";
2568
+ }
2569
+
2394
2570
  async function openFile(path, button) {
2395
- selectTree(button);
2571
+ const ws = $("project-workspace");
2572
+ if (ws) {
2573
+ ws.classList.remove("no-file-open");
2574
+ }
2575
+ const btn = button || document.querySelector(`[data-file="${path}"]`);
2576
+ selectTree(btn);
2396
2577
  $("viewer-path").textContent = path;
2397
2578
  $("viewer-kind").textContent = "读取中";
2398
2579
  $("viewer-body").className = "viewer-body empty";
@@ -2428,12 +2609,16 @@ $("viewer-copy-btn").addEventListener("click", async () => {
2428
2609
  }
2429
2610
  });
2430
2611
 
2612
+ // 关闭文件预览按钮,恢复对话框铺满状态
2613
+ $("viewer-close-btn")?.addEventListener("click", () => {
2614
+ closeFile();
2615
+ });
2616
+
2431
2617
  async function loadProject() {
2432
2618
  const files = await json("/api/project-files");
2433
2619
  state.files = files.files || [];
2434
2620
  renderTree();
2435
- const goal = document.querySelector('[data-file="notes/goal.md"]') || document.querySelector("[data-file]");
2436
- if (goal) goal.click();
2621
+ // 默认不自动打开文件,让对话框铺满工作台主区域;用户点击文件树或对话中文件链接时再展示
2437
2622
  }
2438
2623
 
2439
2624
  async function loadEcosystem() {
@@ -2745,8 +2930,25 @@ const streamBubbles = new Map();
2745
2930
  let lastLocalUserText = "";
2746
2931
  let wakeState = null;
2747
2932
 
2933
+ function expandChat() {
2934
+ const ws = $("project-workspace");
2935
+ if (ws && ws.classList.contains("chat-collapsed")) {
2936
+ ws.classList.remove("chat-collapsed");
2937
+ localStorage.setItem("psyclaw_chat_collapsed", "false");
2938
+ }
2939
+ }
2940
+
2941
+ function collapseChat() {
2942
+ const ws = $("project-workspace");
2943
+ if (ws && !ws.classList.contains("chat-collapsed")) {
2944
+ ws.classList.add("chat-collapsed");
2945
+ localStorage.setItem("psyclaw_chat_collapsed", "true");
2946
+ }
2947
+ }
2948
+
2748
2949
  function openConsole() {
2749
- setView("chat");
2950
+ setView("project");
2951
+ expandChat();
2750
2952
  queueMicrotask(() => consoleInput?.focus());
2751
2953
  }
2752
2954
 
@@ -2755,6 +2957,8 @@ function openConsoleWithMessage(text) {
2755
2957
  appendLog("sys", text);
2756
2958
  }
2757
2959
 
2960
+ const PSYCLAW_AVATAR_SVG = `<svg viewBox="0 0 24 24"><path d="M12 2v20M12 2c-3.3 0-6 2.7-6 6v3c0 3.3 2.7 6 6 6s6-2.7 6-6V8c0-3.3-2.7-6-6-6zM4 9h4M16 9h4M9 22h6"/></svg>`;
2961
+
2758
2962
  function appendLog(role, text) {
2759
2963
  const entry = document.createElement("div");
2760
2964
  entry.className = `log-entry ${role}`;
@@ -2766,7 +2970,7 @@ function appendLog(role, text) {
2766
2970
  `;
2767
2971
  } else if (role === "agent") {
2768
2972
  entry.innerHTML = `
2769
- <div class="agent-avatar">ψ</div>
2973
+ <div class="agent-avatar">${PSYCLAW_AVATAR_SVG}</div>
2770
2974
  <div class="agent-content-wrap">
2771
2975
  <div class="agent-meta">
2772
2976
  <span>PsyClaw Assistant</span>
@@ -2790,7 +2994,7 @@ function ensureStreamBubble(messageId) {
2790
2994
  entry.className = "log-entry agent";
2791
2995
  entry.dataset.messageId = messageId;
2792
2996
  entry.innerHTML = `
2793
- <div class="agent-avatar">ψ</div>
2997
+ <div class="agent-avatar">${PSYCLAW_AVATAR_SVG}</div>
2794
2998
  <div class="agent-content-wrap">
2795
2999
  <div class="agent-meta">
2796
3000
  <span>PsyClaw Assistant</span>
@@ -3081,14 +3285,28 @@ document.querySelectorAll(".chip").forEach(chip => {
3081
3285
  });
3082
3286
  });
3083
3287
 
3084
- /* --- 侧边栏折叠与展开交互 --- */
3288
+ /* --- 侧边栏与工作台对话框折叠交互 --- */
3085
3289
  const layoutEl = document.querySelector(".layout");
3086
3290
  const navToggleBtn = $("nav-toggle-btn");
3087
-
3088
- function initNavCollapse() {
3089
- const saved = localStorage.getItem("psyclaw_nav_collapsed");
3090
- if (saved === "true") {
3291
+ const chatCollapseBtn = $("chat-collapse-btn");
3292
+ const consoleCollapsedBar = $("console-collapsed-bar");
3293
+ const workspaceEl = $("project-workspace");
3294
+
3295
+ function initWorkbenchCollapse() {
3296
+ const savedNav = localStorage.getItem("psyclaw_nav_collapsed");
3297
+ // 平时默认折叠成图标;除非用户主动展开(存为 "false")
3298
+ if (savedNav !== "false") {
3091
3299
  layoutEl?.classList.add("nav-collapsed");
3300
+ } else {
3301
+ layoutEl?.classList.remove("nav-collapsed");
3302
+ }
3303
+
3304
+ // 对话框折叠态记忆
3305
+ const savedChat = localStorage.getItem("psyclaw_chat_collapsed");
3306
+ if (savedChat === "true") {
3307
+ workspaceEl?.classList.add("chat-collapsed");
3308
+ } else {
3309
+ workspaceEl?.classList.remove("chat-collapsed");
3092
3310
  }
3093
3311
  }
3094
3312
 
@@ -3098,7 +3316,29 @@ navToggleBtn?.addEventListener("click", () => {
3098
3316
  localStorage.setItem("psyclaw_nav_collapsed", isCollapsed ? "true" : "false");
3099
3317
  });
3100
3318
 
3101
- initNavCollapse();
3319
+ chatCollapseBtn?.addEventListener("click", () => {
3320
+ if (!workspaceEl) return;
3321
+ const isCollapsed = workspaceEl.classList.toggle("chat-collapsed");
3322
+ localStorage.setItem("psyclaw_chat_collapsed", isCollapsed ? "true" : "false");
3323
+ });
3324
+
3325
+ consoleCollapsedBar?.addEventListener("click", () => {
3326
+ expandChat();
3327
+ queueMicrotask(() => consoleInput?.focus());
3328
+ });
3329
+
3330
+ // 全局监听对话框中的文件跳转胶囊 (.file-jump-pill) 点击
3331
+ document.addEventListener("click", (e) => {
3332
+ const pill = e.target.closest(".file-jump-pill");
3333
+ if (!pill) return;
3334
+ const targetPath = pill.dataset.jumpFile;
3335
+ if (targetPath) {
3336
+ e.preventDefault();
3337
+ openFile(targetPath);
3338
+ }
3339
+ });
3340
+
3341
+ initWorkbenchCollapse();
3102
3342
 
3103
3343
  /* --- 顶栏快捷命令 Quick Actions --- */
3104
3344
  const initModal = $("init-modal");