@rubytech/create-maxy-code 0.1.322 → 0.1.324

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.
Files changed (88) hide show
  1. package/dist/index.js +55 -3
  2. package/package.json +1 -1
  3. package/payload/platform/plugins/admin/skills/insight/SKILL.md +1 -1
  4. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +36 -5
  5. package/payload/platform/plugins/docs/references/admin-ui.md +12 -0
  6. package/payload/platform/plugins/docs/references/deployment.md +19 -0
  7. package/payload/platform/plugins/docs/references/plugins-guide.md +4 -4
  8. package/payload/platform/plugins/memory/PLUGIN.md +0 -1
  9. package/payload/platform/plugins/memory/mcp/dist/index.js +0 -45
  10. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  11. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js +6 -6
  12. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js.map +1 -1
  13. package/payload/platform/plugins/notion-import/.claude-plugin/plugin.json +1 -1
  14. package/payload/platform/plugins/notion-import/PLUGIN.md +6 -6
  15. package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +1 -1
  16. package/payload/platform/plugins/notion-import/skills/notion-import/references/databases.md +1 -1
  17. package/payload/platform/plugins/obsidian-import/.claude-plugin/plugin.json +1 -1
  18. package/payload/platform/plugins/obsidian-import/PLUGIN.md +5 -5
  19. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +1 -1
  20. package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +1 -1
  21. package/payload/platform/plugins/substack-import/PLUGIN.md +8 -8
  22. package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +2 -2
  23. package/payload/platform/plugins/substack-import/skills/substack-import/references/posts.md +1 -1
  24. package/payload/platform/plugins/x-import/.claude-plugin/plugin.json +1 -1
  25. package/payload/platform/plugins/x-import/PLUGIN.md +5 -5
  26. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
  27. package/payload/platform/scripts/check-no-esm-require.mjs +3 -0
  28. package/payload/platform/scripts/identity-forbidden-token-check.mjs +0 -1
  29. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  30. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +0 -1
  31. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  32. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/http-server.js +24 -7
  34. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  35. package/payload/platform/services/claude-session-manager/dist/index.js +3 -3
  36. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  37. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts.map +1 -1
  38. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js +8 -4
  39. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js.map +1 -1
  40. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +3 -3
  41. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  42. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +13 -12
  43. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  44. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +5 -4
  45. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  46. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  47. package/payload/platform/services/claude-session-manager/dist/reaper.js +6 -6
  48. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -1
  49. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  50. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +0 -1
  51. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  52. package/payload/platform/templates/specialists/agents/coding-assistant.md +1 -1
  53. package/payload/platform/templates/specialists/agents/database-operator.md +2 -6
  54. package/payload/platform/templates/specialists/agents/librarian.md +20 -7
  55. package/payload/server/power-health.cjs +129 -0
  56. package/payload/server/public/assets/AdminLoginScreens-BaNHSvDG.js +1 -0
  57. package/payload/server/public/assets/AdminShell-6Iq4co_0.js +1 -0
  58. package/payload/server/public/assets/{Checkbox-DjANdKoK.js → Checkbox-BoljWa0z.js} +1 -1
  59. package/payload/server/public/assets/OperatorConversations-DL9372pQ.css +1 -0
  60. package/payload/server/public/assets/OperatorConversations-yKFxglvV.js +9 -0
  61. package/payload/server/public/assets/{admin--FlkQOMu.js → admin-DgGttnBt.js} +1 -1
  62. package/payload/server/public/assets/{browser-vowQc0TJ.js → browser-BLoa93fm.js} +1 -1
  63. package/payload/server/public/assets/chat-BJ4229vV.js +1 -0
  64. package/payload/server/public/assets/data-BK_ggj-z.js +1 -0
  65. package/payload/server/public/assets/{graph-B-64Cq-y.js → graph-iNIIHeRn.js} +3 -3
  66. package/payload/server/public/assets/{graph-labels-Dtd2ckXH.js → graph-labels-IeLlsqB1.js} +1 -1
  67. package/payload/server/public/assets/operator-plsrZHSk.js +1 -0
  68. package/payload/server/public/assets/page-BOQHw8Fa.js +30 -0
  69. package/payload/server/public/assets/{public-CrFepd06.js → public-CuMZDmDF.js} +1 -1
  70. package/payload/server/public/browser.html +4 -4
  71. package/payload/server/public/chat.html +5 -5
  72. package/payload/server/public/data.html +4 -4
  73. package/payload/server/public/graph.html +6 -6
  74. package/payload/server/public/index.html +6 -6
  75. package/payload/server/public/operator.html +7 -7
  76. package/payload/server/public/public.html +5 -5
  77. package/payload/server/server-init.cjs +40 -0
  78. package/payload/server/server.js +36 -1
  79. package/payload/platform/plugins/memory/mcp/scripts/backfill-typed-edges.ts +0 -72
  80. package/payload/platform/templates/specialists/agents/archive-ingest-operator.md +0 -45
  81. package/payload/server/public/assets/AdminLoginScreens-D1X4M9wX.js +0 -1
  82. package/payload/server/public/assets/AdminShell-BGZ3d3gY.js +0 -1
  83. package/payload/server/public/assets/OperatorConversations-BkitSIiT.js +0 -9
  84. package/payload/server/public/assets/OperatorConversations-C-eFXT7w.css +0 -1
  85. package/payload/server/public/assets/chat-Cw6rUWiC.js +0 -1
  86. package/payload/server/public/assets/data-9ArhwX1q.js +0 -1
  87. package/payload/server/public/assets/operator-Cqn1Ne60.js +0 -1
  88. package/payload/server/public/assets/page-DQ5D6Dg9.js +0 -30
@@ -3,7 +3,7 @@ name: database-operator
3
3
  description: "Execute a single graph write on the memory graph when the label, properties, and parent are already decided. Delegate when one fact or relationship needs to land in the graph and the target is unambiguous; not for documents, transcripts, or bulk archives."
4
4
  summary: "Executes graph writes on admin's behalf when delegated via the Task tool — admin names each write, the specialist runs it."
5
5
  model: claude-haiku-4-5-20251001
6
- tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-edge, mcp__plugin_memory_memory__memory-update-by-name, mcp__plugin_memory_memory__memory-lookup-by-name, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_memory_memory__memory-typed-edge-pass, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
6
+ tools: Read, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-edge, mcp__plugin_memory_memory__memory-update-by-name, mcp__plugin_memory_memory__memory-lookup-by-name, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_memory_memory__profile-update, mcp__plugin_memory_memory__profile-read, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_work_work__work-update, mcp__plugin_work_work__project-create, mcp__plugin_work_work__project-update
7
7
  ---
8
8
 
9
9
  You are an expert Neo4J graph operator. Admin delegates a graph-write to you through the Task tool; the prompt admin sends names what should land in the graph in plain English.
@@ -20,10 +20,6 @@ The `accountId` property is supplied by the writers from server-side environment
20
20
 
21
21
  Decide the precise operations against the schema, execute them with the writers in your tool surface, and report each write back to admin as `{label, elementId}` so admin can confirm the outcome to the operator. If admin's brief is ambiguous about which label, which edge type, or which existing node to attach to, name the ambiguity in your reply rather than guessing.
22
22
 
23
- ## Typed-edge auto-extraction pass (on `/insight`)
24
-
25
- When admin's brief names the typed-edge pass and supplies a `sinceIso` timestamp, call `memory-typed-edge-pass` with that timestamp exactly once. The tool reads prose-bearing nodes (Message/Page/Meeting/KnowledgeDocument/ConversationArchive/Idea/Note/Post/Report — `:KnowledgeDocument` covers email threads via `source:'email'`; `:ConversationArchive` covers chat transcripts) the account wrote since `sinceIso`, asks Haiku for typed-edge proposals against a closed allowlist, validates each one, and MERGEs accepted edges with `createdBy` provenance. Return the full counter object verbatim — admin needs `nodesProcessed` and `accepted` for its insight-pass summary. Do not reinterpret the counts or summarise them.
26
-
27
23
  ## Bulk external archives route elsewhere
28
24
 
29
- Obsidian vault, ICS calendar archive, X (Twitter) archive, and Notion workspace export ingestion all moved to the `archive-ingest-operator` specialist (Sonnet) schema-mapping ambiguity in those flows requires the larger model. If admin's brief points at one of those archive types, hand back to admin so it can dispatch the right specialist.
25
+ Obsidian vault, ICS calendar archive, X (Twitter) archive, Notion workspace export, and Substack export ingestion all belong to the `librarian` specialist, which owns foreground ingest of documents, transcripts, LinkedIn, and every bulk archive type. If admin's brief points at one of those archive types, hand back to admin so it can dispatch the librarian.
@@ -1,16 +1,16 @@
1
1
  ---
