wiki-viewer 2.12.0 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +14 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/routes-manifest.json +81 -3
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +7 -7
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +7 -7
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/live/attach/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/{internal/span → live/attach}/route.js +11 -11
- package/.next/standalone/.next/server/app/api/agent/live/attach/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/live/attach/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route.js +17 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/live/md-preview/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route.js +17 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/live/poll/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/reply/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/reply/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/live/reply/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/live/reply/route.js +17 -0
- package/.next/standalone/.next/server/app/api/agent/live/reply/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/{internal/span → live/reply}/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/live/reply/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route.js +18 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/live/web-preview/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +9 -9
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/pdf/save/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/asset/route.js +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/asset/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/route.js +1 -1
- package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/branch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js +1 -1
- package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/content/route.js +1 -1
- package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-history/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route.js +18 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-request/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route.js +18 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-resolve/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-status/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-status/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-status/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-status/route.js +16 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-status/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/live/md-status/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/{agent/internal/span → wiki/live/md-status}/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/wiki/live/request/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/request/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/live/request/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/live/request/route.js +16 -0
- package/.next/standalone/.next/server/app/api/wiki/live/request/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/live/request/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/live/request/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route.js +17 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/live/status/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/outlinks/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/scratch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/search/route.js +1 -1
- package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route.js +7 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/picker.js/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route.js +16 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/request/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route.js +17 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/resolve/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route.js +16 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/web-tweak/status/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/s/[token]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +14 -1
- package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_031ecpl.js +274 -0
- package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0afqvqi.js +3 -0
- package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0ofi5.l.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__07wa2lq._.js → [root-of-the-server]__0-l8919._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0e~2gkf._.js → [root-of-the-server]__0-vsohg._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.xk8gi._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0002pqj._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01v1udu._.js +16 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01y-312._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__020sc-x._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02373p-._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0n2r6u9._.js → [root-of-the-server]__03c8~ck._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__03qy0.z._.js +55 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__056pu9b._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06kspyc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07bxa4u._.js +90 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08xiuca._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0936qml._.js +43 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__09g2xhj._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0badnl7._.js +43 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bqhp4b._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0dk42.p._.js +90 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e_irm6._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0iksibp._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jlrhzi._.js +55 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kamtmx._.js +50 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kpcc70._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0laknd~._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0m.o598._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0mgvfb5._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n7uto3._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oxzq2p._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0r-3u3v._.js +8 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t8r97l._.js +50 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vuw0yp._.js +50 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0xoz8e8._.js → [root-of-the-server]__0wtrbmm._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0y4lx2l._.js +50 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z5xk6f._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zrcu6l._.js +20 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10-ona2._.js +20 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__130a-u1._.js +50 -0
- package/.next/standalone/.next/server/chunks/_079xuln._.js +1 -1
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_live_attach_route_actions_0cy5eae.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_live_md-preview_route_actions_07po~tm.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_live_poll_route_actions_0tef7r~.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_live_reply_route_actions_0modpib.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_live_web-preview_route_actions_0qjm1cw.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_live_md-request_route_actions_0z5ad2q.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_live_md-resolve_route_actions_0_8g88b.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_live_md-status_route_actions_02ykgzf.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_live_request_route_actions_00m8pc2.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_live_status_route_actions_0v.pypx.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_web-tweak_picker_js_route_actions_118~f~j.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_web-tweak_request_route_actions_0wlzrco.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_web-tweak_resolve_route_actions_0wq6pw5.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_web-tweak_status_route_actions_0vr4h6u.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{0~w0_katex_dist_katex_mjs_0-fyxoz._.js → 0~w0_katex_dist_katex_mjs_0okh~tf._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_blockDiagram-GPEHLZMM_mjs_0v204vn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_c4Diagram-AAUBKEIU_mjs_0.iwqva._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-3OPIFGDE_mjs_09p1amp._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-5ZQYHXKU_mjs_0z1.978._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-727SXJPM_mjs_115~dsb._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-AQP2D5EJ_mjs_0euza.d._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-CSCIHK7Q_mjs_01i7moi._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-KSCS5N6A_mjs_0v4oeem._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_chunk-O5CBEL6O_mjs_11437bo._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_dagre-BM42HDAG_mjs_05ekknz._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_diagram-OG6HWLK6_mjs_0t5sus6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_erDiagram-TEJ5UH35_mjs_0v6rnqy._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_flowDiagram-I6XJVG4X_mjs_13pu1pv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_gitGraphDiagram-PVQCEYII_mjs_0jp8i-h._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_ishikawaDiagram-YF4QCWOH_mjs_0tcayi4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_journeyDiagram-JHISSGLW_mjs_0-ln2o9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_kanban-definition-UN3LZRKU_mjs_0_sdvmq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_mindmap-definition-RKZ34NQL_mjs_002sdr9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_quadrantDiagram-W4KKPZXB_mjs_0re1qsf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_requirementDiagram-4Y6WPE33_mjs_067p6fg._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_sankeyDiagram-5OEKKPKP_mjs_11ifrnu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_sequenceDiagram-3UESZ5HK_mjs_015n5fb._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_stateDiagram-AJRCARHV_mjs_0q8ykwx._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_timeline-definition-PNZ67QCA_mjs_0ie6b6s._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_vennDiagram-CIIHVFJN_mjs_0hds9fe._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_wardleyDiagram-YWT4CUSO_mjs_0s.dkn9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_xychartDiagram-2RQKCTM6_mjs_0v-eh5w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_mermaid_core_mjs_0hj_n-~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0~4py6h._.js → [root-of-the-server]__0t5fses._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0d9d~c~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0kkaybx._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0oq8kwv._.js +284 -12
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0f0qocb._.js → node_modules__pnpm_0-l23--._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0_g0a7t._.js → node_modules__pnpm_00d-n5v._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0v7wopg._.js → node_modules__pnpm_014r.0e._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0zdl7-7._.js → node_modules__pnpm_03j578g._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_04rulr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09y5c~i._.js → node_modules__pnpm_05qsb2c._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0sdy2lv._.js → node_modules__pnpm_08i5ti8._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0b6_242._.js → node_modules__pnpm_09t82cx._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0f6r-u~._.js → node_modules__pnpm_09~hu70._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0pggrwu._.js → node_modules__pnpm_0cfriah._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_02qa21p._.js → node_modules__pnpm_0ct341~._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0d4-t2b._.js → node_modules__pnpm_0eps_u_._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0fb6~r_._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0q9s5k5._.js → node_modules__pnpm_0k47joo._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0l9eomm._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0q_v1_2._.js → node_modules__pnpm_0nsy85b._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0vahm7l._.js → node_modules__pnpm_0n~wbom._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0.xieh4._.js → node_modules__pnpm_0o1._vw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0kib6pw._.js → node_modules__pnpm_0t21hj7._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0~wqhb9._.js → node_modules__pnpm_0tl8mi0._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0f9artj._.js → node_modules__pnpm_0tqv.ym._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_05c~go7._.js → node_modules__pnpm_0v9mhna._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_07hg43b._.js → node_modules__pnpm_0w8.hpb._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0_zd0nt._.js → node_modules__pnpm_0wrxa~f._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0g_tlt-._.js → node_modules__pnpm_0xrjcxa._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ghm84g._.js → node_modules__pnpm_0xrusyy._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0c6q9~6._.js → node_modules__pnpm_0y.wb-7._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0tvmv0e._.js → node_modules__pnpm_0yu-3eu._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0k6yfdh._.js → node_modules__pnpm_11q1n~-._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_01~03ak._.js → node_modules__pnpm_1323nh~._.js} +2 -2
- package/.next/standalone/.next/server/functions-config-manifest.json +15 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/0k~5ok-cacnor.js +417 -0
- package/.next/standalone/.next/static/chunks/{04um2f1eeqcss.js → 0noq2zqrh0z_0.js} +1 -1
- package/.next/standalone/.next/static/chunks/{04f8lhbw6m9ee.js → 0tn7wdt213lbb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{138ap~9f.rqkh.css → 12-umagms5yro.css} +1 -1
- package/.next/standalone/.next/static/chunks/17446l.6t9j17.css +1 -0
- package/.next/standalone/.test-floor +1 -1
- package/.next/standalone/_status.md +19 -0
- package/.next/standalone/meta/contract.md +67 -0
- package/.next/standalone/meta/overview.md +10 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/queries/lint-2026-08-15.md +28 -0
- package/.next/standalone/server.js +1 -1
- package/.next/standalone/specs/changes/block-preconditions/proposal.md +90 -0
- package/.next/standalone/specs/changes/blockref-frontmatter-misalign/proposal.md +81 -0
- package/.next/standalone/specs/changes/collective-agent-review/design.md +183 -0
- package/.next/standalone/specs/changes/collective-agent-review/proposal.md +138 -0
- package/.next/standalone/specs/changes/collective-agent-review/requirements.md +100 -0
- package/.next/standalone/specs/changes/collective-agent-review/tasks.md +62 -0
- package/.next/standalone/specs/changes/live-collab/design.md +141 -0
- package/.next/standalone/specs/changes/live-collab/proposal.md +133 -0
- package/.next/standalone/specs/changes/live-collab/requirements.md +91 -0
- package/.next/standalone/specs/changes/live-collab/tasks.md +39 -0
- package/.next/standalone/specs/changes/live-collab-web/findings-termdeck.md +120 -0
- package/.next/standalone/specs/changes/live-collab-web/proposal.md +184 -0
- package/.next/standalone/specs/changes/live-unified/design.md +49 -0
- package/.next/standalone/specs/changes/live-unified/proposal.md +54 -0
- package/.next/standalone/specs/changes/web-tweak-variants/proposal.md +65 -0
- package/.next/standalone/wp-test-6mm5qr/burst-0.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-1.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-10.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-11.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-12.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-13.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-14.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-15.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-16.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-17.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-18.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-19.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-2.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-20.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-21.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-22.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-23.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-24.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-25.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-26.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-27.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-28.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-29.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-3.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-30.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-31.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-32.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-33.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-34.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-35.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-36.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-37.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-38.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-39.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-4.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-40.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-41.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-42.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-43.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-44.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-45.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-46.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-47.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-48.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-49.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-5.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-6.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-7.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-8.txt +1 -0
- package/.next/standalone/wp-test-6mm5qr/burst-9.txt +1 -0
- package/.next/standalone/wp-test-SiMBLk/child/nested.txt +1 -0
- package/.next/standalone/wp-test-SiMBLk/rootfile.txt +1 -0
- package/.next/standalone/wp-test-bFyuuZ/child/nested.txt +1 -0
- package/.next/standalone/wp-test-bFyuuZ/rootfile.txt +1 -0
- package/.next/standalone/wp-test-dn9shN/after-reset.txt +1 -0
- package/.next/standalone/wp-test-gL64l2/shared.txt +1 -0
- package/.next/standalone/wp-test-mlyQ7q/test.txt +1 -0
- package/.next/standalone/wp-test-o3g2XI/shared.txt +1 -0
- package/.next/standalone/wp-test-oHeYCM/subA/a.txt +1 -0
- package/.next/standalone/wp-test-oHeYCM/subB/b.txt +1 -0
- package/package.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/internal/span/route/app-paths-manifest.json +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__04vo55d._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_g-.kr._.js +0 -20
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bpv09n._.js +0 -20
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e1kbl7._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0omny3u._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q~ky91._.js +0 -16
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0r--676._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x.030x._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xlo2r_._.js +0 -3
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_internal_span_route_actions_121if52.js +0 -3
- package/.next/standalone/.next/static/chunks/0gogvjz6oxo51.css +0 -1
- package/.next/standalone/.next/static/chunks/11ehczv8yax~_.js +0 -145
- /package/.next/standalone/.next/server/app/api/agent/{internal/span → live/attach}/route/build-manifest.json +0 -0
- /package/.next/standalone/.next/server/app/api/agent/{internal/span → live/attach}/route/server-reference-manifest.json +0 -0
- /package/.next/standalone/.next/server/app/api/agent/{internal/span → live/attach}/route.js.map +0 -0
- /package/.next/standalone/.next/static/{AsrmwC0YfrYEMAXj2s0Wx → BXRSlvxAOCUzi4h8wCLQi}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{AsrmwC0YfrYEMAXj2s0Wx → BXRSlvxAOCUzi4h8wCLQi}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{AsrmwC0YfrYEMAXj2s0Wx → BXRSlvxAOCUzi4h8wCLQi}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Proposal: Live agent collaboration
|
|
2
|
+
|
|
3
|
+
**Status:** Draft (implementing)
|
|
4
|
+
**Change name:** live-collab
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
Agent collaboration in wiki-viewer is pull-based and stateless. An agent calls the HTTP
|
|
9
|
+
API when *it* decides to, applies an edit, and disconnects. There is no notion of a human
|
|
10
|
+
sitting in the editor right now with an agent attached and waiting. A person cannot point
|
|
11
|
+
at a specific block, say "shorten this," and get a response in the same breath.
|
|
12
|
+
|
|
13
|
+
The impeccable skill's live mode nails that UX for websites: a human selects a rendered
|
|
14
|
+
element, an already-attached agent receives the request over a held-open channel, responds
|
|
15
|
+
in seconds, and the human iterates (steer) or resolves (accept/discard) in one continuous
|
|
16
|
+
session. We want that interaction for wiki-viewer documents, starting with Markdown, without
|
|
17
|
+
importing impeccable's HTML/DOM/HMR machinery (which does not apply to a text editor whose
|
|
18
|
+
real render surface is TipTap over the true file).
|
|
19
|
+
|
|
20
|
+
## Desired outcome
|
|
21
|
+
|
|
22
|
+
A human editing a Markdown file can select a top-level block, ask an attached agent to act
|
|
23
|
+
on it with a freeform instruction, and see the agent's proposal appear as a normal
|
|
24
|
+
`activity record` in TipTap within seconds, then track it. The agent stays attached
|
|
25
|
+
across the turn so the human can steer and iterate. This is the day-to-day primary mode of
|
|
26
|
+
agent collaboration.
|
|
27
|
+
|
|
28
|
+
## What we are actually emulating
|
|
29
|
+
|
|
30
|
+
Not "selection-scoped edits." The load-bearing combination is:
|
|
31
|
+
|
|
32
|
+
- **Selection** — the human points at a precise block; the agent's edit scope is bounded to it.
|
|
33
|
+
- **Presence** — the agent holds a long-poll open and is *already blocked waiting*, so human
|
|
34
|
+
input wakes it immediately (semantically live, even though the transport is agent-initiated
|
|
35
|
+
long-poll, not literal server push).
|
|
36
|
+
- **Live dispatch** — a human action in the editor pushes an event to that waiting agent now.
|
|
37
|
+
- **Iteration** — generate -> steer -> accept/discard is one continuous session, not unrelated
|
|
38
|
+
HTTP calls.
|
|
39
|
+
|
|
40
|
+
The presence + live-dispatch + session-continuity control plane is genuinely new surface. It
|
|
41
|
+
sits *above* the existing mutation engine.
|
|
42
|
+
|
|
43
|
+
## Architecture decision: one commit engine, two preflight policies
|
|
44
|
+
|
|
45
|
+
We do **not** build a second write engine, and we do **not** rewrite the proof protocol.
|
|
46
|
+
|
|
47
|
+
- Both live and async edits flow through the **same canonical commit path** (block-ops ->
|
|
48
|
+
`.md` + `.proof/` provenance -> lock -> audit -> idempotency). This is the invariant a
|
|
49
|
+
reviewer enforces: live and async both call the same commit function.
|
|
50
|
+
- They differ only in a **preflight anchor policy**:
|
|
51
|
+
- `exact` (live): exact `blockRef` + exact `baseRevision` + deterministic idempotency.
|
|
52
|
+
Fail closed on any staleness. No fuzzy quote-matching, no moved-content search, no
|
|
53
|
+
cross-revision block-ref recovery, no auto-rebase. "This request applies to exactly what
|
|
54
|
+
the human selected at revision R; if that is no longer true, reject it."
|
|
55
|
+
- `recover` (async/MCP): today's full defensive machinery (durable block-ref recovery,
|
|
56
|
+
reconciliation) for stateless agents that may return hours later.
|
|
57
|
+
|
|
58
|
+
It becomes a forbidden "second writer" only if someone applies live edits outside the
|
|
59
|
+
canonical commit path. That is the line review enforces.
|
|
60
|
+
|
|
61
|
+
### Live is primary; async is niche
|
|
62
|
+
|
|
63
|
+
Unattended/remote agent edits (MCP, scheduled jobs) are a real but niche use case. Live is
|
|
64
|
+
much more useful day-to-day. Therefore:
|
|
65
|
+
|
|
66
|
+
- The `exact` (live) path is the default and where day-to-day effort and polish go.
|
|
67
|
+
- The `recover` (async) path is kept but not centered or grown. When the two policies would
|
|
68
|
+
diverge on a design detail, the live path wins; async follows.
|
|
69
|
+
- Proof's convolution (block-ref indirection, sidecar recovery) is **retained and quarantined
|
|
70
|
+
behind `anchorPolicy: "recover"`**, justified by the niche async user, never by the live UX.
|
|
71
|
+
- We do **not** delete async machinery now. Revisit shrinking `recover` only if the niche user
|
|
72
|
+
disappears, and only after the live UX is proven and we can measure what actually fires.
|
|
73
|
+
|
|
74
|
+
## Scope
|
|
75
|
+
|
|
76
|
+
- New agent-facing live session/presence transport: attach (long-poll), event delivery, ACK,
|
|
77
|
+
session + request lifecycle. Per-workspace namespaced, auth via existing bearer + `X-Agent-Id`
|
|
78
|
+
+ `X-Workspace`.
|
|
79
|
+
- Editor affordance: select a top-level block -> "Ask agent" -> freeform instruction ->
|
|
80
|
+
dispatch a `generate` event; steer / accept / discard controls for the live turn.
|
|
81
|
+
- Live request correlation: tier-2 provenance records carry `{liveSessionId, liveRequestId}`.
|
|
82
|
+
- `exact` preflight policy wired into the existing commit path via `Idempotency-Key =
|
|
83
|
+
live:<requestId>`.
|
|
84
|
+
- Minimal durable state in the existing SQLite db: live sessions + requests + delivery/ACK
|
|
85
|
+
cursor. No new on-disk journal directory.
|
|
86
|
+
|
|
87
|
+
## Non-goals
|
|
88
|
+
|
|
89
|
+
- No impeccable helper server, no injected `live.js`, no HTML/CSS source localization, no HMR
|
|
90
|
+
overlay, no variants, no scribble annotations.
|
|
91
|
+
- No arbitrary text/code selection (Markdown top-level blocks only for v1).
|
|
92
|
+
- No served-app / website collaboration.
|
|
93
|
+
- **No second write engine / no `applyLiveEdit()` outside the canonical commit path.**
|
|
94
|
+
- No rewrite of the proof protocol; no deletion of async recovery machinery.
|
|
95
|
+
- No multiple concurrent proposals per block; one outstanding request per session/block.
|
|
96
|
+
- No Yjs/CRDT/WebSockets; no multi-human concurrent editing.
|
|
97
|
+
- No fuzzy recovery, rebasing, or heroic stale-request recovery on the live path.
|
|
98
|
+
|
|
99
|
+
## Risks
|
|
100
|
+
|
|
101
|
+
1. **Stale human intent** (top correctness risk). Human selects block at R1, sends
|
|
102
|
+
instruction, edits manually to R2, agent then processes. The agent must use the request's
|
|
103
|
+
original `baseRevision`; on conflict the request is marked `stale`/`conflicted` and a new
|
|
104
|
+
human request is required. Fail closed.
|
|
105
|
+
2. **Replayed requests -> duplicate edits.** Solved by deterministic
|
|
106
|
+
`Idempotency-Key = live:<requestId>`; the agent must not invent a fresh key after recovery.
|
|
107
|
+
3. **Structural edits destroying block identity** (move/split/merge/delete while pending).
|
|
108
|
+
Fail closed via revision + exact block-ref check; no fuzzy recovery in v1.
|
|
109
|
+
4. **Presence ambiguity** (working vs crashed vs network-gone vs forgot-to-reopen-poll).
|
|
110
|
+
Handled with a small lease/timeout: timeout means disconnected; reconnect resumes from last
|
|
111
|
+
ACK. Do not over-model presence.
|
|
112
|
+
5. **Accidentally creating another editor protocol.** Red flag if the live layer starts adding
|
|
113
|
+
live snapshots / live accept-writer / live diff format. Those already belong to tier-2.
|
|
114
|
+
|
|
115
|
+
## Acceptance criteria
|
|
116
|
+
|
|
117
|
+
1. An agent can attach to a workspace live session over a held-open long-poll and receive a
|
|
118
|
+
`generate` event pushed by a human editor action within ~1s of the action.
|
|
119
|
+
2. Selecting a top-level Markdown block in TipTap and submitting an instruction produces a
|
|
120
|
+
tier-2 activity/audit provenance edit committed through the existing commit path, correlated with the live
|
|
121
|
+
request id in provenance.
|
|
122
|
+
3. The human can steer (send a follow-up instruction in the same session) and the agent
|
|
123
|
+
receives it on its next held poll.
|
|
124
|
+
4. Accept and revert of the resulting activity/audit provenance work through the existing editor UI and are
|
|
125
|
+
reported back to the live session as `resolved{accepted|reverted}`.
|
|
126
|
+
5. A manual edit that changes the target block's revision before the agent commits causes the
|
|
127
|
+
live request to fail closed as `stale`, not a silent re-interpretation.
|
|
128
|
+
6. Replaying the same live request (agent crash before ACK, then reconnect) does not produce a
|
|
129
|
+
duplicate edit, verified via the deterministic idempotency key.
|
|
130
|
+
7. Live edits and existing async tier-2 edits both go through one commit function; there is no
|
|
131
|
+
separate live filesystem-mutation path.
|
|
132
|
+
8. `pnpm test`, `pnpm typecheck`, `pnpm lint` pass; new behavior covered by tests in
|
|
133
|
+
`src/tests/proof/`.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Requirements: Live agent collaboration
|
|
2
|
+
|
|
3
|
+
Each requirement is observable behavior with GIVEN/WHEN/THEN scenarios.
|
|
4
|
+
|
|
5
|
+
## R1 — Agent attaches and holds presence
|
|
6
|
+
|
|
7
|
+
GIVEN a registered agent with a valid bearer token, `X-Agent-Id`, and `X-Workspace`
|
|
8
|
+
WHEN it `POST /api/agent/live/attach`
|
|
9
|
+
THEN a live session is created (or the existing open one reused) and `{ sessionId }` returned
|
|
10
|
+
AND while the agent holds `GET /api/agent/live/poll` open, the session's `agent_last_seen`
|
|
11
|
+
is refreshed so the session reports `attached: true`.
|
|
12
|
+
|
|
13
|
+
## R2 — Human dispatch reaches the waiting agent quickly
|
|
14
|
+
|
|
15
|
+
GIVEN an attached agent holding a live poll
|
|
16
|
+
AND a human editing a Markdown file with a top-level block selected
|
|
17
|
+
WHEN the human submits an instruction via `POST /api/wiki/live/request`
|
|
18
|
+
`{ path, blockRef, baseRevision, kind: "generate", instruction }`
|
|
19
|
+
THEN the held agent poll returns `{ type: "generate", request: { requestId, path, blockRef,
|
|
20
|
+
baseRevision, instruction } }` within ~1s of the submission (not on a fixed slow interval).
|
|
21
|
+
|
|
22
|
+
## R3 — Agent edit lands as a activity/audit provenance through the existing engine, correlated
|
|
23
|
+
|
|
24
|
+
GIVEN a delivered `generate` request with id `<rid>`
|
|
25
|
+
WHEN the agent `POST /api/agent/files/<path>` with `Idempotency-Key: live:<rid>`,
|
|
26
|
+
`baseRevision` equal to the request's, and an op carrying `inResponseTo: "live:<rid>"`
|
|
27
|
+
THEN the edit is committed by the existing `applyOps` path, written as clean markdown whose
|
|
28
|
+
`ActivityAttrs.inResponseTo === "live:<rid>"`
|
|
29
|
+
AND no new/separate write path is used.
|
|
30
|
+
|
|
31
|
+
## R4 — Steer within the same session
|
|
32
|
+
|
|
33
|
+
GIVEN an open live session with a resolved-or-working prior turn
|
|
34
|
+
WHEN the human submits another `POST /api/wiki/live/request { kind: "steer", instruction }`
|
|
35
|
+
THEN the agent receives it on its next held poll as `{ type: "steer", ... }`.
|
|
36
|
+
|
|
37
|
+
## R5 — Accept / revert reported to the session
|
|
38
|
+
|
|
39
|
+
GIVEN a activity/audit provenance produced by a live request
|
|
40
|
+
WHEN the human accepts or reverts it through the existing editor proof UI and the client
|
|
41
|
+
posts `POST /api/wiki/live/request { kind: "accept" | "discard" }`
|
|
42
|
+
THEN the corresponding `live_request` is marked `resolved` with
|
|
43
|
+
`outcome = accepted | reverted`.
|
|
44
|
+
|
|
45
|
+
## R6 — Stale intent fails closed
|
|
46
|
+
|
|
47
|
+
GIVEN a `generate` request captured at `baseRevision = R`
|
|
48
|
+
AND the human manually edits the file so its revision becomes `R+1` before the agent commits
|
|
49
|
+
WHEN the agent commits with `baseRevision = R`
|
|
50
|
+
THEN `applyOps` returns `409 STALE_REVISION`, the agent replies `error`, and the
|
|
51
|
+
`live_request` is marked `stale`
|
|
52
|
+
AND the document is NOT silently re-edited against `R+1`.
|
|
53
|
+
|
|
54
|
+
## R7 — Replay safety
|
|
55
|
+
|
|
56
|
+
GIVEN a `generate` request `<rid>` whose tier-2 edit already committed
|
|
57
|
+
AND the agent crashed before replying, then reconnects and re-POSTs the same edit
|
|
58
|
+
WHEN it reuses `Idempotency-Key: live:<rid>` with the identical payload
|
|
59
|
+
THEN the cached tier-2 response is returned and NO duplicate edit is produced.
|
|
60
|
+
|
|
61
|
+
## R8 — One outstanding request per session
|
|
62
|
+
|
|
63
|
+
GIVEN a session with a non-terminal (`pending`/`delivered`/`working`) request
|
|
64
|
+
WHEN a human submits another `generate` for that session
|
|
65
|
+
THEN the dispatch is rejected with a clear conflict status until the prior turn resolves.
|
|
66
|
+
|
|
67
|
+
## R9 — Presence timeout
|
|
68
|
+
|
|
69
|
+
GIVEN a session whose agent stopped polling longer than the lease TTL
|
|
70
|
+
WHEN the editor queries `GET /api/wiki/live/status`
|
|
71
|
+
THEN it reports `attached: false`.
|
|
72
|
+
|
|
73
|
+
## R10 — Auth and workspace isolation
|
|
74
|
+
|
|
75
|
+
GIVEN two workspaces
|
|
76
|
+
WHEN an agent attached to workspace A polls
|
|
77
|
+
THEN it never receives live requests enqueued for workspace B
|
|
78
|
+
AND all agent live routes reject requests failing `checkAuth` / `enforceScope`.
|
|
79
|
+
|
|
80
|
+
## R11 — Editor affordance
|
|
81
|
+
|
|
82
|
+
GIVEN the Markdown editor with a top-level block selected
|
|
83
|
+
WHEN the user opens the bubble menu
|
|
84
|
+
THEN an "Ask agent" action is present that opens an instruction popover and dispatches R2.
|
|
85
|
+
|
|
86
|
+
## Verification
|
|
87
|
+
|
|
88
|
+
- `pnpm test` (proof suite) with new tests in `src/tests/proof/` covering R1-R10 at the
|
|
89
|
+
store + route level.
|
|
90
|
+
- `pnpm typecheck`, `pnpm lint`, `pnpm build` pass.
|
|
91
|
+
- R11 verified by component wiring (bubble-menu action present, dispatch call shape correct).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Tasks: Live agent collaboration
|
|
2
|
+
|
|
3
|
+
## Backend
|
|
4
|
+
- [x] Live store (`src/lib/proof/live/store.ts`): SQLite `live.db`, session + request
|
|
5
|
+
tables, presence TTL, one-outstanding-per-session enqueue, deterministic ids.
|
|
6
|
+
- [x] Agent transport: `POST /api/agent/live/attach`, `GET /api/agent/live/poll`
|
|
7
|
+
(long-poll, presence via held request), `POST /api/agent/live/reply`.
|
|
8
|
+
- [x] Human dispatch: `POST /api/wiki/live/request` (generate/steer/accept/discard,
|
|
9
|
+
CSRF-checked), `GET /api/wiki/live/status`.
|
|
10
|
+
- [x] Correlation: poll event surfaces `idempotencyKey = live:<id>` and
|
|
11
|
+
`inResponseTo = live:<id>` for the agent to carry into the Tier-2 edit. No new
|
|
12
|
+
write path; commit stays `applyOps`.
|
|
13
|
+
|
|
14
|
+
## Frontend
|
|
15
|
+
- [x] `EditorBubbleMenu`: add "Ask agent" action (`onAskAgent`).
|
|
16
|
+
- [x] `AskAgentPopover`: instruction input, agent-attached indicator, dispatch to
|
|
17
|
+
`/api/wiki/live/request`, stale/conflict/detached feedback.
|
|
18
|
+
- [x] `editor.tsx`: `openAskAgentForSelection` using existing `resolveSelectionBlock`,
|
|
19
|
+
render popover, wire prop.
|
|
20
|
+
|
|
21
|
+
## Tests
|
|
22
|
+
- [x] `src/tests/proof/live-collab.test.ts` covering R1, R2/R3, R5, R6, R7, R8, R9, R10.
|
|
23
|
+
|
|
24
|
+
## Docs
|
|
25
|
+
- [x] `agents/wiki-viewer-skill/SKILL.md`: "Live collaboration" section (loop + rules).
|
|
26
|
+
- [x] proposal.md / requirements.md / design.md.
|
|
27
|
+
|
|
28
|
+
## Verification
|
|
29
|
+
- [x] `pnpm typecheck` clean.
|
|
30
|
+
- [x] `pnpm lint` clean.
|
|
31
|
+
- [x] `pnpm test` — 656 pass, floor 648 (8 new live-collab tests included).
|
|
32
|
+
|
|
33
|
+
## Deferred / out of scope (recorded, not built)
|
|
34
|
+
- R4 steer + R11 editor-affordance covered by wiring, not a dedicated automated test
|
|
35
|
+
(steer reuses the same enqueue/poll path proven by R2/R8).
|
|
36
|
+
- Client-side agent runtime that actually attaches and edits (this change ships the
|
|
37
|
+
server channel + human UI; the agent side is the skill contract in SKILL.md).
|
|
38
|
+
- Async `recover` policy untouched; live path relies on `applyOps`' built-in exact
|
|
39
|
+
revision/ref checks. No deletion of proof machinery.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
> SUPERSEDED for the v1 shape. TermDeck is retained here as *ideation reference
|
|
2
|
+
> only*. The actual build target is impeccable-grade (variant preview bound to an
|
|
3
|
+
> immutable candidate source patch, write-on-accept). See `proposal.md`. Do not
|
|
4
|
+
> implement the shallow "prose to agent, reload" model described at the bottom of
|
|
5
|
+
> this file.
|
|
6
|
+
|
|
7
|
+
# Gap 2 research: TermDeck's "Tweak mode" and what it means for wiki-viewer
|
|
8
|
+
|
|
9
|
+
Source studied: `huytieu/termdeck-localterm` (a fork of `localterm`, whose wiki
|
|
10
|
+
is itself *inspired by wiki-viewer*). Commit `25e6850`. The relevant feature is
|
|
11
|
+
**Tweak mode**: "point at the pixel, the agent gets the selector."
|
|
12
|
+
|
|
13
|
+
## What TermDeck actually built
|
|
14
|
+
|
|
15
|
+
Much simpler than impeccable. No HMR, no variants, no DOM→source localization,
|
|
16
|
+
no write-on-accept. The whole thing is ~200 lines of injected JS + a proxy + a
|
|
17
|
+
prose message to a terminal agent. Three pieces:
|
|
18
|
+
|
|
19
|
+
### 1. An injected element-picker script (`packages/server/src/artifact-picker.ts`)
|
|
20
|
+
A self-contained IIFE (`ARTIFACT_PICKER_JS`) appended into any rendered HTML.
|
|
21
|
+
- Hover highlights the element under the cursor (`elementFromPoint`), click marks it.
|
|
22
|
+
- Builds a **robust CSS selector** by walking up ≤6 ancestors: prefers `#id`
|
|
23
|
+
(and stops), else `tag.class1.class2` (first two non-picker classes), adds
|
|
24
|
+
`:nth-of-type(n)` only when siblings share the tag. (`cssPath()`)
|
|
25
|
+
- Captures a **snippet** (`outerHTML`, truncated to ~400 chars → open tag + text)
|
|
26
|
+
and the element's `textContent` (≤200 chars).
|
|
27
|
+
- Talks to the parent **only via `window.postMessage`** — protocol
|
|
28
|
+
`{source:'termdeck-picker', cmd:'enable'|'disable'|'remove'|'clear'}` down,
|
|
29
|
+
`{event:'ready'|'selected', id, selector, tag, snippet, text, rect}` up.
|
|
30
|
+
- Because it's postMessage-only, it works from a **sandboxed null-origin iframe**
|
|
31
|
+
(no `allow-same-origin` needed). Overlay chrome is fixed-position, pointer-events
|
|
32
|
+
none, huge z-index, and self-marked so it never picks itself.
|
|
33
|
+
|
|
34
|
+
### 2. Two HTML surfaces get the picker (`apps/terminal/src/components/wiki-detail.tsx`)
|
|
35
|
+
- **Local `.html` file** → rendered via `srcDoc`, with `<script src="/api/artifact/picker.js">`
|
|
36
|
+
appended before `</body>`.
|
|
37
|
+
- **Remote deploy URL** → fetched server-side through `/api/artifact/proxy`, which
|
|
38
|
+
strips CSP `<meta>`, injects a `<base href>` so relative assets resolve to the
|
|
39
|
+
real origin, and **inlines** the picker (`injectArtifactChrome`). Manual redirect
|
|
40
|
+
following detects cross-host SSO gates and shows a readable notice instead of a
|
|
41
|
+
blank login page.
|
|
42
|
+
- The parent React component bridges: translates the in-frame element rect to page
|
|
43
|
+
coords (using the iframe's own offset) and anchors a "what should change?" note
|
|
44
|
+
popover. One pending pick at a time; a batch tray stacks several.
|
|
45
|
+
|
|
46
|
+
### 3. Dispatch is just prose to a terminal (`sendTweaks`)
|
|
47
|
+
No structured edit protocol at all. It formats:
|
|
48
|
+
```
|
|
49
|
+
In the artifact `path`, apply these N edits to the matching elements:
|
|
50
|
+
|
|
51
|
+
Tweak 1 — `selector` (<tag>):
|
|
52
|
+
Current: <snippet>
|
|
53
|
+
Change: <your note>
|
|
54
|
+
```
|
|
55
|
+
…and sends it as one chat message into the linked terminal session (`chatAboutSelection`).
|
|
56
|
+
The agent (Claude in a shell) reads it, finds the source, edits the file itself, the
|
|
57
|
+
dev server/HMR reloads the iframe. Accept/revert is just "look at the page again."
|
|
58
|
+
|
|
59
|
+
## How this maps onto wiki-viewer
|
|
60
|
+
|
|
61
|
+
We are closer than TermDeck was, in the parts that matter:
|
|
62
|
+
|
|
63
|
+
- **Injection seam already exists.** `src/app/api/app-proxy/[...path]/route.ts`
|
|
64
|
+
already `rewriteHtml()`s proxied app HTML and injects a `<script>` + a service
|
|
65
|
+
worker. Adding a picker `<script>` is the same move TermDeck makes.
|
|
66
|
+
- **Sandbox already correct.** `website-viewer.tsx` sandboxes without
|
|
67
|
+
`allow-same-origin`; a postMessage-only picker fits that exactly (per AGENTS.md
|
|
68
|
+
security model: never combine `allow-scripts` + `allow-same-origin`).
|
|
69
|
+
- **We already have live presence + a real dispatch channel.** TermDeck fires a
|
|
70
|
+
prose message into a terminal. We have the live-collab control plane
|
|
71
|
+
(`/api/wiki/live/request` → attached agent → reply). A web "tweak" is just a
|
|
72
|
+
new live request `kind` carrying `{selector, tag, snippet, note}` instead of
|
|
73
|
+
`{blockRef, instruction}`.
|
|
74
|
+
|
|
75
|
+
What we do NOT get for free, and what makes web genuinely different from markdown:
|
|
76
|
+
|
|
77
|
+
- **No source identity.** For markdown, a block-ref maps a rendered node to a
|
|
78
|
+
canonical source region and the edit commits through tier-2. For an arbitrary
|
|
79
|
+
HTML app, a CSS selector does **not** identify a source location — the agent
|
|
80
|
+
must *find* where that element is generated (JSX, template, framework) and edit
|
|
81
|
+
that. That search is the agent's job (exactly as in TermDeck), not the protocol's.
|
|
82
|
+
- **No activity/audit provenance / accept-revert.** The edit lands in real source files via tier-1
|
|
83
|
+
raw FS (or the agent's own shell), not as a reviewable block-op. Review is
|
|
84
|
+
"reload the preview." This is a *different persistence model* and must not be
|
|
85
|
+
bolted onto the tier-2 engine.
|
|
86
|
+
|
|
87
|
+
## Recommended shape for wiki-viewer Gap 2 (v1)
|
|
88
|
+
|
|
89
|
+
Steal TermDeck's model almost verbatim, ride our existing rails:
|
|
90
|
+
|
|
91
|
+
1. **Picker script** served/injected into (a) local `.html` previews via `srcDoc`
|
|
92
|
+
and (b) proxied node-apps via the existing `rewriteHtml` seam. postMessage-only.
|
|
93
|
+
Reuse TermDeck's `cssPath`/`snippet` logic (MIT — reimplement, credit in comment).
|
|
94
|
+
2. **Element-select UX** in `website-viewer.tsx` / `node-app-viewer.tsx`: a "Tweak"
|
|
95
|
+
toggle, hover highlight, click → note popover, optional batch tray.
|
|
96
|
+
3. **Dispatch via live channel**, new request kind `tweak` (or `web.tweak`):
|
|
97
|
+
`{ path, selector, tag, snippet, note }`. The attached agent receives it on poll.
|
|
98
|
+
4. **Agent edits real source** through tier-1 raw FS (`/api/agent/fs/*`), not tier-2.
|
|
99
|
+
No activity/audit provenance. The preview reloads (node-app HMR, or re-fetch for static HTML).
|
|
100
|
+
5. Explicit non-goals for v1: no HMR variant preview, no write-on-accept staging,
|
|
101
|
+
no DOM→source auto-localization, no CSS-only inline patching. The agent finds
|
|
102
|
+
and edits source, same as a human would from a bug report.
|
|
103
|
+
|
|
104
|
+
## The load-bearing decision (needs Anh)
|
|
105
|
+
|
|
106
|
+
Web tweak is a **second persistence model** (edit real source, reload preview),
|
|
107
|
+
distinct from markdown live (block-op activity/audit provenance, activity tracking). That is fine and
|
|
108
|
+
matches reality — but it means "live collaboration" becomes an umbrella over two
|
|
109
|
+
concretely different flows. Options:
|
|
110
|
+
|
|
111
|
+
- **A. Two explicit modes under one presence channel** (recommended): same attach/
|
|
112
|
+
poll/reply + session, request `kind` distinguishes `generate|steer` (markdown,
|
|
113
|
+
tier-2) from `tweak` (web, tier-1). One agent runtime handles both. Honest about
|
|
114
|
+
the two persistence models; minimal new surface.
|
|
115
|
+
- **B. Keep web tweak entirely separate** (TermDeck-style, prose to a terminal),
|
|
116
|
+
not wired to the proof/live stack at all. Simplest, but throws away the presence
|
|
117
|
+
channel we just built and duplicates dispatch.
|
|
118
|
+
|
|
119
|
+
Recommend A. Ship the picker + element UX first (pure frontend + injection, no
|
|
120
|
+
protocol risk), then wire the `tweak` request kind onto the existing live channel.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Proposal: impeccable-grade live collaboration for web surfaces
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
Live collaboration (markdown) shipped: point at a rendered block, an attached
|
|
6
|
+
agent edits it in-session, the change lands as a reviewable activity/audit provenance. That
|
|
7
|
+
covers `.md`. It does **not** cover the web surfaces wiki-viewer renders in an
|
|
8
|
+
iframe: local `.html` previews (`website-viewer`) and running node-apps behind
|
|
9
|
+
`app-proxy` (`node-app-viewer`).
|
|
10
|
+
|
|
11
|
+
For web, the analogous experience is impeccable's: point at a rendered DOM
|
|
12
|
+
element, describe the change, **see it applied live on the real page before
|
|
13
|
+
anything is written**, then accept (commit to source) or discard (revert, source
|
|
14
|
+
never touched). We want that experience baked in, at impeccable's depth, not a
|
|
15
|
+
shallow "send a note to a terminal" imitation.
|
|
16
|
+
|
|
17
|
+
## Desired outcome
|
|
18
|
+
|
|
19
|
+
In a web preview, the user toggles **Tweak** mode, clicks an element, and types
|
|
20
|
+
what should change. The attached agent returns a **preview patch** that is
|
|
21
|
+
applied inside the iframe via postMessage, so the user sees the variant on the
|
|
22
|
+
live page immediately. The user then:
|
|
23
|
+
|
|
24
|
+
- **Accept** → agent writes the real source (tier-1 raw FS); preview reload
|
|
25
|
+
reflects the committed change.
|
|
26
|
+
- **Discard** → the DOM patch is reverted in-frame; no source was touched.
|
|
27
|
+
|
|
28
|
+
Same attach / poll / reply presence channel already built for markdown. One
|
|
29
|
+
attached agent runtime handles both markdown (`generate`/`steer`) and web
|
|
30
|
+
(`web.tweak`) requests.
|
|
31
|
+
|
|
32
|
+
## Why this is achievable with minimum new machinery
|
|
33
|
+
|
|
34
|
+
Impeccable's expensive invention was the variant hot-swap pipeline. We get the
|
|
35
|
+
equivalent almost free because our web surfaces are **already iframes** and we
|
|
36
|
+
already have a **postMessage element picker** (`src/lib/web-tweak/picker.ts`):
|
|
37
|
+
|
|
38
|
+
- **Variant preview = a DOM/CSS patch applied inside the iframe**, not an HMR
|
|
39
|
+
rebuild. The picker gains `apply`/`revert` commands; the parent posts the
|
|
40
|
+
agent's patch in, the element visibly changes, the original is retained for
|
|
41
|
+
revert. The DOM patch is the *rendering* of the variant; the bound candidate
|
|
42
|
+
source patch is the *thing accept commits*. Both are produced by the single
|
|
43
|
+
`web.tweak` reply so accept never re-synthesizes.
|
|
44
|
+
- **Presence + dispatch already exist** (the live channel we shipped).
|
|
45
|
+
- **Injection seam already exists**: `app-proxy` `rewriteHtml()` injects scripts
|
|
46
|
+
into proxied app HTML; static `.html` can carry the picker via `srcDoc` or the
|
|
47
|
+
assets route. The picker is postMessage-only, so it runs in the existing
|
|
48
|
+
no-`allow-same-origin` sandbox with no security regression.
|
|
49
|
+
- **Source write already exists**: tier-1 raw FS (`/api/agent/fs/*`).
|
|
50
|
+
|
|
51
|
+
## The deliberate divergence: write-on-accept
|
|
52
|
+
|
|
53
|
+
Web live is **write-on-accept**: source is untouched until the user accepts a
|
|
54
|
+
previewed variant. This is the *opposite* of markdown live (write-first, then
|
|
55
|
+
review the activity/audit provenance). That divergence is intentional and is *why* the claim
|
|
56
|
+
holds. Each surface uses the persistence model that is impeccable-grade for it:
|
|
57
|
+
|
|
58
|
+
| | Markdown live | Web live (this) |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| Preview | activity/audit provenance in TipTap over real file | DOM patch in iframe, source clean |
|
|
61
|
+
| Persistence | write-first, activity tracking span | write-on-accept to real source |
|
|
62
|
+
| Write path | tier-2 block-ops | tier-1 raw FS |
|
|
63
|
+
| Identity | block-ref → source region | CSS selector (agent localizes source) |
|
|
64
|
+
|
|
65
|
+
Both ride one presence channel and one agent runtime. Two persistence models,
|
|
66
|
+
one product promise.
|
|
67
|
+
|
|
68
|
+
## The preview transaction (the core object)
|
|
69
|
+
|
|
70
|
+
Identity for a web tweak is NOT just a CSS selector. Every tweak is a versioned
|
|
71
|
+
**preview transaction**, keyed by a server-issued `previewId`:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
previewId
|
|
75
|
+
-> selected DOM fingerprint (selector, tag, snippet, text)
|
|
76
|
+
-> domPreviewOps (ephemeral, applied in-frame; data-only)
|
|
77
|
+
-> candidateSourcePatch (immutable; the exact edit accept will write)
|
|
78
|
+
-> baseFiles[] ({ path, sha256 }) the candidate was derived against
|
|
79
|
+
-> status requested | preview-ready | accepted | discarded | invalidated
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`web.tweak` reply MUST carry both `domPreviewOps` and `candidateSourcePatch`
|
|
83
|
+
plus `baseFiles`. Accept commits `candidateSourcePatch` verbatim **iff** every
|
|
84
|
+
`baseFiles[].sha256` still matches on disk; otherwise the transaction is
|
|
85
|
+
`invalidated` (user re-tweaks). Accept never re-localizes or re-synthesizes.
|
|
86
|
+
This is what makes it a *reviewed variant* rather than a *visual proposal*.
|
|
87
|
+
|
|
88
|
+
## Scope
|
|
89
|
+
|
|
90
|
+
1. Extend the picker protocol with `apply`/`revert` (ephemeral DOM patch inside
|
|
91
|
+
the iframe) plus original-state retention. Patch language is **data-only**:
|
|
92
|
+
text, attributes (denylist: event handlers, `javascript:` URLs, script/iframe
|
|
93
|
+
insertion, form/nav targets), and inline style. No arbitrary JS/eval.
|
|
94
|
+
2. New live request kind `web.tweak` carrying `{ path, previewId, selector, tag,
|
|
95
|
+
snippet, note }`; agent reply carries `{ domPreviewOps, candidateSourcePatch,
|
|
96
|
+
baseFiles }`. The candidate source patch is derived at reply time, not accept.
|
|
97
|
+
3. Accept/discard control plane on the live channel: `web.accept` / `web.discard`
|
|
98
|
+
reference a `previewId`. `web.accept` verifies `baseFiles` hashes then commits
|
|
99
|
+
`candidateSourcePatch` via tier-1; mismatch -> `invalidated`, no write.
|
|
100
|
+
4. Mount Tweak UX in `website-viewer.tsx` and `node-app-viewer.tsx`: toggle,
|
|
101
|
+
hover highlight (from picker), note popover, preview state, accept/discard bar.
|
|
102
|
+
Accept/Discard originate ONLY from trusted parent UI, never from an iframe
|
|
103
|
+
message.
|
|
104
|
+
5. Inject the picker: proxied apps via `rewriteHtml`; static `.html` via the
|
|
105
|
+
assets/srcDoc path.
|
|
106
|
+
6. Agent runtime: extend `runLiveLoop` to handle `web.tweak` (produce DOM preview
|
|
107
|
+
ops AND candidate source patch + base hashes in one reply) and `web.accept`
|
|
108
|
+
(verify hashes, tier-1 write). Passthrough reference handler for smoke tests.
|
|
109
|
+
|
|
110
|
+
## Message-trust rules (iframe -> parent)
|
|
111
|
+
|
|
112
|
+
Every iframe->parent message is hostile input:
|
|
113
|
+
|
|
114
|
+
- Verify `event.source === iframe.contentWindow` (opaque origin makes
|
|
115
|
+
`event.origin` checks insufficient on their own).
|
|
116
|
+
- Strict schema validation; reject unknown fields/types.
|
|
117
|
+
- Iframe messages may only carry *selection* facts (selector/snippet/rect). They
|
|
118
|
+
MUST NOT be able to trigger a filesystem write or an accept. Accept/discard are
|
|
119
|
+
driven by parent control state keyed on `previewId`.
|
|
120
|
+
- No nonce is assumed secret from page JS sharing the frame.
|
|
121
|
+
|
|
122
|
+
## v1 surface note (post-review)
|
|
123
|
+
|
|
124
|
+
Web tweak in v1 is offered **only on the opaque-origin static-HTML preview**
|
|
125
|
+
(the `srcDoc` path in `website-viewer`). It is intentionally **not** offered for
|
|
126
|
+
running node-apps: the proxied app is served from the wiki-viewer origin with an
|
|
127
|
+
`allow-same-origin` iframe (required for the app to run), so hostile page JS
|
|
128
|
+
could reach `parent.document` and click Accept, bypassing the postMessage
|
|
129
|
+
boundary. Node-app tweak requires a dedicated isolated proxy origin and is
|
|
130
|
+
deferred. The picker is still injected into proxied HTML (harmless, inert without
|
|
131
|
+
parent postMessage) so the capability is ready once an isolated origin exists.
|
|
132
|
+
|
|
133
|
+
## Non-goals (v1)
|
|
134
|
+
|
|
135
|
+
- No HMR/build-pipeline variant rebuild (DOM patch preview is the mechanism).
|
|
136
|
+
- No automatic DOM→source localization by the *protocol*; the agent finds the
|
|
137
|
+
source (as a human would), the selector+snippet+note is its lead.
|
|
138
|
+
- No multi-variant A/B stacks; one pending preview per element.
|
|
139
|
+
- No CSS-only inline persistence; accept always writes real source.
|
|
140
|
+
- No collaboration on third-party remote sites we don't own the source for.
|
|
141
|
+
- No change to the markdown tier-2 engine (must not bolt web preview onto it).
|
|
142
|
+
|
|
143
|
+
## Risks
|
|
144
|
+
|
|
145
|
+
- **Preview/source fidelity gap** (the main risk): a DOM mutation may map to a
|
|
146
|
+
materially different source change (CSS token vs prop vs conditional vs shared
|
|
147
|
+
class), a framework re-render may overwrite the DOM patch, or one rendered
|
|
148
|
+
instance may map to a component affecting many instances. Mitigation: the
|
|
149
|
+
candidate source patch is produced *with* the preview and bound to `previewId`;
|
|
150
|
+
accept commits that candidate, and the post-accept reload is *verification*
|
|
151
|
+
(does the reviewed candidate render as expected), not the first time source is
|
|
152
|
+
interpreted. If the agent cannot produce a confident candidate patch at
|
|
153
|
+
`web.tweak` time, it returns preview-only with `candidateSourcePatch: null` and
|
|
154
|
+
the UI shows "visual only, not acceptable" rather than offering a false accept.
|
|
155
|
+
- **Base drift between preview and accept**: user, watcher, HMR, or another agent
|
|
156
|
+
changes the source files after preview. Mitigation: accept verifies
|
|
157
|
+
`baseFiles[].sha256`; any mismatch invalidates the transaction (no write, user
|
|
158
|
+
re-tweaks). Never opportunistically rebase.
|
|
159
|
+
- **Two persistence models** invite confusion. Mitigation: explicit request-kind
|
|
160
|
+
namespacing (`web.*`), separate write path, this spec's boundary table, and a
|
|
161
|
+
line-review rule: `web.*` never touches tier-2, markdown never touches tier-1.
|
|
162
|
+
- **Sandbox**: keep postMessage-only; never add `allow-same-origin` to a
|
|
163
|
+
script-enabled preview.
|
|
164
|
+
|
|
165
|
+
## Acceptance criteria
|
|
166
|
+
|
|
167
|
+
- Toggling Tweak in a web preview highlights elements on hover and captures a
|
|
168
|
+
selector+snippet on click.
|
|
169
|
+
- A note dispatched for a selected element reaches the attached agent as a
|
|
170
|
+
`web.tweak` request on the existing poll channel, carrying a `previewId`.
|
|
171
|
+
- The `web.tweak` reply produces a preview transaction with `domPreviewOps`,
|
|
172
|
+
`candidateSourcePatch` (or explicit null), and `baseFiles` hashes.
|
|
173
|
+
- The DOM preview ops are applied inside the iframe and visibly change the live
|
|
174
|
+
page with no source file changing (verified: file sha256/mtime unchanged).
|
|
175
|
+
- Discard reverts the element to its original state in-frame; source unchanged.
|
|
176
|
+
- Accept with matching `baseFiles` hashes writes `candidateSourcePatch` via
|
|
177
|
+
tier-1 and reloads the preview; accept with a stale hash invalidates and writes
|
|
178
|
+
nothing.
|
|
179
|
+
- A `candidateSourcePatch: null` transaction offers no accept (visual only).
|
|
180
|
+
- An iframe->parent message cannot trigger a write or accept; accept/discard come
|
|
181
|
+
only from parent control state. (protocol-abuse test)
|
|
182
|
+
- `event.source` identity is verified on picker messages. (protocol-abuse test)
|
|
183
|
+
- No `allow-same-origin` is combined with `allow-scripts` on any tweak preview.
|
|
184
|
+
- Markdown live behavior and tier-2 engine are unchanged (existing tests green).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Unified Live — design & contracts
|
|
2
|
+
|
|
3
|
+
Grounded in recon (2026-08-15). File refs are current.
|
|
4
|
+
|
|
5
|
+
## Server: markdown proposal store (write-on-accept)
|
|
6
|
+
Mirror the web-tweak preview-store transaction, but for markdown. New store `src/lib/proof/live/md-proposal-store.ts` (or extend preview-store with `surface` tag — prefer a separate table to avoid destabilizing shipped web-tweak).
|
|
7
|
+
|
|
8
|
+
Table `md_proposal`:
|
|
9
|
+
- `previewId` (pk), `workspace_id`, `path`, `block_ref`, `base_revision`, `base_block_hash`,
|
|
10
|
+
- `request_id`, `state` (requested|ready|resolving|accepted|discarded|invalidated),
|
|
11
|
+
- `variants` JSON `[{variantId, label, markdown}]`, `selected_variant_id`,
|
|
12
|
+
- `created_at`, `resolved_at`.
|
|
13
|
+
Atomic `claimForResolve(previewId)`; drift check compares current block markdown hash to `base_block_hash` under file lock at accept.
|
|
14
|
+
|
|
15
|
+
### Human routes (UI-only, trusted)
|
|
16
|
+
- `POST /api/wiki/live/md-request` → `{path, blockRef, baseRevision, baseBlockHash, instruction, selectionText?, selectionStart?, selectionEnd?}` → creates proposal (state=requested), enqueues live request (kind `generate`, carries `previewId`), returns `{previewId, requestId}`.
|
|
17
|
+
- `GET /api/wiki/live/md-status?previewId=` → `{state, variants, selectedVariantId, ...}`.
|
|
18
|
+
- `POST /api/wiki/live/md-resolve` → `{previewId, action: accept|discard, variantId?}`. Accept: claim → re-read block, verify hash == base_block_hash (else `invalidated`) → commit chosen variant verbatim via tier-2 `block.replace` at `base_revision` → state=accepted. Discard: claim → state=discarded. **No agent auth accepted here.**
|
|
19
|
+
|
|
20
|
+
### Agent submit (MCP backend)
|
|
21
|
+
Reuse existing `/api/agent/live/*`. Extend the agent web-preview submit concept for markdown, OR add `POST /api/agent/live/md-preview` → `{previewId, requestId, variants:[{variantId,label,markdown}]}` (2–5 variants enforced) → validates ownership/scope, stores variants, state=ready, marks request resolved(working→ready). Data-only (markdown strings); no file write.
|
|
22
|
+
|
|
23
|
+
## MCP tools (packages/wiki-viewer-mcp)
|
|
24
|
+
Delete: `live` subcommand, `runLiveLoop`, `passthroughHandler`, `llmHandler`, `claudePrompt`, `passthroughWebHandler`, `passthroughVariantsHandler`, and loop/reference tests in `live-client.test.ts`. Keep `LiveClient.attach/poll/reply/snapshot/applyTier2Ops` as tool backends.
|
|
25
|
+
|
|
26
|
+
New tools in `server.ts` + `tool-schemas.ts` + `tool-handlers.ts`:
|
|
27
|
+
- `live_attach` → `{sessionId, workspaceId}`.
|
|
28
|
+
- `live_poll {sessionId, afterSeq}` → held ~25s; returns next request `{requestId, kind, surface, previewId?, path, blockRef, baseRevision, instruction, selectionText?, ...}` or `{type:"timeout"}`. Model calls it in a loop while attending.
|
|
29
|
+
- `live_snapshot {path}` → tier-2 blocks + revision (for finding target block markdown).
|
|
30
|
+
- `live_reply {requestId, status}` → working|done|error.
|
|
31
|
+
- `live_submit_markdown {previewId, requestId, variants:[{variantId?,label,markdown}]}` → posts to md-preview; enforces 2–5 variants; server derives variantId if absent.
|
|
32
|
+
- `live_submit_web {previewId, requestId, variants|domPreviewOps, candidateSourcePatch, baseFiles}` → posts to existing web-preview.
|
|
33
|
+
|
|
34
|
+
Agent flow (documented in skill): call `live_attach` once → loop `live_poll` → on `generate` markdown request: `live_snapshot`, produce 2–5 rewrites of the target block, `live_submit_markdown`, `live_reply done` → loop. Agent NEVER accepts.
|
|
35
|
+
|
|
36
|
+
## Client: shared Live overlay + ephemeral markdown preview
|
|
37
|
+
- Presence component (new, shared) `src/components/editor/live-presence.tsx`: polls `/api/wiki/live/status`; solid/amber + Connect; grace window.
|
|
38
|
+
- Markdown ephemeral preview: integration point `editor.tsx:435-464` (block annotation effect provides `[data-block-ref]` slots + `blockRefPositions`). On proposal `ready`, render selected variant via `markdownToHtml(candidate, {pagePath, sanitize: isViewing})` into an overlay pinned to the target block slot; hide original block visually; cycle = swap candidate; **Accept** → POST md-resolve accept (server commits) then reload snapshot; **Discard** → drop client state only. Never call `editor.commands.setContent` for preview; never write activity/audit provenance for pending preview.
|
|
39
|
+
- Target selection reuses `resolveSelectionBlock` (block primary, text-range as context fields).
|
|
40
|
+
- Verb/label alignment in `web-tweak-overlay.tsx`: Target/Variant/Proposal/Accept/Discard/Go.
|
|
41
|
+
|
|
42
|
+
## Delete from live path (client)
|
|
43
|
+
`run-review-bar.tsx`, `instruction-queue-bar.tsx`, `instruction-popover.tsx`, activity/audit provenance hover popover + delegation IF no pending-review remains, `onInstruct` in `bubble-menu.tsx` and its editor wiring, `draftInstructions`/`sentInstructions` state. Keep: `ActivityProvenance` extension, sanitize-schema activity/audit provenance support, `wrapAsActivityProvenance`/`unwrapActivityProvenances`/`revertActivityProvenance` (accepted provenance), server accepted-provenance ops.
|
|
44
|
+
|
|
45
|
+
## Keep as-is
|
|
46
|
+
Tier-2 `/api/agent/files` commit path (stale/idempotency), web-tweak resolve/status/picker routes, content-clock revision, block-ref frontmatter offset fix, filesystem MCP tools.
|
|
47
|
+
|
|
48
|
+
## Test floor
|
|
49
|
+
Current floor 693–694. Replace deleted live/loop tests with: md-proposal store lifecycle (requested→ready→accept commits verbatim / discard leaves file identical / invalidated on drift), MCP tool-handler tests, presence honesty. Keep suite green.
|