@agentprojectcontext/apx 1.32.0 → 1.33.0

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 (230) hide show
  1. package/package.json +6 -1
  2. package/skills/apc-context/SKILL.md +5 -2
  3. package/skills/apx/SKILL.md +3 -3
  4. package/skills/apx-agency-agents/SKILL.md +5 -5
  5. package/skills/apx-agent/SKILL.md +7 -7
  6. package/skills/apx-mcp/SKILL.md +6 -4
  7. package/skills/apx-mcp-builder/SKILL.md +4 -7
  8. package/skills/apx-project/SKILL.md +4 -5
  9. package/skills/apx-routine/SKILL.md +14 -12
  10. package/skills/apx-runtime/SKILL.md +5 -3
  11. package/skills/apx-sessions/SKILL.md +5 -5
  12. package/skills/apx-skill-builder/SKILL.md +10 -6
  13. package/skills/apx-task/SKILL.md +8 -8
  14. package/skills/apx-telegram/SKILL.md +23 -7
  15. package/skills/apx-voice/SKILL.md +8 -6
  16. package/src/core/{agent-system.js → agent/build-agent-system.js} +10 -12
  17. package/src/core/agent/index.js +0 -2
  18. package/src/core/{agent-memory.js → agent/memory.js} +2 -2
  19. package/src/core/agent/model-router.js +21 -43
  20. package/src/core/agent/prompt-builder.js +17 -63
  21. package/src/core/agent/prompts/action-discipline.md +24 -0
  22. package/src/core/agent/prompts/channels/code.md +8 -12
  23. package/src/core/agent/prompts/channels/desktop.md +6 -4
  24. package/src/core/agent/prompts/channels/routine.md +10 -1
  25. package/src/core/agent/prompts/channels/telegram.md +10 -1
  26. package/src/core/agent/prompts/channels/web_code.md +20 -0
  27. package/src/core/agent/prompts/modes/voice.md +2 -2
  28. package/src/core/agent/prompts/super-agent-base.md +2 -2
  29. package/src/core/agent/run-agent.js +37 -35
  30. package/src/core/agent/runtime-bridge.js +42 -0
  31. package/src/core/agent/self-memory.js +19 -9
  32. package/src/core/agent/skills/catalog.js +65 -0
  33. package/src/core/agent/skills/index.js +6 -0
  34. package/src/{host/daemon/skills-loader.js → core/agent/skills/loader.js} +3 -3
  35. package/src/core/agent/skills/rag.js +91 -0
  36. package/src/core/agent/skills/trigger.js +71 -0
  37. package/src/{host/daemon → core/agent}/super-agent.js +5 -5
  38. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/add-project.js +3 -4
  39. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/call-agent.js +2 -2
  40. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/call-mcp.js +1 -2
  41. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/call-runtime.js +10 -11
  42. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/create-task.js +1 -1
  43. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/discover-tools.js +1 -1
  44. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/edit-file.js +1 -2
  45. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/import-agent.js +4 -5
  46. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-agents.js +1 -1
  47. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-skills.js +7 -2
  48. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-tasks.js +1 -1
  49. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-vault-agents.js +1 -1
  50. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/load-skill.js +1 -1
  51. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/read-agent-memory.js +1 -1
  52. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/read-self-memory.js +1 -1
  53. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/remember.js +1 -1
  54. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/run-shell.js +1 -2
  55. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/search-messages.js +1 -1
  56. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/search-sessions.js +1 -1
  57. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/send-telegram.js +0 -2
  58. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/set-identity.js +1 -3
  59. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/set-permission-mode.js +1 -3
  60. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/tail-messages.js +1 -1
  61. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/transcribe-audio.js +1 -1
  62. package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/write-file.js +1 -2
  63. package/src/core/agent/tools/helpers.js +74 -0
  64. package/src/{host/daemon/super-agent-tools → core/agent/tools}/registry-bridge.js +3 -3
  65. package/src/{host/daemon/super-agent-tools/index.js → core/agent/tools/registry.js} +31 -32
  66. package/src/core/apc/agents-vault.js +37 -0
  67. package/src/core/{scaffold.js → apc/scaffold.js} +4 -5
  68. package/src/core/{config.js → config/index.js} +21 -27
  69. package/src/core/config/paths.js +32 -0
  70. package/src/core/constants/actors.js +8 -0
  71. package/src/core/constants/channels.js +19 -0
  72. package/src/core/constants/index.js +5 -0
  73. package/src/core/constants/permissions.js +17 -0
  74. package/src/core/constants/roles.js +9 -0
  75. package/src/core/engines/_streaming.js +63 -0
  76. package/src/core/engines/anthropic.js +11 -22
  77. package/src/core/engines/ollama.js +7 -16
  78. package/src/core/identity/index.js +8 -0
  79. package/src/core/{identity.js → identity/self.js} +5 -5
  80. package/src/core/{telegram-identity.js → identity/telegram.js} +1 -1
  81. package/src/core/logging.js +1 -1
  82. package/src/core/mascot.js +1 -1
  83. package/src/core/memory/active-threads.js +10 -10
  84. package/src/core/memory/broker.js +9 -9
  85. package/src/core/memory/compactor.js +2 -2
  86. package/src/core/memory/index.js +2 -2
  87. package/src/core/memory/indexer.js +1 -1
  88. package/src/core/{code-sessions-store.js → stores/code-sessions.js} +7 -8
  89. package/src/core/{messages-store.js → stores/messages.js} +6 -4
  90. package/src/core/stores/routine-memory.js +71 -0
  91. package/src/core/{routines-store.js → stores/routines.js} +1 -3
  92. package/src/core/stores/runtime-sessions.js +99 -0
  93. package/src/core/{tasks-store.js → stores/tasks.js} +3 -8
  94. package/src/core/update-check.js +1 -1
  95. package/src/core/util/ids.js +14 -0
  96. package/src/core/util/index.js +2 -0
  97. package/src/core/util/time.js +9 -0
  98. package/src/core/voice/tts.js +1 -1
  99. package/src/host/daemon/api/admin-config.js +4 -3
  100. package/src/host/daemon/api/admin.js +1 -1
  101. package/src/host/daemon/api/agents.js +4 -25
  102. package/src/host/daemon/api/artifacts.js +26 -1
  103. package/src/host/daemon/api/code.js +62 -17
  104. package/src/host/daemon/api/confirm.js +1 -1
  105. package/src/host/daemon/api/connections.js +2 -2
  106. package/src/host/daemon/api/conversations.js +2 -2
  107. package/src/host/daemon/api/deck.js +1 -1
  108. package/src/host/daemon/api/desktop.js +1 -1
  109. package/src/host/daemon/api/embeddings.js +4 -4
  110. package/src/host/daemon/api/engines.js +2 -2
  111. package/src/host/daemon/api/exec.js +20 -5
  112. package/src/host/daemon/api/identity.js +1 -1
  113. package/src/host/daemon/api/mcps.js +1 -1
  114. package/src/host/daemon/api/messages.js +1 -1
  115. package/src/host/daemon/api/runtimes.js +9 -8
  116. package/src/host/daemon/api/sessions-search.js +1 -1
  117. package/src/host/daemon/api/sessions.js +2 -2
  118. package/src/host/daemon/api/shared.js +5 -4
  119. package/src/host/daemon/api/skills.js +30 -0
  120. package/src/host/daemon/api/super-agent.js +29 -9
  121. package/src/host/daemon/api/tasks.js +2 -2
  122. package/src/host/daemon/api/telegram.js +1 -1
  123. package/src/host/daemon/api/tools.js +6 -6
  124. package/src/host/daemon/api/tts.js +2 -2
  125. package/src/host/daemon/api/voice.js +14 -12
  126. package/src/host/daemon/api.js +2 -0
  127. package/src/host/daemon/compact.js +1 -1
  128. package/src/host/daemon/db.js +4 -4
  129. package/src/host/daemon/desktop-ws.js +1 -1
  130. package/src/host/daemon/index.js +4 -4
  131. package/src/host/daemon/plugins/{desktop.js → desktop/index.js} +11 -6
  132. package/src/host/daemon/plugins/index.js +2 -2
  133. package/src/host/daemon/plugins/{telegram.js → telegram/index.js} +52 -193
  134. package/src/host/daemon/plugins/telegram/media.js +162 -0
  135. package/src/host/daemon/projects-helpers.js +54 -0
  136. package/src/host/daemon/routines.js +28 -12
  137. package/src/host/daemon/smoke.js +2 -2
  138. package/src/host/daemon/token-store.js +1 -1
  139. package/src/host/daemon/transcription.js +2 -2
  140. package/src/host/daemon/wakeup.js +2 -2
  141. package/src/interfaces/cli/commands/agent.js +3 -3
  142. package/src/interfaces/cli/commands/command.js +1 -1
  143. package/src/interfaces/cli/commands/config.js +3 -2
  144. package/src/interfaces/cli/commands/desktop.js +1 -1
  145. package/src/interfaces/cli/commands/exec.js +2 -1
  146. package/src/interfaces/cli/commands/identity.js +2 -2
  147. package/src/interfaces/cli/commands/init.js +1 -1
  148. package/src/interfaces/cli/commands/mcp.js +1 -1
  149. package/src/interfaces/cli/commands/memory.js +2 -2
  150. package/src/interfaces/cli/commands/model.js +16 -6
  151. package/src/interfaces/cli/commands/project.js +1 -1
  152. package/src/interfaces/cli/commands/routine.js +58 -0
  153. package/src/interfaces/cli/commands/search.js +1 -1
  154. package/src/interfaces/cli/commands/session.js +4 -4
  155. package/src/interfaces/cli/commands/setup.js +4 -3
  156. package/src/interfaces/cli/commands/skills.js +25 -4
  157. package/src/interfaces/cli/commands/status.js +1 -1
  158. package/src/interfaces/cli/commands/sys.js +11 -4
  159. package/src/interfaces/cli/commands/update.js +1 -1
  160. package/src/interfaces/cli/index.js +4 -4
  161. package/src/interfaces/cli/postinstall.js +2 -2
  162. package/src/interfaces/mcp-server/index.js +1 -1
  163. package/src/interfaces/tui/component/prompt/index.tsx +3 -1
  164. package/src/interfaces/tui/context/sdk-apx.tsx +47 -7
  165. package/src/interfaces/tui/context/sync-apx.tsx +20 -2
  166. package/src/interfaces/tui/context/sync.tsx +2 -1
  167. package/src/interfaces/tui/routes/session/index.tsx +151 -136
  168. package/src/interfaces/tui/routes/session/sidebar-apx.tsx +37 -15
  169. package/src/interfaces/tui/run.ts +2 -0
  170. package/src/interfaces/web/dist/assets/index-7dVT2O1S.css +1 -0
  171. package/src/interfaces/web/dist/assets/index-DWsE_8Nz.js +602 -0
  172. package/src/interfaces/web/dist/assets/index-DWsE_8Nz.js.map +1 -0
  173. package/src/interfaces/web/dist/index.html +2 -2
  174. package/src/interfaces/web/package-lock.json +6 -6
  175. package/src/interfaces/web/src/App.tsx +53 -32
  176. package/src/interfaces/web/src/components/RobyBubble.tsx +12 -6
  177. package/src/interfaces/web/src/components/UiSelect.tsx +13 -3
  178. package/src/interfaces/web/src/components/chat/SkillPicker.tsx +77 -0
  179. package/src/interfaces/web/src/components/code/CodeArtifactsTab.tsx +253 -111
  180. package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +10 -8
  181. package/src/interfaces/web/src/components/code/CodeComposer.tsx +20 -17
  182. package/src/interfaces/web/src/components/code/CodeContextTab.tsx +43 -18
  183. package/src/interfaces/web/src/components/code/CodeFileTree.tsx +212 -0
  184. package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +121 -0
  185. package/src/interfaces/web/src/components/code/CodeProjectPicker.tsx +1 -1
  186. package/src/interfaces/web/src/components/code/CodeSessionList.tsx +30 -26
  187. package/src/interfaces/web/src/components/code/CodeSidePanel.tsx +40 -21
  188. package/src/interfaces/web/src/components/code/CodeTerminal.tsx +140 -0
  189. package/src/interfaces/web/src/components/common/TabLayout.tsx +11 -7
  190. package/src/interfaces/web/src/components/common/TabNav.tsx +3 -3
  191. package/src/interfaces/web/src/components/layout/ProjectSidebar.tsx +4 -2
  192. package/src/interfaces/web/src/components/ui/chat-input.tsx +17 -6
  193. package/src/interfaces/web/src/hooks/useChat.ts +48 -2
  194. package/src/interfaces/web/src/hooks/useNavCollapseCtx.tsx +83 -0
  195. package/src/interfaces/web/src/hooks/usePersonaName.ts +11 -0
  196. package/src/interfaces/web/src/i18n/en.ts +7 -7
  197. package/src/interfaces/web/src/i18n/es.ts +8 -8
  198. package/src/interfaces/web/src/lib/api/agents.ts +1 -1
  199. package/src/interfaces/web/src/lib/api/artifacts.ts +10 -0
  200. package/src/interfaces/web/src/lib/api/code.ts +4 -2
  201. package/src/interfaces/web/src/lib/api/skills.ts +25 -0
  202. package/src/interfaces/web/src/lib/api.ts +1 -0
  203. package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +430 -86
  204. package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +5 -18
  205. package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +1 -8
  206. package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +39 -40
  207. package/src/interfaces/web/src/screens/project/ChatTab.tsx +16 -16
  208. package/src/skills/apc-context/SKILL.md +159 -0
  209. package/src/core/agent/ghost-guard.js +0 -24
  210. package/src/core/agent/prompts/channels/terminal.md +0 -16
  211. package/src/host/daemon/apc-runtime-context.js +0 -124
  212. package/src/host/daemon/super-agent-tools/helpers.js +0 -124
  213. package/src/host/daemon/tool-call-parser.js +0 -2
  214. package/src/interfaces/web/dist/assets/index-63P_ji1a.js +0 -571
  215. package/src/interfaces/web/dist/assets/index-63P_ji1a.js.map +0 -1
  216. package/src/interfaces/web/dist/assets/index-DLWy6dYz.css +0 -1
  217. /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/ask-questions.js +0 -0
  218. /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-files.js +0 -0
  219. /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-mcps.js +0 -0
  220. /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/list-projects.js +0 -0
  221. /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/read-file.js +0 -0
  222. /package/src/{host/daemon/super-agent-tools/tools → core/agent/tools/handlers}/search-files.js +0 -0
  223. /package/src/core/agent/{pseudo-tools.js → tools/pseudo-tools.js} +0 -0
  224. /package/src/core/agent/{tool-call-parser.js → tools/tool-call-parser.js} +0 -0
  225. /package/src/core/{parser.js → apc/parser.js} +0 -0
  226. /package/src/core/{apc-skill-sync.js → apc/skill-sync.js} +0 -0
  227. /package/src/core/{artifacts-store.js → stores/artifacts.js} +0 -0
  228. /package/src/{host/daemon → core/stores}/engine-sessions.js +0 -0
  229. /package/src/core/{session-store.js → stores/sessions.js} +0 -0
  230. /package/src/host/daemon/plugins/{telegram-ask.js → telegram/ask.js} +0 -0
