@payconductor/houndsman 0.7.0 → 0.10.0

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 (88) hide show
  1. package/README.md +20 -0
  2. package/package.json +1 -1
  3. package/src/cli/commands/command.ts +10 -1
  4. package/src/cli/commands/context-command.ts +40 -2
  5. package/src/cli/commands/hunt-command.ts +28 -2
  6. package/src/cli/commands/review-command.ts +30 -2
  7. package/src/cli/commands/worktree-command.ts +118 -0
  8. package/src/cli/help.ts +12 -2
  9. package/src/cli/index.ts +14 -4
  10. package/src/core/ai/ai-client.ts +21 -0
  11. package/src/core/ai/ai-sdk-model-provider.ts +43 -18
  12. package/src/core/ai/features/technical-summarizer.ts +43 -0
  13. package/src/core/ai/index.ts +4 -1
  14. package/src/core/ai/prompts/context.ts +3 -3
  15. package/src/core/ai/prompts/technical.ts +30 -0
  16. package/src/core/ai/provider-capabilities.ts +45 -0
  17. package/src/core/ai/schemas.ts +19 -3
  18. package/src/core/ai/types.ts +3 -1
  19. package/src/core/ast/service.ts +7 -2
  20. package/src/core/brief.ts +26 -4
  21. package/src/core/commands/context.ts +9 -1
  22. package/src/core/commands/findings.ts +11 -5
  23. package/src/core/commands/review.ts +13 -0
  24. package/src/core/commands/scaffold.ts +9 -2
  25. package/src/core/config.ts +30 -1
  26. package/src/core/defaults.ts +7 -0
  27. package/src/core/engine/houndsman-engine.ts +26 -3
  28. package/src/core/engine/review-scope.ts +17 -22
  29. package/src/core/engine/review-session.ts +25 -2
  30. package/src/core/engine/review-workspace.ts +204 -0
  31. package/src/core/git-runner.ts +8 -1
  32. package/src/core/jev/jev-detector.ts +10 -2
  33. package/src/core/orchestrator.ts +176 -15
  34. package/src/core/paths.ts +3 -0
  35. package/src/core/pr-context.ts +11 -6
  36. package/src/core/project-config.ts +21 -1
  37. package/src/core/renderers/resume-renderer.ts +17 -34
  38. package/src/core/report-builder.ts +6 -6
  39. package/src/core/services/git-repository.ts +46 -0
  40. package/src/core/services/pr-resolver.ts +147 -0
  41. package/src/core/services/worktree-manager.ts +293 -0
  42. package/src/core/storage/file/file-storage.ts +14 -1
  43. package/src/core/storage/paths.ts +30 -1
  44. package/src/core/storage/sqlite/mappers.ts +4 -0
  45. package/src/core/storage/sqlite/schema.ts +13 -3
  46. package/src/core/storage/sqlite/sqlite-storage.ts +28 -8
  47. package/src/core/storage/types.ts +13 -0
  48. package/src/core/storage/work-area.ts +20 -1
  49. package/src/core/technical-summary.ts +398 -0
  50. package/src/core/types.ts +2 -0
  51. package/src/harness/agent/agent-factory.ts +1 -0
  52. package/src/harness/agent/review-agent.ts +11 -1
  53. package/src/harness/config/harness-config.ts +6 -1
  54. package/src/harness/hunt/hunt-options.ts +17 -0
  55. package/src/harness/hunt/hunt-session.ts +7 -20
  56. package/src/index.ts +33 -0
  57. package/src/server/client/App.tsx +51 -12
  58. package/src/server/client/DeleteRunModal.tsx +163 -0
  59. package/src/server/client/PrsSection.tsx +296 -0
  60. package/src/server/client/ResumePanel.tsx +17 -20
  61. package/src/server/client/RunsSection.tsx +73 -0
  62. package/src/server/client/Sidebar.tsx +171 -358
  63. package/src/server/client/icons.tsx +10 -0
  64. package/src/server/client/sidebar-sections.tsx +73 -0
  65. package/src/server/client/utils/constants.ts +7 -2
  66. package/src/server/client/utils/sidebar-prefs.ts +64 -0
  67. package/src/server/client/utils/types.ts +27 -0
  68. package/src/server/index.ts +113 -406
  69. package/src/server/pr-inbox.ts +15 -4
  70. package/src/server/run-repository.ts +103 -2
  71. package/src/server/styles.css +454 -0
  72. package/src/skill/README.md +11 -3
  73. package/src/skill/SKILL.md +44 -10
  74. package/src/skill/hunt.md +33 -7
  75. package/src/tests/__snapshots__/baseline.test.ts.snap +99 -24
  76. package/src/tests/ai-core.test.ts +71 -0
  77. package/src/tests/ai-features.test.ts +36 -0
  78. package/src/tests/baseline.test.ts +4 -1
  79. package/src/tests/cli.test.ts +2 -1
  80. package/src/tests/harness-agent.test.ts +19 -0
  81. package/src/tests/review-resume.test.ts +36 -8
  82. package/src/tests/review-scope.test.ts +67 -0
  83. package/src/tests/review-scripts.test.ts +2 -2
  84. package/src/tests/server.test.ts +54 -1
  85. package/src/tests/sidebar-sections.test.ts +94 -0
  86. package/src/tests/technical-summary.test.ts +176 -0
  87. package/src/tests/worktree.test.ts +404 -0
  88. package/assets/logo-legacy.png +0 -0
