@ouro.bot/cli 0.1.0-alpha.2 → 0.1.0-alpha.200

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 (215) hide show
  1. package/README.md +187 -191
  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/assets/ouroboros.png +0 -0
  6. package/changelog.json +1248 -0
  7. package/dist/heart/active-work.js +832 -0
  8. package/dist/heart/bridges/manager.js +358 -0
  9. package/dist/heart/bridges/state-machine.js +135 -0
  10. package/dist/heart/bridges/store.js +123 -0
  11. package/dist/heart/cares.js +179 -0
  12. package/dist/heart/commitments.js +111 -0
  13. package/dist/heart/config.js +114 -28
  14. package/dist/heart/core.js +689 -120
  15. package/dist/heart/cross-chat-delivery.js +146 -0
  16. package/dist/heart/daemon/agent-config-check.js +149 -0
  17. package/dist/heart/daemon/agent-discovery.js +81 -0
  18. package/dist/heart/daemon/agent-service.js +360 -0
  19. package/dist/heart/daemon/auth-flow.js +477 -0
  20. package/dist/heart/daemon/cadence.js +70 -0
  21. package/dist/heart/daemon/daemon-cli.js +2897 -193
  22. package/dist/heart/daemon/daemon-entry.js +194 -8
  23. package/dist/heart/daemon/daemon-health.js +136 -0
  24. package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
  25. package/dist/heart/daemon/daemon-tombstone.js +123 -0
  26. package/dist/heart/daemon/daemon.js +488 -13
  27. package/dist/heart/daemon/habit-migration.js +181 -0
  28. package/dist/heart/daemon/habit-parser.js +119 -0
  29. package/dist/heart/daemon/habit-scheduler.js +369 -0
  30. package/dist/heart/daemon/hatch-animation.js +35 -0
  31. package/dist/heart/daemon/hatch-flow.js +32 -122
  32. package/dist/heart/daemon/hatch-specialist.js +7 -2
  33. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  34. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  35. package/dist/heart/daemon/inner-status.js +89 -0
  36. package/dist/heart/daemon/launchd.js +165 -0
  37. package/dist/heart/daemon/log-tailer.js +4 -3
  38. package/dist/heart/daemon/mcp-server.js +591 -0
  39. package/dist/heart/daemon/message-router.js +17 -8
  40. package/dist/heart/daemon/os-cron-deps.js +134 -0
  41. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  42. package/dist/heart/daemon/ouro-bot-wrapper.js +4 -3
  43. package/dist/heart/daemon/ouro-path-installer.js +221 -0
  44. package/dist/heart/daemon/ouro-uti.js +11 -2
  45. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  46. package/dist/heart/daemon/outlook-http.js +439 -0
  47. package/dist/heart/daemon/outlook-read.js +1618 -0
  48. package/dist/heart/daemon/outlook-render.js +1032 -0
  49. package/dist/heart/daemon/outlook-types.js +7 -0
  50. package/dist/heart/daemon/outlook-view.js +194 -0
  51. package/dist/heart/daemon/process-manager.js +94 -1
  52. package/dist/heart/daemon/run-hooks.js +39 -0
  53. package/dist/heart/daemon/runtime-logging.js +61 -14
  54. package/dist/heart/daemon/runtime-metadata.js +219 -0
  55. package/dist/heart/daemon/runtime-mode.js +67 -0
  56. package/dist/heart/daemon/safe-mode.js +161 -0
  57. package/dist/heart/daemon/sense-manager.js +314 -0
  58. package/dist/heart/daemon/session-id-resolver.js +131 -0
  59. package/dist/heart/daemon/skill-management-installer.js +94 -0
  60. package/dist/heart/daemon/socket-client.js +202 -0
  61. package/dist/heart/daemon/specialist-orchestrator.js +129 -0
  62. package/dist/heart/daemon/specialist-prompt.js +101 -0
  63. package/dist/heart/daemon/specialist-tools.js +283 -0
  64. package/dist/heart/daemon/staged-restart.js +138 -0
  65. package/dist/heart/daemon/task-scheduler.js +3 -25
  66. package/dist/heart/daemon/thoughts.js +507 -0
  67. package/dist/heart/daemon/update-checker.js +111 -0
  68. package/dist/heart/daemon/update-hooks.js +138 -0
  69. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  70. package/dist/heart/delegation.js +62 -0
  71. package/dist/heart/identity.js +220 -52
  72. package/dist/heart/intentions.js +173 -0
  73. package/dist/heart/kicks.js +2 -20
  74. package/dist/heart/migrate-config.js +127 -0
  75. package/dist/heart/model-capabilities.js +48 -0
  76. package/dist/heart/obligations.js +225 -0
  77. package/dist/heart/presence.js +185 -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 +178 -0
  81. package/dist/heart/providers/anthropic-token.js +163 -0
  82. package/dist/heart/providers/anthropic.js +199 -36
  83. package/dist/heart/providers/azure.js +116 -10
  84. package/dist/heart/providers/github-copilot.js +157 -0
  85. package/dist/heart/providers/minimax.js +33 -3
  86. package/dist/heart/providers/openai-codex.js +51 -16
  87. package/dist/heart/sense-truth.js +61 -0
  88. package/dist/heart/session-activity.js +172 -0
  89. package/dist/heart/session-recall.js +216 -0
  90. package/dist/heart/start-of-turn-packet.js +232 -0
  91. package/dist/heart/streaming.js +120 -33
  92. package/dist/heart/sync.js +217 -0
  93. package/dist/heart/target-resolution.js +127 -0
  94. package/dist/heart/tempo.js +93 -0
  95. package/dist/heart/temporal-view.js +41 -0
  96. package/dist/heart/tool-activity-callbacks.js +36 -0
  97. package/dist/heart/tool-description.js +135 -0
  98. package/dist/heart/tool-loop.js +200 -0
  99. package/dist/heart/turn-coordinator.js +28 -0
  100. package/dist/mind/associative-recall.js +122 -32
  101. package/dist/mind/bundle-manifest.js +77 -1
  102. package/dist/mind/context.js +125 -14
  103. package/dist/mind/{memory.js → diary.js} +69 -56
  104. package/dist/mind/episodes.js +119 -0
  105. package/dist/mind/file-state.js +179 -0
  106. package/dist/mind/first-impressions.js +16 -2
  107. package/dist/mind/friends/channel.js +64 -0
  108. package/dist/mind/friends/group-context.js +144 -0
  109. package/dist/mind/friends/store-file.js +36 -0
  110. package/dist/mind/friends/trust-explanation.js +74 -0
  111. package/dist/mind/friends/types.js +9 -1
  112. package/dist/mind/journal-index.js +161 -0
  113. package/dist/mind/obligation-steering.js +221 -0
  114. package/dist/mind/obligations.js +138 -0
  115. package/dist/mind/pending.js +76 -9
  116. package/dist/mind/phrases.js +1 -0
  117. package/dist/mind/prompt.js +861 -105
  118. package/dist/mind/scrutiny.js +173 -0
  119. package/dist/mind/token-estimate.js +8 -12
  120. package/dist/nerves/cli-logging.js +15 -2
  121. package/dist/nerves/coverage/audit.js +1 -1
  122. package/dist/nerves/coverage/run-artifacts.js +1 -1
  123. package/dist/nerves/event-buffer.js +111 -0
  124. package/dist/nerves/index.js +63 -3
  125. package/dist/nerves/observation.js +20 -0
  126. package/dist/nerves/runtime.js +5 -1
  127. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  128. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  129. package/dist/outlook-ui/index.html +15 -0
  130. package/dist/repertoire/ado-client.js +4 -2
  131. package/dist/repertoire/ado-semantic.js +11 -5
  132. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  133. package/dist/repertoire/coding/context-pack.js +330 -0
  134. package/dist/repertoire/coding/feedback.js +301 -0
  135. package/dist/repertoire/coding/index.js +4 -1
  136. package/dist/repertoire/coding/manager.js +210 -4
  137. package/dist/repertoire/coding/spawner.js +58 -12
  138. package/dist/repertoire/coding/tools.js +209 -7
  139. package/dist/repertoire/data/ado-endpoints.json +188 -0
  140. package/dist/repertoire/guardrails.js +291 -0
  141. package/dist/repertoire/mcp-client.js +254 -0
  142. package/dist/repertoire/mcp-manager.js +251 -0
  143. package/dist/repertoire/shell-sessions.js +133 -0
  144. package/dist/repertoire/skills.js +14 -23
  145. package/dist/repertoire/tasks/board.js +43 -5
  146. package/dist/repertoire/tasks/fix.js +182 -0
  147. package/dist/repertoire/tasks/index.js +28 -10
  148. package/dist/repertoire/tasks/lifecycle.js +2 -2
  149. package/dist/repertoire/tasks/parser.js +3 -2
  150. package/dist/repertoire/tasks/scanner.js +194 -37
  151. package/dist/repertoire/tasks/transitions.js +11 -28
  152. package/dist/repertoire/tools-base.js +1360 -271
  153. package/dist/repertoire/tools-bluebubbles.js +94 -0
  154. package/dist/repertoire/tools-github.js +1 -6
  155. package/dist/repertoire/tools-teams.js +65 -59
  156. package/dist/repertoire/tools.js +318 -91
  157. package/dist/scripts/claude-code-hook.js +41 -0
  158. package/dist/scripts/claude-code-stop-hook.js +47 -0
  159. package/dist/senses/attention-queue.js +97 -0
  160. package/dist/senses/bluebubbles-client.js +532 -0
  161. package/dist/senses/bluebubbles-entry.js +13 -0
  162. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  163. package/dist/senses/bluebubbles-media.js +339 -0
  164. package/dist/senses/bluebubbles-model.js +261 -0
  165. package/dist/senses/bluebubbles-mutation-log.js +116 -0
  166. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  167. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  168. package/dist/senses/bluebubbles.js +1327 -0
  169. package/dist/senses/cli/adapter.js +274 -0
  170. package/dist/senses/cli/ink-app.js +156 -0
  171. package/dist/senses/cli/inline-diff.js +64 -0
  172. package/dist/senses/cli/message-list.js +51 -0
  173. package/dist/senses/cli/ouro-tui.js +349 -0
  174. package/dist/senses/cli/spinner-imperative.js +135 -0
  175. package/dist/senses/cli/spinner.js +101 -0
  176. package/dist/senses/cli/status-line.js +60 -0
  177. package/dist/senses/cli/streaming-markdown.js +526 -0
  178. package/dist/senses/cli/tool-display.js +83 -0
  179. package/dist/senses/cli/tool-render.js +85 -0
  180. package/dist/senses/cli/tui-store.js +198 -0
  181. package/dist/senses/cli/virtual-list.js +35 -0
  182. package/dist/senses/cli-entry.js +1 -1
  183. package/dist/senses/cli-layout.js +187 -0
  184. package/dist/senses/cli.js +687 -262
  185. package/dist/senses/commands.js +65 -1
  186. package/dist/senses/continuity.js +94 -0
  187. package/dist/senses/habit-turn-message.js +108 -0
  188. package/dist/senses/inner-dialog-worker.js +112 -19
  189. package/dist/senses/inner-dialog.js +592 -84
  190. package/dist/senses/pipeline.js +693 -0
  191. package/dist/senses/shared-turn.js +196 -0
  192. package/dist/senses/surface-tool.js +95 -0
  193. package/dist/senses/teams.js +817 -151
  194. package/dist/senses/trust-gate.js +112 -2
  195. package/package.json +24 -7
  196. package/skills/configure-dev-tools.md +81 -0
  197. package/subagents/README.md +4 -70
  198. package/AdoptionSpecialist.ouro/agent.json +0 -20
  199. package/dist/heart/daemon/subagent-installer.js +0 -125
  200. package/dist/inner-worker-entry.js +0 -4
  201. package/subagents/work-doer.md +0 -233
  202. package/subagents/work-merger.md +0 -624
  203. package/subagents/work-planner.md +0 -373
  204. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  205. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  206. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  207. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  208. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  209. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  210. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  211. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  212. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  213. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  214. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  215. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
