@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
@@ -12,9 +12,10 @@
12
12
  // stateful: the turn handler rebuilds `previousMessages` from the stored
13
13
  // transcript, runs the super-agent on the `code` channel (with plan/build mode
14
14
  // + per-mode tool gating), then persists the rich assistant turn.
15
- import { runSuperAgent } from "../super-agent.js";
15
+ import { runSuperAgent } from "#core/agent/super-agent.js";
16
16
  import { appendSuperAgentErrorTrace } from "./shared.js";
17
- import { createWebConfirmAdapter } from "../../../core/confirmation/adapters/web.js";
17
+ import { createWebConfirmAdapter } from "#core/confirmation/adapters/web.js";
18
+ import { CHANNELS } from "#core/constants/channels.js";
18
19
  import {
19
20
  listCodeSessions,
20
21
  getCodeSession,
@@ -22,9 +23,10 @@ import {
22
23
  updateCodeSession,
23
24
  removeCodeSession,
24
25
  appendTurn,
25
- } from "../../../core/code-sessions-store.js";
26
- import { captureBaseline, diffAgainstBaseline, initGitRepo } from "../../../core/git-baseline.js";
27
- import { loggerFor } from "../../../core/logging.js";
26
+ } from "#core/stores/code-sessions.js";
27
+ import { captureBaseline, diffAgainstBaseline, initGitRepo } from "#core/git-baseline.js";
28
+ import { loggerFor } from "#core/logging.js";
29
+ import { readAgents } from "#core/apc/parser.js";
28
30
 
29
31
  const log = loggerFor("code");
30
32
 
@@ -80,20 +82,51 @@ function modeGuidanceFor(mode) {
80
82
  "for choices. Prefer 2–4 mutually-exclusive options when a question has a",
81
83
  "natural shortlist (yes/no, which-of-these, …); leave options empty for",
82
84
  "open-ended answers (API keys, names, free-form ideas).",
85
+ "If the previous assistant turn already asked these same questions and the",
86
+ "current user message is the compiled answers, DO NOT call ask_questions",
87
+ "again — process the answers and proceed with the task.",
83
88
  ].join(" ");
84
89
  }
85
90
 
86
91
  // Build the [{role, content}] history the super-agent expects from the stored
87
- // rich transcript: flatten each turn's text parts (tool parts are internal).
92
+ // rich transcript: flatten each turn's text parts. Tool parts are normally
93
+ // internal, but ask_questions is special — without surfacing it the model
94
+ // loses track that it ALREADY asked, sees the user's compiled-answer reply
95
+ // as a fresh request, and asks again forever. We render a one-line synthetic
96
+ // summary of each ask_questions call so the next turn's context shows
97
+ // "I asked X, the user replied Y" naturally.
98
+ function summarizeAskQuestionsPart(part) {
99
+ const raw = part?.args?.questions;
100
+ if (!Array.isArray(raw) || raw.length === 0) return null;
101
+ const lines = raw
102
+ .map((q) => {
103
+ if (typeof q === "string") return `- ${q}`;
104
+ if (!q || typeof q !== "object" || typeof q.question !== "string") return null;
105
+ const opts = Array.isArray(q.options) ? q.options : [];
106
+ const optStr = opts
107
+ .map((o) => (typeof o === "string" ? o : (o && typeof o.label === "string" ? o.label : "")))
108
+ .filter(Boolean)
109
+ .join(", ");
110
+ return optStr ? `- ${q.question} (opciones: ${optStr})` : `- ${q.question}`;
111
+ })
112
+ .filter(Boolean);
113
+ if (lines.length === 0) return null;
114
+ return `[ask_questions]\n${lines.join("\n")}`;
115
+ }
116
+
88
117
  function historyFrom(session) {
89
- return (session.messages || []).map((m) => ({
90
- role: m.role,
91
- content: (m.parts || [])
92
- .filter((p) => p && p.kind === "text" && p.text)
93
- .map((p) => p.text)
94
- .join("\n\n")
95
- .trim(),
96
- }));
118
+ return (session.messages || []).map((m) => {
119
+ const chunks = [];
120
+ for (const p of m.parts || []) {
121
+ if (!p) continue;
122
+ if (p.kind === "text" && p.text) chunks.push(p.text);
123
+ else if (p.kind === "tool" && p.tool === "ask_questions") {
124
+ const summary = summarizeAskQuestionsPart(p);
125
+ if (summary) chunks.push(summary);
126
+ }
127
+ }
128
+ return { role: m.role, content: chunks.join("\n\n").trim() };
129
+ });
97
130
  }
