@critiquedotsh/harness 0.1.10 → 0.1.11

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 +1015 -870
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -21318,708 +21318,451 @@ 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{--rail-w:0px}
21369
+ .shell.rail-off .rail{display:none}
21370
+ .shell.changes-off{--changes-w:0px}
21371
+ .shell.changes-off .gutter,.shell.changes-off .changes{display:none}
21372
+ .shell.term-off .term{display:none}
21373
+ .gutter{background:var(--line);cursor:col-resize}
21374
+
21375
+ /* sidebar */
21376
+ .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}
21377
+ .rail-top{height:34px;display:flex;align-items:center;justify-content:space-between;padding:0 4px}
21378
+ .brand{display:inline-flex;align-items:center;gap:9px;color:var(--fg);font-weight:650;font-size:13px;min-width:0}
21379
+ .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)}
21380
+ .brand span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21381
+ .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)}
21382
+ .rail .plus:hover{background:var(--hover);border-color:var(--line-strong)}
21383
+ .rail-search{position:relative}
21384
+ .rail-search svg{position:absolute;left:10px;top:9px;color:var(--faint);pointer-events:none}
21385
+ .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}
21386
+ .rail .search:focus{border-color:var(--line);background:rgba(255,255,255,.025)}
21387
+ #sessions{display:flex;flex-direction:column;gap:2px;min-height:0;overflow:auto;overscroll-behavior:contain;padding-right:1px;flex:1}
21388
+ .session-row{display:grid;grid-template-columns:minmax(0,1fr) 28px;gap:2px;align-items:center;border-radius:8px}
21389
+ .session-row:hover,.session-row.on{background:var(--hover)}
21390
+ .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}
21391
+ .session-row.on .session-item{color:var(--fg)}
21392
+ .session-delete{width:26px;height:26px;border:0;background:transparent;color:transparent;border-radius:7px;display:grid;place-items:center}
21393
+ .session-row:hover .session-delete{color:var(--faint)}
21394
+ .session-delete:hover{background:rgba(239,119,112,.1)!important;color:var(--red)!important}
21395
+ .rail-footer{border-top:1px solid var(--line);padding-top:8px;display:grid;gap:5px}
21396
+ .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}
21397
+ .rail-footer button:hover{background:var(--hover);color:var(--fg)}
21398
+ .repo-mini{padding:4px 9px;color:var(--faint);font:10.5px ui-monospace,Menlo,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21399
+
21400
+ /* main */
21401
+ .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)}
21402
+ .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}
21403
+ .topbar-left{display:flex;align-items:center;gap:9px;min-width:0;flex:1}
21404
+ .session-title{min-width:0;font-size:12.5px;font-weight:600;color:var(--fg);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21405
+ .top-actions{display:flex;align-items:center;gap:5px;min-width:0}
21406
+ .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}
21407
+ .icon-btn{width:30px;padding:0}
21408
+ .icon-btn:hover,.toolbar-btn:hover,.icon-btn.on,.toolbar-btn.on{background:var(--hover);color:var(--fg);border-color:var(--line)}
21409
+ .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}
21410
+ .top-status,.badge{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--faint);font-size:11px}
21411
+ .badge.err{color:var(--red)}
21412
+ #stop{color:var(--red);background:rgba(239,119,112,.08)}
21413
+ main{min-height:0;overflow:auto;overscroll-behavior:contain;scrollbar-gutter:stable}
21414
+ #empty{max-width:700px;margin:17vh auto 0;padding:0 28px 44px}
21415
+ #empty h1{margin:0 0 10px;font-size:27px;line-height:1.2;font-weight:520;letter-spacing:-.04em;color:var(--fg)}
21416
+ #empty p{margin:0;color:var(--muted);font-size:13px;line-height:1.6;max-width:540px}
21417
+ .empty-actions{display:flex;flex-wrap:wrap;gap:7px;margin-top:22px}
21418
+ .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}
21419
+ .empty-actions button:hover{background:var(--hover);color:var(--fg)}
21420
+ #feed{display:none;max-width:780px;margin:0 auto;padding:30px 28px 38px}
21421
+ #feed.on{display:block}
21422
+ .turn{margin:0 0 34px;position:relative}
21423
+ .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}
21424
+ .reply{margin:0;color:#e9e3da;font-size:14px;line-height:1.63;word-break:break-word}
21425
+ .reply>*:first-child{margin-top:0}.reply>*:last-child{margin-bottom:0}
21426
+ .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}
21427
+ .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}
21428
+ .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)}
21429
+ .reply a{color:#a9c8ff;text-decoration:none}.reply a:hover{text-decoration:underline}
21430
+ .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}
21431
+ .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)}
21432
+ .reply hr{border:0;border-top:1px solid var(--line);margin:16px 0}
21433
+ .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}
21434
+ .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}
21435
+ .reply .md-code code{background:none;border:0;padding:0}
21436
+ .md-table{margin:10px 0 14px;overflow:auto;border:1px solid var(--line);border-radius:10px;background:#121210}
21437
+ .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}
21438
+
21439
+ /* activity: each tool is its own row */
21440
+ .activity{display:grid;gap:5px;margin:9px 0 13px}
21441
+ .tool-event,.think{margin:0;border:0;background:transparent;color:var(--muted);font-size:11.5px}
21442
+ .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}
21443
+ .tool-event summary::-webkit-details-marker,.think summary::-webkit-details-marker{display:none}
21444
+ .tool-event summary:hover,.think summary:hover{background:var(--hover);color:var(--fg)}
21445
+ .tool-dot{width:7px;height:7px;border-radius:999px;background:var(--faint);flex:0 0 auto}
21446
+ .tool-event.running .tool-dot{background:var(--amber);box-shadow:0 0 0 3px rgba(224,170,67,.08)}
21447
+ .tool-event.done .tool-dot{background:var(--green)}
21448
+ .tool-event.failed .tool-dot{background:var(--red)}
21449
+ .tool-name{font-family:ui-monospace,Menlo,monospace;color:#c5bdb1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
21450
+ .tool-phase{color:var(--faint)}
21451
+ .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}
21452
+ .think{margin:6px 0;color:var(--faint)}
21453
+ .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}
21454
+ .note,.alert,.review-card{margin:10px 0;padding:8px 10px;border-radius:8px;line-height:1.5;word-break:break-word;font-size:12px}
21455
+ .note{padding:5px 2px;background:transparent;border:0;color:var(--faint);font-family:ui-monospace,Menlo,monospace}
21456
+ .alert{background:rgba(239,119,112,.07);border:1px solid rgba(239,119,112,.18);color:#f0b8b4}
21457
+ .review-card{background:rgba(85,216,140,.045);border:1px solid rgba(85,216,140,.18);color:#d8e7dd}
21458
+ .trust{display:none}
21459
+ .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}
21460
+
21461
+ /* composer */
21462
+ .dock{padding:8px 18px 14px;background:linear-gradient(180deg,transparent,rgba(15,15,14,.96) 18%)}
21463
+ .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)}
21464
+ .composer-line{display:flex;align-items:flex-end;gap:5px}
21465
+ .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)}
21466
+ .composer-line textarea::placeholder{color:#716b63}
21467
+ .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}
21468
+ .round-btn:hover,.plus-btn:hover,.mic-btn:hover,.mic-btn.on{background:var(--hover);color:var(--fg)}
21469
+ .composer-foot{display:flex;align-items:center;gap:6px;padding:3px 3px 1px;min-height:36px}
21470
+ .composer-left,.composer-right{display:flex;align-items:center;gap:5px;min-width:0}.composer-right{margin-left:auto;flex:0 0 auto}
21471
+ .pick{position:relative}
21472
+ .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}
21473
+ .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)}
21474
+ .pick-open .caret,#model-open .caret{opacity:.45;font-size:9px}
21475
+ .model-ico{width:15px!important;height:15px!important;display:block;flex:0 0 auto;border-radius:4px}
21476
+ .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}
21477
+ .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}
21478
+ .pick-menu.open,#model-menu.open,#mention.open,.cmd-pop.open,.branch-menu.open,.ship-menu.open{display:grid}
21479
+ .pick-menu{bottom:36px;left:0;min-width:210px;max-height:300px;overflow:auto;overscroll-behavior:contain;padding:5px}
21480
+ #model-menu{right:0;bottom:36px;width:310px;max-height:360px;grid-template-rows:auto minmax(0,1fr);overscroll-behavior:contain}
21481
+ #model-filter{width:100%;height:39px;background:#121211;border:0;border-bottom:1px solid var(--line);padding:0 11px;outline:0;font-size:12px}
21482
+ #model-list{overflow:auto;overscroll-behavior:contain;max-height:310px;padding:5px}
21483
+ .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}
21484
+ .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)}
21485
+ #model{position:absolute;opacity:0;pointer-events:none;width:0;height:0}
21486
+ #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)}
21487
+ #send:hover{transform:translateY(-1px);filter:brightness(1.04)}#send.steer{background:#bfe8cf;color:#142219}#send:disabled{opacity:.45;cursor:not-allowed}
21488
+ #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)}
21489
+ .autonomy-pill.auto{color:var(--amber);border-color:rgba(224,170,67,.24);background:rgba(224,170,67,.055)}
21490
+ .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}
21491
+ .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)}
21492
+ .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)}
21493
+ #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}
21494
+
21495
+ /* terminal */
21496
+ .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)}
21497
+
21498
+ /* workspace */
21499
+ .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)}
21500
+ #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}
21501
+
21502
+ /* overlays */
21503
+ .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)}
21504
+ #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)}
21505
+ .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)}
21506
+
21507
+ /* command browser */
21508
+ .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}
21509
+
21510
+ /* settings */
21511
+ .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)}
21512
+ .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)}
21513
+ .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}
21514
+ #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}
21515
+ .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)}
21516
+
21517
+ /* resume picker */
21518
+ .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}
21519
+
21520
+ @media(max-width:1100px){.shell,.shell.rail-off{grid-template-columns:var(--rail-w) 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)}}
21521
+ @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
21522
  </style>