@@ -0,0 +1,179 @@
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.createCare = createCare;
37
+ exports.readCares = readCares;
38
+ exports.readActiveCares = readActiveCares;
39
+ exports.updateCare = updateCare;
40
+ exports.resolveCare = resolveCare;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const runtime_1 = require("../nerves/runtime");
44
+ const sync_1 = require("./sync");
45
+ function caresDir(agentRoot) {
46
+ return path.join(agentRoot, "arc", "cares");
47
+ }
48
+ function careFilePath(agentRoot, id) {
49
+ return path.join(caresDir(agentRoot), `${id}.json`);
50
+ }
51
+ function generateId() {
52
+ const timestamp = Date.now();
53
+ const random = Math.random().toString(36).slice(2, 10);
54
+ return `care-${timestamp}-${random}`;
55
+ }
56
+ function createCare(agentRoot, input) {
57
+ const now = new Date().toISOString();
58
+ const id = generateId();
59
+ const care = {
60
+ id,
61
+ label: input.label,
62
+ why: input.why,
63
+ kind: input.kind,
64
+ status: input.status,
65
+ salience: input.salience,
66
+ steward: input.steward,
67
+ relatedFriendIds: input.relatedFriendIds,
68
+ relatedAgentIds: input.relatedAgentIds,
69
+ relatedObligationIds: input.relatedObligationIds,
70
+ relatedEpisodeIds: input.relatedEpisodeIds,
71
+ currentRisk: input.currentRisk,
72
+ nextCheckAt: input.nextCheckAt,
73
+ createdAt: now,
74
+ updatedAt: now,
75
+ };
76
+ const dir = caresDir(agentRoot);
77
+ fs.mkdirSync(dir, { recursive: true });
78
+ const filePath = careFilePath(agentRoot, id);
79
+ fs.writeFileSync(filePath, JSON.stringify(care, null, 2), "utf-8");
80
+ (0, sync_1.trackSyncWrite)(filePath);
81
+ (0, runtime_1.emitNervesEvent)({
82
+ component: "heart",
83
+ event: "heart.care_created",
84
+ message: `care created: ${input.label}`,
85
+ meta: { careId: id, status: input.status, salience: input.salience },
86
+ });
87
+ return care;
88
+ }
89
+ function readCares(agentRoot) {
90
+ const dir = caresDir(agentRoot);
91
+ if (!fs.existsSync(dir)) {
92
+ (0, runtime_1.emitNervesEvent)({
93
+ component: "heart",
94
+ event: "heart.cares_read",
95
+ message: "read cares: directory missing, returning empty",
96
+ meta: { count: 0 },
97
+ });
98
+ return [];
99
+ }
100
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
101
+ const cares = [];
102
+ for (const file of files) {
103
+ try {
104
+ const content = fs.readFileSync(path.join(dir, file), "utf-8");
105
+ const care = JSON.parse(content);
106
+ cares.push(care);
107
+ }
108
+ catch {
109
+ // Skip malformed JSON files gracefully
110
+ }
111
+ }
112
+ (0, runtime_1.emitNervesEvent)({
113
+ component: "heart",
114
+ event: "heart.cares_read",
115
+ message: `read ${cares.length} cares`,
116
+ meta: { count: cares.length },
117
+ });
118
+ return cares;
119
+ }
120
+ function readActiveCares(agentRoot) {
121
+ const all = readCares(agentRoot);
122
+ const active = all.filter((c) => c.status === "active" || c.status === "watching");
123
+ (0, runtime_1.emitNervesEvent)({
124
+ component: "heart",
125
+ event: "heart.active_cares_read",
126
+ message: `read ${active.length} active cares`,
127
+ meta: { count: active.length, total: all.length },
128
+ });
129
+ return active;
130
+ }
131
+ function readCareFile(agentRoot, id) {
132
+ const filePath = careFilePath(agentRoot, id);
133
+ if (!fs.existsSync(filePath)) {
134
+ throw new Error(`Care not found: ${id}`);
135
+ }
136
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
137
+ }
138
+ function writeCareFile(agentRoot, care) {
139
+ const filePath = careFilePath(agentRoot, care.id);
140
+ fs.writeFileSync(filePath, JSON.stringify(care, null, 2), "utf-8");
141
+ (0, sync_1.trackSyncWrite)(filePath);
142
+ }
143
+ function updateCare(agentRoot, id, updates) {
144
+ const care = readCareFile(agentRoot, id);
145
+ const now = new Date().toISOString();
146
+ const updated = {
147
+ ...care,
148
+ ...updates,
149
+ id: care.id, // protect ID from overwrite
150
+ createdAt: care.createdAt, // protect createdAt
151
+ updatedAt: now,
152
+ };
153
+ writeCareFile(agentRoot, updated);
154
+ (0, runtime_1.emitNervesEvent)({
155
+ component: "heart",
156
+ event: "heart.care_updated",
157
+ message: `care updated: ${updated.label}`,
158
+ meta: { careId: id, updates: Object.keys(updates) },
159
+ });
160
+ return updated;
161
+ }
162
+ function resolveCare(agentRoot, id) {
163
+ const care = readCareFile(agentRoot, id);
164
+ const now = new Date().toISOString();
165
+ const resolved = {
166
+ ...care,
167
+ status: "resolved",
168
+ resolvedAt: now,
169
+ updatedAt: now,
170
+ };
171
+ writeCareFile(agentRoot, resolved);
172
+ (0, runtime_1.emitNervesEvent)({
173
+ component: "heart",
174
+ event: "heart.care_resolved",
175
+ message: `care resolved: ${resolved.label}`,
176
+ meta: { careId: id },
177
+ });
178
+ return resolved;
179
+ }
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deriveCommitments = deriveCommitments;
4
+ exports.formatCommitments = formatCommitments;
5
+ const obligations_1 = require("./obligations");
6
+ const runtime_1 = require("../nerves/runtime");
7
+ function describeActiveObligation(obligation) {
8
+ if (obligation.status === "pending") {
9
+ return `i owe ${obligation.origin.friendId}: ${obligation.content}`;
10
+ }
11
+ const surface = obligation.currentSurface?.label;
12
+ const statusText = obligation.status.replaceAll("_", " ");
13
+ if (surface) {
14
+ return `i owe ${obligation.origin.friendId}: ${obligation.content} (${statusText} in ${surface})`;
15
+ }
16
+ return `i owe ${obligation.origin.friendId}: ${obligation.content} (${statusText})`;
17
+ }
18
+ function deriveCommitments(activeWorkFrame, innerJob, pendingObligations) {
19
+ const committedTo = [];
20
+ const completionCriteria = [];
21
+ const safeToIgnore = [];
22
+ // Persistent obligations from the obligation store
23
+ // Sort by status priority: investigating/waiting/updating before pending
24
+ if (pendingObligations && pendingObligations.length > 0) {
25
+ const sorted = [...pendingObligations].sort((a, b) => {
26
+ const advancedA = a.status !== "pending" && a.status !== "fulfilled" ? 0 : 1;
27
+ const advancedB = b.status !== "pending" && b.status !== "fulfilled" ? 0 : 1;
28
+ return advancedA - advancedB;
29
+ });
30
+ let hasAdvancedObligation = false;
31
+ for (const ob of sorted) {
32
+ if (!(0, obligations_1.isOpenObligationStatus)(ob.status))
33
+ continue;
34
+ committedTo.push(describeActiveObligation(ob));
35
+ if (ob.status !== "pending")
36
+ hasAdvancedObligation = true;
37
+ }
38
+ completionCriteria.push("fulfill my outstanding obligations");
39
+ if (hasAdvancedObligation) {
40
+ completionCriteria.push("close my active obligation loops");
41
+ }
42
+ }
43
+ // Inner job
44
+ if (innerJob.status === "queued" || innerJob.status === "running") {
45
+ const contentSuffix = innerJob.content ? ` -- ${innerJob.content.slice(0, 60)}` : "";
46
+ committedTo.push(`i'm thinking through something privately${contentSuffix}`);
47
+ }
48
+ else if (innerJob.status === "surfaced") {
49
+ committedTo.push("i finished thinking about something and need to bring it back");
50
+ }
51
+ // mustResolveBeforeHandoff
52
+ if (activeWorkFrame.mustResolveBeforeHandoff) {
53
+ committedTo.push("i need to finish what i started before moving on");
54
+ completionCriteria.push("resolve the current thread before moving on");
55
+ }
56
+ // Bridges
57
+ for (const bridge of activeWorkFrame.bridges) {
58
+ committedTo.push(`i have shared work: ${bridge.summary || bridge.objective}`);
59
+ }
60
+ if (activeWorkFrame.bridges.length > 0) {
61
+ completionCriteria.push("keep shared work aligned across sessions");
62
+ }
63
+ // Tasks
64
+ for (const taskName of activeWorkFrame.taskPressure?.liveTaskNames ?? []) {
65
+ committedTo.push(`i'm tracking: ${taskName}`);
66
+ }
67
+ // Obligation completion criteria
68
+ if (innerJob.obligationStatus === "pending") {
69
+ const name = innerJob.origin?.friendName ?? innerJob.origin?.friendId ?? "them";
70
+ completionCriteria.push(`bring my answer back to ${name}`);
71
+ }
72
+ // Default completion criteria
73
+ if (completionCriteria.length === 0) {
74
+ completionCriteria.push("just be present in this conversation");
75
+ }
76
+ // Safe to ignore
77
+ if (innerJob.status === "idle" && !(activeWorkFrame.inner?.hasPending)) {
78
+ safeToIgnore.push("no private thinking in progress");
79
+ }
80
+ if (activeWorkFrame.bridges.length === 0) {
81
+ safeToIgnore.push("no shared work to coordinate");
82
+ }
83
+ if ((activeWorkFrame.taskPressure?.liveTaskNames ?? []).length === 0) {
84
+ safeToIgnore.push("no active tasks to track");
85
+ }
86
+ (0, runtime_1.emitNervesEvent)({
87
+ component: "engine",
88
+ event: "engine.commitments_derive",
89
+ message: "derived commitments frame",
90
+ meta: { committedCount: committedTo.length, criteriaCount: completionCriteria.length },
91
+ });
92
+ return { committedTo, completionCriteria, safeToIgnore };
93
+ }
94
+ function formatCommitments(commitments) {
95
+ const sections = [];
96
+ if (commitments.committedTo.length === 0) {
97
+ sections.push("i'm not holding anything specific right now. i'm free to be present.");
98
+ }
99
+ else {
100
+ sections.push("## what i'm holding right now");
101
+ sections.push("");
102
+ sections.push(commitments.committedTo.map((c) => `- ${c}`).join("\n"));
103
+ }
104
+ sections.push("");
105
+ sections.push("## what \"done\" looks like");
106
+ sections.push(commitments.completionCriteria.map((c) => `- ${c}`).join("\n"));
107
+ sections.push("");
108
+ sections.push("## what i can let go of");
109
+ sections.push(commitments.safeToIgnore.map((c) => `- ${c}`).join("\n"));
110
+ return sections.join("\n");
111
+ }
@@ -35,63 +35,87 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.loadConfig = loadConfig;
37
37
  exports.resetConfigCache = resetConfigCache;
