@ouro.bot/cli 0.1.0-alpha.28 → 0.1.0-alpha.280

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 (267) hide show
  1. package/README.md +187 -191
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
  4. package/changelog.json +1696 -0
  5. package/dist/arc/attention-types.js +8 -0
  6. package/dist/arc/cares.js +140 -0
  7. package/dist/arc/episodes.js +117 -0
  8. package/dist/arc/intentions.js +133 -0
  9. package/dist/arc/json-store.js +117 -0
  10. package/dist/arc/obligations.js +237 -0
  11. package/dist/arc/presence.js +185 -0
  12. package/dist/heart/active-work.js +832 -0
  13. package/dist/heart/agent-entry.js +37 -2
  14. package/dist/heart/auth/auth-flow.js +456 -0
  15. package/dist/heart/bridges/manager.js +358 -0
  16. package/dist/heart/bridges/state-machine.js +135 -0
  17. package/dist/heart/bridges/store.js +123 -0
  18. package/dist/heart/commitments.js +111 -0
  19. package/dist/heart/config-registry.js +304 -0
  20. package/dist/heart/config.js +63 -30
  21. package/dist/heart/core.js +644 -196
  22. package/dist/heart/cross-chat-delivery.js +131 -0
  23. package/dist/heart/daemon/agent-config-check.js +149 -0
  24. package/dist/heart/daemon/agent-discovery.js +79 -3
  25. package/dist/heart/daemon/agent-service.js +360 -0
  26. package/dist/heart/daemon/cadence.js +70 -0
  27. package/dist/heart/daemon/cli-defaults.js +574 -0
  28. package/dist/heart/daemon/cli-exec.js +1932 -0
  29. package/dist/heart/daemon/cli-parse.js +762 -0
  30. package/dist/heart/daemon/cli-render.js +503 -0
  31. package/dist/heart/daemon/cli-types.js +8 -0
  32. package/dist/heart/daemon/daemon-cli.js +29 -1155
  33. package/dist/heart/daemon/daemon-entry.js +234 -3
  34. package/dist/heart/daemon/daemon-health.js +136 -0
  35. package/dist/heart/daemon/daemon-runtime-sync.js +153 -12
  36. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  37. package/dist/heart/daemon/daemon.js +702 -57
  38. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  39. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  40. package/dist/heart/daemon/inner-status.js +89 -0
  41. package/dist/heart/daemon/launchd.js +46 -9
  42. package/dist/heart/daemon/log-tailer.js +82 -12
  43. package/dist/heart/daemon/logs-prune.js +105 -0
  44. package/dist/heart/daemon/message-router.js +17 -8
  45. package/dist/heart/daemon/os-cron-deps.js +134 -0
  46. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  47. package/dist/heart/daemon/process-manager.js +180 -0
  48. package/dist/heart/daemon/pulse.js +463 -0
  49. package/dist/heart/daemon/run-hooks.js +2 -0
  50. package/dist/heart/daemon/runtime-logging.js +67 -16
  51. package/dist/heart/daemon/runtime-metadata.js +101 -0
  52. package/dist/heart/daemon/runtime-mode.js +67 -0
  53. package/dist/heart/daemon/safe-mode.js +161 -0
  54. package/dist/heart/daemon/sense-manager.js +72 -3
  55. package/dist/heart/daemon/session-id-resolver.js +131 -0
  56. package/dist/heart/daemon/skill-management-installer.js +94 -0
  57. package/dist/heart/daemon/socket-client.js +307 -0
  58. package/dist/heart/daemon/task-scheduler.js +3 -25
  59. package/dist/heart/daemon/thoughts.js +510 -0
  60. package/dist/heart/delegation.js +62 -0
  61. package/dist/heart/habits/habit-migration.js +181 -0
  62. package/dist/heart/habits/habit-parser.js +119 -0
  63. package/dist/heart/habits/habit-scheduler.js +371 -0
  64. package/dist/heart/{daemon → hatch}/hatch-flow.js +30 -120
  65. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  66. package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
  67. package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
  68. package/dist/heart/identity.js +163 -60
  69. package/dist/heart/kicks.js +2 -20
  70. package/dist/heart/mcp/mcp-server.js +653 -0
  71. package/dist/heart/migrate-config.js +127 -0
  72. package/dist/heart/model-capabilities.js +59 -0
  73. package/dist/heart/outlook/outlook-http.js +439 -0
  74. package/dist/heart/outlook/outlook-read.js +1618 -0
  75. package/dist/heart/outlook/outlook-render.js +1032 -0
  76. package/dist/heart/outlook/outlook-types.js +7 -0
  77. package/dist/heart/outlook/outlook-view.js +194 -0
  78. package/dist/heart/progress-story.js +42 -0
  79. package/dist/heart/provider-failover.js +88 -0
  80. package/dist/heart/provider-ping.js +162 -0
  81. package/dist/heart/providers/anthropic-token.js +163 -0
  82. package/dist/heart/providers/anthropic.js +169 -46
  83. package/dist/heart/providers/azure.js +98 -11
  84. package/dist/heart/providers/error-classification.js +63 -0
  85. package/dist/heart/providers/github-copilot.js +136 -0
  86. package/dist/heart/providers/minimax-vlm.js +189 -0
  87. package/dist/heart/providers/minimax.js +23 -5
  88. package/dist/heart/providers/openai-codex.js +33 -22
  89. package/dist/heart/session-activity.js +172 -0
  90. package/dist/heart/session-recall.js +216 -0
  91. package/dist/heart/start-of-turn-packet.js +330 -0
  92. package/dist/heart/streaming.js +36 -27
  93. package/dist/heart/sync.js +277 -0
  94. package/dist/heart/target-resolution.js +127 -0
  95. package/dist/heart/tempo.js +93 -0
  96. package/dist/heart/temporal-view.js +41 -0
  97. package/dist/heart/tool-activity-callbacks.js +36 -0
  98. package/dist/heart/tool-description.js +135 -0
  99. package/dist/heart/tool-loop.js +200 -0
  100. package/dist/heart/turn-context.js +358 -0
  101. package/dist/heart/turn-coordinator.js +28 -0
  102. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  103. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  104. package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
  105. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  106. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  107. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  108. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  109. package/dist/mind/associative-recall.js +126 -66
  110. package/dist/mind/bundle-manifest.js +8 -1
  111. package/dist/mind/context.js +125 -14
  112. package/dist/mind/{memory.js → diary.js} +68 -96
  113. package/dist/mind/embedding-provider.js +60 -0
  114. package/dist/mind/file-state.js +179 -0
  115. package/dist/mind/first-impressions.js +14 -1
  116. package/dist/mind/friends/channel.js +56 -0
  117. package/dist/mind/friends/group-context.js +144 -0
  118. package/dist/mind/friends/resolver.js +37 -0
  119. package/dist/mind/friends/store-file.js +58 -3
  120. package/dist/mind/friends/trust-explanation.js +74 -0
  121. package/dist/mind/friends/types.js +8 -0
  122. package/dist/mind/journal-index.js +161 -0
  123. package/dist/mind/obligation-steering.js +221 -0
  124. package/dist/mind/pending.js +76 -9
  125. package/dist/mind/prompt.js +874 -109
  126. package/dist/mind/scrutiny.js +173 -0
  127. package/dist/mind/token-estimate.js +8 -12
  128. package/dist/nerves/cli-logging.js +7 -1
  129. package/dist/nerves/coverage/audit.js +1 -1
  130. package/dist/nerves/coverage/file-completeness.js +50 -5
  131. package/dist/nerves/coverage/run-artifacts.js +1 -1
  132. package/dist/nerves/event-buffer.js +111 -0
  133. package/dist/nerves/index.js +220 -4
  134. package/dist/nerves/observation.js +20 -0
  135. package/dist/nerves/runtime.js +5 -1
  136. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  137. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  138. package/dist/outlook-ui/index.html +15 -0
  139. package/dist/repertoire/ado-client.js +15 -56
  140. package/dist/repertoire/ado-semantic.js +11 -10
  141. package/dist/repertoire/api-client.js +97 -0
  142. package/dist/repertoire/bitwarden-store.js +319 -0
  143. package/dist/repertoire/bw-installer.js +79 -0
  144. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  145. package/dist/repertoire/coding/context-pack.js +330 -0
  146. package/dist/repertoire/coding/feedback.js +197 -30
  147. package/dist/repertoire/coding/manager.js +149 -2
  148. package/dist/repertoire/coding/spawner.js +55 -9
  149. package/dist/repertoire/coding/tools.js +170 -7
  150. package/dist/repertoire/commerce-errors.js +109 -0
  151. package/dist/repertoire/commerce-self-test.js +156 -0
  152. package/dist/repertoire/credential-access.js +515 -0
  153. package/dist/repertoire/duffel-client.js +185 -0
  154. package/dist/repertoire/github-client.js +14 -55
  155. package/dist/repertoire/graph-client.js +11 -52
  156. package/dist/repertoire/guardrails.js +369 -0
  157. package/dist/repertoire/mcp-client.js +255 -0
  158. package/dist/repertoire/mcp-manager.js +305 -0
  159. package/dist/repertoire/mcp-tools.js +63 -0
  160. package/dist/repertoire/shell-sessions.js +133 -0
  161. package/dist/repertoire/skills.js +14 -23
  162. package/dist/repertoire/stripe-client.js +131 -0
  163. package/dist/repertoire/tasks/board.js +43 -5
  164. package/dist/repertoire/tasks/fix.js +182 -0
  165. package/dist/repertoire/tasks/index.js +28 -10
  166. package/dist/repertoire/tasks/lifecycle.js +2 -2
  167. package/dist/repertoire/tasks/parser.js +3 -2
  168. package/dist/repertoire/tasks/scanner.js +194 -37
  169. package/dist/repertoire/tasks/transitions.js +11 -28
  170. package/dist/repertoire/tools-base.js +43 -771
  171. package/dist/repertoire/tools-bluebubbles.js +201 -0
  172. package/dist/repertoire/tools-bridge.js +141 -0
  173. package/dist/repertoire/tools-config.js +185 -0
  174. package/dist/repertoire/tools-continuity.js +248 -0
  175. package/dist/repertoire/tools-credential.js +182 -0
  176. package/dist/repertoire/tools-files.js +342 -0
  177. package/dist/repertoire/tools-flight.js +224 -0
  178. package/dist/repertoire/tools-flow.js +62 -0
  179. package/dist/repertoire/tools-github.js +1 -7
  180. package/dist/repertoire/tools-memory.js +347 -0
  181. package/dist/repertoire/tools-session.js +739 -0
  182. package/dist/repertoire/tools-shell.js +120 -0
  183. package/dist/repertoire/tools-stripe.js +180 -0
  184. package/dist/repertoire/tools-surface.js +243 -0
  185. package/dist/repertoire/tools-teams.js +12 -62
  186. package/dist/repertoire/tools-travel.js +125 -0
  187. package/dist/repertoire/tools-user-profile.js +144 -0
  188. package/dist/repertoire/tools-vault.js +110 -0
  189. package/dist/repertoire/tools.js +155 -130
  190. package/dist/repertoire/travel-api-client.js +360 -0
  191. package/dist/repertoire/user-profile.js +118 -0
  192. package/dist/repertoire/vault-setup.js +241 -0
  193. package/dist/scripts/claude-code-hook.js +41 -0
  194. package/dist/scripts/claude-code-stop-hook.js +47 -0
  195. package/dist/senses/attention-queue.js +97 -0
  196. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  197. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +143 -9
  198. package/dist/senses/bluebubbles/entry.js +13 -0
  199. package/dist/senses/bluebubbles/inbound-log.js +110 -0
  200. package/dist/senses/bluebubbles/index.js +1410 -0
  201. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +140 -23
  202. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +20 -5
  203. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  204. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  205. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  206. package/dist/senses/cli/bracketed-paste.js +82 -0
  207. package/dist/senses/cli/image-paste.js +211 -0
  208. package/dist/senses/cli/image-ref-navigation.js +75 -0
  209. package/dist/senses/cli/ink-app.js +156 -0
  210. package/dist/senses/cli/inline-diff.js +64 -0
  211. package/dist/senses/cli/input-keys.js +174 -0
  212. package/dist/senses/cli/kill-ring.js +86 -0
  213. package/dist/senses/cli/message-list.js +51 -0
  214. package/dist/senses/cli/ouro-tui.js +595 -0
  215. package/dist/senses/cli/spinner-imperative.js +135 -0
  216. package/dist/senses/cli/spinner.js +101 -0
  217. package/dist/senses/cli/status-line.js +60 -0
  218. package/dist/senses/cli/streaming-markdown.js +526 -0
  219. package/dist/senses/cli/tool-display.js +83 -0
  220. package/dist/senses/cli/tool-render.js +85 -0
  221. package/dist/senses/cli/tui-store.js +240 -0
  222. package/dist/senses/cli/virtual-list.js +35 -0
  223. package/dist/senses/cli-entry.js +1 -1
  224. package/dist/senses/cli-layout.js +187 -0
  225. package/dist/senses/cli.js +569 -246
  226. package/dist/senses/commands.js +65 -1
  227. package/dist/senses/continuity.js +94 -0
  228. package/dist/senses/habit-turn-message.js +108 -0
  229. package/dist/senses/inner-dialog-worker.js +112 -19
  230. package/dist/senses/inner-dialog.js +593 -85
  231. package/dist/senses/pipeline.js +552 -0
  232. package/dist/senses/shared-turn.js +199 -0
  233. package/dist/senses/surface-tool.js +68 -0
  234. package/dist/senses/teams.js +664 -165
  235. package/dist/senses/trust-gate.js +112 -2
  236. package/package.json +14 -7
  237. package/skills/agent-commerce.md +106 -0
  238. package/skills/browser-navigation.md +110 -0
  239. package/skills/commerce-setup-guide.md +116 -0
  240. package/skills/commerce-setup.md +84 -0
  241. package/skills/configure-dev-tools.md +81 -0
  242. package/skills/travel-planning.md +138 -0
  243. package/dist/heart/daemon/subagent-installer.js +0 -134
  244. package/dist/senses/bluebubbles-entry.js +0 -11
  245. package/dist/senses/bluebubbles.js +0 -421
  246. package/dist/senses/debug-activity.js +0 -108
  247. package/subagents/README.md +0 -73
  248. package/subagents/work-doer.md +0 -235
  249. package/subagents/work-merger.md +0 -618
  250. package/subagents/work-planner.md +0 -382
  251. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  252. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  253. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  254. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  255. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  256. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  257. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  258. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  259. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  260. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  261. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  262. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  263. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  264. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  265. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  266. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  267. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -0,0 +1,94 @@
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.ensureSkillManagement = ensureSkillManagement;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const runtime_1 = require("../../nerves/runtime");
40
+ const identity_1 = require("../identity");
41
+ const SKILL_MANAGEMENT_URL = "https://raw.githubusercontent.com/ouroborosbot/ouroboros-skills/main/skills/skill-management/SKILL.md";
42
+ async function ensureSkillManagement() {
43
+ const bundlesRoot = (0, identity_1.getAgentBundlesRoot)();
44
+ if (!fs.existsSync(bundlesRoot))
45
+ return;
46
+ // Find all agent bundles
47
+ const entries = fs.readdirSync(bundlesRoot).filter(e => e.endsWith(".ouro"));
48
+ if (entries.length === 0)
49
+ return;
50
+ // Check if ANY bundle is missing the skill
51
+ const missing = entries.filter(e => {
52
+ const targetPath = path.join(bundlesRoot, e, "skills", "skill-management.md");
53
+ return !fs.existsSync(targetPath);
54
+ });
55
+ if (missing.length === 0)
56
+ return;
57
+ // eslint-disable-next-line no-console -- terminal UX: visible install status
58
+ console.log("installing skill-management from ouroboros-skills...");
59
+ try {
60
+ const response = await fetch(SKILL_MANAGEMENT_URL);
61
+ if (!response.ok) {
62
+ // eslint-disable-next-line no-console -- terminal UX: visible install status
63
+ console.error(`✗ failed to fetch skill-management (HTTP ${response.status})`);
64
+ (0, runtime_1.emitNervesEvent)({
65
+ level: "warn",
66
+ component: "daemon",
67
+ event: "daemon.skill_management_install_error",
68
+ message: "failed to fetch skill-management from GitHub",
69
+ meta: { status: response.status, url: SKILL_MANAGEMENT_URL },
70
+ });
71
+ return;
72
+ }
73
+ const content = await response.text();
74
+ for (const bundle of missing) {
75
+ const skillsDir = path.join(bundlesRoot, bundle, "skills");
76
+ const targetPath = path.join(skillsDir, "skill-management.md");
77
+ fs.mkdirSync(skillsDir, { recursive: true });
78
+ fs.writeFileSync(targetPath, content, "utf-8");
79
+ }
80
+ // eslint-disable-next-line no-console -- terminal UX: visible install status
81
+ console.log(`✓ installed skill-management (${missing.length} agent${missing.length > 1 ? "s" : ""})`);
82
+ }
83
+ catch (error) {
84
+ // eslint-disable-next-line no-console -- terminal UX: visible install status
85
+ console.error(`✗ failed to install skill-management: ${error instanceof Error ? error.message : String(error)}`);
86
+ (0, runtime_1.emitNervesEvent)({
87
+ level: "warn",
88
+ component: "daemon",
89
+ event: "daemon.skill_management_install_error",
90
+ message: "failed to install skill-management skill",
91
+ meta: { error: error instanceof Error ? error.message : String(error) },
92
+ });
93
+ }
94
+ }
@@ -0,0 +1,307 @@
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.DEFAULT_DAEMON_SOCKET_PATH = void 0;
37
+ exports.__bypassVitestGuardForTests = __bypassVitestGuardForTests;
38
+ exports.sendDaemonCommand = sendDaemonCommand;
39
+ exports.checkDaemonSocketAlive = checkDaemonSocketAlive;
40
+ exports.requestInnerWake = requestInnerWake;
41
+ const fs = __importStar(require("fs"));
42
+ const net = __importStar(require("net"));
43
+ const runtime_1 = require("../../nerves/runtime");
44
+ exports.DEFAULT_DAEMON_SOCKET_PATH = "/tmp/ouroboros-daemon.sock";
45
+ /**
46
+ * Defense-in-depth: detect if we're running under vitest. Tests that forget
47
+ * to `vi.mock("../../heart/daemon/socket-client")` would otherwise leak real
48
+ * `inner.wake` commands (with whatever literal agent name the test uses,
49
+ * commonly "testagent") into whichever real daemon happens to be running on
50
+ * the developer's machine. That has caused real outages when test loops
51
+ * flooded the production-on-localhost daemon.
52
+ *
53
+ * We detect vitest via `process.argv` (not env vars — the project bans those)
54
+ * and convert all socket operations into safe no-ops. Individual tests are
55
+ * still expected to vi.mock this module so they can assert on call counts,
56
+ * but this guard guarantees that "I forgot to mock" can never again take
57
+ * down the daemon.
58
+ *
59
+ * The socket-client's OWN tests (which exercise the real functions against a
60
+ * test socket) call `__bypassVitestGuardForTests(true)` to opt out of the
61
+ * guard. We persist that flag on globalThis so it survives `vi.resetModules`
62
+ * (which clears the module cache between tests).
63
+ *
64
+ * HARDENING (cross-file leak protection): the bypass flag lives on globalThis
65
+ * and is process-wide. With vitest's default `fileParallelism: true`,
66
+ * concurrently-running test files in the same worker can have the bypass on
67
+ * even though they didn't ask for it — and any test that uses
68
+ * `name: "testagent"` and exercises a code path through this module will
69
+ * leak `inner.wake testagent` to the production daemon socket. We saw this
70
+ * cause a real outage on 2026-04-08 (daemon SIGTERMed mid-validation).
71
+ *
72
+ * Defense: even when the bypass flag is set, we ALWAYS hard-block calls that
73
+ * target the production daemon socket path. Test files that legitimately
74
+ * exercise the real socket-client code paths use a synthetic socket path like
75
+ * `/tmp/daemon.sock` or `/tmp/some-real-daemon.sock` — those keep working.
76
+ * Calls to `/tmp/ouroboros-daemon.sock` (DEFAULT_DAEMON_SOCKET_PATH) under
77
+ * vitest are unconditionally blocked, regardless of bypass state. This makes
78
+ * the cross-file leak vector impossible without restricting legitimate
79
+ * socket-client unit tests.
80
+ */
81
+ const BYPASS_KEY = "__ouro_socket_client_bypass_vitest_guard__";
82
+ /** ONLY for socket-client.test.ts. Do not call from any other test or production code. */
83
+ function __bypassVitestGuardForTests(bypass) {
84
+ ;
85
+ globalThis[BYPASS_KEY] = bypass;
86
+ }
87
+ function isVitestProcess() {
88
+ /* v8 ignore next -- defensive: process and process.argv always exist in node @preserve */
89
+ if (typeof process === "undefined" || !Array.isArray(process.argv))
90
+ return false;
91
+ return process.argv.some((arg) => typeof arg === "string" && arg.includes("vitest"));
92
+ }
93
+ function isProductionDaemonSocket(socketPath) {
94
+ return socketPath === exports.DEFAULT_DAEMON_SOCKET_PATH;
95
+ }
96
+ /**
97
+ * Returns true when this socket call should be converted into a safe no-op
98
+ * because we're under vitest and the call would otherwise leak into a real
99
+ * daemon. The bypass flag short-circuits the guard for non-production socket
100
+ * paths only — production socket paths are ALWAYS blocked under vitest.
101
+ */
102
+ function shouldSuppressSocketCall(socketPath) {
103
+ if (!isVitestProcess())
104
+ return false;
105
+ if (isProductionDaemonSocket(socketPath))
106
+ return true;
107
+ return globalThis[BYPASS_KEY] !== true;
108
+ }
109
+ function sendDaemonCommand(socketPath, command) {
110
+ if (shouldSuppressSocketCall(socketPath)) {
111
+ (0, runtime_1.emitNervesEvent)({
112
+ level: "warn",
113
+ component: "daemon",
114
+ event: "daemon.socket_command_test_blocked",
115
+ message: "blocked socket command from leaking into real daemon under vitest",
116
+ meta: { socketPath, kind: command.kind, isProductionSocket: isProductionDaemonSocket(socketPath) },
117
+ });
118
+ return Promise.resolve({ ok: true, message: "test mode: socket call suppressed" });
119
+ }
120
+ (0, runtime_1.emitNervesEvent)({
121
+ component: "daemon",
122
+ event: "daemon.socket_command_start",
123
+ message: "sending daemon command over socket",
124
+ meta: { socketPath, kind: command.kind },
125
+ });
126
+ return new Promise((resolve, reject) => {
127
+ const client = net.createConnection(socketPath);
128
+ let raw = "";
129
+ client.on("connect", () => {
130
+ // Write the command + newline delimiter. DO NOT call client.end()
131
+ // afterwards — the server closes the connection once it has written
132
+ // its response, which triggers our on("end") handler with the full
133
+ // response in `raw`.
134
+ //
135
+ // Calling client.end() here half-closes the TCP connection. The
136
+ // daemon server uses net.createServer() with the default
137
+ // allowHalfOpen: false, so when the server sees the client's FIN it
138
+ // auto-closes its own writable side — and any response the server
139
+ // tries to write after processing a long-running command (like
140
+ // agent.senseTurn, which runs a full LLM turn) gets dropped on the
141
+ // floor. Verified via repro: with client.end(), agent.senseTurn
142
+ // returns empty in ~149ms; without it, the same call returns the real
143
+ // response in ~5.8s. This is a regression of the fix in #303 that
144
+ // was silently reverted by 253e4b1f (commit titled "socket half-close
145
+ // fix" but actually *added* the half-close back).
146
+ client.write(JSON.stringify(command) + "\n");
147
+ });
148
+ client.on("data", (chunk) => {
149
+ raw += chunk.toString("utf-8");
150
+ });
151
+ client.on("error", (error) => {
152
+ (0, runtime_1.emitNervesEvent)({
153
+ level: "error",
154
+ component: "daemon",
155
+ event: "daemon.socket_command_error",
156
+ message: "daemon socket command failed",
157
+ meta: {
158
+ socketPath,
159
+ kind: command.kind,
160
+ error: error.message,
161
+ },
162
+ });
163
+ reject(error);
164
+ });
165
+ client.on("end", () => {
166
+ const trimmed = raw.trim();
167
+ if (trimmed.length === 0 && command.kind === "daemon.stop") {
168
+ (0, runtime_1.emitNervesEvent)({
169
+ component: "daemon",
170
+ event: "daemon.socket_command_end",
171
+ message: "daemon socket command completed",
172
+ meta: { socketPath, kind: command.kind, ok: true },
173
+ });
174
+ resolve({ ok: true, message: "daemon stopped" });
175
+ return;
176
+ }
177
+ if (trimmed.length === 0) {
178
+ const error = new Error("Daemon returned empty response.");
179
+ (0, runtime_1.emitNervesEvent)({
180
+ level: "error",
181
+ component: "daemon",
182
+ event: "daemon.socket_command_error",
183
+ message: "daemon socket command returned empty response",
184
+ meta: {
185
+ socketPath,
186
+ kind: command.kind,
187
+ error: error.message,
188
+ },
189
+ });
190
+ reject(error);
191
+ return;
192
+ }
193
+ try {
194
+ const parsed = JSON.parse(trimmed);
195
+ (0, runtime_1.emitNervesEvent)({
196
+ component: "daemon",
197
+ event: "daemon.socket_command_end",
198
+ message: "daemon socket command completed",
199
+ meta: {
200
+ socketPath,
201
+ kind: command.kind,
202
+ ok: parsed.ok,
203
+ },
204
+ });
205
+ resolve(parsed);
206
+ }
207
+ catch (error) {
208
+ (0, runtime_1.emitNervesEvent)({
209
+ level: "error",
210
+ component: "daemon",
211
+ event: "daemon.socket_command_error",
212
+ message: "daemon socket command returned invalid JSON",
213
+ meta: {
214
+ socketPath,
215
+ kind: command.kind,
216
+ error: error instanceof Error ? error.message : String(error),
217
+ },
218
+ });
219
+ reject(error);
220
+ }
221
+ });
222
+ });
223
+ }
224
+ function checkDaemonSocketAlive(socketPath) {
225
+ if (shouldSuppressSocketCall(socketPath)) {
226
+ return Promise.resolve(false);
227
+ }
228
+ (0, runtime_1.emitNervesEvent)({
229
+ component: "daemon",
230
+ event: "daemon.socket_alive_check_start",
231
+ message: "checking daemon socket health",
232
+ meta: { socketPath },
233
+ });
234
+ return new Promise((resolve) => {
235
+ const client = net.createConnection(socketPath);
236
+ let raw = "";
237
+ let done = false;
238
+ const finalize = (alive) => {
239
+ if (done)
240
+ return;
241
+ done = true;
242
+ (0, runtime_1.emitNervesEvent)({
243
+ component: "daemon",
244
+ event: "daemon.socket_alive_check_end",
245
+ message: "daemon socket health check completed",
246
+ meta: { socketPath, alive },
247
+ });
248
+ resolve(alive);
249
+ };
250
+ if ("setTimeout" in client && typeof client.setTimeout === "function") {
251
+ client.setTimeout(800, () => {
252
+ client.destroy();
253
+ finalize(false);
254
+ });
255
+ }
256
+ client.on("connect", () => {
257
+ // Same half-close rationale as sendDaemonCommand: do NOT call
258
+ // client.end() here. The server closes after responding and that
259
+ // triggers the on("end") handler below.
260
+ client.write(JSON.stringify({ kind: "daemon.status" }) + "\n");
261
+ });
262
+ client.on("data", (chunk) => {
263
+ raw += chunk.toString("utf-8");
264
+ });
265
+ client.on("error", () => finalize(false));
266
+ client.on("end", () => {
267
+ if (raw.trim().length === 0) {
268
+ finalize(false);
269
+ return;
270
+ }
271
+ try {
272
+ JSON.parse(raw);
273
+ finalize(true);
274
+ }
275
+ catch {
276
+ finalize(false);
277
+ }
278
+ });
279
+ });
280
+ }
281
+ async function requestInnerWake(agent, socketPath = exports.DEFAULT_DAEMON_SOCKET_PATH) {
282
+ if (shouldSuppressSocketCall(socketPath)) {
283
+ (0, runtime_1.emitNervesEvent)({
284
+ level: "warn",
285
+ component: "daemon",
286
+ event: "daemon.inner_wake_test_blocked",
287
+ message: "blocked inner wake from leaking into real daemon under vitest",
288
+ meta: { agent, socketPath, isProductionSocket: isProductionDaemonSocket(socketPath) },
289
+ });
290
+ return null;
291
+ }
292
+ const socketAvailable = fs.existsSync(socketPath);
293
+ (0, runtime_1.emitNervesEvent)({
294
+ component: "daemon",
295
+ event: "daemon.inner_wake_request",
296
+ message: "requesting daemon-managed inner wake",
297
+ meta: {
298
+ agent,
299
+ socketPath,
300
+ socketAvailable,
301
+ },
302
+ });
303
+ if (!socketAvailable) {
304
+ return null;
305
+ }
306
+ return sendDaemonCommand(socketPath, { kind: "inner.wake", agent });
307
+ }
@@ -39,6 +39,7 @@ const path = __importStar(require("path"));
39
39
  const identity_1 = require("../identity");
