tarsk 0.5.78 → 0.5.79

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 (145) hide show
  1. package/dist/bundled-skills/skill-creator/eval-viewer/generate_review.js +183 -95
  2. package/dist/bundled-skills/skill-creator/scripts/__tests__/improve_description.test.js +77 -0
  3. package/dist/bundled-skills/skill-creator/scripts/__tests__/package_skill.test.js +203 -0
  4. package/dist/bundled-skills/skill-creator/scripts/__tests__/run_eval.test.js +125 -0
  5. package/dist/bundled-skills/skill-creator/scripts/__tests__/utils.test.js +149 -0
  6. package/dist/bundled-skills/skill-creator/scripts/aggregate_benchmark.js +2 -0
  7. package/dist/bundled-skills/skill-creator/scripts/improve_description.js +42 -22
  8. package/dist/bundled-skills/skill-creator/scripts/package_skill.js +68 -40
  9. package/dist/bundled-skills/skill-creator/scripts/run_eval.js +60 -32
  10. package/dist/bundled-skills/skill-creator/scripts/run_loop.js +224 -150
  11. package/dist/bundled-skills/skill-creator/scripts/utils.js +71 -41
  12. package/dist/index.js +162426 -152725
  13. package/dist/node_modules/@libsql/darwin-x64/README.md +3 -0
  14. package/dist/node_modules/@libsql/darwin-x64/index.node +0 -0
  15. package/dist/node_modules/@libsql/darwin-x64/package.json +36 -0
  16. package/dist/public/assets/account-view-DGfJrmbM.js +1 -0
  17. package/dist/public/assets/alert-dialog-D5UGH4qW.js +7 -0
  18. package/dist/public/assets/api-odZ7g9AN.js +2 -0
  19. package/dist/public/assets/{async-error-boundary-Dll_zcqr.js → async-error-boundary-CbAQza_Z.js} +1 -1
  20. package/dist/public/assets/browser-tab-DZUa8JpJ.js +12 -0
  21. package/dist/public/assets/{button-B5aMz2Rk.js → button-B7hsXP2P.js} +1 -1
  22. package/dist/public/assets/{card-DRr14MEQ.js → card-BTgRxBeB.js} +1 -1
  23. package/dist/public/assets/chat-dock-context-CANpJk1z.js +1 -0
  24. package/dist/public/assets/{commit-dialog-C-JfaoS6.js → commit-dialog-DAUjE4cb.js} +1 -1
  25. package/dist/public/assets/{commit-error-dialog-VXqZLeta.js → commit-error-dialog-2tnhCseF.js} +1 -1
  26. package/dist/public/assets/{commit-method-fields-DAd1unUF.js → commit-method-fields-Dj2uqPrP.js} +1 -1
  27. package/dist/public/assets/conversation-history-view-CpinBoLp.js +1 -0
  28. package/dist/public/assets/create-project-dialog-V4ZiwQkg.js +2 -0
  29. package/dist/public/assets/{create-repo-dialog-mBGGkX-g.js → create-repo-dialog-DG9Ax-yf.js} +1 -1
  30. package/dist/public/assets/delete-confirm-dialog-Dg2q6cGA.js +1 -0
  31. package/dist/public/assets/diff-view-KJQqPVMa.js +4 -0
  32. package/dist/public/assets/{dist-T8-4ZfS0.js → dist-B9o9ZI_U.js} +1 -1
  33. package/dist/public/assets/{dist-DwblUvSf.js → dist-BF1fIO22.js} +1 -1
  34. package/dist/public/assets/{dist-CWYnBq-n.js → dist-CM7ef_Ef.js} +1 -1
  35. package/dist/public/assets/{dist-COfI64N5.js → dist-Ms_QN0HI.js} +1 -1
  36. package/dist/public/assets/{dist-sThe8WYP.js → dist-R7ILWSDv.js} +1 -1
  37. package/dist/public/assets/{dist-DDYi9MQo.js → dist-T2H2nD62.js} +1 -1
  38. package/dist/public/assets/{dist-TCNzmc2V.js → dist-Xi9Q--PI.js} +1 -1
  39. package/dist/public/assets/dist-bAGdBaoO.js +2 -0
  40. package/dist/public/assets/{es2015-Bu0NIPbn.js → es2015-3o6GJKAC.js} +1 -1
  41. package/dist/public/assets/{explorer-monaco-editor-q8CnSwWA.js → explorer-monaco-editor-BUfO46YV.js} +1 -1
  42. package/dist/public/assets/explorer-tab-view-CXFHVIyO.js +2 -0
  43. package/dist/public/assets/explorer-tree-D3N9CgUw.js +1 -0
  44. package/dist/public/assets/explorer-view-Qla3PjXX.js +76 -0
  45. package/dist/public/assets/{git-history-dialog-XEr5pugf.js → git-history-dialog-hQ3LY348.js} +1 -1
  46. package/dist/public/assets/index-BQ4LyrcX.css +1 -0
  47. package/dist/public/assets/index-C1jToYjL.js +112 -0
  48. package/dist/public/assets/{lucide-react-B-115rul.js → lucide-react-CNNzKD4G.js} +1 -1
  49. package/dist/public/assets/{model-list-controls-DAZM0NBC.js → model-list-controls-Dzi-bA4G.js} +1 -1
  50. package/dist/public/assets/onboarding-dialog-CWHYidh3.js +1 -0
  51. package/dist/public/assets/{pill-tabs-QsjH027B.js → pill-tabs-B-GZBSAx.js} +1 -1
  52. package/dist/public/assets/{progress-indicator-C01aPXIe.js → progress-indicator-Dr6KLjL5.js} +1 -1
  53. package/dist/public/assets/project-coding-view-XHObCz5c.js +1 -0
  54. package/dist/public/assets/{project-danger-zone-view-BaSu793w.js → project-danger-zone-view-DnUMqsVk.js} +1 -1
  55. package/dist/public/assets/project-env-vars-view-CZ2H31qr.js +1 -0
  56. package/dist/public/assets/project-model-aliases-view-BDLn_rnO.js +1 -0
  57. package/dist/public/assets/project-settings-view-BiPB--It.js +1 -0
  58. package/dist/public/assets/project-tools-view-rHqvcYmB.js +1 -0
  59. package/dist/public/assets/providers-list-view-CgmQms1S.js +1 -0
  60. package/dist/public/assets/pull-request-dialog-B2IuZfiC.js +1 -0
  61. package/dist/public/assets/{pull-with-changes-dialog-DDp_srHq.js → pull-with-changes-dialog-0GcFybrs.js} +1 -1
  62. package/dist/public/assets/{push-before-pr-dialog-Bt0BChlV.js → push-before-pr-dialog-BsHxhNkj.js} +1 -1
  63. package/dist/public/assets/{scroll-area-DwRwR2nQ.js → scroll-area-fMQC4KJw.js} +1 -1
  64. package/dist/public/assets/settings-general-tabs-view-DFH-XX7K.js +2 -0
  65. package/dist/public/assets/settings-general-view-DQTKXkvD.js +1 -0
  66. package/dist/public/assets/settings-list-COPIEKbu.js +1 -0
  67. package/dist/public/assets/settings-logs-view-DkZI0-PQ.js +5 -0
  68. package/dist/public/assets/settings-mcp-servers-view-DNUF0p87.js +5 -0
  69. package/dist/public/assets/settings-models-view-CAfXeeqi.js +1 -0
  70. package/dist/public/assets/settings-plugins-view-Wgp98zEC.js +2 -0
  71. package/dist/public/assets/settings-providers-view-CDXMVzWQ.js +2 -0
  72. package/dist/public/assets/settings-setup-view-gkQGOFn4.js +2 -0
  73. package/dist/public/assets/settings-skills-view-CcyTQlPl.js +2 -0
  74. package/dist/public/assets/settings-slack-view-idgTLLDo.js +1 -0
  75. package/dist/public/assets/settings-slash-commands-view-CPfpTFt5.js +1 -0
  76. package/dist/public/assets/settings-statistics-view-CewvaKLi.js +1 -0
  77. package/dist/public/assets/settings-storage-view-3HPIVaYG.js +1 -0
  78. package/dist/public/assets/settings-subagents-view-CWD4EWyU.js +2 -0
  79. package/dist/public/assets/settings-system-prompt-view-DitIaAmi.js +1 -0
  80. package/dist/public/assets/{settings-tab-bar-DAHxT5KE.js → settings-tab-bar-BKrNKoYV.js} +1 -1
  81. package/dist/public/assets/settings-view-C1rDwQOL.js +2 -0
  82. package/dist/public/assets/{slug-utils-BQZ6c2py.js → slug-utils-ZC2qISlV.js} +1 -1
  83. package/dist/public/assets/store-DqAPgNUQ.js +9 -0
  84. package/dist/public/assets/{table-7hMwxpkF.js → table-DjVI02Kg.js} +1 -1
  85. package/dist/public/assets/tasks-view-07DwlYR7.js +1 -0
  86. package/dist/public/assets/{terminal-panel-BNOIOh8z.js → terminal-panel-B-B0Mjbv.js} +2 -2
  87. package/dist/public/assets/{toggle-group-UiksQ0n9.js → toggle-group-Ti6E2rBa.js} +1 -1
  88. package/dist/public/assets/{tooltip-Dvmz78Z_.js → tooltip-Dz8vH1DG.js} +1 -1
  89. package/dist/public/assets/{use-active-dock-panel-instance-2LfvItRH.js → use-active-dock-panel-instance-C7H1mX2G.js} +1 -1
  90. package/dist/public/assets/use-installed-ai-files-CNN44_z3.js +1 -0
  91. package/dist/public/assets/use-settings-page-loading-CpaBd260.js +1 -0
  92. package/dist/public/assets/use-toast-xpb5jNtN.js +1 -0
  93. package/dist/public/assets/{useBaseQuery-D5as4SgS.js → useBaseQuery-DZ0hJ6lN.js} +1 -1
  94. package/dist/public/assets/{utils-B-qS8qMg.js → utils-BW67ZVub.js} +1 -1
  95. package/dist/public/assets/{web-DyqJbQ3L.js → web-BBOGW-Jp.js} +1 -1
  96. package/dist/public/assets/{web-gEWIDddb.js → web-CsFwi45J.js} +1 -1
  97. package/dist/public/assets/{web-B9ndApmi.js → web-DmkLaAFF.js} +1 -1
  98. package/dist/public/assets/{web-BkuMY08B.js → web-kuH5W1xE.js} +1 -1
  99. package/dist/public/browser-preview-rpc.js +123 -68
  100. package/dist/public/index.html +25 -23
  101. package/package.json +6 -5
  102. package/dist/public/assets/account-view-Bzv2EHnc.js +0 -1
  103. package/dist/public/assets/api-OO3KSG8d.js +0 -2
  104. package/dist/public/assets/browser-tab-Cwa1TB3I.js +0 -12
  105. package/dist/public/assets/chat-dock-context-Cnq0BWgm.js +0 -1
  106. package/dist/public/assets/context-menu-BKOotkeD.js +0 -1
  107. package/dist/public/assets/conversation-history-view-CcdQRxoP.js +0 -1
  108. package/dist/public/assets/create-project-dialog-D1VaSgqh.js +0 -2
  109. package/dist/public/assets/delete-confirm-dialog-Cx9nT7Xd.js +0 -1
  110. package/dist/public/assets/diff-view-CyOnLSEA.js +0 -4
  111. package/dist/public/assets/dist-DNkA3vYh.js +0 -2
  112. package/dist/public/assets/explorer-tab-view-G2HmkQyY.js +0 -2
  113. package/dist/public/assets/explorer-tree-DAuc2Npx.js +0 -1
  114. package/dist/public/assets/explorer-view-BDMlnV3f.js +0 -76
  115. package/dist/public/assets/index-C4WzOmf3.css +0 -1
  116. package/dist/public/assets/index-DD_a7tQU.js +0 -3665
  117. package/dist/public/assets/onboarding-dialog-Dd9hiOOf.js +0 -1
  118. package/dist/public/assets/project-coding-view-DbKI7sbW.js +0 -1
  119. package/dist/public/assets/project-env-vars-view-BB66j52E.js +0 -1
  120. package/dist/public/assets/project-model-aliases-view-o1-Z2es5.js +0 -1
  121. package/dist/public/assets/project-settings-view-BKjvtOtk.js +0 -1
  122. package/dist/public/assets/project-tools-view-CZbblznF.js +0 -1
  123. package/dist/public/assets/providers-list-view-ChY2DXYc.js +0 -1
  124. package/dist/public/assets/pull-request-dialog-BZgY4vrw.js +0 -1
  125. package/dist/public/assets/settings-general-tabs-view-BH7AaXyP.js +0 -2
  126. package/dist/public/assets/settings-general-view-B-t99LmD.js +0 -1
  127. package/dist/public/assets/settings-list-Dn4CHP4Z.js +0 -1
  128. package/dist/public/assets/settings-logs-view-BCRjz-Fr.js +0 -5
  129. package/dist/public/assets/settings-mcp-servers-view-xv9D4DPO.js +0 -5
  130. package/dist/public/assets/settings-models-view-rUeqlE4k.js +0 -1
  131. package/dist/public/assets/settings-plugins-view-qnWmII61.js +0 -2
  132. package/dist/public/assets/settings-providers-view-DsxTdBEQ.js +0 -2
  133. package/dist/public/assets/settings-setup-view-ew5KW8gL.js +0 -2
  134. package/dist/public/assets/settings-skills-view-C4NxP4gI.js +0 -3
  135. package/dist/public/assets/settings-slack-view-BNT5ervf.js +0 -1
  136. package/dist/public/assets/settings-slash-commands-view-CE7FT3dB.js +0 -1
  137. package/dist/public/assets/settings-statistics-view-jKPoSWBs.js +0 -1
  138. package/dist/public/assets/settings-storage-view-C_Rs-9Hw.js +0 -1
  139. package/dist/public/assets/settings-subagents-view-DHVSAmCY.js +0 -2
  140. package/dist/public/assets/settings-system-prompt-view-B_nF2HUy.js +0 -1
  141. package/dist/public/assets/settings-view-BY6OO-xy.js +0 -2
  142. package/dist/public/assets/store-B7EgrEO7.js +0 -9
  143. package/dist/public/assets/tasks-view-Dc7sthjm.js +0 -1
  144. package/dist/public/assets/use-installed-ai-files-BkpswqGI.js +0 -1
  145. package/dist/public/assets/use-settings-page-loading-BTySlInF.js +0 -1
