@rowan-agent/agent 0.9.0 → 0.9.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.
package/dist/index.d.ts CHANGED
@@ -590,6 +590,10 @@ type AgentContext = {
590
590
  phases?: PhaseRegistry;
591
591
  };
592
592
 
593
+ /**
594
+ * `root` anchors relative paths and the Bash working directory. It is not a
595
+ * filesystem sandbox: core Tools use the permissions of the host process.
596
+ */
593
597
  type CoreToolContext = {
594
598
  root?: string;
595
599
  maxReadBytes?: number;
@@ -607,6 +611,8 @@ type AgentDefinition = Readonly<{
607
611
  prompt: string;
608
612
  tools?: readonly string[];
609
613
  skills?: readonly string[];
614
+ /** Host-supplied Skills private to this Agent Definition/Bundle. */
615
+ bundledSkills?: readonly Skill[];
610
616
  phases?: PhaseRegistrySelection;
611
617
  contexts?: readonly string[];
612
618
  model?: ModelRef;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/harness/tools/index.ts
2
2
  import { mkdir, readFile as readFile2, stat, writeFile } from "fs/promises";
3
- import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep as sep2 } from "path";
3
+ import { basename as basename2, dirname as dirname2, relative as relative2, resolve as resolve2 } from "path";
4
4
  import Type2 from "typebox";
5
5
  import Schema from "typebox/schema";
6
6
 
@@ -308,9 +308,6 @@ function resolveCoreToolPath(context, path = ".") {
308
308
  const inputPath = normalizeCoreToolInputPath(path);
309
309
  const absolutePath = resolve2(root, inputPath);
310
310
  const relativePath = relative2(root, absolutePath);
311
- if (relativePath === ".." || relativePath.startsWith(`..${sep2}`) || isAbsolute2(relativePath)) {
312
- throw new Error(`Path escapes workspace root: ${path}`);
313
- }
314
311
  return {
315
312
  root,
316
313
  inputPath,
@@ -465,7 +462,7 @@ async function captureStream(stream, maxBytes) {
465
462
  function createReadTool(context) {
466
463
  return {
467
464
  name: "read",
468
- description: "Read a file in the workspace.",
465
+ description: "Read a file using the host process filesystem permissions.",
469
466
  parameters: ReadArgsSchema,
470
467
  promptSnippet: "Read file contents.",
471
468
  promptGuidelines: ["Read files before editing them."],
@@ -536,7 +533,7 @@ function createReadTool(context) {
536
533
  function createWriteTool(context) {
537
534
  return {
538
535
  name: "write",
539
- description: "Create or overwrite a file in the workspace.",
536
+ description: "Create or overwrite a file using the host process filesystem permissions.",
540
537
  parameters: WriteArgsSchema,
541
538
  promptSnippet: "Create or overwrite files.",
542
539
  promptGuidelines: ["Use edit for partial changes."],
@@ -588,7 +585,7 @@ function applyEditReplacements(current, edits) {
588
585
  function createEditTool(context) {
589
586
  return {
590
587
  name: "edit",
591
- description: "Apply exact text replacements to a workspace file.",
588
+ description: "Apply exact text replacements using the host process filesystem permissions.",
592
589
  parameters: EditArgsSchema,
593
590
  promptSnippet: "Apply exact text replacements.",
594
591
  promptGuidelines: ["Read the file first; each oldText must match exactly once."],
@@ -624,7 +621,7 @@ function createEditTool(context) {
624
621
  function createBashTool(context) {
625
622
  return {
626
623
  name: "bash",
627
- description: "Run a bash command in the workspace.",
624
+ description: "Run a bash command with the host process filesystem permissions; root is the working directory.",
628
625
  parameters: BashArgsSchema,
629
626
  promptSnippet: "Run shell commands.",
630
627
  promptGuidelines: ["Use read/write/edit for file operations."],
@@ -1049,6 +1046,7 @@ function assertAgentDefinition(value) {
1049
1046
  requiredString(value.prompt, "definition.prompt");
1050
1047
  optionalStringList(value.tools, "definition.tools");
1051
1048
  optionalStringList(value.skills, "definition.skills");
1049
+ optionalBundledSkills(value.bundledSkills, "definition.bundledSkills");
1052
1050
  optionalPhaseRegistrySelection(value.phases, "definition.phases");
1053
1051
  optionalStringList(value.contexts, "definition.contexts");
1054
1052
  if ("extensions" in value) throw new TypeError("definition.extensions is not supported; Extensions are Runtime-global");
@@ -1120,6 +1118,19 @@ function optionalStringList(value, field) {
1120
1118
  }
1121
1119
  return names;
1122
1120
  }
1121
+ function optionalBundledSkills(value, field) {
1122
+ if (value === void 0) return;
1123
+ if (!Array.isArray(value)) throw new TypeError(`${field} must be an array of Skills`);
1124
+ const names = /* @__PURE__ */ new Set();
1125
+ for (const [index, item] of value.entries()) {
1126
+ if (!isRecord(item) || typeof item.name !== "string" || item.name.trim() === "" || typeof item.description !== "string" || typeof item.filePath !== "string" || typeof item.baseDir !== "string" || typeof item.content !== "string" || typeof item.disableModelInvocation !== "boolean") {
1127
+ throw new TypeError(`${field}[${index}] is invalid`);
1128
+ }
1129
+ if (names.has(item.name)) throw new TypeError(`Duplicate bundled Skill "${item.name}".`);
1130
+ names.add(item.name);
1131
+ }
1132
+ return value;
1133
+ }
1123
1134
  function optionalPhaseRegistrySelection(value, field) {
1124
1135
  if (value === void 0) return void 0;
1125
1136
  if (!isRecord(value)) throw new TypeError(`${field} must be an object`);
@@ -1514,6 +1525,13 @@ function selectNamedResources(candidates, names, kind) {
1514
1525
  }
1515
1526
  return selected;
1516
1527
  }
1528
+ function mergeSkills(...layers) {
1529
+ const byName = /* @__PURE__ */ new Map();
1530
+ for (const layer of layers) {
1531
+ for (const skill of layer ?? []) byName.set(skill.name, skill);
1532
+ }
1533
+ return [...byName.values()];
1534
+ }
1517
1535
 
1518
1536
  // src/harness/context/system-prompt.ts
1519
1537
  function buildSystemPrompt(options) {
@@ -1540,7 +1558,7 @@ function buildSystemPrompt(options) {
1540
1558
  }
1541
1559
  const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
1542
1560
  const skillsSection = skillsBlock ? `The following skills provide specialized instructions for specific tasks.
1543
- Read the full skill file when the task matches its description.
1561
+ Use the read tool to load a skill's file when the task matches its description.
1544
1562
  When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md) and use that absolute path in tool commands.
1545
1563
 
1546
1564
  ${skillsBlock}
@@ -2043,7 +2061,7 @@ async function runPhaseLoop(config, state, registry) {
2043
2061
  const toolExecutionManager = createToolExecutionManager();
2044
2062
  const execution = createPhaseExecution(config, state, phase, messageManager, toolExecutionManager, registry);
2045
2063
  const phaseTools = selectPhaseTools(allTools, phase.tools);
2046
- const phaseSkills = phase.name === DEFAULT_PHASE_ID ? config.context.skills : phase.skills ?? [];
2064
+ const phaseSkills = mergeSkills(config.context.skills, phase.skills);
2047
2065
  let phaseContext = {
2048
2066
  systemPrompt: config.context.systemPrompt,
2049
2067
  messages: messageManager.visible(),
@@ -2534,7 +2552,7 @@ async function executeParallelPhase(config, state, registry, phase, payload, con
2534
2552
  const messages = [...context];
2535
2553
  const allTools = buildToolsWithRouting(config, availablePhases);
2536
2554
  const phaseTools = selectPhaseTools(allTools, phase.tools);
2537
- const phaseSkills = phase.name === DEFAULT_PHASE_ID ? config.context.skills : phase.skills ?? [];
2555
+ const phaseSkills = mergeSkills(config.context.skills, phase.skills);
2538
2556
  const systemPrompt = config.context.systemPrompt;
2539
2557
  const phaseContext = {
2540
2558
  systemPrompt,
@@ -3016,6 +3034,9 @@ function snapshotConfig(config) {
3016
3034
  ...config.definition,
3017
3035
  ...config.definition.tools ? { tools: Object.freeze([...config.definition.tools]) } : {},
3018
3036
  ...config.definition.skills ? { skills: Object.freeze([...config.definition.skills]) } : {},
3037
+ ...config.definition.bundledSkills ? {
3038
+ bundledSkills: Object.freeze(config.definition.bundledSkills.map((skill) => Object.freeze({ ...skill })))
3039
+ } : {},
3019
3040
  ...config.definition.phases ? {
3020
3041
  phases: Object.freeze({
3021
3042
  entryPhaseId: config.definition.phases.entryPhaseId,
@@ -3494,10 +3515,9 @@ function resolveDefinitionContext(config, assembled = {}) {
3494
3515
  config.definition.tools,
3495
3516
  "Tool"
3496
3517
  );
3497
- const skills = selectNamedResources(
3498
- config.resources.skills,
3499
- config.definition.skills,
3500
- "Skill"
3518
+ const skills = mergeSkills(
3519
+ selectNamedResources(config.resources.skills, config.definition.skills, "Skill"),
3520
+ config.definition.bundledSkills
3501
3521
  );
3502
3522
  const contexts = selectNamedResources(
3503
3523
  config.resources.contexts ?? [],
@@ -4691,6 +4711,13 @@ var ResourceRegistry = class {
4691
4711
  }
4692
4712
  };
4693
4713
  function snapshotResourceValue(kind, value) {
4714
+ if (kind === "agent") {
4715
+ const agent = value;
4716
+ return Object.freeze({
4717
+ ...agent,
4718
+ ...agent.bundledSkills ? { bundledSkills: Object.freeze(agent.bundledSkills.map((skill) => Object.freeze({ ...skill }))) } : {}
4719
+ });
4720
+ }
4694
4721
  if (kind !== "phase") return value;
4695
4722
  const phase = value;
4696
4723
  const snapshot = {
@@ -4964,7 +4991,10 @@ function resolveConfigurationSnapshot(registry, input) {
4964
4991
  const layer = input.definition.layer;
4965
4992
  const definition = applyDefinitionLayer(base, layer);
4966
4993
  const tools = selectNamedResources(resolved.tools, definition.tools, "Tool");
4967
- const skills = selectNamedResources(resolved.skills, definition.skills, "Skill");
4994
+ const skills = mergeSkills(
4995
+ selectNamedResources(resolved.skills, definition.skills, "Skill"),
4996
+ definition.bundledSkills
4997
+ );
4968
4998
  const phases = resolvePhases(resolved.phases, definition.phases);
4969
4999
  const contexts = selectNamedResources(input.contexts ?? [], base.contexts, "Context");
4970
5000
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",