21690
21523
  </head>
21691
21524
  <body${remote ? ' class="remote"' : ""}>
21692
21525
  <div class="shell">
21693
21526
  <aside class="rail">
21694
21527
  <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>
21528
+ <div class="brand"><div class="mark" title="CritiqueCode">C</div><span>CritiqueCode</span></div>
21697
21529
  </div>
21698
- <div class="rail-copy">
21699
- <button type="button" class="plus" id="new-session" title="New session" aria-label="New session">
21530
+ <button type="button" class="plus" id="new-session" title="New session">
21700
21531
  <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
21532
+ New chat
21702
21533
  </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">
21534
+ <div class="rail-search">
21535
+ <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>
21536
+ <input id="session-search" class="search" placeholder="Search chats" autocomplete="off">
21537
+ </div>
21705
21538
  <div id="sessions"></div>
21539
+ <div class="rail-footer">
21540
+ <button type="button" id="fork-session" title="Fork this conversation">
21541
+ <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>
21542
+ Fork chat
21543
+ </button>
21544
+ <button type="button" id="rail-settings">
21545
+ <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>
21546
+ Settings
21547
+ </button>
21548
+ <div class="repo-mini" title="${repositoryRoot}">${repositoryName} \xB7 ${branch}</div>
21706
21549
  </div>
21707
21550
  </aside>
21551
+
21708
21552
  <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>
21553
+ <header class="topbar">
21554
+ <div class="topbar-left">
21555
+ <button type="button" class="icon-btn" id="toggle-rail" title="Chats" aria-label="Toggle chats">
21556
+ <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>
21557
+ </button>
21558
+ <button type="button" class="icon-btn top-new-chat" id="top-new-session" title="New chat" aria-label="New chat">
21559
+ <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>
21560
+ </button>
21561
+ <div class="session-title" id="session-title"><span id="session-label">New session</span></div>
21713
21562
  </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>
21563
+ <div class="top-actions">
21564
+ <span class="top-status" id="status" hidden></span>
21565
+ <button type="button" class="toolbar-btn" id="changes-pill" title="Open workspace">
21566
+ <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>
21567
+ <span class="toolbar-label">Changes</span><span class="count" id="changes-count">0</span>
21568
+ <span hidden id="changes-plus">+0</span><span hidden id="changes-minus">\u22120</span>
21569
+ </button>
21570
+ <button type="button" class="icon-btn" id="toggle-term" title="Terminal" aria-label="Toggle terminal">
21571
+ <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>
21572
+ </button>
21573
+ <button type="button" class="icon-btn" id="toggle-changes" title="Workspace" aria-label="Toggle workspace">
21574
+ <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>
21575
+ </button>
21576
+ <button type="button" class="icon-btn" id="studio-open" title="Settings" aria-label="Settings">
21577
+ <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>
21578
+ </button>
21579
+ <button type="button" class="icon-btn" id="stop" title="Stop run" aria-label="Stop" hidden>\u25A0</button>
21741
21580
  </div>
21581
+ <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
21582
  </header>
21583
+
21743
21584
  <main>
21744
21585
  <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>
21586
+ <h1>What are we building?</h1>
21587
+ <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>
21588
+ <div class="empty-actions">
21589
+ <button type="button" data-starter="Review the current changes and tell me what needs fixing">Review current changes</button>
21590
+ <button type="button" data-starter="Explain this repository and its main architecture">Explain the repository</button>
21591
+ <button type="button" id="empty-commands">Browse commands</button>
21592
+ </div>
21760
21593
  </div>
21761
21594
  <div id="feed"></div>
21762
21595
  </main>
21596
+
21763
21597
  <div class="term" id="term">
21764
21598
  <header>
21765
- <span>Terminal \xB7 repo root <span class="trust unverified">Not Evidence</span></span>
21599
+ <span>Terminal \xB7 repo root</span>
21766
21600
  <span>
21767
- <label class="always-row"><input type="checkbox" id="term-bg"> Background</label>
21601
+ <label class="always-row"><input type="checkbox" id="term-bg"> background</label>
21768
21602
  <div class="pick" data-pick="term-timeout">
21769
21603
  <button type="button" class="pick-open" id="term-timeout-open" aria-haspopup="listbox" aria-expanded="false">60s <span class="caret">\u25BE</span></button>
21770
21604
  <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>
21605
+ <select id="term-timeout" aria-label="Timeout"><option value="60000">60s</option><option value="180000">3m</option><option value="600000">10m</option></select>
21776
21606
  </div>
21777
21607
  <button type="button" id="term-clear">Clear</button>
21778
21608
  </span>
21779
21609
  </header>
21780
21610
  <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>
21611
+ <form id="term-form"><input id="term-input" autocomplete="off" spellcheck="false" placeholder="Run a command in this repository\u2026"></form>
21784
21612
  </div>
21613
+
21785
21614
  <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
21615
  <div class="composer">
21801
- <div id="mention">
21802
- <div id="mention-list"></div>
21803
- </div>
21616
+ <div id="mention"><div id="mention-list"></div></div>
21804
21617
  <div class="composer-line">
21805
21618
  <div class="cmds">
21806
- <button type="button" class="plus-btn" id="cmd-open" aria-haspopup="menu" aria-expanded="false" title="Commands and attachments">+</button>
21619
+ <button type="button" class="plus-btn" id="cmd-open" aria-haspopup="menu" aria-expanded="false" title="Add context or browse commands">+</button>
21807
21620
  <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>
21621
+ <button type="button" id="commands-open">Commands &amp; skills\u2026</button>
21622
+ <button type="button" id="attach">Attach repository path\u2026</button>
21623
+ <button type="button" data-cmd="/login">Login / connect inference</button>
21825
21624
  </div>
21826
21625
  </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>
21626
+ <textarea id="input" rows="1" placeholder="Message CritiqueCode\u2026" title="Type / for commands and skills, @ to add context"></textarea>
21833
21627
  <button type="button" class="mic-btn" id="voice" title="Voice input" aria-label="Voice input">
21834
21628
  <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
21629
  </button>
21836
21630
  </div>
21837
21631
  <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>
21632
+ <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
21633
  <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">
21634
+ <div class="composer-left">
21859
21635
  <div class="pick" data-pick="mode">
21860
21636
  <button type="button" class="pick-open" id="mode-open" aria-haspopup="listbox" aria-expanded="false">Agent <span class="caret">\u25BE</span></button>
21861
21637
  <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>
21638
+ <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
21639
  </div>
21869
21640
  <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>
21641
+ <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
21642
  <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>
21643
+ <select id="autonomy" aria-label="Approval mode"><option value="ask">Ask</option><option value="auto">Auto approve</option></select>
21876
21644
  </div>
21877
21645
  <div class="model-wrap pick">
21878
21646
  <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>
21647
+ <div id="model-menu"><input id="model-filter" placeholder="Search models\u2026" autocomplete="off"><div id="model-list"></div></div>
21883
21648
  <select id="model" aria-label="Author model">${options}</select>
21884
21649
  </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>
21650
+ </div>
21651
+ <div class="composer-right">
21652
+ <button type="button" id="review-run" title="Run an independent review">Review</button>
21653
+ <button type="button" id="send" aria-label="Send" title="Send">
21654
+ <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>
21655
+ </button>
21907
21656
  </div>
21908
21657
  </div>
21909
21658
  </div>
21910
21659
  </div>
21911
21660
  </div>
21912
- <div class="gutter" id="gutter" title="Resize"></div>
21661
+
21662
+ <div class="gutter" id="gutter" title="Resize workspace"></div>
21913
21663
  <aside class="changes" id="changes-pane">
21914
21664
  <header>
21915
21665
  <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>
21666
+ <button type="button" class="icon-btn" id="close-changes" title="Close workspace" aria-label="Close workspace">\xD7</button>
21667
+ <div class="sum" id="changes-sum">${branch}</div>
21668
+ <ol class="gate" id="ship-gate"></ol>
21918
21669
  </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>
21670
+ <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
21671
  <div class="work-stack">
21926
21672
  <div class="workspace" id="tab-tree">
21927
- <input id="grep" placeholder="Search files\u2026">
21673
+ <input id="grep" placeholder="Find file or text\u2026">
21928
21674
  <div class="tree" id="tree"></div>
21929
21675
  <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>
21676
+ <div class="diff-title-wrap">
21677
+ <button type="button" id="all-changes" class="diff-back" hidden>\u2190 All changes</button>
21678
+ <b id="diff-title">Working changes</b>
21936
21679
  </div>
21680
+ <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
21681
  </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>
21682
+ <div class="diff" id="diff"><div class="diff-loading">Open Workspace to inspect working-tree diffs.</div></div>
21683
+ <pre id="file-view" hidden></pre><iframe id="preview" hidden sandbox="allow-same-origin" title="Preview"></iframe>
21952
21684
  </div>
21685
+ <div class="workspace" id="tab-findings" hidden><input id="find-filter" placeholder="Filter findings\u2026"><div id="find-list" class="tree"></div></div>
21686
+ <div class="workspace" id="tab-timeline" hidden><div id="timeline" class="tree"></div></div>
21687
+ <div class="compare" id="tab-compare" hidden><div id="compare-left"></div><div id="compare-right"></div></div>
21953
21688
  </div>
21954
21689
  <div class="change-list" id="change-list"></div>
21955
21690
  </aside>
21956
21691
  </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>
