nexus-agentd 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  export declare const icons: {
2
2
  overview: string;
3
3
  runs: string;
4
+ artifacts: string;
4
5
  agents: string;
5
6
  workspaces: string;
6
7
  keys: string;
@@ -2,6 +2,7 @@ const base = (paths) => `<svg viewBox="0 0 24 24" aria-hidden="true" focusable="
2
2
  export const icons = {
3
3
  overview: base('<rect x="3" y="3" width="7" height="9" rx="1.5"/><rect x="14" y="3" width="7" height="5" rx="1.5"/><rect x="14" y="12" width="7" height="9" rx="1.5"/><rect x="3" y="16" width="7" height="5" rx="1.5"/>'),
4
4
  runs: base('<path d="M22 12h-2.5a2 2 0 0 0-1.93 1.46l-2.1 7.4a.25.25 0 0 1-.48 0L9.24 3.14a.25.25 0 0 0-.48 0l-2.1 7.4A2 2 0 0 1 4.73 12H2"/>'),
5
+ artifacts: base('<path d="M21 8v8a2 2 0 0 1-1 1.73l-7 4a2 2 0 0 1-2 0l-7-4A2 2 0 0 1 3 16V8a2 2 0 0 1 1-1.73l7-4a2 2 0 0 1 2 0l7 4A2 2 0 0 1 21 8Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/>'),
5
6
  agents: base('<path d="M12 8V4.5"/><circle cx="12" cy="3" r="1.1"/><rect x="4" y="8" width="16" height="12" rx="3"/><path d="M2 14h2"/><path d="M20 14h2"/><path d="M9.5 13v1.6"/><path d="M14.5 13v1.6"/><path d="M9.5 17.2h5"/>'),
6
7
  workspaces: base('<path d="M20 20a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-7.1a2 2 0 0 1-1.66-.89l-.75-1.12A2 2 0 0 0 8.83 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2Z"/>'),
7
8
  keys: base('<circle cx="8" cy="15" r="4.2"/><path d="m11.1 12 8-8"/><path d="m15.4 7.7 2.9 2.9"/><path d="m17.6 5.5 2.9 2.9"/>'),
@@ -1,17 +1,17 @@
1
1
  import { markup } from './markup.js';
2
2
  import { styles } from './styles.js';
3
3
  import { sources } from './app/sources.js';
4
- const page = `<!doctype html>
5
- <html lang="zh-CN">
6
- <head>
7
- <meta charset="utf-8">
8
- <meta name="viewport" content="width=device-width, initial-scale=1">
9
- <meta name="color-scheme" content="light dark">
10
- <title>Agent Nexus</title>
11
- <style>${styles}</style>
12
- <script type="module" defer src="/ui/app.js"></script>
13
- </head>
14
- <body>${markup}</body>
4
+ const page = `<!doctype html>
5
+ <html lang="zh-CN">
6
+ <head>
7
+ <meta charset="utf-8">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1">
9
+ <meta name="color-scheme" content="light dark">
10
+ <title>Agent Nexus</title>
11
+ <style>${styles}</style>
12
+ <script type="module" defer src="/ui/app.js"></script>
13
+ </head>
14
+ <body>${markup}</body>
15
15
  </html>`;
16
16
  const entryModule = `import './app/main.js'\n`;
17
17
  const modules = { '/ui/app.js': entryModule };
@@ -30,6 +30,7 @@ export const markup = String.raw `
30
30
  <p class="nav-group-label" id="nav-group-run">运行</p>
31
31
  <button class="nav-item active" data-page="overview">${icons.overview}<span>总览</span></button>
32
32
  <button class="nav-item" data-page="runs">${icons.runs}<span>运行记录</span></button>
33
+ <button class="nav-item" data-page="artifacts">${icons.artifacts}<span>产物</span></button>
33
34
  </div>
34
35
  <div class="nav-group" role="group" aria-labelledby="nav-group-config">
35
36
  <p class="nav-group-label" id="nav-group-config">网关配置</p>
@@ -39,11 +39,11 @@ export const styles = String.raw `
39
39
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
40
40
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
41
41
 
42
- /* 字号阶梯,全站只用这六级:
42
+ /* 字号阶梯,全站只用这六级(面向中文正文做了整体上调):
43
43
  2xs 大写微标签(表头 / badge)· xs 辅助说明 · sm 正文与表格
44
44
  md 面板与 drawer 标题 · lg 页面标题 · stat 统计数字 */
45
- --fs-2xs: 11px; --fs-xs: 12px; --fs-sm: 13px;
46
- --fs-md: 14px; --fs-lg: 16px; --fs-stat: 28px;
45
+ --fs-2xs: 12px; --fs-xs: 13px;
46
+ --fs-sm: 14px; --fs-md: 15px; --fs-lg: 17px; --fs-stat: 28px;
47
47
 
48
48
  --radius: 6px;
49
49
  --radius-lg: calc(var(--radius) + 2px);
@@ -117,7 +117,7 @@ body {
117
117
  margin: 0;
118
118
  background: hsl(var(--background));
119
119
  color: hsl(var(--foreground));
120
- font: var(--fs-sm)/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
120
+ font: var(--fs-sm)/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
121
121
  "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif;
122
122
  -webkit-font-smoothing: antialiased;
123
123
  text-rendering: optimizeLegibility;
@@ -220,6 +220,7 @@ input[type="checkbox"] { width: 14px; height: 14px; padding: 0; accent-color: hs
220
220
  .button.solid-danger:hover:not(:disabled) { background: hsl(var(--destructive) / .9); color: hsl(var(--destructive-foreground)); }
221
221
  .button.small { height: 26px; padding: 0 var(--sp-2); font-size: var(--fs-xs); }
222
222
  .button svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
223
+ a.button { color: hsl(var(--foreground)); text-decoration: none; }
223
224
 
224
225
  .icon-button {
225
226
  display: inline-flex; align-items: center; justify-content: center;
@@ -327,7 +328,7 @@ button[aria-busy="true"]::after { content: '…'; margin-left: var(--sp-1); }
327
328
  .empty-state .button { margin-top: var(--sp-3); }
328
329
 
329
330
  /* Stats */
330
- .stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
331
+ .stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
331
332
  .stat {
332
333
  padding: var(--sp-4) var(--sp-5);
333
334
  background: hsl(var(--card));
@@ -337,6 +338,8 @@ button[aria-busy="true"]::after { content: '…'; margin-left: var(--sp-1); }
337
338
  }
338
339
  .stat span { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-weight: 500; }
339
340
  .stat strong { font-size: var(--fs-stat); font-weight: 600; letter-spacing: -.02em; line-height: 1.2; font-variant-numeric: tabular-nums; }
341
+ a.stat { color: inherit; text-decoration: none; }
342
+ a.stat:hover { border-color: hsl(var(--muted-foreground) / .4); box-shadow: var(--shadow-sm); }
340
343
 
341
344
  /* ── Toolbar ──────────────────────────────────────────────────────── */
342
345
  .toolbar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
@@ -359,7 +362,7 @@ tbody tr:last-child td { border-bottom: 0; }
359
362
  tbody tr:hover { background: hsl(var(--muted) / .5); }
360
363
  tr[data-run-detail] { cursor: pointer; }
361
364
 
362
- .agent-name { display: grid; gap: 2px; min-width: 0; }
365
+ .agent-name { display: grid; gap: var(--sp-1); min-width: 0; }
363
366
  .agent-name strong { font-size: var(--fs-sm); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
364
367
  .agent-name small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
365
368
  .error-detail { color: hsl(var(--destructive-text)); font-size: var(--fs-sm); overflow-wrap: anywhere; line-height: 1.4; }
@@ -377,7 +380,7 @@ tr[data-run-detail] { cursor: pointer; }
377
380
  /* ── Badges & status ──────────────────────────────────────────────── */
378
381
  .badge {
379
382
  display: inline-flex; align-items: center;
380
- height: 20px; padding: 0 var(--sp-2);
383
+ height: 22px; padding: 0 var(--sp-2);
381
384
  border: 1px solid hsl(var(--border));
382
385
  border-radius: 4px;
383
386
  background: hsl(var(--secondary));
@@ -386,7 +389,7 @@ tr[data-run-detail] { cursor: pointer; }
386
389
  }
387
390
  .status {
388
391
  display: inline-flex; align-items: center; gap: var(--sp-2);
389
- height: 22px; padding: 0 var(--sp-2);
392
+ height: 24px; padding: 0 var(--sp-2);
390
393
  border-radius: 9999px;
391
394
  background: hsl(var(--secondary));
392
395
  color: hsl(var(--muted-foreground));
@@ -433,11 +436,11 @@ tr[data-run-detail] { cursor: pointer; }
433
436
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
434
437
  overflow: hidden;
435
438
  color: hsl(var(--foreground));
436
- font-size: var(--fs-sm); line-height: 1.5;
439
+ font-size: var(--fs-sm); line-height: 1.6;
437
440
  white-space: pre-wrap;
438
441
  overflow-wrap: anywhere;
439
442
  }
440
- .run-progress { display: grid; gap: 2px; }
443
+ .run-progress { display: grid; gap: var(--sp-1); }
441
444
  .run-progress strong { font-size: var(--fs-xs); font-weight: 600; }
442
445
  .run-progress small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
443
446
  .run-meta {
@@ -473,6 +476,11 @@ tr[data-run-detail] { cursor: pointer; }
473
476
  overflow: hidden;
474
477
  background: hsl(var(--border));
475
478
  }
479
+ /* 紧凑指标网格(总览系统状态等):复用 run-detail-item 的视觉,密度更高 */
480
+ .run-detail-grid.compact { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 0; }
481
+ .run-detail-grid.compact .run-detail-item { padding: var(--sp-2) var(--sp-3); }
482
+ /* 嵌在 panel 里时通到边框,避免双层描边 */
483
+ .panel > .run-detail-grid.compact { border: 0; border-radius: 0; }
476
484
  .run-detail-item { padding: var(--sp-3); background: hsl(var(--card)); display: grid; gap: var(--sp-1); align-content: start; }
477
485
  .run-detail-item span { color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
478
486
  .run-detail-item strong { font-size: var(--fs-sm); font-weight: 500; overflow-wrap: anywhere; }
@@ -502,12 +510,19 @@ tr[data-run-detail] { cursor: pointer; }
502
510
  transition: border-color var(--duration-fast) var(--ease-standard);
503
511
  }
504
512
  .list-row:hover { border-color: hsl(var(--muted-foreground) / .4); }
505
- .list-row-main { display: grid; gap: 2px; min-width: 0; }
513
+ .list-row-main { display: grid; gap: var(--sp-1); min-width: 0; }
506
514
  .list-row-main > * { min-width: 0; }
507
515
  .list-row-main strong, .path { font-size: var(--fs-sm); font-weight: 600; overflow-wrap: anywhere; }
508
516
  .list-row-main small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); overflow-wrap: anywhere; }
509
- .panel-body > .workspace-list, .panel-body > .overview-list { gap: var(--sp-2); }
510
- .panel-body .list-row { border-radius: var(--radius); }
517
+ /* panel 里嵌套的列表去掉卡片套卡片:压平成分隔线行 */
518
+ .panel-body .overview-list, .panel-body .workspace-list { gap: 0; }
519
+ .panel-body .list-row {
520
+ border: 0; border-radius: 0; background: transparent;
521
+ border-bottom: 1px solid hsl(var(--border));
522
+ padding: var(--sp-3) 0;
523
+ min-height: 0;
524
+ }
525
+ .panel-body .list-row:last-child { border-bottom: 0; }
511
526
 
512
527
  /* ── API keys ─────────────────────────────────────────────────────── */
513
528
  .key-table { min-width: 760px; width: 100%; table-layout: fixed; }
@@ -589,6 +604,37 @@ tr[data-run-detail] { cursor: pointer; }
589
604
  font-size: var(--fs-xs);
590
605
  }
591
606
 
607
+ /* ── Artifacts page ───────────────────────────────────────────────── */
608
+ .artifact-table { min-width: 760px; table-layout: fixed; }
609
+ .artifact-table th:nth-child(1) { width: 64px; }
610
+ .artifact-table th:nth-child(3) { width: 18%; }
611
+ .artifact-table th:nth-child(4), .artifact-table th:nth-child(5) { width: 120px; }
612
+ .artifact-table th:nth-child(6) { width: 180px; }
613
+ .artifact-table td { height: 56px; }
614
+ /* 产物类型图标瓦片(默认不加载内容,点击后进详情抽屉预览) */
615
+ .artifact-tile {
616
+ display: grid; place-items: center;
617
+ width: 44px; height: 44px;
618
+ border: 1px solid hsl(var(--border));
619
+ border-radius: var(--radius);
620
+ background: hsl(var(--muted) / .4);
621
+ color: hsl(var(--muted-foreground));
622
+ transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard);
623
+ }
624
+ .artifact-tile:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
625
+ .artifact-tile svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
626
+ .artifact-tile svg.filled { fill: currentColor; stroke: none; }
627
+ .artifact-preview-wrap { display: grid; justify-items: center; gap: var(--sp-2); margin-bottom: var(--sp-4); }
628
+ .artifact-link-row { display: grid; gap: var(--sp-1); margin-bottom: var(--sp-4); }
629
+ .artifact-link-line { display: flex; align-items: center; gap: var(--sp-2); }
630
+ .artifact-link-line code { flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--fs-xs); overflow-wrap: anywhere; }
631
+ .artifact-link-line code a { color: hsl(var(--foreground)); text-decoration: underline; text-underline-offset: 2px; }
632
+ .artifact-link-line code a:hover { color: hsl(var(--accent-foreground)); }
633
+ .artifact-link-line .button { flex-shrink: 0; }
634
+ .artifact-preview { max-width: 100%; max-height: 320px; border: 1px solid hsl(var(--border)); border-radius: var(--radius); background: hsl(var(--muted) / .4); }
635
+ .artifact-preview-wrap audio { width: 100%; }
636
+ .artifact-text-preview { width: 100%; max-height: 480px; }
637
+
592
638
  /* ── Drawer ───────────────────────────────────────────────────────── */
