@elizaos/app-core 2.0.0-alpha.348 → 2.0.0-alpha.349
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/package.json +5 -5
- package/packages/app-core/src/components/character/CharacterExperienceWorkspace.d.ts.map +1 -1
- package/packages/app-core/src/components/character/CharacterExperienceWorkspace.js +1 -1
- package/packages/app-core/src/components/character/CharacterHubView.d.ts.map +1 -1
- package/packages/app-core/src/components/character/CharacterHubView.js +72 -77
- package/packages/app-core/src/components/character/CharacterLearnedSkillsSection.d.ts.map +1 -1
- package/packages/app-core/src/components/character/CharacterLearnedSkillsSection.js +1 -1
- package/packages/app-core/src/components/character/CharacterOverviewSection.d.ts +11 -15
- package/packages/app-core/src/components/character/CharacterOverviewSection.d.ts.map +1 -1
- package/packages/app-core/src/components/character/CharacterOverviewSection.js +56 -61
- package/packages/app-core/src/components/chat/widgets/wallet-status.d.ts.map +1 -1
- package/packages/app-core/src/components/chat/widgets/wallet-status.js +26 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/app-core",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.349",
|
|
4
4
|
"description": "Shared application core for elizaOS white-label agent apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -469,7 +469,7 @@
|
|
|
469
469
|
"@capacitor/preferences": "^8.0.1",
|
|
470
470
|
"@capacitor/push-notifications": "^8.0.0",
|
|
471
471
|
"@clack/prompts": "^1.0.0",
|
|
472
|
-
"@elizaos/agent": "^2.0.0-alpha.
|
|
472
|
+
"@elizaos/agent": "^2.0.0-alpha.349",
|
|
473
473
|
"@elizaos/app-companion": "^0.0.0",
|
|
474
474
|
"@elizaos/app-elizamaker": "^0.0.0",
|
|
475
475
|
"@elizaos/app-lifeops": "^0.0.0",
|
|
@@ -478,11 +478,11 @@
|
|
|
478
478
|
"@elizaos/app-task-coordinator": "^0.0.0",
|
|
479
479
|
"@elizaos/app-training": "^0.0.1",
|
|
480
480
|
"@elizaos/app-vincent": "^0.0.0",
|
|
481
|
-
"@elizaos/core": "^2.0.0-alpha.
|
|
481
|
+
"@elizaos/core": "^2.0.0-alpha.349",
|
|
482
482
|
"@elizaos/plugin-browser-bridge": "^0.1.0",
|
|
483
483
|
"@elizaos/plugin-wechat": "^0.1.0",
|
|
484
|
-
"@elizaos/shared": "^2.0.0-alpha.
|
|
485
|
-
"@elizaos/ui": "^2.0.0-alpha.
|
|
484
|
+
"@elizaos/shared": "^2.0.0-alpha.349",
|
|
485
|
+
"@elizaos/ui": "^2.0.0-alpha.349",
|
|
486
486
|
"@radix-ui/react-checkbox": "^1.3.3",
|
|
487
487
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
488
488
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CharacterExperienceWorkspace.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterExperienceWorkspace.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,uBAAuB,CAAC;AAqK/B,wBAAgB,4BAA4B,CAAC,EAC3C,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,EAAE;IACD,WAAW,EAAE,yBAAyB,EAAE,CAAC;IACzC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,CAAC,EAAE,CACjB,UAAU,EAAE,yBAAyB,EACrC,KAAK,EAAE,wBAAwB,KAC5B,IAAI,CAAC;IACV,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,
|
|
1
|
+
{"version":3,"file":"CharacterExperienceWorkspace.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterExperienceWorkspace.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EAC1B,MAAM,uBAAuB,CAAC;AAqK/B,wBAAgB,4BAA4B,CAAC,EAC3C,WAAW,EACX,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,GACrB,EAAE;IACD,WAAW,EAAE,yBAAyB,EAAE,CAAC;IACzC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,gBAAgB,CAAC,EAAE,CACjB,UAAU,EAAE,yBAAyB,EACrC,KAAK,EAAE,wBAAwB,KAC5B,IAAI,CAAC;IACV,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC,2CAkqBA"}
|
|
@@ -175,7 +175,7 @@ export function CharacterExperienceWorkspace({ experiences, selectedExperienceId
|
|
|
175
175
|
? experiences.find((experience) => experience.id === visibleSelectedExperience.supersedes)
|
|
176
176
|
: null, [experiences, visibleSelectedExperience]);
|
|
177
177
|
if (experiences.length === 0) {
|
|
178
|
-
return (_jsxs("section", { className: "rounded-2xl border border-dashed border-border/40 bg-bg-muted/20 px-5 py-8 text-sm text-muted", children: [_jsx("div", { className: "text-base font-semibold text-txt", children: "
|
|
178
|
+
return (_jsxs("section", { className: "rounded-2xl border border-dashed border-border/40 bg-bg-muted/20 px-5 py-8 text-sm text-muted", children: [_jsx("div", { className: "text-base font-semibold text-txt", children: "I haven\u2019t learned anything yet." }), _jsx("p", { className: "mt-1 max-w-xl", children: "As we work together I\u2019ll keep notes here \u2014 what worked, what didn\u2019t, things I want to remember next time. Each lesson lands with the context that produced it so you can review or correct me." })] }));
|
|
179
179
|
}
|
|
180
180
|
return (_jsxs("section", { className: "flex min-w-0 flex-col gap-4", children: [_jsxs("div", { className: "rounded-2xl border border-border/40 bg-bg/70 p-4", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h3", { className: "text-base font-semibold text-txt", children: "Experience" }), _jsx("p", { className: "text-sm text-muted", children: "Triage learned outcomes by priority, confidence, evidence, and correction history." })] }), _jsxs("div", { className: "rounded-full border border-border/40 px-3 py-1 text-xs font-semibold text-muted", children: [filteredExperiences.length, " of ", experiences.length, " shown"] })] }), _jsxs("div", { className: "mt-4 grid gap-3 md:grid-cols-4", children: [_jsx(StatTile, { label: "Captured", value: String(stats.total), detail: `${stats.reviewCount} need review` }), _jsx(StatTile, { label: "Avg importance", value: formatPercent(stats.averageImportance), detail: "Ranking weight" }), _jsx(StatTile, { label: "Avg confidence", value: formatPercent(stats.averageConfidence), detail: "Evidence strength" }), _jsx(StatTile, { label: "Corrections", value: String(stats.corrections), detail: "Beliefs revised" })] }), _jsxs("div", { className: "mt-4 grid gap-3 lg:grid-cols-[minmax(14rem,1.4fr)_repeat(5,minmax(8rem,1fr))]", children: [_jsxs("label", { htmlFor: "experience-search", className: "min-w-0", children: [_jsx("span", { className: "sr-only", children: "Search experiences" }), _jsx(Input, { id: "experience-search", type: "search", value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), placeholder: "Search learning, evidence, tags...", className: "h-9 rounded-xl border-border/40 bg-bg-muted/15" })] }), _jsxs("label", { className: "min-w-0", children: [_jsx("span", { className: "sr-only", children: "Outcome filter" }), _jsxs("select", { "aria-label": "Outcome filter", value: outcomeFilter, onChange: (event) => setOutcomeFilter(event.target.value), className: "h-9 w-full rounded-xl border border-border/40 bg-bg-muted/15 px-3 text-sm text-txt", children: [_jsx("option", { value: "all", children: "All outcomes" }), filters.outcomes.map((outcome) => (_jsx("option", { value: outcome, children: outcome }, outcome)))] })] }), _jsxs("label", { className: "min-w-0", children: [_jsx("span", { className: "sr-only", children: "Domain filter" }), _jsxs("select", { "aria-label": "Domain filter", value: domainFilter, onChange: (event) => setDomainFilter(event.target.value), className: "h-9 w-full rounded-xl border border-border/40 bg-bg-muted/15 px-3 text-sm text-txt", children: [_jsx("option", { value: "all", children: "All domains" }), filters.domains.map((domain) => (_jsx("option", { value: domain, children: domain }, domain)))] })] }), _jsxs("label", { className: "min-w-0", children: [_jsx("span", { className: "sr-only", children: "Tag filter" }), _jsxs("select", { "aria-label": "Tag filter", value: tagFilter, onChange: (event) => setTagFilter(event.target.value), className: "h-9 w-full rounded-xl border border-border/40 bg-bg-muted/15 px-3 text-sm text-txt", children: [_jsx("option", { value: "all", children: "All tags" }), filters.tags.map((tag) => (_jsx("option", { value: tag, children: tag }, tag)))] })] }), _jsxs("label", { className: "min-w-0", children: [_jsx("span", { className: "sr-only", children: "Review filter" }), _jsxs("select", { "aria-label": "Review filter", value: reviewFilter, onChange: (event) => setReviewFilter(event.target.value), className: "h-9 w-full rounded-xl border border-border/40 bg-bg-muted/15 px-3 text-sm text-txt", children: [_jsx("option", { value: "all", children: "All review states" }), _jsx("option", { value: "needs-review", children: "Needs review" }), _jsx("option", { value: "corrected", children: "Corrected belief" }), _jsx("option", { value: "superseded", children: "Supersedes prior" })] })] }), _jsxs("label", { className: "min-w-0", children: [_jsx("span", { className: "sr-only", children: "Sort experiences" }), _jsxs("select", { "aria-label": "Sort experiences", value: sortMode, onChange: (event) => setSortMode(event.target.value), className: "h-9 w-full rounded-xl border border-border/40 bg-bg-muted/15 px-3 text-sm text-txt", children: [_jsx("option", { value: "priority", children: "Priority" }), _jsx("option", { value: "newest", children: "Newest" }), _jsx("option", { value: "importance", children: "Importance" }), _jsx("option", { value: "confidence", children: "Lowest confidence" })] })] })] })] }), _jsxs("div", { className: "grid min-w-0 gap-4 xl:grid-cols-[minmax(19rem,25rem)_minmax(0,1fr)]", children: [_jsxs("div", { className: "flex min-h-[28rem] min-w-0 flex-col overflow-hidden rounded-2xl border border-border/40 bg-bg/70", children: [_jsxs("div", { className: "border-b border-border/30 px-4 py-3", children: [_jsx("div", { className: "text-[0.65rem] font-semibold uppercase tracking-[0.08em] text-muted", children: "Review queue" }), _jsx("p", { className: "mt-1 text-sm text-muted", children: "Priority favors high importance, low confidence, and corrected beliefs." })] }), _jsx("div", { className: "custom-scrollbar flex min-w-0 flex-1 flex-col overflow-y-auto", children: filteredExperiences.length === 0 ? (_jsx("div", { className: "px-4 py-8 text-sm text-muted", children: "No experiences match the current filters." })) : (filteredExperiences.map((experience) => {
|
|
181
181
|
const isSelected = experience.id === visibleSelectedExperience?.id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CharacterHubView.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterHubView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AA0BzD,OAAO,KAAK,EACV,aAAa,EAKd,MAAM,wBAAwB,CAAC;AA2BhC,KAAK,qBAAqB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"CharacterHubView.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterHubView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AA0BzD,OAAO,KAAK,EACV,aAAa,EAKd,MAAM,wBAAwB,CAAC;AA2BhC,KAAK,qBAAqB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAqIrD,wBAAgB,gBAAgB,CAAC,EAC/B,CAAC,EACD,OAAO,EACP,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,6BAA6B,EAC7B,cAAc,EACd,2BAA2B,EAC3B,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,MAAM,GACP,EAAE;IACD,CAAC,EAAE,aAAa,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,yBAAyB,EAAE,mBAAmB,EAAE,CAAC;IACjD,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,6BAA6B,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,cAAc,EAAE,CAAC,GAAG,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,2BAA2B,EAAE,CAC3B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,KACV,IAAI,CAAC;IACV,eAAe,EAAE,OAAO,CAAC;IACzB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAChC,2CAm0BA"}
|
|
@@ -95,10 +95,33 @@ function latestTimestamp(value) {
|
|
|
95
95
|
const date = new Date(value);
|
|
96
96
|
return Number.isNaN(date.getTime()) ? 0 : date.getTime();
|
|
97
97
|
}
|
|
98
|
-
function
|
|
99
|
-
if (
|
|
100
|
-
return
|
|
101
|
-
|
|
98
|
+
function formatRelativeTime(value) {
|
|
99
|
+
if (value === null || value === undefined)
|
|
100
|
+
return "";
|
|
101
|
+
const time = typeof value === "number" ? value : new Date(value).getTime();
|
|
102
|
+
if (Number.isNaN(time) || time <= 0)
|
|
103
|
+
return "";
|
|
104
|
+
const diff = Date.now() - time;
|
|
105
|
+
if (diff < 0)
|
|
106
|
+
return "just now";
|
|
107
|
+
const minute = 60_000;
|
|
108
|
+
const hour = 60 * minute;
|
|
109
|
+
const day = 24 * hour;
|
|
110
|
+
if (diff < minute)
|
|
111
|
+
return "just now";
|
|
112
|
+
if (diff < hour) {
|
|
113
|
+
const value = Math.round(diff / minute);
|
|
114
|
+
return `${value}m ago`;
|
|
115
|
+
}
|
|
116
|
+
if (diff < day) {
|
|
117
|
+
const value = Math.round(diff / hour);
|
|
118
|
+
return `${value}h ago`;
|
|
119
|
+
}
|
|
120
|
+
if (diff < 7 * day) {
|
|
121
|
+
const value = Math.round(diff / day);
|
|
122
|
+
return `${value}d ago`;
|
|
123
|
+
}
|
|
124
|
+
return new Date(time).toLocaleDateString();
|
|
102
125
|
}
|
|
103
126
|
export function CharacterHubView({ d, bioText, normalizedMessageExamples, pendingStyleEntries, styleEntryDrafts, handleFieldEdit, applyFieldEdit, handlePendingStyleEntryChange, applyStyleEdit, handleStyleEntryDraftChange, characterSaving, characterSaveSuccess, characterSaveError, hasPendingChanges, onSave, }) {
|
|
104
127
|
const { setActionNotice, setTab, tab, t } = useApp();
|
|
@@ -275,109 +298,81 @@ export function CharacterHubView({ d, bioText, normalizedMessageExamples, pendin
|
|
|
275
298
|
};
|
|
276
299
|
}, []);
|
|
277
300
|
const customKnowledgeDocuments = useMemo(() => knowledgeDocuments.filter((document) => !isDefaultKnowledgeDocument(document)), [knowledgeDocuments]);
|
|
278
|
-
const starterOverviewWidgets = useMemo(() => [
|
|
279
|
-
{
|
|
280
|
-
section: "personality",
|
|
281
|
-
title: "Personality",
|
|
282
|
-
caption: "Add bio, style, and examples",
|
|
283
|
-
score: 0,
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
section: "knowledge",
|
|
287
|
-
title: "Knowledge",
|
|
288
|
-
caption: "Upload or teach source material",
|
|
289
|
-
score: 0,
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
section: "skills",
|
|
293
|
-
title: "Skills",
|
|
294
|
-
caption: "Let the agent learn useful abilities",
|
|
295
|
-
score: 0,
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
section: "experience",
|
|
299
|
-
title: "Experience",
|
|
300
|
-
caption: "Record outcomes and lessons",
|
|
301
|
-
score: 0,
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
section: "relationships",
|
|
305
|
-
title: "Relationships",
|
|
306
|
-
caption: "Build identity and preference memory",
|
|
307
|
-
score: 0,
|
|
308
|
-
},
|
|
309
|
-
], []);
|
|
310
301
|
const overviewWidgets = useMemo(() => {
|
|
311
302
|
const styleItems = Object.values(d.style ?? {}).reduce((count, values) => count + (Array.isArray(values) ? values.length : 0), 0);
|
|
303
|
+
const exampleCount = normalizedMessageExamples.length;
|
|
312
304
|
const latestPersonalityUpdate = historyEntries.reduce((latest, entry) => Math.max(latest, latestTimestamp(entry.timestamp)), 0);
|
|
313
305
|
const activeSkills = learnedSkills.filter((skill) => skill.status !== "disabled");
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const relationshipNames = relationshipActivity
|
|
321
|
-
.map((item) => item.personName)
|
|
322
|
-
.filter(Boolean);
|
|
306
|
+
const recentDocs = [...customKnowledgeDocuments]
|
|
307
|
+
.sort((left, right) => latestTimestamp(right.createdAt) - latestTimestamp(left.createdAt))
|
|
308
|
+
.slice(0, 3);
|
|
309
|
+
const recentExperience = [...experienceRecords]
|
|
310
|
+
.sort((left, right) => latestTimestamp(right.updatedAt ?? right.createdAt) -
|
|
311
|
+
latestTimestamp(left.updatedAt ?? left.createdAt))[0];
|
|
312
|
+
const relationshipNames = Array.from(new Set(relationshipActivity
|
|
313
|
+
.map((item) => item.personName?.trim())
|
|
314
|
+
.filter((name) => Boolean(name))));
|
|
315
|
+
const trimmedBio = bioText.trim();
|
|
316
|
+
const personalityHasContent = trimmedBio.length > 0 || styleItems > 0 || exampleCount > 0;
|
|
317
|
+
const personalityBody = trimmedBio ? (_jsx("p", { className: "line-clamp-3 text-xs leading-relaxed text-muted", children: trimmedBio })) : (_jsxs("div", { className: "flex flex-wrap gap-1.5 text-2xs", children: [styleItems > 0 ? (_jsxs("span", { className: "rounded-full border border-border/30 bg-bg-muted/30 px-2 py-0.5 text-muted", children: [styleItems, " style rule", styleItems === 1 ? "" : "s"] })) : null, exampleCount > 0 ? (_jsxs("span", { className: "rounded-full border border-border/30 bg-bg-muted/30 px-2 py-0.5 text-muted", children: [exampleCount, " example", exampleCount === 1 ? "" : "s"] })) : null] }));
|
|
323
318
|
return [
|
|
324
319
|
{
|
|
325
320
|
section: "personality",
|
|
326
321
|
title: "Personality",
|
|
327
|
-
|
|
328
|
-
? `Updated ${
|
|
329
|
-
:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
{ label: "Bio", value: bioText.trim() ? 1 : 0 },
|
|
333
|
-
{ label: "Style", value: ratio(styleItems, 8) },
|
|
334
|
-
{ label: "History", value: ratio(historyEntries.length, 8) },
|
|
335
|
-
],
|
|
322
|
+
meta: latestPersonalityUpdate > 0
|
|
323
|
+
? `Updated ${formatRelativeTime(latestPersonalityUpdate)}`
|
|
324
|
+
: null,
|
|
325
|
+
body: personalityBody,
|
|
326
|
+
isEmpty: !personalityHasContent,
|
|
336
327
|
},
|
|
337
328
|
{
|
|
338
329
|
section: "knowledge",
|
|
339
330
|
title: "Knowledge",
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
],
|
|
331
|
+
meta: customKnowledgeDocuments.length > 0
|
|
332
|
+
? `${customKnowledgeDocuments.length} doc${customKnowledgeDocuments.length === 1 ? "" : "s"}`
|
|
333
|
+
: null,
|
|
334
|
+
body: recentDocs.length > 0 ? (_jsx("ul", { className: "flex flex-col gap-1 text-xs text-muted", children: recentDocs.map((doc) => (_jsx("li", { className: "truncate", children: doc.filename }, doc.id))) })) : null,
|
|
335
|
+
isEmpty: customKnowledgeDocuments.length === 0,
|
|
346
336
|
},
|
|
347
337
|
{
|
|
348
338
|
section: "skills",
|
|
349
339
|
title: "Skills",
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
340
|
+
meta: activeSkills.length > 0
|
|
341
|
+
? `${activeSkills.length} active`
|
|
342
|
+
: null,
|
|
343
|
+
body: activeSkills.length > 0 ? (_jsxs("div", { className: "flex flex-wrap gap-1.5", children: [activeSkills.slice(0, 5).map((skill) => (_jsx("span", { className: "truncate rounded-full border border-border/30 bg-bg-muted/30 px-2 py-0.5 text-2xs text-muted", title: skill.name, children: skill.name }, skill.name))), activeSkills.length > 5 ? (_jsxs("span", { className: "text-2xs text-muted", children: ["+", activeSkills.length - 5, " more"] })) : null] })) : null,
|
|
344
|
+
isEmpty: activeSkills.length === 0,
|
|
353
345
|
},
|
|
354
346
|
{
|
|
355
347
|
section: "experience",
|
|
356
348
|
title: "Experience",
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
349
|
+
meta: experienceRecords.length > 0
|
|
350
|
+
? `${experienceRecords.length} lesson${experienceRecords.length === 1 ? "" : "s"}`
|
|
351
|
+
: null,
|
|
352
|
+
body: recentExperience ? (_jsx("p", { className: "line-clamp-3 text-xs italic leading-relaxed text-muted", children: recentExperience.learning ||
|
|
353
|
+
recentExperience.result ||
|
|
354
|
+
recentExperience.context ||
|
|
355
|
+
recentExperience.type })) : null,
|
|
356
|
+
isEmpty: experienceRecords.length === 0,
|
|
364
357
|
},
|
|
365
358
|
{
|
|
366
359
|
section: "relationships",
|
|
367
360
|
title: "Relationships",
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
361
|
+
meta: relationshipNames.length > 0
|
|
362
|
+
? `${relationshipNames.length} ${relationshipNames.length === 1 ? "person" : "people"}`
|
|
363
|
+
: null,
|
|
364
|
+
body: relationshipNames.length > 0 ? (_jsxs("div", { className: "flex flex-wrap gap-1.5", children: [relationshipNames.slice(0, 4).map((name) => (_jsx("span", { className: "truncate rounded-full border border-border/30 bg-bg-muted/30 px-2 py-0.5 text-2xs text-muted", title: name, children: name }, name))), relationshipNames.length > 4 ? (_jsxs("span", { className: "text-2xs text-muted", children: ["+", relationshipNames.length - 4, " more"] })) : null] })) : null,
|
|
365
|
+
isEmpty: relationshipNames.length === 0,
|
|
371
366
|
},
|
|
372
367
|
];
|
|
373
368
|
}, [
|
|
374
369
|
bioText,
|
|
375
|
-
customKnowledgeDocuments
|
|
370
|
+
customKnowledgeDocuments,
|
|
376
371
|
d.style,
|
|
377
372
|
experienceRecords,
|
|
378
373
|
historyEntries,
|
|
379
|
-
knowledgeDocuments.length,
|
|
380
374
|
learnedSkills,
|
|
375
|
+
normalizedMessageExamples.length,
|
|
381
376
|
relationshipActivity,
|
|
382
377
|
]);
|
|
383
378
|
const timelineItems = useMemo(() => historyEntries.map(mapHistoryEntryToTimelineItem), [historyEntries]);
|
|
@@ -508,14 +503,14 @@ export function CharacterHubView({ d, bioText, normalizedMessageExamples, pendin
|
|
|
508
503
|
})()) }) }));
|
|
509
504
|
const renderSection = () => {
|
|
510
505
|
if (activeSection === "overview") {
|
|
511
|
-
return (_jsx(CharacterOverviewSection, {
|
|
506
|
+
return (_jsx(CharacterOverviewSection, { characterName: d.name, widgets: overviewWidgets, onOpenSection: handleOverviewOpenSection }));
|
|
512
507
|
}
|
|
513
508
|
if (activeSection === "personality") {
|
|
514
509
|
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-8", children: [_jsxs("section", { className: "rounded-2xl border border-border/40 bg-bg/70 px-4 py-4", children: [_jsxs("div", { className: "mb-4", children: [_jsx("h2", { className: "text-lg font-semibold text-txt", children: "Personality" }), _jsx("p", { className: "text-sm text-muted", children: "Save your bio manually. Style rules and examples autosave as you edit them." })] }), _jsx(CharacterIdentityPanel, { bioText: bioText, handleFieldEdit: handleFieldEdit, t: t }), _jsxs("div", { className: "mt-4 flex flex-wrap items-center justify-between gap-3 border-t border-border/30 pt-4", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [characterSaveSuccess ? (_jsx("span", { className: "rounded-sm border border-status-success/20 bg-status-success-bg px-2 py-1 text-2xs font-semibold text-status-success", children: characterSaveSuccess })) : null, characterSaveError ? (_jsx("span", { className: "rounded-sm border border-status-danger/20 bg-status-danger-bg px-2 py-1 text-2xs font-medium text-status-danger", children: characterSaveError })) : null] }), _jsx(Button, { type: "button", className: "h-9 rounded-sm px-4 text-sm font-semibold tracking-[0.02em]", disabled: characterSaving || !hasPendingChanges, onClick: () => {
|
|
515
510
|
void handleManualSave();
|
|
516
511
|
}, children: characterSaving
|
|
517
512
|
? t("charactereditor.Saving", { defaultValue: "saving..." })
|
|
518
|
-
: t("charactereditor.Save", { defaultValue: "Save" }) })] })] }), _jsx("section", { className: "rounded-2xl border border-border/40 bg-bg/70 px-4 py-4", children: _jsx(CharacterStylePanel, { d: d, pendingStyleEntries: pendingStyleEntries, styleEntryDrafts: styleEntryDrafts, handlePendingStyleEntryChange: handlePendingStyleEntryChange, handleAddStyleEntry: handleAutoAddStyleEntry, handleRemoveStyleEntry: handleAutoRemoveStyleEntry, handleStyleEntryDraftChange: handleStyleEntryDraftChange, handleCommitStyleEntry: handleAutoCommitStyleEntry, handleReorderStyleEntries: handleAutoReorderStyleEntries, t: t }) }), _jsx("section", { className: "rounded-2xl border border-border/40 bg-bg/70 px-4 py-4", children: _jsx(CharacterExamplesPanel, { d: d, normalizedMessageExamples: normalizedMessageExamples, handleFieldEdit: handleAutoSavedExamplesEdit, t: t }) }),
|
|
513
|
+
: t("charactereditor.Save", { defaultValue: "Save" }) })] })] }), _jsx("section", { className: "rounded-2xl border border-border/40 bg-bg/70 px-4 py-4", children: _jsx(CharacterStylePanel, { d: d, pendingStyleEntries: pendingStyleEntries, styleEntryDrafts: styleEntryDrafts, handlePendingStyleEntryChange: handlePendingStyleEntryChange, handleAddStyleEntry: handleAutoAddStyleEntry, handleRemoveStyleEntry: handleAutoRemoveStyleEntry, handleStyleEntryDraftChange: handleStyleEntryDraftChange, handleCommitStyleEntry: handleAutoCommitStyleEntry, handleReorderStyleEntries: handleAutoReorderStyleEntries, t: t }) }), _jsx("section", { className: "rounded-2xl border border-border/40 bg-bg/70 px-4 py-4", children: _jsx(CharacterExamplesPanel, { d: d, normalizedMessageExamples: normalizedMessageExamples, handleFieldEdit: handleAutoSavedExamplesEdit, t: t }) }), historyLoading || historyError || timelineItems.length > 0 ? (_jsx("section", { className: "rounded-2xl border border-border/40 bg-bg/70 px-4 py-4", children: historyError ? (_jsx("div", { className: "rounded-xl border border-danger/30 bg-danger/10 px-4 py-3 text-sm text-danger", children: historyError })) : historyLoading ? (_jsx("div", { className: "text-sm text-muted", children: "Loading personality history\u2026" })) : (_jsx(CharacterPersonalityTimeline, { entries: timelineItems })) })) : null] }));
|
|
519
514
|
}
|
|
520
515
|
if (activeSection === "knowledge") {
|
|
521
516
|
return (_jsx("section", { className: "rounded-2xl border border-border/40 bg-bg/70 p-0", children: _jsx(KnowledgeView, { embedded: true, fileInputId: "character-hub-knowledge-upload", onDocumentsChange: setKnowledgeDocuments, onSelectedDocumentIdChange: setSelectedKnowledgeDocumentId, selectedDocumentId: selectedKnowledgeDocumentId, showSelectorRail: false }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CharacterLearnedSkillsSection.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterLearnedSkillsSection.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,6BAA6B,
|
|
1
|
+
{"version":3,"file":"CharacterLearnedSkillsSection.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterLearnedSkillsSection.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,6BAA6B,4CAwI5C"}
|
|
@@ -69,7 +69,7 @@ export function CharacterLearnedSkillsSection() {
|
|
|
69
69
|
? "Loading"
|
|
70
70
|
: `${grouped.proposed.length} proposed · ${grouped.active.length} active · ${grouped.disabled.length} disabled` })] }), _jsx(Button, { variant: "outline", size: "icon", className: "h-8 w-8 rounded-lg", onClick: () => {
|
|
71
71
|
void refresh();
|
|
72
|
-
}, disabled: loading, "aria-label": "Refresh learned skills", title: "Refresh", children: _jsx(RefreshCw, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }) })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [errorMessage ? (_jsx("div", { className: "rounded-xl border border-danger/40 bg-danger/10 px-3 py-2.5 text-xs-tight leading-5 text-danger", children: errorMessage })) : null, grouped.proposed.length > 0 ? (_jsx(SkillSection, { title: "Pending proposals", skills: grouped.proposed, busyName: busyName, onPromote: (name) => performAction(name, "POST", "promote"), onDelete: (name) => performAction(name, "DELETE", "delete") })) : null, grouped.active.length > 0 ? (_jsx(SkillSection, { title: "Active learned skills", skills: grouped.active, busyName: busyName, onDisable: (name) => performAction(name, "POST", "disable"), onDelete: (name) => performAction(name, "DELETE", "delete") })) : null, grouped.disabled.length > 0 ? (_jsx(SkillSection, { title: "Disabled", skills: grouped.disabled, busyName: busyName, onDelete: (name) => performAction(name, "DELETE", "delete") })) : null, isEmpty ? (_jsx("div", { className: "rounded-xl border border-dashed border-border/60 bg-bg-hover/40 px-3 py-3 text-xs-tight leading-5 text-muted", children: "
|
|
72
|
+
}, disabled: loading, "aria-label": "Refresh learned skills", title: "Refresh", children: _jsx(RefreshCw, { className: `h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }) })] }), _jsxs("div", { className: "flex flex-col gap-4", children: [errorMessage ? (_jsx("div", { className: "rounded-xl border border-danger/40 bg-danger/10 px-3 py-2.5 text-xs-tight leading-5 text-danger", children: errorMessage })) : null, grouped.proposed.length > 0 ? (_jsx(SkillSection, { title: "Pending proposals", skills: grouped.proposed, busyName: busyName, onPromote: (name) => performAction(name, "POST", "promote"), onDelete: (name) => performAction(name, "DELETE", "delete") })) : null, grouped.active.length > 0 ? (_jsx(SkillSection, { title: "Active learned skills", skills: grouped.active, busyName: busyName, onDisable: (name) => performAction(name, "POST", "disable"), onDelete: (name) => performAction(name, "DELETE", "delete") })) : null, grouped.disabled.length > 0 ? (_jsx(SkillSection, { title: "Disabled", skills: grouped.disabled, busyName: busyName, onDelete: (name) => performAction(name, "DELETE", "delete") })) : null, isEmpty ? (_jsx("div", { className: "rounded-xl border border-dashed border-border/60 bg-bg-hover/40 px-3 py-3 text-xs-tight leading-5 text-muted", children: "I haven\u2019t picked up any abilities yet. Browse the catalog or add one by example, and I\u2019ll start using it." })) : null] })] }));
|
|
73
73
|
}
|
|
74
74
|
function SkillSection({ title, skills, busyName, onPromote, onDisable, onDelete, }) {
|
|
75
75
|
return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("div", { className: "text-2xs font-semibold uppercase tracking-wide text-muted", children: title }), _jsx("ul", { className: "flex flex-col gap-2", children: skills.map((skill) => (_jsx("li", { children: _jsx(Card, { className: "border-border/50 bg-bg-hover/60 shadow-none", children: _jsx(CardContent, { className: "flex flex-col gap-2 px-3 py-3 text-xs-tight", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("div", { className: "font-mono text-sm font-semibold text-txt", children: skill.name }), _jsx("div", { className: "text-xs-tight text-muted", children: skill.description }), _jsxs("div", { className: "flex flex-wrap gap-x-2 gap-y-1 text-2xs uppercase tracking-wide text-muted", children: [_jsx("span", { children: skill.source }), _jsxs("span", { children: [skill.refinedCount, " refinements"] }), _jsxs("span", { children: [formatScore(skill.lastEvalScore), " score"] }), _jsx("span", { children: formatDate(skill.createdAt) })] }), skill.derivedFromTrajectory ? (_jsxs("div", { className: "text-2xs text-muted", children: ["Derived from trajectory:", " ", _jsxs("a", { href: `/trajectories/${skill.derivedFromTrajectory}`, className: "underline", children: [skill.derivedFromTrajectory.slice(0, 8), "\u2026"] })] })) : null] }), _jsxs("div", { className: "flex shrink-0 flex-col gap-1", children: [onPromote ? (_jsx(Button, { size: "sm", variant: "default", disabled: busyName === skill.name, onClick: () => onPromote(skill.name), children: "Promote" })) : null, onDisable ? (_jsx(Button, { size: "sm", variant: "outline", disabled: busyName === skill.name, onClick: () => onDisable(skill.name), children: "Disable" })) : null, _jsx(Button, { size: "sm", variant: "ghost", disabled: busyName === skill.name, onClick: () => onDelete(skill.name), children: "Delete" })] })] }) }) }) }, skill.name))) })] }));
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import type { CharacterHubSection } from "./character-hub-helpers";
|
|
2
3
|
type OverviewSection = Exclude<CharacterHubSection, "overview">;
|
|
3
|
-
export interface CharacterOverviewBar {
|
|
4
|
-
label: string;
|
|
5
|
-
value: number;
|
|
6
|
-
}
|
|
7
|
-
export interface CharacterOverviewSlice {
|
|
8
|
-
label: string;
|
|
9
|
-
value: number;
|
|
10
|
-
}
|
|
11
4
|
export interface CharacterOverviewWidget {
|
|
12
|
-
|
|
13
|
-
caption: string;
|
|
14
|
-
nodes?: string[];
|
|
15
|
-
pie?: CharacterOverviewSlice[];
|
|
16
|
-
score?: number;
|
|
5
|
+
/** Section the widget links to. */
|
|
17
6
|
section: OverviewSection;
|
|
7
|
+
/** Header title. */
|
|
18
8
|
title: string;
|
|
9
|
+
/** Optional small text on the right side of the header (count or "Updated 2h ago"). */
|
|
10
|
+
meta?: string | null;
|
|
11
|
+
/** Real preview content rendered in the widget body. */
|
|
12
|
+
body?: ReactNode | null;
|
|
13
|
+
/** True when no real content exists. Empty widgets are hidden. */
|
|
14
|
+
isEmpty: boolean;
|
|
19
15
|
}
|
|
20
|
-
export declare function CharacterOverviewSection({
|
|
16
|
+
export declare function CharacterOverviewSection({ characterName, onOpenSection, widgets, }: {
|
|
17
|
+
characterName?: string | null;
|
|
21
18
|
onOpenSection: (section: OverviewSection) => void;
|
|
22
|
-
starterWidgets: CharacterOverviewWidget[];
|
|
23
19
|
widgets: CharacterOverviewWidget[];
|
|
24
20
|
}): import("react/jsx-runtime").JSX.Element;
|
|
25
21
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CharacterOverviewSection.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterOverviewSection.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CharacterOverviewSection.d.ts","sourceRoot":"","sources":["../../../../../../src/components/character/CharacterOverviewSection.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,KAAK,eAAe,GAAG,OAAO,CAAC,mBAAmB,EAAE,UAAU,CAAC,CAAC;AAEhE,MAAM,WAAW,uBAAuB;IACtC,mCAAmC;IACnC,OAAO,EAAE,eAAe,CAAC;IACzB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wDAAwD;IACxD,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,kEAAkE;IAClE,OAAO,EAAE,OAAO,CAAC;CAClB;AAyLD,wBAAgB,wBAAwB,CAAC,EACvC,aAAa,EACb,aAAa,EACb,OAAO,GACR,EAAE;IACD,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,OAAO,EAAE,uBAAuB,EAAE,CAAC;CACpC,2CAkDA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { ArrowRight, BookOpen, Brain, Network, PencilLine, Sparkles, } from "lucide-react";
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowRight, BookOpen, Brain, MessageCircle, Network, PencilLine, Sparkles, Zap, } from "lucide-react";
|
|
4
3
|
const WIDGET_ICONS = {
|
|
5
4
|
personality: PencilLine,
|
|
6
5
|
knowledge: BookOpen,
|
|
@@ -8,69 +7,65 @@ const WIDGET_ICONS = {
|
|
|
8
7
|
experience: Brain,
|
|
9
8
|
relationships: Network,
|
|
10
9
|
};
|
|
11
|
-
const
|
|
12
|
-
personality: "
|
|
13
|
-
knowledge: "
|
|
14
|
-
skills: "
|
|
15
|
-
experience: "
|
|
16
|
-
relationships: "
|
|
10
|
+
const WIDGET_TONE = {
|
|
11
|
+
personality: "text-accent",
|
|
12
|
+
knowledge: "text-status-info",
|
|
13
|
+
skills: "text-accent",
|
|
14
|
+
experience: "text-status-success",
|
|
15
|
+
relationships: "text-status-warning",
|
|
17
16
|
};
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
const GETTING_STARTED_SUGGESTIONS = [
|
|
18
|
+
{
|
|
19
|
+
section: "personality",
|
|
20
|
+
icon: PencilLine,
|
|
21
|
+
label: "Tell me who I am",
|
|
22
|
+
hint: "Write a short bio so I know how to show up.",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
section: "knowledge",
|
|
26
|
+
icon: BookOpen,
|
|
27
|
+
label: "Give me something to read",
|
|
28
|
+
hint: "Upload notes, docs, or links I can study.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
section: "experience",
|
|
32
|
+
icon: MessageCircle,
|
|
33
|
+
label: "Talk with me for a bit",
|
|
34
|
+
hint: "I learn from our conversations as we go.",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
section: "skills",
|
|
38
|
+
icon: Zap,
|
|
39
|
+
label: "Turn on some abilities",
|
|
40
|
+
hint: "Pick the skills I should be good at.",
|
|
41
|
+
},
|
|
23
42
|
];
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
43
|
+
function GettingStarted({ characterName, onOpenSection, }) {
|
|
44
|
+
const name = characterName?.trim() ? characterName.trim() : "your character";
|
|
45
|
+
return (_jsxs("section", { className: "flex flex-col gap-5 rounded-2xl border border-border/30 bg-card/40 p-6", "aria-label": "Get started with your character", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("h2", { className: "text-lg font-semibold text-txt", children: ["Let\u2019s shape ", name] }), _jsxs("p", { className: "max-w-xl text-sm text-muted", children: [name, " is a blank slate right now. Pick anything below to start \u2014 there\u2019s no wrong order, and you can always change your mind."] })] }), _jsx("div", { className: "grid gap-2 md:grid-cols-2", children: GETTING_STARTED_SUGGESTIONS.map((suggestion) => {
|
|
46
|
+
const Icon = suggestion.icon;
|
|
47
|
+
return (_jsxs("button", { type: "button", onClick: () => onOpenSection(suggestion.section), className: "group flex items-start gap-3 rounded-xl border border-border/30 bg-bg/40 p-3 text-left transition-colors hover:border-border/60 hover:bg-bg/70 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50", children: [_jsx("span", { className: "mt-0.5 inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-accent/12 text-accent", children: _jsx(Icon, { className: "h-4 w-4", "aria-hidden": true }) }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("span", { className: "truncate text-sm font-semibold text-txt", children: suggestion.label }), _jsx("span", { className: "text-xs text-muted", children: suggestion.hint })] }), _jsx(ArrowRight, { className: "mt-1 h-4 w-4 shrink-0 text-muted transition-colors group-hover:text-txt", "aria-hidden": true })] }, suggestion.section));
|
|
48
|
+
}) })] }));
|
|
28
49
|
}
|
|
29
|
-
function
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
const circumference = 2 * Math.PI * radius;
|
|
33
|
-
let offset = 0;
|
|
34
|
-
if (total <= 0) {
|
|
35
|
-
return (_jsx("div", { className: "h-16 w-16 rounded-full border border-dashed border-border/50" }));
|
|
36
|
-
}
|
|
37
|
-
return (_jsxs("svg", { className: "h-16 w-16 -rotate-90", viewBox: "0 0 64 64", "aria-hidden": true, children: [_jsx("title", { children: "Overview distribution" }), _jsx("circle", { cx: "32", cy: "32", r: radius, fill: "none", stroke: "rgba(255,255,255,0.08)", strokeWidth: "10" }), slices.map((slice, index) => {
|
|
38
|
-
const length = (Math.max(slice.value, 0) / total) * circumference;
|
|
39
|
-
const element = (_jsx("circle", { cx: "32", cy: "32", r: radius, fill: "none", stroke: PIE_COLORS[index % PIE_COLORS.length], strokeDasharray: `${length} ${circumference - length}`, strokeDashoffset: -offset, strokeLinecap: "butt", strokeWidth: "10" }, `${slice.label}-${slice.value}`));
|
|
40
|
-
offset += length;
|
|
41
|
-
return element;
|
|
42
|
-
})] }));
|
|
43
|
-
}
|
|
44
|
-
function ScoreRing({ score }) {
|
|
45
|
-
const radius = 22;
|
|
46
|
-
const circumference = 2 * Math.PI * radius;
|
|
47
|
-
const progress = clampRatio(score) * circumference;
|
|
48
|
-
return (_jsxs("svg", { className: "h-16 w-16 -rotate-90", viewBox: "0 0 64 64", "aria-hidden": true, children: [_jsx("title", { children: "Overview score" }), _jsx("circle", { cx: "32", cy: "32", r: radius, fill: "none", stroke: "rgba(255,255,255,0.08)", strokeWidth: "10" }), _jsx("circle", { cx: "32", cy: "32", r: radius, fill: "none", stroke: "var(--accent)", strokeDasharray: `${progress} ${circumference - progress}`, strokeLinecap: "round", strokeWidth: "10" })] }));
|
|
49
|
-
}
|
|
50
|
-
function MiniBars({ bars }) {
|
|
51
|
-
return (_jsx("div", { className: "flex min-w-0 flex-col gap-2", children: bars.slice(0, 4).map((bar) => (_jsxs("div", { className: "grid grid-cols-[4.25rem_1fr] gap-2", children: [_jsx("span", { className: "truncate text-2xs font-medium uppercase tracking-[0.08em] text-muted", children: bar.label }), _jsx("div", { className: "h-2 overflow-hidden bg-bg-muted/35", children: _jsx("div", { className: "h-full bg-accent", style: { width: `${clampRatio(bar.value) * 100}%` } }) })] }, bar.label))) }));
|
|
52
|
-
}
|
|
53
|
-
function NodeGraph({ nodes }) {
|
|
54
|
-
const visible = Array.from(new Set(nodes.filter(Boolean))).slice(0, 5);
|
|
55
|
-
return (_jsxs("div", { className: "relative h-24 overflow-hidden border border-border/30 bg-bg-muted/15", children: [_jsx("div", { className: "absolute left-1/2 top-1/2 h-8 w-8 -translate-x-1/2 -translate-y-1/2 bg-accent/20 text-accent", children: _jsx(Network, { className: "m-2 h-4 w-4", "aria-hidden": true }) }), visible.map((node, index) => {
|
|
56
|
-
const angle = -Math.PI / 2 + (index / Math.max(visible.length, 1)) * 6.28;
|
|
57
|
-
const x = 50 + Math.cos(angle) * 34;
|
|
58
|
-
const y = 50 + Math.sin(angle) * 30;
|
|
59
|
-
return (_jsx("div", { className: "absolute h-7 w-7 -translate-x-1/2 -translate-y-1/2 border border-status-warning/45 bg-status-warning-bg text-center text-[0.68rem] font-semibold leading-7 text-status-warning", style: { left: `${x}%`, top: `${y}%` }, title: node, children: node
|
|
60
|
-
.split(/\s+/)
|
|
61
|
-
.slice(0, 2)
|
|
62
|
-
.map((part) => part[0]?.toUpperCase() ?? "")
|
|
63
|
-
.join("") || "?" }, node));
|
|
64
|
-
})] }));
|
|
50
|
+
function NextUpHint({ suggestion, onOpenSection, }) {
|
|
51
|
+
const Icon = suggestion.icon;
|
|
52
|
+
return (_jsxs("button", { type: "button", onClick: () => onOpenSection(suggestion.section), className: "group flex w-full items-center gap-3 rounded-xl border border-border/30 bg-card/30 px-4 py-3 text-left transition-colors hover:border-border/60 hover:bg-card/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50", children: [_jsx("span", { className: "inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-accent/12 text-accent", children: _jsx(Icon, { className: "h-3.5 w-3.5", "aria-hidden": true }) }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("span", { className: "text-2xs font-semibold uppercase tracking-[0.12em] text-muted", children: "Next up" }), _jsx("span", { className: "truncate text-sm font-medium text-txt", children: suggestion.label })] }), _jsx("span", { className: "text-xs text-muted group-hover:text-txt", children: suggestion.hint }), _jsx(ArrowRight, { className: "h-4 w-4 shrink-0 text-muted transition-colors group-hover:text-txt", "aria-hidden": true })] }));
|
|
65
53
|
}
|
|
66
54
|
function OverviewWidget({ onOpenSection, widget, }) {
|
|
67
55
|
const Icon = WIDGET_ICONS[widget.section];
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
const nodes = widget.nodes?.filter(Boolean) ?? [];
|
|
71
|
-
return (_jsxs("section", { className: "flex min-h-[15rem] min-w-0 flex-col border border-border/35 bg-bg/70 p-4", children: [_jsxs("div", { className: "flex min-w-0 items-start justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { className: `inline-flex h-9 w-9 shrink-0 items-center justify-center ${WIDGET_ACCENTS[widget.section]}`, children: _jsx(Icon, { className: "h-5 w-5", "aria-hidden": true }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("h3", { className: "truncate text-sm font-semibold text-txt", children: widget.title }), _jsx("p", { className: "truncate text-xs text-muted", children: widget.caption })] })] }), pie.length > 0 ? (_jsx(MiniPie, { slices: pie })) : (_jsx(ScoreRing, { score: widget.score ?? 0 }))] }), _jsxs("div", { className: "mt-4 flex min-h-0 flex-1 flex-col justify-center gap-4", children: [nodes.length > 0 ? _jsx(NodeGraph, { nodes: nodes }) : null, bars.length > 0 ? _jsx(MiniBars, { bars: bars }) : null] }), _jsx("div", { className: "mt-4 flex justify-end", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "h-8 px-2", onClick: () => onOpenSection(widget.section), "aria-label": `Open ${widget.title}`, children: _jsx(ArrowRight, { className: "h-4 w-4", "aria-hidden": true }) }) })] }));
|
|
56
|
+
const accent = WIDGET_TONE[widget.section];
|
|
57
|
+
return (_jsxs("button", { type: "button", onClick: () => onOpenSection(widget.section), className: "group flex h-44 min-w-0 flex-col gap-3 rounded-2xl border border-border/30 bg-card/40 p-4 text-left transition-colors hover:border-border/55 hover:bg-card/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50", "aria-label": `Open ${widget.title}`, children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { className: `inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-bg-muted/40 ${accent}`, children: _jsx(Icon, { className: "h-4 w-4", "aria-hidden": true }) }), _jsx("h3", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-txt", children: widget.title }), widget.meta ? (_jsx("span", { className: "shrink-0 text-2xs font-medium text-muted", children: widget.meta })) : null] }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: widget.body ?? null }), _jsx("div", { className: "flex justify-end", children: _jsx(ArrowRight, { className: "h-4 w-4 text-muted transition-colors group-hover:text-txt", "aria-hidden": true }) })] }));
|
|
72
58
|
}
|
|
73
|
-
export function CharacterOverviewSection({
|
|
74
|
-
const visibleWidgets = widgets.
|
|
75
|
-
|
|
59
|
+
export function CharacterOverviewSection({ characterName, onOpenSection, widgets, }) {
|
|
60
|
+
const visibleWidgets = widgets.filter((widget) => !widget.isEmpty);
|
|
61
|
+
const allEmpty = visibleWidgets.length === 0;
|
|
62
|
+
// Pick a "next up" hint when some content exists but most sections are empty.
|
|
63
|
+
// Cycles through missing sections in canonical order.
|
|
64
|
+
const missingSuggestion = !allEmpty
|
|
65
|
+
? GETTING_STARTED_SUGGESTIONS.find((suggestion) => widgets.some((widget) => widget.section === suggestion.section && widget.isEmpty))
|
|
66
|
+
: null;
|
|
67
|
+
if (allEmpty) {
|
|
68
|
+
return (_jsx("section", { className: "flex min-w-0 flex-col gap-4", "aria-label": "Character overview", children: _jsx(GettingStarted, { characterName: characterName, onOpenSection: onOpenSection }) }));
|
|
69
|
+
}
|
|
70
|
+
return (_jsxs("section", { className: "flex min-w-0 flex-col gap-3", "aria-label": "Character overview", children: [missingSuggestion ? (_jsx(NextUpHint, { suggestion: missingSuggestion, onOpenSection: onOpenSection })) : null, _jsx("div", { className: "grid items-stretch gap-3 md:grid-cols-2 xl:grid-cols-3", children: visibleWidgets.map((widget) => (_jsx(OverviewWidget, { widget: widget, onOpenSection: onOpenSection }, widget.section))) })] }));
|
|
76
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-status.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/chat/widgets/wallet-status.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wallet-status.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/chat/widgets/wallet-status.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,2BAA2B,EAC3B,sBAAsB,EACvB,MAAM,SAAS,CAAC;AA4JjB,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,kDAwKvE;AAED,eAAO,MAAM,oBAAoB,EAAE,2BAMlC,CAAC"}
|
|
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Check, Copy, Wallet } from "lucide-react";
|
|
3
3
|
import { useEffect, useMemo, useState } from "react";
|
|
4
4
|
import { useApp } from "../../../state";
|
|
5
|
-
import { resolveChainKey } from "../../inventory/chainConfig";
|
|
5
|
+
import { getNativeLogoUrl, resolveChainKey, } from "../../inventory/chainConfig";
|
|
6
|
+
import { normalizeInventoryImageUrl } from "../../inventory/media-url";
|
|
6
7
|
import { EmptyWidgetState, WidgetSection } from "./shared";
|
|
7
8
|
const DUST_THRESHOLD_USD = 0.01;
|
|
8
9
|
const COPY_FEEDBACK_MS = 1200;
|
|
@@ -16,15 +17,15 @@ const EVM_CHAIN_ORDER = [
|
|
|
16
17
|
"avax",
|
|
17
18
|
];
|
|
18
19
|
const EVM_CHAIN_KEYS = new Set(EVM_CHAIN_ORDER);
|
|
19
|
-
const
|
|
20
|
-
ethereum: "
|
|
21
|
-
base: "
|
|
22
|
-
arbitrum: "
|
|
23
|
-
optimism: "
|
|
24
|
-
polygon: "
|
|
25
|
-
bsc: "
|
|
26
|
-
avax: "
|
|
27
|
-
solana: "
|
|
20
|
+
const CHAIN_DISPLAY_LABELS = {
|
|
21
|
+
ethereum: "Ethereum",
|
|
22
|
+
base: "Base",
|
|
23
|
+
arbitrum: "Arbitrum",
|
|
24
|
+
optimism: "Optimism",
|
|
25
|
+
polygon: "Polygon",
|
|
26
|
+
bsc: "BNB Chain",
|
|
27
|
+
avax: "Avalanche",
|
|
28
|
+
solana: "Solana",
|
|
28
29
|
};
|
|
29
30
|
function shortenAddress(value) {
|
|
30
31
|
if (!value)
|
|
@@ -65,7 +66,21 @@ function normalizeEvmChainKeys(chainNames) {
|
|
|
65
66
|
return EVM_CHAIN_ORDER.filter((chainKey) => seen.has(chainKey));
|
|
66
67
|
}
|
|
67
68
|
function ChainBadge({ chain }) {
|
|
68
|
-
|
|
69
|
+
// Use the same per-chain logo URLs the wallet page uses — these are real
|
|
70
|
+
// raster logos pulled from the trustwallet/assets repo (see
|
|
71
|
+
// CHAIN_CONFIGS[*].nativeLogoUrl) and cover every chain we register,
|
|
72
|
+
// including Arbitrum / Optimism / Polygon that the SVG-only ChainIcon
|
|
73
|
+
// doesn't have paths for.
|
|
74
|
+
const [errored, setErrored] = useState(false);
|
|
75
|
+
const label = CHAIN_DISPLAY_LABELS[chain];
|
|
76
|
+
const url = errored
|
|
77
|
+
? null
|
|
78
|
+
: (normalizeInventoryImageUrl(getNativeLogoUrl(chain)) ?? null);
|
|
79
|
+
if (url) {
|
|
80
|
+
return (_jsx("img", { src: url, alt: label, title: label, width: 16, height: 16, className: "inline-flex h-4 w-4 shrink-0 rounded-full bg-bg/40 object-cover", onError: () => setErrored(true) }));
|
|
81
|
+
}
|
|
82
|
+
// Tiny initials fallback when the logo URL fails or is missing.
|
|
83
|
+
return (_jsx("span", { className: "inline-flex h-4 shrink-0 items-center rounded-full border border-border/35 bg-bg/40 px-1.5 font-mono text-[0.52rem] font-semibold leading-none text-muted", title: label, "aria-label": label, children: label.slice(0, 3).toUpperCase() }));
|
|
69
84
|
}
|
|
70
85
|
function ChainBadges({ chains }) {
|
|
71
86
|
return (_jsx("span", { className: "flex min-w-0 flex-wrap items-center gap-1", children: chains.map((chain) => (_jsx(ChainBadge, { chain: chain }, chain))) }));
|