21692
+
21693
+ <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>
21694
+
21695
+ <div class="palette" id="palette"><input id="palette-q" placeholder="Commands and skills\u2026" autocomplete="off"><div id="palette-list"></div></div>
21696
+
21697
+ <div class="sheet" id="command-sheet"><div class="card command-card">
21698
+ <div class="sheet-head"><h3>Commands &amp; skills</h3><button type="button" id="close-commands" aria-label="Close">\xD7</button></div>
21699
+ <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
21700
  </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>
21701
+
21702
+ <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>
21703
+
21704
+ <div class="sheet" id="studio-sheet"><div class="card settings-card">
21705
+ <nav class="settings-nav">
21706
+ <div class="settings-nav-head"><b>Settings</b><button type="button" class="settings-close" id="close-studio" aria-label="Close settings">\xD7</button></div>
21707
+ <div class="settings-mobile-tabs" style="display:contents">
21708
+ <button type="button" class="on" data-settings-tab="general">General</button>
21709
+ <button type="button" data-settings-tab="models">Models</button>
21710
+ <button type="button" data-settings-tab="usage">Usage</button>
21711
+ <button type="button" data-settings-tab="skills">Skills</button>
21712
+ <button type="button" data-settings-tab="approvals">Approvals</button>
21713
+ <button type="button" data-settings-tab="connections">Connections</button>
21714
+ </div>
21715
+ </nav>
21716
+ <div class="settings-content">
21717
+ <section class="settings-panel on" data-settings-panel="general">
21718
+ <h2>General</h2><p class="sub">Keep the chat surface quiet; the controls that matter less live here.</p>
21719
+ <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>
21720
+ <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>
21721
+ <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>
21722
+ <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>
21723
+ <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>
21724
+ ${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>` : ""}
21725
+ <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>
21726
+ </section>
21727
+
21728
+ <section class="settings-panel" data-settings-panel="models">
21729
+ <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>
21730
+ <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>
21731
+ <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>
21732
+ <div id="studio-indep" class="settings-note"></div>
21733
+ </section>
21734
+
21735
+ <section class="settings-panel" data-settings-panel="usage">
21736
+ <h2>Usage</h2><p class="sub">Token and cost usage for this loaded chat, plus server-side phase/model totals when available.</p>
21737
+ <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>
21738
+ <div class="usage-chart" id="usage-chart"><div class="usage-empty">Usage appears here as model calls complete.</div></div>
21739
+ <h3>By phase</h3><div class="breakdown" id="usage-phase"></div>
21740
+ <h3>By model</h3><div class="breakdown" id="usage-model"></div>
21741
+ <pre id="cost-panel" hidden></pre>
21742
+ </section>
21743
+
21744
+ <section class="settings-panel" data-settings-panel="skills">
21745
+ <h2>Skills</h2><p class="sub">Skills extend the author with repository- or agent-specific guidance.</p>
21746
+ <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>
21747
+ <div id="skill-list" class="skill-list" style="margin-top:10px"></div>
21748
+ </section>
21749
+
21750
+ <section class="settings-panel" data-settings-panel="approvals">
21751
+ <h2>Approvals</h2><p class="sub">Recent command approval decisions on this machine.</p>
21752
+ <div id="audit-panel" class="audit-list"></div>
21753
+ </section>
21754
+
21755
+ <section class="settings-panel" data-settings-panel="connections">
21756
+ <h2>Connections</h2><p class="sub">Store provider keys locally for BYOK routes.</p>
21757
+ <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>
21758
+ <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>
21759
+ <div class="modal-actions"><button type="button" id="save-key">Store key</button></div>
21760
+ </section>
22021
21761
  </div>
22022
21762
  </div></div>
21763
+
21764
+ <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>
21765
+ <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
21766
  <script type="application/json" id="boot">${bootJson}</script>
22024
21767
  <script type="application/json" id="model-icons">${iconsJson}</script>
22025
21768
  <script type="application/json" id="thinking-boot">${thinkingJson}</script>
@@ -22076,6 +21819,12 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22076
21819
  var busy = false;
22077
21820
  var promptQueue = [];
22078
21821
  var applyingSnapshot = false;
21822
+ var usageHistory = [];
21823
+ var studioCosts = null;
21824
+ var workspaceRefreshTimer = null;
21825
+ var workspacePollTimer = null;
21826
+ var thinkingStartedAt = 0;
21827
+ var thinkingTimer = null;
22079
21828
  var thinkingEl = document.getElementById("thinking");
22080
21829
  if (thinkingEl) {
22081
21830
  (thinkingBoot.levels || []).forEach(function (level) {
@@ -22146,8 +21895,12 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22146
21895
  }
22147
21896
 
22148
21897
  function modelIconHtml(option) {
22149
- var raw = option && (option.getAttribute("data-icon") || iconMap[option.getAttribute("data-provider") || ""] || "");
22150
- return raw || iconMap.other || "";
21898
+ var provider = option && (option.getAttribute("data-provider") || "") || "other";
21899
+ var raw = option && (option.getAttribute("data-icon") || iconMap[provider] || "");
21900
+ if (raw) return raw;
21901
+ var label = option && (option.text || option.value) || provider || "model";
21902
+ var letter = String(label).replace(/^[^a-z0-9]+/i, "").charAt(0).toUpperCase() || "M";
21903
+ return "<span class=\\"model-fallback\\" aria-hidden=\\"true\\">" + esc(letter) + "</span>";
22151
21904
  }
22152
21905
 
22153
21906
  function setPickLabel(openId, text, iconHtml) {
@@ -22269,6 +22022,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22269
22022
  render();
22270
22023
  menu.className = "pick-menu open";
22271
22024
  open.setAttribute("aria-expanded", "true");
22025
+ trapWheel(menu);
22272
22026
  }
22273
22027
  });
22274
22028
  menu.addEventListener("click", function (e) { e.stopPropagation(); });
@@ -22504,10 +22258,22 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22504
22258
  if (modelEl) modelEl.disabled = false;
22505
22259
  sendEl.className = busy ? "steer" : "";
22506
22260
  sendEl.setAttribute("aria-label", busy ? "Queue follow-up" : "Send");
22507
- inputEl.placeholder = busy ? "Queue a follow-up." : "Send follow-up.";
22261
+ sendEl.title = busy ? "Queue follow-up" : "Send";
22262
+ inputEl.placeholder = busy ? "Queue a follow-up\u2026" : "Message CritiqueCode\u2026";
22508
22263
  var stop = document.getElementById("stop");
22509
22264
  if (stop) stop.hidden = !busy;
22510
- if (was && !busy) flushQueue(false);
22265
+ if (busy && !workspacePollTimer) {
22266
+ workspacePollTimer = setInterval(function () { refreshWorkspaceSnapshot(false); }, 1800);
22267
+ }
22268
+ if (!busy && workspacePollTimer) {
22269
+ clearInterval(workspacePollTimer);
22270
+ workspacePollTimer = null;
22271
+ }
22272
+ if (!busy) finishThinkingTimer();
22273
+ if (was && !busy) {
22274
+ refreshWorkspaceSnapshot(true);
22275
+ flushQueue(false);
22276
+ }
22511
22277
  }
22512
22278
 
22513
22279
  function renderQueue() {
@@ -22541,6 +22307,11 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22541
22307
  }
22542
22308
 
22543
22309
  function dispatchPrompt(text) {
22310
+ var normalized = text.trim().toLowerCase();
22311
+ if (normalized === "/resume" || normalized === "resume") {
22312
+ showResumePicker();
22313
+ return;
22314
+ }
22544
22315
  if (text === "/login" || text === "login") {
22545
22316
  startLogin();
22546
22317
  return;
@@ -22591,6 +22362,29 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22591
22362
  resetUsage();
22592
22363
  }
22593
22364
 
22365
+ function deleteSession(id, title) {
22366
+ if (!id) return;
22367
+ var name = title || "this chat";
22368
+ if (!window.confirm("Delete " + name + "? This cannot be undone.")) return;
22369
+ var path = "/api/sessions/" + encodeURIComponent(id);
22370
+ api("DELETE", path).then(function (res) {
22371
+ if (res.ok) return res;
22372
+ if (res.status !== 404 && res.status !== 405) return res;
22373
+ return api("POST", "/api/sessions/delete", { id: id });
22374
+ }).then(function (res) {
22375
+ if (!res || !res.ok) {
22376
+ if (!res) return;
22377
+ return readError(res, "Session deletion is not available in this build.").then(function (msg) { addBlock("alert", msg); });
22378
+ }
22379
+ return api("GET", "/api/snapshot").then(function (fresh) {
22380
+ if (!fresh.ok) return;
22381
+ return fresh.json().then(function (body) {
22382
+ if (body.sessions) renderSessions(body.sessions, body.session_id || body.id || activeSessionId);
22383
+ });
22384
+ });
22385
+ }).catch(function () { addBlock("alert", "Could not delete that chat."); });
22386
+ }
22387
+
22594
22388
  function renderSessions(list, activeId) {
22595
22389
  allSessions = list || allSessions;
22596
22390
  if (!sessionsEl) return;
@@ -22599,20 +22393,104 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22599
22393
  (allSessions || []).filter(function (item) {
22600
22394
  return !q || String(item.title || "").toLowerCase().indexOf(q) >= 0;
22601
22395
  }).forEach(function (item) {
22396
+ var row = document.createElement("div");
22397
+ row.className = "session-row" + (item.id === activeId ? " on" : "");
22602
22398
  var btn = document.createElement("button");
22603
22399
  btn.type = "button";
22604
- btn.className = "session-item" + (item.id === activeId ? " on" : "");
22400
+ btn.className = "session-item";
22605
22401
  btn.textContent = item.title || "Session";
22606
22402
  btn.title = item.title || item.id;
22607
22403
  btn.addEventListener("click", function () {
22608
22404
  if (item.id === activeSessionId) return;
22405
+ api("POST", "/api/sessions/select", { id: item.id }).catch(function () { addBlock("alert", "Could not open that chat."); });
22406
+ if (window.innerWidth <= 760) { layout.rail = false; applyLayout(); }
22407
+ });
22408
+ btn.addEventListener("dblclick", function (e) {
22409
+ e.preventDefault();
22410
+ e.stopPropagation();
22411
+ var next = window.prompt("Rename chat", item.title || "Session");
22412
+ if (!next) return;
22413
+ renameSession(item.id, next.trim());
22414
+ });
22415
+ var del = document.createElement("button");
22416
+ del.type = "button";
22417
+ del.className = "session-delete";
22418
+ del.title = "Delete chat";
22419
+ del.setAttribute("aria-label", "Delete " + (item.title || "chat"));
22420
+ 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>";
22421
+ del.addEventListener("click", function (e) { e.stopPropagation(); deleteSession(item.id, item.title || "this chat"); });
22422
+ row.appendChild(btn); row.appendChild(del); sessionsEl.appendChild(row);
22423
+ });
22424
+ activeSessionId = activeId || activeSessionId;
22425
+ }
22426
+
22427
+ function renameSession(id, title) {
22428
+ if (!id || !title) return;
22429
+ api("POST", "/api/sessions/rename", { id: id, title: title }).then(function (res) {
22430
+ if (!res.ok) return readError(res, "Could not rename that chat.").then(function (msg) { addBlock("alert", msg); });
22431
+ return res.json().then(function (body) {
22432
+ if (body.sessions) renderSessions(body.sessions, body.id || activeSessionId);
22433
+ if (body.title) setSessionTitle(body.title);
22434
+ });
22435
+ }).catch(function () { addBlock("alert", "Could not rename that chat."); });
22436
+ }
22437
+
22438
+ function showResumePicker() {
22439
+ showFeed();
22440
+ turnEl = null;
22441
+ assistantEl = null;
22442
+ var wrap = document.createElement("div");
22443
+ wrap.className = "resume-picker";
22444
+ var head = document.createElement("div");
22445
+ head.className = "resume-head";
22446
+ var title = document.createElement("strong");
22447
+ title.textContent = "Resume a chat";
22448
+ var hint = document.createElement("span");
22449
+ hint.textContent = String((allSessions || []).length) + " chats";
22450
+ head.appendChild(title);
22451
+ head.appendChild(hint);
22452
+ wrap.appendChild(head);
22453
+ var list = document.createElement("div");
22454
+ list.className = "resume-list";
22455
+ var sessions = (allSessions || []).filter(function (item) { return item.id !== activeSessionId; });
22456
+ if (!sessions.length) {
22457
+ var empty = document.createElement("div");
22458
+ empty.className = "resume-empty";
22459
+ empty.textContent = "No other chats yet.";
22460
+ list.appendChild(empty);
22461
+ }
22462
+ sessions.forEach(function (item) {
22463
+ var row = document.createElement("button");
22464
+ row.type = "button";
22465
+ row.className = "resume-chat";
22466
+ var copy = document.createElement("span");
22467
+ copy.className = "resume-copy";
22468
+ var chatTitle = document.createElement("strong");
22469
+ chatTitle.textContent = item.title || "Untitled chat";
22470
+ copy.appendChild(chatTitle);
22471
+ if (item.updated_at || item.created_at) {
22472
+ var time = document.createElement("span");
22473
+ var value = item.updated_at || item.created_at;
22474
+ try {
22475
+ time.textContent = new Date(value).toLocaleString([], { dateStyle: "medium", timeStyle: "short" });
22476
+ } catch (e) { time.textContent = ""; }
22477
+ copy.appendChild(time);
22478
+ }
22479
+ var arrow = document.createElement("span");
22480
+ arrow.className = "resume-arrow";
22481
+ arrow.textContent = "\u203A";
22482
+ row.appendChild(copy);
22483
+ row.appendChild(arrow);
22484
+ row.addEventListener("click", function () {
22609
22485
  api("POST", "/api/sessions/select", { id: item.id }).catch(function () {
22610
- addBlock("alert", "Could not open that session.");
22486
+ addBlock("alert", "Could not resume that chat.");
22611
22487
  });
22612
22488
  });
22613
- sessionsEl.appendChild(btn);
22489
+ list.appendChild(row);
22614
22490
  });
22615
- activeSessionId = activeId || activeSessionId;
22491
+ wrap.appendChild(list);
22492
+ feedEl.appendChild(wrap);
22493
+ scrollMain();
22616
22494
  }
22617
22495
 
22618
22496
  function replayEvents(events) {
@@ -22640,12 +22518,14 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22640
22518
  showFeed();
22641
22519
  turnEl = null;
22642
22520
  assistantEl = null;
22521
+ var copy = text == null ? "" : String(text);
22522
+ if (className === "note") {
22523
+ var last = feedEl.lastElementChild;
22524
+ if (last && last.classList.contains("note") && last.textContent === copy) return last;
22525
+ }
22643
22526
  var node = document.createElement("div");
22644
22527
  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
- }
22528
+ node.textContent = copy;
22649
22529
  feedEl.appendChild(node);
22650
22530
  scrollMain();
22651
22531
  return node;
@@ -22681,112 +22561,165 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22681
22561
  scrollMain();
22682
22562
  }
22683
22563
 
22684
- function addTool(name, phase, detail) {
22685
- if (name === "critique_task") return;
22564
+ function activityRoot() {
22686
22565
  if (!turnEl) {
22687
22566
  showFeed();
22688
22567
  turnEl = document.createElement("div");
22689
22568
  turnEl.className = "turn";
22690
22569
  feedEl.appendChild(turnEl);
22691
22570
  }
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);
22571
+ var root = turnEl.querySelector(".activity");
22572
+ if (!root) {
22573
+ root = document.createElement("div");
22574
+ root.className = "activity";
22575
+ if (assistantEl) turnEl.insertBefore(root, assistantEl);
22576
+ else turnEl.appendChild(root);
22714
22577
  }
22578
+ return root;
22579
+ }
22580
+
22581
+ function humanToolName(name) {
22582
+ return String(name || "tool").replace(/_/g, " ");
22583
+ }
22584
+
22585
+ function addTool(name, phase, detail) {
22586
+ if (name === "critique_task") return;
22587
+ var root = activityRoot();
22588
+ var node = document.createElement("details");
22589
+ var state = /fail|error|denied/i.test(String(phase || "")) ? "failed" : /start|run|progress/i.test(String(phase || "")) ? "running" : "done";
22590
+ node.className = "tool-event " + state;
22591
+ if (detail) node.open = false;
22592
+ var summary = document.createElement("summary");
22593
+ var dot = document.createElement("span"); dot.className = "tool-dot";
22594
+ var label = document.createElement("span"); label.className = "tool-name"; label.textContent = humanToolName(name);
22595
+ var p = document.createElement("span"); p.className = "tool-phase"; p.textContent = phase || "";
22596
+ summary.appendChild(dot); summary.appendChild(label); if (phase) summary.appendChild(p);
22597
+ node.appendChild(summary);
22598
+ if (detail) { var body = document.createElement("div"); body.className = "tool-detail"; body.textContent = detail; node.appendChild(body); }
22599
+ root.appendChild(node);
22600
+ scheduleWorkspaceRefresh();
22715
22601
  scrollMain();
22716
22602
  }
22717
22603
 
22718
- function addThink(text) {
22719
- if (!turnEl) {
22720
- showFeed();
22721
- turnEl = document.createElement("div");
22722
- turnEl.className = "turn";
22723
- feedEl.appendChild(turnEl);
22604
+ function finishThinkingTimer() {
22605
+ if (thinkingTimer) { clearInterval(thinkingTimer); thinkingTimer = null; }
22606
+ var node = turnEl && turnEl.querySelector(".think");
22607
+ if (node && thinkingStartedAt && !applyingSnapshot) {
22608
+ var s = node.querySelector("summary span:last-child");
22609
+ if (s) s.textContent = "Thinking \xB7 " + Math.max(1, Math.round((Date.now() - thinkingStartedAt) / 1000)) + "s";
22724
22610
  }
22725
- var node = turnEl.querySelector(".think");
22611
+ thinkingStartedAt = 0;
22612
+ }
22613
+
22614
+ function addThink(text) {
22615
+ var root = activityRoot();
22616
+ var node = root.querySelector(".think");
22726
22617
  if (!node) {
22727
22618
  node = document.createElement("details");
22728
22619
  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 || "");
22620
+ var summary = document.createElement("summary");
22621
+ summary.innerHTML = "<span class=\\"tool-dot\\"></span><span>Thinking</span>";
22622
+ var body = document.createElement("div");
22623
+ node.appendChild(summary); node.appendChild(body); root.appendChild(node);
22624
+ if (!applyingSnapshot) {
22625
+ thinkingStartedAt = Date.now();
22626
+ thinkingTimer = setInterval(function () {
22627
+ if (!thinkingStartedAt) return;
22628
+ var label = summary.querySelector("span:last-child");
22629
+ if (label) label.textContent = "Thinking \xB7 " + Math.max(1, Math.round((Date.now() - thinkingStartedAt) / 1000)) + "s";
22630
+ }, 1000);
22631
+ }
22632
+ }
22633
+ var bodyEl = node.querySelector("div");
22634
+ if (bodyEl) bodyEl.textContent = (bodyEl.textContent || "") + (text || "");
22734
22635
  scrollMain();
22735
22636
  }
22736
22637
 
22737
22638
  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();
22639
+ tokensIn = 0; tokensOut = 0; tokensReason = 0; contextUsed = 0;
22640
+ lastInput = 0; lastOutput = 0; lastReason = 0; costUsd = 0; usageHistory = [];
22641
+ renderUsagePanel(studioCosts);
22752
22642
  }
22753
22643
 
22754
22644
  function addUsage(ev) {
22755
22645
  lastInput = Number(ev.input_tokens || 0);
22756
22646
  lastOutput = Number(ev.output_tokens || 0);
22757
22647
  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);
22648
+ tokensIn += lastInput; tokensOut += lastOutput; tokensReason += lastReason;
22649
+ var eventCost = Number(ev.cost_usd || 0);
22650
+ if (!eventCost) eventCost = estimateUsageCostUsd(lastInput, lastOutput, lastReason);
22651
+ costUsd += eventCost;
22762
22652
  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) : "");
22653
+ usageHistory.push({
22654
+ input: lastInput, output: lastOutput, reasoning: lastReason,
22655
+ cost: Number(ev.cost_usd || 0), model: ev.model || "", phase: ev.source || ev.phase || "author", at: Date.now()
22656
+ });
22657
+ if (usageHistory.length > 80) usageHistory = usageHistory.slice(-80);
22658
+ renderUsagePanel(studioCosts);
22659
+ }
22660
+
22661
+ function updateContextRing() { renderUsagePanel(studioCosts); }
22662
+
22663
+ function fmtNum(value) { return Number(value || 0).toLocaleString(); }
22664
+ function fmtCost(value) { return "$" + Number(value || 0).toFixed(Number(value || 0) < 1 ? 4 : 2); }
22665
+
22666
+ function estimateUsageCostUsd(input, output, reasoning) {
22667
+ return Number(input || 0) * 0.0000001 + Number(output || 0) * 0.0000004 + Number(reasoning || 0) * 0.0000002;
22668
+ }
22669
+
22670
+ function renderBars(targetId, rows) {
22671
+ var target = document.getElementById(targetId);
22672
+ if (!target) return;
22673
+ target.innerHTML = "";
22674
+ if (!rows || !rows.length) { target.innerHTML = "<div class=\\"usage-empty\\" style=\\"height:52px\\">No data yet</div>"; return; }
22675
+ var max = Math.max.apply(null, rows.map(function (r) { return r.value; }).concat([1]));
22676
+ rows.slice(0, 10).forEach(function (row) {
22677
+ var el = document.createElement("div"); el.className = "break-row";
22678
+ var name = document.createElement("span"); name.textContent = row.label;
22679
+ var track = document.createElement("div"); track.className = "break-track";
22680
+ var fill = document.createElement("div"); fill.className = "break-fill"; fill.style.width = Math.max(2, row.value / max * 100) + "%"; track.appendChild(fill);
22681
+ var val = document.createElement("span"); val.className = "break-val"; val.textContent = fmtNum(row.value);
22682
+ el.appendChild(name); el.appendChild(track); el.appendChild(val); target.appendChild(el);
22683
+ });
22684
+ }
22685
+
22686
+ function renderUsagePanel(costs) {
22687
+ var totalInput = costs && Number(costs.total_input || 0) || tokensIn;
22688
+ var totalOutput = costs && Number(costs.total_output || 0) || tokensOut;
22689
+ var ui = document.getElementById("usage-input"); if (ui) ui.textContent = fmtNum(totalInput);
22690
+ var uo = document.getElementById("usage-output"); if (uo) uo.textContent = fmtNum(totalOutput);
22691
+ var ur = document.getElementById("usage-reason"); if (ur) ur.textContent = fmtNum(tokensReason);
22692
+ var reported = costUsd || (costs && Number(costs.total_cost_usd || 0)) || 0;
22693
+ var display = reported > 0 ? reported : (costs && Number(costs.estimated_cost_usd || 0)) || estimateUsageCostUsd(totalInput, totalOutput, tokensReason);
22694
+ var estimated = reported <= 0 && display > 0;
22695
+ var uc = document.getElementById("usage-cost");
22696
+ if (uc) uc.textContent = (estimated ? "~" : "") + fmtCost(display);
22697
+ var chart = document.getElementById("usage-chart");
22698
+ if (chart) {
22699
+ if (!usageHistory.length) chart.innerHTML = "<div class=\\"usage-empty\\">Usage appears here as model calls complete.</div>";
22700
+ else {
22701
+ var vals = usageHistory.map(function (r) { return r.input + r.output + r.reasoning; });
22702
+ var max = Math.max.apply(null, vals.concat([1]));
22703
+ var w = 640, h = 150, gap = 2, bw = Math.max(2, (w - (vals.length - 1) * gap) / vals.length);
22704
+ 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("");
22705
+ 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>";
22706
+ }
22707
+ }
22708
+ var phaseRows = [];
22709
+ 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) }); });
22710
+ else {
22711
+ var phase = {}; usageHistory.forEach(function (r) { var k=r.phase||"author"; phase[k]=(phase[k]||0)+r.input+r.output+r.reasoning; });
22712
+ Object.keys(phase).forEach(function (k) { phaseRows.push({label:k,value:phase[k]}); });
22767
22713
  }
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";
22714
+ renderBars("usage-phase", phaseRows);
22715
+ var modelRows = [];
22716
+ 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)}); });
22717
+ else {
22718
+ var models={}; usageHistory.forEach(function(r){var k=r.model||"current model";models[k]=(models[k]||0)+r.input+r.output+r.reasoning;});
22719
+ Object.keys(models).forEach(function(k){modelRows.push({label:k.replace(/^openrouter\\//,""),value:models[k]});});
22720
+ }
22721
+ modelRows.sort(function(a,b){return b.value-a.value;});
22722
+ renderBars("usage-model", modelRows);
22790
22723
  }
22791
22724
 
22792
22725
  function addAgent(detail, phase) {
@@ -22816,101 +22749,186 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
22816
22749
  if (btn) btn.innerHTML = "\u2387 " + esc(currentBranch) + " <span class=\\"caret\\">\u25BE</span>";
22817
22750
  }
22818
22751
 
22752
+ function normalizeChangeFiles(data) {
22753
+ var files = (data && data.files) || [];
22754
+ if ((!files || !files.length) && data && data.changed_paths && data.changed_paths.length) {
22755
+ files = data.changed_paths.map(function (path) { return { path: path, added: 0, deleted: 0, kind: "modified" }; });
22756
+ }
22757
+ return files || [];
22758
+ }
22759
+
22760
+ function renderPatchInto(container, patch, path) {
22761
+ var head = document.createElement("div");
22762
+ head.className = "diff-file-head";
22763
+ head.textContent = path;
22764
+ container.appendChild(head);
22765
+ var body = document.createElement("div");
22766
+ body.className = "diff-patch";
22767
+ var patchStr = String(patch || "");
22768
+ if (!patchStr.trim()) {
22769
+ var empty = document.createElement("div");
22770
+ empty.className = "hunk";
22771
+ empty.textContent = "No textual diff available.";
22772
+ body.appendChild(empty);
22773
+ container.appendChild(body);
22774
+ return;
22775
+ }
22776
+ var oldLn = 0;
22777
+ var newLn = 0;
22778
+ patchStr.split("\\n").forEach(function (line) {
22779
+ if (line.indexOf("@@") === 0) {
22780
+ var hunk = line.match(/@@ -(\\d+)(?:,\\d+)? \\+(\\d+)/);
22781
+ if (hunk) { oldLn = Number(hunk[1]) - 1; newLn = Number(hunk[2]) - 1; }
22782
+ var hunkEl = document.createElement("div");
22783
+ hunkEl.className = "hunk";
22784
+ hunkEl.textContent = line;
22785
+ body.appendChild(hunkEl);
22786
+ return;
22787
+ }
22788
+ if (line.indexOf("diff ") === 0 || line.indexOf("index ") === 0 || line.indexOf("---") === 0 || line.indexOf("+++") === 0) {
22789
+ var meta = document.createElement("div");
22790
+ meta.className = "hunk";
22791
+ meta.textContent = line;
22792
+ body.appendChild(meta);
22793
+ return;
22794
+ }
22795
+ var kind = "ctx";
22796
+ var left = "";
22797
+ var right = "";
22798
+ if (line.charAt(0) === "+") { kind = "add"; newLn += 1; right = String(newLn); }
22799
+ else if (line.charAt(0) === "-") { kind = "del"; oldLn += 1; left = String(oldLn); }
22800
+ else { oldLn += 1; newLn += 1; left = String(oldLn); right = String(newLn); }
22801
+ var row = document.createElement("div");
22802
+ row.className = "row " + kind;
22803
+ var a = document.createElement("span"); a.className = "ln"; a.textContent = left;
22804
+ var b = document.createElement("span"); b.className = "ln"; b.textContent = right;
22805
+ var code = document.createElement("span"); code.className = "code"; code.textContent = line;
22806
+ row.appendChild(a); row.appendChild(b); row.appendChild(code);
22807
+ body.appendChild(row);
22808
+ });
22809
+ container.appendChild(body);
22810
+ }
22811
+
22812
+ function loadAllDiffs(files) {
22813
+ var diffEl = document.getElementById("diff");
22814
+ var view = document.getElementById("file-view");
22815
+ var preview = document.getElementById("preview");
22816
+ var title = document.getElementById("diff-title");
22817
+ var back = document.getElementById("all-changes");
22818
+ if (back) back.hidden = true;
22819
+ if (title) title.textContent = files.length + (files.length === 1 ? " changed file" : " changed files");
22820
+ if (diffEl) { diffEl.hidden = false; diffEl.innerHTML = ""; }
22821
+ if (view) view.hidden = true;
22822
+ if (preview) preview.hidden = true;
22823
+ if (!files || !files.length) {
22824
+ if (diffEl) diffEl.innerHTML = "<div class=\\"diff-loading\\">No changed files.</div>";
22825
+ return;
22826
+ }
22827
+ var loading = document.createElement("div");
22828
+ loading.className = "diff-loading";
22829
+ loading.textContent = "Loading diffs\u2026";
22830
+ if (diffEl) diffEl.appendChild(loading);
22831
+ var paths = files.map(function (f) { return f.path; });
22832
+ Promise.all(paths.map(function (path) {
22833
+ return api("GET", "/api/changes?path=" + encodeURIComponent(path))
22834
+ .then(function (res) { return res.json().then(function (body) { return { path: path, patch: body.patch }; }); })
22835
+ .catch(function () { return { path: path, patch: "" }; });
22836
+ })).then(function (results) {
22837
+ if (!diffEl) return;
22838
+ diffEl.innerHTML = "";
22839
+ results.forEach(function (result) {
22840
+ var section = document.createElement("section");
22841
+ section.className = "diff-file";
22842
+ renderPatchInto(section, result.patch || "No textual diff available.", result.path);
22843
+ diffEl.appendChild(section);
22844
+ });
22845
+ });
22846
+ }
22847
+
22848
+ function loadFileContent(path, btn) {
22849
+ selectedPath = path;
22850
+ document.querySelectorAll(".tree button").forEach(function (el) {
22851
+ el.classList.toggle("on", el.getAttribute("data-path") === path);
22852
+ });
22853
+ if (btn) btn.classList.add("on");
22854
+ var title = document.getElementById("diff-title");
22855
+ var diffEl = document.getElementById("diff");
22856
+ var view = document.getElementById("file-view");
22857
+ var preview = document.getElementById("preview");
22858
+ var back = document.getElementById("all-changes");
22859
+ if (back) back.hidden = false;
22860
+ if (title) title.textContent = path;
22861
+ if (diffEl) diffEl.hidden = true;
22862
+ if (preview) preview.hidden = true;
22863
+ if (view) {
22864
+ view.hidden = false;
22865
+ view.textContent = "Loading\u2026";
22866
+ }
22867
+ var pane = document.getElementById("changes-pane");
22868
+ if (pane) pane.classList.add("open");
22869
+ api("GET", "/api/file?path=" + encodeURIComponent(path))
22870
+ .then(function (res) {
22871
+ if (!res.ok) throw new Error("Could not load file");
22872
+ return res.json();
22873
+ })
22874
+ .then(function (file) {
22875
+ if (view) {
22876
+ view.hidden = false;
22877
+ view.textContent = String(file.text || "");
22878
+ }
22879
+ if (preview && /\\.html?$/i.test(path)) {
22880
+ preview.hidden = false;
22881
+ preview.srcdoc = String(file.text || "");
22882
+ }
22883
+ })
22884
+ .catch(function () {
22885
+ if (view) view.textContent = "Could not load " + path;
22886
+ });
22887
+ }
22888
+
22819
22889
  function renderChanges(data) {
22820
22890
  var list = document.getElementById("change-list");
22821
22891
  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;
22892
+ var files = normalizeChangeFiles(data);
22893
+ var computedAdded = files.reduce(function (n, f) { return n + Number(f.added || 0); }, 0);
22894
+ var computedDeleted = files.reduce(function (n, f) { return n + Number(f.deleted || 0); }, 0);
22895
+ var added = Number(data && data.added || 0) || computedAdded;
22896
+ var deleted = Number(data && data.deleted || 0) || computedDeleted;
22825
22897
  var branch = data && (data.branch || data.text) ? (data.branch || data.text) : currentBranch;
22826
22898
  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;
22899
+ if (sum) sum.textContent = branch + " \xB7 " + files.length + (files.length === 1 ? " changed file" : " changed files") + ((added || deleted) ? " \xB7 +" + added + " \u2212" + deleted : "");
22900
+ var count = document.getElementById("changes-count"); if (count) count.textContent = String(files.length);
22901
+ var plus = document.getElementById("changes-plus"); var minus = document.getElementById("changes-minus");
22902
+ if (plus) plus.textContent = "+" + added; if (minus) minus.textContent = "\u2212" + deleted;
22903
+ 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
22904
  fileKinds = {};
22835
22905
  files.forEach(function (file) { fileKinds[file.path] = file.kind || (file.untracked ? "untracked" : "modified"); });
22836
22906
  if (list) {
22837
22907
  list.innerHTML = "";
22838
22908
  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);
22909
+ var btn = document.createElement("button"); btn.type = "button"; btn.className = "change-file";
22910
+ btn.innerHTML = "<span></span><span><span class=\\"plus\\">+" + Number(file.added || 0) + "</span> <span class=\\"minus\\">\u2212" + Number(file.deleted || 0) + "</span></span>";
22911
+ btn.querySelector("span").textContent = file.path; btn.addEventListener("click", function () { loadFileContent(file.path, btn); }); list.appendChild(btn);
22846
22912
  });
22847
22913
  }
22848
22914
  setPaths(files.map(function (file) { return file.path; }));
22849
22915
  loadTree();
22916
+ if (!selectedPath) {
22917
+ loadAllDiffs(files);
22918
+ }
22850
22919
  }
22851
22920
 
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
- }
22921
+ function scheduleWorkspaceRefresh() {
22922
+ if (workspaceRefreshTimer) clearTimeout(workspaceRefreshTimer);
22923
+ workspaceRefreshTimer = setTimeout(function () { refreshWorkspaceSnapshot(false); }, 450);
22924
+ }
22925
+
22926
+ function refreshWorkspaceSnapshot(force) {
22927
+ if (workspaceRefreshTimer) { clearTimeout(workspaceRefreshTimer); workspaceRefreshTimer = null; }
22928
+ return api("GET", "/api/snapshot").then(function (res) { return res.ok ? res.json() : null; }).then(function (s) {
22929
+ if (!s) return;
22930
+ if (s.files || s.changed_paths) renderChanges(s);
22931
+ if (force && s.sessions) renderSessions(s.sessions, s.active_session_id || activeSessionId);
22914
22932
  }).catch(function () {});
22915
22933
  }
22916
22934
 
@@ -23043,6 +23061,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23043
23061
  break;
23044
23062
  case "busy":
23045
23063
  setBusy(ev.busy);
23064
+ if (!ev.busy) scheduleWorkspaceRefresh();
23046
23065
  break;
23047
23066
  case "ended":
23048
23067
  setBusy(false);
@@ -23069,6 +23088,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23069
23088
  if (thinkingEl && s.thinking_level) thinkingEl.value = s.thinking_level;
23070
23089
  syncPick("mode");
23071
23090
  syncPick("autonomy");
23091
+ syncAutonomyVisual();
23072
23092
  syncPick("thinking");
23073
23093
  syncPick("review-depth");
23074
23094
  syncPick("review-lens");
@@ -23080,7 +23100,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23080
23100
  if (s.events && s.events.length) replayEvents(s.events);
23081
23101
  else if (s.last_review_text) setReview(s.last_review_text);
23082
23102
  if (s.pending_exec) showExec(s.pending_exec);
23083
- if (s.files) renderChanges(s);
23103
+ if (s.files || s.changed_paths) renderChanges(s);
23084
23104
  if (s.ended) {
23085
23105
  setStatus("Session ended", "err");
23086
23106
  addBlock("note", "Session ended \xB7 " + s.ended);
@@ -23134,56 +23154,109 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23134
23154
  });
23135
23155
  }
23136
23156
 
23157
+ function cleanSkillDescription(s) {
23158
+ var desc = String(s && s.description || "").trim();
23159
+ var constraint = String(s && s.constraint || "").trim();
23160
+ 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 "";
23161
+ return desc;
23162
+ }
23163
+
23164
+ function renderSkills(rows) {
23165
+ var skills = document.getElementById("skill-list");
23166
+ if (!skills) return;
23167
+ skills.innerHTML = "";
23168
+ (rows || []).forEach(function (s) {
23169
+ var row = document.createElement("div"); row.className = "skill-row";
23170
+ var head = document.createElement("div"); head.className = "skill-head";
23171
+ var name = document.createElement("b"); name.textContent = s.name || s.id || "Skill";
23172
+ var source = document.createElement("span"); source.className = "skill-source"; source.textContent = s.source || "skill";
23173
+ head.appendChild(name); head.appendChild(source); row.appendChild(head);
23174
+ 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);
23175
+ if (s.origin) { var origin = document.createElement("div"); origin.className = "skill-origin"; origin.textContent = s.origin; row.appendChild(origin); }
23176
+ skills.appendChild(row);
23177
+ });
23178
+ if (!rows || !rows.length) skills.innerHTML = "<div class=\\"settings-note\\">No skills discovered.</div>";
23179
+ }
23180
+
23181
+ function renderAudit(rows) {
23182
+ var audit = document.getElementById("audit-panel"); if (!audit) return; audit.innerHTML = "";
23183
+ (rows || []).slice().reverse().slice(0, 80).forEach(function (a) {
23184
+ var row = document.createElement("div"); row.className = "audit-row";
23185
+ var at = document.createElement("span"); at.textContent = a.at ? new Date(a.at).toLocaleString() : "";
23186
+ var decision = document.createElement("span"); decision.textContent = (a.decision || "") + (a.scope ? " \xB7 " + a.scope : "");
23187
+ var code = document.createElement("code"); code.textContent = a.preview || a.purpose || "";
23188
+ row.appendChild(at); row.appendChild(decision); row.appendChild(code); audit.appendChild(row);
23189
+ });
23190
+ if (!rows || !rows.length) audit.innerHTML = "<div class=\\"settings-note\\">No approval decisions yet.</div>";
23191
+ }
23192
+
23137
23193
  function loadStudio() {
23138
23194
  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;
23195
+ var author = document.getElementById("studio-author"); var review = document.getElementById("studio-review");
23196
+ if (author && modelEl) { author.innerHTML = modelEl.innerHTML; author.value = modelEl.value; }
23142
23197
  if (review && modelEl) review.innerHTML = modelEl.innerHTML;
23143
23198
  if (body.badges) {
23199
+ if (review && body.badges.review && body.badges.review.id) review.value = body.badges.review.id;
23144
23200
  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.";
23201
+ 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
23202
  }
23149
- var skills = document.getElementById("skill-list");
23150
23203
  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);
23204
+ renderSkills(body.skills || []);
23205
+ studioCosts = body.costs || studioCosts;
23206
+ renderUsagePanel(studioCosts);
23207
+ renderAudit(body.audit || []);
23160
23208
  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
- }
23209
+ 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(""); }
23210
+ var left = document.getElementById("compare-left"); var right = document.getElementById("compare-right");
23211
+ 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
23212
  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");
23213
+ 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); });
23214
+ syncPick("studio-author"); syncPick("studio-review"); syncPick("key-kind");
23215
+ trapScrollableMenus();
23184
23216
  }).catch(function () {});
23185
23217
  }
23186
23218
 
23219
+ function openSheet(id) { var el = document.getElementById(id); if (el) el.className = "sheet open"; }
23220
+ function closeSheet(id) { var el = document.getElementById(id); if (el) el.className = "sheet"; }
23221
+
23222
+ function renderCommandBrowser() {
23223
+ var list = document.getElementById("command-list"); var search = document.getElementById("command-search");
23224
+ if (!list) return;
23225
+ var q = String(search && search.value || ""); list.innerHTML = "";
23226
+ rankSlashItems(slashCatalog(), q).slice(0, 80).forEach(function (item) {
23227
+ var row = document.createElement("button"); row.type = "button"; row.className = "command-row";
23228
+ var code = document.createElement("span"); code.className = "command-code"; code.textContent = item.value;
23229
+ var desc = document.createElement("span"); desc.className = "command-desc"; desc.textContent = item.description || item.label || "";
23230
+ var kind = document.createElement("span"); kind.className = "command-kind"; kind.textContent = item.kind;
23231
+ row.appendChild(code); row.appendChild(desc); row.appendChild(kind);
23232
+ row.addEventListener("click", function () { closeSheet("command-sheet"); inputEl.value = item.value + " "; inputEl.focus(); autosizeInput(); });
23233
+ list.appendChild(row);
23234
+ });
23235
+ }
23236
+
23237
+ function showCommands() { closePicks(); renderCommandBrowser(); openSheet("command-sheet"); var q = document.getElementById("command-search"); if (q) setTimeout(function(){ q.focus(); }, 0); }
23238
+
23239
+ function selectSettingsTab(name) {
23240
+ document.querySelectorAll("[data-settings-tab]").forEach(function (b) { b.classList.toggle("on", b.getAttribute("data-settings-tab") === name); });
23241
+ document.querySelectorAll("[data-settings-panel]").forEach(function (p) { p.classList.toggle("on", p.getAttribute("data-settings-panel") === name); });
23242
+ if (name === "usage") renderUsagePanel(studioCosts);
23243
+ }
23244
+
23245
+ function autosizeInput() { inputEl.style.height = "auto"; inputEl.style.height = Math.min(190, Math.max(44, inputEl.scrollHeight)) + "px"; }
23246
+
23247
+ function trapWheel(el) {
23248
+ if (!el || el.dataset.wheelTrap === "1") return;
23249
+ el.dataset.wheelTrap = "1";
23250
+ el.addEventListener("wheel", function (e) {
23251
+ e.stopPropagation();
23252
+ var top = el.scrollTop <= 0; var bottom = Math.ceil(el.scrollTop + el.clientHeight) >= el.scrollHeight;
23253
+ if ((e.deltaY < 0 && top) || (e.deltaY > 0 && bottom)) e.preventDefault();
23254
+ }, { passive: false });
23255
+ }
23256
+ function trapScrollableMenus() {
23257
+ [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);
23258
+ }
23259
+
23187
23260
  function connect() {
23188
23261
  if (es) {
23189
23262
  es.close();
@@ -23219,7 +23292,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23219
23292
 
23220
23293
  function submitText(raw, steerNow) {
23221
23294
  var text = (raw == null ? inputEl.value : raw).trim();
23222
- if (raw == null && text) inputEl.value = "";
23295
+ if (raw == null && text) { inputEl.value = ""; autosizeInput(); }
23223
23296
  if (!text) {
23224
23297
  if (steerNow) flushQueue(true);
23225
23298
  return;
@@ -23241,6 +23314,18 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23241
23314
  });
23242
23315
  }
23243
23316
 
23317
+ on("commands-open", "click", function () { var pop=document.getElementById("cmd-pop"); if(pop) pop.classList.remove("open"); showCommands(); });
23318
+ on("empty-commands", "click", showCommands);
23319
+ on("close-commands", "click", function () { closeSheet("command-sheet"); });
23320
+ var commandSearch = document.getElementById("command-search");
23321
+ if (commandSearch) commandSearch.addEventListener("input", renderCommandBrowser);
23322
+ document.querySelectorAll("[data-starter]").forEach(function (btn) { btn.addEventListener("click", function () { inputEl.value = btn.getAttribute("data-starter") || ""; autosizeInput(); inputEl.focus(); }); });
23323
+ document.querySelectorAll("[data-settings-tab]").forEach(function (btn) { btn.addEventListener("click", function () { selectSettingsTab(btn.getAttribute("data-settings-tab")); }); });
23324
+ on("rail-settings", "click", function () { loadStudio(); openSheet("studio-sheet"); });
23325
+ on("close-legend", "click", function () { closeSheet("legend-sheet"); });
23326
+ inputEl.addEventListener("input", autosizeInput);
23327
+ trapScrollableMenus();
23328
+
23244
23329
  sendEl.addEventListener("click", function () { submitText(null, false); });
23245
23330
  on("queue-send", "click", function () { flushQueue(true); });
23246
23331
  on("queue-clear", "click", function () { promptQueue = []; renderQueue(); });
@@ -23256,6 +23341,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23256
23341
  modelMenu.className = "open";
23257
23342
  modelOpen.setAttribute("aria-expanded", "true");
23258
23343
  renderModelList();
23344
+ trapWheel(document.getElementById("model-list"));
23259
23345
  if (modelFilter) modelFilter.focus();
23260
23346
  }
23261
23347
  });
@@ -23277,11 +23363,28 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23277
23363
  if (thinkingEl) thinkingEl.addEventListener("change", function () {
23278
23364
  saveSetting({ thinking_level: thinkingEl.value });
23279
23365
  });
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.");
23366
+ function createNewSession() {
23367
+ api("POST", "/api/sessions", {})
23368
+ .then(function (res) {
23369
+ if (!res.ok) {
23370
+ return readError(res, "Could not start a new session.").then(function (msg) { addBlock("alert", msg); });
23371
+ }
23372
+ if (window.innerWidth <= 760) {
23373
+ layout.rail = false;
23374
+ applyLayout();
23375
+ }
23376
+ inputEl.focus();
23377
+ })
23378
+ .catch(function () { addBlock("alert", "Could not start a new session."); });
23379
+ }
23380
+ on("new-session", "click", createNewSession);
23381
+ on("top-new-session", "click", createNewSession);
23382
+ on("all-changes", "click", function () {
23383
+ selectedPath = "";
23384
+ var back = document.getElementById("all-changes");
23385
+ if (back) back.hidden = true;
23386
+ refreshWorkspaceSnapshot(false).then(function () {
23387
+ document.querySelectorAll(".tree button.on").forEach(function (el) { el.classList.remove("on"); });
23285
23388
  });
23286
23389
  });
23287
23390
  on("fork-session", "click", function () {
@@ -23294,6 +23397,11 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23294
23397
  var searchEl = document.getElementById("session-search");
23295
23398
  if (searchEl) searchEl.addEventListener("input", function () { renderSessions(allSessions, activeSessionId); });
23296
23399
 
23400
+ function syncAutonomyVisual() {
23401
+ var open = document.getElementById("autonomy-open"); var sel = document.getElementById("autonomy");
23402
+ if (open && sel) open.classList.toggle("auto", sel.value === "auto");
23403
+ }
23404
+
23297
23405
  function renderChips() {
23298
23406
  var el = document.getElementById("ref-chips");
23299
23407
  if (!el) return;
@@ -23359,21 +23467,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23359
23467
  return;
23360
23468
  }
23361
23469
  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
- }
23470
+ loadFileContent(node.path, btn);
23377
23471
  });
23378
23472
  into.appendChild(btn);
23379
23473
  if (node.dir && !collapsed) renderTreeNodes(node.children || [], depth + 1, into);
@@ -23452,7 +23546,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23452
23546
  if (!selectedPath) return;
23453
23547
  api("POST", "/api/changes/revert", { path: selectedPath }).then(function (res) {
23454
23548
  if (!res.ok) return readError(res, "Could not reject that file.").then(function (msg) { addBlock("alert", msg); });
23455
- loadTree();
23549
+ refreshWorkspaceSnapshot(true);
23456
23550
  }).catch(function () {});
23457
23551
  });
23458
23552
  on("accept-file", "click", function () {
@@ -23545,7 +23639,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23545
23639
  var modeEl = document.getElementById("mode");
23546
23640
  var autonomyEl = document.getElementById("autonomy");
23547
23641
  if (modeEl) modeEl.addEventListener("change", function () { saveSetting({ agent_mode: modeEl.value }); });
23548
- if (autonomyEl) autonomyEl.addEventListener("change", function () { saveSetting({ autonomy: autonomyEl.value }); });
23642
+ if (autonomyEl) autonomyEl.addEventListener("change", function () { saveSetting({ autonomy: autonomyEl.value }); syncAutonomyVisual(); });
23549
23643
 
23550
23644
  feedEl.addEventListener("click", function (e) {
23551
23645
  var btn = e.target.closest && e.target.closest(".copy");
@@ -23589,7 +23683,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23589
23683
  }
23590
23684
 
23591
23685
  var shell = document.querySelector(".shell");
23592
- var layout = { rail: true, changes: window.innerWidth >= 1100, term: false };
23686
+ var layout = { rail: window.innerWidth > 760, changes: false, term: false };
23593
23687
  try {
23594
23688
  var saved = localStorage.getItem("critique.code-web.layout");
23595
23689
  if (saved) layout = Object.assign(layout, JSON.parse(saved));
@@ -23602,7 +23696,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23602
23696
  var pane = document.getElementById("changes-pane");
23603
23697
  if (pane) pane.classList.toggle("open", !!layout.changes);
23604
23698
  var railBtn = document.getElementById("toggle-rail");
23605
- if (railBtn) railBtn.textContent = layout.rail ? "\u2039" : "\u203A";
23699
+ if (railBtn) railBtn.classList.toggle("on", !!layout.rail);
23606
23700
  try { localStorage.setItem("critique.code-web.layout", JSON.stringify(layout)); } catch (e) {}
23607
23701
  }
23608
23702
  applyLayout();
@@ -23764,15 +23858,8 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23764
23858
  }).join("");
23765
23859
  if (sheet) sheet.className = "sheet open";
23766
23860
  });
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
- });
23861
+ on("studio-open", "click", function () { loadStudio(); selectSettingsTab("general"); openSheet("studio-sheet"); });
23862
+ on("close-studio", "click", function () { closeSheet("studio-sheet"); });
23776
23863
  on("save-key", "click", function () {
23777
23864
  var kind = document.getElementById("key-kind");
23778
23865
  var value = document.getElementById("key-value");
@@ -23796,7 +23883,7 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23796
23883
  if (sheet) sheet.className = "sheet";
23797
23884
  if (res.ok) {
23798
23885
  if (body.branch) setBranchLabel(body.branch);
23799
- loadTree();
23886
+ refreshWorkspaceSnapshot(true);
23800
23887
  loadBranches();
23801
23888
  }
23802
23889
  }); });
@@ -23845,6 +23932,19 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23845
23932
  }
23846
23933
  if (paletteQ) paletteQ.addEventListener("input", renderPalette);
23847
23934
  renderPalette();
23935
+ var themeLight = document.getElementById("theme-light");
23936
+ function applyTheme(light) {
23937
+ document.documentElement.setAttribute("data-theme", light ? "light" : "dark");
23938
+ try { localStorage.setItem("critique-code-theme", light ? "light" : "dark"); } catch (e) {}
23939
+ }
23940
+ if (themeLight) {
23941
+ var savedTheme = "";
23942
+ try { savedTheme = localStorage.getItem("critique-code-theme") || ""; } catch (e) {}
23943
+ var useLight = savedTheme === "light";
23944
+ themeLight.checked = useLight;
23945
+ applyTheme(useLight);
23946
+ themeLight.addEventListener("change", function () { applyTheme(themeLight.checked); });
23947
+ }
23848
23948
  document.querySelectorAll(".work-tabs button").forEach(function (btn) {
23849
23949
  btn.addEventListener("click", function () {
23850
23950
  document.querySelectorAll(".work-tabs button").forEach(function (el) { el.classList.remove("on"); });
@@ -23912,8 +24012,12 @@ window.CRITIQUE_CODE_TOKEN = "__CRITIQUE_CODE_TOKEN__";
23912
24012
  addBlock("alert", "Could not load this session. Refresh the loopback tab.");
23913
24013
  });
23914
24014
  renderModelList();
24015
+ renderCommandBrowser();
24016
+ autosizeInput();
24017
+ syncAutonomyVisual();
23915
24018
  updateContextRing();
23916
24019
  loadStudio();
24020
+ refreshWorkspaceSnapshot(false);
23917
24021
  connect();
23918
24022
  })();
23919
24023
  </script>
@@ -28610,7 +28714,8 @@ ${prior}`.trim();
28610
28714
  source: "author",
28611
28715
  model: authorModelId(implementer[0]),
28612
28716
  input_tokens: turn.usage?.input_tokens ?? 0,
28613
- output_tokens: turn.usage?.output_tokens ?? 0
28717
+ output_tokens: turn.usage?.output_tokens ?? 0,
28718
+ cost_usd: turn.usage?.cost_usd
28614
28719
  });
