@ouro.bot/cli 0.1.0-alpha.3 → 0.1.0-alpha.300

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 (289) hide show
  1. package/README.md +188 -190
  2. package/SerpentGuide.ouro/agent.json +82 -0
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +6 -3
  4. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
  5. package/SerpentGuide.ouro/psyche/identities/python.md +31 -0
  6. package/assets/ouroboros.png +0 -0
  7. package/changelog.json +1888 -0
  8. package/dist/arc/attention-types.js +8 -0
  9. package/dist/arc/cares.js +140 -0
  10. package/dist/arc/episodes.js +117 -0
  11. package/dist/arc/intentions.js +133 -0
  12. package/dist/arc/json-store.js +117 -0
  13. package/dist/arc/obligations.js +237 -0
  14. package/dist/arc/packets.js +203 -0
  15. package/dist/arc/presence.js +185 -0
  16. package/dist/heart/active-work.js +832 -0
  17. package/dist/heart/agent-entry.js +37 -2
  18. package/dist/heart/attachments/image-normalize.js +194 -0
  19. package/dist/heart/attachments/materialize.js +230 -0
  20. package/dist/heart/attachments/render.js +29 -0
  21. package/dist/heart/attachments/store.js +103 -0
  22. package/dist/heart/attachments/types.js +138 -0
  23. package/dist/heart/auth/auth-flow.js +456 -0
  24. package/dist/heart/bridges/manager.js +358 -0
  25. package/dist/heart/bridges/state-machine.js +135 -0
  26. package/dist/heart/bridges/store.js +123 -0
  27. package/dist/heart/bundle-state.js +168 -0
  28. package/dist/heart/commitments.js +111 -0
  29. package/dist/heart/config-registry.js +304 -0
  30. package/dist/heart/config.js +123 -28
  31. package/dist/heart/core.js +738 -191
  32. package/dist/heart/cross-chat-delivery.js +131 -0
  33. package/dist/heart/daemon/agent-config-check.js +149 -0
  34. package/dist/heart/daemon/agent-discovery.js +157 -0
  35. package/dist/heart/daemon/agent-service.js +360 -0
  36. package/dist/heart/daemon/cadence.js +70 -0
  37. package/dist/heart/daemon/cli-defaults.js +574 -0
  38. package/dist/heart/daemon/cli-exec.js +1945 -0
  39. package/dist/heart/daemon/cli-parse.js +808 -0
  40. package/dist/heart/daemon/cli-render.js +503 -0
  41. package/dist/heart/daemon/cli-types.js +8 -0
  42. package/dist/heart/daemon/daemon-cli.js +29 -673
  43. package/dist/heart/daemon/daemon-entry.js +259 -8
  44. package/dist/heart/daemon/daemon-health.js +136 -0
  45. package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
  46. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  47. package/dist/heart/daemon/daemon.js +745 -18
  48. package/dist/heart/daemon/health-monitor.js +38 -0
  49. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  50. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  51. package/dist/heart/daemon/inner-status.js +89 -0
  52. package/dist/heart/daemon/launchd.js +171 -0
  53. package/dist/heart/daemon/log-tailer.js +82 -12
  54. package/dist/heart/daemon/logs-prune.js +105 -0
  55. package/dist/heart/daemon/message-router.js +17 -8
  56. package/dist/heart/daemon/os-cron-deps.js +134 -0
  57. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  58. package/dist/heart/daemon/process-manager.js +181 -1
  59. package/dist/heart/daemon/pulse.js +463 -0
  60. package/dist/heart/daemon/run-hooks.js +39 -0
  61. package/dist/heart/daemon/runtime-logging.js +70 -15
  62. package/dist/heart/daemon/runtime-metadata.js +219 -0
  63. package/dist/heart/daemon/runtime-mode.js +67 -0
  64. package/dist/heart/daemon/safe-mode.js +161 -0
  65. package/dist/heart/daemon/sense-manager.js +335 -0
  66. package/dist/heart/daemon/session-id-resolver.js +131 -0
  67. package/dist/heart/daemon/skill-management-installer.js +94 -0
  68. package/dist/heart/daemon/socket-client.js +307 -0
  69. package/dist/heart/daemon/task-scheduler.js +3 -25
  70. package/dist/heart/daemon/thoughts.js +510 -0
  71. package/dist/heart/delegation.js +62 -0
  72. package/dist/heart/habits/habit-migration.js +181 -0
  73. package/dist/heart/habits/habit-parser.js +140 -0
  74. package/dist/heart/habits/habit-scheduler.js +371 -0
  75. package/dist/heart/hatch/hatch-animation.js +35 -0
  76. package/dist/heart/{daemon → hatch}/hatch-flow.js +31 -130
  77. package/dist/heart/{daemon → hatch}/hatch-specialist.js +7 -2
  78. package/dist/heart/hatch/specialist-orchestrator.js +129 -0
  79. package/dist/heart/hatch/specialist-prompt.js +101 -0
  80. package/dist/heart/hatch/specialist-tools.js +283 -0
  81. package/dist/heart/identity.js +241 -54
  82. package/dist/heart/kicks.js +2 -20
  83. package/dist/heart/mcp/mcp-server.js +653 -0
  84. package/dist/heart/migrate-config.js +127 -0
  85. package/dist/heart/model-capabilities.js +59 -0
  86. package/dist/heart/outlook/outlook-http.js +439 -0
  87. package/dist/heart/outlook/outlook-read.js +1618 -0
  88. package/dist/heart/outlook/outlook-render.js +1032 -0
  89. package/dist/heart/outlook/outlook-types.js +7 -0
  90. package/dist/heart/outlook/outlook-view.js +194 -0
  91. package/dist/heart/progress-story.js +42 -0
  92. package/dist/heart/provider-failover.js +88 -0
  93. package/dist/heart/provider-ping.js +162 -0
  94. package/dist/heart/providers/anthropic-token.js +163 -0
  95. package/dist/heart/providers/anthropic.js +181 -41
  96. package/dist/heart/providers/azure.js +98 -11
  97. package/dist/heart/providers/error-classification.js +63 -0
  98. package/dist/heart/providers/github-copilot.js +136 -0
  99. package/dist/heart/providers/minimax-vlm.js +189 -0
  100. package/dist/heart/providers/minimax.js +23 -5
  101. package/dist/heart/providers/openai-codex.js +33 -22
  102. package/dist/heart/sense-truth.js +61 -0
  103. package/dist/heart/session-activity.js +172 -0
  104. package/dist/heart/session-recall.js +216 -0
  105. package/dist/heart/start-of-turn-packet.js +339 -0
  106. package/dist/heart/streaming.js +120 -33
  107. package/dist/heart/sync.js +332 -0
  108. package/dist/heart/target-resolution.js +127 -0
  109. package/dist/heart/tempo.js +93 -0
  110. package/dist/heart/temporal-view.js +41 -0
  111. package/dist/heart/tool-activity-callbacks.js +36 -0
  112. package/dist/heart/tool-description.js +135 -0
  113. package/dist/heart/tool-friction.js +55 -0
  114. package/dist/heart/tool-loop.js +200 -0
  115. package/dist/heart/turn-context.js +358 -0
  116. package/dist/heart/turn-coordinator.js +28 -0
  117. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  118. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +5 -4
  119. package/dist/heart/versioning/ouro-path-installer.js +221 -0
  120. package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
  121. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  122. package/dist/heart/versioning/staged-restart.js +146 -0
  123. package/dist/heart/versioning/update-checker.js +113 -0
  124. package/dist/heart/versioning/update-hooks.js +142 -0
  125. package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
  126. package/dist/mind/associative-recall.js +135 -66
  127. package/dist/mind/bundle-manifest.js +77 -1
  128. package/dist/mind/context.js +125 -14
  129. package/dist/mind/diary-integrity.js +60 -0
  130. package/dist/mind/{memory.js → diary.js} +84 -96
  131. package/dist/mind/embedding-provider.js +60 -0
  132. package/dist/mind/file-state.js +179 -0
  133. package/dist/mind/first-impressions.js +16 -2
  134. package/dist/mind/friends/channel.js +64 -0
  135. package/dist/mind/friends/group-context.js +144 -0
  136. package/dist/mind/friends/resolver.js +37 -0
  137. package/dist/mind/friends/store-file.js +58 -3
  138. package/dist/mind/friends/trust-explanation.js +74 -0
  139. package/dist/mind/friends/types.js +9 -1
  140. package/dist/mind/journal-index.js +161 -0
  141. package/dist/mind/obligation-steering.js +221 -0
  142. package/dist/mind/pending.js +76 -9
  143. package/dist/mind/phrases.js +1 -0
  144. package/dist/mind/prompt.js +1011 -107
  145. package/dist/mind/scrutiny.js +173 -0
  146. package/dist/mind/token-estimate.js +8 -12
  147. package/dist/nerves/cli-logging.js +22 -3
  148. package/dist/nerves/coverage/audit.js +1 -1
  149. package/dist/nerves/coverage/file-completeness.js +59 -5
  150. package/dist/nerves/coverage/run-artifacts.js +1 -1
  151. package/dist/nerves/event-buffer.js +111 -0
  152. package/dist/nerves/index.js +224 -4
  153. package/dist/nerves/observation.js +20 -0
  154. package/dist/nerves/redact.js +79 -0
  155. package/dist/nerves/runtime.js +5 -1
  156. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  157. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  158. package/dist/outlook-ui/index.html +15 -0
  159. package/dist/repertoire/ado-client.js +17 -56
  160. package/dist/repertoire/ado-semantic.js +11 -10
  161. package/dist/repertoire/api-client.js +97 -0
  162. package/dist/repertoire/bitwarden-store.js +319 -0
  163. package/dist/repertoire/bundle-templates.js +72 -0
  164. package/dist/repertoire/bw-installer.js +79 -0
  165. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  166. package/dist/repertoire/coding/context-pack.js +330 -0
  167. package/dist/repertoire/coding/feedback.js +301 -0
  168. package/dist/repertoire/coding/index.js +4 -1
  169. package/dist/repertoire/coding/manager.js +220 -13
  170. package/dist/repertoire/coding/spawner.js +58 -12
  171. package/dist/repertoire/coding/tools.js +209 -7
  172. package/dist/repertoire/commerce-errors.js +109 -0
  173. package/dist/repertoire/commerce-self-test.js +156 -0
  174. package/dist/repertoire/credential-access.js +527 -0
  175. package/dist/repertoire/data/ado-endpoints.json +188 -0
  176. package/dist/repertoire/duffel-client.js +185 -0
  177. package/dist/repertoire/github-client.js +14 -55
  178. package/dist/repertoire/graph-client.js +11 -52
  179. package/dist/repertoire/guardrails.js +375 -0
  180. package/dist/repertoire/mcp-client.js +255 -0
  181. package/dist/repertoire/mcp-manager.js +305 -0
  182. package/dist/repertoire/mcp-tools.js +63 -0
  183. package/dist/repertoire/shell-sessions.js +133 -0
  184. package/dist/repertoire/skills.js +14 -23
  185. package/dist/repertoire/stripe-client.js +131 -0
  186. package/dist/repertoire/tasks/board.js +43 -5
  187. package/dist/repertoire/tasks/fix.js +182 -0
  188. package/dist/repertoire/tasks/index.js +28 -10
  189. package/dist/repertoire/tasks/lifecycle.js +2 -2
  190. package/dist/repertoire/tasks/parser.js +3 -2
  191. package/dist/repertoire/tasks/scanner.js +194 -37
  192. package/dist/repertoire/tasks/transitions.js +11 -28
  193. package/dist/repertoire/tool-results.js +29 -0
  194. package/dist/repertoire/tools-attachments.js +316 -0
  195. package/dist/repertoire/tools-base.js +45 -707
  196. package/dist/repertoire/tools-bluebubbles.js +94 -0
  197. package/dist/repertoire/tools-bridge.js +141 -0
  198. package/dist/repertoire/tools-bundle.js +984 -0
  199. package/dist/repertoire/tools-config.js +185 -0
  200. package/dist/repertoire/tools-continuity.js +248 -0
  201. package/dist/repertoire/tools-credential.js +182 -0
  202. package/dist/repertoire/tools-files.js +342 -0
  203. package/dist/repertoire/tools-flight.js +224 -0
  204. package/dist/repertoire/tools-flow.js +105 -0
  205. package/dist/repertoire/tools-github.js +1 -7
  206. package/dist/repertoire/tools-memory.js +374 -0
  207. package/dist/repertoire/tools-session.js +739 -0
  208. package/dist/repertoire/tools-shell.js +120 -0
  209. package/dist/repertoire/tools-stripe.js +180 -0
  210. package/dist/repertoire/tools-surface.js +243 -0
  211. package/dist/repertoire/tools-teams.js +64 -61
  212. package/dist/repertoire/tools-travel.js +125 -0
  213. package/dist/repertoire/tools-user-profile.js +144 -0
  214. package/dist/repertoire/tools-vault.js +110 -0
  215. package/dist/repertoire/tools.js +149 -98
  216. package/dist/repertoire/travel-api-client.js +360 -0
  217. package/dist/repertoire/user-profile.js +118 -0
  218. package/dist/repertoire/vault-setup.js +241 -0
  219. package/dist/scripts/claude-code-hook.js +41 -0
  220. package/dist/scripts/claude-code-stop-hook.js +47 -0
  221. package/dist/senses/attention-queue.js +116 -0
  222. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  223. package/dist/senses/bluebubbles/attachment-download.js +137 -0
  224. package/dist/senses/bluebubbles/client.js +568 -0
  225. package/dist/senses/bluebubbles/entry.js +13 -0
  226. package/dist/senses/bluebubbles/inbound-log.js +113 -0
  227. package/dist/senses/bluebubbles/index.js +1427 -0
  228. package/dist/senses/bluebubbles/media.js +390 -0
  229. package/dist/senses/bluebubbles/model.js +282 -0
  230. package/dist/senses/bluebubbles/mutation-log.js +116 -0
  231. package/dist/senses/bluebubbles/replay.js +129 -0
  232. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  233. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  234. package/dist/senses/cli/bracketed-paste.js +82 -0
  235. package/dist/senses/cli/image-paste.js +287 -0
  236. package/dist/senses/cli/image-ref-navigation.js +75 -0
  237. package/dist/senses/cli/ink-app.js +156 -0
  238. package/dist/senses/cli/inline-diff.js +64 -0
  239. package/dist/senses/cli/input-keys.js +174 -0
  240. package/dist/senses/cli/kill-ring.js +86 -0
  241. package/dist/senses/cli/message-list.js +51 -0
  242. package/dist/senses/cli/ouro-tui.js +595 -0
  243. package/dist/senses/cli/spinner-imperative.js +135 -0
  244. package/dist/senses/cli/spinner.js +101 -0
  245. package/dist/senses/cli/status-line.js +60 -0
  246. package/dist/senses/cli/streaming-markdown.js +526 -0
  247. package/dist/senses/cli/tool-display.js +83 -0
  248. package/dist/senses/cli/tool-render.js +85 -0
  249. package/dist/senses/cli/tui-store.js +240 -0
  250. package/dist/senses/cli/virtual-list.js +35 -0
  251. package/dist/senses/cli-entry.js +1 -1
  252. package/dist/senses/cli-layout.js +187 -0
  253. package/dist/senses/cli.js +772 -264
  254. package/dist/senses/commands.js +65 -1
  255. package/dist/senses/continuity.js +94 -0
  256. package/dist/senses/habit-turn-message.js +108 -0
  257. package/dist/senses/inner-dialog-worker.js +112 -19
  258. package/dist/senses/inner-dialog.js +633 -86
  259. package/dist/senses/pipeline.js +560 -0
  260. package/dist/senses/shared-turn.js +195 -0
  261. package/dist/senses/surface-tool.js +68 -0
  262. package/dist/senses/teams.js +814 -196
  263. package/dist/senses/trust-gate.js +112 -2
  264. package/package.json +25 -9
  265. package/skills/agent-commerce.md +106 -0
  266. package/skills/browser-navigation.md +110 -0
  267. package/skills/commerce-setup-guide.md +116 -0
  268. package/skills/commerce-setup.md +84 -0
  269. package/skills/configure-dev-tools.md +81 -0
  270. package/skills/travel-planning.md +138 -0
  271. package/AdoptionSpecialist.ouro/agent.json +0 -20
  272. package/AdoptionSpecialist.ouro/psyche/identities/python.md +0 -1
  273. package/dist/heart/daemon/subagent-installer.js +0 -125
  274. package/dist/inner-worker-entry.js +0 -4
  275. package/subagents/README.md +0 -73
  276. package/subagents/work-doer.md +0 -233
  277. package/subagents/work-merger.md +0 -624
  278. package/subagents/work-planner.md +0 -373
  279. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  280. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  281. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  282. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  283. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  284. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  285. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  286. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  287. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  288. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  289. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getSpecialistTools = getSpecialistTools;
