@ouro.bot/cli 0.1.0-alpha.20 → 0.1.0-alpha.201

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 (204) 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 +1254 -0
  5. package/dist/heart/active-work.js +832 -0
  6. package/dist/heart/bridges/manager.js +358 -0
  7. package/dist/heart/bridges/state-machine.js +135 -0
  8. package/dist/heart/bridges/store.js +123 -0
  9. package/dist/heart/cares.js +179 -0
  10. package/dist/heart/commitments.js +111 -0
  11. package/dist/heart/config.js +54 -30
  12. package/dist/heart/core.js +620 -124
  13. package/dist/heart/cross-chat-delivery.js +146 -0
  14. package/dist/heart/daemon/agent-config-check.js +149 -0
  15. package/dist/heart/daemon/agent-discovery.js +81 -0
  16. package/dist/heart/daemon/agent-service.js +360 -0
  17. package/dist/heart/daemon/auth-flow.js +477 -0
  18. package/dist/heart/daemon/cadence.js +70 -0
  19. package/dist/heart/daemon/daemon-cli.js +2444 -217
  20. package/dist/heart/daemon/daemon-entry.js +182 -4
  21. package/dist/heart/daemon/daemon-health.js +136 -0
  22. package/dist/heart/daemon/daemon-runtime-sync.js +231 -0
  23. package/dist/heart/daemon/daemon-tombstone.js +123 -0
  24. package/dist/heart/daemon/daemon.js +460 -18
  25. package/dist/heart/daemon/habit-migration.js +181 -0
  26. package/dist/heart/daemon/habit-parser.js +119 -0
  27. package/dist/heart/daemon/habit-scheduler.js +369 -0
  28. package/dist/heart/daemon/hatch-flow.js +31 -112
  29. package/dist/heart/daemon/hatch-specialist.js +3 -3
  30. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  31. package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
  32. package/dist/heart/daemon/inner-status.js +89 -0
  33. package/dist/heart/daemon/launchd.js +165 -0
  34. package/dist/heart/daemon/log-tailer.js +4 -3
  35. package/dist/heart/daemon/mcp-server.js +591 -0
  36. package/dist/heart/daemon/message-router.js +17 -8
  37. package/dist/heart/daemon/os-cron-deps.js +134 -0
  38. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  39. package/dist/heart/daemon/ouro-path-installer.js +78 -34
  40. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  41. package/dist/heart/daemon/outlook-http.js +439 -0
  42. package/dist/heart/daemon/outlook-read.js +1618 -0
  43. package/dist/heart/daemon/outlook-render.js +1032 -0
  44. package/dist/heart/daemon/outlook-types.js +7 -0
  45. package/dist/heart/daemon/outlook-view.js +194 -0
  46. package/dist/heart/daemon/process-manager.js +93 -0
  47. package/dist/heart/daemon/run-hooks.js +39 -0
  48. package/dist/heart/daemon/runtime-logging.js +58 -15
  49. package/dist/heart/daemon/runtime-metadata.js +101 -0
  50. package/dist/heart/daemon/runtime-mode.js +67 -0
  51. package/dist/heart/daemon/safe-mode.js +161 -0
  52. package/dist/heart/daemon/sense-manager.js +50 -2
  53. package/dist/heart/daemon/session-id-resolver.js +131 -0
  54. package/dist/heart/daemon/skill-management-installer.js +94 -0
  55. package/dist/heart/daemon/socket-client.js +202 -0
  56. package/dist/heart/daemon/specialist-prompt.js +10 -7
  57. package/dist/heart/daemon/specialist-tools.js +49 -3
  58. package/dist/heart/daemon/staged-restart.js +138 -0
  59. package/dist/heart/daemon/task-scheduler.js +3 -25
  60. package/dist/heart/daemon/thoughts.js +507 -0
  61. package/dist/heart/daemon/update-checker.js +111 -0
  62. package/dist/heart/daemon/update-hooks.js +138 -0
  63. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  64. package/dist/heart/delegation.js +62 -0
  65. package/dist/heart/identity.js +147 -55
  66. package/dist/heart/intentions.js +173 -0
  67. package/dist/heart/kicks.js +2 -20
  68. package/dist/heart/migrate-config.js +127 -0
  69. package/dist/heart/model-capabilities.js +48 -0
  70. package/dist/heart/obligations.js +225 -0
  71. package/dist/heart/presence.js +185 -0
  72. package/dist/heart/progress-story.js +42 -0
  73. package/dist/heart/provider-failover.js +88 -0
  74. package/dist/heart/provider-ping.js +178 -0
  75. package/dist/heart/providers/anthropic-token.js +163 -0
  76. package/dist/heart/providers/anthropic.js +187 -41
  77. package/dist/heart/providers/azure.js +116 -10
  78. package/dist/heart/providers/github-copilot.js +157 -0
  79. package/dist/heart/providers/minimax.js +33 -3
  80. package/dist/heart/providers/openai-codex.js +51 -16
  81. package/dist/heart/session-activity.js +172 -0
  82. package/dist/heart/session-recall.js +216 -0
  83. package/dist/heart/start-of-turn-packet.js +232 -0
  84. package/dist/heart/streaming.js +36 -27
  85. package/dist/heart/sync.js +217 -0
  86. package/dist/heart/target-resolution.js +127 -0
  87. package/dist/heart/tempo.js +93 -0
  88. package/dist/heart/temporal-view.js +41 -0
  89. package/dist/heart/tool-activity-callbacks.js +36 -0
  90. package/dist/heart/tool-description.js +135 -0
  91. package/dist/heart/tool-loop.js +200 -0
  92. package/dist/heart/turn-coordinator.js +28 -0
  93. package/dist/mind/associative-recall.js +122 -32
  94. package/dist/mind/bundle-manifest.js +19 -1
  95. package/dist/mind/context.js +125 -14
  96. package/dist/mind/{memory.js → diary.js} +69 -56
  97. package/dist/mind/episodes.js +119 -0
  98. package/dist/mind/file-state.js +179 -0
  99. package/dist/mind/first-impressions.js +16 -2
  100. package/dist/mind/friends/channel.js +56 -0
  101. package/dist/mind/friends/group-context.js +144 -0
  102. package/dist/mind/friends/store-file.js +36 -0
  103. package/dist/mind/friends/trust-explanation.js +74 -0
  104. package/dist/mind/friends/types.js +8 -0
  105. package/dist/mind/journal-index.js +161 -0
  106. package/dist/mind/obligation-steering.js +221 -0
  107. package/dist/mind/obligations.js +138 -0
  108. package/dist/mind/pending.js +76 -9
  109. package/dist/mind/phrases.js +1 -0
  110. package/dist/mind/prompt.js +785 -103
  111. package/dist/mind/scrutiny.js +173 -0
  112. package/dist/mind/token-estimate.js +8 -12
  113. package/dist/nerves/coverage/audit.js +1 -1
  114. package/dist/nerves/coverage/run-artifacts.js +1 -1
  115. package/dist/nerves/event-buffer.js +111 -0
  116. package/dist/nerves/index.js +63 -3
  117. package/dist/nerves/observation.js +20 -0
  118. package/dist/nerves/runtime.js +5 -1
  119. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  120. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  121. package/dist/outlook-ui/index.html +15 -0
  122. package/dist/repertoire/ado-semantic.js +11 -5
  123. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  124. package/dist/repertoire/coding/context-pack.js +330 -0
  125. package/dist/repertoire/coding/feedback.js +197 -30
  126. package/dist/repertoire/coding/manager.js +149 -2
  127. package/dist/repertoire/coding/spawner.js +55 -9
  128. package/dist/repertoire/coding/tools.js +170 -7
  129. package/dist/repertoire/guardrails.js +291 -0
  130. package/dist/repertoire/mcp-client.js +254 -0
  131. package/dist/repertoire/mcp-manager.js +251 -0
  132. package/dist/repertoire/shell-sessions.js +133 -0
  133. package/dist/repertoire/skills.js +14 -23
  134. package/dist/repertoire/tasks/board.js +43 -5
  135. package/dist/repertoire/tasks/fix.js +182 -0
  136. package/dist/repertoire/tasks/index.js +28 -10
  137. package/dist/repertoire/tasks/lifecycle.js +2 -2
  138. package/dist/repertoire/tasks/parser.js +3 -2
  139. package/dist/repertoire/tasks/scanner.js +194 -37
  140. package/dist/repertoire/tasks/transitions.js +11 -28
  141. package/dist/repertoire/tools-base.js +1345 -320
  142. package/dist/repertoire/tools-bluebubbles.js +94 -0
  143. package/dist/repertoire/tools-github.js +1 -6
  144. package/dist/repertoire/tools-teams.js +12 -59
  145. package/dist/repertoire/tools.js +318 -124
  146. package/dist/scripts/claude-code-hook.js +41 -0
  147. package/dist/scripts/claude-code-stop-hook.js +47 -0
  148. package/dist/senses/attention-queue.js +97 -0
  149. package/dist/senses/bluebubbles-client.js +102 -3
  150. package/dist/senses/bluebubbles-entry.js +2 -0
  151. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  152. package/dist/senses/bluebubbles-media.js +118 -23
  153. package/dist/senses/bluebubbles-model.js +12 -4
  154. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  155. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  156. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  157. package/dist/senses/bluebubbles.js +1008 -102
  158. package/dist/senses/cli/adapter.js +274 -0
  159. package/dist/senses/cli/ink-app.js +156 -0
  160. package/dist/senses/cli/inline-diff.js +64 -0
  161. package/dist/senses/cli/message-list.js +51 -0
  162. package/dist/senses/cli/ouro-tui.js +349 -0
  163. package/dist/senses/cli/spinner-imperative.js +135 -0
  164. package/dist/senses/cli/spinner.js +101 -0
  165. package/dist/senses/cli/status-line.js +60 -0
  166. package/dist/senses/cli/streaming-markdown.js +526 -0
  167. package/dist/senses/cli/tool-display.js +83 -0
  168. package/dist/senses/cli/tool-render.js +85 -0
  169. package/dist/senses/cli/tui-store.js +198 -0
  170. package/dist/senses/cli/virtual-list.js +35 -0
  171. package/dist/senses/cli-entry.js +1 -1
  172. package/dist/senses/cli-layout.js +187 -0
  173. package/dist/senses/cli.js +508 -243
  174. package/dist/senses/commands.js +65 -1
  175. package/dist/senses/continuity.js +94 -0
  176. package/dist/senses/habit-turn-message.js +108 -0
  177. package/dist/senses/inner-dialog-worker.js +112 -19
  178. package/dist/senses/inner-dialog.js +592 -84
  179. package/dist/senses/pipeline.js +693 -0
  180. package/dist/senses/shared-turn.js +196 -0
  181. package/dist/senses/surface-tool.js +95 -0
  182. package/dist/senses/teams.js +667 -120
  183. package/dist/senses/trust-gate.js +112 -2
  184. package/package.json +16 -6
  185. package/skills/configure-dev-tools.md +81 -0
  186. package/subagents/README.md +4 -70
  187. package/dist/heart/daemon/subagent-installer.js +0 -134
  188. package/dist/senses/debug-activity.js +0 -107
  189. package/subagents/work-doer.md +0 -235
  190. package/subagents/work-merger.md +0 -618
  191. package/subagents/work-planner.md +0 -382
  192. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  193. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  194. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  195. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  196. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  197. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  198. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  199. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  200. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  201. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  202. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  203. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  204. /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
