geneseed 4.9.1 → 4.9.3

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 (66) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/SHIPPED.md +1 -1
  3. package/adapters/opencode/plugins/geneseed-context.js +7 -1
  4. package/adapters/opencode/plugins/geneseed-guard.js +123 -12
  5. package/adapters/opencode/plugins/geneseed-learn.js +7 -1
  6. package/docs/concepts/enforcement-table.md +1 -1
  7. package/docs/concepts/exclusions.md +1 -2
  8. package/docs/concepts/hooks.md +3 -2
  9. package/docs/guides/upgrade.md +1 -1
  10. package/harness.config.json +1 -1
  11. package/js/README.md +30 -9
  12. package/js/build/args.mjs +9 -8
  13. package/js/build/driver.mjs +21 -21
  14. package/js/build/emit-claude.mjs +3 -3
  15. package/js/build/generate.mjs +4 -5
  16. package/js/build/source.mjs +18 -22
  17. package/js/hosts/gitref.mjs +5 -3
  18. package/js/hosts/hooks-done.mjs +21 -9
  19. package/js/hosts/hooks-learn.mjs +23 -10
  20. package/js/hosts/hooks-prims.mjs +25 -0
  21. package/js/hosts/hooks.mjs +19 -4
  22. package/js/hosts/installs.mjs +5 -4
  23. package/js/hosts/loss.mjs +98 -0
  24. package/js/hosts/native.mjs +3 -1
  25. package/js/hosts/owned.mjs +34 -6
  26. package/js/hosts/settings.mjs +6 -5
  27. package/js/inspect/checks-probe.mjs +1 -1
  28. package/js/inspect/cost.mjs +37 -5
  29. package/js/inspect/diff.mjs +154 -64
  30. package/js/inspect/validate.mjs +2 -2
  31. package/js/lib/fs.mjs +73 -2
  32. package/js/maintain/setup.mjs +31 -7
  33. package/js/maintain/uninstall.mjs +1 -1
  34. package/js/maintain/update.mjs +1 -1
  35. package/js/web/actions.mjs +36 -3
  36. package/js/web/api.mjs +17 -6
  37. package/js/web/handler.mjs +4 -16
  38. package/js/web/jobs.mjs +5 -3
  39. package/js/web/state.mjs +3 -0
  40. package/package.json +1 -1
  41. package/web/dist/assets/{Activity-GQGAZHIE.js → Activity-C8sZVIUU.js} +1 -1
  42. package/web/dist/assets/{ActivityDetail-DktWyxim.js → ActivityDetail-Cc6vWUS4.js} +1 -1
  43. package/web/dist/assets/Dashboard-C5ATa3ow.js +2 -0
  44. package/web/dist/assets/{Docs-CsWYLnN1.js → Docs-tDW7i7mo.js} +3 -3
  45. package/web/dist/assets/GreenhouseView-zk2Uzc3A.js +2 -0
  46. package/web/dist/assets/Installs-CB_rvbBP.js +3 -0
  47. package/web/dist/assets/JournalView-Bfj27XHC.js +1 -0
  48. package/web/dist/assets/Laws-BA3CzUf5.js +3 -0
  49. package/web/dist/assets/Library-BWwiy9Vb.js +1 -0
  50. package/web/dist/assets/{Loops-BUBOeM0C.js → Loops-DaPk-ckL.js} +2 -2
  51. package/web/dist/assets/{OperatorHudView-BJuCYsjf.js → OperatorHudView-CyiGhiHk.js} +1 -1
  52. package/web/dist/assets/Personal-Bwd27CmT.js +1 -0
  53. package/web/dist/assets/{Tabs-GPQlocTw.js → Tabs-BOD7Kaz1.js} +1 -1
  54. package/web/dist/assets/drawable-CyLe1gtW.js +1 -0
  55. package/web/dist/assets/index-DQXG_mqo.js +2 -0
  56. package/web/dist/index.html +1 -1
  57. package/web/src/pages/Laws.jsx +60 -353
  58. package/web/dist/assets/Dashboard-CmSn6JfK.js +0 -2
  59. package/web/dist/assets/GreenhouseView-Dt_cIxAY.js +0 -2
  60. package/web/dist/assets/Installs-CWuUU4I3.js +0 -2
  61. package/web/dist/assets/JournalView-ClbZj_YF.js +0 -1
  62. package/web/dist/assets/Laws-R5zZCmya.js +0 -3
  63. package/web/dist/assets/Library-u36V7oSD.js +0 -1
  64. package/web/dist/assets/Personal-DWQuSAUz.js +0 -1
  65. package/web/dist/assets/drawable-CE-arUnF.js +0 -1
  66. package/web/dist/assets/index-3lnPT_1J.js +0 -2
@@ -1,16 +1,21 @@
1
- import React, { useEffect, useRef, useState } from 'react'
1
+ import { useEffect, useRef, useState } from 'react'
2
2
  import { api } from '../api/index.js'
3
3
  import { go } from '../lib/router.js'
4
4
  import { useAsync } from '../hooks/useAsync.js'
5
+ import { useRules } from '../hooks/useRules.js'
6
+ import { useRuleSelection } from '../hooks/useRuleSelection.js'
5
7
  import { romanToInt } from '../lib/roman.js'
6
8
  import Loading from '../components/Loading.jsx'
7
9
  import ErrorState from '../components/ErrorState.jsx'
8
10
  import { LAW_CATS, PACK_CATS } from '../lib/lawCats.js'
9
- import { GATE_SWITCH, enforcedBy, gateAddress, parseRuleTitle } from '../lib/constitution.js'
11
+ import { GATE_COPY, GATE_SWITCH, enforcedBy, parseRuleTitle } from '../lib/constitution.js'
10
12
  import Seg from '../components/Seg.jsx'
11
- import CatalogRow from '../components/CatalogRow.jsx'
12
13
  import FilterInput from '../components/FilterInput.jsx'
13
14
  import { useConfirm } from '../hooks/useConfirm.jsx'
15
+ import LawRow from './Laws/LawRow.jsx'
16
+ import TierStrip from './Laws/TierStrip.jsx'
17
+ import GateAsks from './Laws/GateAsks.jsx'
18
+ import PackPanel from './Laws/PackPanel.jsx'
14
19
 
15
20
  // THE FILENAME AND THE ROUTE STAY `laws`. tests/helpers/cli_golden.mjs hard-requires this path,
16
21
  // doctor's lawMetaProblems reads this ONE file out of web/src, and the npm partition ships it
@@ -212,144 +217,40 @@ const DOCTRINE_META = {
212
217
  ],
213
218
  }
214
219
 