37
+ exports.createSpecialistExecTool = createSpecialistExecTool;
38
+ const crypto = __importStar(require("crypto"));
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const tools_base_1 = require("../../repertoire/tools-base");
42
+ const hatch_flow_1 = require("./hatch-flow");
43
+ const hatch_animation_1 = require("./hatch-animation");
44
+ const bundle_manifest_1 = require("../../mind/bundle-manifest");
45
+ const runtime_1 = require("../../nerves/runtime");
46
+ const completeAdoptionTool = {
47
+ type: "function",
48
+ function: {
49
+ name: "complete_adoption",
50
+ description: "finalize the agent bundle and hatch the new agent. call this only when you have written all 5 psyche files and agent.json to the temp directory, and the human has approved the bundle.",
51
+ parameters: {
52
+ type: "object",
53
+ properties: {
54
+ name: {
55
+ type: "string",
56
+ description: "the PascalCase name for the new agent (e.g. 'Slugger')",
57
+ },
58
+ handoff_message: {
59
+ type: "string",
60
+ description: "a warm handoff message to display to the human after the agent is hatched",
61
+ },
62
+ phone: {
63
+ type: "string",
64
+ description: "the human's phone number (optional, for iMessage contact recognition)",
65
+ },
66
+ teams_handle: {
67
+ type: "string",
68
+ description: "the human's Teams email/handle (optional, for Teams contact recognition)",
69
+ },
70
+ },
71
+ required: ["name", "handoff_message"],
72
+ },
73
+ },
74
+ };
75
+ const readFileTool = tools_base_1.baseToolDefinitions.find((d) => d.tool.function.name === "read_file");
76
+ const writeFileTool = tools_base_1.baseToolDefinitions.find((d) => d.tool.function.name === "write_file");
77
+ const listDirToolSchema = {
78
+ type: "function",
79
+ function: {
80
+ name: "list_directory",
81
+ description: "list directory contents",
82
+ parameters: {
83
+ type: "object",
84
+ properties: { path: { type: "string" } },
85
+ required: ["path"],
86
+ },
87
+ },
88
+ };
89
+ /**
90
+ * Returns the specialist's tool schema array.
91
+ */
92
+ function getSpecialistTools() {
93
+ return [completeAdoptionTool, tools_base_1.settleTool, readFileTool.tool, writeFileTool.tool, listDirToolSchema];
94
+ }
95
+ const PSYCHE_FILES = ["SOUL.md", "IDENTITY.md", "LORE.md", "TACIT.md", "ASPIRATIONS.md"];
96
+ function isPascalCase(name) {
97
+ return /^[A-Z][a-zA-Z0-9]*$/.test(name);
98
+ }
99
+ function writeReadme(dir, purpose) {
100
+ fs.mkdirSync(dir, { recursive: true });
101
+ const readmePath = path.join(dir, "README.md");
102
+ /* v8 ignore next -- defensive: guard against re-scaffold on existing bundle @preserve */
103
+ if (!fs.existsSync(readmePath)) {
104
+ fs.writeFileSync(readmePath, `# ${path.basename(dir)}\n\n${purpose}\n`, "utf-8");
105
+ }
106
+ }
107
+ function scaffoldBundle(bundleRoot) {
108
+ writeReadme(path.join(bundleRoot, "memory"), "Persistent memory store.");
109
+ writeReadme(path.join(bundleRoot, "memory", "daily"), "Daily memory entries.");
110
+ writeReadme(path.join(bundleRoot, "memory", "archive"), "Archived memory.");
111
+ writeReadme(path.join(bundleRoot, "friends"), "Known friend records.");
112
+ writeReadme(path.join(bundleRoot, "tasks"), "Task files.");
113
+ writeReadme(path.join(bundleRoot, "tasks", "one-shots"), "One-shot tasks.");
114
+ writeReadme(path.join(bundleRoot, "habits"), "Recurring habits and autonomous rhythms.");
115
+ writeReadme(path.join(bundleRoot, "tasks", "ongoing"), "Ongoing tasks.");
116
+ writeReadme(path.join(bundleRoot, "skills"), "Local skill files.");
117
+ writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
118
+ writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
119
+ // Memory scaffold files
120
+ const memoryRoot = path.join(bundleRoot, "memory");
121
+ const factsPath = path.join(memoryRoot, "facts.jsonl");
122
+ const entitiesPath = path.join(memoryRoot, "entities.json");
123
+ /* v8 ignore next -- defensive: guard against re-scaffold on existing bundle @preserve */
124
+ if (!fs.existsSync(factsPath))
125
+ fs.writeFileSync(factsPath, "", "utf-8");
126
+ /* v8 ignore next -- defensive: guard against re-scaffold on existing bundle @preserve */
127
+ if (!fs.existsSync(entitiesPath))
128
+ fs.writeFileSync(entitiesPath, "{}\n", "utf-8");
129
+ // bundle-meta.json
130
+ const meta = (0, bundle_manifest_1.createBundleMeta)();
131
+ fs.writeFileSync(path.join(bundleRoot, "bundle-meta.json"), JSON.stringify(meta, null, 2) + "\n", "utf-8");
132
+ }
133
+ function moveDir(src, dest) {
134
+ try {
135
+ fs.renameSync(src, dest);
136
+ }
137
+ catch {
138
+ /* v8 ignore start -- cross-device fallback: only triggers on EXDEV (e.g. /tmp → different mount), untestable in CI @preserve */
139
+ fs.cpSync(src, dest, { recursive: true });
140
+ fs.rmSync(src, { recursive: true, force: true });
141
+ /* v8 ignore stop */
142
+ }
143
+ }
144
+ async function execCompleteAdoption(args, deps) {
145
+ const name = args.name;
146
+ const handoffMessage = args.handoff_message;
147
+ if (!name) {
148
+ return "error: missing required 'name' parameter";
149
+ }
150
+ if (!isPascalCase(name)) {
151
+ return `error: name '${name}' must be PascalCase (e.g. 'Slugger', 'MyAgent')`;
152
+ }
153
+ // Validate psyche files exist
154
+ const psycheDir = path.join(deps.tempDir, "psyche");
155
+ const missingPsyche = PSYCHE_FILES.filter((f) => !fs.existsSync(path.join(psycheDir, f)));
156
+ if (missingPsyche.length > 0) {
157
+ return `error: missing psyche files in temp directory: ${missingPsyche.join(", ")}. write them first using write_file.`;
158
+ }
159
+ // Validate agent.json exists
160
+ const agentJsonPath = path.join(deps.tempDir, "agent.json");
161
+ if (!fs.existsSync(agentJsonPath)) {
162
+ return "error: agent.json not found in temp directory. write it first using write_file.";
163
+ }
164
+ // Validate target doesn't exist
165
+ const targetBundle = path.join(deps.bundlesRoot, `${name}.ouro`);
166
+ if (fs.existsSync(targetBundle)) {
167
+ return `error: bundle '${name}.ouro' already exists at ${deps.bundlesRoot}. choose a different name.`;
168
+ }
169
+ // Scaffold structural dirs into tempDir
170
+ scaffoldBundle(deps.tempDir);
171
+ // Move tempDir -> final bundle location
172
+ moveDir(deps.tempDir, targetBundle);
173
+ // Write secrets
174
+ try {
175
+ (0, hatch_flow_1.writeSecretsFile)(name, deps.provider, deps.credentials, deps.secretsRoot);
176
+ }
177
+ catch (e) {
178
+ // Rollback: remove the moved bundle
179
+ try {
180
+ fs.rmSync(targetBundle, { recursive: true, force: true });
181
+ }
182
+ catch {
183
+ // Best effort cleanup
184
+ }
185
+ return `error: failed to write secrets: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(e)}`;
186
+ }
187
+ // Create initial friend record if contact info provided
188
+ const phone = args.phone;
189
+ const teamsHandle = args.teams_handle;
190
+ if (phone || teamsHandle) {
191
+ const friendId = crypto.randomUUID();
192
+ const now = new Date().toISOString();
193
+ const externalIds = [];
194
+ if (phone)
195
+ externalIds.push({ provider: "imessage-handle", externalId: phone, linkedAt: now });
196
+ if (teamsHandle)
197
+ externalIds.push({ provider: "aad", externalId: teamsHandle, linkedAt: now });
198
+ const friendRecord = {
199
+ id: friendId,
200
+ name: deps.humanName ?? "primary",
201
+ trustLevel: "family",
202
+ externalIds,
203
+ tenantMemberships: [],
204
+ toolPreferences: {},
205
+ notes: {},
206
+ createdAt: now,
207
+ updatedAt: now,
208
+ schemaVersion: 1,
209
+ };
210
+ const friendPath = path.join(targetBundle, "friends", `${friendId}.json`);
211
+ fs.writeFileSync(friendPath, JSON.stringify(friendRecord, null, 2), "utf-8");
212
+ }
213
+ // Play hatch animation
214
+ await (0, hatch_animation_1.playHatchAnimation)(name, deps.animationWriter);
215
+ // Display handoff message
216
+ /* v8 ignore next -- UI-only: handoff message display, covered by integration @preserve */
217
+ if (handoffMessage && deps.animationWriter) {
218
+ deps.animationWriter(`\n${handoffMessage}\n`);
219
+ }
220
+ (0, runtime_1.emitNervesEvent)({
221
+ component: "daemon",
222
+ event: "daemon.adoption_complete",
223
+ message: "adoption completed successfully",
224
+ meta: { agentName: name, bundlePath: targetBundle },
225
+ });
226
+ return JSON.stringify({ success: true, agentName: name, bundlePath: targetBundle });
227
+ }
228
+ /**
229
+ * Create a specialist tool executor with the given dependencies captured in closure.
230
+ */
231
+ function createSpecialistExecTool(deps) {
232
+ (0, runtime_1.emitNervesEvent)({
233
+ component: "daemon",
234
+ event: "daemon.specialist_exec_tool_created",
235
+ message: "specialist exec tool created",
236
+ meta: { tempDir: deps.tempDir },
237
+ });
238
+ return async (name, args) => {
239
+ (0, runtime_1.emitNervesEvent)({
240
+ component: "daemon",
241
+ event: "daemon.specialist_tool_exec",
242
+ message: "executing specialist tool",
243
+ meta: { tool: name },
244
+ });
245
+ if (name === "complete_adoption") {
246
+ return execCompleteAdoption(args, deps);
247
+ }
248
+ if (name === "read_file") {
249
+ try {
250
+ return fs.readFileSync(args.path, "utf-8");
251
+ }
252
+ catch (e) {
253
+ return `error: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive @preserve */ String(e)}`;
254
+ }
255
+ }
256
+ if (name === "write_file") {
257
+ try {
258
+ const dir = path.dirname(args.path);
259
+ fs.mkdirSync(dir, { recursive: true });
260
+ const content = typeof args.content === "string"
261
+ ? args.content
262
+ : JSON.stringify(args.content, null, 2);
263
+ fs.writeFileSync(args.path, content, "utf-8");
264
+ return `wrote ${args.path}`;
265
+ }
266
+ catch (e) {
267
+ return `error: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive @preserve */ String(e)}`;
268
+ }
269
+ }
270
+ if (name === "list_directory") {
271
+ try {
272
+ return fs
273
+ .readdirSync(args.path, { withFileTypes: true })
274
+ .map((e) => `${e.isDirectory() ? "d" : "-"} ${e.name}`)
275
+ .join("\n");
276
+ }
277
+ catch (e) {
278
+ return `error: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive @preserve */ String(e)}`;
279
+ }
280
+ }
281
+ return `error: unknown tool '${name}'`;
282
+ };
283
+ }
@@ -33,20 +33,40 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = void 0;
36
+ exports.HARNESS_CANONICAL_REPO_URL = exports.DEFAULT_AGENT_SENSES = exports.DEFAULT_VAULT_SERVER_URL = exports.DEFAULT_AGENT_PHRASES = exports.DEFAULT_AGENT_CONTEXT = exports.PROVIDER_CREDENTIALS = void 0;
37
+ exports.resolveVaultConfig = resolveVaultConfig;
38
+ exports.normalizeSenses = normalizeSenses;
37
39
  exports.buildDefaultAgentTemplate = buildDefaultAgentTemplate;
