@agentprojectcontext/apx 1.33.0 → 1.34.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 (172) hide show
  1. package/package.json +1 -1
  2. package/skills/apc-context/SKILL.md +2 -5
  3. package/skills/apx/SKILL.md +49 -61
  4. package/src/core/agent/a2a/reply.js +48 -0
  5. package/src/core/agent/build-agent-system.js +4 -3
  6. package/src/core/agent/channels/voice-context.js +98 -0
  7. package/src/core/agent/memory.js +2 -1
  8. package/src/core/agent/prompt-builder.js +2 -1
  9. package/src/core/agent/prompts/modes/code-build.md +1 -0
  10. package/src/core/agent/prompts/modes/code-plan.md +1 -0
  11. package/src/core/agent/prompts/modes/index.js +28 -0
  12. package/src/core/agent/skills/loader.js +22 -18
  13. package/src/core/agent/stream/turn-accumulator.js +73 -0
  14. package/src/core/agent/suggestions.js +37 -0
  15. package/src/core/agent/tools/handlers/add-project.js +5 -2
  16. package/src/core/agent/tools/handlers/call-runtime.js +3 -2
  17. package/src/core/agent/tools/handlers/transcribe-audio.js +1 -1
  18. package/src/core/agent/tools/helpers.js +2 -2
  19. package/src/core/agent/tools/names.js +138 -0
  20. package/src/core/agent/tools/registry-bridge.js +6 -14
  21. package/src/core/agent/tools/registry.js +68 -65
  22. package/src/core/apc/context-copy.js +27 -0
  23. package/src/core/apc/notes.js +19 -0
  24. package/src/core/apc/parser.js +13 -6
  25. package/src/core/apc/paths.js +87 -0
  26. package/src/core/apc/scaffold.js +82 -74
  27. package/src/core/apc/skill-sync.js +13 -1
  28. package/src/core/channels/telegram/dispatch.js +595 -0
  29. package/src/core/channels/telegram/helpers.js +130 -0
  30. package/src/core/config/index.js +3 -2
  31. package/src/core/config/redact.js +95 -0
  32. package/src/core/constants/channels.js +2 -0
  33. package/src/core/constants/code-modes.js +10 -0
  34. package/src/core/constants/index.js +1 -0
  35. package/src/core/deck/manifest.js +186 -0
  36. package/src/core/engines/catalog.js +83 -0
  37. package/src/core/engines/gemini.js +28 -11
  38. package/src/core/engines/index.js +11 -1
  39. package/src/core/{tools → http-tools}/browser.js +0 -1
  40. package/src/core/{tools → http-tools}/fetch.js +0 -1
  41. package/src/core/{tools → http-tools}/glob.js +0 -1
  42. package/src/core/{tools → http-tools}/grep.js +0 -1
  43. package/src/core/{tools → http-tools}/registry.js +0 -1
  44. package/src/core/{tools → http-tools}/search.js +0 -1
  45. package/src/core/i18n/en.js +9 -0
  46. package/src/core/i18n/es.js +12 -0
  47. package/src/core/i18n/index.js +54 -0
  48. package/src/core/i18n/pt.js +9 -0
  49. package/src/core/identity/telegram.js +2 -1
  50. package/src/core/mcp/runner.js +272 -14
  51. package/src/core/mcp/sources.js +3 -2
  52. package/src/core/routines/index.js +16 -0
  53. package/src/{host/daemon/routines.js → core/routines/runner.js} +36 -103
  54. package/src/core/runtime-skills/apc-context/SKILL.md +159 -0
  55. package/src/core/runtime-skills/apx/SKILL.md +95 -0
  56. package/src/core/runtime-skills/apx-mcp/SKILL.md +116 -0
  57. package/src/core/runtime-skills/{claude-code.md → claude-code/SKILL.md} +1 -0
  58. package/src/core/runtime-skills/{codex-cli.md → codex-cli/SKILL.md} +1 -0
  59. package/src/core/runtime-skills/{opencode-cli.md → opencode-cli/SKILL.md} +1 -0
  60. package/src/core/runtime-skills/{openrouter.md → openrouter/SKILL.md} +1 -0
  61. package/src/{host/daemon/env-detect.js → core/runtimes/detect.js} +1 -1
  62. package/src/core/stores/code-sessions.js +50 -2
  63. package/src/core/stores/routine-memory.js +1 -1
  64. package/src/core/stores/sessions-search.js +121 -0
  65. package/src/core/stores/sessions.js +38 -0
  66. package/src/core/vars/index.js +14 -0
  67. package/src/core/vars/interpolate.js +86 -0
  68. package/src/core/vars/sources.js +151 -0
  69. package/src/core/voice/audio-decode.js +38 -0
  70. package/src/core/voice/transcription.js +225 -0
  71. package/src/host/daemon/api/admin-config.js +5 -82
  72. package/src/host/daemon/api/agents.js +5 -5
  73. package/src/host/daemon/api/code.js +17 -169
  74. package/src/host/daemon/api/config.js +3 -4
  75. package/src/host/daemon/api/conversations.js +8 -29
  76. package/src/host/daemon/api/deck.js +37 -404
  77. package/src/host/daemon/api/engines.js +1 -50
  78. package/src/host/daemon/api/exec.js +1 -1
  79. package/src/host/daemon/api/mcps.js +32 -0
  80. package/src/host/daemon/api/routines.js +1 -1
  81. package/src/host/daemon/api/runtimes.js +4 -3
  82. package/src/host/daemon/api/sessions-search.js +24 -140
  83. package/src/host/daemon/api/sessions.js +12 -30
  84. package/src/host/daemon/api/shared.js +2 -1
  85. package/src/host/daemon/api/telegram.js +1 -11
  86. package/src/host/daemon/api/tools.js +6 -6
  87. package/src/host/daemon/api/transcribe.js +2 -2
  88. package/src/host/daemon/api/vars.js +137 -0
  89. package/src/host/daemon/api/voice.js +13 -290
  90. package/src/host/daemon/api.js +2 -0
  91. package/src/host/daemon/db.js +6 -6
  92. package/src/host/daemon/deck-exec.js +148 -0
  93. package/src/host/daemon/index.js +3 -3
  94. package/src/host/daemon/plugins/telegram/index.js +24 -687
  95. package/src/host/daemon/routines-scheduler.js +64 -0
  96. package/src/host/daemon/smoke.js +3 -2
  97. package/src/host/daemon/whisper-server.js +225 -0
  98. package/src/interfaces/cli/commands/agent.js +3 -2
  99. package/src/interfaces/cli/commands/command.js +2 -3
  100. package/src/interfaces/cli/commands/messages.js +6 -2
  101. package/src/interfaces/cli/commands/pair.js +5 -4
  102. package/src/interfaces/cli/commands/search.js +1 -1
  103. package/src/interfaces/cli/commands/sessions.js +3 -2
  104. package/src/interfaces/cli/commands/skills.js +36 -55
  105. package/src/interfaces/web/dist/assets/index-DdmSRtsz.css +1 -0
  106. package/src/interfaces/web/dist/assets/index-M4FspaCH.js +613 -0
  107. package/src/interfaces/web/dist/assets/index-M4FspaCH.js.map +1 -0
  108. package/src/interfaces/web/dist/index.html +2 -2
  109. package/src/interfaces/web/package-lock.json +182 -182
  110. package/src/interfaces/web/src/components/ModelCombobox.tsx +44 -8
  111. package/src/interfaces/web/src/components/TelegramChannelDialog.tsx +1 -1
  112. package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +76 -0
  113. package/src/interfaces/web/src/components/chat/MessageBubble.tsx +16 -3
  114. package/src/interfaces/web/src/components/chat/MessageList.tsx +23 -1
  115. package/src/interfaces/web/src/components/chat/ModelPicker.tsx +3 -1
  116. package/src/interfaces/web/src/components/code/CodeArtifactsTab.tsx +4 -4
  117. package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +1 -1
  118. package/src/interfaces/web/src/components/code/CodeFileTree.tsx +3 -2
  119. package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +3 -2
  120. package/src/interfaces/web/src/components/code/CodeTerminal.tsx +3 -2
  121. package/src/interfaces/web/src/components/config/GlobalConfigEditor.tsx +2 -1
  122. package/src/interfaces/web/src/components/deck/WidgetRow.tsx +2 -1
  123. package/src/interfaces/web/src/components/inputs/KeyValueList.tsx +93 -0
  124. package/src/interfaces/web/src/components/inputs/VarTokenInput.tsx +449 -0
  125. package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +2 -1
  126. package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +2 -2
  127. package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +5 -4
  128. package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +3 -2
  129. package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +3 -2
  130. package/src/interfaces/web/src/components/ui/chat-input.tsx +5 -4
  131. package/src/interfaces/web/src/components/ui/sidebar.tsx +3 -2
  132. package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +2 -1
  133. package/src/interfaces/web/src/constants/index.ts +1 -1
  134. package/src/interfaces/web/src/i18n/en.ts +174 -7
  135. package/src/interfaces/web/src/i18n/es.ts +179 -15
  136. package/src/interfaces/web/src/lib/api/mcps.ts +25 -0
  137. package/src/interfaces/web/src/lib/api/vars.ts +38 -0
  138. package/src/interfaces/web/src/lib/api.ts +1 -0
  139. package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -31
  140. package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +1 -1
  141. package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +4 -3
  142. package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +7 -6
  143. package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +4 -3
  144. package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +1 -1
  145. package/src/interfaces/web/src/screens/project/ConfigTab.tsx +132 -1
  146. package/src/interfaces/web/src/screens/project/McpsTab.tsx +549 -104
  147. package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +1 -1
  148. package/src/interfaces/web/src/screens/project/VarsTab.tsx +300 -0
  149. package/src/interfaces/web/src/types/daemon.ts +5 -0
  150. package/src/host/daemon/transcription.js +0 -538
  151. package/src/host/daemon/whisper-transcribe.py +0 -73
  152. package/src/interfaces/web/dist/assets/index-7dVT2O1S.css +0 -1
  153. package/src/interfaces/web/dist/assets/index-DWsE_8Nz.js +0 -602
  154. package/src/interfaces/web/dist/assets/index-DWsE_8Nz.js.map +0 -1
  155. /package/src/{host/daemon → core/apc}/projects-helpers.js +0 -0
  156. /package/src/{host/daemon/plugins → core/channels}/telegram/ask.js +0 -0
  157. /package/src/{host/daemon/plugins → core/channels}/telegram/media.js +0 -0
  158. /package/src/core/{tools → http-tools}/index.js +0 -0
  159. /package/{skills → src/core/runtime-skills}/apx-agency-agents/SKILL.md +0 -0
  160. /package/{skills → src/core/runtime-skills}/apx-agent/SKILL.md +0 -0
  161. /package/{skills → src/core/runtime-skills}/apx-mcp-builder/SKILL.md +0 -0
  162. /package/{skills → src/core/runtime-skills}/apx-project/SKILL.md +0 -0
  163. /package/{skills → src/core/runtime-skills}/apx-routine/SKILL.md +0 -0
  164. /package/{skills → src/core/runtime-skills}/apx-runtime/SKILL.md +0 -0
  165. /package/{skills → src/core/runtime-skills}/apx-sessions/SKILL.md +0 -0
  166. /package/{skills → src/core/runtime-skills}/apx-skill-builder/SKILL.md +0 -0
  167. /package/{skills → src/core/runtime-skills}/apx-task/SKILL.md +0 -0
  168. /package/{skills → src/core/runtime-skills}/apx-telegram/SKILL.md +0 -0
  169. /package/{skills → src/core/runtime-skills}/apx-voice/SKILL.md +0 -0
  170. /package/src/{host/daemon/compact.js → core/stores/conversations-compactor.js} +0 -0
  171. /package/src/{host/daemon → core/stores}/conversations.js +0 -0
  172. /package/src/{host/daemon → core/util}/thinking.js +0 -0
