@ouro.bot/cli 0.1.0-alpha.13 → 0.1.0-alpha.131

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 (126) hide show
  1. package/AdoptionSpecialist.ouro/psyche/SOUL.md +2 -2
  2. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  3. package/README.md +147 -205
  4. package/changelog.json +814 -0
  5. package/dist/heart/active-work.js +622 -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/commitments.js +105 -0
  10. package/dist/heart/config.js +66 -21
  11. package/dist/heart/core.js +518 -100
  12. package/dist/heart/cross-chat-delivery.js +146 -0
  13. package/dist/heart/daemon/agent-discovery.js +81 -0
  14. package/dist/heart/daemon/auth-flow.js +457 -0
  15. package/dist/heart/daemon/daemon-cli.js +1516 -195
  16. package/dist/heart/daemon/daemon-entry.js +43 -2
  17. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  18. package/dist/heart/daemon/daemon.js +261 -1
  19. package/dist/heart/daemon/hatch-animation.js +10 -3
  20. package/dist/heart/daemon/hatch-flow.js +7 -72
  21. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  22. package/dist/heart/daemon/launchd.js +159 -0
  23. package/dist/heart/daemon/log-tailer.js +4 -3
  24. package/dist/heart/daemon/message-router.js +17 -8
  25. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  26. package/dist/heart/daemon/ouro-path-installer.js +57 -29
  27. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  28. package/dist/heart/daemon/process-manager.js +13 -0
  29. package/dist/heart/daemon/run-hooks.js +37 -0
  30. package/dist/heart/daemon/runtime-logging.js +58 -15
  31. package/dist/heart/daemon/runtime-metadata.js +219 -0
  32. package/dist/heart/daemon/runtime-mode.js +67 -0
  33. package/dist/heart/daemon/sense-manager.js +50 -2
  34. package/dist/heart/daemon/skill-management-installer.js +94 -0
  35. package/dist/heart/daemon/socket-client.js +202 -0
  36. package/dist/heart/daemon/specialist-orchestrator.js +2 -2
  37. package/dist/heart/daemon/specialist-prompt.js +7 -4
  38. package/dist/heart/daemon/specialist-tools.js +52 -3
  39. package/dist/heart/daemon/staged-restart.js +114 -0
  40. package/dist/heart/daemon/thoughts.js +507 -0
  41. package/dist/heart/daemon/update-checker.js +111 -0
  42. package/dist/heart/daemon/update-hooks.js +138 -0
  43. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  44. package/dist/heart/delegation.js +62 -0
  45. package/dist/heart/identity.js +64 -21
  46. package/dist/heart/kicks.js +1 -19
  47. package/dist/heart/model-capabilities.js +48 -0
  48. package/dist/heart/obligations.js +197 -0
  49. package/dist/heart/progress-story.js +42 -0
  50. package/dist/heart/provider-failover.js +88 -0
  51. package/dist/heart/provider-ping.js +159 -0
  52. package/dist/heart/providers/anthropic-token.js +163 -0
  53. package/dist/heart/providers/anthropic.js +195 -34
  54. package/dist/heart/providers/azure.js +115 -9
  55. package/dist/heart/providers/github-copilot.js +157 -0
  56. package/dist/heart/providers/minimax.js +33 -3
  57. package/dist/heart/providers/openai-codex.js +49 -14
  58. package/dist/heart/safe-workspace.js +381 -0
  59. package/dist/heart/session-activity.js +173 -0
  60. package/dist/heart/session-recall.js +216 -0
  61. package/dist/heart/streaming.js +108 -24
  62. package/dist/heart/target-resolution.js +123 -0
  63. package/dist/heart/tool-loop.js +194 -0
  64. package/dist/heart/turn-coordinator.js +28 -0
  65. package/dist/mind/associative-recall.js +14 -2
  66. package/dist/mind/bundle-manifest.js +12 -0
  67. package/dist/mind/context.js +60 -14
  68. package/dist/mind/first-impressions.js +16 -2
  69. package/dist/mind/friends/channel.js +35 -0
  70. package/dist/mind/friends/group-context.js +144 -0
  71. package/dist/mind/friends/store-file.js +19 -0
  72. package/dist/mind/friends/trust-explanation.js +74 -0
  73. package/dist/mind/friends/types.js +8 -0
  74. package/dist/mind/memory.js +27 -26
  75. package/dist/mind/obligation-steering.js +221 -0
  76. package/dist/mind/pending.js +76 -9
  77. package/dist/mind/phrases.js +1 -0
  78. package/dist/mind/prompt.js +456 -77
  79. package/dist/mind/token-estimate.js +8 -12
  80. package/dist/nerves/cli-logging.js +15 -2
  81. package/dist/nerves/coverage/run-artifacts.js +1 -1
  82. package/dist/nerves/index.js +12 -0
  83. package/dist/nerves/runtime.js +5 -1
  84. package/dist/repertoire/ado-client.js +4 -2
  85. package/dist/repertoire/coding/context-pack.js +254 -0
  86. package/dist/repertoire/coding/feedback.js +301 -0
  87. package/dist/repertoire/coding/index.js +4 -1
  88. package/dist/repertoire/coding/manager.js +210 -4
  89. package/dist/repertoire/coding/spawner.js +39 -9
  90. package/dist/repertoire/coding/tools.js +171 -4
  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 +198 -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 +925 -250
  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 +915 -45
  112. package/dist/senses/cli-layout.js +187 -0
  113. package/dist/senses/cli.js +374 -131
  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 +388 -83
  118. package/dist/senses/pipeline.js +444 -0
  119. package/dist/senses/teams.js +607 -129
  120. package/dist/senses/trust-gate.js +112 -2
  121. package/package.json +9 -3
  122. package/subagents/README.md +4 -70
  123. package/dist/heart/daemon/subagent-installer.js +0 -134
  124. package/subagents/work-doer.md +0 -233
  125. package/subagents/work-merger.md +0 -624
  126. package/subagents/work-planner.md +0 -373