+ }
@@ -40,6 +40,7 @@ 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;
44
45
  exports.getTeamsSecondaryConfig = getTeamsSecondaryConfig;
45
46
  exports.getContextConfig = getContextConfig;
@@ -49,38 +50,40 @@ exports.getTeamsChannelConfig = getTeamsChannelConfig;
49
50
  exports.getBlueBubblesConfig = getBlueBubblesConfig;
50
51
  exports.getBlueBubblesChannelConfig = getBlueBubblesChannelConfig;
51
52
  exports.getIntegrationsConfig = getIntegrationsConfig;
53
+ exports.getSyncConfig = getSyncConfig;
52
54
  exports.getOpenAIEmbeddingsApiKey = getOpenAIEmbeddingsApiKey;
53
55
  exports.getLogsDir = getLogsDir;
56
+ exports.sanitizeKey = sanitizeKey;
57
+ exports.slugify = slugify;
58
+ exports.resolveSessionPath = resolveSessionPath;
54
59
  exports.sessionPath = sessionPath;
55
60
  exports.logPath = logPath;
56
61
  const fs = __importStar(require("fs"));
57
62
  const path = __importStar(require("path"));
58
- const os = __importStar(require("os"));
59
63
  const identity_1 = require("./identity");
60
64
  const runtime_1 = require("../nerves/runtime");