215
- // Tiny inline formatter: render `code` spans and *emphasis* in plain rule text.
216
- // The full rule bodies are kept lightly marked-up in src/, so a minimal formatter is enough — we
217
- // don't need the full Markdown renderer here.
218
- function LawText({ text }) {
219
- const parts = String(text).split(/(`[^`]+`|\*[^*]+\*)/g)
220
- return (
221
- <>
222
- {parts.map((p, i) => {
223
- if (p.startsWith('`') && p.endsWith('`')) return <code key={i}>{p.slice(1, -1)}</code>
224
- if (p.startsWith('*') && p.endsWith('*') && p.length > 2)
225
- return <em key={i}>{p.slice(1, -1)}</em>
226
- return <React.Fragment key={i}>{p}</React.Fragment>
227
- })}
228
- </>
229
- )
230
- }
231
-
232
- // One expandable row of the constitution table, shared by all three tiers via CatalogRow
233
- // (the lazy-load/expand-panel machinery). The address is the catalog's `name`: a Roman
234
- // numeral, `<pack>.<n>` or `ont:<id>`; `no` is what the No. column prints.
235
- function LawRow({ law, isOpen, onToggle, toggleCol = null }) {
236
- const head = (
237
- <>
238
- <span className="law-no">
239
- <span className="x" aria-hidden="true">
240
- ›
241
- </span>
242
- {law.no}
243
- </span>
244
- <span className="law-name">
245
- <span>{law.name}</span>
246
- {law.ess ? <span className="law-princ">{law.ess}</span> : null}
247
- </span>
248
- <span className="law-latin">{law.latin}</span>
249
- <span className={`law-status ${law.statusTone}`}>{law.status}</span>
250
- <span
251
- className={`law-enf${law.enf === 'Hook gate' ? ' hook' : law.enf === 'Gate off' ? ' gate-off' : ''}`}
252
- >
253
- {law.enf}
254
- </span>
255
- </>
256
- )
257
- return (
258
- <CatalogRow
259
- addr={law.addr}
260
- isOpen={isOpen}
261
- onToggle={onToggle}
262
- className={`law-row${toggleCol ? ' has-toggle' : ''}${isOpen ? ' on' : ''}${law.off ? ' law-off' : ''}`}
263
- style={{ '--cc': law.c }}
264
- head={head}
265
- toggleCol={toggleCol}
266
- renderBody={(detail) => (
267
- <p>
268
- <LawText text={detail.body || law.ess} />
269
- </p>
270
- )}
271
- srcLine={`$ geneseed law ${law.addr} · ${law.src}`}
272
- />
273
- )
274
- }
275
-
276
- // The four tiers as one strip: each with its count, a bar for how much of it is in force,
277
- // and a line on what the count means. The tier the table is showing is lit; the fourth
278
- // (your own rules) lives on the Personal page and links there.
279
- function TierStrip({ tiers, current }) {
280
- return (
281
- <div className="tier-strip">
282
- {tiers.map((t, i) => {
283
- const body = (
284
- <>
285
- <span className="tier-k mono">TIER {i + 1}</span>
286
- <span className="tier-top">
287
- <span className="tier-name">{t.name}</span>
288
- <span className="tier-n mono">{t.n}</span>
289
- </span>
290
- <span className="tier-bar" aria-hidden="true">
291
- <span style={{ width: `${Math.round(t.fill * 100)}%` }} />
292
- </span>
293
- <span className="tier-sub">{t.sub}</span>
294
- </>
295
- )
296
- return t.href ? (
297
- <a key={t.key} className="tier" href={t.href}>
298
- {body}
299
- </a>
300
- ) : (
301
- <div key={t.key} className={`tier${current === t.key ? ' on' : ''}`}>
302
- {body}
303
- </div>
304
- )
305
- })}
306
- </div>
307
- )
308
- }
309
-
310
- // How often each hook gate stopped to ask, from the gate ledger (`setup.gates`). The ledger
311
- // keys by gate id (`process-5`); lib/constitution.js turns that into the rule's address,
312
- // and the catalog names it.
313
- function GateAsks({ gates, byAddr, onJump }) {
314
- const asks = Object.entries(gates?.asks || {}).sort((a, b) => b[1] - a[1])
315
- const max = Math.max(1, ...asks.map(([, n]) => n))
316
- return (
317
- <section className="panel" aria-labelledby="gate-asks">
318
- <div className="panel-head">
319
- <h2 id="gate-asks">Gate asks</h2>
320
- <span className="mono dim">{gates?.total ?? 0} in ledger</span>
321
- </div>
322
- {asks.length ? (
323
- <ul className="gate-list">
324
- {asks.map(([gate, n]) => {
325
- const addr = gateAddress(gate)
326
- return (
327
- <li key={gate}>
328
- {/* The whole entry is the control: it takes you to the rule in the table. */}
329
- <button type="button" className="gate-row" onClick={() => onJump(addr)}>
330
- <span className="gate-top">
331
- <span className="gate-name">{byAddr[addr]?.name || addr}</span>
332
- <span className="mono dim">{addr}</span>
333
- <span className="mono gate-n">{n}</span>
334
- </span>
335
- <span className="hbar warn" aria-hidden="true">
336
- <span style={{ width: `${(n / max) * 100}%` }} />
337
- </span>
338
- </button>
339
- </li>
340
- )
341
- })}
342
- </ul>
343
- ) : (
344
- <p className="sub">No gate has asked yet.</p>
345
- )}
346
- <p className="panel-note">
347
- {gates?.standing_down?.length
348
- ? `Standing down: ${gates.standing_down.join(', ')}.`
349
- : 'None standing down.'}
350
- </p>
351
- </section>
352
- )
220
+ // The doctrine rows, grouped by pack in the order the server sends them (PACK_ORDER, the reading
221
+ // order, not alphabetical). Every pack is here whether or not it is built in. Pure over the
222
+ // catalog items, so the page can build it before its early returns and hand it to the selection.
223
+ function doctrinePacks(items) {
224
+ const packs = []
225
+ for (const it of items) {
226
+ if (it.tier !== 'doctrine') continue
227
+ let pack = packs.find((p) => p.pack === it.pack)
228
+ if (!pack) {
229
+ pack = {
230
+ pack: it.pack,
231
+ title: it.packTitle || it.pack,
232
+ desc: it.packDesc || '',
233
+ // ⚠ `packActive`, NOT the first rule's `active`. A pack is on when the install built
234
+ // it in AT ALL; with the per-rule axis its first rule can be the excluded one.
235
+ active: it.packActive !== false,
236
+ rules: [],
237
+ }
238
+ packs.push(pack)
239
+ }
240
+ const [, ess] = DOCTRINE_META[it.name] || [it.pack, '']
241
+ const t = parseRuleTitle(it.title)
242
+ pack.rules.push({
243
+ addr: it.name,
244
+ no: `${it.pack} ${it.name.split('.')[1] || ''}`,
245
+ name: t.name,
246
+ latin: t.latin,
247
+ ess,
248
+ enf: enforcedBy(it.name),
249
+ c: PACK_CATS[it.pack] || 'var(--text-3)',
250
+ src: `doctrines/${it.pack}.md`,
251
+ })
252
+ }
253
+ return packs
353
254
  }
354
255
 
355
256
  // `selected` is the address from a #/item/law/<address> deep link (Spotlight, the
@@ -358,10 +259,7 @@ function GateAsks({ gates, byAddr, onJump }) {
358
259
  export default function Laws({ selected, overview, setup, onAction, dataRev }) {
359
260
  const confirm = useConfirm()
360
261
  const { data, error } = useAsync(() => api.catalog('laws'), [dataRev], 'catalog:laws')
361
- const { data: rulesData } = useAsync(
362
- () => Promise.resolve(api.rules?.()).catch(() => null),
363
- [dataRev],
364
- )
262
+ const { data: rulesData } = useRules(dataRev)
365
263
  const [tab, setTab] = useState('all')
366
264
  const [q, setQ] = useState('')
367
265
  const open = selected || null
@@ -397,36 +295,22 @@ export default function Laws({ selected, overview, setup, onAction, dataRev }) {
397
295
  // `data`, which is null on the first render; a `useState` placed after `if (!data)` makes
398
296
  // React see a different number of hooks between the loading render and the loaded one
399
297
  // and throw, taking the whole page down rather than just the control.
400
- const allItems = data?.items || []
401
- // ⚠ THE UNIT IS THE RULE, not the pack. The selection below is a list of rule ADDRESSES
402
- // (`process.7`), and the pack axis is DERIVED from it when Apply builds the request: a
403
- // pack with every rule off drops out of `--doctrines` entirely, so the rendered AGENT.md
404
- // never carries a pack header with nothing under it.
405
- const deployedRules = allItems
406
- .filter((i) => i.tier === 'doctrine' && i.active !== false)
407
- .map((i) => i.name)
408
- const deployedKey = deployedRules.join(',')
409
- const [picked, setPicked] = useState([])
410
- // Re-sync on the VALUE, never on the payload's identity: `data` is a fresh object on every
411
- // refetch, so an identity dependency would discard a half-made selection. Adjusted during
412
- // render against the last-synced key (React's "adjust state on prop change").
413
- const [syncedKey, setSyncedKey] = useState('')
414
- if (syncedKey !== deployedKey) {
415
- setSyncedKey(deployedKey)
416
- setPicked(deployedKey ? deployedKey.split(',') : [])
417
- }
418
-
419
- if (error) return <ErrorState error={error} />
420
- if (!data) return <Loading />
421
-
298
+ const items = data?.items || []
299
+ const packs = doctrinePacks(items)
422
300
  // The gate switches (Laws I, III, IV), as the deployed install reports them
423
301
  // (`overview.install.secretsGate` / `doneGate` / `deletionGate`). Anything but an explicit
424
302
  // `false` — an older daemon, no install — reads as armed.
425
303
  const armed = (addr) => overview?.install?.[GATE_SWITCH[addr].key] !== false
426
304
  const gateArmed = armed('IV')
305
+ // Nothing to rebuild means nothing to toggle: a source render with no deployed install
306
+ // still READS, it just cannot be changed from here.
307
+ const install = overview?.install
308
+ const canApply = Boolean(install && onAction)
309
+ const sel = useRuleSelection({ items, packs, install, canApply, onAction, gateArmed })
310
+ const { deployedRules, isOn, toggleRule, packOn, packState, allRules } = sel
427
311
 
428
- const items = allItems
429
- const isOn = (addr) => picked.includes(addr)
312
+ if (error) return <ErrorState error={error} />
313
+ if (!data) return <Loading />
430
314
 
431
315
  const ontology = items
432
316
  .filter((it) => it.tier === 'ontology')
@@ -473,37 +357,6 @@ export default function Laws({ selected, overview, setup, onAction, dataRev }) {
473
357
  }
474
358
  })
475
359
 
476
- // Grouped by pack, in the order the server sends them (PACK_ORDER, the reading order, not
477
- // alphabetical). Every pack is here whether or not it is built in.
478
- const packs = []
479
- for (const it of items) {
480
- if (it.tier !== 'doctrine') continue
481
- let pack = packs.find((p) => p.pack === it.pack)
482
- if (!pack) {
483
- pack = {
484
- pack: it.pack,
485
- title: it.packTitle || it.pack,
486
- desc: it.packDesc || '',
487
- // ⚠ `packActive`, NOT the first rule's `active`. A pack is on when the install built
488
- // it in AT ALL; with the per-rule axis its first rule can be the excluded one.
489
- active: it.packActive !== false,
490
- rules: [],
491
- }
492
- packs.push(pack)
493
- }
494
- const [, ess] = DOCTRINE_META[it.name] || [it.pack, '']
495
- const t = parseRuleTitle(it.title)
496
- pack.rules.push({
497
- addr: it.name,
498
- no: `${it.pack} ${it.name.split('.')[1] || ''}`,
499
- name: t.name,
500
- latin: t.latin,
501
- ess,
502
- enf: enforcedBy(it.name),
503
- c: PACK_CATS[it.pack] || 'var(--text-3)',
504
- src: `doctrines/${it.pack}.md`,
505
- })
506
- }
507
360
  // A doctrine row's status is the STAGED switch against what is deployed: a rule the
508
361
  // install carries reads Active, one it excludes reads Off, and a rule whose switch was
509
362
  // flipped but not applied says so rather than reporting the staged state as fact.
@@ -514,95 +367,14 @@ export default function Laws({ selected, overview, setup, onAction, dataRev }) {
514
367
  return { ...r, off: !on, status, statusTone: on ? 'ok' : on === live ? '' : 'warn' }
515
368
  }
516
369
 
517
- // ---- the pack selection: STAGED here, applied once -------------------------------------
518
- //
519
- // ⚠ ONE REBUILD, NOT ONE PER TOGGLE. A selection is a SET: acting on each click would
520
- // re-emit the install once per switch, each rebuild describing a state nobody asked for.
521
- // So the switches edit local state and `Apply` sends the whole selection.
522
- const toggleRule = (addr) =>
523
- setPicked((cur) => (cur.includes(addr) ? cur.filter((a) => a !== addr) : [...cur, addr]))
524
- // A pack is on when any of its rules is; its switch turns every rule on or every rule off.
525
- const packOn = (p) => p.rules.some((r) => isOn(r.addr))
526
- const togglePack = (p) => {
527
- const addrs = p.rules.map((r) => r.addr)
528
- setPicked((cur) =>
529
- packOn(p) ? cur.filter((a) => !addrs.includes(a)) : [...new Set([...cur, ...addrs])],
530
- )
531
- }
532
- // ⚠ A STAGED PACK MUST NOT READ AS A DEPLOYED ONE. `p.active` is what the install built;
533
- // `packOn(p)` is what the switches currently say. Where they differ the line says so.
534
- const packState = (p) => {
535
- const on = p.rules.filter((r) => isOn(r.addr)).length
536
- if (!on) return p.active ? 'staged off' : 'not built in'
537
- if (!p.active) return `staged on · ${on} of ${p.rules.length}`
538
- return `${on} of ${p.rules.length} active`
539
- }
540
370
  // What the install excludes today: a rule that is off inside a pack it still builds in.
541
371
  const deployedExcluded = packs
542
372
  .filter((p) => p.active)
543
373
  .flatMap((p) => p.rules.filter((r) => !deployedRules.includes(r.addr)).map((r) => r.addr))
544
- const allRules = packs.flatMap((p) => p.rules.map((r) => r.addr))
545
- const pickedRules = allRules.filter(isOn)
546
- const dirty = pickedRules.join(',') !== deployedKey
547
- const CONSENT = 'process.5'
548
- const losingConsent = deployedRules.includes(CONSENT) && !picked.includes(CONSENT)
549
- // Nothing to rebuild means nothing to toggle: a source render with no deployed install
550
- // still READS, it just cannot be changed from here.
551
- const install = overview?.install
552
- const canApply = Boolean(install && onAction)
553
-
554
- // ⚠ TWO AXES OUT OF ONE SELECTION. The user only ever touches rules; the request carries
555
- // both `doctrines` (the packs with at least one rule left) and `excludeRules` (the rules
556
- // dropped from the packs that survive).
557
- const applyPacks = async () => {
558
- if (!canApply || !dirty) return
559
- const keptPacks = packs.filter((p) => p.rules.some((r) => isOn(r.addr))).map((p) => p.pack)
560
- const excludeRules = packs
561
- .filter((p) => keptPacks.includes(p.pack))
562
- .flatMap((p) => p.rules.filter((r) => !isOn(r.addr)).map((r) => r.addr))
563
- const warn = losingConsent
564
- ? '\n\nprocess 5 carries commit/push consent. Dropping it also removes the git-gate ' +
565
- 'hook, so commits and pushes stop being confirmed at the tool boundary. ' +
566
- (gateArmed
567
- ? '(Real data loss stays gated: that is Rule IV’s, not the pack’s.)'
568
- : '(Rule IV’s deletion gate is off on this install, so real data loss is not asked about either.)')
569
- : ''
570
- const what = pickedRules.length
571
- ? `${pickedRules.length} of ${allRules.length} doctrine rules`
572
- : 'no doctrine rules'
573
- const ok = await confirm(
574
- `Rebuild ${install.host} · ${install.scope} with ${what}? ` +
575
- `It rebuilds in place, non-destructive.${warn}`,
576
- { title: 'Rebuild with these rules?', confirmLabel: 'Rebuild' },
577
- )
578
- if (ok) onAction('install', { ...install, doctrines: keptPacks, excludeRules })
579
- }
580
374
 
581
375
  // ⚠ ONE SWITCH, APPLIED AT ONCE. Unlike the rule selection it is not a set: a click asks, and
582
376
  // a yes rebuilds the install with the opposite switch. Every other axis rides along unchanged
583
377
  // (`install` is spread, and the server reads the rest back off the install, per gate).
584
- const GATE_COPY = {
585
- I: {
586
- arm: 'Writes that would carry a credential-shaped string are refused again.',
587
- off:
588
- 'A write carrying a credential-shaped string (on OpenCode, also a write to a key ' +
589
- 'file) stops being refused. Rule I’s text still binds the agent; protected checks, ' +
590
- 'real data loss and commit/push consent stay gated.',
591
- },
592
- III: {
593
- arm: 'A turn that edited files cannot end before the project’s declared checks pass.',
594
- off:
595
- 'A turn that edited files may end without the checks in .geneseed/done-checks.txt ' +
596
- 'passing. Rule III’s text still binds the agent; every other gate stays.',
597
- },
598
- IV: {
599
- arm: 'Commands that would lose data nothing else holds ask again.',
600
- off:
601
- 'Commands that would really lose data — discarding uncommitted work, deleting an ' +
602
- 'unpushed branch, removing untracked files — stop asking. Rule IV’s text still binds ' +
603
- 'the agent; secrets, root-wide scans and commit/push consent stay gated.',
604
- },
605
- }
606
378
  const toggleGate = async (addr) => {
607
379
  if (!canApply) return
608
380
  const { key, label } = GATE_SWITCH[addr]
@@ -697,7 +469,6 @@ export default function Laws({ selected, overview, setup, onAction, dataRev }) {
697
469
  const shownCount =
698
470
  (showInv ? invRows.length : 0) +
699
471
  (showDoc ? packs.reduce((n, p) => n + p.rules.filter(match).length, 0) : 0)
700
- const maxPack = Math.max(1, ...packs.map((p) => p.rules.length))
701
472
 
702
473
  return (
703
474
  <>
@@ -855,77 +626,13 @@ export default function Laws({ selected, overview, setup, onAction, dataRev }) {
855
626
  </section>
856
627
 
857
628
  <aside className="aside-stack">
858
- <section className="panel" aria-labelledby="doc-packs">
859
- <div className="panel-head">
860
- <h2 id="doc-packs">Doctrine packs</h2>
861
- <span className="mono dim">
862
- {packs.filter(packOn).length}/{packs.length} on
863
- </span>
864
- </div>
865
- {packs.length ? (
866
- <ul className="pack-list">
867
- {packs.map((p) => {
868
- const on = p.rules.filter((r) => isOn(r.addr)).length
869
- return (
870
- <li key={p.pack} className={packOn(p) ? '' : 'off'}>
871
- <span className="pl-name" title={p.desc}>
872
- {p.title}
873
- </span>
874
- <span className="hbar" aria-hidden="true">
875
- <span style={{ width: `${(on / maxPack) * 100}%` }} />
876
- </span>
877
- <span className="mono pl-n">{on}</span>
878
- {canApply ? (
879
- <button
880
- type="button"
881
- className={`sw-toggle${packOn(p) ? ' on' : ''}`}
882
- role="switch"
883
- aria-checked={packOn(p)}
884
- aria-label={`${p.title} pack`}
885
- onClick={() => togglePack(p)}
886
- />
887
- ) : null}
888
- </li>
889
- )
890
- })}
891
- </ul>
892
- ) : (
893
- <p className="sub">This install predates the three-tier constitution.</p>
894
- )}
895
- {canApply && packs.length > 0 && (
896
- <>
897
- {losingConsent && (
898
- <p className="pack-warn" role="status" aria-live="polite">
899
- Dropping <b>process 5</b> also removes the commit/push consent gate:{' '}
900
- <code>git commit</code> and <code>git push</code> stop being confirmed at the
901
- tool boundary.{' '}
902
- {gateArmed
903
- ? 'Real data loss stays gated by Rule IV.'
904
- : 'Rule IV’s deletion gate is off on this install too.'}
905
- </p>
906
- )}
907
- <div className="pack-apply">
908
- <button type="button" className="btn" onClick={applyPacks} disabled={!dirty}>
909
- Apply{dirty ? ` (${pickedRules.length}/${allRules.length} rules)` : ''}
910
- </button>
911
- <button
912
- type="button"
913
- className="btn ghost"
914
- onClick={() => setPicked(deployedKey ? deployedKey.split(',') : [])}
915
- disabled={!dirty}
916
- >
917
- Revert
918
- </button>
919
- </div>
920
- <p className="panel-note" role="status" aria-live="polite">
921
- {dirty
922
- ? `Not applied yet. Apply rebuilds ${install.host} · ${install.scope} once, ` +
923
- 'with every change together.'
924
- : 'Matches the deployed install. Changing a pack rebuilds it.'}
925
- </p>
926
- </>
927
- )}
928
- </section>
629
+ <PackPanel
630
+ packs={packs}
631
+ sel={sel}
632
+ canApply={canApply}
633
+ install={install}
634
+ gateArmed={gateArmed}
635
+ />
929
636
  <GateAsks gates={setup?.gates} byAddr={byAddr} onJump={jumpToRule} />
930
637
  </aside>
931
638
  </div>
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/GreenhouseView-Dt_cIxAY.js","assets/sections-BET3c1WT.js","assets/react-BOF6yL40.js","assets/drawable-CE-arUnF.js","assets/index-3lnPT_1J.js","assets/api-CiXlkbe0.js","assets/index-BCJz4_8C.css","assets/jobBuckets-Dbq8ZlWW.js","assets/OperatorHudView-BJuCYsjf.js","assets/JournalView-ClbZj_YF.js"])))=>i.map(i=>d[i]);
2
- import{n as e,o as t,r as n,s as r}from"./sections-BET3c1WT.js";import{i,t as a}from"./react-BOF6yL40.js";import{t as o}from"./api-CiXlkbe0.js";import{A as s,F as c,G as l,J as u,L as d,M as f,N as p,P as m,R as h,S as g,W as _,_ as v,b as y,t as b,v as x}from"./index-3lnPT_1J.js";var S=r(i(),1),C={neutral:`Loaded & ready`,imperial:`The Codex in force`,military:`The unit stands ready`,cyberpunk:`Jacked in`,wizard:`Wards in place`,pirate:`The crew stands ready`,gamer:`Game loaded`,sports:`The squad takes the field`,biker:`The crew rolls out`,commentator:`Lights out, away we go`,verstappen:`Setup's in`,joker:`Mic check`,mean:`Rules are up`,marvin:`Online. Reluctantly.`},w=e=>e.deployed?C[e.theme]||`Loaded & ready`:`Not deployed`,T=a();function E({value:e,size:t=232}){let n=u(e,1100)??0,r=t/2-14,i=2*Math.PI*r,a=i*(1-n);return(0,T.jsxs)(`div`,{className:`ring-wrap`,style:{width:t,height:t},children:[(0,T.jsxs)(`svg`,{viewBox:`0 0 ${t} ${t}`,children:[(0,T.jsx)(`circle`,{cx:t/2,cy:t/2,r,fill:`none`,stroke:`var(--surface-3)`,strokeWidth:`10`}),(0,T.jsx)(`circle`,{cx:t/2,cy:t/2,r,fill:`none`,stroke:`var(--accent)`,strokeWidth:`10`,strokeLinecap:`round`,strokeDasharray:i,strokeDashoffset:a}),Array.from({length:48}).map((e,i)=>{let a=i/48*2*Math.PI,o=r-18,s=r-24,c=t/2+Math.cos(a)*o,l=t/2+Math.sin(a)*o,u=t/2+Math.cos(a)*s,d=t/2+Math.sin(a)*s;return(0,T.jsx)(`line`,{x1:c,y1:l,x2:u,y2:d,stroke:`var(--line-2)`,strokeWidth:`1`,opacity:i/48<n?.9:.25},i)})]}),(0,T.jsxs)(`div`,{className:`ring-center`,children:[(0,T.jsxs)(`div`,{className:`pct`,children:[Math.round(n*100),(0,T.jsx)(`span`,{style:{fontSize:20,color:`var(--text-3)`},children:`%`})]}),(0,T.jsx)(`div`,{className:`lbl`,children:`germination`})]})]})}function D({overview:e}){let t=f(e.diff),n=e.counts||{};return(0,T.jsxs)(`div`,{className:`card kpiband rise mb-16`,children:[[{key:`agents`,label:`Agents`,hash:`#/agents`},{key:`skills`,label:`Skills`,hash:`#/skills`},{key:`laws`,label:`Dictates`,hash:`#/laws`}].map(e=>{let t=n[e.key];return(0,T.jsxs)(`a`,{className:`kseg`,href:e.hash,title:`Open ${e.label}`,children:[(0,T.jsx)(`span`,{className:`kseg-n`+(t===0?` zero`:``),children:t==null?`—`:(0,T.jsx)(l,{value:t})}),(0,T.jsx)(`span`,{className:`kseg-l`,children:e.label})]},e.key)}),(0,T.jsx)(`div`,{className:`kseg-spacer`}),(0,T.jsxs)(`button`,{className:`kseg`+(t>0?` hot`:``),onClick:()=>_(`#/diff`),title:`Open changes`,children:[(0,T.jsx)(`span`,{className:`kseg-n`+(t===0?` zero`:``),children:(0,T.jsx)(l,{value:t})}),(0,T.jsx)(`span`,{className:`kseg-l`,children:`Local edits`}),t>0&&(0,T.jsx)(`span`,{className:`delta up`,children:`▲`})]})]})}function O({overview:t}){return(0,T.jsx)(`div`,{className:`genome`,children:n.map((n,r)=>{let i=e[n],a=t.counts?.[n];return(0,T.jsxs)(`div`,{className:`card gcell rise`,style:{"--i":r},onClick:()=>_(`#/section/`+n),children:[(0,T.jsxs)(`div`,{className:`gtop`,children:[(0,T.jsx)(`span`,{className:`gname`,children:i.label}),(0,T.jsx)(s,{name:i.icon,className:`gicon`})]}),(0,T.jsx)(`div`,{className:`gcount`+(a===0?` zero`:``),children:a==null?`—`:(0,T.jsx)(l,{value:a})}),(0,T.jsx)(`div`,{className:`gdesc`,children:i.desc})]},n)})})}function k({jobs:e}){if(!e||e.length===0)return(0,T.jsx)(`div`,{className:`feed`,children:(0,T.jsxs)(`div`,{className:`empty`,children:[(0,T.jsx)(`div`,{className:`big`,children:`No activity yet`}),`Actions you run appear here.`]})});let t={done:`ok`,running:`acc`,failed:`bad`},n=[...e].sort((e,t)=>t.started-e.started).slice(0,8);return(0,T.jsx)(`div`,{className:`feed`,children:n.map(e=>(0,T.jsxs)(`div`,{className:`feed-row`,children:[(0,T.jsx)(`span`,{className:`feed-dot ${t[e.status]||`ok`}`}),(0,T.jsx)(`span`,{className:`feed-txt`,children:(0,T.jsx)(`b`,{children:e.action})}),(0,T.jsxs)(`span`,{className:`feed-when`,children:[c(e.started),` ago`]})]},e.id))})}function A({overview:e,sigil:t,setup:r,jobs:i,onAction:a}){let o=w(e),c=m(e,r);return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`div`,{className:`card pad-lg rise mb-16`,children:(0,T.jsxs)(`div`,{className:`hero`,children:[(0,T.jsx)(E,{value:c}),(0,T.jsxs)(`div`,{className:`hero-facts`,children:[(0,T.jsx)(`div`,{className:`ttl`,children:o}),t&&(0,T.jsxs)(`div`,{className:`voice-readout`,children:[(0,T.jsx)(`span`,{className:`vr-cur`,children:`▕`}),(0,T.jsx)(`span`,{className:`vr-txt`,children:t})]},e.theme),(0,T.jsxs)(`p`,{className:`sub`,children:[`One source rendered into `,(0,T.jsx)(`code`,{children:e.target}),`. Every repo on this machine inherits it.`]}),(0,T.jsxs)(`div`,{className:`hero-chips`,children:[(0,T.jsxs)(`span`,{className:`chip`,children:[(0,T.jsx)(`span`,{className:`ck`,children:`voice`}),(0,T.jsx)(`span`,{className:`cv`,style:{textTransform:`capitalize`},children:e.theme})]}),(0,T.jsxs)(`span`,{className:`chip`,children:[(0,T.jsx)(`span`,{className:`ck`,children:`mode`}),(0,T.jsx)(`span`,{className:`cv`,children:e.emit})]}),(0,T.jsxs)(`span`,{className:`chip`,children:[(0,T.jsx)(`span`,{className:`ck`,children:`footprint`}),(0,T.jsx)(`span`,{className:`cv`,children:e.footprint})]}),(0,T.jsxs)(`span`,{className:`chip`,children:[(0,T.jsx)(`span`,{className:`ck`,children:`built`}),(0,T.jsx)(`span`,{className:`cv`,children:e.build_time||`unknown`})]}),(0,T.jsxs)(`span`,{className:`chip`,children:[(0,T.jsx)(`span`,{className:`ck`,children:`fp`}),(0,T.jsx)(`span`,{className:`cv`,children:r?.installed_fp||`—`})]})]}),(0,T.jsxs)(`div`,{className:`row wrap gap-10`,children:[(0,T.jsxs)(`button`,{className:`btn`,onClick:()=>a(`update`),children:[(0,T.jsx)(s,{name:`refresh`}),`Update`]}),(0,T.jsxs)(`button`,{className:`btn ghost`,onClick:()=>a(`build-all`),children:[(0,T.jsx)(s,{name:`build`}),`Rebuild`]}),(0,T.jsxs)(`button`,{className:`btn ghost`,onClick:()=>a(`doctor`),children:[(0,T.jsx)(s,{name:`doctor`}),`Run doctor`]})]})]})]})}),(0,T.jsx)(D,{overview:e}),(0,T.jsxs)(`div`,{className:`grid split-status`,children:[(0,T.jsxs)(`div`,{className:`card pad-lg`,children:[(0,T.jsxs)(`div`,{className:`card-head`,children:[(0,T.jsx)(`h3`,{children:`Capability genome`}),(0,T.jsx)(`div`,{className:`right`,children:(0,T.jsxs)(`span`,{className:`tick`,children:[n.length,` sections`]})})]}),(0,T.jsx)(O,{overview:e})]}),(0,T.jsxs)(`div`,{className:`card pad-lg`,children:[(0,T.jsxs)(`div`,{className:`card-head`,children:[(0,T.jsx)(`h3`,{children:`Recent activity`}),(0,T.jsx)(`div`,{className:`right`,children:(0,T.jsxs)(`span`,{className:`badge acc`,children:[(0,T.jsx)(`span`,{className:`dot`}),`live`]})})]}),(0,T.jsx)(k,{jobs:i})]})]})]})}function j({k:t,overview:n,max:r}){let i=e[t],a=n.counts?.[t]??0;return(0,T.jsxs)(`div`,{className:`strand`,children:[(0,T.jsxs)(`span`,{className:`strand-name`,children:[(0,T.jsx)(`span`,{className:`strand-dot`}),(0,T.jsx)(`a`,{href:`#/section/`+t,className:`strand-link stretch-link`,children:i.label})]}),(0,T.jsx)(`div`,{className:`hbar`,children:(0,T.jsx)(`i`,{style:{width:`${a/r*100}%`}})}),(0,T.jsx)(`span`,{className:`strand-val`,children:a})]})}function M({overview:e,sigil:t,setup:r,jobs:i}){let a=p(e.counts),o=r?.version_verdict||``,s=o.includes(`up to date`),c=f(e.diff),l=[[`Source`,`src/, the canonical genetic material`,r?.source_fp||`—`,!0],[`Render`,`geneseed build → ${e.emit}`,e.theme+` voice`,!0],[`Deployed`,e.target,`inherited by every repo`,!1]];return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`div`,{className:`mb-16`,children:(0,T.jsxs)(`div`,{className:`card pad-lg rise`,style:{position:`relative`,overflow:`hidden`},children:[(0,T.jsx)(`h2`,{className:`h`,style:{fontSize:22,margin:`0 0 18px`},children:`Gene-seed lineage`}),(0,T.jsxs)(`div`,{className:`lineage-track`,children:[(0,T.jsx)(`div`,{className:`spine`}),l.map(([e,t,n,r],i)=>(0,T.jsxs)(`div`,{className:`lineage-step`,children:[(0,T.jsx)(`span`,{className:`node ${r?`on`:``}`}),(0,T.jsx)(`div`,{className:`lt`,children:e}),(0,T.jsx)(`div`,{className:`ld`,children:t}),(0,T.jsx)(`div`,{className:`ltag`,children:n})]},i))]}),(0,T.jsx)(`hr`,{className:`hr`}),t&&(0,T.jsxs)(`div`,{className:`voice-readout`,style:{marginBottom:14},children:[(0,T.jsx)(`span`,{className:`vr-cur`,children:`▕`}),(0,T.jsx)(`span`,{className:`vr-txt`,children:t})]},e.theme),(0,T.jsxs)(`div`,{className:`row wrap gap-10`,children:[(0,T.jsxs)(`span`,{className:`badge ${s?`ok`:`warn`}`,children:[(0,T.jsx)(`span`,{className:`dot`}),`in sync · `,o]}),(0,T.jsxs)(`span`,{className:`badge`,children:[(0,T.jsx)(`span`,{className:`dot`}),c,` local edits`]})]})]})}),(0,T.jsxs)(`div`,{className:`grid split-even`,children:[(0,T.jsxs)(`div`,{className:`card pad-lg`,children:[(0,T.jsxs)(`div`,{className:`card-head`,children:[(0,T.jsx)(`h3`,{children:`Genome strand`}),(0,T.jsx)(`div`,{className:`right`,children:(0,T.jsx)(`span`,{className:`tick`,children:`by volume`})})]}),n.map(t=>(0,T.jsx)(j,{k:t,overview:e,max:a},t))]}),(0,T.jsxs)(`div`,{className:`card pad-lg`,children:[(0,T.jsx)(`div`,{className:`card-head`,children:(0,T.jsx)(`h3`,{children:`Recent activity`})}),(0,T.jsx)(k,{jobs:i})]})]})]})}function N({overview:t,setup:r,jobs:i}){let a=n.reduce((e,n)=>e+(t.counts?.[n]??0),0),o=p(t.counts),s=t.doctor?.ok,c=t.doctor?.problems?.length??0,l=f(t.diff);return(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`div`,{className:`card pad-md rise mb-16`,children:(0,T.jsx)(`div`,{className:`row wrap between gap-16`,children:(0,T.jsxs)(`div`,{className:`row`,style:{gap:20,flexWrap:`wrap`},children:[(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`div`,{className:`tick`,children:`status`}),(0,T.jsx)(`div`,{className:`row`,style:{gap:8,marginTop:4},children:(0,T.jsxs)(`span`,{className:`badge ${t.deployed?`ok`:`warn`}`,children:[(0,T.jsx)(`span`,{className:`dot`}),t.deployed?`deployed`:`not deployed`]})})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`div`,{className:`tick`,children:`voice`}),(0,T.jsx)(`div`,{className:`metric`,style:{fontSize:18,marginTop:6,textTransform:`capitalize`},children:t.theme})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`div`,{className:`tick`,children:`mode`}),(0,T.jsx)(`div`,{className:`mono`,style:{fontSize:14,marginTop:6},children:t.emit})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`div`,{className:`tick`,children:`fingerprint`}),(0,T.jsx)(`div`,{className:`mono`,style:{fontSize:14,marginTop:6,color:`var(--accent)`},children:r?.installed_fp||`—`})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`div`,{className:`tick`,children:`doctor`}),(0,T.jsx)(`div`,{className:`row`,style:{gap:8,marginTop:4},children:s?(0,T.jsxs)(`span`,{className:`badge ok`,children:[(0,T.jsx)(`span`,{className:`dot`}),`clean`]}):(0,T.jsxs)(`span`,{className:`badge warn`,children:[(0,T.jsx)(`span`,{className:`dot`}),c,` issue`,c===1?``:`s`]})})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`div`,{className:`tick`,children:`edits`}),(0,T.jsx)(`div`,{className:`metric`,style:{fontSize:18,marginTop:6},children:l})]})]})})}),(0,T.jsxs)(`div`,{className:`grid split-operator`,children:[(0,T.jsxs)(`div`,{className:`card rise`,style:{"--i":1},children:[(0,T.jsxs)(`div`,{className:`card-head pad-lg`,style:{padding:`18px 20px 0`,marginBottom:14},children:[(0,T.jsx)(`h3`,{children:`Sections`}),(0,T.jsx)(`div`,{className:`right`,children:(0,T.jsxs)(`span`,{className:`tick`,children:[a,` entries total`]})})]}),(0,T.jsxs)(`table`,{className:`tbl`,children:[(0,T.jsx)(`thead`,{children:(0,T.jsxs)(`tr`,{children:[(0,T.jsx)(`th`,{children:`Section`}),(0,T.jsx)(`th`,{children:`Detail`}),(0,T.jsx)(`th`,{style:{width:130},children:`Share`}),(0,T.jsx)(`th`,{className:`num`,children:`Count`})]})}),(0,T.jsx)(`tbody`,{children:n.map(n=>{let r=e[n],i=t.counts?.[n]??0;return(0,T.jsxs)(`tr`,{className:`clickable`,children:[(0,T.jsx)(`td`,{className:`name`,children:(0,T.jsx)(`a`,{href:`#/section/`+n,className:`stretch-link`,children:r.label})}),(0,T.jsx)(`td`,{className:`muted`,children:r.desc}),(0,T.jsx)(`td`,{children:(0,T.jsx)(`div`,{className:`hbar`,children:(0,T.jsx)(`i`,{style:{width:`${i/o*100}%`}})})}),(0,T.jsx)(`td`,{className:`num`,children:i})]},n)})})]})]}),(0,T.jsxs)(`div`,{className:`card pad-lg rise`,style:{"--i":2},children:[(0,T.jsx)(`div`,{className:`card-head`,children:(0,T.jsx)(`h3`,{children:`Run log`})}),(0,T.jsx)(k,{jobs:i})]})]})]})}function P(){let[e,t]=(0,S.useState)(!1),[n,r]=(0,S.useState)(null);return(0,T.jsxs)(`div`,{className:`stale-banner`,role:`alert`,children:[(0,T.jsx)(`span`,{children:n||`This console is running code from before your last upgrade.`}),(0,T.jsx)(`button`,{className:`btn sm`,onClick:async()=>{t(!0),r(null);try{await h()}catch(e){r(e.message),t(!1)}},disabled:e,children:e?`Restarting…`:`Restart`})]})}var F=t({default:()=>z}),I=(0,S.lazy)(()=>b(()=>import(`./GreenhouseView-Dt_cIxAY.js`),__vite__mapDeps([0,1,2,3,4,5,6,7]))),L=(0,S.lazy)(()=>b(()=>import(`./OperatorHudView-BJuCYsjf.js`),__vite__mapDeps([8,1,2,4,5,6,7]))),R=(0,S.lazy)(()=>b(()=>import(`./JournalView-ClbZj_YF.js`),__vite__mapDeps([9,1,2,5,3,4,6])));function z({overview:e,overviewError:t,onRetry:n,themes:r,setup:i,runs:a,onAction:s,layout:c=`cultivar`,dataRev:l}){let u=c,[f,p]=(0,S.useState)(`status`),m=e&&r.find(t=>t.name===e.theme)?.sigil||``,{data:h}=d(()=>u===`greenhouse`||u===`operator`?o.doctor().catch(()=>null):Promise.resolve(null),[u,l]),{data:_}=d(()=>u===`journal`?o.recent().catch(()=>null):Promise.resolve(null),[u,l]);if(!e)return t?(0,T.jsxs)(`div`,{children:[(0,T.jsx)(x,{error:`Could not load the harness overview: ${t}`}),(0,T.jsx)(`button`,{className:`btn`,onClick:n,children:`Retry`})]}):(0,T.jsx)(y,{});let b=e.daemon_stale?(0,T.jsx)(P,{}):null;return e.deployed?f===`status`&&u===`journal`?(0,T.jsxs)(S.Suspense,{fallback:(0,T.jsx)(y,{}),children:[b,(0,T.jsx)(R,{overview:e,recent:_,onAction:s,onDirection:p,dataRev:l})]}):(0,T.jsxs)(T.Fragment,{children:[b,(0,T.jsx)(`div`,{className:`head-row`,children:(0,T.jsx)(g,{"aria-label":`Dashboard view`,children:[[`status`,`Status`],[`lineage`,`Lineage`],[`operator`,`Operator`]].map(([e,t])=>(0,T.jsx)(`button`,{className:f===e?`on`:``,onClick:()=>p(e),"aria-pressed":f===e,children:t},e))})}),(0,T.jsxs)(`div`,{className:`view-in`,children:[f===`status`&&u===`cultivar`&&(0,T.jsx)(A,{overview:e,sigil:m,setup:i,jobs:a,onAction:s}),f===`status`&&u===`greenhouse`&&(0,T.jsx)(S.Suspense,{fallback:(0,T.jsx)(y,{}),children:(0,T.jsx)(I,{overview:e,sigil:m,jobs:a,doctor:h,onAction:s})}),f===`status`&&u===`operator`&&(0,T.jsx)(S.Suspense,{fallback:(0,T.jsx)(y,{}),children:(0,T.jsx)(L,{overview:e,jobs:a,doctor:h,onAction:s})}),f===`lineage`&&(0,T.jsx)(M,{overview:e,sigil:m,setup:i,jobs:a}),f===`operator`&&(0,T.jsx)(N,{overview:e,setup:i,jobs:a})]},f)]}):(0,T.jsxs)(T.Fragment,{children:[b,(0,T.jsx)(v,{onAction:s})]})}export{z as default,w as n,F as t};
@@ -1,2 +0,0 @@
1
- import{n as e,r as t,s as n}from"./sections-BET3c1WT.js";import{i as r,t as i}from"./react-BOF6yL40.js";import{t as a}from"./drawable-CE-arUnF.js";import{A as o,G as s,K as c,M as l,Z as u,et as d,q as f}from"./index-3lnPT_1J.js";import{t as p}from"./jobBuckets-Dbq8ZlWW.js";import{n as m}from"./Dashboard-CmSn6JfK.js";var h=n(r(),1),g=i(),_=12,v=120,y=[`#2BB673`,`#16A6A6`,`#E8A23B`,`#E07A5F`,`#8E7DBE`,`#5BD08A`,`#79856E`],b=650;function x({segments:e,size:t=186,stroke:n=26,caption:r=`capabilities`}){let i=e.reduce((e,t)=>e+t.value,0)||1,o=(0,h.useRef)(null),l=e.map(e=>e.value).join(`,`);(0,h.useLayoutEffect)(()=>{let t=o.current?.querySelectorAll(`path`);if(!t?.length||!c())return;let n=e.filter(e=>e.value>0).map(e=>e.value/i),r=n.map((e,t)=>n.slice(0,t).reduce((e,t)=>e+t,0)),s=a(t);u(s,{draw:`0 0`});let l=d(s,{draw:[`0 0`,`0 1`],duration:(e,t)=>Math.max(b*n[t],60),delay:(e,t)=>b*r[t],ease:`linear`});return f(l,b)},[l]);let p=t/2-n/2,m=t/2,_=t/2,v=[],y=0;for(let t of e)v.push(y),y+=t.value;return(0,g.jsxs)(`svg`,{width:t,height:t,viewBox:`0 0 ${t} ${t}`,children:[(0,g.jsx)(`circle`,{cx:m,cy:_,r:p,fill:`none`,stroke:`var(--surface-3)`,strokeWidth:n}),(0,g.jsx)(`g`,{ref:o,children:e.map((e,t)=>{if(e.value/i<=0)return null;let r=v[t]/i*2*Math.PI-Math.PI/2,a=(v[t]+e.value)/i*2*Math.PI-Math.PI/2,o=m+p*Math.cos(r),s=_+p*Math.sin(r),c=m+p*Math.cos(a),l=_+p*Math.sin(a),u=+(a-r>Math.PI);return(0,g.jsx)(`path`,{d:`M ${o} ${s} A ${p} ${p} 0 ${u} 1 ${c} ${l}`,fill:`none`,stroke:e.color,strokeWidth:n,strokeLinecap:`butt`,children:(0,g.jsxs)(`title`,{children:[e.label,`: `,e.value]})},t)})}),(0,g.jsx)(`text`,{x:m,y:_-4,textAnchor:`middle`,className:`donut-c-num`,children:(0,g.jsx)(s,{value:i,duration:b})}),(0,g.jsx)(`text`,{x:m,y:_+16,textAnchor:`middle`,className:`donut-c-cap`,children:r})]})}function S(e){if(e.length<2)return e.length?`M${e[0][0]},${e[0][1]}`:``;let t=`M${e[0][0]},${e[0][1]}`;for(let n=0;n<e.length-1;n++){let r=e[n-1]||e[n],i=e[n],a=e[n+1],o=e[n+2]||a,s=i[0]+(a[0]-r[0])/6,c=i[1]+(a[1]-r[1])/6,l=a[0]-(o[0]-i[0])/6,u=a[1]-(o[1]-i[1])/6;t+=` C${s},${c} ${l},${u} ${a[0]},${a[1]}`}return t}function C({data:e,height:t=156,accent:n}){if(!e.length)return null;let r=t,i=Math.max(...e.map(e=>e.v),1)+1,a=e.length>1?588/(e.length-1):588,o=e.map((e,t)=>[6+t*a,r-6-e.v/i*(r-14-6)]),s=S(o),c=o[o.length-1],l=o[0],u=`${s} L${c[0]},${r} L${l[0]},${r} Z`;return(0,g.jsxs)(`svg`,{viewBox:`0 0 600 ${r}`,preserveAspectRatio:`none`,style:{width:`100%`,height:t,display:`block`,overflow:`visible`},children:[(0,g.jsx)(`defs`,{children:(0,g.jsxs)(`linearGradient`,{id:`b-grad`,x1:`0`,y1:`0`,x2:`0`,y2:`1`,children:[(0,g.jsx)(`stop`,{offset:`0`,stopColor:n,stopOpacity:`.28`}),(0,g.jsx)(`stop`,{offset:`1`,stopColor:n,stopOpacity:`0`})]})}),(0,g.jsx)(`path`,{d:u,fill:`url(#b-grad)`}),(0,g.jsx)(`path`,{d:s,fill:`none`,stroke:n,strokeWidth:`2`,strokeLinejoin:`round`,strokeLinecap:`round`,vectorEffect:`non-scaling-stroke`}),(0,g.jsx)(`circle`,{cx:c[0],cy:c[1],r:`3.5`,fill:n,vectorEffect:`non-scaling-stroke`})]})}function w({label:e,value:t,sub:n,color:r,icon:i}){return(0,g.jsxs)(`div`,{className:`b-tile`,children:[(0,g.jsx)(`span`,{className:`b-tile-ic`,style:{background:`color-mix(in srgb, ${r} 18%, transparent)`,color:r},children:(0,g.jsx)(o,{name:i})}),(0,g.jsxs)(`div`,{className:`b-tile-body`,children:[(0,g.jsx)(`div`,{className:`b-tile-val`+(t===0?` zero`:``),children:t}),(0,g.jsx)(`div`,{className:`b-tile-label`,children:e})]}),(0,g.jsx)(`div`,{className:`b-tile-sub`,children:n})]})}function T({overview:n,sigil:r,jobs:i,doctor:a,onAction:c}){let u=n.counts||{},d=a?.groups||[],f=d.length>0,h=d.filter(e=>e.problems.length===0).length,b=d.length||1,S=m(n),T=l(n.diff),E=t.filter(e=>(u[e]||0)>0).map((t,n)=>({label:e[t].label,value:u[t]||0,color:y[n%y.length]})),D=E.reduce((e,t)=>e+t.value,0),O=p(i||[],10),k=O.reduce((e,t)=>e+t.v,0);return(0,g.jsxs)(g.Fragment,{children:[(0,g.jsxs)(`div`,{className:`b-greet`,children:[(0,g.jsxs)(`div`,{children:[(0,g.jsx)(`div`,{className:`eyebrow`,children:`your harness`}),(0,g.jsx)(`h1`,{className:`h b-h`,children:S}),(0,g.jsx)(`p`,{className:`sub`,children:r||`A friendly read of every layer growing in your harness.`})]}),(0,g.jsxs)(`div`,{className:`row gap-8`,children:[(0,g.jsxs)(`button`,{className:`btn`,onClick:()=>c(`update`),children:[(0,g.jsx)(o,{name:`refresh`}),`Update`]}),(0,g.jsxs)(`button`,{className:`btn ghost`,onClick:()=>c(`build-all`),children:[(0,g.jsx)(o,{name:`build`}),`Rebuild`]})]})]}),(0,g.jsxs)(`div`,{className:`grid b-hero-grid mb-16`,children:[(0,g.jsxs)(`div`,{className:`card b-hero`,children:[(0,g.jsx)(`div`,{className:`b-hero-ring`,children:(0,g.jsx)(x,{segments:[{label:`pass`,value:h,color:y[0]},{label:`attention`,value:Math.max(b-h,0),color:y[2]}],size:168,stroke:20,caption:`checks`})}),(0,g.jsxs)(`div`,{className:`b-hero-side`,children:[(0,g.jsx)(`h3`,{className:`b-hero-title`,children:f?`${h} of ${b} checks pass`:`Running checks…`}),(0,g.jsxs)(`p`,{className:`sub`,children:[`One source, rendered into `,(0,g.jsx)(`code`,{children:n.target}),` and inherited by every repo on this machine.`]}),f&&(0,g.jsx)(`ul`,{className:`b-hero-checks`,children:d.map(e=>{let t=e.problems.length===0;return(0,g.jsxs)(`li`,{className:`b-hcheck ${t?`ok`:`bad`}`,title:t?`clean`:e.problems.join(`; `),children:[(0,g.jsx)(`span`,{className:`b-hcheck-mark`,children:t?`✓`:`!`}),(0,g.jsx)(`span`,{className:`b-hcheck-label`,children:e.label})]},e.label)})}),(0,g.jsxs)(`div`,{className:`b-chips`,children:[(0,g.jsxs)(`span`,{className:`b-chip`,children:[(0,g.jsx)(`b`,{style:{textTransform:`capitalize`},children:n.theme}),` voice`]}),(0,g.jsx)(`span`,{className:`b-chip`,children:(0,g.jsx)(`b`,{children:n.emit})}),(0,g.jsxs)(`span`,{className:`b-chip`,children:[`built `,(0,g.jsx)(`b`,{children:n.build_time||`unknown`})]})]})]})]}),(0,g.jsxs)(`div`,{className:`b-tiles`,children:[(0,g.jsx)(w,{label:`Agents`,value:u.agents??`—`,sub:`specialists`,color:y[0],icon:`layers`}),(0,g.jsx)(w,{label:`Skills`,value:u.skills??`—`,sub:`workflows`,color:y[1],icon:`skill`}),(0,g.jsx)(w,{label:`Dictates`,value:u.laws??`—`,sub:u.doctrines?`${u.doctrines.active}/${u.doctrines.total} packs · ${u.doctrines.rules} rules`:`all upheld`,color:y[2],icon:`law`}),(0,g.jsx)(w,{label:`Edits`,value:T,sub:`to graft`,color:y[3],icon:`changes`})]})]}),(0,g.jsxs)(`div`,{className:`grid split-even mb-16`,children:[(0,g.jsxs)(`div`,{className:`card pad-lg b-mix-card`,children:[(0,g.jsxs)(`div`,{className:`card-head`,children:[(0,g.jsx)(`h3`,{children:`Capability mix`}),(0,g.jsx)(`div`,{className:`right`,children:(0,g.jsxs)(`span`,{className:`tick`,children:[D,` total`]})})]}),(0,g.jsxs)(`div`,{className:`b-mix`,children:[(0,g.jsx)(x,{segments:E,size:186,stroke:26}),(0,g.jsx)(`div`,{className:`b-legend`,children:E.map(e=>(0,g.jsxs)(`div`,{className:`b-leg-row`,children:[(0,g.jsx)(`span`,{className:`b-leg-dot`,style:{background:e.color}}),(0,g.jsx)(`span`,{className:`b-leg-name`,children:e.label}),(0,g.jsx)(`span`,{className:`b-leg-bar`,children:(0,g.jsx)(`i`,{style:{width:`${e.value/D*100}%`,background:e.color}})}),(0,g.jsx)(`span`,{className:`b-leg-val`,children:e.value})]},e.label))})]})]}),(0,g.jsxs)(`div`,{className:`card pad-lg`,children:[(0,g.jsxs)(`div`,{className:`card-head`,children:[(0,g.jsx)(`h3`,{children:`Recent runs`}),(0,g.jsx)(`div`,{className:`right`,children:(0,g.jsxs)(`span`,{className:`badge ok`,children:[(0,g.jsx)(`span`,{className:`dot`}),`job log`]})})]}),(0,g.jsxs)(`div`,{className:`b-stat-lead`,children:[(0,g.jsx)(`span`,{className:`b-stat-big`,children:(0,g.jsx)(s,{value:k})}),(0,g.jsxs)(`span`,{className:`b-stat-cap`,children:[`runs in the last 10 days · `,h,`/`,b,` checks pass now`]})]}),(0,g.jsx)(C,{data:O,accent:y[0],height:156})]})]}),(0,g.jsxs)(`div`,{className:`card pad-lg`,children:[(0,g.jsxs)(`div`,{className:`card-head`,children:[(0,g.jsx)(`h3`,{children:`Recent activity`}),(0,g.jsx)(`div`,{className:`right`,children:(0,g.jsxs)(`span`,{className:`tick`,children:[`last `,Math.min(i?.length||0,12),` runs`]})})]}),(0,g.jsxs)(`div`,{className:`b-timeline`,children:[(i||[]).slice(0,_).map(e=>{let t=e.status===`done`,n=e.status===`failed`?`warn`:t?`ok`:`acc`;return(0,g.jsxs)(`div`,{className:`b-tl-row`,children:[(0,g.jsx)(`span`,{className:`b-tl-node ${n}`}),(0,g.jsxs)(`div`,{className:`b-tl-body`,children:[(0,g.jsx)(`b`,{children:e.action}),e.output?`: ${e.output.split(`
2
- `)[0].slice(0,v)}`:``]}),(0,g.jsx)(`span`,{className:`b-tl-when`,children:e.duration?`${e.duration}s`:e.status})]},e.id)}),(!i||i.length===0)&&(0,g.jsxs)(`div`,{className:`b-tl-row`,children:[(0,g.jsx)(`span`,{className:`b-tl-node`}),(0,g.jsx)(`div`,{className:`b-tl-body sub`,children:`No runs yet. Trigger an action to populate this.`}),(0,g.jsx)(`span`,{className:`b-tl-when`,children:`—`})]})]})]})]})}export{T as default};
@@ -1,2 +0,0 @@
1
- import{s as e}from"./sections-BET3c1WT.js";import{i as t,t as n}from"./react-BOF6yL40.js";import{t as r}from"./api-CiXlkbe0.js";import{A as i,B as a,D as o,E as s,L as c,O as l,R as u,S as d,V as f,b as p,j as m,k as h,v as g,x as _,y as v,z as y}from"./index-3lnPT_1J.js";import{t as b}from"./Tabs-GPQlocTw.js";var x=e(t(),1),S=n();function C({label:e,value:t,options:n,onChange:r}){return n.length?(0,S.jsx)(`select`,{className:`sel`,"aria-label":e,value:t,onChange:e=>r(e.target.value),children:n.map(e=>(0,S.jsx)(`option`,{value:e,children:e},e))}):null}var w=[`full`,`lean`];function T({on:e,disabled:t,label:n,onToggle:r}){return(0,S.jsx)(`input`,{type:`checkbox`,role:`switch`,className:`sw-toggle${e?` on`:``}`,checked:e,"aria-checked":e,disabled:t,"aria-label":n,onChange:r,onKeyDown:e=>{e.key===`Enter`&&!t&&r()}})}var E=[{key:`theme`,name:`voice`,title:`Voice`},{key:`footprint`,name:`footprint`,title:`Footprint`},{key:`posture`,name:`posture`,title:`Posture`},{key:`mode`,name:`mode`,title:`Mode`},{key:`trust`,name:`trust`,title:`Loop trust`}];function D({value:e,options:t,onChange:n,who:r}){return E.map(i=>(0,S.jsxs)(`label`,{className:`dp-field`,children:[(0,S.jsx)(`span`,{children:i.title}),(0,S.jsx)(C,{label:`${i.name} for ${r}`,value:e[i.key],options:t[i.key],onChange:e=>n(i.key,e)})]},i.key))}function O({host:e,theme:t,options:n,onAction:i,onClose:a,onNote:c}){let[l,u]=(0,x.useState)({path:``,host:e,theme:t,footprint:`full`,posture:`peer`,mode:`direct`,trust:`balanced`}),[d,f]=(0,x.useState)(!1),p=(e,t)=>u(n=>({...n,[e]:t})),m=async()=>{f(!0),c(``);try{let e=await r.pickFolder();e.path?p(`path`,e.path):e.error&&c(e.error)}catch(e){c(e.message)}finally{f(!1)}},h=async()=>{let e=l.path.trim();if(!e){c(`Choose or type a folder to deploy into.`);return}c(``),await i?.(`deploy`,{host:l.host,path:e,theme:l.theme,footprint:l.footprint,posture:l.posture,mode:l.mode,trust:l.trust})&&a()};return(0,S.jsxs)(`div`,{className:`deploy-pop`,children:[(0,S.jsxs)(`div`,{className:`dp-row`,children:[(0,S.jsx)(`input`,{className:`inp dp-path`,type:`text`,placeholder:`/path/to/project, or click Browse…`,value:l.path,onChange:e=>p(`path`,e.target.value),onKeyDown:e=>e.key===`Enter`&&h(),"aria-label":`Folder to deploy into`}),(0,S.jsx)(`button`,{className:`btn ghost sm`,disabled:d,onClick:m,children:d?`Choosing…`:`Browse…`})]}),(0,S.jsxs)(`div`,{className:`dp-row`,children:[(0,S.jsxs)(`label`,{className:`dp-field`,children:[(0,S.jsx)(`span`,{children:`Deploy as`}),(0,S.jsx)(`select`,{className:`sel`,"aria-label":`host for the new harness`,value:l.host,onChange:e=>p(`host`,e.target.value),children:s.map(e=>(0,S.jsx)(`option`,{value:e.id,children:e.label},e.id))})]}),(0,S.jsx)(D,{value:l,options:n,onChange:p,who:`the new harness`}),(0,S.jsx)(`button`,{className:`btn sm`,onClick:h,children:`Deploy`}),(0,S.jsx)(`button`,{className:`btn ghost sm`,onClick:a,children:`Cancel`})]}),(0,S.jsxs)(`p`,{className:`sub dp-note`,children:[`Adds a per-repo harness (`,(0,S.jsx)(`code`,{children:o(l.host).deployAdds}),`) into the folder, non-destructively. It’s then tracked here even after you leave its directory.`]})]})}function k(){let{data:e,error:t,reload:n}=c(()=>r.excludes(),[]),[a,o]=(0,x.useState)(!1),[s,l]=(0,x.useState)([]),u=async(e,t)=>{o(!0);try{let n=await r.excludeMutate(e,t);l(n.messages||[])}catch(e){l(e.body?.messages||[e.message])}finally{o(!1),n()}};return t||!e?.installs?.length?null:(0,S.jsxs)(`div`,{className:`card pad-lg mb-16`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`Excluded folders`})}),(0,S.jsx)(`p`,{className:`sub mb-16`,children:`Sovereign repos: inside these folders every global harness goes dormant — hooks stay silent and the global preamble is not loaded.`}),(e.excludes||[]).map(e=>(0,S.jsxs)(`div`,{className:`row wrap between gap-12`,children:[(0,S.jsx)(`code`,{children:e.path}),(0,S.jsxs)(`span`,{className:`mono muted`,children:[`[`,e.hosts.join(`, `),`]`]}),(0,S.jsx)(`button`,{className:`btn ghost sm`,disabled:a,onClick:()=>u(`remove`,e.path),children:`Remove`})]},e.path)),(0,S.jsxs)(`button`,{className:`btn ghost sm`,disabled:a,onClick:async()=>{o(!0);try{let e=await r.pickFolder();e.path?await u(`add`,e.path):e.error&&l([e.error])}catch(e){l([e.message])}finally{o(!1)}},children:[(0,S.jsx)(i,{name:`folder`}),` Exclude a folder…`]}),s.map((e,t)=>(0,S.jsx)(`p`,{className:`sub`,children:e},t))]})}function A({inst:e,memory:t,busy:n,onMemory:r,onRemove:i,onCancel:a}){return(0,S.jsxs)(`div`,{className:`h-remove`,children:[(0,S.jsxs)(`p`,{className:`hr-msg`,children:[(0,S.jsx)(`strong`,{children:e.scope===`project`?`Remove this harness from the folder?`:`Remove the global ${e.host} install?`}),` `,(0,S.jsxs)(`span`,{className:`sub`,children:[`Deletes `,(0,S.jsx)(`code`,{children:h(e.host,e.scope)}),e.scope===`project`?` and de-lists it.`:`; the row stays, marked “not installed.”`,` `,`This can’t be undone.`]})]}),(0,S.jsxs)(`label`,{className:`field`,children:[(0,S.jsx)(`span`,{children:`Memory and notebook`}),(0,S.jsxs)(`select`,{className:`sel`,"aria-label":`memory disposition`,value:t,onChange:e=>r(e.target.value),children:[(0,S.jsx)(`option`,{value:`keep`,children:`keep in place`}),(0,S.jsx)(`option`,{value:`archive`,children:`archive aside`}),(0,S.jsx)(`option`,{value:`delete`,children:`delete too`})]})]}),(0,S.jsxs)(`div`,{className:`row gap-8`,children:[(0,S.jsx)(`button`,{type:`button`,className:`btn danger`,disabled:n,onClick:i,children:n?`Removing…`:`Remove`}),(0,S.jsx)(`button`,{type:`button`,className:`btn ghost`,onClick:a,children:`Cancel`})]})]})}function j({targets:e,onReveal:t}){let n=e.flatMap(e=>e.servers);return(0,S.jsxs)(`div`,{className:`ip-block`,children:[(0,S.jsxs)(`span`,{className:`ip-label`,children:[`MCP servers `,(0,S.jsx)(`span`,{className:`mono dim`,children:n.length})]}),e.map(e=>(0,S.jsxs)(`div`,{className:`mcp-target`,children:[(0,S.jsxs)(`div`,{className:`mt-head`,children:[(0,S.jsx)(`code`,{title:e.path,children:e.label}),(0,S.jsx)(`button`,{type:`button`,className:`btn ghost sm`,onClick:()=>t(e),title:`Open the folder holding ${e.path} to edit it`,children:`Open folder`})]}),e.servers.length?e.servers.map(e=>(0,S.jsxs)(`div`,{className:`mcp-row`,children:[(0,S.jsx)(`span`,{className:`mono`,children:e.name}),(0,S.jsx)(`span`,{className:`tag ${e.state===`enabled`?`ok`:`warn`}`,children:e.state===`enabled`?`Enabled`:`Disabled`})]},e.name)):(0,S.jsx)(`p`,{className:`sub`,children:`None configured in this file.`})]},e.path))]})}var M={active:[`Active`,`ok`],disabled:[`Disabled`,`warn`],absent:[`Not installed`,``]};function N({inst:e,targets:t,choice:n,unchanged:r,options:i,onPick:a,canAct:s,busy:c,removing:u,onRemoving:d,onApply:f,onToggleInstall:p,onRemove:m,onRevealMcp:h}){let g=`${e.host} · ${e.scope}`,[_,v]=M[e.state]||M.absent,y=e.state===`active`,b=e.state===`absent`;return(0,S.jsxs)(`aside`,{className:`install-panel`,"aria-label":`${g} install`,children:[(0,S.jsx)(`span`,{className:`ip-eyebrow`,children:`Selected install`}),(0,S.jsxs)(`div`,{className:`ip-head`,children:[(0,S.jsx)(`h2`,{children:l(e)}),(0,S.jsx)(`span`,{className:`tag ${v}`,children:_})]}),(0,S.jsx)(`span`,{className:`ip-kind`,children:e.scope===`global`?`Global install`:`Per-project install · ${o(e.host).label}`}),(0,S.jsx)(`code`,{className:`ip-path`,children:e.path}),b?(0,S.jsxs)(`p`,{className:`sub`,children:[`Install Geneseed here as `,(0,S.jsx)(`strong`,{children:e.host}),`. Files are added non-destructively; deactivate or uninstall later.`]}):null,(y||b)&&s?(0,S.jsx)(`div`,{className:`ip-picks`,children:(0,S.jsx)(D,{value:n,options:i,onChange:a,who:g})}):null,y&&t.length?(0,S.jsx)(j,{targets:t,onReveal:h}):null,y&&e.scope===`global`?(0,S.jsx)(k,{}):null,b?null:(0,S.jsxs)(`label`,{className:`ip-switch`,children:[(0,S.jsx)(T,{on:y,disabled:c,label:`activate ${g}`,onToggle:p}),(0,S.jsx)(`span`,{children:y?`Active: loads in every session`:`Disabled: files moved aside`})]}),(0,S.jsx)(`div`,{className:`ip-spacer`}),s?(0,S.jsxs)(`div`,{className:`ip-actions`,children:[b?(0,S.jsx)(`button`,{type:`button`,className:`btn`,onClick:f,children:`Install`}):y?(0,S.jsx)(`button`,{type:`button`,className:`btn`,disabled:r,onClick:f,children:`Apply and rebuild`}):null,b?null:(0,S.jsx)(`button`,{type:`button`,className:`btn ghost danger-line`,"aria-label":`remove ${g} from ${e.path}`,"aria-expanded":!!u,disabled:c,onClick:()=>d(u?null:{memory:`keep`}),children:`Uninstall…`})]}):null,u?(0,S.jsx)(A,{inst:e,memory:u.memory,busy:c,onMemory:e=>d({memory:e}),onRemove:m,onCancel:()=>d(null)}):null]})}var P=(e,t)=>`${e} ${t}`,F={active:[`Active`,`ok`],disabled:[`Disabled`,`warn`]};function I({rows:e,project:t,currentId:n,onPick:r,label:i}){return(0,S.jsx)(`div`,{className:`tbl-scroll`,children:(0,S.jsxs)(`table`,{className:`tbl hosts-tbl`,"aria-label":i,children:[(0,S.jsx)(`thead`,{children:(0,S.jsxs)(`tr`,{children:[(0,S.jsx)(`th`,{children:t?`Project`:`Host`}),(0,S.jsx)(`th`,{children:t?`Host`:`Path`}),(0,S.jsx)(`th`,{children:`Voice`}),(0,S.jsx)(`th`,{children:`Footprint`}),(0,S.jsx)(`th`,{children:`State`}),(0,S.jsx)(`th`,{children:(0,S.jsx)(`span`,{className:`sr-only`,children:`Selected`})})]})}),(0,S.jsx)(`tbody`,{children:e.map(e=>{let[i,a]=F[e.state]||[`Not installed`,``],s=n===e.id,c=e.state===`absent`;return(0,S.jsxs)(`tr`,{className:`pickable${s?` on`:``}${c?` quiet`:``}`,onClick:()=>r(e.id),children:[(0,S.jsx)(`td`,{children:(0,S.jsx)(`button`,{type:`button`,className:`row-pick`,"aria-pressed":s,title:e.path,onClick:()=>r(e.id),children:l(e)})}),t?(0,S.jsx)(`td`,{children:o(e.host).label}):(0,S.jsx)(`td`,{className:`mono path-cell`,title:e.path,children:e.path}),(0,S.jsx)(`td`,{children:c?``:e.theme||``}),(0,S.jsx)(`td`,{children:c?``:e.footprint||``}),(0,S.jsx)(`td`,{children:(0,S.jsx)(`span`,{className:`tag ${a}`,children:i})}),(0,S.jsx)(`td`,{className:`pick-mark`,children:s?`Editing ›`:``})]},e.id)})})]})})}function L({themes:e,current:t}){if(!e.length||!t)return null;let n=[...e].sort((e,n)=>e.name===t?-1:+(n.name===t));return(0,S.jsxs)(`details`,{className:`panel voice-ref`,children:[(0,S.jsxs)(`summary`,{children:[(0,S.jsx)(`span`,{className:`vr-title`,children:`Voices`}),(0,S.jsxs)(`span`,{className:`mono dim`,children:[e.length,` to choose from, set per install`]})]}),(0,S.jsx)(`div`,{className:`vr-list`,children:n.map(e=>(0,S.jsxs)(`div`,{className:`voice-row${e.name===t?` current`:``}`,children:[(0,S.jsx)(`span`,{className:`vr-name`,children:e.name}),(0,S.jsx)(`span`,{className:`vr-desc`,children:e.tagline?`“${e.tagline}”`:e.blurb})]},e.name))})]})}function R({setup:e,overview:t}){if(!e)return null;let n=e.installed_fp&&e.installed_fp===e.source_fp;return(0,S.jsxs)(`section`,{className:`panel`,"aria-labelledby":`checkout-h`,children:[(0,S.jsxs)(`div`,{className:`panel-head`,children:[(0,S.jsx)(`h2`,{id:`checkout-h`,children:`This checkout`}),(0,S.jsx)(`span`,{className:`mono ${n?`t-good`:`t-warn`}`,children:e.version_verdict})]}),(0,S.jsxs)(`dl`,{className:`kv-grid`,children:[(0,S.jsx)(`dt`,{children:`Source`}),(0,S.jsx)(`dd`,{className:`mono`,children:e.root}),(0,S.jsx)(`dt`,{children:`Version`}),(0,S.jsx)(`dd`,{className:`mono`,children:t?.version||`unknown`}),(0,S.jsx)(`dt`,{children:`Fingerprint`}),(0,S.jsx)(`dd`,{className:`mono`,children:e.source_fp})]})]})}function z({onAction:e,themes:t=[],currentTheme:n,overview:a,setup:o,dataRev:s,onMutated:l}){let u=v(),{data:d,error:f}=c(()=>r.installs(),[s]),{data:m,error:h}=c(()=>r.mcp(),[s]),[_,y]=(0,x.useState)(``),[b,C]=(0,x.useState)(``),[T,E]=(0,x.useState)({}),[D,k]=(0,x.useState)(!1),[A,j]=(0,x.useState)(null),[M,F]=(0,x.useState)(``),z=(0,x.useMemo)(()=>{let e={};for(let t of m?.targets||[]){let n=P(t.host||`opencode`,t.root);(e[n]||(e[n]=[])).push(t)}return e},[m]);if(f||h)return(0,S.jsx)(g,{error:f||h});if(!d||!m)return(0,S.jsx)(p,{});let B={active:0,disabled:1,absent:2},V=[...d.installs].sort((e,t)=>(e.scope===`global`?0:1)-(t.scope===`global`?0:1)||(B[e.state]??3)-(B[t.state]??3)),H=V.find(e=>e.id===M)||V.find(e=>e.selected)||V.find(e=>e.state===`active`)||V[0],U=e=>{let t=T[e.id]||{};return{theme:t.theme||e.theme||n||`neutral`,footprint:t.footprint||e.footprint||`full`,posture:t.posture||e.posture||`peer`,mode:t.mode||e.mode||`direct`,trust:t.trust||e.trust||`balanced`}},W=(e,t,n)=>E(r=>({...r,[e.id]:{...r[e.id],[t]:n}})),G=e=>{let t=U(e);return t.theme===e.theme&&t.footprint===(e.footprint||`full`)&&t.posture===(e.posture||`peer`)&&t.mode===(e.mode||`direct`)&&t.trust===(e.trust||`balanced`)},K={theme:t.map(e=>e.name),footprint:w,posture:d.postures||[],mode:d.modes||[],trust:d.trusts||[]},q=async t=>{let{theme:n,footprint:r,posture:i,mode:a,trust:o}=U(t),s=t.state===`absent`?`Install Geneseed into ${t.path} with the “${n}” voice (${r} footprint, ${i} posture, ${a} mode)? Files are added non-destructively (your own config is left untouched); deactivate or uninstall later.`:`Rebuild this install (voice “${n}”, ${r} footprint, ${i} posture, ${a} mode)? It rebuilds in place, non-destructive.`;await u(s,{title:t.state===`absent`?`Install Geneseed?`:`Rebuild this install?`,confirmLabel:t.state===`absent`?`Install`:`Rebuild`})&&e?.(`install`,{host:t.host,scope:t.scope,path:t.path,theme:n,footprint:r,posture:i,mode:a,trust:o})},J=async e=>{if(e.state!==`active`||await u(`Deactivate this install? Files are moved aside, not deleted; reactivate any time.`,{title:`Deactivate this install?`,confirmLabel:`Deactivate`})){C(e.id),y(``);try{let t=await r.installToggle(e.host,e.path,e.state===`active`?`deactivate`:`activate`);if(!t.ok){let e=Array.isArray(t.failed)?t.failed.join(`, `):``;y(t.error||e&&`unrestored: ${e}`||`action failed`);return}l?.()}catch(e){y(e.message)}finally{C(``)}}},Y=async()=>{let e=A;if(e){C(e.id),y(``);try{let t=await r.installRemove(e.host,e.path,e.memory);if(!t.ok){y(t.error||`remove failed`);return}j(null),t.kept?.length&&y(`Removed. Kept ${t.kept.length} file(s) you edited: ${t.kept.join(`, `)} — they are yours now (the CLI geneseed uninstall --force deletes edited files too).`),l?.()}catch(e){y(e.message)}finally{C(``)}}},X=async e=>{y(``);try{let t=await r.mcpReveal(e.path);y(`Opening ${t.dir}. If no window appeared, open that folder by hand.`)}catch(e){y(e.message)}},Z=V.find(e=>e.selected)?.host||V.find(e=>e.state===`active`)?.host||V[0]?.host||`opencode`,ee=V.filter(e=>e.scope===`global`),Q=V.filter(e=>e.scope!==`global`),$=e=>{F(e),j(null)};return(0,S.jsxs)(`div`,{className:`hosts`,children:[(0,S.jsxs)(`div`,{className:`hosts-main`,children:[(0,S.jsxs)(`div`,{className:`toolbar`,children:[(0,S.jsxs)(`span`,{className:`dim`,children:[V.filter(e=>e.state===`active`).length,` active of `,V.length,` `,`detected.`]}),e?(0,S.jsx)(`div`,{className:`row gap-8`,children:(0,S.jsxs)(`button`,{type:`button`,className:`btn ghost`,onClick:()=>e(`build-all`),children:[(0,S.jsx)(i,{name:`refresh`}),` Rebuild all`]})}):null]}),_?(0,S.jsx)(`p`,{className:`tag bad note`,role:`status`,children:_}):null,(0,S.jsxs)(`section`,{className:`panel flush`,"aria-labelledby":`inst-global`,children:[(0,S.jsx)(`div`,{className:`inst-head`,children:(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{id:`inst-global`,children:`Global installs`}),(0,S.jsx)(`p`,{className:`dim`,children:`One per tool. Loaded in every folder, except excluded ones.`})]})}),(0,S.jsx)(I,{rows:ee,currentId:H?.id,onPick:$,label:`Global installs`})]}),(0,S.jsxs)(`section`,{className:`panel flush`,"aria-labelledby":`inst-project`,children:[(0,S.jsxs)(`div`,{className:`inst-head`,children:[(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{id:`inst-project`,children:`Per-project installs`}),(0,S.jsx)(`p`,{className:`dim`,children:`A repo with its own harness. Inside it, only that harness loads.`})]}),e?(0,S.jsxs)(`button`,{type:`button`,className:`btn ghost`,onClick:()=>k(e=>!e),children:[(0,S.jsx)(i,{name:`folder`}),` Deploy to a repo…`]}):null]}),D?(0,S.jsx)(`div`,{className:`inst-deploy`,children:(0,S.jsx)(O,{host:Z,theme:n||`neutral`,options:K,onAction:e,onClose:()=>k(!1),onNote:y})}):null,Q.length?(0,S.jsx)(I,{rows:Q,project:!0,currentId:H?.id,onPick:$,label:`Per-project installs`}):(0,S.jsx)(`div`,{className:`empty inst-empty`,children:`No repo has its own harness yet. Deploy one to give a project its own rules and voice.`})]}),(0,S.jsx)(R,{setup:o,overview:a}),(0,S.jsx)(L,{themes:t,current:a?.theme})]}),H?(0,S.jsx)(N,{inst:H,targets:z[P(H.host,H.path)]||[],choice:U(H),unchanged:G(H),options:K,onPick:(e,t)=>W(H,e,t),canAct:!!e,busy:b===H.id,removing:A?.id===H.id?A:null,onRemoving:e=>j(e&&{id:H.id,host:H.host,path:H.path,memory:e.memory}),onApply:()=>q(H),onToggleInstall:()=>J(H),onRemove:Y,onRevealMcp:X},H.id):null]})}function B(e){return e.startsWith(`@@`)||e.startsWith(`+++`)||e.startsWith(`---`)?`hunk`:e.startsWith(`+`)?`add`:e.startsWith(`-`)?`del`:`ctx`}function V({onMutated:e,onAction:t,dataRev:n}){let a=v(),{data:o,error:s,reload:l}=c(()=>r.diff(),[n]),[u,d]=(0,x.useState)(!1),[f,m]=(0,x.useState)(``),[h,_]=(0,x.useState)(()=>new Set),[y,b]=(0,x.useState)(()=>new Set),[C,w]=(0,x.useState)(null);o&&o!==C&&(w(o),_(new Set),b(new Set(o.files.map(e=>e.rel))));let T=e=>_(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),E=()=>_(e=>e.size===o.files.length?new Set:new Set(o.files.map(e=>e.rel))),D=()=>t?.(`export`),O=async()=>{let t=[...h],n=t.filter(e=>o.files.find(t=>t.rel===e)?.status===`added`),i=n.length?`Restoring will DELETE ${n.length} deployed-only file(s):\n${n.join(`
2
- `)}\n\n`:``;if(await a(`${i}Discard local edits and restore ${t.length} file(s) from source?`,{title:`Restore from source?`,confirmLabel:`Restore`})){d(!0);try{let n=await r.restore(t),i=n.errors.length?` · ${n.errors.length} error(s): ${n.errors.join(`; `)}`:``;m(`Restored ${n.restored.length}, deleted ${n.deleted.length}${i}`),await l(),e?.()}catch(e){m(e.message)}finally{d(!1)}}};if(s)return(0,S.jsx)(g,{error:s});if(!o)return(0,S.jsx)(p,{});if(!o.deployed)return(0,S.jsxs)(`div`,{className:`empty`,children:[(0,S.jsx)(`div`,{className:`big`,children:`No deployed harness`}),`Nothing to diff against.`]});if(!o.diffable)return(0,S.jsxs)(`div`,{className:`empty`,children:[(0,S.jsx)(`div`,{className:`big`,children:`No drift check for this install`}),`The drift check covers global installs only.`]});let k=o.files,A=k.filter(e=>e.status===`edited`).length,j=k.filter(e=>e.status===`added`).length,M=k.filter(e=>e.status===`missing`).length,N=e=>b(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n});return(0,S.jsxs)(S.Fragment,{children:[(0,S.jsxs)(`div`,{className:`head-row mb-16`,children:[(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{className:`h`,children:`Local edits`}),(0,S.jsx)(`p`,{className:`sub`,children:`The agent refines its own deployed files in place. Export them as improvements before any rebuild overwrites them.`})]}),(0,S.jsxs)(`div`,{className:`row gap-10`,children:[(0,S.jsxs)(`button`,{className:`btn ghost`,disabled:u||h.size===0,onClick:O,children:[`Restore`,h.size?` (${h.size})`:``]}),(0,S.jsxs)(`button`,{className:`btn`,disabled:u,onClick:D,children:[(0,S.jsx)(i,{name:`download`}),`Export improvements`]})]})]}),f?(0,S.jsx)(`p`,{className:`sub mb-14`,children:f}):null,k.length===0?(0,S.jsxs)(`div`,{className:`empty`,children:[(0,S.jsx)(`div`,{className:`big`,children:`In sync`}),`Deployed harness matches source.`]}):(0,S.jsxs)(S.Fragment,{children:[(0,S.jsxs)(`div`,{className:`row between mb-14`,children:[(0,S.jsxs)(`div`,{className:`row gap-10`,children:[(0,S.jsxs)(`span`,{className:`badge`,children:[(0,S.jsx)(`span`,{className:`dot`,style:{background:`var(--warn)`}}),A,` edited`]}),(0,S.jsxs)(`span`,{className:`badge`,children:[(0,S.jsx)(`span`,{className:`dot`,style:{background:`var(--good)`}}),j,` added`]}),M>0&&(0,S.jsxs)(`span`,{className:`badge`,children:[(0,S.jsx)(`span`,{className:`dot`,style:{background:`var(--bad)`}}),M,` missing`]})]}),(0,S.jsxs)(`label`,{className:`row dim`,style:{gap:8,fontSize:12.5,cursor:`pointer`},children:[(0,S.jsx)(`input`,{type:`checkbox`,style:{accentColor:`var(--accent)`},checked:h.size===k.length,onChange:E}),`Select all`]})]}),(0,S.jsx)(`div`,{className:`stack gap-12`,children:k.map(e=>{let t=y.has(e.rel),n=e.status===`added`?`ok`:e.status===`missing`?`bad`:`warn`;return(0,S.jsxs)(`div`,{className:`card diff-file${t?` open`:``}`,children:[(0,S.jsxs)(`div`,{className:`diff-head`,children:[(0,S.jsx)(`input`,{type:`checkbox`,className:`chk`,checked:h.has(e.rel),onChange:()=>T(e.rel),onClick:e=>e.stopPropagation(),"aria-label":`Select ${e.rel}`}),(0,S.jsx)(`span`,{className:`fname`,children:e.rel}),(0,S.jsxs)(`span`,{className:`badge ${n}`,children:[(0,S.jsx)(`span`,{className:`dot`}),e.status]}),(0,S.jsxs)(`span`,{className:`dim mono`,style:{marginLeft:`auto`,fontSize:11},children:[e.diff.length,` lines`]}),(0,S.jsx)(`button`,{className:`iconbtn`,onClick:()=>N(e.rel),style:{transform:t?`rotate(90deg)`:`none`},"aria-label":t?`Collapse ${e.rel}`:`Expand ${e.rel}`,"aria-expanded":t,children:(0,S.jsx)(i,{name:`chevron`})})]}),t&&(0,S.jsx)(`div`,{className:`diff-body`,children:e.diff.map((e,t)=>(0,S.jsx)(`div`,{className:`diff-line ${B(e)}`,children:e},t))})]},e.rel)})})]})]})}function H({group:e,i:t}){let n=e.problems.length===0,[r,a]=(0,x.useState)(!n);return(0,S.jsxs)(`div`,{className:`card check rise ${n?``:`bad`} ${r?`open`:``}`,style:{"--i":t*.6},children:[(0,S.jsxs)(`button`,{className:`check-head`,onClick:()=>a(e=>!e),disabled:n,style:{cursor:n?`default`:`pointer`},"aria-expanded":n?void 0:r,children:[(0,S.jsx)(`span`,{className:`feed-dot ${n?`ok`:`bad`}`,style:{width:9,height:9}}),(0,S.jsx)(`h3`,{children:e.label}),(0,S.jsxs)(`span`,{className:`badge ${n?`ok`:`bad`}`,children:[(0,S.jsx)(`span`,{className:`dot`}),n?`clean`:`${e.problems.length} problem${e.problems.length===1?``:`s`}`]}),!n&&(0,S.jsx)(i,{name:`chevron`,className:`chev glyph`})]}),!n&&r&&(0,S.jsx)(`div`,{className:`check-body`,children:e.problems.map(e=>(0,S.jsxs)(`div`,{className:`problem`,children:[(0,S.jsx)(`span`,{className:`x`,children:`✕`}),(0,S.jsx)(`span`,{children:e})]},e))})]})}function U(){let e=(0,x.useRef)(!1),{data:t,error:n,reload:a,setData:o}=c(()=>r.doctor(e.current),[]);return n?(0,S.jsx)(g,{error:n}):(0,S.jsxs)(`div`,{className:`narrow`,children:[(0,S.jsxs)(`div`,{className:`head-row mb-16`,children:[(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{className:`h`,children:`Doctor`}),(0,S.jsx)(`p`,{className:`sub`,children:`Every check builds each theme in a sandbox and validates the result: token resolution, link integrity, parity, and drift.`})]}),(0,S.jsxs)(`button`,{className:`btn ghost`,onClick:()=>{e.current=!0,o(null),a()},disabled:!t,children:[(0,S.jsx)(i,{name:`refresh`}),t?`Re-run checks`:`Running…`]})]}),t?(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(`div`,{className:`card pad-md mb-16`,children:(0,S.jsxs)(`div`,{className:`row wrap between gap-12`,children:[(0,S.jsxs)(`div`,{className:`row`,style:{gap:10,flexWrap:`wrap`},children:[(0,S.jsxs)(`span`,{className:`dim mono`,style:{fontSize:12},children:[`validated `,t.themes.length,` theme`,t.themes.length===1?``:`s`]}),t.themes.map(e=>(0,S.jsx)(`span`,{className:`badge`,style:{textTransform:`capitalize`},children:e},e))]}),t.ok?(0,S.jsxs)(`span`,{className:`badge ok`,children:[(0,S.jsx)(`span`,{className:`dot`}),`all clean`]}):(0,S.jsxs)(`span`,{className:`badge bad`,children:[(0,S.jsx)(`span`,{className:`dot`}),t.problems.length,` problem`,t.problems.length===1?``:`s`]})]})}),(0,S.jsx)(`div`,{className:`stack gap-12`,children:t.groups.map((e,t)=>(0,S.jsx)(H,{group:e,i:t},e.label))})]}):(0,S.jsx)(p,{label:`Running every check (builds each theme in a sandbox)…`})]})}function W(){let e=v(),[t,n]=(0,x.useState)(!1),[a,o]=(0,x.useState)(!1),[s,c]=(0,x.useState)(null);return t?(0,S.jsxs)(`p`,{className:`sub`,children:[`Server stopped. You can close this tab and reopen any time with `,(0,S.jsx)(`code`,{children:`geneseed web`}),`.`]}):(0,S.jsxs)(S.Fragment,{children:[s&&(0,S.jsx)(`p`,{className:`sub`,role:`alert`,children:s}),(0,S.jsxs)(`div`,{className:`row`,children:[(0,S.jsxs)(`button`,{className:`btn ghost`,onClick:async()=>{if(await e(`Restart the local Geneseed server? The console reconnects in a moment.`,{title:`Restart the server?`,confirmLabel:`Restart`})){o(!0),c(null);try{await u()}catch(e){c(e.message),o(!1)}}},disabled:a,children:[(0,S.jsx)(i,{name:`refresh`}),a?`Restarting…`:`Restart server`]}),(0,S.jsxs)(`button`,{className:`btn ghost`,onClick:async()=>{if(await e(`Stop the local Geneseed server? The console goes offline until you start it again.`,{title:`Stop the server?`,confirmLabel:`Stop server`})){c(null);try{await r.shutdown()}catch(e){if(e.status)return c(e.message)}n(!0)}},disabled:a,children:[(0,S.jsx)(i,{name:`x`}),`Stop server`]})]})]})}var G=`https://github.com/Arylmera/Geneseed`,K=`https://github.com/Arylmera`;function q(){let[e,t]=(0,x.useState)(G),[n,a]=(0,x.useState)(!0);return(0,x.useEffect)(()=>{Promise.resolve(r.docsPage?.(`about`)).then(e=>{e?.repo&&(t(e.repo),a(!!e.repo_is_github))}).catch(()=>{})},[]),(0,S.jsxs)(S.Fragment,{children:[(0,S.jsxs)(`div`,{className:`card pad-lg mb-16`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`About`})}),(0,S.jsx)(`p`,{className:`sub mb-16`,children:`Geneseed is a portable, theme-able harness you implant once and use everywhere to grow a disciplined AI coding agent. One canonical source, many voices, MIT-licensed.`}),(0,S.jsxs)(`div`,{className:`row wrap gap-10`,children:[(0,S.jsxs)(`a`,{className:`btn ghost`,href:e,target:`_blank`,rel:`noreferrer`,children:[(0,S.jsx)(i,{name:`github`}),n?`Source on GitHub`:`Source repo`]}),n&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsxs)(`a`,{className:`btn ghost`,href:e+`/issues`,target:`_blank`,rel:`noreferrer`,children:[(0,S.jsx)(i,{name:`external`}),`Issues`]}),(0,S.jsxs)(`a`,{className:`btn ghost`,href:e+`/blob/main/LICENSE`,target:`_blank`,rel:`noreferrer`,children:[(0,S.jsx)(i,{name:`external`}),`MIT License`]})]})]})]}),(0,S.jsxs)(`div`,{className:`card pad-lg`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`Creator`})}),(0,S.jsxs)(`p`,{className:`sub mb-16`,children:[`Geneseed is built by `,(0,S.jsx)(`strong`,{children:`Guillaume Lemer`}),`. It started as a personal, Obsidian-vault-grown agent operating system and was distilled into the repo you are running. Implant it once, and a disciplined agent grows around the same inherited rules, skills, and memory in every repo it follows you into.`]}),(0,S.jsx)(`p`,{className:`sub mb-16`,children:`If you find this useful, a star on the repo or an issue with feedback is the best way to help shape what comes next.`}),(0,S.jsx)(`div`,{className:`row wrap gap-10`,children:(0,S.jsxs)(`a`,{className:`btn ghost`,href:K,target:`_blank`,rel:`noreferrer`,children:[(0,S.jsx)(i,{name:`github`}),`@Arylmera on GitHub`]})})]})]})}function J({overview:e,onAction:t,flavour:n,onFlavour:r,accentMode:o,onAccentMode:s,layout:c,onLayout:l}){let u=v(),p=e?.install,m=e?.footprint,h=async e=>{p&&e!==m&&await u(`Rebuild ${p.host} · ${p.scope} with the “${e}” footprint? It rebuilds in place, non-destructive.`,{title:`Change the footprint?`,confirmLabel:`Rebuild`})&&t?.(`install`,{...p,footprint:e})};return(0,S.jsxs)(`div`,{className:`narrow-lg`,children:[(0,S.jsx)(`div`,{className:`head-row mb-18`,children:(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h2`,{className:`h`,children:`Settings`}),(0,S.jsx)(`p`,{className:`sub`,children:`Console appearance, the footprint of the install you are viewing, machine maintenance (including the update), server control, and about. Each install is managed on the Hosts tab.`})]})}),n&&r&&(0,S.jsxs)(`div`,{className:`card pad-lg mb-16`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`Console direction`})}),(0,S.jsxs)(`p`,{className:`sub mb-16`,children:[f.length,` takes on the same data. Pick a direction; it applies instantly and persists across reloads.`]}),o&&s&&(0,S.jsxs)(`div`,{className:`dir-layout`,children:[(0,S.jsx)(`span`,{className:`tick`,id:`dir-accent-label`,children:`Accent`}),(0,S.jsx)(_,{value:o,onChange:s,labelledBy:`dir-accent-label`}),(0,S.jsx)(`span`,{className:`dir-layout-note sub`,role:`status`,"aria-live":`polite`,children:a(o)})]}),c&&l&&(0,S.jsxs)(`div`,{className:`dir-layout`,children:[(0,S.jsx)(`span`,{className:`tick`,id:`dir-layout-label`,children:`Overview view`}),(0,S.jsx)(d,{"aria-labelledby":`dir-layout-label`,children:y.map(e=>(0,S.jsx)(`button`,{className:c===e.id?`on`:``,onClick:()=>l(e.id),"aria-pressed":c===e.id,title:e.tagline,children:e.short},e.id))}),(0,S.jsx)(`span`,{className:`dir-layout-note sub`,role:`status`,"aria-live":`polite`,children:y.find(e=>e.id===c)?.tagline??``})]}),(0,S.jsx)(`div`,{className:`dir-grid`,children:f.map(e=>(0,S.jsxs)(`button`,{className:`dir-tile dir-${e.id} ${n===e.id?`on`:``}`,onClick:()=>r(e.id),"aria-pressed":n===e.id,children:[(0,S.jsxs)(`span`,{className:`dir-thumb`,"aria-hidden":`true`,children:[(0,S.jsx)(`span`,{className:`dir-thumb-rail`}),(0,S.jsx)(`span`,{className:`dir-thumb-bar`}),(0,S.jsx)(`span`,{className:`dir-thumb-bar`,style:{width:`70%`}}),(0,S.jsx)(`span`,{className:`dir-thumb-bar`,style:{width:`52%`}}),(0,S.jsx)(`span`,{className:`dir-thumb-dot`})]}),(0,S.jsxs)(`span`,{className:`dir-meta`,children:[(0,S.jsxs)(`span`,{className:`dir-name`,children:[e.short,n===e.id&&(0,S.jsx)(`span`,{className:`dir-check`,children:`● active`})]}),(0,S.jsx)(`span`,{className:`dir-tag`,children:e.tagline})]})]},e.id))})]}),p&&m&&(0,S.jsxs)(`div`,{className:`card pad-lg mb-16`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`Harness footprint`})}),(0,S.jsxs)(`p`,{className:`sub mb-16`,children:[`How much of the Rules `,(0,S.jsx)(`code`,{children:`AGENT.md`}),` carries inline each turn, for the current install (`,(0,S.jsxs)(`code`,{children:[p.host,` · `,p.scope]}),`). A token-cost dial; every Rule stays in force either way. Changing it rebuilds the install in place. `,(0,S.jsx)(`a`,{href:`#/docs/footprint`,children:`Learn more →`})]}),(0,S.jsxs)(`div`,{className:`dir-layout`,children:[(0,S.jsx)(`span`,{className:`tick`,id:`footprint-label`,children:`Footprint`}),(0,S.jsx)(d,{"aria-labelledby":`footprint-label`,children:[`full`,`lean`].map(e=>(0,S.jsx)(`button`,{className:m===e?`on`:``,onClick:()=>h(e),"aria-pressed":m===e,children:e},e))}),(0,S.jsx)(`span`,{className:`dir-layout-note sub`,role:`status`,"aria-live":`polite`,children:m===`lean`?`Lean: terse rule lines + a pointer to the full law file (~40% smaller, lighter context per turn).`:`Full: every Rule’s complete text and rationale inlined (maximum guidance, largest context).`})]})]}),(0,S.jsxs)(`div`,{className:`card pad-lg mb-16`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`Maintenance`})}),(0,S.jsxs)(`p`,{className:`sub mb-16`,children:[`Put `,(0,S.jsx)(`code`,{children:`geneseed`}),` on your PATH so it runs from any directory, or remove a global install. Your memory store is always kept. Each runs live in the console.`]}),(0,S.jsxs)(`div`,{className:`row wrap gap-10`,children:[(0,S.jsxs)(`button`,{className:`btn ghost`,onClick:()=>t(`update`),children:[(0,S.jsx)(i,{name:`download`}),`Update (git pull + rebuild)`]}),(0,S.jsxs)(`button`,{className:`btn ghost`,onClick:()=>t(`link`),children:[(0,S.jsx)(i,{name:`external`}),`Add to PATH`]}),(0,S.jsx)(`button`,{className:`btn ghost`,onClick:()=>t(`unlink`),children:`Remove from PATH`}),(0,S.jsxs)(`button`,{className:`btn ghost`,onClick:async()=>{await u(`Uninstall the global Geneseed harness? Your memory store is kept; everything else this install added is removed.`,{title:`Uninstall Geneseed?`,confirmLabel:`Uninstall`})&&t(`uninstall`)},children:[(0,S.jsx)(i,{name:`clear`}),`Uninstall`]})]})]}),(0,S.jsxs)(`div`,{className:`card pad-lg mb-16`,children:[(0,S.jsx)(`div`,{className:`card-head`,children:(0,S.jsx)(`h3`,{children:`Server`})}),(0,S.jsx)(`p`,{className:`sub mb-16`,children:`The console runs a small local server. Leave it running in the background and reopen any time, or stop it when you are done.`}),(0,S.jsx)(W,{})]}),(0,S.jsx)(q,{})]})}function Y({tab:e=`hosts`,overview:t,setup:n,themes:r,onAction:i,onMutated:a,dataRev:o,appearance:s={}}){let c=t?.doctor,l=t?.diff,u={edits:l?m(l):null,doctor:c?c.ok?`clean`:c.problems.length:null};return(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(`div`,{className:`page-head`,children:(0,S.jsxs)(`div`,{children:[(0,S.jsx)(`h1`,{className:`h`,children:`Installs`}),(0,S.jsx)(`p`,{className:`sub`,children:`Where the harness lives on this machine, and how each copy is built.`})]})}),(0,S.jsx)(b,{page:`installs`,current:e,badges:u,label:`Installs`}),e===`hosts`&&(0,S.jsx)(z,{onAction:i,themes:r,currentTheme:t?.theme,overview:t,setup:n,dataRev:o,onMutated:a}),e===`edits`&&(0,S.jsx)(V,{onMutated:a,onAction:i,dataRev:o}),e===`doctor`&&(0,S.jsx)(U,{}),e===`server`&&(0,S.jsx)(J,{overview:t,onAction:i,...s})]})}export{Y as default};