@@ -11,12 +11,22 @@ import {
11
11
  } from "./parser.js";
12
12
  import { readApcContextSkill } from "./skill-sync.js";
13
13
  import { nowIso } from "../util/time.js";
14
+ import {
15
+ apcDir,
16
+ apcProjectFile,
17
+ apcAgentsDir,
18
+ apcAgentFile,
19
+ agentsMdFile,
20
+ } from "./paths.js";
14
21
 
15
22
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
23
  // Now under src/core/apc/ — one more "../" to escape than before.
17
24
  const PACKAGE_ROOT = path.resolve(__dirname, "..", "..", "..");
25
+ // <packageRoot>/skills/<slug>/SKILL.md — the SLIM engine-side set: every skill
26
+ // here is replicated verbatim into project IDE rule files (`apx skills add`) and
27
+ // into ~/.<host>/skills/ (`apx skills sync`). The rich super-agent catalog lives
28
+ // at src/core/runtime-skills/ and is intentionally NOT copied out.
18
29
  const BUNDLED_SKILLS_DIR = path.join(PACKAGE_ROOT, "skills");
19
- const RUNTIME_SKILLS_DIR = path.join(__dirname, "runtime-skills");
20
30
 
21
31
  export const SPEC_VERSION = "0.1.0";
22
32
 