38
- exports.setTestConfig = setTestConfig;
38
+ exports.patchRuntimeConfig = patchRuntimeConfig;
39
39
  exports.getAzureConfig = getAzureConfig;
40
40
  exports.getMinimaxConfig = getMinimaxConfig;
41
41
  exports.getAnthropicConfig = getAnthropicConfig;
42
42
  exports.getOpenAICodexConfig = getOpenAICodexConfig;
43
+ exports.getGithubCopilotConfig = getGithubCopilotConfig;
43
44
  exports.getTeamsConfig = getTeamsConfig;
45
+ exports.getTeamsSecondaryConfig = getTeamsSecondaryConfig;
44
46
  exports.getContextConfig = getContextConfig;
45
47
  exports.getOAuthConfig = getOAuthConfig;
48
+ exports.resolveOAuthForTenant = resolveOAuthForTenant;
46
49
  exports.getTeamsChannelConfig = getTeamsChannelConfig;
50
+ exports.getBlueBubblesConfig = getBlueBubblesConfig;
51
+ exports.getBlueBubblesChannelConfig = getBlueBubblesChannelConfig;
47
52
  exports.getIntegrationsConfig = getIntegrationsConfig;
53
+ exports.getSyncConfig = getSyncConfig;
48
54
  exports.getOpenAIEmbeddingsApiKey = getOpenAIEmbeddingsApiKey;
