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.
- package/dist/bundled-skills/skill-creator/eval-viewer/generate_review.js +183 -95
- package/dist/bundled-skills/skill-creator/scripts/__tests__/improve_description.test.js +77 -0
- package/dist/bundled-skills/skill-creator/scripts/__tests__/package_skill.test.js +203 -0
- package/dist/bundled-skills/skill-creator/scripts/__tests__/run_eval.test.js +125 -0
- package/dist/bundled-skills/skill-creator/scripts/__tests__/utils.test.js +149 -0
- package/dist/bundled-skills/skill-creator/scripts/aggregate_benchmark.js +2 -0
- package/dist/bundled-skills/skill-creator/scripts/improve_description.js +42 -22
- package/dist/bundled-skills/skill-creator/scripts/package_skill.js +68 -40
- package/dist/bundled-skills/skill-creator/scripts/run_eval.js +60 -32
- package/dist/bundled-skills/skill-creator/scripts/run_loop.js +224 -150
- package/dist/bundled-skills/skill-creator/scripts/utils.js +71 -41
- package/dist/index.js +162426 -152725
- package/dist/node_modules/@libsql/darwin-x64/README.md +3 -0
- package/dist/node_modules/@libsql/darwin-x64/index.node +0 -0
- package/dist/node_modules/@libsql/darwin-x64/package.json +36 -0
- package/dist/public/assets/account-view-DGfJrmbM.js +1 -0
- package/dist/public/assets/alert-dialog-D5UGH4qW.js +7 -0
- package/dist/public/assets/api-odZ7g9AN.js +2 -0
- package/dist/public/assets/{async-error-boundary-Dll_zcqr.js → async-error-boundary-CbAQza_Z.js} +1 -1
- package/dist/public/assets/browser-tab-DZUa8JpJ.js +12 -0
- package/dist/public/assets/{button-B5aMz2Rk.js → button-B7hsXP2P.js} +1 -1
- package/dist/public/assets/{card-DRr14MEQ.js → card-BTgRxBeB.js} +1 -1
- package/dist/public/assets/chat-dock-context-CANpJk1z.js +1 -0
- package/dist/public/assets/{commit-dialog-C-JfaoS6.js → commit-dialog-DAUjE4cb.js} +1 -1
- package/dist/public/assets/{commit-error-dialog-VXqZLeta.js → commit-error-dialog-2tnhCseF.js} +1 -1
- package/dist/public/assets/{commit-method-fields-DAd1unUF.js → commit-method-fields-Dj2uqPrP.js} +1 -1
- package/dist/public/assets/conversation-history-view-CpinBoLp.js +1 -0
- package/dist/public/assets/create-project-dialog-V4ZiwQkg.js +2 -0
- package/dist/public/assets/{create-repo-dialog-mBGGkX-g.js → create-repo-dialog-DG9Ax-yf.js} +1 -1
- package/dist/public/assets/delete-confirm-dialog-Dg2q6cGA.js +1 -0
- package/dist/public/assets/diff-view-KJQqPVMa.js +4 -0
- package/dist/public/assets/{dist-T8-4ZfS0.js → dist-B9o9ZI_U.js} +1 -1
- package/dist/public/assets/{dist-DwblUvSf.js → dist-BF1fIO22.js} +1 -1
- package/dist/public/assets/{dist-CWYnBq-n.js → dist-CM7ef_Ef.js} +1 -1
- package/dist/public/assets/{dist-COfI64N5.js → dist-Ms_QN0HI.js} +1 -1
- package/dist/public/assets/{dist-sThe8WYP.js → dist-R7ILWSDv.js} +1 -1
- package/dist/public/assets/{dist-DDYi9MQo.js → dist-T2H2nD62.js} +1 -1
- package/dist/public/assets/{dist-TCNzmc2V.js → dist-Xi9Q--PI.js} +1 -1
- package/dist/public/assets/dist-bAGdBaoO.js +2 -0
- package/dist/public/assets/{es2015-Bu0NIPbn.js → es2015-3o6GJKAC.js} +1 -1
- package/dist/public/assets/{explorer-monaco-editor-q8CnSwWA.js → explorer-monaco-editor-BUfO46YV.js} +1 -1
- package/dist/public/assets/explorer-tab-view-CXFHVIyO.js +2 -0
- package/dist/public/assets/explorer-tree-D3N9CgUw.js +1 -0
- package/dist/public/assets/explorer-view-Qla3PjXX.js +76 -0
- package/dist/public/assets/{git-history-dialog-XEr5pugf.js → git-history-dialog-hQ3LY348.js} +1 -1
- package/dist/public/assets/index-BQ4LyrcX.css +1 -0
- package/dist/public/assets/index-C1jToYjL.js +112 -0
- package/dist/public/assets/{lucide-react-B-115rul.js → lucide-react-CNNzKD4G.js} +1 -1
- package/dist/public/assets/{model-list-controls-DAZM0NBC.js → model-list-controls-Dzi-bA4G.js} +1 -1
- package/dist/public/assets/onboarding-dialog-CWHYidh3.js +1 -0
- package/dist/public/assets/{pill-tabs-QsjH027B.js → pill-tabs-B-GZBSAx.js} +1 -1
- package/dist/public/assets/{progress-indicator-C01aPXIe.js → progress-indicator-Dr6KLjL5.js} +1 -1
- package/dist/public/assets/project-coding-view-XHObCz5c.js +1 -0
- package/dist/public/assets/{project-danger-zone-view-BaSu793w.js → project-danger-zone-view-DnUMqsVk.js} +1 -1
- package/dist/public/assets/project-env-vars-view-CZ2H31qr.js +1 -0
- package/dist/public/assets/project-model-aliases-view-BDLn_rnO.js +1 -0
- package/dist/public/assets/project-settings-view-BiPB--It.js +1 -0
- package/dist/public/assets/project-tools-view-rHqvcYmB.js +1 -0
- package/dist/public/assets/providers-list-view-CgmQms1S.js +1 -0
- package/dist/public/assets/pull-request-dialog-B2IuZfiC.js +1 -0
- package/dist/public/assets/{pull-with-changes-dialog-DDp_srHq.js → pull-with-changes-dialog-0GcFybrs.js} +1 -1
- package/dist/public/assets/{push-before-pr-dialog-Bt0BChlV.js → push-before-pr-dialog-BsHxhNkj.js} +1 -1
- package/dist/public/assets/{scroll-area-DwRwR2nQ.js → scroll-area-fMQC4KJw.js} +1 -1
- package/dist/public/assets/settings-general-tabs-view-DFH-XX7K.js +2 -0
- package/dist/public/assets/settings-general-view-DQTKXkvD.js +1 -0
- package/dist/public/assets/settings-list-COPIEKbu.js +1 -0
- package/dist/public/assets/settings-logs-view-DkZI0-PQ.js +5 -0
- package/dist/public/assets/settings-mcp-servers-view-DNUF0p87.js +5 -0
- package/dist/public/assets/settings-models-view-CAfXeeqi.js +1 -0
- package/dist/public/assets/settings-plugins-view-Wgp98zEC.js +2 -0
- package/dist/public/assets/settings-providers-view-CDXMVzWQ.js +2 -0
- package/dist/public/assets/settings-setup-view-gkQGOFn4.js +2 -0
- package/dist/public/assets/settings-skills-view-CcyTQlPl.js +2 -0
- package/dist/public/assets/settings-slack-view-idgTLLDo.js +1 -0
- package/dist/public/assets/settings-slash-commands-view-CPfpTFt5.js +1 -0
- package/dist/public/assets/settings-statistics-view-CewvaKLi.js +1 -0
- package/dist/public/assets/settings-storage-view-3HPIVaYG.js +1 -0
- package/dist/public/assets/settings-subagents-view-CWD4EWyU.js +2 -0
- package/dist/public/assets/settings-system-prompt-view-DitIaAmi.js +1 -0
- package/dist/public/assets/{settings-tab-bar-DAHxT5KE.js → settings-tab-bar-BKrNKoYV.js} +1 -1
- package/dist/public/assets/settings-view-C1rDwQOL.js +2 -0
- package/dist/public/assets/{slug-utils-BQZ6c2py.js → slug-utils-ZC2qISlV.js} +1 -1
- package/dist/public/assets/store-DqAPgNUQ.js +9 -0
- package/dist/public/assets/{table-7hMwxpkF.js → table-DjVI02Kg.js} +1 -1
- package/dist/public/assets/tasks-view-07DwlYR7.js +1 -0
- package/dist/public/assets/{terminal-panel-BNOIOh8z.js → terminal-panel-B-B0Mjbv.js} +2 -2
- package/dist/public/assets/{toggle-group-UiksQ0n9.js → toggle-group-Ti6E2rBa.js} +1 -1
- package/dist/public/assets/{tooltip-Dvmz78Z_.js → tooltip-Dz8vH1DG.js} +1 -1
- package/dist/public/assets/{use-active-dock-panel-instance-2LfvItRH.js → use-active-dock-panel-instance-C7H1mX2G.js} +1 -1
- package/dist/public/assets/use-installed-ai-files-CNN44_z3.js +1 -0
- package/dist/public/assets/use-settings-page-loading-CpaBd260.js +1 -0
- package/dist/public/assets/use-toast-xpb5jNtN.js +1 -0
- package/dist/public/assets/{useBaseQuery-D5as4SgS.js → useBaseQuery-DZ0hJ6lN.js} +1 -1
- package/dist/public/assets/{utils-B-qS8qMg.js → utils-BW67ZVub.js} +1 -1
- package/dist/public/assets/{web-DyqJbQ3L.js → web-BBOGW-Jp.js} +1 -1
- package/dist/public/assets/{web-gEWIDddb.js → web-CsFwi45J.js} +1 -1
- package/dist/public/assets/{web-B9ndApmi.js → web-DmkLaAFF.js} +1 -1
- package/dist/public/assets/{web-BkuMY08B.js → web-kuH5W1xE.js} +1 -1
- package/dist/public/browser-preview-rpc.js +123 -68
- package/dist/public/index.html +25 -23
- package/package.json +6 -5
- package/dist/public/assets/account-view-Bzv2EHnc.js +0 -1
- package/dist/public/assets/api-OO3KSG8d.js +0 -2
- package/dist/public/assets/browser-tab-Cwa1TB3I.js +0 -12
- package/dist/public/assets/chat-dock-context-Cnq0BWgm.js +0 -1
- package/dist/public/assets/context-menu-BKOotkeD.js +0 -1
- package/dist/public/assets/conversation-history-view-CcdQRxoP.js +0 -1
- package/dist/public/assets/create-project-dialog-D1VaSgqh.js +0 -2
- package/dist/public/assets/delete-confirm-dialog-Cx9nT7Xd.js +0 -1
- package/dist/public/assets/diff-view-CyOnLSEA.js +0 -4
- package/dist/public/assets/dist-DNkA3vYh.js +0 -2
- package/dist/public/assets/explorer-tab-view-G2HmkQyY.js +0 -2
- package/dist/public/assets/explorer-tree-DAuc2Npx.js +0 -1
- package/dist/public/assets/explorer-view-BDMlnV3f.js +0 -76
- package/dist/public/assets/index-C4WzOmf3.css +0 -1
- package/dist/public/assets/index-DD_a7tQU.js +0 -3665
- package/dist/public/assets/onboarding-dialog-Dd9hiOOf.js +0 -1
- package/dist/public/assets/project-coding-view-DbKI7sbW.js +0 -1
- package/dist/public/assets/project-env-vars-view-BB66j52E.js +0 -1
- package/dist/public/assets/project-model-aliases-view-o1-Z2es5.js +0 -1
- package/dist/public/assets/project-settings-view-BKjvtOtk.js +0 -1
- package/dist/public/assets/project-tools-view-CZbblznF.js +0 -1
- package/dist/public/assets/providers-list-view-ChY2DXYc.js +0 -1
- package/dist/public/assets/pull-request-dialog-BZgY4vrw.js +0 -1
- package/dist/public/assets/settings-general-tabs-view-BH7AaXyP.js +0 -2
- package/dist/public/assets/settings-general-view-B-t99LmD.js +0 -1
- package/dist/public/assets/settings-list-Dn4CHP4Z.js +0 -1
- package/dist/public/assets/settings-logs-view-BCRjz-Fr.js +0 -5
- package/dist/public/assets/settings-mcp-servers-view-xv9D4DPO.js +0 -5
- package/dist/public/assets/settings-models-view-rUeqlE4k.js +0 -1
- package/dist/public/assets/settings-plugins-view-qnWmII61.js +0 -2
- package/dist/public/assets/settings-providers-view-DsxTdBEQ.js +0 -2
- package/dist/public/assets/settings-setup-view-ew5KW8gL.js +0 -2
- package/dist/public/assets/settings-skills-view-C4NxP4gI.js +0 -3
- package/dist/public/assets/settings-slack-view-BNT5ervf.js +0 -1
- package/dist/public/assets/settings-slash-commands-view-CE7FT3dB.js +0 -1
- package/dist/public/assets/settings-statistics-view-jKPoSWBs.js +0 -1
- package/dist/public/assets/settings-storage-view-C_Rs-9Hw.js +0 -1
- package/dist/public/assets/settings-subagents-view-DHVSAmCY.js +0 -2
- package/dist/public/assets/settings-system-prompt-view-B_nF2HUy.js +0 -1
- package/dist/public/assets/settings-view-BY6OO-xy.js +0 -2
- package/dist/public/assets/store-B7EgrEO7.js +0 -9
- package/dist/public/assets/tasks-view-Dc7sthjm.js +0 -1
- package/dist/public/assets/use-installed-ai-files-BkpswqGI.js +0 -1
- 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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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,
|
|
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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
77
65
|
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
+
} else {
|
|
82
|
+
includedFiles.push({ filePath, arcname });
|
|
92
83
|
}
|
|
93
|
-
includedFiles.push({ filePath, arcname });
|
|
94
84
|
}
|
|
85
|
+
return includedFiles;
|
|
86
|
+
}
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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 };
|