Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/cli/src/commands/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
ScriptValidationResult,
} from '@archon/workflows/validator';
import { loadConfig, loadRepoConfig } from '@archon/core';
import { getArchonHome } from '@archon/paths';

/**
* Build ValidationConfig from the repo's .archon/config.yaml
Expand Down Expand Up @@ -89,7 +90,8 @@ export async function validateWorkflowsCommand(
const defaultProvider = mergedConfig.assistant;
const { workflows: workflowEntries, errors: loadErrors } = await discoverWorkflowsWithConfig(
cwd,
loadConfig
loadConfig,
{ globalSearchPath: getArchonHome() }
);

// Build results from load errors (Level 1-2 failures)
Expand Down
38 changes: 36 additions & 2 deletions packages/core/src/handlers/command-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ const mockLogger = createMockLogger();
mock.module('@archon/paths', () => ({
createLogger: mock(() => mockLogger),
getArchonWorkspacesPath: mock(() => '/home/test/.archon/workspaces'),
getArchonHome: mock(() => '/home/test/.archon'),
getCommandFolderSearchPaths: mock(() => ['.archon/commands']),
expandTilde: mock((p: string) => p.replace(/^~/, '/home/test')),
ensureProjectStructure: mock(() => Promise.resolve()),
Expand Down Expand Up @@ -1040,8 +1041,14 @@ describe('CommandHandler', () => {

await handleCommand(conversationWithCodebase, '/workflow list');

// Verify loadConfig function is passed as the second argument
expect(spyDiscoverWorkflows).toHaveBeenCalledWith(expect.any(String), expect.any(Function));
// Verify loadConfig function and globalSearchPath are passed
expect(spyDiscoverWorkflows).toHaveBeenCalledWith(
expect.any(String),
expect.any(Function),
{
globalSearchPath: '/home/test/.archon',
}
);
});
});

Expand Down Expand Up @@ -1104,6 +1111,18 @@ describe('CommandHandler', () => {
expect(result.message).toContain('Discovered 1 workflow(s)');
expect(result.message).not.toContain('failed to load');
});

test('should pass globalSearchPath to discoverWorkflowsWithConfig on reload', async () => {
spyDiscoverWorkflows.mockResolvedValueOnce({ workflows: [], errors: [] });

await handleCommand(conversationWithCodebase, '/workflow reload');

expect(spyDiscoverWorkflows).toHaveBeenCalledWith(
expect.any(String),
expect.any(Function),
{ globalSearchPath: '/home/test/.archon' }
);
});
});

describe('/workflow run with load errors', () => {
Expand Down Expand Up @@ -1546,6 +1565,21 @@ describe('CommandHandler', () => {
expect(result.message).toContain('/workflow list');
});

test('should pass globalSearchPath to discoverWorkflowsWithConfig on run', async () => {
spyDiscoverWorkflows.mockResolvedValueOnce({
workflows: [makeTestWorkflowWithSource({ name: 'assist', description: 'test' })],
errors: [],
});

await handleCommand(conversationWithCodebase, '/workflow run nonexistent');

expect(spyDiscoverWorkflows).toHaveBeenCalledWith(
expect.any(String),
expect.any(Function),
{ globalSearchPath: '/home/test/.archon' }
);
});

test('should return error when workflow is not found', async () => {
spyDiscoverWorkflows.mockResolvedValueOnce({
workflows: [
Expand Down
15 changes: 10 additions & 5 deletions packages/core/src/handlers/command-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
cleanupStaleWorktrees,
getWorktreeStatusBreakdown,
} from '../services/cleanup-service';
import { getArchonWorkspacesPath } from '@archon/paths';
import { getArchonWorkspacesPath, getArchonHome } from '@archon/paths';
import { loadConfig } from '../config/config-loader';
import { discoverWorkflowsWithConfig } from '@archon/workflows/workflow-discovery';
import { resolveWorkflowName } from '@archon/workflows/router';
Expand Down Expand Up @@ -563,7 +563,9 @@ async function handleWorkflowCommand(
let workflowEntries: readonly WorkflowWithSource[];
let errors: readonly WorkflowLoadError[];
try {
const result = await discoverWorkflowsWithConfig(workflowCwd, loadConfig);
const result = await discoverWorkflowsWithConfig(workflowCwd, loadConfig, {
globalSearchPath: getArchonHome(),
});
workflowEntries = result.workflows;
errors = result.errors;
} catch (error) {
Expand Down Expand Up @@ -609,7 +611,9 @@ async function handleWorkflowCommand(
case 'reload': {
try {
const { workflows: reloadedWorkflows, errors: reloadErrors } =
await discoverWorkflowsWithConfig(workflowCwd, loadConfig);
await discoverWorkflowsWithConfig(workflowCwd, loadConfig, {
globalSearchPath: getArchonHome(),
});
let msg = `Discovered ${String(reloadedWorkflows.length)} workflow(s).`;
if (reloadErrors.length > 0) {
msg += `\n\n**${String(reloadErrors.length)} failed to load:**\n`;
Expand Down Expand Up @@ -800,11 +804,12 @@ async function handleWorkflowCommand(
'cmd.workflow_run_invoked'
);

// Discover workflows with error handling
let workflowEntries: readonly WorkflowWithSource[];
let loadErrors: readonly WorkflowLoadError[];
try {
const result = await discoverWorkflowsWithConfig(workflowCwd, loadConfig);
const result = await discoverWorkflowsWithConfig(workflowCwd, loadConfig, {
globalSearchPath: getArchonHome(),
});
workflowEntries = result.workflows;
loadErrors = result.errors;
} catch (error) {
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/orchestrator/orchestrator-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1431,7 +1431,9 @@ async function handleWorkflowRunCommand(

let discovery;
try {
discovery = await discoverWorkflowsWithConfig(workflowCwd, loadConfig);
discovery = await discoverWorkflowsWithConfig(workflowCwd, loadConfig, {
globalSearchPath: getArchonHome(),
});
} catch (error) {
const err = error as Error;
getLog().error({ err, cwd: workflowCwd }, 'workflow_discovery_failed');
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/orchestrator/orchestrator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ describe('orchestrator-agent handleMessage', () => {

expect(mockDiscoverWorkflows).toHaveBeenCalledWith(
'/workspace/test-project',
expect.any(Function)
expect.any(Function),
{ globalSearchPath: expect.any(String) }
);
expect(platform.sendMessage).toHaveBeenCalledWith(
'chat-456',
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/routes/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1686,7 +1686,9 @@ export function registerApiRoutes(
return c.json({ workflows: [] });
}

const result = await discoverWorkflowsWithConfig(workingDir, loadConfig);
const result = await discoverWorkflowsWithConfig(workingDir, loadConfig, {
globalSearchPath: getArchonHome(),
});
return c.json({
workflows: result.workflows.map(ws => ({ workflow: ws.workflow, source: ws.source })),
errors: result.errors.length > 0 ? result.errors : undefined,
Expand Down
4 changes: 3 additions & 1 deletion packages/server/src/routes/api.workflows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ describe('GET /api/workflows', () => {
expect(body.workflows[0]?.workflow.name).toBe('deploy');
expect(body.workflows[0]?.source).toBe('bundled');
expect(body.workflows.workflows).toBeUndefined();
expect(mockDiscoverWorkflows).toHaveBeenCalledWith('/tmp/project', expect.any(Function));
expect(mockDiscoverWorkflows).toHaveBeenCalledWith('/tmp/project', expect.any(Function), {
globalSearchPath: expect.any(String),
});
expect(body.errors).toBeDefined();
expect(Array.isArray(body.errors)).toBe(true);
});
Expand Down
Loading