@ouro.bot/cli 0.1.0-alpha.6 → 0.1.0-alpha.60

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 (117) 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 +325 -0
  7. package/dist/heart/active-work.js +178 -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/config.js +57 -23
  12. package/dist/heart/core.js +236 -90
  13. package/dist/heart/cross-chat-delivery.js +146 -0
  14. package/dist/heart/daemon/agent-discovery.js +81 -0
  15. package/dist/heart/daemon/auth-flow.js +351 -0
  16. package/dist/heart/daemon/daemon-cli.js +1173 -227
  17. package/dist/heart/daemon/daemon-entry.js +55 -6
  18. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  19. package/dist/heart/daemon/daemon.js +189 -10
  20. package/dist/heart/daemon/hatch-animation.js +10 -3
  21. package/dist/heart/daemon/hatch-flow.js +4 -82
  22. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  23. package/dist/heart/daemon/launchd.js +159 -0
  24. package/dist/heart/daemon/log-tailer.js +4 -3
  25. package/dist/heart/daemon/message-router.js +17 -8
  26. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  27. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  28. package/dist/heart/daemon/ouro-entry.js +0 -0
  29. package/dist/heart/daemon/ouro-path-installer.js +178 -0
  30. package/dist/heart/daemon/ouro-uti.js +11 -2
  31. package/dist/heart/daemon/process-manager.js +14 -1
  32. package/dist/heart/daemon/run-hooks.js +37 -0
  33. package/dist/heart/daemon/runtime-logging.js +58 -15
  34. package/dist/heart/daemon/runtime-metadata.js +219 -0
  35. package/dist/heart/daemon/runtime-mode.js +67 -0
  36. package/dist/heart/daemon/sense-manager.js +307 -0
  37. package/dist/heart/daemon/socket-client.js +202 -0
  38. package/dist/heart/daemon/specialist-orchestrator.js +53 -84
  39. package/dist/heart/daemon/specialist-prompt.js +64 -5
  40. package/dist/heart/daemon/specialist-tools.js +213 -58
  41. package/dist/heart/daemon/staged-restart.js +114 -0
  42. package/dist/heart/daemon/subagent-installer.js +48 -7
  43. package/dist/heart/daemon/thoughts.js +379 -0
  44. package/dist/heart/daemon/update-checker.js +111 -0
  45. package/dist/heart/daemon/update-hooks.js +138 -0
  46. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  47. package/dist/heart/delegation.js +62 -0
  48. package/dist/heart/identity.js +122 -19
  49. package/dist/heart/kicks.js +1 -19
  50. package/dist/heart/model-capabilities.js +40 -0
  51. package/dist/heart/progress-story.js +42 -0
  52. package/dist/heart/providers/anthropic.js +74 -9
  53. package/dist/heart/providers/azure.js +86 -7
  54. package/dist/heart/providers/minimax.js +4 -0
  55. package/dist/heart/providers/openai-codex.js +12 -3
  56. package/dist/heart/safe-workspace.js +228 -0
  57. package/dist/heart/sense-truth.js +61 -0
  58. package/dist/heart/session-activity.js +169 -0
  59. package/dist/heart/session-recall.js +116 -0
  60. package/dist/heart/streaming.js +100 -22
  61. package/dist/heart/target-resolution.js +123 -0
  62. package/dist/heart/turn-coordinator.js +28 -0
  63. package/dist/mind/associative-recall.js +14 -2
  64. package/dist/mind/bundle-manifest.js +70 -0
  65. package/dist/mind/context.js +27 -11
  66. package/dist/mind/first-impressions.js +16 -2
  67. package/dist/mind/friends/channel.js +35 -0
  68. package/dist/mind/friends/group-context.js +144 -0
  69. package/dist/mind/friends/store-file.js +19 -0
  70. package/dist/mind/friends/trust-explanation.js +74 -0
  71. package/dist/mind/friends/types.js +8 -0
  72. package/dist/mind/memory.js +27 -26
  73. package/dist/mind/pending.js +72 -9
  74. package/dist/mind/phrases.js +1 -0
  75. package/dist/mind/prompt.js +299 -77
  76. package/dist/mind/token-estimate.js +8 -12
  77. package/dist/nerves/cli-logging.js +15 -2
  78. package/dist/nerves/coverage/run-artifacts.js +1 -1
  79. package/dist/repertoire/ado-client.js +4 -2
  80. package/dist/repertoire/coding/feedback.js +134 -0
  81. package/dist/repertoire/coding/index.js +4 -1
  82. package/dist/repertoire/coding/manager.js +62 -4
  83. package/dist/repertoire/coding/spawner.js +3 -3
  84. package/dist/repertoire/coding/tools.js +41 -2
  85. package/dist/repertoire/data/ado-endpoints.json +188 -0
  86. package/dist/repertoire/tasks/board.js +12 -0
  87. package/dist/repertoire/tasks/index.js +23 -9
  88. package/dist/repertoire/tasks/transitions.js +1 -2
  89. package/dist/repertoire/tools-base.js +629 -251
  90. package/dist/repertoire/tools-bluebubbles.js +93 -0
  91. package/dist/repertoire/tools-teams.js +58 -25
  92. package/dist/repertoire/tools.js +92 -48
  93. package/dist/senses/bluebubbles-client.js +210 -5
  94. package/dist/senses/bluebubbles-entry.js +2 -0
  95. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  96. package/dist/senses/bluebubbles-media.js +339 -0
  97. package/dist/senses/bluebubbles-model.js +12 -4
  98. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  99. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  100. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  101. package/dist/senses/bluebubbles.js +890 -45
  102. package/dist/senses/cli-layout.js +87 -0
  103. package/dist/senses/cli.js +345 -144
  104. package/dist/senses/continuity.js +94 -0
  105. package/dist/senses/debug-activity.js +148 -0
  106. package/dist/senses/inner-dialog-worker.js +47 -18
  107. package/dist/senses/inner-dialog.js +330 -84
  108. package/dist/senses/pipeline.js +278 -0
  109. package/dist/senses/teams.js +570 -129
  110. package/dist/senses/trust-gate.js +112 -2
  111. package/package.json +14 -3
  112. package/subagents/README.md +46 -33
  113. package/subagents/work-doer.md +28 -24
  114. package/subagents/work-merger.md +24 -30
  115. package/subagents/work-planner.md +44 -27
  116. package/dist/heart/daemon/specialist-session.js +0 -142
  117. package/dist/inner-worker-entry.js +0 -4
