@rubytech/create-maxy-code 0.1.311 → 0.1.312

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 (55) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/graph-style/dist/index.d.ts +5 -2
  3. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  4. package/payload/platform/lib/graph-style/dist/index.js +65 -2
  5. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  6. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +218 -0
  7. package/payload/platform/lib/graph-style/src/index.ts +53 -2
  8. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +20 -2
  9. package/payload/platform/plugins/docs/references/admin-ui.md +19 -1
  10. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +10 -0
  11. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -1
  12. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +62 -53
  13. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -1
  14. package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts.map +1 -1
  15. package/payload/platform/services/claude-session-manager/dist/scope-record.js +35 -53
  16. package/payload/platform/services/claude-session-manager/dist/scope-record.js.map +1 -1
  17. package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts +45 -0
  18. package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts.map +1 -0
  19. package/payload/platform/services/claude-session-manager/dist/sidecar-store.js +118 -0
  20. package/payload/platform/services/claude-session-manager/dist/sidecar-store.js.map +1 -0
  21. package/payload/server/public/assets/{AccessGate-ChFLk-rp.js → AccessGate-Dh5A79FU.js} +1 -1
  22. package/payload/server/public/assets/{AdminLoginScreens-DU6zgbk5.js → AdminLoginScreens-B8s2TbT7.js} +1 -1
  23. package/payload/server/public/assets/AdminShell-Cu1zlb6L.js +1 -0
  24. package/payload/server/public/assets/{Checkbox-CQGLKMXu.js → Checkbox-B_sOAyv1.js} +1 -1
  25. package/payload/server/public/assets/OperatorConversations-hm0Gpu_Q.js +1 -0
  26. package/payload/server/public/assets/{admin-COHPIWdb.js → admin-gZEndvJT.js} +1 -1
  27. package/payload/server/public/assets/{audio-attachment-mime-DL06xo72.js → audio-attachment-mime-B0b89VnH.js} +1 -1
  28. package/payload/server/public/assets/{brand-CN7uSSKl.css → brand-BcNavK6q.css} +1 -1
  29. package/payload/server/public/assets/{browser-L7N4tAOl.js → browser-BUlB5_MD.js} +1 -1
  30. package/payload/server/public/assets/chat-BnceaVl7.js +1 -0
  31. package/payload/server/public/assets/data-3Nl3P5wt.js +1 -0
  32. package/payload/server/public/assets/{graph-Cro3-mgY.js → graph-DMCKpW6P.js} +2 -2
  33. package/payload/server/public/assets/graph-labels-AZLGoVy8.js +1 -0
  34. package/payload/server/public/assets/operator-BF4F7k23.js +1 -0
  35. package/payload/server/public/assets/page-DQUEst1o.js +1 -0
  36. package/payload/server/public/assets/{public-CX148JKi.js → public-G_-UI9nB.js} +1 -1
  37. package/payload/server/public/assets/{public-next-BCItsUbZ.js → public-next-C8_nExQB.js} +1 -1
  38. package/payload/server/public/assets/{useSelectionMode-BHAAhkDg.js → useSelectionMode-Bf6Rt-sl.js} +1 -1
  39. package/payload/server/public/browser.html +6 -6
  40. package/payload/server/public/chat.html +8 -8
  41. package/payload/server/public/data.html +5 -5
  42. package/payload/server/public/graph.html +8 -8
  43. package/payload/server/public/index.html +8 -8
  44. package/payload/server/public/operator.html +10 -10
  45. package/payload/server/public/public-next.html +9 -9
  46. package/payload/server/public/public.html +7 -7
  47. package/payload/server/server.js +832 -444
  48. package/payload/server/public/assets/AdminShell-BJCYb1v5.js +0 -1
  49. package/payload/server/public/assets/OperatorConversations-CHEQTz20.js +0 -1
  50. package/payload/server/public/assets/chat-B_jYIH9a.js +0 -1
  51. package/payload/server/public/assets/data-BmSTKHR1.js +0 -1
  52. package/payload/server/public/assets/graph-labels-WQQn6JIJ.js +0 -1
  53. package/payload/server/public/assets/operator-B4I25isQ.js +0 -1
  54. package/payload/server/public/assets/page-B-6ZQ4JG.js +0 -1
  55. /package/payload/server/public/assets/{brand-MKGM8WZp.js → brand-BQ_u9UdS.js} +0 -0
@@ -11,75 +11,54 @@
11
11
  // The pid-file regex (^[0-9]+\.json$) and scope-record (\.scope\.json$) never
12
12
  // match <uuid>.reseated.json, so the three sidecars share the dir without
13
13
  // collision.
14
- import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
15
- import { join } from 'node:path';
16
- const RESEAT_FILE_RE = /\.reseated\.json$/;
14
+ //
15
+ // Task 902 the file mechanics (path, atomic write, scan, clear) live in the
16
+ // shared `sidecar-store` helper; this module owns the marker shape, the
17
+ // `[reseat-ledger]` log lines, and the chain/reconcile logic below.
18
+ import { createSidecarStore } from './sidecar-store.js';
17
19
  const RESEAT_CHAIN_MAX_DEPTH = 16;
20
+ const store = createSidecarStore({
21
+ suffix: '.reseated.json',
22
+ validate: (raw) => {
23
+ if (!raw || typeof raw !== 'object')
24
+ return null;
25
+ const r = raw;
26
+ if (typeof r.sourceSessionId === 'string' && typeof r.forkSessionId === 'string' && typeof r.at === 'number') {
27
+ return { sourceSessionId: r.sourceSessionId, forkSessionId: r.forkSessionId, at: r.at };
28
+ }
29
+ return null;
30
+ },
31
+ });
18
32
  export function reseatMarkerPath(sessionsDir, sourceSessionId) {
19
- return join(sessionsDir, `${sourceSessionId}.reseated.json`);
33
+ return store.pathFor(sessionsDir, sourceSessionId);
20
34
  }
