Commit Graph

1217 Commits

Author SHA1 Message Date
claude code agent 227
bc1ea792f5 test(page-templates): cover duplicatePage pageEmbed remap + reference sync (#32)
Extract the per-node pageEmbed remap decision into a shared pure helper
(remapPageEmbedSourceId) and use it BOTH in PageService.duplicatePage and the
JSON walker, so the test guards the real production path (not a mirror that
could drift). Behavior is identical: source in the copied set -> new copy id;
otherwise keep the original. Add jest coverage (16 tests): the remap helper
(in-set/out-of-set/null/nested), syncPageTemplateReferences toDelete (stale refs
removed with the right workspaceId), and insertTemplateReferencesForPages
multi-workspace grouping/filtering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:37:35 +03:00
claude code agent 227
98769155d3 test(page-templates): cover client pageEmbed cycle/self-embed/depth guard (#31)
The cycle/self-embed/depth guard (PAGE_EMBED_MAX_DEPTH=5) lives only on the
client and is the sole protection against runaway nested rendering — and was
untested. Extract the inline predicates into pure, behavior-identical exported
helpers (isPageEmbedCycle, isPageEmbedTooDeep in the ancestry context;
filterPageEmbedOptions in the picker) so they're unit-testable without mounting
the heavy Tiptap NodeView, and add vitest coverage (20 tests): ancestry chain/
host accumulation, cycle (ancestor-in-chain + top-level self-embed), too-deep at
the cap, and picker host-exclusion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:37:35 +03:00
claude code agent 227
4f46f91db4 test(page-templates): fix TransclusionService spec constructor arity
The transclusion specs predated two added constructor params, so they failed to
compile (TS2554: expected 11 args, got 10) and the suites couldn't run. Add the
missing mock args: workspaceRepo (param 11) in the lookup/access specs, and
pageTemplateReferencesRepo (param 4, which had shifted pageRepo into the wrong
slot) in the unsync-html-embed spec. All three suites now compile and pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:22:56 +03:00
claude code agent 227
79d096ed7a fix(page-templates): defense-in-depth workspace checks (#36)
Consistency hardening from #17 review (not currently exploitable):
- toggleTemplate now explicitly rejects a page outside the caller's workspace
  (page.workspaceId !== user.workspaceId -> NotFound, avoiding existence leak)
  instead of relying solely on the space-membership model.
- PageTemplateReferencesRepo.deleteByReferenceAndSources is now workspace-scoped
  (adds a workspaceId filter + param), matching the 'scope by workspaceId
  everywhere' invariant; the sole caller threads its workspaceId.
The PAGE_TEMPLATE_THROTTLER limit is intentionally left as-is (the issue's
throttle item was 'consider only'; no change without usage data).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:42:49 +03:00
claude code agent 227
a15cccf557 chore(page-templates): remove dead findReferencePageIdsBySource (#34)
The 'used in N pages' reverse-navigation method had zero callers in the merged
PR #17 — unreachable, untested code. Remove it. The reverse-navigation feature
can be (re)added with the method if/when it's actually built.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:42:49 +03:00
claude code agent 227
22887c474a chore(page-templates): tidy ts suppression in duplicatePage pageEmbed remap (#37)
Replace bare //@ts-ignore (no space, no reason) with // @ts-expect-error plus a
reason on the pageEmbed sourcePageId reassignment, matching the codebase style.
ProseMirror Attrs is read-only typed, so the reassignment genuinely errors —
@ts-expect-error is valid here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:42:30 +03:00
claude code agent 227
4536d27ad2 fix(page-templates): never strand a page-embed id in-flight (#35)
In the page-embed lookup flush(), the success branch cleared inFlightRef and
resolved waiters only for ids present in the response items. A short/partial
server response would leave a requested id stuck in inFlightRef forever (the
subscribe/refresh path is guarded by !inFlightRef.has(id)) and its refresh()
promise would never resolve. After processing returned items, also clear +
resolve any requested id that wasn't returned, mirroring the catch branch.
Cannot trigger under today's exact-mapping server contract; this is hardening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:42:30 +03:00
claude code agent 227
b8655ae52c fix(page-templates): make page-embed Refresh actually re-render (#40)
The read-only embed renderer mounts a Tiptap EditorProvider with the looked-up
content, but Tiptap consumes the `content` option only at initial mount. After
Refresh busted the lookup cache and re-fetched fresh content, the new content
prop never reached the sub-editor, so the embed appeared not to update at all.

Key PageEmbedContent on result.sourceUpdatedAt (the source page's updatedAt,
already returned by the lookup and bumped on every persisted content change) so
the component and its EditorProvider remount and apply the refreshed content
when the source changes.

Note: server-side freshness vs. live collab edits is bounded by the 10s persist
debounce (collaboration.gateway.ts) — that separate limitation stays documented
in #40 and is out of scope here; this commit fixes the client never re-rendering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:26:42 +03:00
claude code agent 227
c9eb495688 fix(page-templates): clean up page-embed node chrome (#39)
Two design problems on the whole-page embed (pageEmbed) node:

- Double selection frame: the generic square cyan .ProseMirror-selectednode
  outline stacked on top of the rounded .includeWrap border. Add node-pageEmbed
  to the existing outline:none rule (already covering the transclusion nodes) so
  only the single rounded border remains.
- Redundant 'open source' controls: the floating toolbar's external-link button
  duplicated the header badge title link. Remove the toolbar button; the badge
  title is now the single way to open the source (kept Refresh + ... menu).
  Also swap the badge fallback icon IconArrowsMaximize (read as 'expand') for a
  neutral IconFileText.

Follow-ups from review: render the badge whenever the source resolves (so the
only open-source link can't vanish when title+icon are empty), and label the
link (title/aria-label) + add the 'Open source page' i18n key (en-US, ru-RU).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:21:32 +03:00
claude code agent 227
859223db1a fix(page-templates): show a template marker icon in the page tree (#38)
Template pages were toggleable but indistinguishable in the sidebar tree.
Render an IconTemplate next to the title when node.isTemplate is true, wrapped
in a Tooltip(label='Template') with an aria-label + role='img' for AT. The
icon is a child of the row Link so clicks navigate as normal; pointer events
stay enabled so the tooltip's hover handlers fire. Adds the 'Template' i18n
key to en-US and ru-RU (other locales fall back to en-US).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 21:15:43 +03:00
claude_code
b53b0c651e docs(footnotes): delete footnotes design plan
Some checks failed
Develop / build (push) Has been cancelled
The detailed footnotes implementation plan has been removed from the repository now that the design is finalized and tracked elsewhere.
2026-06-20 21:03:50 +03:00
claude_code
be17391e18 docs: remove admin-only HTML embed documentation
Some checks failed
Develop / build (push) Has been cancelled
2026-06-20 21:03:31 +03:00
claude_code
19ae6a0efa Merge pull request 'feat(editor): page templates — live whole-page embed (MVP)' (#17) from feat/page-templates into develop
Some checks failed
Develop / build (push) Has been cancelled
2026-06-20 20:34:44 +03:00
claude_code
7a03321d43 Merge pull request 'feat(editor): admin-only raw HTML/CSS/JS embed (variant C)' (#16) from feat/html-embed-admin into develop
Some checks failed
Develop / build (push) Has been cancelled
2026-06-20 20:19:06 +03:00
claude_code
2b3fc926cc Merge remote-tracking branch 'gitea/develop' into feat/html-embed-admin
# Conflicts:
#	apps/server/src/core/workspace/services/workspace.service.ts
2026-06-20 20:18:44 +03:00
claude_code
e9e9f74ec6 Merge remote-tracking branch 'gitea/develop' into feat/page-templates
# Conflicts:
#	apps/server/src/integrations/throttle/throttle.module.ts
#	apps/server/src/integrations/throttle/throttler-names.ts
2026-06-20 20:18:42 +03:00
claude code agent 227
52efd37fd9 fix(page-templates): import ThrottleModule into collab app so it boots
PageTemplateController (added on this branch) guards its lookup/toggle routes
with UserThrottlerGuard, which depends on the throttler options provided by
ThrottleModule. CollaborationModule -> TransclusionModule registers that
controller, and the collab server bootstraps CollabAppModule, which did not
import ThrottleModule. The API server's AppModule does, so :3000 booted, but
the collab server (:3001) crashed at startup with
'Nest can't resolve dependencies of the UserThrottlerGuard ... THROTTLER:MODULE_OPTIONS'.
Without collab the editor can't sync, so live editing was broken on this branch.

Import ThrottleModule into CollabAppModule, mirroring AppModule, so the guard
resolves in the collab process too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 20:10:09 +03:00
claude_code
d80a419963 ci(develop): build the :develop image on push to develop, not main
Some checks failed
Develop / build (push) Has been cancelled
The "Develop" workflow builds the :develop image but was triggered on
push to main (the stable/default branch, released via v* tags). Switch
the trigger to the develop branch so pushes to develop build the image.
2026-06-20 20:05:44 +03:00
claude_code
6128920264 Merge pull request 'feat(public-share): selectable agent-role identity + fix floating-icon overlap' (#25) from feat/share-assistant-identity-and-branding into develop 2026-06-20 19:59:48 +03:00
claude_code
cf29a0fc11 0.93.0 2026-06-20 19:57:37 +03:00
claude_code
4fe42ead56 feat(public-share): selectable agent-role identity + fix floating-icon overlap
Anonymous public-share AI assistant:
- Add a workspace setting `publicShareAssistantRoleId` so an admin can pick which
  agent role (identity/persona) the anonymous assistant adopts. The role's
  instructions REPLACE the built-in persona while the immutable safety framework
  is still always appended; the role's optional model override takes precedence
  over the cheap publicShareChatModel. Resolved server-authoritatively
  (workspace-scoped, soft-delete aware; disabled/missing roles fall back to the
  built-in persona, so the tool scope remains the real security boundary).
- Plumb the field through the update DTO, ai-settings service, the workspace.repo
  ALLOWED whitelist, resolve()/getMasked(), stream-time role resolution and the
  prompt/model, plus the settings UI: a new "Assistant identity" Select listing
  enabled roles (and surfacing a saved-but-disabled role explicitly).

Public-share branding / floating icon:
- Fix the AI assistant FAB overlapping the "Powered by ..." button (both were
  Affixed bottom-right): stack the FAB above the bottom-right branding.
- Rename "Powered by Docmost" -> "Powered by Gitmost" and point the link at the
  gitmost repo.

Tests: extend public-share-chat.spec (role persona replacement still appends the
safety framework, resolveShareRole edge cases, model-override precedence).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:54:45 +03:00
claude code agent 227
41f3944e79 fix(html-embed): execute embeds on public shares; toggle is server-side kill switch
The html-embed feature toggle was enforced CLIENT-side in the NodeView (reads
settings.htmlEmbed from the logged-in workspace), so an anonymous public-share
viewer — who has no workspace context — always saw it as OFF and got a
placeholder instead of the executing embed. That broke the whole point (a
tracker must run for anonymous visitors).

Make it server-authoritative:
- share.service prepareContentForShare (the single path both share-content
  flows use) strips htmlEmbed from served content when the workspace toggle is
  OFF; both callers (updatePublicAttachments host page + lookupTransclusionForShare)
  resolve the toggle once and pass it. Fail-closed: missing workspace -> OFF ->
  stripped.
- NodeView executes whatever it was served in read-only/share mode
  (shouldExecute = !editor.isEditable || htmlEmbedEnabled); the disabled
  placeholder now only shows in the editable editor when OFF.

Net: anonymous share + toggle ON -> server serves the (admin-authored) embed ->
it executes for everyone; toggle OFF -> stripped server-side from every
share-content path (true kill switch); a non-admin embed can never be served
(save-path strip). No XSS regression in the editable editor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:49:57 +03:00
claude_code
46688074d8 Merge pull request 'feat(tree): server-authoritative realtime tree updates' (#15) from feat/realtime-tree-server into develop 2026-06-20 19:48:36 +03:00
vvzvlad
f650d2591b fix(tree): address realtime-tree-server review findings
- make addTreeNode receivers idempotent (invalidateOnCreatePage guard +
  buildTree dedup) so the author's self-echo no longer duplicates the node
- broadcast realtime tree updates for bulk copy/duplicate and import via a
  root refetch: PAGE_CREATED now carries spaceId and the WS listener falls
  back to refetchRootTreeNodeEvent when no per-node snapshot is present
- remove the now-dead client-relay inbound path (isTreeEvent/handleTreeEvent)
  that remained a stale-restriction-cache attack surface
- honest string|null cast for a root move's parent id
- add tests: buildTree dedup; onPageCreated per-node vs refetch branching

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:48:06 +03:00
claude_code
f72e44c9b7 Merge pull request 'feat(mcp): per-user auth for /mcp (HTTP Basic, server-validated)' (#13) from feat/mcp-per-user-auth into develop 2026-06-20 19:32:02 +03:00
claude code agent 227
8fcce6a674 feat(html-embed): per-workspace feature toggle, default OFF
The admin-only raw HTML/JS embed is a deliberate stored-XSS surface, so gate the
whole feature behind a workspace toggle that is OFF by default; it only works
when a workspace admin explicitly enables it.

- settings.htmlEmbed (boolean, default false) + workspace-update field htmlEmbed,
  persisted via WorkspaceRepo.updateSetting with an audit diff. Flipping it is
  admin-only (same Manage Settings CASL as other workspace toggles).
- New gate htmlEmbedAllowed(featureEnabled, role) = featureEnabled && admin/owner.
  All 7 server write paths (create, duplicate, collab onStoreDocument, REST/MCP/AI
  updatePageContent, single + zip import, transclusion unsync) now read the
  workspace's settings.htmlEmbed and strip unless (toggle ON AND admin). OFF
  (default, or a failed/empty workspace lookup) strips htmlEmbed for EVERYONE
  including admins -> existing embeds are cleaned up on next save, none persist.
- Client (defense-in-depth): the /html slash item is hidden unless toggle ON +
  admin; the NodeView executes nothing and shows a 'disabled in this workspace'
  placeholder when OFF; an admin Switch in Workspace Settings -> General with a
  description of the behavior.
- docs/html-embed-admin.md documents the toggle + admin-only + fail-closed
  coedit (a non-admin save strips an admin's embed) + execution semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 19:28:39 +03:00
claude_code
c718b2a6de Merge pull request 'feat(ai): anonymous AI assistant on public shares' (#14) from feat/public-share-assistant into develop 2026-06-20 18:41:17 +03:00
vvzvlad
0c46f60ddf Merge gitea/develop into feat/public-share-assistant
Resolve conflicts with the independently-merged ai-agent-roles feature:
- ai-chat.module.ts: keep BOTH AiAgentRolesModule and the public-share
  wiring (Share/Search modules, PublicShareChatController, services).
- ai.service.ts: take develop's getChatModel ChatModelOverride superset,
  which already covers the public-share model-id-only override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:40:58 +03:00
vvzvlad
90e9b0a3f4 docs(public-share): document trusted-proxy XFF requirement + cost cap
The anonymous public-share AI assistant's per-IP rate limit is only
effective behind a trusted reverse proxy that overwrites X-Forwarded-For
with the real client IP (the app runs with trustProxy). Document this
deployment requirement and the per-workspace cost backstop env var
(SHARE_AI_WORKSPACE_MAX_PER_HOUR, default 300) in .env.example.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:34:16 +03:00
claude_code
4c1d1aa2ee Merge pull request 'feat(ai-chat): agent roles (admin persona + optional model)' (#11) from feat/ai-agent-roles into develop 2026-06-20 18:31:10 +03:00
vvzvlad
4b31128e24 fix(ai-roles): harden model override, role-name uniqueness, id validation, list least-privilege
Follow-up fixes on the agent-roles feature:

- ai.service: a cross-driver override to the ollama driver (when the
  workspace driver is not ollama) now fails with an explicit 503 instead
  of silently reusing the workspace base URL, which belongs to a different
  provider. Same-driver ollama and openai/gemini overrides are unchanged.
- migration: add a partial unique index on (workspace_id, name) WHERE
  deleted_at IS NULL so role names are unique per workspace without
  soft-deleted rows blocking re-creation; map Postgres 23505 to a 409
  ConflictException on create/update.
- dto: validate the role id as @IsUUID instead of @IsString.
- roles list: do not expose instructions/modelConfig to non-admin members.
  The list endpoint now returns a picker view (id/name/emoji/description/
  enabled) to members and the full view only to admins (same gate as the
  CRUD endpoints). Client IAiRole fields made optional accordingly.

Adds tests for the cross-driver-ollama throw, the 23505->409 mapping, and
the non-admin picker-view security invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:30:33 +03:00
claude_code
127d26c057 Merge pull request 'test(ai-chat): crypto/SSRF/assistant-parts coverage + a11y + refactors' (#10) from feat/ai-chat-review-followups into develop 2026-06-20 18:10:33 +03:00
vvzvlad
45cf4140eb Merge branch 'develop' into feat/ai-chat-review-followups
Integrate the already-merged step-limit work from develop. Only conflict was
ai-chat.service.spec.ts: both sides appended a describe block and edited the
import line. Resolved as a union — keep compactToolOutput + the assistantParts/
serializeSteps/rowToUiMessage suites (this branch) AND the prepareAgentStep
suite (develop), importing all symbols from ai-chat.service.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:09:17 +03:00
claude code agent 227
ec128d54b4 test(ssrf): add IP-level bypass-vector cases (ported from GLM branch)
Adds explicit isIpAllowed cases for the CGNAT, ULA (fd00::/8) and IPv4-mapped
IPv6 loopback (::ffff:127.0.0.1) sample addresses from the parallel
safety-coverage branch. The mapped-loopback case is genuinely new (the existing
table only covered the mapped *private* variant); CGNAT and ULA ranges were
already covered with other samples and are kept here as explicit regression
guards for these specific addresses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:00:43 +03:00
claude code agent 227
cedea4072b refactor(ai-chat)!: unify provider error formatting via describeProviderError
Behaviour change (split out of the test commit per review, and now covered).

Both the stream onError log line and the error text streamed to the client were
formatted by separate inline blocks that only emitted "<status>: <message>".
Route both through the shared describeProviderError() so formatting stays in one
place.

BEHAVIOUR CHANGE: describeProviderError additionally appends a single-line,
300-char-truncated snippet of the provider responseBody/text. So the log line
AND the user-facing stream error now include that snippet (e.g. the HTML error
page from a misconfigured endpoint), which previously neither did. This is
intentional — it makes a misconfigured external endpoint diagnosable — and is
safe: the API key travels in the Authorization header and is never echoed in
the response body (see the util's docstring). A `fallback` param is added so
each call site keeps its own default ('AI stream error' for the stream).

Adds ai-error.util.spec.ts covering the formatter, including the appended /
truncated body snippet, so this behaviour is no longer untested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:59:55 +03:00
claude code agent 227
1e650262a4 fix(ai-chat): record chats that fail on their first turn
Behaviour change (split out of the test commit per review).

In AI SDK v6 the useChat `onFinish` callback does NOT fire when the stream
errors. A brand-new chat whose very first turn fails would therefore never run
the post-turn path: the chat list was not invalidated and the client never
adopted the server-created chat id — so the failed chat only appeared in
history after a manual refresh (the server already creates the row and stores
the error message). Running the same `onTurnFinished()` handler on `onError`
makes the failed chat show up immediately. The error itself is still surfaced
to the user via the existing `error` state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:58:57 +03:00
claude code agent 227
f1980cf425 test(ai-chat): safety-critical coverage + a11y + pure refactors
Unit tests for the safety-critical paths: crypto secret-box (round-trip,
tamper detection, wrong key), the SSRF guard (blocked ranges + DNS-rebinding),
the ai-chat tools service, the page-embedding repo, and the
assistant-parts/serialization helpers. Those server helpers (assistantParts,
rowToUiMessage, serializeSteps) are exported ONLY for the tests — no runtime
change.

Also: keyboard a11y on the chat history header and conversation rows
(role/tabIndex/Enter+Space), and DRY refactors that move shared logic into one
place (isToolPart -> tool-parts util; buildInitialValues in the MCP form).

The behaviour-changing edits that previously rode along in this commit are
split out into the following two commits, per review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:58:44 +03:00
claude_code
965cbb32e5 Merge pull request 'feat(ai-chat): step cap 8→20 + forced final text answer' (#9) from feat/ai-chat-step-limit into develop 2026-06-20 17:47:37 +03:00
vvzvlad
0b969c8675 test(ai-chat): pin step-limit boundary + note AI SDK v7 system->instructions
Port two refinements from the GLM variant onto the Claude base:
- prepareAgentStep: add a comment note that AI SDK v7 renames the per-step
  `system` field to `instructions` (v6 ^6.0.134 still uses `system`), so it
  gets updated correctly on the next SDK bump.
- ai-chat.service.spec: add an explicit off-by-one boundary test for
  prepareAgentStep, expressed via MAX_AGENT_STEPS instead of a hardcoded 18/19
  so it tracks the constant if the cap changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:47:16 +03:00
claude_code
b20ffd1b91 Merge pull request 'feat(tree): Expand all / Collapse all for the space page tree' (#23) from feat/tree-expand-collapse-all-agent227 into develop 2026-06-20 17:40:29 +03:00
vvzvlad
949a251553 fix(tree): close the space menu after Expand all
Expand all kept the menu open (closeMenuOnClick={false}) while Collapse all
closed it. Make both close on click for consistent behavior, and drop the
now-pointless in-menu isExpanding loading state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:39:34 +03:00
vvzvlad
234ae759f5 refactor(tree): borrow cleanups from the sibling expand-all impl
- extract collectAllIds / collectBranchIds into tree/utils and use them in
  space-tree.tsx instead of inline closures
- drop the duplicate SidebarPageTreeDto, reuse the existing SidebarPageDto
  for the /pages/tree endpoint
- type the getSpaceTree client call as api.post<{ items: IPage[] }>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:39:34 +03:00
claude_code
151bd7a0e0 Merge pull request 'feat(ai-settings): rebind endpoint status dot to configured x enabled' (#19) from feat/ai-endpoint-status-dot-config-enabled into develop 2026-06-20 17:22:22 +03:00
vvzvlad
689f435630 docs: remove implemented ai-endpoint-status-dot backlog plan
The configured x enabled status dot is implemented and merged via this
branch, so the backlog plan is no longer needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:22:03 +03:00
claude_code
1982ef0f23 Merge pull request 'feat(ai-settings): put Clear inside the API key field, drop the eye' (#20) from feat/api-key-clear-in-place-of-eye into develop 2026-06-20 17:18:54 +03:00
vvzvlad
4bfb143288 docs: remove implemented api-key-field-clear backlog plan
The in-field Clear for the API key fields is implemented and merged via
this branch, so the backlog plan is no longer needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:18:24 +03:00
claude_code
f8bb4b37ce Merge pull request 'feat(comments): denser comments panel' (#5) from feat/comments-panel-density into develop 2026-06-20 17:10:30 +03:00
claude code agent 180
d11cf0112f Merge branch 'feat/compact-page-tree-toggle-180' into develop
Gate page-tree row density behind the COMPACT_PAGE_TREE flag
(standard 32px default, compact 26px opt-in). Authored by the local
Claude agent on machine 180.
2026-06-20 16:59:43 +03:00
claude code agent 180
36ae4bd3d3 feat(page-tree): gate compact tree density behind COMPACT_PAGE_TREE flag
Make the denser page-tree layout opt-in instead of hardcoded, so row
density can be toggled per deployment via the COMPACT_PAGE_TREE runtime
config flag.

- doc-tree: extract ROW_HEIGHT_STANDARD (32) / ROW_HEIGHT_COMPACT (26);
  default the virtualizer row stride to STANDARD density.
- client: isCompactPageTreeEnabled() in lib/config (reads
  COMPACT_PAGE_TREE, default true); used by space-tree and shared-tree
  to choose the row height.
- server: EnvironmentService.isCompactPageTreeEnabled() and expose
  COMPACT_PAGE_TREE through the window runtime config (static.module).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 16:54:09 +03:00
claude code agent 227
be2530a0b9 chore(tree): document the restriction-cache primitive; drop dead notify code
Release-cycle audit flagged WsService.invalidateSpaceRestrictionCache and
WsTreeService.notifyPageRestricted/notifyPermissionGranted as never-wired dead
code. Investigation: this community fork has NO page-permission grant/revoke/
restrict mutation site (the page-access repo mutators have zero callers — that
flow is EE / not yet built), so there is nothing to wire them into.
- Keep invalidateSpaceRestrictionCache (it's the one-line correctness primitive
  the future permission-mutation path must call to avoid the 30s stale-cache
  window) but document exactly that + add a test that it deletes only the
  space-scoped cache key.
- Remove the untested, security-adjacent dead methods notifyPageRestricted /
  notifyPermissionGranted and their now-orphaned helpers emitToUsers /
  emitToSpaceExceptUsers (no remaining references; build confirms). A future
  permission-change realtime feature can reintroduce them wired + tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 15:50:53 +03:00