@sean.holung/minicode 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -47
- package/dist/scripts/run-benchmarks.js +73 -28
- package/dist/src/agent/config.js +51 -66
- package/dist/src/agent/editable-config.js +50 -58
- package/dist/src/agent/home-env.js +74 -0
- package/dist/src/benchmark/runner.js +142 -59
- package/dist/src/cli/config-slash-command.js +15 -13
- package/dist/src/indexer/project-index.js +49 -13
- package/dist/src/serve/agent-bridge.js +99 -31
- package/dist/src/serve/mcp-server.js +70 -21
- package/dist/src/serve/server.js +198 -8
- package/dist/src/session/session-preview.js +14 -0
- package/dist/src/shared/graph-search.js +80 -0
- package/dist/src/shared/graph-selection.js +40 -0
- package/dist/src/shared/graph-symbols.js +82 -0
- package/dist/src/shared/symbol-resolution.js +33 -0
- package/dist/src/tools/find-path.js +15 -6
- package/dist/src/tools/find-references.js +7 -2
- package/dist/src/tools/get-dependencies.js +8 -3
- package/dist/src/tools/read-symbol.js +9 -3
- package/dist/src/tools/registry.js +4 -1
- package/dist/src/tools/search-code-map.js +18 -3
- package/dist/src/web/app.js +646 -87
- package/dist/src/web/index.html +68 -6
- package/dist/src/web/style.css +208 -1
- package/dist/tests/benchmark-harness.test.js +100 -0
- package/dist/tests/config-api.test.js +5 -5
- package/dist/tests/config-integration.test.js +130 -56
- package/dist/tests/config-slash-command.test.js +12 -11
- package/dist/tests/config.test.js +12 -4
- package/dist/tests/editable-config.test.js +15 -12
- package/dist/tests/file-tools.test.js +34 -1
- package/dist/tests/find-path.test.js +43 -2
- package/dist/tests/find-references.test.js +49 -0
- package/dist/tests/get-dependencies.test.js +23 -0
- package/dist/tests/graph-onboarding.test.js +10 -1
- package/dist/tests/graph-search.test.js +66 -0
- package/dist/tests/graph-selection.test.js +58 -0
- package/dist/tests/graph-symbols.test.js +45 -0
- package/dist/tests/home-env.test.js +56 -0
- package/dist/tests/indexer.test.js +6 -0
- package/dist/tests/read-symbol.test.js +35 -0
- package/dist/tests/request-tracker.test.js +15 -0
- package/dist/tests/run-benchmarks.test.js +117 -33
- package/dist/tests/search-code-map.test.js +2 -0
- package/dist/tests/serve.integration.test.js +338 -9
- package/dist/tests/session-preview.test.js +56 -0
- package/dist/tests/session-ui.test.js +4 -0
- package/dist/tests/settings-ui.test.js +18 -0
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js +2 -1
- package/node_modules/@minicode/agent-sdk/dist/src/agent/agent.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/index.d.ts +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/index.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/index.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/indexer/types.d.ts +3 -0
- package/node_modules/@minicode/agent-sdk/dist/src/indexer/types.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/registry.d.ts +3 -0
- package/node_modules/@minicode/agent-sdk/dist/src/tools/registry.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/registry.js +4 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/registry.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/run-command.d.ts +11 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/run-command.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/run-command.js +4 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/run-command.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/search.d.ts.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/src/tools/search.js +16 -8
- package/node_modules/@minicode/agent-sdk/dist/src/tools/search.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/tests/file-tools.test.js +19 -2
- package/node_modules/@minicode/agent-sdk/dist/tests/file-tools.test.js.map +1 -1
- package/node_modules/@minicode/agent-sdk/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/src/web/index.html
CHANGED
|
@@ -61,7 +61,18 @@
|
|
|
61
61
|
<div class="config-overlay-content">
|
|
62
62
|
<h2>Agent not connected</h2>
|
|
63
63
|
<p id="config-missing" class="config-missing hidden"></p>
|
|
64
|
-
<
|
|
64
|
+
<div id="config-overlay-spotlight" class="config-overlay-spotlight">
|
|
65
|
+
<div class="config-overlay-spotlight-copy">
|
|
66
|
+
<span class="config-overlay-spotlight-badge">Fastest way to start</span>
|
|
67
|
+
<strong>Try minicode for free with OpenRouter</strong>
|
|
68
|
+
<p>Create a free OpenRouter account, connect it to this <code>minicode serve</code> session, and use free models without editing config files first.</p>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="config-overlay-actions config-overlay-spotlight-actions">
|
|
71
|
+
<button id="connect-openrouter-btn" class="dropdown-action" type="button" data-openrouter-connect="true">Connect OpenRouter</button>
|
|
72
|
+
<span class="config-overlay-action-note">Session-only. Nothing is written to disk.</span>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
<p id="config-overlay-intro">minicode needs a model provider to run. Configure one of the following:</p>
|
|
65
76
|
<div class="config-overlay-options">
|
|
66
77
|
<div class="config-overlay-option">
|
|
67
78
|
<strong>Local model (LM Studio, Ollama, etc.)</strong>
|
|
@@ -79,13 +90,14 @@ MODEL=claude-sonnet-4-20250514</pre>
|
|
|
79
90
|
</div>
|
|
80
91
|
<div class="config-overlay-option">
|
|
81
92
|
<strong>OpenRouter / remote OpenAI-compatible</strong>
|
|
82
|
-
<p>Set in <code>~/.minicode/.env</code> or your shell environment:</p>
|
|
93
|
+
<p>Set it manually in <code>~/.minicode/.env</code> or your shell environment:</p>
|
|
83
94
|
<pre>MODEL_PROVIDER=openai-compatible
|
|
84
95
|
OPENAI_BASE_URL=https://openrouter.ai/api/v1
|
|
85
96
|
OPENROUTER_API_KEY=sk-or-...
|
|
86
97
|
MODEL=your-model-name</pre>
|
|
87
98
|
</div>
|
|
88
99
|
</div>
|
|
100
|
+
<p id="config-connect-status" class="config-connect-status hidden"></p>
|
|
89
101
|
<p class="config-overlay-footer">After updating your config, restart <code>minicode serve</code>.</p>
|
|
90
102
|
</div>
|
|
91
103
|
</div>
|
|
@@ -101,7 +113,7 @@ MODEL=your-model-name</pre>
|
|
|
101
113
|
<div id="pane-divider"></div>
|
|
102
114
|
<div id="graph-pane">
|
|
103
115
|
<div id="graph-toolbar">
|
|
104
|
-
<input id="graph-search" type="text" placeholder="Search symbols..." autocomplete="off" />
|
|
116
|
+
<input id="graph-search" type="text" placeholder="Search symbols or files..." autocomplete="off" />
|
|
105
117
|
<button id="graph-analyze" class="header-btn">Analyze</button>
|
|
106
118
|
<button id="graph-fit" class="header-btn">Fit</button>
|
|
107
119
|
<button id="graph-relayout" class="header-btn">Re-layout</button>
|
|
@@ -144,26 +156,33 @@ MODEL=your-model-name</pre>
|
|
|
144
156
|
<div class="modal-header">
|
|
145
157
|
<div>
|
|
146
158
|
<h2 id="settings-title">Settings</h2>
|
|
147
|
-
<p id="settings-subtitle" class="modal-subtitle">Persist non-secret global defaults for future sessions.</p>
|
|
159
|
+
<p id="settings-subtitle" class="modal-subtitle">Persist non-secret global defaults in <code>~/.minicode/.env</code> for future sessions.</p>
|
|
148
160
|
</div>
|
|
149
161
|
<button id="settings-close" class="header-btn" type="button">Close</button>
|
|
150
162
|
</div>
|
|
151
163
|
|
|
152
164
|
<div class="settings-toolbar">
|
|
153
165
|
<div class="settings-path-group">
|
|
154
|
-
<span class="settings-path-label">
|
|
166
|
+
<span class="settings-path-label">Env file</span>
|
|
155
167
|
<code id="settings-path" class="settings-path"></code>
|
|
156
168
|
</div>
|
|
157
169
|
</div>
|
|
158
170
|
|
|
159
171
|
<div id="settings-banner" class="settings-banner hidden" role="status" aria-live="polite"></div>
|
|
172
|
+
<div id="settings-openrouter-session" class="settings-session-banner hidden" role="status" aria-live="polite">
|
|
173
|
+
<div class="settings-session-copy">
|
|
174
|
+
<div class="settings-session-title">OpenRouter is connected for this serve session</div>
|
|
175
|
+
<div id="settings-openrouter-session-meta" class="settings-session-meta"></div>
|
|
176
|
+
</div>
|
|
177
|
+
<button id="disconnect-openrouter-btn" class="header-btn" type="button">Disconnect OpenRouter</button>
|
|
178
|
+
</div>
|
|
160
179
|
<div id="settings-list" class="settings-list">
|
|
161
180
|
<div class="dropdown-empty">Loading settings...</div>
|
|
162
181
|
</div>
|
|
163
182
|
|
|
164
183
|
<div class="modal-footer">
|
|
165
184
|
<p class="settings-footnote">
|
|
166
|
-
Secrets such as API keys stay env-only for now. Saved changes update <code>~/.minicode
|
|
185
|
+
Secrets such as API keys stay env-only for now. Saved changes update <code>~/.minicode/.env</code> and apply to new runs after restart.
|
|
167
186
|
</p>
|
|
168
187
|
<div class="settings-actions">
|
|
169
188
|
<button id="settings-reset" class="header-btn" type="button">Reset changes</button>
|
|
@@ -173,6 +192,49 @@ MODEL=your-model-name</pre>
|
|
|
173
192
|
</section>
|
|
174
193
|
</div>
|
|
175
194
|
|
|
195
|
+
<div id="openrouter-connect-modal" class="modal hidden" aria-hidden="true">
|
|
196
|
+
<div id="openrouter-connect-backdrop" class="modal-backdrop"></div>
|
|
197
|
+
<section class="modal-panel modal-panel-compact" role="dialog" aria-modal="true" aria-labelledby="openrouter-connect-title">
|
|
198
|
+
<div class="modal-header">
|
|
199
|
+
<div>
|
|
200
|
+
<h2 id="openrouter-connect-title">Connect OpenRouter</h2>
|
|
201
|
+
<p class="modal-subtitle">Authorize this <code>minicode serve</code> session and optionally save the resulting setup for future runs.</p>
|
|
202
|
+
</div>
|
|
203
|
+
<button id="openrouter-connect-close" class="header-btn" type="button">Close</button>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div class="openrouter-connect-body">
|
|
207
|
+
<p class="openrouter-connect-lead">
|
|
208
|
+
minicode will redirect you to OpenRouter so you can sign in and approve access. By default, the resulting API key is used only for this live serve session.
|
|
209
|
+
</p>
|
|
210
|
+
|
|
211
|
+
<div class="openrouter-connect-note">
|
|
212
|
+
<strong>Optional persistence</strong>
|
|
213
|
+
<p>If you opt in below, minicode will update <code>~/.minicode/.env</code> after sign-in so future runs can reuse this OpenRouter setup.</p>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<label class="openrouter-persist-toggle" for="openrouter-persist-checkbox">
|
|
217
|
+
<input id="openrouter-persist-checkbox" type="checkbox" />
|
|
218
|
+
<span>Save the OpenRouter credentials and provider defaults to <code>~/.minicode/.env</code> after sign-in.</span>
|
|
219
|
+
</label>
|
|
220
|
+
|
|
221
|
+
<p class="openrouter-connect-help">
|
|
222
|
+
When enabled, minicode will store <code>OPENROUTER_API_KEY</code> and set <code>MODEL_PROVIDER</code> plus <code>OPENAI_BASE_URL</code> for OpenRouter. Nothing is written unless you check the box.
|
|
223
|
+
</p>
|
|
224
|
+
</div>
|
|
225
|
+
|
|
226
|
+
<div class="modal-footer">
|
|
227
|
+
<p class="settings-footnote">
|
|
228
|
+
OpenRouter handles the sign-in. minicode only receives the API key after you approve access.
|
|
229
|
+
</p>
|
|
230
|
+
<div class="settings-actions">
|
|
231
|
+
<button id="openrouter-connect-cancel" class="header-btn" type="button">Cancel</button>
|
|
232
|
+
<button id="openrouter-connect-continue" class="dropdown-action" type="button">Continue</button>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</section>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
176
238
|
<script type="module" src="app.js"></script>
|
|
177
239
|
</body>
|
|
178
240
|
</html>
|
package/dist/src/web/style.css
CHANGED
|
@@ -335,7 +335,7 @@ h1 {
|
|
|
335
335
|
inset: 0;
|
|
336
336
|
z-index: 50;
|
|
337
337
|
display: flex;
|
|
338
|
-
align-items:
|
|
338
|
+
align-items: flex-start;
|
|
339
339
|
justify-content: center;
|
|
340
340
|
background: rgba(26, 27, 38, 0.92);
|
|
341
341
|
backdrop-filter: blur(4px);
|
|
@@ -348,6 +348,7 @@ h1 {
|
|
|
348
348
|
.config-overlay-content {
|
|
349
349
|
max-width: 520px;
|
|
350
350
|
width: 100%;
|
|
351
|
+
margin: 0 auto;
|
|
351
352
|
}
|
|
352
353
|
|
|
353
354
|
.config-overlay-content h2 {
|
|
@@ -362,6 +363,52 @@ h1 {
|
|
|
362
363
|
margin-bottom: 16px;
|
|
363
364
|
}
|
|
364
365
|
|
|
366
|
+
.config-overlay-spotlight {
|
|
367
|
+
display: flex;
|
|
368
|
+
flex-direction: column;
|
|
369
|
+
gap: 12px;
|
|
370
|
+
margin-bottom: 16px;
|
|
371
|
+
padding: 14px 16px;
|
|
372
|
+
border-radius: 8px;
|
|
373
|
+
border: 1px solid rgba(122, 162, 247, 0.35);
|
|
374
|
+
background:
|
|
375
|
+
linear-gradient(135deg, rgba(122, 162, 247, 0.18), rgba(158, 206, 106, 0.08)),
|
|
376
|
+
var(--bg-surface);
|
|
377
|
+
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.config-overlay-spotlight-copy {
|
|
381
|
+
display: flex;
|
|
382
|
+
flex-direction: column;
|
|
383
|
+
gap: 6px;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.config-overlay-spotlight-badge {
|
|
387
|
+
align-self: flex-start;
|
|
388
|
+
padding: 2px 8px;
|
|
389
|
+
border-radius: 999px;
|
|
390
|
+
background: rgba(122, 162, 247, 0.18);
|
|
391
|
+
color: var(--accent);
|
|
392
|
+
font-size: 11px;
|
|
393
|
+
font-weight: 600;
|
|
394
|
+
letter-spacing: 0.02em;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.config-overlay-spotlight strong {
|
|
398
|
+
color: var(--text);
|
|
399
|
+
font-size: 14px;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.config-overlay-spotlight p {
|
|
403
|
+
margin: 0;
|
|
404
|
+
color: var(--text);
|
|
405
|
+
font-size: 12px;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.config-overlay-spotlight-actions {
|
|
409
|
+
margin-bottom: 0;
|
|
410
|
+
}
|
|
411
|
+
|
|
365
412
|
.config-missing {
|
|
366
413
|
color: var(--red, #f7768e);
|
|
367
414
|
font-size: 13px;
|
|
@@ -408,6 +455,44 @@ h1 {
|
|
|
408
455
|
word-break: break-all;
|
|
409
456
|
}
|
|
410
457
|
|
|
458
|
+
.config-overlay-actions {
|
|
459
|
+
display: flex;
|
|
460
|
+
align-items: center;
|
|
461
|
+
gap: 10px;
|
|
462
|
+
margin-bottom: 10px;
|
|
463
|
+
flex-wrap: wrap;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.config-overlay-action-note {
|
|
467
|
+
color: var(--text-dim);
|
|
468
|
+
font-size: 12px;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.config-connect-status {
|
|
472
|
+
font-size: 12px;
|
|
473
|
+
padding: 8px 12px;
|
|
474
|
+
border-radius: 4px;
|
|
475
|
+
margin-top: 14px;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.config-connect-status.info {
|
|
479
|
+
color: var(--text);
|
|
480
|
+
background: rgba(122, 162, 247, 0.14);
|
|
481
|
+
border: 1px solid rgba(122, 162, 247, 0.28);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.config-connect-status.success {
|
|
485
|
+
color: var(--green);
|
|
486
|
+
background: rgba(158, 206, 106, 0.12);
|
|
487
|
+
border: 1px solid rgba(158, 206, 106, 0.28);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.config-connect-status.error {
|
|
491
|
+
color: var(--red, #f7768e);
|
|
492
|
+
background: rgba(247, 118, 142, 0.12);
|
|
493
|
+
border: 1px solid rgba(247, 118, 142, 0.28);
|
|
494
|
+
}
|
|
495
|
+
|
|
411
496
|
.config-overlay-footer {
|
|
412
497
|
margin-top: 16px;
|
|
413
498
|
color: var(--text-dim);
|
|
@@ -773,6 +858,10 @@ footer {
|
|
|
773
858
|
overflow: hidden;
|
|
774
859
|
}
|
|
775
860
|
|
|
861
|
+
.modal-panel-compact {
|
|
862
|
+
width: min(640px, calc(100vw - 32px));
|
|
863
|
+
}
|
|
864
|
+
|
|
776
865
|
.modal-header,
|
|
777
866
|
.modal-footer,
|
|
778
867
|
.settings-toolbar {
|
|
@@ -1009,6 +1098,35 @@ footer {
|
|
|
1009
1098
|
gap: 8px;
|
|
1010
1099
|
}
|
|
1011
1100
|
|
|
1101
|
+
.settings-session-banner {
|
|
1102
|
+
display: flex;
|
|
1103
|
+
align-items: center;
|
|
1104
|
+
justify-content: space-between;
|
|
1105
|
+
gap: 14px;
|
|
1106
|
+
margin: 0 0 14px;
|
|
1107
|
+
padding: 12px 14px;
|
|
1108
|
+
border-radius: 10px;
|
|
1109
|
+
border: 1px solid rgba(122, 162, 247, 0.24);
|
|
1110
|
+
background: rgba(122, 162, 247, 0.09);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
.settings-session-copy {
|
|
1114
|
+
min-width: 0;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
.settings-session-title {
|
|
1118
|
+
font-size: 13px;
|
|
1119
|
+
color: var(--text);
|
|
1120
|
+
font-weight: 600;
|
|
1121
|
+
margin-bottom: 4px;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.settings-session-meta {
|
|
1125
|
+
font-size: 12px;
|
|
1126
|
+
color: var(--text-dim);
|
|
1127
|
+
overflow-wrap: anywhere;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1012
1130
|
.settings-help {
|
|
1013
1131
|
font-size: 11px;
|
|
1014
1132
|
color: var(--text-dim);
|
|
@@ -1040,6 +1158,65 @@ footer {
|
|
|
1040
1158
|
flex-shrink: 0;
|
|
1041
1159
|
}
|
|
1042
1160
|
|
|
1161
|
+
.openrouter-connect-body {
|
|
1162
|
+
padding: 20px;
|
|
1163
|
+
display: flex;
|
|
1164
|
+
flex-direction: column;
|
|
1165
|
+
gap: 14px;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
.openrouter-connect-lead {
|
|
1169
|
+
font-size: 13px;
|
|
1170
|
+
color: var(--text);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
.openrouter-connect-note {
|
|
1174
|
+
padding: 12px 14px;
|
|
1175
|
+
border-radius: 10px;
|
|
1176
|
+
border: 1px solid rgba(122, 162, 247, 0.22);
|
|
1177
|
+
background: rgba(122, 162, 247, 0.08);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
.openrouter-connect-note strong {
|
|
1181
|
+
display: block;
|
|
1182
|
+
color: var(--text);
|
|
1183
|
+
font-size: 13px;
|
|
1184
|
+
margin-bottom: 4px;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
.openrouter-connect-note p,
|
|
1188
|
+
.openrouter-connect-help {
|
|
1189
|
+
font-size: 12px;
|
|
1190
|
+
color: var(--text-dim);
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
.openrouter-persist-toggle {
|
|
1194
|
+
display: flex;
|
|
1195
|
+
align-items: flex-start;
|
|
1196
|
+
gap: 10px;
|
|
1197
|
+
padding: 12px 14px;
|
|
1198
|
+
border-radius: 10px;
|
|
1199
|
+
border: 1px solid var(--border);
|
|
1200
|
+
background: rgba(26, 27, 38, 0.72);
|
|
1201
|
+
cursor: pointer;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
.openrouter-persist-toggle input {
|
|
1205
|
+
margin-top: 2px;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.openrouter-persist-toggle span {
|
|
1209
|
+
font-size: 12px;
|
|
1210
|
+
color: var(--text);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
@media (max-width: 760px) {
|
|
1214
|
+
.settings-session-banner {
|
|
1215
|
+
flex-direction: column;
|
|
1216
|
+
align-items: flex-start;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1043
1220
|
.settings-list::-webkit-scrollbar,
|
|
1044
1221
|
.settings-path::-webkit-scrollbar {
|
|
1045
1222
|
width: 6px;
|
|
@@ -1126,6 +1303,7 @@ main::-webkit-scrollbar-thumb {
|
|
|
1126
1303
|
display: flex;
|
|
1127
1304
|
align-items: center;
|
|
1128
1305
|
justify-content: space-between;
|
|
1306
|
+
gap: 12px;
|
|
1129
1307
|
padding: 6px 10px;
|
|
1130
1308
|
cursor: pointer;
|
|
1131
1309
|
font-size: 12px;
|
|
@@ -1136,14 +1314,39 @@ main::-webkit-scrollbar-thumb {
|
|
|
1136
1314
|
background: var(--bg-hover);
|
|
1137
1315
|
}
|
|
1138
1316
|
|
|
1317
|
+
.search-result-body {
|
|
1318
|
+
display: flex;
|
|
1319
|
+
flex: 1;
|
|
1320
|
+
flex-direction: column;
|
|
1321
|
+
min-width: 0;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1139
1324
|
.search-result-name {
|
|
1140
1325
|
color: var(--text);
|
|
1141
1326
|
font-weight: 500;
|
|
1327
|
+
overflow: hidden;
|
|
1328
|
+
text-overflow: ellipsis;
|
|
1329
|
+
white-space: nowrap;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
.search-result-subtitle {
|
|
1333
|
+
color: var(--text-dim);
|
|
1334
|
+
font-size: 11px;
|
|
1335
|
+
overflow: hidden;
|
|
1336
|
+
text-overflow: ellipsis;
|
|
1337
|
+
white-space: nowrap;
|
|
1142
1338
|
}
|
|
1143
1339
|
|
|
1144
1340
|
.search-result-kind {
|
|
1145
1341
|
font-size: 11px;
|
|
1146
1342
|
opacity: 0.7;
|
|
1343
|
+
flex-shrink: 0;
|
|
1344
|
+
letter-spacing: 0.04em;
|
|
1345
|
+
text-transform: uppercase;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
.search-result-kind.file {
|
|
1349
|
+
opacity: 0.9;
|
|
1147
1350
|
}
|
|
1148
1351
|
|
|
1149
1352
|
#cy {
|
|
@@ -1799,6 +2002,10 @@ main::-webkit-scrollbar-thumb {
|
|
|
1799
2002
|
align-items: stretch;
|
|
1800
2003
|
}
|
|
1801
2004
|
|
|
2005
|
+
.openrouter-persist-toggle {
|
|
2006
|
+
align-items: flex-start;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
1802
2009
|
.settings-path-group {
|
|
1803
2010
|
align-items: flex-start;
|
|
1804
2011
|
}
|
|
@@ -40,6 +40,8 @@ function makeTrace(overrides = {}) {
|
|
|
40
40
|
model: "test-model",
|
|
41
41
|
variant: "baseline",
|
|
42
42
|
commitSha: "abc123",
|
|
43
|
+
sourceWorkspaceRoot: "/workspace/source",
|
|
44
|
+
workspaceRoot: "/tmp/minicode-benchmark/task",
|
|
43
45
|
response: "Found foo in src/foo.ts at line 10.",
|
|
44
46
|
toolCalls: [
|
|
45
47
|
{ name: "search", input: { query: "foo" }, output: "src/foo.ts:10", durationMs: 50 },
|
|
@@ -141,6 +143,24 @@ test("loadBenchmarkTask loads a single task by id", async () => {
|
|
|
141
143
|
await rm(tmpDir, { recursive: true });
|
|
142
144
|
}
|
|
143
145
|
});
|
|
146
|
+
test("loadBenchmarkTask preserves workspaceRoot when provided", async () => {
|
|
147
|
+
const tmpDir = await mkdtemp(path.join(tmpdir(), "bench-workspace-root-"));
|
|
148
|
+
await mkdir(path.join(tmpDir, "navigation", "fixture-task"), { recursive: true });
|
|
149
|
+
await writeFile(path.join(tmpDir, "navigation", "fixture-task", "task.json"), JSON.stringify({
|
|
150
|
+
title: "Fixture task",
|
|
151
|
+
prompt: "Use a fixture workspace",
|
|
152
|
+
workspaceRoot: "test-programs/benchmark-index",
|
|
153
|
+
rubric: {},
|
|
154
|
+
}));
|
|
155
|
+
try {
|
|
156
|
+
const task = await loadBenchmarkTask(tmpDir, "navigation/fixture-task");
|
|
157
|
+
assert.ok(task);
|
|
158
|
+
assert.equal(task.workspaceRoot, "test-programs/benchmark-index");
|
|
159
|
+
}
|
|
160
|
+
finally {
|
|
161
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
});
|
|
144
164
|
test("loadBenchmarkTask returns undefined for missing task", async () => {
|
|
145
165
|
const tmpDir = await createTempTaskDir();
|
|
146
166
|
try {
|
|
@@ -413,6 +433,86 @@ test("runBenchmarkTask tracks symbols from structural tools", async () => {
|
|
|
413
433
|
});
|
|
414
434
|
assert.ok(trace.symbolsQueried.includes("CodingAgent"));
|
|
415
435
|
});
|
|
436
|
+
test("runBenchmarkTask resolves task workspace overrides and isolates the run", async () => {
|
|
437
|
+
const repoRoot = await mkdtemp(path.join(tmpdir(), "bench-repo-root-"));
|
|
438
|
+
const sourceWorkspace = path.join(repoRoot, "fixtures", "sample-project");
|
|
439
|
+
await mkdir(path.join(sourceWorkspace, "src"), { recursive: true });
|
|
440
|
+
await writeFile(path.join(sourceWorkspace, "src", "index.ts"), "export const answer = 42;\n");
|
|
441
|
+
const task = {
|
|
442
|
+
id: "navigation/workspace-root",
|
|
443
|
+
title: "Workspace root test",
|
|
444
|
+
category: "navigation",
|
|
445
|
+
prompt: "Inspect the fixture workspace",
|
|
446
|
+
workspaceRoot: "fixtures/sample-project",
|
|
447
|
+
rubric: {},
|
|
448
|
+
};
|
|
449
|
+
try {
|
|
450
|
+
const config = createTestAgentConfig(repoRoot);
|
|
451
|
+
const trace = await runBenchmarkTask(task, {
|
|
452
|
+
modelClient: new MockModelClient("done"),
|
|
453
|
+
config,
|
|
454
|
+
tools: [],
|
|
455
|
+
variant: "test",
|
|
456
|
+
repoRoot,
|
|
457
|
+
});
|
|
458
|
+
assert.equal(trace.sourceWorkspaceRoot, sourceWorkspace);
|
|
459
|
+
assert.notEqual(trace.workspaceRoot, sourceWorkspace);
|
|
460
|
+
assert.ok(trace.workspaceRoot.includes("minicode-benchmark-"));
|
|
461
|
+
}
|
|
462
|
+
finally {
|
|
463
|
+
await rm(repoRoot, { recursive: true, force: true });
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
test("runBenchmarkTask uses project index metadata to count read_symbol as a file read", async () => {
|
|
467
|
+
const workspaceRoot = path.resolve(import.meta.dirname, "..");
|
|
468
|
+
const task = {
|
|
469
|
+
id: "navigation/structural-file-tracking",
|
|
470
|
+
title: "Structural file tracking",
|
|
471
|
+
category: "navigation",
|
|
472
|
+
prompt: "Read the CodingAgent symbol",
|
|
473
|
+
rubric: {},
|
|
474
|
+
};
|
|
475
|
+
let callCount = 0;
|
|
476
|
+
const mockClient = {
|
|
477
|
+
async chat(params) {
|
|
478
|
+
void params;
|
|
479
|
+
callCount += 1;
|
|
480
|
+
if (callCount === 1) {
|
|
481
|
+
return {
|
|
482
|
+
text: "Looking up symbol",
|
|
483
|
+
toolCalls: [{ id: "t1", name: "read_symbol", input: { name: "CodingAgent" } }],
|
|
484
|
+
stopReason: "tool_use",
|
|
485
|
+
usage: { inputTokens: 100, outputTokens: 50 },
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
text: "Found CodingAgent",
|
|
490
|
+
toolCalls: [],
|
|
491
|
+
stopReason: "end_turn",
|
|
492
|
+
usage: { inputTokens: 100, outputTokens: 50 },
|
|
493
|
+
};
|
|
494
|
+
},
|
|
495
|
+
};
|
|
496
|
+
const config = createTestAgentConfig(workspaceRoot);
|
|
497
|
+
const trace = await runBenchmarkTask(task, {
|
|
498
|
+
modelClient: mockClient,
|
|
499
|
+
config,
|
|
500
|
+
variant: "v1",
|
|
501
|
+
isolateWorkspace: false,
|
|
502
|
+
createToolset: async (taskConfig) => {
|
|
503
|
+
const { buildProjectIndex } = await import("../src/indexer/project-index.js");
|
|
504
|
+
const { createToolRegistry } = await import("../src/tools/registry.js");
|
|
505
|
+
const projectIndex = await buildProjectIndex(taskConfig.workspaceRoot);
|
|
506
|
+
const toolRegistry = createToolRegistry(taskConfig, projectIndex);
|
|
507
|
+
return {
|
|
508
|
+
tools: toolRegistry.getDefinitions(),
|
|
509
|
+
projectIndex,
|
|
510
|
+
};
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
assert.ok(trace.symbolsQueried.includes("CodingAgent"));
|
|
514
|
+
assert.ok(trace.filesRead.some((file) => file.endsWith("packages/agent-sdk/src/agent/agent.ts")), "read_symbol should count the owning file as read");
|
|
515
|
+
});
|
|
416
516
|
// ─── Reporter Tests ────────────────────────────────────────────
|
|
417
517
|
test("buildReport generates correct summary", () => {
|
|
418
518
|
const tasks = [
|
|
@@ -80,7 +80,7 @@ test("GET /api/config returns structured editable settings payload", async () =>
|
|
|
80
80
|
assert.match(body.config, /workspaceRoot/);
|
|
81
81
|
assert.equal(body.restartRequired, true);
|
|
82
82
|
assert.equal(body.secretsUiSupported, false);
|
|
83
|
-
assert.equal(body.settings.configPath, path.join(minicodeHome, "
|
|
83
|
+
assert.equal(body.settings.configPath, path.join(minicodeHome, ".env"));
|
|
84
84
|
const maxSteps = body.settings.entries.find((entry) => entry.key === "maxSteps");
|
|
85
85
|
assert.equal(maxSteps?.type, "number");
|
|
86
86
|
assert.equal(maxSteps?.envVar, "MAX_STEPS");
|
|
@@ -111,16 +111,16 @@ test("POST /api/config persists global settings and returns updated metadata", a
|
|
|
111
111
|
const body = await res.json();
|
|
112
112
|
assert.equal(body.ok, true);
|
|
113
113
|
assert.equal(body.scope, "global");
|
|
114
|
-
assert.equal(body.path, path.join(minicodeHome, "
|
|
114
|
+
assert.equal(body.path, path.join(minicodeHome, ".env"));
|
|
115
115
|
assert.equal(body.restartRequired, true);
|
|
116
116
|
assert.match(body.message, /Persisted config updated/);
|
|
117
117
|
assert.deepEqual(body.saved, [
|
|
118
118
|
{ key: "maxSteps", value: 42 },
|
|
119
119
|
{ key: "enableDynamicPrompt", value: false },
|
|
120
120
|
]);
|
|
121
|
-
const persisted =
|
|
122
|
-
assert.
|
|
123
|
-
assert.
|
|
121
|
+
const persisted = await readFile(path.join(minicodeHome, ".env"), "utf8");
|
|
122
|
+
assert.match(persisted, /^MAX_STEPS=42$/m);
|
|
123
|
+
assert.match(persisted, /^ENABLE_DYNAMIC_PROMPT=false$/m);
|
|
124
124
|
const maxSteps = body.settings.entries.find((entry) => entry.key === "maxSteps");
|
|
125
125
|
assert.equal(maxSteps?.persistedValue, 42);
|
|
126
126
|
});
|