98
131
 
99
132
  // Accumulate stream events into the rich ChatPart shape so the persisted
@@ -180,7 +213,7 @@ export function register(app, { projects, project, config, registries, plugins }
180
213
  app.post("/projects/:pid/code/sessions", (req, res) => {
181
214
  const p = findProject(req, res);
182
215
  if (!p) return;
183
- const { title, model, mode } = req.body || {};
216
+ const { title, model, mode, agentSlug } = req.body || {};
184
217
  let git = captureBaseline(p.path);
185
218
  // No baseline because the project isn't a git repo yet. For real projects
186
219
  // (not the default apx home, id 0) init one so the "changes" diff works —
@@ -198,6 +231,7 @@ export function register(app, { projects, project, config, registries, plugins }
198
231
  title,
199
232
  model,
200
233
  mode,
234
+ agentSlug: agentSlug || null,
201
235
  git,
202
236
  });
203
237
  res.status(201).json(session);
@@ -259,6 +293,15 @@ export function register(app, { projects, project, config, registries, plugins }
259
293
  const mode = session.mode === "plan" ? "plan" : "build";
260
294
  const previousMessages = historyFrom(session);
261
295
 
296
+ // If a project agent is selected, inject its system prompt as a suffix so
297
+ // the super-agent's tool loop runs with the agent's personality/context.
298
+ let agentSystemSuffix = "";
299
+ if (session.agentSlug) {
300
+ const agents = readAgents(p.path);
301
+ const agent = agents.find((a) => a.slug === session.agentSlug);
302
+ if (agent?.body) agentSystemSuffix = `\n\n## Agente seleccionado: ${session.agentSlug}\n${agent.body}`;
303
+ }
304
+
262
305
  // Persist the user turn immediately so a crash mid-stream still records it.
263
306
  appendTurn(p.storagePath, session.id, {
264
307
  role: "user",
@@ -285,15 +328,17 @@ export function register(app, { projects, project, config, registries, plugins }
285
328
  plugins,
286
329
  registries,
287
330
  prompt,
288
- channel: "code",
331
+ channel: CHANNELS.WEB_CODE,
289
332
  channelMeta: {
290
333
  projectId: String(p.id),
291
334
  projectName: p.name,
292
335
  projectPath: p.path,
293
336
  mode,
294
337
  modeGuidance: modeGuidanceFor(mode),
338
+ agentSlug: session.agentSlug || null,
295
339
  },
296
340
  previousMessages,
341
+ systemSuffix: agentSystemSuffix,
297
342
  overrideModel: session.model || undefined,
298
343
  allowedTools: mode === "plan" ? PLAN_TOOLS : "*",
299
344
  // Coding tasks are multi-step: give the loop a high safety ceiling so it
@@ -349,7 +394,7 @@ export function register(app, { projects, project, config, registries, plugins }
349
394
  });
350
395
  appendSuperAgentErrorTrace(req, e, {
351
396
  prompt,
352
- channel: "code",
397
+ channel: CHANNELS.WEB_CODE,
353
398
  previousMessages,
354
399
  model: session.model,
355
400
  stream: true,
@@ -8,7 +8,7 @@
8
8
  // Promise in the agent loop, unblocking it to continue with confirmed: true
9
9
  // or to return a cancelled error.
10
10
 
11
- import { getConfirmationStore } from "../../../core/confirmation/pending-store.js";
11
+ import { getConfirmationStore } from "#core/confirmation/pending-store.js";
12
12
 
13
13
  export function register(app) {
14
14
  app.post("/super-agent/confirm/:correlationId", async (req, res) => {
@@ -1,7 +1,7 @@
1
1
  // GET /projects/:pid/agents/:slug/connections
2
2
  // Builds a per-peer summary of an agent's a2a traffic from the messages store.
3
- import { readAgents } from "../../../core/parser.js";
4
- import { readProjectMessages } from "../../../core/messages-store.js";
3
+ import { readAgents } from "#core/apc/parser.js";
4
+ import { readProjectMessages } from "#core/stores/messages.js";
5
5
 
6
6
  export function register(app, { project }) {
7
7
  app.get("/projects/:pid/agents/:slug/connections", (req, res) => {
@@ -6,8 +6,8 @@
6
6
  // POST /projects/:pid/send (agent-to-agent)
7
7
  import fs from "node:fs";
8
8
  import path from "node:path";
9
- import { readAgents } from "../../../core/parser.js";
10
- import { callEngine } from "../../../core/engines/index.js";
9
+ import { readAgents } from "#core/apc/parser.js";
10
+ import { callEngine } from "#core/engines/index.js";
11
11
  import { listConversations, readConversation } from "../conversations.js";
12
12
  import { compactConversation } from "../compact.js";
13
13
  import { nowIso } from "./shared.js";
@@ -226,7 +226,7 @@ export function register(app, ctx) {
226
226
  // the override we're about to set; we mutate ONLY the override and
227
227
  // leave everything else intact.
228
228
  try {
229
- const { readConfig, writeConfig } = await import("../../../core/config.js");
229
+ const { readConfig, writeConfig } = await import("#core/config/index.js");
230
230
  const fresh = readConfig();
231
231
  fresh.deck = fresh.deck && typeof fresh.deck === "object" ? fresh.deck : {};
232
232
  fresh.deck.widget_overrides =
@@ -15,7 +15,7 @@ import {
15
15
  autostartIsOn,
16
16
  autostartInstall,
17
17
  autostartUninstall,
18
- } from "../../../core/desktop/autostart.js";
18
+ } from "#core/desktop/autostart.js";
19
19
 
20
20
  export function register(app, { plugins }) {
21
21
  app.get("/desktop/status", (_req, res) => {
@@ -8,15 +8,15 @@
8
8
  // POST /embeddings/reindex → { ok, cleared, indexed } (rebuild the vector
9
9
  // store under the current embedder — needed
10
10
  // after switching provider/model)
11
- import { readConfig } from "../../../core/config.js";
11
+ import { readConfig } from "#core/config/index.js";
12
12
  import {
13
13
  listAvailableEmbedEngines,
14
14
  embeddingsConfig,
15
15
  resolveMode,
16
16
  resolveChainOrder,
17
- } from "../../../core/memory/embed-engines/index.js";
18
- import { embedOne } from "../../../core/memory/embeddings.js";
19
- import { reindexMemory } from "../../../core/memory/index.js";
17
+ } from "#core/memory/embed-engines/index.js";
18
+ import { embedOne } from "#core/memory/embeddings.js";
19
+ import { reindexMemory } from "#core/memory/index.js";
20
20
 
21
21
  export function register(app) {
22
22
  app.get("/embeddings/providers", async (_req, res) => {
@@ -1,8 +1,8 @@
1
1
  // GET /engines — list engine adapter ids known to core/engines.
2
2
  // POST /engines/models — live model catalog from a provider.
3
3
  // GET /engines/models — legacy (Ollama only, no auth).
4
- import { ENGINE_IDS } from "../../../core/engines/index.js";
5
- import { fetchJsonWithTimeout } from "../../../core/engines/_health.js";
4
+ import { ENGINE_IDS } from "#core/engines/index.js";
5
+ import { fetchJsonWithTimeout } from "#core/engines/_health.js";
6
6
 
7
7
  const DEFAULT_BASE = {
8
8
  openai: "https://api.openai.com/v1",
@@ -4,9 +4,10 @@
4
4
  //
5
5
  // POST /projects/:pid/agents/:slug/exec one-shot, no history
6
6
  // POST /projects/:pid/agents/:slug/chat append to (or start) a conversation
7
- import { callEngine } from "../../../core/engines/index.js";
8
- import { readAgents } from "../../../core/parser.js";
9
- import { buildAgentSystem } from "../../../core/agent-system.js";
7
+ import { callEngine } from "#core/engines/index.js";
8
+ import { readAgents } from "#core/apc/parser.js";
9
+ import { buildAgentSystem } from "#core/agent/build-agent-system.js";
10
+ import { resolveActiveModel } from "#core/agent/model-router.js";
10
11
  import {
11
12
  startConversation,
12
13
  appendTurn,
@@ -14,6 +15,20 @@ import {
14
15
  setStatus,
15
16
  } from "../conversations.js";
16
17
 
18
+ // Pick a model for a direct agent chat: explicit override → agent's own model →
19
+ // super-agent default (resolved via the same router the super-agent uses, so
20
+ // it walks the fallback chain when the primary is empty/unhealthy).
21
+ async function pickAgentModel({ modelOverride, agent, config }) {
22
+ if (modelOverride) return modelOverride;
23
+ if (agent.fields?.Model) return agent.fields.Model;
24
+ try {
25
+ const routing = await resolveActiveModel(config);
26
+ return routing?.modelId || null;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+
17
32
  export function register(app, { projects, project, config }) {
18
33
  app.post("/projects/:pid/agents/:slug/exec", async (req, res) => {
19
34
  const p = project(req, res);
@@ -28,7 +43,7 @@ export function register(app, { projects, project, config }) {
28
43
  const agents = readAgents(p.path);
29
44
  const agent = agents.find((a) => a.slug === req.params.slug);
30
45
  if (!agent) return res.status(404).json({ error: "agent not found" });
31
- const modelId = modelOverride || agent.fields.Model;
46
+ const modelId = await pickAgentModel({ modelOverride, agent, config });
32
47
  if (!modelId)
33
48
  return res
34
49
  .status(400)
@@ -106,7 +121,7 @@ export function register(app, { projects, project, config }) {
106
121
  const agents = readAgents(p.path);
107
122
  const agent = agents.find((a) => a.slug === req.params.slug);
108
123
  if (!agent) return res.status(404).json({ error: "agent not found" });
109
- const modelId = modelOverride || agent.fields.Model;
124
+ const modelId = await pickAgentModel({ modelOverride, agent, config });
110
125
  if (!modelId)
111
126
  return res
112
127
  .status(400)
@@ -1,6 +1,6 @@
1
1
  // GET /identity full identity.json
2
2
  // PATCH /identity { agent_name?, owner_name?, personality?, owner_context?, language?, timezone? }
3
- import { readIdentity, writeIdentity } from "../../../core/identity.js";
3
+ import { readIdentity, writeIdentity } from "#core/identity/index.js";
4
4
 
5
5
  const ALLOWED_KEYS = new Set([
6
6
  "agent_name",
@@ -18,7 +18,7 @@ import {
18
18
  runtimeMcpsPath,
19
19
  globalMcpsPath,
20
20
  SOURCES,
21
- } from "../../../core/mcp/sources.js";
21
+ } from "#core/mcp/sources.js";
22
22
 
23
23
  // scope alias used by API/CLI -> internal source id used in entry metadata
24
24
  const SCOPE_TO_SOURCE = {
@@ -9,7 +9,7 @@ import {
9
9
  readGlobalMessages,
10
10
  readProjectMessages,
11
11
  searchProjectMessages,
12
- } from "../../../core/messages-store.js";
12
+ } from "#core/stores/messages.js";
13
13
 
14
14
  export function register(app, { project }) {
15
15
  app.get("/projects/:pid/messages", (req, res) => {
@@ -7,18 +7,19 @@
7
7
  // GET /projects/:pid/sessions/:id/resume?summarize=true
8
8
  import fs from "node:fs";
9
9
  import path from "node:path";
10
- import { readAgents } from "../../../core/parser.js";
11
- import { readSessionFrontmatter } from "../../../core/session-store.js";
12
- import { buildAgentSystem } from "../../../core/agent-system.js";
10
+ import { readAgents } from "#core/apc/parser.js";
11
+ import { readSessionFrontmatter } from "#core/stores/sessions.js";
12
+ import { buildAgentSystem } from "#core/agent/build-agent-system.js";
13
+ import { CHANNELS } from "#core/constants/channels.js";
13
14
  import { getRuntime, RUNTIME_IDS } from "../runtimes/index.js";
14
15
  import { detectAll } from "../env-detect.js";
16
+ import { buildRuntimeBridgeHint as buildApfHint } from "#core/agent/runtime-bridge.js";
15
17
  import {
16
- buildApfHint,
17
18
  createRuntimeSession,
18
19
  closeRuntimeSession,
19
- extractApfResult,
20
- } from "../apc-runtime-context.js";
21
- import { runSuperAgent, isSuperAgentEnabled } from "../super-agent.js";
20
+ extractRuntimeResult as extractApfResult,
21
+ } from "#core/stores/runtime-sessions.js";
22
+ import { runSuperAgent, isSuperAgentEnabled } from "#core/agent/super-agent.js";
22
23
 
23
24
  export function register(app, { projects, registries, plugins, project, config }) {
24
25
  app.get("/runtimes", (_req, res) =>
@@ -205,7 +206,7 @@ export function register(app, { projects, registries, plugins, project, config }
205
206
  plugins,
206
207
  registries,
207
208
  prompt,
208
- channel: "api",
209
+ channel: CHANNELS.API,
209
210
  contextNote: `Resume request for session ${id}.`,
210
211
  });
211
212
  out.summary = sa.text;
@@ -4,7 +4,7 @@
4
4
  // then delegates to compactConversation.
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
- import { readAgents } from "../../../core/parser.js";
7
+ import { readAgents } from "#core/apc/parser.js";
8
8
  import { compactConversation } from "../compact.js";
9
9
 
10
10
  export function register(app, { projects, config }) {
@@ -4,8 +4,8 @@
4
4
  // GET /projects/:pid/sessions/:sid by filename (cross-agent lookup)
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
- import { parseSessionFrontmatter, readAgents } from "../../../core/parser.js";
8
- import { collectAllSessions } from "../../../interfaces/cli/commands/sessions.js";
7
+ import { parseSessionFrontmatter, readAgents } from "#core/apc/parser.js";
8
+ import { collectAllSessions } from "#interfaces/cli/commands/sessions.js";
9
9
  import { nowIso } from "./shared.js";
10
10
 
11
11
  export function register(app, { projects, project }) {
@@ -5,9 +5,10 @@
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
7
  import { randomUUID } from "node:crypto";
8
- import { appendErrorTrace, previewText } from "../../../core/logging.js";
9
- import { readAgents } from "../../../core/parser.js";
10
- import { agentMemoryPath } from "../../../core/agent-memory.js";
8
+ import { appendErrorTrace, previewText } from "#core/logging.js";
9
+ import { readAgents } from "#core/apc/parser.js";
10
+ import { agentMemoryPath } from "#core/agent/memory.js";
11
+ import { CHANNELS } from "#core/constants/channels.js";
11
12
 
12
13
  export const nowIso = () =>
13
14
  new Date().toISOString().replace(/\.\d{3}Z$/, "Z");
@@ -141,7 +142,7 @@ export function resolveSuperAgentContext(req, project) {
141
142
  };
142
143
  }
143
144
  return {
144
- channel: "api",
145
+ channel: CHANNELS.API,
145
146
  channelMeta: {
146
147
  projectId: String(project.id),
147
148
  projectName: project.name,
@@ -0,0 +1,30 @@
1
+ // Lightweight `/skills` listing for UI surfaces (web composer picker,
2
+ // future palettes). Same data backing `list_skills` tool, but here without
3
+ // auth-binding to a project — anyone with a valid daemon token can ask
4
+ // "which skills are around right now?".
5
+ //
6
+ // Returns the catalog already condensed (slug + first-sentence description)
7
+ // so the picker doesn't have to repeat the cleanup work.
8
+ import { listSkills } from "#core/agent/skills/loader.js";
9
+ import { condenseSkillDescription } from "#core/agent/skills/catalog.js";
10
+
11
+ export function register(app /*, ctx */) {
12
+ app.get("/skills", (req, res) => {
13
+ const projectPath = typeof req.query?.project_path === "string"
14
+ ? req.query.project_path
15
+ : undefined;
16
+ try {
17
+ const skills = listSkills({ projectPath });
18
+ res.json({
19
+ count: skills.length,
20
+ skills: skills.map(({ slug, source, description }) => ({
21
+ slug,
22
+ source,
23
+ description: condenseSkillDescription(description),
24
+ })),
25
+ });
26
+ } catch (e) {
27
+ res.status(500).json({ error: e.message });
28
+ }
29
+ });
30
+ }
@@ -5,14 +5,17 @@
5
5
  //
6
6
  // POST /projects/:pid/super-agent/chat/stream NDJSON event stream
7
7
  // POST /projects/:pid/super-agent/chat blocking JSON response
8
- import { runSuperAgent } from "../super-agent.js";
8
+ import { runSuperAgent } from "#core/agent/super-agent.js";
9
9
  import {
10
10
  resolveSuperAgentContext,
11
11
  appendSuperAgentErrorTrace,
12
12
  } from "./shared.js";
13
- import { loggerFor } from "../../../core/logging.js";
14
- import { appendGlobalMessage } from "../../../core/messages-store.js";
15
- import { createWebConfirmAdapter } from "../../../core/confirmation/adapters/web.js";
13
+ import { loggerFor } from "#core/logging.js";
14
+ import { appendGlobalMessage } from "#core/stores/messages.js";
15
+ import { createWebConfirmAdapter } from "#core/confirmation/adapters/web.js";
16
+ import { tryResolveSkillCommand } from "#core/agent/skills/trigger.js";
17
+ import { suggestSkillForPrompt } from "#core/agent/skills/rag.js";
18
+ import { CHANNELS } from "#core/constants/channels.js";
16
19
 
17
20
  const log = loggerFor("super-agent");
18
21
 
@@ -20,7 +23,7 @@ const log = loggerFor("super-agent");
20
23
  // RAG index, search_messages, and the "active threads" awareness block. Only
21
24
  // the human surfaces (web big chat + sidebar) — not generic "api"/automation
22
25
  // callers. Best-effort: a logging failure never breaks the reply.
23
- const WEB_LOGGED_CHANNELS = new Set(["web", "web_sidebar"]);
26
+ const WEB_LOGGED_CHANNELS = new Set([CHANNELS.WEB, CHANNELS.WEB_SIDEBAR]);
24
27
  function logWebTurn(channel, { prompt, replyText }) {
25
28
  if (!WEB_LOGGED_CHANNELS.has(channel)) return;
26
29
  try {
@@ -66,11 +69,24 @@ export function register(app, { projects, registries, plugins, project, config }
66
69
  // Optional coding-surface knobs: the terminal Code TUI (apx code, Build
67
70
  // mode) sends these so it runs to completion exactly like the web Code
68
71
  // module. Plain chat callers omit them and keep the lightweight defaults.
69
- const { prompt, previousMessages, model, maxIters, maxTokens, completionContract } =
72
+ const { prompt: rawPrompt, previousMessages, model, maxIters, maxTokens, completionContract } =
70
73
  req.body || {};
71
- if (!prompt) return res.status(400).json({ error: "prompt required" });
74
+ if (!rawPrompt) return res.status(400).json({ error: "prompt required" });
72
75
  const ctx = resolveSuperAgentContext(req, p);
73
76
 
77
+ // `/slug ...` shortcut: load the matching skill body into contextNote and
78
+ // strip the prefix from the user prompt. Falls through unchanged when the
79
+ // slug is unknown.
80
+ const slashed = tryResolveSkillCommand(rawPrompt, { projectPath: p.path });
81
+ const prompt = slashed.handled ? slashed.prompt : rawPrompt;
82
+ if (slashed.handled) {
83
+ ctx.contextNote = [ctx.contextNote, slashed.contextNote].filter(Boolean).join("\n\n");
84
+ } else {
85
+ // Semantic skill nudge — only when there was no explicit /slug.
86
+ const hint = await suggestSkillForPrompt(prompt, { projectPath: p.path });
87
+ if (hint) ctx.contextNote = [ctx.contextNote, hint].filter(Boolean).join("\n\n");
88
+ }
89
+
74
90
  res.setHeader("content-type", "application/x-ndjson; charset=utf-8");
75
91
  res.setHeader("cache-control", "no-cache, no-transform");
76
92
  res.setHeader("x-accel-buffering", "no");
@@ -151,7 +167,7 @@ export function register(app, { projects, registries, plugins, project, config }
151
167
  registries,
152
168
  prompt,
153
169
  contextNote,
154
- channel: "api",
170
+ channel: CHANNELS.API,
155
171
  overrideModel: model,
156
172
  maxTokens:
157
173
  max_tokens && Number.isFinite(Number(max_tokens))
@@ -174,7 +190,8 @@ export function register(app, { projects, registries, plugins, project, config }
174
190
  app.post("/projects/:pid/super-agent/chat", async (req, res) => {
175
191
  const p = project(req, res);
176
192
  if (!p) return;
177
- const { prompt, previousMessages, model } = req.body || {};
193
+ const { prompt, previousMessages, model, maxIters, maxTokens, completionContract } =
194
+ req.body || {};
178
195
  if (!prompt) return res.status(400).json({ error: "prompt required" });
179
196
  const ctx = resolveSuperAgentContext(req, p);
180
197
  try {
@@ -189,6 +206,9 @@ export function register(app, { projects, registries, plugins, project, config }
189
206
  contextNote: ctx.contextNote,
190
207
  previousMessages: previousMessages || [],
191
208
  overrideModel: model,
209
+ ...(Number.isFinite(Number(maxIters)) ? { maxIters: Number(maxIters) } : {}),
210
+ ...(Number.isFinite(Number(maxTokens)) ? { maxTokens: Number(maxTokens) } : {}),
211
+ ...(completionContract ? { completionContract: true } : {}),
192
212
  onEvent: wrapOnEventForLog(null, {
193
213
  trace_id: req.apxTraceId,
194
214
  channel: ctx.channel,
@@ -1,4 +1,4 @@
1
- // Per-project tasks (TODOs). Backed by core/tasks-store.js (JSONL event log).
1
+ // Per-project tasks (TODOs). Backed by core/stores/tasks.js (JSONL event log).
2
2
  // GET /projects/:pid/tasks ?state=open|done|dropped|all&tag=X&agent=Y&due_before=ISO&limit=N
3
3
  // POST /projects/:pid/tasks { title, body?, tags?, due?, agent?, source?, meta? }
4
4
  // GET /projects/:pid/tasks/:id (id or prefix)
@@ -15,7 +15,7 @@ import {
15
15
  dropTask,
16
16
  reopenTask,
17
17
  countTasks,
18
- } from "../../../core/tasks-store.js";
18
+ } from "#core/stores/tasks.js";
19
19
 
20
20
  export function register(app, { project, projects }) {
21
21
  // Global tasks across every project.
@@ -37,7 +37,7 @@ import {
37
37
  listRoles,
38
38
  setRole,
39
39
  removeRole,
40
- } from "../../../core/config.js";
40
+ } from "#core/config/index.js";
41
41
 
42
42
  function redactChannel(channel) {
43
43
  if (!channel?.bot_token) return channel;
@@ -4,12 +4,12 @@
4
4
  // search / glob / grep → filesystem-bounded
5
5
  // registry → /:name wildcard, MOUNT LAST so it
6
6
  // doesn't shadow the specific paths
7
- import { buildBrowserRouter } from "../../../core/tools/browser.js";
8
- import { buildFetchRouter } from "../../../core/tools/fetch.js";
9
- import { buildSearchRouter } from "../../../core/tools/search.js";
10
- import { buildRegistryRouter } from "../../../core/tools/registry.js";
11
- import { buildGlobRouter } from "../../../core/tools/glob.js";
12
- import { buildGrepRouter } from "../../../core/tools/grep.js";
7
+ import { buildBrowserRouter } from "#core/tools/browser.js";
8
+ import { buildFetchRouter } from "#core/tools/fetch.js";
9
+ import { buildSearchRouter } from "#core/tools/search.js";
10
+ import { buildRegistryRouter } from "#core/tools/registry.js";
11
+ import { buildGlobRouter } from "#core/tools/glob.js";
12
+ import { buildGrepRouter } from "#core/tools/grep.js";
13
13
 
14
14
  export function register(app, { express, projects, registries }) {
15
15
  app.use("/tools/fetch", buildFetchRouter(express));
@@ -8,8 +8,8 @@
8
8
  //
9
9
  // Audio files land under ~/.apx/tmp/tts/<uuid>.<ext>. The caller (CLI,
10
10
  // Telegram plugin, overlay) is responsible for picking them up.
11
- import { synthesize, listProviders } from "../../../core/voice/tts.js";
12
- import { readConfig } from "../../../core/config.js";
11
+ import { synthesize, listProviders } from "#core/voice/tts.js";
12
+ import { readConfig } from "#core/config/index.js";
13
13
 
14
14
  export function register(app) {
15
15
  app.post("/tts/say", async (req, res) => {
@@ -1,3 +1,5 @@
1
+ // eslint-disable-next-line -- import below
2
+ import { CHANNELS } from "#core/constants/channels.js";
1
3
  // Daemon HTTP routes for the unified "voice" channel.
2
4
  //
3
5
  // POST /voice/turn { audio?: <base64 or path>, format?, text?, agent?,
@@ -19,12 +21,12 @@ import fs from "node:fs";
19
21
  import path from "node:path";
20
22
  import os from "node:os";
21
23
  import { randomUUID } from "node:crypto";
22
- import { readConfig } from "../../../core/config.js";
23
- import { synthesize } from "../../../core/voice/tts.js";
24
+ import { readConfig } from "#core/config/index.js";
25
+ import { synthesize } from "#core/voice/tts.js";
24
26
  import { transcribe } from "../transcription.js";
25
- import { runSuperAgent, isSuperAgentEnabled } from "../super-agent.js";
26
- import { appendGlobalMessage } from "../../../core/messages-store.js";
27
- import { appendErrorTrace, previewText } from "../../../core/logging.js";
27
+ import { runSuperAgent, isSuperAgentEnabled } from "#core/agent/super-agent.js";
28
+ import { appendGlobalMessage } from "#core/stores/messages.js";
29
+ import { appendErrorTrace, previewText } from "#core/logging.js";
28
30
 
29
31
  // ── Channel-aware pre-processor ────────────────────────────────────
30
32
  //
@@ -84,14 +86,14 @@ function buildChannelContext(channel, { projectId, language = "es" } = {}) {
84
86
  const dynamicNote = `${langDirective}${projectHint}`;
85
87
  switch (channel) {
86
88
  case "voice":
87
- return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: "deck", channelMeta: { voice: true } };
89
+ return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: CHANNELS.DECK, channelMeta: { voice: true } };
88
90
  case "deck":
89
- return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: "deck", channelMeta: {} };
91
+ return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: CHANNELS.DECK, channelMeta: {} };
90
92
  case "desktop":
91
- return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: "desktop", channelMeta: { voice: true } };
93
+ return { ...base, contextNote: dynamicNote, systemSuffix: SUGGESTIONS_INSTRUCTION, wantsSuggestions: true, channel: CHANNELS.DESKTOP, channelMeta: { voice: true } };
92
94
  case "telegram":
93
95
  // Format rules live in channels/telegram.md; keep only the dynamic note.
94
- return { ...base, contextNote: dynamicNote, channel: "telegram", channelMeta: {} };
96
+ return { ...base, contextNote: dynamicNote, channel: CHANNELS.TELEGRAM, channelMeta: {} };
95
97
  default:
96
98
  return { ...base, contextNote: dynamicNote, channel: channel || "api", channelMeta: {} };
97
99
  }
@@ -232,7 +234,7 @@ async function tryVoiceTaskIntent({ projects, userText, hintProjectId }) {
232
234
  };
233
235
  }
234
236
  try {
235
- const { createTask } = await import("../../../core/tasks-store.js");
237
+ const { createTask } = await import("#core/stores/tasks.js");
236
238
  const task = createTask(project.storagePath, {
237
239
  title,
238
240
  source: "voice",
@@ -511,8 +513,8 @@ export function register(app, { projects, plugins, registries }) {
511
513
  }
512
514
 
513
515
  // Note for plugin authors:
514
- // Desktop (src/host/daemon/plugins/desktop.js) and Telegram
515
- // (src/host/daemon/plugins/telegram.js) currently implement their own
516
+ // Desktop (src/host/daemon/plugins/desktop/index.js) and Telegram
517
+ // (src/host/daemon/plugins/telegram/index.js) currently implement their own
516
518
  // STT → agent → render pipelines. To get spoken replies via APX they can
517
519
  // POST to /voice/turn (or call `synthesize()` directly) instead of
518
520
  // re-implementing TTS. This module intentionally does NOT migrate them —