593
639
  .drawer-backdrop { position: fixed; inset: 0; background: rgb(0 0 0 / .4); z-index: var(--z-backdrop); animation: fadeIn var(--duration-fade) var(--ease-out); }
594
640
  .drawer {
@@ -630,12 +676,9 @@ tr[data-run-detail] { cursor: pointer; }
630
676
  .main.settings-page .page-actions { position: absolute; right: max(var(--gutter), calc((100% - 820px) / 2)); }
631
677
  .main.settings-page .page-content { padding-top: var(--sp-8); }
632
678
  .settings-layout { width: min(100%, 820px); margin-inline: auto; }
679
+ /* 设置页顶层布局块之间用分隔线(每节各自包在 .settings-layout 里) */
680
+ .settings-layout + .settings-layout { margin-top: 48px; padding-top: 48px; border-top: 1px solid hsl(var(--border)); }
633
681
  .settings-section { width: 100%; }
634
- .settings-section + .settings-section {
635
- margin-top: 48px;
636
- padding-top: 48px;
637
- border-top: 1px solid hsl(var(--border));
638
- }
639
682
  .settings-section-heading { display: grid; gap: var(--sp-2); margin-bottom: 28px; }
640
683
  .settings-section-heading h2 { font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; }
641
684
  /* 节说明写的是生效范围——这是界面自身无法表达的信息,不要当复述删掉 */
@@ -645,16 +688,6 @@ tr[data-run-detail] { cursor: pointer; }
645
688
  .settings-fields .field input, .settings-fields .field select { max-width: none; }
646
689
  .settings-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: 28px; }
