@agentprojectcontext/apx 1.33.1 → 1.35.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 (208) hide show
  1. package/package.json +1 -1
  2. package/skills/apx/SKILL.md +49 -61
  3. package/src/core/agent/a2a/reply.js +48 -0
  4. package/src/core/agent/build-agent-system.js +136 -59
  5. package/src/core/agent/channels/voice-context.js +98 -0
  6. package/src/core/agent/memory.js +2 -1
  7. package/src/core/agent/prompt-builder.js +178 -124
  8. package/src/core/agent/prompts/channels/code.md +12 -10
  9. package/src/core/agent/prompts/channels/desktop.md +5 -32
  10. package/src/core/agent/prompts/channels/telegram.md +4 -15
  11. package/src/core/agent/prompts/channels/web_code.md +11 -11
  12. package/src/core/agent/prompts/core/agent-base.md +24 -0
  13. package/src/core/agent/prompts/core/project-agent.md +11 -0
  14. package/src/core/agent/prompts/core/super-agent.md +21 -0
  15. package/src/core/agent/prompts/discipline/action.md +10 -0
  16. package/src/core/agent/prompts/discipline/single-segment.md +6 -0
  17. package/src/core/agent/prompts/discipline/two-segment.md +11 -0
  18. package/src/core/agent/prompts/modes/code-build.md +1 -0
  19. package/src/core/agent/prompts/modes/code-plan.md +1 -0
  20. package/src/core/agent/prompts/modes/index.js +28 -0
  21. package/src/core/agent/self-memory.js +43 -1
  22. package/src/core/agent/skills/index-store.js +307 -0
  23. package/src/core/agent/skills/index.js +15 -1
  24. package/src/core/agent/skills/inspector.js +317 -0
  25. package/src/core/agent/skills/loader.js +22 -18
  26. package/src/core/agent/stream/turn-accumulator.js +73 -0
  27. package/src/core/agent/suggestions.js +37 -0
  28. package/src/core/agent/super-agent.js +7 -1
  29. package/src/core/agent/tools/handlers/_git.js +50 -0
  30. package/src/core/agent/tools/handlers/add-project.js +5 -2
  31. package/src/core/agent/tools/handlers/call-runtime.js +3 -2
  32. package/src/core/agent/tools/handlers/git-diff.js +44 -0
  33. package/src/core/agent/tools/handlers/git-log.js +38 -0
  34. package/src/core/agent/tools/handlers/git-show.js +34 -0
  35. package/src/core/agent/tools/handlers/git-status.js +61 -0
  36. package/src/core/agent/tools/handlers/transcribe-audio.js +1 -1
  37. package/src/core/agent/tools/helpers.js +2 -2
  38. package/src/core/agent/tools/names.js +169 -0
  39. package/src/core/agent/tools/registry-bridge.js +6 -14
  40. package/src/core/agent/tools/registry.js +103 -69
  41. package/src/core/apc/context-copy.js +27 -0
  42. package/src/core/apc/notes.js +19 -0
  43. package/src/core/apc/parser.js +12 -5
  44. package/src/core/apc/paths.js +87 -0
  45. package/src/core/apc/scaffold.js +82 -76
  46. package/src/core/apc/skill-sync.js +10 -0
  47. package/src/{host/daemon/plugins → core/channels}/telegram/dispatch.js +38 -16
  48. package/src/core/config/index.js +24 -2
  49. package/src/core/config/redact.js +95 -0
  50. package/src/core/constants/channels.js +2 -0
  51. package/src/core/constants/code-modes.js +10 -0
  52. package/src/core/constants/index.js +1 -0
  53. package/src/core/deck/manifest.js +186 -0
  54. package/src/core/engines/catalog.js +83 -0
  55. package/src/core/{tools → http-tools}/browser.js +0 -1
  56. package/src/core/{tools → http-tools}/fetch.js +0 -1
  57. package/src/core/{tools → http-tools}/glob.js +0 -1
  58. package/src/core/{tools → http-tools}/grep.js +0 -1
  59. package/src/core/{tools → http-tools}/registry.js +0 -1
  60. package/src/core/{tools → http-tools}/search.js +0 -1
  61. package/src/core/i18n/en.js +9 -0
  62. package/src/core/i18n/es.js +12 -0
  63. package/src/core/i18n/index.js +54 -0
  64. package/src/core/i18n/pt.js +9 -0
  65. package/src/core/identity/telegram.js +2 -1
  66. package/src/core/mcp/runner.js +272 -14
  67. package/src/core/mcp/sources.js +3 -2
  68. package/src/core/routines/index.js +16 -0
  69. package/src/{host/daemon/routines.js → core/routines/runner.js} +36 -103
  70. package/src/core/runtime-skills/apc-context/SKILL.md +159 -0
  71. package/src/core/runtime-skills/apx/SKILL.md +83 -0
  72. package/src/core/runtime-skills/apx-agency-agents/SKILL.md +125 -0
  73. package/src/core/runtime-skills/apx-agent/SKILL.md +97 -0
  74. package/src/core/runtime-skills/apx-mcp/SKILL.md +111 -0
  75. package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +169 -0
  76. package/{skills → src/core/runtime-skills}/apx-project/SKILL.md +20 -29
  77. package/src/core/runtime-skills/apx-routine/SKILL.md +127 -0
  78. package/src/core/runtime-skills/apx-runtime/SKILL.md +99 -0
  79. package/src/core/runtime-skills/apx-sessions/SKILL.md +232 -0
  80. package/src/core/runtime-skills/apx-skill-builder/SKILL.md +129 -0
  81. package/{skills → src/core/runtime-skills}/apx-task/SKILL.md +18 -21
  82. package/src/core/runtime-skills/apx-telegram/SKILL.md +120 -0
  83. package/src/core/runtime-skills/apx-voice/SKILL.md +117 -0
  84. package/src/core/runtime-skills/{claude-code.md → claude-code/SKILL.md} +1 -0
  85. package/src/core/runtime-skills/{codex-cli.md → codex-cli/SKILL.md} +1 -0
  86. package/src/core/runtime-skills/{opencode-cli.md → opencode-cli/SKILL.md} +1 -0
  87. package/src/core/runtime-skills/{openrouter.md → openrouter/SKILL.md} +1 -0
  88. package/src/{host/daemon/env-detect.js → core/runtimes/detect.js} +1 -1
  89. package/src/core/stores/code-sessions.js +50 -2
  90. package/src/core/stores/routine-memory.js +1 -1
  91. package/src/core/stores/sessions-search.js +121 -0
  92. package/src/core/stores/sessions.js +38 -0
  93. package/src/core/vars/index.js +14 -0
  94. package/src/core/vars/interpolate.js +86 -0
  95. package/src/core/vars/sources.js +151 -0
  96. package/src/core/voice/audio-decode.js +38 -0
  97. package/src/core/voice/transcription.js +225 -0
  98. package/src/host/daemon/api/admin-config.js +5 -82
  99. package/src/host/daemon/api/agents.js +5 -5
  100. package/src/host/daemon/api/code.js +17 -169
  101. package/src/host/daemon/api/config.js +3 -4
  102. package/src/host/daemon/api/conversations.js +8 -29
  103. package/src/host/daemon/api/deck.js +37 -404
  104. package/src/host/daemon/api/engines.js +1 -80
  105. package/src/host/daemon/api/exec.js +1 -1
  106. package/src/host/daemon/api/mcps.js +32 -0
  107. package/src/host/daemon/api/routines.js +1 -1
  108. package/src/host/daemon/api/runtimes.js +4 -3
  109. package/src/host/daemon/api/sessions-search.js +24 -140
  110. package/src/host/daemon/api/sessions.js +12 -30
  111. package/src/host/daemon/api/shared.js +2 -1
  112. package/src/host/daemon/api/skills.js +140 -6
  113. package/src/host/daemon/api/super-agent.js +56 -1
  114. package/src/host/daemon/api/telegram.js +1 -11
  115. package/src/host/daemon/api/tools.js +6 -6
  116. package/src/host/daemon/api/transcribe.js +2 -2
  117. package/src/host/daemon/api/vars.js +137 -0
  118. package/src/host/daemon/api/voice.js +13 -290
  119. package/src/host/daemon/api.js +2 -0
  120. package/src/host/daemon/db.js +6 -6
  121. package/src/host/daemon/deck-exec.js +148 -0
  122. package/src/host/daemon/index.js +20 -3
  123. package/src/host/daemon/plugins/telegram/index.js +9 -9
  124. package/src/host/daemon/routines-scheduler.js +64 -0
  125. package/src/host/daemon/smoke.js +3 -2
  126. package/src/host/daemon/whisper-server.js +225 -0
  127. package/src/interfaces/cli/branding.js +53 -0
  128. package/src/interfaces/cli/commands/agent.js +3 -2
  129. package/src/interfaces/cli/commands/command.js +2 -3
  130. package/src/interfaces/cli/commands/messages.js +6 -2
  131. package/src/interfaces/cli/commands/pair.js +5 -4
  132. package/src/interfaces/cli/commands/search.js +1 -1
  133. package/src/interfaces/cli/commands/sessions.js +3 -2
  134. package/src/interfaces/cli/commands/skills.js +290 -55
  135. package/src/interfaces/cli/index.js +84 -2
  136. package/src/interfaces/web/dist/assets/index-C0fm31dY.js +618 -0
  137. package/src/interfaces/web/dist/assets/index-C0fm31dY.js.map +1 -0
  138. package/src/interfaces/web/dist/assets/index-UcAqlBO6.css +1 -0
  139. package/src/interfaces/web/dist/index.html +2 -2
  140. package/src/interfaces/web/package-lock.json +182 -182
  141. package/src/interfaces/web/src/components/ModelCombobox.tsx +2 -1
  142. package/src/interfaces/web/src/components/TelegramChannelDialog.tsx +1 -1
  143. package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +76 -0
  144. package/src/interfaces/web/src/components/chat/MessageBubble.tsx +37 -4
  145. package/src/interfaces/web/src/components/chat/MessageList.tsx +23 -1
  146. package/src/interfaces/web/src/components/chat/ModelPicker.tsx +3 -1
  147. package/src/interfaces/web/src/components/code/CodeArtifactsTab.tsx +4 -4
  148. package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +1 -1
  149. package/src/interfaces/web/src/components/code/CodeFileTree.tsx +3 -2
  150. package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +3 -2
  151. package/src/interfaces/web/src/components/code/CodeTerminal.tsx +3 -2
  152. package/src/interfaces/web/src/components/config/GlobalConfigEditor.tsx +2 -1
  153. package/src/interfaces/web/src/components/deck/WidgetRow.tsx +2 -1
  154. package/src/interfaces/web/src/components/inputs/KeyValueList.tsx +93 -0
  155. package/src/interfaces/web/src/components/inputs/VarTokenInput.tsx +449 -0
  156. package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +2 -1
  157. package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +2 -2
  158. package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +73 -4
  159. package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +222 -0
  160. package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +3 -2
  161. package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +3 -2
  162. package/src/interfaces/web/src/components/ui/chat-input.tsx +5 -4
  163. package/src/interfaces/web/src/components/ui/sidebar.tsx +3 -2
  164. package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +2 -1
  165. package/src/interfaces/web/src/constants/index.ts +1 -1
  166. package/src/interfaces/web/src/hooks/useChat.ts +19 -0
  167. package/src/interfaces/web/src/i18n/en.ts +175 -7
  168. package/src/interfaces/web/src/i18n/es.ts +180 -15
  169. package/src/interfaces/web/src/lib/api/mcps.ts +25 -0
  170. package/src/interfaces/web/src/lib/api/skills.ts +70 -0
  171. package/src/interfaces/web/src/lib/api/vars.ts +38 -0
  172. package/src/interfaces/web/src/lib/api.ts +1 -0
  173. package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -31
  174. package/src/interfaces/web/src/screens/SettingsScreen.tsx +6 -2
  175. package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +1 -1
  176. package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +4 -3
  177. package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +7 -6
  178. package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +4 -3
  179. package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +1 -1
  180. package/src/interfaces/web/src/screens/project/ConfigTab.tsx +132 -1
  181. package/src/interfaces/web/src/screens/project/McpsTab.tsx +549 -104
  182. package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +1 -1
  183. package/src/interfaces/web/src/screens/project/VarsTab.tsx +300 -0
  184. package/src/interfaces/web/src/types/daemon.ts +15 -0
  185. package/skills/apx-agency-agents/SKILL.md +0 -141
  186. package/skills/apx-agent/SKILL.md +0 -100
  187. package/skills/apx-mcp-builder/SKILL.md +0 -183
  188. package/skills/apx-routine/SKILL.md +0 -140
  189. package/skills/apx-runtime/SKILL.md +0 -117
  190. package/skills/apx-sessions/SKILL.md +0 -281
  191. package/skills/apx-skill-builder/SKILL.md +0 -153
  192. package/skills/apx-telegram/SKILL.md +0 -131
  193. package/skills/apx-voice/SKILL.md +0 -137
  194. package/src/core/agent/prompts/action-discipline.md +0 -24
  195. package/src/core/agent/prompts/super-agent-base.md +0 -42
  196. package/src/host/daemon/transcription.js +0 -538
  197. package/src/host/daemon/whisper-transcribe.py +0 -73
  198. package/src/interfaces/web/dist/assets/index-Aaiw8BZN.css +0 -1
  199. package/src/interfaces/web/dist/assets/index-DPqtjDjh.js +0 -602
  200. package/src/interfaces/web/dist/assets/index-DPqtjDjh.js.map +0 -1
  201. /package/src/{host/daemon → core/apc}/projects-helpers.js +0 -0
  202. /package/src/{host/daemon/plugins → core/channels}/telegram/ask.js +0 -0
  203. /package/src/{host/daemon/plugins → core/channels}/telegram/helpers.js +0 -0
  204. /package/src/{host/daemon/plugins → core/channels}/telegram/media.js +0 -0
  205. /package/src/core/{tools → http-tools}/index.js +0 -0
  206. /package/src/{host/daemon/compact.js → core/stores/conversations-compactor.js} +0 -0
  207. /package/src/{host/daemon → core/stores}/conversations.js +0 -0
  208. /package/src/{host/daemon → core/util}/thinking.js +0 -0
