@ouro.bot/cli 0.1.0-alpha.87 → 0.1.0-alpha.89

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.
package/changelog.json CHANGED
@@ -1,6 +1,19 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.89",
6
+ "changes": [
7
+ "Spawned coding sessions now inject ~/.ouro-cli/bin into PATH so child processes (claude, codex) can resolve ouro CLI binaries without relying on the parent shell's PATH."
8
+ ]
9
+ },
10
+ {
11
+ "version": "0.1.0-alpha.88",
12
+ "changes": [
13
+ "CLI session repair now strips orphaned tool-result messages when a saved chat history lost the matching assistant tool call, so a broken prior turn no longer bricks every future `ouro chat` message with a tool-call replay error.",
14
+ "Recovered sessions keep valid tool call/result pairs intact while dropping only the stale outputs, which lets live operator chats resume from repaired history instead of forcing a brand-new thread."
15
+ ]
16
+ },
4
17
  {
5
18
  "version": "0.1.0-alpha.87",
6
19
  "changes": [
@@ -227,6 +227,34 @@ function repairSessionMessages(messages) {
227
227
  });
228
228
  return result;
229
229
  }
230
+ function stripOrphanedToolResults(messages) {
231
+ const validCallIds = new Set();
232
+ for (const msg of messages) {
233
+ if (msg.role !== "assistant" || !Array.isArray(msg.tool_calls))
234
+ continue;
235
+ for (const toolCall of msg.tool_calls)
236
+ validCallIds.add(toolCall.id);
237
+ }
238
+ let removed = 0;
239
+ const repaired = messages.filter((msg) => {
240
+ if (msg.role !== "tool")
241
+ return true;
242
+ const keep = validCallIds.has(msg.tool_call_id);
243
+ if (!keep)
244
+ removed++;
245
+ return keep;
246
+ });
247
+ if (removed > 0) {
248
+ (0, runtime_1.emitNervesEvent)({
249
+ level: "warn",
250
+ event: "mind.session_orphan_tool_result_repair",
251
+ component: "mind",
252
+ message: "removed orphaned tool results from session history",
253
+ meta: { removed },
254
+ });
255
+ }
256
+ return repaired;
257
+ }
230
258
  function saveSession(filePath, messages, lastUsage, state) {
231
259
  const violations = validateSessionMessages(messages);
232
260
  if (violations.length > 0) {
@@ -239,6 +267,7 @@ function saveSession(filePath, messages, lastUsage, state) {
239
267
  });
240
268
  messages = repairSessionMessages(messages);
241
269
  }
270
+ messages = stripOrphanedToolResults(messages);
242
271
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
243
272
  const envelope = { version: 1, messages };
244
273
  if (lastUsage)
@@ -269,6 +298,7 @@ function loadSession(filePath) {
269
298
  });
270
299
  messages = repairSessionMessages(messages);
271
300
  }
301
+ messages = stripOrphanedToolResults(messages);
272
302
  const rawState = data?.state && typeof data.state === "object" && data.state !== null
273
303
  ? data.state
274
304
  : undefined;
@@ -36,6 +36,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.spawnCodingProcess = spawnCodingProcess;
37
37
  const child_process_1 = require("child_process");
38
38
  const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
39
41
  const runtime_1 = require("../../nerves/runtime");
40
42
  function buildCommandArgs(runner, workdir) {
41
43
  if (runner === "claude") {
@@ -58,6 +60,18 @@ function buildCommandArgs(runner, workdir) {
58
60
  args: ["exec", "--skip-git-repo-check", "--cd", workdir],
59
61
  };
60
62
  }
63
+ function buildSpawnEnv(baseEnv, homeDir) {
64
+ const binDir = path.join(homeDir, ".ouro-cli", "bin");
65
+ const existingPath = baseEnv.PATH ?? "";
66
+ const pathEntries = existingPath.split(path.delimiter).filter((entry) => entry.length > 0);
67
+ if (!pathEntries.includes(binDir)) {
68
+ pathEntries.unshift(binDir);
69
+ }
70
+ return {
71
+ ...baseEnv,
72
+ PATH: pathEntries.join(path.delimiter),
73
+ };
74
+ }
61
75
  function buildPrompt(request, deps) {
62
76
  const sections = [];
63
77
  sections.push([
@@ -79,8 +93,11 @@ function spawnCodingProcess(request, deps = {}) {
79
93
  const spawnFn = deps.spawnFn ?? ((command, args, options) => (0, child_process_1.spawn)(command, args, options));
80
94
  const existsSync = deps.existsSync ?? fs.existsSync;
81
95
  const readFileSync = deps.readFileSync ?? fs.readFileSync;
96
+ const homeDir = deps.homeDir ?? os.homedir();
97
+ const baseEnv = deps.baseEnv ?? process.env;
82
98
  const prompt = buildPrompt(request, { existsSync, readFileSync });
83
99
  const { command, args } = buildCommandArgs(request.runner, request.workdir);
100
+ const env = buildSpawnEnv(baseEnv, homeDir);
84
101
  (0, runtime_1.emitNervesEvent)({
85
102
  component: "repertoire",
86
103
  event: "repertoire.coding_spawn_start",
@@ -89,6 +106,7 @@ function spawnCodingProcess(request, deps = {}) {
89
106
  });
90
107
  const proc = spawnFn(command, args, {
91
108
  cwd: request.workdir,
109
+ env,
92
110
  stdio: ["pipe", "pipe", "pipe"],
93
111
  });
94
112
  proc.stdin.end(`${prompt}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.87",
3
+ "version": "0.1.0-alpha.89",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",