Commit graph

738 commits

Author SHA1 Message Date
Nexus Dev
22e14545d4 fix(nexus): extend tilde expansion and mkdir to all user path endpoints
Follow-up to commit 91530b07 which only covered agents.adapter_config
.cwd. An audit found three additional user-facing endpoints that
accept filesystem paths without normalization. Same zero-terminal bug
in each: user supplies "~/foo", server stores it raw, downstream
consumers can't resolve the tilde.

Extract the two helpers (expandUserPath, normalizeWorkspaceDir) from
the agents.ts closure into a shared utility so all endpoints use the
same primitive.

new: server/src/utils/path-normalization.ts
  - expandUserPath(candidate): resolves ~ / ~/foo to homedir() and
    path.resolve() to absolute. Null-safe on non-string input.
  - normalizeWorkspaceDir(rawPath, { field }): expand + assert
    absolute + mkdir -p + stat isDirectory + log the change.
    Throws unprocessable (422) on any filesystem failure with a
    field-aware error message.

changed: server/src/routes/agents.ts
  - Replaced the inline expandUserPath + normalizeAdapterConfigPaths
    helpers with a narrow wrapper that delegates to the shared utility.
    Three call sites (create, hire, patch) unchanged in behavior.
  - Removed now-unused imports: mkdir, stat, homedir.

changed: server/src/routes/projects.ts
  - POST /projects/:id/workspaces: normalize req.body.cwd before the
    service call.
  - PATCH /projects/:id/workspaces/:workspaceId: same.
  - Added import.

changed: server/src/routes/execution-workspaces.ts
  - PATCH /execution-workspaces/🆔 normalize req.body.cwd before the
    patch object is built.
  - Added import.

changed: server/src/services/nexus-settings.ts
  - In set(): expand ~ in piperBinaryPath and whisperBinaryPath before
    merging and validating. These are executable paths so we expand
    but don't mkdir — caller still has to install the binary itself,
    but the stored path is now resolvable by the server.
  - Added import.

Not extended:
  - Storage provider baseDir: computed at startup from environment,
    not user request body. Sandboxed. No change needed.
  - Instructions bundle paths: indirectly covered — the legacy path
    resolver depends on cwd being absolute, which 91530b07 ensures.
  - Chat file upload object keys: system-generated, not user-supplied.

Verification: npx tsc --noEmit on server — zero errors introduced in
any touched file. Dev server on :6100 still returns 200.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 18:22:33 +00:00
Nexus Dev
91530b07a4 fix(nexus): expand tilde and mkdir workspace cwd on agent save
Zero-terminal bug fix. When a user set an agent's working directory
to "~/nexus-test-01" through the UI, the path was stored verbatim in
agents.adapter_config.cwd and the downstream local adapters (claude_
local, codex_local, gemini_local, cursor, opencode_local, hermes_
local, etc.) failed to resolve the tilde — shells expand ~, child
processes don't. The user was then expected to ssh in and create the
directory by hand, which contradicts Nexus's zero-terminal charter.

Add two helpers in server/src/routes/agents.ts:

  expandUserPath(candidate)
    Trim, expand leading "~" or "~/" to os.homedir(), then
    path.resolve() to absolute form. Null-safe on non-string input.

  normalizeAdapterConfigPaths(adapterConfig)  [async]
    If adapterConfig.cwd is a non-empty string, expand it, assert
    absolute, mkdir -p (recursive), and stat to confirm it's a
    directory. Any failure becomes an unprocessable (422) error with
    the reason surfaced to the UI. Logs an info line when a path is
    actually changed, so the audit trail records that Nexus expanded
    a user-supplied tilde.

Wire into the three existing call sites:

  POST /api/companies/:companyId/agent-hires
  POST /api/companies/:companyId/agents
  PATCH /api/agents/:id

...all of which previously called applyCreateDefaultsByAdapterType
then secretsSvc.normalizeAdapterConfigForPersistence. Added
normalizeAdapterConfigPaths between the secrets step and
assertAdapterConfigConstraints on create + hire, and between secrets
normalization and syncInstructionsBundleConfigFromFilePath on patch.
Each call site now stores a fully resolved absolute path and is
guaranteed the directory exists on disk.

