@snoglobe/helios 0.2.1 → 0.3.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 (180) hide show
  1. package/README.md +112 -25
  2. package/dist/acp/server.d.ts.map +1 -1
  3. package/dist/acp/server.js +2 -1
  4. package/dist/acp/server.js.map +1 -1
  5. package/dist/app.d.ts.map +1 -1
  6. package/dist/app.js +2 -1
  7. package/dist/app.js.map +1 -1
  8. package/dist/cli/discover.d.ts +12 -0
  9. package/dist/cli/discover.d.ts.map +1 -0
  10. package/dist/cli/discover.js +60 -0
  11. package/dist/cli/discover.js.map +1 -0
  12. package/dist/cli/doctor.d.ts.map +1 -1
  13. package/dist/cli/doctor.js +2 -1
  14. package/dist/cli/doctor.js.map +1 -1
  15. package/dist/cli/export.d.ts.map +1 -1
  16. package/dist/cli/export.js +2 -1
  17. package/dist/cli/export.js.map +1 -1
  18. package/dist/cli/index.d.ts +1 -0
  19. package/dist/cli/index.d.ts.map +1 -1
  20. package/dist/cli/index.js +12 -3
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/cli/options.d.ts +1 -0
  23. package/dist/cli/options.d.ts.map +1 -1
  24. package/dist/cli/options.js +1 -0
  25. package/dist/cli/options.js.map +1 -1
  26. package/dist/cli/replay.d.ts.map +1 -1
  27. package/dist/cli/replay.js +2 -1
  28. package/dist/cli/replay.js.map +1 -1
  29. package/dist/cli/report.d.ts.map +1 -1
  30. package/dist/cli/report.js +15 -10
  31. package/dist/cli/report.js.map +1 -1
  32. package/dist/cli/research.d.ts +12 -0
  33. package/dist/cli/research.d.ts.map +1 -0
  34. package/dist/cli/research.js +60 -0
  35. package/dist/cli/research.js.map +1 -0
  36. package/dist/cli/search.d.ts.map +1 -1
  37. package/dist/cli/search.js +2 -1
  38. package/dist/cli/search.js.map +1 -1
  39. package/dist/cli/sessions.d.ts.map +1 -1
  40. package/dist/cli/sessions.js +2 -1
  41. package/dist/cli/sessions.js.map +1 -1
  42. package/dist/core/orchestrator.d.ts +6 -0
  43. package/dist/core/orchestrator.d.ts.map +1 -1
  44. package/dist/core/orchestrator.js +41 -14
  45. package/dist/core/orchestrator.js.map +1 -1
  46. package/dist/hub/client.d.ts.map +1 -1
  47. package/dist/hub/client.js +3 -2
  48. package/dist/hub/client.js.map +1 -1
  49. package/dist/hub/config.d.ts.map +1 -1
  50. package/dist/hub/config.js +4 -5
  51. package/dist/hub/config.js.map +1 -1
  52. package/dist/init.d.ts +3 -1
  53. package/dist/init.d.ts.map +1 -1
  54. package/dist/init.js +35 -8
  55. package/dist/init.js.map +1 -1
  56. package/dist/memory/context-gate.d.ts +0 -4
  57. package/dist/memory/context-gate.d.ts.map +1 -1
  58. package/dist/memory/context-gate.js +0 -7
  59. package/dist/memory/context-gate.js.map +1 -1
  60. package/dist/memory/experiment-tracker.d.ts +0 -2
  61. package/dist/memory/experiment-tracker.d.ts.map +1 -1
  62. package/dist/memory/experiment-tracker.js +0 -4
  63. package/dist/memory/experiment-tracker.js.map +1 -1
  64. package/dist/memory/global-memory.d.ts +34 -0
  65. package/dist/memory/global-memory.d.ts.map +1 -0
  66. package/dist/memory/global-memory.js +128 -0
  67. package/dist/memory/global-memory.js.map +1 -0
  68. package/dist/metrics/store.d.ts +0 -4
  69. package/dist/metrics/store.d.ts.map +1 -1
  70. package/dist/metrics/store.js +0 -17
  71. package/dist/metrics/store.js.map +1 -1
  72. package/dist/paths.d.ts +8 -0
  73. package/dist/paths.d.ts.map +1 -1
  74. package/dist/paths.js +29 -0
  75. package/dist/paths.js.map +1 -1
  76. package/dist/providers/claude/provider.d.ts +2 -1
  77. package/dist/providers/claude/provider.d.ts.map +1 -1
  78. package/dist/providers/claude/provider.js +83 -16
  79. package/dist/providers/claude/provider.js.map +1 -1
  80. package/dist/providers/openai/provider.d.ts +0 -1
  81. package/dist/providers/openai/provider.d.ts.map +1 -1
  82. package/dist/providers/openai/provider.js +25 -9
  83. package/dist/providers/openai/provider.js.map +1 -1
  84. package/dist/providers/retry.d.ts +6 -0
  85. package/dist/providers/retry.d.ts.map +1 -1
  86. package/dist/providers/retry.js +36 -1
  87. package/dist/providers/retry.js.map +1 -1
  88. package/dist/remote/config.d.ts.map +1 -1
  89. package/dist/remote/config.js +2 -6
  90. package/dist/remote/config.js.map +1 -1
  91. package/dist/remote/connection-pool.d.ts +3 -1
  92. package/dist/remote/connection-pool.d.ts.map +1 -1
  93. package/dist/remote/connection-pool.js +35 -7
  94. package/dist/remote/connection-pool.js.map +1 -1
  95. package/dist/remote/executor.d.ts +0 -1
  96. package/dist/remote/executor.d.ts.map +1 -1
  97. package/dist/remote/executor.js +0 -4
  98. package/dist/remote/executor.js.map +1 -1
  99. package/dist/scheduler/sleep-manager.d.ts.map +1 -1
  100. package/dist/scheduler/sleep-manager.js +5 -7
  101. package/dist/scheduler/sleep-manager.js.map +1 -1
  102. package/dist/scheduler/trigger-scheduler.d.ts.map +1 -1
  103. package/dist/scheduler/trigger-scheduler.js +2 -2
  104. package/dist/scheduler/trigger-scheduler.js.map +1 -1
  105. package/dist/skills/bundled/ablation.md +23 -0
  106. package/dist/skills/bundled/consult.md +6 -0
  107. package/dist/skills/bundled/discover.md +45 -0
  108. package/dist/skills/bundled/paper.md +34 -0
  109. package/dist/skills/bundled/research.md +44 -0
  110. package/dist/skills/bundled/writeup.md +57 -0
  111. package/dist/skills/executor.d.ts +28 -0
  112. package/dist/skills/executor.d.ts.map +1 -0
  113. package/dist/skills/executor.js +148 -0
  114. package/dist/skills/executor.js.map +1 -0
  115. package/dist/skills/loader.d.ts +17 -0
  116. package/dist/skills/loader.d.ts.map +1 -0
  117. package/dist/skills/loader.js +194 -0
  118. package/dist/skills/loader.js.map +1 -0
  119. package/dist/skills/registry.d.ts +12 -0
  120. package/dist/skills/registry.d.ts.map +1 -0
  121. package/dist/skills/registry.js +25 -0
  122. package/dist/skills/registry.js.map +1 -0
  123. package/dist/skills/types.d.ts +37 -0
  124. package/dist/skills/types.d.ts.map +1 -0
  125. package/dist/skills/types.js +2 -0
  126. package/dist/skills/types.js.map +1 -0
  127. package/dist/store/preferences.d.ts.map +1 -1
  128. package/dist/store/preferences.js +3 -11
  129. package/dist/store/preferences.js.map +1 -1
  130. package/dist/tools/compare-runs.d.ts.map +1 -1
  131. package/dist/tools/compare-runs.js +3 -2
  132. package/dist/tools/compare-runs.js.map +1 -1
  133. package/dist/tools/consult.d.ts +4 -2
  134. package/dist/tools/consult.d.ts.map +1 -1
  135. package/dist/tools/consult.js +17 -35
  136. package/dist/tools/consult.js.map +1 -1
  137. package/dist/tools/experiment-branch.js +7 -7
  138. package/dist/tools/experiment-branch.js.map +1 -1
  139. package/dist/tools/file-ops.d.ts.map +1 -1
  140. package/dist/tools/file-ops.js +55 -10
  141. package/dist/tools/file-ops.js.map +1 -1
  142. package/dist/tools/hub.js +17 -17
  143. package/dist/tools/hub.js.map +1 -1
  144. package/dist/tools/memory-tools.d.ts.map +1 -1
  145. package/dist/tools/memory-tools.js +2 -1
  146. package/dist/tools/memory-tools.js.map +1 -1
  147. package/dist/tools/sleep.d.ts.map +1 -1
  148. package/dist/tools/sleep.js +2 -1
  149. package/dist/tools/sleep.js.map +1 -1
  150. package/dist/tools/sweep.js +3 -3
  151. package/dist/tools/sweep.js.map +1 -1
  152. package/dist/tools/web-fetch.d.ts.map +1 -1
  153. package/dist/tools/web-fetch.js +5 -6
  154. package/dist/tools/web-fetch.js.map +1 -1
  155. package/dist/tools/writeup.d.ts +4 -10
  156. package/dist/tools/writeup.d.ts.map +1 -1
  157. package/dist/tools/writeup.js +16 -77
  158. package/dist/tools/writeup.js.map +1 -1
  159. package/dist/ui/commands.d.ts +2 -0
  160. package/dist/ui/commands.d.ts.map +1 -1
  161. package/dist/ui/commands.js +86 -35
  162. package/dist/ui/commands.js.map +1 -1
  163. package/dist/ui/components/input-bar.d.ts +3 -1
  164. package/dist/ui/components/input-bar.d.ts.map +1 -1
  165. package/dist/ui/components/input-bar.js +2 -2
  166. package/dist/ui/components/input-bar.js.map +1 -1
  167. package/dist/ui/components/status-bar.d.ts +3 -1
  168. package/dist/ui/components/status-bar.d.ts.map +1 -1
  169. package/dist/ui/components/status-bar.js +14 -2
  170. package/dist/ui/components/status-bar.js.map +1 -1
  171. package/dist/ui/format.d.ts +4 -0
  172. package/dist/ui/format.d.ts.map +1 -1
  173. package/dist/ui/format.js +8 -0
  174. package/dist/ui/format.js.map +1 -1
  175. package/dist/ui/layout.d.ts.map +1 -1
  176. package/dist/ui/layout.js +40 -7
  177. package/dist/ui/layout.js.map +1 -1
  178. package/dist/ui/panels/conversation.js +7 -3
  179. package/dist/ui/panels/conversation.js.map +1 -1
  180. package/package.json +2 -2
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: writeup
3
+ description: Generate a structured experiment writeup
4
+ tools: [memory_ls, memory_read, show_metrics, compare_runs, read_file, task_output, web_fetch]
5
+ ---
6
+ You are a scientific writing assistant. You will receive experiment notes or a session transcript from an ML research agent.
7
+
8
+ Produce a clean, structured experiment writeup. Write it as a practitioner's report, not an academic paper. Be concise but thorough.
9
+
10
+ ## Available Tools
11
+ You have access to read-only tools to gather data for the writeup. Use them proactively:
12
+ - **memory_ls / memory_read**: Read the agent's memory tree for experiment results, observations, and stored findings
13
+ - **show_metrics / compare_runs**: Query metric data and compare experiment runs
14
+ - **read_file**: Read code, configs, or data files from machines
15
+ - **task_output**: Check output from running or finished tasks
16
+ - **web_fetch**: Fetch referenced papers or documentation
17
+
18
+ Use these tools to fill in gaps — if the notes mention an experiment but lack specific numbers, check metrics or memory. If code changes are referenced, read the relevant files.
19
+
20
+ ## Format
21
+
22
+ # [Title — infer from the goal]
23
+
24
+ ## Objective
25
+ What was the researcher trying to achieve?
26
+
27
+ ## Setup
28
+ - Model architecture, dataset, hardware
29
+ - Key hyperparameters and configuration
30
+
31
+ ## Experiments
32
+ For each distinct experiment/run:
33
+ - What was tried and why
34
+ - Key metrics (include actual numbers)
35
+ - Whether it improved over the previous best
36
+
37
+ ## Results
38
+ - Best configuration found
39
+ - Final metric values
40
+ - Comparison to baseline / starting point
41
+
42
+ ## Observations
43
+ - What worked, what didn't
44
+ - Surprising findings
45
+ - Hypotheses about why certain changes helped/hurt
46
+
47
+ ## Next Steps (if applicable)
48
+ - Promising directions not yet explored
49
+ - Known limitations
50
+
51
+ ## Citations
52
+ - If the work builds on another agent's commit, cite it: "Based on [agent_id/hash_prefix]"
53
+ - If referencing an AgentHub post, cite by post ID: "As noted in post #42"
54
+ - If reproducing or extending results from another agent, credit them explicitly
55
+ - Look for hub_fetch, hub_read, and hub_log tool calls in the transcript to identify sources
56
+
57
+ Keep the writing direct and data-driven. Use actual metric values. Do not invent data.
@@ -0,0 +1,28 @@
1
+ import type { Skill } from "./types.js";
2
+ import type { ToolDefinition, AgentEvent } from "../providers/types.js";
3
+ import type { Orchestrator } from "../core/orchestrator.js";
4
+ export interface SkillExecContext {
5
+ orchestrator: Orchestrator;
6
+ /** All registered tools on the orchestrator (for filtering). */
7
+ allTools: ToolDefinition[];
8
+ /** Signal to stop a looping skill. */
9
+ signal?: AbortSignal;
10
+ }
11
+ /**
12
+ * Execute a skill. Yields AgentEvents that the caller can
13
+ * render however they want (TUI streaming, stdout, tool result JSON, etc.).
14
+ *
15
+ * For looping skills (loop: true), runs repeatedly with delay_ms pauses,
16
+ * each iteration as a fresh session. The model uses memory to maintain
17
+ * continuity. Loops until ctx.signal is aborted.
18
+ */
19
+ export declare function executeSkill(skill: Skill, args: Record<string, string>, input: string, ctx: SkillExecContext): AsyncGenerator<AgentEvent>;
20
+ /**
21
+ * Execute a skill and collect all text output into a string.
22
+ * Used by tools that wrap skills (e.g. the writeup tool, consult tool).
23
+ */
24
+ export declare function executeSkillToString(skill: Skill, args: Record<string, string>, input: string, ctx: SkillExecContext): Promise<{
25
+ text: string;
26
+ error?: string;
27
+ }>;
28
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/skills/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAiB,MAAM,uBAAuB,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAY5D,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,YAAY,CAAC;IAC3B,gEAAgE;IAChE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,sCAAsC;IACtC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAoED;;;;;;;GAOG;AACH,wBAAuB,YAAY,CACjC,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,gBAAgB,GACpB,cAAc,CAAC,UAAU,CAAC,CAyD5B;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAe3C"}
@@ -0,0 +1,148 @@
1
+ import { renderTemplate } from "./loader.js";
2
+ import { formatError } from "../ui/format.js";
3
+ /** Sleep that can be interrupted by an AbortSignal. */
4
+ function interruptibleSleep(ms, signal) {
5
+ if (signal?.aborted)
6
+ return Promise.resolve();
7
+ return new Promise((resolve) => {
8
+ const timer = setTimeout(resolve, ms);
9
+ signal?.addEventListener("abort", () => { clearTimeout(timer); resolve(); }, { once: true });
10
+ });
11
+ }
12
+ /**
13
+ * Resolve which provider a skill should use.
14
+ * "other" means the non-active provider (for consult-style skills).
15
+ */
16
+ function resolveProvider(skill, orch) {
17
+ const cfg = skill.config.provider;
18
+ if (!cfg || cfg === null)
19
+ return orch.currentProvider ?? null;
20
+ if (cfg === "other") {
21
+ const activeName = orch.currentProvider?.name;
22
+ if (!activeName)
23
+ return null;
24
+ const otherName = activeName === "claude" ? "openai" : "claude";
25
+ return orch.getProvider(otherName);
26
+ }
27
+ return orch.getProvider(cfg);
28
+ }
29
+ /** Filter tools based on skill's allow/deny config. */
30
+ function filterTools(allTools, skill) {
31
+ const access = skill.config.tools;
32
+ if (!access)
33
+ return allTools;
34
+ if (access.allow) {
35
+ const allowed = new Set(access.allow);
36
+ return allTools.filter((t) => allowed.has(t.name));
37
+ }
38
+ if (access.deny) {
39
+ const denied = new Set(access.deny);
40
+ return allTools.filter((t) => !denied.has(t.name));
41
+ }
42
+ return allTools;
43
+ }
44
+ /** Run a single iteration of a skill (one provider session). */
45
+ async function* runOnce(skill, args, input, provider, tools, orch) {
46
+ const systemPrompt = renderTemplate(skill.template, args);
47
+ const session = await provider.createSession({
48
+ systemPrompt,
49
+ model: skill.config.model ?? undefined,
50
+ });
51
+ const stream = provider.send(session, input, tools);
52
+ try {
53
+ for await (const event of stream) {
54
+ if (event.type === "done" && event.usage?.costUsd) {
55
+ orch.addCost(event.usage.costUsd, event.usage.inputTokens, event.usage.outputTokens);
56
+ }
57
+ yield event;
58
+ }
59
+ }
60
+ finally {
61
+ // Ensure inner generator is closed on early termination (preserves yield* semantics)
62
+ await stream.return(undefined).catch(() => { });
63
+ await provider.closeSession(session).catch(() => { });
64
+ }
65
+ }
66
+ /**
67
+ * Execute a skill. Yields AgentEvents that the caller can
68
+ * render however they want (TUI streaming, stdout, tool result JSON, etc.).
69
+ *
70
+ * For looping skills (loop: true), runs repeatedly with delay_ms pauses,
71
+ * each iteration as a fresh session. The model uses memory to maintain
72
+ * continuity. Loops until ctx.signal is aborted.
73
+ */
74
+ export async function* executeSkill(skill, args, input, ctx) {
75
+ const provider = resolveProvider(skill, ctx.orchestrator);
76
+ if (!provider) {
77
+ yield { type: "error", error: new Error(`No provider available for skill "${skill.name}"`), recoverable: false };
78
+ return;
79
+ }
80
+ // Check auth for cross-provider skills
81
+ if (skill.config.provider === "other") {
82
+ if (!(await provider.isAuthenticated())) {
83
+ yield {
84
+ type: "error",
85
+ error: new Error(`Provider "${provider.name}" is not authenticated. Run /switch ${provider.name} first.`),
86
+ recoverable: false,
87
+ };
88
+ return;
89
+ }
90
+ }
91
+ const tools = filterTools(ctx.allTools, skill);
92
+ if (!skill.config.loop) {
93
+ // One-shot skill
94
+ yield* runOnce(skill, args, input, provider, tools, ctx.orchestrator);
95
+ return;
96
+ }
97
+ // Looping skill — re-invoke with delay between iterations
98
+ const delayMs = skill.config.delay_ms ?? 60_000;
99
+ let iteration = 0;
100
+ while (!ctx.signal?.aborted) {
101
+ iteration++;
102
+ const loopMsg = skill.config.loop_message ?? "Continue. This is iteration {iteration}.";
103
+ const iterInput = iteration === 1
104
+ ? input
105
+ : loopMsg.replace(/\{iteration\}/g, String(iteration));
106
+ try {
107
+ yield* runOnce(skill, args, iterInput, provider, tools, ctx.orchestrator);
108
+ }
109
+ catch (err) {
110
+ yield {
111
+ type: "error",
112
+ error: err instanceof Error ? err : new Error(String(err)),
113
+ recoverable: true,
114
+ };
115
+ }
116
+ // Wait between iterations (interruptible)
117
+ if (ctx.signal?.aborted)
118
+ break;
119
+ yield {
120
+ type: "text",
121
+ text: `\n*[next iteration in ${Math.round(delayMs / 1000)}s — Esc to stop]*\n`,
122
+ delta: `\n*[next iteration in ${Math.round(delayMs / 1000)}s — Esc to stop]*\n`,
123
+ };
124
+ await interruptibleSleep(delayMs, ctx.signal);
125
+ }
126
+ }
127
+ /**
128
+ * Execute a skill and collect all text output into a string.
129
+ * Used by tools that wrap skills (e.g. the writeup tool, consult tool).
130
+ */
131
+ export async function executeSkillToString(skill, args, input, ctx) {
132
+ let text = "";
133
+ try {
134
+ for await (const event of executeSkill(skill, args, input, ctx)) {
135
+ if (event.type === "text" && event.delta) {
136
+ text += event.delta;
137
+ }
138
+ if (event.type === "error") {
139
+ return { text, error: formatError(event.error) };
140
+ }
141
+ }
142
+ return { text: text || "(empty response)" };
143
+ }
144
+ catch (err) {
145
+ return { text, error: formatError(err) };
146
+ }
147
+ }
148
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/skills/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Skill } from "./types.js";
2
+ /**
3
+ * Copy bundled skills to ~/.helios/skills/ if they don't already exist.
4
+ * Called on first launch (or upgrade when new skills are added).
5
+ * Never overwrites user-edited files.
6
+ */
7
+ export declare function seedBundledSkills(): void;
8
+ export declare function parseSkillFile(filePath: string, source: Skill["source"]): Skill | null;
9
+ /**
10
+ * Discover all skills. Priority: project > user.
11
+ * Bundled skills live in USER_DIR after seeding (see seedBundledSkills).
12
+ * Project skills override user skills with the same name.
13
+ */
14
+ export declare function discoverSkills(projectDir?: string): Skill[];
15
+ /** Render a template with {arg} placeholders replaced. */
16
+ export declare function renderTemplate(template: string, args: Record<string, string>): string;
17
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAgC,MAAM,YAAY,CAAC;AAwGtE;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAiBxC;AAID,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,KAAK,GAAG,IAAI,CAoCtF;AAaD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,CAa3D;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAErF"}
@@ -0,0 +1,194 @@
1
+ import { readdirSync, readFileSync, mkdirSync, copyFileSync, constants as fsConstants } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { HELIOS_DIR } from "../paths.js";
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ /** Directory for bundled skills (lives next to compiled JS). */
7
+ const BUNDLED_DIR = join(__dirname, "bundled");
8
+ /** User-global skills — bundled skills are seeded here on first launch. */
9
+ const USER_DIR = join(HELIOS_DIR, "skills");
10
+ // ─── Frontmatter parser (no yaml dependency needed) ──
11
+ function parseFrontmatter(raw) {
12
+ const match = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
13
+ if (!match)
14
+ return null;
15
+ const meta = {};
16
+ let currentKey = null;
17
+ let currentValue = "";
18
+ let inBlock = false;
19
+ let blockIndent = 0;
20
+ for (const line of match[1].split("\n")) {
21
+ // Continuation of a block (indented sub-keys or list items)
22
+ if (inBlock && currentKey) {
23
+ const indent = line.search(/\S/);
24
+ if (indent > blockIndent || line.trim() === "") {
25
+ currentValue += "\n" + line;
26
+ continue;
27
+ }
28
+ // Block ended — flush
29
+ meta[currentKey] = parseYamlValue(currentValue.trim(), true);
30
+ inBlock = false;
31
+ currentKey = null;
32
+ currentValue = "";
33
+ }
34
+ const kvMatch = line.match(/^(\w[\w-]*)\s*:\s*(.*)$/);
35
+ if (!kvMatch)
36
+ continue;
37
+ const [, key, rest] = kvMatch;
38
+ const trimmed = rest.trim();
39
+ if (trimmed === "" || trimmed.startsWith("\n")) {
40
+ // Block value starts on next line
41
+ currentKey = key;
42
+ currentValue = "";
43
+ inBlock = true;
44
+ blockIndent = key.length + 1;
45
+ }
46
+ else {
47
+ meta[key] = parseYamlValue(trimmed, false);
48
+ }
49
+ }
50
+ // Flush trailing block
51
+ if (inBlock && currentKey) {
52
+ meta[currentKey] = parseYamlValue(currentValue.trim(), true);
53
+ }
54
+ return { meta, body: match[2].trim() };
55
+ }
56
+ function parseYamlValue(raw, isBlock) {
57
+ // Inline list: [a, b, c]
58
+ const listMatch = raw.match(/^\[([^\]]*)\]$/);
59
+ if (listMatch) {
60
+ return listMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
61
+ }
62
+ // Block list (each line starts with "- ")
63
+ if (isBlock && raw.includes("\n")) {
64
+ const lines = raw.split("\n");
65
+ // Check if it's a list
66
+ if (lines.every((l) => l.trim().startsWith("- ") || l.trim() === "")) {
67
+ return lines
68
+ .map((l) => l.trim())
69
+ .filter((l) => l.startsWith("- "))
70
+ .map((l) => l.slice(2).trim());
71
+ }
72
+ // Check if it's a nested object
73
+ const obj = {};
74
+ for (const l of lines) {
75
+ const m = l.trim().match(/^(\w[\w-]*)\s*:\s*(.*)$/);
76
+ if (m)
77
+ obj[m[1]] = parseYamlValue(m[2].trim(), false);
78
+ }
79
+ if (Object.keys(obj).length > 0)
80
+ return obj;
81
+ return raw;
82
+ }
83
+ // Null
84
+ if (raw === "null" || raw === "~")
85
+ return null;
86
+ // Boolean
87
+ if (raw === "true")
88
+ return true;
89
+ if (raw === "false")
90
+ return false;
91
+ // Number
92
+ if (/^-?\d+(\.\d+)?$/.test(raw))
93
+ return Number(raw);
94
+ // Quoted string
95
+ if ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'"))) {
96
+ return raw.slice(1, -1);
97
+ }
98
+ return raw;
99
+ }
100
+ // ─── Skill seeding ──────────────────────────────────
101
+ /**
102
+ * Copy bundled skills to ~/.helios/skills/ if they don't already exist.
103
+ * Called on first launch (or upgrade when new skills are added).
104
+ * Never overwrites user-edited files.
105
+ */
106
+ export function seedBundledSkills() {
107
+ let files;
108
+ try {
109
+ files = readdirSync(BUNDLED_DIR).filter((f) => f.endsWith(".md"));
110
+ }
111
+ catch {
112
+ return; // No bundled dir
113
+ }
114
+ mkdirSync(USER_DIR, { recursive: true });
115
+ for (const file of files) {
116
+ try {
117
+ copyFileSync(join(BUNDLED_DIR, file), join(USER_DIR, file), fsConstants.COPYFILE_EXCL);
118
+ }
119
+ catch {
120
+ // Already exists — don't overwrite user edits
121
+ }
122
+ }
123
+ }
124
+ // ─── Skill loading ───────────────────────────────────
125
+ export function parseSkillFile(filePath, source) {
126
+ try {
127
+ const raw = readFileSync(filePath, "utf-8");
128
+ const parsed = parseFrontmatter(raw);
129
+ if (!parsed)
130
+ return null;
131
+ const { meta, body } = parsed;
132
+ const name = meta.name;
133
+ const description = meta.description;
134
+ if (!name || !description)
135
+ return null;
136
+ const config = {
137
+ name,
138
+ description,
139
+ args: meta.args,
140
+ model: meta.model ?? null,
141
+ reasoning: meta.reasoning ?? null,
142
+ provider: meta.provider ?? null,
143
+ loop: meta.loop === true,
144
+ delay_ms: typeof meta.delay_ms === "number" ? meta.delay_ms : undefined,
145
+ loop_message: meta.loop_message ?? undefined,
146
+ };
147
+ // Parse tools — can be a simple list (shorthand for allow) or object with allow/deny
148
+ if (meta.tools) {
149
+ if (Array.isArray(meta.tools)) {
150
+ config.tools = { allow: meta.tools };
151
+ }
152
+ else if (typeof meta.tools === "object") {
153
+ config.tools = meta.tools;
154
+ }
155
+ }
156
+ return { name, description, source, filePath, config, template: body };
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }
162
+ function loadDir(dir, source) {
163
+ try {
164
+ return readdirSync(dir)
165
+ .filter((f) => f.endsWith(".md"))
166
+ .map((f) => parseSkillFile(join(dir, f), source))
167
+ .filter((s) => s !== null);
168
+ }
169
+ catch {
170
+ return [];
171
+ }
172
+ }
173
+ /**
174
+ * Discover all skills. Priority: project > user.
175
+ * Bundled skills live in USER_DIR after seeding (see seedBundledSkills).
176
+ * Project skills override user skills with the same name.
177
+ */
178
+ export function discoverSkills(projectDir) {
179
+ const byName = new Map();
180
+ for (const skill of loadDir(USER_DIR, "user")) {
181
+ byName.set(skill.name, skill);
182
+ }
183
+ if (projectDir) {
184
+ for (const skill of loadDir(join(projectDir, ".helios", "skills"), "project")) {
185
+ byName.set(skill.name, skill);
186
+ }
187
+ }
188
+ return Array.from(byName.values());
189
+ }
190
+ /** Render a template with {arg} placeholders replaced. */
191
+ export function renderTemplate(template, args) {
192
+ return template.replace(/\{(\w+)\}/g, (match, key) => args[key] ?? match);
193
+ }
194
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/skills/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Skill } from "./types.js";
2
+ export declare class SkillRegistry {
3
+ private skills;
4
+ private projectDir?;
5
+ constructor(projectDir?: string);
6
+ /** Load (or reload) all skills from user + project dirs. */
7
+ load(): void;
8
+ get(name: string): Skill | undefined;
9
+ list(): Skill[];
10
+ names(): string[];
11
+ }
12
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,UAAU,CAAC,CAAS;gBAEhB,UAAU,CAAC,EAAE,MAAM;IAI/B,4DAA4D;IAC5D,IAAI,IAAI,IAAI;IAOZ,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIpC,IAAI,IAAI,KAAK,EAAE;IAIf,KAAK,IAAI,MAAM,EAAE;CAGlB"}
@@ -0,0 +1,25 @@
1
+ import { discoverSkills } from "./loader.js";
2
+ export class SkillRegistry {
3
+ skills = new Map();
4
+ projectDir;
5
+ constructor(projectDir) {
6
+ this.projectDir = projectDir;
7
+ }
8
+ /** Load (or reload) all skills from user + project dirs. */
9
+ load() {
10
+ this.skills.clear();
11
+ for (const skill of discoverSkills(this.projectDir)) {
12
+ this.skills.set(skill.name, skill);
13
+ }
14
+ }
15
+ get(name) {
16
+ return this.skills.get(name);
17
+ }
18
+ list() {
19
+ return Array.from(this.skills.values());
20
+ }
21
+ names() {
22
+ return Array.from(this.skills.keys());
23
+ }
24
+ }
25
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,OAAO,aAAa;IAChB,MAAM,GAAG,IAAI,GAAG,EAAiB,CAAC;IAClC,UAAU,CAAU;IAE5B,YAAY,UAAmB;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,4DAA4D;IAC5D,IAAI;QACF,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpB,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,KAAK;QACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;CACF"}
@@ -0,0 +1,37 @@
1
+ export interface SkillArgDef {
2
+ type: "string" | "number" | "boolean";
3
+ description?: string;
4
+ required?: boolean;
5
+ }
6
+ export interface SkillToolAccess {
7
+ allow?: string[];
8
+ deny?: string[];
9
+ }
10
+ export interface SkillConfig {
11
+ name: string;
12
+ description: string;
13
+ args?: Record<string, SkillArgDef>;
14
+ tools?: SkillToolAccess;
15
+ /** Override model for the sub-session (null = inherit). */
16
+ model?: string | null;
17
+ /** Override reasoning effort (null = inherit). */
18
+ reasoning?: string | null;
19
+ /** "other" routes to the non-active provider (for consult). */
20
+ provider?: "other" | "claude" | "openai" | null;
21
+ /** If true, the skill re-invokes itself in a loop until interrupted. */
22
+ loop?: boolean;
23
+ /** Delay in ms between loop iterations (default: 60000). Only meaningful when loop=true. */
24
+ delay_ms?: number;
25
+ /** Message sent on subsequent loop iterations (supports {iteration} placeholder). */
26
+ loop_message?: string;
27
+ }
28
+ export interface Skill {
29
+ name: string;
30
+ description: string;
31
+ source: "user" | "project";
32
+ filePath: string;
33
+ config: SkillConfig;
34
+ /** The prompt template (markdown body after frontmatter). */
35
+ template: string;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/skills/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,IAAI,CAAC;IAChD,wEAAwE;IACxE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,4FAA4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/skills/types.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../src/store/preferences.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,cAAc,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAQD,wBAAgB,eAAe,IAAI,WAAW,CAO7C;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAQjE"}
1
+ {"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../src/store/preferences.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACnC,cAAc,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,IAAI,WAAW,CAM7C;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAQjE"}
@@ -1,17 +1,9 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
1
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { HELIOS_DIR } from "../paths.js";
4
- const CONFIG_DIR = HELIOS_DIR;
5
- const PREFS_FILE = join(CONFIG_DIR, "preferences.json");
6
- function ensureDir() {
7
- if (!existsSync(CONFIG_DIR)) {
8
- mkdirSync(CONFIG_DIR, { recursive: true });
9
- }
10
- }
4
+ const PREFS_FILE = join(HELIOS_DIR, "preferences.json");
11
5
  export function loadPreferences() {
12
6
  try {
13
- if (!existsSync(PREFS_FILE))
14
- return {};
15
7
  return JSON.parse(readFileSync(PREFS_FILE, "utf-8"));
16
8
  }
17
9
  catch {
@@ -19,7 +11,7 @@ export function loadPreferences() {
19
11
  }
20
12
  }
21
13
  export function savePreferences(prefs) {
22
- ensureDir();
14
+ mkdirSync(HELIOS_DIR, { recursive: true });
23
15
  const existing = loadPreferences();
24
16
  writeFileSync(PREFS_FILE, JSON.stringify({ ...existing, ...prefs }, null, 2), "utf-8");
25
17
  }
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.js","sourceRoot":"","sources":["../../src/store/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,GAAG,UAAU,CAAC;AAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AASxD,SAAS,SAAS;IAChB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,OAAO,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,SAAS,EAAE,CAAC;IACZ,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,aAAa,CACX,UAAU,EACV,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAClD,OAAO,CACR,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"preferences.js","sourceRoot":"","sources":["../../src/store/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AASxD,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,aAAa,CACX,UAAU,EACV,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAClD,OAAO,CACR,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"compare-runs.d.ts","sourceRoot":"","sources":["../../src/tools/compare-runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,GACvB,cAAc,CAuFhB"}
1
+ {"version":3,"file":"compare-runs.d.ts","sourceRoot":"","sources":["../../src/tools/compare-runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,GACvB,cAAc,CAuFhB"}
@@ -1,3 +1,4 @@
1
+ import { toolError } from "../ui/format.js";
1
2
  export function createCompareRunsTool(metricStore) {
2
3
  return {
3
4
  name: "compare_runs",
@@ -30,10 +31,10 @@ export function createCompareRunsTool(metricStore) {
30
31
  const summaryA = metricStore.getTaskSummary(taskA);
31
32
  const summaryB = metricStore.getTaskSummary(taskB);
32
33
  if (Object.keys(summaryA).length === 0) {
33
- return JSON.stringify({ error: `No metrics found for task ${taskA}` });
34
+ return toolError(`No metrics found for task ${taskA}`);
34
35
  }
35
36
  if (Object.keys(summaryB).length === 0) {
36
- return JSON.stringify({ error: `No metrics found for task ${taskB}` });
37
+ return toolError(`No metrics found for task ${taskB}`);
37
38
  }
38
39
  // Get union of metric names, optionally filtered
39
40
  const allNames = new Set([