@gajae-code/coding-agent 0.16.7 → 0.17.1

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 (321) hide show
  1. package/CHANGELOG.md +180 -1
  2. package/dist/types/capability/fs.d.ts +37 -4
  3. package/dist/types/capability/index.d.ts +19 -0
  4. package/dist/types/capability/types.d.ts +9 -0
  5. package/dist/types/cli/doctor/args.d.ts +36 -0
  6. package/dist/types/cli/doctor/checks.d.ts +18 -0
  7. package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
  8. package/dist/types/cli/doctor/context.d.ts +89 -0
  9. package/dist/types/cli/doctor/files.d.ts +27 -0
  10. package/dist/types/cli/doctor/ids.d.ts +20 -0
  11. package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
  12. package/dist/types/cli/doctor/journal.d.ts +43 -0
  13. package/dist/types/cli/doctor/managed-link.d.ts +39 -0
  14. package/dist/types/cli/doctor/native-probe.d.ts +2 -0
  15. package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
  16. package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
  17. package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
  18. package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
  19. package/dist/types/cli/doctor/probe-client.d.ts +9 -0
  20. package/dist/types/cli/doctor/probe-types.d.ts +18 -0
  21. package/dist/types/cli/doctor/probe.d.ts +3 -0
  22. package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
  23. package/dist/types/cli/doctor/repairs.d.ts +28 -0
  24. package/dist/types/cli/doctor/report.d.ts +27 -0
  25. package/dist/types/cli/doctor/runner.d.ts +4 -0
  26. package/dist/types/cli/doctor/safety.d.ts +10 -0
  27. package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
  28. package/dist/types/cli/doctor/service-targets.d.ts +41 -0
  29. package/dist/types/cli/doctor/types.d.ts +145 -0
  30. package/dist/types/cli/doctor-cli.d.ts +7 -0
  31. package/dist/types/cli/doctor-supervisor.d.ts +121 -0
  32. package/dist/types/cli/doctor-worker.d.ts +29 -0
  33. package/dist/types/cli/install-activation.d.ts +158 -0
  34. package/dist/types/cli/macos-community-app.d.ts +41 -0
  35. package/dist/types/cli/mcp-cli.d.ts +0 -11
  36. package/dist/types/cli/update-cli.d.ts +41 -4
  37. package/dist/types/cli-main.d.ts +174 -0
  38. package/dist/types/cli.d.ts +1 -171
  39. package/dist/types/commands/doctor.d.ts +7 -0
  40. package/dist/types/commands/sdk.d.ts +17 -8
  41. package/dist/types/config/autorouting-tier-map.d.ts +19 -0
  42. package/dist/types/config/file-lock.d.ts +27 -3
  43. package/dist/types/config/model-preset-registry.d.ts +1 -0
  44. package/dist/types/config/model-registry.d.ts +12 -5
  45. package/dist/types/config/model-resolver.d.ts +16 -3
  46. package/dist/types/config/models-config-schema.d.ts +2 -0
  47. package/dist/types/config/settings-schema.d.ts +1 -1
  48. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
  49. package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
  50. package/dist/types/cursor.d.ts +9 -9
  51. package/dist/types/discovery/agents-md.d.ts +6 -1
  52. package/dist/types/discovery/helpers.d.ts +36 -7
  53. package/dist/types/discovery/index.d.ts +1 -1
  54. package/dist/types/discovery/mcp-json.d.ts +2 -0
  55. package/dist/types/extensibility/extensions/loader.d.ts +22 -1
  56. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
  57. package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
  58. package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
  59. package/dist/types/extensibility/plugins/manager.d.ts +33 -4
  60. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
  61. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
  62. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
  63. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
  64. package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
  65. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
  66. package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
  67. package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
  68. package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
  69. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
  70. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
  71. package/dist/types/main.d.ts +19 -1
  72. package/dist/types/modes/acp/acp-agent.d.ts +40 -0
  73. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  74. package/dist/types/modes/components/model-selector.d.ts +2 -0
  75. package/dist/types/modes/interactive-mode.d.ts +1 -1
  76. package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
  77. package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
  78. package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
  79. package/dist/types/runtime-mcp/types.d.ts +2 -2
  80. package/dist/types/sdk/acp/adapter.d.ts +5 -1
  81. package/dist/types/sdk/broker/broker.d.ts +51 -0
  82. package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
  83. package/dist/types/sdk/broker/discovery.d.ts +38 -0
  84. package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
  85. package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
  86. package/dist/types/sdk/broker/ensure.d.ts +14 -0
  87. package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
  88. package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
  89. package/dist/types/sdk/broker/runtime.d.ts +26 -0
  90. package/dist/types/sdk/broker/session-index.d.ts +13 -4
  91. package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
  95. package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
  96. package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
  97. package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
  98. package/dist/types/sdk/bus/index.d.ts +2 -0
  99. package/dist/types/sdk/bus/notification-service.d.ts +3 -0
  100. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
  101. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  102. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
  103. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
  104. package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
  105. package/dist/types/sdk/cli/session-cli.d.ts +1 -0
  106. package/dist/types/sdk/host/session-runtime.d.ts +4 -0
  107. package/dist/types/sdk/host/surface-policy.d.ts +3 -1
  108. package/dist/types/sdk/lifecycle/service.d.ts +44 -10
  109. package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
  110. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
  111. package/dist/types/sdk/prompt-failure.d.ts +47 -0
  112. package/dist/types/sdk/prompt-status.d.ts +19 -0
  113. package/dist/types/sdk/router/session-router.d.ts +3 -4
  114. package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
  115. package/dist/types/sdk/session-authority.d.ts +9 -0
  116. package/dist/types/sdk/session.d.ts +3 -1
  117. package/dist/types/session/agent-session.d.ts +1 -1
  118. package/dist/types/session/blob-store.d.ts +1 -1
  119. package/dist/types/session/fallback-chain-controller.d.ts +3 -6
  120. package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
  121. package/dist/types/session/primary-control-surface.d.ts +4 -0
  122. package/dist/types/session/session-manager.d.ts +6 -0
  123. package/dist/types/system-prompt.d.ts +6 -0
  124. package/dist/types/tools/ask.d.ts +25 -0
  125. package/dist/types/tools/image-gen.d.ts +0 -4
  126. package/dist/types/tools/skill-discovery.d.ts +7 -5
  127. package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
  128. package/dist/types/utils/changelog.d.ts +0 -9
  129. package/dist/types/utils/mupdf-wasm.d.ts +1 -0
  130. package/package.json +9 -8
  131. package/scripts/compile-args.ts +8 -4
  132. package/src/capability/fs.ts +395 -17
  133. package/src/capability/index.ts +273 -10
  134. package/src/capability/types.ts +9 -0
  135. package/src/cli/customize-doctor.ts +18 -12
  136. package/src/cli/doctor/args.ts +236 -0
  137. package/src/cli/doctor/checks.ts +431 -0
  138. package/src/cli/doctor/config-repairs.ts +517 -0
  139. package/src/cli/doctor/context.ts +149 -0
  140. package/src/cli/doctor/files.ts +149 -0
  141. package/src/cli/doctor/ids.ts +115 -0
  142. package/src/cli/doctor/install-repairs.ts +335 -0
  143. package/src/cli/doctor/journal.ts +423 -0
  144. package/src/cli/doctor/managed-link.ts +514 -0
  145. package/src/cli/doctor/native-probe.ts +13 -0
  146. package/src/cli/doctor/permission-repairs.ts +242 -0
  147. package/src/cli/doctor/plugin-quarantine.ts +377 -0
  148. package/src/cli/doctor/plugin-restore.ts +59 -0
  149. package/src/cli/doctor/plugin-targets.ts +373 -0
  150. package/src/cli/doctor/probe-client.ts +195 -0
  151. package/src/cli/doctor/probe-types.ts +21 -0
  152. package/src/cli/doctor/probe.ts +42 -0
  153. package/src/cli/doctor/projection-probe.ts +249 -0
  154. package/src/cli/doctor/repairs.ts +1157 -0
  155. package/src/cli/doctor/report.ts +176 -0
  156. package/src/cli/doctor/runner.ts +342 -0
  157. package/src/cli/doctor/safety.ts +40 -0
  158. package/src/cli/doctor/service-repairs.ts +452 -0
  159. package/src/cli/doctor/service-targets.ts +274 -0
  160. package/src/cli/doctor/types.ts +164 -0
  161. package/src/cli/doctor-cli.ts +62 -0
  162. package/src/cli/doctor-supervisor.ts +571 -0
  163. package/src/cli/doctor-worker.ts +181 -0
  164. package/src/cli/install-activation.ts +666 -0
  165. package/src/cli/macos-community-app.ts +1449 -0
  166. package/src/cli/mcp-cli.ts +11 -21
  167. package/src/cli/nofile-limit.ts +5 -1
  168. package/src/cli/plugin-cli.ts +6 -1
  169. package/src/cli/update-cli.ts +362 -264
  170. package/src/cli-main.ts +517 -0
  171. package/src/cli.ts +64 -433
  172. package/src/commands/autoresearch.ts +11 -5
  173. package/src/commands/completion.ts +1 -1
  174. package/src/commands/doctor.ts +13 -0
  175. package/src/commands/sdk.ts +58 -10
  176. package/src/commands/ultragoal.ts +11 -5
  177. package/src/config/autorouting-tier-map.ts +7 -0
  178. package/src/config/file-lock.ts +736 -71
  179. package/src/config/mcp-schema.json +3 -3
  180. package/src/config/model-preset-registry.ts +1 -0
  181. package/src/config/model-registry.ts +80 -27
  182. package/src/config/model-resolver.ts +33 -4
  183. package/src/config/models-config-schema.ts +2 -0
  184. package/src/config/settings-schema.ts +6 -2
  185. package/src/coordinator-mcp/question-gate-codec.ts +1 -0
  186. package/src/coordinator-mcp/server.ts +534 -51
  187. package/src/coordinator-mcp/session-reaper.ts +64 -8
  188. package/src/cursor.ts +223 -53
  189. package/src/discovery/agents-md.ts +74 -8
  190. package/src/discovery/agents.ts +32 -7
  191. package/src/discovery/builtin.ts +184 -75
  192. package/src/discovery/claude-plugins.ts +85 -17
  193. package/src/discovery/cline.ts +38 -10
  194. package/src/discovery/cursor.ts +19 -6
  195. package/src/discovery/gemini.ts +62 -22
  196. package/src/discovery/github.ts +13 -3
  197. package/src/discovery/helpers.ts +483 -89
  198. package/src/discovery/index.ts +1 -0
  199. package/src/discovery/mcp-json.ts +36 -10
  200. package/src/discovery/opencode.ts +36 -19
  201. package/src/discovery/ssh.ts +11 -8
  202. package/src/discovery/windsurf.ts +12 -3
  203. package/src/exec/bash-executor.ts +10 -3
  204. package/src/exec/isolated-shell.ts +15 -2
  205. package/src/extensibility/extensions/loader.ts +88 -26
  206. package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
  207. package/src/extensibility/gjc-plugins/paths.ts +4 -1
  208. package/src/extensibility/gjc-plugins/types.ts +27 -0
  209. package/src/extensibility/plugins/manager.ts +200 -22
  210. package/src/extensibility/plugins/marketplace/cache.ts +55 -2
  211. package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
  212. package/src/extensibility/plugins/marketplace/registry.ts +153 -0
  213. package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
  214. package/src/extensibility/runtime-skill-discovery.ts +61 -9
  215. package/src/extensibility/skill-management.ts +7 -1
  216. package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
  217. package/src/gjc-runtime/launch-worktree.test.ts +248 -0
  218. package/src/gjc-runtime/launch-worktree.ts +275 -38
  219. package/src/gjc-runtime/repository-binding.ts +26 -1
  220. package/src/gjc-runtime/session-layout.ts +10 -0
  221. package/src/gjc-runtime/session-state-lock.ts +330 -23
  222. package/src/gjc-runtime/session-state-sidecar.ts +328 -80
  223. package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
  224. package/src/harness-control-plane/session-lease.ts +2 -2
  225. package/src/internal-urls/docs-index.generated.ts +28 -26
  226. package/src/main.ts +150 -29
  227. package/src/memories/index.ts +24 -2
  228. package/src/modes/acp/acp-agent.ts +522 -68
  229. package/src/modes/components/agent-dashboard.ts +3 -1
  230. package/src/modes/components/model-selector.ts +28 -19
  231. package/src/modes/components/plugin-settings.ts +2 -1
  232. package/src/modes/controllers/selector-controller.ts +15 -9
  233. package/src/modes/interactive-mode.ts +21 -3
  234. package/src/prompts/system/system-prompt.md +5 -1
  235. package/src/prompts/tools/browser.md +1 -1
  236. package/src/prompts/tools/move-session.md +4 -0
  237. package/src/prompts/tools/read.md +2 -1
  238. package/src/prompts/tools/skill-discovery.md +6 -5
  239. package/src/prompts/tools/task.md +1 -0
  240. package/src/runtime-mcp/config-writer.ts +228 -0
  241. package/src/runtime-mcp/oauth-discovery.ts +114 -14
  242. package/src/runtime-mcp/policy-json-edit.ts +129 -0
  243. package/src/runtime-mcp/startup-policy.ts +14 -0
  244. package/src/runtime-mcp/types.ts +2 -2
  245. package/src/sdk/acp/adapter.ts +27 -12
  246. package/src/sdk/broker/broker.ts +273 -44
  247. package/src/sdk/broker/daemon-entry.ts +119 -0
  248. package/src/sdk/broker/discovery.ts +173 -20
  249. package/src/sdk/broker/doctor-restart.ts +206 -0
  250. package/src/sdk/broker/endpoint-authority.ts +36 -0
  251. package/src/sdk/broker/ensure.ts +49 -14
  252. package/src/sdk/broker/lifecycle.ts +174 -42
  253. package/src/sdk/broker/process-incarnation.ts +86 -2
  254. package/src/sdk/broker/runtime.ts +145 -21
  255. package/src/sdk/broker/session-index.ts +136 -22
  256. package/src/sdk/broker/spawn-substrate.ts +4 -1
  257. package/src/sdk/broker/transport.ts +5 -0
  258. package/src/sdk/broker/worktree-occupancy.ts +21 -1
  259. package/src/sdk/bus/chat-daemon-cli.ts +63 -0
  260. package/src/sdk/bus/chat-daemon-control.ts +260 -64
  261. package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
  262. package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
  263. package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
  264. package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
  265. package/src/sdk/bus/index.ts +252 -51
  266. package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
  267. package/src/sdk/bus/notification-service.ts +21 -3
  268. package/src/sdk/bus/reconciliation-store.ts +17 -11
  269. package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
  270. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  271. package/src/sdk/bus/telegram-daemon-control.ts +47 -0
  272. package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
  273. package/src/sdk/bus/telegram-daemon.ts +178 -13
  274. package/src/sdk/cli/session-cli.ts +100 -12
  275. package/src/sdk/host/host.ts +2 -7
  276. package/src/sdk/host/session-runtime.test.ts +329 -8
  277. package/src/sdk/host/session-runtime.ts +202 -50
  278. package/src/sdk/host/surface-policy.ts +8 -1
  279. package/src/sdk/lifecycle/service.ts +199 -22
  280. package/src/sdk/mcp/server.ts +1 -1
  281. package/src/sdk/prompt-deadline-lease.ts +12 -4
  282. package/src/sdk/prompt-deadline-manager.ts +5 -7
  283. package/src/sdk/prompt-failure.ts +148 -0
  284. package/src/sdk/prompt-status.ts +30 -1
  285. package/src/sdk/prompt-watchdog.ts +11 -3
  286. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  287. package/src/sdk/protocol/operation-registry.ts +20 -8
  288. package/src/sdk/router/session-router.ts +8 -3
  289. package/src/sdk/service-artifact-paths.ts +26 -0
  290. package/src/sdk/session-authority.ts +10 -0
  291. package/src/sdk/session.ts +361 -194
  292. package/src/session/agent-session.ts +398 -93
  293. package/src/session/blob-store.ts +9 -9
  294. package/src/session/fallback-chain-controller.ts +3 -7
  295. package/src/session/internal/managed-session-scope.ts +445 -29
  296. package/src/session/internal/managed-session-storage.ts +38 -6
  297. package/src/session/primary-control-surface.ts +12 -0
  298. package/src/session/session-manager.ts +11 -3
  299. package/src/session/session-storage.ts +1 -1
  300. package/src/session-import/codex.ts +6 -1
  301. package/src/session-import/redact.ts +7 -0
  302. package/src/skill-state/workflow-mutation-guard.ts +645 -39
  303. package/src/slash-commands/builtin-registry.ts +7 -3
  304. package/src/system-prompt.ts +8 -0
  305. package/src/task/executor.ts +36 -3
  306. package/src/task/types.ts +27 -5
  307. package/src/tools/ask.ts +114 -34
  308. package/src/tools/browser/actions.ts +2 -2
  309. package/src/tools/browser/tab-worker.ts +11 -8
  310. package/src/tools/descriptors.ts +6 -1
  311. package/src/tools/fetch.ts +7 -2
  312. package/src/tools/image-gen.ts +33 -34
  313. package/src/tools/read.ts +78 -32
  314. package/src/tools/skill-discovery.ts +17 -7
  315. package/src/tools/tool-catalog.generated.ts +8 -8
  316. package/src/tools/ultragoal-ask-guard.ts +16 -26
  317. package/src/utils/changelog.ts +7 -1
  318. package/src/utils/git.ts +3 -1
  319. package/src/utils/markit.ts +24 -2
  320. package/src/utils/mupdf-wasm.ts +26 -0
  321. package/src/web/search/providers/openai-compatible.ts +191 -14
