@elizaos/app-core 2.0.0-alpha.349 → 2.0.0-alpha.350

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.
Files changed (48) hide show
  1. package/i18n/locales/en.json +2 -0
  2. package/package.json +5 -5
  3. package/packages/agent/src/api/conversation-metadata.d.ts.map +1 -1
  4. package/packages/agent/src/api/conversation-metadata.js +3 -0
  5. package/packages/agent/src/api/server-helpers-swarm.d.ts +2 -0
  6. package/packages/agent/src/api/server-helpers-swarm.d.ts.map +1 -1
  7. package/packages/agent/src/api/server-helpers-swarm.js +98 -7
  8. package/packages/agent/src/api/server-types.d.ts +1 -1
  9. package/packages/agent/src/api/server-types.d.ts.map +1 -1
  10. package/packages/agent/src/auth/credentials.d.ts +2 -0
  11. package/packages/agent/src/auth/credentials.d.ts.map +1 -1
  12. package/packages/agent/src/auth/credentials.js +18 -11
  13. package/packages/agent/src/providers/page-scoped-context.d.ts.map +1 -1
  14. package/packages/agent/src/providers/page-scoped-context.js +8 -1
  15. package/packages/app-core/src/character/character-draft-helpers.d.ts +1 -1
  16. package/packages/app-core/src/character/character-draft-helpers.d.ts.map +1 -1
  17. package/packages/app-core/src/character/character-draft-helpers.js +35 -10
  18. package/packages/app-core/src/components/apps/GameView.d.ts.map +1 -1
  19. package/packages/app-core/src/components/apps/GameView.js +50 -2
  20. package/packages/app-core/src/components/pages/AppsPageView.d.ts.map +1 -1
  21. package/packages/app-core/src/components/pages/AppsPageView.js +3 -4
  22. package/packages/app-core/src/components/pages/AppsView.d.ts.map +1 -1
  23. package/packages/app-core/src/components/pages/AppsView.js +377 -8
  24. package/packages/app-core/src/components/pages/page-scoped-conversations.d.ts +1 -1
  25. package/packages/app-core/src/components/pages/page-scoped-conversations.d.ts.map +1 -1
  26. package/packages/app-core/src/components/pages/page-scoped-conversations.js +14 -0
  27. package/packages/app-core/src/components/settings/ProviderSwitcher.d.ts.map +1 -1
  28. package/packages/app-core/src/components/settings/ProviderSwitcher.js +12 -2
  29. package/packages/app-core/src/components/settings/SubscriptionStatus.d.ts +9 -1
  30. package/packages/app-core/src/components/settings/SubscriptionStatus.d.ts.map +1 -1
  31. package/packages/app-core/src/components/settings/SubscriptionStatus.js +6 -4
  32. package/packages/app-core/src/i18n/locales/en.json +2 -0
  33. package/packages/app-core/src/navigation/index.d.ts +10 -0
  34. package/packages/app-core/src/navigation/index.d.ts.map +1 -1
  35. package/packages/app-core/src/navigation/index.js +25 -0
  36. package/packages/app-core/src/shell/DetachedShellRoot.d.ts.map +1 -1
  37. package/packages/app-core/src/shell/DetachedShellRoot.js +8 -4
  38. package/packages/app-core/src/state/AppContext.d.ts.map +1 -1
  39. package/packages/app-core/src/state/AppContext.js +4 -11
  40. package/packages/app-core/src/state/useCharacterState.d.ts.map +1 -1
  41. package/packages/app-core/src/state/useCharacterState.js +4 -1
  42. package/packages/app-core/src/state/useNavigationState.d.ts.map +1 -1
  43. package/packages/app-core/src/state/useNavigationState.js +2 -2
  44. package/packages/app-core/src/utils/name-tokens.d.ts +18 -0
  45. package/packages/app-core/src/utils/name-tokens.d.ts.map +1 -1
  46. package/packages/app-core/src/utils/name-tokens.js +27 -0
  47. package/packages/shared/src/contracts/onboarding.d.ts +2 -0
  48. package/packages/shared/src/contracts/onboarding.d.ts.map +1 -1
@@ -2426,6 +2426,8 @@
2426
2426
  "subscriptionstatus.CallbackUrlMissingCode": "Callback URL is missing the ?code= parameter.",
2427
2427
  "subscriptionstatus.ChatGPTSubscription": "ChatGPT subscription credentials are expired or invalid. Reconnect\n to continue.",
2428
2428
  "subscriptionstatus.ChatGPTSubscriptionTitle": "ChatGPT Subscription",
2429
+ "subscriptionstatus.ClaudeCodeCliDetectedBody": "Signed in via the Claude Code CLI on this machine. To sign out, run `claude logout` in a terminal — the app can't clear CLI credentials. Connect in-app below to link this account to Milady explicitly.",
2430
+ "subscriptionstatus.ClaudeCodeCliDetectedTitle": "Claude Code CLI detected",
2429
2431
  "subscriptionstatus.ClaudeSubscription": "Claude subscription credentials are expired or invalid. Reconnect\n to continue.",
2430
2432
  "subscriptionstatus.ClaudeSubscriptionTitle": "Claude Subscription",
2431
2433
  "subscriptionstatus.ClaudeTosWarning": "Claude subscriptions can only be used through the Claude Code CLI (Anthropic TOS). Your subscription will power task agents but not the main agent runtime. For the main agent, use Eliza Cloud, a direct Anthropic API key, or another provider.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/app-core",