2
2
  name: librarian
3
- description: "Ingest documents (PDF, text, web pages), conversation transcripts (WhatsApp, Telegram, iMessage, Slack, meeting minutes), and LinkedIn exports into the memory graph. Delegate when the operator hands you a file or transcript that should land in the graph."
4
- summary: "Owns foreground ingest of documents, conversation transcripts, and external archives into the memory graph."
3
+ description: "Ingest documents (PDF, text, web pages), conversation transcripts (WhatsApp, Telegram, iMessage, Slack, meeting minutes), LinkedIn exports, and bulk external archives (Obsidian vaults, .ics calendar exports, X (Twitter) archives, Notion workspace exports, Substack exports) into the memory graph. Delegate when the operator hands you a file, transcript, or archive that should land in the graph."
4
+ summary: "Owns foreground ingest of documents, conversation transcripts, LinkedIn, and bulk external archives into the memory graph."
5
5
  model: claude-opus-4-8[1m]
6
- tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-edge, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_work_work__work-create, mcp__plugin_url-get_url-get__url-get, Read, Bash, Skill, WebFetch
6
+ tools: mcp__plugin_memory_memory__memory-ingest-extract, mcp__plugin_memory_memory__memory-ingest, mcp__plugin_memory_memory__memory-ingest-web, mcp__plugin_memory_memory__memory-archive-write, mcp__plugin_memory_memory__memory-write, mcp__plugin_memory_memory__memory-update, mcp__plugin_memory_memory__memory-edge, mcp__plugin_memory_memory__memory-search, mcp__plugin_memory_memory__obsidian-vault-import, mcp__plugin_memory_memory__conversation-archive-list-chunks, mcp__plugin_memory_memory__conversation-archive-derive-insights, mcp__plugin_memory_memory__conversation-archive-enrich-rejection, mcp__plugin_scheduling_scheduling__schedule-archive-ics, mcp__plugin_contacts_contacts__contact-create, mcp__plugin_contacts_contacts__contact-update, mcp__plugin_work_work__work-create, mcp__plugin_url-get_url-get__url-get, Read, Bash, Skill, WebFetch
7
7
  ---
8
8
 
9
9
  # Librarian
10
10
 
11
- You are the foreground ingester for this account's memory graph. The admin agent dispatches you when the operator hands over a document, a conversation transcript, a LinkedIn export, or an unzipped tree that needs to land in the graph. You run one ingest pipeline end-to-end, surface the operator-narrative lines the skills define, and return a structured outcome to the admin agent.
11
+ You are the foreground ingester for this account's memory graph. The admin agent dispatches you when the operator hands over a document, a conversation transcript, a LinkedIn export, a bulk external archive (an Obsidian vault, an `.ics` calendar export, an X (Twitter) archive, a Notion workspace export, or a Substack export), or an unzipped tree that needs to land in the graph. You run one ingest pipeline end-to-end, surface the operator-narrative lines the skills define, and return a structured outcome to the admin agent.
12
12
 
13
- You are not the background recorder. The narrow per-turn recorder (`database-operator`) fires from a Stop hook with the just-completed admin turn as stdin; it writes only the memory tools and never invokes ingest skills. You are the wide-surface ingester invoked on demand.
13
+ You are not the single-write executor. `database-operator` is the narrow specialist the admin dispatches via the Task tool inside the live session when one already-decided fact or relationship needs to land in the graph; it writes only the memory tools and never invokes ingest skills. You are the wide-surface ingester invoked on demand. There is no background or per-turn recorder.
14
14
 
15
15
  ## Three rules
16
16
 
@@ -29,7 +29,7 @@ These three rules win when anything else in this prompt conflicts with them.
29
29
 
30
30
  ## Skill routing
31
31
 
32
- The dispatch brief from the admin agent names the input class. Map it to one skill. **After routing, the first tool call MUST be `Skill <skill-name>`. Any `memory-*` write tool called before the skill content is loaded into context is a contract violation.**
32
+ The dispatch brief from the admin agent names the input class. Map it to one skill. **After routing to a skill, the first tool call MUST be `Skill <skill-name>`. Any `memory-*` write tool called before the skill content is loaded into context is a contract violation.** The `.ics` calendar export is the single exception: it has no skill — route it straight to the `schedule-archive-ics` tool flow (see Bulk external archives).
33
33
 
34
34
  | Input | Skill | Parent label |
35
35
  |---|---|---|
@@ -38,13 +38,26 @@ The dispatch brief from the admin agent names the input class. Map it to one ski
38
38
  | Granola / Otter / Circleback meeting ingest (provider MCP connected to the host) | `conversation-archive-mcp` | `:ConversationArchive` (same identity formula as `conversation-archive`; source ∈ {granola, otter, circleback}; per-provider meeting ID and `calendarEventId` stamped as cross-references) |
39
39
  | Per-row enrich pass over an existing conversation-document parent | `conversation-archive-enrich` | (mutates existing `:Section` chunks) |
40
40
  | LinkedIn Basic Data Export directory | `linkedin-import` | flat-dataset MERGE via `memory-archive-write` |
41
+ | Obsidian vault directory | `obsidian-import` (two-phase: dry-run → operator disambiguation → commit) | `:KnowledgeDocument` per page (wikilinks resolve to pages/entities; tags → `:DefinedTerm`; embedded images → `:DigitalDocument`) |
42
+ | `.ics` calendar export | `schedule-archive-ics` tool flow (dry-run → commit; **no skill load** — see Bulk external archives below) | `:Meeting` MERGEd on `(accountId, uid)`; attendees resolve to `:Person` by lowercased email |
43
+ | X (Twitter) archive directory | `x-import` | tweet stream → one `:KnowledgeDocument` (`source='x'`); each DM participant set → `:ConversationArchive` (`source='x-dm'`) |
44
+ | Notion workspace export | `notion-import` | `:KnowledgeDocument` per page + schema-mapped labels per database row |
45
+ | Substack export | `substack-import` | per-post `:KnowledgeDocument {kind:'substack-post'}` + one `:KnowledgeDocument {kind:'substack-subscriber-roster'}` carrying `:MENTIONS` to each subscriber `:Person` |
41
46
  | Post-unzip tree forwarded by admin | route by detected shape (LinkedIn export folder → `linkedin-import`; loose docs → `document-ingest`; transcript files → `conversation-archive`) | per branch |
42
47
 
43
48
  If the brief is ambiguous between two skills (e.g. an unzipped tree that contains both LinkedIn CSVs and a loose PDF), return to admin with the disambiguation question; do not start a write.
44
49
 
50
+ ## Bulk external archives
51
+
52
+ The Obsidian, X, Notion, and Substack archive types each load their own skill — route per the table, then `Skill <skill-name>` first. The `.ics` calendar export is the one tool-flow exception with no skill: call `mcp__plugin_scheduling_scheduling__schedule-archive-ics` with `mode='dry-run'`, present the attendee-resolution preview to the operator (how many already exist under this account, how many would be cross-account-skipped, how many new `:Person` stubs would be created, plus the sample list), then call again with `mode='commit'` after the operator confirms. Each VEVENT becomes one `:Meeting` MERGEd on `(accountId, uid)` (idempotent re-ingest); cross-account email collisions skip the attendance edge — do not propose to override this.
53
+
54
+ **Surface schema-mapping ambiguity; do not blanket-`:MENTIONS`.** Edge types are closed (the skills name `:MENTIONS` / `:ABOUT` as the documented catch-alls). When a source row carries a relationship that no listed edge fits and both catch-alls are wrong, surface the gap in your reply (`{ambiguity: "no canonical edge for <relationship>", proposed: "MENTIONS"}`) rather than silently catch-all-writing every unmapped relation. The same applies to an ambiguous label or an ambiguous existing-node attachment — name the ambiguity, do not guess.
55
+
56
+ **Archive account-isolation is load-bearing.** Inline `@person` mentions and attendee identifiers always resolve against `:Person {accountId}` or `:AdminUser {accountId}` only; participants are never auto-created from an archive row. A sender or attendee outside the account's existing nodes is surfaced, not minted.
57
+
45
58
  ## Graph hierarchy
46
59
 
47
- Every node has a parent in the canonical chain `LocalBusiness → Project → Task | Person | Organisation | KnowledgeDocument | ConversationArchive` (`:ConversationArchive` is a peer parent). The wrapped writers reject orphans. The four ingest skills each name the anchor or participant flow that must complete before any write; honour those flows.
60
+ Every node has a parent in the canonical chain `LocalBusiness → Project → Task | Person | Organisation | KnowledgeDocument | ConversationArchive` (`:ConversationArchive` is a peer parent). The wrapped writers reject orphans. Each ingest skill names the anchor or participant flow that must complete before any write; honour those flows.
48
61
 