40
40
  const runtime_1 = require("../../nerves/runtime");
41
41
  const parser_1 = require("../../repertoire/tasks/parser");
42
+ const cadence_1 = require("./cadence");
42
43
  function walkMarkdownFiles(root, readdirSync, existsSync, files) {
43
44
  if (!existsSync(root))
44
45
  return;
@@ -53,29 +54,6 @@ function walkMarkdownFiles(root, readdirSync, existsSync, files) {
53
54
  }
54
55
  }
55
56
  }
56
- function parseCadence(raw) {
57
- if (typeof raw !== "string")
58
- return null;
59
- const value = raw.trim();
60
- if (!value)
61
- return null;
62
- // Cron format (minute hour day month weekday)
63
- if (/^\S+\s+\S+\s+\S+\s+\S+\s+\S+$/.test(value)) {
64
- return value;
65
- }
66
- const cadenceMatch = /^(\d+)(m|h|d)$/.exec(value);
67
- if (!cadenceMatch)
68
- return null;
69
- const interval = Number.parseInt(cadenceMatch[1], 10);
70
- if (!Number.isFinite(interval) || interval <= 0)
71
- return null;
72
- const unit = cadenceMatch[2];
73
- if (unit === "m")
74
- return `*/${interval} * * * *`;
75
- if (unit === "h")
76
- return `0 */${interval} * * *`;
77
- return `0 0 */${interval} * *`;
78
- }
79
57
  function parseScheduledAt(raw) {
80
58
  if (typeof raw !== "string")
81
59
  return null;
@@ -140,7 +118,7 @@ class TaskDrivenScheduler {
140
118
  const nextTaskPaths = new Map();
141
119
  for (const agent of this.agents) {
142
120
  const taskRoot = path.join(this.bundlesRoot, `${agent}.ouro`, "tasks");
143
- const collections = ["one-shots", "ongoing", "habits"];
121
+ const collections = ["one-shots", "ongoing"];
144
122
  const files = [];
145
123
  for (const collection of collections) {
146
124
  walkMarkdownFiles(path.join(taskRoot, collection), this.readdirSync, this.existsSync, files);
@@ -157,7 +135,7 @@ class TaskDrivenScheduler {
157
135
  nextTaskPaths.set(`${agent}:${taskId}`, filePath);
158
136
  if (task.status === "done")
159
137
  continue;
160
- const cadence = parseCadence(task.frontmatter.cadence);
138
+ const cadence = (0, cadence_1.parseCadenceToCron)(task.frontmatter.cadence);
161
139
  if (cadence) {
162
140
  const id = `${agent}:${taskId}:cadence`;
163
141
  nextJobs.set(id, {