61
65
  const DEFAULT_SECRETS_TEMPLATE = {
62
66
  providers: {
63
- // Keep provider field ordering consistent: model first, then auth credentials,
64
- // then provider-specific transport fields.
65
67
  azure: {
66
- modelName: "",
67
68
  apiKey: "",
68
69
  endpoint: "",
69
70
  deployment: "",
70
71
  apiVersion: "2025-04-01-preview",
72
+ managedIdentityClientId: "",
71
73
  },
72
74
  minimax: {
73
- model: "",
74
75
  apiKey: "",
75
76
  },
76
77
  anthropic: {
77
- model: "claude-opus-4-6",
78
78
  setupToken: "",
79
79
  },
80
80
  "openai-codex": {
81
- model: "gpt-5.4",
82
81
  oauthAccessToken: "",
83
82
  },
83
+ "github-copilot": {
84
+ githubToken: "",
85
+ baseUrl: "",
86
+ },
84
87
  },
85
88
  teams: {
86
89
  clientId: "",
@@ -125,6 +128,7 @@ function defaultRuntimeConfig() {
125
128
  minimax: { ...DEFAULT_SECRETS_TEMPLATE.providers.minimax },
126
129
  anthropic: { ...DEFAULT_SECRETS_TEMPLATE.providers.anthropic },
127
130
  "openai-codex": { ...DEFAULT_SECRETS_TEMPLATE.providers["openai-codex"] },
131
+ "github-copilot": { ...DEFAULT_SECRETS_TEMPLATE.providers["github-copilot"] },
128
132
  },
129
133
  teams: { ...DEFAULT_SECRETS_TEMPLATE.teams },
130
134
  teamsSecondary: { ...DEFAULT_SECRETS_TEMPLATE.teamsSecondary },
@@ -136,7 +140,7 @@ function defaultRuntimeConfig() {
136
140
  integrations: { ...DEFAULT_SECRETS_TEMPLATE.integrations },
137
141
  };
138
142
  }
139
- let _cachedConfig = null;
143
+ let _runtimeConfigOverride = null;
140
144
  let _testContextOverride = null;
141
145
  function resolveConfigPath() {
142
146
  return (0, identity_1.getAgentSecretsPath)();
@@ -158,15 +162,6 @@ function deepMerge(defaults, partial) {
158
162
  return result;
159
163
  }
160
164
  function loadConfig() {
161
- if (_cachedConfig) {
162
- (0, runtime_1.emitNervesEvent)({
163
- event: "config.load",
164
- component: "config/identity",
165
- message: "config loaded from cache",
166
- meta: { source: "cache" },
167
- });
168
- return _cachedConfig;
169
- }
170
165
  const configPath = resolveConfigPath();
171
166
  // Auto-create config directory if it doesn't exist
172
167
  const configDir = path.dirname(configPath);
@@ -227,7 +222,10 @@ function loadConfig() {
227
222
  },
228
223
  });
229
224
  }
