ltcai 4.6.0 → 4.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/README.md +121 -193
- package/docs/CHANGELOG.md +78 -1
- package/docs/V4_6_0_LIVING_BRAIN_EXPERIENCE_REPORT.md +33 -19
- package/docs/V4_6_1_RELEASE_REFRESH_REPORT.md +42 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +12 -11
- package/frontend/src/App.tsx +657 -173
- package/frontend/src/components/BrainConversation.tsx +10 -2
- package/frontend/src/components/LivingBrain.tsx +197 -106
- package/frontend/src/components/ProductFlow.tsx +188 -130
- package/frontend/src/styles.css +1327 -36
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/package.json +1 -1
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +5 -5
- package/static/app/assets/index-7U86v70r.css +2 -0
- package/static/app/assets/index-D1jAPQws.js +16 -0
- package/static/app/assets/index-D1jAPQws.js.map +1 -0
- package/static/app/index.html +2 -2
- package/static/app/assets/index-By-G-Kay.css +0 -2
- package/static/app/assets/index-CJx6WuQH.js +0 -336
- package/static/app/assets/index-CJx6WuQH.js.map +0 -1
|
@@ -78,39 +78,58 @@ export function ProductFlow({ onComplete }: { onComplete: () => void }) {
|
|
|
78
78
|
}, [analysis, step]);
|
|
79
79
|
|
|
80
80
|
return (
|
|
81
|
-
<
|
|
82
|
-
<div className="
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
81
|
+
<div className="ritual-shell" aria-label="Awaken your Brain">
|
|
82
|
+
<div className="ritual-container">
|
|
83
|
+
{/* The living presence participates in the ritual at every step */}
|
|
84
|
+
<div className="ritual-brain">
|
|
85
|
+
<LivingBrain
|
|
86
|
+
state={
|
|
87
|
+
step === "login" ? "idle" :
|
|
88
|
+
step === "analysis" ? "listening" :
|
|
89
|
+
step === "recommend" ? "recalling" :
|
|
90
|
+
"thinking"
|
|
91
|
+
}
|
|
92
|
+
intensity={step === "install" ? 0.92 : 0.7}
|
|
93
|
+
size="large"
|
|
94
|
+
showLabel={false}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{step === "login" && (
|
|
99
|
+
<LoginScreen onSuccess={() => setStep("analysis")} />
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
{step === "analysis" && (
|
|
103
|
+
<AnalysisScreen
|
|
104
|
+
analysis={analysis}
|
|
105
|
+
error={analysisError}
|
|
106
|
+
onContinue={() => setStep("recommend")}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
|
|
110
|
+
{step === "recommend" && (
|
|
111
|
+
<RecommendationScreen
|
|
112
|
+
recommendations={recommendations}
|
|
113
|
+
onBack={() => setStep("analysis")}
|
|
114
|
+
onSelect={(model) => {
|
|
115
|
+
setSelected(model);
|
|
116
|
+
setStep("install");
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
)}
|
|
120
|
+
|
|
121
|
+
{step === "install" && (
|
|
122
|
+
<InstallScreen
|
|
123
|
+
model={selected || recommendations[0] || fallbackModel()}
|
|
124
|
+
onBack={() => setStep("recommend")}
|
|
125
|
+
onComplete={() => {
|
|
126
|
+
try { localStorage.setItem(FLOW_COMPLETE_KEY, "true"); } catch {}
|
|
127
|
+
onComplete();
|
|
128
|
+
}}
|
|
129
|
+
/>
|
|
130
|
+
)}
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
114
133
|
);
|
|
115
134
|
}
|
|
116
135
|
|
|
@@ -157,34 +176,36 @@ function LoginScreen({ onSuccess }: { onSuccess: () => void }) {
|
|
|
157
176
|
}
|
|
158
177
|
|
|
159
178
|
return (
|
|
160
|
-
<
|
|
161
|
-
<div className="
|
|
162
|
-
<div className="
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
<
|
|
179
|
+
<div>
|
|
180
|
+
<div className="ritual-title">Welcome to your mind.</div>
|
|
181
|
+
<div className="ritual-subtitle">This is private. Everything stays on your machine. Begin by opening a local profile for your Brain.</div>
|
|
182
|
+
|
|
183
|
+
<form onSubmit={submit} className="ritual-card" style={{ maxWidth: 420, margin: "0 auto" }}>
|
|
184
|
+
<div style={{ display: "grid", gap: "0.85rem" }}>
|
|
185
|
+
<div>
|
|
186
|
+
<div style={{ fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "1px", color: "hsl(var(--fg-muted))", marginBottom: 4 }}>Your name</div>
|
|
187
|
+
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="You" />
|
|
188
|
+
</div>
|
|
189
|
+
<div>
|
|
190
|
+
<div style={{ fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "1px", color: "hsl(var(--fg-muted))", marginBottom: 4 }}>Email (local only)</div>
|
|
191
|
+
<Input value={email} onChange={(e) => setEmail(e.target.value)} type="email" placeholder="you@local" />
|
|
192
|
+
</div>
|
|
193
|
+
<div>
|
|
194
|
+
<div style={{ fontSize: "0.75rem", textTransform: "uppercase", letterSpacing: "1px", color: "hsl(var(--fg-muted))", marginBottom: 4 }}>Password</div>
|
|
195
|
+
<Input value={password} onChange={(e) => setPassword(e.target.value)} type="password" placeholder="Create a strong local password" />
|
|
196
|
+
</div>
|
|
167
197
|
</div>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
<Input value={password} onChange={(event) => setPassword(event.target.value)} type="password" autoComplete="current-password" placeholder="Use your local password" />
|
|
180
|
-
</label>
|
|
181
|
-
{error ? <div className="flow-error">{error}</div> : null}
|
|
182
|
-
<Button className="login-submit" type="submit" disabled={busy || !email.trim()}>
|
|
183
|
-
{busy ? "Opening" : "Continue"} <ChevronRight className="h-4 w-4" />
|
|
184
|
-
</Button>
|
|
185
|
-
</form>
|
|
186
|
-
</div>
|
|
187
|
-
</section>
|
|
198
|
+
|
|
199
|
+
{error && <div style={{ marginTop: "0.85rem", padding: "0.6rem 0.85rem", background: "hsl(var(--destructive)/0.12)", border: "1px solid hsl(var(--destructive)/0.4)", borderRadius: 10, fontSize: "0.9rem" }}>{error}</div>}
|
|
200
|
+
|
|
201
|
+
<Button type="submit" disabled={busy || !email.trim()} style={{ width: "100%", marginTop: "1rem" }}>
|
|
202
|
+
{busy ? "Opening the Brain..." : "Open my Brain"}
|
|
203
|
+
</Button>
|
|
204
|
+
<div style={{ fontSize: "0.75rem", color: "hsl(var(--fg-muted))", marginTop: "0.6rem" }}>
|
|
205
|
+
Your first conversation will feel like coming home.
|
|
206
|
+
</div>
|
|
207
|
+
</form>
|
|
208
|
+
</div>
|
|
188
209
|
);
|
|
189
210
|
}
|
|
190
211
|
|
|
@@ -199,36 +220,42 @@ function AnalysisScreen({
|
|
|
199
220
|
}) {
|
|
200
221
|
const detected = buildDetectedFacts(analysis);
|
|
201
222
|
return (
|
|
202
|
-
<
|
|
203
|
-
<div className="
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<h1>Learning what your computer can do.</h1>
|
|
207
|
-
<p>Lattice checks the essentials, then recommends the best local Brain for this machine.</p>
|
|
208
|
-
</div>
|
|
209
|
-
<Badge variant={analysis ? "success" : "muted"}>{analysis ? "complete" : "analyzing"}</Badge>
|
|
223
|
+
<div>
|
|
224
|
+
<div className="ritual-title">Understanding your home.</div>
|
|
225
|
+
<div className="ritual-subtitle">
|
|
226
|
+
We are learning what kind of mind this computer can support. Your Brain will live here — quietly, privately, powerfully.
|
|
210
227
|
</div>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
<
|
|
216
|
-
<
|
|
228
|
+
|
|
229
|
+
<div className="ritual-fact-grid">
|
|
230
|
+
{detected.map((item, idx) => (
|
|
231
|
+
<div key={idx} className="ritual-fact">
|
|
232
|
+
<div className="ritual-fact-label">{item.label}</div>
|
|
233
|
+
<div className="ritual-fact-value">{item.value}</div>
|
|
234
|
+
<div style={{ fontSize: "0.8rem", color: "hsl(var(--fg-muted))", marginTop: 3 }}>{item.detail}</div>
|
|
217
235
|
</div>
|
|
218
236
|
))}
|
|
219
237
|
</div>
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
<div>
|
|
223
|
-
<
|
|
224
|
-
<
|
|
238
|
+
|
|
239
|
+
<div className="ritual-card" style={{ marginTop: "1rem" }}>
|
|
240
|
+
<div style={{ display: "flex", alignItems: "center", gap: "0.6rem" }}>
|
|
241
|
+
<Sparkles style={{ color: "hsl(var(--brain-core))" }} />
|
|
242
|
+
<div>
|
|
243
|
+
<div style={{ fontWeight: 620 }}>{analysis ? recommendedSummary(analysis) : "Preparing the best fit..."}</div>
|
|
244
|
+
<div style={{ fontSize: "0.9rem", color: "hsl(var(--fg-muted))" }}>
|
|
245
|
+
{analysis ? "A short, personal list of minds is ready for you to choose from." : "Reading your machine. This is gentle."}
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
225
248
|
</div>
|
|
226
249
|
</div>
|
|
227
|
-
|
|
228
|
-
<div className="
|
|
229
|
-
|
|
250
|
+
|
|
251
|
+
{error && <div className="ritual-card" style={{ borderColor: "hsl(var(--destructive)/0.4)", background: "hsl(var(--destructive)/0.06)" }}>{error}</div>}
|
|
252
|
+
|
|
253
|
+
<div style={{ marginTop: "1.25rem" }}>
|
|
254
|
+
<Button onClick={onContinue} disabled={!analysis && !error} style={{ minWidth: 260 }}>
|
|
255
|
+
See how your Brain can think
|
|
256
|
+
</Button>
|
|
230
257
|
</div>
|
|
231
|
-
</
|
|
258
|
+
</div>
|
|
232
259
|
);
|
|
233
260
|
}
|
|
234
261
|
|
|
@@ -243,36 +270,34 @@ function RecommendationScreen({
|
|
|
243
270
|
}) {
|
|
244
271
|
const items = recommendations.length ? recommendations : [fallbackModel()];
|
|
245
272
|
return (
|
|
246
|
-
<
|
|
247
|
-
<div className="
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
<h1>Recommended for your computer.</h1>
|
|
251
|
-
<p>A short list, ranked for this Mac. No catalog digging required.</p>
|
|
252
|
-
</div>
|
|
273
|
+
<div>
|
|
274
|
+
<div className="ritual-title">How shall your mind think today?</div>
|
|
275
|
+
<div className="ritual-subtitle">
|
|
276
|
+
A short, honest list chosen for the computer you are on right now. Pick the one that feels right.
|
|
253
277
|
</div>
|
|
254
|
-
|
|
278
|
+
|
|
279
|
+
<div style={{ maxWidth: 560, margin: "0 auto" }}>
|
|
255
280
|
{items.slice(0, 3).map((model, index) => (
|
|
256
281
|
<button
|
|
257
282
|
key={`${model.role}-${model.id}`}
|
|
258
|
-
className=
|
|
259
|
-
onClick={() => onSelect(model)}
|
|
283
|
+
className="ritual-model-card"
|
|
284
|
+
onClick={() => model.supported && onSelect(model)}
|
|
260
285
|
disabled={!model.supported}
|
|
286
|
+
style={{ width: "100%" }}
|
|
261
287
|
>
|
|
262
|
-
<
|
|
263
|
-
<
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
</span>
|
|
267
|
-
<Badge variant={model.supported ? "success" : "warning"}>{model.supported ? model.size || "ready" : "needs update"}</Badge>
|
|
288
|
+
<div className="role">{rankLabel(model.role, index)}</div>
|
|
289
|
+
<div className="name">{model.shortName}</div>
|
|
290
|
+
<div className="reason">{model.reason} · {model.size || "ready"}</div>
|
|
291
|
+
{!model.supported && <div style={{ color: "hsl(var(--destructive))", marginTop: 6, fontSize: "0.85rem" }}>Needs attention on this machine</div>}
|
|
268
292
|
</button>
|
|
269
293
|
))}
|
|
270
294
|
</div>
|
|
271
|
-
|
|
295
|
+
|
|
296
|
+
<div style={{ marginTop: "1.1rem", display: "flex", justifyContent: "center", gap: "1rem", alignItems: "center" }}>
|
|
272
297
|
<Button variant="ghost" onClick={onBack}>Back</Button>
|
|
273
|
-
<
|
|
298
|
+
<div style={{ fontSize: "0.82rem", color: "hsl(var(--fg-muted))" }}>Your choice becomes the current voice of your Brain.</div>
|
|
274
299
|
</div>
|
|
275
|
-
</
|
|
300
|
+
</div>
|
|
276
301
|
);
|
|
277
302
|
}
|
|
278
303
|
|
|
@@ -288,7 +313,7 @@ function InstallScreen({
|
|
|
288
313
|
const [busy, setBusy] = React.useState(false);
|
|
289
314
|
const [stage, setStage] = React.useState<InstallStage>("idle");
|
|
290
315
|
const [percent, setPercent] = React.useState(0);
|
|
291
|
-
const [message, setMessage] = React.useState("
|
|
316
|
+
const [message, setMessage] = React.useState("Your Brain is waiting for this mind.");
|
|
292
317
|
const [error, setError] = React.useState<string | null>(null);
|
|
293
318
|
|
|
294
319
|
async function start() {
|
|
@@ -329,39 +354,72 @@ function InstallScreen({
|
|
|
329
354
|
}
|
|
330
355
|
}
|
|
331
356
|
|
|
357
|
+
const brainStateForStage: any =
|
|
358
|
+
stage === "download" ? "thinking" :
|
|
359
|
+
stage === "validate" ? "recalling" :
|
|
360
|
+
stage === "load" ? "synthesizing" :
|
|
361
|
+
stage === "done" ? "idle" : "listening";
|
|
362
|
+
|
|
332
363
|
return (
|
|
333
|
-
<
|
|
334
|
-
<div className="
|
|
335
|
-
|
|
336
|
-
<
|
|
337
|
-
|
|
338
|
-
<h1>{model.shortName}</h1>
|
|
339
|
-
<p>Lattice will install, download, validate, and load the selected Brain.</p>
|
|
340
|
-
</div>
|
|
364
|
+
<div>
|
|
365
|
+
<div className="ritual-title">Bring this mind home.</div>
|
|
366
|
+
<div className="ritual-subtitle">
|
|
367
|
+
<strong>{model.shortName}</strong> — {model.reason}.<br />
|
|
368
|
+
We will download (if needed), validate, and load it. Nothing happens without your explicit consent.
|
|
341
369
|
</div>
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
370
|
+
|
|
371
|
+
{/* Living Brain reacts to the ceremony of installation */}
|
|
372
|
+
<div style={{ margin: "0.6rem auto 1rem" }}>
|
|
373
|
+
<LivingBrain
|
|
374
|
+
state={brainStateForStage}
|
|
375
|
+
intensity={stage === "download" || stage === "load" ? 0.96 : 0.82}
|
|
376
|
+
size="normal"
|
|
377
|
+
/>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<div className="ritual-progress">
|
|
381
|
+
<div className="ritual-stage-list">
|
|
382
|
+
{(["install", "download", "validate", "load"] as const).map((item) => (
|
|
383
|
+
<div key={item} className={`ritual-stage ${installStepState(stage, item)}`}>
|
|
384
|
+
<CheckCircle2 style={{ width: 15, height: 15 }} />
|
|
385
|
+
<span>{installLabel(item)}</span>
|
|
386
|
+
</div>
|
|
387
|
+
))}
|
|
388
|
+
</div>
|
|
389
|
+
|
|
390
|
+
<div className="ritual-bar">
|
|
391
|
+
<span style={{ width: `${Math.max(4, Math.min(100, percent))}%` }} />
|
|
392
|
+
</div>
|
|
349
393
|
</div>
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
394
|
+
|
|
395
|
+
<div className="ritual-status">{message}</div>
|
|
396
|
+
|
|
397
|
+
{error && (
|
|
398
|
+
<div className="ritual-card" style={{ borderColor: "hsl(var(--destructive)/0.45)", background: "hsl(var(--destructive)/0.07)", marginBottom: "1rem" }}>
|
|
399
|
+
{error}
|
|
400
|
+
<div style={{ marginTop: "0.5rem", fontSize: "0.85rem" }}>You can go back and choose a different mind, or try again.</div>
|
|
354
401
|
</div>
|
|
355
|
-
|
|
402
|
+
)}
|
|
403
|
+
|
|
404
|
+
<div style={{ display: "flex", gap: "0.75rem", justifyContent: "center", marginTop: "1rem" }}>
|
|
405
|
+
<Button variant="ghost" onClick={onBack} disabled={busy}>Choose differently</Button>
|
|
406
|
+
|
|
407
|
+
{stage !== "done" ? (
|
|
408
|
+
<Button
|
|
409
|
+
onClick={start}
|
|
410
|
+
disabled={busy || !model.supported}
|
|
411
|
+
>
|
|
412
|
+
{busy ? "Waking the mind..." : "Yes — make this my Brain"}
|
|
413
|
+
</Button>
|
|
414
|
+
) : (
|
|
415
|
+
<Button onClick={onComplete}>Enter your Brain</Button>
|
|
416
|
+
)}
|
|
356
417
|
</div>
|
|
357
|
-
|
|
358
|
-
<div
|
|
359
|
-
|
|
360
|
-
<Button onClick={stage === "done" ? onComplete : start} disabled={busy || !model.supported}>
|
|
361
|
-
{stage === "done" ? "Enter Brain" : busy ? "Loading" : "Install & Load"}
|
|
362
|
-
</Button>
|
|
418
|
+
|
|
419
|
+
<div style={{ fontSize: "0.72rem", color: "hsl(var(--fg-muted))", marginTop: "0.9rem" }}>
|
|
420
|
+
Explicit consent only. All work happens locally on your machine.
|
|
363
421
|
</div>
|
|
364
|
-
</
|
|
422
|
+
</div>
|
|
365
423
|
);
|
|
366
424
|
}
|
|
367
425
|
|