@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,58 +1,58 @@
1
- export interface TriggerEvalAttempt {
2
- trigger: boolean;
3
- reason: string;
4
- }
5
-
6
- export interface TriggerEvalItemResult {
7
- query: string;
8
- should_trigger: boolean;
9
- triggers: number;
10
- runs: number;
11
- trigger_rate: number;
12
- predicted_trigger: boolean;
13
- pass: boolean;
14
- attempts: TriggerEvalAttempt[];
15
- }
16
-
17
- export interface TriggerEvalSummary {
18
- passed: number;
19
- failed: number;
20
- total: number;
21
- pass_rate: number;
22
- precision: number;
23
- recall: number;
24
- }
25
-
26
- export interface TriggerEvalReport {
27
- skill_name: string;
28
- description: string;
29
- results: TriggerEvalItemResult[];
30
- summary: TriggerEvalSummary;
31
- meta: {
32
- provider?: string;
33
- model?: string | null;
34
- runs_per_query: number;
35
- trigger_threshold: number;
36
- note: string;
37
- };
38
- }
39
-
40
- export interface TriggerEvalOptions {
41
- skillPath: string;
42
- evalsPath: string;
43
- provider?: string;
44
- model?: string;
45
- output?: string;
46
- runsPerQuery?: number;
47
- triggerThreshold?: number;
48
- maxIter?: number;
49
- reasoningMode?: string;
50
- descriptionOverride?: string;
51
- }
52
-
53
- export function parseTriggerDecision(text: string): TriggerEvalAttempt;
54
- export function summarizeTriggerResults(results: TriggerEvalItemResult[]): TriggerEvalSummary;
55
- export function runTriggerEval(
56
- options: TriggerEvalOptions,
57
- runner?: (prompt: string, options: TriggerEvalOptions) => Promise<string>
58
- ): Promise<TriggerEvalReport>;
1
+ export interface TriggerEvalAttempt {
2
+ trigger: boolean;
3
+ reason: string;
4
+ }
5
+
6
+ export interface TriggerEvalItemResult {
7
+ query: string;
8
+ should_trigger: boolean;
9
+ triggers: number;
10
+ runs: number;
11
+ trigger_rate: number;
12
+ predicted_trigger: boolean;
13
+ pass: boolean;
14
+ attempts: TriggerEvalAttempt[];
15
+ }
16
+
17
+ export interface TriggerEvalSummary {
18
+ passed: number;
19
+ failed: number;
20
+ total: number;
21
+ pass_rate: number;
22
+ precision: number;
23
+ recall: number;
24
+ }
25
+
26
+ export interface TriggerEvalReport {
27
+ skill_name: string;
28
+ description: string;
29
+ results: TriggerEvalItemResult[];
30
+ summary: TriggerEvalSummary;
31
+ meta: {
32
+ provider?: string;
33
+ model?: string | null;
34
+ runs_per_query: number;
35
+ trigger_threshold: number;
36
+ note: string;
37
+ };
38
+ }
39
+
40
+ export interface TriggerEvalOptions {
41
+ skillPath: string;
42
+ evalsPath: string;
43
+ provider?: string;
44
+ model?: string;
45
+ output?: string;
46
+ runsPerQuery?: number;
47
+ triggerThreshold?: number;
48
+ maxIter?: number;
49
+ reasoningMode?: string;
50
+ descriptionOverride?: string;
51
+ }
52
+
53
+ export function parseTriggerDecision(text: string): TriggerEvalAttempt;
54
+ export function summarizeTriggerResults(results: TriggerEvalItemResult[]): TriggerEvalSummary;
55
+ export function runTriggerEval(
56
+ options: TriggerEvalOptions,
57
+ runner?: (prompt: string, options: TriggerEvalOptions) => Promise<string>
58
+ ): Promise<TriggerEvalReport>;
@@ -1,226 +1,226 @@
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 {
7
- extractJsonObject,
8
- loadKodaXSDK,
9
- loadSkill,
10
- } from './utils.js';
11
-
12
- function buildTriggerEvalPrompt(skillName, description, query) {
13
- return [
14
- 'You are evaluating whether a KodaX skill description should trigger for a user request.',
15
- 'Decide whether the skill should be used based only on the skill name, description, and query.',
16
- 'Return JSON only with this exact shape:',
17
- '{"trigger": true, "reason": "short explanation"}',
18
- '',
19
- `Skill name: ${skillName}`,
20
- `Skill description: ${description}`,
21
- `User query: ${query}`,
22
- ].join('\n');
23
- }
24
-
25
- export function parseTriggerDecision(text) {
26
- const parsed = extractJsonObject(text);
27
- if (!parsed || typeof parsed !== 'object') {
28
- throw new Error('Could not parse trigger decision JSON');
29
- }
30
-
31
- return {
32
- trigger: parsed.trigger === true,
33
- reason: typeof parsed.reason === 'string' ? parsed.reason.trim() : '',
34
- };
35
- }
36
-
37
- async function defaultRunPrompt(prompt, options) {
38
- const { runKodaX } = await loadKodaXSDK();
39
- const result = await runKodaX(
40
- {
41
- provider: options.provider,
42
- maxIter: options.maxIter ?? 12,
43
- model: options.model,
44
- reasoningMode: options.reasoningMode ?? 'off',
45
- thinking: options.reasoningMode ? options.reasoningMode !== 'off' : false,
46
- },
47
- prompt
48
- );
49
-
50
- return result.lastText;
51
- }
52
-
53
- export function summarizeTriggerResults(results) {
54
- const positives = results.filter((result) => result.should_trigger);
55
- const negatives = results.filter((result) => !result.should_trigger);
56
- const predictedPositives = results.filter((result) => result.predicted_trigger);
57
- const truePositives = positives.filter((result) => result.predicted_trigger).length;
58
- const falsePositives = negatives.filter((result) => result.predicted_trigger).length;
59
-
60
- const summary = {
61
- passed: 0,
62
- failed: 0,
63
- total: results.length,
64
- pass_rate: 0,
65
- precision: 0,
66
- recall: 0,
67
- };
68
-
69
- for (const result of results) {
70
- if (result.pass) {
71
- summary.passed += 1;
72
- } else {
73
- summary.failed += 1;
74
- }
75
- }
76
-
77
- summary.pass_rate = summary.total === 0 ? 0 : summary.passed / summary.total;
78
- summary.precision = predictedPositives.length === 0
79
- ? 0
80
- : truePositives / predictedPositives.length;
81
- summary.recall = positives.length === 0 ? 0 : truePositives / positives.length;
82
-
83
- return summary;
84
- }
85
-
86
- export async function runTriggerEval(options, runner = defaultRunPrompt) {
87
- const skill = await loadSkill(options.skillPath);
88
- const currentDescription = options.descriptionOverride
89
- ?? String(skill.frontmatter.description ?? '').trim();
90
- const evalFile = JSON.parse(await readFile(options.evalsPath, 'utf8'));
91
- const evals = Array.isArray(evalFile.evals) ? evalFile.evals : [];
92
- const runsPerQuery = Number.isFinite(options.runsPerQuery) && options.runsPerQuery > 0
93
- ? Math.floor(options.runsPerQuery)
94
- : 1;
95
- const threshold = Number.isFinite(options.triggerThreshold)
96
- ? Math.min(Math.max(options.triggerThreshold, 0), 1)
97
- : 0.5;
98
- const results = [];
99
-
100
- for (const item of evals) {
101
- const query = String(item.query ?? item.prompt ?? '').trim();
102
- if (!query) {
103
- continue;
104
- }
105
-
106
- const shouldTrigger = item.should_trigger === true;
107
- let triggers = 0;
108
- const attempts = [];
109
-
110
- for (let runIndex = 0; runIndex < runsPerQuery; runIndex += 1) {
111
- const response = await runner(
112
- buildTriggerEvalPrompt(skill.frontmatter.name, currentDescription, query),
113
- options
114
- );
115
- const parsed = parseTriggerDecision(response);
116
- if (parsed.trigger) {
117
- triggers += 1;
118
- }
119
- attempts.push(parsed);
120
- }
121
-
122
- const triggerRate = triggers / runsPerQuery;
123
- const predictedTrigger = triggerRate >= threshold;
124
- const pass = shouldTrigger
125
- ? predictedTrigger
126
- : !predictedTrigger;
127
-
128
- results.push({
129
- query,
130
- should_trigger: shouldTrigger,
131
- triggers,
132
- runs: runsPerQuery,
133
- trigger_rate: triggerRate,
134
- predicted_trigger: predictedTrigger,
135
- pass,
136
- attempts,
137
- });
138
- }
139
-
140
- const summary = summarizeTriggerResults(results);
141
-
142
- return {
143
- skill_name: skill.frontmatter.name,
144
- description: currentDescription,
145
- results,
146
- summary,
147
- meta: {
148
- provider: options.provider,
149
- model: options.model ?? null,
150
- runs_per_query: runsPerQuery,
151
- trigger_threshold: threshold,
152
- note: 'This is a KodaX-native description eval, not a Claude Code tool-trace replay.',
153
- },
154
- };
155
- }
156
-
157
- function parseArgs(argv) {
158
- const args = {
159
- skillPath: '',
160
- evalsPath: '',
161
- provider: 'anthropic',
162
- model: undefined,
163
- output: undefined,
164
- runsPerQuery: 1,
165
- triggerThreshold: 0.5,
166
- maxIter: 12,
167
- reasoningMode: 'off',
168
- descriptionOverride: undefined,
169
- };
170
-
171
- for (let index = 2; index < argv.length; index += 1) {
172
- const token = argv[index];
173
- if (token === '--skill-path' && argv[index + 1]) {
174
- args.skillPath = argv[++index];
175
- } else if (token === '--evals' && argv[index + 1]) {
176
- args.evalsPath = argv[++index];
177
- } else if (token === '--provider' && argv[index + 1]) {
178
- args.provider = argv[++index];
179
- } else if (token === '--model' && argv[index + 1]) {
180
- args.model = argv[++index];
181
- } else if (token === '--output' && argv[index + 1]) {
182
- args.output = argv[++index];
183
- } else if (token === '--runs-per-query' && argv[index + 1]) {
184
- args.runsPerQuery = Number(argv[++index]);
185
- } else if (token === '--trigger-threshold' && argv[index + 1]) {
186
- args.triggerThreshold = Number(argv[++index]);
187
- } else if (token === '--max-iter' && argv[index + 1]) {
188
- args.maxIter = Number(argv[++index]);
189
- } else if (token === '--reasoning' && argv[index + 1]) {
190
- args.reasoningMode = argv[++index];
191
- } else if (token === '--description' && argv[index + 1]) {
192
- args.descriptionOverride = argv[++index];
193
- }
194
- }
195
-
196
- return args;
197
- }
198
-
199
- async function main() {
200
- const args = parseArgs(process.argv);
201
- if (!args.skillPath || !args.evalsPath) {
202
- console.error('Usage: node scripts/run-trigger-eval.js --skill-path <dir> --evals <evals.json> [--provider anthropic] [--output results.json]');
203
- process.exit(1);
204
- }
205
-
206
- const results = await runTriggerEval(args);
207
- const outputText = `${JSON.stringify(results, null, 2)}\n`;
208
-
209
- if (args.output) {
210
- await writeFile(args.output, outputText, 'utf8');
211
- console.log(`Wrote ${path.resolve(args.output)}`);
212
- } else {
213
- process.stdout.write(outputText);
214
- }
215
- }
216
-
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 {
7
+ extractJsonObject,
8
+ loadKodaXSDK,
9
+ loadSkill,
10
+ } from './utils.js';
11
+
12
+ function buildTriggerEvalPrompt(skillName, description, query) {
13
+ return [
14
+ 'You are evaluating whether a KodaX skill description should trigger for a user request.',
15
+ 'Decide whether the skill should be used based only on the skill name, description, and query.',
16
+ 'Return JSON only with this exact shape:',
17
+ '{"trigger": true, "reason": "short explanation"}',
18
+ '',
19
+ `Skill name: ${skillName}`,
20
+ `Skill description: ${description}`,
21
+ `User query: ${query}`,
22
+ ].join('\n');
23
+ }
24
+
25
+ export function parseTriggerDecision(text) {
26
+ const parsed = extractJsonObject(text);
27
+ if (!parsed || typeof parsed !== 'object') {
28
+ throw new Error('Could not parse trigger decision JSON');
29
+ }
30
+
31
+ return {
32
+ trigger: parsed.trigger === true,
33
+ reason: typeof parsed.reason === 'string' ? parsed.reason.trim() : '',
34
+ };
35
+ }
36
+
37
+ async function defaultRunPrompt(prompt, options) {
38
+ const { runKodaX } = await loadKodaXSDK();
39
+ const result = await runKodaX(
40
+ {
41
+ provider: options.provider,
42
+ maxIter: options.maxIter ?? 12,
43
+ model: options.model,
44
+ reasoningMode: options.reasoningMode ?? 'off',
45
+ thinking: options.reasoningMode ? options.reasoningMode !== 'off' : false,
46
+ },
47
+ prompt
48
+ );
49
+
50
+ return result.lastText;
51
+ }
52
+
53
+ export function summarizeTriggerResults(results) {
54
+ const positives = results.filter((result) => result.should_trigger);
55
+ const negatives = results.filter((result) => !result.should_trigger);
56
+ const predictedPositives = results.filter((result) => result.predicted_trigger);
57
+ const truePositives = positives.filter((result) => result.predicted_trigger).length;
58
+ const falsePositives = negatives.filter((result) => result.predicted_trigger).length;
59
+
60
+ const summary = {
61
+ passed: 0,
62
+ failed: 0,
63
+ total: results.length,
64
+ pass_rate: 0,
65
+ precision: 0,
66
+ recall: 0,
67
+ };
68
+
69
+ for (const result of results) {
70
+ if (result.pass) {
71
+ summary.passed += 1;
72
+ } else {
73
+ summary.failed += 1;
74
+ }
75
+ }
76
+
77
+ summary.pass_rate = summary.total === 0 ? 0 : summary.passed / summary.total;
78
+ summary.precision = predictedPositives.length === 0
79
+ ? 0
80
+ : truePositives / predictedPositives.length;
81
+ summary.recall = positives.length === 0 ? 0 : truePositives / positives.length;
82
+
83
+ return summary;
84
+ }
85
+
86
+ export async function runTriggerEval(options, runner = defaultRunPrompt) {
87
+ const skill = await loadSkill(options.skillPath);
88
+ const currentDescription = options.descriptionOverride
89
+ ?? String(skill.frontmatter.description ?? '').trim();
90
+ const evalFile = JSON.parse(await readFile(options.evalsPath, 'utf8'));
91
+ const evals = Array.isArray(evalFile.evals) ? evalFile.evals : [];
92
+ const runsPerQuery = Number.isFinite(options.runsPerQuery) && options.runsPerQuery > 0
93
+ ? Math.floor(options.runsPerQuery)
94
+ : 1;
95
+ const threshold = Number.isFinite(options.triggerThreshold)
96
+ ? Math.min(Math.max(options.triggerThreshold, 0), 1)
97
+ : 0.5;
98
+ const results = [];
99
+
100
+ for (const item of evals) {
101
+ const query = String(item.query ?? item.prompt ?? '').trim();
102
+ if (!query) {
103
+ continue;
104
+ }
105
+
106
+ const shouldTrigger = item.should_trigger === true;
107
+ let triggers = 0;
108
+ const attempts = [];
109
+
110
+ for (let runIndex = 0; runIndex < runsPerQuery; runIndex += 1) {
111
+ const response = await runner(
112
+ buildTriggerEvalPrompt(skill.frontmatter.name, currentDescription, query),
113
+ options
114
+ );
115
+ const parsed = parseTriggerDecision(response);
116
+ if (parsed.trigger) {
117
+ triggers += 1;
118
+ }
119
+ attempts.push(parsed);
120
+ }
121
+
122
+ const triggerRate = triggers / runsPerQuery;
123
+ const predictedTrigger = triggerRate >= threshold;
124
+ const pass = shouldTrigger
125
+ ? predictedTrigger
126
+ : !predictedTrigger;
127
+
128
+ results.push({
129
+ query,
130
+ should_trigger: shouldTrigger,
131
+ triggers,
132
+ runs: runsPerQuery,
133
+ trigger_rate: triggerRate,
134
+ predicted_trigger: predictedTrigger,
135
+ pass,
136
+ attempts,
137
+ });
138
+ }
139
+
140
+ const summary = summarizeTriggerResults(results);
141
+
142
+ return {
143
+ skill_name: skill.frontmatter.name,
144
+ description: currentDescription,
145
+ results,
146
+ summary,
147
+ meta: {
148
+ provider: options.provider,
149
+ model: options.model ?? null,
150
+ runs_per_query: runsPerQuery,
151
+ trigger_threshold: threshold,
152
+ note: 'This is a KodaX-native description eval, not a Claude Code tool-trace replay.',
153
+ },
154
+ };
155
+ }
156
+
157
+ function parseArgs(argv) {
158
+ const args = {
159
+ skillPath: '',
160
+ evalsPath: '',
161
+ provider: 'anthropic',
162
+ model: undefined,
163
+ output: undefined,
164
+ runsPerQuery: 1,
165
+ triggerThreshold: 0.5,
166
+ maxIter: 12,
167
+ reasoningMode: 'off',
168
+ descriptionOverride: undefined,
169
+ };
170
+
171
+ for (let index = 2; index < argv.length; index += 1) {
172
+ const token = argv[index];
173
+ if (token === '--skill-path' && argv[index + 1]) {
174
+ args.skillPath = argv[++index];
175
+ } else if (token === '--evals' && argv[index + 1]) {
176
+ args.evalsPath = argv[++index];
177
+ } else if (token === '--provider' && argv[index + 1]) {
178
+ args.provider = argv[++index];
179
+ } else if (token === '--model' && argv[index + 1]) {
180
+ args.model = argv[++index];
181
+ } else if (token === '--output' && argv[index + 1]) {
182
+ args.output = argv[++index];
183
+ } else if (token === '--runs-per-query' && argv[index + 1]) {
184
+ args.runsPerQuery = Number(argv[++index]);
185
+ } else if (token === '--trigger-threshold' && argv[index + 1]) {
186
+ args.triggerThreshold = Number(argv[++index]);
187
+ } else if (token === '--max-iter' && argv[index + 1]) {
188
+ args.maxIter = Number(argv[++index]);
189
+ } else if (token === '--reasoning' && argv[index + 1]) {
190
+ args.reasoningMode = argv[++index];
191
+ } else if (token === '--description' && argv[index + 1]) {
192
+ args.descriptionOverride = argv[++index];
193
+ }
194
+ }
195
+
196
+ return args;
197
+ }
198
+
199
+ async function main() {
200
+ const args = parseArgs(process.argv);
201
+ if (!args.skillPath || !args.evalsPath) {
202
+ console.error('Usage: node scripts/run-trigger-eval.js --skill-path <dir> --evals <evals.json> [--provider anthropic] [--output results.json]');
203
+ process.exit(1);
204
+ }
205
+
206
+ const results = await runTriggerEval(args);
207
+ const outputText = `${JSON.stringify(results, null, 2)}\n`;
208
+
209
+ if (args.output) {
210
+ await writeFile(args.output, outputText, 'utf8');
211
+ console.log(`Wrote ${path.resolve(args.output)}`);
212
+ } else {
213
+ process.stdout.write(outputText);
214
+ }
215
+ }
216
+
217
217
  const isDirectRun = process.env.KODAX_MODULE_BUNDLE !== 'true'
218
218
  && process.argv[1]
219
- && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
220
-
221
- if (isDirectRun) {
222
- main().catch((error) => {
223
- console.error(error instanceof Error ? error.message : String(error));
224
- process.exit(1);
225
- });
226
- }
219
+ && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]);
220
+
221
+ if (isDirectRun) {
222
+ main().catch((error) => {
223
+ console.error(error instanceof Error ? error.message : String(error));
224
+ process.exit(1);
225
+ });
226
+ }