@flame0510/project-aether 1.6.2 → 1.8.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.
- package/LICENSE +21 -0
- package/README.md +6 -2
- package/agent-templates/atlas/HEARTBEAT.md +1 -1
- package/app/agents/ImageDownloadBanner.tsx +171 -37
- package/app/api/agents/download-image/route.ts +29 -5
- package/app/api/agents/image-status/route.ts +17 -2
- package/app/api/assistant/route.ts +21 -5
- package/app/api/auth/login/route.ts +2 -2
- package/app/api/metrics/route.ts +126 -23
- package/app/api/setup/agent-image/route.ts +6 -4
- package/app/api/system-health/route.ts +25 -21
- package/app/components/DashboardToolbar.tsx +2 -2
- package/app/components/LineageGraphPage.tsx +4 -4
- package/app/components/SessionDrawer.tsx +8 -8
- package/app/components/Sidebar.tsx +10 -0
- package/app/components/Skeleton.tsx +4 -1
- package/app/components/SystemCockpit.tsx +83 -3
- package/app/components/ui/Meter.tsx +34 -0
- package/app/components/ui/TimeSeriesChart.tsx +226 -0
- package/app/components/ui/index.ts +2 -0
- package/app/globals.css +42 -1
- package/app/setup/PageClient.tsx +1 -1
- package/app/system/PageClient.tsx +263 -0
- package/app/system/SystemSkeleton.tsx +115 -0
- package/app/system/loading.tsx +13 -0
- package/app/system/page.tsx +5 -0
- package/bin/postinstall.js +5 -1
- package/daemon.js +274 -214
- package/docs/ARCHITECTURE.md +65 -34
- package/docs/CONTAINER-TERMINAL.md +17 -8
- package/docs/DESIGN-SYSTEM.md +22 -12
- package/docs/FRONTEND-ARCHITECTURE.md +8 -4
- package/docs/REV4A.md +37 -86
- package/docs/dev/API-REFERENCE.md +102 -19
- package/docs/dev/DATABASE.md +79 -28
- package/docs/dev/SESSION-MAINTENANCE-PLAN.md +6 -6
- package/docs/rag/DATA-FRESHNESS.md +31 -15
- package/docs/rag/GLOSSARY.md +8 -5
- package/docs/rag/REV4A-OVERVIEW.md +14 -7
- package/docs/rag/WHAT-I-CAN-ANSWER.md +4 -3
- package/lib/agent-images.ts +43 -14
- package/lib/buildAgentImage.ts +142 -6
- package/lib/db-bootstrap.mjs +0 -11
- package/lib/metrics-db.ts +48 -0
- package/lib/patterns/sessionPresentation.ts +4 -2
- package/lib/rev4a-auth.d.ts +1 -0
- package/lib/rev4a-auth.js +18 -2
- package/next.config.mjs +9 -1
- package/package.json +2 -2
- package/scripts/backup.sh +48 -54
- package/scripts/check-language.mjs +21 -3
- package/scripts/restore.sh +77 -59
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Skeleton } from '../components/Skeleton';
|
|
2
|
+
import { Surface } from '../components/ui';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Placeholders for the System page, used by `loading.tsx` while the route loads and by the
|
|
6
|
+
* page before its first answer. Each shimmer sits inside the same class as the text it
|
|
7
|
+
* stands in for (`ui-kicker`, `ui-metric-value`, `ui-key-value`, `ui-meter`), so the line
|
|
8
|
+
* boxes — and the card, grid and page heights — are the real ones and nothing jumps when
|
|
9
|
+
* the data lands. Measured against the loaded page, desktop and mobile.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The header description: a fixed sentence, then the host facts on one line of their own —
|
|
14
|
+
* cut with an ellipsis rather than wrapped, so a long hostname cannot change the height.
|
|
15
|
+
*/
|
|
16
|
+
export function SystemDescription({ host }: { host: string | null }) {
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
CPU, memory and storage of the machine Rev4a runs on.
|
|
20
|
+
{/* width 0 + min-width 100%: the line takes the header's width without adding its own
|
|
21
|
+
(unwrapped) width to the header's minimum — else a long hostname widens the page. */}
|
|
22
|
+
<span style={{ display: 'block', width: 0, minWidth: '100%', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
23
|
+
{host ?? <Skeleton as="span" inline width={260} height={12} />}
|
|
24
|
+
</span>
|
|
25
|
+
</>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function KeyValueRow({ label, value }: { label: number; value: number }) {
|
|
30
|
+
return (
|
|
31
|
+
<div className="ui-key-value">
|
|
32
|
+
<span><Skeleton as="span" inline width={label} height={11} /></span>
|
|
33
|
+
<span><Skeleton as="span" inline width={value} height={11} /></span>
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function MeterRow() {
|
|
39
|
+
return (
|
|
40
|
+
<div className="ui-meter">
|
|
41
|
+
<Skeleton height={6} style={{ flex: 1 }} />
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function FigureCard({ title, rows }: { title: number; rows: [number, number][] }) {
|
|
47
|
+
return (
|
|
48
|
+
<Surface as="article">
|
|
49
|
+
<div className="ui-kicker"><Skeleton as="span" inline width={title} height={10} /></div>
|
|
50
|
+
<div className="ui-metric-value"><Skeleton as="span" inline width={72} height={26} accent /></div>
|
|
51
|
+
<MeterRow />
|
|
52
|
+
<div className="ui-key-values" style={{ marginTop: 12 }}>
|
|
53
|
+
{rows.map(([l, v], i) => <KeyValueRow key={i} label={l} value={v} />)}
|
|
54
|
+
</div>
|
|
55
|
+
</Surface>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function SystemCardsSkeleton() {
|
|
60
|
+
return (
|
|
61
|
+
<div className="system-cards" aria-busy="true" aria-label="Loading machine metrics">
|
|
62
|
+
<FigureCard title={28} rows={[[40, 20], [120, 110]]} />
|
|
63
|
+
<FigureCard title={52} rows={[[80, 110], [64, 48], [110, 90]]} />
|
|
64
|
+
<Surface as="article">
|
|
65
|
+
<div className="ui-kicker"><Skeleton as="span" inline width={56} height={10} /></div>
|
|
66
|
+
<div style={{ marginTop: 14 }}>
|
|
67
|
+
<div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap' }}>
|
|
68
|
+
<span style={{ fontSize: 13 }}><Skeleton as="span" inline width={24} height={12} /></span>
|
|
69
|
+
<span style={{ display: 'flex', gap: 4 }}>
|
|
70
|
+
<span className="ui-pill"><Skeleton as="span" inline width={40} height={9} /></span>
|
|
71
|
+
<span className="ui-pill"><Skeleton as="span" inline width={56} height={9} /></span>
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
<MeterRow />
|
|
75
|
+
<div style={{ marginTop: 6 }}>
|
|
76
|
+
<KeyValueRow label={150} value={80} />
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
</Surface>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The chart grid: CPU, memory and one disk, each at the real plot height (160 px). */
|
|
85
|
+
export function SystemChartsSkeleton({ count = 3 }: { count?: number }) {
|
|
86
|
+
return (
|
|
87
|
+
<div className="system-charts" aria-hidden="true">
|
|
88
|
+
{Array.from({ length: count }).map((_, i) => (
|
|
89
|
+
<Surface as="section" key={i}>
|
|
90
|
+
<div className="ui-kicker"><Skeleton as="span" inline width={150} height={10} /></div>
|
|
91
|
+
<Skeleton height={160} />
|
|
92
|
+
<div className="ui-chart__table">
|
|
93
|
+
<div style={{ fontSize: 10 }}><Skeleton as="span" inline width={48} height={9} /></div>
|
|
94
|
+
</div>
|
|
95
|
+
</Surface>
|
|
96
|
+
))}
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The range switch (1h · 24h · 7d · 30d) for the route's loading state, where the real tabs cannot render. */
|
|
102
|
+
export function SystemRangeSkeleton() {
|
|
103
|
+
return (
|
|
104
|
+
<div
|
|
105
|
+
aria-hidden="true"
|
|
106
|
+
style={{ display: 'flex', borderBottom: '1px solid var(--border)', marginBottom: 20, height: 44, alignItems: 'center' }}
|
|
107
|
+
>
|
|
108
|
+
{[18, 24, 18, 24].map((w, i) => (
|
|
109
|
+
<div key={i} style={{ flex: 1, display: 'flex', justifyContent: 'center' }}>
|
|
110
|
+
<Skeleton width={w} height={11} />
|
|
111
|
+
</div>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Page, PageHeader } from '../components/ui';
|
|
2
|
+
import { SystemCardsSkeleton, SystemChartsSkeleton, SystemDescription, SystemRangeSkeleton } from './SystemSkeleton';
|
|
3
|
+
|
|
4
|
+
export default function SystemLoading() {
|
|
5
|
+
return (
|
|
6
|
+
<Page>
|
|
7
|
+
<PageHeader eyebrow="Host" title="System" description={<SystemDescription host={null} />} />
|
|
8
|
+
<SystemCardsSkeleton />
|
|
9
|
+
<SystemRangeSkeleton />
|
|
10
|
+
<SystemChartsSkeleton />
|
|
11
|
+
</Page>
|
|
12
|
+
);
|
|
13
|
+
}
|
package/bin/postinstall.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Post-install hook: build Next.js app if .next doesn't exist.
|
|
4
|
+
*
|
|
5
|
+
* Skipped when REV4A_SKIP_POSTINSTALL_BUILD is set: CI and the release workflow run
|
|
6
|
+
* `npm run build` as an explicit step, and a second build here would run before every
|
|
7
|
+
* other check and swallow its own failure.
|
|
4
8
|
*/
|
|
5
9
|
const { existsSync } = require('fs');
|
|
6
10
|
const { join } = require('path');
|
|
@@ -8,7 +12,7 @@ const { join } = require('path');
|
|
|
8
12
|
const ROOT = join(__dirname, '..');
|
|
9
13
|
const NEXT_DIR = join(ROOT, '.next');
|
|
10
14
|
|
|
11
|
-
if (!existsSync(NEXT_DIR)) {
|
|
15
|
+
if (!process.env.REV4A_SKIP_POSTINSTALL_BUILD && !existsSync(NEXT_DIR)) {
|
|
12
16
|
try {
|
|
13
17
|
const { execSync } = require('child_process');
|
|
14
18
|
console.log('[rev4a] Building dashboard… (one-time, may take a minute)');
|