@@ -0,0 +1,44 @@
1
+ // git_diff — show the diff for a project. Defaults to unstaged working-tree
2
+ // changes; pass staged=true for the index, or `ref` to diff against a commit.
3
+ import { runGit, resolveGitCwd } from "./_git.js";
4
+
5
+ export default {
6
+ name: "git_diff",
7
+ category: "code",
8
+ schema: {
9
+ type: "function",
10
+ function: {
11
+ name: "git_diff",
12
+ description:
13
+ "Show the git diff for a project. Defaults to UNSTAGED changes (working tree vs index). Set staged=true for the index vs HEAD, or pass ref (a commit, branch, or 'HEAD~1') to diff the working tree against that ref. Optional path argument limits the diff to a file/directory. Output is capped — use git_status first to choose what to diff if the change is large.",
14
+ parameters: {
15
+ type: "object",
16
+ properties: {
17
+ project: { type: "string", description: "project id, name, or path" },
18
+ cwd: { type: "string", description: "explicit working directory (overrides project)" },
19
+ staged: { type: "boolean", description: "diff the index vs HEAD instead of the working tree" },
20
+ ref: { type: "string", description: "ref to diff against (commit / branch / HEAD~N)" },
21
+ path: { type: "string", description: "limit the diff to this path (file or directory)" },
22
+ stat: { type: "boolean", description: "summary only (--stat) instead of full diff" },
23
+ },
24
+ },
25
+ },
26
+ },
27
+ makeHandler: (ctx) => async ({ project, cwd, staged, ref, path: subPath, stat } = {}) => {
28
+ const root = resolveGitCwd(ctx, { project, cwd });
29
+ const args = ["diff", "--no-color"];
30
+ if (stat) args.push("--stat");
31
+ if (staged) args.push("--staged");
32
+ if (ref) args.push(ref);
33
+ if (subPath) args.push("--", subPath);
34
+ const r = await runGit(args, { cwd: root });
35
+ if (!r.ok) return { ok: false, error: r.stderr || `git diff exited ${r.code}` };
36
+ return {
37
+ ok: true,
38
+ cwd: root,
39
+ diff: r.stdout,
40
+ truncated: r.truncated,
41
+ args: args.slice(1),
42
+ };
43
+ },
44
+ };
@@ -0,0 +1,38 @@
1
+ // git_log — recent commits for a project. One-line format by default.
2
+ import { runGit, resolveGitCwd } from "./_git.js";
3
+
4
+ export default {
5
+ name: "git_log",
6
+ category: "code",
7
+ schema: {
8
+ type: "function",
9
+ function: {
10
+ name: "git_log",
11
+ description:
12
+ "List recent commits for a project. Defaults to the last 20 commits in one-line format. Pass path to limit to a file/directory, ref to start from a different commit/branch, or full=true for the full message + stats.",
13
+ parameters: {
14
+ type: "object",
15
+ properties: {
16
+ project: { type: "string", description: "project id, name, or path" },
17
+ cwd: { type: "string", description: "explicit working directory (overrides project)" },
18
+ limit: { type: "integer", description: "max commits to return (default 20, capped at 200)" },
19
+ ref: { type: "string", description: "ref to start from (branch / commit / HEAD~N); defaults to HEAD" },
20
+ path: { type: "string", description: "limit to commits touching this path" },
21
+ full: { type: "boolean", description: "show full subject + body + stat instead of oneline" },
22
+ },
23
+ },
24
+ },
25
+ },
26
+ makeHandler: (ctx) => async ({ project, cwd, limit = 20, ref, path: subPath, full } = {}) => {
27
+ const root = resolveGitCwd(ctx, { project, cwd });
28
+ const safeLimit = Math.max(1, Math.min(Number(limit) || 20, 200));
29
+ const args = ["log", `-n${safeLimit}`, "--no-color"];
30
+ if (full) args.push("--format=fuller", "--stat");
31
+ else args.push("--oneline", "--decorate=short");
32
+ if (ref) args.push(ref);
33
+ if (subPath) args.push("--", subPath);
34
+ const r = await runGit(args, { cwd: root });
35
+ if (!r.ok) return { ok: false, error: r.stderr || `git log exited ${r.code}` };
36
+ return { ok: true, cwd: root, log: r.stdout, truncated: r.truncated };
37
+ },
38
+ };
@@ -0,0 +1,34 @@
1
+ // git_show — inspect a single commit (or branch tip): subject, author, files
2
+ // changed, full diff.
3
+ import { runGit, resolveGitCwd } from "./_git.js";
4
+
5
+ export default {
6
+ name: "git_show",
7
+ category: "code",
8
+ schema: {
9
+ type: "function",
10
+ function: {
11
+ name: "git_show",
12
+ description:
13
+ "Show a single git commit (or any ref) — message, author, files changed, and full diff. Use `ref` to point at a commit hash, branch, or HEAD~N. Defaults to HEAD.",
14
+ parameters: {
15
+ type: "object",
16
+ properties: {
17
+ project: { type: "string", description: "project id, name, or path" },
18
+ cwd: { type: "string", description: "explicit working directory (overrides project)" },
19
+ ref: { type: "string", description: "ref to show (commit / branch / HEAD~N); defaults to HEAD" },
20
+ stat: { type: "boolean", description: "show stat summary instead of full diff" },
21
+ },
22
+ },
23
+ },
24
+ },
25
+ makeHandler: (ctx) => async ({ project, cwd, ref = "HEAD", stat } = {}) => {
26
+ const root = resolveGitCwd(ctx, { project, cwd });
27
+ const args = ["show", "--no-color"];
28
+ if (stat) args.push("--stat");
29
+ args.push(ref);
30
+ const r = await runGit(args, { cwd: root });
31
+ if (!r.ok) return { ok: false, error: r.stderr || `git show exited ${r.code}` };
32
+ return { ok: true, cwd: root, ref, output: r.stdout, truncated: r.truncated };
33
+ },
34
+ };
@@ -0,0 +1,61 @@
1
+ // git_status — porcelain working-tree status for a project. Returns the raw
2
+ // porcelain text plus a structured list of files so the model doesn't have to
3
+ // re-parse it.
4
+ import { runGit, resolveGitCwd } from "./_git.js";
5
+
6
+ function parsePorcelain(text) {
7
+ const files = [];
8
+ for (const line of String(text).split("\n")) {
9
+ if (!line) continue;
10
+ // Format: XY <path> (optionally `XY <orig> -> <renamed>` for renames)
11
+ const xy = line.slice(0, 2);
12
+ const rest = line.slice(3);
13
+ const renameIdx = rest.indexOf(" -> ");
14
+ let pathStr = rest;
15
+ let origPath = null;
16
+ if (renameIdx >= 0) {
17
+ origPath = rest.slice(0, renameIdx);
18
+ pathStr = rest.slice(renameIdx + 4);
19
+ }
20
+ files.push({
21
+ staged: xy[0] !== " " && xy[0] !== "?",
22
+ unstaged: xy[1] !== " ",
23
+ untracked: xy === "??",
24
+ status: xy.trim(),
25
+ path: pathStr,
26
+ ...(origPath ? { original_path: origPath } : {}),
27
+ });
28
+ }
29
+ return files;
30
+ }
31
+
32
+ export default {
33
+ name: "git_status",
34
+ category: "code",
35
+ schema: {
36
+ type: "function",
37
+ function: {
38
+ name: "git_status",
39
+ description:
40
+ "Show the git working-tree status (staged + unstaged + untracked) for a project. Returns porcelain output plus a parsed list of files. Pass project (id/name/path) OR cwd. Use this BEFORE summarizing changes or BEFORE staging.",
41
+ parameters: {
42
+ type: "object",
43
+ properties: {
44
+ project: { type: "string", description: "project id, name, or path; falls back to the active project if omitted" },
45
+ cwd: { type: "string", description: "explicit working directory (overrides project)" },
46
+ },
47
+ },
48
+ },
49
+ },
50
+ makeHandler: (ctx) => async ({ project, cwd } = {}) => {
51
+ const root = resolveGitCwd(ctx, { project, cwd });
52
+ const r = await runGit(["status", "--porcelain=v1", "-uall"], { cwd: root });
53
+ if (!r.ok) return { ok: false, error: r.stderr || `git status exited ${r.code}` };
54
+ return {
55
+ ok: true,
56
+ cwd: root,
57
+ files: parsePorcelain(r.stdout),
58
+ raw: r.stdout,
59
+ };
60
+ },
61
+ };
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import crypto from "node:crypto";
5
- import { transcribe } from "#host/daemon/transcription.js";
5
+ import { transcribe } from "#core/voice/transcription.js";
6
6
 
