@rubytech/create-sitedesk-code 0.1.387 → 0.1.389
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/dist/__tests__/joblogic-excluded.test.js +39 -0
- package/dist/index.js +21 -0
- package/package.json +1 -1
- package/payload/platform/config/brand.json +3 -3
- package/payload/platform/plugins/.claude-plugin/marketplace.json +0 -10
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -2
- package/payload/platform/plugins/docs/references/admin-session.md +4 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +18 -1
- package/payload/platform/plugins/docs/references/joblogic.md +2 -0
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +7 -3
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +2 -0
- package/payload/platform/plugins/work/PLUGIN.md +3 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.d.ts +2 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.js +98 -0
- package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.js.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/index.js +16 -0
- package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.d.ts +53 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.d.ts.map +1 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.js +80 -0
- package/payload/platform/plugins/work/mcp/dist/tools/session-metering.js.map +1 -0
- package/payload/platform/plugins/work/mcp/package.json +2 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +98 -8
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pricing.d.ts +45 -0
- package/payload/platform/services/claude-session-manager/dist/pricing.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/pricing.js +57 -0
- package/payload/platform/services/claude-session-manager/dist/pricing.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.d.ts +38 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.js +292 -0
- package/payload/platform/services/claude-session-manager/dist/session-metering.js.map +1 -0
- package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
- package/payload/premium-plugins/.claude-plugin/marketplace.json +0 -15
- package/payload/server/public/assets/{AdminLoginScreens-BejIjbmU.js → AdminLoginScreens-CerrEc_m.js} +1 -1
- package/payload/server/public/assets/AdminShell-cRTvNRbo.js +1 -0
- package/payload/server/public/assets/{Checkbox-1F1tzqca.js → Checkbox-Dh2pLMFN.js} +1 -1
- package/payload/server/public/assets/{Transcript-DkGa4CQH.js → Transcript-B_GVJujB.js} +1 -1
- package/payload/server/public/assets/{admin-DqQARkjy.js → admin-BXaYelnR.js} +1 -1
- package/payload/server/public/assets/{browser-nDtEK6RC.js → browser-fhjGE7fH.js} +1 -1
- package/payload/server/public/assets/calendar-PnZudAtc.js +1 -0
- package/payload/server/public/assets/chat-Dy_zrjKS.js +1 -0
- package/payload/server/public/assets/chevron-left-IB6TmMZ_.js +1 -0
- package/payload/server/public/assets/data-B2IcjAj6.js +1 -0
- package/payload/server/public/assets/{graph-DFyicKd7.js → graph-CycO3tkW.js} +2 -2
- package/payload/server/public/assets/{graph-labels-D3BQdcpD.js → graph-labels-DlSsSpBV.js} +1 -1
- package/payload/server/public/assets/{operator-BxrjWdT9.js → operator-L4kBC-zS.js} +1 -1
- package/payload/server/public/assets/page-D5E-Ng4D.js +1 -0
- package/payload/server/public/assets/page-M8sD9LOi.js +32 -0
- package/payload/server/public/assets/{public-DbdqfdYq.js → public-BmnajF3K.js} +1 -1
- package/payload/server/public/assets/{rotate-ccw-BkX8HODe.js → rotate-ccw-W5HhvAbo.js} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-D1TI1xvd.css +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-UqZbmzYy.js +9 -0
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +5 -5
- package/payload/server/public/chat.html +8 -8
- package/payload/server/public/data.html +7 -7
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +10 -10
- package/payload/server/public/operator.html +10 -10
- package/payload/server/public/public.html +8 -8
- package/payload/server/server.js +444 -315
- package/payload/platform/plugins/joblogic/.claude-plugin/plugin.json +0 -21
- package/payload/platform/plugins/joblogic/PLUGIN.md +0 -182
- package/payload/platform/plugins/joblogic/lib/mcp-spawn-tee/index.js +0 -193
- package/payload/platform/plugins/joblogic/lib/mcp-spawn-tee/package.json +0 -3
- package/payload/platform/plugins/joblogic/mcp/dist/index.d.ts +0 -2
- package/payload/platform/plugins/joblogic/mcp/dist/index.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/index.js +0 -229
- package/payload/platform/plugins/joblogic/mcp/dist/index.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.d.ts +0 -31
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.js +0 -78
- package/payload/platform/plugins/joblogic/mcp/dist/lib/auth.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.d.ts +0 -35
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.js +0 -106
- package/payload/platform/plugins/joblogic/mcp/dist/lib/client.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.d.ts +0 -8
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.js +0 -41
- package/payload/platform/plugins/joblogic/mcp/dist/lib/idempotency.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.d.ts +0 -21
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.d.ts.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.js +0 -47
- package/payload/platform/plugins/joblogic/mcp/dist/lib/secrets.js.map +0 -1
- package/payload/platform/plugins/joblogic/mcp/package.json +0 -10
- package/payload/platform/plugins/joblogic/skills/joblogic/SKILL.md +0 -32
- package/payload/platform/plugins/sales/.claude-plugin/plugin.json +0 -8
- package/payload/platform/plugins/sales/PLUGIN.md +0 -106
- package/payload/platform/plugins/sales/references/close-tracking.md +0 -69
- package/payload/platform/plugins/sales/references/comparisons.md +0 -99
- package/payload/platform/plugins/sales/references/competitive-positioning.md +0 -51
- package/payload/platform/plugins/sales/references/faq.md +0 -73
- package/payload/platform/plugins/sales/references/objection-handling.md +0 -157
- package/payload/platform/plugins/sales/references/pricing.md +0 -101
- package/payload/premium-plugins/teaching/.claude-plugin/plugin.json +0 -8
- package/payload/premium-plugins/teaching/PLUGIN.md +0 -58
- package/payload/premium-plugins/teaching/skills/interactive-tutor/SKILL.md +0 -59
- package/payload/premium-plugins/teaching/skills/interactive-tutor/references/assessment.md +0 -70
- package/payload/premium-plugins/teaching/skills/interactive-tutor/references/classroom-conduct.md +0 -43
- package/payload/premium-plugins/teaching/skills/interactive-tutor/references/teaching-modes.md +0 -83
- package/payload/premium-plugins/teaching/skills/lesson-planner/SKILL.md +0 -48
- package/payload/premium-plugins/teaching/skills/lesson-planner/references/context-gathering.md +0 -41
- package/payload/premium-plugins/teaching/skills/lesson-planner/references/plan-structure.md +0 -94
- package/payload/premium-plugins/teaching/skills/study-pack-builder/SKILL.md +0 -52
- package/payload/premium-plugins/teaching/skills/study-pack-builder/references/disaggregation.md +0 -49
- package/payload/premium-plugins/teaching/skills/study-pack-builder/references/materials.md +0 -116
- package/payload/premium-plugins/venture-studio/.claude-plugin/plugin.json +0 -8
- package/payload/premium-plugins/venture-studio/PLUGIN.md +0 -128
- package/payload/premium-plugins/venture-studio/bin/scaffold.sh +0 -116
- package/payload/premium-plugins/venture-studio/skills/brand-pack/SKILL.md +0 -256
- package/payload/premium-plugins/venture-studio/skills/brand-pack/references/color-psychology.md +0 -118
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +0 -436
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/business-plan-template.md +0 -64
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/competitive-battlecard.md +0 -37
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/competitor-analysis.md +0 -32
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/compliance-research-checklist.md +0 -53
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/data-room-structure.md +0 -88
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/deck-blueprint-template.md +0 -39
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/design-tokens-application.md +0 -79
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/html-pdf-pipeline.md +0 -236
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/internal-workings-scrub.md +0 -33
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/monetization-strategy.md +0 -35
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/pricing-strategy.md +0 -37
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/strategy-frameworks.md +0 -46
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/termsheet-template.md +0 -88
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/index.html +0 -1565
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/render-pdf.mjs +0 -91
- package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/term_sheet.html +0 -715
- package/payload/premium-plugins/venture-studio/skills/legal-essentials/SKILL.md +0 -65
- package/payload/premium-plugins/venture-studio/skills/office-hours/SKILL.md +0 -587
- package/payload/premium-plugins/venture-studio/skills/prototype-host/SKILL.md +0 -179
- package/payload/premium-plugins/venture-studio/skills/prototype-host/references/cloudflared-ingress-edit.md +0 -81
- package/payload/premium-plugins/venture-studio/skills/prototype-host/references/scaffold-frameworks.md +0 -60
- package/payload/premium-plugins/venture-studio/skills/prototype-host/references/systemd-user-service.md +0 -104
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/SKILL.md +0 -342
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/aarrr-metrics.md +0 -275
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/assumption-testing.md +0 -93
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/boolean-search.md +0 -308
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/build-measure-learn.md +0 -262
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/business-model-canvas.md +0 -171
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/commitment-signals.md +0 -246
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/design-thinking.md +0 -183
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/earlyvangelist.md +0 -190
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/first-principles.md +0 -58
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/fishbone.md +0 -114
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/five-whys.md +0 -43
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/ice-scoring.md +0 -237
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/innovation-accounting.md +0 -290
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/jtbd.md +0 -105
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/landing-page.md +0 -361
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-sizing.md +0 -58
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-type.md +0 -167
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mom-test.md +0 -193
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mvp-types.md +0 -200
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/og-images.md +0 -239
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pareto.md +0 -103
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/persona-development.md +0 -291
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pivot-types.md +0 -225
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/positioning-statement.md +0 -179
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/prd.md +0 -363
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pre-mortem.md +0 -74
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/problem-validation.md +0 -253
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/product-market-fit.md +0 -256
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/research-synthesis.md +0 -276
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/strategy-red-team.md +0 -41
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/three-engines-of-growth.md +0 -248
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/validation-tests.md +0 -89
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/value-proposition-canvas.md +0 -121
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/win-loss-analysis.md +0 -242
- package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/workflow-mapping.md +0 -271
- package/payload/premium-plugins/writer-craft/.claude-plugin/plugin.json +0 -21
- package/payload/premium-plugins/writer-craft/PLUGIN.md +0 -134
- package/payload/premium-plugins/writer-craft/agents/writer-craft--manuscript-reviewer.md +0 -108
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts +0 -8
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js +0 -71
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/dist/index.js.map +0 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-lifeline/package.json +0 -7
- package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/index.js +0 -193
- package/payload/premium-plugins/writer-craft/lib/mcp-spawn-tee/package.json +0 -3
- package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts +0 -51
- package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js +0 -196
- package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js.map +0 -1
- package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/package.json +0 -7
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts +0 -3
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js +0 -58
- package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts +0 -3
- package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js +0 -403
- package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts +0 -14
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js +0 -47
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +0 -117
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +0 -138
- package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +0 -90
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +0 -609
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts +0 -19
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js +0 -124
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +0 -38
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +0 -93
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +0 -61
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +0 -171
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts +0 -35
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js +0 -127
- package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js.map +0 -1
- package/payload/premium-plugins/writer-craft/mcp/package-lock.json +0 -1327
- package/payload/premium-plugins/writer-craft/mcp/package.json +0 -19
- package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +0 -420
- package/payload/premium-plugins/writer-craft/mcp/src/index.ts +0 -457
- package/payload/premium-plugins/writer-craft/mcp/src/lib/neo4j.ts +0 -56
- package/payload/premium-plugins/writer-craft/mcp/src/lib/voice-corpus.ts +0 -154
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +0 -833
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-ingest-session-text.ts +0 -153
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +0 -148
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +0 -270
- package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-tag-content.ts +0 -181
- package/payload/premium-plugins/writer-craft/mcp/tsconfig.json +0 -8
- package/payload/premium-plugins/writer-craft/skills/citation-style/SKILL.md +0 -94
- package/payload/premium-plugins/writer-craft/skills/citation-style/references/book-and-chapter-models.md +0 -77
- package/payload/premium-plugins/writer-craft/skills/citation-style/references/citation-rules.md +0 -103
- package/payload/premium-plugins/writer-craft/skills/citation-style/references/journal-article-models.md +0 -74
- package/payload/premium-plugins/writer-craft/skills/citation-style/references/other-source-models.md +0 -146
- package/payload/premium-plugins/writer-craft/skills/citation-style/references/reference-list-rules.md +0 -70
- package/payload/premium-plugins/writer-craft/skills/editorial-practice/SKILL.md +0 -108
- package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/copyediting.md +0 -73
- package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/developmental-editing.md +0 -85
- package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/genre-specific-editing.md +0 -78
- package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/line-editing.md +0 -55
- package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/self-editing.md +0 -89
- package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/SKILL.md +0 -114
- package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/audience-analysis.md +0 -73
- package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/crafting-persuasive-story.md +0 -76
- package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/persuasion-case-studies.md +0 -67
- package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/transformation-framework.md +0 -86
- package/payload/premium-plugins/writer-craft/skills/point-of-view/SKILL.md +0 -97
- package/payload/premium-plugins/writer-craft/skills/point-of-view/references/indirect-narration.md +0 -72
- package/payload/premium-plugins/writer-craft/skills/point-of-view/references/pov-types-and-voice.md +0 -91
- package/payload/premium-plugins/writer-craft/skills/point-of-view/references/protagonist-filter.md +0 -71
- package/payload/premium-plugins/writer-craft/skills/point-of-view/references/tense-and-person.md +0 -85
- package/payload/premium-plugins/writer-craft/skills/prose-craft/SKILL.md +0 -100
- package/payload/premium-plugins/writer-craft/skills/prose-craft/references/punctuation-and-grammar.md +0 -72
- package/payload/premium-plugins/writer-craft/skills/prose-craft/references/repetition.md +0 -71
- package/payload/premium-plugins/writer-craft/skills/prose-craft/references/sound-and-rhythm.md +0 -64
- package/payload/premium-plugins/writer-craft/skills/prose-craft/references/word-economy.md +0 -93
- package/payload/premium-plugins/writer-craft/skills/reader-engagement/SKILL.md +0 -100
- package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/cause-effect-setup-payoff.md +0 -79
- package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/conflict-escalation.md +0 -81
- package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/hooking-readers.md +0 -67
- package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/neurochemistry-of-engagement.md +0 -94
- package/payload/premium-plugins/writer-craft/skills/review-manuscript/SKILL.md +0 -111
- package/payload/premium-plugins/writer-craft/skills/review-manuscript/references/review-manuscript-checklist.md +0 -119
- package/payload/premium-plugins/writer-craft/skills/review-prose/SKILL.md +0 -99
- package/payload/premium-plugins/writer-craft/skills/review-prose/references/prose-review-checklist.md +0 -112
- package/payload/premium-plugins/writer-craft/skills/review-scene/SKILL.md +0 -99
- package/payload/premium-plugins/writer-craft/skills/review-scene/references/scene-analysis-framework.md +0 -95
- package/payload/premium-plugins/writer-craft/skills/story-architecture/SKILL.md +0 -106
- package/payload/premium-plugins/writer-craft/skills/story-architecture/references/blueprinting-and-scene-cards.md +0 -118
- package/payload/premium-plugins/writer-craft/skills/story-architecture/references/inner-issue-and-protagonist-goal.md +0 -66
- package/payload/premium-plugins/writer-craft/skills/story-architecture/references/misbelief-desire-worldview.md +0 -87
- package/payload/premium-plugins/writer-craft/skills/story-architecture/references/origin-scenes-and-escalation.md +0 -82
- package/payload/premium-plugins/writer-craft/skills/story-blueprint/SKILL.md +0 -133
- package/payload/premium-plugins/writer-craft/skills/story-blueprint/references/blueprinting-exercises.md +0 -118
- package/payload/premium-plugins/writer-craft/skills/story-blueprint/references/blueprinting-process.md +0 -128
- package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +0 -241
- package/payload/server/public/assets/AdminShell-D2-uBSB5.js +0 -1
- package/payload/server/public/assets/calendar-CO4Bwmho.js +0 -1
- package/payload/server/public/assets/chat-DeIge_bC.js +0 -1
- package/payload/server/public/assets/chevron-left-DhVdq0aN.js +0 -1
- package/payload/server/public/assets/data-B1GIdzHk.js +0 -1
- package/payload/server/public/assets/page-ByDLq_o1.js +0 -1
- package/payload/server/public/assets/page-D-Ep4bXd.js +0 -32
- package/payload/server/public/assets/useSubAccountSwitcher-DMbRhLPv.js +0 -9
- package/payload/server/public/assets/useSubAccountSwitcher-DS0iqSkP.css +0 -1
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
# The Blueprinting Process — Step by Step
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The blueprint is not a traditional outline. It is built scene by scene, grounded in the protagonist's internal story, and developed iteratively alongside drafting. Plot is the servant of story — external events exist to force the internal transformation.
|
|
6
|
-
|
|
7
|
-
The process starts with the internal architecture and builds outward.
|
|
8
|
-
|
|
9
|
-
## Step 1: The What If
|
|
10
|
-
|
|
11
|
-
Every story begins with a premise. A story-worthy What If must contain three elements:
|
|
12
|
-
|
|
13
|
-
1. **Context** — the specific world, circumstances, and relationships that make the situation meaningful
|
|
14
|
-
2. **Conflict** — not just external obstacle, but the seed of internal struggle
|
|
15
|
-
3. **A point** — the thematic question the story will interrogate
|
|
16
|
-
|
|
17
|
-
### Testing Your What If
|
|
18
|
-
A neutral What If is not story-worthy:
|
|
19
|
-
- "What if a woman got a new job?" → neutral, no internal conflict implied
|
|
20
|
-
- "What if a woman who built her identity around being indispensable at work was promoted into a role where she has to delegate everything?" → story-worthy, implies collision between identity and situation
|
|
21
|
-
|
|
22
|
-
The What If is not a plot summary. It is closer to a thesis statement for the story's meaning.
|
|
23
|
-
|
|
24
|
-
## Step 2: The Protagonist
|
|
25
|
-
|
|
26
|
-
The protagonist is not whoever the story happens to — it's the person whose internal change the story is about.
|
|
27
|
-
|
|
28
|
-
### Key Questions
|
|
29
|
-
- Who has the most to lose internally?
|
|
30
|
-
- Whose worldview will be most challenged by the What If?
|
|
31
|
-
- Who will be forced to change or be destroyed by the attempt to avoid it?
|
|
32
|
-
|
|
33
|
-
### Common Errors
|
|
34
|
-
- Introducing too many characters without a clear focal point
|
|
35
|
-
- Choosing a protagonist who is too passive or already enlightened
|
|
36
|
-
- Confusing the most active character with the most internally conflicted one
|
|
37
|
-
|
|
38
|
-
## Step 3: Misbelief and Desire
|
|
39
|
-
|
|
40
|
-
### The Misbelief
|
|
41
|
-
A false conclusion about how the world works, rooted in a specific past experience. Not a character flaw — a coping strategy. It protected the protagonist once; now it imprisons them.
|
|
42
|
-
|
|
43
|
-
Excavate until the misbelief is:
|
|
44
|
-
- Specific enough to state in one sentence
|
|
45
|
-
- Traceable to a concrete origin experience
|
|
46
|
-
- Active — currently shaping decisions
|
|
47
|
-
- In direct conflict with the desire
|
|
48
|
-
|
|
49
|
-
### The Desire
|
|
50
|
-
Something the protagonist has wanted, perhaps for years. The misbelief prevents them from achieving it. Every time they move toward the desire, the misbelief sabotages them.
|
|
51
|
-
|
|
52
|
-
## Step 4: The Origin Scene
|
|
53
|
-
|
|
54
|
-
Write the specific moment the misbelief formed. Not a summary — a full scene in the protagonist's subjective POV. The reader must see the emotional logic: how this conclusion made sense at the time.
|
|
55
|
-
|
|
56
|
-
## Step 5: Escalating Backstory
|
|
57
|
-
|
|
58
|
-
Write 3-5 scenes from the protagonist's past showing the misbelief deepening:
|
|
59
|
-
- Each scene tests or activates the misbelief
|
|
60
|
-
- The protagonist acts on it, and the result appears to confirm it
|
|
61
|
-
- Each scene escalates in significance — the costs increase
|
|
62
|
-
- The pattern explains who the protagonist is on page one
|
|
63
|
-
|
|
64
|
-
## Step 6: The Opening
|
|
65
|
-
|
|
66
|
-
The novel begins at the last possible moment — when the protagonist can no longer avoid confronting the thing the misbelief has protected them from.
|
|
67
|
-
|
|
68
|
-
The opening scene must accomplish:
|
|
69
|
-
1. Establish the protagonist's internal state (desire, misbelief, the world they believe they're living in)
|
|
70
|
-
2. Introduce the unavoidable external problem
|
|
71
|
-
3. Plant seeds of major internal conflicts
|
|
72
|
-
4. Establish a ticking clock
|
|
73
|
-
|
|
74
|
-
### The Unavoidable External Problem Must:
|
|
75
|
-
- Directly threaten or challenge the misbelief
|
|
76
|
-
- Activate the long-standing desire
|
|
77
|
-
- Have a clear ticking clock
|
|
78
|
-
- Have a clear consequence the reader can anticipate from page one
|
|
79
|
-
|
|
80
|
-
Write a first-layer version. It will be rewritten many times. Use TK for elements not yet known.
|
|
81
|
-
|
|
82
|
-
## Step 7: The Ending (The Aha Moment)
|
|
83
|
-
|
|
84
|
-
Determine the internal climax before constructing the middle.
|
|
85
|
-
|
|
86
|
-
The Aha moment is not the plot climax — it is the moment of internal change: when the protagonist confronts and dismantles (or fails to dismantle) their misbelief.
|
|
87
|
-
|
|
88
|
-
Requirements:
|
|
89
|
-
- **Earned** — pushed to the absolute edge
|
|
90
|
-
- **Specific** — a precise scene-level moment
|
|
91
|
-
- **Tied to the third rail** — causally connected to everything the plot has put them through
|
|
92
|
-
|
|
93
|
-
The ending will change as the story deepens. That is fine.
|
|
94
|
-
|
|
95
|
-
## Step 8: Building Scene Cards
|
|
96
|
-
|
|
97
|
-
With opening and ending bookended, build Scene Cards connecting them.
|
|
98
|
-
|
|
99
|
-
For each scene:
|
|
100
|
-
- **External event**: What happens
|
|
101
|
-
- **Internal meaning**: How it forces the internal struggle forward
|
|
102
|
-
- **Urgency hook**: What question it raises for the reader
|
|
103
|
-
- **Cause**: What scene triggered this one
|
|
104
|
-
- **Effect**: What this scene triggers next
|
|
105
|
-
|
|
106
|
-
### Using TK
|
|
107
|
-
"To come" — a placeholder for something that must be there but isn't yet known. TKs are not failures; they are honest markers of what needs excavation.
|
|
108
|
-
|
|
109
|
-
### Mining the Past for Plot
|
|
110
|
-
Use backstory scenes to generate plot events. The protagonist's misbelief will predictably cause them to react in certain ways — those reactions generate consequences — those consequences become plot.
|
|
111
|
-
|
|
112
|
-
### The Sixth Tick
|
|
113
|
-
The last thing that happens before the novel begins. The final moment of the "before" life. Usually the event that makes the unavoidable external problem unavoidable.
|
|
114
|
-
|
|
115
|
-
## Step 9: Writing Forward
|
|
116
|
-
|
|
117
|
-
Stories grow in spirals:
|
|
118
|
-
- Write a scene → it reveals something about the past
|
|
119
|
-
- Revise earlier scenes → reveals something about the future
|
|
120
|
-
- Each pass deepens rather than merely extends
|
|
121
|
-
|
|
122
|
-
Draft and blueprint simultaneously. The two activities inform each other. Don't complete the blueprint before writing; don't write without blueprinting.
|
|
123
|
-
|
|
124
|
-
### The Plot Trap
|
|
125
|
-
Once a plot is in motion, it is tempting to follow external events wherever they lead while the internal story quietly suffocates. For every external event, ask: does it force the internal struggle forward? If not, cut or replace.
|
|
126
|
-
|
|
127
|
-
### Trust the Cards
|
|
128
|
-
When lost in a scene, return to the Scene Card. What is the internal meaning of this moment? What must the protagonist realise, resist, or choose?
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: voice-mirror
|
|
3
|
-
description: "Capture the operator's authorial voice from their own writing and apply it to agent-drafted content. Activate when the operator asks to tag historical content as human-authored, to distil a style profile, to retrieve voice exemplars for a drafting task, or to record their edit on an agent draft as feedback. Other drafting skills (email composition, Postiz publisher, property-brochure, prospectus) call `voice-retrieve-conditioning` transparently — `voiceMirror: false` in the calling skill's frontmatter opts out."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Voice Mirror
|
|
7
|
-
|
|
8
|
-
Distil the operator's own voice from the content they have actually written, and condition agent drafts on it so generated copy reads as theirs. Anthropic models cannot be fine-tuned; voice mimicry comes from in-context conditioning — a style card plus a handful of real exemplars. The 1M context window makes this affordable.
|
|
9
|
-
|
|
10
|
-
The skill is built on five deterministic MCP tools served by the `writer-craft` plugin's MCP server (`premium-plugins/writer-craft/mcp/`):
|
|
11
|
-
|
|
12
|
-
| Tool | Purpose |
|
|
13
|
-
|------|---------|
|
|
14
|
-
| `voice-tag-content` | Stamp historical or new content nodes with `authorshipMode` and operator-supplied `format`. Bulk-tags arrays of node ids. |
|
|
15
|
-
| `voice-distil-profile` | Walk the `human-only` corpus for a given `format` and `scope` and produce a `:VoiceProfile {styleCard, generatedAt, corpusSize, feedbackEntries, format, scope}` node. `scope='personal'` (default) walks one author; `scope='org'` walks the whole account. Without a `format`, enumerates all formats present in that scope's corpus and distils each. |
|
|
16
|
-
| `voice-retrieve-conditioning` | Return `{styleCard, exemplars[], status}` for a drafting brief. Requires `brief.format`; `brief.scope` (default `personal`) picks personal vs org voice, with a personal→org fallback. K=5 for short-form, K=15 for long-form. Token-budget bounded. |
|
|
17
|
-
| `voice-record-feedback` | When the operator edits an agent draft, write a `:VoiceEdit {originalText, editedText, intent, occurredAt, format}-[:FEEDBACK_FOR]->(:VoiceProfile {format})` node. The `intent` field is a Haiku-summarised diff. |
|
|
18
|
-
| `voice-ingest-session-text` | Write operator turns from the current session as `:Message {format:'text', authorshipMode:'human-only'}` corpus nodes. The agent reads its own operator turns from context and passes them as `turns`. Deduplicates via `contentHash`. Invoked on demand when the operator asks to capture this session's voice. |
|
|
19
|
-
|
|
20
|
-
## Surface — establishment is admin-only; conditioning is shared with the drafting seat
|
|
21
|
-
|
|
22
|
-
The four **establishment** tools (`voice-tag-content`, `voice-distil-profile`, `voice-ingest-session-text`, `voice-record-feedback`) are admin-allowlisted and exist only on the admin agent's tool surface. No specialist carries them, by design: `format` and `authorshipMode` are editorial choices the operator makes, so building and curating a voice profile is an operator-interactive admin flow, not a step a specialist runs unattended.
|
|
23
|
-
|
|
24
|
-
`voice-retrieve-conditioning` is different. It is the **drafting-time** conditioning tool: a drafting skill calls it to pull the style card and exemplars and condition its prose. It is carried by `specialists:content-producer` (the authoring seat, which holds `plainly` and `prose-craft`) and is **not** on the admin surface — conditioning is drafting-seat-only. The consulting prose deliverables (`decision-memo`, `narrative-builder`, `pitch-deck`), the property brochure (`property-brochure`), and the investor data-room business plan (Stage 3 prose) all compose on content-producer and condition there. The split that holds: the operator curates voice with the four establishment tools on the admin seat; any drafting seat only retrieves it. Admin never calls `voice-retrieve-conditioning` directly — the conditioning instruction goes into the brief admin hands to content-producer.
|
|
25
|
-
|
|
26
|
-
This matters most right after an ingest. When a specialist (the librarian) files a document and the operator then asks to tag it — "mark that as me / human-only / marketing-copy" — the tagging is yours to run, not the specialist's. The specialist cannot call `voice-tag-content` and will hand back the created node's identifier instead. Take that id and run `voice-tag-content` here. If the id is not in context (a later turn, the librarian's return scrolled off), fall back to the unknown-authorship query in the backfill flow below to find the just-filed node. Never route the tag back into a specialist; a specialist reporting "voice-tag-content is not in my tools" is the boundary working as intended, not a failure to escalate.
|
|
27
|
-
|
|
28
|
-
## When to activate
|
|
29
|
-
|
|
30
|
-
Activate when the operator says any of:
|
|
31
|
-
|
|
32
|
-
- **"Tag this as me" / "I wrote that" / "mark these as human-only".** Drives `voice-tag-content`.
|
|
33
|
-
- **"Build my voice profile" / "distil my style" / "rebuild the voice mirror".** Drives `voice-distil-profile`.
|
|
34
|
-
- **"Read my writing first" / "draft this in my voice" — when the operator is asking for a hand-written-quality draft, not a generic AI reply.** Drives `voice-retrieve-conditioning`; the calling drafting skill is the actual surface, this skill is the conditioning input.
|
|
35
|
-
- **"Use my edit as a teaching example" / "remember how I changed that".** Drives `voice-record-feedback`.
|
|
36
|
-
- **"Review my historical writing and tag it" / "start the backfill".** Drives the interactive backfill flow described below.
|
|
37
|
-
- **"Capture my voice from this chat" / "ingest this session" / "learn how I write from this conversation".** Drives the on-demand session-text capture flow described below.
|
|
38
|
-
|
|
39
|
-
Do **not** activate for:
|
|
40
|
-
|
|
41
|
-
- Writing-craft review tasks (`prose-craft`, `review-prose`, etc.). Those are critique skills, not voice-capture.
|
|
42
|
-
- Public-figure voice mimicry. Out of scope — see the `## Out of scope` section.
|
|
43
|
-
- Audio voice cloning. Different domain entirely.
|
|
44
|
-
|
|
45
|
-
## Corpus formats
|
|
46
|
-
|
|
47
|
-
Voice profiles are segmented by content format. The closed enum is:
|
|
48
|
-
|
|
49
|
-
| Format | Operator picks for |
|
|
50
|
-
|--------|--------------------|
|
|
51
|
-
| `text` | `:Message` nodes; the operator's session turns, captured on demand via `voice-ingest-session-text` when the operator asks to capture this session's voice |
|
|
52
|
-
| `email` | Email threads stored as `:KnowledgeDocument {source:'email'}` or `:ConversationArchive {source:'email'}` |
|
|
53
|
-
| `social-post` | `:SocialPost` nodes |
|
|
54
|
-
| `article` | Long-form `:KnowledgeDocument` the operator considers an article |
|
|
55
|
-
| `note` | Short-form `:KnowledgeDocument` the operator considers a note |
|
|
56
|
-
| `marketing-copy` | Any node the operator considers marketing copy |
|
|
57
|
-
|
|
58
|
-
Format is editorial — the operator picks it per node when calling `voice-tag-content`. The tool does not infer it.
|
|
59
|
-
|
|
60
|
-
## Flow — backfill review (one-shot session)
|
|
61
|
-
|
|
62
|
-
Run when the operator first installs voice-mirror, then whenever they want to refresh the corpus.
|
|
63
|
-
|
|
64
|
-
### 1. Pick a corpus stream
|
|
65
|
-
|
|
66
|
-
The operator's authored content lives in two stream shapes that the backfill UX handles differently:
|
|
67
|
-
|
|
68
|
-
- **Discrete documents and posts** — `:KnowledgeDocument` (covers email threads via `source:'email'`), `:SocialPost`, and one-off `:Message` nodes. Per-item tagging with previews.
|
|
69
|
-
- **Chat archives** — conversation-document `:KnowledgeDocument` nodes (those carrying `conversationIdentity`) with their child `:Section` chunks. Per-conversation tagging because chunking happens server-side and the operator owns whole conversations, not individual chunks. Chat is the highest-leverage corpus — the unguarded voice that email rarely captures.
|
|
70
|
-
|
|
71
|
-
Ask the operator which stream to backfill first. Default to chat archives when the account has any conversation-document `:KnowledgeDocument` nodes, because that's where voice signal is strongest.
|
|
72
|
-
|
|
73
|
-
### 2a. Discrete documents — paginate in batches of 10
|
|
74
|
-
|
|
75
|
-
Query for `:KnowledgeDocument | :SocialPost | :Message` nodes belonging to this operator's account whose `authorshipMode` is `unknown`. Order by `dateSent | datePublished | dateCreated` descending — most recent first. For each batch, surface a numbered list with: source label, date, recipient or topic, and a one-line preview (first ~120 chars of body). Operator commands name both mode and format:
|
|
76
|
-
|
|
77
|
-
- `1-10 human-only article` — tag every item in the batch as `human-only` with format `article`.
|
|
78
|
-
- `1,3,7 human-only email` — tag a subset with mode + format.
|
|
79
|
-
- `2 human-led-agent-assisted note` — single-item.
|
|
80
|
-
- `5 agent-led-human-reviewed marketing-copy` — single-item.
|
|
81
|
-
- `1-10 human-only article author:joel` — attribute the batch to a named author (a `userId`) rather than the tagging operator.
|
|
82
|
-
- `skip` — leave the batch as `unknown` and advance.
|
|
83
|
-
- `stop` — exit the backfill; the next session resumes from where the operator left off.
|
|
84
|
-
|
|
85
|
-
`format` is required on every command; the tool will not infer it. If the operator omits the format, ask before tagging. `author:<userId>` is optional — **omit it and the content is attributed to the tagging operator**, so single-operator accounts get personal attribution for free and behave exactly as before. Name an author only on a multi-operator account when tagging someone else's writing. Bulk-tag via `voice-tag-content` once per operator response. Emit `[voice-tag] mode=<mode> format=<format> scope=personal author=<userId> count=<n>` per write.
|
|
86
|
-
|
|
87
|
-
### 2b. Chat archives — paginate per conversation-document parent
|
|
88
|
-
|
|
89
|
-
For each conversation-document `:KnowledgeDocument` (with `conversationIdentity` set) that has at least one `:Section` chunk whose `authorshipMode` is `unknown`, surface: source file, participant names, message count, date range, and a one-line summary. Offer:
|
|
90
|
-
|
|
91
|
-
- `human-only` — tag every child `:Section` chunk in this conversation as `human-only`.
|
|
92
|
-
- `mixed` — open the conversation for per-chunk tagging (rare; only when the archive contains multiple authors on the operator's side).
|
|
93
|
-
- `not me` — tag every chunk as `agent-only` (e.g. a Slack channel where the operator only forwarded other people's messages).
|
|
94
|
-
- `skip` / `stop` — same semantics as 2a.
|
|
95
|
-
|
|
96
|
-
Bulk-tag via `voice-tag-content` with the list of `:Section` element IDs the conversation-document contains, passing `format='text'` (chat archives are unambiguously text-format). Attribution defaults to the tagging operator; on a multi-operator account, pass `author:<userId>` to attribute the conversation to the operator who actually owns it. The skill emits `[voice-tag] mode=<mode> format=<format> scope=personal author=<userId> count=<chunk-count>` once per conversation.
|
|
97
|
-
|
|
98
|
-
Authorship at conversation granularity is a deliberate UX trade-off: chunks within a conversation almost always share the same operator's voice, and per-chunk tagging at archive scale would burn the operator's attention. The `mixed` opt-in covers the rare case where it matters.
|
|
99
|
-
|
|
100
|
-
### 3. Distil when the corpus crosses threshold
|
|
101
|
-
|
|
102
|
-
After each backfill batch, check whether the qualifying corpus (`authorshipMode IN ['human-only', 'human-led-agent-assisted']`) for any format has grown ≥20% since the last `:VoiceProfile.corpusSize` for that format (or ≥1 entry if no profile exists for that format). If yes, offer to run `voice-distil-profile` immediately. The operator can defer; the next scheduled distillation will pick it up.
|
|
103
|
-
|
|
104
|
-
## On-demand text-format capture (session turns)
|
|
105
|
-
|
|
106
|
-
Operator turns are captured into the `text` corpus on demand — when the operator asks to capture this session's voice, never automatically. There is no SessionEnd hook; the operator is in the loop.
|
|
107
|
-
|
|
108
|
-
When the operator says "capture my voice from this chat" (or similar):
|
|
109
|
-
|
|
110
|
-
1. Read the operator's own turns from the live conversation context — the user messages already in this session.
|
|
111
|
-
2. Call `voice-ingest-session-text` with those turns as the `turns` array. The tool filters out slash commands, harness injections (`<system-reminder>`), and large paste blocks, deduplicates via SHA256 content hash, and writes each new turn as a `:Message {format:'text', authorshipMode:'human-only'}` node.
|
|
112
|
-
3. The tool triggers an incremental `text`-format distillation if the corpus grew ≥20% since the last profile.
|
|
113
|
-
|
|
114
|
-
This runs only on the admin seat (the tool is admin-allowlisted). Accounts without a voice profile degrade gracefully — capture simply populates the corpus for the first distillation.
|
|
115
|
-
|
|
116
|
-
## Flow — drafting-time conditioning
|
|
117
|
-
|
|
118
|
-
Drafting skills (email composition, Postiz, property-brochure, investor-data-room Stage 3 prose, prospectus) call `voice-retrieve-conditioning` transparently before assembling their prompt. The skill takes a brief — `{topic, format, length, register, scope}` — where `format` is the target corpus format and `scope` picks whose voice to draft in. Default `scope` is `personal` (the calling operator's own voice); a drafting skill whose output goes out under the business name passes `scope: "org"` for the house voice. Email composition stays personal; property-brochure, the investor-data-room Stage 3 business plan, and the prospectus skills request `org`. It returns:
|
|
119
|
-
|
|
120
|
-
```yaml
|
|
121
|
-
styleCard: |
|
|
122
|
-
sentenceLengthDistribution: short-heavy (median 12 words)
|
|
123
|
-
register: warm-professional, British, contraction-friendly
|
|
124
|
-
favoured: ["properly", "the right thing", "happy to"]
|
|
125
|
-
avoided: ["circle back", "synergy", "leverage"]
|
|
126
|
-
taboos: ["per my last email", "kind regards"]
|
|
127
|
-
opening: drop the salutation if the thread is mid-flow; otherwise "Hi <name>,"
|
|
128
|
-
closing: "Best, Neo" — no signature block
|
|
129
|
-
exemplars:
|
|
130
|
-
- source: Email to Sarah Knight, 2026-04-12, re: lease draft
|
|
131
|
-
body: "…actual operator-written paragraph…"
|
|
132
|
-
- source: SocialPost on LinkedIn, 2026-03-30
|
|
133
|
-
body: "…"
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
Drafting skills inject both blocks into their prompt. Opt-out is per-skill: declare `voiceMirror: false` in the skill's frontmatter and the calling site skips the fetch. Default is on.
|
|
137
|
-
|
|
138
|
-
The tool returns `{styleCard, exemplars, status}` with a discriminated `status`:
|
|
139
|
-
|
|
140
|
-
- **`ok`** — a profile and/or exemplars were returned for the requested scope; inject both blocks.
|
|
141
|
-
- **`fallback-org`** — a `personal` request found no personal profile/corpus, so the **org (house) voice** was returned instead. Inject the (org) blocks and draft normally. This is the standing signal that the calling operator has no personal attribution yet — the account is running on the house voice. Don't tell the operator they have "no profile"; they have the house one.
|
|
142
|
-
- **`no-data`** — the lookup ran but no `:VoiceProfile` exists for this scope and the corpus is empty (and, for a personal request, no org profile either). Fall back to default register; this is the only state where you say "you have no voice profile yet".
|
|
143
|
-
- **`error`** — the lookup failed (the payload carries an `error` message). Fall back to default register *exactly as for no-data* so drafting never crashes — but **never** tell the operator they have no profile; the profile state is unknown because the lookup errored.
|
|
144
|
-
|
|
145
|
-
In all four states drafting proceeds. `ok` and `fallback-org` inject a style card; `no-data` and `error` degrade to the default register. The distinction matters only for what you tell the operator about *why* a given voice was (or was not) applied.
|
|
146
|
-
|
|
147
|
-
Emit `[voice-retrieve] scope=<scope> format=<format> status=<status> styleCardBytes=<n> exemplarCount=<k> tokenBudget=<n>` per call.
|
|
148
|
-
|
|
149
|
-
## Flow — feedback capture
|
|
150
|
-
|
|
151
|
-
When the operator edits an agent draft (in the email composer's edit loop, or in any drafting skill that supports inline edits), capture the diff:
|
|
152
|
-
|
|
153
|
-
1. The calling skill passes `{originalText, editedText, format, scope}` to `voice-record-feedback`. `scope` matches the scope the draft was retrieved at — an edit on an org draft passes `scope: "org"`.
|
|
154
|
-
2. The tool runs a Haiku diff summarisation to produce an `intent` field — a one-sentence description of what the operator changed and why. Example intents: "shorter and dropped the apology", "switched to first person", "removed sign-off", "added a specific date".
|
|
155
|
-
3. The tool writes `(:VoiceEdit {originalText, editedText, intent, occurredAt, userId, scope, accountId, format})-[:FEEDBACK_FOR]->(:VoiceProfile {format})` for the scoped profile. An org edit routes to the org profile (`userId='__org__'`); a personal edit to the operator's own. The real editor is always preserved via `(:AdminUser)-[:AUTHORED]->(:VoiceEdit)`, even on org edits.
|
|
156
|
-
|
|
157
|
-
Feedback accumulates between distillations. The next `voice-distil-profile` run at the matching scope reads every `:VoiceEdit` linked to that profile and feeds the intents into the style-card refinement.
|
|
158
|
-
|
|
159
|
-
Emit `[voice-record-feedback] scope=<scope> userId=<id|__org__> format=<format> intent="<haiku-summary>" diffBytes=<n>`.
|
|
160
|
-
|
|
161
|
-
## Distillation cadence
|
|
162
|
-
|
|
163
|
-
`voice-distil-profile` re-runs per format when **either**:
|
|
164
|
-
|
|
165
|
-
- the `human-only` corpus for that format has grown ≥20% since the last `:VoiceProfile.corpusSize` for that format, OR
|
|
166
|
-
- 30 days have passed since `:VoiceProfile.generatedAt` for that format.
|
|
167
|
-
|
|
168
|
-
A re-run within the 30-day window with <20% growth is a no-op — the tool returns the existing profile unchanged and emits `[voice-distil] skip reason=below-threshold format=<format>`.
|
|
169
|
-
|
|
170
|
-
The triggering surface is the skill, not a scheduled job. Distillation runs on demand: at the end of a backfill batch, when the email composer notices stale-profile narration, or when the operator says "rebuild my voice profile".
|
|
171
|
-
|
|
172
|
-
### Amend mode (single-document update)
|
|
173
|
-
|
|
174
|
-
Activate when the operator names one or more specific documents and wants them folded into their voice profile right now — e.g. **"I just published this new article, take that into account"**, **"that thread to Sarah is a good example of how I write — fold it in"**, or **"add this essay to my voice profile"**. The full-corpus distil cadence is wrong for "this specific document, now" — the operator's signal is the document choice, not the cadence guard.
|
|
175
|
-
|
|
176
|
-
Call `voice-distil-profile` with:
|
|
177
|
-
|
|
178
|
-
- `mode: 'amend'`
|
|
179
|
-
- `format: <VoiceFormat>` — required; the operator's per-format profile
|
|
180
|
-
- `nodeIds: [<elementId>, ...]` — the documents the operator picked (one or more)
|
|
181
|
-
|
|
182
|
-
The tool returns `{existingStyleCard, exemplars[], feedbackIntents[], eligible, ineligible}`. Compare the named exemplars against the prior card and the recent edit intents, then choose:
|
|
183
|
-
|
|
184
|
-
- **Material delta** — compose an updated YAML and call `mode: 'write'` with `styleCardYaml` and `amendedFromNodeIds: [<elementId>, ...]` listing the documents that actually moved the card. The write bypasses the cadence guard and adds `LEARNED_FROM` edges to those documents (pre-existing edges remain).
|
|
185
|
-
- **No material delta** — reply to the operator in-turn ("nothing in that article shifts your voice card; the prior profile still applies"). Do not call `mode: 'write'`. `generatedAt` only advances on a write.
|
|
186
|
-
|
|
187
|
-
When `eligible=0` (every named document failed the predicate) surface the `ineligible[]` payload to the operator naming the per-id reason (`node-not-found`, `wrong-account`, `ineligible-authorship-mode`, `trashed`, `ineligible-label`) rather than silently no-op. Most commonly this means the documents are tagged as `agent-only` and need re-tagging via `voice-tag-content` before they can amend a profile.
|
|
188
|
-
|
|
189
|
-
Amend mode does not apply to the on-demand session-text capture path. Session-text ingest stays on the full-corpus path; amend is operator-initiated only.
|
|
190
|
-
|
|
191
|
-
## Org and personal scope
|
|
192
|
-
|
|
193
|
-
Every account holds, per format, **one org (house) profile and any number of personal profiles** at once:
|
|
194
|
-
|
|
195
|
-
- **Personal** — one operator's own voice. Key `(accountId, userId, format)`, `scope='personal'`, anchored on the operator's `:AdminUser`. Distilled from that operator's author-tagged content only (`n.voiceAuthor = userId`).
|
|
196
|
-
- **Org** — the account/house voice. Key `(accountId, '__org__', format)`, `scope='org'`, anchored on the account's `:LocalBusiness`. Distilled from the **whole account** (every author's content), not one person's.
|
|
197
|
-
|
|
198
|
-
`__org__` is a reserved sentinel userId. It keeps the existing `(accountId, userId, format)` unique constraint valid with no migration — exactly one org profile per `(account, format)` — and a real operator must never hold it.
|
|
199
|
-
|
|
200
|
-
Which voice a draft uses is the `scope` on the retrieval brief: `"my voice"` → personal, `"the house/org voice"` → org. A personal request with no personal profile yet falls back to the org profile (`status: "fallback-org"`); an org request with no org profile degrades to the default register (`status: "no-data"`).
|
|
201
|
-
|
|
202
|
-
**Single-operator accounts are unchanged.** With author omitted at tag time, the sole operator is the implicit author, so their personal corpus equals the account-wide corpus and personal distillation reproduces the prior single profile. Legacy content carries no `voiceAuthor`; it appears only in the account-wide org walk until re-tagged, and personal drafts fall back to the org voice in the meantime.
|
|
203
|
-
|
|
204
|
-
## Observability
|
|
205
|
-
|
|
206
|
-
| Tag | When |
|
|
207
|
-
|-----|------|
|
|
208
|
-
| `[voice-tag] mode=<mode> format=<format> scope=personal author=<userId> count=<n>` | Every tag write. `author=` is the resolved value (operator's id when omitted). |
|
|
209
|
-
| `[voice-distil] scope=<scope> userId=<id\|__org__> anchor=<AdminUser\|LocalBusiness> format=<format> corpusSize=<n> generatedAt=<iso> feedbackEntries=<n>` | Each distillation write. Org also carries `sentinel=__org__`. |
|
|
210
|
-
| `[voice-distil] scope=<scope> userId=<id\|__org__> format=<format> skip reason=<below-threshold\|recent\|empty-corpus>` | When the cadence/empty guard fires. |
|
|
211
|
-
| `[voice-distil] scope=<scope> mode=amend userId=<id\|__org__> format=<format> nodeIds=<count> existingProfile=<elementId\|none> eligible=<n> ineligible=<n> exemplars=<n>` | Each amend-mode call. `eligible=0` means surface `ineligible[]` to the operator, never silently no-op. |
|
|
212
|
-
| `[voice-distil] scope=<scope> mode=write userId=<id\|__org__> anchor=<…> format=<format> amended=true amendedFromNodeIds=<count> ...` | Amend-write fired (operator-initiated update persisted). |
|
|
213
|
-
| `[voice-retrieve] scope=<scope> format=<format> status=<ok\|fallback-org\|no-data\|error> styleCardBytes=<n> exemplarCount=<k> tokenBudget=<n>` | Each retrieval. `status=fallback-org` proves the personal→org fallback fired. |
|
|
214
|
-
| `[voice-record-feedback] scope=<scope> userId=<id\|__org__> format=<format> intent="<haiku-summary>" diffBytes=<n>` | Each feedback write. |
|
|
215
|
-
| `[voice-ingest-session-text] sessionId=<id> adminUser=<id> turns=<n> bytes=<n> skipped=<m>` | On-demand session-text capture. |
|
|
216
|
-
|
|
217
|
-
**Confirms working:** `[voice-retrieve] exemplarCount≥1` precedes every drafting-skill prompt assembly when the calling skill has not opted out. `[voice-distil]` appears at least once per 30-day window per active format per operator. `[voice-ingest-session-text] turns≥1` appears when the operator asks to capture a session's voice.
|
|
218
|
-
|
|
219
|
-
**Indicates failure:** `[voice-retrieve] exemplarCount=0` with non-empty corpus → similarity index broken; `[voice-distil] error …` → corpus walk or LLM call failed; absence of `[voice-record-feedback]` after an operator-edit-then-send flow → feedback loop is dead.
|
|
220
|
-
|
|
221
|
-
**Diagnostic path:**
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
journalctl -u maxy-code | grep -E '\[voice-(tag|distil|retrieve|record-feedback|ingest-session-text)\]'
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
Filter by `userId=<id>` for per-operator drill-down.
|
|
228
|
-
|
|
229
|
-
## Out of scope
|
|
230
|
-
|
|
231
|
-
- Voice blending across multiple authors (no "Joel + Neo combined voice").
|
|
232
|
-
- Style transfer from public-figure corpora — voice-mirror only learns from the operator's own writing.
|
|
233
|
-
- Audio voice cloning / speech synthesis — different domain.
|
|
234
|
-
- Auto-tagging legacy content via heuristics — backfill is operator-driven only; the agent never guesses authorship.
|
|
235
|
-
- Admin-UI editing of the `styleCard` — operator edits via `database-operator` for now. Surfacing this in a dedicated UI is a follow-up task.
|
|
236
|
-
|
|
237
|
-
## Dependencies
|
|
238
|
-
|
|
239
|
-
- **Memory plugin's graph-write gate** is the single write boundary; new tools route through it, never bypass.
|
|
240
|
-
- **Haiku LLM call path** (already used by `memory-classify`) is reused for diff-intent summarisation.
|
|
241
|
-
- **`:AdminUser` must exist** for the operator before distillation runs. Personal-mode operators with `Person {role: "admin-personal"}` need to be promoted to an `:AdminUser` first — out of scope here.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as e}from"./chunk-CAM3fms7.js";import{C as t,D as n,I as r,L as i,M as a,O as o,S as s,T as c,_ as l,c as u,d,h as f,j as p,l as m,o as h,p as g,r as ee,s as _,t as te,u as ne,v,w as re,x as y,y as ie}from"./useSubAccountSwitcher-DMbRhLPv.js";async function ae(){try{let e=await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`logout`})});return e.ok?(await e.json().catch(()=>({})))?.logged_out===!0:(console.error(`[admin-ui] claude-logout http-status=${e.status}`),!1)}catch(e){return console.error(`[admin-ui] claude-logout fetch failed: ${e instanceof Error?e.message:String(e)}`),!1}}var b=e(i(),1),x=a(),S={sm:14,md:16,lg:18},C={sm:30,md:38,lg:46};function w({variant:e=`primary`,size:t=`md`,icon:n,iconPosition:r=`leading`,loading:i=!1,fullWidth:a=!1,disabled:o=!1,type:s=`button`,onClick:c,"aria-label":l,style:u,className:d,children:f}){let p=[`btn`,`btn--${e}`,t===`md`?``:`btn--${t}`,a?`btn--full`:``,d].filter(Boolean).join(` `),m=S[t],h={...e===`send`?{width:C[t],height:C[t]}:{},...u},g=Object.keys(h).length>0;return(0,x.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,x.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,x.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,x.jsx)(n,{size:m})]}),i&&(0,x.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var oe=n(`archive-restore`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h2`,key:`tvwodi`}],[`path`,{d:`M20 8v11a2 2 0 0 1-2 2h-2`,key:`1gkqxj`}],[`path`,{d:`m9 15 3-3 3 3`,key:`1pd0qc`}],[`path`,{d:`M12 12v9`,key:`192myk`}]]),T=n(`archive`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8`,key:`1s80jp`}],[`path`,{d:`M10 12h4`,key:`a56b0p`}]]),E=n(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),se=n(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),ce=n(`history`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}],[`path`,{d:`M12 7v5l4 2`,key:`1fdv2h`}]]),D=n(`list-todo`,[[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}],[`path`,{d:`m3 17 2 2 4-4`,key:`1jhpwq`}],[`rect`,{x:`3`,y:`4`,width:`6`,height:`6`,rx:`1`,key:`cif1o7`}]]),le=n(`message-square`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]),ue=n(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),O=n(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),k=n(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),de=n(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),A=`maxy-shell-side-px`;function fe(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function j(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-fe());return Math.min(Math.max(e,248),n)}function pe(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(A);if(!e)return 264;let t=parseInt(e,10);if(!Number.isFinite(t))return console.warn(`[admin-ui] sidebar-width-parse-failed stored=${JSON.stringify(e)} fallback=264`),264;if(t>=248)return j(t)}catch{}return 264}function me({targetSelector:e=`.platform`}){let t=(0,b.useRef)(null),[n,r]=(0,b.useState)(()=>pe()),i=(0,b.useRef)(n);(0,b.useLayoutEffect)(()=>{let t=document.querySelector(e);!t||!(t instanceof HTMLElement)||(t.style.setProperty(`--side-px`,`${n}px`),i.current=n)},[n,e]);let a=(0,b.useCallback)(()=>{r(e=>{let t=j(e);return t===e?e:t})},[]);(0,b.useEffect)(()=>{a(),window.addEventListener(`resize`,a);let t=document.querySelector(e),n=null;return t instanceof HTMLElement&&(n=new MutationObserver(a),n.observe(t,{attributes:!0,attributeFilter:[`data-artefact`,`class`]})),()=>{window.removeEventListener(`resize`,a),n?.disconnect()}},[a,e]);let o=e=>{e.preventDefault();let n=t.current;if(!n)return;n.setPointerCapture(e.pointerId),n.classList.add(`dragging`);let a=!1,o=e=>{a=!0,r(j(Math.round(e.clientX)))},s=()=>{if(n.releasePointerCapture(e.pointerId),n.classList.remove(`dragging`),window.removeEventListener(`pointermove`,o),window.removeEventListener(`pointerup`,s),!a)return;let t=i.current;try{window.localStorage.setItem(A,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=j(264);r(e);try{window.localStorage.removeItem(A)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,x.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var M=r();function he({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,b.useRef)(null),[s,c]=(0,b.useState)({position:`fixed`,visibility:`hidden`}),l=(0,b.useCallback)(()=>{let t=e.current,n=o.current;if(!t||!n)return;let r=t.getBoundingClientRect(),i=n.getBoundingClientRect(),a=r.right-i.width;a<4&&(a=4);let s=window.innerHeight-r.bottom<i.height+8&&r.top>i.height+8?r.top-i.height:r.bottom;c({position:`fixed`,left:a,top:s,visibility:`visible`})},[e]);return(0,b.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,b.useEffect)(()=>{let n=e=>{e.key===`Escape`&&t()},r=n=>{let r=n.target;e.current?.contains(r)||o.current?.contains(r)||t()},i=n=>{let r=e.current;r&&n.target instanceof Node&&n.target.contains(r)&&t()},a=()=>t();return document.addEventListener(`keydown`,n),document.addEventListener(`pointerdown`,r),window.addEventListener(`scroll`,i,!0),window.addEventListener(`resize`,a),()=>{document.removeEventListener(`keydown`,n),document.removeEventListener(`pointerdown`,r),window.removeEventListener(`scroll`,i,!0),window.removeEventListener(`resize`,a)}},[e,t]),(0,M.createPortal)((0,x.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function ge({action:e,disabled:t,open:n,onToggle:r,onClose:i}){let a=(0,b.useRef)(null);return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(`button`,{ref:a,type:`button`,className:`conv-action`,onClick:r,disabled:t,"aria-haspopup":`dialog`,"aria-expanded":n,"aria-label":e.label,title:e.title,children:e.icon}),n&&(0,x.jsx)(he,{anchorRef:a,onClose:i,className:e.panelClassName,role:`dialog`,ariaLabel:e.label,children:e.panel()})]})}function _e({actions:e,disabled:n,collapsed:r}){let[i,a]=(0,b.useState)(null),[o,s]=(0,b.useState)(!1),[c,l]=(0,b.useState)(null),u=(0,b.useRef)(null);(0,b.useEffect)(()=>{a(null),s(!1),l(null)},[r]);let d=(0,b.useCallback)(()=>{s(!1),l(null)},[]);return r?(0,x.jsxs)(`div`,{className:`conv-actions`,children:[(0,x.jsx)(`button`,{ref:u,type:`button`,className:`conv-action conv-actions-overflow`,onClick:()=>s(e=>!e),disabled:n,"aria-haspopup":`menu`,"aria-expanded":o,"aria-label":`Session actions`,title:`Session actions`,children:(0,x.jsx)(t,{size:12})}),o&&(0,x.jsx)(he,{anchorRef:u,onClose:d,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,x.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,x.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`dialog`,"aria-expanded":c===e.key,disabled:n,onClick:()=>l(t=>t===e.key?null:e.key),children:[e.icon,(0,x.jsx)(`span`,{children:e.menuLabel})]}),c===e.key&&(0,x.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,x.jsxs)(`button`,{type:`button`,role:`menuitem`,className:e.danger?`conv-action-danger`:void 0,"aria-busy":e.busy,disabled:n,onClick:t=>{e.onClick?.(t),d()},children:[e.icon,(0,x.jsx)(`span`,{children:e.menuLabel})]},e.key))})]}):(0,x.jsx)(`div`,{className:`conv-actions`,children:e.map(e=>e.panel?(0,x.jsx)(ge,{action:e,disabled:n,open:i===e.key,onToggle:()=>a(t=>t===e.key?null:e.key),onClose:()=>a(null)},e.key):(0,x.jsx)(`button`,{type:`button`,className:e.danger?`conv-action conv-action-danger`:`conv-action`,onClick:e.onClick,disabled:n,"aria-busy":e.busy,"aria-label":e.label,title:e.title,children:e.icon},e.key))})}var N=`claude-opus-4-8[1m]`,P=`claude-sonnet-5`,F=`claude-haiku-4-5`,I={[N]:`Opus 4.8 (1M context)`,[P]:`Sonnet 5`,[F]:`Haiku 4.5`};function L(e){return I[e]??e}var ve=[N,P,F];function R(e){return e.replace(/\[1m\]$/,``)}function ye(e){return ve.find(t=>R(t)===R(e))??e}var z=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`],be=[`low`,`medium`,`high`,`xhigh`];[...z],[...be],[...be];var xe=[N,P,F],Se={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},Ce=z.map(e=>({value:e,label:Se[e]??e})),we={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},B=be.map(e=>({value:e,label:we[e]??e}));function V(e){if(e){let t=xe.find(t=>R(t)===R(e));if(t)return t}return N}function Te({row:e,adminFetch:t,onError:n}){let[r,i]=(0,b.useState)(()=>V(e.model)),[a,o]=(0,b.useState)(``),[s,c]=(0,b.useState)(``),[l,u]=(0,b.useState)(!1),d=(0,b.useRef)(!1);(0,b.useEffect)(()=>{i(V(e.model))},[e.model]);let f=async()=>{if(!d.current){d.current=!0,u(!0);try{let i=await t(`/api/admin/session-reseat`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({fromSessionId:e.sessionId,model:r,...a?{permissionMode:a}:{},...s?{effort:s}:{}})});if(!i.ok){n(`Could not reset ${e.title} (status ${i.status})`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} status=${i.status}`),d.current=!1,u(!1);return}let o=await i.json().catch(()=>({}));o.target?window.location.assign(o.target):(n(`Reset of ${e.title} returned no target`),d.current=!1,u(!1))}catch(t){n(`Could not reset ${e.title} (network error)`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} error=${t instanceof Error?t.message:String(t)}`),d.current=!1,u(!1)}}};return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsxs)(`label`,{className:`reseat-field`,children:[(0,x.jsx)(`span`,{children:`Model`}),(0,x.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:xe.map(e=>(0,x.jsx)(`option`,{value:e,children:L(e)},e))})]}),(0,x.jsxs)(`label`,{className:`reseat-field`,children:[(0,x.jsx)(`span`,{children:`Mode`}),(0,x.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,x.jsx)(`option`,{value:``,children:`Keep current`}),Ce.map(e=>(0,x.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,x.jsxs)(`label`,{className:`reseat-field`,children:[(0,x.jsx)(`span`,{children:`Effort`}),(0,x.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,x.jsx)(`option`,{value:``,children:`Keep current`}),B.map(e=>(0,x.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,x.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void f(),children:l?(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(ie,{size:12,className:`spin`,"aria-hidden":`true`}),`Resetting…`]}):`Reset`})]})}function Ee(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return n>0?`${t}m ${n}s`:`${t}m`}function H(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function U(e){if(navigator.clipboard)try{return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}function De({target:e,onConfirm:t,onCancel:n}){return e?(0,x.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,x.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,x.jsxs)(`div`,{className:`claude-info-header`,children:[(0,x.jsx)(`span`,{children:`Delete this conversation?`}),(0,x.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,x.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[`This permanently removes the transcript. It is not moved to Archive and cannot be recovered.`,e.live&&(0,x.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,x.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,x.jsx)(w,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,x.jsx)(w,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var Oe=`auth-refresh-failed`;function ke({error:e,onClose:t}){if(!e)return null;let n=e.reason===Oe,r=n?`Claude sign-in expired`:`Session didn’t open`,i=n?`Your claude.ai login has expired. Re-authenticate to resume sessions.`:`The session did not bind within 60 seconds, so there is no live conversation to open.`;return(0,x.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,x.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,x.jsxs)(`div`,{className:`claude-info-header`,children:[(0,x.jsx)(`span`,{children:r}),(0,x.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,x.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,x.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,x.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function W(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,b.useState)(null);if(!t)return null;let u=i.flatMap(e=>e.events?.filter(e=>e.type===`usage`)??[]),d=u.at(-1),f=d?.peak_request_pct==null?d?.context_window?Math.round((d.input_tokens+d.cache_creation_tokens+d.cache_read_tokens)/d.context_window*100):0:Math.round(d.peak_request_pct*100),p=u.reduce((e,t)=>e+t.input_tokens+t.cache_creation_tokens+t.cache_read_tokens+t.output_tokens,0),m=i.flatMap(e=>e.events?.filter(e=>e.type===`rate_limit`)??[]).at(-1),h=u.reduce((e,t)=>e+(t.total_cost_usd??0),0),g=r?.account?.subscriptionType,ee=e=>{let t=e*1e3-Date.now();if(t<=0)return`now`;let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4);return n>0?`${n}h ${r}m`:`${r}m`};return(0,x.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,x.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,x.jsxs)(`div`,{className:`claude-info-header`,children:[(0,x.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,x.jsx)(`span`,{children:`Claude Code`}),(0,x.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,x.jsxs)(`div`,{className:`claude-info-section`,children:[(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,x.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,x.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,x.jsxs)(x.Fragment,{children:[(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,x.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,x.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,x.jsxs)(`div`,{className:`claude-info-section`,children:[(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:p>0?H(p):`—`})]}),(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,x.jsx)(`span`,{className:`claude-info-value`,children:Ee(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,x.jsxs)(`div`,{className:`claude-info-row`,children:[(0,x.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,x.jsx)(`button`,{type:`button`,className:`claude-info-value claude-info-id-copy`,title:`${e} (${o?`flushed`:`pre-flush`}) — click to copy`,onClick:async()=>{l(await U(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}var Ae=`https://claude.ai/code`,je=200,Me=[500,1e3,1500,2e3,2500,3e3,3e3];function Ne(e,t,n){if(e&&n.target)return{kind:`navigate`,url:n.target,sameOrigin:!0};let r=n.slug??n.bridgeSessionId??null;if(e&&r)return{kind:`navigate`,url:`${Ae}/${r}`,sameOrigin:!1};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function Pe(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function Fe(e){let{businessName:t,cacheKey:n,role:r,userName:i,userAvatar:a,onSelectProjects:d,onSelectPeople:te,onSelectTasks:ie,onSelectAgents:ae,onCloseMobileDrawer:S,collapsed:C,selectedWhatsappId:w,onSelectWhatsappConversation:A,initialWhatsappSurface:fe=!1,onSelectData:j,onCloseData:pe,initialDataSurface:me=!1}=e,M=g(n),he=(0,b.useCallback)(e=>({key:`reseat`,label:`Reset session ${e.title} (model, mode, effort)`,menuLabel:`Reset`,title:`Reset — move this session onto a chosen model, mode, and effort`,icon:(0,x.jsx)(O,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,x.jsx)(Te,{row:e,adminFetch:M,onError:e=>V({message:e,failed:!0})})}),[M]),ge=o.productName,N=typeof i==`string`?i:i===null?`name unavailable`:t||ge,P=(N.trim().charAt(0)||`?`).toUpperCase(),[F,I]=(0,b.useState)(me?`data`:fe?`whatsapp`:`sessions`),[L,ve]=(0,b.useState)([]),[R,ye]=(0,b.useState)(!1),[z,be]=(0,b.useState)(null),[xe,Se]=(0,b.useState)(!1),[Ce,we]=(0,b.useState)(`file`),[B,V]=(0,b.useState)(null),[Ee,H]=(0,b.useState)(null),[U,Oe]=(0,b.useState)([]),[W,Ae]=(0,b.useState)(!1),[Fe,Ie]=(0,b.useState)(null),[G,K]=(0,b.useState)(!1),[q,Be]=(0,b.useState)(!1),[J,Ve]=(0,b.useState)(!1),[Y,He]=(0,b.useState)(null),[Ue,We]=(0,b.useState)(new Set),[Ge,Ke]=(0,b.useState)(null),[qe,Je]=(0,b.useState)(new Set),[Ye,Xe]=(0,b.useState)(new Set),[Ze,Qe]=(0,b.useState)(new Set),[X,$e]=(0,b.useState)(null),[et,Z]=(0,b.useState)(``),[tt,nt]=(0,b.useState)(!1),[rt,it]=(0,b.useState)(!1),at=(0,b.useRef)(null),ot=(0,b.useRef)(0),[st,ct]=(0,b.useState)(0);(0,b.useEffect)(()=>{let e=at.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(e=>{let t=e[0]?.contentRect.width??0;ct(e=>Math.abs(e-t)<1?e:t)});return t.observe(e),()=>t.disconnect()},[F]);let lt=st>0&&st<400,[ut,dt]=(0,b.useState)([]),[ft,pt]=(0,b.useState)(!1),[mt,ht]=(0,b.useState)(null),[gt,_t]=(0,b.useState)(`whatsapp`),vt=(0,b.useCallback)(e=>{if(S(),!n){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),V({message:`Session not ready — try again`,failed:!0});return}if(!e.downloadPath){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=not-downloadable`),V({message:`${e.name} can’t be downloaded`,failed:!0});return}console.info(`[admin-ui] artefact-download id=${e.id} root=${e.downloadRoot??`data`} path=${e.downloadPath}`),ee(n,e.downloadPath,e.downloadRoot??`data`),V({message:`Downloading ${e.name}`,failed:!1})},[n,S]);(0,b.useEffect)(()=>{if(!B)return;let e=setTimeout(()=>V(null),2500);return()=>clearTimeout(e)},[B]);let yt=(0,b.useCallback)(async()=>{if(n){Se(!0),be(null);try{let e=await M(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);ve((await e.json()).artefacts??[]),ye(!0)}catch(e){let t=e instanceof Error?e.message:String(e);be(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{Se(!1)}}},[n,M]),Q=(0,b.useCallback)(async()=>{if(!n)return null;let e=++ot.current;K(!0),Ie(null);try{let t=await M(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===ot.current?(Oe(r),He(n.accountId??null),Ae(!0),r):(console.info(`[admin-ui] sidebar-sessions-stale-response-dropped token=${e}`),r)}catch(t){let n=t instanceof Error?t.message:String(t);return e===ot.current&&Ie(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===ot.current&&K(!1)}},[n,M]),bt=(0,b.useCallback)(async()=>{if(n){ht(null);try{let e=await M(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);dt((await e.json()).conversations??[]),pt(!0)}catch(e){let t=e instanceof Error?e.message:String(e);ht(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[n,M]);(0,b.useEffect)(()=>{!n||W||Q()},[n,W,Q]),(0,b.useEffect)(()=>{if(!n)return;let e=null;return bt(),e=setInterval(()=>{bt()},Le),()=>{e!==null&&clearInterval(e)}},[n,bt]),(0,b.useEffect)(()=>{if(!n)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Q()}function r(){e===null&&(e=setInterval(t,Re))}function i(){e!==null&&(clearInterval(e),e=null)}function a(){document.hidden?i():(t(),r())}return document.hidden||r(),document.addEventListener(`visibilitychange`,a),()=>{i(),document.removeEventListener(`visibilitychange`,a)}},[n,Q]);let xt=(0,b.useMemo)(()=>{let e=new Map;for(let t of _)e.set(t,[]);for(let t of ut)e.get(t.channel)?.push(t);for(let t of _)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[ut]),St={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},Ct=()=>{A(null),I(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${R?L.length:0} collapsed=${C}`),yt()},$=1.5,wt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),yt()},Tt=()=>{A(null),I(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${W?U.length:0} collapsed=${C}`),W||Q()},Et=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},Dt=()=>{I(`data`),console.info(`[admin-ui] sidebar-nav surface=data collapsed=${C}`),j(),S()},Ot=e=>{pe?.(),I(`whatsapp`),_t(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${xt.get(e)?.length??0} collapsed=${C}`)},kt=(0,b.useCallback)(async e=>{if(qe.has(e.sessionId))return;Je(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await M(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,name:e.title||e.sessionId,...e.accountId?{targetAccountId:e.accountId}:{}})}),r=await n.json().catch(()=>({})),i=Ne(n.ok,n.status,{...r,sessionId:r.sessionId??e.sessionId});console.info(`[admin-ui] sidebar-session-resume sessionId=${e.sessionId} status=${n.status} outcome=${i.kind} slug=${r.slug??r.bridgeSessionId??`none`}`),i.kind===`navigate`?(S(),t?t.location.href=i.url:window.open(i.url,`_blank`)):(t?.close(),console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} status=${n.status} reason=${i.reason}`),H(i))}catch(n){t?.close();let r=n instanceof Error?n.message:String(n);console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} error=${r}`),H({sessionId:e.sessionId,reason:r})}finally{Je(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[M,S,qe]),At=(0,b.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Me.length;n++){await new Promise(e=>setTimeout(e,Me[n-1]));let r=await Q();if(r&&r.some(t=>t.sessionId===e)){console.info(`[admin-ui] sidebar-new-session-converged sessionId=${t} via=retry attempts=${n}`);return}}console.error(`[admin-ui] sidebar-new-session-converge-timeout sessionId=${t}`)},[Q]),jt=(0,b.useCallback)(async()=>{if(!rt){it(!0);try{let e=await M(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),t=await e.json().catch(()=>({})),n=Ne(e.ok,e.status,t);console.info(`[admin-ui] sidebar-new-session-spawned status=${e.status} outcome=${n.kind} slug=${t.slug??t.bridgeSessionId??`none`}`),n.kind===`navigate`?n.sameOrigin?window.location.assign(n.url):(window.open(n.url,`_blank`),t.sessionId?At(t.sessionId):console.error(`[admin-ui] sidebar-new-session-converge-skipped reason=no-session-id`)):(console.error(`[admin-ui] sidebar-new-session-failed status=${e.status} reason=${n.reason}`),H(n))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-new-session-failed error=${t}`),H({sessionId:null,reason:t})}finally{it(!1)}}},[M,rt,At]),Mt=(0,b.useCallback)((e,t)=>{e.stopPropagation(),Ke(t)},[]),Nt=(0,b.useCallback)(async e=>{if(!Ue.has(e.sessionId)){We(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await M(`/api/admin/session-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId})});if(!t.ok){let n=await t.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} status=${t.status} error=${n.error??`unknown`}`),V({message:`Delete failed: ${n.error??`status ${t.status}`}`,failed:!0});return}let n=await t.json();console.info(`[admin-ui] sidebar-session-delete sessionId=${e.sessionId} live=${e.live} confirmed=true pidKilled=${n.pidKilled??`?`} deleted=${n.deleted??`?`}`),Oe(t=>t.filter(t=>t.sessionId!==e.sessionId)),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} error=${n}`),V({message:`Delete failed: ${n}`,failed:!0})}finally{We(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}}},[M,Ue,Q]),Pt=(0,b.useCallback)(async(e,t)=>{if(e.stopPropagation(),!Ye.has(t.sessionId)){Xe(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await M(`/api/admin/session-stop`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId})});if(!e.ok){let n=await e.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} status=${e.status} error=${n.error??`unknown`}`),V({message:`Stop failed: ${n.error??`status ${e.status}`}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-stop sessionId=${t.sessionId}`),Q()}catch(e){let n=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} error=${n}`),V({message:`Stop failed: ${n}`,failed:!0})}finally{Xe(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[M,Ye,Q]),Ft=(0,b.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!Ze.has(t.sessionId)){Qe(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await M(`/api/admin/session-archive`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId,mode:n})});if(!e.ok){let r=await e.json().catch(()=>({})),i=r.detail??r.error??`status ${e.status}`;console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} status=${e.status} error=${r.error??`unknown`}`),V({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${i}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-archive sessionId=${t.sessionId} mode=${n}`),Q()}catch(e){let r=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} error=${r}`),V({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{Qe(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[M,Ze,Q]),It=(0,b.useCallback)(async e=>{let t=et.trim();if(!t){V({message:`Title can’t be empty`,failed:!0});return}if(t.length>je){V({message:`Title too long (max ${je})`,failed:!0});return}nt(!0);try{let n=await M(`/api/admin/session-rename`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,title:t})});if(!n.ok){let t=await n.json().catch(()=>({})),r=t.reason??t.error??`status ${n.status}`;console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${r}`),V({message:`Rename failed: ${r}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=ok`),$e(null),Z(``),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${n}`),V({message:`Rename failed: ${n}`,failed:!0})}finally{nt(!1)}},[M,et,Q]);return(0,x.jsxs)(`aside`,{className:`side`,children:[(0,x.jsx)(`div`,{className:`side-new-session-row`,children:(0,x.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:jt,disabled:rt,"aria-busy":rt,children:[(0,x.jsx)(ue,{size:14}),(0,x.jsx)(`span`,{children:rt?`Spawning…`:`New session`})]})}),(0,x.jsxs)(`nav`,{className:`side-nav`,children:[(0,x.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),te(),S()},children:[(0,x.jsx)(de,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:`People`}),(0,x.jsx)(`span`,{className:`kbd`})]}),(0,x.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),ae(),S()},children:[(0,x.jsx)(E,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:`Agents`}),(0,x.jsx)(`span`,{className:`kbd`})]}),(0,x.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),d(),S()},children:[(0,x.jsx)(se,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:p().term}),(0,x.jsx)(`span`,{className:`kbd`})]}),(0,x.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),ie(),S()},children:[(0,x.jsx)(D,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,x.jsx)(`span`,{className:`kbd`})]}),(0,x.jsxs)(`button`,{type:`button`,className:`nav-row${F===`artefacts`?` active`:``}`,onClick:Ct,children:[(0,x.jsx)(y,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,x.jsx)(`span`,{className:`kbd`})]}),(0,x.jsxs)(`button`,{type:`button`,className:`nav-row${F===`sessions`?` active`:``}`,onClick:Tt,children:[(0,x.jsx)(ce,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,x.jsx)(`span`,{className:`kbd`})]}),(0,x.jsxs)(`button`,{type:`button`,className:`nav-row${F===`data`?` active`:``}`,onClick:Dt,children:[(0,x.jsx)(c,{size:20,strokeWidth:$}),(0,x.jsx)(`span`,{className:`label`,children:`Data`}),(0,x.jsx)(`span`,{className:`kbd`})]}),ft&&_.filter(e=>xt.get(e).length>0).map(e=>(0,x.jsxs)(`button`,{type:`button`,className:`nav-row${F===`whatsapp`&>===e?` active`:``}`,onClick:()=>Ot(e),children:[(0,x.jsx)(m,{channel:e,size:16}),(0,x.jsx)(`span`,{className:`label`,children:St[e]}),(0,x.jsx)(`span`,{className:`kbd`})]},e)),mt&&(0,x.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,x.jsx)(`span`,{className:`label`,children:mt})})]}),F===`artefacts`&&(0,x.jsxs)(`div`,{className:`side-list`,children:[(0,x.jsxs)(`div`,{className:`group-head`,children:[(0,x.jsx)(`span`,{children:`Artefacts`}),(0,x.jsxs)(`span`,{className:`group-head-meta`,children:[(0,x.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:wt,disabled:xe,children:(0,x.jsx)(l,{size:12,className:xe?`spinning`:void 0})}),(0,x.jsx)(`span`,{children:xe?`…`:String(L.length)})]})]}),z&&(0,x.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:z}),R&&!z&&L.length>0&&(()=>{let e=L.filter(e=>e.kind===`agent-template`).length,t=L.length-e;return(0,x.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:L.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,x.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${Ce===e.key?` active`:``}`,onClick:()=>we(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,x.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),R&&!z&&L.length===0&&(0,x.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),L.filter(e=>Ce===`all`?!0:Ce===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let t=e.kind===`agent-template`,n=t?E:y,r=Pe(e.updatedAt),i=e.downloadPath!==null;return(0,x.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>vt(e),disabled:!i,style:i?void 0:{cursor:`default`},title:i?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,x.jsx)(n,{size:14,className:`conv-icon`,"data-kind":t?`agent`:`file`,"aria-label":t?`agent template`:`file`}),(0,x.jsxs)(`span`,{className:`conv-stack`,children:[(0,x.jsx)(`span`,{className:`conv-name-line`,children:(0,x.jsx)(`span`,{className:`conv-name`,children:e.name})}),r&&(0,x.jsx)(`span`,{className:`conv-timestamp`,children:r})]}),i&&(0,x.jsx)(re,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),F===`sessions`&&(()=>{let e=U.filter(e=>q?!0:!e.isSubagent).filter(e=>J?!0:!e.archived),t=U.some(e=>e.isSubagent),n=U.some(e=>e.archived);return(0,x.jsxs)(`div`,{className:`side-list`,ref:at,children:[(0,x.jsxs)(`div`,{className:`group-head`,children:[(0,x.jsx)(`span`,{children:`Sessions`}),(0,x.jsxs)(`span`,{className:`group-head-meta`,children:[(0,x.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:Et,disabled:G,children:(0,x.jsx)(l,{size:12,className:G?`spinning`:void 0})}),(0,x.jsx)(`span`,{children:G?`…`:String(e.length)})]})]}),Y&&(0,x.jsx)(`div`,{className:`side-account-id`,title:`This install's accountId. The first 8 characters match the truncated UUID label on the live Remote Control daemon entry in claude.ai/code.`,children:(0,x.jsx)(`code`,{children:Y})}),(t||n)&&(0,x.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,x.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${q?` active`:``}`,"aria-pressed":q,onClick:()=>Be(e=>!e),title:q?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),n&&(0,x.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${J?` active`:``}`,"aria-pressed":J,onClick:()=>Ve(e=>!e),title:J?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),Fe&&(0,x.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:Fe}),W&&!Fe&&e.length===0&&(0,x.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=Pe(e.startedAt),n=qe.has(e.sessionId),r=Ue.has(e.sessionId),i=Ye.has(e.sessionId),a=Ze.has(e.sessionId),o=n||r||i||a,c=()=>{window.location.assign(`/chat?session=${e.sessionId}`)},l=[{key:`open`,label:`Resume session ${e.title} in claude.ai/code`,menuLabel:`Resume in claude.ai/code`,title:`Resume in a fresh local Remote Control PTY`,icon:(0,x.jsx)(s,{size:12}),busy:n,onClick:()=>{kt(e)}},{key:`message`,label:`Open session ${e.title} in admin webchat`,menuLabel:`Open in webchat`,title:`Open in admin webchat (/chat) — sending resumes this session`,icon:(0,x.jsx)(le,{size:12}),onClick:()=>{c()}},...e.live?[{key:`stop`,label:`Stop session ${e.title}`,menuLabel:`Stop`,title:`Stop session process (keeps the conversation, can resume later)`,icon:(0,x.jsx)(k,{size:12}),busy:i,onClick:t=>{Pt(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,x.jsx)(oe,{size:12}),busy:a,onClick:t=>{Ft(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,x.jsx)(T,{size:12}),busy:a,onClick:t=>{Ft(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,x.jsx)(v,{size:12}),busy:tt&&X===e.sessionId,onClick:t=>{t.stopPropagation(),$e(e.sessionId),Z(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,x.jsx)(f,{size:12}),danger:!0,busy:r,onClick:t=>{Mt(t,e)}},he({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,x.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,x.jsxs)(`div`,{className:`conv-main-static conv-main-clickable`,role:`button`,tabIndex:0,"aria-label":`Open ${e.personName??e.title} in webchat`,onClick:()=>{X!==e.sessionId&&c()},onKeyDown:t=>{X!==e.sessionId&&(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),c())},children:[(0,x.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,x.jsxs)(`span`,{className:`conv-stack`,children:[(0,x.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,x.jsx)(ne,{channel:e.channel,size:13}),X===e.sessionId?(0,x.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,value:et,disabled:tt,"aria-label":`New title for session ${e.title}`,onChange:e=>Z(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),It(e)):t.key===`Escape`&&(t.preventDefault(),$e(null),Z(``))},onBlur:()=>{X===e.sessionId&&!tt&&($e(null),Z(``))}}):(0,x.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,x.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,x.jsx)(`code`,{className:`conv-session-id`,title:`First 8 characters of this session's id — distinguishes rows with identical auto-titles. The resume/delete buttons act on the full id.`,children:e.sessionId.slice(0,8)}),t&&(0,x.jsxs)(`span`,{children:[` · `,t]})]})]})]}),(0,x.jsx)(_e,{actions:l,disabled:o,collapsed:lt})]},e.sessionId)})]})})(),F===`whatsapp`&&(0,x.jsxs)(`div`,{className:`side-list`,children:[(0,x.jsxs)(`div`,{className:`group-head`,children:[(0,x.jsx)(`span`,{children:St[gt]}),(0,x.jsxs)(`span`,{className:`group-head-meta`,children:[(0,x.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{bt()},children:(0,x.jsx)(l,{size:12})}),(0,x.jsx)(`span`,{children:String(xt.get(gt).length)})]})]}),xt.get(gt).map(e=>{let t=Pe(e.lastMessageAt),n=u(e);return(0,x.jsxs)(`div`,{className:`conv conv-with-actions${e.source===`store`?e.scope===`admin`?` conv-scope-admin`:` conv-scope-public`:``}${w===n?` active`:``}`,children:[(0,x.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{A(e),S()},title:e.title,children:[(0,x.jsx)(m,{channel:e.channel,size:14}),(0,x.jsxs)(`span`,{className:`conv-stack`,children:[(0,x.jsx)(`span`,{className:`conv-name-line`,children:(0,x.jsx)(`span`,{className:`conv-name`,children:h(e)})}),t&&(0,x.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),e.source===`session`&&(0,x.jsx)(_e,{actions:[he({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1,collapsed:lt})]},n)})]}),(0,x.jsx)(ze,{}),(0,x.jsxs)(`div`,{className:`side-foot`,children:[(0,x.jsx)(`div`,{className:`avatar`,children:a?(0,x.jsx)(`img`,{src:a,alt:N}):P}),(0,x.jsxs)(`div`,{className:`who`,children:[(0,x.jsx)(`span`,{className:`name`,children:N}),(0,x.jsx)(`span`,{className:`role`,children:r??`operator`})]})]}),B&&(0,x.jsx)(`div`,{className:`copy-toast${B.failed?` copy-toast-failed`:``}`,role:`status`,children:B.message}),(0,x.jsx)(ke,{error:Ee,onClose:()=>H(null)}),(0,x.jsx)(De,{target:Ge,onCancel:()=>Ke(null),onConfirm:()=>{let e=Ge;Ke(null),e&&Nt(e)}})]})}var Ie=5e3,Le=3e4,Re=3e4;function ze(){let[e,t]=(0,b.useState)(null);if((0,b.useEffect)(()=>{let e=!1,n=null;async function r(){try{let n=await fetch(`/api/admin/system-stats`);if(!n.ok){console.error(`[admin-ui] system-stats-fetch-failed status=${n.status}`);return}let r=await n.json();e||t(r)}catch(e){console.error(`[admin-ui] system-stats-fetch-failed reason=${e instanceof Error?e.message:String(e)}`)}}function i(){n===null&&(r(),n=setInterval(()=>{r()},Ie))}function a(){n!==null&&(clearInterval(n),n=null)}function o(){document.hidden?a():i()}return document.hidden||i(),document.addEventListener(`visibilitychange`,o),()=>{e=!0,a(),document.removeEventListener(`visibilitychange`,o)}},[]),!e||e.platform===`darwin`)return null;let n=e.cpuPct,r=e.memUsedPct,i=n!==null&&n>=.9,a=n!==null&&n>=.98,o=r!==null&&r>=.9,s=r!==null&&r>=.98,c=i||o,l=a||s,u=e=>e===null?`—`:`${Math.round(e*100)}%`,d=e=>{if(e===null)return{width:`0%`,background:`var(--text-tertiary)`};let t=Math.min(1,Math.max(0,e)),n=Math.round(140*(1-t));return{width:`${Math.round(t*100)}%`,background:`hsl(${n}, 65%, 45%)`}},f=[`system-stats`];return c&&f.push(`system-stats--warn`),l&&f.push(`system-stats--crit`),(0,x.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,x.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,x.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,x.jsx)(`div`,{className:`system-stats__bar`,children:(0,x.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,x.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,x.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,x.jsx)(`div`,{className:`system-stats__bar`,children:(0,x.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var G=`admin-sidebar-collapsed`,K=`admin-sidebar-drawer-open`;function q(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(G)===`1`}catch{return!1}}function Be(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(G,`1`):window.sessionStorage.removeItem(G)}catch{}}function J(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(K)===`1`}catch{return!1}}function Ve(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(K,`1`):window.sessionStorage.removeItem(K)}catch{}}var Y=720;function He(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.remoteJid??``)}&acct=${encodeURIComponent(t.accountId??``)}`}}function Ue(e){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?data=1`}}function We(e,t){if(e!==`/`)return null;let n=new URLSearchParams(t),r=n.get(`wa`),i=n.get(`acct`);return!r||!i?null:{sessionId:``,projectDir:``,title:``,senderId:null,startedAt:``,channel:`whatsapp`,role:`public`,operatorName:null,whatsappName:null,lastMessageAt:null,modelGated:!1,model:null,source:`store`,accountId:i,remoteJid:r}}function Ge(e,t){return e===`/`?new URLSearchParams(t).has(`data`):!1}function Ke(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`calendar`?`/calendar`:e===`chat`?`/chat`:`/browser`}function qe(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,userName:s,userAvatar:c,role:l,onOpenConversations:f,children:m,footer:h}=e,{subAccounts:g,activeAccountId:ee,switching:_,switchAccount:ne}=te(t),[v,re]=(0,b.useState)(()=>q()),[y,ie]=(0,b.useState)(()=>J()),[ae,S]=(0,b.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${Y}px)`).matches),[C,w]=(0,b.useState)(()=>typeof window>`u`||Ge(window.location.pathname,window.location.search)?null:We(window.location.pathname,window.location.search)),[oe]=(0,b.useState)(()=>C!==null),[T,E]=(0,b.useState)(()=>typeof window>`u`?!1:Ge(window.location.pathname,window.location.search)),[se]=(0,b.useState)(()=>T);(0,b.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${Y}px)`),t=e=>S(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let ce=(0,b.useCallback)(e=>{Be(e),re(e)},[]),D=(0,b.useCallback)(e=>{Ve(e),ie(e)},[]);(0,b.useEffect)(()=>{if(typeof window>`u`)return;let e=window.location?.pathname??``;console.info(`[admin-ui] shell-mount route=${e} variant=${r} sidebar=${r===`operator`?`none`:`present`} collapsed=${v} drawer=${y}`)},[]),(0,b.useEffect)(()=>{typeof window>`u`||!C||(console.info(`[admin-ui] wa-hydrate route=/ remoteJid=${C.remoteJid??``}`),window.history.replaceState(null,``,`/`))},[]),(0,b.useEffect)(()=>{typeof window>`u`||!T||(console.info(`[admin-ui] data-hydrate route=/`),window.history.replaceState(null,``,`/`))},[]);let le=(0,b.useCallback)(e=>{if(E(!1),e===null){w(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=He(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?w(e):window.location.href=n.href},[]),ue=(0,b.useCallback)(()=>{let e=typeof window<`u`?window.location.pathname:`/`,t=Ue(e);if(console.info(`[admin-ui] data-open route=${e} via=${t.via}`),t.via===`navigate`){window.location.href=t.href;return}w(null),E(!0)},[]),O=ae?y:!v,k=(0,b.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${Y}px)`).matches){let e=y;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),D(!e)}else{let e=v;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),ce(!e)}},[v,y,ce,D]),de=(0,b.useCallback)(e=>{let t=Ke(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),A={collapsed:v,mobileDrawerOpen:y,sidebarOpen:O,onToggleSidebar:k,setMobileDrawerOpen:D,selectedWhatsapp:C,onClearWhatsapp:()=>w(null),dataOpen:T};return r===`operator`?(0,x.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,x.jsx)(d,{businessName:n,variant:r,onNavigate:de,onOpenConversations:f,onToggleSidebar:k,sidebarOpen:O,onLogout:i,onDisconnect:a,disconnecting:o,cacheKey:t,subAccounts:g,activeAccountId:ee,switchingAccount:_,onSwitchAccount:ne}),(0,x.jsx)(`div`,{className:`platform platform-operator`,children:typeof m==`function`?m(A):m}),h]}):(0,x.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,x.jsx)(d,{businessName:n,variant:r,onNavigate:de,onOpenConversations:f,onToggleSidebar:k,sidebarOpen:O,onLogout:i,onDisconnect:a,disconnecting:o,cacheKey:t,subAccounts:g,activeAccountId:ee,switchingAccount:_,onSwitchAccount:ne}),(0,x.jsxs)(`div`,{className:`platform${y?` menu-open`:``}${v?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,x.jsx)(Fe,{businessName:n,cacheKey:t,role:l??null,userName:s,userAvatar:c??null,onSelectProjects:()=>{window.location.href=`/graph?label=${p().label}`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/graph?label=Task`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>D(!1),collapsed:v,mobileDrawerOpen:y,selectedWhatsappId:C?u(C):null,onSelectWhatsappConversation:le,initialWhatsappSurface:oe,onSelectData:ue,onCloseData:()=>E(!1),initialDataSurface:se}),!ae&&(0,x.jsx)(me,{}),typeof m==`function`?m(A):m]}),y&&(0,x.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>D(!1)}),h]})}export{oe as _,F as a,ye as c,k as d,O as f,T as g,E as h,U as i,L as l,D as m,Ne as n,N as o,ue as p,W as r,P as s,qe as t,de as u,w as v,ae as y};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{o as e}from"./chunk-CAM3fms7.js";import{D as t,F as n,L as r,M as i,P as a,S as o,f as s,h as c,m as l,v as u,w as d,y as f}from"./useSubAccountSwitcher-DMbRhLPv.js";import{t as p,u as m,y as h}from"./AdminShell-D2-uBSB5.js";import{t as g}from"./chevron-left-DhVdq0aN.js";var _=t(`calendar`,[[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`4`,rx:`2`,key:`1hopcy`}],[`path`,{d:`M3 10h18`,key:`8toen8`}]]),v=t(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),y=t(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 6v6l4 2`,key:`mmk7yg`}]]),b=t(`map-pin`,[[`path`,{d:`M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0`,key:`1r0f0z`}],[`circle`,{cx:`12`,cy:`10`,r:`3`,key:`ilqhr7`}]]),x=t(`sticky-note`,[[`path`,{d:`M21 9a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 15 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2z`,key:`1dfntj`}],[`path`,{d:`M15 3v5a1 1 0 0 0 1 1h5`,key:`6s6qgf`}]]),S=t(`user-plus`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}],[`line`,{x1:`19`,x2:`19`,y1:`8`,y2:`14`,key:`1bvyxn`}],[`line`,{x1:`22`,x2:`16`,y1:`11`,y2:`11`,key:`1shjgl`}]]),C=n(),w=e(r(),1);function T(e){return new Date(e.getFullYear(),e.getMonth(),e.getDate())}function E(e,t){let n=new Date(e);return n.setDate(n.getDate()+t),n}function D(e){let t=T(e),n=t.getDay();return E(t,n===0?-6:1-n)}function O(e){let t=D(e);return Array.from({length:7},(e,n)=>E(t,n))}function k(e){let t=D(new Date(e.getFullYear(),e.getMonth(),1));return Array.from({length:42},(e,n)=>E(t,n))}function A(){return Array.from({length:24},(e,t)=>t)}function ee(e){let t=e.getFullYear();return Array.from({length:12},(e,n)=>new Date(t,n,1))}function j(e,t){switch(e){case`day`:{let e=T(t);return{from:e,to:E(e,1)}}case`week`:{let e=D(t);return{from:e,to:E(e,7)}}case`month`:{let e=D(new Date(t.getFullYear(),t.getMonth(),1));return{from:e,to:E(e,42)}}case`year`:return{from:new Date(t.getFullYear(),0,1),to:new Date(t.getFullYear()+1,0,1)}}}function M(e,t,n){switch(e){case`day`:return E(t,n);case`week`:return E(t,n*7);case`month`:return new Date(t.getFullYear(),t.getMonth()+n,1);case`year`:return new Date(t.getFullYear()+n,t.getMonth(),1)}}function N(e,t){return e.getFullYear()===t.getFullYear()&&e.getMonth()===t.getMonth()&&e.getDate()===t.getDate()}function P(e,t){return{role:`button`,tabIndex:0,onClick:()=>t(e),onKeyDown:n=>{(n.key===`Enter`||n.key===` `)&&(n.preventDefault(),t(e))}}}var F=i(),I=[`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`,`Sun`],L=3;function R(e){return e.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`})}function te({anchor:e,meetings:t,onSelect:n}){let r=k(e),i=e.getMonth(),a=new Date;return(0,F.jsxs)(`div`,{className:`cal-month`,children:[(0,F.jsx)(`div`,{className:`cal-weekday-row`,children:I.map(e=>(0,F.jsx)(`div`,{className:`cal-weekday`,children:e},e))}),(0,F.jsx)(`div`,{className:`cal-month-grid`,children:r.map(e=>{let r=t.filter(t=>N(new Date(t.startsAt),e)).sort((e,t)=>e.startsAt.localeCompare(t.startsAt)),o=e.getMonth()!==i,s=N(e,a);return(0,F.jsxs)(`div`,{className:`cal-cell${o?` cal-cell-out`:``}${s?` cal-cell-today`:``}`,children:[(0,F.jsx)(`div`,{className:`cal-cell-num`,children:e.getDate()}),r.slice(0,L).map(e=>(0,F.jsxs)(`div`,{className:`cal-chip`,title:e.title??`Untitled`,...P(e,n),children:[!e.isAllDay&&(0,F.jsx)(`span`,{className:`cal-chip-time`,children:R(new Date(e.startsAt))}),e.title??`Untitled`]},e.meetingId)),r.length>L&&(0,F.jsxs)(`div`,{className:`cal-more`,children:[`+`,r.length-L,` more`]})]},e.toISOString())})})]})}var z=1440,B=1.8;function V(e){return e.getHours()*60+e.getMinutes()}function H(e){return e.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`})}function U({day:e,meetings:t,hourHeight:n,onSelect:r}){let i=n*24,a=t.filter(t=>!t.isAllDay&&N(new Date(t.startsAt),e));return(0,F.jsx)(`div`,{className:`cal-day-col`,children:(0,F.jsxs)(`div`,{className:`cal-hours`,style:{height:`${i}px`},children:[Array.from({length:24},(e,t)=>(0,F.jsx)(`div`,{className:`cal-hour-line`,style:{top:`${t*n}px`}},t)),a.map(t=>{let n=new Date(t.startsAt),i=t.endsAt?new Date(t.endsAt):new Date(n.getTime()+30*6e4),a=V(n),o=N(i,e)?V(i):z,s=a/z*100,c=Math.max((o-a)/z*100,B);return(0,F.jsxs)(`div`,{className:`cal-event`,style:{top:`${s}%`,height:`${c}%`},title:t.title??`Untitled`,...P(t,r),children:[(0,F.jsx)(`span`,{className:`cal-event-time`,children:H(n)}),(0,F.jsx)(`span`,{className:`cal-event-title`,children:t.title??`Untitled`})]},t.meetingId)})]})})}var W=44;function G(e){let t=new Date;return t.setHours(e,0,0,0),t.toLocaleTimeString([],{hour:`numeric`})}function K({anchor:e,meetings:t,onSelect:n}){let r=O(e),i=new Date;return(0,F.jsxs)(`div`,{className:`cal-timed`,children:[(0,F.jsxs)(`div`,{className:`cal-day-headrow`,children:[(0,F.jsx)(`div`,{className:`cal-timed-gutter`}),r.map(e=>(0,F.jsxs)(`div`,{className:`cal-day-head${N(e,i)?` cal-day-head-today`:``}`,children:[(0,F.jsx)(`span`,{className:`cal-day-head-name`,children:e.toLocaleDateString([],{weekday:`short`})}),(0,F.jsx)(`span`,{className:`cal-day-head-num`,children:e.getDate()})]},e.toISOString()))]}),(0,F.jsxs)(`div`,{className:`cal-allday-band`,children:[(0,F.jsx)(`div`,{className:`cal-timed-gutter`,children:`All-day`}),r.map(e=>(0,F.jsx)(`div`,{className:`cal-allday-cell`,children:t.filter(t=>t.isAllDay&&N(new Date(t.startsAt),e)).map(e=>(0,F.jsx)(`div`,{className:`cal-allday-chip`,title:e.title??`Untitled`,...P(e,n),children:e.title??`Untitled`},e.meetingId))},e.toISOString()))]}),(0,F.jsxs)(`div`,{className:`cal-timed-cols`,children:[(0,F.jsx)(`div`,{className:`cal-timed-gutter`,children:A().map(e=>(0,F.jsx)(`div`,{className:`cal-hour-label`,style:{height:`${W}px`},children:e===0?``:G(e)},e))}),r.map(e=>(0,F.jsx)(U,{day:e,meetings:t,hourHeight:W,onSelect:n},e.toISOString()))]})]})}var q=52;function J(e){let t=new Date;return t.setHours(e,0,0,0),t.toLocaleTimeString([],{hour:`numeric`})}function Y({anchor:e,meetings:t,onSelect:n}){let r=t.filter(t=>t.isAllDay&&N(new Date(t.startsAt),e));return(0,F.jsxs)(`div`,{className:`cal-timed cal-timed-single`,children:[(0,F.jsxs)(`div`,{className:`cal-allday-band`,children:[(0,F.jsx)(`div`,{className:`cal-timed-gutter`,children:`All-day`}),(0,F.jsx)(`div`,{className:`cal-allday-cell`,children:r.map(e=>(0,F.jsx)(`div`,{className:`cal-allday-chip`,title:e.title??`Untitled`,...P(e,n),children:e.title??`Untitled`},e.meetingId))})]}),(0,F.jsxs)(`div`,{className:`cal-timed-cols`,children:[(0,F.jsx)(`div`,{className:`cal-timed-gutter`,children:A().map(e=>(0,F.jsx)(`div`,{className:`cal-hour-label`,style:{height:`${q}px`},children:e===0?``:J(e)},e))}),(0,F.jsx)(U,{day:e,meetings:t,hourHeight:q,onSelect:n})]})]})}var X=[`M`,`T`,`W`,`T`,`F`,`S`,`S`];function Z(e){return`${e.getFullYear()}-${e.getMonth()}-${e.getDate()}`}function ne({anchor:e,meetings:t,onPickMonth:n}){let r=new Date,i=new Set(t.map(e=>Z(new Date(e.startsAt))));return(0,F.jsx)(`div`,{className:`cal-year`,children:(0,F.jsx)(`div`,{className:`cal-year-grid`,children:ee(e).map(e=>{let t=k(e),a=e.getMonth();return(0,F.jsxs)(`button`,{type:`button`,className:`cal-mini`,onClick:()=>n(e),title:e.toLocaleDateString([],{month:`long`,year:`numeric`}),children:[(0,F.jsx)(`div`,{className:`cal-mini-title`,children:e.toLocaleDateString([],{month:`long`})}),(0,F.jsx)(`div`,{className:`cal-mini-weekrow`,children:X.map((e,t)=>(0,F.jsx)(`span`,{className:`cal-mini-weekday`,children:e},t))}),(0,F.jsx)(`div`,{className:`cal-mini-grid`,children:t.map(e=>{let t=e.getMonth()!==a,n=N(e,r),o=!t&&i.has(Z(e));return(0,F.jsxs)(`span`,{className:`cal-mini-day${t?` cal-mini-day-out`:``}${n?` cal-mini-day-today`:``}`,children:[e.getDate(),o&&(0,F.jsx)(`span`,{className:`cal-mini-dot`})]},e.toISOString())})})]},a)})})})}var re={meeting:`Meeting`,event:`Event`,task:`Task`};function ie(e){let t=new Date(e),n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())}T${n(t.getHours())}:${n(t.getMinutes())}`}function ae(e){return new Date(e).toISOString()}function Q(e){return Math.floor(new Date(e).getTime()/6e4)}function oe(e){let t=new Date(e.startsAt);if(e.isAllDay)return t.toLocaleDateString([],{weekday:`long`,day:`numeric`,month:`long`,year:`numeric`});let n=t.toLocaleDateString([],{weekday:`long`,day:`numeric`,month:`long`,year:`numeric`}),r=t.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`});return e.endsAt?`${n} · ${r} – ${new Date(e.endsAt).toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`})}`:`${n} · ${r}`}function se(e){if(!e)return null;let t=e.match(/filename="([^"]+)"/);return t?t[1]:null}function ce(e,t){return e.email??`${e.name??`unknown`}-${t}`}function le({a:e}){let t=e.name||e.email||`Unknown`,n=e.name&&e.email?e.email:null;return(0,F.jsxs)(`span`,{className:`cal-attendee-lines`,children:[(0,F.jsx)(`span`,{className:`cal-attendee-name`,children:t}),n&&(0,F.jsx)(`span`,{className:`cal-attendee-email`,children:n})]})}function ue({meeting:e,adminFetch:t,onClose:n,onSaved:r,onDeleted:i}){let a=e.kind===`meeting`,[o,s]=(0,w.useState)(!1),[p,h]=(0,w.useState)(!1),[g,v]=(0,w.useState)(!1),[C,T]=(0,w.useState)(!1),[E,D]=(0,w.useState)(null),[O,k]=(0,w.useState)(e),[A,ee]=(0,w.useState)(e.title??``),[j,M]=(0,w.useState)(ie(e.startsAt)),[N,P]=(0,w.useState)(e.endsAt?ie(e.endsAt):``),[I,L]=(0,w.useState)(e.location??``),[R,te]=(0,w.useState)(e.privateNote??``),[z,B]=(0,w.useState)(``),[V,H]=(0,w.useState)(``);(0,w.useEffect)(()=>{let e=e=>{e.key===`Escape`&&!C&&n()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[C,n]);let U=(0,w.useCallback)(()=>{let e={},t=A.trim();t!==(O.title??``)&&(e.title=t);let n=ae(j);Q(n)!==Q(O.startsAt)&&(e.startsAt=n);let r=N?ae(N):null;(r===null?O.endsAt!==null:O.endsAt===null||Q(r)!==Q(O.endsAt))&&(e.endsAt=r);let i=I.trim()||null;i!==(O.location??null)&&(e.location=i);let a=R.trim()||null;return a!==(O.privateNote??null)&&(e.privateNote=a),e},[A,j,N,I,R,O]),W=(0,w.useCallback)(async()=>{let n=U();if(Object.keys(n).length===0){s(!1);return}T(!0),D(null);try{let i=await t(`/api/admin/calendar/meetings/${encodeURIComponent(e.meetingId)}`,{method:`PATCH`,headers:{"content-type":`application/json`},body:JSON.stringify(n)});if(!i.ok)throw Error(`HTTP ${i.status}`);let a=await i.json();k(a.meeting),r(a.meeting),s(!1)}catch(e){D(e instanceof Error?e.message:`Save failed`)}finally{T(!1)}},[t,U,e.meetingId,r]),G=(0,w.useCallback)(async()=>{let n=z.trim(),i=V.trim();if(!(!n&&!i)){T(!0),D(null);try{let a=await t(`/api/admin/calendar/meetings/${encodeURIComponent(e.meetingId)}/attendees`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({name:n||void 0,email:i||void 0})});if(!a.ok)throw Error(`HTTP ${a.status}`);let o=await a.json();k(o.meeting),r(o.meeting),B(``),H(``)}catch(e){D(e instanceof Error?e.message:`Add failed`)}finally{T(!1)}}},[t,z,V,e.meetingId,r]),K=(0,w.useCallback)(async n=>{let i=n.email?{email:n.email}:{name:n.name};T(!0),D(null);try{let n=await t(`/api/admin/calendar/meetings/${encodeURIComponent(e.meetingId)}/attendees`,{method:`DELETE`,headers:{"content-type":`application/json`},body:JSON.stringify(i)});if(!n.ok)throw Error(`HTTP ${n.status}`);let a=await n.json();k(a.meeting),r(a.meeting)}catch(e){D(e instanceof Error?e.message:`Remove failed`)}finally{T(!1)}},[t,e.meetingId,r]),q=(0,w.useCallback)(async()=>{T(!0),D(null);try{let n=await t(`/api/admin/calendar/meetings/${encodeURIComponent(e.meetingId)}`,{method:`DELETE`});if(!n.ok)throw Error(`HTTP ${n.status}`);i(e.meetingId)}catch(e){D(e instanceof Error?e.message:`Delete failed`),T(!1)}},[t,e.meetingId,i]),J=(0,w.useCallback)(async n=>{v(!1),T(!0),D(null);try{let r=await t(`/api/admin/calendar/meetings/${encodeURIComponent(e.meetingId)}/ics?attendees=${n?`1`:`0`}`);if(!r.ok)throw Error(`HTTP ${r.status}`);let i=await r.blob(),a=se(r.headers.get(`content-disposition`))??`meeting.ics`,o=URL.createObjectURL(i),s=document.createElement(`a`);s.href=o,s.download=a,document.body.appendChild(s),s.click(),s.remove(),URL.revokeObjectURL(o)}catch(e){D(e instanceof Error?e.message:`Download failed`)}finally{T(!1)}},[t,e.meetingId]),Y=re[e.kind??`meeting`],X=z.trim().length>0||V.trim().length>0;return(0,F.jsx)(`div`,{className:`cal-modal-overlay`,onClick:()=>{C||n()},children:(0,F.jsxs)(`div`,{className:`cal-modal`,role:`dialog`,"aria-modal":`true`,"aria-label":o?`Edit meeting`:`Meeting detail`,onClick:e=>e.stopPropagation(),children:[(0,F.jsxs)(`div`,{className:`cal-modal-header`,children:[(0,F.jsx)(`span`,{className:`cal-modal-kind`,children:Y}),(0,F.jsx)(`button`,{type:`button`,className:`cal-modal-close`,onClick:n,"aria-label":`Close`,autoFocus:!0,disabled:C,children:(0,F.jsx)(l,{size:16})})]}),!o&&(0,F.jsxs)(`div`,{className:`cal-modal-body`,children:[(0,F.jsx)(`div`,{className:`cal-modal-title`,children:O.title??`Untitled`}),(0,F.jsxs)(`div`,{className:`cal-modal-row`,children:[(0,F.jsx)(y,{size:14}),(0,F.jsx)(`span`,{children:oe(O)})]}),O.location&&(0,F.jsxs)(`div`,{className:`cal-modal-row`,children:[(0,F.jsx)(b,{size:14}),(0,F.jsx)(`span`,{children:O.location})]}),O.attendees.length>0&&(0,F.jsxs)(`div`,{className:`cal-modal-row cal-modal-row-top`,children:[(0,F.jsx)(m,{size:14}),(0,F.jsx)(`div`,{className:`cal-modal-attendees`,children:O.attendees.map((e,t)=>(0,F.jsx)(`div`,{className:`cal-attendee-row`,children:(0,F.jsx)(le,{a:e})},ce(e,t)))})]}),O.privateNote&&(0,F.jsxs)(`div`,{className:`cal-modal-row cal-modal-row-top`,children:[(0,F.jsx)(x,{size:14}),(0,F.jsx)(`span`,{className:`cal-modal-note`,children:O.privateNote})]}),(0,F.jsxs)(`div`,{className:`cal-modal-row cal-modal-meta`,children:[(0,F.jsx)(_,{size:14}),(0,F.jsx)(`span`,{children:Y})]})]}),o&&(0,F.jsxs)(`div`,{className:`cal-modal-body`,children:[(0,F.jsxs)(`label`,{className:`cal-modal-field`,children:[(0,F.jsx)(`span`,{children:`Title`}),(0,F.jsx)(`input`,{type:`text`,value:A,onChange:e=>ee(e.target.value),disabled:C})]}),(0,F.jsxs)(`label`,{className:`cal-modal-field`,children:[(0,F.jsx)(`span`,{children:`Start`}),(0,F.jsx)(`input`,{type:`datetime-local`,value:j,onChange:e=>M(e.target.value),disabled:C})]}),(0,F.jsxs)(`label`,{className:`cal-modal-field`,children:[(0,F.jsx)(`span`,{children:`End`}),(0,F.jsx)(`input`,{type:`datetime-local`,value:N,onChange:e=>P(e.target.value),disabled:C})]}),(0,F.jsxs)(`label`,{className:`cal-modal-field`,children:[(0,F.jsx)(`span`,{children:`Location`}),(0,F.jsx)(`input`,{type:`text`,value:I,onChange:e=>L(e.target.value),disabled:C})]}),(0,F.jsxs)(`div`,{className:`cal-modal-field`,children:[(0,F.jsx)(`span`,{children:`Attendees`}),(0,F.jsxs)(`div`,{className:`cal-modal-attendees cal-modal-attendees-edit`,children:[O.attendees.length===0&&(0,F.jsx)(`div`,{className:`cal-attendee-empty`,children:`No attendees yet.`}),O.attendees.map((e,t)=>(0,F.jsxs)(`div`,{className:`cal-attendee-row cal-attendee-row-edit`,children:[(0,F.jsx)(le,{a:e}),(0,F.jsx)(`button`,{type:`button`,className:`cal-attendee-remove`,onClick:()=>K(e),disabled:C,"aria-label":`Remove ${e.name||e.email||`attendee`}`,children:(0,F.jsx)(l,{size:13})})]},ce(e,t)))]}),(0,F.jsxs)(`div`,{className:`cal-attendee-add`,children:[(0,F.jsx)(`input`,{type:`text`,placeholder:`Name`,value:z,onChange:e=>B(e.target.value),disabled:C,"aria-label":`Attendee name`}),(0,F.jsx)(`input`,{type:`email`,placeholder:`Email`,value:V,onChange:e=>H(e.target.value),disabled:C,"aria-label":`Attendee email`}),(0,F.jsx)(`button`,{type:`button`,className:`cal-modal-btn cal-attendee-add-btn`,onClick:G,disabled:C||!X,"aria-label":`Add attendee`,children:C?(0,F.jsx)(f,{size:13,className:`spin`}):(0,F.jsx)(S,{size:13})})]})]}),(0,F.jsxs)(`label`,{className:`cal-modal-field`,children:[(0,F.jsx)(`span`,{children:`Private note`}),(0,F.jsx)(`textarea`,{className:`cal-modal-textarea`,value:R,onChange:e=>te(e.target.value),disabled:C,rows:3,placeholder:`Only you and your team can see this.`})]})]}),E&&(0,F.jsx)(`div`,{className:`cal-modal-error`,children:E}),a&&(0,F.jsxs)(`div`,{className:`cal-modal-actions`,children:[!o&&!p&&!g&&(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`button`,{type:`button`,className:`cal-modal-btn`,onClick:()=>s(!0),disabled:C,children:[(0,F.jsx)(u,{size:14}),` Edit`]}),(0,F.jsxs)(`button`,{type:`button`,className:`cal-modal-btn cal-modal-btn-danger`,onClick:()=>h(!0),disabled:C,children:[(0,F.jsx)(c,{size:14}),` Delete`]}),(0,F.jsxs)(`button`,{type:`button`,className:`cal-modal-btn cal-modal-btn-download`,onClick:()=>{O.attendees.length>0?v(!0):J(!1)},disabled:C,children:[C?(0,F.jsx)(f,{size:14,className:`spin`}):(0,F.jsx)(d,{size:14}),` Download`]})]}),g&&(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`span`,{className:`cal-modal-confirm-text`,children:`Include attendees in the file?`}),(0,F.jsxs)(`button`,{type:`button`,className:`cal-modal-btn cal-modal-btn-primary`,onClick:()=>J(!0),disabled:C,children:[C?(0,F.jsx)(f,{size:14,className:`spin`}):null,` Yes`]}),(0,F.jsx)(`button`,{type:`button`,className:`cal-modal-btn`,onClick:()=>J(!1),disabled:C,children:`No`}),(0,F.jsx)(`button`,{type:`button`,className:`cal-modal-btn`,onClick:()=>v(!1),disabled:C,children:`Cancel`})]}),o&&(0,F.jsxs)(F.Fragment,{children:[(0,F.jsxs)(`button`,{type:`button`,className:`cal-modal-btn cal-modal-btn-primary`,onClick:W,disabled:C,children:[C?(0,F.jsx)(f,{size:14,className:`spin`}):null,` Save`]}),(0,F.jsx)(`button`,{type:`button`,className:`cal-modal-btn`,onClick:()=>{s(!1),D(null)},disabled:C,children:`Cancel`})]}),p&&(0,F.jsxs)(F.Fragment,{children:[(0,F.jsx)(`span`,{className:`cal-modal-confirm-text`,children:`Delete this meeting?`}),(0,F.jsxs)(`button`,{type:`button`,className:`cal-modal-btn cal-modal-btn-danger`,onClick:q,disabled:C,children:[C?(0,F.jsx)(f,{size:14,className:`spin`}):null,` Delete`]}),(0,F.jsx)(`button`,{type:`button`,className:`cal-modal-btn`,onClick:()=>h(!1),disabled:C,children:`Cancel`})]})]})]})})}var $=`maxy-admin-session-key`,de=[`day`,`week`,`month`,`year`];function fe(e,t){switch(e){case`day`:return t.toLocaleDateString([],{weekday:`long`,day:`numeric`,month:`long`,year:`numeric`});case`week`:{let{from:e,to:n}=j(`week`,t),r=new Date(n.getTime()-1);return`${e.toLocaleDateString([],{day:`numeric`,month:`short`})} – ${r.toLocaleDateString([],{day:`numeric`,month:`short`,year:`numeric`})}`}case`month`:return t.toLocaleDateString([],{month:`long`,year:`numeric`});case`year`:return String(t.getFullYear())}}function pe(){let[e,t]=(0,w.useState)(null),[n,r]=(0,w.useState)(!1),[i,a]=(0,w.useState)(void 0),[o,c]=(0,w.useState)(null),[l,u]=(0,w.useState)(void 0),[d,m]=(0,w.useState)(null),[g,_]=(0,w.useState)(null);(0,w.useEffect)(()=>{let e=!1,n=null;try{n=sessionStorage.getItem($)}catch{}if(!n){r(!0);return}return fetch(`/api/admin/session?session_key=${encodeURIComponent(n)}`).then(async i=>{if(!e){if(i.status===401){try{sessionStorage.removeItem($)}catch{}window.location.href=`/`;return}if(i.ok)try{let e=await i.json();typeof e.businessName==`string`&&a(e.businessName),e.sessionId!==void 0&&c(e.sessionId??null),_(e.role??null),u(e.userName===void 0?null:e.userName),m(e.avatar??null)}catch{}t(n),r(!0)}}).catch(()=>{e||(t(n),r(!0))}),()=>{e=!0}},[]);let v=(0,w.useCallback)(()=>{try{sessionStorage.removeItem($)}catch{}window.location.href=`/`},[]),[y,b]=(0,w.useState)(!1),x=(0,w.useCallback)(async()=>{b(!0);try{let e=await h();if(e){try{sessionStorage.removeItem($)}catch{}window.location.href=`/`}return e}finally{b(!1)}},[]);return n?e?(0,F.jsx)(s,{cacheKey:e,surface:`calendar`,onSessionExpired:({code:e,path:t})=>{console.warn(`[admin-auth] outcome=session-expired-redirect code=${e} path=${t} surface=calendar`);try{sessionStorage.removeItem($)}catch{}window.location.href=`/`},children:(0,F.jsx)(p,{cacheKey:e,businessName:i,sessionId:o,onLogout:v,onDisconnect:x,disconnecting:y,userName:l,userAvatar:d,role:g,children:(0,F.jsx)(me,{cacheKey:e})})}):(0,F.jsx)(`div`,{className:`cal-page`,children:(0,F.jsxs)(`div`,{className:`cal-empty`,children:[(0,F.jsx)(`p`,{children:`You are not signed in.`}),(0,F.jsxs)(`p`,{children:[`Open the `,(0,F.jsx)(`a`,{href:`/`,className:`cal-link`,children:`main admin page`}),` and log in, then return here.`]})]})}):(0,F.jsx)(`div`,{className:`cal-page`,children:(0,F.jsxs)(`div`,{className:`cal-loading`,children:[(0,F.jsx)(f,{size:18,className:`spin`}),` Loading…`]})})}function me({cacheKey:e}){let{adminFetch:t,sessionRefetchNonce:n}=a({initialCacheKey:e,surface:`calendar`}),[r,i]=(0,w.useState)(`month`),[s,c]=(0,w.useState)(()=>new Date),[l,u]=(0,w.useState)([]),[d,p]=(0,w.useState)(!1),[m,h]=(0,w.useState)(null),[y,b]=(0,w.useState)(null),[x,S]=(0,w.useState)(null);(0,w.useEffect)(()=>{let e=!1;return t(`/api/admin/calendar/booking-link`).then(async t=>{if(e||!t.ok)return;let n=await t.json();typeof n.bookingDomain==`string`&&n.bookingDomain&&S(n.bookingDomain)}).catch(()=>{}),()=>{e=!0}},[t]),(0,w.useEffect)(()=>{let e=!1,{from:n,to:i}=j(r,s);return p(!0),h(null),t(`/api/admin/calendar/meetings?from=${encodeURIComponent(n.toISOString())}&to=${encodeURIComponent(i.toISOString())}`).then(async t=>{if(e)return;if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.json();u(Array.isArray(n.meetings)?n.meetings:[])}).catch(t=>{e||(h(t instanceof Error?t.message:`Failed to load`),u([]))}).finally(()=>{e||p(!1)}),()=>{e=!0}},[r,s,n,t]);let C=(0,w.useCallback)(()=>c(new Date),[]),T=(0,w.useCallback)(()=>c(e=>M(r,e,-1)),[r]),E=(0,w.useCallback)(()=>c(e=>M(r,e,1)),[r]),D=(0,w.useCallback)(e=>{c(e),i(`month`)},[]);(0,w.useEffect)(()=>{b(null)},[r,s]);let O=(0,w.useCallback)(e=>{u(t=>t.map(t=>t.meetingId===e.meetingId?e:t)),b(e)},[]),k=(0,w.useCallback)(e=>{u(t=>t.filter(t=>t.meetingId!==e)),b(null)},[]);return(0,F.jsxs)(`div`,{className:`cal-page`,children:[(0,F.jsxs)(`header`,{className:`cal-header`,children:[(0,F.jsxs)(`div`,{className:`cal-title`,children:[(0,F.jsx)(_,{size:20}),` Calendar`]}),(0,F.jsxs)(`div`,{className:`cal-nav`,children:[(0,F.jsx)(`button`,{type:`button`,className:`cal-today-btn`,onClick:C,children:`Today`}),(0,F.jsx)(`button`,{type:`button`,className:`cal-nav-btn`,onClick:T,"aria-label":`Previous`,children:(0,F.jsx)(g,{size:18})}),(0,F.jsx)(`button`,{type:`button`,className:`cal-nav-btn`,onClick:E,"aria-label":`Next`,children:(0,F.jsx)(v,{size:18})}),(0,F.jsx)(`span`,{className:`cal-range-label`,children:fe(r,s)}),d&&(0,F.jsx)(f,{size:16,className:`spin`})]}),(0,F.jsx)(`div`,{className:`cal-views`,children:de.map(e=>(0,F.jsx)(`button`,{type:`button`,className:`cal-view-btn${e===r?` cal-view-btn-active`:``}`,onClick:()=>i(e),children:e.charAt(0).toUpperCase()+e.slice(1)},e))}),x&&(0,F.jsxs)(`a`,{className:`cal-booking-link`,href:`https://${x}`,target:`_blank`,rel:`noopener noreferrer`,children:[(0,F.jsx)(o,{size:14}),` Booking page`]})]}),(0,F.jsxs)(`div`,{className:`cal-body`,children:[m&&(0,F.jsxs)(`div`,{className:`cal-error`,children:[`Could not load the calendar: `,m]}),r===`day`&&(0,F.jsx)(Y,{anchor:s,meetings:l,onSelect:b}),r===`week`&&(0,F.jsx)(K,{anchor:s,meetings:l,onSelect:b}),r===`month`&&(0,F.jsx)(te,{anchor:s,meetings:l,onSelect:b}),r===`year`&&(0,F.jsx)(ne,{anchor:s,meetings:l,onPickMonth:D})]}),y&&(0,F.jsx)(ue,{meeting:y,adminFetch:t,onClose:()=>b(null),onSaved:O,onDeleted:k})]})}(0,C.createRoot)(document.getElementById(`root`)).render((0,F.jsx)(pe,{}));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{F as e,M as t}from"./useSubAccountSwitcher-DMbRhLPv.js";import"./admin-types-hioowVct.js";import"./AdminShell-D2-uBSB5.js";import{n}from"./page-D-Ep4bXd.js";import"./Transcript-DkGa4CQH.js";var r=e(),i=t();(0,r.createRoot)(document.getElementById(`root`)).render((0,i.jsx)(n,{}));
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{D as e}from"./useSubAccountSwitcher-DMbRhLPv.js";var t=e(`chevron-left`,[[`path`,{d:`m15 18-6-6 6-6`,key:`1wnfg3`}]]);export{t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{F as e,M as t}from"./useSubAccountSwitcher-DMbRhLPv.js";import{t as n}from"./page-ByDLq_o1.js";import"./Transcript-DkGa4CQH.js";import"./graph-labels-D3BQdcpD.js";var r=e(),i=t();(0,r.createRoot)(document.getElementById(`root`)).render((0,i.jsx)(n,{}));
|