@@ -18,8 +18,8 @@
18
18
  <link rel="apple-touch-icon" href="/favicon/dark/apple-touch-icon.png" media="(prefers-color-scheme: dark)" />
19
19
  <link rel="manifest" href="/favicon/white/site.webmanifest" media="(prefers-color-scheme: light)" />
20
20
  <link rel="manifest" href="/favicon/dark/site.webmanifest" media="(prefers-color-scheme: dark)" />
21
- <script type="module" crossorigin src="/assets/index-63P_ji1a.js"></script>
22
- <link rel="stylesheet" crossorigin href="/assets/index-DLWy6dYz.css">
21
+ <script type="module" crossorigin src="/assets/index-DWsE_8Nz.js"></script>
22
+ <link rel="stylesheet" crossorigin href="/assets/index-7dVT2O1S.css">
23
23
  </head>
24
24
  <body class="bg-background text-foreground antialiased">
25
25
  <div id="root"></div>
@@ -2077,9 +2077,9 @@
2077
2077
  "license": "MIT"
2078
2078
  },
2079
2079
  "node_modules/@types/node": {
2080
- "version": "25.9.2",
2081
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz",
2082
- "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==",
2080
+ "version": "25.9.3",
2081
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz",
2082
+ "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==",
2083
2083
  "devOptional": true,
2084
2084
  "license": "MIT",
2085
2085
  "dependencies": {
@@ -2236,9 +2236,9 @@
2236
2236
  }
2237
2237
  },
