@skilder-ai/runtime 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -87668,6 +87668,7 @@ var DEFAULT_OPTIMIZATION_INSIGHTS_LOOKBACK_SECONDS = 30 * 24 * 60 * 60;
87668
87668
  // ../common/src/constants.node.ts
87669
87669
  var MCP_CALL_TOOL_TIMEOUT = parseInt(process.env.MCP_CALL_TOOL_TIMEOUT ?? "10000", 10);
87670
87670
  var DEFAULT_REQUEST_TIMEOUT = parseInt(process.env.DEFAULT_REQUEST_TIMEOUT ?? "10000", 10);
87671
+ var SCRIPT_ROUTE_TIMEOUT_MS = 31e4;
87671
87672
 
87672
87673
  // ../../node_modules/.pnpm/bcryptjs@3.0.3/node_modules/bcryptjs/index.js
87673
87674
  var nextTick = typeof setImmediate === "function" ? setImmediate : typeof scheduler === "object" && typeof scheduler.postTask === "function" ? scheduler.postTask.bind(scheduler) : setTimeout;
@@ -143989,7 +143990,6 @@ var ACTIVATION_COOLDOWN_MS = 6e4;
143989
143990
  var DEFAULT_IDLE_TIMEOUT_MS = 3e5;
143990
143991
  var DEFAULT_SCRIPT_TIMEOUT_MS = 3e4;
143991
143992
  var MAX_INTERACTIVE_SCRIPT_TIMEOUT_MS = 3e5;
143992
- var SCRIPT_ROUTE_TIMEOUT_MS = MAX_INTERACTIVE_SCRIPT_TIMEOUT_MS + 1e4;
143993
143993
  var MAX_SCRIPT_OUTPUT_SIZE = 10485760;
143994
143994
  var MAX_CONCURRENT_SCRIPTS = 16;
143995
143995
  var MAX_DELEGATE_DEPTH = 3;
@@ -144653,16 +144653,13 @@ SkillContentService = __decorate12([
144653
144653
  ], SkillContentService);
144654
144654
 
144655
144655
  // src/services/static-tools/init-skilder.handler.ts
