@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,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OUTLOOK_DEFAULT_PORT = exports.OUTLOOK_DEFAULT_INNER_VISIBILITY = exports.OUTLOOK_RELEASE_INTERACTION_MODEL = exports.OUTLOOK_PRODUCT_NAME = void 0;
4
+ exports.OUTLOOK_PRODUCT_NAME = "Ouro Outlook";
5
+ exports.OUTLOOK_RELEASE_INTERACTION_MODEL = "read-only";
6
+ exports.OUTLOOK_DEFAULT_INNER_VISIBILITY = "summary";
7
+ exports.OUTLOOK_DEFAULT_PORT = 6876;
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildOutlookMachineView = buildOutlookMachineView;
4
+ exports.buildOutlookAgentView = buildOutlookAgentView;
5
+ const runtime_1 = require("../../nerves/runtime");
6
+ const outlook_types_1 = require("./outlook-types");
7
+ function deriveAttention(agent) {
8
+ if (agent.degraded.status === "degraded") {
9
+ return { level: "degraded", label: "Degraded" };
10
+ }
11
+ if (agent.freshness.status === "stale") {
12
+ return { level: "stale", label: "Stale" };
13
+ }
14
+ if (agent.tasks.blockedCount > 0 || agent.coding.blockedCount > 0) {
15
+ return { level: "blocked", label: "Blocked" };
16
+ }
17
+ if (agent.tasks.liveCount > 0 || agent.coding.activeCount > 0 || agent.obligations.openCount > 0) {
18
+ return { level: "active", label: "Active" };
19
+ }
20
+ return { level: "idle", label: "Idle" };
21
+ }
22
+ function deriveAgentAttention(agent) {
23
+ return deriveAttention({
24
+ agentName: agent.agentName,
25
+ enabled: agent.enabled,
26
+ freshness: agent.freshness,
27
+ degraded: agent.degraded,
28
+ tasks: {
29
+ liveCount: agent.tasks.liveCount,
30
+ blockedCount: agent.tasks.blockedCount,
31
+ },
32
+ obligations: {
33
+ openCount: agent.obligations.openCount,
34
+ },
35
+ coding: {
36
+ activeCount: agent.coding.activeCount,
37
+ blockedCount: agent.coding.blockedCount,
38
+ },
39
+ });
40
+ }
41
+ function buildTotals(machine) {
42
+ return machine.agents.reduce((totals, agent) => ({
43
+ agents: totals.agents + 1,
44
+ enabledAgents: totals.enabledAgents + (agent.enabled ? 1 : 0),
45
+ degradedAgents: totals.degradedAgents + (agent.degraded.status === "degraded" ? 1 : 0),
46
+ staleAgents: totals.staleAgents + (agent.freshness.status === "stale" ? 1 : 0),
47
+ liveTasks: totals.liveTasks + agent.tasks.liveCount,
48
+ blockedTasks: totals.blockedTasks + agent.tasks.blockedCount,
49
+ openObligations: totals.openObligations + agent.obligations.openCount,
50
+ activeCodingAgents: totals.activeCodingAgents + (agent.coding.activeCount > 0 ? 1 : 0),
51
+ blockedCodingAgents: totals.blockedCodingAgents + (agent.coding.blockedCount > 0 ? 1 : 0),
52
+ }), {
53
+ agents: 0,
54
+ enabledAgents: 0,
55
+ degradedAgents: 0,
56
+ staleAgents: 0,
57
+ liveTasks: 0,
58
+ blockedTasks: 0,
59
+ openObligations: 0,
60
+ activeCodingAgents: 0,
61
+ blockedCodingAgents: 0,
62
+ });
63
+ }
64
+ function deriveMood(machine, daemon) {
65
+ if (machine.degraded.status === "degraded" || daemon.health === "warn") {
66
+ return "strained";
67
+ }
68
+ if (machine.freshness.status === "stale") {
69
+ return "watchful";
70
+ }
71
+ return "calm";
72
+ }
73
+ function buildOutlookMachineView(input) {
74
+ const totals = buildTotals(input.machine);
75
+ const agents = input.machine.agents
76
+ .map((agent) => ({
77
+ ...agent,
78
+ attention: deriveAttention(agent),
79
+ }))
80
+ .sort((left, right) => {
81
+ const leftAt = left.freshness.latestActivityAt ?? "";
82
+ const rightAt = right.freshness.latestActivityAt ?? "";
83
+ return rightAt.localeCompare(leftAt);
84
+ });
85
+ return {
86
+ overview: {
87
+ productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
88
+ observedAt: input.machine.observedAt,
89
+ primaryEntryPoint: input.daemon.outlookUrl,
90
+ daemon: input.daemon,
91
+ runtime: input.machine.runtime,
92
+ freshness: input.machine.freshness,
93
+ degraded: input.machine.degraded,
94
+ totals,
95
+ mood: deriveMood(input.machine, input.daemon),
96
+ entrypoints: [
97
+ { kind: "web", label: "Open Outlook", target: input.daemon.outlookUrl },
98
+ { kind: "cli", label: "CLI JSON", target: "ouro outlook --json" },
99
+ ],
100
+ },
101
+ agents,
102
+ };
103
+ }
104
+ function normalizeViewer(viewer) {
105
+ return {
106
+ kind: viewer?.kind ?? "human",
107
+ agentName: viewer?.agentName,
108
+ innerDetail: viewer?.innerDetail ?? "summary",
109
+ };
110
+ }
111
+ function buildInnerView(inner, viewer) {
112
+ if (viewer.innerDetail === "deep") {
113
+ return {
114
+ mode: "deep",
115
+ status: inner.status,
116
+ summary: inner.surfacedSummary,
117
+ hasPending: inner.hasPending,
118
+ origin: inner.origin,
119
+ obligationStatus: inner.obligationStatus,
120
+ };
121
+ }
122
+ return {
123
+ mode: "summary",
124
+ status: inner.status,
125
+ summary: inner.surfacedSummary,
126
+ hasPending: inner.hasPending,
127
+ };
128
+ }
129
+ function buildRecentActivity(agent) {
130
+ const items = [
131
+ ...agent.coding.items.map((item) => ({
132
+ kind: "coding",
133
+ at: item.lastActivityAt,
134
+ label: item.checkpoint ?? `${item.runner} ${item.status}`,
135
+ detail: item.workdir,
136
+ })),
137
+ ...agent.sessions.items.map((item) => ({
138
+ kind: "session",
139
+ at: item.lastActivityAt,
140
+ label: `${item.friendName} via ${item.channel}`,
141
+ detail: item.key,
142
+ })),
143
+ ...agent.obligations.items.map((item) => ({
144
+ kind: "obligation",
145
+ at: item.updatedAt,
146
+ label: item.content,
147
+ detail: item.nextAction ?? item.status,
148
+ })),
149
+ ];
150
+ if (agent.inner.latestActivityAt) {
151
+ items.push({
152
+ kind: "inner",
153
+ at: agent.inner.latestActivityAt,
154
+ label: agent.inner.surfacedSummary ?? agent.inner.status,
155
+ detail: agent.inner.hasPending ? "pending inner work" : agent.inner.obligationStatus ?? "no linked obligation",
156
+ });
157
+ }
158
+ return items
159
+ .filter((item) => Number.isFinite(Date.parse(item.at)))
160
+ .sort((left, right) => right.at.localeCompare(left.at))
161
+ .slice(0, 4);
162
+ }
163
+ function buildOutlookAgentView(input) {
164
+ /* v8 ignore next */
165
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.outlook_view_agent", message: `building outlook view for ${input.agent.agentName}`, meta: { agent: input.agent.agentName } });
166
+ const viewer = normalizeViewer(input.viewer);
167
+ return {
168
+ productName: outlook_types_1.OUTLOOK_PRODUCT_NAME,
169
+ interactionModel: outlook_types_1.OUTLOOK_RELEASE_INTERACTION_MODEL,
170
+ viewer,
171
+ agent: {
172
+ agentName: input.agent.agentName,
173
+ agentRoot: input.agent.agentRoot,
174
+ enabled: input.agent.enabled,
175
+ provider: input.agent.provider,
176
+ senses: input.agent.senses,
177
+ freshness: input.agent.freshness,
178
+ degraded: input.agent.degraded,
179
+ attention: deriveAgentAttention(input.agent),
180
+ },
181
+ work: {
182
+ tasks: input.agent.tasks,
183
+ obligations: input.agent.obligations,
184
+ sessions: input.agent.sessions,
185
+ coding: input.agent.coding,
186
+ bridges: input.agent.tasks.activeBridges,
187
+ },
188
+ inner: buildInnerView(input.agent.inner, viewer),
189
+ activity: {
190
+ freshness: input.agent.freshness,
191
+ recent: buildRecentActivity(input.agent),
192
+ },
193
+ };
194
+ }
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildProgressStory = buildProgressStory;
4
+ exports.renderProgressStory = renderProgressStory;
5
+ const runtime_1 = require("../nerves/runtime");
6
+ function labelForScope(scope) {
7
+ return scope === "inner-delegation" ? "inner work" : "shared work";
8
+ }
9
+ function compactDetail(text) {
10
+ if (typeof text !== "string")
11
+ return null;
12
+ const trimmed = text.trim();
13
+ return trimmed.length > 0 ? trimmed : null;
14
+ }
15
+ function buildProgressStory(input) {
16
+ const detailLines = [
17
+ compactDetail(input.objective),
18
+ compactDetail(input.outcomeText),
19
+ compactDetail(input.bridgeId ? `bridge: ${input.bridgeId}` : null),
20
+ compactDetail(input.taskName ? `task: ${input.taskName}` : null),
21
+ ].filter((line) => Boolean(line));
22
+ const story = {
23
+ statusLine: `${labelForScope(input.scope)}: ${input.phase}`,
24
+ detailLines,
25
+ };
26
+ (0, runtime_1.emitNervesEvent)({
27
+ component: "engine",
28
+ event: "engine.progress_story_build",
29
+ message: "built shared progress story",
30
+ meta: {
31
+ scope: input.scope,
32
+ phase: input.phase,
33
+ detailLines: detailLines.length,
34
+ hasBridge: Boolean(input.bridgeId),
35
+ hasTask: Boolean(input.taskName),
36
+ },
37
+ });
38
+ return story;
39
+ }
40
+ function renderProgressStory(story) {
41
+ return [story.statusLine, ...story.detailLines].join("\n");
42
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildFailoverContext = buildFailoverContext;
4
+ exports.handleFailoverReply = handleFailoverReply;
5
+ const runtime_1 = require("../nerves/runtime");
6
+ const FAILING_PROVIDER_LABELS = {
7
+ "auth-failure": "its credentials need to be refreshed",
8
+ "usage-limit": "has also hit its usage limit",
9
+ "rate-limit": "is also being rate limited",
10
+ "server-error": "is also experiencing an outage",
11
+ "network-error": "could not be reached",
12
+ "unknown": "could not be reached",
13
+ };
14
+ const CLASSIFICATION_LABELS = {
15
+ "auth-failure": "authentication failed",
16
+ "usage-limit": "hit its usage limit",
17
+ "rate-limit": "is being rate limited",
18
+ "server-error": "is experiencing an outage",
19
+ "network-error": "is unreachable (network error)",
20
+ "unknown": "encountered an error",
21
+ };
22
+ function buildFailoverContext(_errorMessage, classification, currentProvider, currentModel, agentName, inventory, providerModels) {
23
+ const label = CLASSIFICATION_LABELS[classification];
24
+ const providerWithModel = currentModel ? `${currentProvider} (${currentModel})` : currentProvider;
25
+ const errorSummary = `${providerWithModel} ${label}`;
26
+ const workingProviders = [];
27
+ const unconfiguredProviders = [];
28
+ const failingProviders = [];
29
+ for (const [provider, result] of Object.entries(inventory)) {
30
+ if (result.ok) {
31
+ workingProviders.push(provider);
32
+ }
33
+ else if (result.classification === "auth-failure" && result.message === "no credentials configured") {
34
+ unconfiguredProviders.push(provider);
35
+ }
36
+ else {
37
+ // Configured but ping failed (expired token, provider also down, etc.)
38
+ failingProviders.push({ provider, classification: result.classification });
39
+ }
40
+ }
41
+ const lines = [`${errorSummary}.`];
42
+ if (workingProviders.length > 0) {
43
+ const switchDescriptions = workingProviders.map((p) => {
44
+ const model = providerModels[p];
45
+ return model ? `${p} (${model})` : /* v8 ignore next -- defensive: model always present in secrets @preserve */ p;
46
+ });
47
+ const switchOptions = workingProviders.map((p) => `"switch to ${p}"`).join(" or ");
48
+ lines.push(`these providers are ready to go: ${switchDescriptions.join(", ")}.`);
49
+ lines.push(`reply ${switchOptions} to continue.`);
50
+ }
51
+ if (failingProviders.length > 0) {
52
+ for (const { provider, classification } of failingProviders) {
53
+ /* v8 ignore next -- defensive: all classifications have labels @preserve */
54
+ const detail = FAILING_PROVIDER_LABELS[classification] ?? "could not be reached";
55
+ lines.push(`${provider} is configured but ${detail}. run \`ouro auth --agent ${agentName} --provider ${provider}\` to refresh.`);
56
+ }
57
+ }
58
+ if (unconfiguredProviders.length > 0) {
59
+ lines.push(`to set up ${unconfiguredProviders.join(", ")}, run \`ouro auth --agent ${agentName}\` in terminal.`);
60
+ }
61
+ if (workingProviders.length === 0 && unconfiguredProviders.length === 0 && failingProviders.length === 0) {
62
+ lines.push(`no other providers are available. run \`ouro auth --agent ${agentName}\` in terminal to configure one.`);
63
+ }
64
+ (0, runtime_1.emitNervesEvent)({
65
+ component: "engine",
66
+ event: "engine.failover_context_built",
67
+ message: "built provider failover context",
68
+ meta: { currentProvider, classification, workingProviders, unconfiguredProviders },
69
+ });
70
+ return {
71
+ errorSummary,
72
+ classification,
73
+ currentProvider,
74
+ agentName,
75
+ workingProviders,
76
+ unconfiguredProviders,
77
+ userMessage: lines.join(" "),
78
+ };
79
+ }
80
+ function handleFailoverReply(reply, context) {
81
+ const lower = reply.toLowerCase().trim();
82
+ for (const provider of context.workingProviders) {
83
+ if (lower.includes(`switch to ${provider}`) || lower === provider) {
84
+ return { action: "switch", provider };
85
+ }
86
+ }
87
+ return { action: "dismiss" };
88
+ }
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeErrorMessage = sanitizeErrorMessage;
4
+ exports.pingProvider = pingProvider;
5
+ exports.runHealthInventory = runHealthInventory;
6
+ const identity_1 = require("./identity");
7
+ const anthropic_1 = require("./providers/anthropic");
8
+ const azure_1 = require("./providers/azure");
9
+ const minimax_1 = require("./providers/minimax");
10
+ const openai_codex_1 = require("./providers/openai-codex");
11
+ const github_copilot_1 = require("./providers/github-copilot");
12
+ const auth_flow_1 = require("./auth/auth-flow");
13
+ const runtime_1 = require("../nerves/runtime");
14
+ const PING_TIMEOUT_MS = 10_000;
15
+ /**
16
+ * Strip raw JSON/HTML API response bodies from error messages.
17
+ * SDK errors often include the full response: "400 {"type":"error",...}" or "403 <html>...".
18
+ * Extract just the HTTP status and a short human-readable summary.
19
+ */
20
+ function sanitizeErrorMessage(message) {
21
+ const statusMatch = message.match(/^(\d{3})\s/);
22
+ if (!statusMatch)
23
+ return message;
24
+ const status = statusMatch[1];
25
+ const body = message.slice(status.length).trim();
26
+ // HTML response (Cloudflare challenge, error pages, etc.)
27
+ if (body.startsWith("<") || body.includes("<!DOCTYPE") || body.includes("<html")) {
28
+ return `HTTP ${status}`;
29
+ }
30
+ // JSON response
31
+ if (body.startsWith("{")) {
32
+ try {
33
+ const json = JSON.parse(body);
34
+ const inner = json?.error?.message;
35
+ if (typeof inner === "string" && inner && inner !== "Error") {
36
+ return `${status} ${inner}`;
37
+ }
38
+ }
39
+ catch { /* not valid JSON */ }
40
+ return `HTTP ${status}`;
41
+ }
42
+ // Already clean (e.g., "401 Provided authentication token is expired.")
43
+ return message;
44
+ }
45
+ function hasEmptyCredentials(provider, config) {
46
+ const record = config;
47
+ return identity_1.PROVIDER_CREDENTIALS[provider].required.some((key) => !record[key]);
48
+ }
49
+ function createRuntimeForPing(provider, _config) {
50
+ // The provider constructors read credentials from the active config via getXxxConfig().
51
+ // For ping, this is acceptable because verifyProviderCredentials patches the runtime
52
+ // config before calling ping. The model string is a default — for anthropic the ping
53
+ // overrides it with haiku anyway, and for others it's used in a minimal API call.
54
+ const DEFAULT_MODELS = {
55
+ anthropic: "claude-haiku-4-5-20251001",
56
+ azure: "gpt-4o",
57
+ minimax: "MiniMax-M2.7",
58
+ "openai-codex": "codex-mini-latest",
59
+ "github-copilot": "gpt-4o",
60
+ };
61
+ /* v8 ignore next -- fallback: all known providers are in DEFAULT_MODELS @preserve */
62
+ const model = DEFAULT_MODELS[provider] ?? "unknown";
63
+ switch (provider) {
64
+ case "anthropic":
65
+ return (0, anthropic_1.createAnthropicProviderRuntime)(model);
66
+ case "azure":
67
+ return (0, azure_1.createAzureProviderRuntime)(model);
68
+ case "minimax":
69
+ return (0, minimax_1.createMinimaxProviderRuntime)(model);
70
+ case "openai-codex":
71
+ return (0, openai_codex_1.createOpenAICodexProviderRuntime)(model);
72
+ case "github-copilot":
73
+ return (0, github_copilot_1.createGithubCopilotProviderRuntime)(model);
74
+ /* v8 ignore next 2 -- exhaustive: all providers handled above @preserve */
75
+ default:
76
+ throw new Error(`unsupported provider for ping: ${provider}`);
77
+ }
78
+ }
79
+ async function pingProvider(provider, config) {
80
+ if (hasEmptyCredentials(provider, config)) {
81
+ return { ok: false, classification: "auth-failure", message: "no credentials configured" };
82
+ }
83
+ let runtime;
84
+ try {
85
+ runtime = createRuntimeForPing(provider, config);
86
+ /* v8 ignore start -- factory creation failure: tested via individual provider init tests @preserve */
87
+ }
88
+ catch (error) {
89
+ return {
90
+ ok: false,
91
+ classification: "auth-failure",
92
+ message: error instanceof Error ? error.message : String(error),
93
+ };
94
+ }
95
+ /* v8 ignore stop */
96
+ try {
97
+ const controller = new AbortController();
98
+ /* v8 ignore next -- timeout callback: only fires after 10s, tests resolve faster @preserve */
99
+ const timeout = setTimeout(() => controller.abort(), PING_TIMEOUT_MS);
100
+ try {
101
+ // Minimal API call — no thinking, no reasoning, no tools.
102
+ if (provider === "anthropic") {
103
+ // Use haiku for the ping — setup tokens may not have access to newer
104
+ // models, but if haiku works, the credentials are valid.
105
+ // Override the beta header to exclude thinking (which requires a
106
+ // thinking param in the request body).
107
+ const client = runtime.client;
108
+ await client.messages.create({ model: "claude-haiku-4-5-20251001", max_tokens: 1, messages: [{ role: "user", content: "ping" }] }, { signal: controller.signal, headers: { "anthropic-beta": "claude-code-20250219,oauth-2025-04-20" } });
109
+ }
110
+ else if (provider === "openai-codex") {
111
+ // Codex uses the Responses API (chatgpt.com/backend-api/codex/responses),
112
+ // not the Chat Completions API. Ping via responses endpoint.
113
+ const client = runtime.client;
114
+ await client.responses.create({ model: runtime.model, input: "ping", store: false }, { signal: controller.signal });
115
+ }
116
+ else {
117
+ // OpenAI-compatible providers (azure, minimax, github-copilot)
118
+ const client = runtime.client;
119
+ await client.chat.completions.create({ model: runtime.model, max_tokens: 1, messages: [{ role: "user", content: "ping" }] }, { signal: controller.signal });
120
+ }
121
+ return { ok: true };
122
+ }
123
+ finally {
124
+ clearTimeout(timeout);
125
+ }
126
+ }
127
+ catch (error) {
128
+ const err = error instanceof Error ? error : /* v8 ignore next -- defensive @preserve */ new Error(String(error));
129
+ let classification;
130
+ try {
131
+ classification = runtime.classifyError(err);
132
+ }
133
+ catch {
134
+ /* v8 ignore next -- defensive: classifyError should not throw @preserve */
135
+ classification = "unknown";
136
+ }
137
+ (0, runtime_1.emitNervesEvent)({
138
+ component: "engine",
139
+ event: "engine.provider_ping_fail",
140
+ message: `provider ping failed: ${provider}`,
141
+ meta: { provider, classification, error: err.message },
142
+ });
143
+ return { ok: false, classification, message: sanitizeErrorMessage(err.message) };
144
+ }
145
+ }
146
+ const PINGABLE_PROVIDERS = ["anthropic", "openai-codex", "azure", "minimax", "github-copilot"];
147
+ async function runHealthInventory(agentName, currentProvider, deps = {}) {
148
+ /* v8 ignore next -- default: tests inject ping dep @preserve */
149
+ const ping = deps.ping ?? pingProvider;
150
+ const { secrets } = (0, auth_flow_1.loadAgentSecrets)(agentName);
151
+ const providers = PINGABLE_PROVIDERS.filter((p) => p !== currentProvider);
152
+ const results = await Promise.all(providers.map(async (provider) => {
153
+ const config = secrets.providers[provider];
154
+ const result = await ping(provider, config);
155
+ return [provider, result];
156
+ }));
157
+ const inventory = {};
158
+ for (const [provider, result] of results) {
159
+ inventory[provider] = result;
160
+ }
161
+ return inventory;
162
+ }
@@ -0,0 +1,163 @@
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.needsRefresh = needsRefresh;
37
+ exports.refreshAnthropicToken = refreshAnthropicToken;
38
+ exports.persistTokenState = persistTokenState;
39
+ exports.ensureFreshToken = ensureFreshToken;
40
+ /* v8 ignore start -- OAuth token lifecycle: requires live API calls, tested via integration @preserve */
41
+ const fs = __importStar(require("fs"));
42
+ const runtime_1 = require("../../nerves/runtime");
43
+ const identity_1 = require("../identity");
44
+ const OAUTH_TOKEN_ENDPOINT = "https://console.anthropic.com/v1/oauth/token";
45
+ const OAUTH_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
46
+ const REFRESH_MARGIN_MS = 5 * 60 * 1000; // refresh 5 minutes before expiry
47
+ /**
48
+ * Check if the Anthropic OAuth token needs refreshing.
49
+ * Returns true if no expiresAt is set (legacy token) or if within 5 min of expiry.
50
+ */
51
+ function needsRefresh(expiresAt) {
52
+ if (!expiresAt)
53
+ return true; // legacy token with no expiry — always try refresh
54
+ return Date.now() > expiresAt - REFRESH_MARGIN_MS;
55
+ }
56
+ /**
57
+ * Refresh an Anthropic OAuth access token using the refresh token.
58
+ * Returns the new token state or null if refresh fails.
59
+ */
60
+ async function refreshAnthropicToken(refreshToken, fetchImpl = fetch) {
61
+ try {
62
+ const response = await fetchImpl(OAUTH_TOKEN_ENDPOINT, {
63
+ method: "POST",
64
+ headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify({
66
+ grant_type: "refresh_token",
67
+ refresh_token: refreshToken,
68
+ client_id: OAUTH_CLIENT_ID,
69
+ }),
70
+ });
71
+ if (!response.ok) {
72
+ (0, runtime_1.emitNervesEvent)({
73
+ level: "warn",
74
+ component: "engine",
75
+ event: "engine.anthropic_token_refresh_failed",
76
+ message: `token refresh failed: ${response.status}`,
77
+ meta: { status: response.status },
78
+ });
79
+ return null;
80
+ }
81
+ const json = await response.json();
82
+ if (!json.access_token) {
83
+ (0, runtime_1.emitNervesEvent)({
84
+ level: "warn",
85
+ component: "engine",
86
+ event: "engine.anthropic_token_refresh_failed",
87
+ message: "token refresh returned no access_token",
88
+ meta: {},
89
+ });
90
+ return null;
91
+ }
92
+ const state = {
93
+ accessToken: json.access_token,
94
+ refreshToken: json.refresh_token ?? refreshToken, // keep old if not returned
95
+ expiresAt: Date.now() + (json.expires_in ?? 28800) * 1000, // default 8h
96
+ };
97
+ (0, runtime_1.emitNervesEvent)({
98
+ component: "engine",
99
+ event: "engine.anthropic_token_refreshed",
100
+ message: "anthropic OAuth token refreshed",
101
+ meta: { expiresAt: new Date(state.expiresAt).toISOString() },
102
+ });
103
+ return state;
104
+ }
105
+ catch (error) {
106
+ (0, runtime_1.emitNervesEvent)({
107
+ level: "warn",
108
+ component: "engine",
109
+ event: "engine.anthropic_token_refresh_error",
110
+ message: "token refresh threw",
111
+ meta: { error: error instanceof Error ? error.message : String(error) },
112
+ });
113
+ return null;
114
+ }
115
+ }
116
+ /**
117
+ * Persist refreshed token state back to secrets.json.
118
+ */
119
+ function persistTokenState(agentName, state) {
120
+ try {
121
+ const secretsPath = (0, identity_1.getAgentSecretsPath)(agentName);
122
+ const raw = fs.readFileSync(secretsPath, "utf-8");
123
+ const secrets = JSON.parse(raw);
124
+ secrets.providers = secrets.providers ?? {};
125
+ secrets.providers.anthropic = secrets.providers.anthropic ?? {};
126
+ secrets.providers.anthropic.setupToken = state.accessToken;
127
+ secrets.providers.anthropic.refreshToken = state.refreshToken;
128
+ secrets.providers.anthropic.expiresAt = state.expiresAt;
129
+ fs.writeFileSync(secretsPath, JSON.stringify(secrets, null, 2) + "\n", "utf-8");
130
+ /* v8 ignore start -- defensive: persistence failure must not crash the provider @preserve */
131
+ }
132
+ catch (error) {
133
+ (0, runtime_1.emitNervesEvent)({
134
+ level: "warn",
135
+ component: "engine",
136
+ event: "engine.anthropic_token_persist_error",
137
+ message: "failed to persist refreshed token",
138
+ meta: { error: error instanceof Error ? error.message : String(error) },
139
+ });
140
+ }
141
+ /* v8 ignore stop */
142
+ }
143
+ /**
144
+ * Ensure the Anthropic token is fresh. If expired, refresh and persist.
145
+ * Returns the current valid access token, or null if refresh failed and
146
+ * the existing token is expired.
147
+ */
148
+ async function ensureFreshToken(currentToken, refreshToken, expiresAt, agentName, fetchImpl) {
149
+ if (!needsRefresh(expiresAt)) {
150
+ return currentToken; // still fresh
151
+ }
152
+ if (!refreshToken) {
153
+ // No refresh token — use the current token as-is (may be expired)
154
+ return currentToken;
155
+ }
156
+ const newState = await refreshAnthropicToken(refreshToken, fetchImpl);
157
+ if (!newState) {
158
+ return currentToken; // refresh failed — try the old token
159
+ }
160
+ persistTokenState(agentName, newState);
161
+ return newState.accessToken;
162
+ }
163
+ /* v8 ignore stop */