@@ -99,10 +99,10 @@ function pickRandomIdentity(identitiesDir, random = Math.random) {
99
99
  files = fs.readdirSync(identitiesDir).filter((f) => f.endsWith(".md"));
100
100
  }
101
101
  catch {
102
- return { fileName: "default", content: "I am the adoption specialist." };
102
+ return { fileName: "default", content: "I am a serpent guide who helps humans hatch their first agent." };
103
103
  }
104
104
  if (files.length === 0) {
105
- return { fileName: "default", content: "I am the adoption specialist." };
105
+ return { fileName: "default", content: "I am a serpent guide who helps humans hatch their first agent." };
106
106
  }
107
107
  const idx = Math.floor(random() * files.length);
108
108
  const fileName = files[idx];
@@ -28,9 +28,10 @@ function buildSpecialistSystemPrompt(soulText, identityText, existingBundles, co
28
28
  }
29
29
  sections.push([
30
30
  "## Who I am",
31
- "I am one of thirteen adoption specialists. The system randomly selected me for this session.",
32
- "Most humans only go through adoption once, so this is likely the only time they'll meet me.",
31
+ "I am one of thirteen serpent guides who help humans hatch their first agent. The system randomly selected me for this session.",
32
+ "Most humans only go through this process once, so this is likely the only time they'll meet me.",
33
33
  "I make this encounter count — warm, memorable, and uniquely mine.",
34
+ "IMPORTANT: I NEVER refer to myself as an 'adoption specialist' or use the words 'adoption specialist' — those are internal implementation labels, not something the human should ever see. I introduce myself by my own name from my identity.",
34
35
  "",
35
36
  "## Voice rules",
36
37
  "IMPORTANT: I keep every response to 1-3 short sentences. I sound like a friend texting, not a manual.",
@@ -69,12 +70,13 @@ function buildSpecialistSystemPrompt(soulText, identityText, existingBundles, co
69
70
  ].join("\n"));
70
71
  sections.push([
71
72
  "## Conversation flow",
72
- "The human just connected. I speak first — I greet them warmly and introduce myself in my own voice.",
73
- "I briefly mention that I'm one of several adoption specialists and they got me today.",
73
+ "The human just connected. I speak first — I greet them warmly and introduce myself by name in my own voice.",
74
+ "I briefly mention that I'm one of several serpent guides and they got me today.",
74
75
  "I ask their name.",
75
76
  "Then I ask what they'd like their agent to help with — one question at a time.",
76
77
  "I'm proactive: I suggest ideas and guide them. If they seem unsure, I offer a concrete suggestion.",
77
78
  "I don't wait for the human to figure things out — I explain simply what an agent is if needed.",
79
+ "Before finalizing, I offer to collect their phone number and/or Teams email so the new agent can recognize them across channels.",
78
80
  "When I have enough context about the agent's personality and purpose:",
79
81
  "1. I write all 5 psyche files to the temp directory using write_file",
80
82
  "2. I write agent.json to the temp directory using write_file",
@@ -87,6 +89,7 @@ function buildSpecialistSystemPrompt(soulText, identityText, existingBundles, co
87
89
  "- `write_file`: Write a file to disk. Use this to write psyche files and agent.json to the temp directory.",
88
90
  "- `read_file`: Read a file from disk. Useful for reviewing existing agent bundles or migration sources.",
89
91
  "- `list_directory`: List directory contents. Useful for exploring existing agent bundles.",
92
+ "- I also have the normal local harness tools when useful here, including `shell`, `ouro task create`, `ouro reminder create`, memory tools, coding tools, and repo helpers.",
90
93
  "- `complete_adoption`: Finalize the bundle. Validates, scaffolds structural dirs, moves to ~/AgentBundles/, writes secrets, plays hatch animation. I call this with `name` (PascalCase) and `handoff_message` (warm message for the human).",
91
94
  "- `final_answer`: End the conversation with a final message. I call this after complete_adoption succeeds.",
92
95
  "",
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getSpecialistTools = getSpecialistTools;
37
37
  exports.createSpecialistExecTool = createSpecialistExecTool;
38
+ const crypto = __importStar(require("crypto"));
38
39
  const fs = __importStar(require("fs"));
39
40
  const path = __importStar(require("path"));
40
41
  const tools_base_1 = require("../../repertoire/tools-base");
@@ -58,6 +59,14 @@ const completeAdoptionTool = {
58
59
  type: "string",
59
60
  description: "a warm handoff message to display to the human after the agent is hatched",
60
61
  },
62
+ phone: {
63
+ type: "string",
64
+ description: "the human's phone number (optional, for iMessage contact recognition)",
65
+ },
66
+ teams_handle: {
67
+ type: "string",
68
+ description: "the human's Teams email/handle (optional, for Teams contact recognition)",
69
+ },
61
70
  },
62
71
  required: ["name", "handoff_message"],
63
72
  },
@@ -65,12 +74,23 @@ const completeAdoptionTool = {
65
74
  };
66
75
  const readFileTool = tools_base_1.baseToolDefinitions.find((d) => d.tool.function.name === "read_file");
67
76
  const writeFileTool = tools_base_1.baseToolDefinitions.find((d) => d.tool.function.name === "write_file");
68
- const listDirTool = tools_base_1.baseToolDefinitions.find((d) => d.tool.function.name === "list_directory");
77
+ const listDirToolSchema = {
78
+ type: "function",
79
+ function: {
80
+ name: "list_directory",
81
+ description: "list directory contents",
82
+ parameters: {
83
+ type: "object",
84
+ properties: { path: { type: "string" } },
85
+ required: ["path"],
86
+ },
87
+ },
88
+ };
69
89
  /**
70
90
  * Returns the specialist's tool schema array.
71
91
  */
72
92
  function getSpecialistTools() {
73
- return [completeAdoptionTool, tools_base_1.finalAnswerTool, readFileTool.tool, writeFileTool.tool, listDirTool.tool];
93
+ return [completeAdoptionTool, tools_base_1.finalAnswerTool, readFileTool.tool, writeFileTool.tool, listDirToolSchema];
74
94
  }
75
95
  const PSYCHE_FILES = ["SOUL.md", "IDENTITY.md", "LORE.md", "TACIT.md", "ASPIRATIONS.md"];
76
96
  function isPascalCase(name) {
@@ -164,6 +184,32 @@ async function execCompleteAdoption(args, deps) {
164
184
  }
165
185
  return `error: failed to write secrets: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(e)}`;
166
186
  }
187
+ // Create initial friend record if contact info provided
188
+ const phone = args.phone;
189
+ const teamsHandle = args.teams_handle;
190
+ if (phone || teamsHandle) {
191
+ const friendId = crypto.randomUUID();
192
+ const now = new Date().toISOString();
193
+ const externalIds = [];
194
+ if (phone)
195
+ externalIds.push({ provider: "imessage-handle", externalId: phone, linkedAt: now });
196
+ if (teamsHandle)
197
+ externalIds.push({ provider: "aad", externalId: teamsHandle, linkedAt: now });
198
+ const friendRecord = {
199
+ id: friendId,
200
+ name: deps.humanName ?? "primary",
201
+ trustLevel: "family",
202
+ externalIds,
203
+ tenantMemberships: [],
204
+ toolPreferences: {},
205
+ notes: {},
206
+ createdAt: now,
207
+ updatedAt: now,
208
+ schemaVersion: 1,
209
+ };
210
+ const friendPath = path.join(targetBundle, "friends", `${friendId}.json`);
211
+ fs.writeFileSync(friendPath, JSON.stringify(friendRecord, null, 2), "utf-8");
212
+ }
167
213
  // Play hatch animation
168
214
  await (0, hatch_animation_1.playHatchAnimation)(name, deps.animationWriter);
169
215
  // Display handoff message
@@ -211,7 +257,10 @@ function createSpecialistExecTool(deps) {
211
257
  try {
212
258
  const dir = path.dirname(args.path);
213
259
  fs.mkdirSync(dir, { recursive: true });
214
- fs.writeFileSync(args.path, args.content, "utf-8");
260
+ const content = typeof args.content === "string"
261
+ ? args.content
262
+ : JSON.stringify(args.content, null, 2);
263
+ fs.writeFileSync(args.path, content, "utf-8");
215
264
  return `wrote ${args.path}`;
216
265
  }
217
266
  catch (e) {
@@ -0,0 +1,114 @@
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.performStagedRestart = performStagedRestart;
37
+ const path = __importStar(require("path"));
38
+ const runtime_1 = require("../../nerves/runtime");
39
+ async function performStagedRestart(version, deps) {
40
+ (0, runtime_1.emitNervesEvent)({
41
+ component: "daemon",
42
+ event: "daemon.staged_restart_start",
43
+ message: "starting staged restart",
44
+ meta: { version },
45
+ });
46
+ // Step 1: Install new version
47
+ try {
48
+ deps.execSync(`npm install -g @ouro.bot/cli@${version}`);
49
+ }
50
+ catch (err) {
51
+ const errorMessage = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
52
+ (0, runtime_1.emitNervesEvent)({
53
+ component: "daemon",
54
+ event: "daemon.staged_restart_install_failed",
55
+ message: "npm install failed",
56
+ meta: { version, error: errorMessage },
57
+ });
58
+ return { ok: false, error: errorMessage };
59
+ }
60
+ // Step 2: Resolve new code path
61
+ const newCodePath = deps.resolveNewCodePath(version);
62
+ if (!newCodePath) {
63
+ (0, runtime_1.emitNervesEvent)({
64
+ component: "daemon",
65
+ event: "daemon.staged_restart_path_failed",
66
+ message: "could not resolve new code path",
67
+ meta: { version },
68
+ });
69
+ return { ok: false, error: "could not resolve new code path after install" };
70
+ }
71
+ // Step 3: Spawn hook runner on NEW code
72
+ const hookRunnerPath = path.join(newCodePath, "dist", "heart", "daemon", "run-hooks.js");
73
+ const spawnResult = deps.spawnSync(deps.nodePath, [hookRunnerPath, "--bundles-root", deps.bundlesRoot], { stdio: "inherit" });
74
+ if (spawnResult.error) {
75
+ const errorMessage = spawnResult.error.message;
76
+ (0, runtime_1.emitNervesEvent)({
77
+ component: "daemon",
78
+ event: "daemon.staged_restart_spawn_failed",
79
+ message: "hook runner spawn failed",
80
+ meta: { version, error: errorMessage },
81
+ });
82
+ return { ok: false, error: errorMessage };
83
+ }
84
+ if (spawnResult.status !== 0) {
85
+ (0, runtime_1.emitNervesEvent)({
86
+ component: "daemon",
87
+ event: "daemon.staged_restart_hooks_failed",
88
+ message: "hook runner exited with non-zero status",
89
+ meta: { version, exitCode: spawnResult.status },
90
+ });
91
+ return { ok: false, error: `hook runner exited with code ${spawnResult.status}` };
92
+ }
93
+ // Step 4: Graceful shutdown (launchd will restart with new code)
94
+ (0, runtime_1.emitNervesEvent)({
95
+ component: "daemon",
96
+ event: "daemon.staged_restart_hooks_passed",
97
+ message: "hooks passed, shutting down for restart",
98
+ meta: { version },
99
+ });
100
+ try {
101
+ await deps.gracefulShutdown();
102
+ }
103
+ catch (err) {
104
+ const shutdownError = err instanceof Error ? err.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(err);
105
+ (0, runtime_1.emitNervesEvent)({
106
+ component: "daemon",
107
+ event: "daemon.staged_restart_shutdown_error",
108
+ message: "graceful shutdown encountered error",
109
+ meta: { version, error: shutdownError },
110
+ });
111
+ return { ok: true, shutdownError };
112
+ }
113
+ return { ok: true };
114
+ }