230
- _cachedConfig = deepMerge(defaultRuntimeConfig(), sanitizedFileData);
225
+ const mergedConfig = deepMerge(defaultRuntimeConfig(), sanitizedFileData);
226
+ const config = _runtimeConfigOverride
227
+ ? deepMerge(mergedConfig, _runtimeConfigOverride)
228
+ : mergedConfig;
231
229
  (0, runtime_1.emitNervesEvent)({
232
230
  event: "config.load",
233
231
  component: "config/identity",
@@ -235,22 +233,22 @@ function loadConfig() {
235
233
  meta: {
236
234
  source: "disk",
237
235
  used_defaults_only: Object.keys(fileData).length === 0,
236
+ override_applied: _runtimeConfigOverride !== null,
238
237
  },
239
238
  });
240
- return _cachedConfig;
239
+ return config;
241
240
  }
242
241
  function resetConfigCache() {
243
- _cachedConfig = null;
242
+ _runtimeConfigOverride = null;
244
243
  _testContextOverride = null;
245
244
  }
246
245
  function patchRuntimeConfig(partial) {
247
- loadConfig(); // ensure _cachedConfig exists
248
246
  const contextPatch = partial.context;
249
247
  if (contextPatch) {
250
248
  const base = _testContextOverride ?? identity_1.DEFAULT_AGENT_CONTEXT;
251
249
  _testContextOverride = deepMerge(base, contextPatch);
252
250
  }
253
- _cachedConfig = deepMerge(_cachedConfig, partial);
251
+ _runtimeConfigOverride = deepMerge((_runtimeConfigOverride ?? {}), partial);
254
252
  }