@@ -26,12 +36,12 @@ export const SPEC_VERSION = "0.1.0";
26
36
  // install/update from the canonical APC repo (see src/interfaces/cli/postinstall.js).
27
37
  // ---------------------------------------------------------------------------
28
38
 
29
- // Bundled skills apx lives in skills/apx/. apc-context is synced from
30
- // the canonical APC repo (../apc or GitHub) never edited in APX.
39
+ // Read one slim skill from <packageRoot>/skills/<slug>/SKILL.md. `apc-context`
40
+ // is special-cased to refresh from the canonical APC repo if available.
31
41
  function readBundledSkill(slug) {
32
42
  if (slug === "apc-context") {
33
43
  const synced = readApcContextSkill();
34
- return synced?.text || null;
44
+ if (synced?.text) return synced.text;
35
45
  }
36
46
  const file = path.join(BUNDLED_SKILLS_DIR, slug, "SKILL.md");
37
47
  if (!fs.existsSync(file)) return null;
@@ -132,19 +142,11 @@ const GLOBAL_SKILL_DIRS = [
132
142
  path.join(os.homedir(), ".agents", "skills"), // Antigravity/other skills.sh adopters
133
143
  ];
134
144
 
135
- function readRuntimeSkillFiles() {
136
- if (!fs.existsSync(RUNTIME_SKILLS_DIR)) return [];
137
- return fs.readdirSync(RUNTIME_SKILLS_DIR)
138
- .filter((name) => name.endsWith(".md"))
139
- .sort()
140
- .map((name) => ({
141
- slug: path.basename(name, ".md"),
142
- md: fs.readFileSync(path.join(RUNTIME_SKILLS_DIR, name), "utf8").trim(),
143
- }));
144
- }
145
-
146
145
  // Install APX + APC context skills into IDE rule files. Returns an array of result objects.
147
146
  // targetIds: array of target ids to install; null = all project targets.
147
+ // Writes the slim engine-side skill from <packageRoot>/skills/. The rich
148
+ // super-agent set in src/core/runtime-skills/ is intentionally never written
149
+ // into project IDE files.
148
150
  export function installIdeSkills(root, targetIds = null) {
149
151
  const apxRaw = readBundledSkill("apx");
150
152
  const apcRaw = readBundledSkill("apc-context");
@@ -195,36 +197,27 @@ export function installIdeSkills(root, targetIds = null) {
195
197
  // on the user's machine after `npm install -g .` (or `npm update -g apx`)
196
198
  // without anyone having to touch this file.
197
199
  //
198
- // Excluded: directory names starting with "." (e.g. .DS_Store), and any
199
- // runtime-only CLI skill that lives under src/core/runtime-skills/ those
200
- // are loaded in-process at daemon startup and are NOT for IDE consumption.
201
- // Public: bundled skill slugs grouped by scope.
202
- // public → pushed to every global skill dir on install / sync (default).
203
- // optional → not pushed by default; user opts in with --include-optional
204
- // or `apx skills add <slug> --global` for one-off install.
205
- // internal → APX-developer skills (mcp-builder, skill-builder, etc.); never
206
- // pushed globally, only available to APX itself via the bundled
207
- // copy. Avoids cluttering other IDEs with stuff their users won't
208
- // run.
200
+ // Excluded: directory names starting with "." (e.g. .DS_Store).
201
+ // Every slug under <packageRoot>/skills/ is part of the slim engine set and
202
+ // gets pushed to global dirs on `apx skills sync`. No scope filtering — the
203
+ // dir IS the contract.
209
204
  export function listBundledSkillSlugs() {
210
205
  return discoverBundledSkills().map((s) => s.slug);
211
206
  }
212
207
 
213
208
  export function listBundledSkills() {
214
- return discoverBundledSkills().map(({ slug, scope }) => ({ slug, scope }));
209
+ return discoverBundledSkills().map(({ slug }) => ({ slug }));
210
+ }
211
+
212
+ // Backwards-compat alias — every bundled slug here IS an engine slug now.
213
+ export function listEngineSkills() {
214
+ return listBundledSkills();
215
215
  }
216
216
 
217
- // Tiny frontmatter peek we only need the `scope:` field. Avoids pulling in
218
- // a full YAML parser for one optional line.
219
- function parseFrontmatterScope(md) {
220
- if (!md.startsWith("---\n")) return "public";
221
- const end = md.indexOf("\n---", 4);
222
- if (end === -1) return "public";
223
- const m = md.slice(4, end).match(/^scope:\s*(\w+)/m);
224
- if (!m) return "public";
225
- const s = m[1].toLowerCase();
226
- if (s === "internal" || s === "optional" || s === "public") return s;
227
- return "public";
217
+ // Legacy slugs APX used to ship to global dirs but no longer does — exposed so
218
+ // the CLI can report what `installGlobalSkills` will prune.
219
+ export function listLegacyPruneSlugs() {
220
+ return [...PRUNE_LEGACY_SLUGS];
228
221
  }
229
222
 
230
223
  function discoverBundledSkills() {
@@ -237,65 +230,80 @@ function discoverBundledSkills() {
237
230
  const skillFile = path.join(root, entry.name, "SKILL.md");
238
231
  if (!fs.existsSync(skillFile)) continue;
239
232
  const md = fs.readFileSync(skillFile, "utf8");
240
- out.push({ slug: entry.name, md, scope: parseFrontmatterScope(md) });
233
+ out.push({ slug: entry.name, md });
241
234
  }
242
235
  return out.sort((a, b) => a.slug.localeCompare(b.slug));
243
236
  }
244
237
 
245
- // Install bundled skills to every global ~/.../skills/ dir so Claude Code,
246
- // Cursor, Codex, and other IDEs see them.
238
+ // Install the slim engine skill set to every global ~/.../skills/ dir
239
+ // (Claude Code, Cursor, Codex, Antigravity/skills.sh). External engines only
240
+ // need to know how to talk TO apx — not the full APX sub-skill catalog. The
241
+ // rich bundled set in skills/<slug>/ stays in-repo for the APX super-agent.
242
+ //
243
+ // The set lives at skills/engines/<slug>/SKILL.md and is currently:
244
+ // apx, apx-mcp, apc-context.
247
245
  //
248
- // By default only `scope: public` skills land globally. Pass
249
- // includeOptional / includeInternal to push the other tiers (or call
250
- // `apx skills add <slug> --global` for a single one).
246
+ // `includeOptional` / `includeInternal` are kept as no-op flags for backward
247
+ // compatibility with `apx skills sync --include-…`; the slim set has no tiers.
251
248
  //
252
- // Pruning: if a slug that was previously installed has since been demoted to
253
- // internal/optional (or marked as non-public for the current call), we remove
254
- // the stale global copy unless prune=false. Keeps IDE skill lists clean.
249
+ // Pruning: removes stale APX-shipped slugs that are no longer in the engine
250
+ // set (the catalog of slugs APX has ever published, see PRUNE_LEGACY_SLUGS).
251
+ // Skills the user installed themselves are NOT touched.
255
252
  //
256
253
  // Returns an array of { dir, skill, file, status, scope }.
257
- // status ∈ {created, updated, unchanged, pruned, skipped}
254
+ // status ∈ {created, updated, unchanged, pruned}
255
+ const PRUNE_LEGACY_SLUGS = [
256
+ "apx-agency-agents",
257
+ "apx-agent",
258
+ "apx-mcp-builder",
259
+ "apx-project",
260
+ "apx-routine",
261
+ "apx-runtime",
262
+ "apx-sessions",
263
+ "apx-skill-builder",
264
+ "apx-task",
265
+ "apx-telegram",
266
+ "apx-voice",
267
+ // Runtime CLI docs that previously leaked into global dirs — these are
268
+ // loaded in-process by the daemon and should NOT live on disk in IDE skill
269
+ // dirs.
270
+ "claude-code",
271
+ "codex-cli",
272
+ "opencode-cli",
273
+ "openrouter",
274
+ ];
275
+
258
276
  export function installGlobalSkills({
259
- includeOptional = false,
260
- includeInternal = false,
261
277
  prune = true,
278
+ // No-ops kept for CLI backward compatibility (the slim engine set has no tiers).
279
+ includeOptional: _includeOptional = false,
280
+ includeInternal: _includeInternal = false,
262
281
  } = {}) {
263
- const all = discoverBundledSkills();
264
- const wanted = all.filter((s) => {
265
- if (s.scope === "internal") return includeInternal;
266
- if (s.scope === "optional") return includeOptional;
267
- return true; // public
268
- });
282
+ const wanted = discoverBundledSkills();
269
283
  const wantedSlugs = new Set(wanted.map((s) => s.slug));
270
- const knownSlugs = new Set(all.map((s) => s.slug));
271
284
 
272
285
  const results = [];
273
286
  for (const base of GLOBAL_SKILL_DIRS) {
274
- // Push the wanted set.
275
- for (const { slug, md, scope } of wanted) {
287
+ for (const { slug, md } of wanted) {
276
288
  const dest = path.join(base, slug, "SKILL.md");
277
289
  fs.mkdirSync(path.dirname(dest), { recursive: true });
278
290
  const existed = fs.existsSync(dest);
279
291
  const previous = existed ? fs.readFileSync(dest, "utf8") : null;
280
292
  if (previous === md) {
281
- results.push({ dir: base, skill: slug, file: dest, status: "unchanged", scope });
293
+ results.push({ dir: base, skill: slug, file: dest, status: "unchanged", scope: "engine" });
282
294
  continue;
283
295
  }
284
296
  fs.writeFileSync(dest, md, "utf8");
285
- results.push({ dir: base, skill: slug, file: dest, status: existed ? "updated" : "created", scope });
297
+ results.push({ dir: base, skill: slug, file: dest, status: existed ? "updated" : "created", scope: "engine" });
286
298
  }
287
- // Prune anything WE shipped previously but should no longer be there
288
- // (slug exists in the bundle but isn't `wanted` this run).
289
299
  if (prune) {
290
- for (const { slug, scope } of all) {
300
+ for (const slug of PRUNE_LEGACY_SLUGS) {
291
301
  if (wantedSlugs.has(slug)) continue;
292
- if (!knownSlugs.has(slug)) continue;
293
302
  const dest = path.join(base, slug, "SKILL.md");
294
303
  if (!fs.existsSync(dest)) continue;
295
304
  fs.unlinkSync(dest);
296
- // Best-effort: drop the now-empty <slug>/ dir too.
297
305
  try { fs.rmdirSync(path.dirname(dest)); } catch {}
298
- results.push({ dir: base, skill: slug, file: dest, status: "pruned", scope });
306
+ results.push({ dir: base, skill: slug, file: dest, status: "pruned", scope: "legacy" });
299
307
  }
300
308
  }
301
309
  }
@@ -421,7 +429,7 @@ function writeMigrateMd(apfDir, found) {
421
429
  // Get the stable APX storage ID for a project, generating one if it doesn't exist.
422
430
  // Called by the daemon when registering a project.
423
431
  export function getOrCreateApxId(root) {
424
- const p = path.join(root, ".apc", "project.json");
432
+ const p = apcProjectFile(root);
425
433
  if (!fs.existsSync(p)) return null;
426
434
  let cfg;
427
435
  try { cfg = JSON.parse(fs.readFileSync(p, "utf8")); } catch { return null; }
@@ -437,7 +445,7 @@ export function initApf(directory, { name } = {}) {
437
445
  const root = path.resolve(directory);
438
446
  fs.mkdirSync(root, { recursive: true });
439
447
 
440
- const apfDir = path.join(root, ".apc");
448
+ const apfDir = apcDir(root);
441
449
  fs.mkdirSync(path.join(apfDir, "agents"), { recursive: true });
442
450
  fs.mkdirSync(path.join(apfDir, "skills"), { recursive: true });
443
451
  fs.mkdirSync(path.join(apfDir, "commands"), { recursive: true });
@@ -467,7 +475,7 @@ export function initApf(directory, { name } = {}) {
467
475
  fs.writeFileSync(gitignore, APC_GITIGNORE);
468
476
  }
469
477
 
470
- const agentsMd = path.join(root, "AGENTS.md");
478
+ const agentsMd = agentsMdFile(root);
471
479
  if (!fs.existsSync(agentsMd)) {
472
480
  fs.writeFileSync(agentsMd, AGENTS_MD_TEMPLATE);
473
481
  }
@@ -483,13 +491,13 @@ export function initApf(directory, { name } = {}) {
483
491
  }
484
492
 
485
493
  export function ensureAgentDir(root, slug) {
486
- fs.mkdirSync(path.join(root, ".apc", "agents"), { recursive: true });
487
- return path.join(root, ".apc", "agents");
494
+ fs.mkdirSync(apcAgentsDir(root), { recursive: true });
495
+ return apcAgentsDir(root);
488
496
  }
489
497
 
490
498
  // Write .apc/agents/<slug>.md — the canonical agent definition file.
491
499
  export function writeAgentFile(root, slug, fields, body = "") {
492
- const dest = path.join(root, ".apc", "agents", `${slug}.md`);
500
+ const dest = apcAgentFile(root, slug);
493
501
  const lines = ["---"];
494
502
  const order = ["role", "model", "language", "description", "skills", "tools"];
495
503
  const written = new Set();
@@ -577,7 +585,7 @@ export function restoreVaultAgent(slug) {
577
585
 
578
586
  // Add a slug to the project's agents.imported list in project.json
579
587
  export function addImportedAgent(root, slug) {
580
- const p = path.join(root, ".apc", "project.json");
588
+ const p = apcProjectFile(root);
581
589
  let cfg = {};
582
590
  try { cfg = JSON.parse(fs.readFileSync(p, "utf8")); } catch {}
583
591
  if (!cfg.agents) cfg.agents = {};
@@ -4,9 +4,14 @@ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
6
6
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
- export const PACKAGE_ROOT = path.resolve(__dirname, "..", "..");
7
+ // __dirname is src/core/apc/ after the Phase 3 move (was src/core/ before).
8
+ // Repo root is three levels up, not two.
9
+ export const PACKAGE_ROOT = path.resolve(__dirname, "..", "..", "..");
8
10
 
11
+ // Engine-side slim copy (replicated to ~/.<host>/skills/ by apx skills sync).
9
12
  export const APC_SKILL_REL = path.join("skills", "apc-context", "SKILL.md");
13
+ // Runtime-internal copy (loaded by the super-agent — never published outside).
14
+ export const APC_BUILTIN_SKILL_REL = path.join("src", "core", "runtime-skills", "apc-context", "SKILL.md");
10
15
  export const APC_SKILL_REMOTE =
11
16
  "https://raw.githubusercontent.com/agentprojectcontext/agentprojectcontext/main/skills/apc-context/SKILL.md";
12
17
 
@@ -93,5 +98,12 @@ export async function refreshApcContextSkill({ packageRoot = PACKAGE_ROOT, timeo
93
98
 
94
99
  fs.mkdirSync(path.dirname(dest), { recursive: true });
95
100
  fs.writeFileSync(dest, text, "utf8");
101
+
102
+ // Keep the runtime-internal copy (src/core/runtime-skills/apc-context/) in
103
+ // sync — that's where the super-agent loads it from.
104
+ const builtinDest = path.join(packageRoot, APC_BUILTIN_SKILL_REL);
105
+ fs.mkdirSync(path.dirname(builtinDest), { recursive: true });
106
+ fs.writeFileSync(builtinDest, text, "utf8");
107
+
96
108
  return { ok: true, source, refreshed: true };
97
109
  }