38
40
  exports.getAgentName = getAgentName;
39
41
  exports.getRepoRoot = getRepoRoot;
40
42
  exports.getAgentBundlesRoot = getAgentBundlesRoot;
41
43
  exports.getAgentRoot = getAgentRoot;
44
+ exports.getAgentStateRoot = getAgentStateRoot;
45
+ exports.getAgentRepoWorkspacesRoot = getAgentRepoWorkspacesRoot;
46
+ exports.getAgentDaemonStateRoot = getAgentDaemonStateRoot;
47
+ exports.getAgentDaemonLogsDir = getAgentDaemonLogsDir;
48
+ exports.getAgentDaemonLoggingConfigPath = getAgentDaemonLoggingConfigPath;
49
+ exports.getAgentMessagesRoot = getAgentMessagesRoot;
50
+ exports.getAgentToolsRoot = getAgentToolsRoot;
42
51
  exports.getAgentSecretsPath = getAgentSecretsPath;
43
52
  exports.loadAgentConfig = loadAgentConfig;
44
53
  exports.setAgentName = setAgentName;
54
+ exports.setAgentConfigOverride = setAgentConfigOverride;
55
+ exports.resetAgentConfigCache = resetAgentConfigCache;
45
56
  exports.resetIdentity = resetIdentity;