3
- "version": "2.0.0-alpha.349",
3
+ "version": "2.0.0-alpha.350",
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.349",
472
+ "@elizaos/agent": "^2.0.0-alpha.350",
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.349",
481
+ "@elizaos/core": "^2.0.0-alpha.350",
482
482
  "@elizaos/plugin-browser-bridge": "^0.1.0",
483
483
  "@elizaos/plugin-wechat": "^0.1.0",
484
- "@elizaos/shared": "^2.0.0-alpha.349",
485
- "@elizaos/ui": "^2.0.0-alpha.349",
484
+ "@elizaos/shared": "^2.0.0-alpha.350",
485
+ "@elizaos/ui": "^2.0.0-alpha.350",
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":"conversation-metadata.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/api/conversation-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EAErB,MAAM,mBAAmB,CAAC;AAE3B,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAyBpD,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,OAAO,GACb,oBAAoB,GAAG,SAAS,CAkDlC;AAED,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,UAAU,CAAC,EACvD,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,OAAO,GACzB,kBAAkB,CAkBpB;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,SAAS,EAC/C,sBAAsB,CAAC,EAAE,MAAM,GAC9B,oBAAoB,GAAG,SAAS,CAkBlC;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,OAAO,CAOT;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,OAAO,CAGT"}
1
+ {"version":3,"file":"conversation-metadata.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/api/conversation-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EAErB,MAAM,mBAAmB,CAAC;AAE3B,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AA4BpD,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,OAAO,GACb,oBAAoB,GAAG,SAAS,CAkDlC;AAED,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,UAAU,CAAC,EACvD,OAAO,EAAE,MAAM,EACf,gBAAgB,CAAC,EAAE,OAAO,GACzB,kBAAkB,CAkBpB;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,SAAS,EAC/C,sBAAsB,CAAC,EAAE,MAAM,GAC9B,oBAAoB,GAAG,SAAS,CAkBlC;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,OAAO,CAOT;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAChD,OAAO,CAGT"}
@@ -7,8 +7,11 @@ const VALID_SCOPES = new Set([
7
7
  "automation-draft",
8
8
  "page-character",
9
9
  "page-apps",
10
+ "page-connectors",
10
11
  "page-phone",
12
+ "page-plugins",
11
13
  "page-lifeops",
14
+ "page-settings",
12
15
  "page-wallet",
13
16
  "page-browser",
14
17
  "page-automations",
@@ -46,6 +46,8 @@ export declare function handleSwarmSynthesis(st: {
46
46
  originalTask: string;
47
47
  status: string;
48
48
  completionSummary: string;
49
+ roomId?: string | null;
50
+ workdir?: string;
49
51
  }>;
50
52
  total: number;
51
53
  completed: number;
@@ -1 +1 @@
1
- {"version":3,"file":"server-helpers-swarm.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/api/server-helpers-swarm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-helpers-swarm.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/api/server-helpers-swarm.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,9 @@
2
2
  * Swarm/autonomy/coding-agent helpers extracted from server.ts.
3
3
  */
4
4
  import crypto from "node:crypto";
5
+ import { promises as fs } from "node:fs";
6
+ import os from "node:os";
7
+ import path from "node:path";
5
8
  import { ChannelType, createMessageMemory, logger, stringToUuid, } from "@elizaos/core";
6
9
  import { generateChatResponse as generateChatResponseFromChatRoutes } from "./chat-routes.js";
7
10
  import { resolveClientChatAdminEntityId } from "./client-chat-admin.js";
@@ -131,8 +134,8 @@ export function wireCodingAgentSwarmSynthesis(st) {
131
134
  const coordinator = getCoordinatorFromRuntime(st.runtime);
132
135
  if (!coordinator?.setSwarmCompleteCallback)
133
136
  return false;
134
- coordinator.setSwarmCompleteCallback(async () => {
135
- // Deliberately no-op -- synthesis happens via the streamer instead.
137
+ coordinator.setSwarmCompleteCallback(async (payload) => {
138
+ await handleSwarmSynthesis(st, payload);
136
139
  });
137
140
  return true;
138
141
  }
@@ -149,15 +152,46 @@ export async function handleSwarmSynthesis(st, payload, routeMessage = (text, so
149
152
  const resultText = await buildSynthesisResultText(payload);
150
153
  logger.info("[swarm-synthesis] Synthesis generated, routing to user");
151
154
  await routeMessage(resultText, "swarm_synthesis");
152
- await routeSynthesisToConnector(runtime, resultText);
155
+ // coordinator.sourceRoomId is declared on the interface but never assigned
156
+ // by the orchestrator, so without a fallback the connector route is dead.
157
+ // Pick the most recently terminal task's roomId: that's the task whose
158
+ // completion fired this swarm_complete, and whose room is waiting for an
159
+ // answer. Naively taking "first task with a roomId" leaks results into
160
+ // stale rooms when the coordinator carries tasks across rooms.
161
+ const terminalStatuses = new Set(["completed", "stopped", "errored"]);
162
+ let fallbackRoomId = null;
163
+ for (let i = payload.tasks.length - 1; i >= 0; i--) {
164
+ const candidate = payload.tasks[i];
165
+ if (typeof candidate.roomId !== "string" || !candidate.roomId)
166
+ continue;
167
+ if (terminalStatuses.has(candidate.status)) {
168
+ fallbackRoomId = candidate.roomId;
169
+ break;
170
+ }
171
+ // Track last-seen room as a fallback if no terminal task carries one.
172
+ if (!fallbackRoomId) {
173
+ fallbackRoomId = candidate.roomId;
174
+ }
175
+ }
176
+ await routeSynthesisToConnector(runtime, resultText, fallbackRoomId);
153
177
  }
154
178
  async function buildSynthesisResultText(payload) {
155
179
  const parts = await Promise.all(payload.tasks.map(buildTaskResultLine));
156
180
  return parts.length === 1
157
- ? `done -- ${parts[0]}`
158
- : `done -- ${payload.total} tasks:\n${parts.map((p) => `- ${p}`).join("\n")}`;
181
+ ? parts[0]
182
+ : `${payload.total} tasks:\n${parts.map((p) => `- ${p}`).join("\n")}`;
159
183
  }
160
184
  async function buildTaskResultLine(task) {
185
+ // Prefer the agent's actual final assistant message: that's the real
186
+ // deliverable (news brief, code summary, URL, etc.). The coordinator's
187
+ // completionSummary is a meta-judgment about whether the task finished,
188
+ // not the content the agent produced. Only fall through if the jsonl
189
+ // can't be read.
190
+ if (task.workdir) {
191
+ const finalText = await readAgentFinalAssistantMessage(task.workdir);
192
+ if (finalText)
193
+ return finalText;
194
+ }
161
195
  if (task.completionSummary)
162
196
  return task.completionSummary;
163
197
  const portMatch = task.originalTask.match(/port\s+(\d+)/i);
@@ -170,6 +204,63 @@ async function buildTaskResultLine(task) {
170
204
  }
171
205
  return `built the files but server isn't running on port ${port} yet`;
172
206
  }
207
+ async function readAgentFinalAssistantMessage(workdir) {
208
+ try {
209
+ // claude-code persists each session under a project directory whose name
210
+ // is the workdir with both "/" and "." replaced by "-" (so a hidden
211
+ // path like /home/u/.milady/workspaces/<id> becomes
212
+ // -home-u--milady-workspaces-<id>).
213
+ const sanitized = workdir.replace(/[/.]/g, "-");
214
+ const projectDir = path.join(os.homedir(), ".claude", "projects", sanitized);
215
+ const entries = await fs.readdir(projectDir, { withFileTypes: true });
216
+ const jsonls = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
217
+ if (jsonls.length === 0)
218
+ return null;
219
+ const stats = await Promise.all(jsonls.map(async (e) => ({
220
+ name: e.name,
221
+ mtime: (await fs.stat(path.join(projectDir, e.name))).mtimeMs,
222
+ })));
223
+ stats.sort((a, b) => b.mtime - a.mtime);
224
+ const newest = path.join(projectDir, stats[0].name);
225
+ const raw = await fs.readFile(newest, "utf8");
226
+ let lastText = "";
227
+ for (const line of raw.split("\n")) {
228
+ const trimmed = line.trim();
229
+ if (!trimmed)
230
+ continue;
231
+ try {
232
+ const obj = JSON.parse(trimmed);
233
+ if (obj.type !== "assistant")
234
+ continue;
235
+ const message = obj.message;
236
+ if (!message || message.role !== "assistant")
237
+ continue;
238
+ const content = message.content;
239
+ if (typeof content === "string") {
240
+ lastText = content;
241
+ }
242
+ else if (Array.isArray(content)) {
243
+ for (const part of content) {
244
+ if (part &&
245
+ typeof part === "object" &&
246
+ part.type === "text" &&
247
+ typeof part.text === "string") {
248
+ lastText = part.text;
249
+ }
250
+ }
251
+ }
252
+ }
253
+ catch {
254
+ // skip malformed lines
255
+ }
256
+ }
257
+ const collapsed = lastText.trim();
258
+ return collapsed.length > 0 ? collapsed : null;
259
+ }
260
+ catch {
261
+ return null;
262
+ }
263
+ }
173
264
  async function isPortServing(port) {
174
265
  try {
175
266
  const res = await fetch(`http://localhost:${port}/`, {
@@ -181,9 +272,9 @@ async function isPortServing(port) {
181
272
  return false;
182
273
  }
183
274
  }
184
- async function routeSynthesisToConnector(runtime, resultText) {
275
+ async function routeSynthesisToConnector(runtime, resultText, fallbackRoomId = null) {
185
276
  const coordinator = getCoordinatorFromRuntime(runtime);
186
- const sourceRoomId = coordinator?.sourceRoomId;
277
+ const sourceRoomId = coordinator?.sourceRoomId ?? fallbackRoomId;
187
278
  if (!sourceRoomId)
188
279
  return;
189
280
  try {
@@ -14,7 +14,7 @@ import type { ConnectorHealthMonitor } from "./connector-health.js";
14
14
  import type { RegistryService } from "./registry-service.js";
15
15
  export type { TrainingServiceLike, TrainingServiceWithRuntime, } from "@elizaos/app-training/services/training-service-like";
16
16
  import type { TrainingServiceWithRuntime } from "@elizaos/app-training/services/training-service-like";
17
- export type ConversationScope = "general" | "automation-coordinator" | "automation-workflow" | "automation-workflow-draft" | "automation-draft" | "page-character" | "page-apps" | "page-phone" | "page-lifeops" | "page-settings" | "page-wallet" | "page-browser" | "page-automations";
17
+ export type ConversationScope = "general" | "automation-coordinator" | "automation-workflow" | "automation-workflow-draft" | "automation-draft" | "page-character" | "page-apps" | "page-connectors" | "page-phone" | "page-plugins" | "page-lifeops" | "page-settings" | "page-wallet" | "page-browser" | "page-automations";
18
18
  export type ConversationAutomationType = "coordinator_text" | "n8n_workflow";
19
19
  export interface ConversationMetadata {
20
20
  scope?: ConversationScope;
@@ -1 +1 @@
1
- {"version":3,"file":"server-types.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/api/server-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-types.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/api/server-types.ts"],"names":[],"mappings":"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"}
@@ -36,11 +36,13 @@ export declare function getAccessToken(provider: SubscriptionProvider): Promise<
36
36
  * awaited without `await` — silently marking every user as
37
37
  * "configured: true".
38
38
  */
39
+ export type SubscriptionCredentialSource = "app" | "claude-code-cli" | "setup-token" | "codex-cli" | null;
39
40
  export declare function getSubscriptionStatus(): Array<{
40
41
  provider: SubscriptionProvider;
41
42
  configured: boolean;
42
43
  valid: boolean;
43
44
  expiresAt: number | null;
45
+ source: SubscriptionCredentialSource;
44
46
  }>;
45
47
  /**
46
48
  * Apply subscription credentials to the environment.
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/auth/credentials.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EAEtB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAqBpB;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,gBAAgB,GAC5B,IAAI,CAaN;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,oBAAoB,GAC7B,iBAAiB,GAAG,IAAI,CAW1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAUtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAI3E;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BxB;AAuCD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,IAAI,KAAK,CAAC;IAC7C,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC,CAmDD;AAkJD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,4BAA4B,CAAC,MAAM,CAAC,EAAE;IAC1D,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE;YAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE;gBAAE,OAAO,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAC;KAC5E,CAAC;CACH,GAAG,OAAO,CAAC,IAAI,CAAC,CAoEhB"}
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/auth/credentials.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EAEtB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAqBpB;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,oBAAoB,EAC9B,WAAW,EAAE,gBAAgB,GAC5B,IAAI,CAaN;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,oBAAoB,GAC7B,iBAAiB,GAAG,IAAI,CAW1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAUtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAI3E;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BxB;AAuCD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,4BAA4B,GACpC,KAAK,GACL,iBAAiB,GACjB,aAAa,GACb,WAAW,GACX,IAAI,CAAC;AAET,wBAAgB,qBAAqB,IAAI,KAAK,CAAC;IAC7C,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,4BAA4B,CAAC;CACtC,CAAC,CAmED;AAkJD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,4BAA4B,CAAC,MAAM,CAAC,EAAE;IAC1D,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE;YAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE;gBAAE,OAAO,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAC;KAC5E,CAAC;CACH,GAAG,OAAO,CAAC,IAAI,CAAC,CAoEhB"}
@@ -142,17 +142,6 @@ function hasCodexCliSubscriptionAuth() {
142
142
  return false;
143
143
  }
144
144
  }
145
- /**
146
- * Get all configured subscription providers and their status.
147
- *
148
- * IMPORTANT: stays synchronous. For Anthropic we check whether a
149
- * Claude Code OAuth credential blob exists on disk or in the keychain
150
- * via `readClaudeCodeOAuthBlob()` (sync, no refresh) rather than
151
- * calling `importClaudeCodeOAuthToken()` which is async and returns
152
- * a `Promise<string | null>` that would always be truthy when
153
- * awaited without `await` — silently marking every user as
154
- * "configured: true".
155
- */
156
145
  export function getSubscriptionStatus() {
157
146
  const providers = [
158
147
  "anthropic-subscription",
@@ -166,15 +155,19 @@ export function getSubscriptionStatus() {
166
155
  // of every `GET /api/subscription/status` request.
167
156
  const claudeBlob = provider === "anthropic-subscription" ? readClaudeCodeOAuthBlob() : null;
168
157
  let importedClaudeAuth = null;
158
+ let claudeSource = null;
169
159
  if (provider === "anthropic-subscription") {
170
160
  if (claudeBlob?.accessToken) {
171
161
  // Blob exists with a parsed accessToken — the user has Claude
172
162
  // Code installed and authenticated. Expiry is validated
173
163
  // below via the `valid` field.
174
164
  importedClaudeAuth = claudeBlob.accessToken;
165
+ claudeSource = "claude-code-cli";
175
166
  }
176
167
  else {
177
168
  importedClaudeAuth = readConfiguredAnthropicSetupToken();
169
+ if (importedClaudeAuth)
170
+ claudeSource = "setup-token";
178
171
  }
179
172
  }
180
173
  const importedCodexAuth = provider === "openai-codex" && hasCodexCliSubscriptionAuth();
@@ -189,6 +182,19 @@ export function getSubscriptionStatus() {
189
182
  const blobValid = claudeBlob
190
183
  ? blobExpiresAt === null || blobExpiresAt > Date.now()
191
184
  : false;
185
+ // App-owned credentials take priority over system/CLI sources —
186
+ // they represent an explicit in-app OAuth, and they're the only
187
+ // source the DELETE /api/subscription/{provider} route can clear.
188
+ let source = null;
189
+ if (stored !== null) {
190
+ source = "app";
191
+ }
192
+ else if (provider === "anthropic-subscription" && claudeSource) {
193
+ source = claudeSource;
194
+ }
195
+ else if (importedCodexAuth) {
196
+ source = "codex-cli";
197
+ }
192
198
  return {
193
199
  provider,
194
200
  configured: stored !== null || Boolean(importedClaudeAuth || importedCodexAuth),
@@ -198,6 +204,7 @@ export function getSubscriptionStatus() {
198
204
  ? blobValid
199
205
  : Boolean(importedCodexAuth),
200
206
  expiresAt: stored?.credentials.expires ?? blobExpiresAt,
207
+ source,
201
208
  };
202
209
  });
203
210
  }
@@ -1 +1 @@
1
- {"version":3,"file":"page-scoped-context.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/providers/page-scoped-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,QAAQ,EAGT,MAAM,eAAe,CAAC;AAumBvB,eAAO,MAAM,yBAAyB,EAAE,QA8DvC,CAAC"}
1
+ {"version":3,"file":"page-scoped-context.d.ts","sourceRoot":"","sources":["../../../../../../agent/src/providers/page-scoped-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,QAAQ,EAGT,MAAM,eAAe,CAAC;AAinBvB,eAAO,MAAM,yBAAyB,EAAE,QA8DvC,CAAC"}
@@ -10,7 +10,10 @@ const PAGE_SCOPE_BRIEF = {
10
10
  "page-character": "The user is in the Character view. The Character hub is organized into Overview, Personality, Knowledge, Experience, and Relationships. Name, voice, and system prompt live in Settings > Identity; Personality focuses on bio, style rules, message examples, and evolution history; Knowledge holds uploaded and learned knowledge; Experience surfaces durable learnings the agent recorded; Relationships shows the full relationship graph, facts, memories, and user-scoped personality preferences. When the user asks what to do, explain the relevant hub section, recommend the next improvement from live state, and offer to draft exact copy. Guide the user to the relevant section rather than fabricate a generic setter action.",
11
11
  "page-automations": "The user is in the Automations view. They can create coordinator-text triggers, one-off tasks, recurring tasks, and n8n workflows; set cron or interval schedules; configure wake mode (inject_now / schedule_at / interval), max-runs, and enabled state; browse templates; inspect existing automations; and troubleshoot failed runs. Action vocabulary: createTriggerTaskAction, manageTasksAction. When the user asks what to do, recommend trigger vs task vs workflow based on the event, schedule, and desired result. Triggers and workflows already in the system are listed in live state below; reference them by display name when answering.",
12
12
  "page-apps": "The user is in the Apps view. They can browse and compare catalog apps, launch apps, stop running apps, open attached live viewers, inspect run health and summaries, and manage favorites or recent apps. Action vocabulary: launchAppAction, stopAppAction. When the user asks what to do, recommend an app or run-management action from the live catalog and running app state. Refer to apps by display name and never invent app names.",
13
+ "page-connectors": "The user is in the Connectors view. They can inspect connector availability, authentication state, setup requirements, webhook readiness, and integration health. When the user asks what to do, recommend the smallest connector setup or troubleshooting action that fits the visible state. Never invent connected accounts, permissions, webhook state, or delivery results.",
14
+ "page-plugins": "The user is in the Plugins view. They can inspect installed plugins, registry plugins, configuration readiness, plugin health, and runtime capability gaps. When the user asks what to do, recommend the smallest plugin setup or troubleshooting action that fits the visible state. Never invent installed plugins, credentials, or enabled capabilities.",
13
15
  "page-lifeops": "The user is in the LifeOps view. They can inspect the overview, goals, reminders, calendar, messages, mail, sleep, screen time, social context, connector setup, capability readiness, and LifeOps settings. The LifeOps app provider and actions are the authoritative execution path for creating or changing personal workflows, reminders, goals, schedules, inbox drafts, connector setup, and executive-assistant follow-through. When the user asks what to do, recommend capability readiness and overview review first, then suggest the smallest concrete LifeOps action. Reference only live LifeOps state below; never invent reminders, messages, calendar events, goals, or connector status.",
16
+ "page-settings": "The user is in the Settings view. They can tune models, providers, permissions, connectors, wallet RPC, cloud account state, appearance, updates, and feature toggles. When the user asks what to do, recommend the smallest concrete settings change that fits the visible section. Ask before changes that affect security, spending, or external accounts. Never invent provider status, account state, or permission grants.",
14
17
  "page-wallet": "The user is in the Wallet view. They can inspect token inventory, NFTs, LP position status, current balance, P&L, activity, EVM/Solana addresses, RPC/provider readiness, wallet/RPC settings, and Vincent trading. There are no chain filters in this surface. When the user asks what to do, recommend the smallest concrete wallet action and confirm asset, amount, destination, slippage/risk limits, and execution path before invoking any available action. If the user asks about trading, betting, gambling, predicting, Hyperliquid, or Polymarket, surface Vincent as the preferred integration when connected or suggest connecting it when not connected. Never invent balances, positions, fills, or execution support.",
15
18
  "automation-draft": "This is an automation-creation room. The user wants to create exactly one automation. Decide the right shape based on their description and call the matching action exactly once:\n" +
16
19
  '- Recurring prompt or schedule (e.g. "every morning summarize my inbox") → CREATE_TRIGGER_TASK with a clear displayName, instructions, and schedule.\n' +
@@ -420,6 +423,10 @@ async function renderLiveStateForScope(runtime, scope) {
420
423
  return renderAppsLiveState();
421
424
  case "page-lifeops":
422
425
  return renderLifeOpsLiveState();
426
+ case "page-connectors":
427
+ case "page-plugins":
428
+ case "page-settings":
429
+ return null;
423
430
  case "page-wallet":
424
431
  return renderWalletLiveState();
425
432
  default:
@@ -435,7 +442,7 @@ function formatSourceTail(entries) {
435
442
  }
436
443
  export const pageScopedContextProvider = {
437
444
  name: "page-scoped-context",
438
- description: "Operational context for the current page-scoped chat (Browser, Character, Apps, LifeOps, Automations, Wallet).",
445
+ description: "Operational context for the current page-scoped chat (Browser, Character, Apps, Connectors, Plugins, Settings, LifeOps, Automations, Wallet).",
439
446
  dynamic: false,
440
447
  position: 5,
441
448
  async get(runtime, message) {
@@ -21,7 +21,7 @@ export declare function loadCharacter(ctx: CharacterActionContext): Promise<void
21
21
  export declare function normalizeGeneratedMessageExamples(input: unknown, fallbackAgentName?: string, options?: {
22
22
  fallbackMissingSpeaker?: boolean;
23
23
  }): MessageExampleGroup[];
24
- export declare function prepareDraftForSave(draft: CharacterData): Record<string, unknown>;
24
+ export declare function prepareDraftForSave(draft: CharacterData, previousName?: string): Record<string, unknown>;
25
25
  export declare function parseMessageExamplesInput(value: string): Array<{
26
26
  examples: Array<{
27
27
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"character-draft-helpers.d.ts","sourceRoot":"","sources":["../../../../../src/character/character-draft-helpers.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEhE,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CAC9D,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,WAAW,CAAC;IACpB,gBAAgB,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,iBAAiB,EAAE,CACjB,EAAE,EAAE,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,CAAC,KACzD,IAAI,CAAC;IACV,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACtD,uBAAuB,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAiHD,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,OAAO,EACd,iBAAiB,SAAU,EAC3B,OAAO,GAAE;IAAE,sBAAsB,CAAC,EAAE,OAAO,CAAA;CAAO,GACjD,mBAAmB,EAAE,CAqCvB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuFzB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAC9D,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CAC9D,CAAC,CAiBD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAKvD"}
1
+ {"version":3,"file":"character-draft-helpers.d.ts","sourceRoot":"","sources":["../../../../../src/character/character-draft-helpers.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGhE,KAAK,mBAAmB,GAAG;IACzB,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CAC9D,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,WAAW,CAAC;IACpB,gBAAgB,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,iBAAiB,EAAE,CACjB,EAAE,EAAE,aAAa,GAAG,CAAC,CAAC,IAAI,EAAE,aAAa,KAAK,aAAa,CAAC,KACzD,IAAI,CAAC;IACV,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACtD,uBAAuB,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAiHD,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,OAAO,EACd,iBAAiB,SAAU,EAC3B,OAAO,GAAE;IAAE,sBAAsB,CAAC,EAAE,OAAO,CAAA;CAAO,GACjD,mBAAmB,EAAE,CAqCvB;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA8GzB;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAC9D,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CAC9D,CAAC,CAiBD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAKvD"}
@@ -1,4 +1,5 @@
1
1
  /** Character action helpers — CRUD and draft management. */
2
+ import { tokenizeNameOccurrences } from "../utils/name-tokens";
2
3
  export async function loadCharacter(ctx) {
3
4
  ctx.setCharacterLoading(true);
4
5
  ctx.setCharacterSaveError(null);
@@ -144,7 +145,7 @@ export function normalizeGeneratedMessageExamples(input, fallbackAgentName = "Ag
144
145
  .map((group) => normalizeConversation(group, fallbackAgentName, options))
145
146
  .filter((group) => Boolean(group));
146
147
  }
147
- export function prepareDraftForSave(draft) {
148
+ export function prepareDraftForSave(draft, previousName) {
148
149
  // Only pick fields the API schema accepts (.strict() rejects unknown keys)
149
150
  const result = {};
150
151
  if (draft.name?.trim()) {
@@ -156,26 +157,50 @@ export function prepareDraftForSave(draft) {
156
157
  else if (typeof result.name === "string") {
157
158
  result.username = result.name;
158
159
  }
160
+ // Build a tokenizer that replaces whole-word occurrences of the
161
+ // current *and* previous agent name with `{{name}}`. Load-side expansion
162
+ // (useCharacterState.loadCharacter → replaceNameTokens) renders them back
163
+ // against whatever the current name is, so renames now propagate through
164
+ // every free-text field without manual edits.
165
+ //
166
+ // Both names are tokenized so a rename within the same save pass also
167
+ // catches old-name literals that the user didn't hand-edit.
168
+ const currentName = typeof result.name === "string" ? result.name : "";
169
+ const previousNameTrimmed = previousName?.trim() ?? "";
170
+ const tokenize = (value) => {
171
+ let out = value;
172
+ if (currentName)
173
+ out = tokenizeNameOccurrences(out, currentName);
174
+ if (previousNameTrimmed && previousNameTrimmed !== currentName) {
175
+ out = tokenizeNameOccurrences(out, previousNameTrimmed);
176
+ }
177
+ return out;
178
+ };
159
179
  if (draft.system)
160
- result.system = draft.system;
180
+ result.system = tokenize(draft.system);
161
181
  if (typeof draft.bio === "string") {
162
182
  const lines = draft.bio
163
183
  .split("\n")
164
184
  .map((l) => l.trim())
165
- .filter((l) => l.length > 0);
185
+ .filter((l) => l.length > 0)
186
+ .map(tokenize);
166
187
  if (lines.length > 0)
167
188
  result.bio = lines;
168
189
  }
169
190
  else if (Array.isArray(draft.bio) && draft.bio.length > 0) {
170
- result.bio = draft.bio;
191
+ result.bio = draft.bio.map(tokenize);
171
192
  }
172
193
  const adjectives = (draft.adjectives ?? []).filter((s) => s.trim().length > 0);
173
194
  if (adjectives.length > 0)
174
195
  result.adjectives = adjectives;
175
- const topics = (draft.topics ?? []).filter((s) => s.trim().length > 0);
196
+ const topics = (draft.topics ?? [])
197
+ .filter((s) => s.trim().length > 0)
198
+ .map(tokenize);
176
199
  if (topics.length > 0)
177
200
  result.topics = topics;
178
- const postExamples = (draft.postExamples ?? []).filter((s) => s.trim().length > 0);
201
+ const postExamples = (draft.postExamples ?? [])
202
+ .filter((s) => s.trim().length > 0)
203
+ .map(tokenize);
179
204
  if (postExamples.length > 0)
180
205
  result.postExamples = postExamples;
181
206
  if (draft.messageExamples != null) {
@@ -193,7 +218,7 @@ export function prepareDraftForSave(draft) {
193
218
  return {
194
219
  name: msg.name.trim(),
195
220
  content: {
196
- text: msg.content.text.trim(),
221
+ text: tokenize(msg.content.text.trim()),
197
222
  ...(originalMessage?.content?.actions
198
223
  ? { actions: originalMessage.content.actions }
199
224
  : {}),
@@ -208,11 +233,11 @@ export function prepareDraftForSave(draft) {
208
233
  if (draft.style) {
209
234
  const style = {};
210
235
  if (draft.style.all?.length)
211
- style.all = draft.style.all;
236
+ style.all = draft.style.all.map(tokenize);
212
237
  if (draft.style.chat?.length)
213
- style.chat = draft.style.chat;
238
+ style.chat = draft.style.chat.map(tokenize);
214
239
  if (draft.style.post?.length)
215
- style.post = draft.style.post;
240
+ style.post = draft.style.post.map(tokenize);
216
241
  if (Object.keys(style).length > 0)
217
242
  result.style = style;
218
243
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GameView.d.ts","sourceRoot":"","sources":["../../../../../../src/components/apps/GameView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,OAAO,EAGL,KAAK,eAAe,EAGrB,MAAM,WAAW,CAAC;AAUnB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAW3E,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,eAAe,GAAG,IAAI,GAC9B,eAAe,GAAG,IAAI,CAcxB;AA8ED,eAAO,MAAM,wBAAwB,EAAE,SAAS,qBAAqB,EAyC3D,CAAC;AAEX,wBAAgB,yBAAyB,CAAC,EACxC,YAAY,GACb,EAAE;IACD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,2CA0VA;AAED,wBAAgB,QAAQ,4CAyhDvB"}
1
+ {"version":3,"file":"GameView.d.ts","sourceRoot":"","sources":["../../../../../../src/components/apps/GameView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,OAAO,EAGL,KAAK,eAAe,EAGrB,MAAM,WAAW,CAAC;AAUnB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAW3E,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,eAAe,GAAG,IAAI,GAC9B,eAAe,GAAG,IAAI,CAcxB;AA8ED,eAAO,MAAM,wBAAwB,EAAE,SAAS,qBAAqB,EAkD3D,CAAC;AAEX,wBAAgB,yBAAyB,CAAC,EACxC,YAAY,GACb,EAAE;IACD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,2CA8ZA;AAED,wBAAgB,QAAQ,4CAyhDvB"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /**
3
3
  * Game View — embeds a running app's game client in an iframe.
4
4
  *
@@ -10,6 +10,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
10
10
  */
11
11
  import { packageNameToAppRouteSlug } from "@elizaos/shared/contracts/apps";
12
12
  import { Button, Input, useDocumentVisibility, useIntervalWhenDocumentVisible, useTimeout, } from "@elizaos/ui";
13
+ import { Pin, PinOff } from "lucide-react";
13
14
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
14
15
  import { client, } from "../../api";
15
16
  import { invokeDesktopBridgeRequest, isElectrobunRuntime } from "../../bridge";
@@ -108,6 +109,14 @@ export const DESKTOP_GAME_CLICK_AUDIT = [
108
109
  runtimeRequirement: "desktop",
109
110
  coverage: "automated",
110
111
  },
112
+ {
113
+ id: "game-native-always-on-top",
114
+ entryPoint: "game",
115
+ label: "Toggle Game Window Always On Top",
116
+ expectedAction: "Toggle whether the native game window floats above other windows.",
117
+ runtimeRequirement: "desktop",
118
+ coverage: "automated",
119
+ },
111
120
  {
112
121
  id: "game-native-snapshot",
113
122
  entryPoint: "game",
@@ -130,6 +139,7 @@ export function DesktopGameWindowControls({ gameWindowId, }) {
130
139
  const [busyAction, setBusyAction] = useState(null);
131
140
  const [message, setMessage] = useState(null);
132
141
  const [error, setError] = useState(null);
142
+ const [alwaysOnTop, setAlwaysOnTop] = useState(false);
133
143
  const [boundsLabel, setBoundsLabel] = useState(t("gameview.BoundsUnavailable", { defaultValue: "Bounds unavailable." }));
134
144
  const [gpuWindowId, setGpuWindowId] = useState(null);
135
145
  const branding = useBranding();
@@ -138,6 +148,7 @@ export function DesktopGameWindowControls({ gameWindowId, }) {
138
148
  setBoundsLabel(t("gameview.WaitingForNativeGameWindow", {
139
149
  defaultValue: "Waiting for native game window.",
140
150
  }));
151
+ setAlwaysOnTop(false);
141
152
  }
142
153
  else {
143
154
  const bounds = await invokeDesktopBridgeRequest({
@@ -148,6 +159,17 @@ export function DesktopGameWindowControls({ gameWindowId, }) {
148
159
  if (bounds) {
149
160
  setBoundsLabel(`${bounds.width}x${bounds.height} @ ${bounds.x},${bounds.y}`);
150
161
  }
162
+ try {
163
+ const windows = await invokeDesktopBridgeRequest({
164
+ rpcMethod: "canvasListWindows",
165
+ ipcChannel: "canvas:listWindows",
166
+ });
167
+ const currentWindow = windows?.windows.find((item) => item.id === gameWindowId);
168
+ setAlwaysOnTop(currentWindow?.alwaysOnTop ?? false);
169
+ }
170
+ catch (err) {
171
+ console.warn("[GameView] Failed to refresh game window pin state", err);
172
+ }
151
173
  }
152
174
  const gpuWindows = await invokeDesktopBridgeRequest({
153
175
  rpcMethod: "gpuWindowList",
@@ -225,7 +247,33 @@ export function DesktopGameWindowControls({ gameWindowId, }) {
225
247
  });
226
248
  }, t("gameview.HidNativeGameWindow", {
227
249
  defaultValue: "Hid native game window.",
228
- }), false), disabled: !gameWindowId || busyAction === "game-native-hide", children: t("gameview.HideWindow", { defaultValue: "Hide Window" }) }), _jsx(Button, { variant: "outline", size: "sm", className: "h-7 text-xs shadow-sm hover:border-accent", onClick: () => void runAction("game-native-snapshot", async () => {
250
+ }), false), disabled: !gameWindowId || busyAction === "game-native-hide", children: t("gameview.HideWindow", { defaultValue: "Hide Window" }) }), _jsxs(Button, { variant: alwaysOnTop ? "default" : "outline", size: "sm", className: "h-7 gap-1.5 text-xs shadow-sm hover:border-accent", onClick: () => void runAction("game-native-always-on-top", async () => {
251
+ if (!gameWindowId) {
252
+ throw new Error(t("gameview.GameWindowNotReadyYet", {
253
+ defaultValue: "Game window not ready yet.",
254
+ }));
255
+ }
256
+ const next = !alwaysOnTop;
257
+ const result = await invokeDesktopBridgeRequest({
258
+ rpcMethod: "canvasSetAlwaysOnTop",
259
+ ipcChannel: "canvas:setAlwaysOnTop",
260
+ params: { id: gameWindowId, flag: next },
261
+ });
262
+ if (!result?.success) {
263
+ throw new Error(t("gameview.GameWindowNoLongerOpen", {
264
+ defaultValue: "Game window is no longer open.",
265
+ }));
266
+ }
267
+ setAlwaysOnTop(next);
268
+ }, alwaysOnTop
269
+ ? t("gameview.NativeGameWindowNormal", {
270
+ defaultValue: "Native game window acts like a normal window.",
271
+ })
272
+ : t("gameview.NativeGameWindowPinned", {
273
+ defaultValue: "Native game window stays on top.",
274
+ })), disabled: !gameWindowId || busyAction === "game-native-always-on-top", children: [alwaysOnTop ? (_jsx(PinOff, { className: "h-3.5 w-3.5", "aria-hidden": "true" })) : (_jsx(Pin, { className: "h-3.5 w-3.5", "aria-hidden": "true" })), alwaysOnTop
275
+ ? t("gameview.NormalWindow", { defaultValue: "Normal Window" })
276
+ : t("gameview.KeepOnTop", { defaultValue: "Keep On Top" })] }), _jsx(Button, { variant: "outline", size: "sm", className: "h-7 text-xs shadow-sm hover:border-accent", onClick: () => void runAction("game-native-snapshot", async () => {
229
277
  if (!gameWindowId) {
230
278
  throw new Error(t("gameview.GameWindowNotReadyYet", {
231
279
  defaultValue: "Game window not ready yet.",