helixevo 0.5.0 → 0.6.1
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/CHANGELOG.md +24 -0
- package/README.md +10 -7
- package/dashboard/app/coevolution/client.tsx +75 -31
- package/dashboard/app/commands/page.tsx +63 -9
- package/dashboard/app/guide/page.tsx +68 -9
- package/dashboard/app/ontology/client.tsx +88 -25
- package/dashboard/app/page.tsx +38 -0
- package/dashboard/app/projects/client.tsx +13 -19
- package/dashboard/app/research/client.tsx +29 -8
- package/dashboard/app/topology/client.tsx +54 -29
- package/dashboard/components/guide-deep-link.tsx +22 -0
- package/dashboard/components/next-step-empty-state.tsx +53 -0
- package/dashboard/components/operator-loop-trail.tsx +46 -0
- package/dashboard/components/sidebar-nav.tsx +9 -5
- package/dashboard/components/surface-jump-links.tsx +69 -0
- package/dashboard/lib/data.ts +631 -52
- package/dashboard/lib/loop-map.ts +190 -0
- package/dashboard/lib/release-spotlight.ts +17 -0
- package/dist/cli.js +528 -49
- package/package.json +1 -1
|
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
|
|
|
6
6
|
import { MetricCard } from '@/components/metric-card'
|
|
7
7
|
import { PageHero } from '@/components/page-hero'
|
|
8
8
|
import { SectionFrame } from '@/components/section-frame'
|
|
9
|
+
import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
10
|
+
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
11
|
+
import { NextStepEmptyState } from '@/components/next-step-empty-state'
|
|
9
12
|
import type { OntologyControlDashboardSummary, OntologyReviewDecisionStatus } from '@/lib/data'
|
|
10
13
|
|
|
11
14
|
type RunState = 'idle' | 'running' | 'success' | 'error'
|
|
@@ -68,43 +71,49 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
|
|
|
68
71
|
return (
|
|
69
72
|
<div style={{ display: 'grid', gap: 22 }}>
|
|
70
73
|
<PageHero
|
|
71
|
-
eyebrow="Semantic
|
|
72
|
-
title="Ontology
|
|
73
|
-
description="Inspect the stable kernel, review frontier concept hypotheses
|
|
74
|
+
eyebrow="Semantic control"
|
|
75
|
+
title="Ontology Semantic Control"
|
|
76
|
+
description="Inspect the stable kernel, review frontier concept hypotheses, promote approved extensions, track active semantic consumers, and keep ontology adoption governed rather than free-form."
|
|
74
77
|
chips={[
|
|
75
78
|
{ label: `${dashboard.summary.frontier} frontier`, tone: dashboard.summary.frontier > 0 ? 'yellow' : 'neutral' },
|
|
76
79
|
{ label: `${dashboard.summary.reviewOpen} open review`, tone: dashboard.summary.reviewOpen > 0 ? 'yellow' : 'green' },
|
|
77
80
|
{ label: `${dashboard.summary.extensions} approved extensions`, tone: dashboard.summary.extensions > 0 ? 'blue' : 'neutral' },
|
|
78
|
-
{ label: `${dashboard.
|
|
81
|
+
{ label: `${dashboard.adoption.activeConcepts} active concepts`, tone: dashboard.adoption.activeConcepts > 0 ? 'green' : 'neutral' },
|
|
82
|
+
{ label: `${dashboard.adoption.routesInfluenced} semantically influenced routes`, tone: dashboard.adoption.routesInfluenced > 0 ? 'purple' : 'neutral' },
|
|
79
83
|
{ label: formatMode(dashboard.governance.activeMode), tone: dashboard.governance.activeMode === 'transfer-focused' ? 'purple' : dashboard.governance.activeMode === 'project-critical' ? 'yellow' : 'blue' },
|
|
80
84
|
]}
|
|
81
85
|
actions={
|
|
82
86
|
<div style={{ display: 'grid', gap: 12 }}>
|
|
83
87
|
<div className="hero-note-card">
|
|
84
88
|
<div className="hero-note-label">Native ontology state</div>
|
|
85
|
-
<div className="hero-note-title">Kernel +
|
|
86
|
-
<div className="hero-note-copy">
|
|
89
|
+
<div className="hero-note-title">Kernel + review + semantic adoption</div>
|
|
90
|
+
<div className="hero-note-copy">Use this surface to move from frontier hypotheses into approved extensions, inspect active semantic consumers, and manage deprecation with operator-visible risk rather than hidden drift.</div>
|
|
87
91
|
</div>
|
|
88
|
-
<div style={{ display: '
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
<div style={{ display: 'grid', gap: 10 }}>
|
|
93
|
+
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
|
|
94
|
+
<button onClick={() => runAction('refresh', {}, 'ontology refresh')} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Refresh ontology frontier</button>
|
|
95
|
+
</div>
|
|
96
|
+
<SurfaceJumpLinks surface="ontology" variant="compact" title="Semantic handoffs" />
|
|
92
97
|
</div>
|
|
93
98
|
</div>
|
|
94
99
|
}
|
|
95
100
|
/>
|
|
96
101
|
|
|
102
|
+
<OperatorLoopTrail surface="ontology" />
|
|
103
|
+
|
|
97
104
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
|
|
98
105
|
<MetricCard label="Kernel concepts" value={dashboard.summary.kernelConcepts} sublabel={`${dashboard.kernel.relationFamilies.length} relation families`} tone="purple" icon="◎" />
|
|
99
106
|
<MetricCard label="Frontier hypotheses" value={dashboard.summary.frontier} sublabel={`${dashboard.summary.reviewOpen} open • ${dashboard.summary.deferred} deferred`} tone={dashboard.summary.reviewOpen > 0 ? 'yellow' : 'neutral'} icon="◇" />
|
|
100
|
-
<MetricCard label="Approved extensions" value={dashboard.summary.extensions} sublabel={`${dashboard.summary.deprecated} deprecated`} tone={dashboard.summary.extensions > 0 ? 'blue' : 'neutral'} icon="↑" />
|
|
107
|
+
<MetricCard label="Approved extensions" value={dashboard.summary.extensions} sublabel={`${dashboard.summary.deprecated} deprecated • ${dashboard.adoption.unusedExtensions} unused`} tone={dashboard.summary.extensions > 0 ? 'blue' : 'neutral'} icon="↑" />
|
|
108
|
+
<MetricCard label="Active semantic concepts" value={dashboard.adoption.activeConcepts} sublabel={`${dashboard.adoption.totalBindings} bindings • ${dashboard.adoption.routesInfluenced} routed influences`} tone={dashboard.adoption.activeConcepts > 0 ? 'green' : 'neutral'} icon="⇄" />
|
|
109
|
+
<MetricCard label="Deprecation-sensitive" value={dashboard.adoption.conceptsAtDeprecationRisk} sublabel="approved concepts with live consumers" tone={dashboard.adoption.conceptsAtDeprecationRisk > 0 ? 'yellow' : 'neutral'} icon="!" />
|
|
101
110
|
<MetricCard label="Concept changes" value={dashboard.summary.changeEvents} sublabel={`${dashboard.summary.promoted} promoted • ${dashboard.summary.rejected} rejected`} tone={dashboard.summary.changeEvents > 0 ? 'green' : 'neutral'} icon="⇄" />
|
|
102
111
|
</div>
|
|
103
112
|
|
|
104
113
|
<SectionFrame
|
|
105
114
|
eyebrow="Kernel"
|
|
106
115
|
title="Stable semantic anchor"
|
|
107
|
-
description="The kernel remains the constitutional layer.
|
|
116
|
+
description="The kernel remains the constitutional layer. HelixEvo still keeps it stable while governed frontier review, approved extensions, and semantic adoption grow around it."
|
|
108
117
|
>
|
|
109
118
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
|
110
119
|
<span className="badge badge-gray">version {dashboard.kernel.version}</span>
|
|
@@ -124,6 +133,45 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
|
|
|
124
133
|
</div>
|
|
125
134
|
</SectionFrame>
|
|
126
135
|
|
|
136
|
+
<SectionFrame
|
|
137
|
+
eyebrow="Adoption"
|
|
138
|
+
title="Semantic consumer coverage"
|
|
139
|
+
description="Approved concepts now become visible as live semantic consumers across pressure, route rationale, transfer, and topology interpretation rather than remaining passive approved vocabulary."
|
|
140
|
+
>
|
|
141
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 16 }}>
|
|
142
|
+
<div className="guide-dimension-card" style={{ borderLeftColor: 'var(--green)' }}>
|
|
143
|
+
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--green)' }}>Top active concepts</div>
|
|
144
|
+
<div style={{ display: 'grid', gap: 8, marginTop: 10 }}>
|
|
145
|
+
{dashboard.adoption.topActiveConcepts.length > 0 ? dashboard.adoption.topActiveConcepts.map((concept) => (
|
|
146
|
+
<div key={concept.conceptId} style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>
|
|
147
|
+
<strong style={{ color: 'var(--text)' }}>{concept.conceptName}</strong>
|
|
148
|
+
<div>{concept.totalBindings} bindings • {Object.entries(concept.bindingsByTargetType).map(([target, count]) => `${target}:${count}`).join(' • ')}</div>
|
|
149
|
+
</div>
|
|
150
|
+
)) : <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>No active semantic consumers yet.</div>}
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
<div className="guide-dimension-card" style={{ borderLeftColor: 'var(--yellow)' }}>
|
|
154
|
+
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--yellow)' }}>Deprecation risk</div>
|
|
155
|
+
<div style={{ display: 'grid', gap: 8, marginTop: 10 }}>
|
|
156
|
+
{dashboard.adoption.atRiskConcepts.length > 0 ? dashboard.adoption.atRiskConcepts.map((concept) => (
|
|
157
|
+
<div key={concept.conceptId} style={{ fontSize: 12, color: 'var(--text-dim)', lineHeight: 1.6 }}>
|
|
158
|
+
<strong style={{ color: 'var(--text)' }}>{concept.conceptName}</strong>
|
|
159
|
+
<div>{concept.warning}</div>
|
|
160
|
+
</div>
|
|
161
|
+
)) : <div style={{ fontSize: 12, color: 'var(--text-dim)' }}>No deprecation-sensitive concepts right now.</div>}
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 16 }}>
|
|
166
|
+
<span className="badge badge-gray">bindings → signals {dashboard.adoption.bindingsByTargetType['pressure-signal'] ?? 0}</span>
|
|
167
|
+
<span className="badge badge-gray">motifs {dashboard.adoption.bindingsByTargetType['pressure-motif'] ?? 0}</span>
|
|
168
|
+
<span className="badge badge-gray">routes {dashboard.adoption.bindingsByTargetType['route-recommendation'] ?? 0}</span>
|
|
169
|
+
<span className="badge badge-gray">transfers {dashboard.adoption.bindingsByTargetType['transfer-event'] ?? 0}</span>
|
|
170
|
+
<span className="badge badge-gray">topology {dashboard.adoption.bindingsByTargetType['topology-review'] ?? 0}</span>
|
|
171
|
+
<span className="badge badge-gray">unused extensions {dashboard.adoption.unusedExtensions}</span>
|
|
172
|
+
</div>
|
|
173
|
+
</SectionFrame>
|
|
174
|
+
|
|
127
175
|
<SectionFrame
|
|
128
176
|
eyebrow="Frontier"
|
|
129
177
|
title="Reviewable concept hypotheses"
|
|
@@ -156,10 +204,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
|
|
|
156
204
|
</div>
|
|
157
205
|
</div>
|
|
158
206
|
)) : (
|
|
159
|
-
<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
207
|
+
<NextStepEmptyState
|
|
208
|
+
title="No ontology frontier concepts yet"
|
|
209
|
+
description="Run a frontier refresh after pressure motifs, project gaps, or topology review patterns accumulate. Frontier creation is the first step before any concept can become active semantic control."
|
|
210
|
+
command="helixevo ontology --refresh"
|
|
211
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
|
|
212
|
+
guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
|
|
213
|
+
/>
|
|
163
214
|
)}
|
|
164
215
|
</div>
|
|
165
216
|
</SectionFrame>
|
|
@@ -167,7 +218,7 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
|
|
|
167
218
|
<SectionFrame
|
|
168
219
|
eyebrow="Extensions"
|
|
169
220
|
title="Approved ontology extensions"
|
|
170
|
-
description="Promoted concepts live here as approved semantic vocabulary.
|
|
221
|
+
description="Promoted concepts live here as approved semantic vocabulary. Once active, they can shape pressure, route rationale, transfer interpretation, and topology review while deprecation remains bounded and explicit."
|
|
171
222
|
>
|
|
172
223
|
<div style={{ display: 'grid', gap: 12 }}>
|
|
173
224
|
{dashboard.extensions.length > 0 ? dashboard.extensions.map((concept) => (
|
|
@@ -180,22 +231,31 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
|
|
|
180
231
|
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
|
|
181
232
|
<span className={`badge badge-${toneForConcept(concept.conceptKind)}`}>{concept.conceptKind}</span>
|
|
182
233
|
<span className="badge badge-gray">{concept.status}</span>
|
|
234
|
+
<span className="badge badge-gray">{concept.adoptionCount} bindings</span>
|
|
183
235
|
<span className="badge badge-gray">{(concept.evidenceIds?.length ?? 0)} evidence ids</span>
|
|
236
|
+
{concept.warning ? <span className="badge badge-yellow">deprecation risk</span> : null}
|
|
184
237
|
</div>
|
|
185
238
|
</div>
|
|
186
239
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 12 }}>
|
|
187
240
|
<span className="badge badge-gray">{(concept.projectIds?.length ?? 0)} projects</span>
|
|
241
|
+
<span className="badge badge-gray">signals {concept.bindingsByTargetType['pressure-signal'] ?? 0}</span>
|
|
242
|
+
<span className="badge badge-gray">routes {concept.bindingsByTargetType['route-recommendation'] ?? 0}</span>
|
|
243
|
+
<span className="badge badge-gray">transfers {concept.bindingsByTargetType['transfer-event'] ?? 0}</span>
|
|
188
244
|
<span className="badge badge-gray">created {formatDate(concept.createdAt)}</span>
|
|
189
245
|
{concept.status !== 'deprecated' ? (
|
|
190
246
|
<button onClick={() => runAction('deprecate', { conceptId: concept.id, rationale: `Deprecate ontology extension ${concept.name} after operator review.` }, `deprecate ${concept.name}`)} disabled={pendingKey === concept.id} className="badge badge-gray" style={{ border: 'none', cursor: 'pointer' }}>Deprecate</button>
|
|
191
247
|
) : null}
|
|
192
248
|
</div>
|
|
249
|
+
{concept.warning ? <div className="signal-text" style={{ marginTop: 10 }}>• {concept.warning}</div> : null}
|
|
193
250
|
</div>
|
|
194
251
|
)) : (
|
|
195
|
-
<
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
252
|
+
<NextStepEmptyState
|
|
253
|
+
title="No approved extensions yet"
|
|
254
|
+
description="Approved extensions appear after frontier concepts pass semantic review. Promotion is what turns reviewed ontology into live semantic adoption."
|
|
255
|
+
command="helixevo ontology --review <conceptId> --decision promote"
|
|
256
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
|
|
257
|
+
guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
|
|
258
|
+
/>
|
|
199
259
|
)}
|
|
200
260
|
</div>
|
|
201
261
|
</SectionFrame>
|
|
@@ -219,10 +279,13 @@ export default function OntologyClient({ initialDashboard }: { initialDashboard:
|
|
|
219
279
|
</div>
|
|
220
280
|
</div>
|
|
221
281
|
)) : (
|
|
222
|
-
<
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
282
|
+
<NextStepEmptyState
|
|
283
|
+
title="No ontology changes logged yet"
|
|
284
|
+
description="Refresh the frontier or review a concept to create the first native ontology events and start a visible semantic history instead of hidden drift."
|
|
285
|
+
command="helixevo ontology --refresh"
|
|
286
|
+
pageLink={{ label: 'Open Topology', href: '/topology', tone: 'yellow' }}
|
|
287
|
+
guideLink={{ label: 'Guide · Semantic Control', anchor: 'semanticcontrol', tone: 'green' }}
|
|
288
|
+
/>
|
|
226
289
|
)}
|
|
227
290
|
</div>
|
|
228
291
|
</SectionFrame>
|
package/dashboard/app/page.tsx
CHANGED
|
@@ -4,6 +4,9 @@ import { OverviewActions } from '@/components/overview-actions'
|
|
|
4
4
|
import { PageHero } from '@/components/page-hero'
|
|
5
5
|
import { MetricCard } from '@/components/metric-card'
|
|
6
6
|
import { SectionFrame } from '@/components/section-frame'
|
|
7
|
+
import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
8
|
+
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
9
|
+
import { CURRENT_RELEASE_SPOTLIGHT } from '@/lib/release-spotlight'
|
|
7
10
|
|
|
8
11
|
export const dynamic = 'force-dynamic'
|
|
9
12
|
|
|
@@ -57,6 +60,8 @@ export default function Overview() {
|
|
|
57
60
|
}
|
|
58
61
|
/>
|
|
59
62
|
|
|
63
|
+
<OperatorLoopTrail surface="overview" />
|
|
64
|
+
|
|
60
65
|
<div className="grid-5">
|
|
61
66
|
<MetricCard label="Total skills" value={summary.skills.total} sublabel={`${summary.skills.evolved} evolved • ${summary.skillTests} skill tests`} tone="purple" href="/network" icon="◆" />
|
|
62
67
|
<MetricCard label="Accepted proposals" value={summary.evolution.accepted} sublabel={`${summary.evolution.rejected} rejected`} tone="green" href="/evolution" icon="✓" />
|
|
@@ -65,6 +70,29 @@ export default function Overview() {
|
|
|
65
70
|
<MetricCard label="Frontier candidates" value={frontier.programs.length} sublabel={`${summary.canaries} active canaries`} tone="neutral" href="/frontier" icon="▲" />
|
|
66
71
|
</div>
|
|
67
72
|
|
|
73
|
+
<SectionFrame
|
|
74
|
+
eyebrow={`Release spotlight · v${CURRENT_RELEASE_SPOTLIGHT.version}`}
|
|
75
|
+
title={CURRENT_RELEASE_SPOTLIGHT.title}
|
|
76
|
+
description={CURRENT_RELEASE_SPOTLIGHT.summary}
|
|
77
|
+
tone="blue"
|
|
78
|
+
>
|
|
79
|
+
<div className="grid-2" style={{ gap: 16 }}>
|
|
80
|
+
<div style={{ display: 'grid', gap: 10 }}>
|
|
81
|
+
{CURRENT_RELEASE_SPOTLIGHT.bullets.map((item) => (
|
|
82
|
+
<div key={item} className="signal-text">• {item}</div>
|
|
83
|
+
))}
|
|
84
|
+
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 4 }}>
|
|
85
|
+
{CURRENT_RELEASE_SPOTLIGHT.nextActions.map((action) => (
|
|
86
|
+
<Link key={action.href} href={action.href} className={`hero-chip hero-chip-${action.tone}`} style={{ textDecoration: 'none' }}>
|
|
87
|
+
{action.label}
|
|
88
|
+
</Link>
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
<SurfaceJumpLinks surface="overview" variant="panel" title="Jump into the updated loop" />
|
|
93
|
+
</div>
|
|
94
|
+
</SectionFrame>
|
|
95
|
+
|
|
68
96
|
<SectionFrame
|
|
69
97
|
eyebrow="Execution layer"
|
|
70
98
|
title="Quick actions"
|
|
@@ -151,6 +179,14 @@ export default function Overview() {
|
|
|
151
179
|
href="/ontology"
|
|
152
180
|
icon="◎"
|
|
153
181
|
/>
|
|
182
|
+
<MetricCard
|
|
183
|
+
label="Active semantic concepts"
|
|
184
|
+
value={ontology.ontologyLoop.adoption.activeConcepts}
|
|
185
|
+
sublabel={`${ontology.ontologyLoop.adoption.totalBindings} bindings • ${ontology.ontologyLoop.adoption.routesInfluenced} influenced routes`}
|
|
186
|
+
tone={ontology.ontologyLoop.adoption.activeConcepts > 0 ? 'green' : 'neutral'}
|
|
187
|
+
href="/ontology"
|
|
188
|
+
icon="⇄"
|
|
189
|
+
/>
|
|
154
190
|
<MetricCard
|
|
155
191
|
label="Observed mutation verbs"
|
|
156
192
|
value={ontology.mutationOperationsObserved}
|
|
@@ -175,6 +211,8 @@ export default function Overview() {
|
|
|
175
211
|
<span className="badge badge-gray">{ontology.pressureMotifs.promotionReady} motifs currently recommend generalize</span>
|
|
176
212
|
<span className="badge badge-gray">{ontology.transferEvents.total} transfer events logged ({ontology.transferEvents.realized} realized)</span>
|
|
177
213
|
<span className="badge badge-gray">ontology → {ontology.ontologyLoop.frontier} frontier • {ontology.ontologyLoop.extensions} extensions • {ontology.ontologyLoop.changeEvents} changes</span>
|
|
214
|
+
<span className="badge badge-gray">semantic adoption → {ontology.ontologyLoop.adoption.activeConcepts} active concepts • {ontology.ontologyLoop.adoption.totalBindings} bindings • {ontology.ontologyLoop.adoption.routesInfluenced} influenced routes</span>
|
|
215
|
+
<span className="badge badge-gray">deprecation risk → {ontology.ontologyLoop.adoption.conceptsAtDeprecationRisk} concepts • {ontology.ontologyLoop.adoption.unusedExtensions} unused extensions</span>
|
|
178
216
|
<span className="badge badge-gray">topology → {ontology.topologyReviews.open} open • {ontology.topologyReviews.accepted} accepted • {ontology.topologyReviews.generatedFromManualReview} manual-route</span>
|
|
179
217
|
<span className="badge badge-gray">execution → {ontology.topologyExecution.prepared} prepared • {ontology.topologyExecution.applied} applied • {ontology.topologyExecution.rolledBack} rolled back</span>
|
|
180
218
|
<Link href="/ontology" className="badge badge-blue" style={{ textDecoration: 'none' }}>Open ontology control</Link>
|
|
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
|
|
|
6
6
|
import { MetricCard } from '@/components/metric-card'
|
|
7
7
|
import { PageHero } from '@/components/page-hero'
|
|
8
8
|
import { SectionFrame } from '@/components/section-frame'
|
|
9
|
+
import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
10
|
+
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
11
|
+
import { NextStepEmptyState } from '@/components/next-step-empty-state'
|
|
9
12
|
import type { ProjectProfile } from '@/lib/data'
|
|
10
13
|
|
|
11
14
|
type SetupState = 'idle' | 'analyzing' | 'done' | 'error' | 'cancelled'
|
|
@@ -364,18 +367,13 @@ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTr
|
|
|
364
367
|
<div className="hero-note-title">Analyze → Match → Gap scan → Action</div>
|
|
365
368
|
<div className="hero-note-copy">Run a profile, review the skill fit, then send uncovered needs into Research or the Skill Network.</div>
|
|
366
369
|
</div>
|
|
367
|
-
<
|
|
368
|
-
<Link href="/network" style={buttonStyle('purple')}>
|
|
369
|
-
Open Skill Network
|
|
370
|
-
</Link>
|
|
371
|
-
<Link href="/research" style={buttonStyle('blue')}>
|
|
372
|
-
Open Research
|
|
373
|
-
</Link>
|
|
374
|
-
</div>
|
|
370
|
+
<SurfaceJumpLinks surface="projects" variant="compact" title="Observation handoffs" />
|
|
375
371
|
</div>
|
|
376
372
|
}
|
|
377
373
|
/>
|
|
378
374
|
|
|
375
|
+
<OperatorLoopTrail surface="projects" />
|
|
376
|
+
|
|
379
377
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16, marginBottom: 24 }}>
|
|
380
378
|
<MetricCard
|
|
381
379
|
label="Portfolio"
|
|
@@ -764,17 +762,13 @@ export default function ProjectsClient({ profiles, skillCount, projectAnalysisTr
|
|
|
764
762
|
tone="yellow"
|
|
765
763
|
>
|
|
766
764
|
{profiles.length === 0 ? (
|
|
767
|
-
<
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
<div className="empty-state-desc">
|
|
775
|
-
Start with a local folder or GitHub repository. The resulting profile will show matched skills, uncovered gaps, and recommended next steps.
|
|
776
|
-
</div>
|
|
777
|
-
</div>
|
|
765
|
+
<NextStepEmptyState
|
|
766
|
+
title="No analyzed projects yet"
|
|
767
|
+
description={`Start with a local folder or GitHub repository. The resulting profile will show matched skills, uncovered gaps, activation traces, and the next routed action against your ${skillCount} current skills.`}
|
|
768
|
+
command="helixevo project-setup <path>"
|
|
769
|
+
pageLink={{ label: 'Open Research', href: '/research', tone: 'blue' }}
|
|
770
|
+
guideLink={{ label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'purple' }}
|
|
771
|
+
/>
|
|
778
772
|
) : (
|
|
779
773
|
<div style={{ display: 'grid', gap: 18 }}>
|
|
780
774
|
{profiles.map(profile => {
|
|
@@ -5,6 +5,9 @@ import { ConsolePanel } from '@/components/console-panel'
|
|
|
5
5
|
import { MetricCard } from '@/components/metric-card'
|
|
6
6
|
import { PageHero } from '@/components/page-hero'
|
|
7
7
|
import { SectionFrame } from '@/components/section-frame'
|
|
8
|
+
import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
9
|
+
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
10
|
+
import { NextStepEmptyState } from '@/components/next-step-empty-state'
|
|
8
11
|
|
|
9
12
|
interface Discovery {
|
|
10
13
|
id: string
|
|
@@ -190,8 +193,20 @@ export default function ResearchClient({ buffer, projects, coevolution }: Props)
|
|
|
190
193
|
{ label: `${buffer.drafts.length} drafts`, tone: 'yellow' },
|
|
191
194
|
{ label: `${nearPass.length} near-pass drafts`, tone: 'green' },
|
|
192
195
|
]}
|
|
196
|
+
actions={
|
|
197
|
+
<div style={{ display: 'grid', gap: 12 }}>
|
|
198
|
+
<div className="hero-note-card">
|
|
199
|
+
<div className="hero-note-label">Discovery handoff</div>
|
|
200
|
+
<div className="hero-note-title">Observe gaps → research patterns → draft reusable skills</div>
|
|
201
|
+
<div className="hero-note-copy">Use Research when recurring project demand needs external evidence before it can become a stronger response or semantic pattern.</div>
|
|
202
|
+
</div>
|
|
203
|
+
<SurfaceJumpLinks surface="research" variant="compact" title="Discovery handoffs" />
|
|
204
|
+
</div>
|
|
205
|
+
}
|
|
193
206
|
/>
|
|
194
207
|
|
|
208
|
+
<OperatorLoopTrail surface="research" />
|
|
209
|
+
|
|
195
210
|
<SectionFrame
|
|
196
211
|
eyebrow="Why research now"
|
|
197
212
|
title="Current pressure handoff"
|
|
@@ -371,10 +386,13 @@ export default function ResearchClient({ buffer, projects, coevolution }: Props)
|
|
|
371
386
|
tone="blue"
|
|
372
387
|
>
|
|
373
388
|
{buffer.discoveries.length === 0 ? (
|
|
374
|
-
<
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
389
|
+
<NextStepEmptyState
|
|
390
|
+
title="No discoveries yet"
|
|
391
|
+
description="Run research to search the web for techniques your skill network does not cover yet, then compare those discoveries against the current routed pressure picture."
|
|
392
|
+
command="helixevo research"
|
|
393
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'green' }}
|
|
394
|
+
guideLink={{ label: 'Guide · Adaptation Loop', anchor: 'loop', tone: 'purple' }}
|
|
395
|
+
/>
|
|
378
396
|
) : (
|
|
379
397
|
<div className="summary-list">
|
|
380
398
|
{buffer.discoveries.sort((a, b) => b.score - a.score).map((discovery) => (
|
|
@@ -400,10 +418,13 @@ export default function ResearchClient({ buffer, projects, coevolution }: Props)
|
|
|
400
418
|
tone="yellow"
|
|
401
419
|
>
|
|
402
420
|
{buffer.drafts.length === 0 ? (
|
|
403
|
-
<
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
421
|
+
<NextStepEmptyState
|
|
422
|
+
title="No drafts yet"
|
|
423
|
+
description="Once research has enough evidence, it will generate the first draft skills and evaluate them against the current thresholds before they enter the wider loop."
|
|
424
|
+
command="helixevo research --verbose"
|
|
425
|
+
pageLink={{ label: 'Open Projects', href: '/projects', tone: 'blue' }}
|
|
426
|
+
guideLink={{ label: 'Guide · Quick Start', anchor: 'quickstart', tone: 'purple' }}
|
|
427
|
+
/>
|
|
407
428
|
) : (
|
|
408
429
|
<div className="summary-list">
|
|
409
430
|
{buffer.drafts.sort((a, b) => b.avgScore - a.avgScore).map((draft) => (
|
|
@@ -6,6 +6,9 @@ import { ConsolePanel } from '@/components/console-panel'
|
|
|
6
6
|
import { MetricCard } from '@/components/metric-card'
|
|
7
7
|
import { PageHero } from '@/components/page-hero'
|
|
8
8
|
import { SectionFrame } from '@/components/section-frame'
|
|
9
|
+
import { OperatorLoopTrail } from '@/components/operator-loop-trail'
|
|
10
|
+
import { SurfaceJumpLinks } from '@/components/surface-jump-links'
|
|
11
|
+
import { NextStepEmptyState } from '@/components/next-step-empty-state'
|
|
9
12
|
import type { GovernanceModeName, GovernanceState, TopologyDashboardSummary, TopologyReviewDecisionStatus, TopologyReviewStatus } from '@/lib/data'
|
|
10
13
|
|
|
11
14
|
type RunState = 'idle' | 'running' | 'success' | 'error' | 'stopped'
|
|
@@ -251,16 +254,18 @@ export default function TopologyClient({
|
|
|
251
254
|
<div className="hero-note-title">{formatMode(dashboard.governance.activeMode)}</div>
|
|
252
255
|
<div className="hero-note-copy">{dashboard.governance.profile.explanation}</div>
|
|
253
256
|
</div>
|
|
254
|
-
<div style={{ display: '
|
|
255
|
-
<
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
<
|
|
257
|
+
<div style={{ display: 'grid', gap: 10 }}>
|
|
258
|
+
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
|
|
259
|
+
<button onClick={handleOptimize} disabled={runState === 'running'} className="badge badge-blue" style={{ border: 'none', cursor: 'pointer' }}>Run graph optimize</button>
|
|
260
|
+
</div>
|
|
261
|
+
<SurfaceJumpLinks surface="topology" variant="compact" title="Structural handoffs" />
|
|
259
262
|
</div>
|
|
260
263
|
</div>
|
|
261
264
|
}
|
|
262
265
|
/>
|
|
263
266
|
|
|
267
|
+
<OperatorLoopTrail surface="topology" />
|
|
268
|
+
|
|
264
269
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 16 }}>
|
|
265
270
|
<MetricCard label="Open review items" value={dashboard.summary.open} sublabel={`${dashboard.summary.deferred} deferred • ${dashboard.summary.accepted} accepted`} tone={dashboard.summary.open > 0 ? 'yellow' : 'green'} icon="⇄" />
|
|
266
271
|
<MetricCard label="Accepted ready" value={dashboard.acceptedReady.length} sublabel="accepted candidates not yet prepared for execution" tone={dashboard.acceptedReady.length > 0 ? 'blue' : 'neutral'} icon="✓" />
|
|
@@ -286,6 +291,7 @@ export default function TopologyClient({
|
|
|
286
291
|
<span className={`badge badge-${toneForChange(candidate.changeType)}`}>{candidate.changeType}</span>
|
|
287
292
|
<span className="badge badge-gray">accepted</span>
|
|
288
293
|
<span className="badge badge-gray">risk {(candidate.riskScore * 100).toFixed(0)}%</span>
|
|
294
|
+
{(candidate.semanticConceptIds ?? []).slice(0, 2).map((conceptId) => <span key={`${candidate.id}-${conceptId}`} className="badge badge-green">{conceptId}</span>)}
|
|
289
295
|
</div>
|
|
290
296
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 12 }}>
|
|
291
297
|
<button
|
|
@@ -299,10 +305,13 @@ export default function TopologyClient({
|
|
|
299
305
|
</div>
|
|
300
306
|
</div>
|
|
301
307
|
)) : (
|
|
302
|
-
<
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
308
|
+
<NextStepEmptyState
|
|
309
|
+
title="No accepted candidates waiting for preparation"
|
|
310
|
+
description="Accept a topology review item first, then it can enter the reviewed execution pipeline and become a prepared apply plan."
|
|
311
|
+
command="helixevo graph --optimize"
|
|
312
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
|
|
313
|
+
guideLink={{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow' }}
|
|
314
|
+
/>
|
|
306
315
|
)}
|
|
307
316
|
</div>
|
|
308
317
|
|
|
@@ -341,10 +350,13 @@ export default function TopologyClient({
|
|
|
341
350
|
</div>
|
|
342
351
|
</div>
|
|
343
352
|
)) : (
|
|
344
|
-
<
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
353
|
+
<NextStepEmptyState
|
|
354
|
+
title="No prepared plans yet"
|
|
355
|
+
description="Prepared plans will appear here after an accepted review candidate is converted into an explicit apply plan with snapshot-backed safety."
|
|
356
|
+
command="helixevo topology --prepare <candidateId>"
|
|
357
|
+
pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
|
|
358
|
+
guideLink={{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow' }}
|
|
359
|
+
/>
|
|
348
360
|
)}
|
|
349
361
|
</div>
|
|
350
362
|
</div>
|
|
@@ -414,6 +426,7 @@ export default function TopologyClient({
|
|
|
414
426
|
<span className={`badge badge-${toneForChange(candidate.changeType)}`}>{candidate.changeType}</span>
|
|
415
427
|
<span className="badge badge-gray">{candidate.source}</span>
|
|
416
428
|
<span className="badge badge-gray">confidence {(candidate.confidence * 100).toFixed(0)}%</span>
|
|
429
|
+
{(candidate.semanticConceptIds ?? []).slice(0, 2).map((conceptId) => <span key={`${candidate.id}-${conceptId}`} className="badge badge-green">{conceptId}</span>)}
|
|
417
430
|
</div>
|
|
418
431
|
{candidate.latestDecision ? (
|
|
419
432
|
<div style={{ display: 'grid', gap: 4, marginTop: 10 }}>
|
|
@@ -424,10 +437,13 @@ export default function TopologyClient({
|
|
|
424
437
|
</div>
|
|
425
438
|
</div>
|
|
426
439
|
)) : (
|
|
427
|
-
<
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
440
|
+
<NextStepEmptyState
|
|
441
|
+
title="No topology decisions yet"
|
|
442
|
+
description="Run graph optimize to populate the queue, then accept, defer, or reject structural candidates from this page so the review memory becomes explicit."
|
|
443
|
+
command="helixevo graph --optimize"
|
|
444
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
|
|
445
|
+
guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'blue' }}
|
|
446
|
+
/>
|
|
431
447
|
)}
|
|
432
448
|
</div>
|
|
433
449
|
</SectionFrame>
|
|
@@ -466,6 +482,7 @@ export default function TopologyClient({
|
|
|
466
482
|
<span className="badge badge-gray">{candidate.source}</span>
|
|
467
483
|
<span className="badge badge-gray">confidence {(candidate.confidence * 100).toFixed(0)}%</span>
|
|
468
484
|
<span className="badge badge-gray">risk {(candidate.riskScore * 100).toFixed(0)}%</span>
|
|
485
|
+
{(candidate.semanticConceptIds ?? []).slice(0, 2).map((conceptId) => <span key={`${candidate.id}-${conceptId}`} className="badge badge-green">{conceptId}</span>)}
|
|
469
486
|
{(candidate.projectIds ?? []).slice(0, 3).map((projectId) => <span key={`${candidate.id}-${projectId}`} className="badge badge-gray">{projectId}</span>)}
|
|
470
487
|
</div>
|
|
471
488
|
<div style={{ display: 'grid', gap: 4, marginTop: 10 }}>
|
|
@@ -488,10 +505,13 @@ export default function TopologyClient({
|
|
|
488
505
|
</div>
|
|
489
506
|
</div>
|
|
490
507
|
)) : (
|
|
491
|
-
<
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
508
|
+
<NextStepEmptyState
|
|
509
|
+
title="No topology backlog yet"
|
|
510
|
+
description="Refresh structural review candidates from this page to turn manual-review into a populated operator lane instead of a placeholder route label."
|
|
511
|
+
command="helixevo graph --optimize"
|
|
512
|
+
pageLink={{ label: 'Open Ontology', href: '/ontology', tone: 'green' }}
|
|
513
|
+
guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'blue' }}
|
|
514
|
+
/>
|
|
495
515
|
)}
|
|
496
516
|
</div>
|
|
497
517
|
</SectionFrame>
|
|
@@ -536,10 +556,12 @@ export default function TopologyClient({
|
|
|
536
556
|
</div>
|
|
537
557
|
</div>
|
|
538
558
|
)) : (
|
|
539
|
-
<
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
559
|
+
<NextStepEmptyState
|
|
560
|
+
title="No applied topology history yet"
|
|
561
|
+
description="Applied topology history will appear here once a prepared safe plan is executed and snapshot-backed rollback continuity becomes relevant."
|
|
562
|
+
command="helixevo topology --apply <planId>"
|
|
563
|
+
guideLink={{ label: 'Guide · Maturity & Safety', anchor: 'maturity', tone: 'yellow' }}
|
|
564
|
+
/>
|
|
543
565
|
)}
|
|
544
566
|
</div>
|
|
545
567
|
</SectionFrame>
|
|
@@ -564,10 +586,13 @@ export default function TopologyClient({
|
|
|
564
586
|
</div>
|
|
565
587
|
</div>
|
|
566
588
|
)) : (
|
|
567
|
-
<
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
589
|
+
<NextStepEmptyState
|
|
590
|
+
title="No structural candidates stored yet"
|
|
591
|
+
description="The structural review ledger will populate after the first topology refresh and then persist reviewed intent across decisions and execution."
|
|
592
|
+
command="helixevo graph --optimize"
|
|
593
|
+
pageLink={{ label: 'Open Co-Evolution', href: '/coevolution', tone: 'purple' }}
|
|
594
|
+
guideLink={{ label: 'Guide · Surface Map', anchor: 'surfaces', tone: 'blue' }}
|
|
595
|
+
/>
|
|
571
596
|
)}
|
|
572
597
|
</div>
|
|
573
598
|
</SectionFrame>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import Link from 'next/link'
|
|
2
|
+
import { guideHref, type GuideAnchorId, type SurfaceTone } from '@/lib/loop-map'
|
|
3
|
+
|
|
4
|
+
function toneClass(tone: SurfaceTone) {
|
|
5
|
+
return `hero-chip hero-chip-${tone}`
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function GuideDeepLink({
|
|
9
|
+
anchor,
|
|
10
|
+
label,
|
|
11
|
+
tone = 'neutral',
|
|
12
|
+
}: {
|
|
13
|
+
anchor: GuideAnchorId
|
|
14
|
+
label: string
|
|
15
|
+
tone?: SurfaceTone
|
|
16
|
+
}) {
|
|
17
|
+
return (
|
|
18
|
+
<Link href={guideHref(anchor)} className={toneClass(tone)} style={{ textDecoration: 'none' }}>
|
|
19
|
+
{label}
|
|
20
|
+
</Link>
|
|
21
|
+
)
|
|
22
|
+
}
|