Commit Graph
4428 Commits
Author SHA1 Message Date
Vikhyath Mondreti af859cd508 feat(workflows): lock/duplicate improvements for workflows (#4387)
* feat(workflows): lock/duplicate improvements

* fix duplicate var remap bug

* address comments

* remove dead vars

* fix tests

* address comments

* code cleanup

* address comments

* address comments

* minor change

* remove dead code
2026-05-01 20:42:10 -07:00
WaleedandClaude Opus 4.7 50e118a033 fix(serializer): apply tools.config.params before validating required tool params (#4391)
* fix(serializer): apply tools.config.params before validating required tool params

* fix(serializer): guard array results and drop redundant fallback in tool param validation

* fix(blocks): align canonicalParamId with tool param name for file inputs

Renames the canonical id from `document` to `file` on firecrawl, reducto v2,
pulse v2, and extend v2 so pre-execution validation resolves the value
under the same key the tool expects, eliminating false "missing required
fields: file" errors at submit time.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(blocks): drop extraneous comments from canonical file-input renames

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(serializer): drop tools.config.params invocation; enforce canonical-id contract via audit

The serializer's pre-execution validator no longer runs the block's
`tools.config.params` mapper to discover renamed tool param ids. Instead
it relies on the contract that every required+user-only tool param is
backed by a subBlock whose `id` or `canonicalParamId` equals the tool
param id, and a new audit (`bun run check:block-canonical`) enforces
this. Migrates posthog (`personalApiKey` → canonical `apiKey`) so the
audit passes cleanly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(scripts): consolidate block registry CI checks into one script

Folds the canonical-id contract audit into the existing subblock ID
stability script and renames it to `check-block-registry.ts`. Both
checks share the same `getAllBlocks()` import and registry-invariant
purpose, so a single CI gate now catches both regression classes.
The early-exit path on the stability check no longer short-circuits
the canonical-id check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(scripts): unify check-block-registry result reporting

Each check returns a discriminated `CheckResult` (pass | skip | fail)
so the runner prints one definitive line per check instead of mixing a
"skipping" message with a redundant "passed" line. Failure messages
include a per-check header explaining the runtime impact.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:00:05 -07:00
Waleed 9655e8e96c improvement(home): anchor @-mention popup at caret and right-size dropdown widths (#4393)
* improvement(home): anchor @-mention popup at caret and right-size dropdown widths

* fix(home): align caret-anchor marker to text-top so mention popup clears glyph

* fix(home): enable collision avoidance for @-mention popup so it fits in narrow chats
2026-05-01 19:44:22 -07:00
Waleed 5863276da2 fix(csp): allow https images in markdown preview and html sandbox (#4394)
* fix(csp): allow https images in markdown preview and html sandbox

* fix(csp): remove inoperative self token from sandboxed html preview img-src

* chore(csp): remove redundant img-src entries superseded by https scheme

* fix(csp): revert html preview img-src to data: blob: to preserve connect-src none isolation
2026-05-01 18:40:59 -07:00
Theodore Li 39c6aef1a6 fix(files): unstick monaco find widget tooltips and surface logs in mothership add-resource (#4395) 2026-05-01 21:39:27 -04:00
Waleed cc28ba8c70 fix(mail): use html-to-text for plaintext email fallback (#4392) 2026-05-01 17:47:47 -07:00
Waleed da09a2a19c improvement(mothership): reuse logs detail panel in resource view (#4389)
* improvement(mothership): reuse logs detail panel in resource view

* improvement(logs): drop unnecessary memo and export tab type

* fix(logs): notify embedder on every resolved-tab change
2026-05-01 16:52:15 -07:00
Waleed 38aa163b1c fix(oauth): trim Atlassian OAuth scopes to fix CloudFront 414 (#4388)
* fix(oauth): trim Atlassian OAuth scopes to fix CloudFront 414

* fix(oauth): restore Confluence scopes whose tools are still active

* fix(oauth): add JSM Forms scopes for form tools

* fix(oauth): restore read:issue.vote:jira scope

Jira issue retrieve tool reads fields.votes.votes and fields.votes.hasVoted
from the GET /rest/api/3/issue payload, which requires the
read:issue.vote:jira granular scope. Restoring to prevent vote data from
being omitted in retrieve responses.

* fix(oauth): drop redundant Jira granular scopes covered by classic

Atlassian recommends <50 scopes per OAuth app to keep authorize URLs
under URL-length limits. Drops 20 granular Jira read/write scopes that
are subsumed by the classic read:jira-work / write:jira-work scopes
already in the list. Existing user tokens are unaffected — Atlassian
refresh keeps originally-granted scopes; the trimmed list only applies
to new authorizations.

Kept granular scopes: delete:* (no classic equivalent) and JSM
granular scopes (separate scope family).

* fix(oauth): re-add read:issue.vote:jira to match PR description

Bugbot flagged that the previous classic-scope collapse dropped this
granular scope while the PR description still claimed it was restored.
Classic read:jira-work covers vote reads, but adding the granular
explicitly keeps the description, code, and intent aligned.
2026-05-01 16:30:48 -07:00
WaleedandClaude Opus 4.7 add55b4ffa improvement(executor): correctness-by-construction for workflow logs (#4382)
* improvement(executor): correctness-by-construction for workflow logs

Replace the post-hoc reconciliation layer with a deterministic emission
protocol: drain pending callback promises at terminal boundaries, mint a
per-invocation blockExecutionId, and key console entries by that ID.
Eliminates races between block:* and execution:* events without changing
per-block latency.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(executor): remove stale fire-and-forget assertion

The deleted test asserted wrappedOnBlockStart returns before the user
callback resolves. After the Stage 1 drain refactor, wrappedOnBlockStart
must await the user callback so the executor's trackCallback set covers
SSE writes — otherwise the drain at terminal-event time can't guarantee
block:* flushes before execution:*.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(console-store): cover blockExecutionId keying and idempotency

Locks in the new console store invariants:
- Primary lookup via entryIdByBlockExecutionId fires no legacy warn
- Unknown blockExecutionId falls back to legacy keying and warns
- No-blockExecutionId updates use legacy path silently
- addConsole twice with same blockExecutionId returns the existing entry
- Distinct blockExecutionIds (loop iterations) produce distinct entries

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(executor): capture BlockExecutor locally so finally drains its own instance

Previously this.blockExecutor was overwritten on every buildExecutionPipeline
call. Concurrent or re-entrant execute()/executeFromBlock() calls would have
their finally block drain the wrong instance, allowing the first execution's
block events to land after its terminal event. Returning { engine, blockExecutor }
and capturing both locally makes the drain pinned to the same instance the
engine.run() ran against.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(terminal): capture store logger by label, not first warn-bearing mock

The previous capture used `.find` over all createLogger results, which
returned whichever module created a logger first — not the store's
logger — causing the legacy-keying warn assertion to see 0 calls.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 15:54:53 -07:00
Waleed bdaf112db7 improvement(tables): bump column auto-fit cap from 600px to 1000px (#4384) 2026-05-01 13:12:26 -07:00
Waleed 94dd2e1168 improvement(workflow): narrow zustand selectors and optimize log tree builds (#4378)
* improvement(workflow): narrow zustand selectors and optimize log tree builds

- Add useIsCurrentWorkflowExecuting selector; swap broad useCurrentWorkflowExecution in action-bar/chat
- Use useShallow for execution-state subset in useWorkflowExecution
- Drop useCallback-wrapped object selectors in diff-controls and use-block-state (use primitive selectors)
- Stabilize EMPTY_SUBBLOCK_VALUES constant for empty-workflow selector results in api-info-modal, mcp, tag-dropdown
- O(n) Map lookups in buildEntryTree (was O(n^2) filter scans)
- Skip expanded-paths reset when structured-output data is content-stable
- Extract ReactFlow constants out of workflow.tsx into workflow-constants.ts

* fix(workflow): seed structured-output JSON ref and centralize EMPTY_SUBBLOCK_VALUES

- Use null sentinel for prevDataJsonRef and lazily stringify prevDataRef on first compare so the optimization holds on the first stream refresh after mount
- Export EMPTY_SUBBLOCK_VALUES from the subblock store; remove three duplicated module constants

* chore(ci): bump api-validation route baseline to 717

PR #4373 added apps/sim/app/api/table/[tableId]/export/route.ts but didn't
update the audit baseline, so unrelated PRs fail check:api-validation:strict.
Bump baseline to match current route count.
2026-05-01 12:16:50 -07:00
Vikhyath Mondreti a7a941f1a7 improvement(invites): remove confusing copy (#4380) 2026-05-01 12:16:25 -07:00
Vikhyath Mondreti b10b4479fe improvement(repo): update ship skills, flatten internal tools contracts dir (#4379)
* improvement(repo): update ship skills, flatten internal tools contracts dir

* update baselines

* address comments
2026-05-01 12:08:00 -07:00
WaleedandClaude Opus 4.7 a9c12a2b36 feat(tables): add export, import column creation, infinite row pagination (#4373)
* feat(tables): add export, import column creation, infinite row pagination

- Add `/api/table/[tableId]/export` route streaming CSV/JSON downloads
- Rename `/import-csv` route to `/import` and extend to auto-create new
  columns from unmapped CSV headers via `createColumns` form field
- Switch table view to `useInfiniteQuery` so tables larger than 1000
  rows fully load; reconcile created rows into the paginated cache so
  "New row" past 1000 no longer reverts on invalidate
- Wire scroll-driven prefetch (600px from bottom) and pre-drain pages
  before append to keep new-row position consistent
- Polish import-csv dialog flow and add Export action to header

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(table): route boundary validation through Zod contracts

Switch the table query hooks and the import/export routes to the
codebase's contract-based request pattern so the API validation audit
and boundary policy ratchet pass.

- `hooks/queries/tables.ts` now calls every endpoint via
  `requestJson(contract, ...)`; the only remaining raw `fetch` calls are
  the streaming export download and the multipart CSV upload, both
  annotated `boundary-raw-fetch:`.
- The import and export routes parse `params`, the `format` query, and
  the multipart form fields with shared schemas from
  `@/lib/api/contracts/tables`. Two new contract schemas
  (`csvImportCreateColumnsSchema`, `tableExportFormatSchema`) cover the
  fields specific to these routes.
- Bumps the audit baseline by one route to account for the new export
  endpoint.

* fix(table): address PR bot review

- Move the `isAppendingRowRef` reset into the create-row mutation's
  `onSettled` callback. The previous `try/finally` cleared the guard
  immediately after `mutate()` returned, before the request completed,
  so a rapid second click on "New row" could fire a duplicate create.
- Drop the unused `addTableColumns` wrapper from `lib/table/service`.
  The CSV import flow only ever uses the transaction-bound
  `addTableColumnsWithTx`; the standalone wrapper was dead code.

* fix(table): re-throw on infinite-query fetch error in append-row drain

`useInfiniteQuery.fetchNextPage()` resolves (rather than rejects) when a
page request fails — the resolved value carries `status: 'error'` while
`hasNextPage` still reflects the last successful page. The drain loop in
`handleAppendRow` relied on a thrown error to bail, so a failed mid-drain
fetch could spin indefinitely and leave the append guard stuck on.

Re-throw inside `fetchNextPageWrapped` when the result is an error so the
caller's `try/catch` runs as intended.

* fix(table): import TABLE_LIMITS from constants to keep server code out of client bundle

The client hook `use-table-data.ts` was importing `TABLE_LIMITS` as a
value from the `@/lib/table` barrel, which transitively pulls in
`service.ts` and the `postgres` driver. Turbopack then tried to bundle
`fs`, `net`, `tls`, and `perf_hooks` into the client component graph and
the production build failed.

Import `TABLE_LIMITS` directly from `@/lib/table/constants` (a pure
constants module) and keep the type imports against the barrel.

* fix(table): run batch unique check inside import transaction

`checkBatchUniqueConstraintsDb` queried the global `db` connection, so
inside a single import transaction (one tx wrapping all batches) the
constraint lookup couldn't see uncommitted rows from prior batches —
duplicates that crossed `CSV_MAX_BATCH_SIZE` boundaries slipped through.

Accept an optional executor and pass `trx` from `batchInsertRowsWithTx`
so the lookup observes the in-flight transaction state.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 10:00:24 -07:00
Vikhyath Mondreti 47208e0de6 improvement(repo): reorganize contracts directory (#4376)
* chore(contracts): reorg microsoft/google contracts

* chore(contracts): reorg directory
2026-05-01 09:18:37 -07:00
Vikhyath Mondreti ea2b6abd9e improvement(trace): billing trace span typing (#4375) 2026-05-01 00:38:17 -07:00
WaleedandClaude Opus 4.7 e2b3ae43e3 fix(terminal): correct error/cancel block status in logs panel (#4372)
* fix(terminal): correct error/cancel block status in logs panel

Three bugs in the workflow editor's terminal/logs panel where block
status diverged from the engine's truth on error paths:

1. **Errored block shown as "canceled"** — when the SSE 'add' mode
   produced a duplicate entry on block error and `cancelRunningEntries`
   then swept the original placeholder.
2. **Upstream blocks stuck on "Running"** — terminal events arrived
   before the engine's last block events under reconnect/timeout, so
   the live panel never received the per-block terminal state.
3. **Phantom "Run Error" pseudo-row** — the failing block rendered as
   "canceled" while a synthetic row carried the real error text.

Fixes:

- **Fix B** (`addConsoleErrorEntry`): when a running placeholder exists
  for `(blockId, executionId)`, route through `updateConsoleErrorEntry`
  instead of creating a second entry. Aligns 'add' mode with the
  existing 'update' mode behavior.
- **Fix C** (`reconcileFinalBlockLogs`): terminal SSE events now carry
  `finalBlockLogs` (server-authoritative snapshot). On
  execution:error / execution:cancelled, reconcile any still-running
  entries with their server-side terminal state. Recovers correctness
  on network drop, server timeout/abort, and reconnect-resume paths
  where individual block:* events may not have reached the client.
- **Fix D** (`addExecutionErrorConsoleEntry`): cross-check
  `useTerminalConsoleStore` for entries with `error` set scoped to the
  executionId before emitting the synthetic "Run Error" row. Suppresses
  the phantom row when the failing block already carries the message.
- **Signature refactor**: `handleExecutionErrorConsole` /
  `handleExecutionCancelledConsole` now take a typed
  `ExecutionConsoleDeps` object instead of stacking positional deps —
  matches the existing `createBlockEventHandlers(config, deps)`
  precedent in the same file.

Tests:

- 12 tests in `workflow-execution-utils.test.ts` covering Fix B/C/D and
  the deps-object signature refactor.
- Centralized terminal-console store mock in `@sim/testing` so future
  tests can stub the store without per-file boilerplate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(terminal): wire copilot cancellation to finalBlockLogs reconciliation

Address Greptile review:

- `executeWorkflowWithFullLogging`'s `onExecutionCancelled` was `() => {}`
  and silently dropped the `finalBlockLogs` payload, so Bug 2's "upstream
  blocks stuck on Running" fix did not fire on copilot-initiated
  cancellations. Wire it through `handleExecutionCancelledConsole` to
  match the SSE-route `onExecutionCancelled` path.
- Test for the `blockType !== 'error'` filter used a different
  `executionId` than the seeded entry, so the executionId scope rejected
  the entry before the blockType predicate ran. Align executionIds so
  the test actually exercises the filter.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(terminal): pass durationMs in reconnect cancellation handler

Reconnect-resume `onExecutionCancelled` was forwarding `finalBlockLogs`
but not `data?.duration`, so the "Run Cancelled" entry rendered with a
0ms duration. Match the other two `handleExecutionCancelledConsole`
callsites.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 19:52:44 -07:00
Waleed 8b6307aea4 feat(gmail): add edit draft and update label tools (#4374)
* feat(gmail): add edit draft and update label tools

* fix(gmail): correct legacy block access list and docs heading for edit_draft_v2

* fix(gmail): use shared contract for edit-draft route

* regen docs

* fix(knowledge): inline reranker model list in description for doc generator

* resolve
2026-04-30 19:51:02 -07:00
Vikhyath Mondreti be9c959f1a improvement(types): enforce patterns outside just hooks directory and fix CI check + fix tracing billing issue (#4367)
* improvement(types): enforce outside just hooks dir and update CI checks

* fix billing account details for kb embeddings

* more fixes

* fix byok issue

* address comments

* fix

* more comments

* address bugbot
2026-04-30 19:37:51 -07:00
Waleed 0c25fc4ee1 fix(auth): resolve CORS errors for self-hosted deployments behind reverse proxies (#4369)
* fix(auth): resolve CORS errors for self-hosted deployments behind reverse proxies

- auth client now uses browser origin first, falling back to NEXT_PUBLIC_APP_URL
- socket client falls back to page origin when served from non-localhost (assumes /socket.io is proxied)
- add TRUSTED_ORIGINS env var to extend Better Auth trustedOrigins (apex+www, alias hostnames)
- warn at startup when NEXT_PUBLIC_APP_URL is localhost in production
- preprocess empty NEXT_PUBLIC_SOCKET_URL so docker-compose ${VAR:-} works
- migrate remaining uuid/nanoid/randomUUID usages to @sim/utils generateId/generateShortId
- extend generateShortId with optional alphabet param (rejection sampling)
- document TRUSTED_ORIGINS in .env.example, docker-compose.prod.yml, and helm values.yaml

Fixes simstudioai/sim#1243

* fix(auth): address PR review comments

* chore(env): drop unnecessary NEXT_PUBLIC_SOCKET_URL preprocess (skipValidation is true)

* fix(docker): include @sim/utils in migrations image

Migration scripts now import generateId from @sim/utils/id; without copying packages/utils into the image, bun install fails to resolve the workspace dep at build time and the import fails at runtime.

* fix(helm): remove unused NEXT_PUBLIC_SOCKET_URL from realtime sections

The realtime service never reads NEXT_PUBLIC_SOCKET_URL — its env schema
only includes BETTER_AUTH_URL, NEXT_PUBLIC_APP_URL, ALLOWED_ORIGINS,
BETTER_AUTH_SECRET, INTERNAL_API_SECRET, DATABASE_URL, and REDIS_URL.
Remove the dead config from all helm values files and the values schema.

* fix(helm): allow empty NEXT_PUBLIC_SOCKET_URL in values schema

The default in values.yaml is now "" (empty string), which falls back to
the page origin at runtime. The schema previously required a valid URI,
which would reject the default. Mirror the INTERNAL_API_BASE_URL pattern
using anyOf with const "". Also add TRUSTED_ORIGINS to the schema.

* docs(self-hosting): mark NEXT_PUBLIC_SOCKET_URL as optional

The page-origin fallback in getSocketUrl() means self-hosters no longer
need to set NEXT_PUBLIC_SOCKET_URL when realtime is on the same origin
as the app. Update docs to reflect this:

- Remove NEXT_PUBLIC_SOCKET_URL from .env scaffolding examples in
  docker.mdx, platforms.mdx, environment-variables.mdx
- Mark the variable as Optional in the env vars table with the new
  default behavior described
- Update troubleshooting to point at reverse-proxy /socket.io routing
  rather than the env var
- Flip dev docker-compose defaults (local, ollama, devcontainer) from
  http://localhost:3002 to empty for consistency with prod.yml; the
  in-code localhost fallback handles the dev case identically

Applied across all 6 documentation languages (en/fr/de/ja/es/zh).

* chore: untrack and ignore .claude/scheduled_tasks.lock
2026-04-30 19:26:19 -07:00
Theodore Li 60804894bd fix(ui): fix tasks loading being cancelled, disable fork button (#4371)
* fix(ui): skip cancelling in flight sidebar requests on empty cache

* Add additional guard

* Address feedback

* Disable fork button
2026-04-30 22:06:47 -04:00
Waleed 220f8c8b10 feat(knowledge): add chunking strategies and regex strict boundaries (#4368)
* feat(knowledge): add chunking strategies and regex strict boundaries

- Add Token, Sentence, Recursive, and Regex chunkers with strategy selection in create-base modal
- Add opt-in strict boundaries mode for regex chunker so each match becomes its own chunk
- Add chunking strategies docs page with industry references

* fix(chunkers): strip capturing groups and validate strictBoundaries scope

- Convert capturing groups to non-capturing in regex chunker so split() doesn't surface delimiter text as spurious chunks
- Reject strictBoundaries in chunkingConfigSchema when strategy is not regex

* fix(chunkers): also strip named capture groups in regex patterns

Named groups (?<name>...) are still capturing groups so split() interleaves
their matched text. Convert them to non-capturing alongside plain ( groups.

* fix(chunkers): exclude lookbehind from named-group rewrite

Tighten NAMED_GROUP_PREFIX with negative lookahead so patterns like
(?<=<tag>) are not misidentified as named capture groups.
2026-04-30 18:33:52 -07:00
Waleed 124fe1796b improvement(toast): widen error toasts and bump line-clamp to 3 (#4370) 2026-04-30 17:48:22 -07:00
Theodore Li dafeaaaaa6 fix(ui): Add warning for organization-wide settings (#4366)
* fix(ui): Add warning for organization-wide settings

* Create emcn component

* Bump up text padding a tad

* apply emcn-design-review

* Address greptile comments
2026-04-30 19:09:52 -04:00
Waleed 46d6b1d332 fix(tasks): fix sidebar tasks skeleton hanging indefinitely (#4365)
* fix(tasks): fix sidebar tasks skeleton hanging indefinitely

Switch useTasks to skipToken + keepPreviousData and derive tasksLoading
from isLoading (isPending && isFetching) instead of data presence.
This matches the established useWorkflows pattern and prevents the
skeleton from hanging forever on query errors or when workspaceId
is temporarily absent.

* fix(tasks): show home UI for empty new tasks
2026-04-30 14:55:07 -07:00
Theodore LiandClaude Opus 4.7 49c12011dc feat(ui): update context menu (#4362)
* feat(ui): update context menu

* fix(user-input): clear mention state on submit

Programmatic plusMenuRef.close() sets the dropdown's internal open=false but
Radix doesn't fire onOpenChange for controlled changes, so handlePlusMenuClose
never ran and mentionRangeRef stayed truthy after submitting a message with
an active @mention. That caused the keydown handler to keep intercepting
ArrowUp/ArrowDown/Tab post-submit, breaking the "edit last queued message"
ArrowUp shortcut until the user typed again.

Clear mentionRangeRef and mentionQuery inline alongside the close() call.

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

* chore(ui): widen mention/plus dropdown to 420px

Long resource names were truncating in a 320px-wide menu. Bump to 420px and
cap with max-w on viewport so it can't overflow on small screens. Overrides
the emcn DropdownMenuContent's default max-w-[220px] via twMerge.

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

* chore(ui): trim mention/plus dropdown width to 360px

420px felt too wide; 360px gives long resource names enough room without
dominating the input area.

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

* tweak context menu widths

* address greptile review on PR #4362

- plus-menu-dropdown: drop folder type from the flat mention list (folders organize
  resources but aren't an insertable mention target — the nested rendering already
  excludes them).
- user-input: fold Enter into the mention-mode keydown guard so Enter confirms the
  highlighted resource instead of submitting the form. Falls through to the normal
  Enter-submit path when no match is highlighted (Tab keeps prior behavior).
- dropdown-menu wrapper: drop the misleading cast on the spread — runtime accepts
  onOpenAutoFocus regardless and the cast was hiding any future props added to
  DropdownMenuContentProps.
- plus-menu-dropdown: trim mention-mode + submenu widths to 300px (320px clipped on
  the narrower copilot panel).

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 17:33:22 -04:00
WaleedandClaude Opus 4.7 91092842e3 fix(settings): rename credentials to secrets, align role display (#4364)
- Rename credentials/ folder to secrets/ to match the page name
- Replace Badge with disabled Combobox for non-admin role display in secrets and integrations details views, full-width when no admin actions
- Reorder integrations credential row buttons so Details is rightmost
- Split credential-skeleton: page-level moves to secrets-skeleton, row-level moves to integrations/credential-skeleton
- Cleanup: useMemo→const where deps were trivial, ROLE_OPTIONS const, --text-success token

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 14:18:48 -07:00
Waleed d60747d4b7 feat(mothership): draft persistence, new task eager creation, doc preview fix, and loading polish (#4361)
* feat(mothership): draft persistence, new task eager creation, doc preview fix, and loading polish

- Add `useMothershipDraftsStore` (persist) to save and restore draft text, file
  attachments, and contexts per chat scope key; cleared on workspace reset
- Add `useCreateTask` mutation that eagerly POSTs a new chat, optimistically
  prepends it to the sidebar task list, and navigates to `/task/:id` — removes
  the `id:'new'` placeholder pattern entirely
- Fix docx/pptx/pdf preview: remove `!isDocFormat` guards in
  `file-preview-adapter` so preview sessions are created and streaming content
  is set during agent writes, suppressing intermediate compilation errors
- Replace `Loader2` (lucide) with `Loader` (emcn) across auth, chat, knowledge,
  logs, deploy, and tool-input components; add `Clipboard` icon to emcn
- Add `EditorContextMenu` to the Monaco file viewer
- Expand Monaco `SIM_DARK` and `SIM_LIGHT` token rules with string.link,
  delimiter, tag, attribute, and Markdown tokens (strong, emphasis, variable)

* fix(files): dispose onContextMenu listener and handle clipboard rejection

* fix(tasks): clear workspaceId:new draft after eager task creation

* fix(user-input): always update prevDefaultValueRef on defaultValue change

Prevents stale ref when defaultValue transitions through empty — if
defaultValue goes non-empty → empty → same non-empty value, the ref
was not updated on the empty transition, causing setValue to be skipped
on the subsequent change.

Also removes unnecessary useCallback wrapping from handleSendQueuedHead,
handleEditQueued, handleEditQueuedTail in MothershipChat — none have a
reference observer (UserInput stores them via refs, QueuedMessages is
not React.memo-wrapped).

* fix(files): improve light mode number token contrast to 4.8x

* fix(tasks): annotate raw fetch in createChat for boundary check

* fix(tasks): use requestJson with createMothershipChatContract instead of raw fetch

* fix(cleanup): remove cancelQueries from onSuccess, remove redundant Scissors className

* fix(tasks): guard handleNewTask against concurrent calls via ref lock

* fix(drafts): guard save effect against first-render race that wipes file-only drafts

On mount the save effect fired before the restore effect's setState calls
propagated, so fileAttachments and contexts were still empty. For a draft
with files but no text this caused isEmpty() to return true and setDraft to
delete the entry. Added isFirstSaveRef to skip the initial run; the restore
triggers a re-render that fires the save with the full, correct payload.

* fix(files): only show loading skeleton while fetching, relax mongo auth validation

- files.tsx: gate loading skeleton on isLoading so navigating to a missing
  file ID doesn't permanently show the skeleton after load completes
- database-tools.ts: remove refine() pairing username+password on mongo
  connection schema so either field can be provided independently

* revert(database-tools): restore mongo username+password paired validation
2026-04-30 13:45:59 -07:00
Vikhyath Mondreti 6b0de36238 chore(skills): update checklist for boundary e2e checklist (#4363)
* chore(skills): update checklist for boundary e2e checklist

* fix formatting
2026-04-30 13:12:09 -07:00
Vikhyath Mondreti b8959eb20d improvement(repo): zod based client-server boundary (#4355)
* improvement(repo): centralized zod contracts (#4336)

* improvement(repo): zod schema contracts

* type checks

* fix(notion): correctly register tool (#4337)

* fix func blokc

* more improvements

* fix tests

* type check

* remove v3 refs

* minor type improvements

* address comments

* update jira contract

* remove validateJsonBody

* improvement(repo): consolidation of boundary helpers + better unknown usage (#4352)

* improvement(repo): consolidation of boundary helpers + better unknown usage

* address comments

* improve file transfer error messaging

* fix docs listing schema drift

* fix inocrrect type casting

* address council comments

* remove prefix
2026-04-30 12:16:28 -07:00
Waleed 24de32b29a fix(secrets): invalidate env queries so dropdown updates without refresh (#4359)
* fix(secrets): invalidate env queries so dropdown updates without refresh

* improvement(secrets): use targeted workspaces key for env invalidation
2026-04-30 12:14:28 -07:00
Waleed 7377a10847 fix(custom-tool): include schema parameters in code wand prompt (#4360) 2026-04-30 12:14:07 -07:00
Waleed 07e7670d15 improvement(sidebar): remove unnecessary useCallback and useMemo wrappers (#4357)
* fix(sidebar): show skeleton on tasks error state, not 'New task' placeholder

* improvement(sidebar): remove unnecessary useCallback and useMemo wrappers

* fix(sidebar): use data-first pattern for tasks loading guard
2026-04-30 10:32:26 -07:00
WaleedandClaude Opus 4.7 d94f4c9943 feat(knowledge): add embedding model selection and Cohere reranker (#4349)
* feat(knowledge): add embedding model selection and Cohere reranker

* fix(knowledge): split reranker model constants into client-safe module

* fix(knowledge): bill rerank on every successful API call and fix MDX docs literal

* test(knowledge): align embedding tests with provider abstraction changes

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): require explicit Azure deployment per OpenAI embedding model

Greptile P1: when AZURE_OPENAI_* was set, every OpenAI embedding model was
routed to the single KB_OPENAI_MODEL_NAME deployment. A KB created with
text-embedding-3-large would be embedded by whatever model that deployment
serves while billing tracked 3-large pricing — and chunks ingested via Azure
versus queried via real OpenAI would land in mismatched vector spaces.

Now require AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_(SMALL|LARGE) per model.
Falls back to KB_OPENAI_MODEL_NAME only for text-embedding-3-small (legacy).
If no deployment is configured for the chosen model, route to direct OpenAI
instead of silently routing to the wrong deployment.

Also fix type predicate in search/route.ts to use KnowledgeBaseAccessResult
so the build passes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): skip platform reranker billing for BYOK Cohere keys

Cursor bugbot found that resolveCohereKey discarded BYOK status, so the
search route always added platform rerankerCost even when the workspace
supplied its own Cohere key.

Now resolveCohereKey returns { apiKey, isBYOK } and rerank() returns
{ results, isBYOK }. The search route checks rerankIsBYOK before adding
rerankerCost or emitting the rerankerCost/rerankerSearchUnits fields,
mirroring how generateEmbeddings handles BYOK billing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): match search tokenizer to embedding provider; remove dead var

Cursor bugbot:
- Token estimation was hardcoded to 'openai' for every embedding model.
  For gemini-embedding-001 the cost was computed against an OpenAI-tokenized
  count, producing wrong input.tokens.prompt and (slightly) wrong cost.
  Now derive the tokenizer provider from the embedding model's provider.
- rerankApplied was set but never read. Removed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): match chunk tokenizer to KB embedding provider

Cursor bugbot: createChunk and updateChunk hardcoded the 'openai' tokenizer
when computing the stored tokenCount. For KBs using gemini-embedding-001 the
count was estimated with the wrong heuristic, leading to inaccurate stored
counts (and any billing derived from them). Now derive the tokenizer from
the KB's embedding model provider, matching the search route.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(knowledge): centralize tokenizer mapping on EmbeddingModelInfo

Add tokenizerProvider directly to EmbeddingModelInfo so callers read it
from the registry instead of reimplementing the gemini→google / openai→openai
map at each call site. Removes the local helper in chunks/service.ts and
the inline ternary in search/route.ts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(knowledge): lock embedding model to KB_EMBEDDING_MODEL env var

Remove the user-facing model picker from the KB create modal and the
embeddingModel field from the create/update API schemas. The active model
is now selected server-side via KB_EMBEDDING_MODEL, which collapses Azure
routing to a single deployment (KB_OPENAI_MODEL_NAME) and drops the
per-model AZURE_OPENAI_DEPLOYMENT_TEXT_EMBEDDING_3_* env vars and
SUPPORTED_EMBEDDING_MODEL_IDS / UI-only label+description registry fields.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): use provider tokenizer for chunks and bound rerank indices

- documents/service.ts: replace ceil(len/4) heuristic with estimateTokenCount using the embedding model's tokenizerProvider so token counts match billing
- reranker.ts: filter Cohere rerank results to valid indices before mapping to defend against malformed responses
- utils.test.ts: add embeddingModel to kb fixture so getEmbeddingModelInfo resolves

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): use .count from estimateTokenCount return value

estimateTokenCount returns a TokenEstimate object, not a number — access
.count so the integer token count is stored instead of an object.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): only enforce single embedding model when query is present

Tag-only searches don't generate a query embedding, so two KBs with
different embedding models can be filtered together. Gate the guard on
hasQuery so cross-model tag-only queries no longer 400.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): use getConfiguredEmbeddingModel in copilot KB creation

Copilot-created KBs were hardcoded to text-embedding-3-small, ignoring
KB_EMBEDDING_MODEL. This caused cross-KB searches mixing copilot- and
API-created KBs to hit the embedding-model-mismatch guard.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): make EMBEDDING_DIMENSIONS a literal type

CreateKnowledgeBaseData.embeddingDimension is typed as the literal 1536,
so EMBEDDING_DIMENSIONS needs `as const` to satisfy it after the copilot
path switched to passing the constant.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): use per-KB embedding model in v1 search route

The v1 search endpoint was passing undefined to generateSearchEmbedding,
which silently fell back to text-embedding-3-small. KBs created while
KB_EMBEDDING_MODEL=gemini-embedding-001 (or any non-default) would have
their queries embedded with the wrong model. Now resolves the model from
the KB rows like the internal route, with the same multi-model guard.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore(knowledge): polish embedding/reranker implementation

- Drop unused supportsCustomDimensions from EmbeddingModelInfo (every
  registered model supports it; OpenAI/Azure paths now always send
  dimensions: 1536).
- Type SUPPORTED_EMBEDDING_MODELS as Partial<Record<...>> so index lookups
  surface as possibly-undefined in the type system instead of relying on
  runtime null checks alone.
- Require AZURE_OPENAI_API_VERSION in the Azure routing gate. Missing
  api-version no longer slips through as ?api-version=undefined; it now
  falls back to direct OpenAI.
- Use the embedding provider's tokenizer (estimateTokenCount) for the
  Gemini fallback token estimate instead of len/4, so billing matches
  the model's tokenization.
- Drop unreachable 'text-embedding-3-small' fallback in the manual chunk
  upload route — accessCheck.knowledgeBase is non-null after the access
  guard.
- docs-chunker now reads getConfiguredEmbeddingModel() so Sim's docs
  ingestion respects KB_EMBEDDING_MODEL like the user-facing paths.
- Add v1 search route test covering per-KB model resolution and the
  cross-KB mixed-model rejection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): resolve type errors and unhandled rejection in search routes

- Use accessCheck.knowledgeBase.embeddingModel directly in chunks response
- Narrow access-check predicate to KnowledgeBaseAccessResult in v1 search
- Move inaccessible-KB 404 check before query embedding promise creation

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): pass Gemini API key via x-goog-api-key header

URLs end up in server access logs, proxy logs, and APM tools, so embedding
the key as a query param risks accidental exposure. Google explicitly
recommends the header form for the Gemini REST API.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): default Azure deployment name to embedding model name

Restore the prior fallback so existing Azure deployments — which conventionally
name the deployment after the model — continue to route through Azure when
KB_OPENAI_MODEL_NAME is unset. Before this fix, those deployments silently fell
through to direct OpenAI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): cap Gemini batches at 100 items, add singular GEMINI_API_KEY fallback

- Gemini's batchEmbedContents API rejects requests with more than 100
  items. The token-based batcher could pack hundreds of short chunks
  into a single request, causing 400s. Add maxItemsPerRequest on
  ResolvedProvider and split token batches further when set.
- Mirror resolveOpenAIKey by accepting GEMINI_API_KEY (singular) as a
  fallback before requiring the rotating GEMINI_API_KEY_1/2/3 keys.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(knowledge): prefer singular Cohere key before rotation

Match resolveOpenAIKey/resolveGeminiKey order: check the singular
COHERE_API_KEY before falling back to rotating keys.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 01:45:56 -07:00
Waleed cb8ea3a870 fix(fork): clear task selection before navigating to fork (#4356) 2026-04-29 23:39:02 -07:00
Waleed cb43b596b9 feat(fork): optimistic sidebar entry + Fork | prefix for forked tasks (#4353)
* feat(fork): optimistic sidebar entry + rename to 'Fork | Chat Name'

Adds the forked task to the sidebar immediately by writing an optimistic
entry into the task list cache in onSuccess, before the background refetch
arrives. Without this, the sidebar showed no new task until the invalidation
refetch completed after navigation.

Also moves the Fork prefix to the front of the name ('Fork | Chat Name')
so it is immediately scannable in the sidebar.

* fix(fork): cancel in-flight queries before optimistic sidebar write
2026-04-29 22:39:59 -07:00
Waleed 2bb5c91554 improvement(kb-selector): add search to knowledge base selector subblock (#4351) 2026-04-29 19:59:01 -07:00
Waleed 541c1b5846 fix(fork): scope task list invalidation to current workspace (#4350)
* fix(fork): scope task list invalidation to current workspace

* fix(sidebar): remove mutation objects from useCallback deps

Mutation objects are not referentially stable in TanStack Query v5 — only
.mutate() and .mutateAsync() are stable. Removed deleteTaskMutation,
deleteTasksMutation, markTaskReadMutation, and markTaskUnreadMutation from
their respective useCallback dependency arrays to avoid unnecessary
recreations on every mutation state update.
2026-04-29 19:35:41 -07:00
WaleedandClaude Opus 4.7 0c69302369 fix(integrations): harden jira, jsm, ashby, google drive, slack, confluence, notion (#4345)
* fix(integrations): validate and harden jira, jsm, ashby, google drive, slack, confluence, notion

Audit and fix contract drift, input validation, and error handling across integrations:

- Jira: NaN guards on worklog seconds, JSON.parse try/catch on internal API responses,
  domain normalization (strip leading https://), JQL injection prevention via project
  key validation, ADF helper consolidation, /search/jql nextPageToken pagination,
  defensive .trim() on ID path params, encodeURIComponent on watcher account IDs,
  resolveAssigneeAccountId helper, parent-as-object wrapping, summary fallback,
  add read-bulk operation. Restored total field (always null) to preserve contract.
- JSM: customer/organization route validation
- Ashby: types and tool output cleanup across all 30+ tools
- Google Drive: tighter response handling across read/write/share tools
- Slack: types and tool fixes (canvas, reactions, messaging, members)
- Confluence: update tool and types
- Docs: regenerated mdx for all touched integrations

* fix(ashby): add subblock migrations for removed expand form definition fields

* fix(slack): restore canvas_id fallback to data.id for backwards compat

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(jsm): explicit 400 when deprecated `emails` param is sent

Address greptile review on PR #4345: instead of silently dropping
`emails` and falling through to list-customers, return a 400 telling
the caller to use `accountIds`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(google_drive): include HTTP status in fallback error messages

Address greptile review on PR #4345: when Google Drive returns a non-JSON
error body, surface the response status/statusText so failures are
diagnosable instead of falling through to a generic message.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): drop stray websiteUrl→website remap for update_candidate

The update_candidate tool reads params.websiteUrl directly; mapping it
to result.website added a confusing dead field. The websiteUrl subBlock
auto-passes through with the matching name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(google_drive): rename canonical params to avoid subBlock ID clash

`mimeType`, `query`, and `pageSize` canonical IDs collided with existing
subBlock IDs in the same block (failing the canonical-param validation
test). Drop the canonicalParamId from search/get_content single-input
fields and route them to tool params explicitly in tools.config.params.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): remove filterCandidateId from removed-subblock migrations

The candidate-id filter was reintroduced as a valid Ashby subBlock, but
the migration map still rewrote it to _removed_filterCandidateId on every
workflow load, silently breaking the field. Drop the entry so user values
persist.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): restore documented response fields dropped during refactor

Restore three fields that exist in Ashby's API responses but were dropped
during the recent refactor: applicationLimitCalloutHtml on /jobPosting.info,
compensation on /job.info (and add the `compensation` expand), and managerId
on /user.list.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* correctness

* updated types

* fix(ashby): gate operation-specific param mappings to prevent stale overwrites

Multiple subBlocks share the same target tool param (createdAt is set by
appCreatedAt/candidateCreatedAt/noteCreatedAt; candidateId by appCandidateId/
filterCandidateId). Because subBlock values persist across operation switches,
a stale value from a prior operation could silently overwrite the correct one.
Guard each mapping with an explicit operation check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): gate offerApplicationId mapping by operation

Same shared-target hazard as the prior fix: offerApplicationId maps to
result.applicationId without an operation guard, so a stale value from
list_offers could overwrite the active applicationId on get_application,
change_application_stage, or list_interviews.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(ashby): include list_locations in includeArchived condition

Ashby's /location.list accepts includeArchived per the API docs, and the
docs page already documents the toggle for list_locations. Add the missing
operation value so the toggle renders.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(jira): forward explicit notifyUsers=true query param on issue update

Block now distinguishes true/false/undefined for notifyUsers, but the route
collapsed true and undefined into a no-param request. Forward the explicit
true intent so it survives any future API default change or proxy override.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(jira): quote project key in JQL to defend against injection

* fix(jira): quote project key in bulk_read JQL for defense in depth

The alphanumeric regex check above already blocks injection, but quoting
the project key matches the pattern used elsewhere (issues/route.ts) and
hardens the path against future regex changes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 19:08:23 -07:00
Waleed 36742740aa fix(cleanup): batch orphaned snapshot deletes to avoid slow-query spike (#4348)
* fix(cleanup): batch orphaned snapshot deletes to avoid slow-query spike

* fix(cleanup): recheck orphan condition in delete to close TOCTOU gap
2026-04-29 18:02:46 -07:00
Waleed 60816702f5 fix(files): use incremental applyEdits to prevent streaming flicker in Monaco editor (#4347)
* fix(files): use incremental applyEdits to prevent streaming flicker in Monaco editor

* fix(files): use actual model value for additive applyEdits guard

* fix(files): use pushEditOperations instead of applyEdits to align with VS Code streaming pattern

* fix(files): revert to applyEdits to avoid polluting undo stack during streaming
2026-04-29 17:41:02 -07:00
Waleed a9d4e2eca8 fix(trace): normalize keyed tool names and show credits in trace view (#4344)
* fix(trace): normalize keyed tool names and show credits in trace view

- Export normalizeToolId from tools/index.ts so trace-view can reuse it
- Strip resource-id suffixes (knowledge_search_<uuid>, workflow_executor_<uuid>, table_*_<id>) from tool span names at display time so icons resolve and names are readable
- Replace raw dollar formatting with credits in trace header and agent detail panel

* fix(trace): fix sub-credit display, locale, and pluralization in formatCostAmount

* fix(trace): extract normalizeToolId to client-safe module, consolidate log-details formatting utils

* refactor(trace): consolidate shared span utilities into log-details/utils

* fix(tools): import normalizeToolId for internal use after extracting to normalize.ts

* style(trace-spans): replace inline transform style with Tailwind rotate-180 on disclosure chevron

* fix(trace-spans): show credits instead of dollars for cost display

* refactor(trace): move formatCostAmount and getDisplayName to shared utils, normalize tool names in trace-spans

* fix(trace-spans): simplify formatCostSummary to show total credits only
2026-04-29 15:34:02 -07:00
Waleed 1a321c5d5f feat(fork): fork chat from any assistant message (#4343)
* feat(fork): fork chat from any assistant message

* fix(fork): toast on failure, disabled opacity, copy previewYaml/planArtifact/config

* fix(fork): type guard for mothership-only, prevent title accumulation on re-fork

* fix(fork): register task_forked PostHog event type
2026-04-29 12:51:17 -07:00
Waleed 7d8ec24768 feat(firecrawl): add parse operation and revert short-input selection style (#4340)
* feat(firecrawl): add parse operation and revert short-input selection style

* chore(firecrawl): regenerate docs and integrations data for parse

* fix(firecrawl): forward firecrawl error body in parse route response

* fix(firecrawl): add pricing config to parse tool hosting
2026-04-29 12:04:12 -07:00
Theodore Li 8d042f7d20 fix(copilot): fix new task error (#4341)
* fix(copilot): fix new task error

* Keep recent copilot chat open on refresh
2026-04-29 14:39:24 -04:00
Waleed 94f5411a2b fix(files): streaming preview invariant + OOXML style extraction (#4335)
* fix(files): suppress transient streaming preview errors for docx and pptx

* feat(files): add OOXML style extraction for uploaded docx/pptx files

New GET /api/workspaces/[id]/files/[fileId]/style endpoint + VFS read
path files/by-id/{id}/style that returns a compact JSON style summary
from an uploaded binary .docx or .pptx: theme name, 12-slot color
palette, major/minor font pair, and key named styles (Normal, H1-H3,
Title). Logic lives in a shared lib/copilot/vfs/document-style.ts so
both the REST API and the VFS read handler reuse the same parsing code.

* chore(files): polish style extraction — type narrowing + empty-styles guard

Explicit 'docx' | 'pptx' type annotation after the extension guard in
both route.ts and workspace-vfs.ts so TypeScript sees the narrowed type
rather than string. Only set summary.styles when the parsed array is
non-empty so the JSON response doesn't include "styles": []. Remove
redundant inline WHAT-comments from parseColorSlot.

* fix(files): tighten streaming preview invariant and component consistency

- Apply structural invariant to PDF streaming path: never surface errors
  while streamingContent is defined; only log at info level
- Remove redundant setRenderError(null) from DOCX streaming effect — the
  gate at the display layer already suppresses errors during streaming
- Wrap PptxPreview in memo for consistency with DocxPreview
- Add key={file.id} to PptxPreview mount site (was missing, DocxPreview
  had it) so the component resets when the viewed file changes
- Fix --text-body → --text-primary across PreviewError, UnsupportedPreview,
  and MermaidDiagram error label; --text-body is not a valid EMCN token

* fix(files): remove setRenderError(null) from PPTX and PDF streaming paths

* feat(files): add compiled-check endpoint and VFS path for binary document self-verification

* fix(files): remove dead renderError state from IframePreview

* refactor(files): hoist BINARY_DOC_TASKS to module scope in compiled-check route and VFS handler

* fix(files): deduplicate BINARY_DOC_TASKS and add size guard to VFS compiled-check
2026-04-29 09:05:53 -07:00
Waleed 52c93d414b improvement(docs): soften video hover opacity (#4339) 2026-04-29 08:43:15 -07:00
Vikhyath Mondreti 61342e2567 fix(notion): correctly register tool (#4337) 2026-04-28 20:41:40 -07:00
Theodore LiandClaude Opus 4.7 ed7786d7fd fix(ui): adjust docx and code rendering (#4334)
* fix(ui): adjust docx and code rendering

* fix(ui): address PR feedback on docx fit and Monaco type cast

Use computed padding from `.docx-wrapper` instead of a hardcoded 60px
so the fit calculation survives docx-preview library changes. Replace
the inline `import()` cast for ShowLightbulbIconMode with a top-level
type import.

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

* fix lint

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 22:52:11 -04:00
Waleed e2ded1643c fix(snapshot): stop markdown preview auto-scroll during patch streams + snapshot styling (#4333)
* fix(files): stop markdown preview auto-scrolling during copilot patch streams

fix(snapshot): use surface-4 background for input/output code blocks in light mode

* fix(files): separate auto-scroll gate from streaming render mode in MarkdownPreview
2026-04-28 18:37:15 -07:00