@kodax-ai/kodax 0.7.95 → 0.7.96-alpha.2

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 (163) hide show
  1. package/CHANGELOG.md +178 -1
  2. package/LICENSE +158 -158
  3. package/README.md +149 -24
  4. package/README_CN.md +117 -24
  5. package/config-templates/config.example.jsonc +2 -1
  6. package/config-templates/integrations/a2a.example.jsonc +91 -91
  7. package/config-templates/integrations/extensions.example.jsonc +7 -7
  8. package/config-templates/integrations/mcp.example.jsonc +16 -16
  9. package/dist/builtin/code-review/SKILL.md +82 -82
  10. package/dist/builtin/git-workflow/SKILL.md +84 -84
  11. package/dist/builtin/skill-creator/SKILL.md +127 -127
  12. package/dist/builtin/skill-creator/agents/analyzer.md +12 -12
  13. package/dist/builtin/skill-creator/agents/comparator.md +13 -13
  14. package/dist/builtin/skill-creator/agents/grader.md +13 -13
  15. package/dist/builtin/skill-creator/references/schemas.md +227 -227
  16. package/dist/builtin/skill-creator/scripts/aggregate-benchmark.d.ts +46 -46
  17. package/dist/builtin/skill-creator/scripts/aggregate-benchmark.js +208 -208
  18. package/dist/builtin/skill-creator/scripts/analyze-benchmark.d.ts +46 -46
  19. package/dist/builtin/skill-creator/scripts/analyze-benchmark.js +286 -286
  20. package/dist/builtin/skill-creator/scripts/compare-runs.d.ts +62 -62
  21. package/dist/builtin/skill-creator/scripts/compare-runs.js +330 -330
  22. package/dist/builtin/skill-creator/scripts/generate-review.d.ts +33 -33
  23. package/dist/builtin/skill-creator/scripts/generate-review.js +414 -414
  24. package/dist/builtin/skill-creator/scripts/grade-evals.d.ts +73 -73
  25. package/dist/builtin/skill-creator/scripts/grade-evals.js +402 -402
  26. package/dist/builtin/skill-creator/scripts/improve-description.d.ts +23 -23
  27. package/dist/builtin/skill-creator/scripts/improve-description.js +160 -160
  28. package/dist/builtin/skill-creator/scripts/init-skill.d.ts +14 -14
  29. package/dist/builtin/skill-creator/scripts/init-skill.js +155 -155
  30. package/dist/builtin/skill-creator/scripts/install-skill.d.ts +29 -29
  31. package/dist/builtin/skill-creator/scripts/install-skill.js +173 -173
  32. package/dist/builtin/skill-creator/scripts/package-skill.d.ts +38 -38
  33. package/dist/builtin/skill-creator/scripts/package-skill.js +121 -121
  34. package/dist/builtin/skill-creator/scripts/quick-validate.d.ts +8 -8
  35. package/dist/builtin/skill-creator/scripts/quick-validate.js +163 -163
  36. package/dist/builtin/skill-creator/scripts/run-eval.d.ts +66 -66
  37. package/dist/builtin/skill-creator/scripts/run-eval.js +353 -353
  38. package/dist/builtin/skill-creator/scripts/run-loop.d.ts +49 -49
  39. package/dist/builtin/skill-creator/scripts/run-loop.js +242 -242
  40. package/dist/builtin/skill-creator/scripts/run-trigger-eval.d.ts +58 -58
  41. package/dist/builtin/skill-creator/scripts/run-trigger-eval.js +224 -224
  42. package/dist/builtin/tdd/SKILL.md +56 -56
  43. package/dist/chunks/agent-4FABF6WK.js +2 -0
  44. package/dist/chunks/argument-completer-72VHB2VL.js +2 -0
  45. package/dist/chunks/{chunk-7JXA3533.js → chunk-4OIQZWA5.js} +223 -226
  46. package/dist/chunks/{chunk-BNVSKIAB.js → chunk-6BVF3HZ7.js} +136 -136
  47. package/dist/chunks/chunk-7JZZIFZH.js +501 -0
  48. package/dist/chunks/chunk-AC7Z2OIY.js +2 -0
  49. package/dist/chunks/{chunk-JS452J2F.js → chunk-C4KYZAFU.js} +2 -2
  50. package/dist/chunks/chunk-CHUPIWIF.js +251 -0
  51. package/dist/chunks/{chunk-C4DTUKTR.js → chunk-GYUU7XLH.js} +5 -4
  52. package/dist/chunks/{chunk-OK4AXDC5.js → chunk-HAX55GOQ.js} +1 -1
  53. package/dist/chunks/chunk-JKTJCGO2.js +418 -0
  54. package/dist/chunks/{chunk-O743AJ5V.js → chunk-LQYETRFK.js} +171 -175
  55. package/dist/chunks/{chunk-2PEDBGKN.js → chunk-LTUZTQ6W.js} +1 -1
  56. package/dist/chunks/chunk-LYWDUSKO.js +2 -0
  57. package/dist/chunks/chunk-NGH6T4FD.js +92 -0
  58. package/dist/chunks/{chunk-SRIJX5ZP.js → chunk-NVRWCSA5.js} +1 -1
  59. package/dist/chunks/chunk-O4DS7RIQ.js +384 -0
  60. package/dist/chunks/chunk-ORXU6OWZ.js +2 -0
  61. package/dist/chunks/chunk-POTW3O65.js +124 -0
  62. package/dist/chunks/{chunk-2TM3W3GK.js → chunk-RIQSS56Y.js} +1 -1
  63. package/dist/chunks/chunk-U27XKEN5.js +407 -0
  64. package/dist/chunks/{chunk-6ABQJUK6.js → chunk-XUX6OUCA.js} +2 -2
  65. package/dist/chunks/{client-JDOS3YJR.js → client-4C456K4O.js} +1 -1
  66. package/dist/chunks/compaction-config-3VQRDFF4.js +2 -0
  67. package/dist/chunks/{construction-bootstrap-YCWHHUYO.js → construction-bootstrap-AHN7EDGG.js} +1 -1
  68. package/dist/chunks/dist-BCBQXAGI.js +2 -0
  69. package/dist/chunks/dist-QK2YDWU6.js +2 -0
  70. package/dist/chunks/host-VIHV7ADG.js +2 -0
  71. package/dist/chunks/run-manager-NBVMU3KV.js +2 -0
  72. package/dist/chunks/utils-MEJZ2IGI.js +2 -0
  73. package/dist/index.d.ts +22 -21
  74. package/dist/index.js +7 -7
  75. package/dist/kodax_bootstrap.js +26 -26
  76. package/dist/kodax_cli.js +1905 -1882
  77. package/dist/native/darwin-arm64/LICENSE-APACHE.txt +13 -0
  78. package/dist/native/darwin-arm64/kodax-text-transaction.node +0 -0
  79. package/dist/native/darwin-arm64/manifest.json +16 -0
  80. package/dist/native/darwin-x64/LICENSE-APACHE.txt +13 -0
  81. package/dist/native/darwin-x64/kodax-text-transaction.node +0 -0
  82. package/dist/native/darwin-x64/manifest.json +16 -0
  83. package/dist/native/linux-arm64/LICENSE-APACHE.txt +13 -0
  84. package/dist/native/linux-arm64/kodax-text-transaction.node +0 -0
  85. package/dist/native/linux-arm64/manifest.json +16 -0
  86. package/dist/native/linux-x64/LICENSE-APACHE.txt +13 -0
  87. package/dist/native/linux-x64/kodax-text-transaction.node +0 -0
  88. package/dist/native/linux-x64/manifest.json +16 -0
  89. package/dist/native/win32-x64/LICENSE-APACHE.txt +13 -0
  90. package/dist/native/win32-x64/NOTICE-windows-sandbox.txt +8 -0
  91. package/dist/native/win32-x64/kodax-windows-sandbox.exe +0 -0
  92. package/dist/native/win32-x64/kodax-windows-text-transaction.node +0 -0
  93. package/dist/native/win32-x64/manifest.json +30 -0
  94. package/dist/provider-capabilities.json +108 -2
  95. package/dist/runtime-worker.js +1745 -1727
  96. package/dist/sandbox-network-broker.js +1715 -0
  97. package/dist/sdk-a2a.d.ts +13 -12
  98. package/dist/sdk-a2a.js +1 -1
  99. package/dist/sdk-agent.d.ts +27 -18
  100. package/dist/sdk-agent.js +1 -1
  101. package/dist/sdk-coding.d.ts +107 -58
  102. package/dist/sdk-coding.js +1 -1
  103. package/dist/sdk-experimental-memory.d.ts +4 -4
  104. package/dist/sdk-experimental-memory.js +1 -1
  105. package/dist/sdk-llm.d.ts +9 -10
  106. package/dist/sdk-llm.js +1 -1
  107. package/dist/sdk-mcp.js +1 -1
  108. package/dist/sdk-media.d.ts +1 -1
  109. package/dist/sdk-media.js +1 -1
  110. package/dist/sdk-repl.d.ts +25 -17
  111. package/dist/sdk-repl.js +1 -1
  112. package/dist/sdk-runtime.d.ts +41 -17
  113. package/dist/sdk-runtime.js +1 -1
  114. package/dist/sdk-sandbox.d.ts +17 -3
  115. package/dist/sdk-sandbox.js +1 -1
  116. package/dist/sdk-session.d.ts +8 -7
  117. package/dist/sdk-session.js +1 -1
  118. package/dist/sdk-skills.js +1 -1
  119. package/dist/semantic-worker.js +61 -61
  120. package/dist/types-chunks/{base.d-vopO1rml.d.ts → base.d-COo8E2dk.d.ts} +18 -27
  121. package/dist/types-chunks/{bash-prefix-extractor.d-B2rxNI4L.d.ts → bash-prefix-extractor.d-DQOlA8cy.d.ts} +72 -52
  122. package/dist/types-chunks/{capability-learning.d-CE1tm29C.d.ts → capability-learning.d-lRPgA3Or.d.ts} +1 -1
  123. package/dist/types-chunks/{capsule.d-Y7QRS4J2.d.ts → capsule.d-0zxsgXg_.d.ts} +3 -3
  124. package/dist/types-chunks/{controller.d-BR-UVeUR.d.ts → controller.d-BTtyIIC1.d.ts} +1 -1
  125. package/dist/types-chunks/{controller.d-C5noq5-w.d.ts → controller.d-C7tXUcXo.d.ts} +2 -2
  126. package/dist/types-chunks/{guardrail.d-DqHD-61O.d.ts → guardrail.d-DKTyEHJa.d.ts} +5 -5
  127. package/dist/types-chunks/{history-retrieval.d-CKU8zmt_.d.ts → history-retrieval.d-CHnL99S7.d.ts} +2 -2
  128. package/dist/types-chunks/{public-api.d-D7fXaWW8.d.ts → public-api.d-Dx3L3W4Z.d.ts} +7 -4
  129. package/dist/types-chunks/{repl.d-BYDb14s6.d.ts → repl.d-mO01olIa.d.ts} +5 -5
  130. package/dist/types-chunks/{resolver.d-CwHUwbdE.d.ts → resolver.d-DlXPjeyx.d.ts} +38 -6
  131. package/dist/types-chunks/{review-inbox.d-BSgFewyj.d.ts → review-inbox.d-WDSe1nze.d.ts} +1 -1
  132. package/dist/types-chunks/{run-manager.d-BVJSntpS.d.ts → run-manager.d-DENbbzgR.d.ts} +1 -1
  133. package/dist/types-chunks/{sdk-session-CqEG84oP.d.ts → sdk-session-DYHGXXH4.d.ts} +3 -3
  134. package/dist/types-chunks/{shell-command-sets.d-DqaaBwhU.d.ts → shell-command-sets.d-CjFqS4dp.d.ts} +1 -1
  135. package/dist/types-chunks/{side-query.d-iH0P9ASy.d.ts → side-query.d-j8A3sFv_.d.ts} +2 -2
  136. package/dist/types-chunks/{types.d-rUOjXych.d.ts → types.d-BbZjR0Wr.d.ts} +1 -1
  137. package/dist/types-chunks/{types.d-CaTXAW_Q.d.ts → types.d-BkTIKdH6.d.ts} +2 -2
  138. package/dist/types-chunks/{types.d-C5xQEFcj.d.ts → types.d-DncLrpu_.d.ts} +4 -4
  139. package/dist/types-chunks/{types.d-CK9A9rpP.d.ts → types.d-Xy0f3x4i.d.ts} +9 -0
  140. package/dist/types-chunks/{utils.d-CWUyLiXo.d.ts → utils.d-CnxefMos.d.ts} +6 -6
  141. package/package.json +10 -3
  142. package/public_docs/README.md +130 -0
  143. package/public_docs/configuration/sandbox.md +289 -0
  144. package/public_docs/sdk/embedder-guide.md +6674 -0
  145. package/scripts/kodax-bin.cjs +28 -28
  146. package/scripts/production-env.cjs +25 -25
  147. package/dist/chunks/agent-XXZMXKKA.js +0 -2
  148. package/dist/chunks/argument-completer-KCYDGTQW.js +0 -2
  149. package/dist/chunks/chunk-77PNP27P.js +0 -92
  150. package/dist/chunks/chunk-7QBWHCIZ.js +0 -2
  151. package/dist/chunks/chunk-BHE66SP3.js +0 -123
  152. package/dist/chunks/chunk-BR2OSB2I.js +0 -722
  153. package/dist/chunks/chunk-DSMONSVB.js +0 -407
  154. package/dist/chunks/chunk-Q5VRWSKG.js +0 -418
  155. package/dist/chunks/chunk-XWRPOGJN.js +0 -4
  156. package/dist/chunks/chunk-Y5VIQBT6.js +0 -383
  157. package/dist/chunks/compaction-config-EGS4577X.js +0 -2
  158. package/dist/chunks/dist-ITTXQHRJ.js +0 -2
  159. package/dist/chunks/dist-KFYN3OKD.js +0 -2
  160. package/dist/chunks/host-VAYADIPW.js +0 -2
  161. package/dist/chunks/run-manager-52IJZMZJ.js +0 -2
  162. package/dist/chunks/utils-P7PBSL3R.js +0 -2
  163. package/dist/sandbox-workspace-session.js +0 -1705
