Skip to content

Tags: RoseAgent/ProjectRose

Tags

v1.9.4-build.68

Toggle v1.9.4-build.68's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Refactor/architecture (#75)

* Split llmClient god-module into focused modules

llmClient.ts had grown to 1137 lines mixing five unrelated concerns.
Extract three of them, leaving llmClient.ts owning only the streaming loop:

- modelResolution.ts  — resolveModel + projectrose SSE-patch fetch
- coreTools.ts        — buildCoreTools (the 445-line tool catalog)
- contextCompression.ts — compressTurnsForContext + turn-splitting helpers

Pure move: all four function bodies are byte-identical to the originals;
importers (index.ts, aiService.ts) repointed at the new modules. No cycle —
buildCoreTools is still injected via toolRegistry.registerCoreTools.

typecheck clean; 251 unit tests pass; app builds and boots.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Extract calendar invite-and-merge into a shared service

The "read event → verify Google-synced → send invite → merge attendees
locally" sequence was duplicated in two layers: the agent tool handler
(handleCalendarInviteToEvent) and the renderer IPC handler (inviteToEvent),
which also meant business logic lived inline in the IPC registration block.

Move it to a single leaf service, memory/calendarInvite.ts, returning a
discriminated EventInviteOutcome so each caller keeps its own presentation
(the tool returns prefixed strings; the IPC returns GoogleApplyResult) with
zero change to either's user-facing messages. Lives in its own module rather
than calendar.ts to avoid a cycle (googleCalendar.ts already imports calendar).

typecheck clean; 251 unit tests pass; all three bundles build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add characterization tests for routine/channel-rule field parsers

These two on-disk markdown parsers had no test coverage. Lock their current
parse/build/round-trip behavior (tools inline + sub-list, unknown-bullet
preservation, boolean variants, RRULE normalization, source coercion, section
ordering, slugify) before extracting their shared scaffolding.

19 tests, all green against current code.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Extract shared rule-document scaffolding for routine/channel parsers

routineFields.ts and channelRuleFields.ts implemented the same on-disk
markdown skeleton twice — line-walking, the tools inline/sub-list state
machine, unknown-bullet preservation, the ## section walk, the builder tail,
parseBoolean, and slugify were byte-near-identical (the channel parser's
header even reads "Mirrors routineFields.ts"). A parse fix had to be applied
in both, inviting silent divergence.

Move the skeleton to shared/ruleDocument.ts (parseRuleDocument /
buildRuleDocument / parseBoolean / slugify). Each parser now only maps the
generic labeled bullets to its typed fields and supplies its ordered metadata
bullets on build, keeping its domain-specific coercion (RRULE normalization,
source enum). routineFields 250->151, channelRuleFields 234->135.

Behavior preserved: the 19 characterization tests added in the prior commit
stay green. typecheck clean; 270 tests pass; all three bundles build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add agent tools for managing routines from chat; bump to 1.9.4

rose-routines now registers eight routines_* extension tools (list, read,
create, update, delete, run_now, list_runs, read_run) following the
rose-channels pattern: declared in both manifests, registered via
ctx.registerTools() so the strict catalog reconciliation holds. Writes go
through saveRoutine/deleteRoutine so every change reschedules the timer
and broadcasts routines:changed like a UI edit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix path traversal in routines tools; restore calendar invite error precedence

Review fixes from /code-review:
- Reject slugs/filenames with separators or dot segments at the
  rose-routines path-building chokepoints, closing arbitrary
  read/overwrite/delete via agent-supplied ../ values
- Validate run filenames end in .md and surface bad-slug errors
  instead of swallowing them in try/catch
- Check no-event/not-synced before empty attendees in the shared
  invite service so the agent sees the real blocker first
- Clear a routine's schedule on empty recurrence instead of writing
  the malformed rule "RRULE:"
- Share normaliseRrule from routineFields instead of mirroring it
- Move the duplicate-slug guard into createRoutine so every caller
  is protected, not just the agent tool

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

v1.9.3-build.67

Toggle v1.9.3-build.67's commit message
Pin Windows release runner to windows-2022 (VS2026 breaks node-gyp)