255
253
  function getAzureConfig() {
256
254
  const config = loadConfig();
@@ -268,6 +266,10 @@ function getOpenAICodexConfig() {
268
266
  const config = loadConfig();
269
267
  return { ...config.providers["openai-codex"] };
270
268
  }
269
+ function getGithubCopilotConfig() {
270
+ const config = loadConfig();
271
+ return { ...config.providers["github-copilot"] };
272
+ }
271
273
  function getTeamsConfig() {
272
274
  const config = loadConfig();
273
275
  return { ...config.teams };
@@ -335,24 +337,46 @@ function getIntegrationsConfig() {
335
337
  const config = loadConfig();
336
338
  return { ...config.integrations };
337
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
+ }
338
353
  function getOpenAIEmbeddingsApiKey() {
339
354
  return getIntegrationsConfig().openaiEmbeddingsApiKey;
340
355
  }
341
356
  function getLogsDir() {
342
- return path.join(os.homedir(), ".agentstate", (0, identity_1.getAgentName)(), "logs");
357
+ return path.join((0, identity_1.getAgentRoot)(), "state", "logs");
343
358
  }
344
359
  function sanitizeKey(key) {
345
360
  return key.replace(/[/:]/g, "_");
346
361
  }
347
- function sessionPath(friendId, channel, key) {
348
- // On Azure App Service, os.homedir() returns /root which is ephemeral.
349
- // Use /home (persistent storage) when WEBSITE_SITE_NAME is set.
350
- /* v8 ignore next -- Azure vs local path branch; environment-specific @preserve */
351
- const homeBase = process.env.WEBSITE_SITE_NAME ? "/home" : os.homedir();
352
- const dir = path.join(homeBase, ".agentstate", (0, identity_1.getAgentName)(), "sessions", friendId, channel);
353
- 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
+ }
354
375
  return path.join(dir, sanitizeKey(key) + ".json");
355
376
  }
377
+ function sessionPath(friendId, channel, key) {
378
+ return resolveSessionPath(friendId, channel, key, { ensureDir: true });
379
+ }
356
380
  function logPath(channel, key) {
357
381
  return path.join(getLogsDir(), channel, sanitizeKey(key) + ".ndjson");
358
382
  }