@@ -10,7 +10,7 @@ import { registerProvider } from "../capability";
10
10
  import { type ContextFile, contextFileCapability } from "../capability/context-file";
11
11
  import { type Extension, type ExtensionManifest, extensionCapability } from "../capability/extension";
12
12
  import { type ExtensionModule, extensionModuleCapability } from "../capability/extension-module";
13
- import { readDirEntries, readFile } from "../capability/fs";
13
+ import { isSingleLinkRegularFileAt, type ReadScope, readDirEntries, readFile } from "../capability/fs";
14
14
  import { type Hook, hookCapability } from "../capability/hook";
15
15
  import { type Instruction, instructionCapability } from "../capability/instruction";
16
16
  import { type MCPServer, mcpCapability } from "../capability/mcp";
@@ -25,11 +25,13 @@ import type { LoadContext, LoadResult } from "../capability/types";
25
25
  import { expandTilde } from "../tools/path-utils";
26
26
  import {
27
27
  buildRuleFromMarkdown,
28
+ canonicalizePathWithinHome,
28
29
  createSourceMeta,
29
30
  discoverExtensionModulePaths,
30
31
  expandEnvVarsDeep,
31
32
  getAncestorDirs,
32
33
  getExtensionNameFromPath,
34
+ getReadOptions,
33
35
  getUserSkillScanDirs,
34
36
  loadFilesFromDir,
35
37
  readContainedFile,
@@ -58,17 +60,41 @@ function resolveUserAgentDir(ctx: LoadContext): string {
58
60
  return ctx.userAgentDir ?? path.join(ctx.home, PATHS.userAgent);
59
61
  }
60
62
 
63
+ function readScopeForLevel(level: "user" | "project"): ReadScope {
64
+ return level === "user" ? "native" : "project";
65
+ }
66
+
67
+ async function canonicalBuiltinPath(ctx: LoadContext, filePath: string, scope: ReadScope): Promise<string | null> {
68
+ return (await canonicalizePathWithinHome(ctx, filePath, undefined, scope)) ?? null;
69
+ }
70
+
71
+ async function readBuiltinFile(ctx: LoadContext, filePath: string, scope: ReadScope): Promise<string | null> {
72
+ const canonicalPath = await canonicalBuiltinPath(ctx, filePath, scope);
73
+ if (!canonicalPath) return null;
74
+ return readFile(canonicalPath, getReadOptions(ctx, scope));
75
+ }
76
+
77
+ function getProjectStopDirectory(ctx: LoadContext): string | undefined {
78
+ if (ctx.repoRoot) return ctx.repoRoot;
79
+ const homeRelative = path.relative(ctx.home, ctx.cwd);
80
+ const cwdIsWithinHome =
81
+ homeRelative === "" ||
82
+ (homeRelative !== ".." && !homeRelative.startsWith(`..${path.sep}`) && !path.isAbsolute(homeRelative));
83
+ return ctx.isolatedHome || cwdIsWithinHome ? ctx.home : undefined;
84
+ }
85
+
61
86
  function getProjectConfigDirs(): string[] {
62
- return [PATHS.projectDir];
87
+ // Native project configuration is always rooted at `.gjc`. The configured
88
+ // config-dir name redirects the user profile only; allowing it to rewrite a
89
+ // project path would make explicit-home preflight and discovery disagree.
90
+ return [".gjc"];
63
91
  }
64
92
 
65
- async function ifNonEmptyDir(...seg: string[]): Promise<string | null> {
66
- let dir = path.join(...seg);
67
- const entries = await readDirEntries(dir);
93
+ async function ifNonEmptyDir(ctx: LoadContext, scope: ReadScope, ...seg: string[]): Promise<string | null> {
94
+ const dir = await canonicalBuiltinPath(ctx, path.join(...seg), scope);
95
+ if (!dir) return null;
96
+ const entries = await readDirEntries(dir, getReadOptions(ctx, scope));
68
97
  if (entries.length > 0) {
69
- if (!path.isAbsolute(dir)) {
70
- dir = path.resolve(dir);
71
- }
72
98
  return dir;
73
99
  }
74
100
  return null;
@@ -78,12 +104,12 @@ async function getConfigDirs(ctx: LoadContext): Promise<Array<{ dir: string; lev
78
104
  const result: Array<{ dir: string; level: "user" | "project" }> = [];
79
105
 
80
106
  for (const projectConfigDir of getProjectConfigDirs()) {
81
- const projectDir = await ifNonEmptyDir(ctx.cwd, projectConfigDir);
107
+ const projectDir = await ifNonEmptyDir(ctx, "project", ctx.cwd, projectConfigDir);
82
108
  if (projectDir) {
83
109
  result.push({ dir: projectDir, level: "project" });
84
110
  }
85
111
  }
86
- const userDir = await ifNonEmptyDir(resolveUserAgentDir(ctx));
112
+ const userDir = await ifNonEmptyDir(ctx, "native", resolveUserAgentDir(ctx));
87
113
  if (userDir) {
88
114
  result.push({ dir: userDir, level: "user" });
89
115
  }
@@ -91,14 +117,10 @@ async function getConfigDirs(ctx: LoadContext): Promise<Array<{ dir: string; lev
91
117
  return result;
92
118
  }
93
119
 
94
- async function findNearestProjectConfigDir(
95
- cwd: string,
96
- repoRoot?: string | null,
97
- home?: string,
98
- ): Promise<{ dir: string; depth: number } | null> {
99
- for (const ancestor of getAncestorDirs(cwd, repoRoot ?? home, home)) {
120
+ async function findNearestProjectConfigDir(ctx: LoadContext): Promise<{ dir: string; depth: number } | null> {
121
+ for (const ancestor of getAncestorDirs(ctx.cwd, getProjectStopDirectory(ctx))) {
100
122
  for (const projectConfigDir of getProjectConfigDirs()) {
101
- const configDir = await ifNonEmptyDir(ancestor.dir, projectConfigDir);
123
+ const configDir = await ifNonEmptyDir(ctx, "project", ancestor.dir, projectConfigDir);
102
124
  if (configDir) return { dir: configDir, depth: ancestor.depth };
103
125
  }
104
126
  }
@@ -235,11 +257,11 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
235
257
 
236
258
  const contents = await Promise.allSettled(
237
259
  paths.map(async p => {
238
- const content = await readFile(p.path);
239
- if (content) {
240
- return { path: p.path, content, level: p.level };
241
- }
242
- return null;
260
+ const scope = readScopeForLevel(p.level);
261
+ const canonicalPath = await canonicalBuiltinPath(ctx, p.path, scope);
262
+ if (!canonicalPath) return null;
263
+ const content = await readBuiltinFile(ctx, canonicalPath, scope);
264
+ return content ? { path: canonicalPath, content, level: p.level } : null;
243
265
  }),
244
266
  );
245
267
 
@@ -265,11 +287,9 @@ registerProvider<MCPServer>(mcpCapability.id, {
265
287
  async function loadSystemPrompt(ctx: LoadContext): Promise<LoadResult<SystemPrompt>> {
266
288
  const items: SystemPrompt[] = [];
267
289
 
268
- // User scope is the agent directory — the directory `gjc config path` prints
269
- // and the only user-scope seam. A profile is a separate scope; the default
270
- // profile's home-relative SYSTEM.md is not read under one.
271
- const userPath = path.join(resolveUserAgentDir(ctx), "SYSTEM.md");
272
- const userContent = await readContainedFile(resolveUserAgentDir(ctx), userPath);
290
+ const userAgentDir = resolveUserAgentDir(ctx);
291
+ const userPath = path.join(userAgentDir, "SYSTEM.md");
292
+ const userContent = await readContainedFile(userAgentDir, userPath, ctx.userAgentIdentity);
273
293
  if (userContent) {
274
294
  items.push({
275
295
  path: userPath,
@@ -279,10 +299,15 @@ async function loadSystemPrompt(ctx: LoadContext): Promise<LoadResult<SystemProm
279
299
  });
280
300
  }
281
301
 
282
- const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx.cwd, ctx.repoRoot, ctx.home);
302
+ const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx);
283
303
  if (nearestProjectConfigDir) {
284
- const projectPath = path.join(nearestProjectConfigDir.dir, "SYSTEM.md");
285
- const projectContent = await readFile(projectPath);
304
+ const projectPath = await canonicalBuiltinPath(
305
+ ctx,
306
+ path.join(nearestProjectConfigDir.dir, "SYSTEM.md"),
307
+ "project",
308
+ );
309
+ if (!projectPath) return { items, warnings: [] };
310
+ const projectContent = await readBuiltinFile(ctx, projectPath, "project");
286
311
  if (projectContent) {
287
312
  items.push({
288
313
  path: projectPath,
@@ -307,13 +332,17 @@ registerProvider<SystemPrompt>(systemPromptCapability.id, {
307
332
  // Skills
308
333
  async function loadSkills(ctx: LoadContext): Promise<LoadResult<Skill>> {
309
334
  // Walk up from cwd finding .gjc/skills/ in ancestors (closest first)
310
- const ancestors = getAncestorDirs(ctx.cwd, ctx.repoRoot ?? ctx.home, ctx.home);
335
+ const ancestors = getAncestorDirs(ctx.cwd, getProjectStopDirectory(ctx)).filter(
336
+ ({ dir }) => path.resolve(dir) !== path.resolve(ctx.home),
337
+ );
311
338
  const projectScans = ancestors.flatMap(({ dir }) =>
312
339
  getProjectConfigDirs().map(projectConfigDir =>
313
340
  scanSkillsFromDir(ctx, {
314
341
  dir: path.join(dir, projectConfigDir, "skills"),
342
+ linkContainmentRoot: ctx.repoRoot ?? undefined,
315
343
  providerId: PROVIDER_ID,
316
344
  level: "project",
345
+ scope: "project",
317
346
  requireDescription: true,
318
347
  }),
319
348
  ),
@@ -328,6 +357,7 @@ async function loadSkills(ctx: LoadContext): Promise<LoadResult<Skill>> {
328
357
  authorityRoot: path.resolve(dir) === path.resolve(userAgentDir, "skills") ? userAgentDir : undefined,
329
358
  providerId: PROVIDER_ID,
330
359
  level: "user",
360
+ scope: "native",
331
361
  requireDescription: true,
332
362
  }),
333
363
  );
@@ -357,6 +387,7 @@ async function loadSlashCommands(ctx: LoadContext): Promise<LoadResult<SlashComm
357
387
  const commandsDir = path.join(dir, "commands");
358
388
  const result = await loadFilesFromDir<SlashCommand>(ctx, commandsDir, PROVIDER_ID, level, {
359
389
  extensions: ["md"],
390
+ scope: readScopeForLevel(level),
360
391
  transform: (name, content, path, source) => ({
361
392
  name: name.replace(/\.md$/, ""),
362
393
  path,
@@ -393,6 +424,7 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
393
424
  const rulesDir = path.join(dir, "rules");
394
425
  const result = await loadFilesFromDir<Rule>(ctx, rulesDir, PROVIDER_ID, level, {
395
426
  extensions: ["md", "mdc"],
427
+ scope: readScopeForLevel(level),
396
428
  transform: (name, content, path, source) =>
397
429
  buildRuleFromMarkdown(name, content, path, source, { stripNamePattern: /\.(md|mdc)$/ }),
398
430
  });
@@ -410,13 +442,12 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
410
442
  await loadRulesFromDirs([...projectConfigDirs, ...userConfigDirs]);
411
443
 
412
444
  const userRulesFile = path.join(resolveUserAgentDir(ctx), "RULES.md");
413
- const userRule = await loadStickyRulesFile(userRulesFile, "user");
445
+ const userRule = await loadStickyRulesFile(ctx, userRulesFile, "user");
414
446
  if (userRule) items.push(userRule);
415
-
416
- const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx.cwd, ctx.repoRoot, ctx.home);
447
+ const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx);
417
448
  if (nearestProjectConfigDir) {
418
449
  const projectRulesFile = path.join(nearestProjectConfigDir.dir, "RULES.md");
419
- const projectRule = await loadStickyRulesFile(projectRulesFile, "project");
450
+ const projectRule = await loadStickyRulesFile(ctx, projectRulesFile, "project");
420
451
  if (projectRule) items.push(projectRule);
421
452
  }
422
453
 
@@ -427,11 +458,21 @@ async function loadRules(ctx: LoadContext): Promise<LoadResult<Rule>> {
427
458
  * Read a top-level `RULES.md` and synthesize an always-apply rule.
428
459
  * Returns null when the file is absent or empty so callers can short-circuit.
429
460
  */
430
- async function loadStickyRulesFile(filePath: string, level: "user" | "project"): Promise<Rule | null> {
431
- const content = await readContainedFile(path.dirname(filePath), filePath);
461
+ async function loadStickyRulesFile(
462
+ ctx: LoadContext,
463
+ filePath: string,
464
+ level: "user" | "project",
465
+ ): Promise<Rule | null> {
466
+ const scope = readScopeForLevel(level);
467
+ const canonicalPath = level === "user" ? filePath : await canonicalBuiltinPath(ctx, filePath, scope);
468
+ if (!canonicalPath) return null;
469
+ const content =
470
+ level === "user"
471
+ ? await readContainedFile(path.dirname(filePath), filePath, ctx.userAgentIdentity)
472
+ : await readBuiltinFile(ctx, canonicalPath, scope);
432
473
  if (!content) return null;
433
- const source = createSourceMeta(PROVIDER_ID, filePath, level);
434
- const rule = buildRuleFromMarkdown("RULES.md", content, filePath, source, { ruleName: "RULES" });
474
+ const source = createSourceMeta(PROVIDER_ID, canonicalPath, level);
475
+ const rule = buildRuleFromMarkdown("RULES.md", content, canonicalPath, source, { ruleName: "RULES" });
435
476
  // Force alwaysApply regardless of frontmatter — the whole point of RULES.md
436
477
  // is to be reattached every turn.
437
478
  return { ...rule, alwaysApply: true };
@@ -454,6 +495,7 @@ async function loadPrompts(ctx: LoadContext): Promise<LoadResult<Prompt>> {
454
495
  const promptsDir = path.join(dir, "prompts");
455
496
  const result = await loadFilesFromDir<Prompt>(ctx, promptsDir, PROVIDER_ID, level, {
456
497
  extensions: ["md"],
498
+ scope: readScopeForLevel(level),
457
499
  transform: (name, content, path, source) => ({
458
500
  name: name.replace(/\.md$/, ""),
459
501
  path,
@@ -481,12 +523,10 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
481
523
  const items: ExtensionModule[] = [];
482
524
  const warnings: string[] = [];
483
525
 
484
- const resolveExtensionPath = (rawPath: string): string => {
526
+ const resolveExtensionPath = async (rawPath: string, scope: ReadScope): Promise<string | undefined> => {
485
527
  const expanded = expandTilde(rawPath, ctx.home);
486
- if (path.isAbsolute(expanded)) {
487
- return expanded;
488
- }
489
- return path.resolve(ctx.cwd, expanded);
528
+ const resolved = path.isAbsolute(expanded) ? expanded : path.resolve(ctx.cwd, expanded);
529
+ return await canonicalizePathWithinHome(ctx, resolved, undefined, scope);
490
530
  };
491
531
 
492
532
  const createExtensionModule = (extPath: string, level: "user" | "project"): ExtensionModule => ({
@@ -499,8 +539,18 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
499
539
  const configDirs = await getConfigDirs(ctx);
500
540
 
501
541
  const [discoveredResults, settingsResults] = await Promise.all([
502
- Promise.all(configDirs.map(({ dir }) => discoverExtensionModulePaths(ctx, path.join(dir, "extensions")))),
503
- Promise.all(configDirs.map(({ dir }) => readFile(path.join(dir, "settings.json")))),
542
+ Promise.all(
543
+ configDirs.map(({ dir, level }) =>
544
+ discoverExtensionModulePaths(ctx, path.join(dir, "extensions"), {
545
+ scope: readScopeForLevel(level),
546
+ }),
547
+ ),
548
+ ),
549
+ Promise.all(
550
+ configDirs.map(({ dir, level }) =>
551
+ readBuiltinFile(ctx, path.join(dir, "settings.json"), readScopeForLevel(level)),
552
+ ),
553
+ ),
504
554
  ]);
505
555
 
506
556
  for (let i = 0; i < configDirs.length; i++) {
@@ -531,8 +581,13 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
531
581
  warnings.push(`Invalid extension path in ${settingsPath}: ${String(entry)}`);
532
582
  continue;
533
583
  }
584
+ const resolvedPath = await resolveExtensionPath(entry, readScopeForLevel(level));
585
+ if (!resolvedPath) {
586
+ warnings.push(`Extension path escapes isolated home in ${settingsPath}: ${entry}`);
587
+ continue;
588
+ }
534
589
  settingsExtensions.push({
535
- resolvedPath: resolveExtensionPath(entry),
590
+ resolvedPath,
536
591
  settingsPath,
537
592
  level,
538
593
  });
@@ -540,8 +595,16 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
540
595
  }
541
596
 
542
597
  const [entriesResults, fileContents] = await Promise.all([
543
- Promise.all(settingsExtensions.map(({ resolvedPath }) => readDirEntries(resolvedPath))),
544
- Promise.all(settingsExtensions.map(({ resolvedPath }) => readFile(resolvedPath))),
598
+ Promise.all(
599
+ settingsExtensions.map(({ resolvedPath, level }) =>
600
+ readDirEntries(resolvedPath, getReadOptions(ctx, readScopeForLevel(level))),
601
+ ),
602
+ ),
603
+ Promise.all(
604
+ settingsExtensions.map(({ resolvedPath, level }) =>
605
+ readBuiltinFile(ctx, resolvedPath, readScopeForLevel(level)),
606
+ ),
607
+ ),
545
608
  ]);
546
609
 
547
610
  const dirDiscoveryPromises: Array<{
@@ -556,7 +619,9 @@ async function loadExtensionModules(ctx: LoadContext): Promise<LoadResult<Extens
556
619
 
557
620
  if (entries.length > 0) {
558
621
  dirDiscoveryPromises.push({
559
- promise: discoverExtensionModulePaths(ctx, resolvedPath),
622
+ promise: discoverExtensionModulePaths(ctx, resolvedPath, {
623
+ scope: readScopeForLevel(level),
624
+ }),
560
625
  level,
561
626
  });
562
627
  } else if (content !== null) {
@@ -591,7 +656,11 @@ async function loadExtensions(ctx: LoadContext): Promise<LoadResult<Extension>>
591
656
  const warnings: string[] = [];
592
657
 
593
658
  const configDirs = await getConfigDirs(ctx);
594
- const entriesResults = await Promise.all(configDirs.map(({ dir }) => readDirEntries(path.join(dir, "extensions"))));
659
+ const entriesResults = await Promise.all(
660
+ configDirs.map(({ dir, level }) =>
661
+ readDirEntries(path.join(dir, "extensions"), getReadOptions(ctx, readScopeForLevel(level))),
662
+ ),
663
+ );
595
664
 
596
665
  const manifestCandidates: Array<{
597
666
  extDir: string;
@@ -609,17 +678,23 @@ async function loadExtensions(ctx: LoadContext): Promise<LoadResult<Extension>>
609
678
  if (entry.name.startsWith(".")) continue;
610
679
  if (!entry.isDirectory()) continue;
611
680
 
612
- const extDir = path.join(extensionsDir, entry.name);
681
+ const scope = readScopeForLevel(level);
682
+ const extDir = await canonicalBuiltinPath(ctx, path.join(extensionsDir, entry.name), scope);
683
+ if (!extDir) continue;
684
+ const manifestPath = await canonicalBuiltinPath(ctx, path.join(extDir, "gemini-extension.json"), scope);
685
+ if (!manifestPath) continue;
613
686
  manifestCandidates.push({
614
687
  extDir,
615
- manifestPath: path.join(extDir, "gemini-extension.json"),
688
+ manifestPath,
616
689
  entryName: entry.name,
617
690
  level,
618
691
  });
619
692
  }
620
693
  }
621
694
 
622
- const manifestContents = await Promise.all(manifestCandidates.map(({ manifestPath }) => readFile(manifestPath)));
695
+ const manifestContents = await Promise.all(
696
+ manifestCandidates.map(({ manifestPath, level }) => readBuiltinFile(ctx, manifestPath, readScopeForLevel(level))),
697
+ );
623
698
 
624
699
  for (let i = 0; i < manifestCandidates.length; i++) {
625
700
  const content = manifestContents[i];
@@ -661,6 +736,7 @@ async function loadInstructions(ctx: LoadContext): Promise<LoadResult<Instructio
661
736
  const instructionsDir = path.join(dir, "instructions");
662
737
  const result = await loadFilesFromDir<Instruction>(ctx, instructionsDir, PROVIDER_ID, level, {
663
738
  extensions: ["md"],
739
+ scope: readScopeForLevel(level),
664
740
  transform: (name, content, path, source) => {
665
741
  const { frontmatter, body } = parseFrontmatter(content, { source: path });
666
742
  return {
@@ -702,15 +778,22 @@ async function loadHooks(ctx: LoadContext): Promise<LoadResult<Hook>> {
702
778
 
703
779
  for (const { dir, level } of configDirs) {
704
780
  for (const hookType of hookTypes) {
781
+ const scope = readScopeForLevel(level);
782
+ const typeDir = await canonicalBuiltinPath(ctx, path.join(dir, "hooks", hookType), scope);
783
+ if (!typeDir) continue;
705
784
  typeDirRequests.push({
706
- typeDir: path.join(dir, "hooks", hookType),
785
+ typeDir,
707
786
  hookType,
708
787
  level,
709
788
  });
710
789
  }
711
790
  }
712
791
 
713
- const typeEntriesResults = await Promise.all(typeDirRequests.map(({ typeDir }) => readDirEntries(typeDir)));
792
+ const typeEntriesResults = await Promise.all(
793
+ typeDirRequests.map(({ typeDir, level }) =>
794
+ readDirEntries(typeDir, getReadOptions(ctx, readScopeForLevel(level))),
795
+ ),
796
+ );
714
797
 
715
798
  for (let i = 0; i < typeDirRequests.length; i++) {
716
799
  const { typeDir, hookType, level } = typeDirRequests[i];
@@ -720,7 +803,9 @@ async function loadHooks(ctx: LoadContext): Promise<LoadResult<Hook>> {
720
803
  if (entry.name.startsWith(".")) continue;
721
804
  if (!entry.isFile()) continue;
722
805
 
723
- const hookPath = path.join(typeDir, entry.name);
806
+ const hookPath = await canonicalBuiltinPath(ctx, path.join(typeDir, entry.name), readScopeForLevel(level));
807
+ if (!hookPath) continue;
808
+ if (ctx.isolatedHome && !(await isSingleLinkRegularFileAt(hookPath))) continue;
724
809
  const baseName = entry.name.includes(".") ? entry.name.slice(0, entry.name.lastIndexOf(".")) : entry.name;
725
810
  const tool = baseName === "*" ? "*" : baseName;
726
811
 
@@ -752,7 +837,16 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
752
837
  const warnings: string[] = [];
753
838
 
754
839
  const configDirs = await getConfigDirs(ctx);
755
- const entriesResults = await Promise.all(configDirs.map(({ dir }) => readDirEntries(path.join(dir, "tools"))));
840
+ const toolsDirs = await Promise.all(
841
+ configDirs.map(({ dir, level }) => canonicalBuiltinPath(ctx, path.join(dir, "tools"), readScopeForLevel(level))),
842
+ );
843
+ const entriesResults = await Promise.all(
844
+ toolsDirs.map((toolsDir, i) =>
845
+ toolsDir
846
+ ? readDirEntries(toolsDir, getReadOptions(ctx, readScopeForLevel(configDirs[i].level)))
847
+ : Promise.resolve([]),
848
+ ),
849
+ );
756
850
 
757
851
  const fileLoadPromises: Array<Promise<{ items: CustomTool[]; warnings?: string[] }>> = [];
758
852
  const subDirCandidates: Array<{
@@ -762,15 +856,15 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
762
856
  }> = [];
763
857
 
764
858
  for (let i = 0; i < configDirs.length; i++) {
765
- const { dir, level } = configDirs[i];
859
+ const { level } = configDirs[i];
766
860
  const toolEntries = entriesResults[i];
767
- if (toolEntries.length === 0) continue;
768
-
769
- const toolsDir = path.join(dir, "tools");
861
+ const toolsDir = toolsDirs[i];
862
+ if (toolEntries.length === 0 || !toolsDir) continue;
770
863
 
771
864
  fileLoadPromises.push(
772
865
  loadFilesFromDir<CustomTool>(ctx, toolsDir, PROVIDER_ID, level, {
773
866
  extensions: ["json", "md", "ts", "js", "sh", "bash", "py"],
867
+ scope: readScopeForLevel(level),
774
868
  transform: (name, content, path, source) => {
775
869
  if (name.endsWith(".json")) {
776
870
  const data = tryParseJson<{ name?: string; description?: string }>(content);
@@ -819,8 +913,14 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
819
913
  if (entry.name.startsWith(".")) continue;
820
914
  if (!entry.isDirectory()) continue;
821
915
 
916
+ const indexPath = await canonicalBuiltinPath(
917
+ ctx,
918
+ path.join(toolsDir, entry.name, "index.ts"),
919
+ readScopeForLevel(level),
920
+ );
921
+ if (!indexPath) continue;
822
922
  subDirCandidates.push({
823
- indexPath: path.join(toolsDir, entry.name, "index.ts"),
923
+ indexPath,
824
924
  entryName: entry.name,
825
925
  level,
826
926
  });
@@ -829,7 +929,9 @@ async function loadTools(ctx: LoadContext): Promise<LoadResult<CustomTool>> {
829
929
 
830
930
  const [fileResults, indexContents] = await Promise.all([
831
931
  Promise.all(fileLoadPromises),
832
- Promise.all(subDirCandidates.map(({ indexPath }) => readFile(indexPath))),
932
+ Promise.all(
933
+ subDirCandidates.map(({ indexPath, level }) => readBuiltinFile(ctx, indexPath, readScopeForLevel(level))),
934
+ ),
833
935
  ]);
834
936
 
835
937
  for (const result of fileResults) {
@@ -879,9 +981,10 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
879
981
  };
880
982
 
881
983
  for (const { dir, level } of await getConfigDirs(ctx)) {
882
- const settingsPath = path.join(dir, "settings.json");
883
- const settingsContent = await readFile(settingsPath);
884
- if (settingsContent) {
984
+ const scope = readScopeForLevel(level);
985
+ const settingsPath = await canonicalBuiltinPath(ctx, path.join(dir, "settings.json"), scope);
986
+ const settingsContent = settingsPath ? await readBuiltinFile(ctx, settingsPath, scope) : null;
987
+ if (settingsContent && settingsPath) {
885
988
  const data = tryParseJson<Record<string, unknown>>(settingsContent);
886
989
  if (data) {
887
990
  items.push({
@@ -895,8 +998,9 @@ async function loadSettings(ctx: LoadContext): Promise<LoadResult<Settings>> {
895
998
  }
896
999
  }
897
1000
 
898
- const configPath = path.join(dir, "config.yml");
899
- const configContent = await readFile(configPath);
1001
+ const configPath = await canonicalBuiltinPath(ctx, path.join(dir, "config.yml"), scope);
1002
+ if (!configPath) continue;
1003
+ const configContent = await readBuiltinFile(ctx, configPath, scope);
900
1004
  if (!configContent) continue;
901
1005
 
902
1006
  const data = parseYamlSettings(configContent, configPath);
@@ -926,8 +1030,9 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
926
1030
  const items: ContextFile[] = [];
927
1031
  const warnings: string[] = [];
928
1032
 
929
- const userPath = path.join(resolveUserAgentDir(ctx), "AGENTS.md");
930
- const userContent = await readContainedFile(resolveUserAgentDir(ctx), userPath);
1033
+ const userAgentDir = resolveUserAgentDir(ctx);
1034
+ const userPath = path.join(userAgentDir, "AGENTS.md");
1035
+ const userContent = await readContainedFile(userAgentDir, userPath, ctx.userAgentIdentity);
931
1036
  if (userContent) {
932
1037
  items.push({
933
1038
  path: userPath,
@@ -937,11 +1042,15 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
937
1042
  });
938
1043
  }
939
1044
 
940
- const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx.cwd, ctx.repoRoot, ctx.home);
1045
+ const nearestProjectConfigDir = await findNearestProjectConfigDir(ctx);
941
1046
  if (nearestProjectConfigDir) {
942
- const projectPath = path.join(nearestProjectConfigDir.dir, "AGENTS.md");
943
- const projectContent = await readFile(projectPath);
944
- if (projectContent) {
1047
+ const projectPath = await canonicalBuiltinPath(
1048
+ ctx,
1049
+ path.join(nearestProjectConfigDir.dir, "AGENTS.md"),
1050
+ "project",
1051
+ );
1052
+ const projectContent = projectPath ? await readBuiltinFile(ctx, projectPath, "project") : null;
1053
+ if (projectContent && projectPath) {
945
1054
  items.push({
946
1055
  path: projectPath,
947
1056
  content: projectContent,