@@ -0,0 +1,454 @@
1
+ /*
2
+ * Estilos da UI de triagem (`houndsman server`) — tema escuro, primária âmbar.
3
+ * Servido em `/assets/styles.css`; o shell (`index.ts`) só aponta o <link>.
4
+ */
5
+
6
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
7
+
8
+ :root {
9
+ color-scheme: dark;
10
+ --bg:#0a0a0c; --surface:#101014; --surface-2:#17171c; --card:#131318;
11
+ --border:rgba(255,255,255,.07); --border-strong:rgba(255,255,255,.14);
12
+ --fg:#ece9e4; --muted:#9d978e; --muted-2:#6d6862;
13
+ --accent:#f0a52c; --accent-strong:#ffc247; --accent-soft:rgba(240,165,44,.07); --accent-line:rgba(240,165,44,.25);
14
+ --blocking:#f2595e; --attention:#eda13a; --suggestion:#5aa4f0; --nit:#8d8a85; --success:#45c07a;
15
+ --radius:16px; --radius-lg:18px;
16
+ --font-sans:"Poppins","Space Grotesk","Geist Sans",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
17
+ --font-mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
18
+ }
19
+ * { box-sizing:border-box; }
20
+ html, body { height:100%; }
21
+ body { margin:0; font-size:14px; background:var(--bg); color:var(--fg); font-family:var(--font-sans); -webkit-font-smoothing:antialiased; }
22
+ body::before { content:""; position:fixed; inset:0; pointer-events:none; z-index:0;
23
+ background:radial-gradient(820px 420px at 8% -12%, rgba(240,165,44,.08), transparent 62%); }
24
+ code, pre, .mono { font-family:var(--font-mono); tab-size:4; }
25
+ ::-webkit-scrollbar { width:10px; height:10px; }
26
+ ::-webkit-scrollbar-thumb { background:rgba(255,255,255,.1); border:2px solid transparent; border-radius:999px; background-clip:padding-box; }
27
+ ::-webkit-scrollbar-thumb:hover { background:rgba(255,255,255,.18); background-clip:padding-box; }
28
+ .app { position:relative; z-index:1; display:flex; height:100vh; overflow:hidden; }
29
+ /* Sidebar = rail fixa de seções + painel expansível (largura em --side-width). */
30
+ .sidebar { position:relative; flex:0 0 auto; display:flex; height:100%; overflow:hidden;
31
+ --rail-w:52px; --side-width:360px;
32
+ width:calc(var(--rail-w) + var(--side-width));
33
+ background:var(--surface); border-right:1px solid var(--border); }
34
+ .sidebar.collapsed { width:var(--rail-w); }
35
+ .sidebar.collapsed .side-panel, .sidebar.collapsed .side-resizer { display:none; }
36
+ .side-rail { flex:0 0 var(--rail-w); width:var(--rail-w); display:flex; flex-direction:column; align-items:center; gap:4px;
37
+ padding:10px 0; background:var(--surface-2); border-right:1px solid var(--border);
38
+ overflow-x:hidden; overflow-y:auto; }
39
+ .rail-btn { position:relative; flex:none; display:grid; place-items:center; width:40px; height:40px; padding:0;
40
+ color:var(--muted); background:transparent; border:1px solid transparent; border-radius:11px; cursor:pointer;
41
+ transition:color .15s ease, background .15s ease, border-color .15s ease; }
42
+ .rail-btn:hover { color:var(--fg); background:rgba(255,255,255,.05); }
43
+ .rail-btn:focus-visible { outline:none; color:var(--fg); border-color:var(--accent-line); }
44
+ .rail-btn.active { color:var(--accent); background:var(--accent-soft); }
45
+ .rail-btn.active::before { content:""; position:absolute; left:-6px; top:9px; bottom:9px; width:2px; border-radius:2px; background:var(--accent); }
46
+ .rail-badge { position:absolute; top:2px; right:0; min-width:16px; padding:0 4px; font-family:var(--font-mono);
47
+ font-size:9px; font-weight:600; line-height:15px; text-align:center; color:var(--muted); background:var(--surface);
48
+ border:1px solid var(--border-strong); border-radius:999px; }
49
+ .rail-btn.active .rail-badge { color:var(--accent); border-color:var(--accent-line); }
50
+ .rail-spacer { flex:1; }
51
+ .rail-toggle { color:var(--muted-2); }
52
+ .rail-toggle .icon.flip { transform:rotate(180deg); }
53
+ .side-panel { flex:1; min-width:0; display:flex; flex-direction:column; overflow:hidden; }
54
+ .side-head { display:flex; flex-direction:column; gap:12px; padding:16px 14px 12px; border-bottom:1px solid var(--border); }
55
+ .side-title { min-width:0; }
56
+ .side-title h2 { margin:0 0 3px; font-size:13px; font-weight:700; letter-spacing:.01em; }
57
+ .side-hint { margin:0; color:var(--muted-2); font-size:11px; line-height:1.45; }
58
+ .side-body { flex:1; min-height:0; display:flex; flex-direction:column; gap:14px; padding:14px;
59
+ overflow-x:hidden; overflow-y:auto; }
60
+ .side-section { display:flex; flex-direction:column; gap:14px; min-width:0; }
61
+ .side-section[hidden] { display:none; }
62
+ .side-resizer { position:absolute; top:0; right:-3px; bottom:0; z-index:20; width:7px; background:transparent;
63
+ cursor:col-resize; touch-action:none; }
64
+ .side-resizer:hover, .side-resizer:focus-visible { background:var(--accent-line); outline:none; }
65
+ body.resizing-sidebar { cursor:col-resize; user-select:none; }
66
+ .brand { display:flex; align-items:center; gap:12px; }
67
+ .brand .logo { width:42px; height:42px; object-fit:contain; border-radius:12px; background:var(--surface-2); border:1px solid var(--border); }
68
+ .sidebar h1 { font-size:15.5px; font-weight:700; letter-spacing:-.01em; margin:0; }
69
+ .sub { color:var(--muted); font-size:11.5px; margin:0; }
70
+ .section-label { margin:4px 0 0; font-size:10px; font-weight:700; letter-spacing:.16em; text-transform:uppercase; color:var(--muted-2); }
71
+ .runs { display:flex; flex-direction:column; gap:6px; }
72
+ .run { display:flex; flex-direction:column; gap:8px; text-align:left; cursor:pointer; font:inherit; color:inherit; padding:11px 13px;
73
+ background:transparent; border:1px solid transparent; border-radius:var(--radius); transition:background .15s ease, border-color .15s ease; }
74
+ .run:hover { background:var(--surface-2); border-color:var(--border); }
75
+ .run.active { background:var(--accent-soft); border-color:var(--accent-line); }
76
+ .run-top { display:flex; align-items:flex-start; gap:8px; }
77
+ .run-icon { flex:none; margin-top:2px; color:var(--muted-2); }
78
+ .run.active .run-icon { color:var(--accent); }
79
+ .run-branch { font-size:12.5px; font-weight:600; line-height:1.35; word-break:break-word; }
80
+ .run-meta { display:flex; align-items:center; gap:10px; font-family:var(--font-mono); font-size:10.5px; color:var(--muted); }
81
+ .run-when { display:inline-flex; align-items:center; gap:6px; }
82
+ .run-count { margin-left:auto; color:var(--muted-2); }
83
+ .run-badge { align-self:flex-start; display:inline-flex; align-items:center; gap:6px; padding:4px 9px; border-radius:999px;
84
+ font-size:10px; font-weight:700; letter-spacing:.07em; text-transform:uppercase;
85
+ color:var(--success); background:rgba(69,192,122,.12); border:1px solid rgba(69,192,122,.32); }
86
+ .run-status { font-size:10px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--muted-2); }
87
+ .status-reviewing, .status-fixing { color:var(--accent); }
88
+ .status-review_done { color:var(--suggestion); }
89
+ .status-fix_done { color:var(--success); }
90
+ .status-timeout { color:var(--blocking); }
91
+ .icon-btn { display:inline-grid; place-items:center; width:26px; height:26px; color:var(--muted); background:transparent; border:1px solid var(--border); border-radius:8px; cursor:pointer; text-decoration:none; }
92
+ .icon-btn:hover { color:var(--fg); border-color:var(--border-strong); }
93
+ .icon-btn:disabled { opacity:.5; cursor:not-allowed; }
94
+ .pr-toolbar { display:flex; align-items:center; justify-content:space-between; gap:8px; }
95
+ .pr-toolbar .section-label { margin:0; }
96
+ .prs { display:flex; flex-direction:column; gap:8px; }
97
+ .pr { display:flex; flex-direction:column; gap:7px; padding:11px 12px; background:var(--card); border:1px solid var(--border); border-radius:var(--radius); }
98
+ .pr.current { background:var(--accent-soft); border-color:var(--accent-line); }
99
+ .pr-head { display:flex; align-items:center; gap:7px; font-family:var(--font-mono); font-size:11px; color:var(--muted); }
100
+ .pr-icon { color:var(--muted-2); }
101
+ .pr.current .pr-icon { color:var(--accent); }
102
+ .pr-number { font-weight:600; color:var(--fg); }
103
+ .pr-current { padding:1px 6px; font-size:9px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--accent); background:rgba(240,165,44,.12); border-radius:999px; }
104
+ .pr-title { margin:0; font-size:12.5px; font-weight:600; line-height:1.4; word-break:break-word; }
105
+ .pr-meta { display:flex; flex-wrap:wrap; align-items:center; gap:1px 5px; margin:0; font-family:var(--font-mono); font-size:10.5px; color:var(--muted-2); }
106
+ .pr-branch { color:var(--suggestion); }
107
+ .pr-worktree-badge { display:inline-flex; align-items:center; gap:4px; padding:1px 6px; font-family:var(--font-mono); font-size:9px;
108
+ font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--success);
109
+ background:rgba(69,192,122,.12); border:1px solid rgba(69,192,122,.3); border-radius:999px; }
110
+ .pr-review { margin:0; font-size:10.5px; font-weight:600; }
111
+ .pr-review-APPROVED { color:var(--success); }
112
+ .pr-review-CHANGES_REQUESTED { color:var(--blocking); }
113
+ .pr-review-REVIEW_REQUIRED { color:var(--attention); }
114
+ .pr-actions { display:flex; flex-wrap:wrap; gap:6px; margin-top:2px; }
115
+ .pr-btn { display:inline-flex; align-items:center; gap:5px; font:inherit; font-size:10.5px; font-weight:600; cursor:pointer; padding:4px 9px; color:var(--muted);
116
+ background:transparent; border:1px solid var(--border-strong); border-radius:999px; text-decoration:none; }
117
+ .pr-btn:hover { color:var(--fg); border-color:var(--accent-line); }
118
+ .pr-btn:disabled { opacity:.45; cursor:not-allowed; }
119
+ .pr-btn.danger { color:var(--accent); background:var(--accent-soft); border-color:var(--accent-line); }
120
+ .pr-warning { margin:0; padding:8px 10px; font-size:11px; line-height:1.5; color:var(--attention);
121
+ background:rgba(237,161,58,.08); border:1px solid rgba(237,161,58,.24); border-radius:10px; }
122
+ .pr-notice { margin:0; padding:8px 10px; font-size:11px; line-height:1.5; color:var(--success);
123
+ background:rgba(69,192,122,.08); border:1px solid rgba(69,192,122,.24); border-radius:10px; }
124
+ .pr-current-branch { margin:0; font-family:var(--font-mono); font-size:10.5px; color:var(--muted-2); }
125
+ .pr-current-branch code { color:var(--fg); }
126
+ .comments { display:flex; flex-direction:column; gap:18px; }
127
+ .comments-toolbar { display:flex; align-items:center; justify-content:space-between; gap:12px; }
128
+ .comments-counts { display:flex; flex-wrap:wrap; align-items:center; gap:12px; font-size:11.5px; color:var(--muted); }
129
+ .comments-counts b { font-family:var(--font-mono); font-weight:600; color:var(--fg); }
130
+ .comment-group { display:flex; flex-direction:column; gap:10px; }
131
+ .comment-group-title { margin:0; font-size:11px; font-weight:700; letter-spacing:.16em; text-transform:uppercase; color:var(--muted-2); }
132
+ .comment-file-group { display:flex; flex-direction:column; gap:8px; }
133
+ .comment-group-label { display:flex; align-items:center; gap:8px; margin:0; font-family:var(--font-mono); font-size:11.5px; color:var(--suggestion); }
134
+ .comment-thread { display:flex; flex-direction:column; overflow:hidden; background:var(--card); border:1px solid var(--border); border-radius:var(--radius-lg); }
135
+ .comment-thread-head { display:flex; align-items:center; gap:8px; padding:9px 13px; font-family:var(--font-mono); font-size:11px; color:var(--muted);
136
+ background:var(--surface-2); border-bottom:1px solid var(--border); }
137
+ .comment-file { overflow:hidden; color:var(--fg); text-overflow:ellipsis; white-space:nowrap; }
138
+ .pr-comment { display:flex; flex-direction:column; gap:7px; padding:12px 14px; border-top:1px solid var(--border); }
139
+ .comment-thread .pr-comment:first-of-type { border-top:0; }
140
+ .pr-comment.reply { margin-left:26px; background:rgba(255,255,255,.012); border-left:2px solid var(--accent-line); }
141
+ .pr-comment-head { display:flex; align-items:center; gap:9px; font-size:11px; color:var(--muted-2); }
142
+ .pr-comment-author { font-size:12px; font-weight:600; color:var(--fg); }
143
+ .pr-comment-link { display:inline-flex; align-items:center; gap:5px; font-size:11px; color:var(--muted); text-decoration:none; }
144
+ .pr-comment-link:hover { color:var(--accent); }
145
+ .pr-comment-body { font-size:12.5px; line-height:1.6; color:#f0ece6; }
146
+ .pr-comment-body .md-p, .pr-comment-body .md-list { font-size:12.5px; }
147
+ .main { flex:1; min-width:0; display:flex; flex-direction:column; overflow-y:auto; }
148
+ .topbar { position:sticky; top:0; z-index:10; display:flex; align-items:center; justify-content:space-between; gap:16px;
149
+ padding:13px 24px; border-bottom:1px solid var(--border); background:rgba(16,16,20,.74);
150
+ backdrop-filter:blur(16px) saturate(140%); -webkit-backdrop-filter:blur(16px) saturate(140%); }
151
+ .segmented { display:inline-flex; gap:4px; padding:4px; background:var(--surface-2); border:1px solid var(--border); border-radius:999px; }
152
+ .seg-btn { display:inline-flex; align-items:center; gap:8px; font:inherit; font-size:12.5px; font-weight:600; cursor:pointer;
153
+ color:var(--muted); background:transparent; border:1px solid transparent; border-radius:999px; padding:7px 16px;
154
+ transition:color .15s ease, background .15s ease; }
155
+ .seg-btn:hover { color:var(--fg); }
156
+ .seg-btn.active { color:#1b1305; background:linear-gradient(180deg, var(--accent-strong), var(--accent)); box-shadow:0 4px 14px rgba(240,165,44,.24); }
157
+ .topbar-right { display:flex; align-items:center; gap:14px; }
158
+ .auto-refresh { display:inline-flex; align-items:center; gap:8px; white-space:nowrap; font-family:var(--font-mono); font-size:11.5px; color:var(--muted); }
159
+ .dot { width:8px; height:8px; border-radius:50%; background:var(--success); box-shadow:0 0 0 3px rgba(69,192,122,.14); }
160
+ .dot.busy { background:var(--accent); box-shadow:0 0 0 3px rgba(240,165,44,.18); animation:pulse 1.1s ease-in-out infinite; }
161
+ .btn { display:inline-flex; align-items:center; gap:8px; font:inherit; font-size:12.5px; font-weight:500; cursor:pointer; color:var(--fg);
162
+ padding:8px 15px; background:var(--surface-2); border:1px solid var(--border-strong); border-radius:999px;
163
+ transition:background .15s ease, border-color .15s ease, color .15s ease; }
164
+ .btn:hover { background:#202027; border-color:var(--accent-line); }
165
+ .btn:disabled { opacity:.55; cursor:not-allowed; }
166
+ .btn.danger { color:#ffb3b3; background:rgba(255,86,86,.12); border-color:rgba(255,86,86,.4); }
167
+ .btn.danger:hover { background:rgba(255,86,86,.2); border-color:rgba(255,86,86,.62); }
168
+ .modal-check { display:flex; align-items:flex-start; gap:10px; padding:12px 14px; font-size:12.5px; line-height:1.55;
169
+ color:var(--fg); background:var(--surface-2); border:1px solid var(--border); border-radius:12px; cursor:pointer; }
170
+ .modal-check input { margin:3px 0 0; flex:none; accent-color:var(--accent); }
171
+ .modal-check code { font-family:var(--font-mono); font-size:11.5px; color:var(--muted); word-break:break-all; }
172
+ .modal-warn { margin:0; font-size:12px; line-height:1.55; color:var(--muted); }
173
+ .icon.spin { animation:spin .8s linear infinite; }
174
+ .content { width:100%; max-width:1180px; margin:0 auto; padding:22px 24px 64px; }
175
+ .page-header { display:flex; align-items:flex-start; justify-content:space-between; gap:18px; margin-bottom:16px; }
176
+ .page-header-text { min-width:0; }
177
+ .page-header-actions { display:flex; align-items:center; gap:10px; flex:none; }
178
+ .btn.submit-review { color:#1b1305; background:linear-gradient(180deg, var(--accent-strong), var(--accent)); border-color:transparent; box-shadow:0 4px 14px rgba(240,165,44,.22); }
179
+ .btn.submit-review:hover { background:linear-gradient(180deg, var(--accent-strong), var(--accent)); border-color:transparent; filter:brightness(1.07); }
180
+ .page-title { margin:0 0 8px; font-size:26px; font-weight:700; letter-spacing:-.02em; word-break:break-word; }
181
+ .page-sub { margin:0; max-width:78ch; color:var(--muted); font-size:12.5px; line-height:1.55; }
182
+ .page-sub code { color:var(--fg); background:rgba(255,255,255,.06); border-radius:6px; padding:1px 6px; font-size:11.5px; }
183
+ .error { color:#ff8b8f; font-size:12.5px; }
184
+ .empty { color:var(--muted); font-size:13px; }
185
+ .kpis { display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:12px; margin:20px 0 18px; }
186
+ .kpi { display:flex; flex-direction:column; gap:8px; padding:15px 16px; background:var(--card);
187
+ border:1px solid var(--border); border-radius:var(--radius-lg); }
188
+ .kpi-label { font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--muted-2); }
189
+ .kpi-value { font-size:30px; font-weight:700; line-height:1; letter-spacing:-.02em; font-variant-numeric:tabular-nums; }
190
+ .kpi-hint { font-family:var(--font-mono); font-size:11px; color:var(--muted-2); }
191
+ .kpi-execute .kpi-value { color:var(--accent); }
192
+ .kpi-ignore .kpi-value { color:var(--muted); }
193
+ .kpi-done .kpi-value { color:var(--success); }
194
+ .progress { margin:0 0 22px; }
195
+ .progress-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; font-size:11.5px; color:var(--muted); }
196
+ .progress-head .pct { color:var(--fg); font-family:var(--font-mono); }
197
+ .progress-track { height:8px; border-radius:999px; background:var(--surface-2); border:1px solid var(--border); overflow:hidden; }
198
+ .progress-fill { display:block; height:100%; border-radius:999px; background:linear-gradient(90deg, #2c8f57, var(--success)); transition:width .35s ease; }
199
+ .filters { display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin-bottom:20px; }
200
+ .search { display:flex; align-items:center; gap:8px; flex:1 1 240px; max-width:330px; padding:8px 14px; color:var(--muted);
201
+ background:var(--surface-2); border:1px solid var(--border-strong); border-radius:999px; }
202
+ .search:focus-within { color:var(--accent); border-color:var(--accent-line); }
203
+ .search input { flex:1; min-width:0; font:inherit; font-size:12.5px; color:var(--fg); background:transparent; border:0; outline:0; }
204
+ .search input::placeholder { color:var(--muted-2); }
205
+ .search-clear { padding:0 2px; font-size:15px; line-height:1; color:var(--muted); background:transparent; border:0; cursor:pointer; }
206
+ .chips { display:inline-flex; gap:3px; padding:4px; background:var(--surface-2); border:1px solid var(--border); border-radius:999px; }
207
+ .chip { display:inline-flex; align-items:center; gap:6px; font:inherit; font-size:12px; font-weight:600; cursor:pointer; color:var(--muted);
208
+ padding:6px 13px; background:transparent; border:1px solid transparent; border-radius:999px; transition:color .15s ease, background .15s ease; }
209
+ .chip:hover { color:var(--fg); }
210
+ .chip.active { color:#14100a; background:#e9e5df!important; }
211
+ .sev-group { margin-bottom:24px; }
212
+ .sev-head { display:flex; align-items:center; gap:8px; margin:0 0 10px; font-size:11px; font-weight:700;
213
+ letter-spacing:.16em; text-transform:uppercase; color:var(--muted-2); }
214
+ .sev-head .n { font-family:var(--font-mono); letter-spacing:0; }
215
+ .sev-group.sev-blocking .sev-head { color:var(--blocking); }
216
+ .sev-group.sev-attention .sev-head { color:var(--attention); }
217
+ .sev-group.sev-suggestion .sev-head { color:var(--suggestion); }
218
+ .sev-group.sev-nit .sev-head { color:var(--nit); }
219
+ .card { position:relative; margin-bottom:20px; overflow:hidden; background:var(--card);
220
+ border:1px solid var(--border); border-left:4px solid var(--border-strong); border-radius:var(--radius-lg);
221
+ transition:background .15s ease, border-color .15s ease, opacity .2s ease; }
222
+ .card:hover { background:#16161b; }
223
+ .card.sev-blocking { border-left-color:var(--blocking); }
224
+ .card.sev-attention { border-left-color:var(--attention); }
225
+ .card.sev-suggestion { border-left-color:var(--suggestion); }
226
+ .card.sev-nit { border-left-color:var(--nit); }
227
+ .card.absent { opacity:.5; }
228
+ .card.done { opacity:.6; }
229
+ .card-head { display:flex; align-items:center; gap:10px; padding:12px 14px 0; }
230
+ .chev { display:grid; place-items:center; flex:none; width:22px; height:22px; cursor:pointer; color:var(--muted-2);
231
+ background:transparent; border:1px solid transparent; border-radius:7px; }
232
+ .chev:hover { color:var(--fg); background:rgba(255,255,255,.06); }
233
+ .chev:focus-visible { color:var(--fg); border-color:var(--accent-line); outline:none; }
234
+ .chev svg { transition:transform .18s ease; }
235
+ .chev.open svg { transform:rotate(90deg); }
236
+ .sev-badge { display:inline-flex; align-items:center; flex:none; padding:3px 9px; border-radius:999px;
237
+ font-size:10px; letter-spacing:.08em; text-transform:uppercase; }
238
+ .card.sev-blocking .sev-badge { color:var(--blocking); background:rgba(242,89,94,.12); }
239
+ .card.sev-attention .sev-badge { color:var(--attention); background:rgba(237,161,58,.12); }
240
+ .card.sev-suggestion .sev-badge { color:var(--suggestion); background:rgba(90,164,240,.12); }
241
+ .card.sev-nit .sev-badge { color:var(--nit); background:rgba(255,255,255,.06); }
242
+ .loc { display:inline-flex; align-items:center; gap:7px; max-width: 406ch; overflow:hidden; white-space:break-spaces; text-overflow:ellipsis;
243
+ padding:4px 9px; font-family:var(--font-mono); font-size:11.5px; color:#aba7a1; text-decoration:none; }
244
+ .loc:hover { color:#fff; }
245
+ .loc .ext { flex:none; opacity:0; transition:opacity .15s ease; }
246
+ .loc:hover .ext { opacity:1; }
247
+ .loc.static { color:var(--muted); }
248
+ .count { padding:2px 7px; font-family:var(--font-mono); font-size:11px; color:var(--muted);
249
+ background:var(--surface-2); border:1px solid var(--border); border-radius:999px; }
250
+ .spacer { flex:1; }
251
+ .done-btn { display:inline-flex; align-items:center; gap:7px; flex:none; font:inherit; font-size:12px; font-weight:600; cursor:pointer;
252
+ padding:7px 13px; color:var(--muted); background:transparent; border:1px solid var(--border-strong); border-radius:999px;
253
+ transition:color .15s ease, background .15s ease, border-color .15s ease; }
254
+ .done-btn:hover { color:var(--fg); border-color:rgba(69,192,122,.55); }
255
+ .done-btn:disabled { opacity:.55; cursor:not-allowed; }
256
+ .done-btn.is-done { color:var(--success); background:rgba(69,192,122,.14); border-color:rgba(69,192,122,.5); }
257
+ .card-title { margin:9px 0 0; padding:0 16px 20px; font-size:14px; font-weight:400; }
258
+ .card.done .card-title { color:#b7b7b7; text-decoration:line-through; text-decoration-color:rgba(255,255,255,.15); }
259
+ .card-body { display:flex; flex-direction:column; gap:12px; padding:20px 16px 15px; background:rgba(255,255,255,.012); border-top:1px solid var(--border); }
260
+ .meta-row { display:flex; flex-wrap:wrap; gap:14px; font-size:11.5px; color:var(--muted); }
261
+ .meta { display:inline-flex; align-items:center; gap:7px; }
262
+ .meta-k { font-size:10px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); }
263
+ .meta code { padding:2px 6px; font-size:11.5px; color:var(--fg); background:rgba(255,255,255,.04); border:1px solid var(--border); border-radius:6px; }
264
+ .action-block { display:flex; gap:11px; padding:0; background:transparent; border:0; border-radius:0; }
265
+ .action-icon { flex:none; display:inline-block; margin-top:3px; margin-right:2px; color:var(--accent); }
266
+ .action-text { flex:1; min-width:0; }
267
+ .action-label { display:block; margin-bottom:4px; font-size:10px; font-weight:600; letter-spacing:.12em; text-transform:uppercase; color:var(--accent); }
268
+ .action-text p, .md-p { margin:0 0 6px; font-size:13px; line-height:1.65; color:#f0ece6; white-space:pre-wrap; }
269
+ .action-text p:last-child { margin-bottom:0; }
270
+ .md-list { margin:0 0 6px; padding-left:20px; font-size:13px; line-height:1.65; color:#f0ece6; }
271
+ .md-list li { margin:0 0 2px; }
272
+ .md-quote { margin:0 0 6px; padding:2px 0 2px 10px; border-left:2px solid var(--accent-line); color:var(--muted); font-size:13px; line-height:1.65; white-space:pre-wrap; }
273
+ .action-text code, .md-code { font-family:var(--font-mono); font-size:11.5px; padding:1px 5px; color:#f0ece6; background:rgba(255,255,255,.06); border:1px solid var(--border); border-radius:5px; }
274
+ code.md-path { color:#8fc7ff; background:rgba(90,164,240,.1); border-color:rgba(90,164,240,.24); }
275
+ .action-text a, .md-p a, .md-list a, .md-quote a, .md-table a, .md-h a { color:var(--accent-strong); text-decoration:underline; text-underline-offset:2px; }
276
+ .action-text strong, .md-p strong, .md-list strong, .md-quote strong, .md-table strong, .md-h strong { color:#fff; font-weight:600; }
277
+ .action-text em, .md-p em, .md-list em, .md-quote em, .md-table em, .md-h em { color:#e9e4dc; }
278
+ .md-code-block { margin:6px 0; padding:10px 12px; max-height:320px; overflow:auto; white-space:pre; font-size:11.5px; line-height:1.6; color:#cdc7bf; background:#0b0b0e; border-radius:10px; }
279
+ .md-h { margin:16px 0 8px; font-size:14px; font-weight:700; line-height:1.35; letter-spacing:-.01em; color:#eee9e2; }
280
+ .md-h:first-child { margin-top:0; }
281
+ .md-h1 { font-size:19px; }
282
+ .md-h2 { font-size:16px; }
283
+ .md-h3 { font-size:14px; }
284
+ .md-h4, .md-h5, .md-h6 { font-size:13px; color:#e4dfd7; font-weight:600; }
285
+ .md-hr { margin:14px 0; border:0; border-top:1px solid var(--border); }
286
+ .md-table-wrap { margin:8px 0 12px; padding:4px; overflow-x:auto; border:1px solid rgba(255,255,255,.07); border-radius:10px; background:rgba(255,255,255,.012); }
287
+ .md-table { width:100%; border-collapse:separate; border-spacing:3px; font-size:12px; line-height:1.5; }
288
+ .md-table th, .md-table td { padding:6px 9px; text-align:left; vertical-align:top; border:1px solid rgba(255,255,255,.035); border-radius:6px; }
289
+ .md-table th { color:var(--muted); font-weight:600; background:rgba(255,255,255,.03); }
290
+ .md-table td { color:#d8d3cc; }
291
+ .decision-tags-block { display:flex; align-items:center; gap:8px; }
292
+ .evidence { margin:0; padding: 16px; white-space:break-spaces; font-size:12px; line-height:1.6; color:#cdc7bf;
293
+ background:#0b0b0e; border:1px solid var(--border); border-radius:var(--radius); }
294
+ .evidence-block { display:flex; flex-direction:column; gap:6px; }
295
+ .evidence-head { display:flex; justify-content:flex-end; }
296
+ .code-lang { font-family:var(--font-mono); font-size:9.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); }
297
+ .code-evidence { white-space:pre; overflow:auto; }
298
+ .tok-keyword { color:#c792ea; }
299
+ .tok-string { color:#9ddc8a; }
300
+ .tok-comment { color:#6d6862; font-style:italic; }
301
+ .tok-number { color:#8fc7ff; }
302
+ .tok-type { color:var(--accent-strong); }
303
+ .tok-function { color:#82aaff; }
304
+ .tok-property { color:#e6c07b; }
305
+ .tok-punct { color:#8d8a85; }
306
+ .tags { display:flex; flex-wrap:wrap; align-items:center; gap:7px; margin-left: auto; }
307
+ .tags-label { display:inline-flex; align-items:center; gap:6px; font-size:10px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); }
308
+ .tag { display:inline-flex; align-items:center; gap:6px; padding:3px 9px; font-family:var(--font-mono); font-size:11px; color:var(--muted);
309
+ background:var(--surface-2); border:1px solid var(--border); border-radius:999px; }
310
+ .decisions { display:inline-flex; gap:3px; align-self:flex-start; padding:4px; background:var(--surface-2); border:1px solid var(--border); border-radius:999px; }
311
+ .dec-btn { font:inherit; font-size:12px; font-weight:600; cursor:pointer; color:var(--muted); padding:6px 15px;
312
+ background:transparent; border:1px solid transparent; border-radius:999px; transition:color .15s ease, background .15s ease; }
313
+ .dec-btn:hover { color:var(--fg); }
314
+ .dec-btn:disabled { opacity:.55; cursor:not-allowed; }
315
+ .dec-btn.dec-execute.active { color:#1b1305; background:linear-gradient(180deg, var(--accent-strong), var(--accent)); }
316
+ .dec-btn.dec-ignore.active { color:#ffd2d3; background:rgba(242,89,94,.18); box-shadow:inset 0 0 0 1px rgba(242,89,94,.45); }
317
+ .dec-btn.dec-pending.active { color:var(--fg); background:rgba(255,255,255,.08); box-shadow:inset 0 0 0 1px var(--border-strong); }
318
+ .comment { position:relative; }
319
+ .comment textarea { width:100%; min-height:58px; padding:11px 13px 26px; resize:vertical; font:inherit; font-size:12.5px; line-height:1.5;
320
+ color:var(--fg); background:var(--surface-2); border:1px solid var(--border-strong); border-radius:var(--radius); outline:none;
321
+ transition:border-color .15s ease, box-shadow .15s ease; }
322
+ .comment textarea::placeholder { color:var(--muted-2); }
323
+ .comment textarea:focus { border-color:var(--accent-line); box-shadow:0 0 0 3px rgba(240,165,44,.12); }
324
+ .comment-status { position:absolute; right:12px; bottom:9px; display:inline-flex; align-items:center; gap:6px;
325
+ font-family:var(--font-mono); font-size:11px; color:var(--muted); }
326
+ .comment-status.saved { color:var(--success); }
327
+ .artifacts { display:flex; flex-direction:column; }
328
+ .artifact-layout { display:grid; grid-template-columns:minmax(190px,250px) minmax(0,1fr); gap:16px; align-items:start; }
329
+ .artifact-list { display:flex; flex-direction:column; gap:14px; max-height:72vh; overflow:auto; padding:2px 4px 2px 0; }
330
+ .artifact-group { display:flex; flex-direction:column; gap:4px; }
331
+ .artifact-group-label { margin:0 0 2px; font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
332
+ .artifact-item { display:flex; flex-direction:column; gap:2px; text-align:left; cursor:pointer; font:inherit; color:var(--muted);
333
+ padding:8px 10px; background:transparent; border:1px solid transparent; border-radius:10px;
334
+ transition:background .15s ease, border-color .15s ease, color .15s ease; }
335
+ .artifact-item:hover { color:var(--fg); background:var(--surface-2); border-color:var(--border); }
336
+ .artifact-item.active { color:var(--fg); background:var(--accent-soft); border-color:var(--accent-line); }
337
+ .artifact-item-name { font-family:var(--font-mono); font-size:11.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
338
+ .artifact-item-kind { font-size:9.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); }
339
+ .artifact-item.active .artifact-item-kind { color:var(--accent); }
340
+ .artifact-pane { min-width:0; }
341
+ .artifact-head { display:flex; align-items:flex-start; justify-content:space-between; gap:14px; margin-bottom:12px; }
342
+ .artifact-title { margin:0 0 5px; font-family:var(--font-mono); font-size:13px; font-weight:600; word-break:break-word; }
343
+ .artifact-desc { margin:0; max-width:78ch; color:var(--muted); font-size:12.5px; line-height:1.55; }
344
+ .artifact-kind-badge { flex:none; display:inline-flex; align-items:center; padding:3px 9px; font-size:10px; font-weight:700;
345
+ letter-spacing:.08em; text-transform:uppercase; color:var(--accent); background:var(--accent-soft);
346
+ border:1px solid var(--accent-line); border-radius:999px; }
347
+ .artifact-view { margin:0; padding:14px 16px; max-height:70vh; overflow:auto; font-size:12px; line-height:1.6; color:#cdc7bf;
348
+ background:#0b0b0e; border:1px solid var(--border); border-radius:var(--radius); }
349
+ .artifact-markdown { white-space:normal; }
350
+ .artifact-markdown .md-p, .artifact-markdown .md-list, .artifact-markdown .md-quote { font-size:12.5px; }
351
+ .artifact-markdown .md-p, .artifact-markdown .md-list { color:#d8d3cc; }
352
+ .artifact-markdown .md-code-block { border:1px solid var(--border); }
353
+ .json-view { white-space:pre; }
354
+ .json-key { color:var(--accent-strong); }
355
+ .json-string { color:#9ddc8a; }
356
+ .json-number { color:#8fc7ff; }
357
+ .json-literal { color:#d7a6ff; }
358
+ .json-punct { color:#8d8a85; }
359
+ @media (max-width:900px) { .artifact-layout { grid-template-columns:1fr; } .artifact-list { max-height:240px; } }
360
+ .sent-tag { display:inline-flex; align-items:center; gap:5px; padding:2px 8px; font-size:10px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
361
+ color:var(--success); background:rgba(69,192,122,.12); border:1px solid rgba(69,192,122,.32); border-radius:999px; text-decoration:none; }
362
+ .sent-tag:hover { color:#fff; }
363
+ .sent-tag.gh { color:#b9c7d6; background:rgba(139,164,191,.12); border-color:rgba(139,164,191,.35); }
364
+ .sent-tag.gh:hover { color:#fff; background:rgba(139,164,191,.2); }
365
+ .resume { display:flex; flex-direction:column; }
366
+ .resume-hero { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; padding:18px 20px;
367
+ background:linear-gradient(135deg, rgba(240,165,44,.08), rgba(255,255,255,.015) 55%);
368
+ border:1px solid var(--border); border-radius:var(--radius-lg); }
369
+ .resume-kicker { display:block; font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--accent); }
370
+ .resume-title { margin:5px 0 7px; font-size:22px; font-weight:700; letter-spacing:-.02em; word-break:break-word; }
371
+ .resume-meta { display:flex; flex-wrap:wrap; align-items:center; gap:12px; margin:0; font-size:12px; color:var(--muted); }
372
+ .resume-pr { display:inline-flex; align-items:center; gap:5px; color:var(--accent-strong); text-decoration:none; }
373
+ .resume-pr:hover { text-decoration:underline; }
374
+ .resume-hero-side { display:flex; flex:none; flex-direction:column; align-items:flex-end; gap:10px; }
375
+ .resume-status { display:inline-flex; align-items:center; padding:5px 12px; font-size:11px; font-weight:700; letter-spacing:.04em; border-radius:999px; }
376
+ .resume-status.blocking { color:var(--blocking); background:rgba(242,89,94,.12); border:1px solid rgba(242,89,94,.35); }
377
+ .resume-status.attention { color:var(--attention); background:rgba(237,161,58,.12); border:1px solid rgba(237,161,58,.35); }
378
+ .resume-status.clean { color:var(--success); background:rgba(69,192,122,.12); border:1px solid rgba(69,192,122,.35); }
379
+ .resume-kpis { margin:14px 0 18px; }
380
+ .resume-kpis .kpi-value { font-size:24px; }
381
+ .churn-add { color:var(--success); }
382
+ .churn-del { color:var(--blocking); }
383
+ .churn-sep { margin:0 3px; color:var(--muted-2); font-weight:400; }
384
+ .kpi-blocking .kpi-value { color:var(--blocking); }
385
+ .kpi-attention .kpi-value { color:var(--attention); }
386
+ .kpi-total .kpi-value { color:var(--fg); }
387
+ .resume-grid { display:grid; grid-template-columns:minmax(0,1.35fr) minmax(0,1fr); gap:16px; align-items:start; }
388
+ .resume-card { min-width:0; padding:16px 18px; background:var(--card); border:1px solid var(--border); border-radius:var(--radius-lg); }
389
+ .resume-card-head { display:flex; align-items:center; justify-content:space-between; gap:10px; }
390
+ .resume-card-title { margin:0 0 10px; font-size:12px; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
391
+ .resume-card-count { display:inline-flex; align-items:center; justify-content:center; min-width:22px; height:22px; margin-bottom:10px; padding:0 7px;
392
+ font-family:var(--font-mono); font-size:11px; color:var(--accent); background:var(--accent-soft); border:1px solid var(--accent-line); border-radius:999px; }
393
+ .resume-narrative .md-p:last-child { margin-bottom:0; }
394
+ .resume-domains { display:flex; flex-direction:column; gap:8px; margin:0; padding:0; list-style:none; }
395
+ .resume-domain { display:flex; flex-direction:column; gap:7px; padding:10px 12px; background:var(--surface-2);
396
+ border:1px solid var(--border); border-radius:10px; }
397
+ .resume-domain-head { display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
398
+ .resume-domain-name { font-size:12.5px; font-weight:600; color:var(--fg); }
399
+ .resume-domain-files { flex:none; font-family:var(--font-mono); font-size:10.5px; color:var(--muted-2); }
400
+ .resume-domain-sev { display:flex; flex-wrap:wrap; gap:6px; }
401
+ .resume-domain-sev .sev-badge { padding:2px 7px; font-size:9.5px; }
402
+ .resume-domain-ok { font-size:11.5px; color:var(--success); }
403
+ @media (max-width:900px) { .resume-grid { grid-template-columns:1fr; } .resume-hero { flex-direction:column; } .resume-hero-side { flex-direction:row; align-items:flex-start; } }
404
+ .modal-layer { position:fixed; inset:0; z-index:50; display:grid; place-items:center; padding:24px; }
405
+ .modal-backdrop { position:absolute; inset:0; width:100%; padding:0; background:rgba(5,5,7,.66); border:0; cursor:default; backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px); }
406
+ .modal { position:relative; width:min(640px, 100%); max-height:min(78vh, 780px); display:flex; flex-direction:column; overflow:hidden;
407
+ background:var(--surface); border:1px solid var(--border-strong); border-radius:var(--radius-lg); box-shadow:0 24px 70px rgba(0,0,0,.5); }
408
+ .modal-head { display:flex; align-items:flex-start; justify-content:space-between; gap:14px; padding:18px 20px 14px; border-bottom:1px solid var(--border); }
409
+ .modal-title { margin:0; font-size:17px; font-weight:700; letter-spacing:-.01em; }
410
+ .modal-sub { margin:5px 0 0; font-size:12px; color:var(--muted); line-height:1.5; }
411
+ .modal-close { flex:none; display:grid; place-items:center; width:30px; height:30px; font:inherit; font-size:19px; line-height:1; color:var(--muted); background:transparent; border:1px solid var(--border); border-radius:9px; cursor:pointer; }
412
+ .modal-close:hover { color:var(--fg); border-color:var(--border-strong); }
413
+ .modal-body { display:flex; flex-direction:column; gap:16px; padding:16px 20px; overflow-y:auto; }
414
+ .modal-foot { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:14px 20px; background:var(--surface-2); border-top:1px solid var(--border); }
415
+ .submit-field { display:flex; flex-direction:column; gap:8px; }
416
+ .submit-label { font-size:10px; font-weight:700; letter-spacing:.14em; text-transform:uppercase; color:var(--muted-2); }
417
+ .submit-summary { padding:13px 15px; font-size:12.5px; color:var(--fg); background:var(--accent-soft); border:1px solid var(--accent-line); border-radius:var(--radius); }
418
+ .submit-summary b { font-family:var(--font-mono); }
419
+ .submit-list { display:flex; flex-direction:column; gap:6px; max-height:240px; overflow-y:auto; padding-right:2px; }
420
+ .submit-item { display:flex; align-items:center; gap:10px; padding:8px 11px; font-size:12px; background:var(--surface-2); border:1px solid var(--border); border-radius:10px; }
421
+ .submit-item.sent { opacity:.7; }
422
+ .submit-item .rule { flex:1; min-width:0; color:var(--muted); overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
423
+ .submit-empty { color:var(--muted); font-size:12.5px; }
424
+ .submit-field .chips { flex-wrap:wrap; }
425
+ .submit-check { display:inline-flex; align-items:center; gap:8px; font-size:12.5px; color:var(--muted); cursor:pointer; }
426
+ .submit-check input { accent-color:var(--accent); }
427
+ .submit-actions { display:flex; align-items:center; gap:8px; }
428
+ .sev-badge.sev-blocking { color:var(--blocking); background:rgba(242,89,94,.12); }
429
+ .sev-badge.sev-attention { color:var(--attention); background:rgba(237,161,58,.12); }
430
+ .sev-badge.sev-suggestion { color:var(--suggestion); background:rgba(90,164,240,.12); }
431
+ .sev-badge.sev-nit { color:var(--nit); background:rgba(255,255,255,.06); }
432
+ @keyframes pulse { 0%,100% { opacity:1; transform:scale(1); } 50% { opacity:.4; transform:scale(.8); } }
433
+ @keyframes spin { to { transform:rotate(360deg); } }
434
+ @media (max-width:980px) { .kpis { grid-template-columns:repeat(2, minmax(0,1fr)); } }
435
+ @media (max-width:1100px) {
436
+ /* Painel largo reduz o espaço do conteúdo: compacta o topo para evitar scroll-x. */
437
+ .topbar { gap:12px; padding:12px 16px; }
438
+ .seg-btn { gap:6px; padding:7px 11px; font-size:12px; }
439
+ .auto-refresh { display:none; }
440
+ }
441
+ @media (max-width:720px) {
442
+ /* Em telas estreitas as abas viram só ícone (o título do botão explica cada uma). */
443
+ .seg-btn { padding:8px 10px; }
444
+ .seg-btn .seg-label { display:none; }
445
+ }
446
+ @media (max-width:820px) {
447
+ /* Mantém a rail fixa e encolhe o painel para preservar o conteúdo principal. */
448
+ .sidebar { width:calc(var(--rail-w) + clamp(220px, 35vw, var(--side-width))); }
449
+ .side-head { padding:14px 12px 10px; }
450
+ .side-body { padding:12px; }
451
+ .topbar { padding:12px 16px; }
452
+ .content { padding:18px 16px 56px; }
453
+ .auto-refresh { display:none; }
454
+ }
@@ -39,13 +39,20 @@ Um único skill (`/houndsman`), quatro capabilities (detalhadas em `hunt.md`, `t
39
39
  | 2. Revisar | *(subagentes)* | skill | `findings/<watchdog>.json` (um por watchdog) |
40
40
  | 3. Finalizar | `bun run houndsman --finalize` | skill | `review.md` |
41
41
 
42
+ > **Alvo = PR** (ex.: “revise a PR 456”): troque os passos por `houndsman context --pr 456`,
43
+ > `houndsman --pr 456` e `houndsman --pr 456 --finalize`. O prepare cria um **worktree**
44
+ > detached em `<repo>/.houndsman/worktrees/<repo>/<branch>`; os briefs trazem
45
+ > `**Worktree:**` e os subagentes devem ler essa árvore (nunca o clone principal).
46
+
42
47
  ## Comandos
43
48
 
44
49
  | Comando | Função |
45
50
  |---|---|
46
- | `houndsman context` | Passo 0 — contexto da PR via `gh` |
51
+ | `houndsman context` | Passo 0 — contexto da PR via `gh` (`--pr <n>`/`--worktree <path>`) |
47
52
  | `houndsman` | Passo 1 — preparar (gera os briefs) |
48
- | `houndsman --finalize` | Passo 3 — gerar o relatório |
53
+ | `houndsman --pr <n>` | Passo 1 em worktree dedicado (revisões paralelas) |
54
+ | `houndsman --finalize` | Passo 3 — gerar o relatório (`--pr <n>` reusa o worktree) |
55
+ | `houndsman worktree <ação>` | `list`/`add`/`remove`/`prune`/`path` dos worktrees |
49
56
  | `houndsman watchdog <id>` | Contexto de um watchdog (`--json`, `--rules`) |
50
57
  | `houndsman findings <sub>` | Triagem/correção dos findings (`list`/`set`/`done`/`sync`/`batch`/`verify`/...) |
51
58
  | `houndsman server` | UI local de triagem (Bun.serve + Preact) |
@@ -57,7 +64,8 @@ Um único skill (`/houndsman`), quatro capabilities (detalhadas em `hunt.md`, `t
57
64
  ### Flags
58
65
 
59
66
  `--config <path>` · `--base <branch>` (default `main`) · `--head <ref>` (default `HEAD`) ·
60
- `--branch <nome>` · `--clean` · `--full` · `--no-jev` · `--fail-on-blocking` (no `--finalize`).
67
+ `--branch <nome>` · `--pr <n>` · `--worktree <path>` · `--clean` · `--full` · `--no-jev` ·
68
+ `--fail-on-blocking` (no `--finalize`).
61
69
 
62
70
  ## Artefatos
63
71
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: houndsman
3
- description: 'Revisa Pull Requests com watchdogs especializados por domínio de negócio e mantém essas regras alinhadas ao projeto. Use para revisar/code review de PR, atualizar as regras de revisão dos watchdogs e corrigir/verificar os findings da revisão. Capabilities: `hunt` (revisar a PR), `train` (atualizar regras), `fix` (corrigir achados), `verify` (violações resolvidas?).'
4
- argument-hint: 'Capability: hunt | train | fix | verify (default: hunt)'
3
+ description: 'Revisa Pull Requests com watchdogs especializados por domínio de negócio e mantém essas regras alinhadas ao projeto. Use para revisar/code review de PR, atualizar as regras de revisão dos watchdogs e corrigir/verificar os findings da revisão. Quando o alvo é uma PR (#456, “PR 456” ou URL do GitHub), revisa em worktree isolado automaticamente. Capabilities: `hunt` (revisar a PR), `train` (atualizar regras), `fix` (corrigir achados), `verify` (violações resolvidas?).'
4
+ argument-hint: 'Capability e alvo: hunt --pr 456 | hunt feature/x | train | fix | verify (default: hunt)'
5
5
  ---
6
6
 
7
7
  # houndsman — {{projectName}}
@@ -26,16 +26,50 @@ especialista por domínio · **finding** = um achado da revisão · **Jev** = pr
26
26
  ## Invocação
27
27
 
28
28
  ```
29
- /houndsman → hunt (default)
30
- /houndsman hunt → revisar a Pull Request
31
- /houndsman train → atualizar as regras dos watchdogs
32
- /houndsman fix → corrigir os findings
33
- /houndsman verify → conferir se as violações foram resolvidas
29
+ /houndsman → hunt (default)
30
+ /houndsman hunt → revisar a Pull Request
31
+ /houndsman hunt, revise a pr 456 → hunt da PR 456 (worktree automático)
32
+ /houndsman hunt feature/minha-branch → hunt da branch (clone atual)
33
+ /houndsman train → atualizar as regras dos watchdogs
34
+ /houndsman fix → corrigir os findings
35
+ /houndsman verify → conferir se as violações foram resolvidas
34
36
  ```
35
37
 
36
- Um argumento extra é o alvo da capability (ex.: `/houndsman hunt feature/minha-branch`).
37
- Escolha a capability pelo que o usuário quer, leia o documento correspondente em
38
- `.houndsman/core/skill/<capability>.md` e siga-o.
38
+ Um argumento extra é o alvo da capability. Escolha a capability pelo que o usuário quer,
39
+ leia o documento correspondente em `.houndsman/core/skill/<capability>.md` e siga-o.
40
+
41
+ ### Alvo da revisão (PR × branch)
42
+
43
+ Interprete o alvo em linguagem natural **antes** de rodar o CLI:
44
+
45
+ | O usuário disse | Alvo | Flags |
46
+ |---|---|---|
47
+ | `PR 456`, `#456`, `pull 456`, `456` (número sozinho), `https://github.com/org/repo/pull/456` | PR | `--pr 456` |
48
+ | `feature/minha-branch`, `branch feature/x` | branch | `--branch feature/minha-branch` |
49
+ | nada | branch atual | *(sem flag)* |
50
+
51
+ > **PR citada ⇒ worktree obrigatório.** Nunca rode `houndsman` “puro” para revisar uma PR que o
52
+ > usuário nomeou: o prepare precisa criar o worktree dedicado. Também **nunca** faça
53
+ > `git checkout` da PR no clone principal — é isso que permite revisar várias PRs ao mesmo
54
+ > tempo.
55
+
56
+ Sequência para uma PR (ex.: 456):
57
+
58
+ ```bash
59
+ houndsman context --pr 456
60
+ houndsman --pr 456 # cria/reusa o worktree e imprime o caminho
61
+ # despache os briefs (cada um traz **Worktree:** <path>)
62
+ houndsman --pr 456 --finalize
63
+ ```
64
+
65
+ - O worktree vive em `<repo>/.houndsman/worktrees/<repo>/<branch>` (detached no commit da PR)
66
+ e é reutilizado nas próximas execuções da mesma branch. Ele fica **dentro do workspace**
67
+ (e o staging também) para o agente ler/executar sem prompts de permissão.
68
+ - Use `--worktree <path>` para aproveitar um worktree já existente.
69
+ - O prepare imprime `PR #456 — <head> → <base>`; use `<head>` em `status ping`,
70
+ `findings` e `verify` (`--branch <head>`). A review guarda o worktree, então esses
71
+ comandos leem a árvore correta.
72
+ - PR de fork também funciona: o CLI busca `refs/pull/<n>/head`.
39
73
 
40
74
  > **Depois de revisar (`hunt`), valide na UI:** `bun run houndsman server --open` — revise os
41
75
  > achados e marque os que devem ser executados (`execute`) antes de rodar `fix`.