49
62
  ## When a tool returns an error
50
63
 
@@ -0,0 +1,129 @@
1
+ 'use strict'
2
+
3
+ // Pi power-health decoders. Pure: every function takes command output as a
4
+ // string argument (or an injected `runner`) so the same logic runs and tests
5
+ // off-device. The admin server is otherwise blind to a brownout — the kernel
6
+ // logs `Undervoltage detected!` to the journal but nothing surfaces it to
7
+ // server.log. These builders turn the vcgencmd sticky word + unclean-reboot
8
+ // count into one greppable `[power-health]` line, read by server-init.cjs at
9
+ // boot and on a 15-minute interval.
10
+
11
+ function parseThrottled(hex) {
12
+ if (typeof hex !== 'string') return null
13
+ const m = hex.match(/0x[0-9a-fA-F]+/)
14
+ if (!m) return null
15
+ const v = Number.parseInt(m[0], 16)
16
+ if (!Number.isFinite(v)) return null
17
+ const bit = (n) => (v & (1 << n)) !== 0
18
+ return {
19
+ raw: '0x' + v.toString(16),
20
+ undervoltNow: bit(0), // bit 0 — under-voltage right now
21
+ throttledNow: bit(2), // bit 2 — currently throttled
22
+ softTempNow: bit(3), // bit 3 — soft temperature limit active now
23
+ undervoltOccurred: bit(16),// bit 16 — under-voltage has occurred (sticky)
24
+ throttleOccurred: bit(18), // bit 18 — throttling has occurred (sticky)
25
+ softTempOccurred: bit(19), // bit 19 — soft temp limit has occurred (sticky)
26
+ }
27
+ }
28
+
29
+ function parseExt5v(text) {
30
+ if (typeof text !== 'string') return null
31
+ const m = text.match(/=\s*([\d.]+)\s*V/)
32
+ if (!m) return null
33
+ const v = Number.parseFloat(m[1])
34
+ return Number.isFinite(v) ? v : null
35
+ }
36
+
37
+ function _firstIso(line) {
38
+ const m = line.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[^\s]*/)
39
+ return m ? new Date(m[0]) : null
40
+ }
41
+
42
+ // Count boots whose `last -x --time-format iso reboot shutdown` record (newest
43
+ // first) is not immediately preceded in time by a `shutdown` — the boot-loop /
44
+ // brownout-reset signature. Only reboots within `windowHours` before `now`
45
+ // count. The oldest reboot in the window has no earlier neighbour captured and
46
+ // is treated as unclean, matching "no preceding shutdown".
47
+ function countUncleanReboots(lastOutput, windowHours, now) {
48
+ if (typeof lastOutput !== 'string') return 0
49
+ const rows = []
50
+ for (const raw of lastOutput.split('\n')) {
51
+ const line = raw.trim()
52
+ if (line.startsWith('reboot')) rows.push({ type: 'reboot', time: _firstIso(line) })
53
+ else if (line.startsWith('shutdown')) rows.push({ type: 'shutdown', time: _firstIso(line) })
54
+ }
55
+ const cutoff = now.getTime() - windowHours * 3600 * 1000
56
+ let count = 0
57
+ for (let i = 0; i < rows.length; i++) {
58
+ const r = rows[i]
59
+ if (r.type !== 'reboot') continue
60
+ if (!r.time || r.time.getTime() < cutoff) continue
61
+ const earlier = rows[i + 1]
62
+ const clean = earlier && earlier.type === 'shutdown'
63
+ if (!clean) count++
64
+ }
65
+ return count
66
+ }
67
+
68
+ const _DUR_UNIT_SEC = { us: 1e-6, ms: 1e-3, s: 1, sec: 1, m: 60, min: 60, h: 3600, hr: 3600 }
69
+
70
+ // `systemctl show -p RuntimeWatchdogUSec` returns either a raw microsecond
71
+ // integer (e.g. `=20000000`) or a systemd duration (`=20s`, `=2min`) depending
72
+ // on the systemd version; both must read as the same seconds value or the
73
+ // watchdog line would falsely log `unset`/`0`. A bare integer is microseconds
74
+ // (the property name says USec); a unit-suffixed value is a duration.
75
+ function _watchdogSeconds(text, key) {
76
+ if (typeof text !== 'string') return null
77
+ const m = text.match(new RegExp(key + '=([^\\s]+)'))
78
+ if (!m) return null
79
+ const val = m[1]
80
+ let sec
81
+ if (/^\d+$/.test(val)) {
82
+ const us = Number.parseInt(val, 10)
83
+ if (!Number.isFinite(us)) return null
84
+ sec = Math.round(us / 1_000_000)
85
+ } else {
86
+ let total = 0
87
+ let matched = false
88
+ for (const part of val.matchAll(/(\d+(?:\.\d+)?)\s*(us|ms|sec|s|min|m|hr|h)/g)) {
89
+ const unit = _DUR_UNIT_SEC[part[2]]
90
+ if (unit === undefined) continue
91
+ total += Number.parseFloat(part[1]) * unit
92
+ matched = true
93
+ }
94
+ if (!matched) return null
95
+ sec = Math.round(total)
96
+ }
97
+ // systemd reports `RuntimeWatchdogUSec=0` when the watchdog is unconfigured;
98
+ // surface that as unset, not an armed-at-zero-seconds reading.
99
+ return sec === 0 ? null : sec
100
+ }
101
+
102
+ function buildStatusLine({ runner, now }) {
103
+ const throttledRaw = runner('vcgencmd', ['get_throttled'])
104
+ const t = parseThrottled(throttledRaw || '')
105
+ if (!t) return null
106
+ const ext5v = parseExt5v(runner('vcgencmd', ['pmic_read_adc', 'EXT5V_V']) || '')
107
+ const lastOut = runner('last', ['-x', '--time-format', 'iso', 'reboot', 'shutdown']) || ''
108
+ const unclean = countUncleanReboots(lastOut, 24, now)
109
+ const ext5vStr = ext5v === null ? 'unavailable' : ext5v.toFixed(2)
110
+ return `[power-health] throttled=${t.raw} undervolt_now=${t.undervoltNow} ` +
111
+ `undervolt_occurred=${t.undervoltOccurred} reboots_unclean_24h=${unclean} ext5v_v=${ext5vStr}`
112
+ }
113
+
114
+ // `status` may be passed in precomputed (the caller arms the interval off the
115
+ // same buildStatusLine result, so recomputing here would fire the vcgencmd/last
116
+ // probes a second time at boot). When omitted, it is computed here.
117
+ function buildBootLines({ runner, now, lanIp, status }) {
118
+ const lines = [`[power-health] op=boot lan_ip=${lanIp || 'unknown'}`]
119
+ const wd = runner('systemctl', ['show', '-p', 'RuntimeWatchdogUSec', '-p', 'RebootWatchdogUSec'])
120
+ const runtimeSec = _watchdogSeconds(wd, 'RuntimeWatchdogUSec')
121
+ const rebootSec = _watchdogSeconds(wd, 'RebootWatchdogUSec')
122
+ lines.push(`[power-health] watchdog runtimeSec=${runtimeSec === null ? 'unset' : runtimeSec} ` +
123
+ `rebootSec=${rebootSec === null ? 'unset' : rebootSec}`)
124
+ const s = status === undefined ? buildStatusLine({ runner, now }) : status
125
+ lines.push(s || '[power-health] skipped (no vcgencmd)')
126
+ return lines
127
+ }
128
+
129
+ module.exports = { parseThrottled, parseExt5v, countUncleanReboots, buildStatusLine, buildBootLines }
@@ -0,0 +1 @@
1
+ import{o as e}from"./chunk-Pqm5yXtL.js";import{L as t,O as n,V as r,b as i,x as a,y as o}from"./OperatorConversations-yKFxglvV.js";import{i as s}from"./admin-types-CJrGd46U.js";import{g as c,l}from"./AdminShell-6Iq4co_0.js";import{t as u}from"./Checkbox-BoljWa0z.js";var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(r(),1);function h(e=`admin`){let[n,r]=(0,m.useState)(`loading`),[i,a]=(0,m.useState)(``),[o,l]=(0,m.useState)(``),[u,h]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(!1),[b,x]=(0,m.useState)(!1),[S,C]=(0,m.useState)(!1),[w,T]=(0,m.useState)(!1),[E,D]=(0,m.useState)(null),[O,k]=(0,m.useState)(null),[A,j]=(0,m.useState)(void 0),[M,N]=(0,m.useState)(null),[P,F]=(0,m.useState)(void 0),[I,L]=(0,m.useState)(null),[ee,R]=(0,m.useState)(null),[z,B]=(0,m.useState)([]),[V,H]=(0,m.useState)(!1),[U,W]=(0,m.useState)(void 0),G=(0,m.useRef)(void 0),[K,q]=(0,m.useState)(!1);(0,m.useEffect)(()=>{typeof window>`u`||fetch(`/api/remote-auth/status`).then(e=>e.ok?e.json():null).then(e=>{e?.configured&&q(!0)}).catch(()=>{})},[]);let J=(0,m.useRef)(null),Y=(0,m.useRef)(null);(0,m.useEffect)(()=>{async function e(){let e=null;try{e=sessionStorage.getItem(`maxy-admin-session-key`)}catch{}if(!e)return!1;try{let t=await fetch(`/api/admin/session?session_key=${encodeURIComponent(e)}`);if(t.status===401){try{sessionStorage.removeItem(`maxy-admin-session-key`)}catch{}return!1}if(!t.ok)return!1;let n=await t.json();D(n.session_key),R(n.sessionId??null),j(n.businessName),N(n.role??null),F(n.userName===void 0?null:n.userName),L(n.avatar??null);let i=s(n.thinkingView);return G.current=i,W(i),r(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(n=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check returned ${i.status} after retries`),r(`set-pin`);return}let a=await i.json();if(!a.pin_configured){r(`set-pin`);return}if(!a.claude_authenticated){r(`connect-claude`);return}if(await e())return;r(`enter-pin`)}catch(e){if(n>0)return await new Promise(e=>setTimeout(e,1500)),t(n-1);console.error(`[admin] health check failed:`,e),r(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{n===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[n]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let t=!1;try{t=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:n,alreadyRedirected:t,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[n,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(n!==`chat`)return;let e=setInterval(async()=>{try{let e=await fetch(`/api/health`);if(e.ok){let t=await e.json();if(t.auth_status===`dead`||t.auth_status===`missing`){r(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let n=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(n===`remote-auth-required`){t(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${n}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[n,E]),(0,m.useEffect)(()=>{n===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&r(`enter-pin`)}).catch(()=>{})},[n]);async function Z(e,t){y(!0);try{let n=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!n.ok){h((await n.json().catch(()=>({}))).error||`Invalid PIN`);return}let i=await n.json();if(i.accounts&&!i.session_key){console.log(`[admin] account picker shown: userId=${i.userId} accountCount=${i.accounts.length}`),B(i.accounts),r(`account-picker`);return}D(i.session_key),R(i.sessionId??null),j(i.businessName),N(i.role??null),F(i.userName===void 0?null:i.userName),L(i.avatar??null);let o=s(i.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,i.session_key)}catch{}a(``),r(`chat`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1),H(!1)}}let Q=(0,m.useCallback)(async e=>{if(e.preventDefault(),v)return;h(``);let t=o.trim();if(!t){h(`Please enter your name.`);return}if(i.length<4){h(`PIN must be at least 4 characters.`);return}let n=i;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:n,name:t})});if(!e.ok){let t=await e.json().catch(()=>({}));if(e.status===409){console.log(`[admin] PIN already configured — re-checking health`);try{let e=await fetch(`/api/health`);if(e.ok){let n=await e.json();n.pin_configured&&n.claude_authenticated?r(`enter-pin`):n.pin_configured?r(`connect-claude`):h(t.error||`Failed to set PIN.`)}else r(`enter-pin`)}catch{r(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let i=await fetch(`/api/health`);if((i.ok?await i.json():null)?.claude_authenticated){await Z(n);return}a(``),r(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[i,v,o]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(i)},[i]),ne=(0,m.useCallback)(async()=>{T(!0);try{if(!await c())return console.warn(`[admin-ui] claude-disconnect not verified — credentials may persist; staying put`),!1;D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}return r(`connect-claude`),!0}finally{T(!1)}},[]),$=(0,m.useCallback)(()=>{D(null),N(null),F(void 0),L(null);try{sessionStorage.removeItem(`maxy-admin-session-key`),sessionStorage.removeItem(`maxy-account-id`),sessionStorage.removeItem(d)}catch{}a(``),h(``),r(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:n,setAppState:r,pin:i,setPin:a,operatorName:o,setOperatorName:l,pinError:u,setPinError:h,showPin:g,setShowPin:_,pinLoading:v,authPolling:b,setAuthPolling:x,authLoading:S,setAuthLoading:C,disconnecting:w,cacheKey:E,setCacheKey:D,claudeInfo:O,setClaudeInfo:k,businessName:A,role:M,userName:P,userAvatar:I,sessionId:ee,setSessionId:R,accounts:z,accountPickerLoading:V,expandAll:U,setExpandAll:W,expandAllDefaultRef:G,remoteAuthEnabled:K,pinInputRef:J,setPinFormRef:Y,handleSetPin:Q,handleLogin:te,handleAccountSelect:(0,m.useCallback)(async e=>{H(!0),h(``),await Z(i,e)},[i]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!i){h(`Enter your current PIN first.`);return}y(!0),h(``);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`DELETE`,headers:{"Content-Type":`application/json`},body:JSON.stringify({currentPin:i})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}a(``),h(``),r(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[i])}}var g=a();function _({inputRef:e,value:t,onChange:n,onComplete:r,showPin:i,autoFocus:a}){let o=(0,m.useRef)([]);function s(e,r){r.key===`Backspace`?(r.preventDefault(),t[e]?n(t.slice(0,e)+t.slice(e+1)):e>0&&(n(t.slice(0,e-1)+t.slice(e)),o.current[e-1]?.focus())):r.key===`ArrowLeft`&&e>0?o.current[e-1]?.focus():r.key===`ArrowRight`&&e<5?o.current[e+1]?.focus():r.key===`Enter`&&(r.preventDefault(),r.currentTarget.form?.requestSubmit())}function c(e,i){let a=i.nativeEvent.data;if(!a||!/^\d$/.test(a))return;let s=t.split(``);for(s[e]=a;s.length<e;)s.push(``);let c=s.join(``).replace(/\D/g,``).slice(0,6);n(c),c.length===6?r?.(c):e<5&&o.current[e+1]?.focus()}function l(e){e.preventDefault();let t=e.clipboardData.getData(`text`).replace(/\D/g,``).slice(0,6);t&&(n(t),t.length===6?r?.(t):o.current[t.length]?.focus())}return(0,g.jsx)(`div`,{className:`pin-field`,children:Array.from({length:6}).map((n,r)=>(0,g.jsx)(`input`,{ref:t=>{o.current[r]=t,r===0&&e&&(e.current=t)},type:`text`,inputMode:`numeric`,className:`pin-box${t[r]?` pin-box-filled`:``}`,value:t[r]?i?t[r]:`•`:``,onKeyDown:e=>s(r,e),onInput:e=>c(r,e),onPaste:l,onFocus:e=>e.target.select(),autoFocus:a&&r===0,autoComplete:`off`,maxLength:1,"aria-label":`PIN digit ${r+1}`},r))})}function v(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:c,pinInputRef:d,setPinFormRef:f,onSubmit:p,operatorName:m,setOperatorName:h}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,o.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,o.productName,` who you are, then choose a PIN.`]}),(0,g.jsxs)(`form`,{ref:f,onSubmit:p,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(`input`,{type:`text`,className:`connect-name-input`,placeholder:`Your full name`,value:m,onChange:e=>h(e.target.value),autoComplete:`name`,autoFocus:!0,required:!0,"aria-label":`Your full name`}),(0,g.jsx)(`div`,{style:{width:38,flexShrink:0},"aria-hidden":`true`})]}),(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!t||!m.trim(),loading:s,"aria-label":`Set PIN`,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsx)(u,{checked:r,onChange:()=>a(e=>!e),label:`Show PIN`})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function y(e){let{pin:t,setPin:n,showPin:r,setShowPin:a,pinLoading:s,pinError:c,pinInputRef:d,onSubmit:f,onChangePin:p,remoteAuthEnabled:m,onSignOutRemote:h}=e;return(0,g.jsxs)(`div`,{className:`connect-page`,children:[m&&h&&(0,g.jsx)(`button`,{type:`button`,className:`connect-signout`,onClick:h,children:`Sign out`}),(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:o.productName}),(0,g.jsxs)(`form`,{onSubmit:f,className:`connect-pin-form`,children:[(0,g.jsxs)(`div`,{className:`pin-input-row`,children:[(0,g.jsx)(_,{inputRef:d,value:t,onChange:n,onComplete:()=>{},showPin:r,autoFocus:!0}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!t,loading:s,children:(0,g.jsxs)(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,g.jsx)(`line`,{x1:`5`,y1:`12`,x2:`19`,y2:`12`}),(0,g.jsx)(`polyline`,{points:`12 5 19 12 12 19`})]})})]}),(0,g.jsxs)(`div`,{className:`pin-options`,children:[(0,g.jsx)(u,{checked:r,onChange:()=>a(e=>!e),label:`Show PIN`}),(0,g.jsx)(l,{type:`button`,variant:`ghost`,onClick:p,children:`Change PIN`})]})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})]})}function b(e){let{accounts:t,loading:r,error:a,onSelect:s}=e;return(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:o.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:t.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:r,type:`button`,children:[(0,g.jsx)(`span`,{className:`account-picker-name`,children:e.businessName||e.accountId}),(0,g.jsx)(`span`,{className:`account-picker-role`,children:e.role}),r&&(0,g.jsx)(n,{className:`account-picker-spinner`,size:16})]},e.accountId))}),a&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:a})]})})}function x(e){let{authPolling:t,setAuthPolling:n,authLoading:r,setAuthLoading:a,pinError:s,setPinError:c,setAppState:u}=e,[d,f]=(0,m.useState)(!1),[p,h]=(0,m.useState)(!1);async function _(){h(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`launch-browser`})})).json();e.launched?f(!0):e.error&&c(e.error)}catch(e){console.error(`[admin] browser launch error:`,e),c(`Could not launch browser.`)}h(!1)}async function v(){a(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){n(!0),f(!0),a(!1);for(let e=0;e<120;e++)if(await new Promise(e=>setTimeout(e,2e3)),(await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`wait`})})).json()).authenticated){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),u(`enter-pin`);return}c(`Timed out waiting for sign-in. Try again.`),n(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}a(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),n(!1),c(``)}return t||d?(0,g.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100dvh`,overflow:`auto`},children:[(0,g.jsxs)(`header`,{className:`chat-header`,style:{paddingBottom:`12px`,flexShrink:0,position:`relative`,maxWidth:`680px`,width:`100%`,margin:`0 auto`,padding:`24px 20px 12px`},children:[t?(0,g.jsx)(`button`,{onClick:y,style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Cancel`,children:`✕`}):(0,g.jsx)(`button`,{onClick:()=>f(!1),style:{position:`absolute`,top:`12px`,right:`12px`,background:`none`,border:`none`,color:`#999`,fontSize:`13px`,cursor:`pointer`,padding:`4px 8px`},"aria-label":`Close browser`,children:`✕`}),(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`chat-logo`}),(0,g.jsx)(`h1`,{className:`chat-tagline`,children:`Connect Claude`}),(0,g.jsx)(`p`,{className:`chat-intro`,children:t?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!t&&(0,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:r,children:r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`})})]}),(0,g.jsx)(`div`,{style:{flex:1,display:`flex`,flexDirection:`column`,minHeight:0,gap:`10px`,padding:`0 0 16px`},children:(0,g.jsx)(`iframe`,{src:`/vnc-viewer.html`,style:{flex:1,width:`100%`,minHeight:0,border:`none`,background:`#111`,display:`block`},title:`Claude Sign-in`})}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,style:{textAlign:`center`,padding:`0 20px 16px`},children:s})]}):(0,g.jsx)(`div`,{className:`connect-page`,children:(0,g.jsxs)(`div`,{className:`connect-content`,children:[(0,g.jsxs)(`div`,{className:`connect-logos`,children:[(0,g.jsx)(`div`,{className:`connect-logo-wrap`,children:(0,g.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`connect-logo`})}),(0,g.jsx)(`svg`,{className:`connect-arrow`,viewBox:`0 0 48 24`,fill:`none`,xmlns:`http://www.w3.org/2000/svg`,children:(0,g.jsx)(`path`,{d:`M0 12h44m0 0l-8-8m8 8l-8 8`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`})}),(0,g.jsxs)(`div`,{className:`connect-logo-wrap`,children:[(0,g.jsx)(`img`,{src:i,alt:o.productName,className:`connect-logo connect-logo--maxy`}),!o.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:o.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,o.productName]}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Sign in with your Anthropic account to get started.`}),(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:r,children:r?(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(`span`,{className:`spin`,style:{display:`inline-block`},children:`✱`}),` Connecting…`]}):`Sign in to Claude`}),(0,g.jsx)(`p`,{style:{marginTop:`6px`,fontSize:`11px`,color:`#999`,maxWidth:`300px`,textAlign:`center`,lineHeight:`1.4`},children:`First time? You may need to sign into your email and Anthropic account in the browser before connecting.`}),(0,g.jsx)(`button`,{onClick:_,disabled:p,style:{marginTop:`12px`,background:`none`,border:`none`,color:`var(--color-primary, #666)`,fontSize:`13px`,cursor:`pointer`,textDecoration:`underline`,textUnderlineOffset:`3px`},children:p?`Launching…`:`Open browser first`}),s&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:s})]})})}function S({auth:e}){return e.appState===`loading`?(0,g.jsx)(`div`,{className:`connect-page`}):e.appState===`set-pin`?(0,g.jsx)(v,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,setPinFormRef:e.setPinFormRef,onSubmit:e.handleSetPin,operatorName:e.operatorName,setOperatorName:e.setOperatorName}):e.appState===`connect-claude`?(0,g.jsx)(x,{authPolling:e.authPolling,setAuthPolling:e.setAuthPolling,authLoading:e.authLoading,setAuthLoading:e.setAuthLoading,pinError:e.pinError,setPinError:e.setPinError,setAppState:e.setAppState}):e.appState===`enter-pin`?(0,g.jsx)(y,{pin:e.pin,setPin:e.setPin,showPin:e.showPin,setShowPin:e.setShowPin,pinLoading:e.pinLoading,pinError:e.pinError,pinInputRef:e.pinInputRef,onSubmit:e.handleLogin,onChangePin:e.handleChangePin,remoteAuthEnabled:e.remoteAuthEnabled,onSignOutRemote:()=>{console.info(`[admin-ui] remote-auth sign-out → /__remote-auth/logout`),window.location.href=`/__remote-auth/logout`}}):e.appState===`account-picker`?(0,g.jsx)(b,{accounts:e.accounts,loading:e.accountPickerLoading,error:e.pinError,onSelect:e.handleAccountSelect}):null}export{h as n,S as t};
@@ -0,0 +1 @@
1
+ import{o as e}from"./chunk-Pqm5yXtL.js";import{A as t,B as n,C as r,E as i,I as a,M as o,N as s,T as c,V as l,f as u,g as d,h as f,j as p,m,p as h,t as g,v as ee,x as te,y as ne}from"./OperatorConversations-yKFxglvV.js";async function _(){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 re=a(`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`}]]),ie=a(`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`}]]),v=a(`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`}]]),y=a(`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`}]]),ae=a(`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`}]]),b=a(`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`}]]),x=a(`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`}]]),oe=a(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),se=a(`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`}]]),ce=a(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),S=a(`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`}]]),C=e(l(),1),w=te(),le={sm:14,md:16,lg:18},T={sm:30,md:38,lg:46};function E({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=le[t],h={...e===`send`?{width:T[t],height:T[t]}:{},...u},g=Object.keys(h).length>0;return(0,w.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,w.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,w.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,w.jsx)(n,{size:m})]}),i&&(0,w.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var D=`maxy-shell-side-px`;function O(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function k(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-O());return Math.min(Math.max(e,248),n)}function A(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(D);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 k(t)}catch{}return 264}function ue({targetSelector:e=`.platform`}){let t=(0,C.useRef)(null),[n,r]=(0,C.useState)(()=>A()),i=(0,C.useRef)(n);(0,C.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,C.useCallback)(()=>{r(e=>{let t=k(e);return t===e?e:t})},[]);(0,C.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(k(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(D,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=k(264);r(e);try{window.localStorage.removeItem(D)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,w.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var de=n();function j({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,C.useRef)(null),[s,c]=(0,C.useState)({position:`fixed`,visibility:`hidden`}),l=(0,C.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,C.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,C.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,de.createPortal)((0,w.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function fe({action:e,disabled:t,open:n,onToggle:r,onClose:i}){let a=(0,C.useRef)(null);return(0,w.jsxs)(w.Fragment,{children:[(0,w.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,w.jsx)(j,{anchorRef:a,onClose:i,className:e.panelClassName,role:`dialog`,ariaLabel:e.label,children:e.panel()})]})}function pe({actions:e,disabled:t,collapsed:n}){let[r,i]=(0,C.useState)(null),[a,s]=(0,C.useState)(!1),[c,l]=(0,C.useState)(null),u=(0,C.useRef)(null);(0,C.useEffect)(()=>{i(null),s(!1),l(null)},[n]);let d=(0,C.useCallback)(()=>{s(!1),l(null)},[]);return n?(0,w.jsxs)(`div`,{className:`conv-actions`,children:[(0,w.jsx)(`button`,{ref:u,type:`button`,className:`conv-action conv-actions-overflow`,onClick:()=>s(e=>!e),disabled:t,"aria-haspopup":`menu`,"aria-expanded":a,"aria-label":`Session actions`,title:`Session actions`,children:(0,w.jsx)(o,{size:12})}),a&&(0,w.jsx)(j,{anchorRef:u,onClose:d,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,w.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,w.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`dialog`,"aria-expanded":c===e.key,disabled:t,onClick:()=>l(t=>t===e.key?null:e.key),children:[e.icon,(0,w.jsx)(`span`,{children:e.menuLabel})]}),c===e.key&&(0,w.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,w.jsxs)(`button`,{type:`button`,role:`menuitem`,className:e.danger?`conv-action-danger`:void 0,"aria-busy":e.busy,disabled:t,onClick:t=>{e.onClick?.(t),d()},children:[e.icon,(0,w.jsx)(`span`,{children:e.menuLabel})]},e.key))})]}):(0,w.jsx)(`div`,{className:`conv-actions`,children:e.map(e=>e.panel?(0,w.jsx)(fe,{action:e,disabled:t,open:r===e.key,onToggle:()=>i(t=>t===e.key?null:e.key),onClose:()=>i(null)},e.key):(0,w.jsx)(`button`,{type:`button`,className:e.danger?`conv-action conv-action-danger`:`conv-action`,onClick:e.onClick,disabled:t,"aria-busy":e.busy,"aria-label":e.label,title:e.title,children:e.icon},e.key))})}var M=`claude-opus-4-8[1m]`,N=`claude-sonnet-4-6`,P=`claude-haiku-4-5`,me={[M]:`Opus 4.8 (1M context)`,[N]:`Sonnet 4.6`,[P]:`Haiku 4.5`};function F(e){return me[e]??e}var he=[M,N,P];function I(e){return e.replace(/\[1m\]$/,``)}function ge(e){return he.find(t=>I(t)===I(e))??e}var L=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`],R=[`low`,`medium`,`high`,`xhigh`];[...L],[...R];var z=[M,N,P],_e={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},B=L.map(e=>({value:e,label:_e[e]??e})),V={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},ve=R.map(e=>({value:e,label:V[e]??e}));function H(e){if(e){let t=z.find(t=>I(t)===I(e));if(t)return t}return M}function ye({row:e,adminFetch:t,onError:n}){let[r,i]=(0,C.useState)(()=>H(e.model)),[a,o]=(0,C.useState)(``),[s,c]=(0,C.useState)(``),[l,u]=(0,C.useState)(!1),d=(0,C.useRef)(!1);(0,C.useEffect)(()=>{i(H(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 re-seat ${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(`Re-seat of ${e.title} returned no target`),d.current=!1,u(!1))}catch(t){n(`Could not re-seat ${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,w.jsxs)(w.Fragment,{children:[(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Model`}),(0,w.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:z.map(e=>(0,w.jsx)(`option`,{value:e,children:F(e)},e))})]}),(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Mode`}),(0,w.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,w.jsx)(`option`,{value:``,children:`Keep current`}),B.map(e=>(0,w.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Effort`}),(0,w.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,w.jsx)(`option`,{value:``,children:`Keep current`}),ve.map(e=>(0,w.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,w.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void f(),children:`Re-seat`})]})}var be=[`whatsapp`,`telegram`];function U(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 xe(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function W(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 Se({target:e,onConfirm:t,onCancel:n}){return e?(0,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`span`,{children:`Delete this conversation?`}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,w.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,w.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,w.jsx)(E,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,w.jsx)(E,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var Ce=`auth-refresh-failed`;function we({error:e,onClose:t}){if(!e)return null;let n=e.reason===Ce,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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`span`,{children:r}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,w.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function Te(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,C.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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,w.jsx)(`span`,{children:`Claude Code`}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,w.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,w.jsxs)(w.Fragment,{children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:p>0?xe(p):`—`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:U(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.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 W(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}var Ee=`https://claude.ai/code`,De=200,Oe=[500,1e3,1500,2e3,2500,3e3,3e3];function ke(e,t,n){if(e&&n.target)return{kind:`navigate`,url:n.target};let r=n.slug??n.bridgeSessionId??null;if(e&&r)return{kind:`navigate`,url:`${Ee}/${r}`};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function Ae(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function G(e){let{businessName:n,cacheKey:a,role:o,userName:l,userAvatar:d,onSelectProjects:g,onSelectPeople:te,onSelectTasks:_,onSelectAgents:le,onCloseMobileDrawer:T,collapsed:E,selectedWhatsappId:D,onSelectWhatsappConversation:O,initialWhatsappSurface:k=!1}=e,A=ee(a),ue=(0,C.useCallback)(e=>({key:`reseat`,label:`Re-seat session ${e.title} (model, mode, effort)`,menuLabel:`Re-seat`,title:`Re-seat — move this session onto a chosen model, mode, and effort`,icon:(0,w.jsx)(se,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,w.jsx)(ye,{row:e,adminFetch:A,onError:e=>V({message:e,failed:!0})})}),[A]),de=ne.productName,j=typeof l==`string`?l:l===null?`name unavailable`:n||de,fe=(j.trim().charAt(0)||`?`).toUpperCase(),[M,N]=(0,C.useState)(k?`whatsapp`:`sessions`),[P,me]=(0,C.useState)([]),[F,he]=(0,C.useState)(!1),[I,ge]=(0,C.useState)(null),[L,R]=(0,C.useState)(!1),[z,_e]=(0,C.useState)(`file`),[B,V]=(0,C.useState)(null),[ve,H]=(0,C.useState)(null),[U,xe]=(0,C.useState)([]),[W,Ce]=(0,C.useState)(!1),[Te,Ee]=(0,C.useState)(null),[G,je]=(0,C.useState)(!1),[K,Fe]=(0,C.useState)(!1),[q,Ie]=(0,C.useState)(!1),[Le,Re]=(0,C.useState)(null),[J,ze]=(0,C.useState)(new Set),[Be,Ve]=(0,C.useState)(null),[He,Ue]=(0,C.useState)(new Set),[We,Ge]=(0,C.useState)(new Set),[Ke,qe]=(0,C.useState)(new Set),[Je,Ye]=(0,C.useState)(null),[Xe,Y]=(0,C.useState)(``),[Ze,Qe]=(0,C.useState)(!1),[X,$e]=(0,C.useState)(!1),et=(0,C.useRef)(null),tt=(0,C.useRef)(0),[nt,rt]=(0,C.useState)(0);(0,C.useEffect)(()=>{let e=et.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(e=>{let t=e[0]?.contentRect.width??0;rt(e=>Math.abs(e-t)<1?e:t)});return t.observe(e),()=>t.disconnect()},[M]);let it=nt>0&&nt<400,[at,ot]=(0,C.useState)([]),[st,ct]=(0,C.useState)(!1),[lt,ut]=(0,C.useState)(null),[dt,ft]=(0,C.useState)(`whatsapp`),pt=(0,C.useCallback)(e=>{if(T(),!a){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}`),u(a,e.downloadPath,e.downloadRoot??`data`),V({message:`Downloading ${e.name}`,failed:!1})},[a,T]);(0,C.useEffect)(()=>{if(!B)return;let e=setTimeout(()=>V(null),2500);return()=>clearTimeout(e)},[B]);let mt=(0,C.useCallback)(async()=>{if(a){R(!0),ge(null);try{let e=await A(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);me((await e.json()).artefacts??[]),he(!0)}catch(e){let t=e instanceof Error?e.message:String(e);ge(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{R(!1)}}},[a,A]),Z=(0,C.useCallback)(async()=>{if(!a)return null;let e=++tt.current;je(!0),Ee(null);try{let t=await A(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===tt.current?(xe(r),Re(n.accountId??null),Ce(!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===tt.current&&Ee(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===tt.current&&je(!1)}},[a,A]),Q=(0,C.useCallback)(async()=>{if(a){ut(null);try{let e=await A(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);ot((await e.json()).conversations??[]),ct(!0)}catch(e){let t=e instanceof Error?e.message:String(e);ut(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[a,A]);(0,C.useEffect)(()=>{!a||W||Z()},[a,W,Z]),(0,C.useEffect)(()=>{if(!a)return;let e=null;return Q(),e=setInterval(()=>{Q()},Me),()=>{e!==null&&clearInterval(e)}},[a,Q]),(0,C.useEffect)(()=>{if(!a)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Z()}function n(){e===null&&(e=setInterval(t,Ne))}function r(){e!==null&&(clearInterval(e),e=null)}function i(){document.hidden?r():(t(),n())}return document.hidden||n(),document.addEventListener(`visibilitychange`,i),()=>{r(),document.removeEventListener(`visibilitychange`,i)}},[a,Z]);let ht=(0,C.useMemo)(()=>{let e=new Map;for(let t of be)e.set(t,[]);for(let t of at)e.get(t.channel)?.push(t);for(let t of be)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[at]),gt={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},_t=()=>{O(null),N(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${F?P.length:0} collapsed=${E}`),mt()},$=1.5,vt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),mt()},yt=()=>{O(null),N(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${W?U.length:0} collapsed=${E}`),W||Z()},bt=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Z()},xt=e=>{N(`whatsapp`),ft(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${ht.get(e)?.length??0} collapsed=${E}`)},St=(0,C.useCallback)(async e=>{if(He.has(e.sessionId))return;Ue(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await A(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,name:e.title||e.sessionId})}),r=await n.json().catch(()=>({})),i=ke(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`?(T(),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{Ue(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[A,T,He]),Ct=(0,C.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Oe.length;n++){await new Promise(e=>setTimeout(e,Oe[n-1]));let r=await Z();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}`)},[Z]),wt=(0,C.useCallback)(async()=>{if(X)return;$e(!0);let e=window.open(``,`_blank`);try{let t=await A(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),n=await t.json().catch(()=>({})),r=ke(t.ok,t.status,n);console.info(`[admin-ui] sidebar-new-session-spawned status=${t.status} outcome=${r.kind} slug=${n.slug??n.bridgeSessionId??`none`}`),r.kind===`navigate`?(e?e.location.href=r.url:window.open(r.url,`_blank`),n.sessionId?Ct(n.sessionId):console.error(`[admin-ui] sidebar-new-session-converge-skipped reason=no-session-id`)):(e?.close(),console.error(`[admin-ui] sidebar-new-session-failed status=${t.status} reason=${r.reason}`),H(r))}catch(t){e?.close();let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-new-session-failed error=${n}`),H({sessionId:null,reason:n})}finally{$e(!1)}},[A,X,Ct]),Tt=(0,C.useCallback)((e,t)=>{e.stopPropagation(),Ve(t)},[]),Et=(0,C.useCallback)(async e=>{if(!J.has(e.sessionId)){ze(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await A(`/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??`?`}`),xe(t=>t.filter(t=>t.sessionId!==e.sessionId)),Z()}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{ze(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}}},[A,J,Z]),Dt=(0,C.useCallback)(async(e,t)=>{if(e.stopPropagation(),!We.has(t.sessionId)){Ge(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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}`),Z()}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{Ge(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,We,Z]),Ot=(0,C.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!Ke.has(t.sessionId)){qe(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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}`),Z()}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})}}},[A,Ke,Z]),kt=(0,C.useCallback)(async e=>{let t=Xe.trim();if(!t){V({message:`Title can’t be empty`,failed:!0});return}if(t.length>De){V({message:`Title too long (max ${De})`,failed:!0});return}Qe(!0);try{let n=await A(`/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`),Ye(null),Y(``),Z()}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{Qe(!1)}},[A,Xe,Z]);return(0,w.jsxs)(`aside`,{className:`side`,children:[(0,w.jsx)(`div`,{className:`side-new-session-row`,children:(0,w.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:wt,disabled:X,"aria-busy":X,children:[(0,w.jsx)(oe,{size:14}),(0,w.jsx)(`span`,{children:X?`Spawning…`:`New session`})]})}),(0,w.jsxs)(`nav`,{className:`side-nav`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),te(),T()},children:[(0,w.jsx)(S,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`People`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),le(),T()},children:[(0,w.jsx)(v,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Agents`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),g(),T()},children:[(0,w.jsx)(y,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Projects`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),_(),T()},children:[(0,w.jsx)(b,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`artefacts`?` active`:``}`,onClick:_t,children:[(0,w.jsx)(t,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`sessions`?` active`:``}`,onClick:yt,children:[(0,w.jsx)(ae,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,w.jsx)(`span`,{className:`kbd`})]}),st&&be.filter(e=>ht.get(e).length>0).map(e=>(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`whatsapp`&&dt===e?` active`:``}`,onClick:()=>xt(e),children:[(0,w.jsx)(m,{channel:e,size:16}),(0,w.jsx)(`span`,{className:`label`,children:gt[e]}),(0,w.jsx)(`span`,{className:`kbd`})]},e)),lt&&(0,w.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,w.jsx)(`span`,{className:`label`,children:lt})})]}),M===`artefacts`&&(0,w.jsxs)(`div`,{className:`side-list`,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:`Artefacts`}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:vt,disabled:L,children:(0,w.jsx)(c,{size:12,className:L?`spinning`:void 0})}),(0,w.jsx)(`span`,{children:L?`…`:String(P.length)})]})]}),I&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:I}),F&&!I&&P.length>0&&(()=>{let e=P.filter(e=>e.kind===`agent-template`).length,t=P.length-e;return(0,w.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:P.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,w.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${z===e.key?` active`:``}`,onClick:()=>_e(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,w.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),F&&!I&&P.length===0&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),P.filter(e=>z===`all`?!0:z===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let n=e.kind===`agent-template`,r=n?v:t,i=Ae(e.updatedAt),a=e.downloadPath!==null;return(0,w.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>pt(e),disabled:!a,style:a?void 0:{cursor:`default`},title:a?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,w.jsx)(r,{size:14,className:`conv-icon`,"data-kind":n?`agent`:`file`,"aria-label":n?`agent template`:`file`}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsx)(`span`,{className:`conv-name-line`,children:(0,w.jsx)(`span`,{className:`conv-name`,children:e.name})}),i&&(0,w.jsx)(`span`,{className:`conv-timestamp`,children:i})]}),a&&(0,w.jsx)(s,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),M===`sessions`&&(()=>{let e=U.filter(e=>K?!0:!e.isSubagent).filter(e=>q?!0:!e.archived),t=U.some(e=>e.isSubagent),n=U.some(e=>e.archived);return(0,w.jsxs)(`div`,{className:`side-list`,ref:et,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:`Sessions`}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:bt,disabled:G,children:(0,w.jsx)(c,{size:12,className:G?`spinning`:void 0})}),(0,w.jsx)(`span`,{children:G?`…`:String(e.length)})]})]}),Le&&(0,w.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,w.jsx)(`code`,{children:Le})}),(t||n)&&(0,w.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,w.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${K?` active`:``}`,"aria-pressed":K,onClick:()=>Fe(e=>!e),title:K?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),n&&(0,w.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${q?` active`:``}`,"aria-pressed":q,onClick:()=>Ie(e=>!e),title:q?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),Te&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:Te}),W&&!Te&&e.length===0&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=Ae(e.startedAt),n=He.has(e.sessionId),a=J.has(e.sessionId),o=We.has(e.sessionId),s=Ke.has(e.sessionId),c=n||a||o||s,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,w.jsx)(p,{size:12}),busy:n,onClick:()=>{St(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,w.jsx)(x,{size:12}),onClick:()=>{window.location.assign(`/chat?session=${e.sessionId}`)}},...e.live?[{key:`stop`,label:`Stop session ${e.title}`,menuLabel:`Stop`,title:`Stop session process (keeps the conversation, can resume later)`,icon:(0,w.jsx)(ce,{size:12}),busy:o,onClick:t=>{Dt(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,w.jsx)(re,{size:12}),busy:s,onClick:t=>{Ot(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,w.jsx)(ie,{size:12}),busy:s,onClick:t=>{Ot(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,w.jsx)(i,{size:12}),busy:Ze&&Je===e.sessionId,onClick:t=>{t.stopPropagation(),Ye(e.sessionId),Y(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,w.jsx)(r,{size:12}),danger:!0,busy:a,onClick:t=>{Tt(t,e)}},ue({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,w.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,w.jsxs)(`div`,{className:`conv-main-static`,children:[(0,w.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,w.jsx)(f,{channel:e.channel,size:13}),Je===e.sessionId?(0,w.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,value:Xe,disabled:Ze,"aria-label":`New title for session ${e.title}`,onChange:e=>Y(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),kt(e)):t.key===`Escape`&&(t.preventDefault(),Ye(null),Y(``))},onBlur:()=>{Je===e.sessionId&&!Ze&&(Ye(null),Y(``))}}):(0,w.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,w.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,w.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,w.jsxs)(`span`,{children:[` · `,t]})]})]})]}),(0,w.jsx)(pe,{actions:l,disabled:c,collapsed:it})]},e.sessionId)})]})})(),M===`whatsapp`&&(0,w.jsxs)(`div`,{className:`side-list`,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:gt[dt]}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{Q()},children:(0,w.jsx)(c,{size:12})}),(0,w.jsx)(`span`,{children:String(ht.get(dt).length)})]})]}),ht.get(dt).map(e=>{let t=Ae(e.lastMessageAt);return(0,w.jsxs)(`div`,{className:`conv conv-with-actions${D===e.sessionId?` active`:``}`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{O(e),T()},title:e.title,children:[(0,w.jsx)(m,{channel:e.channel,size:14}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsxs)(`span`,{className:`conv-name-line`,children:[(0,w.jsx)(`span`,{className:`conv-name`,children:h(e)}),e.role===`public`&&(0,w.jsx)(`span`,{className:`conv-tag conv-tag-public`,children:`Public`})]}),t&&(0,w.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),(0,w.jsx)(pe,{actions:[ue({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1,collapsed:it})]},e.sessionId)})]}),(0,w.jsx)(Pe,{}),(0,w.jsxs)(`div`,{className:`side-foot`,children:[(0,w.jsx)(`div`,{className:`avatar`,children:d?(0,w.jsx)(`img`,{src:d,alt:j}):fe}),(0,w.jsxs)(`div`,{className:`who`,children:[(0,w.jsx)(`span`,{className:`name`,children:j}),(0,w.jsx)(`span`,{className:`role`,children:o??`operator`})]})]}),B&&(0,w.jsx)(`div`,{className:`copy-toast${B.failed?` copy-toast-failed`:``}`,role:`status`,children:B.message}),(0,w.jsx)(we,{error:ve,onClose:()=>H(null)}),(0,w.jsx)(Se,{target:Be,onCancel:()=>Ve(null),onConfirm:()=>{let e=Be;Ve(null),e&&Et(e)}})]})}var je=5e3,Me=3e4,Ne=3e4;function Pe(){let[e,t]=(0,C.useState)(null);if((0,C.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()},je))}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,w.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,w.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,w.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,w.jsx)(`div`,{className:`system-stats__bar`,children:(0,w.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,w.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,w.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,w.jsx)(`div`,{className:`system-stats__bar`,children:(0,w.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var K=`admin-sidebar-collapsed`,Fe=`admin-sidebar-drawer-open`;function q(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(K)===`1`}catch{return!1}}function Ie(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(K,`1`):window.sessionStorage.removeItem(K)}catch{}}function Le(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(Fe)===`1`}catch{return!1}}function Re(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(Fe,`1`):window.sessionStorage.removeItem(Fe)}catch{}}var J=720;function ze(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.sessionId)}&projectDir=${encodeURIComponent(t.projectDir)}`}}function Be(e,t){if(e!==`/`)return null;let n=new URLSearchParams(t),r=n.get(`wa`),i=n.get(`projectDir`);return!r||!i?null:{sessionId:r,projectDir:i,title:``,senderId:null,startedAt:``,channel:`whatsapp`,role:`admin`,operatorName:null,whatsappName:null,lastMessageAt:null,modelGated:!1,model:null}}function Ve(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`chat`?`/chat`:`/browser`}function He(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,userName:s,userAvatar:c,role:l,children:u,footer:f}=e,[p,m]=(0,C.useState)(()=>q()),[h,ee]=(0,C.useState)(()=>Le()),[te,ne]=(0,C.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${J}px)`).matches),[_,re]=(0,C.useState)(()=>typeof window>`u`?null:Be(window.location.pathname,window.location.search)),[ie]=(0,C.useState)(()=>_!==null);(0,C.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${J}px)`),t=e=>ne(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let v=(0,C.useCallback)(e=>{Ie(e),m(e)},[]),y=(0,C.useCallback)(e=>{Re(e),ee(e)},[]);(0,C.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=${p} drawer=${h}`)},[]),(0,C.useEffect)(()=>{typeof window>`u`||!_||(console.info(`[admin-ui] wa-hydrate route=/ sessionId=${_.sessionId.slice(0,8)}`),window.history.replaceState(null,``,`/`))},[]);let ae=(0,C.useCallback)(e=>{if(e===null){re(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=ze(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?re(e):window.location.href=n.href},[]),b=te?h:!p,x=(0,C.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${J}px)`).matches){let e=h;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),y(!e)}else{let e=p;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),v(!e)}},[p,h,v,y]),oe=(0,C.useCallback)(e=>{let t=Ve(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),[se,ce]=(0,C.useState)(`chat`),[S,le]=(0,C.useState)([]);(0,C.useEffect)(()=>{if(r!==`operator`||!t)return;let e=!1;return fetch(`/api/whatsapp-reader/conversations?session_key=${encodeURIComponent(t)}`).then(e=>e.ok?e.json():{conversations:[]}).then(t=>{e||le(t.conversations??[])}).catch(()=>{}),()=>{e=!0}},[r,t]);let T=(0,C.useMemo)(()=>[...new Set(S.map(e=>e.channel))],[S]),E={collapsed:p,mobileDrawerOpen:h,sidebarOpen:b,onToggleSidebar:x,setMobileDrawerOpen:y,selectedWhatsapp:_,onClearWhatsapp:()=>re(null)};return r===`operator`?(0,w.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,w.jsx)(d,{businessName:n,variant:r,onNavigate:oe,conversationsCount:S.length,conversationsChannels:T,onOpenConversations:()=>ce(`conversations`),onToggleSidebar:x,sidebarOpen:b,onLogout:i,onDisconnect:a,disconnecting:o}),(0,w.jsx)(`div`,{className:`platform platform-operator`,children:se===`conversations`?(0,w.jsx)(g,{conversations:S,sessionKey:t??``,onBack:()=>ce(`chat`)}):typeof u==`function`?u(E):u}),f]}):(0,w.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,w.jsx)(d,{businessName:n,variant:r,onNavigate:oe,onToggleSidebar:x,sidebarOpen:b,onLogout:i,onDisconnect:a,disconnecting:o}),(0,w.jsxs)(`div`,{className:`platform${h?` menu-open`:``}${p?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,w.jsx)(G,{businessName:n,cacheKey:t,role:l??null,userName:s,userAvatar:c??null,onSelectProjects:()=>{window.location.href=`/graph?label=Project`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/graph?label=Task`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>y(!1),collapsed:p,mobileDrawerOpen:h,selectedWhatsappId:_?.sessionId??null,onSelectWhatsappConversation:ae,initialWhatsappSurface:ie}),!te&&(0,w.jsx)(ue,{}),typeof u==`function`?u(E):u]}),h&&(0,w.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>y(!1)}),f]})}export{M as a,F as c,se as d,oe as f,_ as g,v as h,P as i,E as l,b as m,ke as n,N as o,x as p,Te as r,ge as s,He as t,S as u};
@@ -1 +1 @@
1
- import{x as e}from"./OperatorConversations-BkitSIiT.js";var t=e();function n({checked:e,onChange:n,label:r,disabled:i}){return(0,t.jsxs)(`label`,{className:`maxy-checkbox${i?` maxy-checkbox--disabled`:``}`,children:[(0,t.jsx)(`input`,{type:`checkbox`,checked:e,onChange:e=>n(e.target.checked),disabled:i}),(0,t.jsx)(`span`,{className:`maxy-checkbox__box`,children:`✱`}),r&&(0,t.jsx)(`span`,{className:`maxy-checkbox__label`,children:r})]})}export{n as t};
1
+ import{x as e}from"./OperatorConversations-yKFxglvV.js";var t=e();function n({checked:e,onChange:n,label:r,disabled:i}){return(0,t.jsxs)(`label`,{className:`maxy-checkbox${i?` maxy-checkbox--disabled`:``}`,children:[(0,t.jsx)(`input`,{type:`checkbox`,checked:e,onChange:e=>n(e.target.checked),disabled:i}),(0,t.jsx)(`span`,{className:`maxy-checkbox__box`,children:`✱`}),r&&(0,t.jsx)(`span`,{className:`maxy-checkbox__label`,children:r})]})}export{n as t};