spexcode 0.5.5 → 0.5.6

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 (24) hide show
  1. package/package.json +1 -1
  2. package/spec-cli/src/git.ts +80 -40
  3. package/spec-cli/src/index.ts +7 -2
  4. package/spec-cli/src/reviewSnapshot.ts +4 -0
  5. package/spec-cli/src/reviews.ts +10 -5
  6. package/spec-dashboard/dist/assets/{App-C5vbTw8Q.js → App-B72LuS5I.js} +2 -2
  7. package/spec-dashboard/dist/assets/Dashboard-C5X4Va3V.js +27 -0
  8. package/spec-dashboard/dist/assets/{EvalsPage-BS7ITcNo.js → EvalsPage-BTvJIW8Q.js} +2 -2
  9. package/spec-dashboard/dist/assets/IssuesPage-Bn94h_HQ.js +1 -0
  10. package/spec-dashboard/dist/assets/{MobileApp-DVLnk9hz.js → MobileApp-ClbtwZ1e.js} +2 -2
  11. package/spec-dashboard/dist/assets/{Modal-6mHq6fbZ.js → Modal-6l_QtCKF.js} +1 -1
  12. package/spec-dashboard/dist/assets/{PageScroll-CAY4S4g4.js → PageScroll-B2kxcqJJ.js} +1 -1
  13. package/spec-dashboard/dist/assets/{ProjectsPage-UQyzsTWN.js → ProjectsPage-C8IPsMKV.js} +1 -1
  14. package/spec-dashboard/dist/assets/{SessionInterface-DKU4c1Z-.js → SessionInterface-B5jf7dW7.js} +11 -11
  15. package/spec-dashboard/dist/assets/SessionWindow-Dag_GiJB.js +1 -0
  16. package/spec-dashboard/dist/assets/{Settings-igR17pns.js → Settings-J3aibcXo.js} +1 -1
  17. package/spec-dashboard/dist/assets/{Thread-B-ZUarN1.js → Thread-Dg35J-Pu.js} +3 -3
  18. package/spec-dashboard/dist/assets/{TimelineChat-sc49Qj5d.js → TimelineChat-f0UF9fXq.js} +1 -1
  19. package/spec-dashboard/dist/assets/{data-B1ot4PF0.js → data-SNi0AmVT.js} +1 -1
  20. package/spec-dashboard/dist/assets/{index-BqBNCa1V.js → index-BUKLPN_4.js} +10 -10
  21. package/spec-dashboard/dist/index.html +1 -1
  22. package/spec-dashboard/dist/assets/Dashboard-u8RIS3NY.js +0 -27
  23. package/spec-dashboard/dist/assets/IssuesPage-DXbqQFW_.js +0 -1
  24. package/spec-dashboard/dist/assets/SessionWindow-zGwJaGbR.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spexcode",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "type": "module",
5
5
  "description": "SpexCode — a spec-driven, self-developing dev tool. The `spex` CLI + spec server reads the .spec tree and its git history, and serves the dashboard.",
6
6
  "license": "MIT",
@@ -360,9 +360,36 @@ type EventStreamRequest = {
360
360
  }
361
361
 
362
362
  type EventPathMemo = EventCacheLocation & {
363
- common: string; shallowPath: string; grafts: string; shallow: string; replacements: string
363
+ common: string; shallowPath: string; grafts: string; shallow: string
364
+ replacementStorage: string; replacements: string
364
365
  }
365
366
  const eventPathMemo = new Map<string, EventPathMemo>()