144656
- function isHatPreloaded(hatId, ctx) {
144657
- return ctx.identity.preloadedHatIds?.includes(hatId) ?? false;
144658
- }
144659
144656
  function buildInitSkilderResponse(ctx) {
144660
144657
  const catalog = ctx.catalog;
144661
- if (!catalog || catalog.hats.length === 0 && catalog.skills.length === 0) {
144658
+ if (!catalog || catalog.hats.length === 0) {
144662
144659
  return [
144663
144660
  "# Welcome to Skilder",
144664
144661
  "",
144665
- "No skills or hats are configured for this session.",
144662
+ "No hats are configured for this session.",
144666
144663
  "",
144667
144664
  "Skilder provides specialized skills and tools to help you accomplish tasks."
144668
144665
  ].join("\n");
@@ -144670,107 +144667,35 @@ function buildInitSkilderResponse(ctx) {
144670
144667
  const lines = [];
144671
144668
  lines.push("# Welcome to Skilder");
144672
144669
  lines.push("");
144673
- lines.push("Skilder provides specialized skills and resources. Use `learn` to access resources by path.");
144670
+ lines.push("Skilder provides specialized skills and resources. Hats are the entry point \u2014 learn a hat first, then learn individual skills to unlock their tools.");
144674
144671
  lines.push("");
144675
- lines.push("**Path Examples:**");
144676
- lines.push('- `learn --path "/Skill Name"` - Learn a skill and unlock its tools');
144677
- lines.push('- `learn --path "/Skill Name/doc.md"` - Get a resource');
144678
- lines.push('- `learn --path "/hats/Hat Name"` - Learn all skills in a hat');
144679
- lines.push('- `execute_script --path "/Skill Name/script.py --args"` - Run a script');
144672
+ lines.push("## Available Hats");
144680
144673
  lines.push("");
144681
- const preloadedHats = catalog.hats.filter((h2) => isHatPreloaded(h2.id, ctx));
144682
- const discoverableHats = catalog.hats.filter((h2) => !isHatPreloaded(h2.id, ctx));
144683
- const preloadedSkillIds = new Set(ctx.identity.preloadedSkillIds ?? []);
144684
- if (discoverableHats.length > 0) {
144685
- lines.push("## Available Hats");
144686
- lines.push("");
144687
- lines.push('Use `learn --path "/hats/Hat Name"` to unlock all skills in a hat.');
144688
- lines.push("");
144689
- for (const hat of discoverableHats) {
144690
- const skillCount = hat.skillIds.length;
144691
- lines.push(
144692
- `- **${hat.name}**${hat.description ? `: ${hat.description}` : ""} (${skillCount} skill${skillCount !== 1 ? "s" : ""})`
144693
- );
144694
- }
144695
- lines.push("");
144696
- }
144697
- const discoverableSkills = catalog.skills.filter((s) => !preloadedSkillIds.has(s.id));
144698
- if (discoverableSkills.length > 0) {
144699
- lines.push("## Available Skills");
144700
- lines.push("");
144701
- lines.push('Use `learn --path "/Skill Name"` to unlock tools and view instructions.');
144702
- lines.push("");
144703
- for (const skill of discoverableSkills) {
144704
- const extras = [];
144705
- const learnableCount = skill.related.filter((r2) => r2.class === "learnable").length;
144706
- const executableCount = skill.related.filter((r2) => r2.class === "executable").length;
144707
- if (learnableCount > 0) {
144708
- extras.push(`${learnableCount} ref${learnableCount !== 1 ? "s" : ""}`);
144709
- }
144710
- if (executableCount > 0) {
144711
- extras.push(`${executableCount} script${executableCount !== 1 ? "s" : ""}`);
144712
- }
144713
- const extrasStr = extras.length > 0 ? ` [${extras.join(", ")}]` : "";
144714
- lines.push(`- **${skill.name}**${skill.description ? `: ${skill.description}` : ""}${extrasStr}`);
144674
+ lines.push("You MUST learn a hat before doing anything else. Hats are the only entry point.");
144675
+ lines.push("");
144676
+ for (const hat of catalog.hats) {
144677
+ lines.push(`### ${hat.name}`);
144678
+ if (hat.description) {
144679
+ lines.push(hat.description);
144715
144680
  }
144716
144681
  lines.push("");
144717
- }
144718
- if (preloadedHats.length > 0) {
144719
- lines.push("## Pre-loaded Hats (Ready to Use)");
144720
- lines.push("");
144721
- for (const hat of preloadedHats) {
144722
- lines.push(`### ${hat.name}`);
144723
- if (hat.description) {
144724
- lines.push(hat.description);
144725
- }
144726
- if (hat.instructions) {
144727
- lines.push("");
144728
- lines.push("**Instructions:**");
144729
- lines.push(hat.instructions);
144730
- }
144731
- lines.push("");
144732
- lines.push("**Skills in this hat:**");
144733
- for (const skillId of hat.skillIds) {
144734
- const skill = catalog.skills.find((s) => s.id === skillId);
144735
- if (skill) {
144736
- lines.push(`- **${skill.name}**${skill.description ? `: ${skill.description}` : ""}`);
144737
- if (skill.instructions) {
144738
- lines.push(` - Instructions: ${skill.instructions}`);
144739
- }
144740
- if (skill.toolNames.length > 0) {
144741
- lines.push(` - Tools: ${skill.toolNames.join(", ")}`);
144742
- }
144743
- }
144744
- }
144745
- lines.push("");
144746
- }
144747
- }
144748
- const preloadedSkills = catalog.skills.filter((s) => preloadedSkillIds.has(s.id));
144749
- const preloadedHatSkillIds = new Set(preloadedHats.flatMap((h2) => h2.skillIds));
144750
- const orphanPreloadedSkills = preloadedSkills.filter((s) => !preloadedHatSkillIds.has(s.id));
144751
- if (orphanPreloadedSkills.length > 0) {
144752
- lines.push("## Pre-loaded Skills (Ready to Use)");
144682
+ lines.push(`**Learn this hat:** \`learn --path "/hats/${hat.name}"\``);
144753
144683
  lines.push("");
144754
- for (const skill of orphanPreloadedSkills) {
144755
- lines.push(`### ${skill.name}`);
144756
- if (skill.description) {
144757
- lines.push(skill.description);
144758
- }
144759
- if (skill.instructions) {
144760
- lines.push("");
144761
- lines.push("**Instructions:**");
144762
- lines.push(skill.instructions);
144763
- }
144764
- if (skill.toolNames.length > 0) {
144765
- lines.push("");
144766
- lines.push(`**Tools:** ${skill.toolNames.join(", ")}`);
144767
- }
144768
- lines.push("");
144769
- }
144770
144684
  }
144771
144685
  return lines.join("\n");
144772
144686
  }
144773
144687
  async function handleInitSkilder(_args, ctx) {
144688
+ if (!ctx.catalog) {
144689
+ ctx.logger.warn(
144690
+ { userId: ctx.identity.id },
144691
+ "init_skilder called with null catalog \u2014 catalog may not have loaded yet"
144692
+ );
144693
+ } else if (ctx.catalog.hats.length === 0) {
144694
+ ctx.logger.warn(
144695
+ { userId: ctx.identity.id, skillCount: ctx.catalog.skills.length },
144696
+ "init_skilder called with no hats in catalog"
144697
+ );
144698
+ }
144774
144699
  return {
144775
144700
  response: { content: [{ type: "text", text: buildInitSkilderResponse(ctx) }] }
144776
144701
  };
@@ -144785,86 +144710,75 @@ function errorResult(text2, skillIds) {
144785
144710
  }
144786
144711
 
144787
144712
  // src/services/static-tools/learn.handler.ts
144788
- function appendReferencedResources(lines, mentions, skillName, heading) {
144713
+ function appendReferencedResources(lines, mentions, related, skillName) {
144789
144714
  if (mentions.length === 0) return;
144790
- lines.push(`## ${heading}`);
144715
+ lines.push("## Resources");
144716
+ lines.push("Only resources referenced in the skill description or instructions are shown.");
144717
+ lines.push("");
144791
144718
  for (const m2 of mentions) {
144792
144719
  const resourcePath = `/${skillName}/${m2.qualifiedName}`;
144720
+ const entry = related.find((r2) => (r2.path ? `${r2.path}/${r2.name}` : r2.name) === m2.qualifiedName);
144721
+ lines.push(`### ${m2.name}`);
144722
+ if (entry?.description) {
144723
+ lines.push(entry.description);
144724
+ }
144725
+ lines.push("");
144793
144726
  if (m2.class === "learnable") {
144794
- lines.push(`- To learn more about \`${m2.qualifiedName}\`: \`learn --path "${resourcePath}"\``);
144727
+ lines.push(`**Consume:** \`learn --path "${resourcePath}"\``);
144795
144728
  } else if (m2.class === "executable") {
144796
- lines.push(`- To execute \`${m2.qualifiedName}\`: \`execute_script --path "${resourcePath}"\``);
144729
+ lines.push(`**Consume:** \`execute_script --path "${resourcePath}"\``);
144797
144730
  } else {
144798
- lines.push(`- To download \`${m2.qualifiedName}\`: \`download_asset --path "${resourcePath}"\``);
144731
+ lines.push(`**Consume:** \`download_asset --path "${resourcePath}"\``);
144799
144732
  }
144733
+ lines.push("");
144800
144734
  }
144801
144735
  }
144802
- function formatSkillDetails(skill, ctx, options) {
144803
- const headingLevel = options?.headingLevel ?? 2;
144804
- const heading = "#".repeat(headingLevel);
144805
- const renderedToolNames = options?.renderedToolNames;
144806
- const firstSkillForTool = options?.firstSkillForTool;
144736
+ function formatSkillDetails(skill, ctx) {
144807
144737
  const lines = [];
144808
144738
  if (skill.description) {
144809
144739
  lines.push(skill.description);
144810
144740
  lines.push("");
144811
144741
  }
144812
144742
  if (skill.instructions) {
144813
- lines.push(`${heading} Instructions`);
144743
+ lines.push("## Instructions");
144814
144744
  lines.push(skill.instructions);
144815
144745
  lines.push("");
144816
144746
  }
144817
144747
  if (skill.toolNames.length > 0) {
144818
- lines.push(`${heading} Available Tools`);
144748
+ lines.push("## Available Tools");
144819
144749
  lines.push("Use `call_tool` with the tool name and input to execute these tools:");
144820
144750
  lines.push("");
144821
144751
  for (const toolName of skill.toolNames) {
144822
- const subHeading = "#".repeat(headingLevel + 1);
144823
- if (renderedToolNames?.has(toolName)) {
144824
- const firstSkill = firstSkillForTool?.get(toolName);
144825
- lines.push(`${subHeading} ${toolName}`);
144826
- lines.push(firstSkill ? `(schema shown above under ${firstSkill})` : "(schema shown above)");
144752
+ const tool2 = ctx.getTools()?.find((t4) => t4.name === toolName);
144753
+ if (tool2) {
144754
+ lines.push(`### ${tool2.name}`);
144755
+ lines.push(tool2.description || "No description");
144756
+ lines.push("");
144757
+ lines.push("**Input Schema:**");
144758
+ lines.push("```json");
144759
+ lines.push(JSON.stringify(tool2.inputSchema, null, 2));
144760
+ lines.push("```");
144827
144761
  lines.push("");
144828
144762
  } else {
144829
- if (renderedToolNames) {
144830
- renderedToolNames.add(toolName);
144831
- firstSkillForTool?.set(toolName, skill.name);
144832
- }
144833
- const tool2 = ctx.getTools()?.find((t4) => t4.name === toolName);
144834
- if (tool2) {
144835
- lines.push(`${subHeading} ${tool2.name}`);
144836
- lines.push(tool2.description || "No description");
144837
- lines.push("");
144838
- lines.push("**Input Schema:**");
144839
- lines.push("```json");
144840
- lines.push(JSON.stringify(tool2.inputSchema, null, 2));
144841
- lines.push("```");
144842
- lines.push("");
144843
- } else {
144844
- ctx.logger.warn(
144845
- { toolName, skillId: skill.id, toolsInitialized: ctx.getTools() != null },
144846
- `Tool "${toolName}" referenced by skill "${skill.name}" not found in tools list`
144847
- );
144848
- lines.push(`${subHeading} ${toolName}`);
144849
- lines.push("Tool definition not available");
144850
- lines.push("");
144851
- }
144763
+ ctx.logger.warn(
144764
+ { toolName, skillId: skill.id, toolsInitialized: ctx.getTools() != null },
144765
+ `Tool "${toolName}" referenced by skill "${skill.name}" not found in tools list`
144766
+ );
144767
+ lines.push(`### ${toolName}`);
144768
+ lines.push("Tool definition not available");
144769
+ lines.push("");
144852
144770
  }
144853
144771
  }
144854
144772
  lines.push('Call these tools using: `call_tool(tool_name="<name>", tool_input={...})`');
144855
144773
  } else {
144856
144774
  lines.push("This skill provides instructions only and has no associated tools.");
144857
144775
  }
144858
- if (skill.instructions && skill.related.length > 0) {
144859
- try {
144860
- const mentions = detectRelatedMentions(skill.instructions, skill.related);
144776
+ if (skill.related.length > 0) {
144777
+ const sourceText = [skill.description, skill.instructions].filter(Boolean).join("\n\n");
144778
+ const mentions = detectRelatedMentions(sourceText, skill.related);
144779
+ if (mentions.length > 0) {
144861
144780
  lines.push("");
144862
- appendReferencedResources(lines, mentions, skill.name, "Resources Referenced in Instructions");
144863
- } catch (error48) {
144864
- ctx.logger.error(
144865
- { err: error48, skillId: skill.id, skillName: skill.name },
144866
- "Failed to detect related mentions in skill instructions \u2014 skipping resource list"
144867
- );
144781
+ appendReferencedResources(lines, mentions, skill.related, skill.name);
144868
144782
  }
144869
144783
  }
144870
144784
  return lines;
@@ -144912,9 +144826,9 @@ function handleGetHat(hatName, ctx) {
144912
144826
  missingSkillIds.push(skillId);
144913
144827
  }
144914
144828
  }
144915
- const totalToolCount = new Set(skills.flatMap((s) => s.toolNames)).size;
144916
144829
  ctx.logger.info(
144917
- `User ${ctx.identity.id} retrieved hat "${hat.name}" with ${skills.length} skills and ${totalToolCount} tools`
144830
+ { userId: ctx.identity.id, hatId: hat.id, hatName: hat.name, skillCount: skills.length },
144831
+ "User retrieved hat"
144918
144832
  );
144919
144833
  const lines = [];
144920
144834
  lines.push(`# Hat: ${hat.name}`);
@@ -144929,13 +144843,16 @@ function handleGetHat(hatName, ctx) {
144929
144843
  lines.push("");
144930
144844
  }
144931
144845
  if (skills.length > 0) {
144932
- lines.push("## Skills Learned");
144846
+ lines.push("## Available Skills");
144847
+ lines.push('Use `learn --path "/Skill Name"` to learn a skill and unlock its tools and resources.');
144933
144848
  lines.push("");
144934
- const renderedToolNames = /* @__PURE__ */ new Set();
144935
- const firstSkillForTool = /* @__PURE__ */ new Map();
144936
144849
  for (const skill of skills) {
144937
144850
  lines.push(`### ${skill.name}`);
144938
- lines.push(...formatSkillDetails(skill, ctx, { headingLevel: 4, renderedToolNames, firstSkillForTool }));
144851
+ if (skill.description) {
144852
+ lines.push(skill.description);
144853
+ }
144854
+ lines.push("");
144855
+ lines.push(`**Learn this skill:** \`learn --path "/${skill.name}"\``);
144939
144856
  lines.push("");
144940
144857
  }
144941
144858
  } else {
@@ -144950,7 +144867,7 @@ function handleGetHat(hatName, ctx) {
144950
144867
  }
144951
144868
  return {
144952
144869
  response: { content: [{ type: "text", text: lines.join("\n") }] },
144953
- skillIds: hat.skillIds
144870
+ skillIds: []
144954
144871
  };
144955
144872
  }
144956
144873
  async function handleGetRelated(skillName, resourceName, ctx) {
@@ -144993,14 +144910,32 @@ To execute this script, use:
144993
144910
  lines.push(`**Description:** ${item.description}`);
144994
144911
  }
144995
144912
  lines.push("");
144996
- if (ctx.skillContentService && ctx.identity.userKey) {
144913
+ if (!ctx.skillContentService) {
144914
+ ctx.logger.error(
144915
+ { resourceId: item.id, skillId: skill.id },
144916
+ "skillContentService not injected \u2014 cannot fetch resource content"
144917
+ );
144918
+ lines.push("*Content unavailable: this runtime is not configured to fetch resource content.*");
144919
+ } else if (!ctx.identity.userKey) {
144920
+ ctx.logger.error(
144921
+ { resourceId: item.id, skillId: skill.id, userId: ctx.identity.id },
144922
+ "userKey missing \u2014 cannot authenticate resource content fetch"
144923
+ );
144924
+ lines.push("*Content unavailable: authentication context is missing. Please reconnect.*");
144925
+ } else {
144997
144926
  try {
144998
144927
  const content = await ctx.skillContentService.getContent(item.id, ctx.identity.userKey);
144999
- if (content) {
145000
- lines.push(content);
145001
- } else {
145002
- lines.push("*No content available for this resource.*");
144928
+ if (content == null) {
144929
+ ctx.logger.error(
144930
+ { resourceId: item.id, resourceName: item.name, skillId: skill.id },
144931
+ "skillContentService.getContent returned null \u2014 no content for resource"
144932
+ );
144933
+ return errorResult(
144934
+ `Error: No content found for resource "${item.name}". The resource may be empty or unavailable.`,
144935
+ [skill.id]
144936
+ );
145003
144937
  }
144938
+ lines.push(content);
145004
144939
  } catch (err) {
145005
144940
  ctx.logger.error({ err, resourceId: item.id }, "Failed to fetch resource content");
145006
144941
  return errorResult(
@@ -145008,8 +144943,6 @@ To execute this script, use:
145008
144943
  [skill.id]
145009
144944
  );
145010
144945
  }
145011
- } else {
145012
- lines.push("*Content unavailable: this runtime is not configured to fetch resource content.*");
145013
144946
  }
145014
144947
  return {
145015
144948
  response: { content: [{ type: "text", text: lines.join("\n") }] },
@@ -145959,7 +145892,8 @@ The path must point to a downloadable (binary) resource in a skill's related ite
145959
145892
  if (toolConfig.__routing.type === "static") {
145960
145893
  this.logger.debug(`Handling static tool ${toolConfig.__routing.toolName} for user ${this.identity.id}`);
145961
145894
  const { response, skillIds } = await this.handleStaticTool(toolConfig.__routing.toolName, args);
145962
- if (toolConfig.__routing.workspaceId) {
145895
+ const isWrapperTool = toolConfig.__routing.toolName === "call_tool";
145896
+ if (toolConfig.__routing.workspaceId && !isWrapperTool) {
145963
145897
  try {
145964
145898
  const message = SkillCallToolRequest.create({
145965
145899
  type: "static",
@@ -149851,12 +149785,29 @@ var ScriptExecutorService = class ScriptExecutorService2 {
149851
149785
  NODE_PATH: (0, import_path2.join)(tempDir, "node_modules")
149852
149786
  }
149853
149787
  });
149788
+ const pendingIds = /* @__PURE__ */ new Set();
149854
149789
  let currentTimeout = timeout2;
149855
149790
  let lastExtendingMethod;
149791
+ const killForTimeout = (reason) => {
149792
+ const ids = Array.from(pendingIds);
149793
+ pendingIds.clear();
149794
+ for (const id of ids) {
149795
+ writeFromKill(id, -32001, reason);
149796
+ }
149797
+ try {
149798
+ child.stdin?.end();
149799
+ } catch (err) {
149800
+ this.logger.debug({ error: err }, "child.stdin.end() during killForTimeout failed");
149801
+ }
149802
+ setTimeout(() => {
149803
+ if (!childExited)
149804
+ child.kill("SIGKILL");
149805
+ }, 250);
149806
+ };
149856
149807
  let timeoutId = setTimeout(() => {
149857
149808
  killed = true;
149858
- child.kill("SIGKILL");
149859
149809
  this.logger.warn({ timeout: currentTimeout, method: lastExtendingMethod }, "Interactive script timed out");
149810
+ killForTimeout(`Script timeout: runtime killed the script after ${currentTimeout}ms${lastExtendingMethod ? ` (last extending method: ${lastExtendingMethod})` : ""}.`);
149860
149811
  }, currentTimeout);
149861
149812
  const resetTimeout = (extraMs, method) => {
149862
149813
  clearTimeout(timeoutId);
@@ -149864,25 +149815,27 @@ var ScriptExecutorService = class ScriptExecutorService2 {
149864
149815
  const remaining = Math.min(extraMs, MAX_INTERACTIVE_SCRIPT_TIMEOUT_MS - elapsed);
149865
149816
  if (remaining <= 0) {
149866
149817
  killed = true;
149867
- child.kill("SIGKILL");
149868
149818
  this.logger.warn({ method }, "Interactive script exceeded max total timeout");
149819
+ killForTimeout(`Script timeout: exceeded max total interactive timeout (${MAX_INTERACTIVE_SCRIPT_TIMEOUT_MS}ms)${method ? ` while waiting on ${method}` : ""}.`);
149869
149820
  return;
149870
149821
  }
149871
149822
  lastExtendingMethod = method;
149872
149823
  currentTimeout = remaining;
149873
149824
  timeoutId = setTimeout(() => {
149874
149825
  killed = true;
149875
- child.kill("SIGKILL");
149876
149826
  this.logger.warn({ timeout: currentTimeout, method: lastExtendingMethod }, "Interactive script timed out");
149827
+ killForTimeout(`Script timeout: runtime killed the script after ${currentTimeout}ms${lastExtendingMethod ? ` (last extending method: ${lastExtendingMethod})` : ""}.`);
149877
149828
  }, currentTimeout);
149878
149829
  };
149879
149830
  const safeWrite = (data) => {
149880
149831
  if (childExited || !child.stdin?.writable)
149881
- return;
149832
+ return false;
149882
149833
  try {
149883
149834
  child.stdin.write(data);
149835
+ return true;
149884
149836
  } catch (err) {
149885
149837
  this.logger.debug({ error: err }, "Failed to write to child stdin (process may have exited)");
149838
+ return false;
149886
149839
  }
149887
149840
  };
149888
149841
  const writeResponse = (id, result) => {
@@ -149891,6 +149844,12 @@ var ScriptExecutorService = class ScriptExecutorService2 {
149891
149844
  const writeError = (id, code, message) => {
149892
149845
  safeWrite(JSON.stringify({ jsonrpc: "2.0", error: { code, message }, id }) + "\n");
149893
149846
  };
149847
+ const writeFromKill = (id, code, message) => {
149848
+ const ok = safeWrite(JSON.stringify({ jsonrpc: "2.0", error: { code, message }, id }) + "\n");
149849
+ if (!ok) {
149850
+ this.logger.warn({ id, message, event: "script_timeout_error_frame_drop" }, "Failed to deliver timeout JSON-RPC error frame to script \u2014 SDK will fall back to generic IPC-closed message");
149851
+ }
149852
+ };
149894
149853
  const rl = (0, import_readline.createInterface)({ input: child.stdout, crlfDelay: Infinity });
149895
149854
  rl.on("line", (line) => {
149896
149855
  if (outputTruncated)
@@ -149918,6 +149877,7 @@ var ScriptExecutorService = class ScriptExecutorService2 {
149918
149877
  return;
149919
149878
  }
149920
149879
  inflightCount++;
149880
+ pendingIds.add(msg.id);
149921
149881
  (async () => {
149922
149882
  try {
149923
149883
  if (msg.method === "delegate") {
@@ -149926,11 +149886,16 @@ var ScriptExecutorService = class ScriptExecutorService2 {
149926
149886
  resetTimeout(toolCallTimeout + timeout2, msg.method);
149927
149887
  }
149928
149888
  const result = await onRequest(msg.method, msg.params);
149929
- writeResponse(msg.id, result);
149889
+ if (pendingIds.delete(msg.id)) {
149890
+ writeResponse(msg.id, result);
149891
+ }
149930
149892
  } catch (err) {
149931
- const message = err instanceof Error ? err.message : String(err);
149932
- writeError(msg.id, -32e3, message);
149893
+ if (pendingIds.delete(msg.id)) {
149894
+ const message = err instanceof Error ? err.message : String(err);
149895
+ writeError(msg.id, -32e3, message);
149896
+ }
149933
149897
  } finally {
149898
+ pendingIds.delete(msg.id);
149934
149899
  inflightCount--;
149935
149900
  if (inflightCount === 0 && inflightDone)
149936
149901
  inflightDone();
@@ -154159,7 +154124,7 @@ ${cleanError}` : cleanError;
154159
154124
  throw new Error("Invalid delegate params: expected { context: string, model?: string, temperature?: number }");
154160
154125
  }
154161
154126
  const { context: context2, model, temperature } = params;
154162
- return this.handleScriptDelegate(context2, model, temperature, workspaceId, userKey, delegateDepth);
154127
+ return this.handleScriptDelegate(context2, model, temperature, workspaceId, userId, userKey, runtimeId, delegateDepth);
154163
154128
  }
154164
154129
  case "scripts/execute": {
154165
154130
  if (!params || typeof params !== "object" || typeof params.path !== "string") {
@@ -154249,7 +154214,7 @@ ${cleanError}` : cleanError;
154249
154214
  * Handle a delegate request from a TypeScript script via JSON-RPC IPC.
154250
154215
  * Spawns a sub-agent using DelegateService and returns the result as a CallToolResult.
154251
154216
  */
154252
- async handleScriptDelegate(context2, model, temperature, workspaceId, userKey, delegateDepth) {
154217
+ async handleScriptDelegate(context2, model, temperature, workspaceId, userId, userKey, runtimeId, delegateDepth) {
154253
154218
  if (!this.delegateService) {
154254
154219
  this.logger.warn({ event: "delegate_service_unavailable" }, "Delegate requested but DelegateService not injected");
154255
154220
  return {
@@ -154262,14 +154227,51 @@ ${cleanError}` : cleanError;
154262
154227
  isError: true
154263
154228
  };
154264
154229
  }
154265
- return this.delegateService.execute({
154266
- context: context2,
154267
- model,
154268
- temperature,
154269
- workspaceId,
154270
- userKey,
154271
- delegateDepth: delegateDepth ?? 0
154230
+ const publishMonitoring = (response) => {
154231
+ try {
154232
+ const message = new SkillCallToolRequest({
154233
+ type: "static",
154234
+ toolName: "delegate",
154235
+ workspaceId,
154236
+ from: runtimeId ?? "script",
154237
+ userId,
154238
+ userKey,
154239
+ arguments: {
154240
+ context: context2,
154241
+ ...model !== void 0 && { model },
154242
+ ...temperature !== void 0 && { temperature }
154243
+ },
154244
+ response,
154245
+ delegateDepth
154246
+ });
154247
+ this.natsService.publish(message);
154248
+ } catch (error48) {
154249
+ this.logger.error({ err: error48, event: "script_delegate_publish_failed" }, "Failed to publish script delegate monitoring event");
154250
+ }
154251
+ };
154252
+ let result;
154253
+ try {
154254
+ result = await this.delegateService.execute({
154255
+ context: context2,
154256
+ model,
154257
+ temperature,
154258
+ workspaceId,
154259
+ userKey,
154260
+ delegateDepth: delegateDepth ?? 0
154261
+ });
154262
+ } catch (error48) {
154263
+ const message = error48 instanceof Error ? error48.message : String(error48);
154264
+ publishMonitoring({
154265
+ content: [{ type: "text", text: `Error: Delegate failed unexpectedly: ${message}` }],
154266
+ isError: true
154267
+ });
154268
+ throw error48;
154269
+ }
154270
+ publishMonitoring({
154271
+ content: result.content,
154272
+ ...result.isError && { isError: true }
154272
154273
  });
154274
+ return result;
154273
154275
  }
154274
154276
  /**
154275
154277
  * Route a tool call from a script to the appropriate MCP server via NATS.