49
55
  exports.getLogsDir = getLogsDir;
56
+ exports.sanitizeKey = sanitizeKey;
57
+ exports.slugify = slugify;
58
+ exports.resolveSessionPath = resolveSessionPath;
50
59
  exports.sessionPath = sessionPath;
51
60
  exports.logPath = logPath;
52
61
  const fs = __importStar(require("fs"));
53
62
  const path = __importStar(require("path"));
54
- const os = __importStar(require("os"));
55
63
  const identity_1 = require("./identity");
56
64
  const runtime_1 = require("../nerves/runtime");
57
65
  const DEFAULT_SECRETS_TEMPLATE = {
58
66
  providers: {
59
- // Keep provider field ordering consistent: model first, then auth credentials,
60
- // then provider-specific transport fields.
61
67
  azure: {
62
- modelName: "",
63
68
  apiKey: "",
64
69
  endpoint: "",
65
70
  deployment: "",
66
71
  apiVersion: "2025-04-01-preview",
72
+ managedIdentityClientId: "",
67
73
  },
68
74
  minimax: {
69
- model: "",
70
75
  apiKey: "",
71
76
  },
72
77
  anthropic: {
73
- model: "claude-opus-4-6",
74
78
  setupToken: "",
75
79
  },
76
80
  "openai-codex": {
77
- model: "gpt-5.2",
78
81
  oauthAccessToken: "",
79
82
  },
83
+ "github-copilot": {
84
+ githubToken: "",
85
+ baseUrl: "",
86
+ },
80
87
  },
81
88
  teams: {
82
89
  clientId: "",
83
90
  clientSecret: "",
84
91
  tenantId: "",
92
+ managedIdentityClientId: "",
85
93
  },
86
94
  oauth: {
87
95
  graphConnectionName: "graph",
88
96
  adoConnectionName: "ado",
89
97
  githubConnectionName: "",
90
98
  },
99
+ teamsSecondary: {
100
+ clientId: "",
101
+ clientSecret: "",
102
+ tenantId: "",
103
+ managedIdentityClientId: "",
104
+ },
91
105
  teamsChannel: {
92
106
  skipConfirmation: true,
93
107
  port: 3978,
94
108
  },
109
+ bluebubbles: {
110
+ serverUrl: "",
111
+ password: "",
112
+ accountId: "default",
113
+ },
114
+ bluebubblesChannel: {
115
+ port: 18790,
116
+ webhookPath: "/bluebubbles-webhook",
117
+ requestTimeoutMs: 30000,
118
+ },
95
119
  integrations: {
96
120
  perplexityApiKey: "",
97
121
  openaiEmbeddingsApiKey: "",
@@ -104,15 +128,19 @@ function defaultRuntimeConfig() {
104
128
  minimax: { ...DEFAULT_SECRETS_TEMPLATE.providers.minimax },
105
129
  anthropic: { ...DEFAULT_SECRETS_TEMPLATE.providers.anthropic },
106
130
  "openai-codex": { ...DEFAULT_SECRETS_TEMPLATE.providers["openai-codex"] },
131
+ "github-copilot": { ...DEFAULT_SECRETS_TEMPLATE.providers["github-copilot"] },
107
132
  },
108
133
  teams: { ...DEFAULT_SECRETS_TEMPLATE.teams },
134
+ teamsSecondary: { ...DEFAULT_SECRETS_TEMPLATE.teamsSecondary },
109
135
  oauth: { ...DEFAULT_SECRETS_TEMPLATE.oauth },
110
136
  context: { ...identity_1.DEFAULT_AGENT_CONTEXT },
111
137
  teamsChannel: { ...DEFAULT_SECRETS_TEMPLATE.teamsChannel },
138
+ bluebubbles: { ...DEFAULT_SECRETS_TEMPLATE.bluebubbles },
139
+ bluebubblesChannel: { ...DEFAULT_SECRETS_TEMPLATE.bluebubblesChannel },
112
140
  integrations: { ...DEFAULT_SECRETS_TEMPLATE.integrations },
113
141
  };
114
142
  }