21
35
  export function writeReseatMarker(sessionsDir, sourceSessionId, forkSessionId, at, logger) {
22
- mkdirSync(sessionsDir, { recursive: true });
23
- const path = reseatMarkerPath(sessionsDir, sourceSessionId);
24
- const tmp = `${path}.tmp.${process.pid}`;
25
- const body = JSON.stringify({ sourceSessionId, forkSessionId, at });
26
- try {
27
- writeFileSync(tmp, body, 'utf8');
28
- renameSync(tmp, path);
36
+ const res = store.write(sessionsDir, sourceSessionId, { sourceSessionId, forkSessionId, at });
37
+ if (res.ok) {
29
38
  logger(`[reseat-ledger] write source=${sourceSessionId.slice(0, 8)} fork=${forkSessionId.slice(0, 8)}`);
30
39
  }
31
- catch (err) {
32
- try {
33
- if (existsSync(tmp))
34
- unlinkSync(tmp);
35
- }
36
- catch { /* best-effort */ }
40
+ else {
41
+ const err = res.error;
37
42
  logger(`[reseat-ledger] write-failed source=${sourceSessionId.slice(0, 8)} err=${err instanceof Error ? err.message : String(err)}`);
38
43
  }
39
44
  }
40
45
  export function readReseatMarker(sessionsDir, sourceSessionId) {
41
- const path = reseatMarkerPath(sessionsDir, sourceSessionId);
42
- try {
43
- const raw = JSON.parse(readFileSync(path, 'utf8'));
44
- if (typeof raw.sourceSessionId === 'string' && typeof raw.forkSessionId === 'string' && typeof raw.at === 'number') {
45
- return { sourceSessionId: raw.sourceSessionId, forkSessionId: raw.forkSessionId, at: raw.at };
46
- }
47
- return null;
48
- }
49
- catch {
50
- return null;
51
- }
46
+ return store.read(sessionsDir, sourceSessionId);
52
47
  }
53
48
  export function readAllReseatMarkers(sessionsDir, logger) {
54
- let entries;
55
- try {
56
- entries = readdirSync(sessionsDir).filter((n) => RESEAT_FILE_RE.test(n));
57
- }
58
- catch {
59
- return [];
60
- }
61
- const out = [];
62
- for (const name of entries) {
63
- const id = name.replace(RESEAT_FILE_RE, '');
64
- const m = readReseatMarker(sessionsDir, id);
65
- if (m)
66
- out.push(m);
67
- else
68
- logger(`[reseat-ledger] skip-unreadable file=${name}`);
69
- }
70
- return out;
49
+ // A marker file that is unreadable OR fails the shape check is skipped and
50
+ // logged, matching the pre-902 readReseatMarker-returns-null behaviour.
51
+ return store.readAll(sessionsDir, (name) => logger(`[reseat-ledger] skip-unreadable file=${name}`));
71
52
  }
72
53
  export function clearReseatMarker(sessionsDir, sourceSessionId, logger) {
73
- const path = reseatMarkerPath(sessionsDir, sourceSessionId);
74
- try {
75
- if (existsSync(path)) {
76
- unlinkSync(path);
77
- logger(`[reseat-ledger] clear source=${sourceSessionId.slice(0, 8)}`);
78
- }
79
- }
80
- catch (err) {
54
+ const res = store.clear(sessionsDir, sourceSessionId);
55
+ if (!res.ok) {
56
+ const err = res.error;
81
57
  logger(`[reseat-ledger] clear-failed source=${sourceSessionId.slice(0, 8)} err=${err instanceof Error ? err.message : String(err)}`);
82
58
  }
59
+ else if (res.removed) {
60
+ logger(`[reseat-ledger] clear source=${sourceSessionId.slice(0, 8)}`);
61
+ }
83
62
  }
84
63
  /**
85
64
  * Follow source -> fork -> fork2 ... while a marker exists and the next fork's
@@ -114,6 +93,36 @@ export function resolveReseatChain(sessionsDir, sourceSessionId, jsonlExists, ma
114
93
  }
115
94
  return { target, hops, redirected, stale };
116
95
  }
96
+ /**
97
+ * The inverse of resolveReseatChain. Given a fork id whose own JSONL does not
98
+ * exist yet (claude --fork-session flushes the copied history only at the
99
+ * fork's first turn), walk the ledger back to the nearest ancestor whose JSONL
100
+ * exists, so the resolver can serve that source transcript read-only until the
101
+ * fork materialises. Returns the source id, or null when forkSessionId is not a
102
+ * recorded fork or no ancestor has a JSONL. Cycle-guarded by a visited set and
103
+ * depth-capped, mirroring resolveReseatChain.
104
+ */
105
+ export function resolveBridgeSource(sessionsDir, forkSessionId, jsonlExists, maxDepth = RESEAT_CHAIN_MAX_DEPTH) {
106
+ // Markers are keyed by source; build the fork -> source inverse once.
107
+ const sourceOf = new Map();
108
+ for (const m of readAllReseatMarkers(sessionsDir, () => { })) {
109
+ sourceOf.set(m.forkSessionId, m.sourceSessionId);
110
+ }
111
+ const visited = new Set([forkSessionId]);
112
+ let current = forkSessionId;
113
+ for (let depth = 0; depth < maxDepth; depth++) {
114
+ const source = sourceOf.get(current);
115
+ if (source === undefined)
116
+ return null; // not a recorded fork / end of chain
117
+ if (visited.has(source))
118
+ return null; // cycle guard
119
+ visited.add(source);
120
+ if (jsonlExists(source))
121
+ return source; // nearest ancestor with a JSONL
122
+ current = source;
123
+ }
124
+ return null;
125
+ }
117
126
  /**
118
127
  * Scan all markers; stop any source that is currently live and whose fork JSONL
119
128
  * still exists (the fork is the real continuation). If a marked source is live
@@ -1 +1 @@
1
- {"version":3,"file":"reseat-ledger.js","sourceRoot":"","sources":["../src/reseat-ledger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reseat-ledger.js","sourceRoot":"","sources":["../src/reseat-ledger.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scope-record.d.ts","sourceRoot":"","sources":["../src/scope-record.ts"],"names":[],"mappings":"AAiBA,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;AAEpC,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAID,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,GACb,IAAI,CAaN;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAyBtF;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAU9F"}
1
+ {"version":3,"file":"scope-record.d.ts","sourceRoot":"","sources":["../src/scope-record.ts"],"names":[],"mappings":"AAoBA,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;AAEpC,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,MAAM,CAAA;CACvB;AAeD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,GACb,IAAI,CAQN;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAMtF;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAQ9F"}
@@ -11,71 +11,53 @@
11
11
  // is the same dir boot-seed already scans for pid files; the pid-file name
12
12
  // regex (`^[0-9]+\.json$`) never matches a `<uuid>.scope.json`, so there is no
13
13
  // collision.
14
- import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
15
- import { join } from 'node:path';
16
- const SCOPE_FILE_RE = /\.scope\.json$/;
14
+ //
15
+ // Task 902 the file mechanics (path, atomic write, scan, clear) live in the
16
+ // shared `sidecar-store` helper; this module owns only the record shape and the
17
+ // `[scope-record]` log lines.
18
+ import { createSidecarStore } from './sidecar-store.js';
19
+ const store = createSidecarStore({
20
+ suffix: '.scope.json',
21
+ validate: (raw) => {
22
+ if (!raw || typeof raw !== 'object')
23
+ return null;
24
+ const sid = raw.sessionId;
25
+ const tok = raw.scopeUnitToken;
26
+ if (typeof sid === 'string' && sid.length > 0 && typeof tok === 'string' && tok.length > 0) {
27
+ return { sessionId: sid, scopeUnitToken: tok };
28
+ }
29
+ return null;
30
+ },
31
+ });
17
32
  export function scopeRecordPath(sessionsDir, sessionId) {
18
- return join(sessionsDir, `${sessionId}.scope.json`);
33
+ return store.pathFor(sessionsDir, sessionId);
19
34
  }
20
35
  export function writeScopeRecord(sessionsDir, sessionId, scopeUnitToken, logger) {
21
- mkdirSync(sessionsDir, { recursive: true });
22
- const path = scopeRecordPath(sessionsDir, sessionId);
23
- const tmp = `${path}.tmp.${process.pid}`;
24
- const body = JSON.stringify({ sessionId, scopeUnitToken });
25
- try {
26
- writeFileSync(tmp, body, 'utf8');
27
- renameSync(tmp, path);
36
+ const res = store.write(sessionsDir, sessionId, { sessionId, scopeUnitToken });
37
+ if (res.ok) {
28
38
  logger(`[scope-record] write sessionId=${sessionId.slice(0, 8)} unitToken=${scopeUnitToken}`);
29
39
  }
30
- catch (err) {
31
- try {
32
- if (existsSync(tmp))
33
- unlinkSync(tmp);
34
- }
35
- catch { /* best-effort */ }
40
+ else {
41
+ const err = res.error;
36
42
  logger(`[scope-record] write-failed sessionId=${sessionId.slice(0, 8)} err=${err instanceof Error ? err.message : String(err)}`);
37
43
  }
38
44
  }
39
45
  export function readAllScopeRecords(sessionsDir, logger) {
40
- let entries;
41
- try {
42
- entries = readdirSync(sessionsDir, { withFileTypes: true });
43
- }
44
- catch {
45
- return [];
46
- }
47
- const out = [];
48
- for (const entry of entries) {
49
- if (!entry.isFile() || !SCOPE_FILE_RE.test(entry.name))
50
- continue;
51
- let parsed;
52
- try {
53
- parsed = JSON.parse(readFileSync(join(sessionsDir, entry.name), 'utf8'));
54
- }
55
- catch {
56
- logger(`[scope-record] parse-failed file=${entry.name}`);
57
- continue;
58
- }
59
- if (!parsed || typeof parsed !== 'object')
60
- continue;
61
- const sid = parsed.sessionId;
62
- const tok = parsed.scopeUnitToken;
63
- if (typeof sid === 'string' && sid.length > 0 && typeof tok === 'string' && tok.length > 0) {
64
- out.push({ sessionId: sid, scopeUnitToken: tok });
65
- }
66
- }
67
- return out;
46
+ // Only JSON-unreadable files log; a parsed-but-wrong-shape file is skipped
47
+ // silently, matching the pre-902 inline scan.
48
+ return store.readAll(sessionsDir, (name, reason) => {
49
+ if (reason === 'unreadable')
50
+ logger(`[scope-record] parse-failed file=${name}`);
51
+ });
68
52
  }
69
53
  export function removeScopeRecord(sessionsDir, sessionId, logger) {
70
- const path = scopeRecordPath(sessionsDir, sessionId);
71
- try {
72
- if (existsSync(path)) {
73
- unlinkSync(path);
74
- logger(`[scope-record] remove sessionId=${sessionId.slice(0, 8)}`);
75
- }
76
- }
77
- catch (err) {
54
+ const res = store.clear(sessionsDir, sessionId);
55
+ if (!res.ok) {
56
+ const err = res.error;
78
57
  logger(`[scope-record] remove-failed sessionId=${sessionId.slice(0, 8)} err=${err instanceof Error ? err.message : String(err)}`);
79
58
  }
59
+ else if (res.removed) {
60
+ logger(`[scope-record] remove sessionId=${sessionId.slice(0, 8)}`);
61
+ }
80
62
  }
81
63
  //# sourceMappingURL=scope-record.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope-record.js","sourceRoot":"","sources":["../src/scope-record.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scope-record.js","sourceRoot":"","sources":["../src/scope-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /** Why `readAll` skipped a file that matched the suffix.
2
+ * `'unreadable'` — the file could not be read or did not parse as JSON.
3
+ * `'invalid'` — it parsed but failed the store's `validate`. */
4
+ export type SidecarSkipReason = 'unreadable' | 'invalid';
5
+ export type WriteResult = {
6
+ ok: true;
7
+ } | {
8
+ ok: false;
9
+ error: unknown;
10
+ };
11
+ export type ClearResult = {
12
+ ok: true;
13
+ removed: boolean;
14
+ } | {
15
+ ok: false;
16
+ error: unknown;
17
+ };
18
+ export interface SidecarStore<T> {
19
+ /** `<sessionsDir>/<id><suffix>`. */
20
+ pathFor(sessionsDir: string, id: string): string;
21
+ /** Atomic write of `record` as JSON (no indentation): create the dir, write a
22
+ * `<path>.tmp.<pid>` sibling, then rename it onto the canonical path. On
23
+ * failure the tmp file is removed best-effort and the caught error is
24
+ * returned rather than thrown — the caller owns the success/failure log. */
25
+ write(sessionsDir: string, id: string, record: T): WriteResult;
26
+ /** Read + parse + validate one record. Null when the file is absent,
27
+ * unreadable, not JSON, or fails `validate`. */
28
+ read(sessionsDir: string, id: string): T | null;
29
+ /** Every valid record in `sessionsDir`. Files not matching the suffix are
30
+ * ignored. A matching file that is unreadable/not-JSON fires
31
+ * `onSkip(name, 'unreadable')`; one that parses but fails `validate` fires
32
+ * `onSkip(name, 'invalid')`. A missing directory yields `[]`. */
33
+ readAll(sessionsDir: string, onSkip?: (fileName: string, reason: SidecarSkipReason) => void): T[];
34
+ /** `existsSync` + `unlink`. `{ ok: true, removed: false }` when the file was
35
+ * already absent; `{ ok: false, error }` when the unlink throws. */
36
+ clear(sessionsDir: string, id: string): ClearResult;
37
+ }
38
+ export declare function createSidecarStore<T>(config: {
39
+ /** Filename suffix including the dot(s), e.g. `'.scope.json'`. */
40
+ suffix: string;
41
+ /** Parse-validate one decoded JSON value into a record, or null if it does
42
+ * not match the store's shape. */
43
+ validate: (raw: unknown) => T | null;
44
+ }): SidecarStore<T>;
45
+ //# sourceMappingURL=sidecar-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar-store.d.ts","sourceRoot":"","sources":["../src/sidecar-store.ts"],"names":[],"mappings":"AAgBA;;oEAEoE;AACpE,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,SAAS,CAAA;AAExD,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AACtE,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAExF,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,oCAAoC;IACpC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IAChD;;;iFAG6E;IAC7E,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,WAAW,CAAA;IAC9D;qDACiD;IACjD,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAAA;IAC/C;;;sEAGkE;IAClE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,GAAG,CAAC,EAAE,CAAA;IACjG;yEACqE;IACrE,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAAA;CACpD;AAMD,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE;IAC5C,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAA;IACd;uCACmC;IACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC,GAAG,IAAI,CAAA;CACrC,GAAG,YAAY,CAAC,CAAC,CAAC,CA8FlB"}
@@ -0,0 +1,118 @@
1
+ // Task 902 — the one per-session sidecar store that scope-record and
2
+ // reseat-ledger both build on. Each store keeps a `<sessionsDir>/<id><suffix>`
3
+ // JSON file and shares the same mechanics: a path builder, an atomic
4
+ // tmp-write + rename (best-effort tmp cleanup on failure), a suffix-matched
5
+ // directory scan, and an `existsSync` + `unlink` clear. Before this helper the
6
+ // two stores were near-verbatim copies that had already begun to drift in how
7
+ // they scanned the directory; collapsing them puts any future fix to
8
+ // partial-write handling or tmp-file cleanup in one place.
9
+ //
10
+ // The helper does NO logging. It returns results, and each store's thin
11
+ // wrapper owns its own log lines — the two stores log with different prefixes
12
+ // and different per-record detail, so unifying the messages here would change
13
+ // operator-greppable output. The wrappers keep their exact strings.
14
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
15
+ import { join } from 'node:path';
16
+ function escapeRegExp(s) {
17
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
18
+ }
19
+ export function createSidecarStore(config) {
20
+ const { suffix, validate } = config;
21
+ const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
22
+ function pathFor(sessionsDir, id) {
23
+ return join(sessionsDir, `${id}${suffix}`);
24
+ }
25
+ function write(sessionsDir, id, record) {
26
+ mkdirSync(sessionsDir, { recursive: true });
27
+ const path = pathFor(sessionsDir, id);
28
+ const tmp = `${path}.tmp.${process.pid}`;
29
+ try {
30
+ writeFileSync(tmp, JSON.stringify(record), 'utf8');
31
+ renameSync(tmp, path);
32
+ return { ok: true };
33
+ }
34
+ catch (error) {
35
+ try {
36
+ if (existsSync(tmp))
37
+ unlinkSync(tmp);
38
+ }
39
+ catch { /* best-effort */ }
40
+ return { ok: false, error };
41
+ }
42
+ }
43
+ function readFileAt(path) {
44
+ let raw;
45
+ try {
46
+ raw = readFileSync(path, 'utf8');
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ try {
52
+ return validate(JSON.parse(raw));
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ }
58
+ function read(sessionsDir, id) {
59
+ return readFileAt(pathFor(sessionsDir, id));
60
+ }
61
+ function readAll(sessionsDir, onSkip) {
62
+ let names;
63
+ try {
64
+ // `withFileTypes` + `isFile` so a sub-directory whose name happens to
65
+ // match the suffix is ignored before any read is attempted — never read
66
+ // as a record, never reported via onSkip.
67
+ names = readdirSync(sessionsDir, { withFileTypes: true })
68
+ .filter((entry) => entry.isFile())
69
+ .map((entry) => entry.name);
70
+ }
71
+ catch {
72
+ return [];
73
+ }
74
+ const out = [];
75
+ for (const name of names) {
76
+ if (!suffixRe.test(name))
77
+ continue;
78
+ const path = join(sessionsDir, name);
79
+ let raw;
80
+ try {
81
+ raw = readFileSync(path, 'utf8');
82
+ }
83
+ catch {
84
+ onSkip?.(name, 'unreadable');
85
+ continue;
86
+ }
87
+ let parsed;
88
+ try {
89
+ parsed = JSON.parse(raw);
90
+ }
91
+ catch {
92
+ onSkip?.(name, 'unreadable');
93
+ continue;
94
+ }
95
+ const record = validate(parsed);
96
+ if (record)
97
+ out.push(record);
98
+ else
99
+ onSkip?.(name, 'invalid');
100
+ }
101
+ return out;
102
+ }
103
+ function clear(sessionsDir, id) {
104
+ const path = pathFor(sessionsDir, id);
105
+ try {
106
+ if (existsSync(path)) {
107
+ unlinkSync(path);
108
+ return { ok: true, removed: true };
109
+ }
110
+ return { ok: true, removed: false };
111
+ }
112
+ catch (error) {
113
+ return { ok: false, error };
114
+ }
115
+ }
116
+ return { pathFor, write, read, readAll, clear };
117
+ }
118
+ //# sourceMappingURL=sidecar-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sidecar-store.js","sourceRoot":"","sources":["../src/sidecar-store.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- import{o as e}from"./chunk-CAM3fms7.js";import{o as t,u as n}from"./brand-MKGM8WZp.js";import{r}from"./useSelectionMode-BHAAhkDg.js";var i=`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,audio/ogg,audio/opus,audio/mp4,audio/mpeg,audio/webm,audio/wav,.opus,.ogg,.m4a,.mp3,.wav,.webm`,a=new Set(i.split(`,`).filter(e=>!e.startsWith(`.`))),o=50*1024*1024,s=typeof window<`u`&&/^(localhost|127\.0\.0\.1|[a-z0-9-]+\.local)(:|$)/.test(window.location.hostname);function c(){let e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;let t=[...e].map(e=>e.toString(16).padStart(2,`0`)).join(``);return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}function l(){let e=window.location.pathname;if(e.startsWith(`/g/`))return;let t=e.match(/^\/([a-z][a-z0-9-]{2,49})$/);return t?t[1]:void 0}function u(){let e=window.location.pathname.match(/^\/g\/([a-z0-9][a-z0-9-]{0,49})$/);return e?e[1]:void 0}var d=e(n(),1);function f(){let[e,t]=(0,d.useState)(null),[n,r]=(0,d.useState)(null),[i,a]=(0,d.useState)(`loading`),[o,f]=(0,d.useState)(``),[p,m]=(0,d.useState)(null),[h,g]=(0,d.useState)(null),[_,v]=(0,d.useState)(!1),[y,b]=(0,d.useState)(null),x=(0,d.useMemo)(()=>l(),[]),S=(0,d.useMemo)(()=>u(),[]),[C,w]=(0,d.useState)(null),T=(0,d.useRef)(x||``),E=(0,d.useRef)(null),D=(0,d.useRef)(null),O=(0,d.useRef)(!1),k=(0,d.useRef)(null),[A,j]=(0,d.useState)(`request-link`),[M,N]=(0,d.useState)(null),P=(0,d.useRef)(null),F=(0,d.useRef)(null);(0,d.useEffect)(()=>{try{let e=sessionStorage.getItem(`maxy_session`);e&&(F.current=e)}catch{}},[]);let I=(0,d.useCallback)(e=>{E.current=e,t(e);try{sessionStorage.setItem(`maxy_session`,e)}catch{}a(`chat`)},[]),L=(0,d.useCallback)(()=>{E.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}t(null),a(`auth-required`),j(`request-link`)},[]),R=(0,d.useCallback)(async e=>{j(`verifying`);try{let t=T.current,n=await fetch(`/api/access/verify-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:e,agentSlug:t})});if(window.history.replaceState({},``,window.location.pathname),n.ok){let e=await n.json().catch(()=>({}));return e?.displayName&&N({displayName:e.displayName,contactValue:``,expiresAt:null,status:`active`}),!0}return j(`verify-failed`),!1}catch{return j(`verify-failed`),!1}},[]),z=(0,d.useCallback)(async()=>{if(E.current)return E.current;if(D.current)return D.current;let e=(async()=>{try{let e=F.current,n=await fetch(`/api/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_id:c(),...x?{agent:x}:{},...S?{group_slug:S}:{},...e?{session_key:e}:{}})});if(!n.ok){let e=await n.json().catch(()=>({error:``}));return s&&console.error(`[session] POST /api/session failed: ${n.status} ${n.statusText}`,e),n.status===404?r(e.error||`Agent not found`):n.status===503&&r(e.error||`Service unavailable`),null}let i=await n.json();if(i.auth_required){i.agent_id&&(T.current=i.agent_id),f(i.displayName||``),i.agentImage&&m(i.agentImage),i.agentImageShape&&g(i.agentImageShape),i.showAgentName&&v(i.showAgentName),i.branding&&b(i.branding),a(`auth-required`);let e=new URLSearchParams(window.location.search).get(`token`);return e?await R(e)&&window.location.reload():j(`request-link`),null}E.current=i.session_key,t(i.session_key),i.displayName&&f(i.displayName),i.agentImage&&m(i.agentImage),i.agentImageShape&&g(i.agentImageShape),i.showAgentName&&v(i.showAgentName),i.branding&&b(i.branding),a(`chat`),i.resumed&&i.messages&&(O.current=!0,k.current=i.messages),i.group&&w({groupSlug:i.groupSlug,groupName:i.groupName,participants:i.participants??[]});try{sessionStorage.setItem(`maxy_session`,i.session_key)}catch{}return i.session_key}catch(e){return s&&console.error(`[session] fetch /api/session threw:`,e),r(`Unable to connect. Please check your connection and try again.`),null}finally{D.current=null}})();return D.current=e,e},[x,S,R]);return{sessionId:e,cacheKeyRef:E,sessionError:n,pageState:i,setPageState:a,agentDisplayName:o,agentImage:p,agentImageShape:h,showAgentName:_,agentSlug:x,branding:y,resolvedSlugRef:T,ensureSession:z,startNewSession:(0,d.useCallback)(async()=>{E.current=null,D.current=null,F.current=null,O.current=!1,k.current=null,t(null),r(null);try{sessionStorage.removeItem(`maxy_session`)}catch{}await z()},[z]),enterChat:I,enterGate:L,resumedRef:O,resumeMessagesRef:k,gateState:A,setGateState:j,grantInfo:M,setGrantInfo:N,gateCacheKeyRef:P,groupContext:C,groupSlug:S}}var p=t();function m({gateState:e,setGateState:t,grantInfo:n,resolvedSlugRef:i}){let[a,o]=(0,d.useState)(``),[s,c]=(0,d.useState)(!1),[l,u]=(0,d.useState)(null);async function f(e){e.preventDefault();let n=a.trim().toLowerCase();if(!n){u(`Enter the email you were invited on.`);return}c(!0),u(null);try{let e=await fetch(`/api/access/request-magic-link`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contactValue:n,agentSlug:i.current})});if(e.status===429){u((await e.json().catch(()=>({})))?.error||`Too many requests. Try again later.`);return}t(`request-sent`)}catch{u(`Could not reach the server. Check your connection and try again.`)}finally{c(!1)}}return(0,p.jsxs)(`div`,{className:`access-gate`,children:[e===`verifying`&&(0,p.jsxs)(`div`,{className:`access-gate-message`,children:[(0,p.jsx)(`h2`,{children:`Verifying your link…`}),(0,p.jsx)(`p`,{children:`This takes a moment.`})]}),e===`verify-failed`&&(0,p.jsxs)(`div`,{className:`access-gate-message`,children:[(0,p.jsx)(`h2`,{children:`That link did not work`}),(0,p.jsx)(`p`,{children:`It may have expired, already been used, or been for a different agent. You can request a fresh one below.`}),(0,p.jsx)(r,{onClick:()=>{t(`request-link`),u(null)},children:`Request a new link`})]}),e===`request-link`&&(0,p.jsxs)(`form`,{className:`access-gate-form`,onSubmit:f,children:[(0,p.jsx)(`h2`,{children:n?.displayName?`Welcome back, ${n.displayName}`:`Sign in`}),(0,p.jsx)(`p`,{children:`Enter the email you were invited on and we will send you a fresh link.`}),(0,p.jsx)(`label`,{htmlFor:`access-email`,children:`Email`}),(0,p.jsx)(`input`,{id:`access-email`,type:`email`,inputMode:`email`,autoComplete:`email`,value:a,onChange:e=>o(e.target.value),disabled:s}),l&&(0,p.jsx)(`p`,{className:`access-gate-error`,children:l}),(0,p.jsx)(r,{type:`submit`,disabled:s||!a.trim(),children:s?`Sending…`:`Send me a link`})]}),e===`request-sent`&&(0,p.jsxs)(`div`,{className:`access-gate-message`,children:[(0,p.jsx)(`h2`,{children:`Check your email`}),(0,p.jsx)(`p`,{children:`If that address is on the invite list, a fresh link is on the way. It expires in 15 minutes.`}),(0,p.jsx)(r,{onClick:()=>{t(`request-link`),o(``),u(null)},children:`Try a different email`})]})]})}export{a,o as i,f as n,s as o,i as r,m as t};
1
+ import{o as e}from"./chunk-CAM3fms7.js";import{o as t,u as n}from"./brand-BQ_u9UdS.js";import{r}from"./useSelectionMode-Bf6Rt-sl.js";var i=`image/jpeg,image/png,image/gif,image/webp,application/pdf,text/plain,text/markdown,text/csv,text/html,text/calendar,audio/ogg,audio/opus,audio/mp4,audio/mpeg,audio/webm,audio/wav,.opus,.ogg,.m4a,.mp3,.wav,.webm`,a=new Set(i.split(`,`).filter(e=>!e.startsWith(`.`))),o=50*1024*1024,s=typeof window<`u`&&/^(localhost|127\.0\.0\.1|[a-z0-9-]+\.local)(:|$)/.test(window.location.hostname);function c(){let e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;let t=[...e].map(e=>e.toString(16).padStart(2,`0`)).join(``);return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}function l(){let e=window.location.pathname;if(e.startsWith(`/g/`))return;let t=e.match(/^\/([a-z][a-z0-9-]{2,49})$/);return t?t[1]:void 0}function u(){let e=window.location.pathname.match(/^\/g\/([a-z0-9][a-z0-9-]{0,49})$/);return e?e[1]:void 0}var d=e(n(),1);function f(){let[e,t]=(0,d.useState)(null),[n,r]=(0,d.useState)(null),[i,a]=(0,d.useState)(`loading`),[o,f]=(0,d.useState)(``),[p,m]=(0,d.useState)(null),[h,g]=(0,d.useState)(null),[_,v]=(0,d.useState)(!1),[y,b]=(0,d.useState)(null),x=(0,d.useMemo)(()=>l(),[]),S=(0,d.useMemo)(()=>u(),[]),[C,w]=(0,d.useState)(null),T=(0,d.useRef)(x||``),E=(0,d.useRef)(null),D=(0,d.useRef)(null),O=(0,d.useRef)(!1),k=(0,d.useRef)(null),[A,j]=(0,d.useState)(`request-link`),[M,N]=(0,d.useState)(null),P=(0,d.useRef)(null),F=(0,d.useRef)(null);(0,d.useEffect)(()=>{try{let e=sessionStorage.getItem(`maxy_session`);e&&(F.current=e)}catch{}},[]);let I=(0,d.useCallback)(e=>{E.current=e,t(e);try{sessionStorage.setItem(`maxy_session`,e)}catch{}a(`chat`)},[]),L=(0,d.useCallback)(()=>{E.current=null;try{sessionStorage.removeItem(`maxy_session`)}catch{}t(null),a(`auth-required`),j(`request-link`)},[]),R=(0,d.useCallback)(async e=>{j(`verifying`);try{let t=T.current,n=await fetch(`/api/access/verify-token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({token:e,agentSlug:t})});if(window.history.replaceState({},``,window.location.pathname),n.ok){let e=await n.json().catch(()=>({}));return e?.displayName&&N({displayName:e.displayName,contactValue:``,expiresAt:null,status:`active`}),!0}return j(`verify-failed`),!1}catch{return j(`verify-failed`),!1}},[]),z=(0,d.useCallback)(async()=>{if(E.current)return E.current;if(D.current)return D.current;let e=(async()=>{try{let e=F.current,n=await fetch(`/api/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({session_id:c(),...x?{agent:x}:{},...S?{group_slug:S}:{},...e?{session_key:e}:{}})});if(!n.ok){let e=await n.json().catch(()=>({error:``}));return s&&console.error(`[session] POST /api/session failed: ${n.status} ${n.statusText}`,e),n.status===404?r(e.error||`Agent not found`):n.status===503&&r(e.error||`Service unavailable`),null}let i=await n.json();if(i.auth_required){i.agent_id&&(T.current=i.agent_id),f(i.displayName||``),i.agentImage&&m(i.agentImage),i.agentImageShape&&g(i.agentImageShape),i.showAgentName&&v(i.showAgentName),i.branding&&b(i.branding),a(`auth-required`);let e=new URLSearchParams(window.location.search).get(`token`);return e?await R(e)&&window.location.reload():j(`request-link`),null}E.current=i.session_key,t(i.session_key),i.displayName&&f(i.displayName),i.agentImage&&m(i.agentImage),i.agentImageShape&&g(i.agentImageShape),i.showAgentName&&v(i.showAgentName),i.branding&&b(i.branding),a(`chat`),i.resumed&&i.messages&&(O.current=!0,k.current=i.messages),i.group&&w({groupSlug:i.groupSlug,groupName:i.groupName,participants:i.participants??[]});try{sessionStorage.setItem(`maxy_session`,i.session_key)}catch{}return i.session_key}catch(e){return s&&console.error(`[session] fetch /api/session threw:`,e),r(`Unable to connect. Please check your connection and try again.`),null}finally{D.current=null}})();return D.current=e,e},[x,S,R]);return{sessionId:e,cacheKeyRef:E,sessionError:n,pageState:i,setPageState:a,agentDisplayName:o,agentImage:p,agentImageShape:h,showAgentName:_,agentSlug:x,branding:y,resolvedSlugRef:T,ensureSession:z,startNewSession:(0,d.useCallback)(async()=>{E.current=null,D.current=null,F.current=null,O.current=!1,k.current=null,t(null),r(null);try{sessionStorage.removeItem(`maxy_session`)}catch{}await z()},[z]),enterChat:I,enterGate:L,resumedRef:O,resumeMessagesRef:k,gateState:A,setGateState:j,grantInfo:M,setGrantInfo:N,gateCacheKeyRef:P,groupContext:C,groupSlug:S}}var p=t();function m({gateState:e,setGateState:t,grantInfo:n,resolvedSlugRef:i}){let[a,o]=(0,d.useState)(``),[s,c]=(0,d.useState)(!1),[l,u]=(0,d.useState)(null);async function f(e){e.preventDefault();let n=a.trim().toLowerCase();if(!n){u(`Enter the email you were invited on.`);return}c(!0),u(null);try{let e=await fetch(`/api/access/request-magic-link`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({contactValue:n,agentSlug:i.current})});if(e.status===429){u((await e.json().catch(()=>({})))?.error||`Too many requests. Try again later.`);return}t(`request-sent`)}catch{u(`Could not reach the server. Check your connection and try again.`)}finally{c(!1)}}return(0,p.jsxs)(`div`,{className:`access-gate`,children:[e===`verifying`&&(0,p.jsxs)(`div`,{className:`access-gate-message`,children:[(0,p.jsx)(`h2`,{children:`Verifying your link…`}),(0,p.jsx)(`p`,{children:`This takes a moment.`})]}),e===`verify-failed`&&(0,p.jsxs)(`div`,{className:`access-gate-message`,children:[(0,p.jsx)(`h2`,{children:`That link did not work`}),(0,p.jsx)(`p`,{children:`It may have expired, already been used, or been for a different agent. You can request a fresh one below.`}),(0,p.jsx)(r,{onClick:()=>{t(`request-link`),u(null)},children:`Request a new link`})]}),e===`request-link`&&(0,p.jsxs)(`form`,{className:`access-gate-form`,onSubmit:f,children:[(0,p.jsx)(`h2`,{children:n?.displayName?`Welcome back, ${n.displayName}`:`Sign in`}),(0,p.jsx)(`p`,{children:`Enter the email you were invited on and we will send you a fresh link.`}),(0,p.jsx)(`label`,{htmlFor:`access-email`,children:`Email`}),(0,p.jsx)(`input`,{id:`access-email`,type:`email`,inputMode:`email`,autoComplete:`email`,value:a,onChange:e=>o(e.target.value),disabled:s}),l&&(0,p.jsx)(`p`,{className:`access-gate-error`,children:l}),(0,p.jsx)(r,{type:`submit`,disabled:s||!a.trim(),children:s?`Sending…`:`Send me a link`})]}),e===`request-sent`&&(0,p.jsxs)(`div`,{className:`access-gate-message`,children:[(0,p.jsx)(`h2`,{children:`Check your email`}),(0,p.jsx)(`p`,{children:`If that address is on the invite list, a fresh link is on the way. It expires in 15 minutes.`}),(0,p.jsx)(r,{onClick:()=>{t(`request-link`),o(``),u(null)},children:`Try a different email`})]})]})}export{a,o as i,f as n,s as o,i as r,m as t};
@@ -1 +1 @@
1
- import{o as e}from"./chunk-CAM3fms7.js";import{a as t,o as n,t as r,u as i}from"./brand-MKGM8WZp.js";import{C as a,_ as o}from"./OperatorConversations-CHEQTz20.js";import{i as s}from"./admin-types-D2qTXuCg.js";import{s as c}from"./AdminShell-BJCYb1v5.js";import{r as l}from"./useSelectionMode-BHAAhkDg.js";import{t as u}from"./Checkbox-CQGLKMXu.js";var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(i(),1);function h(e=`admin`){let[t,n]=(0,m.useState)(`loading`),[r,i]=(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 r=await t.json();D(r.session_key),R(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=s(r.thinkingView);return G.current=i,W(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}if(!a.claude_authenticated){n(`connect-claude`);return}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`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`){n(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){a(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&n(`enter-pin`)}).catch(()=>{})},[t]);async function Z(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){h((await r.json().catch(()=>({}))).error||`Invalid PIN`);return}let a=await r.json();if(a.accounts&&!a.session_key){console.log(`[admin] account picker shown: userId=${a.userId} accountCount=${a.accounts.length}`),B(a.accounts),n(`account-picker`);return}D(a.session_key),R(a.sessionId??null),j(a.businessName),N(a.role??null),F(a.userName===void 0?null:a.userName),L(a.avatar??null);let o=s(a.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,a.session_key)}catch{}i(``),n(`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(r.length<4){h(`PIN must be at least 4 characters.`);return}let a=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:a,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 r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await Z(a);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,o]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(r)},[r]),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 n(`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{}i(``),h(``),n(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:i,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(r,e)},[r]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!r){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:r})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}i(``),h(``),n(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[r])}}var g=n();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:n,setPin:i,showPin:a,setShowPin:o,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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,r.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,r.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:n,onChange:i,onComplete:()=>{},showPin:a}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!n||!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:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function y(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.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:n,onChange:i,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!n,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:a,onChange:()=>o(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:n,loading:i,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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:n.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:i,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}),i&&(0,g.jsx)(o,{className:`account-picker-spinner`,size:16})]},e.accountId))}),a&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:a})]})})}function x(e){let{authPolling:n,setAuthPolling:i,authLoading:a,setAuthLoading:o,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(){o(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){i(!0),f(!0),o(!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.`),i(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),i(!1),c(``)}return n||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:[n?(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:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:a,children:a?(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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:r.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,r.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:a,children:a?(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};
1
+ import{o as e}from"./chunk-CAM3fms7.js";import{a as t,o as n,t as r,u as i}from"./brand-BQ_u9UdS.js";import{v as a,w as o}from"./OperatorConversations-hm0Gpu_Q.js";import{i as s}from"./admin-types-D2qTXuCg.js";import{s as c}from"./AdminShell-Cu1zlb6L.js";import{r as l}from"./useSelectionMode-Bf6Rt-sl.js";import{t as u}from"./Checkbox-B_sOAyv1.js";var d=`admin-landing-redirected`,f=`/graph`;function p(e){return e.variant===`operator`?!1:e.appState===`chat`&&!e.alreadyRedirected}var m=e(i(),1);function h(e=`admin`){let[t,n]=(0,m.useState)(`loading`),[r,i]=(0,m.useState)(``),[a,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 r=await t.json();D(r.session_key),R(r.sessionId??null),j(r.businessName),N(r.role??null),F(r.userName===void 0?null:r.userName),L(r.avatar??null);let i=s(r.thinkingView);return G.current=i,W(i),n(`chat`),!0}catch(e){return console.error(`[admin] session restore failed:`,e),!1}}async function t(r=2){try{let i=await fetch(`/api/health`);if(!i.ok){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check returned ${i.status} after retries`),n(`set-pin`);return}let a=await i.json();if(!a.pin_configured){n(`set-pin`);return}if(!a.claude_authenticated){n(`connect-claude`);return}if(await e())return;n(`enter-pin`)}catch(e){if(r>0)return await new Promise(e=>setTimeout(e,1500)),t(r-1);console.error(`[admin] health check failed:`,e),n(`set-pin`)}}t()},[]),(0,m.useEffect)(()=>{t===`chat`&&fetch(`/api/admin/claude-info`).then(e=>{if(e.ok)return e.json()}).then(e=>{e&&k(e)}).catch(()=>{})},[t]),(0,m.useEffect)(()=>{if(typeof window>`u`)return;let n=!1;try{n=sessionStorage.getItem(d)===`1`}catch{}if(p({appState:t,alreadyRedirected:n,variant:e})){try{sessionStorage.setItem(d,`1`)}catch{}console.info(`[admin-ui] landing-redirect target=${f}`),window.location.replace(f)}},[t,e]);let X=(0,m.useRef)(null);(0,m.useEffect)(()=>{if(t!==`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`){n(`connect-claude`);return}}}catch{}if(E)try{let e=await fetch(`/api/admin/session?session_key=${encodeURIComponent(E)}`);if(e.status!==401)return;let t=(await e.clone().json().catch(()=>null))?.code??`unknown-401`;if(t===`remote-auth-required`){o(`heartbeat`,`/api/admin/session`);return}console.warn(`[admin-auth] outcome=heartbeat-detected-expiry code=${t}`),X.current?.()}catch{}},300*1e3);return()=>clearInterval(e)},[t,E]),(0,m.useEffect)(()=>{t===`connect-claude`&&fetch(`/api/health`).then(e=>e.ok?e.json():null).then(e=>{e?.claude_authenticated&&n(`enter-pin`)}).catch(()=>{})},[t]);async function Z(e,t){y(!0);try{let r=await fetch(`/api/admin/session`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:e,...t?{accountId:t}:{}})});if(!r.ok){h((await r.json().catch(()=>({}))).error||`Invalid PIN`);return}let a=await r.json();if(a.accounts&&!a.session_key){console.log(`[admin] account picker shown: userId=${a.userId} accountCount=${a.accounts.length}`),B(a.accounts),n(`account-picker`);return}D(a.session_key),R(a.sessionId??null),j(a.businessName),N(a.role??null),F(a.userName===void 0?null:a.userName),L(a.avatar??null);let o=s(a.thinkingView);if(G.current=o,W(o),t)try{sessionStorage.setItem(`maxy-account-id`,t)}catch{}try{sessionStorage.setItem(`maxy-admin-session-key`,a.session_key)}catch{}i(``),n(`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=a.trim();if(!t){h(`Please enter your name.`);return}if(r.length<4){h(`PIN must be at least 4 characters.`);return}let o=r;y(!0);try{let e=await fetch(`/api/onboarding/set-pin`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({pin:o,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 r=await e.json();r.pin_configured&&r.claude_authenticated?n(`enter-pin`):r.pin_configured?n(`connect-claude`):h(t.error||`Failed to set PIN.`)}else n(`enter-pin`)}catch{n(`enter-pin`)}return}h(t.error||`Failed to set PIN.`);return}let r=await fetch(`/api/health`);if((r.ok?await r.json():null)?.claude_authenticated){await Z(o);return}i(``),n(`connect-claude`)}catch(e){console.error(`[admin] connection error:`,e),h(`Could not connect.`)}finally{y(!1)}},[r,v,a]),te=(0,m.useCallback)(async e=>{e.preventDefault(),h(``),await Z(r)},[r]),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 n(`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{}i(``),h(``),n(`enter-pin`)},[]);return(0,m.useEffect)(()=>{X.current=$},[$]),{appState:t,setAppState:n,pin:r,setPin:i,operatorName:a,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(r,e)},[r]),handleDisconnect:ne,handleLogout:$,handleChangePin:(0,m.useCallback)(async()=>{if(!r){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:r})});if(!e.ok){h((await e.json().catch(()=>({error:`Incorrect PIN.`}))).error||`Incorrect PIN.`);return}i(``),h(``),n(`set-pin`)}catch(e){console.error(`[admin-auth] change pin failed:`,e),h(e instanceof Error?e.message:String(e))}finally{y(!1)}},[r])}}var g=n();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:n,setPin:i,showPin:a,setShowPin:o,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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Welcome to `,r.productName]}),(0,g.jsxs)(`p`,{className:`connect-subtitle`,children:[`Tell `,r.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:n,onChange:i,onComplete:()=>{},showPin:a}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!n||!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:a,onChange:()=>o(e=>!e),label:`Show PIN`})]}),c&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:c})]})})}function y(e){let{pin:n,setPin:i,showPin:a,setShowPin:o,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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.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:n,onChange:i,onComplete:()=>{},showPin:a,autoFocus:!0}),(0,g.jsx)(l,{variant:`send`,type:`submit`,disabled:!n,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:a,onChange:()=>o(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:n,loading:i,error:o,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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`h1`,{className:`connect-title`,children:r.productName}),(0,g.jsx)(`p`,{className:`connect-subtitle`,children:`Select an account`}),(0,g.jsx)(`div`,{className:`account-picker-list`,children:n.map(e=>(0,g.jsxs)(`button`,{className:`account-picker-card`,onClick:()=>s(e.accountId),disabled:i,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}),i&&(0,g.jsx)(a,{className:`account-picker-spinner`,size:16})]},e.accountId))}),o&&(0,g.jsx)(`p`,{className:`admin-pin-error`,children:o})]})})}function x(e){let{authPolling:n,setAuthPolling:i,authLoading:a,setAuthLoading:o,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(){o(!0),c(``);try{let e=await(await fetch(`/api/onboarding/claude-auth`,{method:`POST`})).json();if(e.started){i(!0),f(!0),o(!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.`),i(!1)}else e.error&&c(e.error)}catch(e){console.error(`[admin] auth flow error:`,e),c(`Could not start auth flow.`)}o(!1)}async function y(){await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`stop`})}),i(!1),c(``)}return n||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:[n?(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:n?`Sign in and authorize in the browser below.`:`Open your email or prepare your accounts, then sign in.`}),!n&&(0,g.jsx)(`div`,{style:{marginTop:`12px`},children:(0,g.jsx)(l,{variant:`primary`,onClick:v,disabled:a,children:a?(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:t,alt:r.productName,className:`connect-logo connect-logo--maxy`}),!r.logoContainsName&&(0,g.jsx)(`span`,{className:`connect-logo-label`,children:r.productName})]})]}),(0,g.jsxs)(`h1`,{className:`connect-title`,children:[`Connect Claude to power `,r.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:a,children:a?(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};