@critiquedotsh/harness 0.1.10 → 0.1.12

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 (2) hide show
  1. package/dist/cli.js +1016 -870
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -21318,708 +21318,452 @@ function critiqueCodeWebPage(input) {
21318
21318
  <title>CritiqueCode</title>
21319
21319
  <style>
21320
21320
  :root {
21321
- --bg: #12110f;
21322
- --rail: #181714;
21323
- --panel: #1c1b18;
21324
- --prompt: #22211d;
21325
- --line: rgba(255,236,222,.1);
21326
- --fg: #f4efe6;
21327
- --muted: #a39a8e;
21328
- --faint: #7a7368;
21329
- --live: #3dd68c;
21330
- --warn: #d4a017;
21331
- --err: #e36d6d;
21332
- --accent: #e61919;
21333
- --ease: cubic-bezier(.32,.72,0,1);
21334
- --rail-w: 248px;
21335
- --changes-w: 360px;
21336
- }
21337
- * { box-sizing: border-box; }
21338
- [hidden] { display: none !important; }
21339
- html, body { margin: 0; height: 100%; height: 100dvh; overflow: hidden; background: var(--bg); color: var(--fg);
21340
- font-family: "IBM Plex Sans", "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
21341
- font-size: 14px; letter-spacing: -0.02em; }
21342
- button, textarea, select, input { font: inherit; color: inherit; }
21343
- button { cursor: pointer; }
21344
- .shell { display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr) 6px var(--changes-w); height: 100dvh; overflow: hidden; }
21345
- .shell.rail-off { --rail-w: 48px; }
21346
- .shell.changes-off { --changes-w: 0px; }
21347
- .shell.changes-off .gutter, .shell.changes-off .changes { display: none; }
21348
- .shell.rail-off .rail-copy { display: none; }
21349
- .shell.rail-off .rail-top { flex-direction: column; }
21350
- .shell.term-off .term { display: none; }
21351
- .gutter { background: var(--line); cursor: col-resize; }
21352
- .rail .search { width: 100%; background: #181818; border: 1px solid var(--line); border-radius: 8px; padding: 7px 8px; color: var(--fg); outline: none; font-size: 12px; }
21353
- .md-code { position: relative; background: #141310; border: 1px solid var(--line); border-radius: 10px; padding: 28px 12px 12px; overflow: auto; font: 12px ui-monospace, Menlo, monospace; line-height: 1.5; }
21354
- .md-code .copy { position: absolute; top: 6px; right: 6px; font-size: 11px; border: 1px solid var(--line); background: #1c1c1c; border-radius: 6px; padding: 2px 8px; }
21355
- .reply { margin: 14px 2px 0; line-height: 1.55; word-break: break-word; color: #e7e1d6; }
21356
- .reply > *:first-child { margin-top: 0; }
21357
- .reply > *:last-child { margin-bottom: 0; }
21358
- .reply h1, .reply h2, .reply h3, .reply h4, .reply h5, .reply h6 { color: var(--fg); font-weight: 600; letter-spacing: -.03em; line-height: 1.3; margin: 18px 0 8px; }
21359
- .reply h1 { font-size: 18px; } .reply h2 { font-size: 16px; } .reply h3 { font-size: 14px; } .reply h4, .reply h5, .reply h6 { font-size: 13px; color: #ddd6c8; }
21360
- .reply p { margin: 0 0 10px; }
21361
- .reply ul, .reply ol { margin: 0 0 12px; padding-left: 1.2em; }
21362
- .reply li { margin: 0 0 4px; }
21363
- .reply li::marker { color: var(--faint); }
21364
- .reply hr { border: 0; border-top: 1px solid var(--line); margin: 14px 0; }
21365
- .reply blockquote { margin: 0 0 12px; padding: 8px 12px; border-left: 2px solid rgba(230,25,25,.7); color: var(--muted); background: rgba(255,236,222,.03); border-radius: 0 8px 8px 0; }
21366
- .reply code { font: 12px ui-monospace, Menlo, monospace; background: rgba(255,236,222,.06); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; }
21367
- .reply .md-code code { background: none; border: 0; padding: 0; }
21368
- .reply a { color: #9ec5ff; text-decoration: none; }
21369
- .reply a:hover { text-decoration: underline; }
21370
- .md-table { margin: 10px 0 14px; overflow: auto; border: 1px solid var(--line); border-radius: 10px; background: #161410; }
21371
- .reply table { width: 100%; border-collapse: collapse; font-size: 12.5px; margin: 0; }
21372
- .reply th, .reply td { padding: 8px 10px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
21373
- .reply th { color: var(--muted); font-weight: 600; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; background: rgba(255,236,222,.04); }
21374
- .reply td { color: #e7e1d6; }
21375
- .reply tr:last-child td { border-bottom: 0; }
21376
- .reply td:first-child, .reply th:first-child { font-family: ui-monospace, Menlo, monospace; font-size: 12px; white-space: nowrap; color: #d8cfc3; }
21377
- .think { margin: 8px 2px 0; color: var(--faint); font-size: 12px; white-space: pre-wrap; }
21378
- .workspace { min-height: 0; padding: 8px; display: grid; gap: 6px; overflow: hidden; }
21379
- .workspace input { width: 100%; background: #181818; border: 1px solid var(--line); border-radius: 8px; padding: 6px 8px; color: var(--fg); outline: none; font-size: 12px; }
21380
- .tree { min-height: 0; overflow: auto; font: 12px ui-monospace, Menlo, monospace; }
21381
- .tree button { display: flex; align-items: center; gap: 6px; width: 100%; text-align: left; border: 0; background: transparent; color: var(--muted); padding: 3px 6px; border-radius: 6px; }
21382
- .tree button:hover { background: rgba(255,255,255,.05); color: var(--fg); }
21383
- .tree button.on { background: rgba(255,236,222,.06); color: var(--fg); }
21384
- .tree .twist { width: 10px; flex-shrink: 0; opacity: .55; font-size: 9px; }
21385
- .tree .kind-untracked, .tree .kind-added { color: #7dcea0; }
21386
- .tree .kind-modified { color: #e4c36a; }
21387
- .tree .kind-deleted { color: #e36d6d; text-decoration: line-through; }
21388
- .tree .kind-renamed { color: #9ec5ff; }
21389
- .diff-actions { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 10px; }
21390
- .diff-actions button, .workspace button { border: 1px solid var(--line); background: #1c1c1c; border-radius: 8px; padding: 5px 8px; font-size: 12px; color: var(--muted); }
21391
- #file-view { white-space: pre-wrap; font: 12px ui-monospace, Menlo, monospace; padding: 12px; color: var(--muted); overflow: auto; }
21392
- #preview { width: 100%; min-height: 240px; border: 0; background: #fff; }
21393
- .chips { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 8px 6px; }
21394
- .chip { font-size: 11px; background: #222; border-radius: 999px; padding: 3px 8px; color: var(--muted); }
21395
- #mode, #autonomy { max-width: 90px; background: transparent; border: 0; color: var(--muted); font-size: 12px; outline: none; }
21396
- #cost { font-variant-numeric: tabular-nums; }
21397
- .rail { background: var(--rail); border-right: 1px solid var(--line); display: flex; flex-direction: column; padding: 12px 10px; gap: 10px; min-width: 0; }
21398
- .rail-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
21399
- .mark { width: 30px; height: 30px; border-radius: 2px; background: var(--accent); color: #fff; display: grid; place-items: center; font-family: ui-monospace, Menlo, monospace; font-size: 12px; font-weight: 700; letter-spacing: .04em; }
21400
- .rail .plus { width: 100%; height: 32px; border-radius: 8px; background: transparent; border: 1px solid var(--line); color: var(--muted); display: flex; align-items: center; justify-content: center; gap: 8px; font-size: 12px; transition: border-color .2s var(--ease), color .2s var(--ease); }
21401
- .rail .plus:hover { color: var(--fg); border-color: rgba(255,255,255,.2); }
21402
- .rail .plus svg { flex-shrink: 0; }
21403
- #sessions { display: flex; flex-direction: column; gap: 4px; overflow: auto; min-height: 0; flex: 1; }
21404
- .session-item { text-align: left; width: 100%; border: 0; background: transparent; color: var(--muted); padding: 8px 10px; border-radius: 8px; font-size: 12px; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21405
- .session-item:hover, .session-item.on { background: rgba(255,255,255,.05); color: var(--fg); }
21406
- .stage { display: grid; grid-template-rows: auto minmax(0, 1fr) auto auto; min-width: 0; min-height: 0; height: 100dvh; overflow: hidden; }
21407
- .changes { background: var(--rail); border-left: 1px solid var(--line); display: grid; grid-template-rows: auto auto minmax(0, 1fr); min-width: 0; min-height: 0; height: 100dvh; overflow: hidden; }
21408
- .changes header { padding: 14px 14px 8px; display: grid; grid-template-columns: 1fr auto; gap: 4px 8px; align-items: center; }
21409
- .changes h2 { margin: 0; font-size: 13px; font-weight: 600; }
21410
- .changes .sum { grid-column: 1 / -1; color: var(--muted); font-size: 12px; margin: 0; }
21411
- .work-stack { min-height: 0; overflow: hidden; display: grid; grid-template-rows: minmax(0, 1fr); }
21412
- .work-stack > * { min-height: 0; height: 100%; }
21413
- #tab-tree { grid-template-rows: auto minmax(0, 1fr) auto minmax(0, 1.15fr); }
21414
- #tab-findings, #tab-timeline { grid-template-rows: auto minmax(0, 1fr); }
21415
- .change-list { display: none; }
21416
- .change-file { display: flex; justify-content: space-between; gap: 8px; width: 100%; text-align: left; border: 0; background: transparent; color: var(--muted); padding: 7px 8px; border-radius: 8px; font-size: 12px; font-family: ui-monospace, Menlo, monospace; }
21417
- .change-file:hover, .change-file.on { background: rgba(255,255,255,.05); color: var(--fg); }
21418
- .change-file .plus { color: var(--live); }
21419
- .change-file .minus { color: var(--err); }
21420
- .diff-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; border-top: 1px solid var(--line); color: var(--muted); font: 11px ui-monospace, Menlo, monospace; }
21421
- .diff-head b { color: var(--fg); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21422
- .diff { min-height: 0; overflow: auto; padding: 0 0 16px; font-family: ui-monospace, Menlo, monospace; font-size: 12px; line-height: 1.55; }
21423
- .diff .hunk { color: var(--faint); padding: 8px 10px 4px; background: rgba(255,236,222,.03); }
21424
- .diff .row { display: grid; grid-template-columns: 44px 44px minmax(0, 1fr); }
21425
- .diff .ln { color: var(--faint); text-align: right; padding: 0 8px; user-select: none; }
21426
- .diff .add { background: rgba(61,214,140,.1); color: #b7ebc9; }
21427
- .diff .del { background: rgba(227,109,109,.12); color: #f0c7c7; }
21428
- .diff .ctx { color: var(--muted); }
21429
- .diff .code { white-space: pre-wrap; word-break: break-word; padding-right: 10px; }
21430
- .term { border-top: 1px solid var(--line); background: #101010; display: grid; grid-template-rows: auto 1fr auto; max-height: 220px; }
21431
- .term header { display: flex; justify-content: space-between; align-items: center; padding: 6px 12px; color: var(--muted); font-size: 12px; }
21432
- .term pre { margin: 0; padding: 8px 12px; overflow: auto; font: 12px ui-monospace, Menlo, monospace; color: #c8c8c8; min-height: 72px; }
21433
- .term form { display: flex; gap: 8px; padding: 6px 10px 10px; }
21434
- .term input { flex: 1; background: #181818; border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; outline: none; font: 12px ui-monospace, Menlo, monospace; }
21435
- .agent { margin: 10px 2px 0; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: #141414; font-size: 12px; color: var(--muted); }
21436
- .agent.running { border-color: rgba(61,214,140,.25); color: var(--fg); }
21437
- .agent b { font-weight: 600; color: var(--fg); }
21438
- header { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 20px 8px; }
21439
- .session { display: flex; align-items: center; gap: 10px; color: var(--fg); font-size: 13px; font-weight: 600; }
21440
- .session svg { opacity: .55; }
21441
- .badges { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; }
21442
- .badge { display: inline-flex; align-items: center; gap: 7px; padding: 5px 10px; border-radius: 2px; background: #181818; border: 1px solid var(--line); color: var(--muted); font-size: 11px; font-family: ui-monospace, Menlo, monospace; font-variant-numeric: tabular-nums; }
21443
- .badge .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--live); box-shadow: 0 0 0 3px rgba(61,214,140,.12); }
21444
- .icon-btn { width: 28px; height: 28px; border: 1px solid var(--line); background: transparent; color: var(--muted); border-radius: 2px; display: grid; place-items: center; }
21445
- .icon-btn:hover, .icon-btn.on { color: var(--fg); border-color: rgba(255,236,222,.22); }
21446
- .badge.auto { color: #ffb020; border-color: rgba(212,160,23,.55); animation: pulse 1.6s ease infinite; }
21447
- .badge.evidence { color: #b7ebc9; border-color: rgba(61,214,140,.35); }
21448
- .badge.unverified { color: var(--muted); }
21449
- .badge.none { color: var(--warn); border-color: rgba(212,160,23,.4); }
21450
- .badge.repair { color: #c9e4ff; border-color: rgba(120,170,255,.35); }
21451
- @keyframes pulse { 50% { opacity: .55 } }
21452
- .trust { display: inline-flex; align-items: center; gap: 6px; font-size: 10px; letter-spacing: .04em; text-transform: uppercase; color: var(--faint); margin-bottom: 6px; }
21453
- .trust.evidence { color: #7dcea0; }
21454
- .trust.none_promoted { color: var(--warn); }
21455
- .trust.verified_repair { color: #9ec5ff; }
21456
- .gate { display: flex; gap: 6px; list-style: none; margin: 0; padding: 0; flex-wrap: wrap; }
21457
- .gate li { font-size: 11px; padding: 4px 8px; border-radius: 999px; border: 1px solid var(--line); color: var(--faint); }
21458
- .gate li.active { color: var(--fg); border-color: rgba(255,236,222,.28); }
21459
- .gate li.ready, .gate li.verified { color: #b7ebc9; border-color: rgba(61,214,140,.3); }
21460
- .gate li.blocked { color: var(--warn); border-color: rgba(212,160,23,.4); }
21461
- .work-tabs { display: flex; gap: 4px; padding: 6px 10px; border-bottom: 1px solid var(--line); }
21462
- .work-tabs button { border: 0; background: transparent; color: var(--muted); font-size: 11px; padding: 4px 8px; border-radius: 6px; width: auto; }
21463
- .work-tabs button.on { color: var(--fg); background: rgba(255,255,255,.06); }
21464
- .find-row { width: 100%; text-align: left; border: 0; background: transparent; color: var(--muted); padding: 8px; border-radius: 8px; font-size: 12px; }
21465
- .find-row:hover { background: rgba(255,255,255,.05); color: var(--fg); }
21466
- .palette { display: none; position: fixed; inset: 12vh 0 auto; margin: 0 auto; width: min(560px, 92vw); background: #161616; border: 1px solid var(--line); border-radius: 12px; z-index: 8; padding: 10px; box-shadow: 0 24px 80px rgba(0,0,0,.5); }
21467
- .palette.open { display: block; }
21468
- .palette input { width: 100%; background: #111; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; outline: none; }
21469
- .palette button { width: 100%; text-align: left; border: 0; background: transparent; color: var(--muted); padding: 8px; border-radius: 8px; }
21470
- .palette button:hover, .palette button.on { background: rgba(255,255,255,.06); color: var(--fg); }
21471
- .sheet { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 7; align-items: center; justify-content: center; padding: 24px; }
21472
- .sheet.open { display: flex; }
21473
- .sheet .card { width: min(640px, 94vw); max-height: 80vh; overflow: auto; background: #161616; border: 1px solid var(--line); border-radius: 14px; padding: 16px; }
21474
- .sheet h3 { margin: 0 0 12px; font-size: 16px; }
21475
- .sheet label { display: block; font-size: 12px; color: var(--muted); margin: 8px 0 4px; }
21476
- .sheet input, .sheet select, .sheet textarea.plain { width: 100%; background: #111; border: 1px solid var(--line); border-radius: 8px; padding: 8px; }
21477
- .compare { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding: 8px; font-size: 12px; }
21478
- #stop.steer, #send.steer { background: #ececec; color: #111; }
21479
- .badge.err { color: var(--err); border-color: rgba(227,109,109,.35); }
21480
- main { min-height: 0; overflow: auto; }
21481
- #empty { max-width: 560px; margin: 12vh auto 0; padding: 0 24px 40px; }
21482
- #empty h1 { margin: 0 0 28px; font-size: 28px; font-weight: 500; color: #6e6e6e; letter-spacing: -.03em; }
21483
- .meta { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; color: var(--muted); font-size: 13px; }
21484
- .meta li { display: grid; grid-template-columns: 18px 1fr; gap: 12px; align-items: start; }
21485
- .meta svg { margin-top: 2px; opacity: .7; }
21486
- .meta strong { color: var(--fg); font-weight: 500; word-break: break-all; }
21487
- #feed { max-width: 720px; margin: 0 auto; padding: 12px 24px 28px; display: none; }
21488
- #feed.on { display: block; }
21489
- .turn { margin: 0 0 28px; }
21490
- .prompt { background: var(--prompt); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
21491
- .steps { margin: 10px 2px 0; color: var(--faint); font-size: 12px; }
21492
- .steps summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; gap: 12px; }
21493
- .steps summary::-webkit-details-marker { display: none; }
21494
- .steps[open] summary { color: var(--muted); }
21495
- .step-list { margin: 8px 0 0; padding: 10px 12px; background: #141414; border-radius: 10px; border: 1px solid var(--line); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--muted); white-space: pre-wrap; word-break: break-word; }
21496
- .note, .alert, .review-card { margin: 12px 0; padding: 12px 14px; border-radius: 10px; line-height: 1.5; word-break: break-word; }
21497
- .note { color: #cfc6b8; background: #161410; border: 1px solid var(--line); font: 12.5px ui-monospace, Menlo, monospace; white-space: pre-wrap; }
21498
- .note .trust { display: none; }
21499
- .alert { background: rgba(227,109,109,.08); color: #f0c7c7; border: 1px solid rgba(227,109,109,.18); }
21500
- .review-card { background: #141414; border: 1px solid var(--line); color: var(--muted); font-size: 13px; }
21501
- .dock { padding: 0 20px 14px; }
21502
- .composer-actions { max-width: 780px; margin: 0 auto 8px; display: flex; align-items: center; gap: 8px; }
21503
- .changes-pill, .ship-btn, .meta-btn {
21504
- display: inline-flex; align-items: center; gap: 8px;
21505
- height: 30px; padding: 0 12px; border-radius: 999px;
21506
- border: 1px solid var(--line); background: #1a1916; color: var(--muted); font-size: 12px;
21507
- }
21508
- .changes-pill .plus { color: var(--live); font-variant-numeric: tabular-nums; }
21509
- .changes-pill .minus { color: var(--err); font-variant-numeric: tabular-nums; }
21510
- .ship-btn:disabled { opacity: .4; cursor: not-allowed; }
21511
- .ship-wrap { position: relative; display: inline-flex; }
21512
- .ship-btn { border-radius: 999px 0 0 999px; background: #22211d; color: var(--fg); }
21513
- .ship-caret { width: 30px; height: 30px; border: 1px solid var(--line); border-left: 0; border-radius: 0 999px 999px 0; background: #22211d; color: var(--muted); }
21514
- .ship-menu { display: none; position: absolute; left: 0; bottom: 36px; min-width: 220px; background: #171614; border: 1px solid var(--line); border-radius: 12px; padding: 6px; z-index: 8; box-shadow: 0 18px 40px rgba(0,0,0,.45); }
21515
- .ship-menu.open, .branch-menu.open { display: grid; gap: 2px; }
21516
- .ship-menu button, .branch-menu button { width: 100%; text-align: left; border: 0; background: transparent; color: var(--muted); padding: 8px 10px; border-radius: 8px; font-size: 12px; }
21517
- .ship-menu button:hover, .branch-menu button:hover { background: rgba(255,236,222,.06); color: var(--fg); }
21518
- .composer { max-width: 780px; margin: 0 auto; background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 6px; }
21519
- textarea { width: 100%; min-height: 64px; max-height: 220px; resize: none; background: transparent; border: 0; padding: 10px 10px 6px; outline: none; line-height: 1.5; font-size: 15px; }
21520
- textarea::placeholder { color: #6a6a6a; }
21521
- .bar { display: flex; align-items: center; gap: 8px; padding: 4px 4px 2px; }
21522
- .cmds { position: relative; }
21523
- .cmd-pop { display: none; position: absolute; left: 0; bottom: 36px; width: 240px; background: #161616; border: 1px solid var(--line); border-radius: 4px; padding: 6px; z-index: 5; box-shadow: 0 18px 40px rgba(0,0,0,.4); }
21524
- .cmd-pop.open { display: grid; gap: 2px; }
21525
- .cmds button, .cmd-pop button { background: transparent; border: 0; color: var(--muted); padding: 7px 8px; border-radius: 2px; font-size: 12px; text-align: left; width: 100%; }
21526
- .cmds > #cmd-open { width: 32px; height: 32px; padding: 0; border: 0; font-size: 18px; line-height: 1; }
21527
- .cmds button:hover, .cmd-pop button:hover { background: rgba(255,236,222,.05); color: var(--fg); }
21528
- .bar-right { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
21529
- .model-chip { color: var(--muted); font-size: 12px; max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21530
- #model { max-width: 220px; background: transparent; border: 0; color: var(--muted); font-size: 12px; padding: 4px 0; outline: none; }
21531
- #model:hover, #model:focus { color: var(--fg); }
21532
- #send { min-width: 72px; height: 32px; border: 0; border-radius: 2px; background: var(--accent); color: #fff; display: grid; place-items: center; padding: 0 12px; font-size: 12px; font-weight: 650; letter-spacing: .04em; text-transform: uppercase; }
21533
- #send:hover { transform: translateY(-1px); }
21534
- #send.steer { background: #3dd68c; }
21535
- #send:disabled, textarea:disabled { opacity: .4; cursor: not-allowed; }
21536
- .queue { margin: 0 8px 8px; border: 1px solid var(--line); border-radius: 12px; background: #141414; }
21537
- .queue[hidden] { display: none; }
21538
- .queue-item { padding: 10px 12px; color: var(--fg); font-size: 13px; white-space: pre-wrap; border-bottom: 1px solid var(--line); }
21539
- .queue-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 6px 10px; color: var(--muted); font-size: 12px; }
21540
- .queue-bar button { border: 0; background: transparent; color: var(--muted); font-size: 12px; padding: 4px 6px; border-radius: 8px; }
21541
- .queue-bar button:hover { color: var(--fg); background: rgba(255,255,255,.05); }
21542
- .queue-bar .now { color: var(--fg); }
21543
- .model-wrap { position: relative; }
21544
- #model-open { max-width: 220px; background: transparent; border: 1px solid var(--line); border-radius: 2px; color: var(--muted); font-size: 12px; padding: 6px 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21545
- #model-open:hover, #model-open[aria-expanded="true"] { color: var(--fg); border-color: rgba(255,255,255,.2); }
21546
- #model-menu { display: none; position: absolute; right: 0; bottom: 36px; width: 280px; max-height: 320px; overflow: hidden; background: #161616; border: 1px solid var(--line); border-radius: 14px; box-shadow: 0 18px 40px rgba(0,0,0,.4); z-index: 5; }
21547
- #model-menu.open { display: grid; grid-template-rows: auto 1fr; }
21548
- #model-filter { width: 100%; background: #101010; border: 0; border-bottom: 1px solid var(--line); color: var(--fg); padding: 10px 12px; outline: none; font-size: 12px; }
21549
- #model-list { overflow: auto; max-height: 260px; padding: 6px; }
21550
- #model-list button { display: block; width: 100%; text-align: left; border: 0; background: transparent; color: var(--muted); padding: 8px 10px; border-radius: 8px; font-size: 12px; }
21551
- #model-list button:hover, #model-list button.on { background: rgba(255,255,255,.06); color: var(--fg); }
21552
- .ctx-wrap { position: relative; display: inline-flex; }
21553
- .ctx { min-width: 52px; height: 28px; padding: 0 8px; border: 1px solid var(--line); background: transparent; color: var(--muted); border-radius: 2px; font: 11px/1 ui-monospace, Menlo, monospace; display: inline-flex; align-items: center; gap: 6px; }
21554
- .ctx svg { display: block; flex-shrink: 0; }
21555
- .ctx svg { display: block; }
21556
- .ctx .track { fill: none; stroke: rgba(255,255,255,.12); stroke-width: 2.4; }
21557
- .ctx .fill { fill: none; stroke: #ececec; stroke-width: 2.4; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 12px 12px; }
21558
- #ctx-tip { display: none; position: absolute; right: 0; top: 32px; width: max-content; max-width: 240px; background: #161616; border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; color: var(--fg); font-size: 12px; z-index: 6; box-shadow: 0 12px 28px rgba(0,0,0,.35); }
21559
- .ctx-wrap:hover #ctx-tip, .ctx-wrap:focus-within #ctx-tip { display: block; }
21560
- #model { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
21561
- #modal { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.55); align-items: center; justify-content: center; padding: 24px; z-index: 4; }
21562
- #modal.open { display: flex; }
21563
- .dialog { width: min(520px, 100%); background: #161616; border: 1px solid var(--line); border-radius: 16px; padding: 18px; }
21564
- .dialog h3 { margin: 0 0 8px; font-size: 15px; font-weight: 600; }
21565
- .dialog .purpose { color: var(--muted); font-size: 13px; }
21566
- .preview { max-height: 240px; overflow: auto; white-space: pre-wrap; word-break: break-word; margin: 12px 0 16px; padding: 12px; background: #101010; border-radius: 10px; font-family: ui-monospace, Menlo, monospace; font-size: 12px; color: var(--muted); }
21567
- .modal-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }
21568
- .modal-actions button { border: 1px solid var(--line); background: #1c1c1c; border-radius: 10px; padding: 8px 12px; }
21569
- .modal-actions .deny { color: var(--err); }
21570
- .modal-actions #always { color: var(--muted); }
21571
- .modal-actions #approve { background: #ececec; color: #111; border-color: transparent; }
21572
- .always-row { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; padding: 4px 8px 0; }
21573
- .always-row input { accent-color: #ececec; }
21574
- @media (max-width: 1100px) {
21575
- .shell, .shell.rail-off { grid-template-columns: var(--rail-w) 1fr; }
21576
- .gutter { display: none; }
21577
- .changes { display: none; }
21578
- .shell:not(.changes-off) .changes,
21579
- .changes.open { display: grid; position: fixed; inset: 0 0 0 auto; width: min(400px, 100%); z-index: 3; box-shadow: -16px 0 40px rgba(0,0,0,.45); }
21580
- }
21581
- @media (max-width: 720px) {
21582
- .shell, .shell.rail-off { grid-template-columns: 1fr; }
21583
- .rail { display: none; }
21584
- .shell:not(.rail-off) .rail {
21585
- display: flex; position: fixed; inset: 0 auto 0 0; width: min(280px, 86vw); z-index: 5;
21586
- box-shadow: 16px 0 40px rgba(0,0,0,.45);
21587
- }
21588
- header { padding: 12px 16px 4px; }
21589
- .dock { padding: 0 12px calc(16px + env(safe-area-inset-bottom)); }
21590
- .bar { flex-wrap: wrap; }
21591
- .bar-right { margin-left: 0; width: 100%; justify-content: flex-end; }
21592
- .composer-foot { flex-wrap: wrap; }
21593
- .composer-actions { flex-wrap: wrap; }
21594
- body.remote .composer textarea { min-height: 88px; font-size: 16px; }
21595
- body.remote #send { min-width: 88px; height: 40px; }
21596
- }
21597
- .composer {
21598
- position: relative;
21599
- max-width: 780px;
21600
- padding: 6px;
21601
- border-radius: 16px;
21602
- background:
21603
- linear-gradient(180deg, rgba(255,236,222,.04), transparent 28%),
21604
- var(--panel);
21605
- border: 1px solid rgba(255,236,222,.12);
21606
- box-shadow: 0 18px 40px rgba(0,0,0,.28), inset 0 1px 0 rgba(255,236,222,.06);
21607
- }
21608
- .composer textarea { min-height: 44px; max-height: 180px; padding: 10px 8px; font-size: 14px; }
21609
- .composer textarea::placeholder { color: #7c746a; }
21610
- .composer-line { display: flex; align-items: flex-end; gap: 6px; }
21611
- .composer-line textarea { flex: 1; min-width: 0; }
21612
- .plus-btn, .mic-btn {
21613
- width: 32px; height: 32px; flex-shrink: 0; border: 0; border-radius: 999px;
21614
- background: transparent; color: var(--muted); display: grid; place-items: center;
21615
- }
21616
- .plus-btn:hover, .mic-btn:hover, .mic-btn.on { color: var(--fg); background: rgba(255,236,222,.06); }
21617
- .composer-foot { display: flex; align-items: center; gap: 8px; padding: 2px 4px 2px; }
21618
- .branch-wrap { position: relative; }
21619
- .branch-menu { display: none; position: absolute; left: 0; bottom: 34px; min-width: 200px; max-height: 240px; overflow: auto; background: #171614; border: 1px solid var(--line); border-radius: 12px; padding: 6px; z-index: 8; }
21620
- .host-chip { color: var(--faint); font-size: 12px; display: inline-flex; align-items: center; gap: 6px; }
21621
- .composer-foot .bar-right { margin-left: auto; }
21622
- #file-view { white-space: pre-wrap; font: 12px ui-monospace, Menlo, monospace; padding: 12px; color: var(--muted); overflow: auto; min-height: 0; }
21623
- #preview { width: 100%; min-height: 0; height: 100%; border: 0; background: #fff; }
21624
- .pick { position: relative; }
21625
- .pick-open, #model-open, #thinking-open {
21626
- display: inline-flex; align-items: center; gap: 7px;
21627
- max-width: 220px; height: 30px; padding: 0 10px;
21628
- background: rgba(255,236,222,.03); border: 1px solid var(--line); border-radius: 8px;
21629
- color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden;
21630
- }
21631
- .pick-open:hover, #model-open:hover, #thinking-open:hover,
21632
- .pick-open[aria-expanded="true"], #model-open[aria-expanded="true"], #thinking-open[aria-expanded="true"] {
21633
- color: var(--fg); border-color: rgba(255,236,222,.22); background: rgba(255,236,222,.06);
21634
- }
21635
- .pick-open .caret, #model-open .caret, #thinking-open .caret { opacity: .45; margin-left: 2px; }
21636
- .model-ico { display: block; flex-shrink: 0; border-radius: 4px; }
21637
- #model-open { max-width: 240px; }
21638
- .pick-menu, #model-menu, #mention {
21639
- display: none; position: absolute; z-index: 8;
21640
- min-width: 220px; max-height: 320px; overflow: hidden;
21641
- background: #171614; border: 1px solid rgba(255,236,222,.14); border-radius: 12px;
21642
- box-shadow: 0 22px 50px rgba(0,0,0,.45);
21643
- }
21644
- .pick-menu.open, #model-menu.open, #mention.open { display: grid; }
21645
- .pick-menu { right: 0; bottom: 36px; padding: 6px; }
21646
- #model-menu { right: 0; bottom: 36px; width: 300px; grid-template-rows: auto 1fr; }
21647
- #mention {
21648
- left: 12px; bottom: calc(100% - 8px); width: min(480px, calc(100% - 24px));
21649
- }
21650
- .term .pick-menu { bottom: auto; top: 28px; }
21651
- .pick-menu button, #model-list button, #mention-list button {
21652
- display: flex; align-items: center; gap: 8px; width: 100%;
21653
- text-align: left; border: 0; background: transparent; color: var(--muted);
21654
- padding: 8px 10px; border-radius: 8px; font-size: 12px;
21655
- }
21656
- .pick-menu button:hover, .pick-menu button.on,
21657
- #model-list button:hover, #model-list button.on,
21658
- #mention-list button:hover, #mention-list button.on {
21659
- background: rgba(255,236,222,.06); color: var(--fg);
21660
- }
21661
- .pick-menu button .meta, #mention-list button .meta { margin-left: auto; color: var(--faint); font-size: 11px; }
21662
- #model-filter {
21663
- width: 100%; background: #12110f; border: 0; border-bottom: 1px solid var(--line);
21664
- color: var(--fg); padding: 10px 12px; outline: none; font-size: 12px;
21665
- }
21666
- #model-list, #mention-list { overflow: auto; max-height: 260px; padding: 6px; }
21667
- .mention-k { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--faint); padding: 8px 10px 4px; }
21668
- #send {
21669
- min-width: 72px; height: 32px; border: 0; border-radius: 8px;
21670
- background: var(--accent); color: #fff; display: grid; place-items: center;
21671
- padding: 0 14px; font-size: 12px; font-weight: 650; letter-spacing: .04em; text-transform: uppercase;
21672
- }
21673
- #send:hover { transform: translateY(-1px); }
21674
- #send.steer { background: var(--live); color: #102016; }
21675
- #send:disabled, textarea:disabled { opacity: .4; cursor: not-allowed; }
21676
- #mode, #autonomy, #model, #thinking, #review-depth, #review-lens, #term-timeout, #studio-author, #studio-review, #key-kind {
21677
- position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0;
21678
- }
21679
- .sheet .pick-menu { bottom: auto; top: 32px; left: 0; right: auto; }
21680
- .bar { gap: 6px; }
21681
- .bar-right { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
21682
- .chip { display: inline-flex; align-items: center; gap: 6px; }
21683
- .prompt { border-radius: 14px; background: var(--prompt); }
21684
- .reply { color: #e8e2d8; }
21685
- #empty h1 { color: #8a8378; font-weight: 500; }
21686
- .rail .plus, .diff-actions button, .workspace button {
21687
- transition: border-color .2s var(--ease), color .2s var(--ease), background .2s var(--ease);
21688
- }
21321
+ --bg:#0f0f0e;
21322
+ --rail:#141412;
21323
+ --surface:#181816;
21324
+ --surface-2:#1d1c19;
21325
+ --surface-3:#23211e;
21326
+ --hover:rgba(255,255,255,.055);
21327
+ --line:rgba(255,244,232,.09);
21328
+ --line-strong:rgba(255,244,232,.16);
21329
+ --fg:#f3eee6;
21330
+ --muted:#aaa197;
21331
+ --faint:#736d65;
21332
+ --green:#55d88c;
21333
+ --amber:#e0aa43;
21334
+ --red:#ef7770;
21335
+ --blue:#8fb7ff;
21336
+ --brand:#e72b2b;
21337
+ --primary:#f1ece4;
21338
+ --primary-fg:#171613;
21339
+ --shadow:0 24px 80px rgba(0,0,0,.48);
21340
+ --ease:cubic-bezier(.2,.8,.2,1);
21341
+ --rail-w:252px;
21342
+ --changes-w:390px;
21343
+ --top-h:48px;
21344
+ }
21345
+ html[data-theme="light"]{
21346
+ --bg:#f6f4ef;
21347
+ --rail:#eeeae3;
21348
+ --surface:#fff;
21349
+ --surface-2:#f3f0ea;
21350
+ --surface-3:#e9e4dc;
21351
+ --hover:rgba(0,0,0,.045);
21352
+ --line:rgba(20,18,14,.1);
21353
+ --line-strong:rgba(20,18,14,.16);
21354
+ --fg:#1a1814;
21355
+ --muted:#5f5a52;
21356
+ --faint:#8a837a;
21357
+ --primary:#1a1814;
21358
+ --primary-fg:#f6f4ef;
21359
+ --shadow:0 24px 80px rgba(0,0,0,.12);
21360
+ }
21361
+ *{box-sizing:border-box}
21362
+ [hidden]{display:none!important}
21363
+ html,body{margin:0;width:100%;height:100%;height:100dvh;overflow:hidden;background:var(--bg);color:var(--fg);font-family:"IBM Plex Sans","Helvetica Neue",ui-sans-serif,system-ui,sans-serif;font-size:14px;letter-spacing:-.015em}
21364
+ button,input,textarea,select{font:inherit;color:inherit}
21365
+ button{cursor:pointer}
21366
+ button:focus-visible,input:focus-visible,textarea:focus-visible{outline:2px solid rgba(143,183,255,.75);outline-offset:2px}
21367
+ .shell{display:grid;grid-template-columns:var(--rail-w) minmax(0,1fr) 1px var(--changes-w);height:100dvh;overflow:hidden}
21368
+ .shell.rail-off{grid-template-columns:minmax(0,1fr) 1px var(--changes-w)}
21369
+ .shell.rail-off .rail{display:none}
21370
+ .shell.changes-off{grid-template-columns:var(--rail-w) minmax(0,1fr)}
21371
+ .shell.changes-off .gutter,.shell.changes-off .changes{display:none}
21372
+ .shell.rail-off.changes-off{grid-template-columns:minmax(0,1fr)}
21373
+ .shell.term-off .term{display:none}
21374
+ .gutter{background:var(--line);cursor:col-resize}
21375
+
21376
+ /* sidebar */
21377
+ .rail{min-width:0;background:var(--rail);border-right:1px solid var(--line);padding:10px 9px 9px;display:flex;flex-direction:column;gap:9px;overflow:hidden}
21378
+ .rail-top{height:34px;display:flex;align-items:center;justify-content:space-between;padding:0 4px}
21379
+ .brand{display:inline-flex;align-items:center;gap:9px;color:var(--fg);font-weight:650;font-size:13px;min-width:0}
21380
+ .mark{width:26px;height:26px;border-radius:7px;background:var(--brand);display:grid;place-items:center;color:#fff;font:700 11px ui-monospace,Menlo,monospace;box-shadow:inset 0 1px 0 rgba(255,255,255,.12)}
21381
+ .brand span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21382
+ .rail .plus{height:36px;width:100%;border:1px solid var(--line);background:transparent;color:var(--fg);border-radius:9px;display:flex;align-items:center;justify-content:flex-start;gap:9px;padding:0 10px;font-size:12.5px;transition:.16s var(--ease)}
21383
+ .rail .plus:hover{background:var(--hover);border-color:var(--line-strong)}
21384
+ .rail-search{position:relative}
21385
+ .rail-search svg{position:absolute;left:10px;top:9px;color:var(--faint);pointer-events:none}
21386
+ .rail .search{width:100%;height:34px;background:transparent;border:1px solid transparent;border-radius:8px;padding:0 10px 0 31px;color:var(--fg);outline:0;font-size:12px}
21387
+ .rail .search:focus{border-color:var(--line);background:rgba(255,255,255,.025)}
21388
+ #sessions{display:flex;flex-direction:column;gap:2px;min-height:0;overflow:auto;overscroll-behavior:contain;padding-right:1px;flex:1}
21389
+ .session-row{display:grid;grid-template-columns:minmax(0,1fr) 28px;gap:2px;align-items:center;border-radius:8px}
21390
+ .session-row:hover,.session-row.on{background:var(--hover)}
21391
+ .session-item{width:100%;min-width:0;text-align:left;border:0;background:transparent;color:var(--muted);padding:8px 9px;border-radius:8px;font-size:12.5px;line-height:1.35;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21392
+ .session-row.on .session-item{color:var(--fg)}
21393
+ .session-delete{width:26px;height:26px;border:0;background:transparent;color:transparent;border-radius:7px;display:grid;place-items:center}
21394
+ .session-row:hover .session-delete{color:var(--faint)}
21395
+ .session-delete:hover{background:rgba(239,119,112,.1)!important;color:var(--red)!important}
21396
+ .rail-footer{border-top:1px solid var(--line);padding-top:8px;display:grid;gap:5px}
21397
+ .rail-footer button{height:34px;border:0;background:transparent;color:var(--muted);border-radius:8px;text-align:left;padding:0 9px;display:flex;align-items:center;gap:9px;font-size:12px}
21398
+ .rail-footer button:hover{background:var(--hover);color:var(--fg)}
21399
+ .repo-mini{padding:4px 9px;color:var(--faint);font:10.5px ui-monospace,Menlo,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21400
+
21401
+ /* main */
21402
+ .stage{display:grid;grid-template-rows:var(--top-h) minmax(0,1fr) auto auto;min-width:0;min-height:0;height:100dvh;overflow:hidden;background:var(--bg)}
21403
+ .topbar{height:var(--top-h);display:flex;align-items:center;gap:10px;padding:0 14px;border-bottom:1px solid var(--line);background:rgba(15,15,14,.86);backdrop-filter:blur(16px);z-index:2}
21404
+ .topbar-left{display:flex;align-items:center;gap:9px;min-width:0;flex:1}
21405
+ .session-title{min-width:0;font-size:12.5px;font-weight:600;color:var(--fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21406
+ .top-actions{display:flex;align-items:center;gap:5px;min-width:0}
21407
+ .icon-btn,.toolbar-btn{border:1px solid transparent;background:transparent;color:var(--muted);border-radius:8px;display:inline-flex;align-items:center;justify-content:center;gap:7px;height:30px;padding:0 8px;font-size:11.5px;white-space:nowrap}
21408
+ .icon-btn{width:30px;padding:0}
21409
+ .icon-btn:hover,.toolbar-btn:hover,.icon-btn.on,.toolbar-btn.on{background:var(--hover);color:var(--fg);border-color:var(--line)}
21410
+ .toolbar-btn .count{min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:rgba(255,255,255,.07);display:inline-grid;place-items:center;color:var(--fg);font:10px ui-monospace,Menlo,monospace}
21411
+ .top-status,.badge{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--faint);font-size:11px}
21412
+ .badge.err{color:var(--red)}
21413
+ #stop{color:var(--red);background:rgba(239,119,112,.08)}
21414
+ main{min-height:0;overflow:auto;overscroll-behavior:contain;scrollbar-gutter:stable}
21415
+ #empty{max-width:700px;margin:17vh auto 0;padding:0 28px 44px}
21416
+ #empty h1{margin:0 0 10px;font-size:27px;line-height:1.2;font-weight:520;letter-spacing:-.04em;color:var(--fg)}
21417
+ #empty p{margin:0;color:var(--muted);font-size:13px;line-height:1.6;max-width:540px}
21418
+ .empty-actions{display:flex;flex-wrap:wrap;gap:7px;margin-top:22px}
21419
+ .empty-actions button{height:32px;border:1px solid var(--line);background:transparent;border-radius:8px;color:var(--muted);padding:0 10px;font-size:11.5px}
21420
+ .empty-actions button:hover{background:var(--hover);color:var(--fg)}
21421
+ #feed{display:none;max-width:780px;margin:0 auto;padding:30px 28px 38px}
21422
+ #feed.on{display:block}
21423
+ .turn{margin:0 0 34px;position:relative}
21424
+ .prompt{max-width:82%;margin:0 0 18px auto;background:var(--surface-2);border:1px solid var(--line);border-radius:16px 16px 5px 16px;padding:11px 14px;line-height:1.5;white-space:pre-wrap;word-break:break-word;color:var(--fg);font-size:13.5px}
21425
+ .reply{margin:0;color:#e9e3da;font-size:14px;line-height:1.63;word-break:break-word}
21426
+ .reply>*:first-child{margin-top:0}.reply>*:last-child{margin-bottom:0}
21427
+ .reply h1,.reply h2,.reply h3,.reply h4{color:var(--fg);font-weight:620;letter-spacing:-.03em;line-height:1.3;margin:20px 0 9px}
21428
+ .reply h1{font-size:19px}.reply h2{font-size:16.5px}.reply h3{font-size:14.5px}.reply h4{font-size:13.5px;color:#ddd6cc}
21429
+ .reply p{margin:0 0 11px}.reply ul,.reply ol{margin:0 0 12px;padding-left:1.25em}.reply li{margin:0 0 4px}.reply li::marker{color:var(--faint)}
21430
+ .reply a{color:#a9c8ff;text-decoration:none}.reply a:hover{text-decoration:underline}
21431
+ .reply code{font:12px ui-monospace,Menlo,monospace;background:rgba(255,255,255,.055);border:1px solid var(--line);border-radius:5px;padding:1px 5px}
21432
+ .reply blockquote{margin:0 0 12px;padding:7px 11px;border-left:2px solid var(--line-strong);color:var(--muted);background:rgba(255,255,255,.02)}
21433
+ .reply hr{border:0;border-top:1px solid var(--line);margin:16px 0}
21434
+ .md-code{position:relative;background:#11110f;border:1px solid var(--line);border-radius:10px;padding:30px 12px 12px;overflow:auto;font:12px ui-monospace,Menlo,monospace;line-height:1.55}
21435
+ .md-code .copy{position:absolute;right:7px;top:7px;border:1px solid var(--line);background:var(--surface);color:var(--muted);border-radius:6px;padding:3px 7px;font-size:10.5px}
21436
+ .reply .md-code code{background:none;border:0;padding:0}
21437
+ .md-table{margin:10px 0 14px;overflow:auto;border:1px solid var(--line);border-radius:10px;background:#121210}
21438
+ .reply table{width:100%;border-collapse:collapse;font-size:12.5px}.reply th,.reply td{padding:8px 10px;text-align:left;vertical-align:top;border-bottom:1px solid var(--line)}.reply th{color:var(--muted);font-weight:600;font-size:11px;background:rgba(255,255,255,.025)}.reply tr:last-child td{border-bottom:0}
21439
+
21440
+ /* activity: each tool is its own row */
21441
+ .activity{display:grid;gap:5px;margin:9px 0 13px}
21442
+ .tool-event,.think{margin:0;border:0;background:transparent;color:var(--muted);font-size:11.5px}
21443
+ .tool-event summary,.think summary{list-style:none;display:flex;align-items:center;gap:8px;min-height:28px;width:max-content;max-width:100%;padding:4px 7px;border-radius:7px;cursor:pointer;user-select:none}
21444
+ .tool-event summary::-webkit-details-marker,.think summary::-webkit-details-marker{display:none}
21445
+ .tool-event summary:hover,.think summary:hover{background:var(--hover);color:var(--fg)}
21446
+ .tool-dot{width:7px;height:7px;border-radius:999px;background:var(--faint);flex:0 0 auto}
21447
+ .tool-event.running .tool-dot{background:var(--amber);box-shadow:0 0 0 3px rgba(224,170,67,.08)}
21448
+ .tool-event.done .tool-dot{background:var(--green)}
21449
+ .tool-event.failed .tool-dot{background:var(--red)}
21450
+ .tool-name{font-family:ui-monospace,Menlo,monospace;color:#c5bdb1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21451
+ .tool-phase{color:var(--faint)}
21452
+ .tool-detail{margin:2px 0 4px 21px;max-width:min(680px,calc(100vw - 64px));padding:9px 10px;border-left:1px solid var(--line);color:#918a81;white-space:pre-wrap;word-break:break-word;font:11px/1.5 ui-monospace,Menlo,monospace}
21453
+ .think{margin:6px 0;color:var(--faint)}
21454
+ .think>div{margin:2px 0 4px 21px;padding-left:10px;border-left:1px solid var(--line);white-space:pre-wrap;word-break:break-word;font-size:11.5px;line-height:1.5;color:#858078}
21455
+ .note,.alert,.review-card{margin:10px 0;padding:8px 10px;border-radius:8px;line-height:1.5;word-break:break-word;font-size:12px}
21456
+ .note{padding:5px 2px;background:transparent;border:0;color:var(--faint);font-family:ui-monospace,Menlo,monospace}
21457
+ .alert{background:rgba(239,119,112,.07);border:1px solid rgba(239,119,112,.18);color:#f0b8b4}
21458
+ .review-card{background:rgba(85,216,140,.045);border:1px solid rgba(85,216,140,.18);color:#d8e7dd}
21459
+ .trust{display:none}
21460
+ .agent{margin:6px 0;padding:7px 9px;border-left:1px solid var(--line);color:var(--muted);font-size:11.5px}.agent.running{border-left-color:var(--amber)}.agent b{color:var(--fg);font-weight:560}
21461
+
21462
+ /* composer */
21463
+ .dock{padding:8px 18px 14px;background:linear-gradient(180deg,transparent,rgba(15,15,14,.96) 18%)}
21464
+ .composer{position:relative;max-width:800px;margin:0 auto;background:var(--surface);border:1px solid var(--line-strong);border-radius:17px;padding:6px;box-shadow:0 16px 42px rgba(0,0,0,.25),inset 0 1px 0 rgba(255,255,255,.035)}
21465
+ .composer-line{display:flex;align-items:flex-end;gap:5px}
21466
+ .composer-line textarea{flex:1;min-width:0;width:100%;min-height:44px;max-height:190px;resize:none;background:transparent;border:0;padding:9px 7px;outline:0;line-height:1.5;font-size:14px;color:var(--fg)}
21467
+ .composer-line textarea::placeholder{color:#716b63}
21468
+ .round-btn,.plus-btn,.mic-btn{width:32px;height:32px;flex:0 0 auto;border:0;border-radius:9px;background:transparent;color:var(--muted);display:grid;place-items:center}
21469
+ .round-btn:hover,.plus-btn:hover,.mic-btn:hover,.mic-btn.on{background:var(--hover);color:var(--fg)}
21470
+ .composer-foot{display:flex;align-items:center;gap:6px;padding:3px 3px 1px;min-height:36px}
21471
+ .composer-left,.composer-right{display:flex;align-items:center;gap:5px;min-width:0}.composer-right{margin-left:auto;flex:0 0 auto}
21472
+ .pick{position:relative}
21473
+ .pick-open,#model-open{height:30px;max-width:190px;display:inline-flex;align-items:center;gap:7px;padding:0 9px;border:1px solid transparent;border-radius:8px;background:transparent;color:var(--muted);font-size:11.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
21474
+ .pick-open:hover,#model-open:hover,.pick-open[aria-expanded="true"],#model-open[aria-expanded="true"]{background:var(--hover);border-color:var(--line);color:var(--fg)}
21475
+ .pick-open .caret,#model-open .caret{opacity:.45;font-size:9px}
21476
+ .model-ico{width:15px!important;height:15px!important;display:block;flex:0 0 auto;border-radius:4px}
21477
+ .model-fallback{width:15px;height:15px;display:inline-grid;place-items:center;border-radius:4px;background:rgba(255,255,255,.08);color:var(--fg);font:700 8px ui-monospace,Menlo,monospace;flex:0 0 auto}
21478
+ .pick-menu,#model-menu,#mention,.cmd-pop,.branch-menu,.ship-menu{display:none;position:absolute;z-index:20;background:#171715;border:1px solid var(--line-strong);border-radius:12px;box-shadow:var(--shadow);overflow:hidden}
21479
+ .pick-menu.open,#model-menu.open,#mention.open,.cmd-pop.open,.branch-menu.open,.ship-menu.open{display:grid}
21480
+ .pick-menu{bottom:36px;left:0;min-width:210px;max-height:300px;overflow:auto;overscroll-behavior:contain;padding:5px}
21481
+ #model-menu{right:0;bottom:36px;width:310px;max-height:360px;grid-template-rows:auto minmax(0,1fr);overscroll-behavior:contain}
21482
+ #model-filter{width:100%;height:39px;background:#121211;border:0;border-bottom:1px solid var(--line);padding:0 11px;outline:0;font-size:12px}
21483
+ #model-list{overflow:auto;overscroll-behavior:contain;max-height:310px;padding:5px}
21484
+ .pick-menu button,#model-list button,#mention-list button{width:100%;min-height:34px;border:0;background:transparent;color:var(--muted);border-radius:8px;padding:7px 9px;text-align:left;display:flex;align-items:center;gap:8px;font-size:11.5px}
21485
+ .pick-menu button:hover,.pick-menu button.on,#model-list button:hover,#model-list button.on,#mention-list button:hover,#mention-list button.on{background:var(--hover);color:var(--fg)}
21486
+ #model{position:absolute;opacity:0;pointer-events:none;width:0;height:0}
21487
+ #send{width:34px;height:34px;border:0;border-radius:10px;background:var(--primary);color:var(--primary-fg);display:grid;place-items:center;padding:0;transition:.14s var(--ease)}
21488
+ #send:hover{transform:translateY(-1px);filter:brightness(1.04)}#send.steer{background:#bfe8cf;color:#142219}#send:disabled{opacity:.45;cursor:not-allowed}
21489
+ #review-run{height:30px;padding:0 10px;border:1px solid var(--line);border-radius:8px;background:transparent;color:var(--muted);font-size:11.5px}#review-run:hover{background:var(--hover);color:var(--fg)}
21490
+ .autonomy-pill.auto{color:var(--amber);border-color:rgba(224,170,67,.24);background:rgba(224,170,67,.055)}
21491
+ .chips{display:flex;flex-wrap:wrap;gap:4px;padding:0 7px 4px}.chip{display:inline-flex;align-items:center;gap:5px;border-radius:7px;background:rgba(255,255,255,.055);padding:3px 7px;color:var(--muted);font-size:10.5px;cursor:pointer}
21492
+ .queue{margin:2px 5px 6px;border:1px solid var(--line);border-radius:10px;background:#141412}.queue-item{padding:8px 10px;color:var(--fg);font-size:12px;white-space:pre-wrap;border-bottom:1px solid var(--line)}.queue-item button{float:right;border:0;background:transparent;color:var(--faint);font-size:10px}.queue-bar{display:flex;align-items:center;justify-content:space-between;padding:6px 9px;color:var(--muted);font-size:10.5px}.queue-bar button{border:0;background:transparent;color:var(--muted);font-size:10.5px}.queue-bar .now{color:var(--fg)}
21493
+ .cmds{position:relative}.cmd-pop{left:0;bottom:38px;width:220px;padding:5px}.cmd-pop button{height:34px;border:0;background:transparent;color:var(--muted);border-radius:8px;padding:0 9px;text-align:left;font-size:11.5px}.cmd-pop button:hover{background:var(--hover);color:var(--fg)}
21494
+ #mention{left:8px;bottom:calc(100% - 4px);width:min(500px,calc(100% - 16px));max-height:330px}#mention-list{overflow:auto;overscroll-behavior:contain;padding:5px}.mention-k{font-size:9px;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);padding:7px 9px 3px}.pick-menu button .meta,#mention-list button .meta{margin-left:auto;color:var(--faint);font-size:10px}
21495
+
21496
+ /* terminal */
21497
+ .term{border-top:1px solid var(--line);background:#0d0d0c;display:grid;grid-template-rows:auto minmax(70px,1fr) auto;max-height:220px}.term header{height:32px;display:flex;align-items:center;justify-content:space-between;padding:0 10px;color:var(--faint);font-size:10.5px}.term header>span{display:flex;align-items:center;gap:6px}.term pre{margin:0;padding:8px 11px;overflow:auto;overscroll-behavior:contain;font:11px/1.5 ui-monospace,Menlo,monospace;color:#bbb4aa}.term form{display:flex;padding:5px 8px 8px}.term input{flex:1;height:31px;background:#141412;border:1px solid var(--line);border-radius:7px;padding:0 9px;outline:0;font:11px ui-monospace,Menlo,monospace}.term button{border:0;background:transparent;color:var(--muted);font-size:10.5px}.term .pick-menu{bottom:auto;top:30px}.always-row{display:flex;align-items:center;gap:7px;color:var(--muted);font-size:11px}.always-row input{accent-color:var(--amber)}
21498
+
21499
+ /* workspace */
21500
+ .changes{min-width:0;min-height:0;height:100dvh;background:var(--rail);border-left:1px solid var(--line);display:grid;grid-template-rows:auto auto minmax(0,1fr);overflow:hidden}.changes>header{padding:11px 10px 8px;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:3px 8px;align-items:center}.changes h2{margin:0;font-size:12.5px;font-weight:620}.changes .sum{grid-column:1/-1;color:var(--faint);font:10.5px ui-monospace,Menlo,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.work-tabs{display:flex;gap:2px;padding:0 7px 7px;border-bottom:1px solid var(--line)}.work-tabs button{height:27px;border:0;background:transparent;color:var(--muted);font-size:10.5px;border-radius:7px;padding:0 8px}.work-tabs button.on{background:var(--hover);color:var(--fg)}.work-stack{min-height:0;overflow:hidden;display:grid}.work-stack>*{min-height:0;height:100%}.workspace{min-height:0;padding:7px;display:grid;gap:6px;overflow:hidden}.workspace input{width:100%;height:32px;background:#121211;border:1px solid var(--line);border-radius:8px;padding:0 9px;outline:0;font-size:11px}.tree{min-height:0;overflow:auto;overscroll-behavior:contain;font:11px ui-monospace,Menlo,monospace}.tree button{width:100%;min-height:27px;border:0;background:transparent;color:var(--muted);border-radius:6px;text-align:left;display:flex;align-items:center;gap:6px;padding:4px 6px}.tree button:hover,.tree button.on{background:var(--hover);color:var(--fg)}.tree .twist{width:9px;flex:0 0 auto;opacity:.55;font-size:8px}.tree .kind-untracked,.tree .kind-added{color:#83d7a4}.tree .kind-modified{color:#e6c36a}.tree .kind-deleted{color:var(--red);text-decoration:line-through}.tree .kind-renamed{color:var(--blue)}
21501
+ #tab-tree{grid-template-rows:auto minmax(110px,.8fr) auto minmax(180px,1.25fr)}#tab-findings,#tab-timeline{grid-template-rows:auto minmax(0,1fr)}.diff-head{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px;align-items:center;padding:5px 2px}.diff-title-wrap{min-width:0;display:flex;align-items:center;gap:8px}.diff-back{flex:0 0 auto;border:0;background:transparent;color:var(--muted);padding:3px 5px;border-radius:6px;font-size:10.5px}.diff-back:hover{color:var(--fg);background:var(--hover)}.diff-head b,#diff-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:10.5px ui-monospace,Menlo,monospace;color:var(--fg)}.diff-actions{display:flex;gap:4px}.diff-actions button{height:27px;border:1px solid var(--line);background:transparent;border-radius:7px;padding:0 7px;color:var(--muted);font-size:10px}.diff-actions button:hover{background:var(--hover);color:var(--fg)}.diff-actions .danger{color:var(--red)}.diff{min-height:0;overflow:auto;overscroll-behavior:contain;padding-bottom:14px;border:1px solid var(--line);border-radius:8px;background:#10100f;font:11px/1.5 ui-monospace,Menlo,monospace}.diff-file+.diff-file{border-top:1px solid var(--line-strong);margin-top:10px;padding-top:5px}.diff-file-head{position:sticky;top:0;z-index:2;padding:8px 10px;background:#151513;border-bottom:1px solid var(--line);color:var(--fg);font:600 11px ui-monospace,Menlo,monospace}.diff-loading{padding:14px;color:var(--faint);font-size:11px}.diff .hunk{color:var(--faint);padding:6px 8px 3px;background:rgba(255,255,255,.02)}.diff .row{display:grid;grid-template-columns:36px 36px minmax(0,1fr)}.diff .ln{color:#5e5953;text-align:right;padding:0 6px;user-select:none}.diff .add{background:rgba(85,216,140,.08);color:#bae7ca}.diff .del{background:rgba(239,119,112,.09);color:#efc3c0}.diff .ctx{color:#aaa39a}.diff .code{white-space:pre-wrap;word-break:break-word;padding-right:7px}#file-view{margin:0;white-space:pre-wrap;font:11px/1.5 ui-monospace,Menlo,monospace;padding:10px;color:var(--muted);overflow:auto;border:1px solid var(--line);border-radius:8px;background:#10100f}#preview{width:100%;height:100%;min-height:0;border:0;background:#fff;border-radius:8px}.compare{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding:8px;font:11px ui-monospace,Menlo,monospace;overflow:auto}.find-row{width:100%;text-align:left;border:0;background:transparent;color:var(--muted);padding:7px;border-radius:7px;font-size:11px}.find-row:hover{background:var(--hover);color:var(--fg)}.change-list{display:none}.gate{display:none}
21502
+
21503
+ /* overlays */
21504
+ .sheet{display:none;position:fixed;inset:0;z-index:50;background:rgba(0,0,0,.55);align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(4px)}.sheet.open{display:flex}.sheet .card{width:min(640px,95vw);max-height:84vh;overflow:auto;overscroll-behavior:contain;background:#161614;border:1px solid var(--line-strong);border-radius:14px;padding:16px;box-shadow:var(--shadow)}.sheet h3{margin:0 0 12px;font-size:15px}.sheet label{display:block;color:var(--muted);font-size:11px;margin:9px 0 4px}.sheet input,.sheet select,.sheet textarea.plain{width:100%;background:#11110f;border:1px solid var(--line);border-radius:8px;padding:8px;outline:0}.modal-actions{display:flex;justify-content:flex-end;gap:7px;flex-wrap:wrap;margin-top:12px}.modal-actions button{min-height:32px;border:1px solid var(--line);background:var(--surface);border-radius:8px;padding:0 10px;color:var(--muted)}.modal-actions button:hover{color:var(--fg);border-color:var(--line-strong)}.modal-actions .deny{color:var(--red)}
21505
+ #modal{display:none;position:fixed;inset:0;z-index:60;background:rgba(0,0,0,.58);align-items:center;justify-content:center;padding:20px}#modal.open{display:flex}.dialog{width:min(520px,100%);background:#161614;border:1px solid var(--line-strong);border-radius:14px;padding:16px;box-shadow:var(--shadow)}.dialog h3{margin:0 0 7px;font-size:15px}.dialog .purpose{color:var(--muted);font-size:12px}.preview{max-height:240px;overflow:auto;overscroll-behavior:contain;white-space:pre-wrap;word-break:break-word;margin:11px 0 14px;padding:10px;background:#10100f;border:1px solid var(--line);border-radius:8px;font:11px/1.5 ui-monospace,Menlo,monospace;color:var(--muted)}
21506
+ .palette{display:none;position:fixed;z-index:65;inset:12vh 0 auto;margin:auto;width:min(560px,92vw);background:#161614;border:1px solid var(--line-strong);border-radius:13px;padding:7px;box-shadow:var(--shadow)}.palette.open{display:block}.palette input{width:100%;height:39px;background:#11110f;border:1px solid var(--line);border-radius:8px;padding:0 10px;outline:0}.palette button{width:100%;min-height:34px;border:0;background:transparent;color:var(--muted);text-align:left;border-radius:8px;padding:6px 8px;font-size:11.5px}.palette button:hover{background:var(--hover);color:var(--fg)}
21507
+
21508
+ /* command browser */
21509
+ .command-card{width:min(720px,95vw)!important;padding:0!important;overflow:hidden!important}.sheet-head{height:50px;padding:0 15px;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between}.sheet-head h3{margin:0}.sheet-head button{border:0;background:transparent;color:var(--muted);width:30px;height:30px;border-radius:7px}.sheet-head button:hover{background:var(--hover);color:var(--fg)}.command-body{padding:12px;display:grid;grid-template-rows:auto minmax(0,1fr);gap:9px;max-height:72vh}.command-body input{margin:0}.command-list{min-height:0;overflow:auto;overscroll-behavior:contain;display:grid;gap:3px}.command-row{display:grid;grid-template-columns:140px minmax(0,1fr) auto;gap:10px;align-items:start;border:0;background:transparent;border-radius:9px;padding:9px 10px;text-align:left;color:var(--muted)}.command-row:hover{background:var(--hover);color:var(--fg)}.command-code{font:11px ui-monospace,Menlo,monospace;color:#d2cbc1}.command-desc{font-size:11.5px;line-height:1.4}.command-kind{font-size:9.5px;color:var(--faint);text-transform:uppercase;letter-spacing:.06em}
21510
+
21511
+ /* settings */
21512
+ .settings-card{width:min(980px,96vw)!important;height:min(720px,92vh);max-height:92vh!important;padding:0!important;overflow:hidden!important;display:grid;grid-template-columns:190px minmax(0,1fr);background:#151513!important}.settings-nav{border-right:1px solid var(--line);padding:13px 9px;display:flex;flex-direction:column;gap:3px;min-height:0}.settings-nav-head{display:flex;align-items:center;justify-content:space-between;padding:4px 7px 12px}.settings-nav-head b{font-size:13px}.settings-nav button[data-settings-tab]{height:33px;border:0;background:transparent;color:var(--muted);border-radius:8px;text-align:left;padding:0 9px;font-size:11.5px}.settings-nav button[data-settings-tab]:hover,.settings-nav button[data-settings-tab].on{background:var(--hover);color:var(--fg)}.settings-close{width:28px;height:28px;border:0;background:transparent;color:var(--muted);border-radius:7px}.settings-close:hover{background:var(--hover);color:var(--fg)}.settings-content{min-width:0;min-height:0;overflow:auto;overscroll-behavior:contain;padding:24px 26px 34px}.settings-panel{display:none;max-width:720px}.settings-panel.on{display:block}.settings-panel h2{margin:0 0 4px;font-size:18px;letter-spacing:-.03em}.settings-panel>.sub{margin:0 0 22px;color:var(--muted);font-size:12px;line-height:1.5}.setting-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:24px;align-items:center;padding:13px 0;border-top:1px solid var(--line)}.setting-copy b{display:block;font-size:12.5px;font-weight:580;margin-bottom:3px}.setting-copy span{display:block;color:var(--muted);font-size:11.5px;line-height:1.45}.setting-control{min-width:190px;display:flex;justify-content:flex-end}.setting-control .pick-menu{bottom:auto;top:36px;right:0;left:auto;max-height:300px;overflow:auto;overscroll-behavior:contain}.setting-control .pick-open{border-color:var(--line);background:rgba(255,255,255,.025);min-width:180px;justify-content:space-between}.setting-control input[type=password]{width:240px;height:34px;background:#11110f;border:1px solid var(--line);border-radius:8px;padding:0 9px}.settings-note{border:1px solid var(--line);background:rgba(255,255,255,.025);border-radius:9px;padding:10px 11px;color:var(--muted);font-size:11.5px;line-height:1.5}.settings-note.warn{border-color:rgba(224,170,67,.22);background:rgba(224,170,67,.045)}
21513
+ .usage-cards{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:14px 0 18px}.usage-card{border:1px solid var(--line);border-radius:10px;padding:10px;background:rgba(255,255,255,.018)}.usage-card span{display:block;color:var(--faint);font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;margin-bottom:6px}.usage-card b{font:600 17px ui-monospace,Menlo,monospace;color:var(--fg)}.usage-chart{height:180px;border:1px solid var(--line);border-radius:10px;background:#11110f;padding:9px;margin-bottom:16px}.usage-chart svg{display:block;width:100%;height:100%;overflow:visible}.usage-empty{height:100%;display:grid;place-items:center;color:var(--faint);font-size:11px}.breakdown{display:grid;gap:7px;margin:8px 0 20px}.break-row{display:grid;grid-template-columns:120px minmax(0,1fr) 90px;gap:9px;align-items:center;font-size:10.5px;color:var(--muted)}.break-track{height:6px;background:rgba(255,255,255,.05);border-radius:999px;overflow:hidden}.break-fill{height:100%;background:#847d74;border-radius:999px}.break-val{text-align:right;font:10.5px ui-monospace,Menlo,monospace;color:var(--faint)}
21514
+ .skill-list{display:grid;gap:7px}.skill-row{border:1px solid var(--line);border-radius:9px;padding:10px 11px;background:rgba(255,255,255,.015)}.skill-head{display:flex;align-items:center;gap:8px;margin-bottom:4px}.skill-head b{font-size:12px}.skill-source{padding:2px 6px;border-radius:999px;background:rgba(255,255,255,.055);color:var(--faint);font-size:9.5px}.skill-desc{color:var(--muted);font-size:11.5px;line-height:1.45}.skill-origin{margin-top:5px;color:var(--faint);font:9.5px ui-monospace,Menlo,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.audit-list{display:grid;gap:5px}.audit-row{display:grid;grid-template-columns:120px 90px minmax(0,1fr);gap:8px;padding:7px 0;border-top:1px solid var(--line);color:var(--muted);font-size:10.5px}.audit-row code{color:#c9c1b7;font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21515
+ #mode,#autonomy,#thinking,#review-depth,#review-lens,#term-timeout,#studio-author,#studio-review,#key-kind{position:absolute;opacity:0;pointer-events:none;width:0;height:0}.hidden-config{display:none!important}
21516
+ .branch-menu{left:0;bottom:36px;min-width:220px;max-height:260px;overflow:auto;overscroll-behavior:contain;padding:5px}.branch-menu button,.ship-menu button{width:100%;border:0;background:transparent;color:var(--muted);padding:7px 9px;text-align:left;border-radius:7px;font-size:11px}.branch-menu button:hover,.ship-menu button:hover{background:var(--hover);color:var(--fg)}.ship-menu{right:0;bottom:36px;min-width:210px;padding:5px}.ship-wrap{position:relative}.meta-btn{height:29px;border:1px solid var(--line);background:transparent;border-radius:8px;padding:0 8px;color:var(--muted);font-size:10.5px}.meta-btn:hover{background:var(--hover);color:var(--fg)}
21517
+
21518
+ /* resume picker */
21519
+ .resume-picker{border-radius:14px;background:#161614;overflow:hidden;border:1px solid var(--line)}.resume-head{display:flex;justify-content:space-between;align-items:center;padding:11px 13px;border-bottom:1px solid var(--line)}.resume-head strong{font-size:12px;font-weight:600}.resume-head span{color:var(--faint);font-size:10.5px}.resume-list{padding:5px;max-height:330px;overflow:auto;overscroll-behavior:contain}.resume-chat{width:100%;border:0;background:transparent;color:var(--fg);padding:9px 10px;border-radius:8px;display:flex;align-items:center;gap:12px;text-align:left}.resume-chat:hover{background:var(--hover)}.resume-copy{min-width:0;flex:1;display:grid;gap:3px}.resume-copy strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:500}.resume-copy span{color:var(--faint);font-size:10px}.resume-arrow{color:var(--faint);font-size:18px}.resume-empty{padding:18px 12px;color:var(--faint);text-align:center;font-size:11px}
21520
+
21521
+ @media(max-width:1100px){.shell,.shell.changes-off{grid-template-columns:var(--rail-w) minmax(0,1fr)}.shell.rail-off,.shell.rail-off.changes-off{grid-template-columns:minmax(0,1fr)}.gutter{display:none}.changes{display:none}.shell:not(.changes-off) .changes,.changes.open{display:grid;position:fixed;inset:0 0 0 auto;width:min(420px,100%);z-index:40;box-shadow:-18px 0 50px rgba(0,0,0,.45)}}
21522
+ @media(max-width:760px){:root{--top-h:46px}.shell,.shell.rail-off{grid-template-columns:1fr}.rail{display:none}.shell:not(.rail-off) .rail{display:flex;position:fixed;inset:0 auto 0 0;width:min(285px,88vw);z-index:45;box-shadow:20px 0 50px rgba(0,0,0,.5)}.topbar{padding:0 10px}.top-actions .toolbar-label{display:none}.top-actions{gap:2px}.toolbar-btn{padding:0 7px}.dock{padding:6px 9px calc(10px + env(safe-area-inset-bottom))}.composer{border-radius:15px}.composer-line textarea{font-size:16px;min-height:46px}.composer-foot{padding-top:2px}.composer-left .pick[data-pick="mode"],.composer-left .pick[data-pick="autonomy"]{display:none}#model-open{max-width:155px}.prompt{max-width:90%;font-size:13.5px}#feed{padding:22px 15px 30px}.settings-card{width:100vw!important;height:100dvh;max-height:100dvh!important;border-radius:0!important;border:0!important;grid-template-columns:1fr}.settings-nav{border-right:0;border-bottom:1px solid var(--line);padding:8px;display:grid;grid-template-columns:1fr auto;gap:5px}.settings-nav-head{grid-column:1/-1;padding:2px 4px 4px}.settings-nav button[data-settings-tab]{display:none}.settings-nav button[data-settings-tab].on{display:none}.settings-mobile-tabs{display:flex!important;grid-column:1/-1;gap:3px;overflow:auto;padding-bottom:1px}.settings-mobile-tabs button{display:block!important;flex:0 0 auto;height:29px!important;padding:0 8px!important}.settings-content{padding:18px 15px 30px}.setting-row{grid-template-columns:1fr;gap:8px}.setting-control{justify-content:flex-start;min-width:0}.setting-control .pick-open{width:100%;max-width:100%}.setting-control .pick{width:100%}.setting-control .pick-menu{left:0;right:auto;width:100%;max-width:100%}.usage-cards{grid-template-columns:1fr 1fr}.break-row{grid-template-columns:88px minmax(0,1fr) 68px}.command-row{grid-template-columns:110px minmax(0,1fr)}.command-kind{display:none}.sheet{padding:0}.command-card{width:100vw!important;height:100dvh;max-height:100dvh!important;border-radius:0!important}.command-body{max-height:calc(100dvh - 50px)}#empty{margin-top:12vh;padding:0 18px}.top-status{display:none}.diff-head{min-height:39px;gap:6px}.diff-title-wrap{overflow:hidden}#diff-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.diff-actions{overflow-x:auto;max-width:52vw;scrollbar-width:none}.diff-actions::-webkit-scrollbar{display:none}.diff-actions button{flex:0 0 auto}.diff,#file-view{border-radius:10px;font-size:10.5px}.diff .row{grid-template-columns:30px 30px minmax(0,1fr)}.diff .ln{padding:0 4px}.diff-file-head{padding:8px}.resume-picker{width:100%;margin:12px 0 24px;border-radius:12px}.resume-list{max-height:min(360px,48dvh)}.resume-chat{min-height:48px}}
21689
21523
  </style>
21690
21524
  </head>
21691
21525
  <body${remote ? ' class="remote"' : ""}>
21692
21526
  <div class="shell">
21693
21527
  <aside class="rail">
21694
21528
  <div class="rail-top">
21695
- <div class="mark" title="CritiqueCode">C</div>
21696
- <button type="button" class="icon-btn" id="toggle-rail" title="Hide sessions" aria-label="Hide sessions">\u2039</button>
21529
+ <div class="brand"><div class="mark" title="CritiqueCode">C</div><span>CritiqueCode</span></div>
21697
21530
  </div>
21698
- <div class="rail-copy">
21699
- <button type="button" class="plus" id="new-session" title="New session" aria-label="New session">
21531
+ <button type="button" class="plus" id="new-session" title="New session">
21700
21532
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 2v10M2 7h10" stroke="currentColor" stroke-width="1.4"/></svg>
21701
- New session
21533
+ New chat
21702
21534
  </button>
21703
- <button type="button" class="plus" id="fork-session" title="Fork this conversation">Fork</button>
21704
- <input id="session-search" class="search" placeholder="Search sessions\u2026" autocomplete="off">
21535
+ <div class="rail-search">
21536
+ <svg width="13" height="13" viewBox="0 0 14 14" fill="none"><circle cx="6" cy="6" r="3.8" stroke="currentColor"/><path d="m9 9 3 3" stroke="currentColor"/></svg>
21537
+ <input id="session-search" class="search" placeholder="Search chats" autocomplete="off">
21538
+ </div>
21705
21539
  <div id="sessions"></div>
21540
+ <div class="rail-footer">
21541
+ <button type="button" id="fork-session" title="Fork this conversation">
21542
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M5 3v5m0 0c0 2 1.5 3 3.5 3H11m-6-3c0-2 1.5-3 3.5-3H11" stroke="currentColor"/><circle cx="4" cy="2.5" r="1.4" stroke="currentColor"/><circle cx="12" cy="4.5" r="1.4" stroke="currentColor"/><circle cx="12" cy="11.5" r="1.4" stroke="currentColor"/></svg>
21543
+ Fork chat
21544
+ </button>
21545
+ <button type="button" id="rail-settings">
21546
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="2.2" stroke="currentColor"/><path d="M8 2.2v1.3M8 12.5v1.3M13.8 8h-1.3M3.5 8H2.2M12.1 3.9l-.9.9M4.8 11.2l-.9.9M12.1 12.1l-.9-.9M4.8 4.8l-.9-.9" stroke="currentColor"/></svg>
21547
+ Settings
21548
+ </button>
21549
+ <div class="repo-mini" title="${repositoryRoot}">${repositoryName} \xB7 ${branch}</div>
21706
21550
  </div>
21707
21551
  </aside>
21552
+
21708
21553
  <div class="stage">
21709
- <header>
21710
- <div class="session" id="session-title">
21711
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 4h10v8H2zM4 4V3a3 3 0 0 1 6 0v1" stroke="currentColor" stroke-width="1.2"/></svg>
21712
- <span id="session-label">New session</span>
21554
+ <header class="topbar">
21555
+ <div class="topbar-left">
21556
+ <button type="button" class="icon-btn" id="toggle-rail" title="Chats" aria-label="Toggle chats">
21557
+ <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><rect x="2" y="2.5" width="12" height="11" rx="1.7" stroke="currentColor"/><path d="M5.5 3v10" stroke="currentColor"/></svg>
21558
+ </button>
21559
+ <button type="button" class="icon-btn top-new-chat" id="top-new-session" title="New chat" aria-label="New chat">
21560
+ <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
21561
+ </button>
21562
+ <div class="session-title" id="session-title"><span id="session-label">New session</span></div>
21713
21563
  </div>
21714
- <div class="badges">
21715
- <span class="badge" id="auto-badge" hidden>auto-approving critique_run</span>
21716
- <ol class="gate" id="ship-gate" title="Ship gate"></ol>
21717
- <span class="badge" id="watch-badge" hidden>watch</span>
21718
- <span class="badge" title="${listenTitle}"><span class="dot" aria-hidden="true"></span>${listenLabel} ${listen}</span>
21719
- ${portalLabel ? `<span class="badge" title="Outbound portals. The kernel stays on this laptop.">${escapeHtml(portalLabel)}</span>` : ""}
21720
- <span class="badge" id="status" hidden></span>
21721
- <span class="badge" id="files-badge" hidden></span>
21722
- <span class="badge" id="cost" hidden></span>
21723
- <span class="ctx-wrap">
21724
- <button type="button" class="ctx" id="ctx-ring" aria-label="Context used" title="Tokens used in this chat versus a 200k context budget">
21725
- <svg width="16" height="16" viewBox="0 0 24 24" aria-hidden="true">
21726
- <circle class="track" cx="12" cy="12" r="9"></circle>
21727
- <circle class="fill" id="ctx-fill" cx="12" cy="12" r="9" stroke-dasharray="56.55" stroke-dashoffset="56.55"></circle>
21728
- </svg>
21729
- <span id="ctx-label">ctx 0%</span>
21730
- </button>
21731
- <div id="ctx-tip">0 / 200,000 tokens</div>
21732
- </span>
21733
- <button type="button" class="icon-btn" id="toggle-term" title="Show or hide terminal" aria-label="Toggle terminal">\u2325</button>
21734
- <button type="button" class="icon-btn" id="toggle-changes" title="Show or hide workspace" aria-label="Toggle workspace">\u2630</button>
21735
- <span class="badge model" id="model-badge" title="${model}">author ${modelShort}</span>
21736
- <span class="badge model" id="review-badge" title="${reviewModel}">review ${reviewModel}</span>
21737
- <button type="button" class="icon-btn" id="trust-open" title="Trust legend">?</button>
21738
- <button type="button" class="icon-btn" id="palette-open" title="Command palette">\u2318</button>
21739
- <button type="button" class="icon-btn" id="studio-open" title="Settings">\u2699</button>
21740
- <button type="button" class="icon-btn" id="stop" title="Stop" hidden>\u25A0</button>
21564
+ <div class="top-actions">
21565
+ <span class="top-status" id="status" hidden></span>
21566
+ <button type="button" class="toolbar-btn" id="changes-pill" title="Open workspace">
21567
+ <svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M3 4h10M3 8h10M3 12h10" stroke="currentColor"/><circle cx="5" cy="4" r="1" fill="currentColor"/><circle cx="11" cy="8" r="1" fill="currentColor"/></svg>
21568
+ <span class="toolbar-label">Changes</span><span class="count" id="changes-count">0</span>
21569
+ <span hidden id="changes-plus">+0</span><span hidden id="changes-minus">\u22120</span>
21570
+ </button>
21571
+ <button type="button" class="icon-btn" id="toggle-term" title="Terminal" aria-label="Toggle terminal">
21572
+ <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><rect x="1.7" y="2.5" width="12.6" height="10.5" rx="1.5" stroke="currentColor"/><path d="m4 6 2 2-2 2M8 10h3" stroke="currentColor"/></svg>
21573
+ </button>
21574
+ <button type="button" class="icon-btn" id="toggle-changes" title="Workspace" aria-label="Toggle workspace">
21575
+ <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><path d="M2.2 3.3h11.6v9.4H2.2zM10.2 3.3v9.4" stroke="currentColor"/></svg>
21576
+ </button>
21577
+ <button type="button" class="icon-btn" id="studio-open" title="Settings" aria-label="Settings">
21578
+ <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="2.2" stroke="currentColor"/><path d="M8 2.2v1.3M8 12.5v1.3M13.8 8h-1.3M3.5 8H2.2M12.1 3.9l-.9.9M4.8 11.2l-.9.9M12.1 12.1l-.9-.9M4.8 4.8l-.9-.9" stroke="currentColor"/></svg>
21579
+ </button>
21580
+ <button type="button" class="icon-btn" id="stop" title="Stop run" aria-label="Stop" hidden>\u25A0</button>
21741
21581
  </div>
21582
+ <span id="files-badge" hidden></span><span id="cost" hidden></span><span id="auto-badge" hidden></span><span id="watch-badge" hidden></span><span id="model-badge" hidden></span><span id="review-badge" hidden></span>
21742
21583
  </header>
21584
+
21743
21585
  <main>
21744
21586
  <div id="empty">
21745
- <h1>New session</h1>
21746
- <ul class="meta">
21747
- <li>
21748
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M2.5 4.5h4l1.5 1.5H13.5v7H2.5z" stroke="currentColor" stroke-width="1.2"/></svg>
21749
- <span><strong>${repositoryRoot}</strong></span>
21750
- </li>
21751
- <li>
21752
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M4 12V8m0 0a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm8-4v4m0 0a2 2 0 1 0 0 4 2 2 0 0 0 0-4zM6 8h4" stroke="currentColor" stroke-width="1.2"/></svg>
21753
- <span>Main branch (<strong>${branch}</strong>)</span>
21754
- </li>
21755
- <li>
21756
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="5.5" stroke="currentColor" stroke-width="1.2"/><path d="M8 5.5V8l2 1.5" stroke="currentColor" stroke-width="1.2"/></svg>
21757
- <span>Loopback only \xB7 ${repositoryName}</span>
21758
- </li>
21759
- </ul>
21587
+ <h1>What are we building?</h1>
21588
+ <p>Ask CritiqueCode to implement, debug, explain, or review this repository. Type <strong>/</strong> for commands and skills, or <strong>@</strong> to attach files and other chats.</p>
21589
+ <div class="empty-actions">
21590
+ <button type="button" data-starter="Review the current changes and tell me what needs fixing">Review current changes</button>
21591
+ <button type="button" data-starter="Explain this repository and its main architecture">Explain the repository</button>
21592
+ <button type="button" id="empty-commands">Browse commands</button>
21593
+ </div>
21760
21594
  </div>
21761
21595
  <div id="feed"></div>
21762
21596
  </main>
21597
+
21763
21598
  <div class="term" id="term">
21764
21599
  <header>
21765
- <span>Terminal \xB7 repo root <span class="trust unverified">Not Evidence</span></span>
21600
+ <span>Terminal \xB7 repo root</span>
21766
21601
  <span>
21767
- <label class="always-row"><input type="checkbox" id="term-bg"> Background</label>
21602
+ <label class="always-row"><input type="checkbox" id="term-bg"> background</label>
21768
21603
  <div class="pick" data-pick="term-timeout">
21769
21604
  <button type="button" class="pick-open" id="term-timeout-open" aria-haspopup="listbox" aria-expanded="false">60s <span class="caret">\u25BE</span></button>
21770
21605
  <div class="pick-menu" id="term-timeout-menu"></div>
21771
- <select id="term-timeout" aria-label="Timeout">
21772
- <option value="60000">60s</option>
21773
- <option value="180000">3m</option>
21774
- <option value="600000">10m</option>
21775
- </select>
21606
+ <select id="term-timeout" aria-label="Timeout"><option value="60000">60s</option><option value="180000">3m</option><option value="600000">10m</option></select>
21776
21607
  </div>
21777
21608
  <button type="button" id="term-clear">Clear</button>
21778
21609
  </span>
21779
21610
  </header>
21780
21611
  <pre id="term-out"></pre>
21781
- <form id="term-form">
21782
- <input id="term-input" autocomplete="off" spellcheck="false" placeholder="Run a command in this repository\u2026">
21783
- </form>
21612
+ <form id="term-form"><input id="term-input" autocomplete="off" spellcheck="false" placeholder="Run a command in this repository\u2026"></form>
21784
21613
  </div>
21614
+
21785
21615
  <div class="dock">
21786
- <div class="composer-actions">
21787
- <button type="button" class="changes-pill" id="changes-pill" title="Show workspace">
21788
- Changes <span class="plus" id="changes-plus">+0</span> <span class="minus" id="changes-minus">-0</span>
21789
- </button>
21790
- <div class="ship-wrap">
21791
- <button type="button" class="ship-btn" id="ship-commit">Create Branch &amp; Commit</button>
21792
- <button type="button" class="ship-caret" id="ship-menu-open" aria-haspopup="menu" aria-expanded="false" aria-label="Commit actions">\u25BE</button>
21793
- <div class="ship-menu" id="ship-menu" role="menu">
21794
- <button type="button" id="commit-current">Commit to current branch</button>
21795
- <button type="button" id="commit-new">Create branch &amp; commit</button>
21796
- <button type="button" id="undo-menu">Undo last commit</button>
21797
- </div>
21798
- </div>
21799
- </div>
21800
21616
  <div class="composer">
21801
- <div id="mention">
21802
- <div id="mention-list"></div>
21803
- </div>
21617
+ <div id="mention"><div id="mention-list"></div></div>
21804
21618
  <div class="composer-line">
21805
21619
  <div class="cmds">
21806
- <button type="button" class="plus-btn" id="cmd-open" aria-haspopup="menu" aria-expanded="false" title="Commands and attachments">+</button>
21620
+ <button type="button" class="plus-btn" id="cmd-open" aria-haspopup="menu" aria-expanded="false" title="Add context or browse commands">+</button>
21807
21621
  <div class="cmd-pop" id="cmd-pop" role="menu">
21808
- <button type="button" data-cmd="/review">Review since checkpoint</button>
21809
- <button type="button" data-cmd="/review all">Review all</button>
21810
- <button type="button" data-cmd="/review critical">Review critical</button>
21811
- <button type="button" data-cmd="/critique">Critique CLI</button>
21812
- <button type="button" data-cmd="/checkpoint">Checkpoint</button>
21813
- <button type="button" data-cmd="/rollback">Rollback</button>
21814
- <button type="button" data-cmd="/explain">Explain</button>
21815
- <button type="button" data-cmd="/dismiss">Dismiss</button>
21816
- <button type="button" data-cmd="/watch on">Watch</button>
21817
- <button type="button" data-cmd="/status">Status</button>
21818
- <button type="button" data-cmd="/doctor">Doctor</button>
21819
- <button type="button" data-cmd="/repair">Repair</button>
21820
- <button type="button" data-cmd="/ship">Ship</button>
21821
- <button type="button" data-cmd="/skills">Skills</button>
21822
- <button type="button" data-cmd="/login" id="login">Login</button>
21823
- <button type="button" id="attach">Attach path</button>
21824
- <button type="button" data-cmd="/exit">Exit</button>
21622
+ <button type="button" id="commands-open">Commands &amp; skills\u2026</button>
21623
+ <button type="button" id="attach">Attach repository path\u2026</button>
21624
+ <button type="button" data-cmd="/login">Login / connect inference</button>
21825
21625
  </div>
21826
21626
  </div>
21827
- <textarea id="input" rows="1" placeholder="Send follow-up." title="Message the author. / commands and skills, @ to tag."></textarea>
21828
- <div class="pick" data-pick="thinking">
21829
- <button type="button" class="pick-open" id="thinking-open" aria-haspopup="listbox" aria-expanded="false">Medium <span class="caret">\u25BE</span></button>
21830
- <div class="pick-menu" id="thinking-menu"></div>
21831
- <select id="thinking" aria-label="Thinking level"></select>
21832
- </div>
21627
+ <textarea id="input" rows="1" placeholder="Message CritiqueCode\u2026" title="Type / for commands and skills, @ to add context"></textarea>
21833
21628
  <button type="button" class="mic-btn" id="voice" title="Voice input" aria-label="Voice input">
21834
21629
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="5" y="2" width="4" height="7" rx="2" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 7.5a3.5 3.5 0 0 0 7 0M7 11v1.5" stroke="currentColor" stroke-width="1.2"/></svg>
21835
21630
  </button>
21836
21631
  </div>
21837
21632
  <div class="chips" id="ref-chips"></div>
21838
- <div class="queue" id="queue" hidden>
21839
- <div id="queue-list"></div>
21840
- <div class="queue-bar">
21841
- <span id="queue-label">Queued \u21B5 to Send</span>
21842
- <div>
21843
- <button type="button" id="queue-clear">Clear</button>
21844
- <button type="button" class="now" id="queue-send">Send now</button>
21845
- </div>
21846
- </div>
21847
- </div>
21633
+ <div class="queue" id="queue" hidden><div id="queue-list"></div><div class="queue-bar"><span id="queue-label"></span><div><button type="button" id="queue-clear">Clear</button><button type="button" class="now" id="queue-send">Send now</button></div></div></div>
21848
21634
  <div class="composer-foot">
21849
- <div class="branch-wrap">
21850
- <button type="button" class="meta-btn" id="branch-open" aria-haspopup="listbox" title="Switch branch">\u2387 ${branch} <span class="caret">\u25BE</span></button>
21851
- <div class="branch-menu" id="branch-menu"></div>
21852
- </div>
21853
- <span class="host-chip" title="Loopback only. The author stays on this machine.">
21854
- <svg width="13" height="13" viewBox="0 0 16 16" fill="none"><rect x="2" y="3" width="12" height="8" rx="1.2" stroke="currentColor" stroke-width="1.2"/><path d="M5 13h6" stroke="currentColor" stroke-width="1.2"/></svg>
21855
- This Mac
21856
- </span>
21857
- <label class="always-row"><input type="checkbox" id="always-approve"> Always approve</label>
21858
- <div class="bar-right">
21635
+ <div class="composer-left">
21859
21636
  <div class="pick" data-pick="mode">
21860
21637
  <button type="button" class="pick-open" id="mode-open" aria-haspopup="listbox" aria-expanded="false">Agent <span class="caret">\u25BE</span></button>
21861
21638
  <div class="pick-menu" id="mode-menu"></div>
21862
- <select id="mode" aria-label="Agent mode">
21863
- <option value="agent">Agent</option>
21864
- <option value="plan">Plan</option>
21865
- <option value="ask">Ask</option>
21866
- <option value="debug">Debug</option>
21867
- </select>
21639
+ <select id="mode" aria-label="Mode"><option value="agent">Agent</option><option value="plan">Plan</option><option value="ask">Ask</option><option value="debug">Debug</option></select>
21868
21640
  </div>
21869
21641
  <div class="pick" data-pick="autonomy">
21870
- <button type="button" class="pick-open" id="autonomy-open" aria-haspopup="listbox" aria-expanded="false">Ask <span class="caret">\u25BE</span></button>
21642
+ <button type="button" class="pick-open autonomy-pill" id="autonomy-open" aria-haspopup="listbox" aria-expanded="false">Ask <span class="caret">\u25BE</span></button>
21871
21643
  <div class="pick-menu" id="autonomy-menu"></div>
21872
- <select id="autonomy" aria-label="Autonomy">
21873
- <option value="ask">Ask</option>
21874
- <option value="auto">Auto</option>
21875
- </select>
21644
+ <select id="autonomy" aria-label="Approval mode"><option value="ask">Ask</option><option value="auto">Auto approve</option></select>
21876
21645
  </div>
21877
21646
  <div class="model-wrap pick">
21878
21647
  <button type="button" id="model-open" aria-haspopup="listbox" aria-expanded="false">${modelShort} <span class="caret">\u25BE</span></button>
21879
- <div id="model-menu">
21880
- <input id="model-filter" placeholder="Search models\u2026" autocomplete="off">
21881
- <div id="model-list"></div>
21882
- </div>
21648
+ <div id="model-menu"><input id="model-filter" placeholder="Search models\u2026" autocomplete="off"><div id="model-list"></div></div>
21883
21649
  <select id="model" aria-label="Author model">${options}</select>
21884
21650
  </div>
21885
- <button type="button" id="review-run" class="pick-open" title="Review since checkpoint">Review</button>
21886
- <div class="pick" data-pick="review-depth">
21887
- <button type="button" class="pick-open" id="review-depth-open" aria-haspopup="listbox">standard <span class="caret">\u25BE</span></button>
21888
- <div class="pick-menu" id="review-depth-menu"></div>
21889
- <select id="review-depth" aria-label="Review depth">
21890
- <option value="standard">standard</option>
21891
- <option value="quick">quick</option>
21892
- <option value="paranoid">paranoid</option>
21893
- </select>
21894
- </div>
21895
- <div class="pick" data-pick="review-lens">
21896
- <button type="button" class="pick-open" id="review-lens-open" aria-haspopup="listbox">general <span class="caret">\u25BE</span></button>
21897
- <div class="pick-menu" id="review-lens-menu"></div>
21898
- <select id="review-lens" aria-label="Review lens">
21899
- <option value="general">general</option>
21900
- <option value="security">security</option>
21901
- <option value="performance">performance</option>
21902
- <option value="reliability">reliability</option>
21903
- <option value="stress">stress</option>
21904
- </select>
21905
- </div>
21906
- <button type="button" id="send" aria-label="Send">Send</button>
21651
+ </div>
21652
+ <div class="composer-right">
21653
+ <button type="button" id="review-run" title="Run an independent review">Review</button>
21654
+ <button type="button" id="send" aria-label="Send" title="Send">
21655
+ <svg width="15" height="15" viewBox="0 0 16 16" fill="none"><path d="M8 13V3m0 0L4.5 6.5M8 3l3.5 3.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
21656
+ </button>
21907
21657
  </div>
21908
21658
  </div>
21909
21659
  </div>
21910
21660
  </div>
21911
21661
  </div>
21912
- <div class="gutter" id="gutter" title="Resize"></div>
21662
+
21663
+ <div class="gutter" id="gutter" title="Resize workspace"></div>
21913
21664
  <aside class="changes" id="changes-pane">
21914
21665
  <header>
21915
21666
  <h2>Workspace</h2>
21916
- <button type="button" class="icon-btn" id="close-changes" title="Hide workspace" aria-label="Hide workspace">\u203A</button>
21917
- <div class="sum" id="changes-sum">Working tree</div>
21667
+ <button type="button" class="icon-btn" id="close-changes" title="Close workspace" aria-label="Close workspace">\xD7</button>
21668
+ <div class="sum" id="changes-sum">${branch}</div>
21669
+ <ol class="gate" id="ship-gate"></ol>
21918
21670
  </header>
21919
- <div class="work-tabs">
21920
- <button type="button" data-tab="tree" class="on">Tree</button>
21921
- <button type="button" data-tab="findings">Findings</button>
21922
- <button type="button" data-tab="timeline">Checkpoints</button>
21923
- <button type="button" data-tab="compare">Compare</button>
21924
- </div>
21671
+ <div class="work-tabs"><button type="button" data-tab="tree" class="on">Files</button><button type="button" data-tab="findings">Findings</button><button type="button" data-tab="timeline">History</button><button type="button" data-tab="compare">Compare</button></div>
21925
21672
  <div class="work-stack">
21926
21673
  <div class="workspace" id="tab-tree">
21927
- <input id="grep" placeholder="Search files\u2026">
21674
+ <input id="grep" placeholder="Find file or text\u2026">
21928
21675
  <div class="tree" id="tree"></div>
21929
21676
  <div class="diff-head">
21930
- <b id="diff-title">Select a file</b>
21931
- <div class="diff-actions">
21932
- <button type="button" id="accept-file">Mark reviewed</button>
21933
- <button type="button" id="reject-file">Reject</button>
21934
- <button type="button" id="commit">Commit</button>
21935
- <button type="button" id="undo">Undo commit</button>
21677
+ <div class="diff-title-wrap">
21678
+ <button type="button" id="all-changes" class="diff-back" hidden>\u2190 All changes</button>
21679
+ <b id="diff-title">Working changes</b>
21936
21680
  </div>
21681
+ <div class="diff-actions"><button type="button" id="accept-file">Keep</button><button type="button" id="reject-file" class="danger">Discard</button><button type="button" id="commit">Commit</button><button type="button" id="undo" title="Soft undo last commit">Undo</button></div>
21937
21682
  </div>
21938
- <div class="diff" id="diff"><div class="hunk">Working tree diffs open here. New files are green in the tree.</div></div>
21939
- <pre id="file-view" hidden></pre>
21940
- <iframe id="preview" hidden sandbox="allow-same-origin" title="Preview"></iframe>
21941
- </div>
21942
- <div class="workspace" id="tab-findings" hidden>
21943
- <input id="find-filter" placeholder="Filter findings\u2026">
21944
- <div id="find-list" class="tree"></div>
21945
- </div>
21946
- <div class="workspace" id="tab-timeline" hidden>
21947
- <div id="timeline" class="tree"></div>
21948
- </div>
21949
- <div class="compare" id="tab-compare" hidden>
21950
- <div id="compare-left"></div>
21951
- <div id="compare-right"></div>
21683
+ <div class="diff" id="diff"><div class="diff-loading">Open Workspace to inspect working-tree diffs.</div></div>
21684
+ <pre id="file-view" hidden></pre><iframe id="preview" hidden sandbox="allow-same-origin" title="Preview"></iframe>
21952
21685
  </div>
21686
+ <div class="workspace" id="tab-findings" hidden><input id="find-filter" placeholder="Filter findings\u2026"><div id="find-list" class="tree"></div></div>
21687
+ <div class="workspace" id="tab-timeline" hidden><div id="timeline" class="tree"></div></div>
21688
+ <div class="compare" id="tab-compare" hidden><div id="compare-left"></div><div id="compare-right"></div></div>
21953
21689
  </div>
21954
21690
  <div class="change-list" id="change-list"></div>
21955
21691
  </aside>
21956
21692
  </div>
21957
- <div id="modal">
21958
- <div class="dialog">
21959
- <h3>Run this command?</h3>
21960
- <div class="purpose" id="exec-purpose"></div>
21961
- <div class="preview" id="exec-preview"></div>
21962
- <div class="modal-actions">
21963
- <button type="button" class="deny" id="deny">Deny</button>
21964
- <button type="button" id="always-session">This session</button>
21965
- <button type="button" id="always">Always approve</button>
21966
- <button type="button" id="approve">Approve</button>
21967
- </div>
21968
- </div>
21969
- </div>
21970
- <div class="palette" id="palette">
21971
- <input id="palette-q" placeholder="Commands and skills\u2026" autocomplete="off">
21972
- <div id="palette-list"></div>
21973
- </div>
21974
- <div class="sheet" id="legend-sheet"><div class="card"><h3>Trust classes</h3><div id="legend-body"></div></div></div>
21975
- <div class="sheet" id="studio-sheet"><div class="card">
21976
- <h3>Settings</h3>
21977
- <label>Author model</label>
21978
- <div class="pick" data-pick="studio-author">
21979
- <button type="button" class="pick-open" id="studio-author-open" aria-haspopup="listbox" aria-expanded="false">Author <span class="caret">\u25BE</span></button>
21980
- <div class="pick-menu" id="studio-author-menu"></div>
21981
- <select id="studio-author" aria-label="Author model"></select>
21982
- </div>
21983
- <label>Review model (independent)</label>
21984
- <div class="pick" data-pick="studio-review">
21985
- <button type="button" class="pick-open" id="studio-review-open" aria-haspopup="listbox" aria-expanded="false">Review <span class="caret">\u25BE</span></button>
21986
- <div class="pick-menu" id="studio-review-menu"></div>
21987
- <select id="studio-review" aria-label="Review model"></select>
21988
- </div>
21989
- <p id="studio-indep" class="note"></p>
21990
- <label>API key kind</label>
21991
- <div class="pick" data-pick="key-kind">
21992
- <button type="button" class="pick-open" id="key-kind-open" aria-haspopup="listbox" aria-expanded="false">Key <span class="caret">\u25BE</span></button>
21993
- <div class="pick-menu" id="key-kind-menu"></div>
21994
- <select id="key-kind" aria-label="API key kind"></select>
21995
- </div>
21996
- <label>Key</label><input id="key-value" type="password" autocomplete="off">
21997
- <div class="modal-actions">
21998
- <button type="button" id="save-key">Store key</button>
21999
- <button type="button" id="close-studio">Close</button>
22000
- </div>
22001
- <h3>Skills</h3><div id="skill-list"></div>
22002
- <h3>Cost</h3><pre id="cost-panel"></pre>
22003
- <h3>Approvals</h3><pre id="audit-panel"></pre>
22004
- </div></div>
22005
- <div class="sheet" id="commit-sheet"><div class="card">
22006
- <h3 id="commit-sheet-title">Commit</h3>
22007
- <label id="commit-branch-wrap" hidden>Branch name<input id="commit-branch" autocomplete="off"></label>
22008
- <label>Message</label>
22009
- <textarea class="plain" id="commit-msg" rows="6"></textarea>
22010
- <div class="modal-actions">
22011
- <button type="button" id="commit-cancel">Cancel</button>
22012
- <button type="button" id="commit-go">Commit</button>
22013
- </div>
21693
+
21694
+ <div id="modal"><div class="dialog"><h3>Run this command?</h3><div class="purpose" id="exec-purpose"></div><div class="preview" id="exec-preview"></div><div class="modal-actions"><button type="button" class="deny" id="deny">Deny</button><button type="button" id="always-session">Approve for session</button><button type="button" id="always">Always approve</button><button type="button" id="approve">Approve once</button></div></div></div>
21695
+
21696
+ <div class="palette" id="palette"><input id="palette-q" placeholder="Commands and skills\u2026" autocomplete="off"><div id="palette-list"></div></div>
21697
+
21698
+ <div class="sheet" id="command-sheet"><div class="card command-card">
21699
+ <div class="sheet-head"><h3>Commands &amp; skills</h3><button type="button" id="close-commands" aria-label="Close">\xD7</button></div>
21700
+ <div class="command-body"><input id="command-search" placeholder="Search commands and skills\u2026" autocomplete="off"><div id="command-list" class="command-list"></div></div>
22014
21701
  </div></div>
22015
- <div class="sheet" id="import-sheet"><div class="card">
22016
- <h3>Import into repo</h3>
22017
- <label>Repo-relative path</label><input id="import-path">
22018
- <div class="modal-actions">
22019
- <button type="button" id="import-cancel">Cancel</button>
22020
- <button type="button" id="import-go">Write file</button>
21702
+
21703
+ <div class="sheet" id="legend-sheet"><div class="card"><h3>Trust &amp; verification</h3><div id="legend-body"></div><div class="modal-actions"><button type="button" id="close-legend">Close</button></div></div></div>
21704
+
21705
+ <div class="sheet" id="studio-sheet"><div class="card settings-card">
21706
+ <nav class="settings-nav">
21707
+ <div class="settings-nav-head"><b>Settings</b><button type="button" class="settings-close" id="close-studio" aria-label="Close settings">\xD7</button></div>
21708
+ <div class="settings-mobile-tabs" style="display:contents">
21709
+ <button type="button" class="on" data-settings-tab="general">General</button>
21710
+ <button type="button" data-settings-tab="models">Models</button>
21711
+ <button type="button" data-settings-tab="usage">Usage</button>
21712
+ <button type="button" data-settings-tab="skills">Skills</button>
21713
+ <button type="button" data-settings-tab="approvals">Approvals</button>
21714
+ <button type="button" data-settings-tab="connections">Connections</button>
21715
+ </div>
21716
+ </nav>
21717
+ <div class="settings-content">
21718
+ <section class="settings-panel on" data-settings-panel="general">
21719
+ <h2>General</h2><p class="sub">Keep the chat surface quiet; the controls that matter less live here.</p>
21720
+ <div class="setting-row"><div class="setting-copy"><b>Thinking level</b><span>How much reasoning budget the author can use.</span></div><div class="setting-control"><div class="pick" data-pick="thinking"><button type="button" class="pick-open" id="thinking-open" aria-haspopup="listbox" aria-expanded="false">Medium <span class="caret">\u25BE</span></button><div class="pick-menu" id="thinking-menu"></div><select id="thinking" aria-label="Thinking level"></select></div></div></div>
21721
+ <div class="setting-row"><div class="setting-copy"><b>Appearance</b><span>Switch between dark and light surfaces.</span></div><div class="setting-control"><label class="always-row"><input type="checkbox" id="theme-light"> Light mode</label></div></div>
21722
+ <div class="setting-row"><div class="setting-copy"><b>Command approval</b><span>Auto approval can execute commands without asking. It is deliberately kept out of the main composer.</span></div><div class="setting-control"><label class="always-row"><input type="checkbox" id="always-approve"> Always approve</label></div></div>
21723
+ <div class="setting-row"><div class="setting-copy"><b>Repository</b><span>${repositoryRoot}</span></div><div class="setting-control"><span class="repo-mini">${branch}</span></div></div>
21724
+ <div class="setting-row"><div class="setting-copy"><b>Web surface</b><span>${listenTitle}</span></div><div class="setting-control"><span class="repo-mini">${listenLabel} ${listen}</span></div></div>
21725
+ ${portalLabel ? `<div class="setting-row"><div class="setting-copy"><b>Remote portals</b><span>Outbound control links; the author still runs on this machine.</span></div><div class="setting-control"><span class="repo-mini">${escapeHtml(portalLabel)}</span></div></div>` : ""}
21726
+ <div class="hidden-config"><select id="review-depth"><option value="standard">standard</option><option value="quick">quick</option><option value="paranoid">paranoid</option></select><select id="review-lens"><option value="general">general</option><option value="security">security</option><option value="performance">performance</option><option value="reliability">reliability</option><option value="stress">stress</option></select><div id="review-depth-menu"></div><button id="review-depth-open"></button><div id="review-lens-menu"></div><button id="review-lens-open"></button></div>
21727
+ </section>
21728
+
21729
+ <section class="settings-panel" data-settings-panel="models">
21730
+ <h2>Models</h2><p class="sub">Choose the author and independent reviewer. Model icons are rendered for every row, with a provider fallback when a model-specific mark is unavailable.</p>
21731
+ <div class="setting-row"><div class="setting-copy"><b>Author model</b><span>Writes and edits the repository.</span></div><div class="setting-control"><div class="pick" data-pick="studio-author"><button type="button" class="pick-open" id="studio-author-open" aria-haspopup="listbox" aria-expanded="false">Author <span class="caret">\u25BE</span></button><div class="pick-menu" id="studio-author-menu"></div><select id="studio-author" aria-label="Author model"></select></div></div></div>
21732
+ <div class="setting-row"><div class="setting-copy"><b>Review model</b><span>Prefer a different model family for genuinely independent review.</span></div><div class="setting-control"><div class="pick" data-pick="studio-review"><button type="button" class="pick-open" id="studio-review-open" aria-haspopup="listbox" aria-expanded="false">Review <span class="caret">\u25BE</span></button><div class="pick-menu" id="studio-review-menu"></div><select id="studio-review" aria-label="Review model"></select></div></div></div>
21733
+ <div id="studio-indep" class="settings-note"></div>
21734
+ </section>
21735
+
21736
+ <section class="settings-panel" data-settings-panel="usage">
21737
+ <h2>Usage</h2><p class="sub">Token and cost usage for this loaded chat, plus server-side phase/model totals when available.</p>
21738
+ <div class="usage-cards"><div class="usage-card"><span>Input</span><b id="usage-input">0</b></div><div class="usage-card"><span>Output</span><b id="usage-output">0</b></div><div class="usage-card"><span>Reasoning</span><b id="usage-reason">0</b></div><div class="usage-card"><span>Cost</span><b id="usage-cost">$0.00</b></div></div>
21739
+ <div class="usage-chart" id="usage-chart"><div class="usage-empty">Usage appears here as model calls complete.</div></div>
21740
+ <h3>By phase</h3><div class="breakdown" id="usage-phase"></div>
21741
+ <h3>By model</h3><div class="breakdown" id="usage-model"></div>
21742
+ <pre id="cost-panel" hidden></pre>
21743
+ </section>
21744
+
21745
+ <section class="settings-panel" data-settings-panel="skills">
21746
+ <h2>Skills</h2><p class="sub">Skills extend the author with repository- or agent-specific guidance.</p>
21747
+ <div class="settings-note">Repository and agent skills are treated as guidance, not as permission to execute commands or as proof that a check passed. That safety rule applies once here instead of being repeated as every skill's description.</div>
21748
+ <div id="skill-list" class="skill-list" style="margin-top:10px"></div>
21749
+ </section>
21750
+
21751
+ <section class="settings-panel" data-settings-panel="approvals">
21752
+ <h2>Approvals</h2><p class="sub">Recent command approval decisions on this machine.</p>
21753
+ <div id="audit-panel" class="audit-list"></div>
21754
+ </section>
21755
+
21756
+ <section class="settings-panel" data-settings-panel="connections">
21757
+ <h2>Connections</h2><p class="sub">Store provider keys locally for BYOK routes.</p>
21758
+ <div class="setting-row"><div class="setting-copy"><b>Provider</b><span>Choose which credential to store.</span></div><div class="setting-control"><div class="pick" data-pick="key-kind"><button type="button" class="pick-open" id="key-kind-open" aria-haspopup="listbox" aria-expanded="false">Provider <span class="caret">\u25BE</span></button><div class="pick-menu" id="key-kind-menu"></div><select id="key-kind" aria-label="API key kind"></select></div></div></div>
21759
+ <div class="setting-row"><div class="setting-copy"><b>API key</b><span>Saved by the local CritiqueCode runtime.</span></div><div class="setting-control"><input id="key-value" type="password" autocomplete="off" placeholder="\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"></div></div>
21760
+ <div class="modal-actions"><button type="button" id="save-key">Store key</button></div>
21761
+ </section>
22021
21762
  </div>
22022
21763
  </div></div>
21764
+
21765
+ <div class="sheet" id="commit-sheet"><div class="card"><h3 id="commit-sheet-title">Commit</h3><label id="commit-branch-wrap" hidden>Branch name<input id="commit-branch" autocomplete="off"></label><label>Message</label><textarea class="plain" id="commit-msg" rows="6"></textarea><div class="modal-actions"><button type="button" id="commit-cancel">Cancel</button><button type="button" id="commit-go">Commit</button></div></div></div>
21766
+ <div class="sheet" id="import-sheet"><div class="card"><h3>Import into repository</h3><label>Repo-relative path</label><input id="import-path"><div class="modal-actions"><button type="button" id="import-cancel">Cancel</button><button type="button" id="import-go">Write file</button></div></div></div>
22023
21767
  <script type="application/json" id="boot">${bootJson}</script>
22024
21768
  <script type="application/json" id="model-icons">${iconsJson}</script>
22025
21769
  <script type="application/json" id="thinking-boot">${thinkingJson}</script>
@@ -22076,6 +21820,12 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22076
21820
  var busy = false;
22077
21821
  var promptQueue = [];
22078
21822
  var applyingSnapshot = false;
21823
+ var usageHistory = [];
21824
+ var studioCosts = null;
21825
+ var workspaceRefreshTimer = null;
21826
+ var workspacePollTimer = null;
21827
+ var thinkingStartedAt = 0;
21828
+ var thinkingTimer = null;
22079
21829
  var thinkingEl = document.getElementById("thinking");
22080
21830
  if (thinkingEl) {
22081
21831
  (thinkingBoot.levels || []).forEach(function (level) {
@@ -22146,8 +21896,12 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22146
21896
  }
22147
21897
 
22148
21898
  function modelIconHtml(option) {
22149
- var raw = option && (option.getAttribute("data-icon") || iconMap[option.getAttribute("data-provider") || ""] || "");
22150
- return raw || iconMap.other || "";
21899
+ var provider = option && (option.getAttribute("data-provider") || "") || "other";
21900
+ var raw = option && (option.getAttribute("data-icon") || iconMap[provider] || "");
21901
+ if (raw) return raw;
21902
+ var label = option && (option.text || option.value) || provider || "model";
21903
+ var letter = String(label).replace(/^[^a-z0-9]+/i, "").charAt(0).toUpperCase() || "M";
21904
+ return "<span class=\\"model-fallback\\" aria-hidden=\\"true\\">" + esc(letter) + "</span>";
22151
21905
  }
22152
21906
 
22153
21907
  function setPickLabel(openId, text, iconHtml) {
@@ -22269,6 +22023,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22269
22023
  render();
22270
22024
  menu.className = "pick-menu open";
22271
22025
  open.setAttribute("aria-expanded", "true");
22026
+ trapWheel(menu);
22272
22027
  }
22273
22028
  });
22274
22029
  menu.addEventListener("click", function (e) { e.stopPropagation(); });
@@ -22504,10 +22259,22 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22504
22259
  if (modelEl) modelEl.disabled = false;
22505
22260
  sendEl.className = busy ? "steer" : "";
22506
22261
  sendEl.setAttribute("aria-label", busy ? "Queue follow-up" : "Send");
22507
- inputEl.placeholder = busy ? "Queue a follow-up." : "Send follow-up.";
22262
+ sendEl.title = busy ? "Queue follow-up" : "Send";
22263
+ inputEl.placeholder = busy ? "Queue a follow-up\u2026" : "Message CritiqueCode\u2026";
22508
22264
  var stop = document.getElementById("stop");
22509
22265
  if (stop) stop.hidden = !busy;
22510
- if (was && !busy) flushQueue(false);
22266
+ if (busy && !workspacePollTimer) {
22267
+ workspacePollTimer = setInterval(function () { refreshWorkspaceSnapshot(false); }, 1800);
22268
+ }
22269
+ if (!busy && workspacePollTimer) {
22270
+ clearInterval(workspacePollTimer);
22271
+ workspacePollTimer = null;
22272
+ }
22273
+ if (!busy) finishThinkingTimer();
22274
+ if (was && !busy) {
22275
+ refreshWorkspaceSnapshot(true);
22276
+ flushQueue(false);
22277
+ }
22511
22278
  }
22512
22279
 
22513
22280
  function renderQueue() {
@@ -22541,6 +22308,11 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22541
22308
  }
22542
22309
 
22543
22310
  function dispatchPrompt(text) {
22311
+ var normalized = text.trim().toLowerCase();
22312
+ if (normalized === "/resume" || normalized === "resume") {
22313
+ showResumePicker();
22314
+ return;
22315
+ }
22544
22316
  if (text === "/login" || text === "login") {
22545
22317
  startLogin();
22546
22318
  return;
@@ -22591,6 +22363,29 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22591
22363
  resetUsage();
22592
22364
  }
22593
22365
 
22366
+ function deleteSession(id, title) {
22367
+ if (!id) return;
22368
+ var name = title || "this chat";
22369
+ if (!window.confirm("Delete " + name + "? This cannot be undone.")) return;
22370
+ var path = "/api/sessions/" + encodeURIComponent(id);
22371
+ api("DELETE", path).then(function (res) {
22372
+ if (res.ok) return res;
22373
+ if (res.status !== 404 && res.status !== 405) return res;
22374
+ return api("POST", "/api/sessions/delete", { id: id });
22375
+ }).then(function (res) {
22376
+ if (!res || !res.ok) {
22377
+ if (!res) return;
22378
+ return readError(res, "Session deletion is not available in this build.").then(function (msg) { addBlock("alert", msg); });
22379
+ }
22380
+ return api("GET", "/api/snapshot").then(function (fresh) {
22381
+ if (!fresh.ok) return;
22382
+ return fresh.json().then(function (body) {
22383
+ if (body.sessions) renderSessions(body.sessions, body.session_id || body.id || activeSessionId);
22384
+ });
22385
+ });
22386
+ }).catch(function () { addBlock("alert", "Could not delete that chat."); });
22387
+ }
22388
+
22594
22389
  function renderSessions(list, activeId) {
22595
22390
  allSessions = list || allSessions;
22596
22391
  if (!sessionsEl) return;
@@ -22599,20 +22394,104 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22599
22394
  (allSessions || []).filter(function (item) {
22600
22395
  return !q || String(item.title || "").toLowerCase().indexOf(q) >= 0;
22601
22396
  }).forEach(function (item) {
22397
+ var row = document.createElement("div");
22398
+ row.className = "session-row" + (item.id === activeId ? " on" : "");
22602
22399
  var btn = document.createElement("button");
22603
22400
  btn.type = "button";
22604
- btn.className = "session-item" + (item.id === activeId ? " on" : "");
22401
+ btn.className = "session-item";
22605
22402
  btn.textContent = item.title || "Session";
22606
22403
  btn.title = item.title || item.id;
22607
22404
  btn.addEventListener("click", function () {
22608
22405
  if (item.id === activeSessionId) return;
22406
+ api("POST", "/api/sessions/select", { id: item.id }).catch(function () { addBlock("alert", "Could not open that chat."); });
22407
+ if (window.innerWidth <= 760) { layout.rail = false; applyLayout(); }
22408
+ });
22409
+ btn.addEventListener("dblclick", function (e) {
22410
+ e.preventDefault();
22411
+ e.stopPropagation();
22412
+ var next = window.prompt("Rename chat", item.title || "Session");
22413
+ if (!next) return;
22414
+ renameSession(item.id, next.trim());
22415
+ });
22416
+ var del = document.createElement("button");
22417
+ del.type = "button";
22418
+ del.className = "session-delete";
22419
+ del.title = "Delete chat";
22420
+ del.setAttribute("aria-label", "Delete " + (item.title || "chat"));
22421
+ del.innerHTML = "<svg width=\\"13\\" height=\\"13\\" viewBox=\\"0 0 16 16\\" fill=\\"none\\"><path d=\\"M3.5 4.5h9M6 4.5V3h4v1.5M5 6.5v6M8 6.5v6M11 6.5v6M4.5 4.5l.5 9h6l.5-9\\" stroke=\\"currentColor\\" stroke-linecap=\\"round\\"/></svg>";
22422
+ del.addEventListener("click", function (e) { e.stopPropagation(); deleteSession(item.id, item.title || "this chat"); });
22423
+ row.appendChild(btn); row.appendChild(del); sessionsEl.appendChild(row);
22424
+ });
22425
+ activeSessionId = activeId || activeSessionId;
22426
+ }
22427
+
22428
+ function renameSession(id, title) {
22429
+ if (!id || !title) return;
22430
+ api("POST", "/api/sessions/rename", { id: id, title: title }).then(function (res) {
22431
+ if (!res.ok) return readError(res, "Could not rename that chat.").then(function (msg) { addBlock("alert", msg); });
22432
+ return res.json().then(function (body) {
22433
+ if (body.sessions) renderSessions(body.sessions, body.id || activeSessionId);
22434
+ if (body.title) setSessionTitle(body.title);
22435
+ });
22436
+ }).catch(function () { addBlock("alert", "Could not rename that chat."); });
22437
+ }
22438
+
22439
+ function showResumePicker() {
22440
+ showFeed();
22441
+ turnEl = null;
22442
+ assistantEl = null;
22443
+ var wrap = document.createElement("div");
22444
+ wrap.className = "resume-picker";
22445
+ var head = document.createElement("div");
22446
+ head.className = "resume-head";
22447
+ var title = document.createElement("strong");
22448
+ title.textContent = "Resume a chat";
22449
+ var hint = document.createElement("span");
22450
+ hint.textContent = String((allSessions || []).length) + " chats";
22451
+ head.appendChild(title);
22452
+ head.appendChild(hint);
22453
+ wrap.appendChild(head);
22454
+ var list = document.createElement("div");
22455
+ list.className = "resume-list";
22456
+ var sessions = (allSessions || []).filter(function (item) { return item.id !== activeSessionId; });
22457
+ if (!sessions.length) {
22458
+ var empty = document.createElement("div");
22459
+ empty.className = "resume-empty";
22460
+ empty.textContent = "No other chats yet.";
22461
+ list.appendChild(empty);
22462
+ }
22463
+ sessions.forEach(function (item) {
22464
+ var row = document.createElement("button");
22465
+ row.type = "button";
22466
+ row.className = "resume-chat";
22467
+ var copy = document.createElement("span");
22468
+ copy.className = "resume-copy";
22469
+ var chatTitle = document.createElement("strong");
22470
+ chatTitle.textContent = item.title || "Untitled chat";
22471
+ copy.appendChild(chatTitle);
22472
+ if (item.updated_at || item.created_at) {
22473
+ var time = document.createElement("span");
22474
+ var value = item.updated_at || item.created_at;
22475
+ try {
22476
+ time.textContent = new Date(value).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
22477
+ } catch (e) { time.textContent = ""; }
22478
+ copy.appendChild(time);
22479
+ }
22480
+ var arrow = document.createElement("span");
22481
+ arrow.className = "resume-arrow";
22482
+ arrow.textContent = "\u203A";
22483
+ row.appendChild(copy);
22484
+ row.appendChild(arrow);
22485
+ row.addEventListener("click", function () {
22609
22486
  api("POST", "/api/sessions/select", { id: item.id }).catch(function () {
22610
- addBlock("alert", "Could not open that session.");
22487
+ addBlock("alert", "Could not resume that chat.");
22611
22488
  });
22612
22489
  });
22613
- sessionsEl.appendChild(btn);
22490
+ list.appendChild(row);
22614
22491
  });
22615
- activeSessionId = activeId || activeSessionId;
22492
+ wrap.appendChild(list);
22493
+ feedEl.appendChild(wrap);
22494
+ scrollMain();
22616
22495
  }
22617
22496
 
22618
22497
  function replayEvents(events) {
@@ -22640,12 +22519,14 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22640
22519
  showFeed();
22641
22520
  turnEl = null;
22642
22521
  assistantEl = null;
22522
+ var copy = text == null ? "" : String(text);
22523
+ if (className === "note") {
22524
+ var last = feedEl.lastElementChild;
22525
+ if (last && last.classList.contains("note") && last.textContent === copy) return last;
22526
+ }
22643
22527
  var node = document.createElement("div");
22644
22528
  node.className = className;
22645
- node.textContent = text == null ? "" : String(text);
22646
- if (className !== "note") {
22647
- stampTrust(node, trust || (className === "review-card" ? "evidence" : className === "alert" ? "unverified" : "unverified"));
22648
- }
22529
+ node.textContent = copy;
22649
22530
  feedEl.appendChild(node);
22650
22531
  scrollMain();
22651
22532
  return node;
@@ -22681,112 +22562,165 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22681
22562
  scrollMain();
22682
22563
  }
22683
22564
 
22684
- function addTool(name, phase, detail) {
22685
- if (name === "critique_task") return;
22565
+ function activityRoot() {
22686
22566
  if (!turnEl) {
22687
22567
  showFeed();
22688
22568
  turnEl = document.createElement("div");
22689
22569
  turnEl.className = "turn";
22690
22570
  feedEl.appendChild(turnEl);
22691
22571
  }
22692
- var steps = turnEl.querySelector(".steps");
22693
- if (!steps) {
22694
- steps = document.createElement("details");
22695
- steps.className = "steps";
22696
- var summary = document.createElement("summary");
22697
- summary.innerHTML = "<span>Show steps</span><span class=\\"dur\\"></span>";
22698
- var list = document.createElement("div");
22699
- list.className = "step-list";
22700
- steps.appendChild(summary);
22701
- steps.appendChild(list);
22702
- if (assistantEl) turnEl.insertBefore(steps, assistantEl);
22703
- else turnEl.appendChild(steps);
22704
- }
22705
- var listEl = steps.querySelector(".step-list");
22706
- var line = (name || "tool") + " " + (phase || "");
22707
- if (detail) line += "\\n" + detail;
22708
- listEl.textContent = (listEl.textContent ? listEl.textContent + "\\n" : "") + line;
22709
- if (!steps.querySelector(".trust")) {
22710
- var t = document.createElement("div");
22711
- t.className = "trust unverified";
22712
- t.textContent = name === "critique_cli" ? "Not Evidence \xB7 sidecar JSON" : "Not Evidence";
22713
- steps.insertBefore(t, steps.firstChild);
22572
+ var root = turnEl.querySelector(".activity");
22573
+ if (!root) {
22574
+ root = document.createElement("div");
22575
+ root.className = "activity";
22576
+ if (assistantEl) turnEl.insertBefore(root, assistantEl);
22577
+ else turnEl.appendChild(root);
22714
22578
  }
22579
+ return root;
22580
+ }
22581
+
22582
+ function humanToolName(name) {
22583
+ return String(name || "tool").replace(/_/g, " ");
22584
+ }
22585
+
22586
+ function addTool(name, phase, detail) {
22587
+ if (name === "critique_task") return;
22588
+ var root = activityRoot();
22589
+ var node = document.createElement("details");
22590
+ var state = /fail|error|denied/i.test(String(phase || "")) ? "failed" : /start|run|progress/i.test(String(phase || "")) ? "running" : "done";
22591
+ node.className = "tool-event " + state;
22592
+ if (detail) node.open = false;
22593
+ var summary = document.createElement("summary");
22594
+ var dot = document.createElement("span"); dot.className = "tool-dot";
22595
+ var label = document.createElement("span"); label.className = "tool-name"; label.textContent = humanToolName(name);
22596
+ var p = document.createElement("span"); p.className = "tool-phase"; p.textContent = phase || "";
22597
+ summary.appendChild(dot); summary.appendChild(label); if (phase) summary.appendChild(p);
22598
+ node.appendChild(summary);
22599
+ if (detail) { var body = document.createElement("div"); body.className = "tool-detail"; body.textContent = detail; node.appendChild(body); }
22600
+ root.appendChild(node);
22601
+ scheduleWorkspaceRefresh();
22715
22602
  scrollMain();
22716
22603
  }
22717
22604
 
22718
- function addThink(text) {
22719
- if (!turnEl) {
22720
- showFeed();
22721
- turnEl = document.createElement("div");
22722
- turnEl.className = "turn";
22723
- feedEl.appendChild(turnEl);
22605
+ function finishThinkingTimer() {
22606
+ if (thinkingTimer) { clearInterval(thinkingTimer); thinkingTimer = null; }
22607
+ var node = turnEl && turnEl.querySelector(".think");
22608
+ if (node && thinkingStartedAt && !applyingSnapshot) {
22609
+ var s = node.querySelector("summary span:last-child");
22610
+ if (s) s.textContent = "Thinking \xB7 " + Math.max(1, Math.round((Date.now() - thinkingStartedAt) / 1000)) + "s";
22724
22611
  }
22725
- var node = turnEl.querySelector(".think");
22612
+ thinkingStartedAt = 0;
22613
+ }
22614
+
22615
+ function addThink(text) {
22616
+ var root = activityRoot();
22617
+ var node = root.querySelector(".think");
22726
22618
  if (!node) {
22727
22619
  node = document.createElement("details");
22728
22620
  node.className = "think";
22729
- node.innerHTML = "<summary>Thinking</summary><div></div>";
22730
- turnEl.appendChild(node);
22731
- }
22732
- var body = node.querySelector("div");
22733
- body.textContent = (body.textContent || "") + (text || "");
22621
+ var summary = document.createElement("summary");
22622
+ summary.innerHTML = "<span class=\\"tool-dot\\"></span><span>Thinking</span>";
22623
+ var body = document.createElement("div");
22624
+ node.appendChild(summary); node.appendChild(body); root.appendChild(node);
22625
+ if (!applyingSnapshot) {
22626
+ thinkingStartedAt = Date.now();
22627
+ thinkingTimer = setInterval(function () {
22628
+ if (!thinkingStartedAt) return;
22629
+ var label = summary.querySelector("span:last-child");
22630
+ if (label) label.textContent = "Thinking \xB7 " + Math.max(1, Math.round((Date.now() - thinkingStartedAt) / 1000)) + "s";
22631
+ }, 1000);
22632
+ }
22633
+ }
22634
+ var bodyEl = node.querySelector("div");
22635
+ if (bodyEl) bodyEl.textContent = (bodyEl.textContent || "") + (text || "");
22734
22636
  scrollMain();
22735
22637
  }
22736
22638
 
22737
22639
  function resetUsage() {
22738
- tokensIn = 0;
22739
- tokensOut = 0;
22740
- tokensReason = 0;
22741
- contextUsed = 0;
22742
- lastInput = 0;
22743
- lastOutput = 0;
22744
- lastReason = 0;
22745
- costUsd = 0;
22746
- var el = document.getElementById("cost");
22747
- if (el) {
22748
- el.hidden = true;
22749
- el.textContent = "";
22750
- }
22751
- updateContextRing();
22640
+ tokensIn = 0; tokensOut = 0; tokensReason = 0; contextUsed = 0;
22641
+ lastInput = 0; lastOutput = 0; lastReason = 0; costUsd = 0; usageHistory = [];
22642
+ renderUsagePanel(studioCosts);
22752
22643
  }
22753
22644
 
22754
22645
  function addUsage(ev) {
22755
22646
  lastInput = Number(ev.input_tokens || 0);
22756
22647
  lastOutput = Number(ev.output_tokens || 0);
22757
22648
  lastReason = Number(ev.reasoning_tokens || 0);
22758
- tokensIn += lastInput;
22759
- tokensOut += lastOutput;
22760
- tokensReason += lastReason;
22761
- if (ev.cost_usd) costUsd += Number(ev.cost_usd);
22649
+ tokensIn += lastInput; tokensOut += lastOutput; tokensReason += lastReason;
22650
+ var eventCost = Number(ev.cost_usd || 0);
22651
+ if (!eventCost) eventCost = estimateUsageCostUsd(lastInput, lastOutput, lastReason);
22652
+ costUsd += eventCost;
22762
22653
  contextUsed = lastInput + lastOutput + lastReason;
22763
- var el = document.getElementById("cost");
22764
- if (el) {
22765
- el.hidden = false;
22766
- el.textContent = tokensIn + "\u2192" + tokensOut + (costUsd ? " \xB7 $" + costUsd.toFixed(4) : "");
22654
+ usageHistory.push({
22655
+ input: lastInput, output: lastOutput, reasoning: lastReason,
22656
+ cost: Number(ev.cost_usd || 0), model: ev.model || "", phase: ev.source || ev.phase || "author", at: Date.now()
22657
+ });
22658
+ if (usageHistory.length > 80) usageHistory = usageHistory.slice(-80);
22659
+ renderUsagePanel(studioCosts);
22660
+ }
22661
+
22662
+ function updateContextRing() { renderUsagePanel(studioCosts); }
22663
+
22664
+ function fmtNum(value) { return Number(value || 0).toLocaleString(); }
22665
+ function fmtCost(value) { return "$" + Number(value || 0).toFixed(Number(value || 0) < 1 ? 4 : 2); }
22666
+
22667
+ function estimateUsageCostUsd(input, output, reasoning) {
22668
+ return Number(input || 0) * 0.0000001 + Number(output || 0) * 0.0000004 + Number(reasoning || 0) * 0.0000002;
22669
+ }
22670
+
22671
+ function renderBars(targetId, rows) {
22672
+ var target = document.getElementById(targetId);
22673
+ if (!target) return;
22674
+ target.innerHTML = "";
22675
+ if (!rows || !rows.length) { target.innerHTML = "<div class=\\"usage-empty\\" style=\\"height:52px\\">No data yet</div>"; return; }
22676
+ var max = Math.max.apply(null, rows.map(function (r) { return r.value; }).concat([1]));
22677
+ rows.slice(0, 10).forEach(function (row) {
22678
+ var el = document.createElement("div"); el.className = "break-row";
22679
+ var name = document.createElement("span"); name.textContent = row.label;
22680
+ var track = document.createElement("div"); track.className = "break-track";
22681
+ var fill = document.createElement("div"); fill.className = "break-fill"; fill.style.width = Math.max(2, row.value / max * 100) + "%"; track.appendChild(fill);
22682
+ var val = document.createElement("span"); val.className = "break-val"; val.textContent = fmtNum(row.value);
22683
+ el.appendChild(name); el.appendChild(track); el.appendChild(val); target.appendChild(el);
22684
+ });
22685
+ }
22686
+
22687
+ function renderUsagePanel(costs) {
22688
+ var totalInput = costs && Number(costs.total_input || 0) || tokensIn;
22689
+ var totalOutput = costs && Number(costs.total_output || 0) || tokensOut;
22690
+ var ui = document.getElementById("usage-input"); if (ui) ui.textContent = fmtNum(totalInput);
22691
+ var uo = document.getElementById("usage-output"); if (uo) uo.textContent = fmtNum(totalOutput);
22692
+ var ur = document.getElementById("usage-reason"); if (ur) ur.textContent = fmtNum(tokensReason);
22693
+ var reported = costUsd || (costs && Number(costs.total_cost_usd || 0)) || 0;
22694
+ var display = reported > 0 ? reported : (costs && Number(costs.estimated_cost_usd || 0)) || estimateUsageCostUsd(totalInput, totalOutput, tokensReason);
22695
+ var estimated = reported <= 0 && display > 0;
22696
+ var uc = document.getElementById("usage-cost");
22697
+ if (uc) uc.textContent = (estimated ? "~" : "") + fmtCost(display);
22698
+ var chart = document.getElementById("usage-chart");
22699
+ if (chart) {
22700
+ if (!usageHistory.length) chart.innerHTML = "<div class=\\"usage-empty\\">Usage appears here as model calls complete.</div>";
22701
+ else {
22702
+ var vals = usageHistory.map(function (r) { return r.input + r.output + r.reasoning; });
22703
+ var max = Math.max.apply(null, vals.concat([1]));
22704
+ var w = 640, h = 150, gap = 2, bw = Math.max(2, (w - (vals.length - 1) * gap) / vals.length);
22705
+ var rects = vals.map(function (v, i) { var bh = Math.max(2, v / max * 126); var x = i * (bw + gap); return "<rect x=\\"" + x.toFixed(1) + "\\" y=\\"" + (140 - bh).toFixed(1) + "\\" width=\\"" + bw.toFixed(1) + "\\" height=\\"" + bh.toFixed(1) + "\\" rx=\\"1.5\\" fill=\\"#827b72\\"><title>" + fmtNum(v) + " tokens</title></rect>"; }).join("");
22706
+ chart.innerHTML = "<svg viewBox=\\"0 0 640 150\\" preserveAspectRatio=\\"none\\" aria-label=\\"Token usage by model call\\"><line x1=\\"0\\" y1=\\"140\\" x2=\\"640\\" y2=\\"140\\" stroke=\\"rgba(255,255,255,.08)\\"/>" + rects + "</svg>";
22707
+ }
22708
+ }
22709
+ var phaseRows = [];
22710
+ if (costs && costs.by_phase) Object.keys(costs.by_phase).forEach(function (k) { var v = costs.by_phase[k] || {}; phaseRows.push({ label:k, value:Number(v.input_tokens||0)+Number(v.output_tokens||0) }); });
22711
+ else {
22712
+ var phase = {}; usageHistory.forEach(function (r) { var k=r.phase||"author"; phase[k]=(phase[k]||0)+r.input+r.output+r.reasoning; });
22713
+ Object.keys(phase).forEach(function (k) { phaseRows.push({label:k,value:phase[k]}); });
22767
22714
  }
22768
- updateContextRing();
22769
- }
22770
-
22771
- function updateContextRing() {
22772
- var used = contextUsed;
22773
- var pct = Math.max(0, Math.min(1, used / contextCap));
22774
- var circ = 56.55;
22775
- var fill = document.getElementById("ctx-fill");
22776
- var tip = document.getElementById("ctx-tip");
22777
- var ring = document.getElementById("ctx-ring");
22778
- if (fill) fill.setAttribute("stroke-dashoffset", String(circ * (1 - pct)));
22779
- var text = used.toLocaleString() + " / " + contextCap.toLocaleString() + " tokens"
22780
- + "\\n" + Math.round(pct * 100) + "% of this chat"
22781
- + "\\ninput " + lastInput.toLocaleString()
22782
- + " \xB7 output " + lastOutput.toLocaleString()
22783
- + (lastReason ? " \xB7 reasoning " + lastReason.toLocaleString() : "")
22784
- + (costUsd ? "\\n$" + costUsd.toFixed(4) : "");
22785
- if (tip) tip.textContent = text;
22786
- var label = document.getElementById("ctx-label");
22787
- if (label) label.textContent = "ctx " + Math.round(pct * 100) + "%";
22788
- if (ring) ring.title = text.replace(/\\n/g, " \xB7 ");
22789
- if (fill) fill.style.stroke = pct > 0.85 ? "#e36d6d" : pct > 0.6 ? "#d4a017" : "#ececec";
22715
+ renderBars("usage-phase", phaseRows);
22716
+ var modelRows = [];
22717
+ if (costs && costs.by_model) Object.keys(costs.by_model).forEach(function (k) { var v=costs.by_model[k]||{}; modelRows.push({label:k.replace(/^openrouter\\//,""),value:Number(v.input_tokens||0)+Number(v.output_tokens||0)}); });
22718
+ else {
22719
+ var models={}; usageHistory.forEach(function(r){var k=r.model||"current model";models[k]=(models[k]||0)+r.input+r.output+r.reasoning;});
22720
+ Object.keys(models).forEach(function(k){modelRows.push({label:k.replace(/^openrouter\\//,""),value:models[k]});});
22721
+ }
22722
+ modelRows.sort(function(a,b){return b.value-a.value;});
22723
+ renderBars("usage-model", modelRows);
22790
22724
  }
22791
22725
 
22792
22726
  function addAgent(detail, phase) {
@@ -22816,101 +22750,186 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22816
22750
  if (btn) btn.innerHTML = "\u2387 " + esc(currentBranch) + " <span class=\\"caret\\">\u25BE</span>";
22817
22751
  }
22818
22752
 
22753
+ function normalizeChangeFiles(data) {
22754
+ var files = (data && data.files) || [];
22755
+ if ((!files || !files.length) && data && data.changed_paths && data.changed_paths.length) {
22756
+ files = data.changed_paths.map(function (path) { return { path: path, added: 0, deleted: 0, kind: "modified" }; });
22757
+ }
22758
+ return files || [];
22759
+ }
22760
+
22761
+ function renderPatchInto(container, patch, path) {
22762
+ var head = document.createElement("div");
22763
+ head.className = "diff-file-head";
22764
+ head.textContent = path;
22765
+ container.appendChild(head);
22766
+ var body = document.createElement("div");
22767
+ body.className = "diff-patch";
22768
+ var patchStr = String(patch || "");
22769
+ if (!patchStr.trim()) {
22770
+ var empty = document.createElement("div");
22771
+ empty.className = "hunk";
22772
+ empty.textContent = "No textual diff available.";
22773
+ body.appendChild(empty);
22774
+ container.appendChild(body);
22775
+ return;
22776
+ }
22777
+ var oldLn = 0;
22778
+ var newLn = 0;
22779
+ patchStr.split("\\n").forEach(function (line) {
22780
+ if (line.indexOf("@@") === 0) {
22781
+ var hunk = line.match(/@@ -(\\d+)(?:,\\d+)? \\+(\\d+)/);
22782
+ if (hunk) { oldLn = Number(hunk[1]) - 1; newLn = Number(hunk[2]) - 1; }
22783
+ var hunkEl = document.createElement("div");
22784
+ hunkEl.className = "hunk";
22785
+ hunkEl.textContent = line;
22786
+ body.appendChild(hunkEl);
22787
+ return;
22788
+ }
22789
+ if (line.indexOf("diff ") === 0 || line.indexOf("index ") === 0 || line.indexOf("---") === 0 || line.indexOf("+++") === 0) {
22790
+ var meta = document.createElement("div");
22791
+ meta.className = "hunk";
22792
+ meta.textContent = line;
22793
+ body.appendChild(meta);
22794
+ return;
22795
+ }
22796
+ var kind = "ctx";
22797
+ var left = "";
22798
+ var right = "";
22799
+ if (line.charAt(0) === "+") { kind = "add"; newLn += 1; right = String(newLn); }
22800
+ else if (line.charAt(0) === "-") { kind = "del"; oldLn += 1; left = String(oldLn); }
22801
+ else { oldLn += 1; newLn += 1; left = String(oldLn); right = String(newLn); }
22802
+ var row = document.createElement("div");
22803
+ row.className = "row " + kind;
22804
+ var a = document.createElement("span"); a.className = "ln"; a.textContent = left;
22805
+ var b = document.createElement("span"); b.className = "ln"; b.textContent = right;
22806
+ var code = document.createElement("span"); code.className = "code"; code.textContent = line;
22807
+ row.appendChild(a); row.appendChild(b); row.appendChild(code);
22808
+ body.appendChild(row);
22809
+ });
22810
+ container.appendChild(body);
22811
+ }
22812
+
22813
+ function loadAllDiffs(files) {
22814
+ var diffEl = document.getElementById("diff");
22815
+ var view = document.getElementById("file-view");
22816
+ var preview = document.getElementById("preview");
22817
+ var title = document.getElementById("diff-title");
22818
+ var back = document.getElementById("all-changes");
22819
+ if (back) back.hidden = true;
22820
+ if (title) title.textContent = files.length + (files.length === 1 ? " changed file" : " changed files");
22821
+ if (diffEl) { diffEl.hidden = false; diffEl.innerHTML = ""; }
22822
+ if (view) view.hidden = true;
22823
+ if (preview) preview.hidden = true;
22824
+ if (!files || !files.length) {
22825
+ if (diffEl) diffEl.innerHTML = "<div class=\\"diff-loading\\">No changed files.</div>";
22826
+ return;
22827
+ }
22828
+ var loading = document.createElement("div");
22829
+ loading.className = "diff-loading";
22830
+ loading.textContent = "Loading diffs\u2026";
22831
+ if (diffEl) diffEl.appendChild(loading);
22832
+ var paths = files.map(function (f) { return f.path; });
22833
+ Promise.all(paths.map(function (path) {
22834
+ return api("GET", "/api/changes?path=" + encodeURIComponent(path))
22835
+ .then(function (res) { return res.json().then(function (body) { return { path: path, patch: body.patch }; }); })
22836
+ .catch(function () { return { path: path, patch: "" }; });
22837
+ })).then(function (results) {
22838
+ if (!diffEl) return;
22839
+ diffEl.innerHTML = "";
22840
+ results.forEach(function (result) {
22841
+ var section = document.createElement("section");
22842
+ section.className = "diff-file";
22843
+ renderPatchInto(section, result.patch || "No textual diff available.", result.path);
22844
+ diffEl.appendChild(section);
22845
+ });
22846
+ });
22847
+ }
22848
+
22849
+ function loadFileContent(path, btn) {
22850
+ selectedPath = path;
22851
+ document.querySelectorAll(".tree button").forEach(function (el) {
22852
+ el.classList.toggle("on", el.getAttribute("data-path") === path);
22853
+ });
22854
+ if (btn) btn.classList.add("on");
22855
+ var title = document.getElementById("diff-title");
22856
+ var diffEl = document.getElementById("diff");
22857
+ var view = document.getElementById("file-view");
22858
+ var preview = document.getElementById("preview");
22859
+ var back = document.getElementById("all-changes");
22860
+ if (back) back.hidden = false;
22861
+ if (title) title.textContent = path;
22862
+ if (diffEl) diffEl.hidden = true;
22863
+ if (preview) preview.hidden = true;
22864
+ if (view) {
22865
+ view.hidden = false;
22866
+ view.textContent = "Loading\u2026";
22867
+ }
22868
+ var pane = document.getElementById("changes-pane");
22869
+ if (pane) pane.classList.add("open");
22870
+ api("GET", "/api/file?path=" + encodeURIComponent(path))
22871
+ .then(function (res) {
22872
+ if (!res.ok) throw new Error("Could not load file");
22873
+ return res.json();
22874
+ })
22875
+ .then(function (file) {
22876
+ if (view) {
22877
+ view.hidden = false;
22878
+ view.textContent = String(file.text || "");
22879
+ }
22880
+ if (preview && /\\.html?$/i.test(path)) {
22881
+ preview.hidden = false;
22882
+ preview.srcdoc = String(file.text || "");
22883
+ }
22884
+ })
22885
+ .catch(function () {
22886
+ if (view) view.textContent = "Could not load " + path;
22887
+ });
22888
+ }
22889
+
22819
22890
  function renderChanges(data) {
22820
22891
  var list = document.getElementById("change-list");
22821
22892
  var sum = document.getElementById("changes-sum");
22822
- var files = (data && data.files) || [];
22823
- var added = data && data.added ? data.added : 0;
22824
- var deleted = data && data.deleted ? data.deleted : 0;
22893
+ var files = normalizeChangeFiles(data);
22894
+ var computedAdded = files.reduce(function (n, f) { return n + Number(f.added || 0); }, 0);
22895
+ var computedDeleted = files.reduce(function (n, f) { return n + Number(f.deleted || 0); }, 0);
22896
+ var added = Number(data && data.added || 0) || computedAdded;
22897
+ var deleted = Number(data && data.deleted || 0) || computedDeleted;
22825
22898
  var branch = data && (data.branch || data.text) ? (data.branch || data.text) : currentBranch;
22826
22899
  if (branch) setBranchLabel(branch);
22827
- if (sum) sum.textContent = branch + " +" + added + " \u2212" + deleted;
22828
- var plus = document.getElementById("changes-plus");
22829
- var minus = document.getElementById("changes-minus");
22830
- if (plus) plus.textContent = "+" + added;
22831
- if (minus) minus.textContent = "\u2212" + deleted;
22832
- var ship = document.getElementById("ship-commit");
22833
- if (ship) ship.disabled = files.length === 0;
22900
+ if (sum) sum.textContent = branch + " \xB7 " + files.length + (files.length === 1 ? " changed file" : " changed files") + ((added || deleted) ? " \xB7 +" + added + " \u2212" + deleted : "");
22901
+ var count = document.getElementById("changes-count"); if (count) count.textContent = String(files.length);
22902
+ var plus = document.getElementById("changes-plus"); var minus = document.getElementById("changes-minus");
22903
+ if (plus) plus.textContent = "+" + added; if (minus) minus.textContent = "\u2212" + deleted;
22904
+ var pill = document.getElementById("changes-pill"); if (pill) pill.title = files.length ? files.length + " changed file" + (files.length === 1 ? "" : "s") + " \xB7 +" + added + " \u2212" + deleted : "No working-tree changes";
22834
22905
  fileKinds = {};
22835
22906
  files.forEach(function (file) { fileKinds[file.path] = file.kind || (file.untracked ? "untracked" : "modified"); });
22836
22907
  if (list) {
22837
22908
  list.innerHTML = "";
22838
22909
  files.forEach(function (file) {
22839
- var btn = document.createElement("button");
22840
- btn.type = "button";
22841
- btn.className = "change-file";
22842
- btn.innerHTML = "<span></span><span><span class=\\"plus\\">+" + file.added + "</span> <span class=\\"minus\\">\u2212" + file.deleted + "</span></span>";
22843
- btn.querySelector("span").textContent = file.path;
22844
- btn.addEventListener("click", function () { loadDiff(file.path, btn); });
22845
- list.appendChild(btn);
22910
+ var btn = document.createElement("button"); btn.type = "button"; btn.className = "change-file";
22911
+ btn.innerHTML = "<span></span><span><span class=\\"plus\\">+" + Number(file.added || 0) + "</span> <span class=\\"minus\\">\u2212" + Number(file.deleted || 0) + "</span></span>";
22912
+ btn.querySelector("span").textContent = file.path; btn.addEventListener("click", function () { loadFileContent(file.path, btn); }); list.appendChild(btn);
22846
22913
  });
22847
22914
  }
22848
22915
  setPaths(files.map(function (file) { return file.path; }));
22849
22916
  loadTree();
22917
+ if (!selectedPath) {
22918
+ loadAllDiffs(files);
22919
+ }
22850
22920
  }
22851
22921
 
22852
- function loadDiff(path, btn) {
22853
- selectedPath = path;
22854
- document.querySelectorAll(".tree button").forEach(function (el) { el.classList.toggle("on", el.getAttribute("data-path") === path); });
22855
- if (btn) btn.classList.add("on");
22856
- var title = document.getElementById("diff-title");
22857
- if (title) title.textContent = path;
22858
- var pane = document.getElementById("changes-pane");
22859
- if (pane) pane.classList.add("open");
22860
- var shell = document.querySelector(".shell");
22861
- if (shell) shell.classList.remove("changes-off");
22862
- api("GET", "/api/changes?path=" + encodeURIComponent(path)).then(function (res) { return res.json(); }).then(function (body) {
22863
- var diffEl = document.getElementById("diff");
22864
- var view = document.getElementById("file-view");
22865
- if (!diffEl) return;
22866
- diffEl.hidden = false;
22867
- if (view) view.hidden = true;
22868
- diffEl.innerHTML = "";
22869
- var patch = String(body.patch || "");
22870
- if (!patch) {
22871
- diffEl.innerHTML = "<div class=\\"hunk\\">No diff for this file.</div>";
22872
- return;
22873
- }
22874
- var oldLn = 0;
22875
- var newLn = 0;
22876
- patch.split("\\n").forEach(function (line) {
22877
- if (line.indexOf("@@") === 0) {
22878
- var hunk = line.match(/@@ -(\\d+)(?:,\\d+)? \\+(\\d+)/);
22879
- if (hunk) { oldLn = Number(hunk[1]) - 1; newLn = Number(hunk[2]) - 1; }
22880
- var head = document.createElement("div");
22881
- head.className = "hunk";
22882
- head.textContent = line;
22883
- diffEl.appendChild(head);
22884
- return;
22885
- }
22886
- if (line.indexOf("diff ") === 0 || line.indexOf("index ") === 0 || line.indexOf("---") === 0 || line.indexOf("+++") === 0) {
22887
- var meta = document.createElement("div");
22888
- meta.className = "hunk";
22889
- meta.textContent = line;
22890
- diffEl.appendChild(meta);
22891
- return;
22892
- }
22893
- var kind = "ctx";
22894
- var left = "";
22895
- var right = "";
22896
- if (line.charAt(0) === "+") { kind = "add"; newLn += 1; right = String(newLn); }
22897
- else if (line.charAt(0) === "-") { kind = "del"; oldLn += 1; left = String(oldLn); }
22898
- else { oldLn += 1; newLn += 1; left = String(oldLn); right = String(newLn); }
22899
- var row = document.createElement("div");
22900
- row.className = "row " + kind;
22901
- var a = document.createElement("span"); a.className = "ln"; a.textContent = left;
22902
- var b = document.createElement("span"); b.className = "ln"; b.textContent = right;
22903
- var code = document.createElement("span"); code.className = "code"; code.textContent = line;
22904
- row.appendChild(a); row.appendChild(b); row.appendChild(code);
22905
- diffEl.appendChild(row);
22906
- });
22907
- var preview = document.getElementById("preview");
22908
- preview.hidden = !/\\.html?$/i.test(path);
22909
- if (!preview.hidden) {
22910
- api("GET", "/api/file?path=" + encodeURIComponent(path)).then(function (res) { return res.json(); }).then(function (file) {
22911
- preview.srcdoc = String(file.text || "");
22912
- }).catch(function () {});
22913
- }
22922
+ function scheduleWorkspaceRefresh() {
22923
+ if (workspaceRefreshTimer) clearTimeout(workspaceRefreshTimer);
22924
+ workspaceRefreshTimer = setTimeout(function () { refreshWorkspaceSnapshot(false); }, 450);
22925
+ }
22926
+
22927
+ function refreshWorkspaceSnapshot(force) {
22928
+ if (workspaceRefreshTimer) { clearTimeout(workspaceRefreshTimer); workspaceRefreshTimer = null; }
22929
+ return api("GET", "/api/snapshot").then(function (res) { return res.ok ? res.json() : null; }).then(function (s) {
22930
+ if (!s) return;
22931
+ if (s.files || s.changed_paths) renderChanges(s);
22932
+ if (force && s.sessions) renderSessions(s.sessions, s.active_session_id || activeSessionId);
22914
22933
  }).catch(function () {});
22915
22934
  }
22916
22935
 
@@ -23043,6 +23062,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23043
23062
  break;
23044
23063
  case "busy":
23045
23064
  setBusy(ev.busy);
23065
+ if (!ev.busy) scheduleWorkspaceRefresh();
23046
23066
  break;
23047
23067
  case "ended":
23048
23068
  setBusy(false);
@@ -23069,6 +23089,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23069
23089
  if (thinkingEl && s.thinking_level) thinkingEl.value = s.thinking_level;
23070
23090
  syncPick("mode");
23071
23091
  syncPick("autonomy");
23092
+ syncAutonomyVisual();
23072
23093
  syncPick("thinking");
23073
23094
  syncPick("review-depth");
23074
23095
  syncPick("review-lens");
@@ -23080,7 +23101,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23080
23101
  if (s.events && s.events.length) replayEvents(s.events);
23081
23102
  else if (s.last_review_text) setReview(s.last_review_text);
23082
23103
  if (s.pending_exec) showExec(s.pending_exec);
23083
- if (s.files) renderChanges(s);
23104
+ if (s.files || s.changed_paths) renderChanges(s);
23084
23105
  if (s.ended) {
23085
23106
  setStatus("Session ended", "err");
23086
23107
  addBlock("note", "Session ended \xB7 " + s.ended);
@@ -23134,56 +23155,109 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23134
23155
  });
23135
23156
  }
23136
23157
 
23158
+ function cleanSkillDescription(s) {
23159
+ var desc = String(s && s.description || "").trim();
23160
+ var constraint = String(s && s.constraint || "").trim();
23161
+ if (!desc || desc === constraint || /Untrusted text. Cannot grant a shell or treat checks as Evidence./i.test(desc) || /Built-in. Wins on name collision/i.test(desc)) return "";
23162
+ return desc;
23163
+ }
23164
+
23165
+ function renderSkills(rows) {
23166
+ var skills = document.getElementById("skill-list");
23167
+ if (!skills) return;
23168
+ skills.innerHTML = "";
23169
+ (rows || []).forEach(function (s) {
23170
+ var row = document.createElement("div"); row.className = "skill-row";
23171
+ var head = document.createElement("div"); head.className = "skill-head";
23172
+ var name = document.createElement("b"); name.textContent = s.name || s.id || "Skill";
23173
+ var source = document.createElement("span"); source.className = "skill-source"; source.textContent = s.source || "skill";
23174
+ head.appendChild(name); head.appendChild(source); row.appendChild(head);
23175
+ var desc = document.createElement("div"); desc.className = "skill-desc"; desc.textContent = cleanSkillDescription(s) || "Available to the author when this task matches the skill."; row.appendChild(desc);
23176
+ if (s.origin) { var origin = document.createElement("div"); origin.className = "skill-origin"; origin.textContent = s.origin; row.appendChild(origin); }
23177
+ skills.appendChild(row);
23178
+ });
23179
+ if (!rows || !rows.length) skills.innerHTML = "<div class=\\"settings-note\\">No skills discovered.</div>";
23180
+ }
23181
+
23182
+ function renderAudit(rows) {
23183
+ var audit = document.getElementById("audit-panel"); if (!audit) return; audit.innerHTML = "";
23184
+ (rows || []).slice().reverse().slice(0, 80).forEach(function (a) {
23185
+ var row = document.createElement("div"); row.className = "audit-row";
23186
+ var at = document.createElement("span"); at.textContent = a.at ? new Date(a.at).toLocaleString() : "";
23187
+ var decision = document.createElement("span"); decision.textContent = (a.decision || "") + (a.scope ? " \xB7 " + a.scope : "");
23188
+ var code = document.createElement("code"); code.textContent = a.preview || a.purpose || "";
23189
+ row.appendChild(at); row.appendChild(decision); row.appendChild(code); audit.appendChild(row);
23190
+ });
23191
+ if (!rows || !rows.length) audit.innerHTML = "<div class=\\"settings-note\\">No approval decisions yet.</div>";
23192
+ }
23193
+
23137
23194
  function loadStudio() {
23138
23195
  api("GET", "/api/studio").then(function (res) { return res.json(); }).then(function (body) {
23139
- var author = document.getElementById("studio-author");
23140
- var review = document.getElementById("studio-review");
23141
- if (author && modelEl) author.innerHTML = modelEl.innerHTML;
23196
+ var author = document.getElementById("studio-author"); var review = document.getElementById("studio-review");
23197
+ if (author && modelEl) { author.innerHTML = modelEl.innerHTML; author.value = modelEl.value; }
23142
23198
  if (review && modelEl) review.innerHTML = modelEl.innerHTML;
23143
23199
  if (body.badges) {
23200
+ if (review && body.badges.review && body.badges.review.id) review.value = body.badges.review.id;
23144
23201
  var indep = document.getElementById("studio-indep");
23145
- if (indep) indep.textContent = body.badges.independent
23146
- ? "Reviewer is a different model than the author."
23147
- : "Author and review currently share a model \u2014 pick a distinct review model.";
23202
+ if (indep) { indep.className = "settings-note" + (body.badges.independent ? "" : " warn"); indep.textContent = body.badges.independent ? "Independent reviewer enabled \u2014 author and reviewer use different models." : "Author and reviewer currently share the same model. Pick a different reviewer for stronger independence."; }
23148
23203
  }
23149
- var skills = document.getElementById("skill-list");
23150
23204
  if (body.skills) slashSkills = body.skills;
23151
- if (skills) {
23152
- skills.innerHTML = (body.skills || []).map(function (s) {
23153
- return "<div class=\\"find-row\\"><b>" + esc(s.name) + "</b> \xB7 " + esc(s.source) + "<br>" + esc(s.constraint) + "</div>";
23154
- }).join("");
23155
- }
23156
- var cost = document.getElementById("cost-panel");
23157
- if (cost && body.costs) cost.textContent = JSON.stringify(body.costs, null, 2);
23158
- var audit = document.getElementById("audit-panel");
23159
- if (audit) audit.textContent = JSON.stringify(body.audit || [], null, 2);
23205
+ renderSkills(body.skills || []);
23206
+ studioCosts = body.costs || studioCosts;
23207
+ renderUsagePanel(studioCosts);
23208
+ renderAudit(body.audit || []);
23160
23209
  var tl = document.getElementById("timeline");
23161
- if (tl) {
23162
- tl.innerHTML = (body.timeline || []).map(function (n) {
23163
- return "<button type=\\"button\\" class=\\"find-row\\">" + esc(n.kind) + " \xB7 " + esc(n.label || n.conclusion || n.id) + "</button>";
23164
- }).join("");
23165
- }
23166
- var left = document.getElementById("compare-left");
23167
- var right = document.getElementById("compare-right");
23168
- if (body.compare && left && right) {
23169
- left.textContent = (body.compare.left.model || "") + "\\nonly:\\n" + (body.compare.only_left || []).join("\\n");
23170
- right.textContent = (body.compare.right.model || "") + "\\nonly:\\n" + (body.compare.only_right || []).join("\\n");
23171
- }
23210
+ if (tl) { tl.innerHTML = (body.timeline || []).map(function (n) { return "<button type=\\"button\\" class=\\"find-row\\">" + esc(n.kind) + " \xB7 " + esc(n.label || n.conclusion || n.id) + "</button>"; }).join(""); }
23211
+ var left = document.getElementById("compare-left"); var right = document.getElementById("compare-right");
23212
+ if (body.compare && left && right) { left.textContent = (body.compare.left.model || "") + "\\nonly:\\n" + (body.compare.only_left || []).join("\\n"); right.textContent = (body.compare.right.model || "") + "\\nonly:\\n" + (body.compare.only_right || []).join("\\n"); }
23172
23213
  var kind = document.getElementById("key-kind");
23173
- if (kind && kind.options.length === 0) {
23174
- (boot.credentials || []).forEach(function (c) {
23175
- var opt = document.createElement("option");
23176
- opt.value = c.kind;
23177
- opt.textContent = c.label;
23178
- kind.appendChild(opt);
23179
- });
23180
- }
23181
- syncPick("studio-author");
23182
- syncPick("studio-review");
23183
- syncPick("key-kind");
23214
+ if (kind && kind.options.length === 0) (boot.credentials || []).forEach(function (c) { var opt = document.createElement("option"); opt.value = c.kind; opt.textContent = c.label; kind.appendChild(opt); });
23215
+ syncPick("studio-author"); syncPick("studio-review"); syncPick("key-kind");
23216
+ trapScrollableMenus();
23184
23217
  }).catch(function () {});
23185
23218
  }
23186
23219
 
23220
+ function openSheet(id) { var el = document.getElementById(id); if (el) el.className = "sheet open"; }
23221
+ function closeSheet(id) { var el = document.getElementById(id); if (el) el.className = "sheet"; }
23222
+
23223
+ function renderCommandBrowser() {
23224
+ var list = document.getElementById("command-list"); var search = document.getElementById("command-search");
23225
+ if (!list) return;
23226
+ var q = String(search && search.value || ""); list.innerHTML = "";
23227
+ rankSlashItems(slashCatalog(), q).slice(0, 80).forEach(function (item) {
23228
+ var row = document.createElement("button"); row.type = "button"; row.className = "command-row";
23229
+ var code = document.createElement("span"); code.className = "command-code"; code.textContent = item.value;
23230
+ var desc = document.createElement("span"); desc.className = "command-desc"; desc.textContent = item.description || item.label || "";
23231
+ var kind = document.createElement("span"); kind.className = "command-kind"; kind.textContent = item.kind;
23232
+ row.appendChild(code); row.appendChild(desc); row.appendChild(kind);
23233
+ row.addEventListener("click", function () { closeSheet("command-sheet"); inputEl.value = item.value + " "; inputEl.focus(); autosizeInput(); });
23234
+ list.appendChild(row);
23235
+ });
23236
+ }
23237
+
23238
+ function showCommands() { closePicks(); renderCommandBrowser(); openSheet("command-sheet"); var q = document.getElementById("command-search"); if (q) setTimeout(function(){ q.focus(); }, 0); }
23239
+
23240
+ function selectSettingsTab(name) {
23241
+ document.querySelectorAll("[data-settings-tab]").forEach(function (b) { b.classList.toggle("on", b.getAttribute("data-settings-tab") === name); });
23242
+ document.querySelectorAll("[data-settings-panel]").forEach(function (p) { p.classList.toggle("on", p.getAttribute("data-settings-panel") === name); });
23243
+ if (name === "usage") renderUsagePanel(studioCosts);
23244
+ }
23245
+
23246
+ function autosizeInput() { inputEl.style.height = "auto"; inputEl.style.height = Math.min(190, Math.max(44, inputEl.scrollHeight)) + "px"; }
23247
+
23248
+ function trapWheel(el) {
23249
+ if (!el || el.dataset.wheelTrap === "1") return;
23250
+ el.dataset.wheelTrap = "1";
23251
+ el.addEventListener("wheel", function (e) {
23252
+ e.stopPropagation();
23253
+ var top = el.scrollTop <= 0; var bottom = Math.ceil(el.scrollTop + el.clientHeight) >= el.scrollHeight;
23254
+ if ((e.deltaY < 0 && top) || (e.deltaY > 0 && bottom)) e.preventDefault();
23255
+ }, { passive: false });
23256
+ }
23257
+ function trapScrollableMenus() {
23258
+ [document.getElementById("model-list"), document.getElementById("studio-author-menu"), document.getElementById("studio-review-menu"), document.getElementById("key-kind-menu"), document.getElementById("thinking-menu"), document.getElementById("mention-list")].forEach(trapWheel);
23259
+ }
23260
+
23187
23261
  function connect() {
23188
23262
  if (es) {
23189
23263
  es.close();
@@ -23219,7 +23293,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23219
23293
 
23220
23294
  function submitText(raw, steerNow) {
23221
23295
  var text = (raw == null ? inputEl.value : raw).trim();
23222
- if (raw == null && text) inputEl.value = "";
23296
+ if (raw == null && text) { inputEl.value = ""; autosizeInput(); }
23223
23297
  if (!text) {
23224
23298
  if (steerNow) flushQueue(true);
23225
23299
  return;
@@ -23241,6 +23315,18 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23241
23315
  });
23242
23316
  }
23243
23317
 
23318
+ on("commands-open", "click", function () { var pop=document.getElementById("cmd-pop"); if(pop) pop.classList.remove("open"); showCommands(); });
23319
+ on("empty-commands", "click", showCommands);
23320
+ on("close-commands", "click", function () { closeSheet("command-sheet"); });
23321
+ var commandSearch = document.getElementById("command-search");
23322
+ if (commandSearch) commandSearch.addEventListener("input", renderCommandBrowser);
23323
+ document.querySelectorAll("[data-starter]").forEach(function (btn) { btn.addEventListener("click", function () { inputEl.value = btn.getAttribute("data-starter") || ""; autosizeInput(); inputEl.focus(); }); });
23324
+ document.querySelectorAll("[data-settings-tab]").forEach(function (btn) { btn.addEventListener("click", function () { selectSettingsTab(btn.getAttribute("data-settings-tab")); }); });
23325
+ on("rail-settings", "click", function () { loadStudio(); openSheet("studio-sheet"); });
23326
+ on("close-legend", "click", function () { closeSheet("legend-sheet"); });
23327
+ inputEl.addEventListener("input", autosizeInput);
23328
+ trapScrollableMenus();
23329
+
23244
23330
  sendEl.addEventListener("click", function () { submitText(null, false); });
23245
23331
  on("queue-send", "click", function () { flushQueue(true); });
23246
23332
  on("queue-clear", "click", function () { promptQueue = []; renderQueue(); });
@@ -23256,6 +23342,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23256
23342
  modelMenu.className = "open";
23257
23343
  modelOpen.setAttribute("aria-expanded", "true");
23258
23344
  renderModelList();
23345
+ trapWheel(document.getElementById("model-list"));
23259
23346
  if (modelFilter) modelFilter.focus();
23260
23347
  }
23261
23348
  });
@@ -23277,11 +23364,28 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23277
23364
  if (thinkingEl) thinkingEl.addEventListener("change", function () {
23278
23365
  saveSetting({ thinking_level: thinkingEl.value });
23279
23366
  });
23280
- on("new-session", "click", function () {
23281
- api("POST", "/api/sessions", {}).then(function (res) {
23282
- if (!res.ok) return readError(res, "Could not start a new session.").then(function (msg) { addBlock("alert", msg); });
23283
- }).catch(function () {
23284
- addBlock("alert", "Could not start a new session.");
23367
+ function createNewSession() {
23368
+ api("POST", "/api/sessions", {})
23369
+ .then(function (res) {
23370
+ if (!res.ok) {
23371
+ return readError(res, "Could not start a new session.").then(function (msg) { addBlock("alert", msg); });
23372
+ }
23373
+ if (window.innerWidth <= 760) {
23374
+ layout.rail = false;
23375
+ applyLayout();
23376
+ }
23377
+ inputEl.focus();
23378
+ })
23379
+ .catch(function () { addBlock("alert", "Could not start a new session."); });
23380
+ }
23381
+ on("new-session", "click", createNewSession);
23382
+ on("top-new-session", "click", createNewSession);
23383
+ on("all-changes", "click", function () {
23384
+ selectedPath = "";
23385
+ var back = document.getElementById("all-changes");
23386
+ if (back) back.hidden = true;
23387
+ refreshWorkspaceSnapshot(false).then(function () {
23388
+ document.querySelectorAll(".tree button.on").forEach(function (el) { el.classList.remove("on"); });
23285
23389
  });
23286
23390
  });
23287
23391
  on("fork-session", "click", function () {
@@ -23294,6 +23398,11 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23294
23398
  var searchEl = document.getElementById("session-search");
23295
23399
  if (searchEl) searchEl.addEventListener("input", function () { renderSessions(allSessions, activeSessionId); });
23296
23400
 
23401
+ function syncAutonomyVisual() {
23402
+ var open = document.getElementById("autonomy-open"); var sel = document.getElementById("autonomy");
23403
+ if (open && sel) open.classList.toggle("auto", sel.value === "auto");
23404
+ }
23405
+
23297
23406
  function renderChips() {
23298
23407
  var el = document.getElementById("ref-chips");
23299
23408
  if (!el) return;
@@ -23359,21 +23468,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23359
23468
  return;
23360
23469
  }
23361
23470
  addRef(node.path);
23362
- if (kind) loadDiff(node.path, btn);
23363
- else {
23364
- selectedPath = node.path;
23365
- var title = document.getElementById("diff-title");
23366
- if (title) title.textContent = node.path;
23367
- api("GET", "/api/file?path=" + encodeURIComponent(node.path)).then(function (res) { return res.json(); }).then(function (file) {
23368
- var view = document.getElementById("file-view");
23369
- var diffEl = document.getElementById("diff");
23370
- if (diffEl) diffEl.hidden = true;
23371
- if (view) {
23372
- view.hidden = false;
23373
- view.textContent = file.text || "";
23374
- }
23375
- }).catch(function () {});
23376
- }
23471
+ loadFileContent(node.path, btn);
23377
23472
  });
23378
23473
  into.appendChild(btn);
23379
23474
  if (node.dir && !collapsed) renderTreeNodes(node.children || [], depth + 1, into);
@@ -23452,7 +23547,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23452
23547
  if (!selectedPath) return;
23453
23548
  api("POST", "/api/changes/revert", { path: selectedPath }).then(function (res) {
23454
23549
  if (!res.ok) return readError(res, "Could not reject that file.").then(function (msg) { addBlock("alert", msg); });
23455
- loadTree();
23550
+ refreshWorkspaceSnapshot(true);
23456
23551
  }).catch(function () {});
23457
23552
  });
23458
23553
  on("accept-file", "click", function () {
@@ -23545,7 +23640,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23545
23640
  var modeEl = document.getElementById("mode");
23546
23641
  var autonomyEl = document.getElementById("autonomy");
23547
23642
  if (modeEl) modeEl.addEventListener("change", function () { saveSetting({ agent_mode: modeEl.value }); });
23548
- if (autonomyEl) autonomyEl.addEventListener("change", function () { saveSetting({ autonomy: autonomyEl.value }); });
23643
+ if (autonomyEl) autonomyEl.addEventListener("change", function () { saveSetting({ autonomy: autonomyEl.value }); syncAutonomyVisual(); });
23549
23644
 
23550
23645
  feedEl.addEventListener("click", function (e) {
23551
23646
  var btn = e.target.closest && e.target.closest(".copy");
@@ -23589,7 +23684,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23589
23684
  }
23590
23685
 
23591
23686
  var shell = document.querySelector(".shell");
23592
- var layout = { rail: true, changes: window.innerWidth >= 1100, term: false };
23687
+ var layout = { rail: window.innerWidth > 760, changes: false, term: false };
23593
23688
  try {
23594
23689
  var saved = localStorage.getItem("critique.code-web.layout");
23595
23690
  if (saved) layout = Object.assign(layout, JSON.parse(saved));
@@ -23602,7 +23697,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23602
23697
  var pane = document.getElementById("changes-pane");
23603
23698
  if (pane) pane.classList.toggle("open", !!layout.changes);
23604
23699
  var railBtn = document.getElementById("toggle-rail");
23605
- if (railBtn) railBtn.textContent = layout.rail ? "\u2039" : "\u203A";
23700
+ if (railBtn) railBtn.classList.toggle("on", !!layout.rail);
23606
23701
  try { localStorage.setItem("critique.code-web.layout", JSON.stringify(layout)); } catch (e) {}
23607
23702
  }
23608
23703
  applyLayout();
@@ -23764,15 +23859,8 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23764
23859
  }).join("");
23765
23860
  if (sheet) sheet.className = "sheet open";
23766
23861
  });
23767
- on("studio-open", "click", function () {
23768
- loadStudio();
23769
- var sheet = document.getElementById("studio-sheet");
23770
- if (sheet) sheet.className = "sheet open";
23771
- });
23772
- on("close-studio", "click", function () {
23773
- var sheet = document.getElementById("studio-sheet");
23774
- if (sheet) sheet.className = "sheet";
23775
- });
23862
+ on("studio-open", "click", function () { loadStudio(); selectSettingsTab("general"); openSheet("studio-sheet"); });
23863
+ on("close-studio", "click", function () { closeSheet("studio-sheet"); });
23776
23864
  on("save-key", "click", function () {
23777
23865
  var kind = document.getElementById("key-kind");
23778
23866
  var value = document.getElementById("key-value");
@@ -23796,7 +23884,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23796
23884
  if (sheet) sheet.className = "sheet";
23797
23885
  if (res.ok) {
23798
23886
  if (body.branch) setBranchLabel(body.branch);
23799
- loadTree();
23887
+ refreshWorkspaceSnapshot(true);
23800
23888
  loadBranches();
23801
23889
  }
23802
23890
  }); });
@@ -23845,6 +23933,19 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23845
23933
  }
23846
23934
  if (paletteQ) paletteQ.addEventListener("input", renderPalette);
23847
23935
  renderPalette();
23936
+ var themeLight = document.getElementById("theme-light");
23937
+ function applyTheme(light) {
23938
+ document.documentElement.setAttribute("data-theme", light ? "light" : "dark");
23939
+ try { localStorage.setItem("critique-code-theme", light ? "light" : "dark"); } catch (e) {}
23940
+ }
23941
+ if (themeLight) {
23942
+ var savedTheme = "";
23943
+ try { savedTheme = localStorage.getItem("critique-code-theme") || ""; } catch (e) {}
23944
+ var useLight = savedTheme === "light";
23945
+ themeLight.checked = useLight;
23946
+ applyTheme(useLight);
23947
+ themeLight.addEventListener("change", function () { applyTheme(themeLight.checked); });
23948
+ }
23848
23949
  document.querySelectorAll(".work-tabs button").forEach(function (btn) {
23849
23950
  btn.addEventListener("click", function () {
23850
23951
  document.querySelectorAll(".work-tabs button").forEach(function (el) { el.classList.remove("on"); });
@@ -23912,8 +24013,12 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23912
24013
  addBlock("alert", "Could not load this session. Refresh the loopback tab.");
23913
24014
  });
23914
24015
  renderModelList();
24016
+ renderCommandBrowser();
24017
+ autosizeInput();
24018
+ syncAutonomyVisual();
23915
24019
  updateContextRing();
23916
24020
  loadStudio();
24021
+ refreshWorkspaceSnapshot(false);
23917
24022
  connect();
23918
24023
  })();
23919
24024
  </script>
@@ -28610,7 +28715,8 @@ ${prior}`.trim();
28610
28715
  source: "author",
28611
28716
  model: authorModelId(implementer[0]),
28612
28717
  input_tokens: turn.usage?.input_tokens ?? 0,
28613
- output_tokens: turn.usage?.output_tokens ?? 0
28718
+ output_tokens: turn.usage?.output_tokens ?? 0,
28719
+ cost_usd: turn.usage?.cost_usd
28614
28720
  });
28615
28721
  const output = typeof turn.output === "string" ? turn.output : JSON.stringify(turn.output);
28616
28722
  noteWithheld(output);
@@ -30551,6 +30657,12 @@ function commandPaletteItems(state) {
30551
30657
  function emptyTokens() {
30552
30658
  return { input_tokens: 0, output_tokens: 0 };
30553
30659
  }
30660
+ function estimateUsageCostUsd(input, output, reasoning = 0) {
30661
+ const inCost = input * 1e-7;
30662
+ const outCost = output * 4e-7;
30663
+ const reasonCost = reasoning * 2e-7;
30664
+ return inCost + outCost + reasonCost;
30665
+ }
30554
30666
  function costBreakdown(entries) {
30555
30667
  const by_phase = {
30556
30668
  author: emptyTokens(),
@@ -30560,6 +30672,7 @@ function costBreakdown(entries) {
30560
30672
  const by_model = {};
30561
30673
  let total_input = 0;
30562
30674
  let total_output = 0;
30675
+ let total_cost_usd = 0;
30563
30676
  for (const entry of entries) {
30564
30677
  const phase = by_phase[entry.source];
30565
30678
  phase.input_tokens += entry.input_tokens;
@@ -30569,8 +30682,10 @@ function costBreakdown(entries) {
30569
30682
  model.output_tokens += entry.output_tokens;
30570
30683
  total_input += entry.input_tokens;
30571
30684
  total_output += entry.output_tokens;
30685
+ total_cost_usd += Number(entry.cost_usd || 0);
30572
30686
  }
30573
- return { by_phase, by_model, total_input, total_output };
30687
+ const estimated_cost_usd = total_cost_usd > 0 ? total_cost_usd : estimateUsageCostUsd(total_input, total_output);
30688
+ return { by_phase, by_model, total_input, total_output, total_cost_usd, estimated_cost_usd };
30574
30689
  }
30575
30690
  function skillPanelRows(skills) {
30576
30691
  return skills.map((skill) => {
@@ -31190,6 +31305,29 @@ exit ${code2 ?? "killed"}
31190
31305
  send(res, 200, { ok: true, id: chat.id });
31191
31306
  return;
31192
31307
  }
31308
+ if (req.method === "POST" && path2 === "/api/sessions/rename") {
31309
+ const body = await readJson(req);
31310
+ const id4 = String(body.id ?? activeId).trim();
31311
+ const title = String(body.title ?? "").trim().slice(0, 120);
31312
+ const chat = chats.find((item) => item.id === id4);
31313
+ if (!chat) {
31314
+ send(res, 404, { error: "unknown session" });
31315
+ return;
31316
+ }
31317
+ if (!title) {
31318
+ send(res, 400, { error: "title required" });
31319
+ return;
31320
+ }
31321
+ chat.title = title;
31322
+ persistChats();
31323
+ if (chat.id === activeId) {
31324
+ emit({ type: "title", title: chat.title, id: chat.id, sessions: sessionSummaries() });
31325
+ } else {
31326
+ emit({ type: "session_list", sessions: sessionSummaries(), id: activeId });
31327
+ }
31328
+ send(res, 200, { ok: true, id: chat.id, title: chat.title, sessions: sessionSummaries() });
31329
+ return;
31330
+ }
31193
31331
  if (req.method === "GET" && path2 === "/api/tree") {
31194
31332
  const prefix = url2.searchParams.get("prefix")?.trim() ?? "";
31195
31333
  const entries = listWorkspaceTree(repositoryRoot, 2e3, prefix);
@@ -31501,12 +31639,20 @@ ${extras.join("\n\n")}` : text);
31501
31639
  const cursor = await new FileReviewCheckpointStore(storeRoot).load();
31502
31640
  const skills = await discoverCritiqueCodeSkills({ cwd: repositoryRoot, env });
31503
31641
  const suppressed = new Set(ops.state().suppressions.map((item) => item.fingerprint));
31642
+ const chatUsage = activeChat().events.filter((event) => event.type === "usage").map((event) => ({
31643
+ at: (/* @__PURE__ */ new Date()).toISOString(),
31644
+ source: "author",
31645
+ model,
31646
+ input_tokens: Number(event.input_tokens || 0),
31647
+ output_tokens: Number(event.output_tokens || 0),
31648
+ cost_usd: event.cost_usd
31649
+ }));
31504
31650
  send(res, 200, {
31505
31651
  ...snapshot(),
31506
31652
  badges: dualModelBadges({ author_model: model, review_models: reviewModels }),
31507
31653
  palette: commandPaletteItems({ watch: watchOn, autonomy, voice: false }),
31508
31654
  skills: skillPanelRows(skills),
31509
- costs: costBreakdown(ops.state().costs),
31655
+ costs: costBreakdown([...ops.state().costs, ...chatUsage]),
31510
31656
  audit: approvalLog,
31511
31657
  timeline: checkpointTimeline({
31512
31658
  cursor: cursor ? {