wezard 1.4.0 → 1.4.2

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 (70) hide show
  1. package/CLAUDE.md +12 -2
  2. package/README.md +154 -58
  3. package/cli/wezard.sh +6 -3
  4. package/dist/cli/init.js +1 -1
  5. package/dist/cli/init.js.map +1 -1
  6. package/dist/daemon/approval.js +0 -6
  7. package/dist/daemon/approval.js.map +1 -1
  8. package/dist/daemon/cc-bridge.js +1 -22
  9. package/dist/daemon/cc-bridge.js.map +1 -1
  10. package/dist/daemon/cfg-sync.js +3 -6
  11. package/dist/daemon/cfg-sync.js.map +1 -1
  12. package/dist/daemon/chat-name.js +6 -2
  13. package/dist/daemon/chat-name.js.map +1 -1
  14. package/dist/daemon/config-api.js +0 -1
  15. package/dist/daemon/config-api.js.map +1 -1
  16. package/dist/daemon/detail.js +53 -9
  17. package/dist/daemon/detail.js.map +1 -1
  18. package/dist/daemon/graph.js +2 -6
  19. package/dist/daemon/graph.js.map +1 -1
  20. package/dist/daemon/inbound.js +4 -4
  21. package/dist/daemon/inbound.js.map +1 -1
  22. package/dist/daemon/index.js +119 -28
  23. package/dist/daemon/index.js.map +1 -1
  24. package/dist/daemon/jobs.js +17 -35
  25. package/dist/daemon/jobs.js.map +1 -1
  26. package/dist/daemon/mirror-bridge.js +262 -197
  27. package/dist/daemon/mirror-bridge.js.map +1 -1
  28. package/dist/daemon/mirror-store.js +2 -33
  29. package/dist/daemon/mirror-store.js.map +1 -1
  30. package/dist/daemon/quota.js +1 -1
  31. package/dist/daemon/quota.js.map +1 -1
  32. package/dist/daemon/session-cache.js +0 -1
  33. package/dist/daemon/session-cache.js.map +1 -1
  34. package/dist/daemon/session-scan.js +4 -22
  35. package/dist/daemon/session-scan.js.map +1 -1
  36. package/dist/daemon/sessions.js +2 -33
  37. package/dist/daemon/sessions.js.map +1 -1
  38. package/dist/daemon/spawn-tmux.js +2 -10
  39. package/dist/daemon/spawn-tmux.js.map +1 -1
  40. package/dist/daemon/subagent-tail.js +2 -2
  41. package/dist/daemon/subagent-tail.js.map +1 -1
  42. package/dist/daemon/tasks.js +1 -1
  43. package/dist/daemon/tasks.js.map +1 -1
  44. package/dist/daemon/wizard.js +9 -30
  45. package/dist/daemon/wizard.js.map +1 -1
  46. package/dist/mcp/server.js +32 -55
  47. package/dist/mcp/server.js.map +1 -1
  48. package/dist/shared/chat-http.js +25 -5
  49. package/dist/shared/chat-http.js.map +1 -1
  50. package/dist/shared/chat-render.js +16 -1
  51. package/dist/shared/chat-render.js.map +1 -1
  52. package/dist/shared/cli-backends.js +0 -11
  53. package/dist/shared/cli-backends.js.map +1 -1
  54. package/dist/shared/detail-render.js +5 -4
  55. package/dist/shared/detail-render.js.map +1 -1
  56. package/dist/shared/detail-store.js +12 -5
  57. package/dist/shared/detail-store.js.map +1 -1
  58. package/dist/shared/exec-path.js +21 -0
  59. package/dist/shared/exec-path.js.map +1 -0
  60. package/dist/shared/json-map-store.js +41 -0
  61. package/dist/shared/json-map-store.js.map +1 -0
  62. package/dist/shared/std.js +26 -0
  63. package/dist/shared/std.js.map +1 -0
  64. package/dist/shared/world.js +191 -0
  65. package/dist/shared/world.js.map +1 -0
  66. package/dist/svr/index.js +1 -1
  67. package/dist/svr/index.js.map +1 -1
  68. package/package.json +1 -1
  69. package/web/chat.css +267 -0
  70. package/web/chat.js +454 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wezard",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "Bridge Claude Code and WeCom: PreToolUse approval cards + bidirectional tmux session mirror with image paste",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/web/chat.css CHANGED