367
+ function replacementStorageIdentity(common: string): string {
368
+ const hash = createHash('sha256')
369
+ const addTree = (root: string, rel: string) => {
370
+ if (!existsSync(root)) return
371
+ const stack = [{ dir: root, rel }]
372
+ while (stack.length) {
373
+ const current = stack.pop()!
374
+ const entries = readdirSync(current.dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))
375
+ for (const entry of entries) {
376
+ const path = join(current.dir, entry.name)
377
+ const name = `${current.rel}/${entry.name}`
378
+ if (entry.isDirectory()) stack.push({ dir: path, rel: name })
379
+ else hash.update(`\0${name}\0`).update(readFileSync(path))
380
+ }
381
+ }
382
+ }
383
+ addTree(join(common, 'refs', 'replace'), 'refs/replace')
384
+ for (const name of ['packed-refs']) {
385
+ const path = join(common, name)
386
+ if (existsSync(path)) hash.update(`\0${name}\0`).update(readFileSync(path))
387
+ }
388
+ // Reftable is opaque here by design: its bytes are only an invalidation signal. Git remains the one
389
+ // parser and supplies the canonical refs/replace targets when those bytes change.
390
+ addTree(join(common, 'reftable'), 'reftable')
391
+ return hash.digest('hex')
392
+ }
366
393
  function eventCacheLocation(root: string): EventCacheLocation {
367
394
  const rootId = rootKey(root), old = eventPathMemo.get(rootId)
368
395
  const common = old?.common ?? git(['-C', root, 'rev-parse', '--path-format=absolute', '--git-common-dir']).trim()
@@ -370,7 +397,10 @@ function eventCacheLocation(root: string): EventCacheLocation {
370
397
  const shallow = existsSync(shallowPath) ? readFileSync(shallowPath, 'utf8') : 'unshallow'
371
398
  const graftsPath = join(common, 'info', 'grafts')
372
399
  const grafts = existsSync(graftsPath) ? readFileSync(graftsPath, 'utf8') : ''
373
- const replacements = git(['-C', root, 'for-each-ref', 'refs/replace', '--format=%(refname) %(objectname)'])
400
+ const replacementStorage = replacementStorageIdentity(common)
401
+ const replacements = old?.replacementStorage === replacementStorage
402
+ ? old.replacements
403
+ : git(['-C', root, 'for-each-ref', 'refs/replace', '--format=%(refname) %(objectname)'])
374
404
  const objectFormat = gitObjectFormat(root)
375
405
  if (old && old.shallow === shallow && old.grafts === grafts && old.replacements === replacements && old.objectFormat === objectFormat)
376
406
  return { path: old.path, identity: old.identity, objectFormat }
@@ -382,7 +412,7 @@ function eventCacheLocation(root: string): EventCacheLocation {
382
412
  const gitDir = gitDirOf(root)
383
413
  const storeIdentity = gitDir === root && common === root ? join(common, '.git') : common
384
414
  const path = join(projectRuntimeRoot(storeIdentity), `${EVENT_CACHE_SCHEMA}-${identity}.ndjson`)
385
- eventPathMemo.set(rootId, { common, shallowPath, grafts, shallow, replacements, path, identity, objectFormat })
415
+ eventPathMemo.set(rootId, { common, shallowPath, grafts, shallow, replacementStorage, replacements, path, identity, objectFormat })
386
416
  return { path, identity, objectFormat }
387
417
  }
388
418
  function emptyEventCache(): EventCache {
@@ -1002,38 +1032,45 @@ function canonicalPathProjector(
1002
1032
  }
1003
1033
 
1004
1034
  type SharedIndexInputs = {
1005
- allPathsOut: string
1006
- topologyOut: string
1035
+ allPaths: Set<string>
1036
+ specPaths: Set<string>
1037
+ topology: TopologyProjection
1007
1038
  historyOut: string
1008
1039
  driftOut: string
1009
1040
  mergeIndex: MergeHistoryEvents
1010
1041
  }
1011
1042
 
1043
+ type TopologyProjection = {
1044
+ order: Map<string, number>
1045
+ parents: Map<string, string[]>
1046
+ reachable: Set<string>
1047
+ }
1048
+
1012
1049
  async function buildIndex(root: string, tip: string, transient: boolean, useCache = true, shared?: SharedIndexInputs): Promise<HistoryIndex> {
1013
1050
  const versions = new Map<string, Version[]>()
1014
1051
  const stats = new Map<string, Map<string, DiffStat>>()
1015
1052
  const mergeVersions = new Set<string>()
1016
1053
  const commitVersions = new Map<string, Version>()
1017
1054
  const commitOrder = new Map<string, number>()
1018
- const [tipPathsOut, topologyOut] = shared
1019
- ? [shared.allPathsOut, shared.topologyOut]
1020
- : await Promise.all([
1055
+ const rawVersions = new Map<string, Version[]>()
1056
+ const rawStats = new Map<string, Map<string, DiffStat>>()
1057
+ let currentPaths: Set<string>
1058
+ let topology: TopologyProjection
1059
+ if (shared) {
1060
+ currentPaths = shared.specPaths
1061
+ topology = shared.topology
1062
+ } else {
1063
+ const [tipPathsOut, topologyOut] = await Promise.all([
1021
1064
  strictEventGit(['-C', root, '-c', 'core.quotePath=false', 'ls-tree', '-r', '-z', '--name-only', tip, '--', '.spec']),
1022
1065
  strictEventGit(['-C', root, 'rev-list', '--parents', tip]),
1023
1066
  ])
1024
- const rawVersions = new Map<string, Version[]>()
1025
- const rawStats = new Map<string, Map<string, DiffStat>>()
1026
- const currentPaths = new Set(tipPathsOut.split('\0').filter((path) => path.startsWith('.spec/')))
1027
- const renamesByFrom = new Map<string, { hash: string; to: string }[]>()
1028
- const topologyOrd = new Map<string, number>(), topologyParents = new Map<string, string[]>()
1029
- let topologyPosition = 0
1030
- for (const line of topologyOut.trim().split('\n')) {
1031
- if (!line) continue
1032
- const [hash, ...parents] = line.split(' ')
1033
- topologyOrd.set(hash, topologyPosition++)
1034
- topologyParents.set(hash, parents)
1067
+ currentPaths = new Set(tipPathsOut.split('\0').filter((path) => path.startsWith('.spec/')))
1068
+ topology = topologyProjection(topologyOut)
1035
1069
  }
1036
- const topologyReachable = new Set(topologyOrd.keys())
1070
+ const renamesByFrom = new Map<string, { hash: string; to: string }[]>()
1071
+ const topologyOrd = topology.order
1072
+ const topologyParents = topology.parents
1073
+ const topologyReachable = topology.reachable
1037
1074
  const out = shared?.historyOut ?? await eventStream(root, tip,
1038
1075
  indexEventRequests(root, tip, topologyOrd, topologyReachable).numstat, !transient, useCache)
1039
1076
  if (!out) return { versions, stats, mergeVersions }
@@ -1363,23 +1400,22 @@ async function buildDriftIndex(root: string, tip: string, transient: boolean, us
1363
1400
  const acks = new Map<string, Set<string>>(), selfAcks = new Map<string, Set<string>>(), specNodes = new Map<string, Set<string>>()
1364
1401
  const ackCandidates = new Map<string, Set<string>>(), trees = new Map<string, string>()
1365
1402
  const idx: DriftIndex = { tip, ord, parents, fileEvents, lineageEvents, lineageKeys: (path) => [path], resolutionEvents: new Map(), acks, selfAcks, specNodes, anc: new Map() }
1366
- const [tipPathsOut, topology] = shared
1367
- ? [shared.allPathsOut, shared.topologyOut]
1368
- : await Promise.all([
1369
- strictEventGit(['-C', root, '-c', 'core.quotePath=false', 'ls-tree', '-r', '-z', '--name-only', tip]),
1403
+ let currentPaths: Set<string>
1404
+ let topology: TopologyProjection
1405
+ if (shared) {
1406
+ currentPaths = shared.allPaths
1407
+ topology = shared.topology
1408
+ } else {
1409
+ const [tipPathsOut, topologyOut] = await Promise.all([
1410
+ strictEventGit(['-C', root, 'ls-tree', '-r', '-z', '--name-only', tip]),
1370
1411
  strictEventGit(['-C', root, 'rev-list', '--parents', tip]),
1371
1412
  ])
1372
- const currentPaths = new Set(tipPathsOut.split('\0').filter(Boolean))
1373
- const topologyOrder = new Map<string, number>(), topologyParents = new Map<string, string[]>(), topologyReachable = new Set<string>()
1374
- let topologyPosition = 0
1375
- for (const line of topology.trim().split('\n')) {
1376
- const [hash, ...parentList] = line.split(' ')
1377
- if (hash) {
1378
- topologyOrder.set(hash, topologyPosition++)
1379
- topologyParents.set(hash, parentList)
1380
- topologyReachable.add(hash)
1381
- }
1413
+ currentPaths = new Set(tipPathsOut.split('\0').filter(Boolean))
1414
+ topology = topologyProjection(topologyOut)
1382
1415
  }
1416
+ const topologyOrder = topology.order
1417
+ const topologyParents = topology.parents
1418
+ const topologyReachable = topology.reachable
1383
1419
  // Numstat is the immutable identity event: unlike a name-only stream it records both sides of a rename,
1384
1420
  // allowing the same event-scoped projection used by spec history to follow forks and reject path reuse.
1385
1421
  const out = shared?.driftOut ?? await eventStream(root, tip,
@@ -1507,16 +1543,17 @@ export function driftIndex(root: string, tip = 'HEAD'): Promise<DriftIndex> {
1507
1543
  return p
1508
1544
  }
1509
1545
 
1510
- function topologyProjection(out: string): { order: Map<string, number>; reachable: Set<string> } {
1511
- const order = new Map<string, number>(), reachable = new Set<string>()
1546
+ function topologyProjection(out: string): TopologyProjection {
1547
+ const order = new Map<string, number>(), parents = new Map<string, string[]>(), reachable = new Set<string>()
1512
1548
  let position = 0
1513
1549
  for (const line of out.trim().split('\n')) {
1514
- const hash = line.split(' ', 1)[0]
1550
+ const [hash, ...parentList] = line.split(' ')
1515
1551
  if (!hash) continue
1516
1552
  order.set(hash, position++)
1553
+ parents.set(hash, parentList)
1517
1554
  reachable.add(hash)
1518
1555
  }
1519
- return { order, reachable }
1556
+ return { order, parents, reachable }
1520
1557
  }
1521
1558
 
1522
1559
  async function buildIndexPair(root: string, tip: string, transient: boolean, useCache = true): Promise<[HistoryIndex, DriftIndex]> {
@@ -1525,11 +1562,14 @@ async function buildIndexPair(root: string, tip: string, transient: boolean, use
1525
1562
  strictEventGit(['-C', root, 'rev-list', '--parents', tip]),
1526
1563
  ])
1527
1564
  const topology = topologyProjection(topologyOut)
1565
+ const allPaths = new Set(allPathsOut.split('\0').filter(Boolean))
1566
+ const specPaths = new Set([...allPaths].filter((path) => path.startsWith('.spec/')))
1528
1567
  const requests = indexEventRequests(root, tip, topology.order, topology.reachable)
1529
1568
  const streams = await deriveEventStreams(root, tip, EVENT_STREAM_KINDS.map((kind) => requests[kind]), !transient, useCache)
1530
1569
  const shared: SharedIndexInputs = {
1531
- allPathsOut,
1532
- topologyOut,
1570
+ allPaths,
1571
+ specPaths,
1572
+ topology,
1533
1573
  historyOut: streams.get('numstat') ?? '',
1534
1574
  driftOut: streams.get('drift-numstat') ?? '',
1535
1575
  mergeIndex: parseMergeHistoryEvents(streams.get('merge') ?? ''),
@@ -632,13 +632,18 @@ app.post('/api/sessions/:id/input', async (c) => {
632
632
  app.post('/api/sessions/:id/stop', async (c) => {
633
633
  const sessionId = c.req.param('id')
634
634
  const authorization = await operationAuthorization(c.req.header.bind(c.req), { op: 'stop', sessionId })
635
- return c.json({ ok: await stopSession(sessionId, { authorization }) })
635
+ const ok = await stopSession(sessionId, { authorization })
636
+ return c.json(ok ? { ok: true } : { ok: false, error: `no stop transition was committed for session ${sessionId}` }, ok ? 200 : 404)
636
637
  })
637
638
  app.post('/api/sessions/:id/interrupt', async (c) => {
638
639
  const result = await interruptSession(c.req.param('id'))
639
640
  return c.json(result, result.ok ? 200 : 502)
640
641
  })
641
- app.post('/api/sessions/:id/close', async (c) => c.json({ ok: await closeSession(c.req.param('id')) }))
642
+ app.post('/api/sessions/:id/close', async (c) => {
643
+ const sessionId = c.req.param('id')
644
+ const ok = await closeSession(sessionId)
645
+ return c.json(ok ? { ok: true } : { ok: false, error: `no close transition was committed for session ${sessionId}` }, ok ? 200 : 404)
646
+ })
642
647
  // archive / legacy unarchive signpost ([[archive]]) — archive proves exact cold/offline ownership before filing;
643
648
  // `{on:false}` enters the same resume transition and recreates the preserved conversation. {ok:false}=no such session.
644
649
  app.post('/api/sessions/:id/archive', async (c) => {
@@ -21,3 +21,7 @@ export function readReviewSnapshot(): ReviewSnapshot {
21
21
  if (!current) throw new Error('review snapshot is unavailable before the first successful graph build')
22
22
  return current
23
23
  }
24
+
25
+ export function hasReviewSnapshot(): boolean {
26
+ return current !== null
27
+ }
@@ -5,7 +5,7 @@ import { buildSessionEvals, type SessionEvals } from '../../spec-eval/src/sessio
5
5
  import { evalTimeline } from '../../spec-eval/src/evaltab.js'
6
6
  import { issuesEnabled as issuesEnabledForReview } from './localIssues.js'
7
7
  import { issueStores as issueStoresForReview } from './issues.js'
8
- import { readReviewSnapshot } from './reviewSnapshot.js'
8
+ import { hasReviewSnapshot, readReviewSnapshot } from './reviewSnapshot.js'
9
9
  // @ts-expect-error The dashboard module is deliberately plain JS so the browser and server execute the
10
10
  // exact same tokenizer/matcher. It is shipped beside the built dashboard by the root package manifest.
11
11
  import { EVAL_FILTER_KIND, evalFilterModel, evalReviewState, issueFilterModel, tokenFilterState } from '../../spec-dashboard/src/reviewFilters.js'
@@ -121,7 +121,11 @@ const issueOrder = (a: any, b: any): number => String(b.created ?? '').localeCom
121
121
  || String(a.id ?? '').localeCompare(String(b.id ?? ''))
122
122
 
123
123
  export async function issuesReview(query: string | undefined, requestedPage: unknown) {
124
- const [, sessions] = await Promise.all([getBoard(), listSessions()])
124
+ // The first request must wait for the first atomic publication. Once one exists, a graph refresh may be
125
+ // rebuilding unrelated board/session state; the published review source remains a valid answer and its
126
+ // revision/poll path will deliver the next generation without making this page join that flight.
127
+ if (!hasReviewSnapshot()) await getBoard()
128
+ const sessions = await listSessions()
125
129
  const issues = readReviewSnapshot().issues.slice().sort(issueOrder)
126
130
  const text = String(query ?? '').trim() || ISSUE_QUERY_DEFAULT
127
131
  const model = issueFilterModel(issues, tokenFilterState(text, 'issue'), { sessions, defaultSection: '' })
@@ -337,15 +341,16 @@ export async function evalsReview(query: string | undefined, requestedPage: unkn
337
341
  }),
338
342
  }
339
343
  }
340
- const board = await getBoard()
344
+ if (!hasReviewSnapshot()) await getBoard()
345
+ const sessions = await listSessions()
341
346
  const items = trunkEvalReviewItems(readReviewSnapshot().evalNodes)
342
- const filtered = evalFilterModel(items, tokenFilterState(text, 'eval'), { sessions: board.sessions, defaultKind: 'all', defaultSection: '' })
347
+ const filtered = evalFilterModel(items, tokenFilterState(text, 'eval'), { sessions, defaultKind: 'all', defaultSection: '' })
343
348
  return {
344
349
  scope: null,
345
350
  gates: [],
346
351
  unknown: 0,
347
352
  ...paginateReview(items, filtered.shown, filtered, requestedPage, {
348
- domain: 'evals', items, sessions: board.sessions.map((session) => session.id),
353
+ domain: 'evals', items, sessions: sessions.map((session) => session.id),
349
354
  }),
350
355
  }
351
356
  }
@@ -1,2 +1,2 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-u8RIS3NY.js","assets/index-BqBNCa1V.js","assets/index-CzutlTDf.css","assets/SessionWindow-zGwJaGbR.js","assets/Thread-B-ZUarN1.js","assets/PageScroll-CAY4S4g4.js","assets/data-B1ot4PF0.js","assets/Modal-6mHq6fbZ.js","assets/bindings-BC9vqpYU.js","assets/Dashboard-C5ap-Sga.css","assets/MobileApp-DVLnk9hz.js","assets/TimelineChat-sc49Qj5d.js","assets/TimelineChat-Cp579UoJ.css","assets/ProjectsPage-UQyzsTWN.js"])))=>i.map(i=>d[i]);
2
- import{u as N,r as a,j as n,I as D,a as B,P as k,i as z,_ as T,D as M,b as G}from"./index-BqBNCa1V.js";import{a as J,l as q,s as F,p as V}from"./data-B1ot4PF0.js";const h=async e=>(e.headers.get("content-type")||"").includes("json")?e.json().catch(()=>null):null,H=5e3,O=(e,r,t)=>({title:typeof(e==null?void 0:e.title)=="string"&&e.title?e.title:r,icon:typeof(e==null?void 0:e.icon)=="string"&&e.icon?e.icon:t});function x(e){if(!e||typeof e!="object")return null;const r=e.id??e.projectId;return r?{id:String(r),identity:O(e.identity||{title:e.name,icon:e.icon},e.name||String(r),"spexcode"),root:typeof e.root=="string"?e.root:"",online:typeof e.online=="boolean"?e.online:null,url:e.url||"",port:e.port??null,gated:!!(e.gated??e.locked??e.hasPassword),configRevision:typeof e.configRevision=="string"?e.configRevision:""}:null}const W=e=>{const r=Array.isArray(e)?e:Array.isArray(e==null?void 0:e.projects)?e.projects:null;return r?r.map(x).filter(Boolean):null},Y=10;function ce(e,r,t=Y){const s=Array.isArray(e)?e:[],o=Math.max(1,Math.ceil(s.length/t)),l=Math.min(Math.max(1,Number.isInteger(r)?r:1),o);return{items:s.slice((l-1)*t,l*t),page:l,pageCount:o}}function Z(e,r,t){var s;if(!e)return t;if(!r)return null;if(r.state==="ok"){const o=(s=r.projects)==null?void 0:s.find(l=>l.id===e);return(o==null?void 0:o.identity)||{title:e,icon:"spexcode"}}return{title:(t==null?void 0:t.title)||e,icon:(t==null?void 0:t.icon)||"spexcode"}}const K=e=>(e==null?void 0:e.state)==="ok"?e.gateway.identity:{title:"Projects",icon:"gateway"},Q=e=>(e==null?void 0:e.title)||"SpexCode",R=(e,r)=>(r==null?void 0:r.state)==="absent"&&e&&e.state!=="absent"?e:r;async function X(){let e;try{e=await fetch("/projects",{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{state:"absent"}}if(e.status===401)return{state:"denied",reason:"admin-login"};if(e.status===403)return{state:"denied",reason:"locked"};if(!e.ok)return{state:"absent"};const r=await h(e),t=W(r);if(!t)return{state:"absent"};const s=r!=null&&r.gateway&&typeof r.gateway=="object"?{identity:O(r.gateway,"Projects","gateway"),revision:typeof r.gateway.revision=="string"?r.gateway.revision:""}:{identity:{title:"Projects",icon:"gateway"},revision:""};return{state:"ok",adminGated:!!(r!=null&&r.adminGated),gateway:s,projects:t}}async function ie(e,{timeoutMs:r=2500}={}){try{const t=await fetch(`/p/${encodeURIComponent(e)}/health`,{cache:"no-store",signal:AbortSignal.timeout(r)});return!t.ok||t.redirected?"unreachable":(await t.text()).trim()==="ok"?"running":"unreachable"}catch{return"unreachable"}}async function C(e,r,t){let s;try{s=await fetch(e,{method:r,headers:{"Content-Type":"application/json",Accept:"application/json"},...r==="PUT"?{body:JSON.stringify({password:t})}:{}})}catch{return{ok:!1,error:"network"}}const o=await h(s)||{};return{ok:s.ok&&o.ok!==!1,status:s.status,...o.error?{error:o.error}:{}}}const le=(e,r)=>C(`/projects/${encodeURIComponent(e)}/password`,"PUT",r),ue=e=>C(`/projects/${encodeURIComponent(e)}/password`,"DELETE"),pe=e=>C("/projects/admin-password","PUT",e),de=()=>C("/projects/admin-password","DELETE");async function ee(e,r){const t=e==="admin"?"/login":`/p/${encodeURIComponent(e.projectId)}/login`;let s;try{s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:r})})}catch{return{ok:!1,error:"network"}}return s.status===401?{ok:!1,error:"wrong-password"}:s.status===403?{ok:!1,error:"locked"}:s.ok||s.redirected?{ok:!0}:{ok:!1,error:`http-${s.status}`}}async function fe(e=""){let r;try{const s=e?`?path=${encodeURIComponent(e)}`:"";r=await fetch(`/projects/browse${s}`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.path)!="string"||!Array.isArray(t==null?void 0:t.entries)?{ok:!1,error:"unexpected answer"}:{ok:!0,path:t.path,parent:typeof t.parent=="string"?t.parent:null,home:typeof t.home=="string"?t.home:t.path,gitRoot:typeof t.gitRoot=="string"?t.gitRoot:null,initialized:!!t.initialized,cataloged:!!t.cataloged,entries:t.entries.filter(s=>s&&typeof s.name=="string"&&typeof s.path=="string").map(s=>({name:s.name,path:s.path,git:!!s.git,initialized:!!s.initialized}))}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function he(e,r={}){let t;try{t=await fetch("/projects",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({root:e,...r})})}catch{return{ok:!1,error:"network"}}const s=await h(t);if(!t.ok)return{ok:!1,status:t.status,error:(s==null?void 0:s.error)||`http-${t.status}`,...s!=null&&s.init&&typeof s.init=="object"?{code:s.init.code??null,output:String(s.init.output??"")}:{}};const o=x(s);return o?{ok:!0,project:o,setup:s.setup??null}:{ok:!1,error:"unexpected answer"}}async function je(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/config`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.content)!="string"||typeof(t==null?void 0:t.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:t.content,revision:t.revision}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function me(e,r,t){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/config`,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({content:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?typeof(o==null?void 0:o.content)!="string"||typeof(o==null?void 0:o.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:o.content,revision:o.revision}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}async function $(e,r,t){let s;try{s=await fetch(e,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({icon:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?{ok:!0,...o}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const ke=(e,r)=>$("/projects/icon",e,r),ge=(e,r,t)=>$(`/projects/${encodeURIComponent(e)}/icon`,r,t);async function U(e,r,t={}){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/${r}`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?!o||typeof o!="object"?{ok:!1,error:"unexpected answer"}:{ok:o.ok===!0,code:o.code??null,output:String(o.output??"")}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const we=(e,r)=>U(e,"init",{harness:r}),ye=e=>U(e,"doctor");async function Pe(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/serve`,{method:"POST",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.status===409?{ok:!0,already:!0,project:x(t==null?void 0:t.project)}:r.ok?{ok:!0,project:x(t==null?void 0:t.project)}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}function I({scope:e,projectLabel:r,locked:t,onUnlocked:s}){const o=N(),[l,S]=a.useState(""),[j,A]=a.useState(!1),[g,P]=a.useState(null),m=e==="admin",p=async b=>{if(b.preventDefault(),!l||j)return;A(!0),P(null);const w=await ee(m?"admin":{projectId:e.projectId},l);A(!1),w.ok?(S(""),s()):P(w.error==="wrong-password"?o("credential.wrong"):o("credential.failed"))};return n.jsx("div",{className:"cred-wrap",children:n.jsxs("form",{className:"cred-card",onSubmit:p,children:[n.jsx("div",{className:"cred-brand",children:"$ spexcode"}),n.jsxs("div",{className:"cred-title",children:[n.jsx(D,{name:"lock",size:14,className:"cred-lock"}),t?o("credential.lockedTitle"):m?o("credential.adminTitle"):o("credential.projectTitle",{name:r||e&&e.projectId||""})]}),t?n.jsx("p",{className:"cred-sub",children:o("credential.lockedBody")}):n.jsxs(n.Fragment,{children:[n.jsx("p",{className:"cred-sub",children:o(m?"credential.adminBody":"credential.projectBody")}),g&&n.jsx("div",{className:"cred-err",children:g}),n.jsx("input",{className:"cred-input",type:"password",autoFocus:!0,required:!0,placeholder:"••••••••••","aria-label":o("credential.passwordLabel"),value:l,onChange:b=>S(b.target.value)}),n.jsx("button",{className:"cred-submit",type:"submit",disabled:j||!l,children:o(j?"credential.checking":"credential.unlock")})]})]})})}const te=a.lazy(()=>T(()=>import("./Dashboard-u8RIS3NY.js").then(e=>e.D),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))),re=a.lazy(()=>T(()=>import("./MobileApp-DVLnk9hz.js"),__vite__mapDeps([10,1,2,3,4,5,6,11,12]))),se=a.lazy(()=>T(()=>import("./ProjectsPage-UQyzsTWN.js"),__vite__mapDeps([13,1,2,7,5,6])));window.addEventListener("vite:preloadError",e=>{const r=String(e.payload);sessionStorage.getItem("spexcode.chunkReload")!==r&&(sessionStorage.setItem("spexcode.chunkReload",r),e.preventDefault(),location.reload())});function oe(){const e=N(),r=B(),[t,s]=a.useState(null),[o,l]=a.useState(!1),S=a.useRef(new Map),j=a.useCallback((u,c)=>{s(J(u,S.current,c))},[]),[A,g]=a.useState(!1),[P,m]=a.useState(null),[p,b]=a.useState(null);a.useEffect(()=>{let u=!0;const c=()=>X().then(y=>{u&&b(L=>R(L,y))}).catch(()=>{u&&b(y=>R(y,{state:"absent"}))});c();const d=setInterval(c,H);return()=>{u=!1,clearInterval(d)}},[]);const w=a.useRef(0),f=a.useCallback(()=>{const u=++w.current;return q().then(c=>{if(!(u!==w.current||!c)){if(c.authRequired){m(c.authRequired);return}m(null),g(!1),j(c.board,!0),c.seal()}}).catch(()=>{u===w.current&&g(!0)})},[j]),v=!k&&!t&&!!p&&p.state!=="absent",E=!k&&!t&&p===null;a.useEffect(()=>{if(v||E)return;f();const u=F({onBoard:(d,y)=>{w.current++,g(!1),j(d,!!(y!=null&&y.authoritative))},onLegacyChange:()=>{f()},onStatus:l}),c=setInterval(()=>{f()},15e3);return()=>{u(),clearInterval(c)}},[f,j,v,E]);const _=t?V(t):null,i=k?Z(k,p,_):v?K(p):_;return a.useEffect(()=>{i&&(document.title=Q(i))},[i==null?void 0:i.title]),a.useEffect(()=>{if(!i)return;const u=v?M:G,c=z(i.icon,u);let d=document.querySelector("link[rel~='icon']");d||(d=document.createElement("link"),d.rel="icon",document.head.appendChild(d)),d.getAttribute("href")!==c&&d.setAttribute("href",c)},[i==null?void 0:i.icon,v]),P&&k?n.jsx(I,{scope:{projectId:k},projectLabel:(i==null?void 0:i.title)||k,onUnlocked:()=>{m(null),f()}}):t?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:r?n.jsx(re,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reloadBoard:f}):n.jsx(te,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reload:f,identity:i,catalog:p,boardLive:o})}):v?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:n.jsx(se,{})}):P?n.jsx(I,{scope:"admin",locked:P==="locked",onUnlocked:()=>{m(null),f()}}):A&&(k||p&&p.state==="absent")?n.jsxs("div",{className:"loading load-error",children:[n.jsx("span",{children:e("hud.loadError")}),n.jsx("button",{className:"load-retry",onClick:()=>{g(!1),f()},children:e("hud.retry")})]}):n.jsx("div",{className:"loading",children:e("hud.loading")})}const be=Object.freeze(Object.defineProperty({__proto__:null,default:oe},Symbol.toStringTag,{value:"Module"}));export{be as A,H as C,ce as a,I as b,de as c,fe as d,je as e,ye as f,ke as g,he as h,we as i,me as j,ge as k,X as l,Pe as m,ue as n,le as o,ie as p,pe as s};
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-C5X4Va3V.js","assets/index-BUKLPN_4.js","assets/index-CzutlTDf.css","assets/SessionWindow-Dag_GiJB.js","assets/Thread-Dg35J-Pu.js","assets/PageScroll-B2kxcqJJ.js","assets/data-SNi0AmVT.js","assets/Modal-6l_QtCKF.js","assets/bindings-BC9vqpYU.js","assets/Dashboard-C5ap-Sga.css","assets/MobileApp-ClbtwZ1e.js","assets/TimelineChat-f0UF9fXq.js","assets/TimelineChat-Cp579UoJ.css","assets/ProjectsPage-C8IPsMKV.js"])))=>i.map(i=>d[i]);
2
+ import{u as N,r as a,j as n,I as D,a as B,P as k,i as z,_ as T,D as M,b as G}from"./index-BUKLPN_4.js";import{a as J,l as q,s as F,p as V}from"./data-SNi0AmVT.js";const h=async e=>(e.headers.get("content-type")||"").includes("json")?e.json().catch(()=>null):null,H=5e3,O=(e,r,t)=>({title:typeof(e==null?void 0:e.title)=="string"&&e.title?e.title:r,icon:typeof(e==null?void 0:e.icon)=="string"&&e.icon?e.icon:t});function x(e){if(!e||typeof e!="object")return null;const r=e.id??e.projectId;return r?{id:String(r),identity:O(e.identity||{title:e.name,icon:e.icon},e.name||String(r),"spexcode"),root:typeof e.root=="string"?e.root:"",online:typeof e.online=="boolean"?e.online:null,url:e.url||"",port:e.port??null,gated:!!(e.gated??e.locked??e.hasPassword),configRevision:typeof e.configRevision=="string"?e.configRevision:""}:null}const W=e=>{const r=Array.isArray(e)?e:Array.isArray(e==null?void 0:e.projects)?e.projects:null;return r?r.map(x).filter(Boolean):null},Y=10;function ce(e,r,t=Y){const s=Array.isArray(e)?e:[],o=Math.max(1,Math.ceil(s.length/t)),l=Math.min(Math.max(1,Number.isInteger(r)?r:1),o);return{items:s.slice((l-1)*t,l*t),page:l,pageCount:o}}function Z(e,r,t){var s;if(!e)return t;if(!r)return null;if(r.state==="ok"){const o=(s=r.projects)==null?void 0:s.find(l=>l.id===e);return(o==null?void 0:o.identity)||{title:e,icon:"spexcode"}}return{title:(t==null?void 0:t.title)||e,icon:(t==null?void 0:t.icon)||"spexcode"}}const K=e=>(e==null?void 0:e.state)==="ok"?e.gateway.identity:{title:"Projects",icon:"gateway"},Q=e=>(e==null?void 0:e.title)||"SpexCode",R=(e,r)=>(r==null?void 0:r.state)==="absent"&&e&&e.state!=="absent"?e:r;async function X(){let e;try{e=await fetch("/projects",{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{state:"absent"}}if(e.status===401)return{state:"denied",reason:"admin-login"};if(e.status===403)return{state:"denied",reason:"locked"};if(!e.ok)return{state:"absent"};const r=await h(e),t=W(r);if(!t)return{state:"absent"};const s=r!=null&&r.gateway&&typeof r.gateway=="object"?{identity:O(r.gateway,"Projects","gateway"),revision:typeof r.gateway.revision=="string"?r.gateway.revision:""}:{identity:{title:"Projects",icon:"gateway"},revision:""};return{state:"ok",adminGated:!!(r!=null&&r.adminGated),gateway:s,projects:t}}async function ie(e,{timeoutMs:r=2500}={}){try{const t=await fetch(`/p/${encodeURIComponent(e)}/health`,{cache:"no-store",signal:AbortSignal.timeout(r)});return!t.ok||t.redirected?"unreachable":(await t.text()).trim()==="ok"?"running":"unreachable"}catch{return"unreachable"}}async function C(e,r,t){let s;try{s=await fetch(e,{method:r,headers:{"Content-Type":"application/json",Accept:"application/json"},...r==="PUT"?{body:JSON.stringify({password:t})}:{}})}catch{return{ok:!1,error:"network"}}const o=await h(s)||{};return{ok:s.ok&&o.ok!==!1,status:s.status,...o.error?{error:o.error}:{}}}const le=(e,r)=>C(`/projects/${encodeURIComponent(e)}/password`,"PUT",r),ue=e=>C(`/projects/${encodeURIComponent(e)}/password`,"DELETE"),pe=e=>C("/projects/admin-password","PUT",e),de=()=>C("/projects/admin-password","DELETE");async function ee(e,r){const t=e==="admin"?"/login":`/p/${encodeURIComponent(e.projectId)}/login`;let s;try{s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:r})})}catch{return{ok:!1,error:"network"}}return s.status===401?{ok:!1,error:"wrong-password"}:s.status===403?{ok:!1,error:"locked"}:s.ok||s.redirected?{ok:!0}:{ok:!1,error:`http-${s.status}`}}async function fe(e=""){let r;try{const s=e?`?path=${encodeURIComponent(e)}`:"";r=await fetch(`/projects/browse${s}`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.path)!="string"||!Array.isArray(t==null?void 0:t.entries)?{ok:!1,error:"unexpected answer"}:{ok:!0,path:t.path,parent:typeof t.parent=="string"?t.parent:null,home:typeof t.home=="string"?t.home:t.path,gitRoot:typeof t.gitRoot=="string"?t.gitRoot:null,initialized:!!t.initialized,cataloged:!!t.cataloged,entries:t.entries.filter(s=>s&&typeof s.name=="string"&&typeof s.path=="string").map(s=>({name:s.name,path:s.path,git:!!s.git,initialized:!!s.initialized}))}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function he(e,r={}){let t;try{t=await fetch("/projects",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({root:e,...r})})}catch{return{ok:!1,error:"network"}}const s=await h(t);if(!t.ok)return{ok:!1,status:t.status,error:(s==null?void 0:s.error)||`http-${t.status}`,...s!=null&&s.init&&typeof s.init=="object"?{code:s.init.code??null,output:String(s.init.output??"")}:{}};const o=x(s);return o?{ok:!0,project:o,setup:s.setup??null}:{ok:!1,error:"unexpected answer"}}async function je(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/config`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.content)!="string"||typeof(t==null?void 0:t.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:t.content,revision:t.revision}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function me(e,r,t){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/config`,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({content:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?typeof(o==null?void 0:o.content)!="string"||typeof(o==null?void 0:o.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:o.content,revision:o.revision}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}async function $(e,r,t){let s;try{s=await fetch(e,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({icon:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?{ok:!0,...o}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const ke=(e,r)=>$("/projects/icon",e,r),ge=(e,r,t)=>$(`/projects/${encodeURIComponent(e)}/icon`,r,t);async function U(e,r,t={}){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/${r}`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?!o||typeof o!="object"?{ok:!1,error:"unexpected answer"}:{ok:o.ok===!0,code:o.code??null,output:String(o.output??"")}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const we=(e,r)=>U(e,"init",{harness:r}),ye=e=>U(e,"doctor");async function Pe(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/serve`,{method:"POST",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.status===409?{ok:!0,already:!0,project:x(t==null?void 0:t.project)}:r.ok?{ok:!0,project:x(t==null?void 0:t.project)}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}function I({scope:e,projectLabel:r,locked:t,onUnlocked:s}){const o=N(),[l,S]=a.useState(""),[j,A]=a.useState(!1),[g,P]=a.useState(null),m=e==="admin",p=async b=>{if(b.preventDefault(),!l||j)return;A(!0),P(null);const w=await ee(m?"admin":{projectId:e.projectId},l);A(!1),w.ok?(S(""),s()):P(w.error==="wrong-password"?o("credential.wrong"):o("credential.failed"))};return n.jsx("div",{className:"cred-wrap",children:n.jsxs("form",{className:"cred-card",onSubmit:p,children:[n.jsx("div",{className:"cred-brand",children:"$ spexcode"}),n.jsxs("div",{className:"cred-title",children:[n.jsx(D,{name:"lock",size:14,className:"cred-lock"}),t?o("credential.lockedTitle"):m?o("credential.adminTitle"):o("credential.projectTitle",{name:r||e&&e.projectId||""})]}),t?n.jsx("p",{className:"cred-sub",children:o("credential.lockedBody")}):n.jsxs(n.Fragment,{children:[n.jsx("p",{className:"cred-sub",children:o(m?"credential.adminBody":"credential.projectBody")}),g&&n.jsx("div",{className:"cred-err",children:g}),n.jsx("input",{className:"cred-input",type:"password",autoFocus:!0,required:!0,placeholder:"••••••••••","aria-label":o("credential.passwordLabel"),value:l,onChange:b=>S(b.target.value)}),n.jsx("button",{className:"cred-submit",type:"submit",disabled:j||!l,children:o(j?"credential.checking":"credential.unlock")})]})]})})}const te=a.lazy(()=>T(()=>import("./Dashboard-C5X4Va3V.js").then(e=>e.D),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))),re=a.lazy(()=>T(()=>import("./MobileApp-ClbtwZ1e.js"),__vite__mapDeps([10,1,2,3,4,5,6,11,12]))),se=a.lazy(()=>T(()=>import("./ProjectsPage-C8IPsMKV.js"),__vite__mapDeps([13,1,2,7,5,6])));window.addEventListener("vite:preloadError",e=>{const r=String(e.payload);sessionStorage.getItem("spexcode.chunkReload")!==r&&(sessionStorage.setItem("spexcode.chunkReload",r),e.preventDefault(),location.reload())});function oe(){const e=N(),r=B(),[t,s]=a.useState(null),[o,l]=a.useState(!1),S=a.useRef(new Map),j=a.useCallback((u,c)=>{s(J(u,S.current,c))},[]),[A,g]=a.useState(!1),[P,m]=a.useState(null),[p,b]=a.useState(null);a.useEffect(()=>{let u=!0;const c=()=>X().then(y=>{u&&b(L=>R(L,y))}).catch(()=>{u&&b(y=>R(y,{state:"absent"}))});c();const d=setInterval(c,H);return()=>{u=!1,clearInterval(d)}},[]);const w=a.useRef(0),f=a.useCallback(()=>{const u=++w.current;return q().then(c=>{if(!(u!==w.current||!c)){if(c.authRequired){m(c.authRequired);return}m(null),g(!1),j(c.board,!0),c.seal()}}).catch(()=>{u===w.current&&g(!0)})},[j]),v=!k&&!t&&!!p&&p.state!=="absent",E=!k&&!t&&p===null;a.useEffect(()=>{if(v||E)return;f();const u=F({onBoard:(d,y)=>{w.current++,g(!1),j(d,!!(y!=null&&y.authoritative))},onLegacyChange:()=>{f()},onStatus:l}),c=setInterval(()=>{f()},15e3);return()=>{u(),clearInterval(c)}},[f,j,v,E]);const _=t?V(t):null,i=k?Z(k,p,_):v?K(p):_;return a.useEffect(()=>{i&&(document.title=Q(i))},[i==null?void 0:i.title]),a.useEffect(()=>{if(!i)return;const u=v?M:G,c=z(i.icon,u);let d=document.querySelector("link[rel~='icon']");d||(d=document.createElement("link"),d.rel="icon",document.head.appendChild(d)),d.getAttribute("href")!==c&&d.setAttribute("href",c)},[i==null?void 0:i.icon,v]),P&&k?n.jsx(I,{scope:{projectId:k},projectLabel:(i==null?void 0:i.title)||k,onUnlocked:()=>{m(null),f()}}):t?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:r?n.jsx(re,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reloadBoard:f}):n.jsx(te,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reload:f,identity:i,catalog:p,boardLive:o})}):v?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:n.jsx(se,{})}):P?n.jsx(I,{scope:"admin",locked:P==="locked",onUnlocked:()=>{m(null),f()}}):A&&(k||p&&p.state==="absent")?n.jsxs("div",{className:"loading load-error",children:[n.jsx("span",{children:e("hud.loadError")}),n.jsx("button",{className:"load-retry",onClick:()=>{g(!1),f()},children:e("hud.retry")})]}):n.jsx("div",{className:"loading",children:e("hud.loading")})}const be=Object.freeze(Object.defineProperty({__proto__:null,default:oe},Symbol.toStringTag,{value:"Module"}));export{be as A,H as C,ce as a,I as b,de as c,fe as d,je as e,ye as f,ke as g,he as h,we as i,me as j,ge as k,X as l,Pe as m,ue as n,le as o,ie as p,pe as s};