@elizaos/plugin-goals 2.0.3-beta.6 → 2.0.3-beta.7
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/dist/actions/goals.d.ts +16 -0
- package/dist/actions/goals.d.ts.map +1 -0
- package/dist/actions/goals.js +150 -0
- package/dist/actions/goals.js.map +1 -0
- package/dist/components/goals/GoalsSpatialView.d.ts +42 -0
- package/dist/components/goals/GoalsSpatialView.d.ts.map +1 -0
- package/dist/components/goals/GoalsSpatialView.js +149 -0
- package/dist/components/goals/GoalsSpatialView.js.map +1 -0
- package/dist/components/goals/GoalsView.d.ts +60 -0
- package/dist/components/goals/GoalsView.d.ts.map +1 -0
- package/dist/components/goals/GoalsView.js +150 -0
- package/dist/components/goals/GoalsView.js.map +1 -0
- package/dist/components/goals/goals-view-bundle.d.ts +2 -0
- package/dist/components/goals/goals-view-bundle.d.ts.map +1 -0
- package/dist/components/goals/goals-view-bundle.js +5 -0
- package/dist/components/goals/goals-view-bundle.js.map +1 -0
- package/dist/db/goals-repository.d.ts +54 -0
- package/dist/db/goals-repository.d.ts.map +1 -0
- package/dist/db/goals-repository.js +239 -0
- package/dist/db/goals-repository.js.map +1 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +2 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +826 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +61 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sql.d.ts +32 -0
- package/dist/db/sql.d.ts.map +1 -0
- package/dist/db/sql.js +130 -0
- package/dist/db/sql.js.map +1 -0
- package/dist/goal-grounding.d.ts +54 -0
- package/dist/goal-grounding.d.ts.map +1 -0
- package/dist/goal-grounding.js +148 -0
- package/dist/goal-grounding.js.map +1 -0
- package/dist/goal-normalize.d.ts +30 -0
- package/dist/goal-normalize.d.ts.map +1 -0
- package/dist/goal-normalize.js +99 -0
- package/dist/goal-normalize.js.map +1 -0
- package/dist/goal-semantic-evaluator.d.ts +12 -0
- package/dist/goal-semantic-evaluator.d.ts.map +1 -0
- package/dist/goal-semantic-evaluator.js +208 -0
- package/dist/goal-semantic-evaluator.js.map +1 -0
- package/dist/goals-runtime.d.ts +34 -0
- package/dist/goals-runtime.d.ts.map +1 -0
- package/dist/goals-runtime.js +44 -0
- package/dist/goals-runtime.js.map +1 -0
- package/dist/goals-service.d.ts +68 -0
- package/dist/goals-service.d.ts.map +1 -0
- package/dist/goals-service.js +293 -0
- package/dist/goals-service.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +13 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +47 -0
- package/dist/plugin.js.map +1 -0
- package/dist/register-terminal-view.d.ts +15 -0
- package/dist/register-terminal-view.d.ts.map +1 -0
- package/dist/register-terminal-view.js +25 -0
- package/dist/register-terminal-view.js.map +1 -0
- package/dist/register.d.ts +9 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +5 -0
- package/dist/register.js.map +1 -0
- package/dist/services/checkin.d.ts +23 -0
- package/dist/services/checkin.d.ts.map +1 -0
- package/dist/services/checkin.js +27 -0
- package/dist/services/checkin.js.map +1 -0
- package/dist/services/migration.d.ts +49 -0
- package/dist/services/migration.d.ts.map +1 -0
- package/dist/services/migration.js +113 -0
- package/dist/services/migration.js.map +1 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +53 -0
- package/dist/types.js.map +1 -0
- package/dist/views/bundle.js +304 -0
- package/dist/views/bundle.js.map +1 -0
- package/package.json +9 -9
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OWNER_GOALS — owner-set long-horizon life goals.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained goal CRUD surface backed by {@link GoalsService} (the goals
|
|
5
|
+
* back-end this plugin owns). Used in the PA-free deployment topology; when
|
|
6
|
+
* `@elizaos/plugin-personal-assistant` is loaded it registers its own richer
|
|
7
|
+
* `OWNER_GOALS` natural-language flow, which delegates to the same
|
|
8
|
+
* {@link GoalsService} CRUD methods.
|
|
9
|
+
*
|
|
10
|
+
* Dispatch: create | update | delete | review. The handler resolves the
|
|
11
|
+
* subaction + params (planner-trust path first, LLM extraction fallback) via
|
|
12
|
+
* `resolveActionArgs`, then calls the goals back-end.
|
|
13
|
+
*/
|
|
14
|
+
import { type Action } from "@elizaos/core";
|
|
15
|
+
export declare const ownerGoalsAction: Action;
|
|
16
|
+
//# sourceMappingURL=goals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goals.d.ts","sourceRoot":"","sources":["../../src/actions/goals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,KAAK,MAAM,EASZ,MAAM,eAAe,CAAC;AA2CvB,eAAO,MAAM,gBAAgB,EAAE,MA4H9B,CAAC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveActionArgs
|
|
3
|
+
} from "@elizaos/core";
|
|
4
|
+
import { GoalsServiceError } from "../goal-normalize.js";
|
|
5
|
+
import { createOwnerGoalsService } from "../goals-runtime.js";
|
|
6
|
+
import { GOAL_ACTIONS, GOALS_CONTEXTS, GOALS_LOG_PREFIX } from "../types.js";
|
|
7
|
+
const SUBACTIONS = {
|
|
8
|
+
create: {
|
|
9
|
+
description: "Create a new owner long-horizon life goal.",
|
|
10
|
+
descriptionCompressed: "create owner long-horizon goal",
|
|
11
|
+
required: ["title"],
|
|
12
|
+
optional: ["description"]
|
|
13
|
+
},
|
|
14
|
+
update: {
|
|
15
|
+
description: "Update an existing owner goal by id.",
|
|
16
|
+
descriptionCompressed: "update owner goal by id",
|
|
17
|
+
required: ["id"],
|
|
18
|
+
optional: ["title", "description"]
|
|
19
|
+
},
|
|
20
|
+
delete: {
|
|
21
|
+
description: "Delete an owner goal by id.",
|
|
22
|
+
descriptionCompressed: "delete owner goal by id",
|
|
23
|
+
required: ["id"]
|
|
24
|
+
},
|
|
25
|
+
review: {
|
|
26
|
+
description: "Review the current state of an owner goal by id.",
|
|
27
|
+
descriptionCompressed: "review owner goal state by id",
|
|
28
|
+
required: ["id"]
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function describeGoal(record) {
|
|
32
|
+
return record.goal.title;
|
|
33
|
+
}
|
|
34
|
+
const ownerGoalsAction = {
|
|
35
|
+
name: "OWNER_GOALS",
|
|
36
|
+
description: "Manage the owner's long-horizon life goals. Actions: create, update, delete, review. Goals carry a horizon (e.g. quarter, year, life) and feed routine + reminder generation.",
|
|
37
|
+
descriptionCompressed: "owner goals: create|update|delete|review; long-horizon, drives routines",
|
|
38
|
+
contexts: [...GOALS_CONTEXTS],
|
|
39
|
+
contextGate: { anyOf: [...GOALS_CONTEXTS] },
|
|
40
|
+
roleGate: { minRole: "ADMIN" },
|
|
41
|
+
tags: [
|
|
42
|
+
"domain:goals",
|
|
43
|
+
"capability:write",
|
|
44
|
+
"capability:update",
|
|
45
|
+
"capability:delete",
|
|
46
|
+
"surface:owner"
|
|
47
|
+
],
|
|
48
|
+
similes: ["GOALS", "LIFE_GOALS", "SET_GOAL", "UPDATE_GOAL", "REVIEW_GOALS"],
|
|
49
|
+
parameters: [
|
|
50
|
+
{
|
|
51
|
+
name: "action",
|
|
52
|
+
description: "Action: create | update | delete | review.",
|
|
53
|
+
required: true,
|
|
54
|
+
schema: { type: "string", enum: [...GOAL_ACTIONS] }
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "id",
|
|
58
|
+
description: "Goal id (update/delete/review).",
|
|
59
|
+
required: false,
|
|
60
|
+
schema: { type: "string" }
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "title",
|
|
64
|
+
description: "Goal title (create/update).",
|
|
65
|
+
required: false,
|
|
66
|
+
schema: { type: "string" }
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "description",
|
|
70
|
+
description: "Longer goal description (create/update).",
|
|
71
|
+
required: false,
|
|
72
|
+
schema: { type: "string" }
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
validate: async (_runtime) => true,
|
|
76
|
+
handler: async (runtime, message, state, options, callback) => {
|
|
77
|
+
const resolved = await resolveActionArgs({
|
|
78
|
+
runtime,
|
|
79
|
+
message,
|
|
80
|
+
state,
|
|
81
|
+
options,
|
|
82
|
+
actionName: "OWNER_GOALS",
|
|
83
|
+
subactions: SUBACTIONS
|
|
84
|
+
});
|
|
85
|
+
if (!resolved.ok) {
|
|
86
|
+
await callback?.({ text: resolved.clarification });
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
text: resolved.clarification,
|
|
90
|
+
data: { action: "clarify", missing: resolved.missing }
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const service = createOwnerGoalsService(runtime);
|
|
94
|
+
const { subaction, params } = resolved;
|
|
95
|
+
try {
|
|
96
|
+
switch (subaction) {
|
|
97
|
+
case "create": {
|
|
98
|
+
const record = await service.createGoal({
|
|
99
|
+
title: params.title ?? "",
|
|
100
|
+
description: params.description
|
|
101
|
+
});
|
|
102
|
+
const text = `Added goal "${describeGoal(record)}".`;
|
|
103
|
+
await callback?.({ text });
|
|
104
|
+
return { success: true, text, data: { action: "create", record } };
|
|
105
|
+
}
|
|
106
|
+
case "update": {
|
|
107
|
+
const record = await service.updateGoal(params.id ?? "", {
|
|
108
|
+
...params.title !== void 0 ? { title: params.title } : {},
|
|
109
|
+
...params.description !== void 0 ? { description: params.description } : {}
|
|
110
|
+
});
|
|
111
|
+
const text = `Updated goal "${describeGoal(record)}".`;
|
|
112
|
+
await callback?.({ text });
|
|
113
|
+
return { success: true, text, data: { action: "update", record } };
|
|
114
|
+
}
|
|
115
|
+
case "delete": {
|
|
116
|
+
const record = await service.getGoal(params.id ?? "");
|
|
117
|
+
await service.deleteGoal(params.id ?? "");
|
|
118
|
+
const text = `${describeGoal(record)} is off your goals list.`;
|
|
119
|
+
await callback?.({ text });
|
|
120
|
+
return {
|
|
121
|
+
success: true,
|
|
122
|
+
text,
|
|
123
|
+
data: { action: "delete", id: params.id }
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
case "review": {
|
|
127
|
+
const record = await service.getGoal(params.id ?? "");
|
|
128
|
+
const text = `Goal "${describeGoal(record)}" is ${record.goal.reviewState.replace(/_/g, " ")} (status: ${record.goal.status}).`;
|
|
129
|
+
await callback?.({ text });
|
|
130
|
+
return { success: true, text, data: { action: "review", record } };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
if (error instanceof GoalsServiceError) {
|
|
135
|
+
const text = `${GOALS_LOG_PREFIX} ${error.message}`;
|
|
136
|
+
await callback?.({ text });
|
|
137
|
+
return {
|
|
138
|
+
success: false,
|
|
139
|
+
text,
|
|
140
|
+
data: { action: subaction, error: error.message }
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
export {
|
|
148
|
+
ownerGoalsAction
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=goals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/actions/goals.ts"],"sourcesContent":["/**\n * OWNER_GOALS — owner-set long-horizon life goals.\n *\n * Self-contained goal CRUD surface backed by {@link GoalsService} (the goals\n * back-end this plugin owns). Used in the PA-free deployment topology; when\n * `@elizaos/plugin-personal-assistant` is loaded it registers its own richer\n * `OWNER_GOALS` natural-language flow, which delegates to the same\n * {@link GoalsService} CRUD methods.\n *\n * Dispatch: create | update | delete | review. The handler resolves the\n * subaction + params (planner-trust path first, LLM extraction fallback) via\n * `resolveActionArgs`, then calls the goals back-end.\n */\n\nimport {\n type Action,\n type ActionResult,\n type HandlerCallback,\n type HandlerOptions,\n type IAgentRuntime,\n type Memory,\n resolveActionArgs,\n type State,\n type SubactionsMap,\n} from \"@elizaos/core\";\nimport type { LifeOpsGoalRecord } from \"@elizaos/shared\";\nimport { GoalsServiceError } from \"../goal-normalize.js\";\nimport { createOwnerGoalsService } from \"../goals-runtime.js\";\nimport { GOAL_ACTIONS, GOALS_CONTEXTS, GOALS_LOG_PREFIX } from \"../types.js\";\n\ntype GoalSubaction = (typeof GOAL_ACTIONS)[number];\n\ninterface GoalActionParams {\n id?: string;\n title?: string;\n description?: string;\n}\n\nconst SUBACTIONS: SubactionsMap<GoalSubaction> = {\n create: {\n description: \"Create a new owner long-horizon life goal.\",\n descriptionCompressed: \"create owner long-horizon goal\",\n required: [\"title\"],\n optional: [\"description\"],\n },\n update: {\n description: \"Update an existing owner goal by id.\",\n descriptionCompressed: \"update owner goal by id\",\n required: [\"id\"],\n optional: [\"title\", \"description\"],\n },\n delete: {\n description: \"Delete an owner goal by id.\",\n descriptionCompressed: \"delete owner goal by id\",\n required: [\"id\"],\n },\n review: {\n description: \"Review the current state of an owner goal by id.\",\n descriptionCompressed: \"review owner goal state by id\",\n required: [\"id\"],\n },\n};\n\nfunction describeGoal(record: LifeOpsGoalRecord): string {\n return record.goal.title;\n}\n\nexport const ownerGoalsAction: Action = {\n name: \"OWNER_GOALS\",\n description:\n \"Manage the owner's long-horizon life goals. Actions: create, update, delete, review. Goals carry a horizon (e.g. quarter, year, life) and feed routine + reminder generation.\",\n descriptionCompressed:\n \"owner goals: create|update|delete|review; long-horizon, drives routines\",\n contexts: [...GOALS_CONTEXTS],\n contextGate: { anyOf: [...GOALS_CONTEXTS] },\n roleGate: { minRole: \"ADMIN\" },\n tags: [\n \"domain:goals\",\n \"capability:write\",\n \"capability:update\",\n \"capability:delete\",\n \"surface:owner\",\n ],\n similes: [\"GOALS\", \"LIFE_GOALS\", \"SET_GOAL\", \"UPDATE_GOAL\", \"REVIEW_GOALS\"],\n parameters: [\n {\n name: \"action\",\n description: \"Action: create | update | delete | review.\",\n required: true,\n schema: { type: \"string\" as const, enum: [...GOAL_ACTIONS] },\n },\n {\n name: \"id\",\n description: \"Goal id (update/delete/review).\",\n required: false,\n schema: { type: \"string\" as const },\n },\n {\n name: \"title\",\n description: \"Goal title (create/update).\",\n required: false,\n schema: { type: \"string\" as const },\n },\n {\n name: \"description\",\n description: \"Longer goal description (create/update).\",\n required: false,\n schema: { type: \"string\" as const },\n },\n ],\n validate: async (_runtime: IAgentRuntime): Promise<boolean> => true,\n handler: async (\n runtime: IAgentRuntime,\n message: Memory,\n state?: State,\n options?: HandlerOptions,\n callback?: HandlerCallback,\n ): Promise<ActionResult> => {\n const resolved = await resolveActionArgs<GoalSubaction, GoalActionParams>({\n runtime,\n message,\n state,\n options,\n actionName: \"OWNER_GOALS\",\n subactions: SUBACTIONS,\n });\n if (!resolved.ok) {\n await callback?.({ text: resolved.clarification });\n return {\n success: false,\n text: resolved.clarification,\n data: { action: \"clarify\", missing: resolved.missing },\n };\n }\n\n const service = createOwnerGoalsService(runtime);\n const { subaction, params } = resolved;\n\n try {\n switch (subaction) {\n case \"create\": {\n const record = await service.createGoal({\n title: params.title ?? \"\",\n description: params.description,\n });\n const text = `Added goal \"${describeGoal(record)}\".`;\n await callback?.({ text });\n return { success: true, text, data: { action: \"create\", record } };\n }\n case \"update\": {\n const record = await service.updateGoal(params.id ?? \"\", {\n ...(params.title !== undefined ? { title: params.title } : {}),\n ...(params.description !== undefined\n ? { description: params.description }\n : {}),\n });\n const text = `Updated goal \"${describeGoal(record)}\".`;\n await callback?.({ text });\n return { success: true, text, data: { action: \"update\", record } };\n }\n case \"delete\": {\n const record = await service.getGoal(params.id ?? \"\");\n await service.deleteGoal(params.id ?? \"\");\n const text = `${describeGoal(record)} is off your goals list.`;\n await callback?.({ text });\n return {\n success: true,\n text,\n data: { action: \"delete\", id: params.id },\n };\n }\n case \"review\": {\n const record = await service.getGoal(params.id ?? \"\");\n const text = `Goal \"${describeGoal(record)}\" is ${record.goal.reviewState.replace(/_/g, \" \")} (status: ${record.goal.status}).`;\n await callback?.({ text });\n return { success: true, text, data: { action: \"review\", record } };\n }\n }\n } catch (error) {\n if (error instanceof GoalsServiceError) {\n const text = `${GOALS_LOG_PREFIX} ${error.message}`;\n await callback?.({ text });\n return {\n success: false,\n text,\n data: { action: subaction, error: error.message },\n };\n }\n throw error;\n }\n },\n};\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GoalsSpatialView — the owner life-direction surface authored once with the
|
|
3
|
+
* spatial vocabulary, so it renders correctly wherever it is displayed:
|
|
4
|
+
*
|
|
5
|
+
* - GUI / XR — mounted in `<SpatialSurface>` (DOM; XR scales up).
|
|
6
|
+
* - TUI — rendered to real terminal lines by the agent terminal, via
|
|
7
|
+
* `registerSpatialTerminalView` (see `register-terminal-view.tsx`).
|
|
8
|
+
*
|
|
9
|
+
* It is purely presentational (a snapshot + an action callback in, primitives
|
|
10
|
+
* out) and imports only the cross-modality primitives plus this plugin's own
|
|
11
|
+
* display DTOs, so it is safe to render in the Node agent process where the
|
|
12
|
+
* terminal lives (no browser/data-fetch import).
|
|
13
|
+
*
|
|
14
|
+
* The view is read-only: goals are owned by the personal-assistant routes and
|
|
15
|
+
* created through the assistant chat, not mutated here. The only interactions
|
|
16
|
+
* are the status-filter toggles, a Retry on the error state, and the "Set a
|
|
17
|
+
* goal" chat affordance on the empty state.
|
|
18
|
+
*/
|
|
19
|
+
import { type GoalItem, type GoalStatus } from "../../types.js";
|
|
20
|
+
/** Coarse load state of the goals surface. */
|
|
21
|
+
export type GoalsLoadStatus = "loading" | "error" | "ready";
|
|
22
|
+
export interface GoalsSnapshot {
|
|
23
|
+
/** Coarse load state. */
|
|
24
|
+
status: GoalsLoadStatus;
|
|
25
|
+
/** Goal records (empty until ready). */
|
|
26
|
+
goals: GoalItem[];
|
|
27
|
+
/** Active status filters; empty = show every status. */
|
|
28
|
+
activeStatuses: GoalStatus[];
|
|
29
|
+
/** Error text when status is "error". */
|
|
30
|
+
error?: string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface GoalsSpatialViewProps {
|
|
33
|
+
snapshot: GoalsSnapshot;
|
|
34
|
+
/**
|
|
35
|
+
* Dispatch by agent id: `retry` (re-fetch on the error state), `new` (ask the
|
|
36
|
+
* assistant to set a goal), and `filter:<status>` (toggle one status chip,
|
|
37
|
+
* status ∈ active|paused|archived|satisfied).
|
|
38
|
+
*/
|
|
39
|
+
onAction?: (action: string) => void;
|
|
40
|
+
}
|
|
41
|
+
export declare function GoalsSpatialView({ snapshot, onAction, }: GoalsSpatialViewProps): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
//# sourceMappingURL=GoalsSpatialView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GoalsSpatialView.d.ts","sourceRoot":"","sources":["../../../src/components/goals/GoalsSpatialView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAEL,KAAK,QAAQ,EAEb,KAAK,UAAU,EAChB,MAAM,gBAAgB,CAAC;AAExB,8CAA8C;AAC9C,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,MAAM,EAAE,eAAe,CAAC;IACxB,wCAAwC;IACxC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,wDAAwD;IACxD,cAAc,EAAE,UAAU,EAAE,CAAC;IAC7B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,aAAa,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AA0DD,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,QAAQ,GACT,EAAE,qBAAqB,2CAqBvB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Card, HStack, List, Text, VStack } from "@elizaos/ui/spatial";
|
|
3
|
+
import {
|
|
4
|
+
GOAL_STATUSES
|
|
5
|
+
} from "../../types.js";
|
|
6
|
+
const STATUS_LABELS = {
|
|
7
|
+
active: "Active",
|
|
8
|
+
paused: "Paused",
|
|
9
|
+
archived: "Archived",
|
|
10
|
+
satisfied: "Achieved"
|
|
11
|
+
};
|
|
12
|
+
const REVIEW_LABELS = {
|
|
13
|
+
idle: "not reviewed",
|
|
14
|
+
on_track: "on track",
|
|
15
|
+
at_risk: "at risk",
|
|
16
|
+
needs_attention: "needs attention"
|
|
17
|
+
};
|
|
18
|
+
const REVIEW_GLYPH = {
|
|
19
|
+
idle: "\u25CB",
|
|
20
|
+
on_track: "\u25CF",
|
|
21
|
+
at_risk: "x",
|
|
22
|
+
needs_attention: "x"
|
|
23
|
+
};
|
|
24
|
+
const REVIEW_TONE = {
|
|
25
|
+
idle: "muted",
|
|
26
|
+
on_track: "success",
|
|
27
|
+
at_risk: "danger",
|
|
28
|
+
needs_attention: "danger"
|
|
29
|
+
};
|
|
30
|
+
function formatDate(value) {
|
|
31
|
+
const date = new Date(value);
|
|
32
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
33
|
+
return date.toLocaleDateString(void 0, {
|
|
34
|
+
month: "short",
|
|
35
|
+
day: "numeric",
|
|
36
|
+
year: "numeric"
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function reviewNudge(goals) {
|
|
40
|
+
const flagged = goals.filter(
|
|
41
|
+
(goal) => goal.reviewState === "at_risk" || goal.reviewState === "needs_attention"
|
|
42
|
+
).length;
|
|
43
|
+
if (flagged === 0) return null;
|
|
44
|
+
return flagged === 1 ? "1 goal needs a review." : `${flagged} goals need a review.`;
|
|
45
|
+
}
|
|
46
|
+
function GoalsSpatialView({
|
|
47
|
+
snapshot,
|
|
48
|
+
onAction
|
|
49
|
+
}) {
|
|
50
|
+
const dispatch = (action) => () => onAction?.(action);
|
|
51
|
+
const active = new Set(snapshot.activeStatuses);
|
|
52
|
+
return /* @__PURE__ */ jsx(Card, { gap: 1, padding: 1, children: snapshot.status === "loading" ? /* @__PURE__ */ jsx(Text, { tone: "muted", style: "caption", children: "Loading goals" }) : snapshot.status === "error" ? /* @__PURE__ */ jsx(GoalsErrorBody, { error: snapshot.error, dispatch }) : /* @__PURE__ */ jsx(
|
|
53
|
+
GoalsReadyBody,
|
|
54
|
+
{
|
|
55
|
+
snapshot,
|
|
56
|
+
active,
|
|
57
|
+
dispatch
|
|
58
|
+
}
|
|
59
|
+
) });
|
|
60
|
+
}
|
|
61
|
+
function GoalsErrorBody({
|
|
62
|
+
error,
|
|
63
|
+
dispatch
|
|
64
|
+
}) {
|
|
65
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "Could not load goals" }),
|
|
67
|
+
error ? /* @__PURE__ */ jsx(Text, { tone: "muted", style: "caption", children: error }) : null,
|
|
68
|
+
/* @__PURE__ */ jsx(HStack, { gap: 1, children: /* @__PURE__ */ jsx(Button, { agent: "retry", onPress: dispatch("retry"), children: "Retry" }) })
|
|
69
|
+
] });
|
|
70
|
+
}
|
|
71
|
+
function GoalsReadyBody({
|
|
72
|
+
snapshot,
|
|
73
|
+
active,
|
|
74
|
+
dispatch
|
|
75
|
+
}) {
|
|
76
|
+
const nudge = reviewNudge(snapshot.goals);
|
|
77
|
+
if (snapshot.goals.length === 0) {
|
|
78
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
79
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: "None" }),
|
|
80
|
+
/* @__PURE__ */ jsx(HStack, { gap: 1, children: /* @__PURE__ */ jsx(Button, { agent: "new", onPress: dispatch("new"), children: "Set a goal" }) })
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
const groups = GOAL_STATUSES.map((status) => ({
|
|
84
|
+
status,
|
|
85
|
+
goals: snapshot.goals.filter((goal) => goal.status === status)
|
|
86
|
+
})).filter((group) => {
|
|
87
|
+
if (group.goals.length === 0) return false;
|
|
88
|
+
if (active.size === 0) return true;
|
|
89
|
+
return active.has(group.status);
|
|
90
|
+
});
|
|
91
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
92
|
+
nudge ? /* @__PURE__ */ jsx(Text, { tone: "muted", style: "caption", children: nudge }) : null,
|
|
93
|
+
/* @__PURE__ */ jsx(HStack, { gap: 1, wrap: true, children: GOAL_STATUSES.map((status) => /* @__PURE__ */ jsx(
|
|
94
|
+
Button,
|
|
95
|
+
{
|
|
96
|
+
variant: active.has(status) ? "solid" : "outline",
|
|
97
|
+
tone: active.has(status) ? "primary" : "default",
|
|
98
|
+
agent: `filter:${status}`,
|
|
99
|
+
onPress: dispatch(`filter:${status}`),
|
|
100
|
+
children: STATUS_LABELS[status]
|
|
101
|
+
},
|
|
102
|
+
status
|
|
103
|
+
)) }),
|
|
104
|
+
groups.length === 0 ? /* @__PURE__ */ jsx(Text, { tone: "muted", align: "center", style: "caption", children: "None" }) : groups.map((group) => /* @__PURE__ */ jsx(GoalsStatusGroup, { group }, group.status))
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
function GoalsStatusGroup({
|
|
108
|
+
group
|
|
109
|
+
}) {
|
|
110
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
111
|
+
/* @__PURE__ */ jsxs(Text, { style: "caption", tone: "muted", children: [
|
|
112
|
+
STATUS_LABELS[group.status],
|
|
113
|
+
" (",
|
|
114
|
+
group.goals.length,
|
|
115
|
+
")"
|
|
116
|
+
] }),
|
|
117
|
+
/* @__PURE__ */ jsx(List, { gap: 0, children: group.goals.map((goal) => /* @__PURE__ */ jsx(GoalRow, { goal }, goal.id)) })
|
|
118
|
+
] });
|
|
119
|
+
}
|
|
120
|
+
function GoalRow({ goal }) {
|
|
121
|
+
const meta = [];
|
|
122
|
+
if (goal.cadenceKind) meta.push(goal.cadenceKind);
|
|
123
|
+
if (goal.target) meta.push(goal.target);
|
|
124
|
+
if (goal.linkedCount > 0) meta.push(`${goal.linkedCount} linked`);
|
|
125
|
+
return /* @__PURE__ */ jsxs(HStack, { gap: 1, align: "center", children: [
|
|
126
|
+
/* @__PURE__ */ jsx(Text, { tone: REVIEW_TONE[goal.reviewState], wrap: false, children: REVIEW_GLYPH[goal.reviewState] }),
|
|
127
|
+
/* @__PURE__ */ jsxs(VStack, { gap: 0, grow: 1, children: [
|
|
128
|
+
/* @__PURE__ */ jsx(Text, { bold: true, wrap: false, children: goal.title }),
|
|
129
|
+
meta.length > 0 ? /* @__PURE__ */ jsx(Text, { style: "caption", tone: "muted", wrap: false, children: meta.join(" \xB7 ") }) : null
|
|
130
|
+
] }),
|
|
131
|
+
/* @__PURE__ */ jsxs(VStack, { gap: 0, children: [
|
|
132
|
+
/* @__PURE__ */ jsx(
|
|
133
|
+
Text,
|
|
134
|
+
{
|
|
135
|
+
style: "caption",
|
|
136
|
+
tone: REVIEW_TONE[goal.reviewState],
|
|
137
|
+
wrap: false,
|
|
138
|
+
align: "end",
|
|
139
|
+
children: REVIEW_LABELS[goal.reviewState]
|
|
140
|
+
}
|
|
141
|
+
),
|
|
142
|
+
/* @__PURE__ */ jsx(Text, { style: "caption", tone: "muted", wrap: false, align: "end", children: formatDate(goal.updatedAt) })
|
|
143
|
+
] })
|
|
144
|
+
] });
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
GoalsSpatialView
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=GoalsSpatialView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/goals/GoalsSpatialView.tsx"],"sourcesContent":["/**\n * GoalsSpatialView — the owner life-direction surface authored once with the\n * spatial vocabulary, so it renders correctly wherever it is displayed:\n *\n * - GUI / XR — mounted in `<SpatialSurface>` (DOM; XR scales up).\n * - TUI — rendered to real terminal lines by the agent terminal, via\n * `registerSpatialTerminalView` (see `register-terminal-view.tsx`).\n *\n * It is purely presentational (a snapshot + an action callback in, primitives\n * out) and imports only the cross-modality primitives plus this plugin's own\n * display DTOs, so it is safe to render in the Node agent process where the\n * terminal lives (no browser/data-fetch import).\n *\n * The view is read-only: goals are owned by the personal-assistant routes and\n * created through the assistant chat, not mutated here. The only interactions\n * are the status-filter toggles, a Retry on the error state, and the \"Set a\n * goal\" chat affordance on the empty state.\n */\n\nimport { Button, Card, HStack, List, Text, VStack } from \"@elizaos/ui/spatial\";\nimport {\n GOAL_STATUSES,\n type GoalItem,\n type GoalReviewState,\n type GoalStatus,\n} from \"../../types.js\";\n\n/** Coarse load state of the goals surface. */\nexport type GoalsLoadStatus = \"loading\" | \"error\" | \"ready\";\n\nexport interface GoalsSnapshot {\n /** Coarse load state. */\n status: GoalsLoadStatus;\n /** Goal records (empty until ready). */\n goals: GoalItem[];\n /** Active status filters; empty = show every status. */\n activeStatuses: GoalStatus[];\n /** Error text when status is \"error\". */\n error?: string | null;\n}\n\nexport interface GoalsSpatialViewProps {\n snapshot: GoalsSnapshot;\n /**\n * Dispatch by agent id: `retry` (re-fetch on the error state), `new` (ask the\n * assistant to set a goal), and `filter:<status>` (toggle one status chip,\n * status ∈ active|paused|archived|satisfied).\n */\n onAction?: (action: string) => void;\n}\n\nconst STATUS_LABELS: Record<GoalStatus, string> = {\n active: \"Active\",\n paused: \"Paused\",\n archived: \"Archived\",\n satisfied: \"Achieved\",\n};\n\nconst REVIEW_LABELS: Record<GoalReviewState, string> = {\n idle: \"not reviewed\",\n on_track: \"on track\",\n at_risk: \"at risk\",\n needs_attention: \"needs attention\",\n};\n\n// Width-1 review marker — filled vs hollow vs cross, never emoji or a checkmark.\n// on_track → ● (settled)\n// at_risk / needs_attention → x (flagged)\n// idle → ○ (not yet reviewed)\nconst REVIEW_GLYPH: Record<GoalReviewState, string> = {\n idle: \"○\",\n on_track: \"●\",\n at_risk: \"x\",\n needs_attention: \"x\",\n};\n\nconst REVIEW_TONE: Record<GoalReviewState, \"muted\" | \"success\" | \"danger\"> = {\n idle: \"muted\",\n on_track: \"success\",\n at_risk: \"danger\",\n needs_attention: \"danger\",\n};\n\nfunction formatDate(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return value;\n return date.toLocaleDateString(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\n// One quiet proactive line: count the goals whose last review flagged them\n// (at_risk / needs_attention). Returns null when nothing is flagged so the line\n// renders only on a real signal (never \"0 goals\").\nfunction reviewNudge(goals: GoalItem[]): string | null {\n const flagged = goals.filter(\n (goal) =>\n goal.reviewState === \"at_risk\" || goal.reviewState === \"needs_attention\",\n ).length;\n if (flagged === 0) return null;\n return flagged === 1\n ? \"1 goal needs a review.\"\n : `${flagged} goals need a review.`;\n}\n\nexport function GoalsSpatialView({\n snapshot,\n onAction,\n}: GoalsSpatialViewProps) {\n const dispatch = (action: string) => () => onAction?.(action);\n const active = new Set(snapshot.activeStatuses);\n\n return (\n <Card gap={1} padding={1}>\n {snapshot.status === \"loading\" ? (\n <Text tone=\"muted\" style=\"caption\">\n Loading goals\n </Text>\n ) : snapshot.status === \"error\" ? (\n <GoalsErrorBody error={snapshot.error} dispatch={dispatch} />\n ) : (\n <GoalsReadyBody\n snapshot={snapshot}\n active={active}\n dispatch={dispatch}\n />\n )}\n </Card>\n );\n}\n\nfunction GoalsErrorBody({\n error,\n dispatch,\n}: {\n error?: string | null;\n dispatch: (action: string) => () => void;\n}) {\n return (\n <>\n <Text bold>Could not load goals</Text>\n {error ? (\n <Text tone=\"muted\" style=\"caption\">\n {error}\n </Text>\n ) : null}\n <HStack gap={1}>\n <Button agent=\"retry\" onPress={dispatch(\"retry\")}>\n Retry\n </Button>\n </HStack>\n </>\n );\n}\n\nfunction GoalsReadyBody({\n snapshot,\n active,\n dispatch,\n}: {\n snapshot: GoalsSnapshot;\n active: Set<GoalStatus>;\n dispatch: (action: string) => () => void;\n}) {\n const nudge = reviewNudge(snapshot.goals);\n\n if (snapshot.goals.length === 0) {\n return (\n <>\n <Text bold>None</Text>\n <HStack gap={1}>\n <Button agent=\"new\" onPress={dispatch(\"new\")}>\n Set a goal\n </Button>\n </HStack>\n </>\n );\n }\n\n // Group by status, dropping empty groups, then apply the active filter.\n const groups = GOAL_STATUSES.map((status) => ({\n status,\n goals: snapshot.goals.filter((goal) => goal.status === status),\n })).filter((group) => {\n if (group.goals.length === 0) return false;\n if (active.size === 0) return true;\n return active.has(group.status);\n });\n\n return (\n <>\n {nudge ? (\n <Text tone=\"muted\" style=\"caption\">\n {nudge}\n </Text>\n ) : null}\n\n <HStack gap={1} wrap>\n {GOAL_STATUSES.map((status) => (\n <Button\n key={status}\n variant={active.has(status) ? \"solid\" : \"outline\"}\n tone={active.has(status) ? \"primary\" : \"default\"}\n agent={`filter:${status}`}\n onPress={dispatch(`filter:${status}`)}\n >\n {STATUS_LABELS[status]}\n </Button>\n ))}\n </HStack>\n\n {groups.length === 0 ? (\n <Text tone=\"muted\" align=\"center\" style=\"caption\">\n None\n </Text>\n ) : (\n groups.map((group) => (\n <GoalsStatusGroup key={group.status} group={group} />\n ))\n )}\n </>\n );\n}\n\nfunction GoalsStatusGroup({\n group,\n}: {\n group: { status: GoalStatus; goals: GoalItem[] };\n}) {\n return (\n <>\n <Text style=\"caption\" tone=\"muted\">\n {STATUS_LABELS[group.status]} ({group.goals.length})\n </Text>\n <List gap={0}>\n {group.goals.map((goal) => (\n <GoalRow key={goal.id} goal={goal} />\n ))}\n </List>\n </>\n );\n}\n\nfunction GoalRow({ goal }: { goal: GoalItem }) {\n const meta: string[] = [];\n if (goal.cadenceKind) meta.push(goal.cadenceKind);\n if (goal.target) meta.push(goal.target);\n if (goal.linkedCount > 0) meta.push(`${goal.linkedCount} linked`);\n\n return (\n <HStack gap={1} align=\"center\">\n <Text tone={REVIEW_TONE[goal.reviewState]} wrap={false}>\n {REVIEW_GLYPH[goal.reviewState]}\n </Text>\n <VStack gap={0} grow={1}>\n <Text bold wrap={false}>\n {goal.title}\n </Text>\n {meta.length > 0 ? (\n <Text style=\"caption\" tone=\"muted\" wrap={false}>\n {meta.join(\" · \")}\n </Text>\n ) : null}\n </VStack>\n <VStack gap={0}>\n <Text\n style=\"caption\"\n tone={REVIEW_TONE[goal.reviewState]}\n wrap={false}\n align=\"end\"\n >\n {REVIEW_LABELS[goal.reviewState]}\n </Text>\n <Text style=\"caption\" tone=\"muted\" wrap={false} align=\"end\">\n {formatDate(goal.updatedAt)}\n </Text>\n </VStack>\n </HStack>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GoalsView — the single GUI/XR data wrapper for the Goals surface.
|
|
3
|
+
*
|
|
4
|
+
* Data-fetching view over the single read-only goals endpoint served by the
|
|
5
|
+
* personal-assistant routes (PA owns the persistence; this plugin only renders):
|
|
6
|
+
* GET {base}/api/lifeops/goals
|
|
7
|
+
*
|
|
8
|
+
* The wire payload is `{ goals: LifeOpsGoalRecord[] }`, where each record is
|
|
9
|
+
* `{ goal: LifeOpsGoalDefinition; links: LifeOpsGoalLink[] }`. We flatten each
|
|
10
|
+
* record to a `GoalItem` at the fetch boundary so the rest of the view renders
|
|
11
|
+
* display-only.
|
|
12
|
+
*
|
|
13
|
+
* It owns the fetch state machine (loading / error / ready), the status-filter
|
|
14
|
+
* selection, and the quiet 20s background poll, then renders the one
|
|
15
|
+
* presentational {@link GoalsSpatialView} inside a {@link SpatialSurface}.
|
|
16
|
+
* Omitting the `modality` prop lets `SpatialSurface` auto-detect GUI vs XR via
|
|
17
|
+
* `window.__elizaXRContext`, so the SAME component serves both surfaces. The
|
|
18
|
+
* TUI surface renders the same `GoalsSpatialView` through the terminal registry
|
|
19
|
+
* (see `register-terminal-view.tsx`).
|
|
20
|
+
*
|
|
21
|
+
* This plugin MUST NOT import from @elizaos/plugin-personal-assistant. The wire
|
|
22
|
+
* DTOs below are declared locally to match the JSON shape PA emits
|
|
23
|
+
* (LifeOpsGoalDefinition / LifeOpsGoalLink in @elizaos/shared).
|
|
24
|
+
*/
|
|
25
|
+
import type { ReactNode } from "react";
|
|
26
|
+
interface GoalDefinitionWire {
|
|
27
|
+
id: string;
|
|
28
|
+
title: string;
|
|
29
|
+
description: string;
|
|
30
|
+
cadence: Record<string, unknown> | null;
|
|
31
|
+
successCriteria: Record<string, unknown>;
|
|
32
|
+
status: string;
|
|
33
|
+
reviewState: string;
|
|
34
|
+
metadata: Record<string, unknown>;
|
|
35
|
+
createdAt: string;
|
|
36
|
+
updatedAt: string;
|
|
37
|
+
}
|
|
38
|
+
interface GoalLinkWire {
|
|
39
|
+
id: string;
|
|
40
|
+
goalId: string;
|
|
41
|
+
linkedType: string;
|
|
42
|
+
linkedId: string;
|
|
43
|
+
}
|
|
44
|
+
interface GoalRecordWire {
|
|
45
|
+
goal: GoalDefinitionWire;
|
|
46
|
+
links: GoalLinkWire[];
|
|
47
|
+
}
|
|
48
|
+
interface GoalsWire {
|
|
49
|
+
goals: GoalRecordWire[];
|
|
50
|
+
}
|
|
51
|
+
export interface GoalsFetchers {
|
|
52
|
+
fetchGoals: () => Promise<GoalsWire>;
|
|
53
|
+
}
|
|
54
|
+
export interface GoalsViewProps {
|
|
55
|
+
/** Test/host injection seam. Defaults to the real `/api/lifeops/goals` GET. */
|
|
56
|
+
fetchers?: GoalsFetchers;
|
|
57
|
+
}
|
|
58
|
+
export declare function GoalsView(props?: GoalsViewProps): ReactNode;
|
|
59
|
+
export default GoalsView;
|
|
60
|
+
//# sourceMappingURL=GoalsView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GoalsView.d.ts","sourceRoot":"","sources":["../../../src/components/goals/GoalsView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAgBvC,UAAU,kBAAkB;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,UAAU,SAAS;IACjB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAMD,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;CACtC;AAcD,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AA+ED,wBAAgB,SAAS,CAAC,KAAK,GAAE,cAAmB,GAAG,SAAS,CA0G/D;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { client } from "@elizaos/ui";
|
|
3
|
+
import { SpatialSurface } from "@elizaos/ui/spatial";
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import {
|
|
6
|
+
GOAL_STATUSES
|
|
7
|
+
} from "../../types.js";
|
|
8
|
+
import { GoalsSpatialView } from "./GoalsSpatialView.js";
|
|
9
|
+
async function getGoals() {
|
|
10
|
+
const response = await fetch(`${client.getBaseUrl()}/api/lifeops/goals`);
|
|
11
|
+
if (!response.ok) {
|
|
12
|
+
throw new Error(`Goals request failed (${response.status})`);
|
|
13
|
+
}
|
|
14
|
+
return await response.json();
|
|
15
|
+
}
|
|
16
|
+
const defaultFetchers = {
|
|
17
|
+
fetchGoals: getGoals
|
|
18
|
+
};
|
|
19
|
+
const KNOWN_STATUSES = new Set(GOAL_STATUSES);
|
|
20
|
+
const KNOWN_REVIEW_STATES = /* @__PURE__ */ new Set([
|
|
21
|
+
"idle",
|
|
22
|
+
"needs_attention",
|
|
23
|
+
"on_track",
|
|
24
|
+
"at_risk"
|
|
25
|
+
]);
|
|
26
|
+
function toStatus(value) {
|
|
27
|
+
return KNOWN_STATUSES.has(value) ? value : "active";
|
|
28
|
+
}
|
|
29
|
+
function toReviewState(value) {
|
|
30
|
+
return KNOWN_REVIEW_STATES.has(value) ? value : "idle";
|
|
31
|
+
}
|
|
32
|
+
function readCadenceKind(cadence) {
|
|
33
|
+
if (cadence && typeof cadence.kind === "string" && cadence.kind.length > 0) {
|
|
34
|
+
return cadence.kind;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function readTarget(criteria) {
|
|
39
|
+
const candidate = criteria.targetText ?? criteria.target ?? criteria.summary ?? criteria.deadline ?? criteria.dueAt;
|
|
40
|
+
if (typeof candidate === "string" && candidate.length > 0) return candidate;
|
|
41
|
+
if (typeof candidate === "number") return String(candidate);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
function mapGoal(record) {
|
|
45
|
+
const { goal, links } = record;
|
|
46
|
+
return {
|
|
47
|
+
id: goal.id,
|
|
48
|
+
title: goal.title,
|
|
49
|
+
description: goal.description ?? "",
|
|
50
|
+
status: toStatus(goal.status),
|
|
51
|
+
reviewState: toReviewState(goal.reviewState),
|
|
52
|
+
cadenceKind: readCadenceKind(goal.cadence),
|
|
53
|
+
target: readTarget(goal.successCriteria ?? {}),
|
|
54
|
+
linkedCount: links.length,
|
|
55
|
+
updatedAt: goal.updatedAt
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function requestNewGoal() {
|
|
59
|
+
client.sendChatMessage?.("Help me set a goal to head toward this quarter.");
|
|
60
|
+
}
|
|
61
|
+
function GoalsView(props = {}) {
|
|
62
|
+
const fetchers = props.fetchers ?? defaultFetchers;
|
|
63
|
+
const [state, setState] = useState({ kind: "loading" });
|
|
64
|
+
const [activeStatuses, setActiveStatuses] = useState(
|
|
65
|
+
() => /* @__PURE__ */ new Set()
|
|
66
|
+
);
|
|
67
|
+
const fetchersRef = useRef(fetchers);
|
|
68
|
+
fetchersRef.current = fetchers;
|
|
69
|
+
const load = useCallback(() => {
|
|
70
|
+
let cancelled = false;
|
|
71
|
+
setState({ kind: "loading" });
|
|
72
|
+
fetchersRef.current.fetchGoals().then((wire) => {
|
|
73
|
+
if (cancelled) return;
|
|
74
|
+
setState({ kind: "ready", goals: wire.goals.map(mapGoal) });
|
|
75
|
+
}).catch((error) => {
|
|
76
|
+
if (cancelled) return;
|
|
77
|
+
setState({
|
|
78
|
+
kind: "error",
|
|
79
|
+
message: error instanceof Error ? error.message : "Could not load goals."
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
return () => {
|
|
83
|
+
cancelled = true;
|
|
84
|
+
};
|
|
85
|
+
}, []);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const cancelInitial = load();
|
|
88
|
+
let active = true;
|
|
89
|
+
const interval = setInterval(() => {
|
|
90
|
+
fetchersRef.current.fetchGoals().then((wire) => {
|
|
91
|
+
if (active)
|
|
92
|
+
setState({ kind: "ready", goals: wire.goals.map(mapGoal) });
|
|
93
|
+
}).catch(() => {
|
|
94
|
+
});
|
|
95
|
+
}, 2e4);
|
|
96
|
+
return () => {
|
|
97
|
+
active = false;
|
|
98
|
+
clearInterval(interval);
|
|
99
|
+
cancelInitial();
|
|
100
|
+
};
|
|
101
|
+
}, [load]);
|
|
102
|
+
const toggleStatus = useCallback((status) => {
|
|
103
|
+
setActiveStatuses((prev) => {
|
|
104
|
+
const next = new Set(prev);
|
|
105
|
+
if (next.has(status)) next.delete(status);
|
|
106
|
+
else next.add(status);
|
|
107
|
+
return next;
|
|
108
|
+
});
|
|
109
|
+
}, []);
|
|
110
|
+
const onAction = useCallback(
|
|
111
|
+
(action) => {
|
|
112
|
+
if (action.startsWith("filter:")) {
|
|
113
|
+
const raw = action.slice("filter:".length);
|
|
114
|
+
if (KNOWN_STATUSES.has(raw)) toggleStatus(raw);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
switch (action) {
|
|
118
|
+
case "retry":
|
|
119
|
+
load();
|
|
120
|
+
return;
|
|
121
|
+
case "new":
|
|
122
|
+
requestNewGoal();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
[load, toggleStatus]
|
|
127
|
+
);
|
|
128
|
+
const snapshot = useMemo(() => {
|
|
129
|
+
const activeList = Array.from(activeStatuses);
|
|
130
|
+
if (state.kind === "loading") {
|
|
131
|
+
return { status: "loading", goals: [], activeStatuses: activeList };
|
|
132
|
+
}
|
|
133
|
+
if (state.kind === "error") {
|
|
134
|
+
return {
|
|
135
|
+
status: "error",
|
|
136
|
+
goals: [],
|
|
137
|
+
activeStatuses: activeList,
|
|
138
|
+
error: state.message
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return { status: "ready", goals: state.goals, activeStatuses: activeList };
|
|
142
|
+
}, [state, activeStatuses]);
|
|
143
|
+
return /* @__PURE__ */ jsx(SpatialSurface, { children: /* @__PURE__ */ jsx(GoalsSpatialView, { snapshot, onAction }) });
|
|
144
|
+
}
|
|
145
|
+
var GoalsView_default = GoalsView;
|
|
146
|
+
export {
|
|
147
|
+
GoalsView,
|
|
148
|
+
GoalsView_default as default
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=GoalsView.js.map
|