@ouro.bot/cli 0.1.0-alpha.9 → 0.1.0-alpha.91

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 (128) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +70 -9
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +147 -205
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +536 -0
  7. package/dist/heart/active-work.js +251 -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/commitments.js +109 -0
  12. package/dist/heart/config.js +68 -23
  13. package/dist/heart/core.js +452 -93
  14. package/dist/heart/cross-chat-delivery.js +146 -0
  15. package/dist/heart/daemon/agent-discovery.js +81 -0
  16. package/dist/heart/daemon/auth-flow.js +430 -0
  17. package/dist/heart/daemon/daemon-cli.js +1738 -269
  18. package/dist/heart/daemon/daemon-entry.js +55 -6
  19. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  20. package/dist/heart/daemon/daemon.js +216 -10
  21. package/dist/heart/daemon/hatch-animation.js +10 -3
  22. package/dist/heart/daemon/hatch-flow.js +7 -82
  23. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  24. package/dist/heart/daemon/launchd.js +159 -0
  25. package/dist/heart/daemon/log-tailer.js +4 -3
  26. package/dist/heart/daemon/message-router.js +17 -8
  27. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  28. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  29. package/dist/heart/daemon/ouro-entry.js +0 -0
  30. package/dist/heart/daemon/ouro-path-installer.js +260 -0
  31. package/dist/heart/daemon/ouro-uti.js +11 -2
  32. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  33. package/dist/heart/daemon/process-manager.js +14 -1
  34. package/dist/heart/daemon/run-hooks.js +37 -0
  35. package/dist/heart/daemon/runtime-logging.js +58 -15
  36. package/dist/heart/daemon/runtime-metadata.js +219 -0
  37. package/dist/heart/daemon/runtime-mode.js +67 -0
  38. package/dist/heart/daemon/sense-manager.js +307 -0
  39. package/dist/heart/daemon/skill-management-installer.js +94 -0
  40. package/dist/heart/daemon/socket-client.js +202 -0
  41. package/dist/heart/daemon/specialist-orchestrator.js +53 -84
  42. package/dist/heart/daemon/specialist-prompt.js +63 -11
  43. package/dist/heart/daemon/specialist-tools.js +211 -60
  44. package/dist/heart/daemon/staged-restart.js +114 -0
  45. package/dist/heart/daemon/thoughts.js +507 -0
  46. package/dist/heart/daemon/update-checker.js +111 -0
  47. package/dist/heart/daemon/update-hooks.js +138 -0
  48. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  49. package/dist/heart/delegation.js +62 -0
  50. package/dist/heart/identity.js +126 -21
  51. package/dist/heart/kicks.js +1 -19
  52. package/dist/heart/model-capabilities.js +48 -0
  53. package/dist/heart/obligations.js +191 -0
  54. package/dist/heart/progress-story.js +42 -0
  55. package/dist/heart/providers/anthropic.js +74 -9
  56. package/dist/heart/providers/azure.js +86 -7
  57. package/dist/heart/providers/github-copilot.js +149 -0
  58. package/dist/heart/providers/minimax.js +4 -0
  59. package/dist/heart/providers/openai-codex.js +12 -3
  60. package/dist/heart/safe-workspace.js +362 -0
  61. package/dist/heart/sense-truth.js +61 -0
  62. package/dist/heart/session-activity.js +169 -0
  63. package/dist/heart/session-recall.js +116 -0
  64. package/dist/heart/streaming.js +100 -22
  65. package/dist/heart/target-resolution.js +123 -0
  66. package/dist/heart/turn-coordinator.js +28 -0
  67. package/dist/mind/associative-recall.js +14 -2
  68. package/dist/mind/bundle-manifest.js +70 -0
  69. package/dist/mind/context.js +57 -11
  70. package/dist/mind/first-impressions.js +16 -2
  71. package/dist/mind/friends/channel.js +35 -0
  72. package/dist/mind/friends/group-context.js +144 -0
  73. package/dist/mind/friends/store-file.js +19 -0
  74. package/dist/mind/friends/trust-explanation.js +74 -0
  75. package/dist/mind/friends/types.js +8 -0
  76. package/dist/mind/memory.js +27 -26
  77. package/dist/mind/obligation-steering.js +31 -0
  78. package/dist/mind/pending.js +76 -9
  79. package/dist/mind/phrases.js +1 -0
  80. package/dist/mind/prompt.js +467 -77
  81. package/dist/mind/token-estimate.js +8 -12
  82. package/dist/nerves/cli-logging.js +15 -2
  83. package/dist/nerves/coverage/run-artifacts.js +1 -1
  84. package/dist/nerves/index.js +12 -0
  85. package/dist/repertoire/ado-client.js +4 -2
  86. package/dist/repertoire/coding/feedback.js +180 -0
  87. package/dist/repertoire/coding/index.js +4 -1
  88. package/dist/repertoire/coding/manager.js +69 -4
  89. package/dist/repertoire/coding/spawner.js +21 -3
  90. package/dist/repertoire/coding/tools.js +105 -2
  91. package/dist/repertoire/data/ado-endpoints.json +188 -0
  92. package/dist/repertoire/guardrails.js +290 -0
  93. package/dist/repertoire/mcp-client.js +254 -0
  94. package/dist/repertoire/mcp-manager.js +195 -0
  95. package/dist/repertoire/skills.js +3 -26
  96. package/dist/repertoire/tasks/board.js +12 -0
  97. package/dist/repertoire/tasks/index.js +23 -9
  98. package/dist/repertoire/tasks/transitions.js +1 -2
  99. package/dist/repertoire/tools-base.js +714 -249
  100. package/dist/repertoire/tools-bluebubbles.js +93 -0
  101. package/dist/repertoire/tools-teams.js +58 -25
  102. package/dist/repertoire/tools.js +106 -53
  103. package/dist/senses/bluebubbles-client.js +210 -5
  104. package/dist/senses/bluebubbles-entry.js +2 -0
  105. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  106. package/dist/senses/bluebubbles-media.js +339 -0
  107. package/dist/senses/bluebubbles-model.js +12 -4
  108. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  109. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  110. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  111. package/dist/senses/bluebubbles.js +894 -45
  112. package/dist/senses/cli-layout.js +187 -0
  113. package/dist/senses/cli.js +400 -164
  114. package/dist/senses/continuity.js +94 -0
  115. package/dist/senses/debug-activity.js +154 -0
  116. package/dist/senses/inner-dialog-worker.js +47 -18
  117. package/dist/senses/inner-dialog.js +377 -83
  118. package/dist/senses/pipeline.js +307 -0
  119. package/dist/senses/teams.js +573 -129
  120. package/dist/senses/trust-gate.js +112 -2
  121. package/package.json +14 -3
  122. package/subagents/README.md +4 -70
  123. package/dist/heart/daemon/specialist-session.js +0 -142
  124. package/dist/heart/daemon/subagent-installer.js +0 -125
  125. package/dist/inner-worker-entry.js +0 -4
  126. package/subagents/work-doer.md +0 -233
  127. package/subagents/work-merger.md +0 -624
  128. package/subagents/work-planner.md +0 -373