7
7
  export default {
8
8
  name: "transcribe_audio",
@@ -1,12 +1,12 @@
1
1
  // Pure / config-only helpers used by tool handlers. Anything that needs the
2
2
  // running daemon's projects registry (projectMeta, resolveProject) lives in
3
- // host/daemon/projects-helpers.js and is re-exported here for back-compat.
3
+ // core/apc/projects-helpers.js and is re-exported here for back-compat.
4
4
  import path from "node:path";
5
5
  import { agentSkills, buildAgentSystem as buildCoreAgentSystem } from "#core/agent/build-agent-system.js";
6
6
  import { buildConfirmDescription } from "#core/confirmation/index.js";
7
7
  import { PERMISSION_MODES, DEFAULT_PERMISSION_MODE } from "#core/constants/permissions.js";
8
8
 
9
- export { projectMeta, resolveProject } from "#host/daemon/projects-helpers.js";
9
+ export { projectMeta, resolveProject } from "#core/apc/projects-helpers.js";
10
10
 
11
11
  export function safePathJoin(root, sub = ".") {
12
12
  const target = path.resolve(root, sub || ".");
@@ -0,0 +1,169 @@
1
+ // Canonical tool names. Every place that mentions a tool by name — handler
2
+ // dispatch, allow-lists, prompt rules, the registry bridge skip-set — imports
3
+ // the constant from here. Refactor-safe: rename once, the rest follows.
4
+ //
5
+ // Keep the keys SCREAMING_SNAKE_CASE and the values snake_case (the on-wire
6
+ // tool name the LLM sees). The two halves stay aligned so a typo on either
7
+ // side is obvious.
8
+
9
+ export const TOOLS = Object.freeze({
10
+ // Discovery / projects / agents
11
+ LIST_PROJECTS: "list_projects",
12
+ ADD_PROJECT: "add_project",
13
+ LIST_AGENTS: "list_agents",
14
+ LIST_VAULT_AGENTS: "list_vault_agents",
15
+ IMPORT_AGENT: "import_agent",
16
+ LIST_MCPS: "list_mcps",
17
+
18
+ // Memory
19
+ READ_AGENT_MEMORY: "read_agent_memory",
20
+ READ_SELF_MEMORY: "read_self_memory",
21
+ REMEMBER: "remember",
22
+
23
+ // Filesystem / shell
24
+ LIST_FILES: "list_files",
25
+ READ_FILE: "read_file",
26
+ WRITE_FILE: "write_file",
27
+ EDIT_FILE: "edit_file",
28
+ SEARCH_FILES: "search_files",
29
+ RUN_SHELL: "run_shell",
30
+
31
+ // History / messages / sessions
32
+ TAIL_MESSAGES: "tail_messages",
33
+ SEARCH_MESSAGES: "search_messages",
34
+ SEARCH_SESSIONS: "search_sessions",
35
+
36
+ // Skills + dynamic tool surface
37
+ LIST_SKILLS: "list_skills",
38
+ LOAD_SKILL: "load_skill",
39
+ DISCOVER_TOOLS: "discover_tools",
40
+
41
+ // Tasks
42
+ LIST_TASKS: "list_tasks",
43
+ CREATE_TASK: "create_task",
44
+
45
+ // Interaction
46
+ ASK_QUESTIONS: "ask_questions",
47
+
48
+ // Delegation / external
49
+ CALL_AGENT: "call_agent",
50
+ CALL_MCP: "call_mcp",
51
+ CALL_RUNTIME: "call_runtime",
52
+
53
+ // Side-effects
54
+ SEND_TELEGRAM: "send_telegram",
55
+ SET_IDENTITY: "set_identity",
56
+ SET_PERMISSION_MODE: "set_permission_mode",
57
+ TRANSCRIBE_AUDIO: "transcribe_audio",
58
+
59
+ // Git — code-channel tools, lazy on chat
60
+ GIT_STATUS: "git_status",
61
+ GIT_DIFF: "git_diff",
62
+ GIT_LOG: "git_log",
63
+ GIT_SHOW: "git_show",
64
+
65
+ // HTTP-bridged registry tools (not native handlers; served via
66
+ // core/tools/registry.js so the regular generic tools work the same way).
67
+ GREP: "grep",
68
+ GLOB: "glob",
69
+ FETCH: "fetch",
70
+ SEARCH: "search",
71
+ });
72
+
73
+ /**
74
+ * Native handlers in src/core/agent/tools/handlers/ that own these names.
75
+ * The registry bridge MUST skip these — otherwise the HTTP roundtrip would
76
+ * shadow the in-process handler with possibly different semantics.
77
+ */
78
+ export const NATIVE_TOOL_NAMES = new Set([
79
+ TOOLS.LIST_PROJECTS,
80
+ TOOLS.LIST_AGENTS,
81
+ TOOLS.LIST_VAULT_AGENTS,
82
+ TOOLS.IMPORT_AGENT,
83
+ TOOLS.ADD_PROJECT,
84
+ TOOLS.LIST_MCPS,
85
+ TOOLS.READ_AGENT_MEMORY,
86
+ TOOLS.LIST_FILES,
87
+ TOOLS.READ_FILE,
88
+ TOOLS.WRITE_FILE,
89
+ TOOLS.EDIT_FILE,
90
+ TOOLS.SEARCH_FILES,
91
+ TOOLS.RUN_SHELL,
92
+ TOOLS.TAIL_MESSAGES,
93
+ TOOLS.SEARCH_MESSAGES,
94
+ TOOLS.CALL_AGENT,
95
+ TOOLS.CALL_MCP,
96
+ TOOLS.CALL_RUNTIME,
97
+ TOOLS.SEND_TELEGRAM,
98
+ TOOLS.SET_IDENTITY,
99
+ TOOLS.SET_PERMISSION_MODE,
100
+ TOOLS.READ_SELF_MEMORY,
101
+ TOOLS.REMEMBER,
102
+ TOOLS.LIST_SKILLS,
103
+ TOOLS.LOAD_SKILL,
104
+ TOOLS.LIST_TASKS,
105
+ TOOLS.CREATE_TASK,
106
+ TOOLS.ASK_QUESTIONS,
107
+ TOOLS.SEARCH_SESSIONS,
108
+ TOOLS.TRANSCRIBE_AUDIO,
109
+ TOOLS.DISCOVER_TOOLS,
110
+ TOOLS.GIT_STATUS,
111
+ TOOLS.GIT_DIFF,
112
+ TOOLS.GIT_LOG,
113
+ TOOLS.GIT_SHOW,
114
+ ]);
115
+
116
+ /**
117
+ * Tools that belong in code-shaped channels (apx code, web_code) but should
118
+ * stay lazy on chat surfaces (telegram, web_sidebar, deck, desktop) — there's
119
+ * no point loading `git_diff` schemas in a Telegram chat.
120
+ *
121
+ * Listed separately so registry.js can promote them into the base set when
122
+ * the channel is a coding surface, without touching the chat base.
123
+ */
124
+ export const CODE_CHANNEL_TOOLS = Object.freeze([
125
+ TOOLS.GIT_STATUS,
126
+ TOOLS.GIT_DIFF,
127
+ TOOLS.GIT_LOG,
128
+ TOOLS.GIT_SHOW,
129
+ ]);
130
+
131
+ /**
132
+ * Read-only allow-list for the Code module's PLAN mode: the agent explores
133
+ * the repo and proposes changes without mutating anything. Build mode uses
134
+ * the full registry — see CODE_BUILD_TOOLS below.
135
+ */
136
+ export const CODE_PLAN_TOOLS = Object.freeze([
137
+ TOOLS.READ_FILE,
138
+ TOOLS.LIST_FILES,
139
+ TOOLS.SEARCH_FILES,
140
+ TOOLS.GREP,
141
+ TOOLS.GLOB,
142
+ TOOLS.LIST_PROJECTS,
143
+ TOOLS.LIST_AGENTS,
144
+ TOOLS.LIST_MCPS,
145
+ TOOLS.READ_AGENT_MEMORY,
146
+ TOOLS.READ_SELF_MEMORY,
147
+ TOOLS.SEARCH_SESSIONS,
148
+ TOOLS.SEARCH_MESSAGES,
149
+ TOOLS.TAIL_MESSAGES,
150
+ TOOLS.LIST_SKILLS,
151
+ TOOLS.LOAD_SKILL,
152
+ TOOLS.LIST_TASKS,
153
+ TOOLS.ASK_QUESTIONS,
154
+ TOOLS.FETCH,
155
+ TOOLS.SEARCH,
156
+ // Git tools are read-only on plan mode and let the agent inspect the
157
+ // working state before proposing edits.
158
+ TOOLS.GIT_STATUS,
159
+ TOOLS.GIT_DIFF,
160
+ TOOLS.GIT_LOG,
161
+ TOOLS.GIT_SHOW,
162
+ ]);
163
+
164
+ /**
165
+ * BUILD mode = unrestricted. Kept as a sentinel value so callers compare
166
+ * against the constant instead of the magic "*" string. The registry treats
167
+ * "*" as "expose every tool the channel is otherwise allowed to see".
168
+ */
169
+ export const CODE_BUILD_TOOLS = "*";
@@ -1,10 +1,9 @@
1
- // daemon/super-agent-tools/registry-bridge.js
2
1
  //
3
2
  // Generic bridge that exposes registry-backed HTTP tools (browser, fetch,
4
3
  // search, glob, grep, etc.) to the super-agent — no per-tool import boilerplate.
5
4
  //
6
5
  // How it works:
7
- // 1. Read TOOL_DEFINITIONS from daemon/tools/registry.js
6
+ // 1. Read TOOL_DEFINITIONS from core/http-tools/registry.js
8
7
  // 2. Drop entries whose names collide with native super-agent tools (those
9
8
  // win — they touch in-process state directly).
10
9
  // 3. For each remaining entry, produce { name, schema, makeHandler } in the
@@ -19,8 +18,9 @@
19
18
  // super-agent-tools/tools/, no import in index.js.
20
19
 
21
20
  import fs from "node:fs";
22
- import { TOOL_DEFINITIONS } from "#core/tools/registry.js";
21
+ import { TOOL_DEFINITIONS } from "#core/http-tools/registry.js";
23
22
  import { TOKEN_PATH } from "#core/config/index.js";
23
+ import { NATIVE_TOOL_NAMES } from "./names.js";
24
24
 
25
25
  // The bridge POSTs to the daemon's OWN HTTP server, which is behind the bearer
26
26
  // auth middleware (see api/shared.js). Without a token every bridged tool call
@@ -42,17 +42,9 @@ function daemonToken() {
42
42
  return cachedToken;
43
43
  }
44
44
 
45
- // Native handlers in super-agent-tools/tools/ that own these names. The bridge
46
- // MUST skip them or the registry version (HTTP roundtrip) would shadow the
47
- // native one with possibly different semantics.
48
- const NATIVE_NAMES = new Set([
49
- "list_projects", "list_agents", "list_vault_agents", "import_agent",
50
- "add_project", "list_mcps", "read_agent_memory",
51
- "list_files", "read_file", "write_file", "edit_file", "search_files",
52
- "run_shell", "tail_messages", "search_messages",
53
- "call_agent", "call_mcp", "call_runtime",
54
- "send_telegram", "set_identity", "set_permission_mode",
55
- ]);
45
+ // Native handler list lives in ./names.js so the bridge skip-set and the
46
+ // allow-lists in api/code.js share one source of truth.
47
+ const NATIVE_NAMES = NATIVE_TOOL_NAMES;
56
48
 
57
49
  // Default allow-list of categories the bridge will expose. The NATIVE_NAMES
58
50
  // filter handles duplicates inside these categories (e.g. "file" contains
@@ -29,8 +29,14 @@ import askQuestions from "./handlers/ask-questions.js";
29
29
  import createTask from "./handlers/create-task.js";
30
30
  import listTasks from "./handlers/list-tasks.js";
31
31
  import discoverTools from "./handlers/discover-tools.js";
32
+ import gitStatus from "./handlers/git-status.js";
33
+ import gitDiff from "./handlers/git-diff.js";
34
+ import gitLog from "./handlers/git-log.js";
35
+ import gitShow from "./handlers/git-show.js";
32
36
  import { createPermissionGuard } from "./helpers.js";
33
37
  import { buildBridgedTools, DEFAULT_CATEGORIES } from "./registry-bridge.js";
38
+ import { TOOLS, CODE_CHANNEL_TOOLS } from "./names.js";
39
+ import { CHANNELS } from "#core/constants/channels.js";
34
40
 
35
41
  const NATIVE_TOOLS = [
36
42
  listProjects,
@@ -64,6 +70,10 @@ const NATIVE_TOOLS = [
64
70
  createTask,
65
71
  listTasks,
66
72
  discoverTools,
73
+ gitStatus,
74
+ gitDiff,
75
+ gitLog,
76
+ gitShow,
67
77
  ];
68
78
 
69
79
  // Registry-backed bridges. Categories can be overridden per-process via env
@@ -76,9 +86,9 @@ function resolveBridgeCategories() {
76
86
  }
77
87
 
78
88
  const BRIDGED_TOOLS = buildBridgedTools({ categories: resolveBridgeCategories() });
79
- const TOOLS = [...NATIVE_TOOLS, ...BRIDGED_TOOLS];
89
+ const ALL_TOOLS = [...NATIVE_TOOLS, ...BRIDGED_TOOLS];
80
90
 
81
- export const TOOL_SCHEMAS = TOOLS.map((tool) => tool.schema);
91
+ export const TOOL_SCHEMAS = ALL_TOOLS.map((tool) => tool.schema);
82
92
 
83
93
  // ---------------------------------------------------------------------------
84
94
  // Lazy tools: base set (always loaded) + on-demand set (revealed via
@@ -93,78 +103,96 @@ export const TOOL_SCHEMAS = TOOLS.map((tool) => tool.schema);
93
103
  // sessions, projects/inventory, basic shell, tasks, skills, and discovery.
94
104
  export const BASE_TOOL_NAMES = new Set([
95
105
  // Discovery — the entry point to everything not loaded here.
96
- "discover_tools",
106
+ TOOLS.DISCOVER_TOOLS,
97
107
  // Inventory — the model needs these to know what exists.
98
- "list_projects",
99
- "list_agents",
100
- "list_mcps",
101
- "list_skills",
102
- "load_skill",
108
+ TOOLS.LIST_PROJECTS,
109
+ TOOLS.LIST_AGENTS,
110
+ TOOLS.LIST_MCPS,
111
+ TOOLS.LIST_SKILLS,
112
+ TOOLS.LOAD_SKILL,
103
113
  // Memory + identity.
104
- "read_agent_memory",
105
- "read_self_memory",
106
- "remember",
107
- "set_identity",
114
+ TOOLS.READ_AGENT_MEMORY,
115
+ TOOLS.READ_SELF_MEMORY,
116
+ TOOLS.REMEMBER,
117
+ TOOLS.SET_IDENTITY,
108
118
  // Sessions + messages (self-recall + channel history).
109
- "search_sessions",
110
- "search_messages",
111
- "tail_messages",
119
+ TOOLS.SEARCH_SESSIONS,
120
+ TOOLS.SEARCH_MESSAGES,
121
+ TOOLS.TAIL_MESSAGES,
112
122
  // Channels + conversation control + lightweight delegation.
113
- "send_telegram",
114
- "ask_questions",
115
- "call_agent",
123
+ TOOLS.SEND_TELEGRAM,
124
+ TOOLS.ASK_QUESTIONS,
125
+ TOOLS.CALL_AGENT,
116
126
  // Tasks (very common ask via chat).
117
- "create_task",
118
- "list_tasks",
127
+ TOOLS.CREATE_TASK,
128
+ TOOLS.LIST_TASKS,
119
129
  // Files + basic shell — frequent enough on chat to keep hot.
120
- "read_file",
121
- "write_file",
122
- "edit_file",
123
- "list_files",
124
- "search_files",
125
- "run_shell",
130
+ TOOLS.READ_FILE,
131
+ TOOLS.WRITE_FILE,
132
+ TOOLS.EDIT_FILE,
133
+ TOOLS.LIST_FILES,
134
+ TOOLS.SEARCH_FILES,
135
+ TOOLS.RUN_SHELL,
126
136
  ]);
127
137
 
128
138
  // Channels that get the FULL registry up front (deliberate, user-picked model,
129
139
  // no cheap-tier TPM cap). Everything else is a "lightweight" channel and starts
130
140
  // on BASE_TOOL_NAMES with discover_tools to expand.
131
- const FULL_CHANNELS = new Set(["routine", "api", "web", "code", "terminal"]);
141
+ const FULL_CHANNELS = new Set([
142
+ CHANNELS.ROUTINE,
143
+ CHANNELS.API,
144
+ CHANNELS.WEB,
145
+ CHANNELS.CODE,
146
+ CHANNELS.WEB_CODE,
147
+ ]);
148
+
149
+ // Coding surfaces — even on the lightweight set, these channels get the
150
+ // git_* tools promoted into the base so the model can inspect the repo
151
+ // without round-tripping through discover_tools every turn.
152
+ const CODE_CHANNELS = new Set([
153
+ CHANNELS.CODE,
154
+ CHANNELS.WEB_CODE,
155
+ ]);
132
156
 
133
157
  // Category labels for grouping the discover_tools catalog. Native tools have no
134
158
  // registry category, so we assign one here; bridged tools carry their own
135
159
  // (browser/fetch/search/file) from registry-bridge.js.
136
160
  const NATIVE_CATEGORY = {
137
- discover_tools: "system",
138
- set_permission_mode: "system",
139
- list_projects: "inventory",
140
- list_agents: "inventory",
141
- list_vault_agents: "inventory",
142
- list_mcps: "inventory",
143
- list_skills: "inventory",
144
- load_skill: "skills",
145
- import_agent: "agents",
146
- add_project: "projects",
147
- call_agent: "agents",
148
- call_runtime: "runtime",
149
- call_mcp: "mcp",
150
- read_agent_memory: "memory",
151
- read_self_memory: "memory",
152
- remember: "memory",
153
- set_identity: "identity",
154
- search_sessions: "sessions",
155
- search_messages: "messages",
156
- tail_messages: "messages",
157
- send_telegram: "messages",
158
- ask_questions: "conversation",
159
- create_task: "tasks",
160
- list_tasks: "tasks",
161
- transcribe_audio: "voice",
162
- read_file: "files",
163
- write_file: "files",
164
- edit_file: "files",
165
- list_files: "files",
166
- search_files: "files",
167
- run_shell: "shell",
161
+ [TOOLS.DISCOVER_TOOLS]: "system",
162
+ [TOOLS.SET_PERMISSION_MODE]: "system",
163
+ [TOOLS.LIST_PROJECTS]: "inventory",
164
+ [TOOLS.LIST_AGENTS]: "inventory",
165
+ [TOOLS.LIST_VAULT_AGENTS]: "inventory",
166
+ [TOOLS.LIST_MCPS]: "inventory",
167
+ [TOOLS.LIST_SKILLS]: "inventory",
168
+ [TOOLS.LOAD_SKILL]: "skills",
169
+ [TOOLS.IMPORT_AGENT]: "agents",
170
+ [TOOLS.ADD_PROJECT]: "projects",
171
+ [TOOLS.CALL_AGENT]: "agents",
172
+ [TOOLS.CALL_RUNTIME]: "runtime",
173
+ [TOOLS.CALL_MCP]: "mcp",
174
+ [TOOLS.READ_AGENT_MEMORY]: "memory",
175
+ [TOOLS.READ_SELF_MEMORY]: "memory",
176
+ [TOOLS.REMEMBER]: "memory",
177
+ [TOOLS.SET_IDENTITY]: "identity",
178
+ [TOOLS.SEARCH_SESSIONS]: "sessions",
179
+ [TOOLS.SEARCH_MESSAGES]: "messages",
180
+ [TOOLS.TAIL_MESSAGES]: "messages",
181
+ [TOOLS.SEND_TELEGRAM]: "messages",
182
+ [TOOLS.ASK_QUESTIONS]: "conversation",
183
+ [TOOLS.CREATE_TASK]: "tasks",
184
+ [TOOLS.LIST_TASKS]: "tasks",
185
+ [TOOLS.TRANSCRIBE_AUDIO]: "voice",
186
+ [TOOLS.READ_FILE]: "files",
187
+ [TOOLS.WRITE_FILE]: "files",
188
+ [TOOLS.EDIT_FILE]: "files",
189
+ [TOOLS.LIST_FILES]: "files",
190
+ [TOOLS.SEARCH_FILES]: "files",
191
+ [TOOLS.RUN_SHELL]: "shell",
192
+ [TOOLS.GIT_STATUS]: "code",
193
+ [TOOLS.GIT_DIFF]: "code",
194
+ [TOOLS.GIT_LOG]: "code",
195
+ [TOOLS.GIT_SHOW]: "code",
168
196
  };
169
197
 
170
198
  function categoryOf(tool) {
@@ -179,7 +207,7 @@ function oneLine(desc = "") {
179
207
 
180
208
  // Static metadata index for every tool — name, schema, category, short blurb.
181
209
  // Used by the per-turn tool session for the catalog and activation lookups.
182
- const TOOL_META = TOOLS.map((t) => ({
210
+ const TOOL_META = ALL_TOOLS.map((t) => ({
183
211
  name: t.name,
184
212
  schema: t.schema,
185
213
  category: categoryOf(t),
@@ -187,24 +215,30 @@ const TOOL_META = TOOLS.map((t) => ({
187
215
  }));
188
216
  const META_BY_NAME = new Map(TOOL_META.map((m) => [m.name, m]));
189
217
 
190
- export const BASE_TOOL_SCHEMAS = TOOLS
218
+ export const BASE_TOOL_SCHEMAS = ALL_TOOLS
191
219
  .filter((t) => BASE_TOOL_NAMES.has(t.name))
192
220
  .map((t) => t.schema);
193
221
 
194
- // Back-compat alias: a few callers/tests historically referenced the "core"
195
- // subset. The base set supersedes it.
196
- export const CORE_TOOL_SCHEMAS = BASE_TOOL_SCHEMAS;
197
-
198
222
  const schemaName = (s) => s?.function?.name || s?.name;
199
223
 
224
+ // Code-channel base = BASE + git_* tools. Pre-computed once.
225
+ const CODE_BASE_TOOL_NAMES = new Set([...BASE_TOOL_NAMES, ...CODE_CHANNEL_TOOLS]);
226
+ const CODE_BASE_TOOL_SCHEMAS = ALL_TOOLS
227
+ .filter((t) => CODE_BASE_TOOL_NAMES.has(t.name))
228
+ .map((t) => t.schema);
229
+
200
230
  /**
201
- * Choose the INITIAL tool schema list for a channel. Full channels get the
202
- * whole registry; lightweight channels (telegram/desktop/deck/web_sidebar) get
203
- * the base set and expand on demand via discover_tools. `full: true` forces the
204
- * complete registry regardless of channel.
231
+ * Choose the INITIAL tool schema list for a channel.
232
+ * - FULL_CHANNELS (api, web, code, web_code, routine) get the whole registry.
233
+ * - CODE_CHANNELS overlap with FULL, but when something forces a smaller set
234
+ * (CODE_PLAN_TOOLS allowlist) the git_* tools are still in their base.
235
+ * - Everything else is "lightweight" and starts on BASE_TOOL_NAMES.
236
+ *
237
+ * `full: true` forces the complete registry regardless of channel.
205
238
  */
206
239
  export function schemasForChannel(channel, { full = false } = {}) {
207
240
  if (full || FULL_CHANNELS.has(channel)) return TOOL_SCHEMAS;
241
+ if (CODE_CHANNELS.has(channel)) return CODE_BASE_TOOL_SCHEMAS;
208
242
  return BASE_TOOL_SCHEMAS;
209
243
  }
210
244
 
@@ -337,7 +371,7 @@ export function makeToolHandlers(ctx) {
337
371
  requestConfirmation: ctx.requestConfirmation || null,
338
372
  }),
339
373
  };
340
- return Object.fromEntries(TOOLS.map((tool) => [tool.name, tool.makeHandler(toolCtx)]));
374
+ return Object.fromEntries(ALL_TOOLS.map((tool) => [tool.name, tool.makeHandler(toolCtx)]));
341
375
  }
342
376
 
343
377
  // Diagnostic helper — useful for `apx daemon status` or debug logging.