@@ -1,49 +1,49 @@
1
- import type { ImproveDescriptionOptions, ImproveDescriptionResult } from './improve-description.js';
2
- import type { TriggerEvalOptions, TriggerEvalReport } from './run-trigger-eval.js';
3
-
4
- export interface DescriptionLoopRecord {
5
- iteration: number;
6
- description: string;
7
- score: string;
8
- train: TriggerEvalReport['summary'];
9
- test: TriggerEvalReport['summary'] | null;
10
- train_results: TriggerEvalReport['results'];
11
- test_results: TriggerEvalReport['results'];
12
- }
13
-
14
- export interface DescriptionLoopReport {
15
- skill_name: string;
16
- original_description: string;
17
- final_description: string;
18
- best_description: string;
19
- history: DescriptionLoopRecord[];
20
- train_size: number;
21
- test_size: number;
22
- }
23
-
24
- export interface DescriptionLoopOptions extends TriggerEvalOptions {
25
- workspaceDir: string;
26
- maxIterations: number;
27
- holdout?: number;
28
- seed?: number;
29
- writeBest?: boolean;
30
- }
31
-
32
- export function splitEvalSet(
33
- evals: Array<Record<string, unknown> & { should_trigger?: boolean }>,
34
- holdout?: number,
35
- seed?: number
36
- ): {
37
- train: Array<Record<string, unknown> & { should_trigger?: boolean }>;
38
- test: Array<Record<string, unknown> & { should_trigger?: boolean }>;
39
- };
40
-
41
- export function runDescriptionLoop(
42
- options: DescriptionLoopOptions,
43
- dependencies?: {
44
- runTriggerEvalFn?: (options: TriggerEvalOptions) => Promise<TriggerEvalReport>;
45
- improveDescriptionFn?: (
46
- options: ImproveDescriptionOptions
47
- ) => Promise<ImproveDescriptionResult>;
48
- }
49
- ): Promise<DescriptionLoopReport>;
1
+ import type { ImproveDescriptionOptions, ImproveDescriptionResult } from './improve-description.js';
2
+ import type { TriggerEvalOptions, TriggerEvalReport } from './run-trigger-eval.js';
3
+
4
+ export interface DescriptionLoopRecord {
5
+ iteration: number;
6
+ description: string;
7
+ score: string;
8
+ train: TriggerEvalReport['summary'];
9
+ test: TriggerEvalReport['summary'] | null;
10
+ train_results: TriggerEvalReport['results'];
11
+ test_results: TriggerEvalReport['results'];
12
+ }
13
+
14
+ export interface DescriptionLoopReport {
15
+ skill_name: string;
16
+ original_description: string;
17
+ final_description: string;
18
+ best_description: string;
19
+ history: DescriptionLoopRecord[];
20
+ train_size: number;
21
+ test_size: number;
22
+ }
23
+
24
+ export interface DescriptionLoopOptions extends TriggerEvalOptions {
25
+ workspaceDir: string;
26
+ maxIterations: number;
27
+ holdout?: number;
28
+ seed?: number;
29
+ writeBest?: boolean;
30
+ }
31
+
32
+ export function splitEvalSet(
33
+ evals: Array<Record<string, unknown> & { should_trigger?: boolean }>,
34
+ holdout?: number,
35
+ seed?: number
36
+ ): {
37
+ train: Array<Record<string, unknown> & { should_trigger?: boolean }>;
38
+ test: Array<Record<string, unknown> & { should_trigger?: boolean }>;
39
+ };
40
+
41
+ export function runDescriptionLoop(
42
+ options: DescriptionLoopOptions,
43
+ dependencies?: {
44
+ runTriggerEvalFn?: (options: TriggerEvalOptions) => Promise<TriggerEvalReport>;
45
+ improveDescriptionFn?: (
46
+ options: ImproveDescriptionOptions
47
+ ) => Promise<ImproveDescriptionResult>;
48
+ }
49
+ ): Promise<DescriptionLoopReport>;
@@ -1,244 +1,244 @@
1
- #!/usr/bin/env node
2
-
3
- import { readFile, writeFile } from 'node:fs/promises';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import { loadSkill, pathExists, writeSkill } from './utils.js';
7
- import { improveDescription } from './improve-description.js';
8
- import { runTriggerEval } from './run-trigger-eval.js';
9
-
10
- export function splitEvalSet(evals, holdout = 0.25, seed = 42) {
11
- if (holdout <= 0 || evals.length < 4) {
12
- return { train: [...evals], test: [] };
13
- }
14
-
15
- let random = seed;
16
- const nextRandom = () => {
17
- random = (random * 1664525 + 1013904223) % 4294967296;
18
- return random / 4294967296;
19
- };
20
-
21
- const shuffle = (items) => {
22
- const result = [...items];
23
- for (let index = result.length - 1; index > 0; index -= 1) {
24
- const swapIndex = Math.floor(nextRandom() * (index + 1));
25
- [result[index], result[swapIndex]] = [result[swapIndex], result[index]];
26
- }
27
- return result;
28
- };
29
-
30
- const positives = evals.filter((item) => item.should_trigger === true);
31
- const negatives = evals.filter((item) => item.should_trigger !== true);
32
- const shuffledPositives = shuffle(positives);
33
- const shuffledNegatives = shuffle(negatives);
34
-
35
- const pickCount = (items) => {
36
- if (items.length <= 1) {
37
- return 0;
38
- }
39
- return Math.max(1, Math.floor(items.length * holdout));
40
- };
41
-
42
- const posCount = pickCount(shuffledPositives);
43
- const negCount = pickCount(shuffledNegatives);
44
-
45
- const test = [
46
- ...shuffledPositives.slice(0, posCount),
47
- ...shuffledNegatives.slice(0, negCount),
48
- ];
49
- const train = [
50
- ...shuffledPositives.slice(posCount),
51
- ...shuffledNegatives.slice(negCount),
52
- ];
53
-
54
- return { train, test };
55
- }
56
-
57
- async function writeTempEvalFile(workspaceDir, name, skillName, evals) {
58
- const filePath = path.join(workspaceDir, `${name}.json`);
59
- await writeFile(filePath, JSON.stringify({ skill_name: skillName, evals }, null, 2), 'utf8');
60
- return filePath;
61
- }
62
-
63
- export async function runDescriptionLoop(
64
- options,
65
- dependencies = {
66
- runTriggerEvalFn: runTriggerEval,
67
- improveDescriptionFn: improveDescription,
68
- }
69
- ) {
70
- const resolvedDependencies = {
71
- runTriggerEvalFn: runTriggerEval,
72
- improveDescriptionFn: improveDescription,
73
- ...dependencies,
74
- };
75
- const skill = await loadSkill(options.skillPath);
76
- const evalFile = JSON.parse(await readFile(options.evalsPath, 'utf8'));
77
- const allEvals = Array.isArray(evalFile.evals) ? evalFile.evals : [];
78
- const { train, test } = splitEvalSet(allEvals, options.holdout, options.seed);
79
- const historyPath = path.join(options.workspaceDir, 'description-history.json');
80
-
81
- let currentDescription = String(skill.frontmatter.description ?? '');
82
- const history = [];
83
- let best = null;
84
-
85
- for (let iteration = 1; iteration <= options.maxIterations; iteration += 1) {
86
- const trainFile = await writeTempEvalFile(options.workspaceDir, `train-iteration-${iteration}`, skill.frontmatter.name, train);
87
- const trainResults = await resolvedDependencies.runTriggerEvalFn({
88
- ...options,
89
- evalsPath: trainFile,
90
- descriptionOverride: currentDescription,
91
- });
92
-
93
- let testResults = null;
94
- if (test.length > 0) {
95
- const testFile = await writeTempEvalFile(options.workspaceDir, `test-iteration-${iteration}`, skill.frontmatter.name, test);
96
- testResults = await resolvedDependencies.runTriggerEvalFn({
97
- ...options,
98
- evalsPath: testFile,
99
- descriptionOverride: currentDescription,
100
- });
101
- }
102
-
103
- const score = `${trainResults.summary.passed}/${trainResults.summary.total}`;
104
- const record = {
105
- iteration,
106
- description: currentDescription,
107
- score,
108
- train: trainResults.summary,
109
- test: testResults?.summary ?? null,
110
- train_results: trainResults.results,
111
- test_results: testResults?.results ?? [],
112
- };
113
- history.push(record);
114
-
115
- const currentComparable = testResults?.summary.passed ?? trainResults.summary.passed;
116
- const bestComparable = best?.comparable ?? -1;
117
- if (currentComparable > bestComparable) {
118
- best = {
119
- comparable: currentComparable,
120
- record,
121
- };
122
- }
123
-
124
- if (trainResults.summary.failed === 0 || iteration === options.maxIterations) {
125
- break;
126
- }
127
-
128
- const improveInputPath = path.join(options.workspaceDir, `iteration-${iteration}-train-results.json`);
129
- await writeFile(improveInputPath, JSON.stringify(trainResults, null, 2), 'utf8');
130
- if (!await pathExists(historyPath)) {
131
- await writeFile(historyPath, JSON.stringify({ history }, null, 2), 'utf8');
132
- }
133
- const improved = await resolvedDependencies.improveDescriptionFn({
134
- ...options,
135
- evalResultsPath: improveInputPath,
136
- historyPath,
137
- });
138
- currentDescription = improved.description;
139
- await writeFile(
140
- historyPath,
141
- JSON.stringify({ history }, null, 2),
142
- 'utf8'
143
- );
144
- }
145
-
146
- if (options.writeBest) {
147
- const finalDescription = best?.record.description ?? currentDescription;
148
- skill.frontmatter.description = finalDescription;
149
- await writeSkill(options.skillPath, skill.frontmatter, skill.body);
150
- }
151
-
152
- return {
153
- skill_name: skill.frontmatter.name,
154
- original_description: skill.frontmatter.description,
155
- final_description: currentDescription,
156
- best_description: best?.record.description ?? currentDescription,
157
- history,
158
- train_size: train.length,
159
- test_size: test.length,
160
- };
161
- }
162
-
163
- function parseArgs(argv) {
164
- const args = {
165
- skillPath: '',
166
- evalsPath: '',
167
- workspaceDir: '',
168
- provider: 'anthropic',
169
- model: undefined,
170
- maxIterations: 3,
171
- runsPerQuery: 1,
172
- triggerThreshold: 0.5,
173
- holdout: 0.25,
174
- seed: 42,
175
- maxIter: 18,
176
- reasoningMode: 'off',
177
- output: undefined,
178
- writeBest: false,
179
- };
180
-
181
- for (let index = 2; index < argv.length; index += 1) {
182
- const token = argv[index];
183
- if (token === '--skill-path' && argv[index + 1]) {
184
- args.skillPath = argv[++index];
185
- } else if (token === '--evals' && argv[index + 1]) {
186
- args.evalsPath = argv[++index];
187
- } else if (token === '--workspace' && argv[index + 1]) {
188
- args.workspaceDir = argv[++index];
189
- } else if (token === '--provider' && argv[index + 1]) {
190
- args.provider = argv[++index];
191
- } else if (token === '--model' && argv[index + 1]) {
192
- args.model = argv[++index];
193
- } else if (token === '--max-iterations' && argv[index + 1]) {
194
- args.maxIterations = Number(argv[++index]);
195
- } else if (token === '--runs-per-query' && argv[index + 1]) {
196
- args.runsPerQuery = Number(argv[++index]);
197
- } else if (token === '--trigger-threshold' && argv[index + 1]) {
198
- args.triggerThreshold = Number(argv[++index]);
199
- } else if (token === '--holdout' && argv[index + 1]) {
200
- args.holdout = Number(argv[++index]);
201
- } else if (token === '--seed' && argv[index + 1]) {
202
- args.seed = Number(argv[++index]);
203
- } else if (token === '--max-iter' && argv[index + 1]) {
204
- args.maxIter = Number(argv[++index]);
205
- } else if (token === '--reasoning' && argv[index + 1]) {
206
- args.reasoningMode = argv[++index];
207
- } else if (token === '--output' && argv[index + 1]) {
208
- args.output = argv[++index];
209
- } else if (token === '--write-best') {
210
- args.writeBest = true;
211
- }
212
- }
213
-
214
- return args;
215
- }
216
-
217
- async function main() {
218
- const args = parseArgs(process.argv);
219
- if (!args.skillPath || !args.evalsPath || !args.workspaceDir) {
220
- console.error('Usage: node scripts/run-loop.js --skill-path <dir> --evals <evals.json> --workspace <dir> [--max-iterations 3]');
221
- process.exit(1);
222
- }
223
-
224
- const report = await runDescriptionLoop(args);
225
- const outputText = `${JSON.stringify(report, null, 2)}\n`;
226
-
227
- if (args.output) {
228
- await writeFile(args.output, outputText, 'utf8');
229
- console.log(`Wrote ${path.resolve(args.output)}`);
230
- } else {
231
- process.stdout.write(outputText);
232
- }
233
- }
234
-
1
+ #!/usr/bin/env node
2
+
3
+ import { readFile, writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { loadSkill, pathExists, writeSkill } from './utils.js';
7
+ import { improveDescription } from './improve-description.js';
8
+ import { runTriggerEval } from './run-trigger-eval.js';
9
+
10
+ export function splitEvalSet(evals, holdout = 0.25, seed = 42) {
11
+ if (holdout <= 0 || evals.length < 4) {
12
+ return { train: [...evals], test: [] };
13
+ }
14
+
15
+ let random = seed;
16
+ const nextRandom = () => {
17
+ random = (random * 1664525 + 1013904223) % 4294967296;
18
+ return random / 4294967296;
19
+ };
20
+
21
+ const shuffle = (items) => {
22
+ const result = [...items];
23
+ for (let index = result.length - 1; index > 0; index -= 1) {
24
+ const swapIndex = Math.floor(nextRandom() * (index + 1));
25
+ [result[index], result[swapIndex]] = [result[swapIndex], result[index]];
26
+ }
27
+ return result;
28
+ };
29
+
30
+ const positives = evals.filter((item) => item.should_trigger === true);
31
+ const negatives = evals.filter((item) => item.should_trigger !== true);
32
+ const shuffledPositives = shuffle(positives);
33
+ const shuffledNegatives = shuffle(negatives);
34
+
35
+ const pickCount = (items) => {
36
+ if (items.length <= 1) {
37
+ return 0;
38
+ }
39
+ return Math.max(1, Math.floor(items.length * holdout));
40
+ };
41
+
42
+ const posCount = pickCount(shuffledPositives);
43
+ const negCount = pickCount(shuffledNegatives);
44
+
45
+ const test = [
46
+ ...shuffledPositives.slice(0, posCount),
47
+ ...shuffledNegatives.slice(0, negCount),
48
+ ];
49
+ const train = [
50
+ ...shuffledPositives.slice(posCount),
51
+ ...shuffledNegatives.slice(negCount),
52
+ ];
53
+
54
+ return { train, test };
55
+ }
56
+
57
+ async function writeTempEvalFile(workspaceDir, name, skillName, evals) {
58
+ const filePath = path.join(workspaceDir, `${name}.json`);
59
+ await writeFile(filePath, JSON.stringify({ skill_name: skillName, evals }, null, 2), 'utf8');
60
+ return filePath;
61
+ }
62
+
63
+ export async function runDescriptionLoop(
64
+ options,
65
+ dependencies = {
66
+ runTriggerEvalFn: runTriggerEval,
67
+ improveDescriptionFn: improveDescription,
68
+ }
69
+ ) {
70
+ const resolvedDependencies = {
71
+ runTriggerEvalFn: runTriggerEval,
72
+ improveDescriptionFn: improveDescription,
73
+ ...dependencies,
74
+ };
75
+ const skill = await loadSkill(options.skillPath);
76
+ const evalFile = JSON.parse(await readFile(options.evalsPath, 'utf8'));
77
+ const allEvals = Array.isArray(evalFile.evals) ? evalFile.evals : [];
78
+ const { train, test } = splitEvalSet(allEvals, options.holdout, options.seed);
79
+ const historyPath = path.join(options.workspaceDir, 'description-history.json');
80
+
81
+ let currentDescription = String(skill.frontmatter.description ?? '');
82
+ const history = [];
83
+ let best = null;
84
+
85
+ for (let iteration = 1; iteration <= options.maxIterations; iteration += 1) {
86
+ const trainFile = await writeTempEvalFile(options.workspaceDir, `train-iteration-${iteration}`, skill.frontmatter.name, train);
87
+ const trainResults = await resolvedDependencies.runTriggerEvalFn({
88
+ ...options,
89
+ evalsPath: trainFile,
90
+ descriptionOverride: currentDescription,
91
+ });
92
+
93
+ let testResults = null;
94
+ if (test.length > 0) {
95
+ const testFile = await writeTempEvalFile(options.workspaceDir, `test-iteration-${iteration}`, skill.frontmatter.name, test);
96
+ testResults = await resolvedDependencies.runTriggerEvalFn({
97
+ ...options,
98
+ evalsPath: testFile,
99
+ descriptionOverride: currentDescription,
100
+ });
101
+ }
102
+
103
+ const score = `${trainResults.summary.passed}/${trainResults.summary.total}`;
104
+ const record = {
105
+ iteration,
106
+ description: currentDescription,
107
+ score,
108
+ train: trainResults.summary,
109
+ test: testResults?.summary ?? null,
110
+ train_results: trainResults.results,
111
+ test_results: testResults?.results ?? [],
112
+ };
113
+ history.push(record);
114
+
115
+ const currentComparable = testResults?.summary.passed ?? trainResults.summary.passed;
116
+ const bestComparable = best?.comparable ?? -1;
117
+ if (currentComparable > bestComparable) {
118
+ best = {
119
+ comparable: currentComparable,
120
+ record,
121
+ };
122
+ }
123
+
124
+ if (trainResults.summary.failed === 0 || iteration === options.maxIterations) {
125
+ break;
126
+ }
127
+
128
+ const improveInputPath = path.join(options.workspaceDir, `iteration-${iteration}-train-results.json`);
129
+ await writeFile(improveInputPath, JSON.stringify(trainResults, null, 2), 'utf8');
130
+ if (!await pathExists(historyPath)) {
131
+ await writeFile(historyPath, JSON.stringify({ history }, null, 2), 'utf8');
132
+ }
133
+ const improved = await resolvedDependencies.improveDescriptionFn({
134
+ ...options,
135
+ evalResultsPath: improveInputPath,
136
+ historyPath,
137
+ });
138
+ currentDescription = improved.description;
139
+ await writeFile(
140
+ historyPath,
141
+ JSON.stringify({ history }, null, 2),
142
+ 'utf8'
143
+ );
144
+ }
145
+
146
+ if (options.writeBest) {
147
+ const finalDescription = best?.record.description ?? currentDescription;
148
+ skill.frontmatter.description = finalDescription;
149
+ await writeSkill(options.skillPath, skill.frontmatter, skill.body);
150
+ }
151
+
152
+ return {
153
+ skill_name: skill.frontmatter.name,
154
+ original_description: skill.frontmatter.description,
155
+ final_description: currentDescription,
156
+ best_description: best?.record.description ?? currentDescription,
157
+ history,
158
+ train_size: train.length,
159
+ test_size: test.length,
160
+ };
161
+ }
162
+
163
+ function parseArgs(argv) {
164
+ const args = {
165
+ skillPath: '',
166
+ evalsPath: '',
167
+ workspaceDir: '',
168
+ provider: 'anthropic',
169
+ model: undefined,
170
+ maxIterations: 3,
171
+ runsPerQuery: 1,
172
+ triggerThreshold: 0.5,
173
+ holdout: 0.25,
174
+ seed: 42,
175
+ maxIter: 18,
176
+ reasoningMode: 'off',
177
+ output: undefined,
178
+ writeBest: false,
179
+ };
180
+
181
+ for (let index = 2; index < argv.length; index += 1) {
182
+ const token = argv[index];
183
+ if (token === '--skill-path' && argv[index + 1]) {
184
+ args.skillPath = argv[++index];
185
+ } else if (token === '--evals' && argv[index + 1]) {
186
+ args.evalsPath = argv[++index];
187
+ } else if (token === '--workspace' && argv[index + 1]) {
188
+ args.workspaceDir = argv[++index];
189
+ } else if (token === '--provider' && argv[index + 1]) {
190
+ args.provider = argv[++index];
191
+ } else if (token === '--model' && argv[index + 1]) {
192
+ args.model = argv[++index];
193
+ } else if (token === '--max-iterations' && argv[index + 1]) {
194
+ args.maxIterations = Number(argv[++index]);
195
+ } else if (token === '--runs-per-query' && argv[index + 1]) {
196
+ args.runsPerQuery = Number(argv[++index]);
197
+ } else if (token === '--trigger-threshold' && argv[index + 1]) {
198
+ args.triggerThreshold = Number(argv[++index]);
199
+ } else if (token === '--holdout' && argv[index + 1]) {
200
+ args.holdout = Number(argv[++index]);
201
+ } else if (token === '--seed' && argv[index + 1]) {
202
+ args.seed = Number(argv[++index]);
203
+ } else if (token === '--max-iter' && argv[index + 1]) {
204
+ args.maxIter = Number(argv[++index]);
205
+ } else if (token === '--reasoning' && argv[index + 1]) {
206
+ args.reasoningMode = argv[++index];
207
+ } else if (token === '--output' && argv[index + 1]) {
208
+ args.output = argv[++index];
209
+ } else if (token === '--write-best') {
210
+ args.writeBest = true;
211
+ }
212
+ }
213
+
214
+ return args;
215
+ }
216
+
217
+ async function main() {
218
+ const args = parseArgs(process.argv);
219
+ if (!args.skillPath || !args.evalsPath || !args.workspaceDir) {
220
+ console.error('Usage: node scripts/run-loop.js --skill-path <dir> --evals <evals.json> --workspace <dir> [--max-iterations 3]');
221
+ process.exit(1);
222
+ }
223
+
224
+ const report = await runDescriptionLoop(args);
225
+ const outputText = `${JSON.stringify(report, null, 2)}\n`;
226
+
227
+ if (args.output) {
228
+ await writeFile(args.output, outputText, 'utf8');
229
+ console.log(`Wrote ${path.resolve(args.output)}`);
230
+ } else {
231
+ process.stdout.write(outputText);
232
+ }
233
+ }
234
+
235
235
  const isDirectRun = process.env.KODAX_MODULE_BUNDLE !== 'true'
236
236
  && process.argv[1]
237
- && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
238
-
239
- if (isDirectRun) {
240
- main().catch((error) => {
241
- console.error(error instanceof Error ? error.message : String(error));
242
- process.exit(1);
243
- });
244
- }
237
+ && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
238
+
239
+ if (isDirectRun) {
240
+ main().catch((error) => {
241
+ console.error(error instanceof Error ? error.message : String(error));
242
+ process.exit(1);
243
+ });
244
+ }