@@ -33,7 +33,6 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.__memoryTestUtils = void 0;
37
36
  exports.ensureMemoryStorePaths = ensureMemoryStorePaths;
38
37
  exports.appendFactsWithDedup = appendFactsWithDedup;
39
38
  exports.readMemoryFacts = readMemoryFacts;
@@ -46,7 +45,9 @@ const crypto_1 = require("crypto");
46
45
  const config_1 = require("../heart/config");
47
46
  const identity_1 = require("../heart/identity");
48
47
  const runtime_1 = require("../nerves/runtime");
48
+ const associative_recall_1 = require("./associative-recall");
49
49
  const DEDUP_THRESHOLD = 0.6;
50
+ const SEMANTIC_DEDUP_THRESHOLD = 0.95;
50
51
  const ENTITY_TOKEN = /[a-z0-9]+/g;
51
52
  const DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small";
52
53
  class OpenAIEmbeddingProvider {
@@ -120,9 +121,16 @@ function readExistingFacts(factsPath) {
120
121
  const raw = fs.readFileSync(factsPath, "utf8").trim();
121
122
  if (!raw)
122
123
  return [];
123
- return raw
124
- .split("\n")
125
- .map((line) => JSON.parse(line));
124
+ const facts = [];
125
+ for (const line of raw.split("\n")) {
126
+ try {
127
+ facts.push(JSON.parse(line));
128
+ }
129
+ catch {
130
+ // Skip corrupt lines (e.g. partial write from a crash).
131
+ }
132
+ }
133
+ return facts;
126
134
  }
127
135
  function readEntityIndex(entitiesPath) {
128
136
  if (!fs.existsSync(entitiesPath))
@@ -170,13 +178,24 @@ function appendDailyFact(dailyDir, fact) {
170
178
  const dayPath = path.join(dailyDir, `${day}.jsonl`);
171
179
  fs.appendFileSync(dayPath, `${JSON.stringify(fact)}\n`, "utf8");
172
180
  }
173
- function appendFactsWithDedup(stores, incoming) {
181
+ function appendFactsWithDedup(stores, incoming, options) {
174
182
  const existing = readExistingFacts(stores.factsPath);
175
183
  const all = [...existing];
176
184
  let added = 0;
177
185
  let skipped = 0;
186
+ const semanticThreshold = options?.semanticThreshold;
178
187
  for (const fact of incoming) {
179
- const duplicate = all.some((prior) => overlapScore(prior.text, fact.text) > DEDUP_THRESHOLD);
188
+ const duplicate = all.some((prior) => {
189
+ if (overlapScore(prior.text, fact.text) > DEDUP_THRESHOLD)
190
+ return true;
191
+ if (semanticThreshold !== undefined &&
192
+ Array.isArray(fact.embedding) && fact.embedding.length > 0 &&
193
+ Array.isArray(prior.embedding) && prior.embedding.length > 0 &&
194
+ fact.embedding.length === prior.embedding.length) {
195
+ return (0, associative_recall_1.cosineSimilarity)(fact.embedding, prior.embedding) > semanticThreshold;
196
+ }
197
+ return false;
198
+ });
180
199
  if (duplicate) {
181
200
  skipped++;
182
201
  continue;
@@ -195,24 +214,6 @@ function appendFactsWithDedup(stores, incoming) {
195
214
  });
196
215
  return { added, skipped };
197
216
  }
198
- function cosineSimilarity(left, right) {
199
- if (left.length === 0 || right.length === 0 || left.length !== right.length)
200
- return 0;
201
- let dot = 0;
202
- let leftNorm = 0;
203
- let rightNorm = 0;
204
- for (let i = 0; i < left.length; i += 1) {
205
- dot += left[i] * right[i];
206
- leftNorm += left[i] * left[i];
207
- rightNorm += right[i] * right[i];
208
- }
209
- if (leftNorm === 0 || rightNorm === 0)
210
- return 0;
211
- return dot / (Math.sqrt(leftNorm) * Math.sqrt(rightNorm));
212
- }
213
- exports.__memoryTestUtils = {
214
- cosineSimilarity,
215
- };
216
217
  function createDefaultEmbeddingProvider() {
217
218
  const apiKey = (0, config_1.getOpenAIEmbeddingsApiKey)().trim();
218
219
  if (!apiKey)
@@ -264,7 +265,7 @@ async function saveMemoryFact(options) {
264
265
  createdAt: (options.now ?? (() => new Date()))().toISOString(),
265
266
  embedding,
266
267
  };
267
- return appendFactsWithDedup(stores, [fact]);
268
+ return appendFactsWithDedup(stores, [fact], { semanticThreshold: SEMANTIC_DEDUP_THRESHOLD });
268
269
  }
269
270
  async function backfillEmbeddings(options) {
270
271
  const memoryRoot = options?.memoryRoot ?? path.join((0, identity_1.getAgentRoot)(), "psyche", "memory");
@@ -365,7 +366,7 @@ async function searchMemoryFacts(query, facts, embeddingProvider) {
365
366
  .filter((fact) => fact.embedding.length === queryEmbedding.length)
366
367
  .map((fact) => ({
367
368
  fact,
368
- score: cosineSimilarity(queryEmbedding, fact.embedding),
369
+ score: (0, associative_recall_1.cosineSimilarity)(queryEmbedding, fact.embedding),
369
370
  }))
370
371
  .filter((entry) => entry.score > 0)
371
372
  .sort((left, right) => right.score - left.score)
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findActivePersistentObligation = findActivePersistentObligation;
4
+ exports.renderActiveObligationSteering = renderActiveObligationSteering;
5
+ const runtime_1 = require("../nerves/runtime");
6
+ function findActivePersistentObligation(frame) {
7
+ if (!frame)
8
+ return null;
9
+ return (frame.pendingObligations ?? []).find((ob) => ob.status !== "pending" && ob.status !== "fulfilled") ?? null;
10
+ }
11
+ function renderActiveObligationSteering(obligation) {
12
+ (0, runtime_1.emitNervesEvent)({
13
+ component: "mind",
14
+ event: "mind.obligation_steering_rendered",
15
+ message: "rendered active obligation steering",
16
+ meta: {
17
+ hasObligation: Boolean(obligation),
18
+ hasSurface: Boolean(obligation?.currentSurface?.label),
19
+ },
20
+ });
21
+ if (!obligation)
22
+ return "";
23
+ const name = obligation.origin.friendId;
24
+ const surfaceLine = obligation.currentSurface?.label
25
+ ? `\nright now that work is happening in ${obligation.currentSurface.label}.`
26
+ : "";
27
+ return `## where my attention is
28
+ i'm already working on something i owe ${name}.${surfaceLine}
29
+
30
+ i should close that loop before i act like this is a fresh blank turn.`;
31
+ }
@@ -33,24 +33,60 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.INNER_DIALOG_PENDING = void 0;
36
37
  exports.getPendingDir = getPendingDir;
38
+ exports.getDeferredReturnDir = getDeferredReturnDir;
39
+ exports.getInnerDialogPendingDir = getInnerDialogPendingDir;
40
+ exports.hasPendingMessages = hasPendingMessages;
41
+ exports.queuePendingMessage = queuePendingMessage;
42
+ exports.enqueueDeferredReturn = enqueueDeferredReturn;
43
+ exports.drainDeferredReturns = drainDeferredReturns;
37
44
  exports.drainPending = drainPending;
38
45
  const fs = __importStar(require("fs"));
39
46
  const path = __importStar(require("path"));
40
- const os = __importStar(require("os"));
47
+ const identity_1 = require("../heart/identity");
41
48
  const runtime_1 = require("../nerves/runtime");
42
49
  function getPendingDir(agentName, friendId, channel, key) {
43
- return path.join(os.homedir(), ".agentstate", agentName, "pending", friendId, channel, key);
50
+ return path.join((0, identity_1.getAgentRoot)(agentName), "state", "pending", friendId, channel, key);
44
51
  }
45
- function drainPending(pendingDir) {
52
+ function getDeferredReturnDir(agentName, friendId) {
53
+ return path.join((0, identity_1.getAgentRoot)(agentName), "state", "pending-returns", friendId);
54
+ }
55
+ /** Canonical inner-dialog pending path segments. */
56
+ exports.INNER_DIALOG_PENDING = { friendId: "self", channel: "inner", key: "dialog" };
57
+ /** Returns the pending dir for this agent's inner dialog. */
58
+ function getInnerDialogPendingDir(agentName) {
59
+ return getPendingDir(agentName, exports.INNER_DIALOG_PENDING.friendId, exports.INNER_DIALOG_PENDING.channel, exports.INNER_DIALOG_PENDING.key);
60
+ }
61
+ function hasPendingMessages(pendingDir) {
46
62
  if (!fs.existsSync(pendingDir))
47
- return [];
63
+ return false;
64
+ try {
65
+ return fs.readdirSync(pendingDir).some((entry) => entry.endsWith(".json") || entry.endsWith(".json.processing"));
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ function writeQueueFile(queueDir, message) {
72
+ fs.mkdirSync(queueDir, { recursive: true });
73
+ const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
74
+ const filePath = path.join(queueDir, fileName);
75
+ fs.writeFileSync(filePath, JSON.stringify(message, null, 2));
76
+ return filePath;
77
+ }
78
+ function queuePendingMessage(pendingDir, message) {
79
+ writeQueueFile(pendingDir, message);
80
+ }
81
+ function drainQueue(queueDir) {
82
+ if (!fs.existsSync(queueDir))
83
+ return { messages: [], recovered: 0 };
48
84
  let entries;
49
85
  try {
50
- entries = fs.readdirSync(pendingDir);
86
+ entries = fs.readdirSync(queueDir);
51
87
  }
52
88
  catch {
53
- return [];
89
+ return { messages: [], recovered: 0 };
54
90
  }
55
91
  // Collect both .json (new) and .processing (crash recovery)
56
92
  const jsonFiles = entries.filter(f => f.endsWith(".json") && !f.endsWith(".processing"));
@@ -62,9 +98,9 @@ function drainPending(pendingDir) {
62
98
  ].sort((a, b) => a.file.localeCompare(b.file));
63
99
  const messages = [];
64
100
  for (const { file, needsRename } of allFiles) {
65
- const srcPath = path.join(pendingDir, file);
101
+ const srcPath = path.join(queueDir, file);
66
102
  const processingPath = needsRename
67
- ? path.join(pendingDir, file + ".processing")
103
+ ? path.join(queueDir, file + ".processing")
68
104
  : srcPath;
69
105
  try {
70
106
  if (needsRename) {
@@ -83,11 +119,42 @@ function drainPending(pendingDir) {
83
119
  catch { /* ignore */ }
84
120
  }
85
121
  }
122
+ return {
123
+ messages,
124
+ recovered: processingFiles.length,
125
+ };
126
+ }
127
+ function enqueueDeferredReturn(agentName, friendId, message) {
128
+ const queueDir = getDeferredReturnDir(agentName, friendId);
129
+ const filePath = writeQueueFile(queueDir, message);
130
+ (0, runtime_1.emitNervesEvent)({
131
+ event: "mind.deferred_return_enqueued",
132
+ component: "mind",
133
+ message: "deferred return queued for later friend delivery",
134
+ meta: { friendId, queueDir },
135
+ });
136
+ return filePath;
137
+ }
138
+ function drainDeferredReturns(agentName, friendId) {
139
+ const queueDir = getDeferredReturnDir(agentName, friendId);
140
+ const { messages } = drainQueue(queueDir);
141
+ (0, runtime_1.emitNervesEvent)({
142
+ event: "mind.deferred_returns_drained",
143
+ component: "mind",
144
+ message: "deferred friend returns drained",
145
+ meta: { friendId, queueDir, count: messages.length },
146
+ });
147
+ return messages;
148
+ }
149
+ function drainPending(pendingDir) {
150
+ if (!fs.existsSync(pendingDir))
151
+ return [];
152
+ const { messages, recovered } = drainQueue(pendingDir);
86
153
  (0, runtime_1.emitNervesEvent)({
87
154
  event: "mind.pending_drained",
88
155
  component: "mind",
89
156
  message: "pending queue drained",
90
- meta: { pendingDir, count: messages.length, recovered: processingFiles.length },
157
+ meta: { pendingDir, count: messages.length, recovered },
91
158
  });
92
159
  return messages;
93
160
  }
@@ -16,6 +16,7 @@ function getPhrases() {
16
16
  message: "loading phrase pools",
17
17
  meta: {},
18
18
  });
19
+ (0, identity_1.resetAgentConfigCache)();
19
20
  const phrases = (0, identity_1.loadAgentConfig)().phrases;
20
21
  (0, runtime_1.emitNervesEvent)({
21
22
  event: "repertoire.load_end",