Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/vast-files-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@workflow/cli": patch
---

Allow opening UI without a valid local config detected, UI will show warning and watch folder
5 changes: 5 additions & 0 deletions packages/cli/src/commands/cancel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export default class Cancel extends BaseCommand {
const { flags, args } = await this.parse(Cancel);

const world = await setupCliWorld(flags, this.config.version);
if (!world) {
throw new Error(
'Failed to connect to backend. Check your configuration.'
);
}

await cancelRun(world, args.runId);
}
Expand Down
13 changes: 11 additions & 2 deletions packages/cli/src/commands/inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,24 @@ export default class Inspect extends BaseCommand {

const id = args.id;

const world = await setupCliWorld(flags, this.config.version);
// For web mode, allow config errors so we can open the web UI for configuration
const isWebMode = flags.web || resource === 'web';
const world = await setupCliWorld(flags, this.config.version, isWebMode);

// Handle web UI mode
if (flags.web || resource === 'web') {
if (isWebMode) {
const actualResource = resource === 'web' ? 'run' : resource;
await launchWebUI(actualResource, id, flags, this.config.version);
process.exit(0);
}

// For non-web commands, we need a valid world
if (!world) {
throw new Error(
'Failed to connect to backend. Check your configuration.'
);
}

// Convert flags to InspectCLIOptions with proper typing
const options = toInspectOptions(flags);

Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/commands/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ export default class Start extends BaseCommand {
const stringArgs = restArgs.map((arg) => String(arg));

const world = await setupCliWorld(flags, this.config.version);
if (!world) {
throw new Error(
'Failed to connect to backend. Check your configuration.'
);
}

await startRun(world, args.workflowName, flags, stringArgs);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/commands/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export default class Web extends BaseCommand {

// Setup the CLI world to write env vars from flags
// This ensures backend, authToken, team, project, etc. are properly set
await setupCliWorld(flags, this.config.version);
// Don't throw on config errors - let the web UI handle them
await setupCliWorld(flags, this.config.version, true);

// Launch web UI with 'run' as the default resource
await launchWebUI('run', id, flags, this.config.version);
Expand Down
21 changes: 7 additions & 14 deletions packages/cli/src/lib/inspect/env.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { access } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import {
findWorkflowDataDir,
possibleWorkflowDataPaths,
} from '@workflow/utils/check-data-dir';
import { findWorkflowDataDir } from '@workflow/utils/check-data-dir';
import { logger } from '../config/log.js';
import { getWorkflowConfig } from '../config/workflow-config.js';
import { getAuth } from './auth.js';
Expand Down Expand Up @@ -76,6 +73,8 @@ async function findManifestPath(cwd: string) {
/**
* Overwrites process.env variables related to local world configuration,
* if relevant environment variables aren't set already.
*
* Throws if the workflow data directory can not be found.
*/
export const inferLocalWorldEnvVars = async () => {
const envVars = getEnvVars();
Expand All @@ -93,7 +92,7 @@ export const inferLocalWorldEnvVars = async () => {
// Infer workflow data directory
if (!envVars.WORKFLOW_LOCAL_DATA_DIR) {
const localResult = await findWorkflowDataDir(cwd);
if (localResult) {
if (localResult.dataDir) {
logger.debug('Found workflow data directory:', localResult.dataDir);
envVars.WORKFLOW_LOCAL_DATA_DIR = localResult.dataDir;
writeEnvVars(envVars);
Expand All @@ -102,21 +101,15 @@ export const inferLocalWorldEnvVars = async () => {
repoRoot = await findRepoRoot(cwd, cwd);
if (repoRoot) {
const repoResult = await findWorkflowDataDir(repoRoot);
if (repoResult) {
if (repoResult.dataDir) {
logger.debug('Found workflow data directory:', repoResult.dataDir);
envVars.WORKFLOW_LOCAL_DATA_DIR = repoResult.dataDir;
writeEnvVars(envVars);
}
}

if (!envVars.WORKFLOW_LOCAL_DATA_DIR) {
logger.error(
`No workflow data directory found in "${cwd}". Have you run any workflows yet?`
);
logger.warn(
`\nCheck whether your data is in any of:\n${possibleWorkflowDataPaths.map((p: string) => ` ${cwd}/${p}${repoRoot && repoRoot !== cwd ? `\n ${repoRoot}/${p}` : ''}`).join('\n')}\n`
);
throw new Error('No workflow data directory found');
const message = `No workflow data directory found in "${cwd}". Have you run any workflows yet?`;
throw new Error(message);
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion packages/cli/src/lib/inspect/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,11 @@ const showTable = (
TABLE_TRUNCATE_IO_LENGTH = displaySettings.dataFieldWidth;

// Show status legend if using abbreviated status
if (displaySettings.abbreviateStatus && visibleProps.includes('status')) {
if (
data.length > 0 &&
displaySettings.abbreviateStatus &&
visibleProps.includes('status')
) {
showStatusLegend();
}

Expand Down
36 changes: 29 additions & 7 deletions packages/cli/src/lib/inspect/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import {
writeEnvVars,
} from './env.js';

/**
* Setup CLI world configuration.
* If throwOnConfigError is false, will return null world with the error message
* instead of throwing, allowing the web UI to open for configuration.
*/
export const setupCliWorld = async (
flags: {
json: boolean;
Expand All @@ -18,8 +23,9 @@ export const setupCliWorld = async (
project: string;
team: string;
},
version: string
) => {
version: string,
ignoreLocalWorldConfigError = false
): Promise<Awaited<ReturnType<typeof createWorld>> | null> => {
setJsonMode(Boolean(flags.json));
setVerboseMode(Boolean(flags.verbose));

Expand All @@ -30,9 +36,9 @@ export const setupCliWorld = async (

logger.showBox(
'green',
` Workflow CLI v${version} `,
` Docs at ${docsUrl} `,
chalk.yellow('This is a beta release - commands might change')
`Workflow CLI v${version}`,
`Docs at ${docsUrl}`,
chalk.yellow('This is a beta release')
);

logger.debug('Inferring env vars, backend:', flags.backend);
Expand All @@ -55,9 +61,25 @@ export const setupCliWorld = async (
flags.backend === 'local' ||
flags.backend === '@workflow/world-local'
) {
await inferLocalWorldEnvVars();
try {
await inferLocalWorldEnvVars();
} catch (error) {
if (ignoreLocalWorldConfigError) {
const configError =
error instanceof Error
? error.message
: 'Unknown configuration error';
logger.warn(
'Failed to find valid local world configuration:',
configError
);
return null;
}
throw error;
}
}

logger.debug('Initializing world');
return createWorld();
const world = await createWorld();
return world;
};
5 changes: 3 additions & 2 deletions packages/cli/src/lib/inspect/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,9 @@ export async function launchWebUI(
const alreadyRunning = await isServerRunning(hostUrl);

if (alreadyRunning) {
logger.info(chalk.cyan('Web UI server is already running'));
logger.info(chalk.cyan(`Access at: ${hostUrl}`));
logger.info(
chalk.cyan(`Web UI server is already running on port ${webPort}.`)
);
} else {
// Start the server
const started = await startWebServer(webPort);
Expand Down
Loading