DB state for the two agents that hit this bug today (Project Manager
and Engineer on the Nexus company) was already patched out-of-band
to /home/mikkel/nexus-test-01 by a direct SQL update and mkdir. This
commit prevents recurrence for any future agent-create or agent-patch.

Not addressed here (scope creep):
  - instructionsFilePath / instructionsRootPath also accept
    user-provided paths but are managed by a separate subsystem;
    they may need their own tilde-expansion pass if the UI ever
    exposes them directly.
  - No restriction on where the cwd can be. Nexus runs as the host
    user and trusts the caller. A future policy could limit cwd to
    $HOME or a configured workspace root, but that's a separate
    decision.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:56:15 +00:00
Nexus Dev
3d2117ee9f fix(nexus): auto-bootstrap invite and vite onnxruntime middleware
Zero-terminal first boot. Previously the bootstrap_ceo invite had to be
created via a CLI command (paperclipai auth bootstrap-ceo) and the UI
showed a code block instructing the user to run it. Nexus is meant to
be zero-terminal, so the server now auto-creates the invite on startup
when no instance admin exists and exposes its relative path through
/api/health. BootstrapPendingPage redirects straight to /invite/{token}.
The CLI command is left intact for headless/SSH-only setups.

Invite flow fixes that surfaced during testing:

  - InviteLanding's invite query had default React Query refetch
    behavior. After a successful bootstrap accept, the invite is marked
    accepted server-side, so the refetch returned "not available" and
    shadowed the success screen, making it look like the bootstrap had
    failed when it actually succeeded. Set staleTime: Infinity +
    refetchOnWindowFocus/Mount/Reconnect: false so the first fetch is a
    one-shot snapshot.

  - Reordered the render checks so result?.kind === "bootstrap" / "join"
    are evaluated before the invite-availability error check — defensive
    against any stray refetch that still leaks through.

  - On bootstrap success, window.location.replace("/") lands the new
    admin directly on the board; the "Bootstrap complete" confirmation
    screen is now an unreachable safety net.

Vite onnxruntime middleware replaces the earlier public/ dump. The
previous commit put ort-wasm-simd-threaded.{mjs,wasm} in ui/public/ so
VAD's onnxWASMBasePath: "/" would find them. That works at runtime but
trips vite's dep optimizer: it scans onnxruntime-web, resolves the
dynamic import string to the public asset, and errors with "files in
/public should not be imported from source code." Remove the files and
add a vite plugin (configureServer middleware) that serves the two URLs
straight from node_modules/.pnpm/onnxruntime-web@*/. Runtime keeps
working and the files never enter vite's module graph.

Production build caveat: the middleware only runs in dev. When building
a static dist for production, the wasm files will need a different
mechanism (e.g. generateBundle hook). Not addressed here.

Also bundled (load-bearing for LAN browser testing):

  - ui/src/lib/queryKeys.ts: add missing 'nexus' group. useNexusMode
    referenced queryKeys.nexus.settings since commit 7bb72a5a (Phase
    33-02) but the key was never added. Caused a blank screen crash on
    any page that mounts Sidebar.

  - ctl.sh: read PORT from .env instead of hardcoding 3100, and read it
    once at the top so every subcommand honors it. Fixes the Version /
    Mode showing '?' in status output after the port move to 6100.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:50:28 +00:00
Nexus Dev
8f6dd220aa fix(nexus): restore chat migrations, mount routes, add onnx assets
HEAD had 3 pairs of drizzle-generated migrations colliding on indices 46-48
(chat set vs doc/feedback/routines set) with a journal that only referenced
one of each pair. Migrations 0047-0055 (chat_conversations, chat_messages,
bookmarks, chat_files, push_subscriptions, etc.) were committed as files on
disk but never added to _journal.json, so drizzle never applied them.