@@ -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)
@@ -33,24 +33,56 @@ 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.enqueueDeferredReturn = enqueueDeferredReturn;
42
+ exports.drainDeferredReturns = drainDeferredReturns;
37
43
  exports.drainPending = drainPending;
38
44
  const fs = __importStar(require("fs"));
39
45
  const path = __importStar(require("path"));
40
- const os = __importStar(require("os"));
46
+ const identity_1 = require("../heart/identity");
41
47
  const runtime_1 = require("../nerves/runtime");
42
48
  function getPendingDir(agentName, friendId, channel, key) {
43
- return path.join(os.homedir(), ".agentstate", agentName, "pending", friendId, channel, key);
49
+ return path.join((0, identity_1.getAgentRoot)(agentName), "state", "pending", friendId, channel, key);
44
50
  }
45
- function drainPending(pendingDir) {
51
+ function getDeferredReturnDir(agentName, friendId) {
52
+ return path.join((0, identity_1.getAgentRoot)(agentName), "state", "pending-returns", friendId);
53
+ }
54
+ /** Canonical inner-dialog pending path segments. */
55
+ exports.INNER_DIALOG_PENDING = { friendId: "self", channel: "inner", key: "dialog" };
56
+ /** Returns the pending dir for this agent's inner dialog. */
57
+ function getInnerDialogPendingDir(agentName) {
58
+ return getPendingDir(agentName, exports.INNER_DIALOG_PENDING.friendId, exports.INNER_DIALOG_PENDING.channel, exports.INNER_DIALOG_PENDING.key);
59
+ }
60
+ function hasPendingMessages(pendingDir) {
46
61
  if (!fs.existsSync(pendingDir))
47
- return [];
62
+ return false;
63
+ try {
64
+ return fs.readdirSync(pendingDir).some((entry) => entry.endsWith(".json") || entry.endsWith(".json.processing"));
65
+ }
66
+ catch {
67
+ return false;
68
+ }
69
+ }
70
+ function writeQueueFile(queueDir, message) {
71
+ fs.mkdirSync(queueDir, { recursive: true });
72
+ const fileName = `${message.timestamp}-${Math.random().toString(36).slice(2, 10)}.json`;
73
+ const filePath = path.join(queueDir, fileName);
74
+ fs.writeFileSync(filePath, JSON.stringify(message, null, 2));
75
+ return filePath;
76
+ }
77
+ function drainQueue(queueDir) {
78
+ if (!fs.existsSync(queueDir))
79
+ return { messages: [], recovered: 0 };
48
80
  let entries;
49
81
  try {
50
- entries = fs.readdirSync(pendingDir);
82
+ entries = fs.readdirSync(queueDir);
51
83
  }
52
84
  catch {
53
- return [];
85
+ return { messages: [], recovered: 0 };
54
86
  }
55
87
  // Collect both .json (new) and .processing (crash recovery)
56
88
  const jsonFiles = entries.filter(f => f.endsWith(".json") && !f.endsWith(".processing"));
@@ -62,9 +94,9 @@ function drainPending(pendingDir) {
62
94
  ].sort((a, b) => a.file.localeCompare(b.file));
63
95
  const messages = [];
64
96
  for (const { file, needsRename } of allFiles) {
65
- const srcPath = path.join(pendingDir, file);
97
+ const srcPath = path.join(queueDir, file);
66
98
  const processingPath = needsRename
67
- ? path.join(pendingDir, file + ".processing")
99
+ ? path.join(queueDir, file + ".processing")
68
100
  : srcPath;
69
101
  try {
70
102
  if (needsRename) {
@@ -83,11 +115,42 @@ function drainPending(pendingDir) {
83
115
  catch { /* ignore */ }
84
116
  }
85
117
  }
118
+ return {
119
+ messages,
120
+ recovered: processingFiles.length,
121
+ };
122
+ }
123
+ function enqueueDeferredReturn(agentName, friendId, message) {
124
+ const queueDir = getDeferredReturnDir(agentName, friendId);
125
+ const filePath = writeQueueFile(queueDir, message);
126
+ (0, runtime_1.emitNervesEvent)({
127
+ event: "mind.deferred_return_enqueued",
128
+ component: "mind",
129
+ message: "deferred return queued for later friend delivery",
130
+ meta: { friendId, queueDir },
131
+ });
132
+ return filePath;
133
+ }
134
+ function drainDeferredReturns(agentName, friendId) {
135
+ const queueDir = getDeferredReturnDir(agentName, friendId);
136
+ const { messages } = drainQueue(queueDir);
137
+ (0, runtime_1.emitNervesEvent)({
138
+ event: "mind.deferred_returns_drained",
139
+ component: "mind",
140
+ message: "deferred friend returns drained",
141
+ meta: { friendId, queueDir, count: messages.length },
142
+ });
143
+ return messages;
144
+ }
145
+ function drainPending(pendingDir) {
146
+ if (!fs.existsSync(pendingDir))
147
+ return [];
148
+ const { messages, recovered } = drainQueue(pendingDir);
86
149
  (0, runtime_1.emitNervesEvent)({
87
150
  event: "mind.pending_drained",
88
151
  component: "mind",
89
152
  message: "pending queue drained",
90
- meta: { pendingDir, count: messages.length, recovered: processingFiles.length },
153
+ meta: { pendingDir, count: messages.length, recovered },
91
154
  });
92
155
  return messages;
93
156
  }
@@ -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",