@@ -213,3 +213,270 @@ body { overflow: hidden; overscroll-behavior: none }
213
213
  .statusbar { gap: 10px; padding: 7px 12px calc(7px + env(safe-area-inset-bottom)) }
214
214
  .sb-io, .statusbar .model { display: none }
215
215
  }
216
+
217
+ /* UA 的 [hidden] 规则和 `.gbar{display:flex}` 这类类选择器同权重, 而作者样式
218
+ 胜出 —— 于是 el.hidden=true 的元素照旧显示 (空的 gbar 会剩一条带边框的窄带)。
219
+ 一条 !important 把 hidden 的语义钉死, 三块视图容器的显隐都靠它。 */
220
+ [hidden] { display: none !important }
221
+
222
+ /* ══ 视图切换 ═══════════════════════════════════════════════════════ */
223
+ /* 三栏并列在顶栏右端。会话 key (.sub) 在窄屏下先让位 —— 它是调试信息, 而切换
224
+ 视图是主操作。 */
225
+ .topbar .views { margin-left: auto; display: flex; gap: 2px; flex: none }
226
+ .topbar .vb {
227
+ font: inherit; font-size: 12px; color: #57606a; background: transparent;
228
+ border: 1px solid transparent; border-radius: 7px; padding: 3px 11px; cursor: pointer;
229
+ }
230
+ .topbar .vb:hover { background: #f6f8fa; color: #1f2328 }
231
+ .topbar .vb.on { background: #0969da; border-color: #0969da; color: #fff; font-weight: 600 }
232
+ .topbar .sub { min-width: 0 }
233
+
234
+ /* 关系/日程栏不需要那条 288px 的会话列表占着半张桌子 —— 图要横向铺开。 */
235
+ .pane { flex: 1; min-height: 0; display: flex; flex-direction: column; background: #fafbfc }
236
+ .app.wide .side { width: 216px }
237
+
238
+ /* ── 侧栏: wizard 身份 ─────────────────────────────────────────────── */
239
+ /* 名字之外还要有职责与出身, 否则一列 `#tag` 说不出谁是谁。两行都单行省略,
240
+ 会话行的高度必须可预期 —— 侧栏是要能一眼扫完的。 */
241
+ .tag-job {
242
+ font-size: 11.5px; color: #0550ae; margin-top: 2px;
243
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
244
+ }
245
+ .tag-kin { margin-top: 2px }
246
+ .tag-kin .kin {
247
+ font-size: 10.5px; color: #6639ba; background: #8250df12; border-radius: 4px;
248
+ padding: 0 5px; font-family: ui-monospace, Menlo, monospace;
249
+ display: inline-block; max-width: 100%; overflow: hidden;
250
+ text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom;
251
+ }
252
+
253
+ /* ══ 关系图 ═════════════════════════════════════════════════════════ */
254
+ .wtools {
255
+ flex: none; display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
256
+ padding: 8px 20px; background: #fff; border-bottom: 1px solid #d0d7de;
257
+ font-size: 11.5px; color: #57606a;
258
+ }
259
+ .wlegend { display: flex; gap: 6px; flex-wrap: wrap }
260
+ /* 图例同时是开关 —— 边一多就得能关掉几种; 把"图例"和"过滤器"做成两样东西
261
+ 只会让人在两处之间对照颜色。 */
262
+ .wtools .chip {
263
+ display: flex; align-items: center; gap: 5px; font: inherit; cursor: pointer;
264
+ background: #fff; border: 1px solid #d0d7de; border-radius: 13px; padding: 2px 10px;
265
+ color: #8c959f;
266
+ }
267
+ .wtools .chip i { width: 14px; height: 0; border-top: 2px solid var(--c); opacity: .35 }
268
+ .wtools .chip b { font-variant-numeric: tabular-nums; font-weight: 700 }
269
+ .wtools .chip.on { color: #1f2328; border-color: var(--c) }
270
+ .wtools .chip.on i { opacity: 1 }
271
+ .wtools .chip.clear, .wtools .chip.only { border-color: #d0d7de; color: #57606a }
272
+ .wtools .chip.only.on { border-color: #0969da; color: #0550ae; background: #ddf4ff }
273
+ .wtools .wstat { margin-left: auto; color: #8c959f; font-variant-numeric: tabular-nums }
274
+ .wtools .wstat b { color: #0969da }
275
+ .wtools .warn { color: #9a6700 }
276
+ .wtools .hint { margin-left: 10px; color: #b1bac4 }
277
+
278
+ .wscroll { flex: 1; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch }
279
+ .wmap { position: relative; padding: 18px 20px 28px; min-width: min-content }
280
+ /* 有关系的节点带一道左侧色条 —— 76 个会话里哪几个真的在协作, 不点开也看得见。 */
281
+ .wnode.rel::before {
282
+ content: ""; position: absolute; left: 1px; top: 8px; bottom: 8px;
283
+ width: 2px; border-radius: 1px; background: #0969da66;
284
+ }
285
+ /* 连线层铺满整张图并且不吃事件 —— 节点的点击/双击必须照常穿过去。 */
286
+ .wedges { position: absolute; inset: 0; pointer-events: none; overflow: visible }
287
+ .wgrid {
288
+ position: relative; display: grid; gap: 16px;
289
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
290
+ align-items: start;
291
+ }
292
+
293
+ .wchat { background: #fff; border: 1px solid #d0d7de; border-radius: 12px; overflow: hidden }
294
+ /* 当前聊天是读图的锚点, 给它一道明确的边 —— 其余的群一律等价, 不再分轻重。 */
295
+ .wchat.self { border-color: #0969da66; box-shadow: 0 0 0 3px #0969da10 }
296
+ .wch {
297
+ display: flex; align-items: baseline; gap: 8px; padding: 9px 13px;
298
+ border-bottom: 1px solid #eaeef2; background: #f6f8fa;
299
+ }
300
+ .wchat.self .wch { background: #f0f6ff }
301
+ .wch .nm {
302
+ font-size: 13px; font-weight: 700; min-width: 0; overflow: hidden;
303
+ text-overflow: ellipsis; white-space: nowrap;
304
+ }
305
+ .wch .here {
306
+ font-size: 10px; color: #0969da; background: #0969da14; border-radius: 4px; padding: 1px 5px;
307
+ }
308
+ .wch .ct {
309
+ margin-left: auto; font-size: 11px; color: #8c959f; flex: none;
310
+ font-family: ui-monospace, Menlo, monospace;
311
+ }
312
+ .wch .ct em { color: #1a7f37; font-style: normal; font-weight: 700 }
313
+ /* 左内边距是同卡片内连线的车道 —— 一条 `#a → #b` 的派活边从这里绕过去, 不必
314
+ 拐出卡片 (拐出去就会被滚动容器裁掉)。 */
315
+ .wrows { padding: 7px 10px 10px 22px; display: flex; flex-direction: column; gap: 3px }
316
+
317
+ .wnode {
318
+ position: relative; display: flex; gap: 8px; align-items: flex-start;
319
+ padding: 6px 8px; border-radius: 8px; cursor: pointer;
320
+ border: 1px solid transparent; transition: opacity .15s, background .12s;
321
+ }
322
+ .wnode:hover { background: #f6f8fa }
323
+ .wnode.self { background: #fffbe8 }
324
+ .wnode.sel { background: #eef4fc; border-color: #0969da55 }
325
+ /* 聚焦时无关节点压暗而不是移除 —— 位置不动, 连点几个节点版面也不跳。 */
326
+ .wnode.dim { opacity: .3 }
327
+ .wnode.cold .wav { filter: grayscale(1); opacity: .55 }
328
+ /* 缩进本身就是家谱; 这道折线只是把"缩给谁看"指实。 */
329
+ .wnode .lin {
330
+ position: absolute; left: -9px; top: 0; bottom: 50%; width: 9px;
331
+ border-left: 1.5px solid #d8cdf0; border-bottom: 1.5px solid #d8cdf0;
332
+ border-bottom-left-radius: 6px;
333
+ }
334
+ .wav {
335
+ position: relative; width: 26px; height: 26px; flex: none; border-radius: 8px;
336
+ background: #f1f3f6; border: 1px solid #eaeef2;
337
+ display: flex; align-items: center; justify-content: center; font-size: 14px;
338
+ }
339
+ .wav .live {
340
+ position: absolute; right: -3px; bottom: -3px; width: 9px; height: 9px;
341
+ border-radius: 50%; background: #1a7f37; border: 2px solid #fff;
342
+ animation: pulse 1.4s infinite;
343
+ }
344
+ .wbody { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px }
345
+ .wl1 { display: flex; align-items: baseline; gap: 6px; min-width: 0 }
346
+ .wname {
347
+ font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden;
348
+ text-overflow: ellipsis; white-space: nowrap;
349
+ }
350
+ .wnode.run .wname { color: #1a7f37 }
351
+ .wtag {
352
+ flex: none; font-size: 10.5px; color: #57606a; background: #f1f3f6;
353
+ border-radius: 4px; padding: 0 5px; font-family: ui-monospace, Menlo, monospace;
354
+ }
355
+ .wtag.def { color: #8c959f }
356
+ .wih { flex: none; font-size: 11px; color: #6639ba }
357
+ .wts {
358
+ margin-left: auto; flex: none; font-size: 10.5px; color: #8c959f;
359
+ font-family: ui-monospace, Menlo, monospace;
360
+ }
361
+ .wjob { font-size: 11.5px; color: #0550ae; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
362
+ .wprev {
363
+ font-size: 11.5px; color: #656d76; overflow: hidden; line-height: 1.4;
364
+ display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
365
+ }
366
+ .wmeta {
367
+ font-size: 10.5px; color: #8c959f; font-family: ui-monospace, Menlo, monospace;
368
+ display: flex; gap: 4px; flex-wrap: wrap; margin-top: 1px;
369
+ }
370
+ .wmeta .sep { opacity: .45 }
371
+
372
+ /* ══ 日程 ═══════════════════════════════════════════════════════════ */
373
+ .plan-in { flex: 1; min-height: 0; overflow-y: auto; padding: 18px 20px 28px }
374
+ .psec { max-width: 900px; margin: 0 auto 22px }
375
+ .psec h3 {
376
+ display: flex; align-items: baseline; gap: 8px; font-size: 13px; margin: 0 0 10px;
377
+ padding-bottom: 7px; border-bottom: 1px solid #d0d7de;
378
+ }
379
+ .psec h3 span {
380
+ font-size: 11px; color: #8c959f; font-weight: 400;
381
+ font-family: ui-monospace, Menlo, monospace;
382
+ }
383
+ .pempty { color: #8c959f; font-size: 12px; padding: 18px 0; text-align: center }
384
+
385
+ /* 未来 12 小时的刻度条 —— 「今晚还有几枪要响」比一张日期列表更该先看见。 */
386
+ .strip {
387
+ background: #fff; border: 1px solid #d0d7de; border-radius: 10px;
388
+ padding: 10px 14px 9px; margin-bottom: 12px;
389
+ }
390
+ .strip .axis {
391
+ position: relative; height: 13px; font-size: 10px; color: #8c959f;
392
+ font-family: ui-monospace, Menlo, monospace;
393
+ }
394
+ .strip .tk { position: absolute; transform: translateX(-50%); white-space: nowrap }
395
+ .strip .tk:first-child { transform: none }
396
+ .strip .rail {
397
+ position: relative; height: 8px; border-radius: 4px; background: #eaeef2; margin: 3px 0 7px;
398
+ }
399
+ .strip .pin {
400
+ position: absolute; top: -3px; width: 8px; height: 14px; margin-left: -4px;
401
+ border-radius: 3px; background: #9a6700; box-shadow: 0 0 0 2px #fff;
402
+ }
403
+ .strip .cap { font-size: 11px; color: #8c959f }
404
+
405
+ .prow {
406
+ display: flex; gap: 14px; background: #fff; border: 1px solid #d0d7de;
407
+ border-radius: 10px; padding: 10px 14px; margin-bottom: 7px;
408
+ }
409
+ .prow .pl { flex: none; width: 152px; border-right: 1px dashed #eaeef2; padding-right: 12px }
410
+ .pwhen { font-size: 11.5px; color: #9a6700; font-weight: 600 }
411
+ .pnext {
412
+ display: flex; align-items: baseline; gap: 6px; margin-top: 3px;
413
+ font-family: ui-monospace, Menlo, monospace;
414
+ }
415
+ .pnext b { font-size: 12.5px; font-variant-numeric: tabular-nums }
416
+ .pnext span { font-size: 10.5px; color: #8c959f }
417
+ .prow .pr { min-width: 0; flex: 1 }
418
+ .ph { display: flex; align-items: center; gap: 7px; flex-wrap: wrap }
419
+ .ph .note { font-size: 11px; color: #57606a }
420
+ .ph .pid {
421
+ margin-left: auto; font-size: 10px; color: #b1bac4;
422
+ font-family: ui-monospace, Menlo, monospace;
423
+ }
424
+ .ptext { font-size: 12px; color: #1f2328; margin-top: 4px; line-height: 1.5; word-break: break-word }
425
+ .pfoot { font-size: 10.5px; color: #8c959f; margin-top: 4px }
426
+
427
+ /* wizard 徽标 —— 日程/工单里凡是提到一个 wizard 都用它, 同聊天的可点进线程。 */
428
+ .wchip {
429
+ display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px;
430
+ background: #f1f3f6; border: 1px solid #eaeef2; border-radius: 12px; padding: 1px 8px;
431
+ max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
432
+ }
433
+ .wchip.go { cursor: pointer; border-color: #0969da33; color: #0550ae }
434
+ .wchip.go:hover { background: #ddf4ff; border-color: #0969da }
435
+
436
+ .jrow { background: #fff; border: 1px solid #d0d7de; border-radius: 10px; padding: 10px 14px; margin-bottom: 7px }
437
+ .jrow.open { border-color: #1a7f3755; box-shadow: 0 0 0 3px #1a7f370d }
438
+ .jh { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap }
439
+ .jid {
440
+ font-size: 10.5px; color: #57606a; background: #f1f3f6; border-radius: 4px;
441
+ padding: 0 6px; font-family: ui-monospace, Menlo, monospace;
442
+ }
443
+ .jt { font-size: 13px; font-weight: 600; min-width: 0 }
444
+ .jst { font-size: 10.5px; color: #8c959f }
445
+ .jrow.open .jst { color: #1a7f37; font-weight: 700 }
446
+ .jts {
447
+ margin-left: auto; font-size: 10.5px; color: #8c959f;
448
+ font-family: ui-monospace, Menlo, monospace;
449
+ }
450
+ .jm { display: flex; flex-direction: column; gap: 3px; margin-top: 7px }
451
+ .jmm { display: flex; align-items: center; gap: 6px; min-width: 0 }
452
+ .jmm em {
453
+ font-style: normal; font-size: 11.5px; color: #656d76; min-width: 0;
454
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
455
+ }
456
+ .jmm .tmp {
457
+ font-style: normal; font-size: 9.5px; color: #9a6700; background: #d4a72c22;
458
+ border-radius: 3px; padding: 0 4px;
459
+ }
460
+ .jmm.none { font-size: 11.5px; color: #b1bac4 }
461
+ .jsum {
462
+ font-size: 12px; color: #1f2328; margin-top: 8px; padding-top: 8px;
463
+ border-top: 1px dashed #eaeef2; line-height: 1.5; white-space: pre-wrap;
464
+ }
465
+
466
+ @media (max-width: 760px) {
467
+ .app.wide .side { display: none }
468
+ .topbar .sub { display: none }
469
+ .topbar .vb { padding: 3px 8px }
470
+ .wmap { padding: 12px }
471
+ .wgrid { grid-template-columns: 1fr }
472
+ .plan-in { padding: 12px }
473
+ .prow { flex-direction: column; gap: 6px }
474
+ .prow .pl { width: auto; border-right: 0; border-bottom: 1px dashed #eaeef2; padding: 0 0 6px }
475
+ .pnext { margin-top: 1px }
476
+ }
477
+
478
+ /* 相关性筛掉的那些 —— 说一声它们还在, 但不占图的位置 (见 shared/world 的说明)。 */
479
+ .wmore {
480
+ padding: 5px 13px 9px; font-size: 10.5px; color: #b1bac4;
481
+ border-top: 1px dashed #eaeef2; margin-top: 2px;
482
+ }