Rename the three non-chat ghost migrations out of the conflict zone
(0046/0047/0048 -> 0056/0057/0058) and extend the journal with entries for
all 12 previously-orphaned migrations so drizzle applies them in order on
fresh DB init.

Also mount chatRoutes() in app.ts — the router was defined in routes/chat.ts
but never wired up, so /api/companies/:id/{conversations,bookmarks} 404'd
even when tables existed.

Ship ort-wasm-simd-threaded.mjs + .wasm in ui/public so VAD can load the
onnxruntime module at /ort-wasm-simd-threaded.mjs instead of getting the
SPA HTML fallback.

Bundles pre-existing LAN-testing hunks in app.ts: conditional COOP/COEP
headers (only on secure/localhost origins) and Vite HMR host fix for
0.0.0.0 binding so the HMR client connects back to whatever hostname the
browser used. These are load-bearing for LAN browser testing on plain HTTP.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:44:43 +00:00
Nexus Dev
1c8a26dbb4 feat: Phase 45 — Content as Skills (9 SKILL.md files, Creative group, gap fixes) 2026-04-05 09:57:20 +00:00
Nexus Dev
d25d88d053 feat: Phase 44 — Video & Presentations (Remotion MP4, SSE progress) 2026-04-05 09:57:11 +00:00
Nexus Dev
e4165adefb feat: Phase 43 — Documents & Branding (PDF reports, brand kit ZIP) 2026-04-05 09:57:02 +00:00
Nexus Dev
0956c31384 feat: Phase 42 — Wallpapers, Social, Format Conversion & Voice (12 platforms, convert pipeline, offline badge) 2026-04-05 09:56:53 +00:00
Nexus Dev
fc55990fde feat: Phase 41 — Diagrams, Icons & Theme Engine (Mermaid, SVG icons, OKLCH palettes) 2026-04-05 09:56:37 +00:00
Nexus Dev
a01c28dff2 feat: Phase 40 — Job Infrastructure (content jobs, SSE events, namespaced storage) 2026-04-05 09:55:08 +00:00
Nexus Dev
f85cab192a [nexus] fix: resolve rebase artifacts — duplicate function, missing import, stale SDK types 2026-04-04 03:58:39 +00:00
Nexus Dev
25e3eda0b9 feat(39-02): voice capability probe in hardware service
- Add VoiceCapability interface with whisperAvailable, piperAvailable, voiceTierSufficient
- Extend HardwareInfo with voiceCapability field
- Add detectVoiceCapability() probing whisper-cpp/whisper and piper with 2s timeout each
- voiceTierSufficient: true for apple_silicon/gpu, or cpu_only with >= 4GB free RAM
- Wrap voice probe in 3s timeout to avoid slowing hardware detection
- Route automatically includes voiceCapability via existing HardwareInfo return
2026-04-04 03:55:50 +00:00
Nexus Dev
0f46d9b3bd test(39-02): add failing tests for voice capability detection 2026-04-04 03:55:50 +00:00
Nexus Dev
22beb245f2 feat(39-01): sentence-buffered TTS streaming + multi-language synthesis
- Export splitSentences() with title-abbreviation protection (Dr., Mr. etc.)
- Add synthesizeSentenceStream() AsyncGenerator yielding per-sentence audio chunks
- Add synthesizeMultiLang() synthesizing same text in N voices via Promise.all
- Add POST /api/synthesize/stream SSE endpoint with base64 audio per sentence
- Add POST /api/synthesize/multi-lang returning array of voiceId+audio pairs
- Existing POST /api/synthesize unchanged (backward compatible)
2026-04-04 03:55:50 +00:00
Nexus Dev
6be251a9fb test(39-01): add failing tests for sentence streaming and multi-lang synthesis 2026-04-04 03:55:50 +00:00
Nexus Dev
6435ccb1c4 feat(38-02): add voice message handling + TTS reply to Telegram bridge
- Refactor text relay into shared relayToAgent() used by both text/voice handlers
- Add bot.on('message:voice') handler: send 'Transcribing...' immediately, process async
- Download OGG from Telegram CDN via ctx.getFile() + fetch, transcribe via voicePipelineService
- Synthesize agent responses to OGG Opus via transcodeToOggOpus() and ctx.replyWithVoice()
- TTS failure degrades gracefully (text reply already sent, voice is bonus)
- telegram.ts stays at 322 lines (under 500-line TGRAM-06 constraint)
2026-04-04 03:55:50 +00:00
Nexus Dev
34bfbe06e1 feat(38-01): wire telegramService + telegramRoutes into app.ts
- Import telegramService, telegramRoutes, nexusSettingsService
- Mount /telegram routes under /api prefix
- Conditionally start Telegram bot on boot if telegramToken is configured
- Token route restarts bot after saving new token
2026-04-04 03:55:50 +00:00
Nexus Dev
69269fea14 feat(38-01): install grammY, create telegramService + telegramRoutes
- Install grammy v2 for long polling Telegram bot
- telegramService: text relay handler, agent prefix, session map, deleteWebhook lifecycle
- telegramRoutes: POST /telegram/token (getMe validation), GET /telegram/status
- telegram.ts under 500 lines (187 lines)
2026-04-04 03:55:50 +00:00
Nexus Dev
c42a64b7a2 feat(37-01): add COOP/COEP headers to Express server for SharedArrayBuffer support
- Add Cross-Origin-Opener-Policy: same-origin middleware before all routes
- Add Cross-Origin-Embedder-Policy: require-corp middleware before all routes
- Required for @ricky0123/vad-react (VAD uses SharedArrayBuffer internally)
2026-04-04 03:55:50 +00:00
Nexus Dev
b204d6318e fix(36): resolve TypeScript errors in voice-pipeline.ts (ffmpegPath cast, callback types) 2026-04-04 03:55:50 +00:00
Nexus Dev
f23c4218aa feat(36-03): wire voiceMode through chat stream, mount voice routes, remove old transcribe
- server/src/routes/chat.ts: destructure voiceMode from req.body in stream endpoint
- server/src/routes/chat.ts: inject dual-output system prompt when voiceMode=full_voice (VPIPE-06)
- server/src/routes/chat.ts: persist voiceMode to messageType column (voice_full/voice_input)
- server/src/routes/chat-files.ts: remove old inline /transcribe endpoint (lines 297-386)
- server/src/app.ts: import and mount voiceRoutes() after nexusSettingsRoutes()
2026-04-04 03:55:50 +00:00
Nexus Dev
bf757509ef feat(36-03): add voice HTTP routes with POST /transcribe and POST /synthesize
- Create server/src/routes/voice.ts with voiceRoutes() factory
- POST /transcribe: multer audio upload → VoicePipelineService.transcribe → JSON response
- POST /synthesize: text body → VoicePipelineService.synthesize → audio/wav response
- Both routes protected by assertBoard(req) auth check
- Create server/src/__tests__/36-voice-routes.test.ts with 5 passing tests
2026-04-04 03:55:50 +00:00
Nexus Dev
9fcf27fed9 feat(36-02): extend nexus-settings schema with voiceMode, telegramToken, and binary paths
- Export VOICE_MODES constant and VoiceMode type from nexus-settings
- Export nexusSettingsSchema for testing
- Add voiceMode field with default 'text' to nexusSettingsSchema
- Add telegramToken optional field to nexusSettingsSchema
- Add piperBinaryPath and whisperBinaryPath optional fields
- Update fallback in get() to use nexusSettingsSchema.parse({}) for consistent defaults
- Add 5 passing tests for nexus-settings schema in 36-voice-schema.test.ts
2026-04-04 03:55:50 +00:00
Nexus Dev
8e564e8125 feat(36-02): add voiceMode field to createMessageSchema and ChatMessage interface
- Add VOICE_MODES constant and VoiceMode type to shared validators/chat.ts
- Extend createMessageSchema with optional voiceMode enum field
- Add voiceMode optional field to ChatMessage interface in types/chat.ts
- Add 36-voice-schema.test.ts with 6 passing tests for voiceMode validation
2026-04-04 03:55:50 +00:00
Nexus Dev
346b42dd73 feat(36-01): VoicePipelineService with transcribe, synthesize, formatForVoice, transcodeToWav16k
- Install ffmpeg-static and @types/ffmpeg-static
- Create voice-pipeline.ts with voicePipelineService factory function
- transcodeToWav16k: pipes audio through ffmpeg at 16kHz mono WAV
- transcribe: whisper-cpp cascade with --language auto, falls back to openai-whisper
- synthesize: piper TTS with sentence chunking and 8s timeout via Promise.race
- formatForVoice: extracts SPOKEN marker or strips markdown as fallback
- Unit tests with mocked child_process (12 tests all passing)
2026-04-04 03:55:50 +00:00
Nexus Dev
5ad8e2bee8 feat(36-02): extend nexus-settings schema with voiceMode, telegramToken, and binary paths
- Export VOICE_MODES constant and VoiceMode type from nexus-settings
- Export nexusSettingsSchema for testing
- Add voiceMode field with default 'text' to nexusSettingsSchema
- Add telegramToken optional field to nexusSettingsSchema
- Add piperBinaryPath and whisperBinaryPath optional fields
- Update fallback in get() to use nexusSettingsSchema.parse({}) for consistent defaults
- Add 5 passing tests for nexus-settings schema in 36-voice-schema.test.ts
2026-04-04 03:55:50 +00:00
Nexus Dev
14e059862b feat(36-02): add voiceMode field to createMessageSchema and ChatMessage interface
- Add VOICE_MODES constant and VoiceMode type to shared validators/chat.ts
- Extend createMessageSchema with optional voiceMode enum field
- Add voiceMode optional field to ChatMessage interface in types/chat.ts
- Add 36-voice-schema.test.ts with 6 passing tests for voiceMode validation
2026-04-04 03:55:49 +00:00
Nexus Dev
36746ed17b feat(34-01): register chatFileRoutes + nexusSettingsRoutes in app.ts, add voiceEnabled to nexus-settings
- Add chatFileRoutes(db, storageService) after assistantHandoffRoutes (inside boardMutationGuard)
- Add nexusSettingsRoutes() after chatFileRoutes
- Extend nexusSettingsSchema with voiceEnabled: z.boolean().default(false)
- Update default return values in nexusSettingsService.get() to include voiceEnabled: false
- Add voiceEnabled?: boolean to NexusSettings client interface in hardware.ts
2026-04-04 03:55:49 +00:00
Nexus Dev
222d00c57f feat(33-03): real AI streaming with memory injection + assistant handoff
Replace streamEcho with Puter proxy AI call, inject memory facts as
system message, append memory after each turn. Assistant-to-PM handoff
creates new conversation with context summary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:49 +00:00
Nexus Dev
7bb72a5a2f feat(33-01,33-02): memory service + sanitizer, personal assistant page
33-01: memory-sanitizer, assistant-memory service, REST routes, 17 tests
33-02: useNexusMode hook, PersonalAssistantPage, sidebar nav, route wiring

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:49 +00:00
Nexus Dev
d1bb30517f feat(31-01): mount puterProxyRoutes in app.ts
- Add import for puterProxyRoutes from routes/puter-proxy.js
- Mount api.use(puterProxyRoutes(db)) after costRoutes inside api Router
- Route is protected by boardMutationGuard as required
2026-04-04 03:55:49 +00:00
Nexus Dev
dbba43cb3c test(31-02): add 11 unit tests for Google OAuth service and routes
- Test 1-2: PKCE generation (verifier/challenge format, auth URL params)
- Test 3: token exchange posts correct body to Google token endpoint
- Test 4-5: storeTokens create and rotate paths
- Test 6: authorize returns {url, stateId} with no companyId in pendingPkce
- Test 7: callback exchanges code and redirects with google_oauth=success
- Test 8: callback with invalid state returns 400
- Test 9: full authorize->callback->claim flow stores tokens by companyId
- Test 10: claim with missing stateId returns 404
- Test 11: api-keys/store upserts via secretService
2026-04-04 03:55:49 +00:00
Nexus Dev
526acbe8aa feat(31-01): implement puterProxyService, puterProxyRoutes, and unit tests
- puterProxyService with storeToken (create/rotate idempotent), resolveToken, chatStream
- chatStream relays to Puter OpenAI-compat endpoint with SSE streaming
- Cost recording with provider=puter, billingType=subscription_included, costCents=0
- Cost recording skipped when agentId is null/undefined (no FK violation)
- puterProxyRoutes with POST /puter-proxy/token and POST /puter-proxy/chat
- Board auth (assertBoard + assertCompanyAccess) on all routes
- All 10 TDD tests passing
2026-04-04 03:55:49 +00:00
Nexus Dev
895b3004be feat(31-02): add googleOAuthRoutes with pendingTokens pattern and mount in app.ts
- POST /oauth/google/authorize: returns {url, stateId}, stores PKCE verifier only (no companyId)
- GET /oauth/google/callback: exchanges code, parks tokens in pendingTokens by stateId
- POST /oauth/google/claim: moves tokens from pendingTokens to secretService with real companyId
- POST /api-keys/store: upserts provider API keys (openai/anthropic/groq) via secretService
- Cleanup of entries older than 10 minutes on each request
- Mounted in app.ts via api.use(googleOAuthRoutes(db))
2026-04-04 03:55:49 +00:00
Nexus Dev
14784d47c2 feat(31-02): add googleOAuthService with PKCE generation and token management
- generatePkce() using crypto.randomBytes base64url verifier and SHA256 challenge
- generateAuthUrl() builds Google OAuth URL with PKCE params for Gemini scopes
- exchangeCode() POSTs to Google token endpoint with code_verifier
- storeTokens() upserts google_gemini_oauth_token via secretService
- resolveTokens() retrieves and parses stored tokens by companyId
2026-04-04 03:55:49 +00:00
Nexus Dev
59bf5dd8ba feat(30-01): hardware and nexus-settings routes, app.ts mounting
- Add hardwareRoutes with unauthenticated GET /system/providers
- Add hardwareRoutes with GET /system/providers/recommendation
- Add nexusSettingsRoutes with board-auth GET/PATCH /nexus/settings
- Mount hardwareRoutes on app before boardMutationGuard (unauthenticated)
- Mount nexusSettingsRoutes on api router (board-auth gated)
2026-04-04 03:55:49 +00:00
Nexus Dev
a9817a9659 feat(30-01): hardware detection, nexus-settings, extended model catalog
- Add hardwareService with Apple Silicon / GPU / cpu_only tier detection
- Add 3s Promise.race timeout for si.graphics() with cpu_only fallback
- Add nexusSettingsService with Zod validation and file-backed persistence
- Extend ollama-model-catalog.json with tier arrays on every variant
- Add qwen3:8b family to catalog
- Update getRecommendedModel to accept optional hardwareTier parameter
- All 13 unit tests pass (TDD green)
2026-04-04 03:55:49 +00:00
Nexus Dev
0fc748d2d4 feat(29-02): Hermes skill injection + default provider integration tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:49 +00:00
Nexus Dev
1ff3953c97 feat(29-01): adapter probe route, Hermes onboarding fallback, neutral templates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:49 +00:00
Nexus Dev
1cf1c1f038 feat(28-02,28-03): Ollama UI surface + Hermes runtime dashboard
28-02: ollamaApi client, model dropdown in config, skill badge
28-03: stateJson merge after heartbeat, HermesRuntimeCard in AgentOverview

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:49 +00:00
Nexus Dev
39327b7660 feat(28-03): merge Hermes runtime data into stateJson and add HermesRuntimeCard
- Add OllamaPsResponse interface and getOllamaMemoryUsage() to ollama.ts
- Import getOllamaMemoryUsage in heartbeat.ts
- Add hermes_local block in updateRuntimeState: COALESCE jsonb merge of hermesModel + hermesMemoryBytes
- Add HermesRuntimeCard component in AgentDetail.tsx
- Render HermesRuntimeCard in AgentOverview gated by adapterType === hermes_local
- Native skill count derived from agentsApi.skills entries with originLabel === Hermes skill
2026-04-04 03:55:49 +00:00
Nexus Dev
5345b67f92 feat(28-01): Ollama service, routes, model catalog
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:48 +00:00
Nexus Dev
9ef04fd1de feat(27-01): close Hermes adapter integration gaps
- Add hermes_local to SESSIONED_LOCAL_ADAPTERS (HERM-03)
- Fix create-mode toolsets field guard (HERM-02)
- Add hermes session codec round-trip tests (HERM-04)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:48 +00:00
Nexus Dev
4b9d267f46 fix(v1.3): close 3 integration gaps from milestone audit
1. Push notifications: call sendPushToAll after streaming completes
2. Mobile offline: add useOfflineQueue + banners to MobileChatView
3. New conversation streaming: call startStream in Path 1 handleSend

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:48 +00:00
Nexus Dev
66bbfbf766 feat(26-04): create push_subscriptions schema, migration, pushService, and push routes
- Add push_subscriptions pgTable with endpoint, p256dh, auth, userId, companyId, deviceLabel
- Add 0055_create_push_subscriptions.sql migration with CREATE TABLE and endpoint index
- Export pushSubscriptions from schema/index.ts
- Create pushService with initVapid, getVapidPublicKey, saveSubscription, removeSubscription, sendPushToAll
- sendPushToAll auto-deletes stale subscriptions on 410/404 response
- Create pushRoutes: GET /vapid-public-key, POST /subscribe, DELETE /subscribe
- Mount /api/push routes and call initVapid() in app.ts with graceful skip
- Install web-push and @types/web-push
2026-04-04 03:55:48 +00:00
Nexus Dev
dae0e3a3be feat(25-06): merge git file service and history endpoint from worktree
Adds gitFileService with commitFile/getLog, wires git commits into
upload flow, adds GET /files/:fileId/history endpoint, and exports
ChatFileHistoryEntry type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 03:55:48 +00:00
Nexus Dev
7ab49d9824 feat(25-07): add placeholder and agent-generated file routes
- Import placeholderService and resolveDefaultStorageDir in chat-files routes
- Track agent_generated project-scoped uploads in PLACEHOLDERS.md manifest
- Add POST /files/:fileId/replace endpoint for placeholder replacement
- Replace endpoint updates manifest and creates cross-reference chain
- Mark FILE-08 and FILE-11 Complete in REQUIREMENTS.md
2026-04-04 03:55:48 +00:00
Nexus Dev
859ba1707b feat(25-07): create placeholderService and add markAsPlaceholder method
- Create server/src/services/placeholder-service.ts with addEntry, replaceEntry, listEntries
- Generates PLACEHOLDERS.md with Active Placeholders and Replaced markdown tables
- Add ChatPlaceholderEntry interface to packages/shared/src/types/chat.ts
- Export ChatPlaceholderEntry from packages/shared/src/index.ts
- Add markAsPlaceholder method to chatFileService in chat-files.ts
2026-04-04 03:55:48 +00:00
Nexus Dev
03df062bec feat(25-04): create ChatCodeFilePreview with syntax highlighting
- Add ChatCodeFilePreview component with hljs syntax highlighting
- Fetch file content from contentPath with credentials
- Use DOMParser-based safe rendering (no dangerouslySetInnerHTML)
- Include copy button, language label, and ChatFileCard download below
- Add extToLang extension-to-language mapping
- Register 14 common languages with hljs
- Add highlight.js as direct dependency in ui/package.json
2026-04-04 03:55:48 +00:00
Nexus Dev
64a90c284e feat(25-08): create VoiceRecordButton and server transcription endpoint
- Add VoiceRecordButton with MediaRecorder API, recording/transcribing/idle states
- Add POST /transcribe endpoint to chat-files.ts using execFileAsync (safe, no shell)
- Tries whisper-cpp first, falls back to openai-whisper Python CLI
- Returns 503 with helpful message if whisper is not installed
2026-04-04 03:55:48 +00:00