ltcai 6.2.0 → 6.3.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 +29 -17
- package/docs/CHANGELOG.md +66 -0
- package/frontend/src/components/onboarding/AnalysisScreen.tsx +127 -0
- package/frontend/src/components/onboarding/DownloadConsentPanel.tsx +29 -0
- package/frontend/src/components/onboarding/InstallScreen.tsx +208 -0
- package/frontend/src/components/onboarding/LanguageChooser.tsx +23 -0
- package/frontend/src/components/onboarding/LoginScreen.tsx +131 -0
- package/frontend/src/components/onboarding/ProductFlowScreens.tsx +13 -688
- package/frontend/src/components/onboarding/RecommendationScreen.tsx +59 -0
- package/frontend/src/components/onboarding/recommendationModel.ts +132 -0
- package/frontend/src/features/admin/AdminConsole.tsx +1 -1
- package/frontend/src/features/brain/BrainCarePanel.tsx +254 -0
- package/frontend/src/features/brain/BrainComposer.tsx +66 -0
- package/frontend/src/features/brain/BrainConversation.tsx +131 -0
- package/frontend/src/features/brain/BrainGraphLayer.tsx +132 -0
- package/frontend/src/features/brain/BrainHome.tsx +28 -795
- package/frontend/src/features/brain/BrainMemoryLayer.tsx +38 -0
- package/frontend/src/features/brain/BrainOverviewPanel.tsx +74 -0
- package/frontend/src/features/brain/BrainRelationshipLayer.tsx +43 -0
- package/frontend/src/features/brain/DepthEmergence.tsx +53 -0
- package/frontend/src/features/brain/types.ts +6 -6
- package/frontend/src/features/review/ReviewCard.tsx +14 -10
- package/frontend/src/features/review/ReviewInbox.tsx +24 -9
- package/frontend/src/i18n.ts +208 -0
- package/frontend/src/pages/Brain.tsx +63 -5
- package/frontend/src/pages/Capture.tsx +139 -43
- package/frontend/src/pages/Library.tsx +72 -6
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/app_factory.py +48 -106
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/runtime/access_runtime.py +97 -0
- package/latticeai/runtime/chat_wiring.py +119 -0
- package/latticeai/runtime/model_wiring.py +40 -0
- package/latticeai/runtime/platform_runtime_wiring.py +2 -3
- package/latticeai/runtime/review_wiring.py +37 -0
- package/latticeai/runtime/tail_wiring.py +21 -0
- package/package.json +2 -2
- package/scripts/check_i18n_literals.mjs +52 -0
- 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-Div5vMlq.css +2 -0
- package/static/app/assets/{index-D91Rz5--.js → index-t1jx1BR9.js} +2 -2
- package/static/app/assets/index-t1jx1BR9.js.map +1 -0
- package/static/app/index.html +2 -2
- package/static/app/assets/index-B2-1Gm0q.css +0 -2
- package/static/app/assets/index-D91Rz5--.js.map +0 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { latticeApi } from "@/api/client";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { Input } from "@/components/ui/input";
|
|
5
|
+
import { t } from "@/i18n";
|
|
6
|
+
import { useAppStore } from "@/store/appStore";
|
|
7
|
+
|
|
8
|
+
const FLOW_USER_KEY = "lattice.productFlow.user";
|
|
9
|
+
|
|
10
|
+
function readSavedFlowUser(): { email?: string; name?: string } | null {
|
|
11
|
+
try {
|
|
12
|
+
const raw = localStorage.getItem(FLOW_USER_KEY);
|
|
13
|
+
return raw ? JSON.parse(raw) : null;
|
|
14
|
+
} catch {}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function LoginScreen({ onSuccess }: { onSuccess: () => void }) {
|
|
19
|
+
const language = useAppStore((state) => state.language);
|
|
20
|
+
const [email, setEmail] = React.useState(() => {
|
|
21
|
+
return readSavedFlowUser()?.email || "you@local";
|
|
22
|
+
});
|
|
23
|
+
const [password, setPassword] = React.useState("");
|
|
24
|
+
const [name, setName] = React.useState(() => readSavedFlowUser()?.name || "You");
|
|
25
|
+
const [busy, setBusy] = React.useState(false);
|
|
26
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
27
|
+
|
|
28
|
+
async function submit(event: React.FormEvent) {
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
const cleanEmail = email.trim();
|
|
31
|
+
const cleanPassword = password.trim();
|
|
32
|
+
const cleanName = name.trim() || cleanEmail.split("@")[0] || "You";
|
|
33
|
+
if (!cleanEmail || !cleanPassword) {
|
|
34
|
+
setError(t(language, "flow.login.missing"));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
setBusy(true);
|
|
38
|
+
setError(null);
|
|
39
|
+
const savedUser = readSavedFlowUser();
|
|
40
|
+
let result = await latticeApi.login(cleanEmail, cleanPassword);
|
|
41
|
+
if (!result.ok) {
|
|
42
|
+
const profile = await latticeApi.profile();
|
|
43
|
+
if (profile.ok && (!savedUser?.email || savedUser.email === cleanEmail)) {
|
|
44
|
+
try { localStorage.setItem(FLOW_USER_KEY, JSON.stringify({ email: cleanEmail, name: cleanName })); } catch {}
|
|
45
|
+
setBusy(false);
|
|
46
|
+
onSuccess();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (savedUser?.email && savedUser.email !== cleanEmail) {
|
|
50
|
+
setBusy(false);
|
|
51
|
+
setError(t(language, "flow.login.otherEmail"));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (savedUser?.email === cleanEmail) {
|
|
55
|
+
setBusy(false);
|
|
56
|
+
setError(t(language, "flow.login.wrongPassword"));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const registered = await latticeApi.register({
|
|
60
|
+
email: cleanEmail,
|
|
61
|
+
password: cleanPassword,
|
|
62
|
+
name: cleanName,
|
|
63
|
+
nickname: cleanName,
|
|
64
|
+
});
|
|
65
|
+
if (registered.ok) result = await latticeApi.login(cleanEmail, cleanPassword);
|
|
66
|
+
}
|
|
67
|
+
if (!result.ok) {
|
|
68
|
+
setBusy(false);
|
|
69
|
+
setError(t(language, "flow.login.unavailable"));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
try { localStorage.setItem(FLOW_USER_KEY, JSON.stringify({ email: cleanEmail, name: cleanName })); } catch {}
|
|
73
|
+
setBusy(false);
|
|
74
|
+
onSuccess();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div>
|
|
79
|
+
<div className="ritual-title">{t(language, "flow.login.title")}</div>
|
|
80
|
+
<div className="ritual-subtitle">{t(language, "flow.login.body")}</div>
|
|
81
|
+
|
|
82
|
+
<ProductPromise />
|
|
83
|
+
|
|
84
|
+
<form onSubmit={submit} className="ritual-card ritual-form">
|
|
85
|
+
<div className="ritual-field-stack">
|
|
86
|
+
<div>
|
|
87
|
+
<div className="ritual-field-label">{t(language, "flow.name")}</div>
|
|
88
|
+
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder={t(language, "flow.name.placeholder")} />
|
|
89
|
+
</div>
|
|
90
|
+
<div>
|
|
91
|
+
<div className="ritual-field-label">{t(language, "flow.email")}</div>
|
|
92
|
+
<Input value={email} onChange={(e) => setEmail(e.target.value)} type="email" placeholder={t(language, "flow.email.placeholder")} />
|
|
93
|
+
</div>
|
|
94
|
+
<div>
|
|
95
|
+
<div className="ritual-field-label">{t(language, "flow.password")}</div>
|
|
96
|
+
<Input value={password} onChange={(e) => setPassword(e.target.value)} type="password" placeholder={t(language, "flow.password.placeholder")} />
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
{error && <div className="ritual-error" role="alert">{error}</div>}
|
|
101
|
+
|
|
102
|
+
<Button type="submit" disabled={busy || !email.trim() || !password.trim()} className="ritual-full-button">
|
|
103
|
+
{busy ? t(language, "flow.login.busy") : t(language, "flow.login.submit")}
|
|
104
|
+
</Button>
|
|
105
|
+
<div className="ritual-note">
|
|
106
|
+
{t(language, "flow.login.note")}
|
|
107
|
+
</div>
|
|
108
|
+
</form>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function ProductPromise() {
|
|
114
|
+
const language = useAppStore((state) => state.language);
|
|
115
|
+
return (
|
|
116
|
+
<div className="ritual-promise" aria-label={t(language, "flow.promise.aria")}>
|
|
117
|
+
<div>
|
|
118
|
+
<span>{t(language, "flow.promise.memory.k")}</span>
|
|
119
|
+
<strong>{t(language, "flow.promise.memory.v")}</strong>
|
|
120
|
+
</div>
|
|
121
|
+
<div>
|
|
122
|
+
<span>{t(language, "flow.promise.model.k")}</span>
|
|
123
|
+
<strong>{t(language, "flow.promise.model.v")}</strong>
|
|
124
|
+
</div>
|
|
125
|
+
<div>
|
|
126
|
+
<span>{t(language, "flow.promise.ownership.k")}</span>
|
|
127
|
+
<strong>{t(language, "flow.promise.ownership.v")}</strong>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|