@@ -150,128 +150,141 @@ async function runIterationEval({
150
150
  return { evalElapsed, trainResults, testResults, trainSummary, testSummary };
151
151
  }
152
152
 
153
- async function runIteration(ctx) {
154
- const {
155
- iteration,
156
- maxIterations,
157
- trainSet,
158
- testSet,
159
- name,
160
- currentDescription,
161
- numWorkers,
162
- timeout,
163
- projectRoot,
164
- runsPerQuery,
165
- triggerThreshold,
166
- model,
167
- verbose,
168
- history,
169
- liveReportPath,
170
- originalDescription,
171
- holdout,
172
- content,
173
- logDir,
174
- } = ctx;
153
+ function printIterationHeader(ctx) {
154
+ if (!ctx.verbose) return;
175
155
 
176
- if (verbose) {
177
- process.stderr.write(`\n${"=".repeat(60)}\n`);
178
- process.stderr.write(`Iteration ${iteration}/${maxIterations}\n`);
179
- process.stderr.write(`Description: ${currentDescription}\n`);
180
- process.stderr.write(`${"=".repeat(60)}\n`);
181
- }
156
+ process.stderr.write(`\n${"=".repeat(60)}\n`);
157
+ process.stderr.write(`Iteration ${ctx.iteration}/${ctx.maxIterations}\n`);
158
+ process.stderr.write(`Description: ${ctx.currentDescription}\n`);
159
+ process.stderr.write(`${"=".repeat(60)}\n`);
160
+ }
182
161
 
183
- const { evalElapsed, trainResults, testResults, trainSummary, testSummary } =
184
- await runIterationEval({
185
- trainSet,
186
- testSet,
187
- name,
188
- currentDescription,
189
- numWorkers,
190
- timeout,
191
- projectRoot,
192
- runsPerQuery,
193
- triggerThreshold,
194
- model,
195
- });
162
+ function createTestHistoryFields(testSummary, testResults) {
163
+ if (!testSummary) {
164
+ return {
165
+ test_passed: null,
166
+ test_failed: null,
167
+ test_total: null,
168
+ test_results: null,
169
+ };
170
+ }
171
+ return {
172
+ test_passed: testSummary.passed,
173
+ test_failed: testSummary.failed,
174
+ test_total: testSummary.total,
175
+ test_results: testResults.results,
176
+ };
177
+ }
196
178
 
197
- history.push({
198
- iteration,
199
- description: currentDescription,
179
+ function createHistoryEntry(ctx, evaluation) {
180
+ const { trainResults, testResults, trainSummary, testSummary } = evaluation;
181
+ return {
182
+ iteration: ctx.iteration,
183
+ description: ctx.currentDescription,
200
184
  train_passed: trainSummary.passed,
201
185
  train_failed: trainSummary.failed,
202
186
  train_total: trainSummary.total,
203
187
  train_results: trainResults.results,
204
- test_passed: testSummary?.passed ?? null,
205
- test_failed: testSummary?.failed ?? null,
206
- test_total: testSummary?.total ?? null,
207
- test_results: testResults?.results ?? null,
188
+ ...createTestHistoryFields(testSummary, testResults),
208
189
  passed: trainSummary.passed,
209
190
  failed: trainSummary.failed,
210
191
  total: trainSummary.total,
211
192
  results: trainResults.results,
212
- });
193
+ };
194
+ }
213
195
 
214
- if (liveReportPath) {
215
- const partialOutput = {
216
- original_description: originalDescription,
217
- best_description: currentDescription,
218
- best_score: "in progress",
219
- iterations_run: history.length,
220
- holdout,
221
- train_size: trainSet.length,
222
- test_size: testSet.length,
223
- history,
224
- };
225
- fs.writeFileSync(liveReportPath, generateHtml(partialOutput, true, name));
226
- }
196
+ function writeLiveIterationReport(ctx) {
197
+ if (!ctx.liveReportPath) return;
198
+
199
+ const partialOutput = {
200
+ original_description: ctx.originalDescription,
201
+ best_description: ctx.currentDescription,
202
+ best_score: "in progress",
203
+ iterations_run: ctx.history.length,
204
+ holdout: ctx.holdout,
205
+ train_size: ctx.trainSet.length,
206
+ test_size: ctx.testSet.length,
207
+ history: ctx.history,
208
+ };
209
+ fs.writeFileSync(ctx.liveReportPath, generateHtml(partialOutput, true, ctx.name));
210
+ }
227
211
 
228
- if (verbose) {
229
- printEvalStats("Train", trainResults.results, evalElapsed);
230
- if (testSummary) {
231
- printEvalStats("Test ", testResults.results, 0);
232
- }
233
- }
212
+ function printIterationStats(ctx, evaluation) {
213
+ if (!ctx.verbose) return;
234
214
 
235
- if (trainSummary.failed === 0) {
236
- if (verbose) {
237
- process.stderr.write(`\nAll train queries passed on iteration ${iteration}!\n`);
238
- }
239
- return `all_passed (iteration ${iteration})`;
215
+ printEvalStats("Train", evaluation.trainResults.results, evaluation.evalElapsed);
216
+ if (evaluation.testSummary) {
217
+ printEvalStats("Test ", evaluation.testResults.results, 0);
240
218
  }
219
+ }
241
220
 
242
- if (iteration === maxIterations) {
243
- if (verbose) {
244
- process.stderr.write(`\nMax iterations reached (${maxIterations}).\n`);
245
- }
246
- return `max_iterations (${maxIterations})`;
221
+ function getIterationExitReason(trainSummary, iteration, maxIterations) {
222
+ if (trainSummary.failed === 0) return `all_passed (iteration ${iteration})`;
223
+ if (iteration === maxIterations) return `max_iterations (${maxIterations})`;
224
+ return null;
225
+ }
226
+
227
+ function printIterationExit(ctx, exitReason) {
228
+ if (!ctx.verbose || !exitReason) return;
229
+
230
+ if (exitReason.startsWith("all_passed")) {
231
+ process.stderr.write(`\nAll train queries passed on iteration ${ctx.iteration}!\n`);
232
+ return;
247
233
  }
234
+ process.stderr.write(`\nMax iterations reached (${ctx.maxIterations}).\n`);
235
+ }
248
236
 
249
- if (verbose) {
237
+ function createBlindedHistory(history) {
238
+ return history.map(function blindEntry(entry) {
239
+ return Object.fromEntries(
240
+ Object.entries(entry).filter(function excludeTestResult([key]) {
241
+ return !key.startsWith("test_");
242
+ }),
243
+ );
244
+ });
245
+ }
246
+
247
+ function improveIterationDescription(ctx, trainResults) {
248
+ if (ctx.verbose) {
250
249
  process.stderr.write("\nImproving description...\n");
251
250
  }
252
251
 
253
252
  const improveStart = Date.now();
254
- const blindedHistory = history.map((h) =>
255
- Object.fromEntries(Object.entries(h).filter(([k]) => !k.startsWith("test_"))),
256
- );
257
253
  const newDescription = improveDescription(
258
- name,
259
- content,
260
- currentDescription,
254
+ ctx.name,
255
+ ctx.content,
256
+ ctx.currentDescription,
261
257
  trainResults,
262
- blindedHistory,
263
- model,
258
+ createBlindedHistory(ctx.history),
259
+ ctx.model,
264
260
  null,
265
- logDir,
266
- iteration,
261
+ ctx.logDir,
262
+ ctx.iteration,
267
263
  );
268
264
  const improveElapsed = (Date.now() - improveStart) / 1000;
269
265
 
270
- if (verbose) {
266
+ if (ctx.verbose) {
271
267
  process.stderr.write(`Proposed (${improveElapsed.toFixed(1)}s): ${newDescription}\n`);
272
268
  }
269
+ return newDescription;
270
+ }
273
271
 
274
- ctx.currentDescription = newDescription;
272
+ async function runIteration(ctx) {
273
+ printIterationHeader(ctx);
274
+ const evaluation = await runIterationEval(ctx);
275
+ ctx.history.push(createHistoryEntry(ctx, evaluation));
276
+ writeLiveIterationReport(ctx);
277
+ printIterationStats(ctx, evaluation);
278
+
279
+ const exitReason = getIterationExitReason(
280
+ evaluation.trainSummary,
281
+ ctx.iteration,
282
+ ctx.maxIterations,
283
+ );
284
+ printIterationExit(ctx, exitReason);
285
+ if (exitReason) return exitReason;
286
+
287
+ ctx.currentDescription = improveIterationDescription(ctx, evaluation.trainResults);
275
288
  return null;
276
289
  }
277
290
 
@@ -355,11 +368,16 @@ async function runLoop({
355
368
  };
356
369
  }
357
370
 
358
- function formatTimestamp(date = new Date()) {
359
- const pad = (n) => String(n).padStart(2, "0");
371
+ function padTimestampValue(value) {
372
+ return String(value).padStart(2, "0");
373
+ }
374
+
375
+ function formatTimestamp(date = new Date(), dateSeparator = "") {
360
376
  return (
361
- `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}_` +
362
- `${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`
377
+ `${date.getFullYear()}${dateSeparator}${padTimestampValue(date.getMonth() + 1)}` +
378
+ `${dateSeparator}${padTimestampValue(date.getDate())}_` +
379
+ `${padTimestampValue(date.getHours())}${padTimestampValue(date.getMinutes())}` +
380
+ `${padTimestampValue(date.getSeconds())}`
363
381
  );
364
382
  }
365
383
 
@@ -398,57 +416,86 @@ function parseArgs(argv) {
398
416
  return args;
399
417
  }
400
418
 
401
- async function main() {
402
- const args = parseArgs(process.argv);
403
- if (!args.evalSet || !args.skillPath || !args.model) {
404
- console.error(
405
- "Usage: node run_loop.js --eval-set PATH --skill-path PATH --model MODEL [--description TEXT] [--num-workers N] [--timeout SEC] [--max-iterations N] [--runs-per-query N] [--trigger-threshold R] [--holdout F] [--verbose] [--report auto|none|PATH] [--results-dir DIR]",
406
- );
407
- process.exit(1);
408
- }
419
+ function getCurrentDate() {
420
+ return new Date();
421
+ }
409
422
 
410
- const evalSet = JSON.parse(fs.readFileSync(args.evalSet, "utf-8"));
411
- const skillPath = path.resolve(args.skillPath);
412
- if (!fs.existsSync(path.join(skillPath, "SKILL.md"))) {
413
- console.error(`Error: No SKILL.md found at ${skillPath}`);
414
- process.exit(1);
415
- }
423
+ function createMainDependencies(overrides = {}) {
424
+ return {
425
+ argv: process.argv,
426
+ readFile: fs.readFileSync,
427
+ fileExists: fs.existsSync,
428
+ writeFile: fs.writeFileSync,
429
+ makeDirectory: fs.mkdirSync,
430
+ resolvePath: path.resolve,
431
+ joinPath: path.join,
432
+ basename: path.basename,
433
+ tempDirectory: os.tmpdir,
434
+ currentDate: getCurrentDate,
435
+ openReport: openInBrowser,
436
+ parseSkill: parseSkillMd,
437
+ runOptimization: runLoop,
438
+ renderReport: generateHtml,
439
+ log: console.log,
440
+ logError: console.error,
441
+ writeError: process.stderr.write.bind(process.stderr),
442
+ exit: process.exit.bind(process),
443
+ ...overrides,
444
+ };
445
+ }
416
446
 
417
- const { name } = parseSkillMd(skillPath);
447
+ function validateMainArgs(args, dependencies) {
448
+ if (args.evalSet && args.skillPath && args.model) return true;
449
+ dependencies.logError(
450
+ "Usage: node run_loop.js --eval-set PATH --skill-path PATH --model MODEL [--description TEXT] [--num-workers N] [--timeout SEC] [--max-iterations N] [--runs-per-query N] [--trigger-threshold R] [--holdout F] [--verbose] [--report auto|none|PATH] [--results-dir DIR]",
451
+ );
452
+ dependencies.exit(1);
453
+ return false;
454
+ }
418
455
 
419
- let liveReportPath = null;
420
- if (args.report !== "none") {
421
- if (args.report === "auto") {
422
- liveReportPath = path.join(
423
- os.tmpdir(),
424
- `skill_description_report_${path.basename(skillPath)}_${formatTimestamp()}.html`,
425
- );
426
- } else {
427
- liveReportPath = path.resolve(args.report);
428
- }
429
- fs.writeFileSync(
430
- liveReportPath,
431
- "<html><body><h1>Starting optimization loop...</h1><meta http-equiv='refresh' content='5'></body></html>",
432
- );
433
- openInBrowser(liveReportPath);
456
+ function resolveMainInputs(args, dependencies) {
457
+ const evalSet = JSON.parse(dependencies.readFile(args.evalSet, "utf-8"));
458
+ const skillPath = dependencies.resolvePath(args.skillPath);
459
+ if (!dependencies.fileExists(dependencies.joinPath(skillPath, "SKILL.md"))) {
460
+ dependencies.logError(`Error: No SKILL.md found at ${skillPath}`);
461
+ dependencies.exit(1);
462
+ return null;
434
463
  }
464
+ const { name } = dependencies.parseSkill(skillPath);
465
+ return { evalSet, skillPath, name };
466
+ }
435
467
 
436
- let resultsDir = null;
437
- if (args.resultsDir) {
438
- const now = new Date();
439
- const pad = (n) => String(n).padStart(2, "0");
440
- const timestamp =
441
- `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_` +
442
- `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
443
- resultsDir = path.join(path.resolve(args.resultsDir), timestamp);
444
- fs.mkdirSync(resultsDir, { recursive: true });
445
- }
468
+ function configureReport(args, skillPath, dependencies) {
469
+ if (args.report === "none") return null;
470
+ const liveReportPath =
471
+ args.report === "auto"
472
+ ? dependencies.joinPath(
473
+ dependencies.tempDirectory(),
474
+ `skill_description_report_${dependencies.basename(skillPath)}_${formatTimestamp(dependencies.currentDate())}.html`,
475
+ )
476
+ : dependencies.resolvePath(args.report);
477
+ dependencies.writeFile(
478
+ liveReportPath,
479
+ "<html><body><h1>Starting optimization loop...</h1><meta http-equiv='refresh' content='5'></body></html>",
480
+ );
481
+ dependencies.openReport(liveReportPath);
482
+ return liveReportPath;
483
+ }
446
484
 
447
- const logDir = resultsDir ? path.join(resultsDir, "logs") : null;
485
+ function configureResults(args, dependencies) {
486
+ if (!args.resultsDir) return null;
487
+ const resultsDir = dependencies.joinPath(
488
+ dependencies.resolvePath(args.resultsDir),
489
+ formatTimestamp(dependencies.currentDate(), "-"),
490
+ );
491
+ dependencies.makeDirectory(resultsDir, { recursive: true });
492
+ return resultsDir;
493
+ }
448
494
 
449
- const output = await runLoop({
450
- evalSet,
451
- skillPath,
495
+ function createRunLoopOptions(args, inputs, liveReportPath, resultsDir, dependencies) {
496
+ return {
497
+ evalSet: inputs.evalSet,
498
+ skillPath: inputs.skillPath,
452
499
  descriptionOverride: args.description,
453
500
  numWorkers: args.numWorkers,
454
501
  timeout: args.timeout,
@@ -459,29 +506,56 @@ async function main() {
459
506
  model: args.model,
460
507
  verbose: args.verbose,
461
508
  liveReportPath,
462
- logDir,
463
- });
509
+ logDir: resultsDir ? dependencies.joinPath(resultsDir, "logs") : null,
510
+ };
511
+ }
464
512
 
513
+ function writeMainOutput(output, inputs, liveReportPath, resultsDir, dependencies) {
465
514
  const jsonOutput = JSON.stringify(output, null, 2);
466
- console.log(jsonOutput);
515
+ dependencies.log(jsonOutput);
467
516
  if (resultsDir) {
468
- fs.writeFileSync(path.join(resultsDir, "results.json"), jsonOutput);
517
+ dependencies.writeFile(dependencies.joinPath(resultsDir, "results.json"), jsonOutput);
469
518
  }
470
-
471
519
  if (liveReportPath) {
472
- fs.writeFileSync(liveReportPath, generateHtml(output, false, name));
473
- process.stderr.write(`\nReport: ${liveReportPath}\n`);
520
+ dependencies.writeFile(liveReportPath, dependencies.renderReport(output, false, inputs.name));
521
+ dependencies.writeError(`\nReport: ${liveReportPath}\n`);
474
522
  }
475
-
476
523
  if (resultsDir && liveReportPath) {
477
- fs.writeFileSync(path.join(resultsDir, "report.html"), generateHtml(output, false, name));
524
+ dependencies.writeFile(
525
+ dependencies.joinPath(resultsDir, "report.html"),
526
+ dependencies.renderReport(output, false, inputs.name),
527
+ );
478
528
  }
479
-
480
529
  if (resultsDir) {
481
- process.stderr.write(`Results saved to: ${resultsDir}\n`);
530
+ dependencies.writeError(`Results saved to: ${resultsDir}\n`);
482
531
  }
483
532
  }
484
533
 
534
+ async function main(overrides = {}) {
535
+ const dependencies = createMainDependencies(overrides);
536
+ const args = parseArgs(dependencies.argv);
537
+ if (!validateMainArgs(args, dependencies)) return null;
538
+
539
+ const inputs = resolveMainInputs(args, dependencies);
540
+ if (!inputs) return null;
541
+
542
+ const liveReportPath = configureReport(args, inputs.skillPath, dependencies);
543
+ const resultsDir = configureResults(args, dependencies);
544
+ const output = await dependencies.runOptimization(
545
+ createRunLoopOptions(args, inputs, liveReportPath, resultsDir, dependencies),
546
+ );
547
+ writeMainOutput(output, inputs, liveReportPath, resultsDir, dependencies);
548
+ return output;
549
+ }
550
+
551
+ module.exports = {
552
+ createBlindedHistory,
553
+ createHistoryEntry,
554
+ getIterationExitReason,
555
+ main,
556
+ parseArgs,
557
+ };
558
+
485
559
  if (require.main === module) {
486
560
  main().catch((error) => {
487
561
  console.error(error.message);
@@ -3,58 +3,88 @@
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
5
 
6
- function parseSkillMd(skillPath) {
7
- const content = fs.readFileSync(path.join(skillPath, "SKILL.md"), "utf-8");
8
- const lines = content.split("\n");
6
+ const MULTILINE_DESCRIPTION_MARKERS = new Set([">", "|", ">-", "|-"]);
9
7
 
8
+ function findFrontmatterEnd(lines) {
10
9
  if (lines[0]?.trim() !== "---") {
11
10
  throw new Error("SKILL.md missing frontmatter (no opening ---)");
12
11
  }
13
12
 
14
- let endIdx = null;
15
- for (let i = 1; i < lines.length; i++) {
16
- if (lines[i]?.trim() === "---") {
17
- endIdx = i;
18
- break;
19
- }
13
+ const endIndex = lines.findIndex(function (line, index) {
14
+ return index > 0 && line?.trim() === "---";
15
+ });
16
+ if (endIndex === -1) {
17
+ throw new Error("SKILL.md missing frontmatter (no closing ---)");
20
18
  }
21
19
 
22
- if (endIdx === null) {
23
- throw new Error("SKILL.md missing frontmatter (no closing ---)");
20
+ return endIndex;
21
+ }
22
+
23
+ function normalizeQuotedScalar(value) {
24
+ return value.trim().replace(/^["']|["']$/g, "");
25
+ }
26
+
27
+ function isIndented(line) {
28
+ return line.startsWith(" ") || line.startsWith("\t");
29
+ }
30
+
31
+ function consumeMultilineDescription(lines, startIndex) {
32
+ const continuationLines = [];
33
+ let nextIndex = startIndex;
34
+
35
+ while (nextIndex < lines.length && isIndented(lines[nextIndex])) {
36
+ continuationLines.push(lines[nextIndex].trim());
37
+ nextIndex += 1;
24
38
  }
25
39
 
26
- let name = "";
27
- let description = "";
28
- const frontmatterLines = lines.slice(1, endIdx);
29
- let i = 0;
30
- while (i < frontmatterLines.length) {
31
- const line = frontmatterLines[i];
32
- if (line.startsWith("name:")) {
33
- name = line
34
- .slice("name:".length)
35
- .trim()
36
- .replace(/^["']|["']$/g, "");
37
- } else if (line.startsWith("description:")) {
38
- let value = line.slice("description:".length).trim();
39
- if (value === ">" || value === "|" || value === ">-" || value === "|-") {
40
- const continuationLines = [];
41
- i += 1;
42
- while (
43
- i < frontmatterLines.length &&
44
- (frontmatterLines[i].startsWith(" ") || frontmatterLines[i].startsWith("\t"))
45
- ) {
46
- continuationLines.push(frontmatterLines[i].trim());
47
- i += 1;
48
- }
49
- description = continuationLines.join(" ");
50
- continue;
51
- }
52
- description = value.replace(/^["']|["']$/g, "");
53
- }
54
- i += 1;
40
+ return {
41
+ description: continuationLines.join(" "),
42
+ nextIndex,
43
+ };
44
+ }
45
+
46
+ function consumeDescription(lines, index, metadata) {
47
+ const value = lines[index].slice("description:".length).trim();
48
+ if (!MULTILINE_DESCRIPTION_MARKERS.has(value)) {
49
+ metadata.description = normalizeQuotedScalar(value);
50
+ return index + 1;
55
51
  }
56
52
 
57
- return { name, description, content };
53
+ const multiline = consumeMultilineDescription(lines, index + 1);
54
+ metadata.description = multiline.description;
55
+ return multiline.nextIndex;
56
+ }
57
+
58
+ function consumeFrontmatterLine(lines, index, metadata) {
59
+ const line = lines[index];
60
+ if (line.startsWith("name:")) {
61
+ metadata.name = normalizeQuotedScalar(line.slice("name:".length));
62
+ return index + 1;
63
+ }
64
+ if (line.startsWith("description:")) {
65
+ return consumeDescription(lines, index, metadata);
66
+ }
67
+ return index + 1;
68
+ }
69
+
70
+ function parseFrontmatter(lines) {
71
+ const metadata = { name: "", description: "" };
72
+ let index = 0;
73
+
74
+ while (index < lines.length) {
75
+ index = consumeFrontmatterLine(lines, index, metadata);
76
+ }
77
+
78
+ return metadata;
79
+ }
80
+
81
+ function parseSkillMd(skillPath) {
82
+ const content = fs.readFileSync(path.join(skillPath, "SKILL.md"), "utf-8");
83
+ const lines = content.split("\n");
84
+ const endIndex = findFrontmatterEnd(lines);
85
+ const metadata = parseFrontmatter(lines.slice(1, endIndex));
86
+
87
+ return { ...metadata, content };
58
88
  }
59
89
 
60
90
  module.exports = { parseSkillMd };