GitHub migrated windows-latest to the windows-2025/VS2026 image. The bundled
node-gyp 9.4.1 only detects VS 2017/2019/2022, so it fails with "Could not find
any Visual Studio installation" when rebuilding native node-pty during
packaging. Pin to windows-2022 (VS 2022) to restore the working toolchain.

Also set fail-fast: false so one platform's failure no longer cancels the
others, giving the full per-OS signal on every run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

v1.9.3-build.66

Toggle v1.9.3-build.66's commit message
Add missing rose-channels, detached-run-transcript, and email-sync-lo…

…op sources

The previous commit (8e1265f) imported these new modules but never staged the
files, breaking CI typecheck/tests and the release build with ERR_MODULE_NOT_FOUND.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

v1.9.2-build.64

Toggle v1.9.2-build.64's commit message
Update release notes

v1.9.1-build.63

Toggle v1.9.1-build.63's commit message
Remove playwrite tests (They have become to dated

v1.9.0-build.62

Toggle v1.9.0-build.62's commit message
Fix CI failing

v1.5.2-build.58

Toggle v1.5.2-build.58's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
[PRD] ipc-pass-through (#74)

* Introduce typed IPC manifest and migrate chat sessions (#39)

Add defineIpc(namespace, methods) which produces a register() function
that wires ipcMain.handle for each method, a typed bindings object that
wraps ipcRenderer.invoke, and inferred types for both sides. Channel
strings are derived as namespace:method so the wire format is unchanged.

Migrate the chat sessions namespace as the tracer slice: the four
SESSION_* enum entries, sessionHandlers.ts, and the verbose preload
session block are all replaced by a single sessionService.ipc.ts
sibling and a registerIpcManifests() switchboard that coexists with
the existing registerAllHandlers().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate prompts to the typed IPC manifest (#40)

Move the prompt logic from src/main/ipc/promptHandlers.ts into a new
promptService.ts and declare the six request methods through a sibling
promptService.ipc.ts. agentMd repoints loadExtensionPrompts to the
service module; the six PROMPTS_* enum entries are removed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate skills list/delete to the IPC manifest, keep upload (#41)

skills.list and skills.delete move to a skillService.ipc.ts sibling
and a new deleteSkill() service function. SKILLS_UPLOAD stays as a
hand-written handler because it opens a file dialog anchored to the
calling BrowserWindow. preload spreads the manifest bindings and adds
upload on top — that merge pattern is the template later mixed
namespaces (extensions, auth) will copy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate files namespace to the IPC manifest (#42)

The eight FILE_* channels become fileService.ipc.ts. preload re-wraps
the manifest bindings into the existing flat api.readFile / writeFile /
... surface so renderer call sites are unchanged. fileHandlers.ts is
deleted and the FILE_* enum entries are gone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate recent projects to the IPC manifest, isolate APP_QUIT (#43)

The four PROJECTS_* handlers move to recentProjects.ipc.ts. The
inline `app.getPath('home')` for the default path is factored into
recentProjects.getDefaultProjectPath(). APP_QUIT becomes a one-method
appHandlers.ts — the manifest is for service surfaces, not Electron
singleton wrappers. projectHandlers.ts is deleted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate settings to a service module and IPC manifest (#44)

settingsHandlers moves to services/settingsService.ts (its business
logic — readSettings, writeSettings, sensitive-field tracking — never
belonged in src/main/ipc). Two manifests are declared: `settings.get/set`
and a single-method `health.checkAll`. Every caller of the old
ipc/settingsHandlers path is repointed to the service location.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate project settings and tools list to the IPC manifest (#45)

projectSettingsHandlers moves to services/projectSettingsService.ts.
Two manifests are declared: `project.getSettings/setSettings` and a
single-method `tools.list` that wraps the core+extension merge. The
three hard-coded channel strings ('project:getSettings',
'project:setSettings', 'tools:list') disappear — namespaces derive
them now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Extract rose setup service and migrate to the IPC manifest (#46)

roseSetupHandlers becomes services/roseSetupService.ts with named
exports checkRoseMd, initRoseProject, ensureRoseScaffold and the
personality constants / buildRoseMd helper. The three ROSE_* enum
entries are replaced by a `rose` namespace manifest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate whisper transcription to the IPC manifest (#47)

The whisper handler body — read settings, set model, transcribe —
becomes whisperService.transcribeAudio. A single-method `whisper`
manifest wraps it. The vestigial saveChatRecording stub is dropped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate updater request channels to the IPC manifest (#48)

The four request channels (check, download, install, skipVersion)
move to updaterService.ipc.ts. The five event-broadcast channels stay
as IPC enum entries because they're emitted via webContents.send and
the manifest covers ipcRenderer.invoke round-trips only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate auth request channels to the IPC manifest (#49)

The five AUTH_* request handlers move to a new authService.ipc.ts;
the underlying auth code is also relocated from main/lib/authHandler
to main/services/authService for consistency. The login handler's
error-rewrap wrapper survives as loginViaAuthWindow(). AUTH_CHANGED
and AUTH_PAIRING_PENDING stay as event-broadcast enum entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate AI request channels to the IPC manifest (#50)

The seven AI_* request channels (chat, contextStatus, compressToolNoise,
getSystemPrompt, cancel, askUserResponse, captureScreenshotResult)
move to services/aiService.ipc.ts. preload re-wraps positional renderer
signatures into the manifest's payload-style bindings so the api shape
stays unchanged. The ten event-broadcast AI_* entries remain in the
IPC enum.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate active speech to the IPC manifest (#51)

The 11 ACTIVE_LISTENING_* invoke channels move to a new
activeSpeechService manifest. The training orchestration (with its
jobPhases map and async setImmediate flow) is factored into
startTrainingJob(). The trimmed activeSpeechHandlers.ts keeps just the
two fire-and-forget ipcMain.on registrations (SEND_CHUNK, CANCEL_DRAFT)
and the one-time speaker-cache init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Migrate extensions to the IPC manifest (#52)

extensionHandlers.ts (730 lines) becomes services/extensionService.ts.
Every previously-inline handler body is factored into a named export
(listExtensions, installFromGit, installFromDisk,
installPreviewFromGit/Disk, installConfirm/Cancel, uninstallExtension,
enableExtension, disableExtension, loadRendererCode, loadMainModule).
The 12 EXTENSION_* enum entries and the dedicated handler file are gone;
the sibling extensionService.ipc.ts declares the namespace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Document the IPC channel policy after the manifest migration (#53)

Add a header to ipcChannels.ts spelling out what belongs in the enum
(event broadcasts and kept-back hand-written handlers) and what does
not (service request/response channels — those are derived from
defineIpc manifests). Tighten the comments on the two register
functions in main/ipc/index.ts now that the migration coexistence is
done.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Repoint chatSessionRun.test.ts mocks at the new service modules

The three vi.mock() calls still pointed at ../../ipc/settingsHandlers,
projectSettingsHandlers, and extensionHandlers — the files that the
manifest migration moved to ../settingsService, ../projectSettingsService,
and ../extensionService. On Linux CI the stale mocks didn't apply, so
listInstalledExtensions ran for real and tried to mkdir /proj. Locally
on Windows the same call succeeded against C:\proj, hiding the issue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v1.5.2-build.57

Toggle v1.5.2-build.57's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Stop the LSP from crashing the app on Finder-launched macOS (#73)

The "tons of pop up errors" reported after the previous Mac PR all
trace back to `spawn node ENOENT` from the LSP manager. When a macOS
`.app` is launched from Finder (or any GUI), the OS hands it a minimal
PATH of `/usr/bin:/bin:/usr/sbin:/sbin` — none of /opt/homebrew/bin,
/usr/local/bin, NVM dirs, etc. So `spawn('node', ...)` fails for every
user whose node lives there (i.e. most of them). The async ENOENT from
spawn had no `'error'` listener either, so it bubbled up as an
uncaughtException → Electron's default modal-dialog popup, twice (py +
ts servers).

Three fixes plus a safety net:

1. `lspManager.ts`: stop relying on a system `node`. Use
   `process.execPath` with `ELECTRON_RUN_AS_NODE=1` so the LSP scripts
   run under Electron's bundled Node — the same pattern VS Code uses.
   Also add a `proc.on('error')` listener so future spawn failures log
   instead of crashing.

2. New `src/main/lib/childProcessEnv.ts` — small helper that prepends
   the usual Mac install locations (homebrew, ~/.bun, ~/.cargo,
   ~/.local/bin, ~/.volta) to PATH for child processes. Used by:
   - `extensionHandlers.runCommand` (extension installer's `npm install`
     was also broken — `npm` isn't on the launchd PATH).
   - `toolHandlers.handleRunCommand` (AI-invoked shell commands need
     to be able to find user-installed tools).

3. `index.ts`: register `process.on('uncaughtException')` and
   `process.on('unhandledRejection')` handlers that log via
   electron-log instead of letting Electron pop a modal dialog. Future
   surprises don't get to spam the user with un-dismissable popups.

4. `extensionHandlers.runCommand`: include a clearer "X is not on PATH"
   hint in the ENOENT branch so users can self-diagnose missing
   binaries instead of seeing a raw stack trace.

Verified by running the packaged app binary with
`env -i PATH=/usr/bin:/bin:/usr/sbin:/sbin` (faithfully reproducing
what `launchd` hands a Finder-launched app). Before this commit: two
"Uncaught Exception" modal dialogs and no LSP. After: both pyright and
typescript-language-server spawn cleanly as Electron-as-node children,
tsserver subprocesses launch under them, no popups, no errors in the
log beyond the existing `[updater] skipping autoUpdater: dev mode`
info line.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v1.5.2-build.56

Toggle v1.5.2-build.56's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Make the unsigned macOS build launchable (#72)

The DMG produced by the release workflow was effectively unusable on
modern macOS: Gatekeeper blocks the unsigned `.app`, the menu bar reads
"Electron" instead of "ProjectRose", the window icon is broken, the
`projectrose://` scheme never reaches the renderer, and only an arm64
artifact is uploaded. None of this needs a Developer ID to fix — these
are bugs in how the app and the build are configured for Darwin.

Changes:

- window.ts: pick `icon.png` on Mac/Linux instead of the Windows `.ico`;
  switch to `titleBarStyle: 'hiddenInset'` on Mac (the existing `hidden`
  + `titleBarOverlay` config clips the native traffic lights) and guard
  the theme:changed overlay refresh.
- menu.ts: prepend `{ role: 'appMenu' }` on Mac so the menu bar shows
  the product name with the canonical About/Hide/Quit slots; move Quit
  off the File menu where the app menu owns it; add the standard
  Window submenu.
- index.ts: register `app.on('open-url')` so projectrose:// links
  delivered to a running app reach the renderer; call
  `setAsDefaultProtocolClient('projectrose')` for dev mode.
- tray.ts: resize the 1024x1024 source to 22x22 and mark it a template
  image so the menu-bar icon adapts to light/dark mode.
- ipcChannels.ts: add DEEPLINK_RECEIVED for the open-url payload.
- package.json `build.mac`: target both arm64 and x64 DMGs (Intel users
  got nothing before); switch icon to `.icns`; add Info.plist entries
  for the URL scheme and the mic/camera usage descriptions (without the
  usage strings the first mic prompt crashes the process).
- release.yml: generate `build/icon.icns` via `iconutil` on the Mac
  runner and upload both DMG artifacts.
- README.md: document the one-time `xattr -dr com.apple.quarantine`
  step users need until a Developer ID is in place.

Auto-updater is already correctly disabled on Darwin
(updaterService.ts:45). Signing/notarization stays out of scope until
an Apple Developer ID exists — the new `build.mac` block leaves
`identity`/`hardenedRuntime`/`notarize` unset, which makes
electron-builder skip signing entirely.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

v1.5.2-build.55

Toggle v1.5.2-build.55's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
[PRD] chat-turn-unification (#71)

* chat-turn-unification: forward sessionId on streaming events (#2)

* chat-turn-unification: route AI_CANCEL by sessionId (#3)

* chat-turn-unification: ChatSession.run owns the chat loop (#4)

* chat-turn-unification: one-shot role on ChatSession; main vs subagent parity (#5)

* chat-turn-unification: useChat slice mirrors the four legacy stores (#6)

* chat-turn-unification: migrate chat input and timeline consumers to useChat (#7)

* chat-turn-unification: migrate sessions and compression consumers to useChat (#8)

* chat-turn-unification: fold empty response and defer into useChat settle (#9)

* chat-turn-unification: delete legacy renderer modules; useChat owns all state (#10)

* chat-turn-unification: multi-session concurrency smoke test (#11)