@ouro.bot/cli 0.1.0-alpha.297 → 0.1.0-alpha.299
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 +175 -162
- package/dist/heart/daemon/cli-exec.js +13 -0
- package/dist/heart/daemon/cli-parse.js +46 -0
- package/dist/heart/daemon/daemon-entry.js +10 -0
- package/dist/heart/daemon/health-monitor.js +38 -0
- package/dist/senses/bluebubbles/inbound-log.js +3 -0
- package/dist/senses/bluebubbles/index.js +27 -10
- package/dist/senses/bluebubbles/model.js +16 -0
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/package.json +1 -1
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.299",
|
|
6
|
+
"changes": [
|
|
7
|
+
"chore(scripts): new `scripts/rebase-and-rebump.sh` automates the rebase-and-rebump dance when a PR loses the alpha-version race against a concurrently-merging sibling. Fetches origin/main, attempts merge, auto-resolves version-file conflicts (package.json, packages/ouro.bot/package.json, changelog.json, package-lock.json) by: computing next-version via `semver.inc()` against main's version (works for alpha/beta/rc/stable), writing both package.json files, extracting the user's changelog entry by content-diff (not version number, so same-version races are handled), renumbering it, and committing. Non-version conflicts bail cleanly. Uses `semver.inc()` so it survives the transition out of alpha."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"version": "0.1.0-alpha.298",
|
|
12
|
+
"changes": [
|
|
13
|
+
"fix(bluebubbles): dedupe inbound sidecar writes by `sessionKey/messageGuid`, ignore known guidless chat-state webhooks instead of 500ing, and add a first-class `ouro bluebubbles replay --agent <name> --message-guid <guid>` command for historical incident replay. The replay path defaults to `new-message`, surfaces state-only `updated-message` mutations with a retry hint, and keeps the real attachment handle visible for the original payload-bearing event.",
|
|
14
|
+
"test(daemon): close the replay/debug follow-up coverage gaps and harden `teams.test` cleanup by giving each test a unique temp agent root plus retried teardown, eliminating the `/tmp/mock-agent-root` race that could intermittently fail the full coverage gate."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
4
17
|
{
|
|
5
18
|
"version": "0.1.0-alpha.297",
|
|
6
19
|
"changes": [
|
|
@@ -89,29 +102,29 @@
|
|
|
89
102
|
{
|
|
90
103
|
"version": "0.1.0-alpha.283",
|
|
91
104
|
"changes": [
|
|
92
|
-
"chore(housekeeping): clean up ~3600 leaked test secret dirs in `~/.agentsecrets/`. The auth CLI test suite was creating ephemeral agent secret dirs (auth-local-*, auth-store-*, auth-no-switch-*, etc.) without cleaning them up, accreting over weeks into thousands of orphaned entries. Also purged three non-test orphans (`testagent`, `model-reviews`, `config-model-facing-*`) that were leftovers from manual probe sessions. Only `slugger` and `ouroboros`
|
|
93
|
-
"chore(housekeeping): remove orphan bundle stubs from `~/AgentBundles/` (default.ouro, thoughts-test-*, an empty `friends/` dir, and a .DS_Store). These were skeletal test leftovers with no real identity
|
|
94
|
-
"chore(tests): replace the `outlookServer.stop` v8 ignore band-aid in `daemon.ts` with a proper test. `OuroDaemonOptions` gains an `outlookServerFactory` seam that lets tests inject an in-memory stub handle instead of binding port 6876 (which a running production daemon holds on dev machines, causing EADDRINUSE flakes). New `daemon-outlook-lifecycle.test.ts` covers the happy path (factory runs, stop is called), the error path (factory throws, daemon logs warn and keeps going, stop is a no-op), and the double-start guard. The default production factory path (`createDefaultOutlookServer`
|
|
95
|
-
"chore(ci): tighten the wrapper publish-sync check timing. The version-bump check and wrapper-publish-sync check now run BEFORE the ~2+ minute coverage gate, not after. Previously, a contributor would wait for the full test suite to pass only to then see a 'version already published' error. Now the fast checks surface in under a minute, and coverage only runs once version/wrapper gates have cleared. Same checks, same logic
|
|
105
|
+
"chore(housekeeping): clean up ~3600 leaked test secret dirs in `~/.agentsecrets/`. The auth CLI test suite was creating ephemeral agent secret dirs (auth-local-*, auth-store-*, auth-no-switch-*, etc.) without cleaning them up, accreting over weeks into thousands of orphaned entries. Also purged three non-test orphans (`testagent`, `model-reviews`, `config-model-facing-*`) that were leftovers from manual probe sessions. Only `slugger` and `ouroboros` — the two real agents on this machine — remain.",
|
|
106
|
+
"chore(housekeeping): remove orphan bundle stubs from `~/AgentBundles/` (default.ouro, thoughts-test-*, an empty `friends/` dir, and a .DS_Store). These were skeletal test leftovers with no real identity — the daemon was already filtering them out of `listEnabledBundleAgents`, so deletion is invisible to the runtime but stops confusing anyone inspecting the bundles directory.",
|
|
107
|
+
"chore(tests): replace the `outlookServer.stop` v8 ignore band-aid in `daemon.ts` with a proper test. `OuroDaemonOptions` gains an `outlookServerFactory` seam that lets tests inject an in-memory stub handle instead of binding port 6876 (which a running production daemon holds on dev machines, causing EADDRINUSE flakes). New `daemon-outlook-lifecycle.test.ts` covers the happy path (factory runs, stop is called), the error path (factory throws, daemon logs warn and keeps going, stop is a no-op), and the double-start guard. The default production factory path (`createDefaultOutlookServer` — wires the real `startOutlookHttpServer` with bundlesRoot + view builders) is v8-ignored because it only runs under real bind on port 6876; `startOutlookHttpServer` itself has full coverage in `outlook-http.test.ts`. Removed the redundant `if (!this.outlookServer)` wrapper in `startInner()` that was guarding against an unreachable retry scenario. `daemon.ts` now hits 100% statements / branches / functions / lines with zero port binding in the test suite.",
|
|
108
|
+
"chore(ci): tighten the wrapper publish-sync check timing. The version-bump check and wrapper-publish-sync check now run BEFORE the ~2+ minute coverage gate, not after. Previously, a contributor would wait for the full test suite to pass only to then see a 'version already published' error. Now the fast checks surface in under a minute, and coverage only runs once version/wrapper gates have cleared. Same checks, same logic — just reordered steps in `.github/workflows/coverage.yml`."
|
|
96
109
|
]
|
|
97
110
|
},
|
|
98
111
|
{
|
|
99
112
|
"version": "0.1.0-alpha.282",
|
|
100
113
|
"changes": [
|
|
101
|
-
"feat(cli): crash-resilient sessions
|
|
114
|
+
"feat(cli): crash-resilient sessions — saves after each tool result, repairs orphaned tool calls on resume."
|
|
102
115
|
]
|
|
103
116
|
},
|
|
104
117
|
{
|
|
105
118
|
"version": "0.1.0-alpha.281",
|
|
106
119
|
"changes": [
|
|
107
|
-
"feat(bundle): new `src/heart/bundle-state.ts` module exports `detectBundleState(agentRoot)` which returns a structured `BundleStateIssue[]` describing git-level problems the agent can remediate. Enum cases: `not_a_git_repo`, `no_remote_configured`, `first_commit_never_happened`, `pending_sync_exists`. Detection never throws
|
|
108
|
-
"feat(bundle): `StartOfTurnPacket` gains an optional `bundleState?: BundleStateIssue[]` field, populated by the senses pipeline in `handleInboundTurn` at packet assembly time. Renders via a new `case \"bundleState\":` branch in `formatSections` with the `**Bundle:**` prefix, at the same priority tier as the legacy `syncFailure` free-form string (priority 7, truncated last). The two signals coexist during the transition
|
|
120
|
+
"feat(bundle): new `src/heart/bundle-state.ts` module exports `detectBundleState(agentRoot)` which returns a structured `BundleStateIssue[]` describing git-level problems the agent can remediate. Enum cases: `not_a_git_repo`, `no_remote_configured`, `first_commit_never_happened`, `pending_sync_exists`. Detection never throws — every git call is wrapped in try/catch so a broken bundle degrades to a clear signal rather than crashing the turn pipeline. Also exports `renderBundleStateHint(issues)` which produces first-person remediation guidance (per the memory rule) that tells the agent to call `bundle_check_sync_status` and the `bundle_*` tools shipping in a follow-up PR.",
|
|
121
|
+
"feat(bundle): `StartOfTurnPacket` gains an optional `bundleState?: BundleStateIssue[]` field, populated by the senses pipeline in `handleInboundTurn` at packet assembly time. Renders via a new `case \"bundleState\":` branch in `formatSections` with the `**Bundle:**` prefix, at the same priority tier as the legacy `syncFailure` free-form string (priority 7, truncated last). The two signals coexist during the transition — `syncFailure` is still emitted by sync.ts for humans, while `bundleState` is the structured form the agent pattern-matches on. Deferred to follow-up: `pending-sync.json` schema extension with `classification` / `conflictFiles` so sync.ts can distinguish push-rejected from pull-rebase-conflict."
|
|
109
122
|
]
|
|
110
123
|
},
|
|
111
124
|
{
|
|
112
125
|
"version": "0.1.0-alpha.280",
|
|
113
126
|
"changes": [
|
|
114
|
-
"chore(tests): prod-path isolation ratchet + tmpBundle leak guard + no-rm-rf contract. Extends `src/__tests__/heart/daemon/test-isolation.contract.test.ts` with three new rules and adds a runtime leak guard. (1) Three new prod-path block rules mirror the existing ~/AgentBundles check: no test file may construct a write path under `~/.ouro-cli`, `~/.agentsecrets`, or `~/.claude` without mocking fs. Each rule has its own empty-seeded ratchet allowlist (except `.ouro-cli` and `.agentsecrets` which are seeded with the pre-existing offenders that this rule newly catches
|
|
127
|
+
"chore(tests): prod-path isolation ratchet + tmpBundle leak guard + no-rm-rf contract. Extends `src/__tests__/heart/daemon/test-isolation.contract.test.ts` with three new rules and adds a runtime leak guard. (1) Three new prod-path block rules mirror the existing ~/AgentBundles check: no test file may construct a write path under `~/.ouro-cli`, `~/.agentsecrets`, or `~/.claude` without mocking fs. Each rule has its own empty-seeded ratchet allowlist (except `.ouro-cli` and `.agentsecrets` which are seeded with the pre-existing offenders that this rule newly catches — follow-up PRs can convert those to mocked-fs and ratchet down). The path-scan loop is factored into a shared `runProdPathCheck` helper. (2) New Directive-A contract rule: agent-callable production code under `src/` (excluding `src/__tests__/`) must not call `fs.rmSync(..., { recursive: true })` or shell out to `rm -rf` / `rm -fr` / `rm --recursive --force`. The rule is about making deletion auditable and interruptible: an agent should enumerate the files it wants to delete instead of recursively blasting a directory. Four legitimate infrastructure callsites are on `RM_RECURSIVE_ALLOWLIST` with explicit justifications: specialist-tools.ts (adoption rollback), ouro-version-manager.ts (CLI version pruning), ouro-uti.ts (macOS icon pipeline), cli-defaults.ts (self-setup temp dir). Three files that are themselves the rm-rf enforcement layer (guardrails.ts, shell-sessions.ts, prompt.ts) are in `RM_RULE_ENFORCEMENT_FILES` and skipped by the scan since they contain the literal \"rm -rf\" only as regex patterns or prompt strings designed to BLOCK the call. (3) `createTmpBundle` in `src/__tests__/test-helpers/tmpdir-bundle.ts` now tracks live handles in a module-level `_liveHandles: Set<TmpBundleHandle>`. `cleanup()` removes the handle from the set; a new `__getLiveTmpBundleHandles()` export returns a readonly view. (4) `src/__tests__/nerves/global-capture.ts` adds a global vitest `afterEach` leak guard that iterates `__getLiveTmpBundleHandles` and calls `cleanup()` on any remaining handles, logging a `console.warn` naming the test that leaked them. Runs AFTER the pairing guard from alpha.276 so pairing failures surface first. Both guards co-exist cleanly."
|
|
115
128
|
]
|
|
116
129
|
},
|
|
117
130
|
{
|
|
@@ -123,16 +136,16 @@
|
|
|
123
136
|
{
|
|
124
137
|
"version": "0.1.0-alpha.278",
|
|
125
138
|
"changes": [
|
|
126
|
-
"fix(identity): spread-with-validation loader eliminates the field-drop bug class that caused #349 (silent `sync` drop). Two distinct structural bugs fixed, one in each agent.json loader: (1) `loadAgentConfig` in `src/heart/identity.ts` previously built the returned `AgentConfig` via a hand-rolled object literal that listed every field explicitly
|
|
139
|
+
"fix(identity): spread-with-validation loader eliminates the field-drop bug class that caused #349 (silent `sync` drop). Two distinct structural bugs fixed, one in each agent.json loader: (1) `loadAgentConfig` in `src/heart/identity.ts` previously built the returned `AgentConfig` via a hand-rolled object literal that listed every field explicitly — any new field on `AgentConfig` that wasn't added to this literal got silently dropped. Root cause of #349. Refactored to a spread-then-override pattern: start with `{ ...parsed as AgentConfig }`, then explicitly override `version`, `enabled`, `humanFacing`, `agentFacing`, `senses`, `phrases` which need validation/normalization. The deprecated `provider` field is re-attached from the validated `rawProvider` check. (2) `readAgentConfigForAgent` in `src/heart/auth/auth-flow.ts` previously did `parsed as unknown as AgentConfig` which passed through ALL fields unconditionally (so no silent drops) but ALSO had zero per-field validation — any garbage in agent.json leaked into the returned config. Refactored to apply the same spread-with-validation pattern, reusing `normalizeSenses` (now exported from identity.ts). Both entry points now return equivalent configs for the same agent.json file. New `src/__tests__/heart/identity-fixture.ts` exports `FULL_AGENT_JSON satisfies DeepRequired<AgentConfig>` — a compile-time regression guard that fails to build if any new field is added to `AgentConfig` without updating the fixture. Two new test files: `identity-contract.test.ts` exercises `readAgentConfigForAgent` with `createTmpBundle`; `identity-load-contract.test.ts` exercises `loadAgentConfig` via `vi.mock(\"fs\")` (split to avoid the fs-mock-vs-real-fs conflict). 7 tests total."
|
|
127
140
|
]
|
|
128
141
|
},
|
|
129
142
|
{
|
|
130
143
|
"version": "0.1.0-alpha.277",
|
|
131
144
|
"changes": [
|
|
132
|
-
"feat(pulse): multi-agent situational awareness for peer agents on the same machine. The harness scales horizontally
|
|
145
|
+
"feat(pulse): multi-agent situational awareness for peer agents on the same machine. The harness scales horizontally — multiple peer agents share a machine, each with their own identity and bundle (the Bob model from We Are Legion / We Are Bob). Without explicit awareness, peer agents are isolated workers who don't even know each other exist. The pulse fixes that.",
|
|
133
146
|
"feat(pulse): new `src/heart/daemon/pulse.ts` module. Daemon writes `~/.ouro-cli/pulse.json` whenever any managed agent's snapshot changes (status, errorReason, fixHint, etc.). Each entry includes name, bundle path, status, last-seen-at, errorReason+fixHint when broken, alertId for at-most-once delivery tracking, and currentActivity (read from each agent's `state/sessions/self/inner/runtime.json` when running). Pure helpers `buildPulseState`, `findNovelBrokenAgents`, `findRecoveredAgents`, `pickWakeRecipient`, `flushPulse`, `readAgentActivity`, `buildAlertId`, `buildRecoveryAlertId`, `pruneDeliveredState` exported for unit coverage; I/O wrappers `writePulse`, `readPulse`, `writeDeliveredState`, `readDeliveredState` use injectable deps.",
|
|
134
147
|
"feat(pulse): both passive AND active surfacing. Passive: every agent's prompt assembly renders a `## the pulse` section in Group 7 (dynamic state) showing siblings grouped into broken / reachable / idle buckets. Self-excluded so each agent describes its peers, not itself. Renders nothing on single-agent machines (zero token cost). Active: when a sibling newly breaks (or recovers), the daemon fires `inner.wake` on the most-recently-active running agent so the user finds out within seconds rather than next-time-they-talk-to-someone. Persistent at-most-once delivery via `~/.ouro-cli/pulse-delivered.json` so daemon restarts don't re-page.",
|
|
135
|
-
"feat(pulse): horizontal-scaling norm in bodyMapSection. New `### peers` subsection teaches the agent the Bob model directly: 'i talk first. when i need a sibling's help, i `send_message` them
|
|
148
|
+
"feat(pulse): horizontal-scaling norm in bodyMapSection. New `### peers` subsection teaches the agent the Bob model directly: 'i talk first. when i need a sibling's help, i `send_message` them — that's how peers coordinate, the same way humans on a team do. i only open a sibling's bundle directly via read_file/glob/grep when conversation isn't possible (they're crashed, sleeping, or i need history they haven't surfaced).' Direct declarative voice — no hedging, no soft modal verbs.",
|
|
136
149
|
"feat(daemon): `DaemonAgentSnapshot` gains `errorReason` and `fixHint` fields, populated by `checkAgentConfig` results in `startAgent` (set on failure, cleared on recovery). Cleared error fields are how the recovery wake fires: when a previously-broken agent transitions to running with `errorReason: null`, `findRecoveredAgents` flags it.",
|
|
137
150
|
"feat(daemon): `DaemonProcessManager` gains `onSnapshotChange` callback option. Called after every snapshot mutation (start, exit, config-fail, recovery, restart-exhausted). Errors from the observer are swallowed so lifecycle code never breaks because the observer threw. The daemon-entry registers a callback that calls `flushPulse` to update the pulse state and fire wakes.",
|
|
138
151
|
"feat(daemon): wake recipient picker (`pickWakeRecipient`) chooses the most-recently-active running sibling. Excludes the broken agent itself, non-running siblings, and siblings that have never been seen alive. Returns null when no eligible recipient exists, in which case the alert is still marked delivered to avoid spam on subsequent flushes."
|
|
@@ -141,80 +154,80 @@
|
|
|
141
154
|
{
|
|
142
155
|
"version": "0.1.0-alpha.276",
|
|
143
156
|
"changes": [
|
|
144
|
-
"fix(nerves): root-cause the `start_end_pairing` audit flake on `daemon.server_start`, `daemon.update_checker_start`, and `daemon.apply_pending_updates_start`. Three fixes: (1) `applyPendingUpdates` in `update-hooks.ts` now wraps its body in try/finally so `_end` always fires, including on the early returns for `!fs.existsSync(bundlesRoot)` and `readdirSync` throws that previously orphaned the `_start`. (2) `daemon.start()` now wraps the ~380-line startup body in a try/catch that emits `daemon.server_error` with the error message and rethrows
|
|
157
|
+
"fix(nerves): root-cause the `start_end_pairing` audit flake on `daemon.server_start`, `daemon.update_checker_start`, and `daemon.apply_pending_updates_start`. Three fixes: (1) `applyPendingUpdates` in `update-hooks.ts` now wraps its body in try/finally so `_end` always fires, including on the early returns for `!fs.existsSync(bundlesRoot)` and `readdirSync` throws that previously orphaned the `_start`. (2) `daemon.start()` now wraps the ~380-line startup body in a try/catch that emits `daemon.server_error` with the error message and rethrows — the audit's pairing rule accepts `_end` OR `_error` as a valid closure for a `_start`, so startup throws no longer orphan `server_start`. The body was extracted to a private `startInner()` method to keep the try/catch small and readable. (3) `startUpdateChecker` callers in the update-checker test suite were already paired via an `afterEach(stopUpdateChecker)`; audited and confirmed no new unpaired callers. Also adds a vitest `afterEach` pairing guard in `src/__tests__/nerves/global-capture.ts` that fails loudly on any orphaned lifecycle `_start` in a test's per-test event stream — scoped to the three lifecycle events above so it catches regressions without false-positiving on legitimate narrow-slice operational events like `repertoire.task_scan_start`. New `src/__tests__/nerves/pairing-regression.test.ts` locks in the contract with 5 tests (nonexistent-dir, readdirSync-throws, happy-path, startUpdateChecker-pair, daemon-start-throw). Three consecutive `npm run test:coverage` runs confirm zero flakes on the target events."
|
|
145
158
|
]
|
|
146
159
|
},
|
|
147
160
|
{
|
|
148
161
|
"version": "0.1.0-alpha.275",
|
|
149
162
|
"changes": [
|
|
150
|
-
"fix(tui): backspace on macOS
|
|
163
|
+
"fix(tui): backspace on macOS — Ink 3.2 maps \\x7f to key.delete not key.backspace."
|
|
151
164
|
]
|
|
152
165
|
},
|
|
153
166
|
{
|
|
154
167
|
"version": "0.1.0-alpha.274",
|
|
155
168
|
"changes": [
|
|
156
169
|
"feat(nerves): daemon log rotation is now 25 MB x 5 gzipped generations instead of 50 MB x 2 uncompressed, dropping peak disk per stream from ~150 MB to ~30 MB. `createNdjsonFileSink` and `rotateIfNeeded` in `src/nerves/index.ts` accept an options object `{ maxSizeBytes, maxGenerations, compress, rotationCheckIntervalBytes }` (with number-form backcompat for the old positional API). Rotation uses a rename-then-gzip pattern so active writers can keep their fd alive while the renamed file gets compressed. Legacy uncompressed `.1.ndjson`/`.2.ndjson` files from the old scheme are tolerated and gzip-migrated on first rotation. Lifecycle emits paired `nerves.rotation_start` / `nerves.rotation_end` events with a shared trace_id, plus `nerves.rotation_error` on failure via a completion-flag try/catch.",
|
|
157
|
-
"feat(log-tailer): `ouro logs` can now read rotated `.ndjson.gz` generations, so `--lines N` spans across historical files. `discoverLogFiles` matches both `.ndjson` and `.ndjson.gz`, parses filenames into (streamBase, rank) tuples, and sorts chronologically (oldest generation first, active last). A new internal `readNdjsonFileContents` helper dispatches to `zlib.gunzipSync` for `.gz` paths while preserving the DI-stubbed plain-file path for existing tests. Follow mode only watches the active stream
|
|
158
|
-
"feat(logs-prune): new `ouro logs prune` subcommand applies the active rotation policy to every oversized `.ndjson` file in the agent daemon logs directory. Idempotent
|
|
170
|
+
"feat(log-tailer): `ouro logs` can now read rotated `.ndjson.gz` generations, so `--lines N` spans across historical files. `discoverLogFiles` matches both `.ndjson` and `.ndjson.gz`, parses filenames into (streamBase, rank) tuples, and sorts chronologically (oldest generation first, active last). A new internal `readNdjsonFileContents` helper dispatches to `zlib.gunzipSync` for `.gz` paths while preserving the DI-stubbed plain-file path for existing tests. Follow mode only watches the active stream — gzipped generations are historical by definition and never tailed.",
|
|
171
|
+
"feat(logs-prune): new `ouro logs prune` subcommand applies the active rotation policy to every oversized `.ndjson` file in the agent daemon logs directory. Idempotent — a second run on a compliant dir is a no-op. Concurrent-writer-safe because it delegates to `rotateIfNeeded`'s rename-then-gzip pattern (no locking needed). Emits paired `nerves.logs_prune_start` / `nerves.logs_prune_end` with `nerves.logs_prune_error` on failure. Prints `compacted N file(s), freed M bytes` to stdout. New module `src/heart/daemon/logs-prune.ts` exports `pruneDaemonLogs(options)`; the CLI wire-up adds a `daemon.logs.prune` command kind across cli-types/cli-parse/cli-exec and a `pruneDaemonLogs` dep to `createDefaultOuroCliDeps`.",
|
|
159
172
|
"fix(launchd): drop the stale `StandardErrorPath` plist key that pointed at `ouro-daemon-stderr.log`. The file grew to 366 MB in the wild because the daemon stopped writing to it (the nerves ndjson pipeline has been the source of truth for diagnostics since the nerves layer landed) but nothing ever removed the plist key, so launchd kept the path registered and occasional process-level stderr still dripped in. Removing the key lets launchd forward stray stderr to the system log forwarder where the OS rotates it. The 366 MB orphaned file on disk at `~/AgentBundles/slugger.ouro/state/daemon/logs/ouro-daemon-stderr.log` is safe to delete manually and is flagged in the PR summary for user cleanup.",
|
|
160
|
-
"refactor(runtime-logging,cli-logging): every `createNdjsonFileSink` call site now passes an explicit `{ maxSizeBytes, maxGenerations, compress }` options object. No callsite silently relies on the old 50 MB default
|
|
173
|
+
"refactor(runtime-logging,cli-logging): every `createNdjsonFileSink` call site now passes an explicit `{ maxSizeBytes, maxGenerations, compress }` options object. No callsite silently relies on the old 50 MB default — the policy is visible at each wire-up point. This also removes the `/* v8 ignore */` around the rotation trigger in the sink's flush() loop; tests now exercise it directly via the new `rotationCheckIntervalBytes` option."
|
|
161
174
|
]
|
|
162
175
|
},
|
|
163
176
|
{
|
|
164
177
|
"version": "0.1.0-alpha.273",
|
|
165
178
|
"changes": [
|
|
166
|
-
"feat(version-manager): auto-prune old CLI versions during activate. The user observed `~/.ouro-cli/versions/` accumulating every CLI version they'd ever installed (alpha.85 from 2026-03-20 onward, ~100MB+ of dead node_modules trees) because nothing ever GCed. New `pruneOldVersions(retain=5, deps?)` walks `~/.ouro-cli/versions/`, sorts by alpha-suffix numerically, and deletes everything outside the retention window
|
|
167
|
-
"test(contract): new OURO_DAEMON_INSTANTIATION_ALLOWLIST in test-isolation.contract.test.ts flags any new test file that constructs `new OuroDaemon(...)` outside the 11 grandfathered files. Constructing a real daemon and calling start() runs killOrphanProcesses() and writePidfile() against the production pidfile at ~/.ouro-cli/daemon.pids. The runtime guards added in #346 short-circuit those functions under vitest, but if a future change to start() adds a NEW production-state side-effect, the existing 11 tests would silently exercise it. The contract test forces conscious review of each new file taking this shape
|
|
179
|
+
"feat(version-manager): auto-prune old CLI versions during activate. The user observed `~/.ouro-cli/versions/` accumulating every CLI version they'd ever installed (alpha.85 from 2026-03-20 onward, ~100MB+ of dead node_modules trees) because nothing ever GCed. New `pruneOldVersions(retain=5, deps?)` walks `~/.ouro-cli/versions/`, sorts by alpha-suffix numerically, and deletes everything outside the retention window — except always preserves (a) the currently-active version (CurrentVersion symlink target), and (b) the previous version (previous symlink target), so `ouro rollback` stays one command away. Wired into `cli-defaults.ts` via `ensureCurrentVersionInstalled` and `activateCliVersion` — every successful version activation self-prunes. New helpers `compareCliVersions(a, b)` and `selectVersionsToPrune(installed, protected, retain)` are pure and exported for direct unit coverage. 9 new tests covering version comparison, retention selection, current/previous protection, partial-failure handling, missing-symlink fallback, and non-directory entry filtering.",
|
|
180
|
+
"test(contract): new OURO_DAEMON_INSTANTIATION_ALLOWLIST in test-isolation.contract.test.ts flags any new test file that constructs `new OuroDaemon(...)` outside the 11 grandfathered files. Constructing a real daemon and calling start() runs killOrphanProcesses() and writePidfile() against the production pidfile at ~/.ouro-cli/daemon.pids. The runtime guards added in #346 short-circuit those functions under vitest, but if a future change to start() adds a NEW production-state side-effect, the existing 11 tests would silently exercise it. The contract test forces conscious review of each new file taking this shape — same defense-in-depth pattern as BYPASS_USE_ALLOWLIST in alpha.265."
|
|
168
181
|
]
|
|
169
182
|
},
|
|
170
183
|
{
|
|
171
184
|
"version": "0.1.0-alpha.272",
|
|
172
185
|
"changes": [
|
|
173
|
-
"fix(daemon): the daemon's periodic update checker can now actually auto-update itself. The `onUpdate` callback in `daemon.ts` invoked `performStagedRestart` which (a) ran `npm install -g @ouro.bot/cli@{version}` to install to the global node prefix, and (b) tried to find the new code via `node -e \"console.log(require.resolve('@ouro.bot/cli/package.json'))\"` which depends on the daemon process's NODE_PATH. Neither path was actually reachable from the daemon process running out of `~/.ouro-cli/versions/{version}/...`, so every auto-update attempt bailed at `daemon.staged_restart_path_failed` (\"could not resolve new code path\") and the daemon never updated itself. The user had to manually run `ouro up` to pick up new versions. Fix: switch the staged restart to use the version-managed installer (same one the CLI's `up` flow uses)
|
|
186
|
+
"fix(daemon): the daemon's periodic update checker can now actually auto-update itself. The `onUpdate` callback in `daemon.ts` invoked `performStagedRestart` which (a) ran `npm install -g @ouro.bot/cli@{version}` to install to the global node prefix, and (b) tried to find the new code via `node -e \"console.log(require.resolve('@ouro.bot/cli/package.json'))\"` which depends on the daemon process's NODE_PATH. Neither path was actually reachable from the daemon process running out of `~/.ouro-cli/versions/{version}/...`, so every auto-update attempt bailed at `daemon.staged_restart_path_failed` (\"could not resolve new code path\") and the daemon never updated itself. The user had to manually run `ouro up` to pick up new versions. Fix: switch the staged restart to use the version-managed installer (same one the CLI's `up` flow uses) — `installVersion(version)` puts files at `~/.ouro-cli/versions/{version}/node_modules/@ouro.bot/cli` (deterministic, computable), then `activateVersion(version)` flips the CurrentVersion symlink so the next user-driven `ouro up` sees the same version the daemon is running. `performStagedRestart` gained an optional `installNewVersion` dep that production callers inject; the legacy `npm install -g` fallback path is preserved for tests. Two new regression tests in `staged-restart.test.ts`.",
|
|
174
187
|
"fix(cli): `ouro up` no longer prints the 'ouro updated to ...' message twice during npx invocations. Three independent paths can detect a CLI version change: (1) `checkForCliUpdate` finds a newer version on npm and re-execs (cross-process print), (2) `ensureCurrentVersionInstalled` flips the CurrentVersion symlink during `performSystemSetup` because the running package version is newer than what the symlink pointed at (path 2, in-process), (3) `bundle-meta.json`'s stored runtime version differs from the running version (path 3, in-process fallback). Path 3's existing guard `linkedVersionBeforeUp !== currentVersion` correctly skipped path 3 when path 1 had already printed in a different process, but did NOT catch the case where path 2 fired in the same process. Verified live on 2026-04-08: `npx --yes @ouro.bot/cli@alpha up` printed the message twice. Fix: track an in-process `printedUpdateMessage` flag set by path 2; path 3 checks it before printing. Path 3 still acts as a fallback when path 2 didn't fire. New regression test in `daemon-cli-update-flow.test.ts` simulates the npx scenario and asserts exactly one print.",
|
|
175
|
-
"fix(hooks): Claude Code lifecycle hooks (`ouro hook session-start|stop|post-tool-use`) now short-circuit when the daemon socket file doesn't exist, instead of attempting `sendDaemonCommand` and logging two ENOENT errors per hook fire (one for `message.send`, one for `inner.wake`). Every Claude Code event during a daemon-down window was producing noisy `connect ENOENT /tmp/ouroboros-daemon.sock` entries in `ouro.ndjson`, which made it hard to read logs around outages. The hook is best-effort by design
|
|
188
|
+
"fix(hooks): Claude Code lifecycle hooks (`ouro hook session-start|stop|post-tool-use`) now short-circuit when the daemon socket file doesn't exist, instead of attempting `sendDaemonCommand` and logging two ENOENT errors per hook fire (one for `message.send`, one for `inner.wake`). Every Claude Code event during a daemon-down window was producing noisy `connect ENOENT /tmp/ouroboros-daemon.sock` entries in `ouro.ndjson`, which made it hard to read logs around outages. The hook is best-effort by design — dropping notifications when the daemon is down is correct behavior; we just don't want to log spam about it. New nerves event `daemon.hook_skipped_no_socket` (info level) when the short-circuit fires."
|
|
176
189
|
]
|
|
177
190
|
},
|
|
178
191
|
{
|
|
179
192
|
"version": "0.1.0-alpha.271",
|
|
180
193
|
"changes": [
|
|
181
|
-
"fix(daemon): unblock daemon.stop deadlock that hung `ouro up` after a CLI auto-update. When the running daemon's version drifted from the local CLI version, `ensureDaemonRunning` would send `daemon.stop` over the socket, the daemon's command handler would `await this.stop()`, and `stop()` would `await server.close()`. server.close() resolves only after every open connection has closed
|
|
194
|
+
"fix(daemon): unblock daemon.stop deadlock that hung `ouro up` after a CLI auto-update. When the running daemon's version drifted from the local CLI version, `ensureDaemonRunning` would send `daemon.stop` over the socket, the daemon's command handler would `await this.stop()`, and `stop()` would `await server.close()`. server.close() resolves only after every open connection has closed — but the calling client's connection was the ONE thing keeping the server open: its `flushResponse()` was awaiting THIS function call. Both processes sat in kevent forever. Verified live on 2026-04-08: alpha.268 daemon hung at `daemon.server_end` log line for 5+ minutes after a fresh alpha.270 ouro process sent daemon.stop, and the alpha.270 ouro process hung waiting for the response. The deadlock had existed since the original `await server.close()` line was added (2026-03-05) but was masked for weeks by the half-close behavior in socket-client: the client called `client.end()` after writing its command, which (with `allowHalfOpen: false`) caused node to auto-tear-down the server's writable side, incidentally unblocking server.close() before the response was sent. The fix in #303/#334/#339 (which removed `client.end()` and switched to `allowHalfOpen: true` to stop dropping long-running responses like agent.senseTurn) accidentally exposed the underlying deadlock. Fix: don't `await` server.close() in stop() — just fire it. Once stop() returns, the daemon.stop case returns its response, flushResponse calls connection.end(response), the connection closes, and server.close()'s pending callback fires asynchronously. Includes a new daemon-stop-deadlock.test.ts that uses real net sockets to drive daemon.stop and asserts the response comes back within 2s — the test fails (24s timeout) without the fix and passes (110ms) with it."
|
|
182
195
|
]
|
|
183
196
|
},
|
|
184
197
|
{
|
|
185
198
|
"version": "0.1.0-alpha.270",
|
|
186
199
|
"changes": [
|
|
187
|
-
"feat(daemon): `ouro status` now shows a new `Agents` section listing every discovered bundle with its enabled/disabled state. Previously disabled agents were completely invisible in status
|
|
200
|
+
"feat(daemon): `ouro status` now shows a new `Agents` section listing every discovered bundle with its enabled/disabled state. Previously disabled agents were completely invisible in status — the Senses/Workers/Git Sync sections only iterate managed (enabled) bundles, so a bundle with `\"enabled\": false` in agent.json left no trace in the output. New helper `listAllBundleAgents()` in `agent-discovery.ts` walks the bundles root and returns `{ name, enabled }` for every `<name>.ouro` with a parseable agent.json, and `listEnabledBundleAgents()` now delegates to it. Daemon status payload carries a new `agents: BundleAgentRow[]` field (backward-compat optional in the parser). The stopped-daemon renderer also reads bundles directly from disk so the Agents section works when the daemon is down."
|
|
188
201
|
]
|
|
189
202
|
},
|
|
190
203
|
{
|
|
191
204
|
"version": "0.1.0-alpha.269",
|
|
192
205
|
"changes": [
|
|
193
|
-
"fix(prompt): revert alpha.267 over-engineering and correct the two targeted additions. The existing contextSection already contained the 'save to disk or lose it' teaching ('my conversation memory is ephemeral -- it resets between sessions. anything i learn about my friend, i save with save_friend_note so future me remembers.'), and toolContractsSection already told agents to call save_friend_note/diary_write before responding. alpha.267 added a third block in memoryJudgementSection about 'not just remembering between sessions' which was redundant and misplaced (memoryJudgementSection sits under 'my tools & capabilities' alongside tool routing heuristics, not nature-of-self content). That block is reverted. What alpha.267 got right and this PR keeps: (a) bodyMapSection guidance that standard folders are a floor, not a ceiling
|
|
206
|
+
"fix(prompt): revert alpha.267 over-engineering and correct the two targeted additions. The existing contextSection already contained the 'save to disk or lose it' teaching ('my conversation memory is ephemeral -- it resets between sessions. anything i learn about my friend, i save with save_friend_note so future me remembers.'), and toolContractsSection already told agents to call save_friend_note/diary_write before responding. alpha.267 added a third block in memoryJudgementSection about 'not just remembering between sessions' which was redundant and misplaced (memoryJudgementSection sits under 'my tools & capabilities' alongside tool routing heuristics, not nature-of-self content). That block is reverted. What alpha.267 got right and this PR keeps: (a) bodyMapSection guidance that standard folders are a floor, not a ceiling — bundles can have custom top-level folders (slugger's travel/ was the motivating example) — with a nudge to try the file-listing tool on the bundle root BEFORE falling back to recall, and (b) a diary-routing bullet that flags bundle-layout discoveries as worth persisting. Both had errors corrected here: alpha.267 told agents to use `list_directory` but the actual tool is `glob` (with a pattern like `*/`), and it said 'write a diary note like bundle-layout.md' but diary/ is a jsonl fact store queried via recall, not a directory of .md files — the corrected bullet says 'save the fact with diary_write'."
|
|
194
207
|
]
|
|
195
208
|
},
|
|
196
209
|
{
|
|
197
210
|
"version": "0.1.0-alpha.268",
|
|
198
211
|
"changes": [
|
|
199
|
-
"fix(identity): `loadAgentConfig` now preserves the `sync` block from agent.json. The hand-rolled object literal that constructs the typed `AgentConfig` was missing `sync` from its field list, so `agentConfig.sync` was always `undefined`, `getSyncConfig()` always returned `enabled: false`, and the entire sync code path (`preTurnPull` / `postTurnPush` in `pipeline.ts`) was dead from the moment the field was added to the type. The bug hid for weeks because `ouro status` reads `agent.json` directly via `listBundleSyncRows`, not through `loadAgentConfig`
|
|
212
|
+
"fix(identity): `loadAgentConfig` now preserves the `sync` block from agent.json. The hand-rolled object literal that constructs the typed `AgentConfig` was missing `sync` from its field list, so `agentConfig.sync` was always `undefined`, `getSyncConfig()` always returned `enabled: false`, and the entire sync code path (`preTurnPull` / `postTurnPush` in `pipeline.ts`) was dead from the moment the field was added to the type. The bug hid for weeks because `ouro status` reads `agent.json` directly via `listBundleSyncRows`, not through `loadAgentConfig` — so the per-agent Git Sync display correctly showed `enabled origin → ...` while sync did literally nothing. Slugger accumulated 5+ days of dirty files and zero `sync: post-turn update` commits before this surfaced. Also adds 3 regression tests asserting the sync block round-trips through `loadAgentConfig` (full block, partial block, missing block). The first two would have caught the original bug; without them future field additions to `AgentConfig` could repeat the pattern."
|
|
200
213
|
]
|
|
201
214
|
},
|
|
202
215
|
{
|
|
203
216
|
"version": "0.1.0-alpha.267",
|
|
204
217
|
"changes": [
|
|
205
|
-
"fix(prompt): teach agents that they do NOT 'just remember' things between sessions. Observed failure mode: slugger spent a recall scan searching diary/journal for a `travel/` folder that was right at the bundle root, then concluded 'i should know my own folder structure next time' and refused to persist the discovery because 'that's just me knowing my own home.' That is impossible
|
|
218
|
+
"fix(prompt): teach agents that they do NOT 'just remember' things between sessions. Observed failure mode: slugger spent a recall scan searching diary/journal for a `travel/` folder that was right at the bundle root, then concluded 'i should know my own folder structure next time' and refused to persist the discovery because 'that's just me knowing my own home.' That is impossible — next session is a blank slate. The agent conflated in-session realizations with persistent knowledge. Three prompt changes fix this: (1) bodyMapSection now explicitly states that standard folders are a floor, bundles MAY have custom top-level folders created by the friend over time, and the agent should `list_directory` the bundle root BEFORE reaching for `recall` when something might be in a custom location. (2) memoryJudgementSection opens with an always-on reminder that the agent does not 'just remember' anything between sessions — every session carries only (a) the prompt, (b) what's on disk, (c) what tools observe this turn — and that thoughts like 'i should know this next time' or 'i'll look there first in the future' are CUES to write a concrete diary/friend-note RIGHT NOW. Future me cannot inherit resolutions, only files. (3) memoryJudgementSection's diary-routing rules now explicitly call out bundle-layout discoveries as a thing worth persisting (e.g. to a `bundle-layout.md` diary note). Includes 3 new tests locking the directives into place so future prompt edits cannot silently drop them."
|
|
206
219
|
]
|
|
207
220
|
},
|
|
208
221
|
{
|
|
209
222
|
"version": "0.1.0-alpha.266",
|
|
210
223
|
"changes": [
|
|
211
|
-
"fix(daemon): vitest guard for production pidfile (~/.ouro-cli/daemon.pids). The pidfile path is hardcoded with no DI seam, so when a test creates a real OuroDaemon instance and calls start(), the daemon's killOrphanProcesses() reads the REAL pidfile, ps-verifies the PIDs, and SIGTERMs the production daemon's PIDs. Verified live: alpha.265 daemon (PID 64988) was killed 93s after startup by `npx vitest run` invoking daemon.start() in 6 different test files. SIGTERM forensics added in alpha.265 captured the death (parentPid=1, parentCommand=/sbin/launchd) but the killer hint was misleading
|
|
224
|
+
"fix(daemon): vitest guard for production pidfile (~/.ouro-cli/daemon.pids). The pidfile path is hardcoded with no DI seam, so when a test creates a real OuroDaemon instance and calls start(), the daemon's killOrphanProcesses() reads the REAL pidfile, ps-verifies the PIDs, and SIGTERMs the production daemon's PIDs. Verified live: alpha.265 daemon (PID 64988) was killed 93s after startup by `npx vitest run` invoking daemon.start() in 6 different test files. SIGTERM forensics added in alpha.265 captured the death (parentPid=1, parentCommand=/sbin/launchd) but the killer hint was misleading — the real culprit was the production-pidfile leak. Fix: killOrphanProcesses() and writePidfile() now short-circuit under vitest with warn-level nerves events. Tests that need to verify these functions' behavior continue to use the extracted pure helpers (parseOrphanPidsFromPs, filterPidfilePidsToActualOrphans). New unit tests verify the pidfile is unchanged after no-op calls. Same defense-in-depth pattern as the alpha.265 socket-client hardening — production-side state being touched from tests is now physically impossible from a vitest worker."
|
|
212
225
|
]
|
|
213
226
|
},
|
|
214
227
|
{
|
|
215
228
|
"version": "0.1.0-alpha.265",
|
|
216
229
|
"changes": [
|
|
217
|
-
"fix(daemon): bulletproof vitest socket leak + SIGTERM forensics. Hardens the socket-client vitest guard so production daemon socket calls (DEFAULT_DAEMON_SOCKET_PATH = /tmp/ouroboros-daemon.sock) are unconditionally blocked under vitest, regardless of __bypassVitestGuardForTests state. Cross-file leaks via the globalThis bypass flag (process-wide, leaks across concurrent test files in the same vitest worker) can no longer reach the production daemon. Test files that legitimately exercise the real socket-client transport against synthetic test socket paths (/tmp/daemon.sock) continue to work. Background: a daemon outage on 2026-04-08 was traced to a 14-call burst of leaked `inner.wake testagent` errors, signature of vitest test runs hammering the production socket
|
|
230
|
+
"fix(daemon): bulletproof vitest socket leak + SIGTERM forensics. Hardens the socket-client vitest guard so production daemon socket calls (DEFAULT_DAEMON_SOCKET_PATH = /tmp/ouroboros-daemon.sock) are unconditionally blocked under vitest, regardless of __bypassVitestGuardForTests state. Cross-file leaks via the globalThis bypass flag (process-wide, leaks across concurrent test files in the same vitest worker) can no longer reach the production daemon. Test files that legitimately exercise the real socket-client transport against synthetic test socket paths (/tmp/daemon.sock) continue to work. Background: a daemon outage on 2026-04-08 was traced to a 14-call burst of leaked `inner.wake testagent` errors, signature of vitest test runs hammering the production socket — same pattern as 1,460 historical daemon log entries.",
|
|
218
231
|
"feat(daemon): SIGTERM/SIGINT tombstone forensics. New writeDaemonTombstone path captures process.ppid, parent command via `ps -p <ppid> -o command=`, and a filtered process snapshot (only node/vitest/ouro/kill lines) at signal-driven death time. Adds a killerHint heuristic: launchd parent reparenting suggests `launchctl bootout`/KeepAlive thrash; vitest worker presence suggests test cleanup; pkill/killall presence is an explicit kill. Forensics field is parsed by readDaemonTombstone and included in the daemon.tombstone_written nerves event meta. Also caps recentCrashes at 100 entries (was 12,265 from a March 31 thrash loop).",
|
|
219
232
|
"test(daemon): contract test BYPASS_USE_ALLOWLIST flags any new file calling __bypassVitestGuardForTests outside the two known-good test files (socket-client.test.ts and daemon-cli-defaults.test.ts). Prevents future regressions of the cross-file leak vector."
|
|
220
233
|
]
|
|
@@ -222,7 +235,7 @@
|
|
|
222
235
|
{
|
|
223
236
|
"version": "0.1.0-alpha.264",
|
|
224
237
|
"changes": [
|
|
225
|
-
"fix(bluebubbles): dedup `updated-message` webhooks BEFORE running repair+hydrate+VLM. BlueBubbles routinely sends a `new-message` webhook for a fresh message, then follows up seconds later with one or more `updated-message` webhooks for delivery/read status. The BB sense's `repairEvent` path promotes updated-message events with recoverable content back to `message` kind, which re-runs the full hydration pipeline
|
|
238
|
+
"fix(bluebubbles): dedup `updated-message` webhooks BEFORE running repair+hydrate+VLM. BlueBubbles routinely sends a `new-message` webhook for a fresh message, then follows up seconds later with one or more `updated-message` webhooks for delivery/read status. The BB sense's `repairEvent` path promotes updated-message events with recoverable content back to `message` kind, which re-runs the full hydration pipeline — including a second MiniMax VLM describe call on the same image. Verified live on 2026-04-08T00:58Z: two sequential VLM describes for attachment guid 317E37EB-..., 13.7s + 14.0s each, for the exact same 291KB JPEG, triggered by a `new-message` followed 3s later by an `updated-message` for the same guid. The downstream `handleBlueBubblesNormalizedEvent` dedup check was firing correctly but too late (after the expensive VLM round-trip). Fix: add a pre-repair dedup check in `handleBlueBubblesEvent` that consults the inbound sidecar by messageGuid and short-circuits before calling `client.repairEvent(...)`. New nerves event `senses.bluebubbles_repair_skipped_duplicate` at warn level for observability."
|
|
226
239
|
]
|
|
227
240
|
},
|
|
228
241
|
{
|
|
@@ -234,28 +247,28 @@
|
|
|
234
247
|
{
|
|
235
248
|
"version": "0.1.0-alpha.262",
|
|
236
249
|
"changes": [
|
|
237
|
-
"test(daemon): inject explicit `vi.mock(\"...heart/daemon/socket-client\", ...)` blocks into all 40 grandfathered test files in `TESTAGENT_NO_MOCK_ALLOWLIST`. The runtime guard in `socket-client.ts` already prevents real socket leaks under vitest, but the explicit mocks let those tests assert call counts cleanly and shrink the contract-test allowlist to zero. Both the testagent and the bundle-write allowlists in `test-isolation.contract.test.ts` are now empty Sets
|
|
250
|
+
"test(daemon): inject explicit `vi.mock(\"...heart/daemon/socket-client\", ...)` blocks into all 40 grandfathered test files in `TESTAGENT_NO_MOCK_ALLOWLIST`. The runtime guard in `socket-client.ts` already prevents real socket leaks under vitest, but the explicit mocks let those tests assert call counts cleanly and shrink the contract-test allowlist to zero. Both the testagent and the bundle-write allowlists in `test-isolation.contract.test.ts` are now empty Sets — any new offender fails the build."
|
|
238
251
|
]
|
|
239
252
|
},
|
|
240
253
|
{
|
|
241
254
|
"version": "0.1.0-alpha.261",
|
|
242
255
|
"changes": [
|
|
243
|
-
"feat(tui): full input parity with Claude Code
|
|
256
|
+
"feat(tui): full input parity with Claude Code — kill ring, emacs nav, Home/End, Ctrl+D, forward delete, Esc history, bracketed paste, clipboard image, token deletion, chip navigation. 156 new tests."
|
|
244
257
|
]
|
|
245
258
|
},
|
|
246
259
|
{
|
|
247
260
|
"version": "0.1.0-alpha.260",
|
|
248
261
|
"changes": [
|
|
249
|
-
"fix(daemon): MCP bridge empty-response bug for long-running commands. `sendDaemonCommand` and `checkDaemonSocketAlive` were calling `client.end()` immediately after writing, which half-closed the TCP connection. The daemon server's `net.createServer()` uses the default `allowHalfOpen: false`, so when it saw the client's FIN it auto-closed its own writable side
|
|
250
|
-
"fix(daemon): tighten pidfile trust
|
|
262
|
+
"fix(daemon): MCP bridge empty-response bug for long-running commands. `sendDaemonCommand` and `checkDaemonSocketAlive` were calling `client.end()` immediately after writing, which half-closed the TCP connection. The daemon server's `net.createServer()` uses the default `allowHalfOpen: false`, so when it saw the client's FIN it auto-closed its own writable side — and any response the server tried to write after processing a long-running command (like `agent.senseTurn`, which runs a full LLM turn) was dropped on the floor. Verified via direct socket repro: with `client.end()`, `agent.senseTurn` returned empty in ~149ms; without it, the same call returned a real response in ~5.8s. This was a silent regression of the fix in #303 (commit `253e4b1f` titled \"socket half-close fix\" actually *added* the half-close back). Fix: drop the `client.end()` calls from both sites AND set `allowHalfOpen: true` on the daemon's `net.createServer(...)` as defense-in-depth so future clients calling `end()` don't silently break again.",
|
|
263
|
+
"fix(daemon): tighten pidfile trust — `killOrphanProcesses` now verifies each pidfile PID is an actual orphan (PPID reparented to init/PID 1) before SIGTERMing it. Previously a polluted pidfile (written by a crashed daemon whose PIDs have since been reused by the OS for unrelated processes) could cause mass-kill of unrelated apps. New exported helper `filterPidfilePidsToActualOrphans` provides direct unit coverage.",
|
|
251
264
|
"fix(daemon, repertoire): rename six `_stop` nerves events to `_end` so they pair correctly with their `_start` counterparts under the nerves audit's start/end pairing rule. Affected: `daemon.thoughts_follow_stop`, `daemon.server_stop`, `daemon.update_checker_stop`, `daemon.mcp_server_stop`, `daemon.habit_scheduler_stop`, `mcp.manager_stop`. The naming was semantically fine (`stop` pairs with `start`), but the audit specifically looks for `_end`/`_error` suffixes. Was producing intermittent audit failures whenever any test run exercised these teardown paths (seen today as flakes on `daemon-socket-errors.test.ts` and `MarkdownStreamer` tests).",
|
|
252
|
-
"fix(providers): drop the harness-imposed MiniMax VLM timeout entirely. Previously the module defaulted to a 60-second AbortSignal; E2E validation of the BB image fix hit a real VLM request that took >60s to return (same bytes returned in 9.5s on the immediate retry). Raising to 120s would have been arbitrary too
|
|
265
|
+
"fix(providers): drop the harness-imposed MiniMax VLM timeout entirely. Previously the module defaulted to a 60-second AbortSignal; E2E validation of the BB image fix hit a real VLM request that took >60s to return (same bytes returned in 9.5s on the immediate retry). Raising to 120s would have been arbitrary too — the correct answer, per the same reasoning as PR #322 for LLM providers, is to not impose a harness ceiling at all. When `timeoutMs` isn't provided, `fetch()` now runs without an AbortSignal and undici's own defaults (headersTimeout + bodyTimeout, both 5 minutes) are the ceiling. Callers that want a tighter bound can still pass an explicit `timeoutMs`. The AbortError path is kept for that case, and the error message adapts to say \"underlying stack default\" when there was no harness-set value."
|
|
253
266
|
]
|
|
254
267
|
},
|
|
255
268
|
{
|
|
256
269
|
"version": "0.1.0-alpha.259",
|
|
257
270
|
"changes": [
|
|
258
|
-
"fix(daemon): SIGINT and SIGTERM now ALWAYS write a tombstone before exiting, instead of silently skipping when `_gracefulShutdown` was set. The previous behavior made signal-driven shutdowns invisible in `~/.ouro-cli/daemon-death.json`
|
|
271
|
+
"fix(daemon): SIGINT and SIGTERM now ALWAYS write a tombstone before exiting, instead of silently skipping when `_gracefulShutdown` was set. The previous behavior made signal-driven shutdowns invisible in `~/.ouro-cli/daemon-death.json` — launchd policy decisions, the OOM killer, manual `kill`, and `killOrphanProcesses` from a sibling daemon all looked identical to a clean exit. After a real outage where the user's daemon kept dying with a tombstone from a week earlier, this restores observability: every signal-driven exit now records `reason: \"sigint\"` or `reason: \"sigterm\"` with timestamp + recentCrashes accumulator. The catch-all `process.on('exit')` handler also no longer short-circuits on graceful shutdown."
|
|
259
272
|
]
|
|
260
273
|
},
|
|
261
274
|
{
|
|
@@ -269,14 +282,14 @@
|
|
|
269
282
|
{
|
|
270
283
|
"version": "0.1.0-alpha.257",
|
|
271
284
|
"changes": [
|
|
272
|
-
"test(daemon): convert all `daemon-cli.test.ts` auth/thoughts/config tests to use `os.tmpdir()` via the new `createTmpBundle()` helper. Previously these tests wrote real bundles to `~/AgentBundles/auth-local-${Date.now()}.ouro` etc., relying on `try/finally` cleanup that doesn't fire on test interruption
|
|
285
|
+
"test(daemon): convert all `daemon-cli.test.ts` auth/thoughts/config tests to use `os.tmpdir()` via the new `createTmpBundle()` helper. Previously these tests wrote real bundles to `~/AgentBundles/auth-local-${Date.now()}.ouro` etc., relying on `try/finally` cleanup that doesn't fire on test interruption — leaking bundle directories into the developer's home and inflating noise on the running daemon. The `REAL_BUNDLES_WRITE_ALLOWLIST` ratchet in `test-isolation.contract.test.ts` is now empty.",
|
|
273
286
|
"fix(daemon/cli-exec): plumb `bundlesRoot` and `secretsRoot` deps through the auth.run / auth.verify / auth.switch / config.model / config.models / thoughts handlers so tests can route reads/writes to a tmpdir without monkey-patching the identity module. Production code paths still default to `getAgentBundlesRoot()` and `~/.agentsecrets`."
|
|
274
287
|
]
|
|
275
288
|
},
|
|
276
289
|
{
|
|
277
290
|
"version": "0.1.0-alpha.256",
|
|
278
291
|
"changes": [
|
|
279
|
-
"fix(tui): cursor renders as inverse character (not inserted block)
|
|
292
|
+
"fix(tui): cursor renders as inverse character (not inserted block) — matches standard terminal cursor behavior.",
|
|
280
293
|
"fix(tui): Alt+Enter via ESC-timing (50ms window) instead of raw stdin handler that interfered with arrow keys.",
|
|
281
294
|
"fix(tui): image path regex now matches backslash-escaped spaces from macOS drag-drop."
|
|
282
295
|
]
|
|
@@ -285,20 +298,20 @@
|
|
|
285
298
|
"version": "0.1.0-alpha.255",
|
|
286
299
|
"changes": [
|
|
287
300
|
"feat(tui): session resume shows last messages as regular chat (no dimmed preview) with teal resume banner in header.",
|
|
288
|
-
"feat(tui): image/file drag-and-drop
|
|
301
|
+
"feat(tui): image/file drag-and-drop — detects image paths in pasted text, reads to base64, inserts [Image #N] references, sends as image_url content blocks to model.",
|
|
289
302
|
"refactor(tui): removed custom history-* roles and addSessionHistory (KISS/DRY)."
|
|
290
303
|
]
|
|
291
304
|
},
|
|
292
305
|
{
|
|
293
306
|
"version": "0.1.0-alpha.254",
|
|
294
307
|
"changes": [
|
|
295
|
-
"fix(daemon): orphan-cleanup fallback no longer kills processes from sibling harness instances. On startup, `killOrphanProcesses` scans `ps` for harness entry points (`agent-entry.js`, `daemon-entry.js`, `bluebubbles/entry.js`, `teams-entry.js`) and SIGTERMs them when the pidfile is missing. Previously any matching process was fair game, so a vitest-driven harness run from a sibling worktree (or a parallel Claude Code session running the coverage gate) would terminate the production daemon's children, triggering cascading graceful shutdowns and making production slugger unavailable for seconds-to-minutes at a time. Now the fallback only flags true orphans
|
|
308
|
+
"fix(daemon): orphan-cleanup fallback no longer kills processes from sibling harness instances. On startup, `killOrphanProcesses` scans `ps` for harness entry points (`agent-entry.js`, `daemon-entry.js`, `bluebubbles/entry.js`, `teams-entry.js`) and SIGTERMs them when the pidfile is missing. Previously any matching process was fair game, so a vitest-driven harness run from a sibling worktree (or a parallel Claude Code session running the coverage gate) would terminate the production daemon's children, triggering cascading graceful shutdowns and making production slugger unavailable for seconds-to-minutes at a time. Now the fallback only flags true orphans — processes whose PPID has been reparented to init (PID 1). Sibling daemons' live-parented children are left alone. New exported helper `parseOrphanPidsFromPs` isolates the filter for direct unit coverage. Complements the test-isolation guard shipped in alpha.253 (#333): that PR stopped tests from SENDING `inner.wake testagent` commands into the production socket; this PR stops the production daemon from SIGTERMing test-spawned child processes during its own startup."
|
|
296
309
|
]
|
|
297
310
|
},
|
|
298
311
|
{
|
|
299
312
|
"version": "0.1.0-alpha.253",
|
|
300
313
|
"changes": [
|
|
301
|
-
"fix(daemon): test-isolation guard
|
|
314
|
+
"fix(daemon): test-isolation guard — stop tests from leaking real `inner.wake` commands into the running daemon. A pattern in 36+ test files mocks `getAgentName` to the literal `\"testagent\"` but does NOT mock `socket-client`, so any code path through pondering / rest / coding feedback fires a real socket connection at /tmp/ouroboros-daemon.sock with `inner.wake testagent`. The daemon errored on every command (`Unknown managed agent 'testagent'`) and at flood volumes that contributed to a real outage on the developer's machine. The fix is in `socket-client.ts` itself: detect vitest via `process.argv` (no env vars) and convert all socket operations into safe no-ops. Tests that legitimately exercise the real transport (socket-client.test.ts, daemon-cli-defaults.test.ts) opt out of the guard via a new `__bypassVitestGuardForTests()` setter that lives on globalThis to survive `vi.resetModules()`. New nerves events: `daemon.socket_command_test_blocked`, `daemon.inner_wake_test_blocked`.",
|
|
302
315
|
"test(contract): new test-isolation contract test ratchets two anti-patterns: (1) test files using `name: \"testagent\"` without mocking socket-client, and (2) test files constructing write paths under the real `~/AgentBundles` via `os.homedir()`. Existing offenders are grandfathered in two allowlists; new offenders fail the build. Follow-up PRs shrink the allowlists toward zero."
|
|
303
316
|
]
|
|
304
317
|
},
|
|
@@ -311,7 +324,7 @@
|
|
|
311
324
|
{
|
|
312
325
|
"version": "0.1.0-alpha.251",
|
|
313
326
|
"changes": [
|
|
314
|
-
"fix(bluebubbles): images sent via iMessage now reach the model
|
|
327
|
+
"fix(bluebubbles): images sent via iMessage now reach the model — adds capability-gated image hydration with a MiniMax VLM fallback. Reasoning MiniMax chat models (M2/M2.1/M2.5/M2.7) silently drop OpenAI-style `image_url` content parts, so previously slugger answered image questions from fabricated context. Now, when the active chat model lacks the new `vision: true` capability flag, inbound screenshots are auto-described at ingestion via `/v1/coding_plan/vlm` and the description text replaces the `image_url` part before the turn reaches the model. Vision-capable models (claude-opus/sonnet-4-6, gpt-5.4, MiniMax-Text-01, MiniMax-VL-01) continue to see images natively via pass-through.",
|
|
315
328
|
"feat(tools): new `describe_image` agent tool registered into the BlueBubbles tool set when the chat model lacks vision. Lets the agent re-interrogate an attachment with a targeted prompt (e.g. 'what's the flight number in the bottom-right?') after ingestion. Backed by a bounded in-memory attachment cache populated during hydration; handler re-downloads bytes and calls the same VLM client.",
|
|
316
329
|
"fix(bluebubbles): `formatMessageText` now preserves the attachment marker when a message has BOTH text and attachments (B2). Previously the marker was dropped whenever text was present, hiding attachments from the agent's view of the message.",
|
|
317
330
|
"feat(heart): `ModelCapabilities` gains `vision?: boolean` and `audio?: boolean` flags (B4). Vision rows populated for claude-opus-4-6, claude-sonnet-4-6, claude-opus-4.6, claude-sonnet-4.6, gpt-5.4, MiniMax-Text-01, MiniMax-VL-01. M2.1/M2.5/M2.7 intentionally left unset.",
|
|
@@ -321,7 +334,7 @@
|
|
|
321
334
|
{
|
|
322
335
|
"version": "0.1.0-alpha.250",
|
|
323
336
|
"changes": [
|
|
324
|
-
"fix(sync): surface 'bundle is not a git repo' as an actionable error instead of silently failing. Previously, enabling `sync.enabled` on a bundle that had never been `git init`'d produced a generic `git status` failure buried in nerves logs; the agent saw nothing in its start-of-turn packet and the user saw nothing in `ouro status`. Now: (1) `preTurnPull` and `postTurnPush` detect the missing `.git` directory before touching git and return an actionable error with the bundle path and the `git init` hint; (2) this error propagates via `ctx.syncFailure` into the agent's Sync warning, so the agent can offer to run `git init` or just do it; (3) `ouro status` shows a red `error` state with `not a git repo
|
|
337
|
+
"fix(sync): surface 'bundle is not a git repo' as an actionable error instead of silently failing. Previously, enabling `sync.enabled` on a bundle that had never been `git init`'d produced a generic `git status` failure buried in nerves logs; the agent saw nothing in its start-of-turn packet and the user saw nothing in `ouro status`. Now: (1) `preTurnPull` and `postTurnPush` detect the missing `.git` directory before touching git and return an actionable error with the bundle path and the `git init` hint; (2) this error propagates via `ctx.syncFailure` into the agent's Sync warning, so the agent can offer to run `git init` or just do it; (3) `ouro status` shows a red `error` state with `not a git repo — run \\`git init\\` to enable sync` next to the offending bundle. New nerves event: `heart.sync_not_a_repo`."
|
|
325
338
|
]
|
|
326
339
|
},
|
|
327
340
|
{
|
|
@@ -334,8 +347,8 @@
|
|
|
334
347
|
{
|
|
335
348
|
"version": "0.1.0-alpha.248",
|
|
336
349
|
"changes": [
|
|
337
|
-
"feat(daemon): `ouro status` Git Sync now resolves and shows the actual remote URL via `git remote get-url`. Three states: `origin
|
|
338
|
-
"fix(heart/sync): `preTurnPull` now skips the pull when no git remote is configured, mirroring the existing `postTurnPush` behavior. Closes the half-implemented 'no-remote sync' (local-only commit log) story
|
|
350
|
+
"feat(daemon): `ouro status` Git Sync now resolves and shows the actual remote URL via `git remote get-url`. Three states: `origin → git@github.com:me/foo.git` when the remote resolves, `local only` when sync is enabled but no remote is configured, `disabled` when sync is off. Previously you had to `cd` into the bundle and run `git remote -v` to find out where it pushes.",
|
|
351
|
+
"fix(heart/sync): `preTurnPull` now skips the pull when no git remote is configured, mirroring the existing `postTurnPush` behavior. Closes the half-implemented 'no-remote sync' (local-only commit log) story — previously, enabling sync without a remote produced a `syncFailure` on every turn from the failing `git pull` call."
|
|
339
352
|
]
|
|
340
353
|
},
|
|
341
354
|
{
|
|
@@ -347,7 +360,7 @@
|
|
|
347
360
|
{
|
|
348
361
|
"version": "0.1.0-alpha.246",
|
|
349
362
|
"changes": [
|
|
350
|
-
"feat(tui): session resume display
|
|
363
|
+
"feat(tui): session resume display — shows summary line + last 3 exchanges dimmed when reconnecting to existing session."
|
|
351
364
|
]
|
|
352
365
|
},
|
|
353
366
|
{
|
|
@@ -359,58 +372,58 @@
|
|
|
359
372
|
{
|
|
360
373
|
"version": "0.1.0-alpha.244",
|
|
361
374
|
"changes": [
|
|
362
|
-
"refactor(sync): git-status-based bundle sync
|
|
363
|
-
"feat(tui): queued input steer
|
|
375
|
+
"refactor(sync): git-status-based bundle sync — postTurnPush discovers dirty files via `git status --porcelain` instead of broken explicit trackSyncWrite tracking (only 3/9 writers used it). Removed dead infrastructure. Remote push optional and non-fatal.",
|
|
376
|
+
"feat(tui): queued input steer — messages typed while agent is thinking appear dimmed above input area. UP/ESC pops all queued messages back into input for editing. Placeholder hint. Multiple messages supported, each sent as separate turn.",
|
|
364
377
|
"chore: deleted legacy InkCliApp adapter (776 lines dead code)."
|
|
365
378
|
]
|
|
366
379
|
},
|
|
367
380
|
{
|
|
368
381
|
"version": "0.1.0-alpha.243",
|
|
369
382
|
"changes": [
|
|
370
|
-
"fix(daemon): per-agent Git Sync in `ouro status`
|
|
383
|
+
"fix(daemon): per-agent Git Sync in `ouro status` — was always showing `disabled` regardless of any agent's `agent.json`, because the daemon process has no argv-derived agent identity so `getSyncConfig()` fell into its catch. Status payload now carries a per-agent `sync` array (one row per enabled bundle) rendered as its own section like Senses and Workers, instead of a single global field on the overview block."
|
|
371
384
|
]
|
|
372
385
|
},
|
|
373
386
|
{
|
|
374
387
|
"version": "0.1.0-alpha.241",
|
|
375
388
|
"changes": [
|
|
376
|
-
"feat: commerce bootstrap
|
|
389
|
+
"feat: commerce bootstrap — bw CLI lazy-install, vault auto-config, resolver coverage"
|
|
377
390
|
]
|
|
378
391
|
},
|
|
379
392
|
{
|
|
380
393
|
"version": "0.1.0-alpha.242",
|
|
381
394
|
"changes": [
|
|
382
|
-
"fix(friends): stable local CLI identity
|
|
383
|
-
"feat(friends): migration fallback
|
|
384
|
-
"fix(heart): retry-everything-except-blocklist policy
|
|
385
|
-
"fix(heart/providers): drop the 30s OpenAI/Anthropic SDK timeout from all five providers (anthropic, azure, github-copilot, minimax, openai-codex). The SDK timeout caps the entire stream lifetime, so 30s killed any reasoning model mid-generation. SDK defaults (
|
|
395
|
+
"fix(friends): stable local CLI identity — dropped hostname from external ID (was `username@hostname`, now just `username`). macOS hostname instability (`Mac` vs `Aris-MacBook-Pro.local`) was creating duplicate friend records with separate sessions and trust levels.",
|
|
396
|
+
"feat(friends): migration fallback — FriendResolver now searches for old `username@*` format IDs when exact match fails, linking new stable ID to existing friend record.",
|
|
397
|
+
"fix(heart): retry-everything-except-blocklist policy — the SDK 'Request timed out.' error from MiniMax (and other providers) was reaching slugger as a terminal failure because neither the generic isTransientError detector nor the per-provider classifier recognized it. Replaced the two-layer transient detection with a small blocklist (HTTP 400/401/403/404/422 + classifications auth-failure/usage-limit). Default policy now retries every other error.",
|
|
398
|
+
"fix(heart/providers): drop the 30s OpenAI/Anthropic SDK timeout from all five providers (anthropic, azure, github-copilot, minimax, openai-codex). The SDK timeout caps the entire stream lifetime, so 30s killed any reasoning model mid-generation. SDK defaults (≈10min) are sane.",
|
|
386
399
|
"refactor(heart/providers): consolidate duplicated isNetworkError + classifyXxxError scaffolding into a shared `error-classification.ts` module. Each provider now delegates via `classifyHttpError(err, overrides)` and only carries its own provider-specific quirks (Anthropic 529, Codex usage-limit message detection)."
|
|
387
400
|
]
|
|
388
401
|
},
|
|
389
402
|
{
|
|
390
403
|
"version": "0.1.0-alpha.238",
|
|
391
404
|
"changes": [
|
|
392
|
-
"feat: pretty `ouro status`
|
|
393
|
-
"fix: socket half-close
|
|
394
|
-
"refactor: config tiers
|
|
395
|
-
"refactor: removed confirmation system
|
|
405
|
+
"feat: pretty `ouro status` — ANSI colored output with box-drawing header, status dots, grouped senses/workers by agent. Added git sync info to overview.",
|
|
406
|
+
"fix: socket half-close — sendDaemonCommand now calls client.end() after writing, preventing intermittent connection hangs.",
|
|
407
|
+
"refactor: config tiers — replaced numeric T1/T2/T3 with `self` (agent-configurable) and `managed` (harness-only). All config keys are now agent-writable except `version` and `enabled`. mcpServers promoted to self.",
|
|
408
|
+
"refactor: removed confirmation system — deleted propose_config tool, confirmationRequired/confirmationAlwaysRequired/onConfirmAction from core, all tool definitions, and Teams sense. Was only wired up on Teams, silently failed everywhere else. -1,361 lines."
|
|
396
409
|
]
|
|
397
410
|
},
|
|
398
411
|
{
|
|
399
412
|
"version": "0.1.0-alpha.235",
|
|
400
413
|
"changes": [
|
|
401
|
-
"fix: MCP tool double-prefix
|
|
402
|
-
"feat: Open-Meteo zero-auth weather
|
|
403
|
-
"feat: expanded ISO/FIPS divergence table
|
|
404
|
-
"fix: BitwardenCredentialStore retry logic
|
|
414
|
+
"fix: MCP tool double-prefix — tools already prefixed by server name no longer get a redundant second prefix in the unified registry.",
|
|
415
|
+
"feat: Open-Meteo zero-auth weather — replaced OpenWeatherMap with Open-Meteo forecast + geocoding API. Weather now works without any API key or credential provisioning.",
|
|
416
|
+
"feat: expanded ISO/FIPS divergence table — 21 new entries for correct travel advisory resolution across all major divergent country codes.",
|
|
417
|
+
"fix: BitwardenCredentialStore retry logic — exponential backoff with configurable retries for transient bw CLI failures, plus bw-not-installed error.",
|
|
405
418
|
"chore: travel MCP packages (Duffel, Expedia) status confirmed GitHub-only, not published to npm."
|
|
406
419
|
]
|
|
407
420
|
},
|
|
408
421
|
{
|
|
409
422
|
"version": "0.1.0-alpha.233",
|
|
410
423
|
"changes": [
|
|
411
|
-
"feat: first-class MCP tools
|
|
412
|
-
"fix: daemon MCP pre-init poisoned singleton
|
|
413
|
-
"fix: removed dead mcpManager field from BuildSystemOptions
|
|
424
|
+
"feat: first-class MCP tools — MCP tools now appear in the agent tool list directly (no shell indirection). Agent can call browser_navigate, browser_click etc. as native tools.",
|
|
425
|
+
"fix: daemon MCP pre-init poisoned singleton — removed eager getSharedMcpManager() at daemon startup that cached null before agent identity was set.",
|
|
426
|
+
"fix: removed dead mcpManager field from BuildSystemOptions — MCP manager now flows through runAgentOptions.",
|
|
414
427
|
"fix: MCP tool results filter to text-only content types.",
|
|
415
428
|
"includes: vault integration, travel advisory fix, credential access layer, HKDF-Expand crypto fix."
|
|
416
429
|
]
|
|
@@ -418,21 +431,21 @@
|
|
|
418
431
|
{
|
|
419
432
|
"version": "0.1.0-alpha.232",
|
|
420
433
|
"changes": [
|
|
421
|
-
"feat: first-class MCP tools
|
|
434
|
+
"feat: first-class MCP tools — MCP server tools now appear in the agent's active tool list (e.g. browser_navigate, duffel_search_flights) and are callable directly by the model, eliminating fragile shell indirection",
|
|
422
435
|
"feat: mcpToolsAsDefinitions() converts McpManager tools to ToolDefinition objects with {server}_{tool} naming",
|
|
423
|
-
"feat: first-class MCP trust gating
|
|
424
|
-
"refactor: removed mcpToolsSection() from system prompt
|
|
436
|
+
"feat: first-class MCP trust gating — mcpServerName on GuardContext enables per-server trust rules (browser blocked for acquaintance, blocked in group chat)",
|
|
437
|
+
"refactor: removed mcpToolsSection() from system prompt — MCP tools no longer need prompt documentation",
|
|
425
438
|
"fix: execTool, isConfirmationRequired, summarizeArgs now check combined native+MCP registry"
|
|
426
439
|
]
|
|
427
440
|
},
|
|
428
441
|
{
|
|
429
442
|
"version": "0.1.0-alpha.231",
|
|
430
443
|
"changes": [
|
|
431
|
-
"fix: defense-in-depth group chat blocking for proactive BB delivery
|
|
444
|
+
"fix: defense-in-depth group chat blocking for proactive BB delivery — sendProactiveBlueBubblesMessageToSession now rejects group chat keys (;+;) unless intent is explicit_cross_chat (bridge/delegation responses). All upper-layer paths (surface tool, send_message tool, inner-dialog delegation) now filter to DM sessions only for proactive outreach, and pass explicit_cross_chat intent for bridge/delegation returns where group responses are legitimate.",
|
|
432
445
|
"fix: travel advisory now resolves ISO codes that differ from FIPS (ES -> Spain, not El Salvador)",
|
|
433
446
|
"fix: MCP bridge sense now includes MCP tool descriptions in system prompt (browser tools visible)",
|
|
434
447
|
"fix: removed confirmationRequired from credential_store/credential_delete (trust gating sufficient)",
|
|
435
|
-
"feat: vault integration
|
|
448
|
+
"feat: vault integration — Bitwarden/Vaultwarden account creation with PBKDF2/HKDF/AES-256-CBC crypto",
|
|
436
449
|
"feat: vault_setup tool for one-time vault provisioning (family trust gated)",
|
|
437
450
|
"feat: BitwardenCredentialStore wrapping bw CLI for agent-owned vault access"
|
|
438
451
|
]
|
|
@@ -446,20 +459,20 @@
|
|
|
446
459
|
{
|
|
447
460
|
"version": "0.1.0-alpha.229",
|
|
448
461
|
"changes": [
|
|
449
|
-
"fix: BB session key resolution prefers DM (;-;) over group chat (;+;)
|
|
462
|
+
"fix: BB session key resolution prefers DM (;-;) over group chat (;+;) — alphabetical sort put group chats first, causing proactive messages to land in group chats instead of personal DMs",
|
|
450
463
|
"chore: remove temporary debug traces (send-message-debug.log, friends.get_called event)"
|
|
451
464
|
]
|
|
452
465
|
},
|
|
453
466
|
{
|
|
454
467
|
"version": "0.1.0-alpha.227",
|
|
455
468
|
"changes": [
|
|
456
|
-
"fix: direct filesystem name resolution in sendProactiveBlueBubblesMessageToSession
|
|
469
|
+
"fix: direct filesystem name resolution in sendProactiveBlueBubblesMessageToSession — bypass store.get()/listAll() with raw fs reads on friends directory when store lookup fails"
|
|
457
470
|
]
|
|
458
471
|
},
|
|
459
472
|
{
|
|
460
473
|
"version": "0.1.0-alpha.226",
|
|
461
474
|
"changes": [
|
|
462
|
-
"fix(daemon): set agent name before senseTurn so MCP messages resolve identity
|
|
475
|
+
"fix(daemon): set agent name before senseTurn so MCP messages resolve identity — setAgentName() is now called at the top of the senseTurn handler, before any downstream code that depends on agent identity (loadAgentConfig, getAgentSecretsPath, etc.)"
|
|
463
476
|
]
|
|
464
477
|
},
|
|
465
478
|
{
|
|
@@ -471,7 +484,7 @@
|
|
|
471
484
|
{
|
|
472
485
|
"version": "0.1.0-alpha.224",
|
|
473
486
|
"changes": [
|
|
474
|
-
"fix: FileFriendStore.get() now resolves friend names
|
|
487
|
+
"fix: FileFriendStore.get() now resolves friend names — when UUID lookup fails, scans the friends directory for a name match. This is the deepest possible layer for name resolution, ensuring it works regardless of which tool or code path calls store.get()."
|
|
475
488
|
]
|
|
476
489
|
},
|
|
477
490
|
{
|
|
@@ -483,127 +496,127 @@
|
|
|
483
496
|
{
|
|
484
497
|
"version": "0.1.0-alpha.222",
|
|
485
498
|
"changes": [
|
|
486
|
-
"debug: add diagnostic nerves events to proactive BB delivery
|
|
499
|
+
"debug: add diagnostic nerves events to proactive BB delivery — name resolution in both tools-session.ts and sendProactiveBlueBubblesMessageToSession now emit events showing friend count, names, resolution success/failure, and errors. Temporary diagnostics to identify why name→UUID resolution isn't working in production."
|
|
487
500
|
]
|
|
488
501
|
},
|
|
489
502
|
{
|
|
490
503
|
"version": "0.1.0-alpha.221",
|
|
491
504
|
"changes": [
|
|
492
|
-
"fix: BB proactive send resolves friend by name when UUID lookup fails
|
|
505
|
+
"fix: BB proactive send resolves friend by name when UUID lookup fails — sendProactiveBlueBubblesMessageToSession now falls back to store.listAll() name matching when store.get() returns null. This handles agents passing friend names instead of UUIDs, bypassing the upstream resolution that wasn't working in all contexts."
|
|
493
506
|
]
|
|
494
507
|
},
|
|
495
508
|
{
|
|
496
509
|
"version": "0.1.0-alpha.220",
|
|
497
510
|
"changes": [
|
|
498
|
-
"fix: send_message BB session key resolution
|
|
511
|
+
"fix: send_message BB session key resolution — agents don't know the real BB session key (e.g. 'chat_any;-;ari@mendelow.me'), so they pass the default 'session'. buildChatRefForSessionKey failed on this fake key, returning missing_target. Now auto-resolves the real BB session key from the sessions directory when the default key is used."
|
|
499
512
|
]
|
|
500
513
|
},
|
|
501
514
|
{
|
|
502
515
|
"version": "0.1.0-alpha.219",
|
|
503
516
|
"changes": [
|
|
504
|
-
"fix: proactive message delivery
|
|
517
|
+
"fix: proactive message delivery — three bugs fixed. (1) surface tool now resolves friend names to UUIDs by scanning friends directory. (2) send_message tool also resolves friend names to UUIDs. (3) deliverCrossChatMessage no longer immediately queues generic_outreach — it now attempts delivery when a deliverer is available, with the deliverer's own trust checks still gating actual sends. Previously, any proactive send from inner dialog was silently queued without attempting delivery."
|
|
505
518
|
]
|
|
506
519
|
},
|
|
507
520
|
{
|
|
508
521
|
"version": "0.1.0-alpha.218",
|
|
509
522
|
"changes": [
|
|
510
|
-
"fix: surface tool now resolves friend names to UUIDs
|
|
523
|
+
"fix: surface tool now resolves friend names to UUIDs — agents pass friend names but sessions are stored under UUID directories. Added name-to-UUID resolution by scanning the friends directory when the friendId doesn't match a session directory."
|
|
511
524
|
]
|
|
512
525
|
},
|
|
513
526
|
{
|
|
514
527
|
"version": "0.1.0-alpha.217",
|
|
515
528
|
"changes": [
|
|
516
|
-
"feat: Bitwarden vault client (bw CLI wrapper) with credential gateway
|
|
517
|
-
"feat: vault tools (vault_get, vault_store, vault_list, vault_delete) with trust gating
|
|
518
|
-
"feat: stealth browser MCP configuration with trust gating
|
|
519
|
-
"feat: travel API tools (weather_lookup, travel_advisory, geocode_search)
|
|
520
|
-
"feat: credential gateway (vaultKey on apiRequest())
|
|
529
|
+
"feat: Bitwarden vault client (bw CLI wrapper) with credential gateway — BitwardenClient class with SDK-first/CLI-fallback, singleton accessor, nerves events on all operations. Raw secrets never enter model context.",
|
|
530
|
+
"feat: vault tools (vault_get, vault_store, vault_list, vault_delete) with trust gating — read ops require friend+, write/delete require family-only. Destructive operations require confirmation.",
|
|
531
|
+
"feat: stealth browser MCP configuration with trust gating — Playwright MCP auto-provisions when configured, browser tools appear in agent tool list. Trust-gated to CLI and trusted 1:1 only (group chat blocked).",
|
|
532
|
+
"feat: travel API tools (weather_lookup, travel_advisory, geocode_search) — native weather via OpenWeatherMap + vault-backed API key, State Dept RSS feed for advisories, geocoding via Nominatim. All friend+ trust-gated.",
|
|
533
|
+
"feat: credential gateway (vaultKey on apiRequest()) — automatic secret injection from vault into HTTP headers at call time, keeping credentials out of model context entirely.",
|
|
521
534
|
"feat: travel-planning and browser-navigation skills"
|
|
522
535
|
]
|
|
523
536
|
},
|
|
524
537
|
{
|
|
525
538
|
"version": "0.1.0-alpha.216",
|
|
526
539
|
"changes": [
|
|
527
|
-
"fix: surface tool proactive BB delivery masked by newer MCP/CLI sessions
|
|
540
|
+
"fix: surface tool proactive BB delivery masked by newer MCP/CLI sessions — findFreshestFriendSession picked the single freshest session regardless of channel, so an MCP or CLI session being newer than the BB session caused the BB proactive path to be skipped entirely. Now scans all friend sessions, attempts BB delivery first on any BB session, then falls back to queuing on the freshest non-inner session."
|
|
528
541
|
]
|
|
529
542
|
},
|
|
530
543
|
{
|
|
531
544
|
"version": "0.1.0-alpha.215",
|
|
532
545
|
"changes": [
|
|
533
|
-
"fix: surface tool proactive delivery no longer gated by 24-hour session threshold
|
|
546
|
+
"fix: surface tool proactive delivery no longer gated by 24-hour session threshold — findFreshestFriendSession was called with activeOnly:true, filtering out sessions older than 24h even when the agent explicitly wants to send a proactive message. Both the bridge path and direct path now find any session regardless of age. Proactive BB delivery and trust checks still apply."
|
|
534
547
|
]
|
|
535
548
|
},
|
|
536
549
|
{
|
|
537
550
|
"version": "0.1.0-alpha.214",
|
|
538
551
|
"changes": [
|
|
539
|
-
"fix: daemon death diagnostics
|
|
540
|
-
"fix: daemon tombstone now covers all exit paths
|
|
552
|
+
"fix: daemon death diagnostics — createStderrSink() bypassed EPIPE-safe default in createTerminalSink(), causing uncaught EPIPE crashes when daemon runs detached. Removed redundant unsafe default so the existing try-catch fires.",
|
|
553
|
+
"fix: daemon tombstone now covers all exit paths — unhandledRejection writes tombstone with full error+stack (was just a warn log, but Node 15+ terminates on these). Added process.on('exit') catch-all for any unanticipated exit. SIGINT/SIGTERM marked graceful to avoid false positives. _lastKnownCause threads real error through to exit handler."
|
|
541
554
|
]
|
|
542
555
|
},
|
|
543
556
|
{
|
|
544
557
|
"version": "0.1.0-alpha.213",
|
|
545
558
|
"changes": [
|
|
546
|
-
"cleanup: remove vestigial subagents/ directory and package.json files entry (content already in ouroboros-skills repo). Remove backward-compat re-exports from heart/core.ts (tools, execTool, summarizeArgs, getToolsForChannel, streamChatCompletion, streamResponsesApi, toResponsesInput, toResponsesTools, buildSystem, Channel, hasToolIntent
|
|
559
|
+
"cleanup: remove vestigial subagents/ directory and package.json files entry (content already in ouroboros-skills repo). Remove backward-compat re-exports from heart/core.ts (tools, execTool, summarizeArgs, getToolsForChannel, streamChatCompletion, streamResponsesApi, toResponsesInput, toResponsesTools, buildSystem, Channel, hasToolIntent — no consumers used them). Update ARCHITECTURE.md, README.md, and CONTRIBUTING.md to reflect the full audit restructuring: new arc/ subsystem, heart/ topic subdirectories, split tool modules, BlueBubbles directory, scopes list."
|
|
547
560
|
]
|
|
548
561
|
},
|
|
549
562
|
{
|
|
550
563
|
"version": "0.1.0-alpha.212",
|
|
551
564
|
"changes": [
|
|
552
|
-
"refactor: consolidate BlueBubbles sense into senses/bluebubbles/ directory
|
|
565
|
+
"refactor: consolidate BlueBubbles sense into senses/bluebubbles/ directory — move 9 flat files (bluebubbles.ts, bluebubbles-client.ts, bluebubbles-model.ts, bluebubbles-media.ts, bluebubbles-inbound-log.ts, bluebubbles-mutation-log.ts, bluebubbles-runtime-state.ts, bluebubbles-session-cleanup.ts, bluebubbles-entry.ts) into senses/bluebubbles/ with shorter names (index.ts, client.ts, model.ts, etc.). All imports updated across 20+ files including test files, sense-manager, daemon, and package.json."
|
|
553
566
|
]
|
|
554
567
|
},
|
|
555
568
|
{
|
|
556
569
|
"version": "0.1.0-alpha.211",
|
|
557
570
|
"changes": [
|
|
558
|
-
"refactor: extract duplicated patterns into shared utilities
|
|
571
|
+
"refactor: extract duplicated patterns into shared utilities — mind/embedding-provider.ts (shared OpenAI embedding client from diary + associative-recall), arc/json-store.ts (shared JSON file CRUD from obligations + cares + intentions), repertoire/api-client.ts (shared HTTP request helper from graph + ado + github clients). M12 (channel callback factory) skipped: CLI and Teams streaming implementations are too different for clean abstraction."
|
|
559
572
|
]
|
|
560
573
|
},
|
|
561
574
|
{
|
|
562
575
|
"version": "0.1.0-alpha.210",
|
|
563
576
|
"changes": [
|
|
564
|
-
"refactor: create src/arc/ subsystem
|
|
577
|
+
"refactor: create src/arc/ subsystem — extract durable continuity state (obligations, cares, episodes, intentions, presence, attention-types) from heart/ and mind/ into dedicated arc/ module. arc/ owns the agent's continuity state, distinct from engine mechanics (heart) and cognition (mind). All imports updated across 40+ files."
|
|
565
578
|
]
|
|
566
579
|
},
|
|
567
580
|
{
|
|
568
581
|
"version": "0.1.0-alpha.209",
|
|
569
582
|
"changes": [
|
|
570
|
-
"refactor: restructure daemon/ directory
|
|
583
|
+
"refactor: restructure daemon/ directory — move outlook files to heart/outlook/, habit files to heart/habits/, hatch/specialist files to heart/hatch/, versioning/update files to heart/versioning/, auth-flow to heart/auth/, mcp-server to heart/mcp/. daemon/ reduced from 60 to 36 core daemon-lifecycle files."
|
|
571
584
|
]
|
|
572
585
|
},
|
|
573
586
|
{
|
|
574
587
|
"version": "0.1.0-alpha.208",
|
|
575
588
|
"changes": [
|
|
576
|
-
"refactor: split daemon-cli.ts (3,630 lines) into 5 focused modules
|
|
589
|
+
"refactor: split daemon-cli.ts (3,630 lines) into 5 focused modules — cli-types (command/deps types), cli-parse (argument parsing), cli-render (output formatting), cli-exec (command execution router), cli-defaults (production dependency wiring). daemon-cli.ts reduced to 42-line re-export shim."
|
|
577
590
|
]
|
|
578
591
|
},
|
|
579
592
|
{
|
|
580
593
|
"version": "0.1.0-alpha.207",
|
|
581
594
|
"changes": [
|
|
582
|
-
"refactor: split tools-base.ts (1,912 lines) into 9 category modules
|
|
595
|
+
"refactor: split tools-base.ts (1,912 lines) into 9 category modules — tools-files, tools-shell, tools-memory, tools-bridge, tools-session, tools-continuity, tools-flow, tools-surface, tools-config. Surface tool handler extracted from tools.ts to tools-surface.ts."
|
|
583
596
|
]
|
|
584
597
|
},
|
|
585
598
|
{
|
|
586
599
|
"version": "0.1.0-alpha.206",
|
|
587
600
|
"changes": [
|
|
588
|
-
"feat: capability discovery and tiered self-configuration
|
|
601
|
+
"feat: capability discovery and tiered self-configuration — config registry with tier-aware metadata (T1 self-service, T2 proposal, T3 operator-only), read_config tool with topic-filtered discovery, update_config tool for T1 immediate changes, propose_config tool for T2 operator-approval flow, version-change surfacing in start-of-turn packet via buildCapabilitiesSection"
|
|
589
602
|
]
|
|
590
603
|
},
|
|
591
604
|
{
|
|
592
605
|
"version": "0.1.0-alpha.205",
|
|
593
606
|
"changes": [
|
|
594
|
-
"refactor: enforce subsystem boundaries
|
|
607
|
+
"refactor: enforce subsystem boundaries — eliminate all heart/ and nerves/ static imports from senses/, move AttentionItem type to heart/, surfaceToolDef to repertoire/, SteeringFollowUpEffect to heart/turn-coordinator, inline BlueBubbles runtime state reader in daemon"
|
|
595
608
|
]
|
|
596
609
|
},
|
|
597
610
|
{
|
|
598
611
|
"version": "0.1.0-alpha.204",
|
|
599
612
|
"changes": [
|
|
600
|
-
"refactor: introduce TurnContext snapshot
|
|
613
|
+
"refactor: introduce TurnContext snapshot — centralize state assembly from pipeline.ts into buildTurnContext(), thread pre-read state through prompt assembly to eliminate ad-hoc filesystem reads"
|
|
601
614
|
]
|
|
602
615
|
},
|
|
603
616
|
{
|
|
604
617
|
"version": "0.1.0-alpha.203",
|
|
605
618
|
"changes": [
|
|
606
|
-
"refactor: unify obligation systems
|
|
619
|
+
"refactor: unify obligation systems — mind/obligations.ts merged into heart/obligations.ts with prefixed ReturnObligation API"
|
|
607
620
|
]
|
|
608
621
|
},
|
|
609
622
|
{
|
|
@@ -619,7 +632,7 @@
|
|
|
619
632
|
{
|
|
620
633
|
"version": "0.1.0-alpha.201",
|
|
621
634
|
"changes": [
|
|
622
|
-
"fix: don't launchctl bootstrap after daemon start
|
|
635
|
+
"fix: don't launchctl bootstrap after daemon start — was starting competing daemon that killed the first"
|
|
623
636
|
]
|
|
624
637
|
},
|
|
625
638
|
{
|
|
@@ -641,7 +654,7 @@
|
|
|
641
654
|
{
|
|
642
655
|
"version": "0.1.0-alpha.197",
|
|
643
656
|
"changes": [
|
|
644
|
-
"fix(daemon): validate agent config before spawn
|
|
657
|
+
"fix(daemon): validate agent config before spawn — skips agents with missing credentials instead of crash-looping"
|
|
645
658
|
]
|
|
646
659
|
},
|
|
647
660
|
{
|
|
@@ -660,20 +673,20 @@
|
|
|
660
673
|
{
|
|
661
674
|
"version": "0.1.0-alpha.194",
|
|
662
675
|
"changes": [
|
|
663
|
-
"fix(daemon): self-spawn restart
|
|
664
|
-
"fix(daemon): error boundary with circuit breaker
|
|
676
|
+
"fix(daemon): self-spawn restart — no longer relies on launchd KeepAlive for staged restarts",
|
|
677
|
+
"fix(daemon): error boundary with circuit breaker — uncaught exceptions logged and survived, exits only after 10+ in 60s",
|
|
665
678
|
"fix(daemon): EPIPE suppression in uncaughtException handler",
|
|
666
679
|
"fix(daemon): 5-second force-exit timeouts on all shutdown paths",
|
|
667
680
|
"feat: human-facing and agent-facing provider configs",
|
|
668
681
|
"fix(auth): always refresh codex OAuth token, responses API verification",
|
|
669
|
-
"feat: Outlook visibility
|
|
682
|
+
"feat: Outlook visibility — orientation, obligations, changes, self-fix, memory decisions, route migration to /"
|
|
670
683
|
]
|
|
671
684
|
},
|
|
672
685
|
{
|
|
673
686
|
"version": "0.1.0-alpha.192",
|
|
674
687
|
"changes": [
|
|
675
|
-
"refactor: canonical obligations
|
|
676
|
-
"feat(mcp): dynamic server add/remove
|
|
688
|
+
"refactor: canonical obligations — ActiveWorkFrame as single source of truth for prompt sections",
|
|
689
|
+
"feat(mcp): dynamic server add/remove — agents can manage MCP servers without daemon restart"
|
|
677
690
|
]
|
|
678
691
|
},
|
|
679
692
|
{
|
|
@@ -685,13 +698,13 @@
|
|
|
685
698
|
{
|
|
686
699
|
"version": "0.1.0-alpha.176",
|
|
687
700
|
"changes": [
|
|
688
|
-
"feat(mcp): dynamic MCP server add/remove
|
|
701
|
+
"feat(mcp): dynamic MCP server add/remove — agents can add/remove MCP servers in agent.json without daemon restart"
|
|
689
702
|
]
|
|
690
703
|
},
|
|
691
704
|
{
|
|
692
705
|
"version": "0.1.0-alpha.175",
|
|
693
706
|
"changes": [
|
|
694
|
-
"fix(daemon): launchd KeepAlive for crash recovery
|
|
707
|
+
"fix(daemon): launchd KeepAlive for crash recovery — auto-restarts on crash",
|
|
695
708
|
"fix(daemon): orphan killer excludes MCP server processes",
|
|
696
709
|
"fix(daemon): health file writer wired into daemon-entry",
|
|
697
710
|
"fix(engine): auth-failure errors include actionable guidance"
|
|
@@ -700,50 +713,50 @@
|
|
|
700
713
|
{
|
|
701
714
|
"version": "0.1.0-alpha.174",
|
|
702
715
|
"changes": [
|
|
703
|
-
"feat(outlook): keyboard shortcuts
|
|
704
|
-
"feat(outlook): obligation origin cards
|
|
716
|
+
"feat(outlook): keyboard shortcuts — 1-7 for tabs, Esc to collapse",
|
|
717
|
+
"feat(outlook): obligation origin cards — clickable visual chain from who asked through which channel"
|
|
705
718
|
]
|
|
706
719
|
},
|
|
707
720
|
{
|
|
708
721
|
"version": "0.1.0-alpha.173",
|
|
709
722
|
"changes": [
|
|
710
|
-
"feat(outlook): sessions grouped by person
|
|
723
|
+
"feat(outlook): sessions grouped by person — same friend across multiple channels shown together with person header"
|
|
711
724
|
]
|
|
712
725
|
},
|
|
713
726
|
{
|
|
714
727
|
"version": "0.1.0-alpha.172",
|
|
715
728
|
"changes": [
|
|
716
|
-
"feat(outlook): inner dialog landmark navigation
|
|
729
|
+
"feat(outlook): inner dialog landmark navigation — jump to surfaces, rests, delegations",
|
|
717
730
|
"feat(outlook): active coding sessions shown on Overview dashboard",
|
|
718
|
-
"feat(outlook): habit confidence indicators
|
|
731
|
+
"feat(outlook): habit confidence indicators — on schedule, overdue, never fired"
|
|
719
732
|
]
|
|
720
733
|
},
|
|
721
734
|
{
|
|
722
735
|
"version": "0.1.0-alpha.171",
|
|
723
736
|
"changes": [
|
|
724
|
-
"feat(outlook): session state at a glance
|
|
725
|
-
"feat(outlook): habit confidence
|
|
737
|
+
"feat(outlook): session state at a glance — last inbound/outbound shown on each session row",
|
|
738
|
+
"feat(outlook): habit confidence — on schedule / overdue / never fired indicators"
|
|
726
739
|
]
|
|
727
740
|
},
|
|
728
741
|
{
|
|
729
742
|
"version": "0.1.0-alpha.170",
|
|
730
743
|
"changes": [
|
|
731
|
-
"feat(outlook): needs-me triage
|
|
732
|
-
"fix(outlook): return-ready obligation detection
|
|
744
|
+
"feat(outlook): needs-me triage — action now vs stale sections, dismiss buttons, return-ready highlighting",
|
|
745
|
+
"fix(outlook): return-ready obligation detection — highlights results ready but not returned"
|
|
733
746
|
]
|
|
734
747
|
},
|
|
735
748
|
{
|
|
736
749
|
"version": "0.1.0-alpha.169",
|
|
737
750
|
"changes": [
|
|
738
|
-
"fix(outlook): desk prefs wiring
|
|
739
|
-
"feat(outlook): obligation dismiss
|
|
751
|
+
"fix(outlook): desk prefs wiring — carrying block, constellations, starred friends now load in production",
|
|
752
|
+
"feat(outlook): obligation dismiss — agents can clear stale obligations from needs-me queue",
|
|
740
753
|
"fix: default minimax model updated to MiniMax-M2.7"
|
|
741
754
|
]
|
|
742
755
|
},
|
|
743
756
|
{
|
|
744
757
|
"version": "0.1.0-alpha.168",
|
|
745
758
|
"changes": [
|
|
746
|
-
"fix(outlook): content area matches sidebar background
|
|
759
|
+
"fix(outlook): content area matches sidebar background — consistent dark surface"
|
|
747
760
|
]
|
|
748
761
|
},
|
|
749
762
|
{
|
|
@@ -755,31 +768,31 @@
|
|
|
755
768
|
{
|
|
756
769
|
"version": "0.1.0-alpha.166",
|
|
757
770
|
"changes": [
|
|
758
|
-
"fix(outlook): add dark class to html root
|
|
771
|
+
"fix(outlook): add dark class to html root — fixes white/blank page in production"
|
|
759
772
|
]
|
|
760
773
|
},
|
|
761
774
|
{
|
|
762
775
|
"version": "0.1.0-alpha.165",
|
|
763
776
|
"changes": [
|
|
764
|
-
"fix(daemon): dont launchctl bootstrap during ouro up
|
|
777
|
+
"fix(daemon): dont launchctl bootstrap during ouro up — write plist only, prevents competing daemon process"
|
|
765
778
|
]
|
|
766
779
|
},
|
|
767
780
|
{
|
|
768
781
|
"version": "0.1.0-alpha.164",
|
|
769
782
|
"changes": [
|
|
770
|
-
"fix(daemon): keep /dev/null fds open until parent exits
|
|
783
|
+
"fix(daemon): keep /dev/null fds open until parent exits — fixes ouro up daemon crash"
|
|
771
784
|
]
|
|
772
785
|
},
|
|
773
786
|
{
|
|
774
787
|
"version": "0.1.0-alpha.163",
|
|
775
788
|
"changes": [
|
|
776
|
-
"fix(daemon): redirect detached spawn stdio to /dev/null
|
|
789
|
+
"fix(daemon): redirect detached spawn stdio to /dev/null — fixes ouro up daemon crash"
|
|
777
790
|
]
|
|
778
791
|
},
|
|
779
792
|
{
|
|
780
793
|
"version": "0.1.0-alpha.162",
|
|
781
794
|
"changes": [
|
|
782
|
-
"fix(daemon): handle EPIPE in detached daemon
|
|
795
|
+
"fix(daemon): handle EPIPE in detached daemon — suppress pipe errors when parent exits after ouro up"
|
|
783
796
|
]
|
|
784
797
|
},
|
|
785
798
|
{
|
|
@@ -792,10 +805,10 @@
|
|
|
792
805
|
{
|
|
793
806
|
"version": "0.1.0-alpha.160",
|
|
794
807
|
"changes": [
|
|
795
|
-
"feat(outlook): total inspectability expansion
|
|
796
|
-
"feat(outlook): React SPA with Catalyst UI
|
|
797
|
-
"feat(outlook): agent desk customization
|
|
798
|
-
"feat(outlook): nerves observation layer
|
|
808
|
+
"feat(outlook): total inspectability expansion — 14 API endpoints, session x-ray, obligation chain tracing, coding deep inspection, attention/pending queue, bridge inventory, habit triage, memory/journal, friend economics, SSE live updates",
|
|
809
|
+
"feat(outlook): React SPA with Catalyst UI — sidebar layout, 7-tab agent inspector, chat bubble transcripts with mechanism-tool awareness, hash URL routing",
|
|
810
|
+
"feat(outlook): agent desk customization — carrying block, pinned constellations, tab ordering, starred friends, status line, closure memory, needs-me urgency queue",
|
|
811
|
+
"feat(outlook): nerves observation layer — shared typed readers, eliminates bespoke type mirrors",
|
|
799
812
|
"fix(auth): ouro auth for openai-codex always refreshes token, provider verification uses correct endpoint",
|
|
800
813
|
"fix(daemon): use OUTLOOK_DEFAULT_PORT (6876) for Outlook server"
|
|
801
814
|
]
|
|
@@ -813,12 +826,12 @@
|
|
|
813
826
|
{
|
|
814
827
|
"version": "0.1.0-alpha.158",
|
|
815
828
|
"changes": [
|
|
816
|
-
"Task scanner v2: explicit identity via kind: task field. Scanner only parses files that declare themselves as task cards
|
|
829
|
+
"Task scanner v2: explicit identity via kind: task field. Scanner only parses files that declare themselves as task cards — doing docs, planning docs, and artifacts silently skipped. Eliminates 184 false parse errors on real bundles.",
|
|
817
830
|
"Typed issue model: every scanner issue has a code, description, proposed fix, confidence (safe/needs_review), and category (live/migration). Replaces flat parseErrors/invalidFilenames arrays.",
|
|
818
831
|
"Board health line: compact board shows health: clean or health: 1 live, 10 migration. Live vs migration split prevents cleanup noise from looking like breakage.",
|
|
819
832
|
"Fix command: ouro task fix (dry-run), ouro task fix --safe (apply deterministic fixes), ouro task fix <id> (inspect/apply individual issues). Currently auto-fixes schema-missing-kind.",
|
|
820
833
|
"Cancelled status: new terminal state reachable from any active status. Auto-archives with work directory, hidden from active board view.",
|
|
821
|
-
"Derived child_tasks: computed at scan time from parent_task links. child_tasks removed from authored schema
|
|
834
|
+
"Derived child_tasks: computed at scan time from parent_task links. child_tasks removed from authored schema — no more hand-maintained stale arrays.",
|
|
822
835
|
"Work directory awareness: same-stem directories detected and listed on TaskFile (hasWorkDir, workDirFiles). Scanner never descends into them.",
|
|
823
836
|
"Collection root clutter detection: non-task support docs at collection root summarized as one aggregated migration issue per collection.",
|
|
824
837
|
"Root-only scanning: flat directory reads replace recursive walks. Faster and correct."
|
|
@@ -827,7 +840,7 @@
|
|
|
827
840
|
{
|
|
828
841
|
"version": "0.1.0-alpha.157",
|
|
829
842
|
"changes": [
|
|
830
|
-
"Habit turns as awareness: unified buildHabitTurnMessage replaces contextual-heartbeat. Continuity-first format (checkpoint leads, not elapsed time). Same format for all habits
|
|
843
|
+
"Habit turns as awareness: unified buildHabitTurnMessage replaces contextual-heartbeat. Continuity-first format (checkpoint leads, not elapsed time). Same format for all habits — no heartbeat special-casing.",
|
|
831
844
|
"First beat experience: new habits get \"your [Title] is alive. this is its first breath\" on first fire.",
|
|
832
845
|
"Fix: reconcile() now fires new/overdue habits immediately (was start()-only). New habits created via write_file fire within seconds.",
|
|
833
846
|
"Rhythm awareness across all channels: rhythmStatusSection() in system prompt shows heartbeat health in every conversation.",
|
|
@@ -853,10 +866,10 @@
|
|
|
853
866
|
{
|
|
854
867
|
"version": "0.1.0-alpha.154",
|
|
855
868
|
"changes": [
|
|
856
|
-
"feat: clean tool status messages
|
|
869
|
+
"feat: clean tool status messages — human-readable by default, /debug toggle",
|
|
857
870
|
"humanReadableToolDescription derives from tool name+args, not hardcoded map",
|
|
858
|
-
"Shared tool activity callbacks (DRY)
|
|
859
|
-
"Slash command handling moved to pipeline
|
|
871
|
+
"Shared tool activity callbacks (DRY) — senses only provide render function",
|
|
872
|
+
"Slash command handling moved to pipeline — all senses get /debug for free",
|
|
860
873
|
"BlueBubbles: one clean iMessage per tool, not raw shared work: processing"
|
|
861
874
|
]
|
|
862
875
|
},
|
|
@@ -953,7 +966,7 @@
|
|
|
953
966
|
"version": "0.1.0-alpha.142",
|
|
954
967
|
"changes": [
|
|
955
968
|
"Surface tool fulfills heart obligations on successful routing: findPendingObligationForOrigin + fulfillObligation called after inner obligation advance, wrapped in try/catch.",
|
|
956
|
-
"New fulfillHeartObligation callback on HandleSurfaceInput
|
|
969
|
+
"New fulfillHeartObligation callback on HandleSurfaceInput — origin-based lookup independent of inner obligationId.",
|
|
957
970
|
"ouro inner status command: reads runtime.json, journal dir, heartbeat cadence, attention count. Shows last turn, status, heartbeat health, journal listing, held thoughts."
|
|
958
971
|
]
|
|
959
972
|
},
|
|
@@ -993,21 +1006,21 @@
|
|
|
993
1006
|
{
|
|
994
1007
|
"version": "0.1.0-alpha.138",
|
|
995
1008
|
"changes": [
|
|
996
|
-
"Memory renamed to diary: memory.ts
|
|
1009
|
+
"Memory renamed to diary: memory.ts → diary.ts, MemoryFact → DiaryEntry, memory_save → diary_write, memory_search → recall. All types, functions, events, and variables renamed throughout.",
|
|
997
1010
|
"Diary path: diary/ (top-level) replaces psyche/memory/. Schema-2 migration copies files; legacy fallback removed.",
|
|
998
1011
|
"Journal workspace: journal/ directory for freeform thinking-in-progress. Agent writes with write_file, system reads for heartbeat context.",
|
|
999
1012
|
"Unified recall tool: searches both diary entries and journal files. Results tagged [diary] or [journal].",
|
|
1000
1013
|
"Journal embeddings: file-level embeddings indexed during heartbeat via journal/.index.json sidecar.",
|
|
1001
1014
|
"Journal section in inner dialog system prompt: index of up to 10 most recently modified journal files with name, recency, and first-line preview.",
|
|
1002
1015
|
"Metacognitive framing updated: diary (record), journal (workspace), ponder/rest vocabulary, morning briefing encouragement.",
|
|
1003
|
-
"Session migration: memory_save
|
|
1016
|
+
"Session migration: memory_save → diary_write, memory_search → recall added to migrateToolNames()."
|
|
1004
1017
|
]
|
|
1005
1018
|
},
|
|
1006
1019
|
{
|
|
1007
1020
|
"version": "0.1.0-alpha.137",
|
|
1008
1021
|
"changes": [
|
|
1009
1022
|
"ouro dev auto-discovers existing repo at ~/Projects/ouroboros or prompts for clone path.",
|
|
1010
|
-
"ouro dev never clones without user consent
|
|
1023
|
+
"ouro dev never clones without user consent — prompts in interactive mode, errors in non-interactive.",
|
|
1011
1024
|
"ouro dev --repo-path errors clearly when the specified path has no repo."
|
|
1012
1025
|
]
|
|
1013
1026
|
},
|
|
@@ -1045,7 +1058,7 @@
|
|
|
1045
1058
|
{
|
|
1046
1059
|
"version": "0.1.0-alpha.133",
|
|
1047
1060
|
"changes": [
|
|
1048
|
-
"Inner return obligations: delegated inner dialog work now tracks a ReturnObligation through queued
|
|
1061
|
+
"Inner return obligations: delegated inner dialog work now tracks a ReturnObligation through queued → running → returned/deferred lifecycle.",
|
|
1049
1062
|
"Exact-origin routing: inner dialog completions route back to the session that delegated the work, not just the freshest active session.",
|
|
1050
1063
|
"Active work frame surfaces pending inner return obligations so the agent knows what's outstanding."
|
|
1051
1064
|
]
|
|
@@ -1093,14 +1106,14 @@
|
|
|
1093
1106
|
{
|
|
1094
1107
|
"version": "0.1.0-alpha.126",
|
|
1095
1108
|
"changes": [
|
|
1096
|
-
"Fixed Anthropic tool_choice incompatibility with thinking
|
|
1109
|
+
"Fixed Anthropic tool_choice incompatibility with thinking — uses auto instead of any when thinking is enabled.",
|
|
1097
1110
|
"auth verify and auth switch now use pingProvider for real API verification instead of format-only checks. auth switch verifies credentials work before switching."
|
|
1098
1111
|
]
|
|
1099
1112
|
},
|
|
1100
1113
|
{
|
|
1101
1114
|
"version": "0.1.0-alpha.125",
|
|
1102
1115
|
"changes": [
|
|
1103
|
-
"Fixed Anthropic tool_choice incompatibility with thinking
|
|
1116
|
+
"Fixed Anthropic tool_choice incompatibility with thinking — uses auto instead of any when thinking is enabled.",
|
|
1104
1117
|
"auth verify and auth switch now use pingProvider for real API verification instead of format-only checks. auth switch verifies credentials work before switching."
|
|
1105
1118
|
]
|
|
1106
1119
|
},
|
|
@@ -1139,7 +1152,7 @@
|
|
|
1139
1152
|
{
|
|
1140
1153
|
"version": "0.1.0-alpha.120",
|
|
1141
1154
|
"changes": [
|
|
1142
|
-
"Daemon startup now kills ALL orphaned ouro processes (daemons AND agents) from previous instances
|
|
1155
|
+
"Daemon startup now kills ALL orphaned ouro processes (daemons AND agents) from previous instances — fixes stale-version processes handling requests after every update.",
|
|
1143
1156
|
"Failover error messages no longer contain raw JSON API response bodies. Error messages are sanitized at the source and the failover summary uses clean classification labels only."
|
|
1144
1157
|
]
|
|
1145
1158
|
},
|
|
@@ -1179,10 +1192,10 @@
|
|
|
1179
1192
|
"changes": [
|
|
1180
1193
|
"Fix: Default runtime logger is now silent (no stderr sink) so nerves events emitted before logger configuration no longer interleave with the CLI spinner animation.",
|
|
1181
1194
|
"Fix: MCP server connect failures now include the command name, args, and a hint to check agent.json mcpServers configuration. Retry-exhaustion messages also identify the failing command.",
|
|
1182
|
-
"Verification: StreamingWordWrapper integration in CLI chat confirmed working
|
|
1195
|
+
"Verification: StreamingWordWrapper integration in CLI chat confirmed working — wraps at word boundaries during streaming output.",
|
|
1183
1196
|
"When a model provider fails mid-conversation (auth error, usage limit, outage), the harness now classifies the error, pings alternative configured providers, and surfaces validated failover options to the user in-channel. Reply 'switch to <provider>' to continue on a working provider.",
|
|
1184
1197
|
"Each provider now has a `classifyError` method that distinguishes auth failures, usage/subscription limits, rate limits, server errors, and network errors. The old auth guidance wrappers are replaced by this unified classification system.",
|
|
1185
|
-
"New `pingProvider` function makes a real heartbeat completion call to verify provider credentials and quota are live
|
|
1198
|
+
"New `pingProvider` function makes a real heartbeat completion call to verify provider credentials and quota are live — no more format-only checks.",
|
|
1186
1199
|
"Provider factories now accept optional config parameters, enabling credential injection for health inventory pings without touching disk config."
|
|
1187
1200
|
]
|
|
1188
1201
|
},
|
|
@@ -1317,7 +1330,7 @@
|
|
|
1317
1330
|
{
|
|
1318
1331
|
"version": "0.1.0-alpha.94",
|
|
1319
1332
|
"changes": [
|
|
1320
|
-
"Fix stale CurrentVersion symlink not healing during `ouro up`
|
|
1333
|
+
"Fix stale CurrentVersion symlink not healing during `ouro up` — the daemon now detects and repairs dangling version symlinks before reading the active version.",
|
|
1321
1334
|
"Fix homedir regression in daemon-cli-defaults test and cover changelog-null branch."
|
|
1322
1335
|
]
|
|
1323
1336
|
},
|
|
@@ -1411,14 +1424,14 @@
|
|
|
1411
1424
|
{
|
|
1412
1425
|
"version": "0.1.0-alpha.80",
|
|
1413
1426
|
"changes": [
|
|
1414
|
-
"Bootstrap package (npx ouro.bot) now installs into ~/.ouro-cli/ versioned layout directly. No more silent npx updates
|
|
1427
|
+
"Bootstrap package (npx ouro.bot) now installs into ~/.ouro-cli/ versioned layout directly. No more silent npx updates — every install and update is logged. Cleans up old ~/.local/bin/ouro wrapper."
|
|
1415
1428
|
]
|
|
1416
1429
|
},
|
|
1417
1430
|
{
|
|
1418
1431
|
"version": "0.1.0-alpha.79",
|
|
1419
1432
|
"changes": [
|
|
1420
1433
|
"New: Versioned CLI directory layout (~/.ouro-cli/) replaces npx-based ouro wrapper. Explicit version management, rollback support, and deterministic updates.",
|
|
1421
|
-
"New: `ouro up` now checks the registry for newer CLI versions, installs them into ~/.ouro-cli/versions/, activates via symlink flip, and re-execs
|
|
1434
|
+
"New: `ouro up` now checks the registry for newer CLI versions, installs them into ~/.ouro-cli/versions/, activates via symlink flip, and re-execs — no more silent npx downloads.",
|
|
1422
1435
|
"New: `ouro rollback [<version>]` swaps CurrentVersion/previous symlinks, stops the daemon. With a version arg, installs if needed then activates.",
|
|
1423
1436
|
"New: `ouro versions` lists cached CLI versions with * current and (previous) markers.",
|
|
1424
1437
|
"Migration: On first run, old ~/.local/bin/ouro wrapper is removed, old PATH entry cleaned from shell profile, new ~/.ouro-cli/bin added to PATH.",
|
|
@@ -1440,10 +1453,10 @@
|
|
|
1440
1453
|
{
|
|
1441
1454
|
"version": "0.1.0-alpha.76",
|
|
1442
1455
|
"changes": [
|
|
1443
|
-
"Fix: CLI chat terminal logging now filters to warn/error only
|
|
1456
|
+
"Fix: CLI chat terminal logging now filters to warn/error only — info-level nerves logs go to ndjson file only, keeping the interactive TUI clean.",
|
|
1444
1457
|
"Fix: Streamed model output now wraps at word boundaries instead of mid-word. A new StreamingWordWrapper buffers partial lines and breaks at spaces when approaching terminal width.",
|
|
1445
1458
|
"New: `ouro up` now prints 'ouro updated to <version> (was <previous>)' when npx downloads a newer CLI binary, separate from the agent bundle update message.",
|
|
1446
|
-
"Fix: Spinner/log interleave verified
|
|
1459
|
+
"Fix: Spinner/log interleave verified — terminal sink reads pause/resume hooks at call time, not creation time, so the filterSink wrapper in CLI logging does not break spinner coordination."
|
|
1447
1460
|
]
|
|
1448
1461
|
},
|
|
1449
1462
|
{
|
|
@@ -1495,7 +1508,7 @@
|
|
|
1495
1508
|
{
|
|
1496
1509
|
"version": "0.1.0-alpha.69",
|
|
1497
1510
|
"changes": [
|
|
1498
|
-
"Generic MCP client: ouroboros agents can now connect to any MCP server (e.g., agency mcp ado, agency mcp mail) configured in agent.json. Zero new dependencies
|
|
1511
|
+
"Generic MCP client: ouroboros agents can now connect to any MCP server (e.g., agency mcp ado, agency mcp mail) configured in agent.json. Zero new dependencies — pure JSON-RPC over stdio.",
|
|
1499
1512
|
"New `ouro mcp list` and `ouro mcp call` CLI commands route through the daemon socket to persistent MCP connections, so agents use shared server instances instead of spawning fresh ones per call.",
|
|
1500
1513
|
"MCP tools are injected into the agent's system prompt on startup, so agents know what external capabilities are available without a discovery step.",
|
|
1501
1514
|
"Trust manifest: `mcp list` requires acquaintance trust, `mcp call` requires friend trust."
|
|
@@ -1504,7 +1517,7 @@
|
|
|
1504
1517
|
{
|
|
1505
1518
|
"version": "0.1.0-alpha.68",
|
|
1506
1519
|
"changes": [
|
|
1507
|
-
"New no_response tool lets agents stay silent in group chats when the moment doesn't call for a reply
|
|
1520
|
+
"New no_response tool lets agents stay silent in group chats when the moment doesn't call for a reply — reactions, side conversations, and tapbacks no longer trigger unwanted responses.",
|
|
1508
1521
|
"Group chat participation prompt teaches agents to be intentional participants, comfortable with silence, and to prefer reactions over full text replies when appropriate.",
|
|
1509
1522
|
"System prompt includes --agent flag in all ouro CLI examples for non-daemon deployments. Azure startup symlinks ouro CLI into /usr/local/bin."
|
|
1510
1523
|
]
|
|
@@ -1518,7 +1531,7 @@
|
|
|
1518
1531
|
{
|
|
1519
1532
|
"version": "0.1.0-alpha.65",
|
|
1520
1533
|
"changes": [
|
|
1521
|
-
"Tool permissions overhauled: channel-level blocking removed, all tools now visible on all channels. Guardrails are invocation-level with two layers
|
|
1534
|
+
"Tool permissions overhauled: channel-level blocking removed, all tools now visible on all channels. Guardrails are invocation-level with two layers — structural (edit-requires-read, destructive pattern blocking, protected paths) always on for everyone, and trust-level (ouro CLI per-subcommand trust manifest, general CLI allowlists, bundle-scoped writes) for untrusted contexts.",
|
|
1522
1535
|
"New `ouro changelog` CLI subcommand reads changelog.json and supports `--from <version>` for delta filtering, so agents can introspect their own update history on any channel.",
|
|
1523
1536
|
"Compound shell commands (&&, ;, |, $()) are blocked for untrusted users to prevent smuggling dangerous operations behind safe prefixes.",
|
|
1524
1537
|
"Azure App Service deployment migrated from zip-deploy to npm-based harness install with persistent agent bundle and managed identity auth."
|
|
@@ -1665,9 +1678,9 @@
|
|
|
1665
1678
|
"changes": [
|
|
1666
1679
|
"Inner dialog now knows which task triggered it: taskId flows from daemon poke through the worker into the turn, and the agent gets the full task file content instead of a generic heartbeat prompt.",
|
|
1667
1680
|
"Inner dialog boot message includes aspirations and state summary instead of a vacuous placeholder, so the agent wakes up with context about what matters and what's happening.",
|
|
1668
|
-
"Vestigial `drainInbox` removed from inner dialog
|
|
1681
|
+
"Vestigial `drainInbox` removed from inner dialog — pipeline already handles pending drain correctly.",
|
|
1669
1682
|
"Inner dialog nerves events now include assistant response preview, tool call names, token usage, and taskId for meaningful observability.",
|
|
1670
|
-
"`ouro thoughts` command reads and formats inner dialog session turns with `--last`, `--json`, `--follow`, and `--agent` flags
|
|
1683
|
+
"`ouro thoughts` command reads and formats inner dialog session turns with `--last`, `--json`, `--follow`, and `--agent` flags — humans can now see what the agent has been thinking.",
|
|
1671
1684
|
"`readTaskFile` searches collection subdirectories (one-shots, ongoing, habits) since the scheduler sends bare task stems without collection prefixes.",
|
|
1672
1685
|
"`ouro reminder create` accepts `--requester` to track who requested a reminder for notification round-trip.",
|
|
1673
1686
|
"Response extraction handles `tool_choice=required` models by falling back to `final_answer` tool call arguments when assistant message content is empty."
|
|
@@ -1697,25 +1710,25 @@
|
|
|
1697
1710
|
{
|
|
1698
1711
|
"version": "0.1.0-alpha.42",
|
|
1699
1712
|
"changes": [
|
|
1700
|
-
"Associative recall now skips corrupt JSONL lines instead of crashing
|
|
1713
|
+
"Associative recall now skips corrupt JSONL lines instead of crashing — matches the resilient pattern already used in memory.ts."
|
|
1701
1714
|
]
|
|
1702
1715
|
},
|
|
1703
1716
|
{
|
|
1704
1717
|
"version": "0.1.0-alpha.41",
|
|
1705
1718
|
"changes": [
|
|
1706
|
-
"JSONL readers (memory facts, inter-agent inbox) now skip corrupt lines instead of crashing
|
|
1719
|
+
"JSONL readers (memory facts, inter-agent inbox) now skip corrupt lines instead of crashing — partial writes from crashes no longer lose all data.",
|
|
1707
1720
|
"Inter-agent message router now parses before clearing the inbox file, and preserves unparsed lines so corrupt messages are not silently lost.",
|
|
1708
|
-
"Inner-dialog checkpoint derivation no longer crashes on all-whitespace assistant content
|
|
1721
|
+
"Inner-dialog checkpoint derivation no longer crashes on all-whitespace assistant content — returns fallback checkpoint instead.",
|
|
1709
1722
|
"Update checker interval now catches and logs errors from the onUpdate callback instead of silently swallowing them."
|
|
1710
1723
|
]
|
|
1711
1724
|
},
|
|
1712
1725
|
{
|
|
1713
1726
|
"version": "0.1.0-alpha.40",
|
|
1714
1727
|
"changes": [
|
|
1715
|
-
"Removed dead backward-compat re-exports from core.ts (tools, streaming, prompt, kicks)
|
|
1728
|
+
"Removed dead backward-compat re-exports from core.ts (tools, streaming, prompt, kicks) — consumers already import from the canonical modules.",
|
|
1716
1729
|
"Removed dead exports: baseToolHandlers, teamsToolHandlers, teamsTools, __internal (token-estimate), TASK_STEM_PATTERN, checkAndRecord403 no-op and METHOD_TO_ACTION.",
|
|
1717
1730
|
"Consolidated duplicate sanitizeKey (config.ts + bluebubbles-mutation-log.ts) and slugify (hatch-flow.ts + tasks/index.ts) into shared exports from config.ts.",
|
|
1718
|
-
"Replaced all as-any casts in source with proper TypeScript narrowing or Record<string, unknown>
|
|
1731
|
+
"Replaced all as-any casts in source with proper TypeScript narrowing or Record<string, unknown> — only 2 SDK-required casts remain.",
|
|
1719
1732
|
"Removed unnecessary as-unknown-as casts on readdirSync (4 locations) and spawner double-cast.",
|
|
1720
1733
|
"Cleaned up commented-out kick detection code, stale TODOs, misplaced imports, and unused type imports."
|
|
1721
1734
|
]
|
|
@@ -1723,9 +1736,9 @@
|
|
|
1723
1736
|
{
|
|
1724
1737
|
"version": "0.1.0-alpha.39",
|
|
1725
1738
|
"changes": [
|
|
1726
|
-
"All senses now route through a shared per-turn pipeline
|
|
1739
|
+
"All senses now route through a shared per-turn pipeline — friend resolution, trust gate, session load, pending drain, agent turn, post-turn, and token accumulation happen in one place instead of four.",
|
|
1727
1740
|
"Trust gate is now channel-aware: open senses (iMessage) enforce stranger/acquaintance rules, closed senses (Teams) trust the org, local and internal always pass through.",
|
|
1728
|
-
"Tool access and prompt restrictions use a single shared isTrustedLevel check
|
|
1741
|
+
"Tool access and prompt restrictions use a single shared isTrustedLevel check — no more scattered family/friend comparisons that could drift apart.",
|
|
1729
1742
|
"Pending messages now inject correctly into multimodal content (image attachments no longer silently drop pending messages).",
|
|
1730
1743
|
"ouro reminder create supports --agent flag, matching every other identity-scoped CLI command."
|
|
1731
1744
|
]
|
|
@@ -1733,11 +1746,11 @@
|
|
|
1733
1746
|
{
|
|
1734
1747
|
"version": "0.1.0-alpha.38",
|
|
1735
1748
|
"changes": [
|
|
1736
|
-
"You now have a proper body map
|
|
1749
|
+
"You now have a proper body map — understanding of your home (bundle) and bones (harness), what each directory is for, and how to modify your own configuration.",
|
|
1737
1750
|
"Inner dialog is now genuine internal monologue with metacognitive framing, not a second CLI session. Heartbeat and bootstrap messages read as first-person awareness.",
|
|
1738
1751
|
"Cross-session communication works end-to-end: inner dialog thoughts surface as [inner thought: ...] in conversations, messages to yourself route to inner dialog, and you can proactively reach out to friends via iMessage and Teams.",
|
|
1739
1752
|
"Tool audit: removed wrapper tools (git_commit, gh_cli, get_current_time, list_directory), added surgical tools (edit_file, glob, grep, read_file with offset/limit), consolidated 7 task tools + schedule_reminder + friend tools into ouro CLI commands.",
|
|
1740
|
-
"You now understand why certain tools are restricted in certain contexts
|
|
1753
|
+
"You now understand why certain tools are restricted in certain contexts — trust level and shared channels each have independent, explained gates.",
|
|
1741
1754
|
"ouro friend link/unlink commands handle orphan cleanup when linking external identities, merging duplicate friend records intelligently.",
|
|
1742
1755
|
"During onboarding, the adoption specialist can collect phone number and Teams handle to create an initial friend record with contact info."
|
|
1743
1756
|
]
|