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
@@ -0,0 +1,125 @@
1
+ const assert = require("node:assert/strict");
2
+ const test = require("node:test");
3
+
4
+ const { handleStreamEventType } = require("../run_eval.js");
5
+
6
+ function createState(cleanName = "example-skill") {
7
+ const finishValues = [];
8
+ return {
9
+ accumulatedJson: "stale input",
10
+ cleanName,
11
+ finish(value) {
12
+ finishValues.push(value);
13
+ },
14
+ finishValues,
15
+ pendingToolName: null,
16
+ };
17
+ }
18
+
19
+ function send(state, type, event = {}) {
20
+ return handleStreamEventType(event, type, state);
21
+ }
22
+
23
+ test("finishes when a supported tool input contains the skill name across deltas", function () {
24
+ const state = createState();
25
+
26
+ assert.equal(
27
+ send(state, "content_block_start", {
28
+ content_block: { name: "Skill", type: "tool_use" },
29
+ }),
30
+ false,
31
+ );
32
+ assert.equal(state.pendingToolName, "Skill");
33
+ assert.equal(state.accumulatedJson, "");
34
+
35
+ assert.equal(
36
+ send(state, "content_block_delta", {
37
+ delta: { partial_json: '{"skill":"example-', type: "input_json_delta" },
38
+ }),
39
+ false,
40
+ );
41
+ assert.equal(
42
+ send(state, "content_block_delta", {
43
+ delta: { partial_json: 'skill"}', type: "input_json_delta" },
44
+ }),
45
+ true,
46
+ );
47
+ assert.deepEqual(state.finishValues, [true]);
48
+ });
49
+
50
+ test("accepts Read and finishes false when its completed input omits the skill name", function () {
51
+ const state = createState();
52
+
53
+ send(state, "content_block_start", {
54
+ content_block: { name: "Read", type: "tool_use" },
55
+ });
56
+ send(state, "content_block_delta", {
57
+ delta: { partial_json: '{"file_path":"other.md"}', type: "input_json_delta" },
58
+ });
59
+
60
+ assert.equal(send(state, "content_block_stop"), true);
61
+ assert.deepEqual(state.finishValues, [false]);
62
+ });
63
+
64
+ test("rejects unsupported tools when their content block starts", function () {
65
+ const state = createState();
66
+
67
+ assert.equal(
68
+ send(state, "content_block_start", {
69
+ content_block: { name: "Bash", type: "tool_use" },
70
+ }),
71
+ true,
72
+ );
73
+ assert.deepEqual(state.finishValues, [false]);
74
+ });
75
+
76
+ test("only accumulates input JSON while a supported tool is pending", function () {
77
+ const state = createState();
78
+
79
+ assert.equal(
80
+ send(state, "content_block_delta", {
81
+ delta: { partial_json: "example-skill", type: "input_json_delta" },
82
+ }),
83
+ false,
84
+ );
85
+ assert.equal(state.accumulatedJson, "stale input");
86
+
87
+ send(state, "content_block_start", {
88
+ content_block: { name: "Skill", type: "tool_use" },
89
+ });
90
+ assert.equal(
91
+ send(state, "content_block_delta", {
92
+ delta: { partial_json: "example-skill", type: "text_delta" },
93
+ }),
94
+ false,
95
+ );
96
+ assert.equal(state.accumulatedJson, "");
97
+ assert.deepEqual(state.finishValues, []);
98
+ });
99
+
100
+ test("message stop finishes based on pending tool state", function () {
101
+ const stateWithoutTool = createState();
102
+ assert.equal(send(stateWithoutTool, "message_stop"), true);
103
+ assert.deepEqual(stateWithoutTool.finishValues, [false]);
104
+
105
+ const stateWithTool = createState();
106
+ stateWithTool.pendingToolName = "Skill";
107
+ stateWithTool.accumulatedJson = '{"skill":"example-skill"}';
108
+ assert.equal(send(stateWithTool, "message_stop"), true);
109
+ assert.deepEqual(stateWithTool.finishValues, [true]);
110
+ });
111
+
112
+ test("ignores unrelated blocks, deltas, stops, and event types", function () {
113
+ const state = createState();
114
+
115
+ assert.equal(send(state, "content_block_start", { content_block: { type: "text" } }), false);
116
+ assert.equal(
117
+ send(state, "content_block_delta", {
118
+ delta: { partial_json: "example-skill", type: "input_json_delta" },
119
+ }),
120
+ false,
121
+ );
122
+ assert.equal(send(state, "content_block_stop"), false);
123
+ assert.equal(send(state, "ping"), false);
124
+ assert.deepEqual(state.finishValues, []);
125
+ });
@@ -0,0 +1,149 @@
1
+ const assert = require("node:assert/strict");
2
+ const fs = require("node:fs");
3
+ const os = require("node:os");
4
+ const path = require("node:path");
5
+ const test = require("node:test");
6
+
7
+ const { parseSkillMd } = require("../utils.js");
8
+
9
+ function withSkill(content, callback) {
10
+ const skillPath = fs.mkdtempSync(path.join(os.tmpdir(), "tarsk-skill-utils-"));
11
+ try {
12
+ fs.writeFileSync(path.join(skillPath, "SKILL.md"), content);
13
+ return callback(skillPath);
14
+ } finally {
15
+ fs.rmSync(skillPath, { recursive: true, force: true });
16
+ }
17
+ }
18
+
19
+ function parse(content) {
20
+ return withSkill(content, parseSkillMd);
21
+ }
22
+
23
+ const scalarCases = [
24
+ {
25
+ name: "plain scalars",
26
+ content: "---\nname: example-skill\ndescription: A useful skill\n---\nBody\n",
27
+ expectedName: "example-skill",
28
+ expectedDescription: "A useful skill",
29
+ },
30
+ {
31
+ name: "double-quoted scalars",
32
+ content: '---\nname: "example-skill"\ndescription: "A useful skill"\n---\n',
33
+ expectedName: "example-skill",
34
+ expectedDescription: "A useful skill",
35
+ },
36
+ {
37
+ name: "single-quoted scalars",
38
+ content: "---\nname: 'example-skill'\ndescription: 'A useful skill'\n---\n",
39
+ expectedName: "example-skill",
40
+ expectedDescription: "A useful skill",
41
+ },
42
+ ];
43
+
44
+ for (const testCase of scalarCases) {
45
+ test(`parses ${testCase.name}`, function () {
46
+ const result = parse(testCase.content);
47
+
48
+ assert.equal(result.name, testCase.expectedName);
49
+ assert.equal(result.description, testCase.expectedDescription);
50
+ assert.equal(result.content, testCase.content);
51
+ });
52
+ }
53
+
54
+ const multilineMarkers = [">", "|", ">-", "|-"];
55
+
56
+ for (const marker of multilineMarkers) {
57
+ test(`parses a ${marker} multiline description with supported indentation`, function () {
58
+ const result = parse(
59
+ `---\nname: multiline\ndescription: ${marker}\n first line\n\tsecond line\nignored: value\n---\n`,
60
+ );
61
+
62
+ assert.equal(result.description, "first line second line");
63
+ });
64
+ }
65
+
66
+ test("stops a multiline description at a non-indented line", function () {
67
+ const result = parse("---\ndescription: >\n first line\nname: after-description\n---\n");
68
+
69
+ assert.equal(result.name, "after-description");
70
+ assert.equal(result.description, "first line");
71
+ });
72
+
73
+ test("does not consume a line indented by only one space", function () {
74
+ const result = parse("---\ndescription: >\n unsupported continuation\n---\n");
75
+
76
+ assert.equal(result.description, "");
77
+ });
78
+
79
+ test("treats a quoted multiline marker as a scalar", function () {
80
+ const result = parse('---\ndescription: ">"\n ignored continuation\n---\n');
81
+
82
+ assert.equal(result.description, ">");
83
+ });
84
+
85
+ const duplicateCases = [
86
+ {
87
+ name: "duplicate names",
88
+ content: "---\nname: first\nname: second\n---\n",
89
+ expectedName: "second",
90
+ expectedDescription: "",
91
+ },
92
+ {
93
+ name: "duplicate scalar descriptions",
94
+ content: "---\ndescription: first\ndescription: second\n---\n",
95
+ expectedName: "",
96
+ expectedDescription: "second",
97
+ },
98
+ {
99
+ name: "a scalar after a multiline description",
100
+ content: "---\ndescription: >\n first\ndescription: second\n---\n",
101
+ expectedName: "",
102
+ expectedDescription: "second",
103
+ },
104
+ {
105
+ name: "a multiline description after a scalar",
106
+ content: "---\ndescription: first\ndescription: |\n second\n---\n",
107
+ expectedName: "",
108
+ expectedDescription: "second",
109
+ },
110
+ ];
111
+
112
+ for (const testCase of duplicateCases) {
113
+ test(`uses the last value for ${testCase.name}`, function () {
114
+ const result = parse(testCase.content);
115
+
116
+ assert.equal(result.name, testCase.expectedName);
117
+ assert.equal(result.description, testCase.expectedDescription);
118
+ });
119
+ }
120
+
121
+ const malformedCases = [
122
+ {
123
+ name: "missing opening delimiter",
124
+ content: "name: example\n---\n",
125
+ message: "SKILL.md missing frontmatter (no opening ---)",
126
+ },
127
+ {
128
+ name: "missing closing delimiter",
129
+ content: "---\nname: example\n",
130
+ message: "SKILL.md missing frontmatter (no closing ---)",
131
+ },
132
+ ];
133
+
134
+ for (const testCase of malformedCases) {
135
+ test(`rejects frontmatter with a ${testCase.name}`, function () {
136
+ assert.throws(
137
+ function () {
138
+ parse(testCase.content);
139
+ },
140
+ { message: testCase.message },
141
+ );
142
+ });
143
+ }
144
+
145
+ test("returns empty metadata when frontmatter has no supported fields", function () {
146
+ const content = "---\ncompatibility: everywhere\n---\nBody\n";
147
+
148
+ assert.deepEqual(parse(content), { name: "", description: "", content });
149
+ });
@@ -87,6 +87,7 @@ function loadGrading(runDir) {
87
87
  }