647
690
  .settings-form-error { width: min(100%, 520px); margin-top: 32px; }
648
- .settings-account-row {
649
- display: grid;
650
- grid-template-columns: minmax(160px, 200px) minmax(0, 1fr);
651
- align-items: start;
652
- gap: 32px;
653
- }
654
- .settings-account-copy { display: grid; gap: var(--sp-1); }
655
- .settings-account-copy strong { font-size: var(--fs-sm); font-weight: 600; }
656
- .settings-account-copy p { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); }
657
- .settings-account-fields { display: grid; gap: 24px; width: min(100%, 520px); }
658
691
 
659
692
  /* ── Toast ────────────────────────────────────────────────────────── */
660
693
  .toast-region {
@@ -728,11 +761,11 @@ tr[data-run-detail] { cursor: pointer; }
728
761
  @media (max-width: 640px) {
729
762
  .page-content { padding: var(--sp-4) var(--gutter) var(--sp-4); }
730
763
  .main.settings-page .page-content { padding-top: var(--sp-6); }
731
- .settings-section + .settings-section { margin-top: 40px; padding-top: 40px; }
764
+ .settings-layout + .settings-layout { margin-top: 40px; padding-top: 40px; }
732
765
  .settings-section-heading { margin-bottom: 24px; }
733
- .settings-account-row { grid-template-columns: 1fr; gap: var(--sp-4); }
734
766
  .search-box { max-width: none; }
735
- .stats { grid-template-columns: 1fr; }
767
+ .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
768
+ .run-detail-grid.compact { grid-template-columns: repeat(2, minmax(0, 1fr)); }
736
769
  .run-summary { grid-template-columns: repeat(2, 1fr); }
737
770
  .run-live-grid { grid-template-columns: minmax(0, 1fr); }
738
771
  .toolbar input[type="search"], .toolbar select { max-width: none; width: 100%; }
@@ -1,21 +1,21 @@
1
- {
2
- "initialized": false,
3
- "listen": {
4
- "host": "0.0.0.0",
5
- "port": 8787
6
- },
7
- "workspaceRoots": [
8
- "/data/repos"
9
- ],
10
- "apiKeys": [],
11
- "maxRequestBytes": 1048576,
12
- "maxAttachmentBytes": 33554432,
13
- "requestTimeoutMs": 30000,
14
- "promptTimeoutMs": 1800000,
15
- "cleanupIntervalMs": 60000,
16
- "maxSessions": 64,
17
- "maxSseConnections": 128,
18
- "maxConnections": 256,
1
+ {
2
+ "initialized": false,
3
+ "listen": {
4
+ "host": "0.0.0.0",
5
+ "port": 8787
6
+ },
7
+ "workspaceRoots": [
8
+ "/data/repos"
9
+ ],
10
+ "apiKeys": [],
11
+ "maxRequestBytes": 1048576,
12
+ "maxAttachmentBytes": 33554432,
13
+ "requestTimeoutMs": 30000,
14
+ "promptTimeoutMs": 1800000,
15
+ "cleanupIntervalMs": 60000,
16
+ "maxSessions": 64,
17
+ "maxSseConnections": 128,
18
+ "maxConnections": 256,
19
19
  "sessionTtlMs": 86400000,
20
20
  "quotas": {
21
21
  "maxSessionsPerKey": 16,
@@ -37,23 +37,23 @@
37
37
  "workspace": "/data/repos/project",
38
38
  "permissionPolicy": "ask"
39
39
  },
40
- "codex": {
41
- "protocol": "acp",
42
- "driver": "codex",
43
- "name": "Codex",
44
- "command": "codex-acp",
45
- "workspace": "/data/repos/project",
46
- "permissionPolicy": "ask"
47
- },
48
- "research": {
49
- "protocol": "a2a",
50
- "name": "Research Agent",
51
- "agentCardUrl": "http://192.168.1.20:8080/.well-known/agent-card.json",
52
- "preferredTransport": "auto",
53
- "auth": {
54
- "type": "none"
55
- },
56
- "timeoutMs": 60000
57
- }
58
- }
59
- }
40
+ "codex": {
41
+ "protocol": "acp",
42
+ "driver": "codex",
43
+ "name": "Codex",
44
+ "command": "codex-acp",
45
+ "workspace": "/data/repos/project",
46
+ "permissionPolicy": "ask"
47
+ },
48
+ "research": {
49
+ "protocol": "a2a",
50
+ "name": "Research Agent",
51
+ "agentCardUrl": "http://192.168.1.20:8080/.well-known/agent-card.json",
52
+ "preferredTransport": "auto",
53
+ "auth": {
54
+ "type": "none"
55
+ },
56
+ "timeoutMs": 60000
57
+ }
58
+ }
59
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexus-agentd",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Local Nexus Gateway daemon with an HTTP/SSE API and WebUI for allowlisted ACP and remote A2A agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "scripts": {
37
37
  "build": "node scripts/generate-webui-sources.mjs && node scripts/clean-dist.mjs && tsc -p tsconfig.json",
38
38
  "typecheck": "node scripts/generate-webui-sources.mjs && tsc -p tsconfig.json --noEmit && tsc -p tsconfig.webui.json",
39
- "test": "tsx --test test/*.test.ts",
39
+ "test": "tsx --test --test-force-exit --test-concurrency=1 test/*.test.ts",
40
40
  "test:webui": "node scripts/generate-webui-sources.mjs && playwright test",
41
41
  "prepack": "npm run build"
42
42
  },