@askrjs/cli 0.0.14 → 0.0.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.
- package/README.md +15 -24
- package/dist/analyze.js +1 -1
- package/dist/cli.js +7 -7
- package/dist/database.d.ts +18 -0
- package/dist/database.js +53 -0
- package/dist/generate.js +10 -4
- package/dist/{guardrails-D6KCKS-H.js → guardrails-XypvEZOT.js} +1 -1
- package/dist/{planner-BEfWRd0x.js → planner-CYi2Y-2W.js} +1 -5
- package/dist/{runner-BSs9Ow3t.js → runner-42nqhW9u.js} +16 -557
- package/dist/{runner-DetGSvGf.js → runner-CEt07ieG.js} +27 -5
- package/dist/skills/askr-ssr-ssg/SKILL.md +1 -3
- package/dist/templates/spa/src/pages/app/_layout.tsx +8 -11
- package/dist/templates/spa/src/pages/app/admin-home.tsx +132 -142
- package/dist/templates/spa/src/pages/app/agent-runs.tsx +26 -33
- package/dist/templates/spa/src/pages/public/home.tsx +9 -12
- package/dist/templates/ssg/src/components/site-shell.tsx +3 -4
- package/dist/templates/ssg/src/pages/about.tsx +11 -14
- package/dist/templates/ssg/src/pages/content.tsx +7 -10
- package/dist/templates/ssg/src/pages/home.tsx +3 -6
- package/dist/templates/startkit/src/components/app-sidebar.tsx +18 -23
- package/dist/templates/startkit/src/components/data-table.tsx +39 -41
- package/dist/templates/startkit/src/pages/workspace/dashboard.tsx +13 -16
- package/dist/update.js +1 -1
- package/package.json +2 -11
- package/dist/verify-hydration.d.ts +0 -35
- package/dist/verify-hydration.js +0 -325
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as inspectBundledSkills } from "./skills-CSGdAZHN.js";
|
|
2
2
|
import { discoverWorkspaceProject } from "./discovery-DUDrZCIC.js";
|
|
3
|
-
import { analysisHasBlockingFindings, runAnalysis } from "./runner-
|
|
3
|
+
import { analysisHasBlockingFindings, runAnalysis } from "./runner-42nqhW9u.js";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { spawn } from "node:child_process";
|
|
@@ -229,16 +229,38 @@ async function runCheck(options, runtime = {}) {
|
|
|
229
229
|
const selected = VALIDATION_SCRIPTS.filter((name) => scripts[name]);
|
|
230
230
|
const manager = managerCommand(await existingLockfiles(project.root), rootWorkspace.manifest);
|
|
231
231
|
const results = [];
|
|
232
|
-
|
|
232
|
+
const selectedChecks = [...Boolean(await fs.stat(path.join(project.root, "database", "index.ts")).catch(() => null)) ? ["database"] : [], ...selected];
|
|
233
|
+
if (analysisHasBlockingFindings(analysis)) for (const name of selectedChecks) results.push({
|
|
233
234
|
name,
|
|
234
235
|
status: "skipped",
|
|
235
|
-
command: `${manager.executable} run ${name}`,
|
|
236
|
+
command: name === "database" ? "askr database validate" : `${manager.executable} run ${name}`,
|
|
236
237
|
exitCode: null,
|
|
237
238
|
stdout: "",
|
|
238
239
|
stderr: "",
|
|
239
240
|
reason: "static analysis must pass first"
|
|
240
241
|
});
|
|
241
|
-
else for (const [index, name] of
|
|
242
|
+
else for (const [index, name] of selectedChecks.entries()) {
|
|
243
|
+
if (name === "database") {
|
|
244
|
+
const result = await (runtime.runDatabaseValidation ?? (await import("./database.js")).runDatabaseValidation)(project.root);
|
|
245
|
+
results.push({
|
|
246
|
+
name,
|
|
247
|
+
command: "askr database validate",
|
|
248
|
+
...result
|
|
249
|
+
});
|
|
250
|
+
if (result.status === "failed") {
|
|
251
|
+
for (const skipped of selectedChecks.slice(index + 1)) results.push({
|
|
252
|
+
name: skipped,
|
|
253
|
+
status: "skipped",
|
|
254
|
+
command: `${manager.executable} run ${skipped}`,
|
|
255
|
+
exitCode: null,
|
|
256
|
+
stdout: "",
|
|
257
|
+
stderr: "",
|
|
258
|
+
reason: "database validation failed"
|
|
259
|
+
});
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
242
264
|
const args = manager.args(name);
|
|
243
265
|
const result = await (runtime.runScript ?? defaultRunScript)(manager.executable, args, project.root);
|
|
244
266
|
results.push({
|
|
@@ -247,7 +269,7 @@ async function runCheck(options, runtime = {}) {
|
|
|
247
269
|
...result
|
|
248
270
|
});
|
|
249
271
|
if (result.status === "failed") {
|
|
250
|
-
for (const skipped of
|
|
272
|
+
for (const skipped of selectedChecks.slice(index + 1)) results.push({
|
|
251
273
|
name: skipped,
|
|
252
274
|
status: "skipped",
|
|
253
275
|
command: `${manager.executable} run ${skipped}`,
|
|
@@ -34,9 +34,7 @@ Use this when the app renders outside the browser or produces static output. The
|
|
|
34
34
|
## Copy This Shape
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const registry = createRouteRegistry(() => {
|
|
37
|
+
registerRoutes(() => {
|
|
40
38
|
page("/docs/{slug}", DocsPage, {
|
|
41
39
|
entries: async () => [{ slug: "getting-started" }, { slug: "routing" }],
|
|
42
40
|
});
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
SettingsIcon,
|
|
7
7
|
SunIcon,
|
|
8
8
|
} from '@askrjs/lucide';
|
|
9
|
-
import { For } from '@askrjs/askr/control';
|
|
10
9
|
import { Link, navigate } from '@askrjs/askr/router';
|
|
11
10
|
import { Button } from '@askrjs/themes/components';
|
|
12
11
|
import { Container, Inline, Stack } from '@askrjs/themes/components';
|
|
@@ -43,16 +42,14 @@ export default function AppLayout({ children }: { children?: unknown }) {
|
|
|
43
42
|
</Link>
|
|
44
43
|
</NavBrand>
|
|
45
44
|
<NavGroup label="Workspace">
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)}
|
|
55
|
-
</For>
|
|
45
|
+
{appNavItems.map((item) => (
|
|
46
|
+
<NavLink href={item.href} match={item.match}>
|
|
47
|
+
<Inline as="span" gap="2" align="center">
|
|
48
|
+
{icons[item.icon]}
|
|
49
|
+
<span>{item.label}</span>
|
|
50
|
+
</Inline>
|
|
51
|
+
</NavLink>
|
|
52
|
+
))}
|
|
56
53
|
</NavGroup>
|
|
57
54
|
<NavGroup label="Session" align="end">
|
|
58
55
|
<NavLink href="/" match="exact">
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { resource } from '@askrjs/askr/resources';
|
|
2
|
-
import { For, Show } from '@askrjs/askr/control';
|
|
3
2
|
import { createPlot } from '@askrjs/charts';
|
|
4
3
|
import { AlertCircleIcon, RefreshCwIcon } from '@askrjs/lucide';
|
|
5
4
|
import { Button } from '@askrjs/themes/components';
|
|
@@ -27,154 +26,145 @@ export default function AdminHomePage() {
|
|
|
27
26
|
const operations = resource(({ signal }) => loadOperations({ signal }), []);
|
|
28
27
|
const snapshot = operations.value;
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
if (operations.error && !snapshot) {
|
|
30
|
+
return (
|
|
31
|
+
<Section>
|
|
32
|
+
<EmptyState
|
|
33
|
+
icon={<AlertCircleIcon size={24} aria-hidden="true" />}
|
|
34
|
+
title="Operations could not load"
|
|
35
|
+
description="The dashboard keeps failures recoverable. Retry the owning resource instead of hiding the error in a toast."
|
|
36
|
+
actions={<Button onPress={() => operations.refresh()}>Retry</Button>}
|
|
37
|
+
/>
|
|
38
|
+
</Section>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
40
41
|
|
|
41
42
|
return (
|
|
42
|
-
<
|
|
43
|
-
<
|
|
44
|
-
<
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
<Stack gap="5">
|
|
44
|
+
<section class="page-heading">
|
|
45
|
+
<Stack gap="2">
|
|
46
|
+
<Badge>projection v{snapshot?.version ?? '...'}</Badge>
|
|
47
|
+
<h1>Workspace home</h1>
|
|
48
|
+
<p class="lead">
|
|
49
|
+
A consistency-aware dashboard for agent runs, queue health, and
|
|
50
|
+
event-sourced read models.
|
|
51
|
+
</p>
|
|
52
|
+
</Stack>
|
|
53
|
+
<Inline gap="2" align="center">
|
|
54
|
+
{operations.pending && snapshot ? <Badge>refreshing</Badge> : null}
|
|
55
|
+
<Button variant="secondary" onPress={() => operations.refresh()}>
|
|
56
|
+
<RefreshCwIcon size={14} aria-hidden="true" /> Refresh
|
|
57
|
+
</Button>
|
|
58
|
+
</Inline>
|
|
59
|
+
</section>
|
|
60
|
+
|
|
61
|
+
{operations.pending && !snapshot ? (
|
|
62
|
+
<Block gap="md">
|
|
63
|
+
<Skeleton style="height: 8rem" />
|
|
64
|
+
<Skeleton style="height: 8rem" />
|
|
65
|
+
<Skeleton style="height: 8rem" />
|
|
66
|
+
</Block>
|
|
67
|
+
) : null}
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
{snapshot ? (
|
|
70
|
+
<>
|
|
71
|
+
<Block gap="md" class="metric-grid">
|
|
72
|
+
{snapshot.metrics.map((metric) => (
|
|
73
|
+
<MetricCard
|
|
74
|
+
label={metric.label}
|
|
75
|
+
value={metric.value}
|
|
76
|
+
trend={metric.trend}
|
|
77
|
+
/>
|
|
78
|
+
))}
|
|
66
79
|
</Block>
|
|
67
|
-
) : null}
|
|
68
80
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
<Block gap="md" align="stretch" class="chart-grid">
|
|
82
|
+
<Card>
|
|
83
|
+
<CardHeader>
|
|
84
|
+
<CardTitle>Run throughput</CardTitle>
|
|
85
|
+
<CardDescription>
|
|
86
|
+
Accepted commands by work type.
|
|
87
|
+
</CardDescription>
|
|
88
|
+
</CardHeader>
|
|
89
|
+
<CardContent>
|
|
90
|
+
<OperationsPlot.Root
|
|
91
|
+
data={snapshot.throughput}
|
|
92
|
+
rowKey="label"
|
|
93
|
+
label="Run throughput"
|
|
94
|
+
description="Accepted commands by work type."
|
|
76
95
|
>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
>
|
|
102
|
-
<OperationsPlot.Bar x="label" y="value" />
|
|
103
|
-
</OperationsPlot.Root>
|
|
104
|
-
</CardContent>
|
|
105
|
-
</Card>
|
|
106
|
-
<Card>
|
|
107
|
-
<CardHeader>
|
|
108
|
-
<CardTitle>Projection lag</CardTitle>
|
|
109
|
-
<CardDescription>
|
|
110
|
-
Lower is better; stale states stay visible.
|
|
111
|
-
</CardDescription>
|
|
112
|
-
</CardHeader>
|
|
113
|
-
<CardContent>
|
|
114
|
-
<OperationsPlot.Root
|
|
115
|
-
data={currentSnapshot.lag}
|
|
116
|
-
rowKey="label"
|
|
117
|
-
label="Projection lag"
|
|
118
|
-
description="Projection lag over the last hour."
|
|
119
|
-
>
|
|
120
|
-
<OperationsPlot.Line x="label" y="value" />
|
|
121
|
-
<OperationsPlot.Point x="label" y="value" />
|
|
122
|
-
</OperationsPlot.Root>
|
|
123
|
-
</CardContent>
|
|
124
|
-
</Card>
|
|
125
|
-
</Block>
|
|
96
|
+
<OperationsPlot.Bar x="label" y="value" />
|
|
97
|
+
</OperationsPlot.Root>
|
|
98
|
+
</CardContent>
|
|
99
|
+
</Card>
|
|
100
|
+
<Card>
|
|
101
|
+
<CardHeader>
|
|
102
|
+
<CardTitle>Projection lag</CardTitle>
|
|
103
|
+
<CardDescription>
|
|
104
|
+
Lower is better; stale states stay visible.
|
|
105
|
+
</CardDescription>
|
|
106
|
+
</CardHeader>
|
|
107
|
+
<CardContent>
|
|
108
|
+
<OperationsPlot.Root
|
|
109
|
+
data={snapshot.lag}
|
|
110
|
+
rowKey="label"
|
|
111
|
+
label="Projection lag"
|
|
112
|
+
description="Projection lag over the last hour."
|
|
113
|
+
>
|
|
114
|
+
<OperationsPlot.Line x="label" y="value" />
|
|
115
|
+
<OperationsPlot.Point x="label" y="value" />
|
|
116
|
+
</OperationsPlot.Root>
|
|
117
|
+
</CardContent>
|
|
118
|
+
</Card>
|
|
119
|
+
</Block>
|
|
126
120
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
121
|
+
{snapshot.consistency !== 'fresh' ? (
|
|
122
|
+
<Alert variant="warning">
|
|
123
|
+
Read models are {snapshot.consistency}. Last processed event is{' '}
|
|
124
|
+
{snapshot.lastEventId}.
|
|
125
|
+
</Alert>
|
|
126
|
+
) : null}
|
|
133
127
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
)}
|
|
176
|
-
</Show>
|
|
177
|
-
</Stack>
|
|
178
|
-
</Show>
|
|
128
|
+
<Card>
|
|
129
|
+
<CardHeader>
|
|
130
|
+
<CardTitle>Recent agent runs</CardTitle>
|
|
131
|
+
<CardDescription>
|
|
132
|
+
Run state is modeled as product state, not a single loading
|
|
133
|
+
boolean.
|
|
134
|
+
</CardDescription>
|
|
135
|
+
</CardHeader>
|
|
136
|
+
<CardContent>
|
|
137
|
+
<div class="run-table-wrap">
|
|
138
|
+
<table class="run-table">
|
|
139
|
+
<thead>
|
|
140
|
+
<tr>
|
|
141
|
+
<th>Run</th>
|
|
142
|
+
<th>Status</th>
|
|
143
|
+
<th>Owner</th>
|
|
144
|
+
<th>Updated</th>
|
|
145
|
+
</tr>
|
|
146
|
+
</thead>
|
|
147
|
+
<tbody>
|
|
148
|
+
{snapshot.runs.map((run) => (
|
|
149
|
+
<tr>
|
|
150
|
+
<td>
|
|
151
|
+
<strong>{run.title}</strong>
|
|
152
|
+
<span>{run.id}</span>
|
|
153
|
+
</td>
|
|
154
|
+
<td>
|
|
155
|
+
<StatusBadge status={run.status} />
|
|
156
|
+
</td>
|
|
157
|
+
<td>{run.owner}</td>
|
|
158
|
+
<td>{formatRelativeTime(run.updatedAt)}</td>
|
|
159
|
+
</tr>
|
|
160
|
+
))}
|
|
161
|
+
</tbody>
|
|
162
|
+
</table>
|
|
163
|
+
</div>
|
|
164
|
+
</CardContent>
|
|
165
|
+
</Card>
|
|
166
|
+
</>
|
|
167
|
+
) : null}
|
|
168
|
+
</Stack>
|
|
179
169
|
);
|
|
180
170
|
}
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
Clock3Icon,
|
|
5
5
|
ShieldAlertIcon,
|
|
6
6
|
} from '@askrjs/lucide';
|
|
7
|
-
import { For } from '@askrjs/askr/control';
|
|
8
7
|
import {
|
|
9
8
|
Badge,
|
|
10
9
|
Card,
|
|
@@ -19,14 +18,12 @@ import StatusBadge, {
|
|
|
19
18
|
} from '../../components/shared/status-badge';
|
|
20
19
|
|
|
21
20
|
const runs: Array<{
|
|
22
|
-
id: string;
|
|
23
21
|
title: string;
|
|
24
22
|
status: RunStatus;
|
|
25
23
|
event: string;
|
|
26
24
|
description: string;
|
|
27
25
|
}> = [
|
|
28
26
|
{
|
|
29
|
-
id: 'reconcile-billing-projection',
|
|
30
27
|
title: 'Reconcile billing projection',
|
|
31
28
|
status: 'running',
|
|
32
29
|
event: 'tool call: compare-ledger',
|
|
@@ -34,7 +31,6 @@ const runs: Array<{
|
|
|
34
31
|
'Streaming events are appended to the timeline and reconciled by event id.',
|
|
35
32
|
},
|
|
36
33
|
{
|
|
37
|
-
id: 'approve-enterprise-workspace',
|
|
38
34
|
title: 'Approve enterprise workspace',
|
|
39
35
|
status: 'requires-action',
|
|
40
36
|
event: 'approval requested',
|
|
@@ -42,7 +38,6 @@ const runs: Array<{
|
|
|
42
38
|
'Human gates are explicit product states, not hidden inside generated text.',
|
|
43
39
|
},
|
|
44
40
|
{
|
|
45
|
-
id: 'refresh-onboarding-cohort',
|
|
46
41
|
title: 'Refresh onboarding cohort',
|
|
47
42
|
status: 'succeeded',
|
|
48
43
|
event: 'projection caught up',
|
|
@@ -66,34 +61,32 @@ export default function AgentRunsPage() {
|
|
|
66
61
|
</section>
|
|
67
62
|
|
|
68
63
|
<Block gap="md" class="agent-grid">
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)}
|
|
96
|
-
</For>
|
|
64
|
+
{runs.map((run) => (
|
|
65
|
+
<Card>
|
|
66
|
+
<CardHeader>
|
|
67
|
+
<Inline justify="between" align="start" gap="3">
|
|
68
|
+
<span class="card-icon">
|
|
69
|
+
{run.status === 'succeeded' ? (
|
|
70
|
+
<CheckCircle2Icon size={18} aria-hidden="true" />
|
|
71
|
+
) : run.status === 'requires-action' ? (
|
|
72
|
+
<ShieldAlertIcon size={18} aria-hidden="true" />
|
|
73
|
+
) : (
|
|
74
|
+
<BotIcon size={18} aria-hidden="true" />
|
|
75
|
+
)}
|
|
76
|
+
</span>
|
|
77
|
+
<StatusBadge status={run.status} />
|
|
78
|
+
</Inline>
|
|
79
|
+
<CardTitle>{run.title}</CardTitle>
|
|
80
|
+
<CardDescription>{run.description}</CardDescription>
|
|
81
|
+
</CardHeader>
|
|
82
|
+
<CardContent>
|
|
83
|
+
<Inline gap="2" align="center">
|
|
84
|
+
<Clock3Icon size={14} aria-hidden="true" />
|
|
85
|
+
<span>{run.event}</span>
|
|
86
|
+
</Inline>
|
|
87
|
+
</CardContent>
|
|
88
|
+
</Card>
|
|
89
|
+
))}
|
|
97
90
|
</Block>
|
|
98
91
|
</Stack>
|
|
99
92
|
);
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
CheckCircle2Icon,
|
|
6
6
|
ShieldCheckIcon,
|
|
7
7
|
} from '@askrjs/lucide';
|
|
8
|
-
import { For } from '@askrjs/askr/control';
|
|
9
8
|
import { Link } from '@askrjs/askr/router';
|
|
10
9
|
import { Button } from '@askrjs/themes/components';
|
|
11
10
|
import {
|
|
@@ -112,17 +111,15 @@ export default function HomePage() {
|
|
|
112
111
|
<Section paddingY="xl">
|
|
113
112
|
<Container size="xl">
|
|
114
113
|
<Block gap="md" class="feature-grid">
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)}
|
|
125
|
-
</For>
|
|
114
|
+
{capabilities.map((item) => (
|
|
115
|
+
<Card>
|
|
116
|
+
<CardHeader>
|
|
117
|
+
<span class="card-icon">{item.icon}</span>
|
|
118
|
+
<CardTitle>{item.title}</CardTitle>
|
|
119
|
+
<CardDescription>{item.description}</CardDescription>
|
|
120
|
+
</CardHeader>
|
|
121
|
+
</Card>
|
|
122
|
+
))}
|
|
126
123
|
</Block>
|
|
127
124
|
</Container>
|
|
128
125
|
</Section>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { For } from '@askrjs/askr/control';
|
|
2
1
|
import { Link } from '@askrjs/askr/router';
|
|
3
2
|
import { Header } from '@askrjs/themes/components';
|
|
4
3
|
import {
|
|
@@ -36,9 +35,9 @@ export function SiteHeader() {
|
|
|
36
35
|
class="navbar-group"
|
|
37
36
|
data-align="end"
|
|
38
37
|
>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
{navItems.map((item) => (
|
|
39
|
+
<NavLink href={item.href}>{item.label}</NavLink>
|
|
40
|
+
))}
|
|
42
41
|
</Nav>
|
|
43
42
|
</Box>
|
|
44
43
|
</Container>
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { For } from '@askrjs/askr/control';
|
|
2
1
|
import { Link } from '@askrjs/askr/router';
|
|
3
2
|
import { Button } from '@askrjs/ui';
|
|
4
3
|
import {
|
|
@@ -55,19 +54,17 @@ export default function Workflow() {
|
|
|
55
54
|
/>
|
|
56
55
|
|
|
57
56
|
<CardGrid>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
>
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
)}
|
|
70
|
-
</For>
|
|
57
|
+
{steps.map((step) => (
|
|
58
|
+
<Card
|
|
59
|
+
eyebrow={step.number}
|
|
60
|
+
title={step.title}
|
|
61
|
+
description={step.body}
|
|
62
|
+
>
|
|
63
|
+
<p>
|
|
64
|
+
<code>{step.command}</code>
|
|
65
|
+
</p>
|
|
66
|
+
</Card>
|
|
67
|
+
))}
|
|
71
68
|
</CardGrid>
|
|
72
69
|
|
|
73
70
|
<Card
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { For } from '@askrjs/askr/control';
|
|
2
1
|
import { Link } from '@askrjs/askr/router';
|
|
3
2
|
import { Button } from '@askrjs/ui';
|
|
4
3
|
import {
|
|
@@ -51,15 +50,13 @@ export default function Content() {
|
|
|
51
50
|
/>
|
|
52
51
|
|
|
53
52
|
<CardGrid>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)}
|
|
62
|
-
</For>
|
|
53
|
+
{routeMap.map((route) => (
|
|
54
|
+
<Card
|
|
55
|
+
eyebrow={route.path}
|
|
56
|
+
title={route.title}
|
|
57
|
+
description={route.note}
|
|
58
|
+
/>
|
|
59
|
+
))}
|
|
63
60
|
</CardGrid>
|
|
64
61
|
</>
|
|
65
62
|
);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { For } from '@askrjs/askr/control';
|
|
2
1
|
import { Link } from '@askrjs/askr/router';
|
|
3
2
|
import { Button } from '@askrjs/ui';
|
|
4
3
|
import {
|
|
@@ -43,11 +42,9 @@ export default function Home() {
|
|
|
43
42
|
/>
|
|
44
43
|
|
|
45
44
|
<CardGrid>
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
)}
|
|
50
|
-
</For>
|
|
45
|
+
{highlights.map((highlight) => (
|
|
46
|
+
<Card title={highlight.title} description={highlight.body} />
|
|
47
|
+
))}
|
|
51
48
|
</CardGrid>
|
|
52
49
|
</>
|
|
53
50
|
);
|