2238
2238
  "node_modules/caniuse-lite": {
2239
- "version": "1.0.30001797",
2240
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz",
2241
- "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==",
2239
+ "version": "1.0.30001799",
2240
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
2241
+ "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==",
2242
2242
  "dev": true,
2243
2243
  "funding": [
2244
2244
  {
@@ -17,6 +17,8 @@ import { TooltipProvider } from "./components/ui/tooltip";
17
17
  import { useTheme } from "./hooks/useTheme";
18
18
  import { useProjects } from "./hooks/useProjects";
19
19
  import { useTokenBootstrap } from "./hooks/useTokenBootstrap";
20
+ import { NavCollapseProvider, useNavCollapseCtx, usePageActions, usePageLabel } from "./hooks/useNavCollapseCtx";
21
+ import { NavToggle } from "./components/common/TabNav";
20
22
  import { t } from "./i18n";
21
23
 
22
24
  export function App() {
@@ -61,28 +63,30 @@ function Shell() {
61
63
  };
62
64
 
63
65
  return (
64
- <div className="flex h-screen w-screen overflow-hidden bg-background text-foreground" data-testid="app-shell">
65
- <ProjectSidebar onSelect={(href) => navigate(href)} onOpenRoby={() => setRobyOpen(true)} />
66
- <main className="m-2 ml-0 flex min-w-0 flex-1 flex-col overflow-hidden rounded-xl border border-border bg-card shadow-sm">
67
- <TopBar onToggleTheme={toggle} isDark={theme === "dark"} pathname={location.pathname} />
68
- <div className="flex-1 overflow-y-auto">
69
- <Routes>
70
- <Route path="/" element={<ApxAdminScreen />} />
71
- <Route path="/settings/*" element={<SettingsScreen />} />
72
- <Route path="/m/voice/*" element={<VoiceScreen />} />
73
- <Route path="/m/desktop/*" element={<DesktopScreen />} />
74
- <Route path="/m/deck/*" element={<DeckScreen />} />
75
- <Route path="/m/code/*" element={<CodeScreen />} />
76
- <Route path="/p/:pid/*" element={<ProjectScreen />} />
77
- <Route path="*" element={<NotFound />} />
78
- </Routes>
79
- </div>
80
- </main>
81
- <AddProjectDialog open={addOpen} onClose={closeAdd} />
82
- {/* Roby (the super-agent) chat sheet. Launcher lives in the rail (below
83
- Settings); open state is owned here so the rail can trigger it. */}
84
- <RobyBubble open={robyOpen} onOpenChange={setRobyOpen} />
85
- </div>
66
+ <NavCollapseProvider>
67
+ <div className="flex h-screen w-screen overflow-hidden bg-background text-foreground" data-testid="app-shell">
68
+ <ProjectSidebar onSelect={(href) => navigate(href)} onOpenRoby={() => setRobyOpen(true)} />
69
+ <main className="m-2 ml-0 flex min-w-0 flex-1 flex-col overflow-hidden rounded-xl border border-border bg-card shadow-sm">
70
+ <TopBar onToggleTheme={toggle} isDark={theme === "dark"} pathname={location.pathname} />
71
+ <div className="flex-1 overflow-y-auto">
72
+ <Routes>
73
+ <Route path="/" element={<ApxAdminScreen />} />
74
+ <Route path="/settings/*" element={<SettingsScreen />} />
75
+ <Route path="/m/voice/*" element={<VoiceScreen />} />
76
+ <Route path="/m/desktop/*" element={<DesktopScreen />} />
77
+ <Route path="/m/deck/*" element={<DeckScreen />} />
78
+ <Route path="/m/code/*" element={<CodeScreen />} />
79
+ <Route path="/p/:pid/*" element={<ProjectScreen />} />
80
+ <Route path="*" element={<NotFound />} />
81
+ </Routes>
82
+ </div>
83
+ </main>
84
+ <AddProjectDialog open={addOpen} onClose={closeAdd} />
85
+ {/* Roby (the super-agent) chat sheet. Launcher lives in the rail (below
86
+ Settings); open state is owned here so the rail can trigger it. */}
87
+ <RobyBubble open={robyOpen} onOpenChange={setRobyOpen} />
88
+ </div>
89
+ </NavCollapseProvider>
86
90
  );
87
91
  }
88
92
 
@@ -96,6 +100,7 @@ function TopBar({
96
100
  pathname: string;
97
101
  }) {
98
102
  const { projects } = useProjects();
103
+ const pageLabel = usePageLabel();
99
104
  const parts = pathname.split("/").filter(Boolean);
100
105
  const project = parts[0] === "p" ? projects.find((p) => String(p.id) === parts[1]) : undefined;
101
106
  const section = parts[0] === "settings"
@@ -109,11 +114,13 @@ function TopBar({
109
114
  ? t("topbar.breadcrumb_root")
110
115
  : parts[0] === "settings"
111
116
  ? [t("topbar.breadcrumb_root"), t("nav.settings"), section].filter(Boolean).join(" › ")
112
- : parts[0] === "p"
113
- ? (isDefault
114
- ? [t("topbar.breadcrumb_root"), t("topbar.breadcrumb_base"), section].filter(Boolean).join(" ")
115
- : [t("topbar.breadcrumb_root"), t("topbar.breadcrumb_projects"), projName, section].filter(Boolean).join(" › "))
116
- : t("topbar.breadcrumb_root");
117
+ : parts[0] === "m"
118
+ ? [t("topbar.breadcrumb_root"), moduleLabel(parts[1]), pageLabel].filter(Boolean).join(" › ")
119
+ : parts[0] === "p"
120
+ ? (isDefault
121
+ ? [t("topbar.breadcrumb_root"), t("topbar.breadcrumb_base"), section].filter(Boolean).join(" › ")
122
+ : [t("topbar.breadcrumb_root"), t("topbar.breadcrumb_projects"), projName, section].filter(Boolean).join(" › "))
123
+ : t("topbar.breadcrumb_root");
117
124
  const subtitle = pathname === "/"
118
125
  ? ""
119
126
  : parts[0] === "settings"
@@ -123,24 +130,38 @@ function TopBar({
123
130
  ? t("base.subtitle")
124
131
  : project ? `${projectKindLabel(project.kind)} · ${project.path}` : "")
125
132
  : "";
133
+ const nav = useNavCollapseCtx();
134
+ const pageActions = usePageActions();
126
135
  return (
127
- <header className="flex h-11 shrink-0 items-center justify-between gap-4 px-4">
128
- <span className="min-w-0 truncate text-xs tracking-wide text-muted-fg">
136
+ <header className="flex h-10 shrink-0 items-center gap-2 border-b border-border/50 px-3">
137
+ {nav && <NavToggle collapsed={nav.collapsed} onToggle={nav.toggle} />}
138
+ <span className="min-w-0 flex-1 truncate text-[11px] tracking-wide text-muted-fg">
129
139
  {crumb}
130
- {subtitle && <span className="text-muted-fg/60"> · {subtitle}</span>}
140
+ {subtitle && <span className="text-muted-fg/50"> · {subtitle}</span>}
131
141
  </span>
142
+ {pageActions}
132
143
  <button
133
144
  type="button"
134
145
  onClick={onToggleTheme}
135
146
  title={isDark ? t("topbar.light") : t("topbar.dark")}
136
- className="rounded-md p-1.5 text-muted-fg hover:bg-accent hover:text-accent-fg"
147
+ className="shrink-0 rounded-md p-1.5 text-muted-fg hover:bg-accent hover:text-accent-fg"
137
148
  >
138
- {isDark ? <Sun size={16} /> : <Moon size={16} />}
149
+ {isDark ? <Sun size={14} /> : <Moon size={14} />}
139
150
  </button>
140
151
  </header>
141
152
  );
142
153
  }
143
154
 
155
+ function moduleLabel(key?: string) {
156
+ switch (key) {
157
+ case "voice": return t("nav.modules.voice");
158
+ case "desktop": return t("nav.modules.desktop");
159
+ case "deck": return t("nav.modules.deck");
160
+ case "code": return t("nav.modules.code");
161
+ default: return key || "";
162
+ }
163
+ }
164
+
144
165
  function settingsLabel(key?: string) {
145
166
  switch (key) {
146
167
  case "super-agent": return t("settings.tabs.super_agent");
@@ -15,6 +15,7 @@ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "
15
15
  import { Button } from "./ui/button";
16
16
  import { ChatInput } from "./ui/chat-input";
17
17
  import { ModelPicker } from "./chat/ModelPicker";
18
+ import { SkillPicker } from "./chat/SkillPicker";
18
19
  import { MessageList } from "./chat/MessageList";
19
20
  import { ContextBar } from "./chat/ContextBar";
20
21
  import { applyStreamEvent, textOf, type ChatMsg } from "../hooks/useChat";
@@ -22,6 +23,7 @@ import { SuperAgent } from "../lib/api";
22
23
  import { STORAGE } from "../constants";
23
24
  import { useToast } from "./Toast";
24
25
  import { t } from "../i18n";
26
+ import { usePersonaName } from "../hooks/usePersonaName";
25
27
  import type { ChatStreamEvent, ConversationMessage } from "../types/daemon";
26
28
 
27
29
  // Load any persisted conversation, dropping half-finished (pending) turns.
@@ -44,6 +46,7 @@ export function RobyBubble({
44
46
  open: boolean;
45
47
  onOpenChange: (open: boolean) => void;
46
48
  }) {
49
+ const persona = usePersonaName();
47
50
  const toast = useToast();
48
51
  const [msgs, setMsgs] = useState<ChatMsg[]>(loadStored);
49
52
  const [draft, setDraft] = useState("");
@@ -170,15 +173,15 @@ export function RobyBubble({
170
173
  >
171
174
  <SheetHeader className="pr-12">
172
175
  <SheetTitle className="flex items-center gap-2">
173
- <Bot size={18} /> {t("roby.title")}
174
- <span className="text-xs font-normal text-muted-fg">{t("roby.badge")}</span>
176
+ <Bot size={18} /> {t("superagent.title", { persona })}
177
+ <span className="text-xs font-normal text-muted-fg">{t("superagent.badge")}</span>
175
178
  </SheetTitle>
176
- <SheetDescription>{t("roby.desc")}</SheetDescription>
179
+ <SheetDescription>{t("superagent.desc")}</SheetDescription>
177
180
  </SheetHeader>
178
181
 
179
182
  <div className="flex-1 overflow-y-auto">
180
183
  {msgs.length === 0 ? (
181
- <p className="mt-6 text-center text-sm text-muted-fg">{t("roby.empty")}</p>
184
+ <p className="mt-6 text-center text-sm text-muted-fg">{t("superagent.empty", { persona })}</p>
182
185
  ) : (
183
186
  <MessageList msgs={msgs} onCopy={copyToClipboard} />
184
187
  )}
@@ -187,13 +190,16 @@ export function RobyBubble({
187
190
  <ContextBar msgs={msgs} />
188
191
 
189
192
  <div className="border-t border-border p-3">
193
+ <div className="mb-1.5">
194
+ <SkillPicker value={draft} onPick={(slug) => setDraft(`/${slug} `)} />
195
+ </div>
190
196
  <ChatInput
191
197
  value={draft}
192
198
  onValueChange={setDraft}
193
199
  onSubmit={() => void send()}
194
200
  onStop={stop}
195
201
  busy={busy}
196
- placeholder={t("roby.placeholder")}
202
+ placeholder={t("superagent.placeholder")}
197
203
  footer={<ModelPicker value={model} onChange={setModel} disabled={busy} />}
198
204
  />
199
205
  <div className="mt-1.5 flex justify-end">
@@ -203,7 +209,7 @@ export function RobyBubble({
203
209
  onClick={newChat}
204
210
  disabled={busy || msgs.length === 0}
205
211
  >
206
- <Plus className="size-3" /> {t("roby.new_chat")}
212
+ <Plus className="size-3" /> {t("superagent.new_chat")}
207
213
  </Button>
208
214
  </div>
209
215
  </div>
@@ -25,6 +25,7 @@ export function UiSelect({
25
25
  placeholder = "— elegir —",
26
26
  disabled,
27
27
  className,
28
+ showIcon = false,
28
29
  }: {
29
30
  value: string;
30
31
  onChange: (value: string) => void;
@@ -32,13 +33,22 @@ export function UiSelect({
32
33
  placeholder?: string;
33
34
  disabled?: boolean;
34
35
  className?: string;
36
+ showIcon?: boolean;
35
37
  }) {
36
38
  return (
37
39
  <Select value={value} onValueChange={(v) => onChange((v as string) ?? "")} disabled={disabled}>
38
40
  <SelectTrigger className={cn("h-9 w-full", className)}>
39
- {/* Show the option's label in the trigger, not the raw value key. */}
40
41
  <SelectValue placeholder={placeholder}>
41
- {(val) => options.find((o) => o.value === val)?.label ?? (val as string)}
42
+ {(val) => {
43
+ const opt = options.find((o) => o.value === val);
44
+ const Icon = showIcon ? opt?.icon : undefined;
45
+ return (
46
+ <span className="flex min-w-0 items-center gap-1.5">
47
+ {Icon && <Icon className="size-3.5 shrink-0" />}
48
+ <span className="truncate">{opt?.label ?? (val as string)}</span>
49
+ </span>
50
+ );
51
+ }}
42
52
  </SelectValue>
43
53
  </SelectTrigger>
44
54
  {/* side=bottom + alignItemWithTrigger=false → dropdown sits BELOW the
@@ -48,7 +58,7 @@ export function UiSelect({
48
58
  sideOffset={6}
49
59
  align="start"
50
60
  alignItemWithTrigger={false}
51
- className="max-w-[min(20rem,var(--available-width))] p-1.5"
61
+ className="w-[var(--anchor-width)] p-1.5"
52
62
  >
53
63
  {options.map((o) => {
54
64
  const Icon = o.icon;
@@ -0,0 +1,77 @@
1
+ import * as React from "react";
2
+ import useSWR from "swr";
3
+ import { Skills, type SkillEntry } from "../../lib/api";
4
+
5
+ interface SkillPickerProps {
6
+ /**
7
+ * Current input value. The picker matches against the leading slug after
8
+ * the first "/". When the input does not start with "/" the picker hides
9
+ * itself entirely.
10
+ */
11
+ value: string;
12
+ /** Optional project path so project-scoped skills appear in the catalog. */
13
+ projectPath?: string;
14
+ /** Called with the chosen slug. Caller decides what to do (typically append `<slug> ` and refocus). */
15
+ onPick: (slug: string) => void;
16
+ }
17
+
18
+ /**
19
+ * Drop-up suggester for `/slug ...` shortcuts on the chat composer. Renders
20
+ * a small list of matching skills above the input when the user starts a
21
+ * message with "/". Keyboard navigation (↑/↓/Enter/Esc) is handled by the
22
+ * parent through `useSkillPickerKeyboard` (so the composer keeps owning the
23
+ * focused textarea).
24
+ */
25
+ export function SkillPicker({ value, projectPath, onPick }: SkillPickerProps) {
26
+ const open = isSkillPickerOpen(value);
27
+ const query = open ? extractQuery(value) : "";
28
+
29
+ const { data } = useSWR(
30
+ open ? ["/skills", projectPath || ""] : null,
31
+ () => Skills.list(projectPath),
32
+ );
33
+
34
+ const list: SkillEntry[] = data?.skills || [];
35
+ const filtered = React.useMemo(() => {
36
+ const q = query.toLowerCase();
37
+ if (!q) return list.slice(0, 8);
38
+ return list
39
+ .filter((s) => s.slug.toLowerCase().includes(q))
40
+ .slice(0, 8);
41
+ }, [list, query]);
42
+
43
+ if (!open || filtered.length === 0) return null;
44
+
45
+ return (
46
+ <div className="rounded-xl border border-border bg-popover/95 text-sm shadow-md backdrop-blur">
47
+ <ul role="listbox" className="max-h-64 overflow-y-auto py-1">
48
+ {filtered.map((s) => (
49
+ <li key={s.slug}>
50
+ <button
51
+ type="button"
52
+ onClick={() => onPick(s.slug)}
53
+ className="flex w-full items-start gap-2 px-3 py-1.5 text-left hover:bg-accent hover:text-accent-foreground"
54
+ >
55
+ <code className="rounded bg-muted px-1.5 py-0.5 text-[11px]">/{s.slug}</code>
56
+ <span className="truncate text-xs text-muted-foreground">{s.description}</span>
57
+ </button>
58
+ </li>
59
+ ))}
60
+ </ul>
61
+ <div className="border-t border-border px-3 py-1.5 text-[10px] text-muted-foreground">
62
+ Type a name to filter · click to insert · the skill body will be loaded for this turn.
63
+ </div>
64
+ </div>
65
+ );
66
+ }
67
+
68
+ /** Trigger detection: the picker shows when the input starts with "/" + an identifier (no space yet). */
69
+ export function isSkillPickerOpen(value: string): boolean {
70
+ const m = value.match(/^\s*\/([A-Za-z0-9_-]*)$/);
71
+ return Boolean(m);
72
+ }
73
+
74
+ function extractQuery(value: string): string {
75
+ const m = value.match(/^\s*\/([A-Za-z0-9_-]*)$/);
76
+ return m ? m[1] : "";
77
+ }