28615
28720
  const output = typeof turn.output === "string" ? turn.output : JSON.stringify(turn.output);
28616
28721
  noteWithheld(output);
@@ -30551,6 +30656,12 @@ function commandPaletteItems(state) {
30551
30656
  function emptyTokens() {
30552
30657
  return { input_tokens: 0, output_tokens: 0 };
30553
30658
  }
30659
+ function estimateUsageCostUsd(input, output, reasoning = 0) {
30660
+ const inCost = input * 1e-7;
30661
+ const outCost = output * 4e-7;
30662
+ const reasonCost = reasoning * 2e-7;
30663
+ return inCost + outCost + reasonCost;
30664
+ }
30554
30665
  function costBreakdown(entries) {
30555
30666
  const by_phase = {
30556
30667
  author: emptyTokens(),
@@ -30560,6 +30671,7 @@ function costBreakdown(entries) {
30560
30671
  const by_model = {};
30561
30672
  let total_input = 0;
30562
30673
  let total_output = 0;
30674
+ let total_cost_usd = 0;
30563
30675
  for (const entry of entries) {
30564
30676
  const phase = by_phase[entry.source];
30565
30677
  phase.input_tokens += entry.input_tokens;
@@ -30569,8 +30681,10 @@ function costBreakdown(entries) {
30569
30681
  model.output_tokens += entry.output_tokens;
30570
30682
  total_input += entry.input_tokens;
30571
30683
  total_output += entry.output_tokens;
30684
+ total_cost_usd += Number(entry.cost_usd || 0);
30572
30685
  }
30573
- return { by_phase, by_model, total_input, total_output };
30686
+ const estimated_cost_usd = total_cost_usd > 0 ? total_cost_usd : estimateUsageCostUsd(total_input, total_output);
30687
+ return { by_phase, by_model, total_input, total_output, total_cost_usd, estimated_cost_usd };
30574
30688
  }
30575
30689
  function skillPanelRows(skills) {
30576
30690
  return skills.map((skill) => {
@@ -31190,6 +31304,29 @@ exit ${code2 ?? "killed"}
31190
31304
  send(res, 200, { ok: true, id: chat.id });
31191
31305
  return;
31192
31306
  }
31307
+ if (req.method === "POST" && path2 === "/api/sessions/rename") {
31308
+ const body = await readJson(req);
31309
+ const id4 = String(body.id ?? activeId).trim();
31310
+ const title = String(body.title ?? "").trim().slice(0, 120);
31311
+ const chat = chats.find((item) => item.id === id4);
31312
+ if (!chat) {
31313
+ send(res, 404, { error: "unknown session" });
31314
+ return;
31315
+ }
31316
+ if (!title) {
31317
+ send(res, 400, { error: "title required" });
31318
+ return;
31319
+ }
31320
+ chat.title = title;
31321
+ persistChats();
31322
+ if (chat.id === activeId) {
31323
+ emit({ type: "title", title: chat.title, id: chat.id, sessions: sessionSummaries() });
31324
+ } else {
31325
+ emit({ type: "session_list", sessions: sessionSummaries(), id: activeId });
31326
+ }
31327
+ send(res, 200, { ok: true, id: chat.id, title: chat.title, sessions: sessionSummaries() });
31328
+ return;
31329
+ }
31193
31330
  if (req.method === "GET" && path2 === "/api/tree") {
31194
31331
  const prefix = url2.searchParams.get("prefix")?.trim() ?? "";
31195
31332
  const entries = listWorkspaceTree(repositoryRoot, 2e3, prefix);
@@ -31501,12 +31638,20 @@ ${extras.join("\n\n")}` : text);
31501
31638
  const cursor = await new FileReviewCheckpointStore(storeRoot).load();
31502
31639
  const skills = await discoverCritiqueCodeSkills({ cwd: repositoryRoot, env });
31503
31640
  const suppressed = new Set(ops.state().suppressions.map((item) => item.fingerprint));
31641
+ const chatUsage = activeChat().events.filter((event) => event.type === "usage").map((event) => ({
31642
+ at: (/* @__PURE__ */ new Date()).toISOString(),
31643
+ source: "author",
31644
+ model,
31645
+ input_tokens: Number(event.input_tokens || 0),
31646
+ output_tokens: Number(event.output_tokens || 0),
31647
+ cost_usd: event.cost_usd
31648
+ }));
31504
31649
  send(res, 200, {
31505
31650
  ...snapshot(),
31506
31651
  badges: dualModelBadges({ author_model: model, review_models: reviewModels }),
31507
31652
  palette: commandPaletteItems({ watch: watchOn, autonomy, voice: false }),
31508
31653
  skills: skillPanelRows(skills),
31509
- costs: costBreakdown(ops.state().costs),
31654
+ costs: costBreakdown([...ops.state().costs, ...chatUsage]),
31510
31655
  audit: approvalLog,
31511
31656
  timeline: checkpointTimeline({
31512
31657
  cursor: cursor ? {