115
- let _cachedConfig = null;
143
+ let _runtimeConfigOverride = null;
116
144
  let _testContextOverride = null;
117
145
  function resolveConfigPath() {
118
146
  return (0, identity_1.getAgentSecretsPath)();
@@ -134,15 +162,6 @@ function deepMerge(defaults, partial) {
134
162
  return result;
135
163
  }
136
164
  function loadConfig() {
137
- if (_cachedConfig) {
138
- (0, runtime_1.emitNervesEvent)({
139
- event: "config.load",
140
- component: "config/identity",
141
- message: "config loaded from cache",
142
- meta: { source: "cache" },
143
- });
144
- return _cachedConfig;
145
- }
146
165
  const configPath = resolveConfigPath();
147
166
  // Auto-create config directory if it doesn't exist
148
167
  const configDir = path.dirname(configPath);
@@ -203,7 +222,10 @@ function loadConfig() {
203
222
  },
204
223
  });
205
224
  }
206
- _cachedConfig = deepMerge(defaultRuntimeConfig(), sanitizedFileData);
225
+ const mergedConfig = deepMerge(defaultRuntimeConfig(), sanitizedFileData);
226
+ const config = _runtimeConfigOverride
227
+ ? deepMerge(mergedConfig, _runtimeConfigOverride)
228
+ : mergedConfig;
207
229
  (0, runtime_1.emitNervesEvent)({
208
230
  event: "config.load",
209
231
  component: "config/identity",
@@ -211,22 +233,22 @@ function loadConfig() {
211
233
  meta: {
212
234
  source: "disk",
213
235
  used_defaults_only: Object.keys(fileData).length === 0,
236
+ override_applied: _runtimeConfigOverride !== null,
214
237
  },
215
238
  });
216
- return _cachedConfig;
239
+ return config;
217
240
  }