46
57
  const fs = __importStar(require("fs"));
47
58
  const os = __importStar(require("os"));
48
59
  const path = __importStar(require("path"));
49
60
  const runtime_1 = require("../nerves/runtime");
61
+ const migrate_config_1 = require("./migrate-config");
62
+ /** Single source of truth for per-provider credential field names, env var mappings, and prompt labels. */
63
+ exports.PROVIDER_CREDENTIALS = {
64
+ anthropic: { required: ["setupToken"], envVars: { ANTHROPIC_API_KEY: "setupToken" }, promptLabels: { setupToken: "Anthropic setup-token" } },
65
+ "openai-codex": { required: ["oauthAccessToken"], envVars: { OPENAI_API_KEY: "oauthAccessToken" }, promptLabels: { oauthAccessToken: "OpenAI Codex OAuth token" } },
66
+ azure: { required: ["apiKey", "endpoint", "deployment"], envVars: { AZURE_OPENAI_API_KEY: "apiKey", AZURE_OPENAI_KEY: "apiKey", AZURE_OPENAI_ENDPOINT: "endpoint", AZURE_OPENAI_DEPLOYMENT: "deployment" }, promptLabels: { apiKey: "Azure API key", endpoint: "Azure endpoint", deployment: "Azure deployment" } },
67
+ minimax: { required: ["apiKey"], envVars: { MINIMAX_API_KEY: "apiKey" }, promptLabels: { apiKey: "MiniMax API key" } },
68
+ "github-copilot": { required: ["githubToken", "baseUrl"], envVars: { GH_TOKEN: "githubToken", GITHUB_TOKEN: "githubToken" }, promptLabels: { githubToken: "GitHub token" } },
69
+ };
50
70
  exports.DEFAULT_AGENT_CONTEXT = {
51
71
  maxTokens: 80000,
52
72
  contextMargin: 20,
@@ -56,12 +76,85 @@ exports.DEFAULT_AGENT_PHRASES = {
56
76
  tool: ["running tool"],
57
77
  followup: ["processing"],
58
78
  };
79
+ exports.DEFAULT_VAULT_SERVER_URL = "https://vault.ouro.bot";
80
+ /**
81
+ * Resolve the vault config for an agent, applying defaults.
82
+ * If vault is not configured in agent.json, returns default values.
83
+ */
84
+ function resolveVaultConfig(agentName, config) {
85
+ return {
86
+ email: config?.email ?? `${agentName}@ouro.bot`,
87
+ serverUrl: config?.serverUrl ?? exports.DEFAULT_VAULT_SERVER_URL,
88
+ };
89
+ }
90
+ exports.DEFAULT_AGENT_SENSES = {
91
+ cli: { enabled: true },
92
+ teams: { enabled: false },
93
+ bluebubbles: { enabled: false },
94
+ };
95
+ function normalizeSenses(value, configFile) {
96
+ const defaults = {
97
+ cli: { ...exports.DEFAULT_AGENT_SENSES.cli },
98
+ teams: { ...exports.DEFAULT_AGENT_SENSES.teams },
99
+ bluebubbles: { ...exports.DEFAULT_AGENT_SENSES.bluebubbles },
100
+ };
101
+ if (value === undefined) {
102
+ return defaults;
103
+ }
104
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
105
+ (0, runtime_1.emitNervesEvent)({
106
+ level: "error",
107
+ event: "config_identity.error",
108
+ component: "config/identity",
109
+ message: "agent config has invalid senses block",
110
+ meta: { path: configFile },
111
+ });
112
+ throw new Error(`agent.json at ${configFile} must include senses as an object when present.`);
113
+ }
114
+ const raw = value;
115
+ const senseNames = ["cli", "teams", "bluebubbles"];
116
+ for (const senseName of senseNames) {
117
+ const rawSense = raw[senseName];
118
+ if (rawSense === undefined) {
119
+ continue;
120
+ }
121
+ if (!rawSense || typeof rawSense !== "object" || Array.isArray(rawSense)) {
122
+ (0, runtime_1.emitNervesEvent)({
123
+ level: "error",
124
+ event: "config_identity.error",
125
+ component: "config/identity",
126
+ message: "agent config has invalid sense config",
127
+ meta: { path: configFile, sense: senseName },
128
+ });
129
+ throw new Error(`agent.json at ${configFile} has invalid senses.${senseName} config.`);
130
+ }
131
+ const enabled = rawSense.enabled;
132
+ if (typeof enabled !== "boolean") {
133
+ (0, runtime_1.emitNervesEvent)({
134
+ level: "error",
135
+ event: "config_identity.error",
136
+ component: "config/identity",
137
+ message: "agent config has invalid sense enabled flag",
138
+ meta: { path: configFile, sense: senseName, enabled: enabled ?? null },
139
+ });
140
+ throw new Error(`agent.json at ${configFile} must include senses.${senseName}.enabled as boolean.`);
141
+ }
142
+ defaults[senseName] = { enabled };
143
+ }
144
+ return defaults;
145
+ }
59
146
  function buildDefaultAgentTemplate(_agentName) {
60
147
  return {
61
- version: 1,
148
+ version: 2,
62
149
  enabled: true,
63
- provider: "anthropic",
150
+ humanFacing: { provider: "anthropic", model: "claude-opus-4-6" },
151
+ agentFacing: { provider: "anthropic", model: "claude-opus-4-6" },
64
152
  context: { ...exports.DEFAULT_AGENT_CONTEXT },
153
+ senses: {
154
+ cli: { ...exports.DEFAULT_AGENT_SENSES.cli },
155
+ teams: { ...exports.DEFAULT_AGENT_SENSES.teams },
156
+ bluebubbles: { ...exports.DEFAULT_AGENT_SENSES.bluebubbles },
157
+ },
65
158
  phrases: {
66
159
  thinking: [...exports.DEFAULT_AGENT_PHRASES.thinking],
67
160
  tool: [...exports.DEFAULT_AGENT_PHRASES.tool],
@@ -70,7 +163,7 @@ function buildDefaultAgentTemplate(_agentName) {
70
163
  };
71
164
  }
72
165
  let _cachedAgentName = null;
73
- let _cachedAgentConfig = null;
166
+ let _agentConfigOverride = null;
74
167
  /**
75
168
  * Parse `--agent <name>` from process.argv.
76
169
  * Caches the result after first parse.
@@ -111,13 +204,49 @@ function getRepoRoot() {
111
204
  * Returns the shared bundle root directory: `~/AgentBundles/`
112
205
  */
113
206
  function getAgentBundlesRoot() {
114
- return path.join(os.homedir(), "AgentBundles");
207
+ const homeBase = process.env.WEBSITE_SITE_NAME ? "/home" : os.homedir();
208
+ return path.join(homeBase, "AgentBundles");
115
209
  }
116
210
  /**
117
211
  * Returns the agent-specific bundle directory: `~/AgentBundles/<agentName>.ouro/`
118
212
  */
119
- function getAgentRoot() {
120
- return path.join(getAgentBundlesRoot(), `${getAgentName()}.ouro`);
213
+ function getAgentRoot(agentName = getAgentName()) {
214
+ return path.join(getAgentBundlesRoot(), `${agentName}.ouro`);
215
+ }
216
+ function resolveOptionalAgentName(agentName) {
217
+ if (agentName && agentName.trim().length > 0)
218
+ return agentName.trim();
219
+ try {
220
+ return getAgentName();
221
+ }
222
+ catch {
223
+ return "slugger";
224
+ }
225
+ }
226
+ /**
227
+ * Returns the bundle-local runtime state directory: `~/AgentBundles/<agentName>.ouro/state/`
228
+ */
229
+ function getAgentStateRoot(agentName) {
230
+ return path.join(getAgentRoot(resolveOptionalAgentName(agentName)), "state");
231
+ }
232
+ exports.HARNESS_CANONICAL_REPO_URL = "https://github.com/ouroborosbot/ouroboros.git";
233
+ function getAgentRepoWorkspacesRoot(agentName) {
234
+ return path.join(getAgentStateRoot(resolveOptionalAgentName(agentName)), "workspaces");
235
+ }
236
+ function getAgentDaemonStateRoot(agentName) {
237
+ return path.join(getAgentStateRoot(resolveOptionalAgentName(agentName)), "daemon");
238
+ }
239
+ function getAgentDaemonLogsDir(agentName) {
240
+ return path.join(getAgentDaemonStateRoot(resolveOptionalAgentName(agentName)), "logs");
241
+ }
242
+ function getAgentDaemonLoggingConfigPath(agentName) {
243
+ return path.join(getAgentDaemonStateRoot(resolveOptionalAgentName(agentName)), "logging.json");
244
+ }
245
+ function getAgentMessagesRoot(agentName) {
246
+ return path.join(getAgentStateRoot(resolveOptionalAgentName(agentName)), "messages");
247
+ }
248
+ function getAgentToolsRoot(agentName) {
249
+ return path.join(getAgentStateRoot(resolveOptionalAgentName(agentName)), "tools");
121
250
  }
122
251
  /**
123
252
  * Returns the conventional secrets path: `~/.agentsecrets/<agentName>/secrets.json`
@@ -125,23 +254,11 @@ function getAgentRoot() {
125
254
  function getAgentSecretsPath(agentName = getAgentName()) {
126
255
  return path.join(os.homedir(), ".agentsecrets", agentName, "secrets.json");
127
256
  }
128
- /**
129
- * Load and parse `<agentRoot>/agent.json`.
130
- * Caches the result after first load.
131
- * Throws descriptive error if file is missing or contains invalid JSON.
132
- */
133
- function loadAgentConfig() {
134
- if (_cachedAgentConfig) {
135
- (0, runtime_1.emitNervesEvent)({
136
- event: "identity.resolve",
137
- component: "config/identity",
138
- message: "loaded agent config from cache",
139
- meta: { source: "cache" },
140
- });
141
- return _cachedAgentConfig;
142
- }
143
- const agentRoot = getAgentRoot();
144
- const configFile = path.join(agentRoot, "agent.json");
257
+ const VALID_PROVIDERS = ["azure", "minimax", "anthropic", "openai-codex", "github-copilot"];
258
+ function isValidProvider(value) {
259
+ return typeof value === "string" && VALID_PROVIDERS.includes(value);
260
+ }
261
+ function readAndParseAgentJson(configFile) {
145
262
  let raw;
146
263
  try {
147
264
  raw = fs.readFileSync(configFile, "utf-8");
@@ -159,9 +276,8 @@ function loadAgentConfig() {
159
276
  });
160
277
  throw new Error(`Cannot read agent.json at ${configFile}. Does the agent directory exist?`);
161
278
  }
162
- let parsed;
163
279
  try {
164
- parsed = JSON.parse(raw);
280
+ return JSON.parse(raw);
165
281
  }
166
282
  catch (error) {
167
283
  (0, runtime_1.emitNervesEvent)({
@@ -176,6 +292,62 @@ function loadAgentConfig() {
176
292
  });
177
293
  throw new Error(`Invalid JSON in agent.json at ${configFile}. Check syntax.`);
178
294
  }
295
+ }
296
+ function validateFacingConfig(parsed, facingName, configFile) {
297
+ const raw = parsed[facingName];
298
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
299
+ (0, runtime_1.emitNervesEvent)({
300
+ level: "error",
301
+ event: "config_identity.error",
302
+ component: "config/identity",
303
+ message: `agent config missing or invalid ${facingName}`,
304
+ meta: { path: configFile, [facingName]: raw ?? null },
305
+ });
306
+ throw new Error(`agent.json at ${configFile} must include ${facingName} as { provider, model }.`);
307
+ }
308
+ const facing = raw;
309
+ if (!isValidProvider(facing.provider)) {
310
+ (0, runtime_1.emitNervesEvent)({
311
+ level: "error",
312
+ event: "config_identity.error",
313
+ component: "config/identity",
314
+ message: `agent config has invalid provider in ${facingName}`,
315
+ meta: { path: configFile, provider: facing.provider ?? null },
316
+ });
317
+ throw new Error(`agent.json at ${configFile} ${facingName}.provider must be one of: ${VALID_PROVIDERS.join(", ")}.`);
318
+ }
319
+ if (typeof facing.model !== "string") {
320
+ (0, runtime_1.emitNervesEvent)({
321
+ level: "error",
322
+ event: "config_identity.error",
323
+ component: "config/identity",
324
+ message: `agent config has invalid model in ${facingName}`,
325
+ meta: { path: configFile, model: facing.model ?? null },
326
+ });
327
+ throw new Error(`agent.json at ${configFile} ${facingName}.model must be a string.`);
328
+ }
329
+ return { provider: facing.provider, model: facing.model };
330
+ }
331
+ /**
332
+ * Load and parse `<agentRoot>/agent.json`.
333
+ * Reads the file fresh on each call unless an override is set.
334
+ * If the config is v1, auto-migrates to v2 via migrateAgentConfigV1ToV2 and re-reads.
335
+ * Throws descriptive error if file is missing or contains invalid JSON.
336
+ */
337
+ function loadAgentConfig() {
338
+ if (_agentConfigOverride) {
339
+ return _agentConfigOverride;
340
+ }
341
+ const agentRoot = getAgentRoot();
342
+ const configFile = path.join(agentRoot, "agent.json");
343
+ let parsed = readAndParseAgentJson(configFile);
344
+ // Inline migration: v1 -> v2
345
+ const rawVersion = parsed.version;
346
+ const initialVersion = typeof rawVersion === "number" ? rawVersion : 1;
347
+ if (initialVersion < 2) {
348
+ (0, migrate_config_1.migrateAgentConfigV1ToV2)(agentRoot);
349
+ parsed = readAndParseAgentJson(configFile);
350
+ }
179
351
  const existingPhrases = parsed.phrases;
180
352
  const needsFill = !existingPhrases ||
181
353
  !existingPhrases.thinking ||
@@ -197,27 +369,11 @@ function loadAgentConfig() {
197
369
  });
198
370
  fs.writeFileSync(configFile, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
199
371
  }
200
- const rawProvider = parsed.provider;
201
- if (rawProvider !== "azure" &&
202
- rawProvider !== "minimax" &&
203
- rawProvider !== "anthropic" &&
204
- rawProvider !== "openai-codex") {
205
- (0, runtime_1.emitNervesEvent)({
206
- level: "error",
207
- event: "config_identity.error",
208
- component: "config/identity",
209
- message: "agent config missing or invalid provider",
210
- meta: {
211
- path: configFile,
212
- provider: rawProvider,
213
- },
214
- });
215
- throw new Error(`agent.json at ${configFile} must include provider: "azure", "minimax", "anthropic", or "openai-codex".`);
216
- }
217
- const rawVersion = parsed.version;
218
- const version = rawVersion === undefined ? 1 : rawVersion;
219
- if (typeof version !== "number" ||
220
- !Number.isInteger(version) ||
372
+ // Validate v2 facing configs
373
+ const humanFacing = validateFacingConfig(parsed, "humanFacing", configFile);
374
+ const agentFacing = validateFacingConfig(parsed, "agentFacing", configFile);
375
+ const version = typeof parsed.version === "number" ? parsed.version : 1;
376
+ if (!Number.isInteger(version) ||
221
377
  version < 1) {
222
378
  (0, runtime_1.emitNervesEvent)({
223
379
  level: "error",
@@ -226,7 +382,7 @@ function loadAgentConfig() {
226
382
  message: "agent config missing or invalid version",
227
383
  meta: {
228
384
  path: configFile,
229
- version: rawVersion,
385
+ version: parsed.version,
230
386
  },
231
387
  });
232
388
  throw new Error(`agent.json at ${configFile} must include version as integer >= 1.`);
@@ -246,21 +402,37 @@ function loadAgentConfig() {
246
402
  });
247
403
  throw new Error(`agent.json at ${configFile} must include enabled as boolean.`);
248
404
  }
249
- _cachedAgentConfig = {
405
+ // Tolerate deprecated provider field for backward compatibility
406
+ const rawProvider = parsed.provider;
407
+ const provider = isValidProvider(rawProvider) ? rawProvider : undefined;
408
+ // Spread parsed first so any field present in AgentConfig is carried
409
+ // through by default, then explicitly override the fields that need
410
+ // validation or normalization. This eliminates the field-drop bug class
411
+ // that caused the `sync` block (and previously `shell`) to be silently
412
+ // omitted from the returned config. Regression-guarded by the
413
+ // Required<AgentConfig> contract test in identity-contract.test.ts.
414
+ const config = {
415
+ ...parsed,
250
416
  version,
251
417
  enabled,
252
- provider: rawProvider,
253
- context: parsed.context,
254
- logging: parsed.logging,
418
+ humanFacing,
419
+ agentFacing,
420
+ senses: normalizeSenses(parsed.senses, configFile),
255
421
  phrases: parsed.phrases,
256
422
  };
423
+ if (provider !== undefined) {
424
+ config.provider = provider;
425
+ }
426
+ else {
427
+ delete config.provider;
428
+ }
257
429
  (0, runtime_1.emitNervesEvent)({
258
430
  event: "identity.resolve",
259
431
  component: "config/identity",
260
432
  message: "loaded agent config from disk",
261
433
  meta: { source: "disk" },
262
434
  });
263
- return _cachedAgentConfig;
435
+ return config;
264
436
  }
265
437
  /**
266
438
  * Prime the agent name cache explicitly.
@@ -271,11 +443,26 @@ function loadAgentConfig() {
271
443
  function setAgentName(name) {
272
444
  _cachedAgentName = name;
273
445
  }
446
+ /**
447
+ * Override the agent config returned by loadAgentConfig().
448
+ * When set to a non-null AgentConfig, loadAgentConfig() returns the override
449
+ * instead of reading from disk. When set to null, normal disk-based loading resumes.
450
+ */
451
+ function setAgentConfigOverride(config) {
452
+ _agentConfigOverride = config;
453
+ }
454
+ /**
455
+ * Preserve the compatibility hook for callers that previously cleared cached
456
+ * disk-backed agent config. Agent config is now read fresh on every call.
457
+ */
458
+ function resetAgentConfigCache() {
459
+ // No-op: disk-backed agent config is no longer memoized in-process.
460
+ }
274
461
  /**
275
462
  * Clear all cached identity state.
276
463
  * Used in tests and when switching agent context.
277
464
  */
278
465
  function resetIdentity() {
279
466
  _cachedAgentName = null;
280
- _cachedAgentConfig = null;
467
+ _agentConfigOverride = null;
281
468
  }