@rowan-agent/agent 0.4.7 → 0.4.8

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/README.md CHANGED
@@ -60,6 +60,8 @@ type AgentOptions = {
60
60
  context: AgentContext;
61
61
  model: LlmModelRef;
62
62
  stream: StreamFn;
63
+ cwd?: string;
64
+ rowanDir?: string; // project-local Rowan directory, default: ".rowan"
63
65
  sessionId?: string;
64
66
  phases?: PhaseRegistry;
65
67
  extensions?: ExtensionRunnerRef;
@@ -460,6 +462,8 @@ export default function myPlugin(rowan: ExtensionAPI) {
460
462
 
461
463
  Multi-provider model configuration via `.rowan/config.yaml`. Supports multiple API providers, per-model settings, environment variable interpolation, and per-phase model overrides.
462
464
 
465
+ Config is loaded from the runtime Rowan directory, which defaults to `.rowan` and can be set when constructing `Agent` via `rowanDir`.
466
+
463
467
  ### Config File
464
468
 
465
469
  Place `config.yaml` in your `.rowan/` directory (alongside `phases/`, `skills/`, etc.):
@@ -632,13 +636,16 @@ const request = buildModelRequest({ systemPrompt, messages, tools });
632
636
 
633
637
  ## Workspace
634
638
 
635
- Workspace resolution — dev mode uses the project root, packaged binary uses `~/.rowan`.
639
+ Workspace resolution uses the current project for both source and binary runs. The project Rowan directory defaults to `<cwd>/.rowan`; pass `rowanDir` to resolve another project-local directory.
636
640
 
637
641
  ```ts
638
642
  import { resolveWorkspacePaths, resolveInWorkspace } from "@rowan-agent/agent";
639
643
 
640
644
  const workspace = resolveWorkspacePaths();
641
645
  // → { mode: "source" | "binary", cwd: string, rowanDir: string }
646
+
647
+ const custom = resolveWorkspacePaths({ rowanDir: ".rowan-project" });
648
+ // → custom.rowanDir is <cwd>/.rowan-project
642
649
  ```
643
650
 
644
651
  ## Loop Metrics
@@ -59,17 +59,10 @@ function detectRuntimeMode(input = {}) {
59
59
  const executable = basename(input.execPath ?? process.execPath).toLowerCase().replace(/\.exe$/, "");
60
60
  return executable === "bun" ? "source" : "binary";
61
61
  }
62
- function defaultSourceStartDir(options) {
62
+ function defaultWorkspaceStartDir(options) {
63
63
  if (options.cwd) {
64
64
  return options.cwd;
65
65
  }
66
- const entrypoint = options.entrypoint ?? process.argv[1];
67
- if (entrypoint) {
68
- const entrypointPath = resolve(process.cwd(), entrypoint);
69
- if (existsSync(entrypointPath)) {
70
- return dirname(entrypointPath);
71
- }
72
- }
73
66
  return process.cwd();
74
67
  }
75
68
  function resolveWorkspaceRoot(options = {}) {
@@ -79,11 +72,7 @@ function resolveWorkspaceRoot(options = {}) {
79
72
  if (override) {
80
73
  return resolveUserPath(override, homeDir);
81
74
  }
82
- const mode = options.mode ?? detectRuntimeMode(options);
83
- if (mode === "binary") {
84
- return homeDir;
85
- }
86
- return findSourceWorkspaceRoot(defaultSourceStartDir(options));
75
+ return findSourceWorkspaceRoot(defaultWorkspaceStartDir(options));
87
76
  }
88
77
  function resolveWorkspacePaths(options = {}) {
89
78
  const mode = options.mode ?? detectRuntimeMode(options);
@@ -91,9 +80,16 @@ function resolveWorkspacePaths(options = {}) {
91
80
  return {
92
81
  mode,
93
82
  cwd,
94
- rowanDir: join(cwd, BINARY_WORKSPACE_DIR)
83
+ rowanDir: resolveProjectRowanDir(cwd, options.rowanDir)
95
84
  };
96
85
  }
86
+ function resolveProjectRowanDir(cwd, rowanDir = BINARY_WORKSPACE_DIR) {
87
+ const inputPath = rowanDir.trim() || BINARY_WORKSPACE_DIR;
88
+ if (isAbsolute(inputPath)) {
89
+ throw new Error(`Project Rowan dir must be a relative path: ${rowanDir}`);
90
+ }
91
+ return resolveWorkspacePath({ root: cwd }, inputPath).absolutePath;
92
+ }
97
93
  function resolveInWorkspace(path, rootOrPaths) {
98
94
  if (path === "~" || path.startsWith("~/") || path.startsWith("~\\")) {
99
95
  return resolveUserPath(path, homedir());
@@ -139,6 +135,7 @@ export {
139
135
  detectRuntimeMode,
140
136
  resolveWorkspaceRoot,
141
137
  resolveWorkspacePaths,
138
+ resolveProjectRowanDir,
142
139
  resolveInWorkspace,
143
140
  normalizeRelativePath,
144
141
  resolveWorkspacePath
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  resolveInWorkspace,
3
3
  resolveWorkspacePaths
4
- } from "./chunk-S7DI7HIF.js";
4
+ } from "./chunk-2FIII4GP.js";
5
5
 
6
6
  // src/harness/phases/loader.ts
7
7
  import { existsSync as existsSync3 } from "fs";
@@ -370,11 +370,18 @@ var PHASE_DIR = "phases";
370
370
  async function loadPhase(input, workspace) {
371
371
  const resolved = resolveResourcePath(input, PHASE_DIR, PHASE_MARKER, workspace);
372
372
  const { frontmatter, body } = await loadMarkdown(resolved);
373
+ const id = inferResourceName(resolved, PHASE_MARKER);
374
+ if (!frontmatter.name) {
375
+ throw new Error(`Phase "${id}" at "${resolved}" is missing required field "name" in PHASE.md frontmatter.`);
376
+ }
377
+ if (!frontmatter.description) {
378
+ throw new Error(`Phase "${id}" at "${resolved}" is missing required field "description" in PHASE.md frontmatter.`);
379
+ }
373
380
  const baseDir = dirname2(resolved);
374
381
  const phase = {
375
- id: inferResourceName(resolved, PHASE_MARKER),
376
- name: frontmatter.name ?? inferResourceName(resolved, PHASE_MARKER),
377
- description: frontmatter.description ?? "",
382
+ id,
383
+ name: frontmatter.name,
384
+ description: frontmatter.description,
378
385
  tools: frontmatter.tools,
379
386
  skills: frontmatter.skills,
380
387
  target: frontmatter.target,
@@ -409,12 +416,16 @@ async function loadPhases(workspace, paths) {
409
416
  const phases = /* @__PURE__ */ new Map();
410
417
  if (paths && paths.length > 0) {
411
418
  for (const path of paths) {
412
- const phase = await loadPhase(path, workspace);
413
- phases.set(phase.id, phase);
419
+ try {
420
+ const phase = await loadPhase(path, workspace);
421
+ phases.set(phase.id, phase);
422
+ } catch (error) {
423
+ console.warn(`Failed to load phase "${path}":`, error);
424
+ }
414
425
  }
415
426
  return { phases, entryPhaseId: null };
416
427
  }
417
- const ws = workspace ?? (await import("./path-TJ2G5L4N.js")).resolveWorkspacePaths();
428
+ const ws = workspace ?? (await import("./path-XORRK2EC.js")).resolveWorkspacePaths();
418
429
  const phasesDir = join3(ws.rowanDir, PHASE_DIR);
419
430
  if (!existsSync3(phasesDir)) {
420
431
  return { phases, entryPhaseId: null };
package/dist/index.cjs CHANGED
@@ -41,6 +41,7 @@ __export(path_exports, {
41
41
  findSourceWorkspaceRoot: () => findSourceWorkspaceRoot,
42
42
  normalizeRelativePath: () => normalizeRelativePath,
43
43
  resolveInWorkspace: () => resolveInWorkspace,
44
+ resolveProjectRowanDir: () => resolveProjectRowanDir,
44
45
  resolveWorkspacePath: () => resolveWorkspacePath,
45
46
  resolveWorkspacePaths: () => resolveWorkspacePaths,
46
47
  resolveWorkspaceRoot: () => resolveWorkspaceRoot
@@ -98,17 +99,10 @@ function detectRuntimeMode(input = {}) {
98
99
  const executable = (0, import_node_path.basename)(input.execPath ?? process.execPath).toLowerCase().replace(/\.exe$/, "");
99
100
  return executable === "bun" ? "source" : "binary";
100
101
  }
101
- function defaultSourceStartDir(options) {
102
+ function defaultWorkspaceStartDir(options) {
102
103
  if (options.cwd) {
103
104
  return options.cwd;
104
105
  }
105
- const entrypoint = options.entrypoint ?? process.argv[1];
106
- if (entrypoint) {
107
- const entrypointPath = (0, import_node_path.resolve)(process.cwd(), entrypoint);
108
- if ((0, import_node_fs.existsSync)(entrypointPath)) {
109
- return (0, import_node_path.dirname)(entrypointPath);
110
- }
111
- }
112
106
  return process.cwd();
113
107
  }
114
108
  function resolveWorkspaceRoot(options = {}) {
@@ -118,11 +112,7 @@ function resolveWorkspaceRoot(options = {}) {
118
112
  if (override) {
119
113
  return resolveUserPath(override, homeDir);
120
114
  }
121
- const mode = options.mode ?? detectRuntimeMode(options);
122
- if (mode === "binary") {
123
- return homeDir;
124
- }
125
- return findSourceWorkspaceRoot(defaultSourceStartDir(options));
115
+ return findSourceWorkspaceRoot(defaultWorkspaceStartDir(options));
126
116
  }
127
117
  function resolveWorkspacePaths(options = {}) {
128
118
  const mode = options.mode ?? detectRuntimeMode(options);
@@ -130,9 +120,16 @@ function resolveWorkspacePaths(options = {}) {
130
120
  return {
131
121
  mode,
132
122
  cwd,
133
- rowanDir: (0, import_node_path.join)(cwd, BINARY_WORKSPACE_DIR)
123
+ rowanDir: resolveProjectRowanDir(cwd, options.rowanDir)
134
124
  };
135
125
  }
126
+ function resolveProjectRowanDir(cwd, rowanDir = BINARY_WORKSPACE_DIR) {
127
+ const inputPath = rowanDir.trim() || BINARY_WORKSPACE_DIR;
128
+ if ((0, import_node_path.isAbsolute)(inputPath)) {
129
+ throw new Error(`Project Rowan dir must be a relative path: ${rowanDir}`);
130
+ }
131
+ return resolveWorkspacePath({ root: cwd }, inputPath).absolutePath;
132
+ }
136
133
  function resolveInWorkspace(path, rootOrPaths) {
137
134
  if (path === "~" || path.startsWith("~/") || path.startsWith("~\\")) {
138
135
  return resolveUserPath(path, (0, import_node_os.homedir)());
@@ -567,11 +564,18 @@ __export(loader_exports, {
567
564
  async function loadPhase(input, workspace) {
568
565
  const resolved = resolveResourcePath(input, PHASE_DIR, PHASE_MARKER, workspace);
569
566
  const { frontmatter, body } = await loadMarkdown(resolved);
567
+ const id = inferResourceName(resolved, PHASE_MARKER);
568
+ if (!frontmatter.name) {
569
+ throw new Error(`Phase "${id}" at "${resolved}" is missing required field "name" in PHASE.md frontmatter.`);
570
+ }
571
+ if (!frontmatter.description) {
572
+ throw new Error(`Phase "${id}" at "${resolved}" is missing required field "description" in PHASE.md frontmatter.`);
573
+ }
570
574
  const baseDir = (0, import_node_path4.dirname)(resolved);
571
575
  const phase = {
572
- id: inferResourceName(resolved, PHASE_MARKER),
573
- name: frontmatter.name ?? inferResourceName(resolved, PHASE_MARKER),
574
- description: frontmatter.description ?? "",
576
+ id,
577
+ name: frontmatter.name,
578
+ description: frontmatter.description,
575
579
  tools: frontmatter.tools,
576
580
  skills: frontmatter.skills,
577
581
  target: frontmatter.target,
@@ -606,8 +610,12 @@ async function loadPhases(workspace, paths) {
606
610
  const phases = /* @__PURE__ */ new Map();
607
611
  if (paths && paths.length > 0) {
608
612
  for (const path of paths) {
609
- const phase = await loadPhase(path, workspace);
610
- phases.set(phase.id, phase);
613
+ try {
614
+ const phase = await loadPhase(path, workspace);
615
+ phases.set(phase.id, phase);
616
+ } catch (error) {
617
+ console.warn(`Failed to load phase "${path}":`, error);
618
+ }
611
619
  }
612
620
  return { phases, entryPhaseId: null };
613
621
  }
@@ -715,6 +723,7 @@ __export(index_exports, {
715
723
  loadConfigFile: () => loadConfigFile,
716
724
  loadExtensionFromFactory: () => loadExtensionFromFactory,
717
725
  loadExtensions: () => loadExtensions,
726
+ loadPhases: () => loadPhases,
718
727
  loadSkill: () => loadSkill,
719
728
  loadSkills: () => loadSkills,
720
729
  messageContentText: () => messageContentText,
@@ -2688,7 +2697,7 @@ var Agent = class {
2688
2697
  * - Merges with CLI-provided phases and skills
2689
2698
  */
2690
2699
  async discoverResources(context) {
2691
- const workspace = resolveWorkspacePaths({ cwd: this.options.cwd });
2700
+ const workspace = resolveWorkspacePaths({ cwd: this.options.cwd, rowanDir: this.options.rowanDir });
2692
2701
  const filePhases = await loadPhases(workspace);
2693
2702
  let phases;
2694
2703
  const providedPhases = this.options.phases;
@@ -2848,7 +2857,7 @@ ${additionalInstructions}` : content;
2848
2857
  * @returns Formatted phase content string, or empty string if not found
2849
2858
  */
2850
2859
  async phase(name) {
2851
- const workspace = resolveWorkspacePaths({ cwd: this.options.cwd });
2860
+ const workspace = resolveWorkspacePaths({ cwd: this.options.cwd, rowanDir: this.options.rowanDir });
2852
2861
  const { loadPhase: loadPhase2, readPhaseContent: readPhaseContent2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
2853
2862
  try {
2854
2863
  const phase = await loadPhase2(name, workspace);
@@ -4198,13 +4207,19 @@ var ExtensionRunner = class {
4198
4207
  if (!registration.id) {
4199
4208
  throw new Error(`Phase registration requires an "id" field.`);
4200
4209
  }
4210
+ if (!registration.name) {
4211
+ throw new Error(`Phase registration "${registration.id}" requires a "name" field.`);
4212
+ }
4213
+ if (!registration.description) {
4214
+ throw new Error(`Phase registration "${registration.id}" requires a "description" field.`);
4215
+ }
4201
4216
  if (this.phases.has(registration.id)) {
4202
4217
  throw new Error(`Duplicate phase id: ${registration.id}`);
4203
4218
  }
4204
4219
  const definition = {
4205
4220
  id: registration.id,
4206
- name: registration.name ?? registration.id,
4207
- description: registration.description ?? "",
4221
+ name: registration.name,
4222
+ description: registration.description,
4208
4223
  run: registration.run,
4209
4224
  ...registration.model ? { model: registration.model } : {}
4210
4225
  };
@@ -4288,14 +4303,19 @@ function readManifestSync(dir) {
4288
4303
  }
4289
4304
  }
4290
4305
  function jitiAliases() {
4291
- return {
4292
- "@rowan-agent/agent": (0, import_node_url.fileURLToPath)(new URL("../index.ts", import_meta2.url)),
4293
- "@rowan-agent/models": (0, import_node_url.fileURLToPath)(new URL("../../../models/src/index.ts", import_meta2.url))
4294
- };
4306
+ const moduleUrl = import_meta2.url;
4307
+ if (!moduleUrl) {
4308
+ return {};
4309
+ }
4310
+ const agentSourcePath = (0, import_node_url.fileURLToPath)(new URL("../index.ts", moduleUrl));
4311
+ if (!(0, import_node_fs6.existsSync)(agentSourcePath)) {
4312
+ return {};
4313
+ }
4314
+ return { "@rowan-agent/agent": agentSourcePath };
4295
4315
  }
4296
4316
  var sharedJiti;
4297
4317
  function getJiti() {
4298
- sharedJiti ??= (0, import_jiti.createJiti)(import_meta2.url, {
4318
+ sharedJiti ??= (0, import_jiti.createJiti)(import_meta2.url || process.cwd(), {
4299
4319
  moduleCache: false,
4300
4320
  alias: jitiAliases()
4301
4321
  });
@@ -4398,6 +4418,9 @@ async function discoverAndLoadExtensions(cwd) {
4398
4418
  return loadExtensions(paths, cwd);
4399
4419
  }
4400
4420
 
4421
+ // src/index.ts
4422
+ init_loader2();
4423
+
4401
4424
  // src/harness/context/index.ts
4402
4425
  init_resource_formatter();
4403
4426
  // Annotate the CommonJS export names for ESM import in node:
@@ -4430,6 +4453,7 @@ init_resource_formatter();
4430
4453
  loadConfigFile,
4431
4454
  loadExtensionFromFactory,
4432
4455
  loadExtensions,
4456
+ loadPhases,
4433
4457
  loadSkill,
4434
4458
  loadSkills,
4435
4459
  messageContentText,
package/dist/index.d.cts CHANGED
@@ -1381,6 +1381,7 @@ type AgentOptions = {
1381
1381
  model: LlmModelRef;
1382
1382
  stream: StreamFn;
1383
1383
  cwd?: string;
1384
+ rowanDir?: string;
1384
1385
  phases?: PhaseRegistry;
1385
1386
  extensionRunnerRef?: ExtensionRunnerRef;
1386
1387
  sessionId?: string;
@@ -1700,6 +1701,7 @@ type ResolveWorkspaceOptions = {
1700
1701
  entrypoint?: string;
1701
1702
  homeDir?: string;
1702
1703
  mode?: RuntimeMode;
1704
+ rowanDir?: string;
1703
1705
  };
1704
1706
  declare function resolveWorkspacePaths(options?: ResolveWorkspaceOptions): WorkspacePaths;
1705
1707
  declare function resolveInWorkspace(path: string, rootOrPaths: string | Pick<WorkspacePaths, "cwd">): string;
@@ -1774,6 +1776,18 @@ declare class AgentEventStream extends EventStream<AgentEvent, AgentMessage[]> {
1774
1776
  constructor();
1775
1777
  }
1776
1778
 
1779
+ /**
1780
+ * Load all phases from .rowan/phases directory.
1781
+ *
1782
+ * Scans for subdirectories containing PHASE.md files.
1783
+ * Returns PhaseRegistry with entryPhaseId:
1784
+ * - null by default (caller must explicitly set to start from a specific phase)
1785
+ * - Set to a specific phase id to start from that phase
1786
+ *
1787
+ * When entryPhaseId is null, AgentLoop starts from "none" phase.
1788
+ */
1789
+ declare function loadPhases(workspace?: WorkspacePaths, paths?: string[]): Promise<PhaseRegistry>;
1790
+
1777
1791
  interface SystemPromptOptions {
1778
1792
  /** Base system prompt. */
1779
1793
  systemPrompt: string;
@@ -1827,4 +1841,4 @@ declare function buildModelRequest(input: ModelRequestInput, options?: {
1827
1841
  model?: LlmModelRef;
1828
1842
  }): LlmRequest;
1829
1843
 
1830
- export { type AbortEvent, type AfterPhaseEvent, type AfterPhaseHookResult, type AfterPhaseResult, type AfterToolCallEvent, type AfterToolCallResult, Agent, type AgentConfigFile, type AgentContext, type AgentEndEvent, AgentEventStream, type AgentOptions, type AgentStartEvent, type AgentStatus, type BeforePhaseEvent, type BeforePhaseHookResult, type BeforePhaseResult, type BeforePromptEvent, type BeforePromptResult, type BeforeToolCallEvent, type BeforeToolCallResult, type EventBus, EventStream, type ExecOptions, type ExecResult, type ExecutionTurn, type Extension, type ExtensionAPI, type ExtensionContext, type ExtensionError, type ExtensionErrorListener, type ExtensionFactory, type ExtensionManifest, type ExtensionPackageManifest, ExtensionRunner, type ExtensionRunnerOptions, type ExtensionRunnerRef, type ExtensionRuntime, type ExtensionUtils, HookError, type HookEvent, type HookEventType, type HookHandler, type HookResultMap, HooksManager, type LoadExtensionsResult, type LoadedExtension, LocalJsonlSessionManager, type LoopMetrics, type MessageEndEvent, type MessageStartEvent, type MessageUpdateEvent, type ModelConfigFromFile, type ModelTranscript, type Phase, type PhaseContext, type PhaseDefinition, type PhaseExecution, type PhaseOutput, type PhaseRegistration, type PhaseRegistry, type PhaseRun, type PhaseState, type ProviderConfigFromFile, type QueueUpdateEvent, type RegisteredPhase, type RegisteredTool, type RunOptions, type RunResult, type SavePointEvent, type Session, type SessionListItem, type SettledEvent, type SourceInfo, type Tool, type ToolDefinition, type ToolExecutionEndEvent, type ToolExecutionResult, type ToolExecutionStartEvent, type ToolExecutionUpdateEvent, type TurnEndEvent, type TurnStartEvent, type WorkspacePaths, appendUserTurn, buildModelRequest, buildSystemPrompt, conversationMessages, createCoreTools, createEventBus, createExtension, createExtensionAPI, createExtensionRunner, createExtensionRuntime, createId, createMessage, createSession, createSourceInfo, createTimestamp, discoverAndLoadExtensions, getGlobalHooks, interpolateEnvVars, latestUserInput, loadConfigFile, loadExtensionFromFactory, loadExtensions, loadSkill, loadSkills, messageContentText, parseModelRef, registerConfigModels, resetGlobalHooks, resolveDefaultModel, resolveInWorkspace, resolveSkillPath, resolveWorkspacePaths, serializeSkills };
1844
+ export { type AbortEvent, type AfterPhaseEvent, type AfterPhaseHookResult, type AfterPhaseResult, type AfterToolCallEvent, type AfterToolCallResult, Agent, type AgentConfigFile, type AgentContext, type AgentEndEvent, AgentEventStream, type AgentOptions, type AgentStartEvent, type AgentStatus, type BeforePhaseEvent, type BeforePhaseHookResult, type BeforePhaseResult, type BeforePromptEvent, type BeforePromptResult, type BeforeToolCallEvent, type BeforeToolCallResult, type EventBus, EventStream, type ExecOptions, type ExecResult, type ExecutionTurn, type Extension, type ExtensionAPI, type ExtensionContext, type ExtensionError, type ExtensionErrorListener, type ExtensionFactory, type ExtensionManifest, type ExtensionPackageManifest, ExtensionRunner, type ExtensionRunnerOptions, type ExtensionRunnerRef, type ExtensionRuntime, type ExtensionUtils, HookError, type HookEvent, type HookEventType, type HookHandler, type HookResultMap, HooksManager, type LoadExtensionsResult, type LoadedExtension, LocalJsonlSessionManager, type LoopMetrics, type MessageEndEvent, type MessageStartEvent, type MessageUpdateEvent, type ModelConfigFromFile, type ModelTranscript, type Phase, type PhaseContext, type PhaseDefinition, type PhaseExecution, type PhaseOutput, type PhaseRegistration, type PhaseRegistry, type PhaseRun, type PhaseState, type ProviderConfigFromFile, type QueueUpdateEvent, type RegisteredPhase, type RegisteredTool, type RunOptions, type RunResult, type SavePointEvent, type Session, type SessionListItem, type SettledEvent, type SourceInfo, type Tool, type ToolDefinition, type ToolExecutionEndEvent, type ToolExecutionResult, type ToolExecutionStartEvent, type ToolExecutionUpdateEvent, type TurnEndEvent, type TurnStartEvent, type WorkspacePaths, appendUserTurn, buildModelRequest, buildSystemPrompt, conversationMessages, createCoreTools, createEventBus, createExtension, createExtensionAPI, createExtensionRunner, createExtensionRuntime, createId, createMessage, createSession, createSourceInfo, createTimestamp, discoverAndLoadExtensions, getGlobalHooks, interpolateEnvVars, latestUserInput, loadConfigFile, loadExtensionFromFactory, loadExtensions, loadPhases, loadSkill, loadSkills, messageContentText, parseModelRef, registerConfigModels, resetGlobalHooks, resolveDefaultModel, resolveInWorkspace, resolveSkillPath, resolveWorkspacePaths, serializeSkills };
package/dist/index.d.ts CHANGED
@@ -1381,6 +1381,7 @@ type AgentOptions = {
1381
1381
  model: LlmModelRef;
1382
1382
  stream: StreamFn;
1383
1383
  cwd?: string;
1384
+ rowanDir?: string;
1384
1385
  phases?: PhaseRegistry;
1385
1386
  extensionRunnerRef?: ExtensionRunnerRef;
1386
1387
  sessionId?: string;
@@ -1700,6 +1701,7 @@ type ResolveWorkspaceOptions = {
1700
1701
  entrypoint?: string;
1701
1702
  homeDir?: string;
1702
1703
  mode?: RuntimeMode;
1704
+ rowanDir?: string;
1703
1705
  };
1704
1706
  declare function resolveWorkspacePaths(options?: ResolveWorkspaceOptions): WorkspacePaths;
1705
1707
  declare function resolveInWorkspace(path: string, rootOrPaths: string | Pick<WorkspacePaths, "cwd">): string;
@@ -1774,6 +1776,18 @@ declare class AgentEventStream extends EventStream<AgentEvent, AgentMessage[]> {
1774
1776
  constructor();
1775
1777
  }
1776
1778
 
1779
+ /**
1780
+ * Load all phases from .rowan/phases directory.
1781
+ *
1782
+ * Scans for subdirectories containing PHASE.md files.
1783
+ * Returns PhaseRegistry with entryPhaseId:
1784
+ * - null by default (caller must explicitly set to start from a specific phase)
1785
+ * - Set to a specific phase id to start from that phase
1786
+ *
1787
+ * When entryPhaseId is null, AgentLoop starts from "none" phase.
1788
+ */
1789
+ declare function loadPhases(workspace?: WorkspacePaths, paths?: string[]): Promise<PhaseRegistry>;
1790
+
1777
1791
  interface SystemPromptOptions {
1778
1792
  /** Base system prompt. */
1779
1793
  systemPrompt: string;
@@ -1827,4 +1841,4 @@ declare function buildModelRequest(input: ModelRequestInput, options?: {
1827
1841
  model?: LlmModelRef;
1828
1842
  }): LlmRequest;
1829
1843
 
1830
- export { type AbortEvent, type AfterPhaseEvent, type AfterPhaseHookResult, type AfterPhaseResult, type AfterToolCallEvent, type AfterToolCallResult, Agent, type AgentConfigFile, type AgentContext, type AgentEndEvent, AgentEventStream, type AgentOptions, type AgentStartEvent, type AgentStatus, type BeforePhaseEvent, type BeforePhaseHookResult, type BeforePhaseResult, type BeforePromptEvent, type BeforePromptResult, type BeforeToolCallEvent, type BeforeToolCallResult, type EventBus, EventStream, type ExecOptions, type ExecResult, type ExecutionTurn, type Extension, type ExtensionAPI, type ExtensionContext, type ExtensionError, type ExtensionErrorListener, type ExtensionFactory, type ExtensionManifest, type ExtensionPackageManifest, ExtensionRunner, type ExtensionRunnerOptions, type ExtensionRunnerRef, type ExtensionRuntime, type ExtensionUtils, HookError, type HookEvent, type HookEventType, type HookHandler, type HookResultMap, HooksManager, type LoadExtensionsResult, type LoadedExtension, LocalJsonlSessionManager, type LoopMetrics, type MessageEndEvent, type MessageStartEvent, type MessageUpdateEvent, type ModelConfigFromFile, type ModelTranscript, type Phase, type PhaseContext, type PhaseDefinition, type PhaseExecution, type PhaseOutput, type PhaseRegistration, type PhaseRegistry, type PhaseRun, type PhaseState, type ProviderConfigFromFile, type QueueUpdateEvent, type RegisteredPhase, type RegisteredTool, type RunOptions, type RunResult, type SavePointEvent, type Session, type SessionListItem, type SettledEvent, type SourceInfo, type Tool, type ToolDefinition, type ToolExecutionEndEvent, type ToolExecutionResult, type ToolExecutionStartEvent, type ToolExecutionUpdateEvent, type TurnEndEvent, type TurnStartEvent, type WorkspacePaths, appendUserTurn, buildModelRequest, buildSystemPrompt, conversationMessages, createCoreTools, createEventBus, createExtension, createExtensionAPI, createExtensionRunner, createExtensionRuntime, createId, createMessage, createSession, createSourceInfo, createTimestamp, discoverAndLoadExtensions, getGlobalHooks, interpolateEnvVars, latestUserInput, loadConfigFile, loadExtensionFromFactory, loadExtensions, loadSkill, loadSkills, messageContentText, parseModelRef, registerConfigModels, resetGlobalHooks, resolveDefaultModel, resolveInWorkspace, resolveSkillPath, resolveWorkspacePaths, serializeSkills };
1844
+ export { type AbortEvent, type AfterPhaseEvent, type AfterPhaseHookResult, type AfterPhaseResult, type AfterToolCallEvent, type AfterToolCallResult, Agent, type AgentConfigFile, type AgentContext, type AgentEndEvent, AgentEventStream, type AgentOptions, type AgentStartEvent, type AgentStatus, type BeforePhaseEvent, type BeforePhaseHookResult, type BeforePhaseResult, type BeforePromptEvent, type BeforePromptResult, type BeforeToolCallEvent, type BeforeToolCallResult, type EventBus, EventStream, type ExecOptions, type ExecResult, type ExecutionTurn, type Extension, type ExtensionAPI, type ExtensionContext, type ExtensionError, type ExtensionErrorListener, type ExtensionFactory, type ExtensionManifest, type ExtensionPackageManifest, ExtensionRunner, type ExtensionRunnerOptions, type ExtensionRunnerRef, type ExtensionRuntime, type ExtensionUtils, HookError, type HookEvent, type HookEventType, type HookHandler, type HookResultMap, HooksManager, type LoadExtensionsResult, type LoadedExtension, LocalJsonlSessionManager, type LoopMetrics, type MessageEndEvent, type MessageStartEvent, type MessageUpdateEvent, type ModelConfigFromFile, type ModelTranscript, type Phase, type PhaseContext, type PhaseDefinition, type PhaseExecution, type PhaseOutput, type PhaseRegistration, type PhaseRegistry, type PhaseRun, type PhaseState, type ProviderConfigFromFile, type QueueUpdateEvent, type RegisteredPhase, type RegisteredTool, type RunOptions, type RunResult, type SavePointEvent, type Session, type SessionListItem, type SettledEvent, type SourceInfo, type Tool, type ToolDefinition, type ToolExecutionEndEvent, type ToolExecutionResult, type ToolExecutionStartEvent, type ToolExecutionUpdateEvent, type TurnEndEvent, type TurnStartEvent, type WorkspacePaths, appendUserTurn, buildModelRequest, buildSystemPrompt, conversationMessages, createCoreTools, createEventBus, createExtension, createExtensionAPI, createExtensionRunner, createExtensionRuntime, createId, createMessage, createSession, createSourceInfo, createTimestamp, discoverAndLoadExtensions, getGlobalHooks, interpolateEnvVars, latestUserInput, loadConfigFile, loadExtensionFromFactory, loadExtensions, loadPhases, loadSkill, loadSkills, messageContentText, parseModelRef, registerConfigModels, resetGlobalHooks, resolveDefaultModel, resolveInWorkspace, resolveSkillPath, resolveWorkspacePaths, serializeSkills };
package/dist/index.js CHANGED
@@ -16,12 +16,12 @@ import {
16
16
  reloadPhases,
17
17
  resolveDefaultModel,
18
18
  resolveResourcePath
19
- } from "./chunk-AFRSS3C5.js";
19
+ } from "./chunk-APSIAOUD.js";
20
20
  import {
21
21
  normalizeRelativePath,
22
22
  resolveInWorkspace,
23
23
  resolveWorkspacePaths
24
- } from "./chunk-S7DI7HIF.js";
24
+ } from "./chunk-2FIII4GP.js";
25
25
 
26
26
  // src/utils.ts
27
27
  function createId(prefix) {
@@ -1966,7 +1966,7 @@ var Agent = class {
1966
1966
  * - Merges with CLI-provided phases and skills
1967
1967
  */
1968
1968
  async discoverResources(context) {
1969
- const workspace = resolveWorkspacePaths({ cwd: this.options.cwd });
1969
+ const workspace = resolveWorkspacePaths({ cwd: this.options.cwd, rowanDir: this.options.rowanDir });
1970
1970
  const filePhases = await loadPhases(workspace);
1971
1971
  let phases;
1972
1972
  const providedPhases = this.options.phases;
@@ -2126,8 +2126,8 @@ ${additionalInstructions}` : content;
2126
2126
  * @returns Formatted phase content string, or empty string if not found
2127
2127
  */
2128
2128
  async phase(name) {
2129
- const workspace = resolveWorkspacePaths({ cwd: this.options.cwd });
2130
- const { loadPhase: loadPhase2, readPhaseContent: readPhaseContent2 } = await import("./loader-UKBWDLDZ.js");
2129
+ const workspace = resolveWorkspacePaths({ cwd: this.options.cwd, rowanDir: this.options.rowanDir });
2130
+ const { loadPhase: loadPhase2, readPhaseContent: readPhaseContent2 } = await import("./loader-MVD5JAKM.js");
2131
2131
  try {
2132
2132
  const phase = await loadPhase2(name, workspace);
2133
2133
  return readPhaseContent2(phase);
@@ -3471,13 +3471,19 @@ var ExtensionRunner = class {
3471
3471
  if (!registration.id) {
3472
3472
  throw new Error(`Phase registration requires an "id" field.`);
3473
3473
  }
3474
+ if (!registration.name) {
3475
+ throw new Error(`Phase registration "${registration.id}" requires a "name" field.`);
3476
+ }
3477
+ if (!registration.description) {
3478
+ throw new Error(`Phase registration "${registration.id}" requires a "description" field.`);
3479
+ }
3474
3480
  if (this.phases.has(registration.id)) {
3475
3481
  throw new Error(`Duplicate phase id: ${registration.id}`);
3476
3482
  }
3477
3483
  const definition = {
3478
3484
  id: registration.id,
3479
- name: registration.name ?? registration.id,
3480
- description: registration.description ?? "",
3485
+ name: registration.name,
3486
+ description: registration.description,
3481
3487
  run: registration.run,
3482
3488
  ...registration.model ? { model: registration.model } : {}
3483
3489
  };
@@ -3560,14 +3566,19 @@ function readManifestSync(dir) {
3560
3566
  }
3561
3567
  }
3562
3568
  function jitiAliases() {
3563
- return {
3564
- "@rowan-agent/agent": fileURLToPath(new URL("../index.ts", import.meta.url)),
3565
- "@rowan-agent/models": fileURLToPath(new URL("../../../models/src/index.ts", import.meta.url))
3566
- };
3569
+ const moduleUrl = import.meta.url;
3570
+ if (!moduleUrl) {
3571
+ return {};
3572
+ }
3573
+ const agentSourcePath = fileURLToPath(new URL("../index.ts", moduleUrl));
3574
+ if (!existsSync2(agentSourcePath)) {
3575
+ return {};
3576
+ }
3577
+ return { "@rowan-agent/agent": agentSourcePath };
3567
3578
  }
3568
3579
  var sharedJiti;
3569
3580
  function getJiti() {
3570
- sharedJiti ??= createJiti(import.meta.url, {
3581
+ sharedJiti ??= createJiti(import.meta.url || process.cwd(), {
3571
3582
  moduleCache: false,
3572
3583
  alias: jitiAliases()
3573
3584
  });
@@ -3698,6 +3709,7 @@ export {
3698
3709
  loadConfigFile,
3699
3710
  loadExtensionFromFactory,
3700
3711
  loadExtensions,
3712
+ loadPhases,
3701
3713
  loadSkill,
3702
3714
  loadSkills,
3703
3715
  messageContentText,
@@ -3,8 +3,8 @@ import {
3
3
  loadPhases,
4
4
  readPhaseContent,
5
5
  reloadPhases
6
- } from "./chunk-AFRSS3C5.js";
7
- import "./chunk-S7DI7HIF.js";
6
+ } from "./chunk-APSIAOUD.js";
7
+ import "./chunk-2FIII4GP.js";
8
8
  export {
9
9
  loadPhase,
10
10
  loadPhases,
@@ -7,10 +7,11 @@ import {
7
7
  findSourceWorkspaceRoot,
8
8
  normalizeRelativePath,
9
9
  resolveInWorkspace,
10
+ resolveProjectRowanDir,
10
11
  resolveWorkspacePath,
11
12
  resolveWorkspacePaths,
12
13
  resolveWorkspaceRoot
13
- } from "./chunk-S7DI7HIF.js";
14
+ } from "./chunk-2FIII4GP.js";
14
15
  export {
15
16
  BINARY_WORKSPACE_DIR,
16
17
  PACKAGED_ENV,
@@ -20,6 +21,7 @@ export {
20
21
  findSourceWorkspaceRoot,
21
22
  normalizeRelativePath,
22
23
  resolveInWorkspace,
24
+ resolveProjectRowanDir,
23
25
  resolveWorkspacePath,
24
26
  resolveWorkspacePaths,
25
27
  resolveWorkspaceRoot
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowan-agent/agent",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",