218
241
  function resetConfigCache() {
219
- _cachedConfig = null;
242
+ _runtimeConfigOverride = null;
220
243
  _testContextOverride = null;
221
244
  }
222
- function setTestConfig(partial) {
223
- loadConfig(); // ensure _cachedConfig exists
245
+ function patchRuntimeConfig(partial) {
224
246
  const contextPatch = partial.context;
225
247
  if (contextPatch) {
226
248
  const base = _testContextOverride ?? identity_1.DEFAULT_AGENT_CONTEXT;
227
249
  _testContextOverride = deepMerge(base, contextPatch);
228
250
  }
229
- _cachedConfig = deepMerge(_cachedConfig, partial);
251
+ _runtimeConfigOverride = deepMerge((_runtimeConfigOverride ?? {}), partial);
230
252
  }
231
253
  function getAzureConfig() {
232
254
  const config = loadConfig();
@@ -244,10 +266,18 @@ function getOpenAICodexConfig() {
244
266
  const config = loadConfig();
245
267
  return { ...config.providers["openai-codex"] };
246
268
  }
269
+ function getGithubCopilotConfig() {
270
+ const config = loadConfig();
271
+ return { ...config.providers["github-copilot"] };
272
+ }
247
273
  function getTeamsConfig() {
248
274
  const config = loadConfig();
249
275
  return { ...config.teams };
250
276
  }
277
+ function getTeamsSecondaryConfig() {
278
+ const config = loadConfig();
279
+ return { ...config.teamsSecondary };
280
+ }
251
281
  function getContextConfig() {
252
282
  if (_testContextOverride) {
253
283
  return { ..._testContextOverride };
@@ -268,29 +298,85 @@ function getOAuthConfig() {
268
298
  const config = loadConfig();
269
299
  return { ...config.oauth };
270
300
  }
301
+ /** Resolve OAuth connection names for a specific tenant, falling back to defaults. */
302
+ function resolveOAuthForTenant(tenantId) {
303
+ const base = getOAuthConfig();
304
+ const overrides = tenantId ? base.tenantOverrides?.[tenantId] : undefined;
305
+ return {
306
+ graphConnectionName: overrides?.graphConnectionName ?? base.graphConnectionName,
307
+ adoConnectionName: overrides?.adoConnectionName ?? base.adoConnectionName,
308
+ githubConnectionName: overrides?.githubConnectionName ?? base.githubConnectionName,
309
+ };
310
+ }
271
311
  function getTeamsChannelConfig() {
272
312
  const config = loadConfig();
273
313
  const { skipConfirmation, flushIntervalMs, port } = config.teamsChannel;
274
314
  return { skipConfirmation, flushIntervalMs, port };
275
315
  }
316
+ function getBlueBubblesConfig() {
317
+ const config = loadConfig();
318
+ const { serverUrl, password, accountId } = config.bluebubbles;
319
+ if (!serverUrl.trim()) {
320
+ throw new Error("bluebubbles.serverUrl is required in secrets.json to run the BlueBubbles sense.");
321
+ }
322
+ if (!password.trim()) {
323
+ throw new Error("bluebubbles.password is required in secrets.json to run the BlueBubbles sense.");
324
+ }
325
+ return {
326
+ serverUrl: serverUrl.trim(),
327
+ password: password.trim(),
328
+ accountId: accountId.trim() || "default",
329
+ };
330
+ }
331
+ function getBlueBubblesChannelConfig() {
332
+ const config = loadConfig();
333
+ const { port, webhookPath, requestTimeoutMs } = config.bluebubblesChannel;
334
+ return { port, webhookPath, requestTimeoutMs };
335
+ }
276
336
  function getIntegrationsConfig() {
277
337
  const config = loadConfig();
278
338
  return { ...config.integrations };
279
339
  }
340
+ function getSyncConfig() {
341
+ try {
342
+ const agentConfig = (0, identity_1.loadAgentConfig)();
343
+ return {
344
+ enabled: agentConfig.sync?.enabled ?? false,
345
+ remote: agentConfig.sync?.remote ?? "origin",
346
+ };
347
+ }
348
+ catch {
349
+ /* v8 ignore next -- defensive: loadAgentConfig failure in test/bootstrap @preserve */
350
+ return { enabled: false, remote: "origin" };
351
+ }
352
+ }
280
353
  function getOpenAIEmbeddingsApiKey() {
281
354
  return getIntegrationsConfig().openaiEmbeddingsApiKey;
282
355
  }
283
356
  function getLogsDir() {
284
- return path.join(os.homedir(), ".agentstate", (0, identity_1.getAgentName)(), "logs");
357
+ return path.join((0, identity_1.getAgentRoot)(), "state", "logs");
285
358
  }
286
359
  function sanitizeKey(key) {
287
360
  return key.replace(/[/:]/g, "_");
288
361
  }
289
- function sessionPath(friendId, channel, key) {
290
- const dir = path.join(os.homedir(), ".agentstate", (0, identity_1.getAgentName)(), "sessions", friendId, channel);
291
- fs.mkdirSync(dir, { recursive: true });
362
+ function slugify(value) {
363
+ return value
364
+ .trim()
365
+ .toLowerCase()
366
+ .replace(/[^a-z0-9]+/g, "-")
367
+ .replace(/^-+/, "")
368
+ .replace(/-+$/, "");
369
+ }
370
+ function resolveSessionPath(friendId, channel, key, options) {
371
+ const dir = path.join((0, identity_1.getAgentRoot)(), "state", "sessions", friendId, channel);
372
+ if (options?.ensureDir) {
373
+ fs.mkdirSync(dir, { recursive: true });
374
+ }
292
375
  return path.join(dir, sanitizeKey(key) + ".json");
293
376
  }
377
+ function sessionPath(friendId, channel, key) {
378
+ return resolveSessionPath(friendId, channel, key, { ensureDir: true });
379
+ }
294
380
  function logPath(channel, key) {
295
381
  return path.join(getLogsDir(), channel, sanitizeKey(key) + ".ndjson");
296
382
  }