88
88
  }
89
89
 
90
+ // fallow-ignore-next-line complexity
90
91
  function buildResult(evalId, runNumber, grading, runDir) {
91
92
  const result = {
92
93
  eval_id: evalId,
@@ -265,6 +266,7 @@ function generateBenchmark(benchmarkDir, skillName = "", skillPath = "") {
265
266
  };
266
267
  }
267
268
 
269
+ // fallow-ignore-next-line complexity
268
270
  function generateMarkdown(benchmark) {
269
271
  const metadata = benchmark.metadata;
270
272
  const runSummary = benchmark.run_summary;
@@ -71,32 +71,52 @@ function buildFailuresText(evalResults) {
71
71
  return text;
72
72
  }
73
73
 
74
+ function isDefined(value) {
75
+ return value != null;
76
+ }
77
+
78
+ function firstDefined(...values) {
79
+ return values.find(isDefined);
80
+ }
81
+
82
+ function formatHistoryScore(attempt) {
83
+ const trainPassed = firstDefined(attempt.train_passed, attempt.passed, 0);
84
+ const trainTotal = firstDefined(attempt.train_total, attempt.total, 0);
85
+ const trainScore = `${trainPassed}/${trainTotal}`;
86
+ if (attempt.test_passed == null) {
87
+ return `train=${trainScore}`;
88
+ }
89
+
90
+ const testTotal = firstDefined(attempt.test_total, "?");
91
+ return `train=${trainScore}, test=${attempt.test_passed}/${testTotal}`;
92
+ }
93
+
94
+ function formatHistoryResult(result) {
95
+ const status = result.pass ? "PASS" : "FAIL";
96
+ return ` [${status}] "${result.query.slice(0, 80)}" (triggered ${result.triggers}/${result.runs})\n`;
97
+ }
98
+
99
+ function renderHistoryAttempt(attempt) {
100
+ let text = `<attempt ${formatHistoryScore(attempt)}>\n`;
101
+ text += `Description: "${attempt.description}"\n`;
102
+ if (attempt.results) {
103
+ text += "Train results:\n";
104
+ text += attempt.results.map(formatHistoryResult).join("");
105
+ }
106
+ if (attempt.note) {
107
+ text += `Note: ${attempt.note}\n`;
108
+ }
109
+ return `${text}</attempt>\n\n`;
110
+ }
111
+
74
112
  function buildHistoryText(history) {
75
113
  if (!history.length) {
76
114
  return "";
77
115
  }
78
116
 
79
- let text = "PREVIOUS ATTEMPTS (do NOT repeat these — try something structurally different):\n\n";
80
- for (const h of history) {
81
- const trainS = `${h.train_passed ?? h.passed ?? 0}/${h.train_total ?? h.total ?? 0}`;
82
- const testS = h.test_passed != null ? `${h.test_passed}/${h.test_total ?? "?"}` : null;
83
- const scoreStr = `train=${trainS}` + (testS ? `, test=${testS}` : "");
84
- text += `<attempt ${scoreStr}>\n`;
85
- text += `Description: "${h.description}"\n`;
86
- if (h.results) {
87
- text += "Train results:\n";
88
- for (const r of h.results) {
89
- const status = r.pass ? "PASS" : "FAIL";
90
- text += ` [${status}] "${r.query.slice(0, 80)}" (triggered ${r.triggers}/${r.runs})\n`;
91
- }
92
- }
93
- if (h.note) {
94
- text += `Note: ${h.note}\n`;
95
- }
96
- text += "</attempt>\n\n";
97
- }
98
-
99
- return text;
117
+ const header =
118
+ "PREVIOUS ATTEMPTS (do NOT repeat these — try something structurally different):\n\n";
119
+ return header + history.map(renderHistoryAttempt).join("");
100
120
  }
101
121
 
102
122
  function buildImprovePrompt(
@@ -307,4 +327,4 @@ if (require.main === module) {
307
327
  main();
308
328
  }
309
329
 
310
- module.exports = { improveDescription, callTarsk };
330
+ module.exports = { improveDescription, buildHistoryText };
@@ -4,7 +4,7 @@
4
4
  const fs = require("fs");
5
5
  const path = require("path");
6
6
  const os = require("os");
7
- const { execSync } = require("child_process");
7
+ const { execFileSync } = require("child_process");
8
8
  const { validateSkill } = require("./quick_validate.js");
9
9
 
10
10
  const EXCLUDE_DIRS = new Set(["__pycache__", "node_modules"]);
@@ -47,75 +47,68 @@ function walkFiles(dir) {
47
47
  return files;
48
48
  }
49
49
 
50
- function packageSkill(skillPath, outputDir = null) {
51
- skillPath = path.resolve(skillPath);
52
-
50
+ function validateSkillDirectory(skillPath) {
53
51
  if (!fs.existsSync(skillPath)) {
54
52
  console.log(`❌ Error: Skill folder not found: ${skillPath}`);
55
- return null;
53
+ return false;
56
54
  }
57
-
58
55
  if (!fs.statSync(skillPath).isDirectory()) {
59
56
  console.log(`❌ Error: Path is not a directory: ${skillPath}`);
60
- return null;
57
+ return false;
61
58
  }
62
-
63
- const skillMd = path.join(skillPath, "SKILL.md");
64
- if (!fs.existsSync(skillMd)) {
59
+ if (!fs.existsSync(path.join(skillPath, "SKILL.md"))) {
65
60
  console.log(`❌ Error: SKILL.md not found in ${skillPath}`);
66
- return null;
67
- }
68
-
69
- console.log("🔍 Validating skill...");
70
- const [valid, message] = validateSkill(skillPath);
71
- if (!valid) {
72
- console.log(`❌ Validation failed: ${message}`);
73
- console.log(" Please fix the validation errors before packaging.");
74
- return null;
61
+ return false;
75
62
  }
76
- console.log(`✅ ${message}\n`);
63
+ return true;
64
+ }
77
65
 
78
- const skillName = path.basename(skillPath);
66
+ function prepareOutputPath(skillPath, outputDir) {
79
67
  const outputPath = outputDir ? path.resolve(outputDir) : process.cwd();
80
68
  if (outputDir) {
81
69
  fs.mkdirSync(outputPath, { recursive: true });
82
70
  }
83
- const skillFilename = path.join(outputPath, `${skillName}.skill`);
71
+ return path.join(outputPath, `${path.basename(skillPath)}.skill`);
72
+ }
84
73
 
74
+ function collectIncludedFiles(skillPath) {
85
75
  const parentDir = path.dirname(skillPath);
86
76
  const includedFiles = [];
87
77
  for (const filePath of walkFiles(skillPath)) {
88
78
  const arcname = path.relative(parentDir, filePath);
89
79
  if (shouldExclude(arcname)) {
90
80
  console.log(` Skipped: ${arcname}`);
91
- continue;
81
+ } else {
82
+ includedFiles.push({ filePath, arcname });
92
83
  }
93
- includedFiles.push({ filePath, arcname });
94
84
  }
85
+ return includedFiles;
86
+ }
95
87
 
96
- if (includedFiles.length === 0) {
97
- console.log("❌ Error: No files to package");
98
- return null;
88
+ function stageFiles(includedFiles, stagingDir) {
89
+ for (const { filePath, arcname } of includedFiles) {
90
+ const destination = path.join(stagingDir, arcname);
91
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
92
+ fs.copyFileSync(filePath, destination);
93
+ console.log(` Added: ${arcname}`);
99
94
  }
95
+ }
100
96
 
97
+ function executeArchive(stagingDir, skillFilename, skillName) {
98
+ execFileSync("zip", ["-r", "-q", skillFilename, skillName], {
99
+ cwd: stagingDir,
100
+ stdio: "inherit",
101
+ });
102
+ }
103
+
104
+ function createArchive(skillPath, skillFilename, archiveExecutor) {
101
105
  const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), "skill-pack-"));
102
106
  try {
103
- for (const { filePath, arcname } of includedFiles) {
104
- const dest = path.join(stagingDir, arcname);
105
- fs.mkdirSync(path.dirname(dest), { recursive: true });
106
- fs.copyFileSync(filePath, dest);
107
- console.log(` Added: ${arcname}`);
108
- }
109
-
107
+ stageFiles(collectIncludedFiles(skillPath), stagingDir);
110
108
  if (fs.existsSync(skillFilename)) {
111
109
  fs.unlinkSync(skillFilename);
112
110
  }
113
-
114
- execSync(`zip -r -q "${skillFilename}" "${skillName}"`, {
115
- cwd: stagingDir,
116
- stdio: "inherit",
117
- });
118
-
111
+ archiveExecutor(stagingDir, skillFilename, path.basename(skillPath));
119
112
  console.log(`\n✅ Successfully packaged skill to: ${skillFilename}`);
120
113
  return skillFilename;
121
114
  } catch (error) {
@@ -126,6 +119,41 @@ function packageSkill(skillPath, outputDir = null) {
126
119
  }
127
120
  }
128
121
 
122
+ function resolveDependencies(dependencies) {
123
+ const providedDependencies = dependencies || {};
124
+ return {
125
+ archiveExecutor: providedDependencies.executeArchive ?? executeArchive,
126
+ skillValidator: providedDependencies.validateSkill ?? validateSkill,
127
+ };
128
+ }
129
+
130
+ function validateBeforePackaging(skillPath, skillValidator) {
131
+ console.log("🔍 Validating skill...");
132
+ const [valid, message] = skillValidator(skillPath);
133
+ if (!valid) {
134
+ console.log(`❌ Validation failed: ${message}`);
135
+ console.log(" Please fix the validation errors before packaging.");
136
+ return false;
137
+ }
138
+ console.log(`✅ ${message}\n`);
139
+ return true;
140
+ }
141
+
142
+ function packageSkill(skillPath, outputDir, dependencies) {
143
+ const resolvedSkillPath = path.resolve(skillPath);
144
+ if (!validateSkillDirectory(resolvedSkillPath)) {
145
+ return null;
146
+ }
147
+
148
+ const { archiveExecutor, skillValidator } = resolveDependencies(dependencies);
149
+ if (!validateBeforePackaging(resolvedSkillPath, skillValidator)) {
150
+ return null;
151
+ }
152
+
153
+ const skillFilename = prepareOutputPath(resolvedSkillPath, outputDir);
154
+ return createArchive(resolvedSkillPath, skillFilename, archiveExecutor);
155
+ }
156
+
129
157
  if (require.main === module) {
130
158
  if (process.argv.length < 3) {
131
159
  console.log("Usage: node package_skill.js <path/to/skill-folder> [output-directory]");
@@ -29,41 +29,69 @@ function buildEnv() {
29
29
  return env;
30
30
  }
31
31
 
32
- function handleStreamEventType(se, seType, state) {
33
- if (seType === "content_block_start") {
34
- const cb = se.content_block ?? {};
35
- if (cb.type === "tool_use") {
36
- const toolName = cb.name ?? "";
37
- if (toolName === "Skill" || toolName === "Read") {
38
- state.pendingToolName = toolName;
39
- state.accumulatedJson = "";
40
- } else {
41
- state.finish(false);
42
- return true;
43
- }
44
- }
45
- } else if (seType === "content_block_delta" && state.pendingToolName) {
46
- const delta = se.delta ?? {};
47
- if (delta.type === "input_json_delta") {
48
- state.accumulatedJson += delta.partial_json ?? "";
49
- if (state.accumulatedJson.includes(state.cleanName)) {
50
- state.finish(true);
51
- return true;
52
- }
53
- }
54
- } else if (seType === "content_block_stop" || seType === "message_stop") {
55
- if (state.pendingToolName) {
56
- state.finish(state.accumulatedJson.includes(state.cleanName));
57
- return true;
58
- }
59
- if (seType === "message_stop") {
60
- state.finish(false);
61
- return true;
62
- }
32
+ function isSupportedTool(toolName) {
33
+ return toolName === "Skill" || toolName === "Read";
34
+ }
35
+
36
+ function handleContentBlockStart(se, state) {
37
+ const contentBlock = se.content_block ?? {};
38
+ if (contentBlock.type !== "tool_use") return false;
39
+
40
+ const toolName = contentBlock.name ?? "";
41
+ if (!isSupportedTool(toolName)) {
42
+ state.finish(false);
43
+ return true;
63
44
  }
45
+
46
+ state.pendingToolName = toolName;
47
+ state.accumulatedJson = "";
64
48
  return false;
65
49
  }
66
50
 
51
+ function handleContentBlockDelta(se, state) {
52
+ if (!state.pendingToolName) return false;
53
+
54
+ const delta = se.delta ?? {};
55
+ if (delta.type !== "input_json_delta") return false;
56
+
57
+ state.accumulatedJson += delta.partial_json ?? "";
58
+ if (!state.accumulatedJson.includes(state.cleanName)) return false;
59
+
60
+ state.finish(true);
61
+ return true;
62
+ }
63
+
64
+ function finishFromAccumulatedInput(state) {
65
+ state.finish(state.accumulatedJson.includes(state.cleanName));
66
+ return true;
67
+ }
68
+
69
+ function handleContentBlockStop(state) {
70
+ if (!state.pendingToolName) return false;
71
+ return finishFromAccumulatedInput(state);
72
+ }
73
+
74
+ function handleMessageStop(state) {
75
+ if (state.pendingToolName) return finishFromAccumulatedInput(state);
76
+ state.finish(false);
77
+ return true;
78
+ }
79
+
80
+ function handleStreamEventType(se, seType, state) {
81
+ switch (seType) {
82
+ case "content_block_start":
83
+ return handleContentBlockStart(se, state);
84
+ case "content_block_delta":
85
+ return handleContentBlockDelta(se, state);
86
+ case "content_block_stop":
87
+ return handleContentBlockStop(state);
88
+ case "message_stop":
89
+ return handleMessageStop(state);
90
+ default:
91
+ return false;
92
+ }
93
+ }
94
+
67
95
  function handleAssistantEvent(message, state) {
68
96
  for (const contentItem of message.content ?? []) {
69
97
  if (contentItem.type !== "tool_use") continue;
@@ -364,4 +392,4 @@ if (require.main === module) {
364
392
  });
365
393
  }
366
394
 
367
- module.exports = { findProjectRoot, runEval };
395
+ module.exports = { findProjectRoot, handleStreamEventType, runEval };