Skip to content

Commit 1ac8d45

Browse files
authored
feat: handle environment.json file in cn serve (#7984)
* feat: handle environment.json file in cn serve * fix: address feedback
1 parent b201072 commit 1ac8d45

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

extensions/cli/src/commands/serve.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { ChatHistoryItem } from "core/index.js";
33
import express, { Request, Response } from "express";
44

55
import { getAccessToken, getAssistantSlug } from "../auth/workos.js";
6+
import { runEnvironmentInstallSafe } from "../environment/environmentHandler.js";
67
import { processCommandFlags } from "../flags/flagProcessor.js";
78
import { toolPermissionManager } from "../permissions/permissionManager.js";
89
import {
@@ -55,6 +56,8 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
5556
const timeoutMs = timeoutSeconds * 1000;
5657
const port = parseInt(options.port || "8000", 10);
5758

59+
// Environment install script will be deferred until after server startup to avoid blocking
60+
5861
// Initialize services with tool permission overrides
5962
const { permissionOverrides } = processCommandFlags(options);
6063

@@ -348,6 +351,9 @@ export async function serve(prompt?: string, options: ServeOptions = {}) {
348351
),
349352
);
350353

354+
// Run environment install script after server startup
355+
runEnvironmentInstallSafe();
356+
351357
// If initial prompt provided, queue it for processing
352358
if (actualPrompt) {
353359
console.log(chalk.dim("\nProcessing initial prompt..."));
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { exec } from "child_process";
2+
import { existsSync, readFileSync } from "fs";
3+
import path from "path";
4+
import { promisify } from "util";
5+
6+
import chalk from "chalk";
7+
8+
const execAsync = promisify(exec);
9+
10+
import { formatError } from "../util/formatError.js";
11+
import { logger } from "../util/logger.js";
12+
13+
interface EnvironmentConfig {
14+
install?: string;
15+
}
16+
17+
const ENVIRONMENT_FILE_NAME = "environment.json";
18+
const ENVIRONMENT_SEARCH_PATHS = [".continue"];
19+
20+
/**
21+
* Finds and reads the environment.json file
22+
*/
23+
function findEnvironmentFile(): EnvironmentConfig | null {
24+
for (const searchPath of ENVIRONMENT_SEARCH_PATHS) {
25+
const environmentPath = path.join(
26+
process.cwd(),
27+
searchPath,
28+
ENVIRONMENT_FILE_NAME,
29+
);
30+
31+
if (existsSync(environmentPath)) {
32+
try {
33+
const content = readFileSync(environmentPath, "utf-8");
34+
const config = JSON.parse(content) as EnvironmentConfig;
35+
logger.debug(`Found environment.json at: ${environmentPath}`);
36+
return config;
37+
} catch (error) {
38+
logger.error(
39+
`Failed to parse environment.json at ${environmentPath}: ${formatError(error)}`,
40+
);
41+
return null;
42+
}
43+
}
44+
}
45+
46+
logger.debug("No environment.json file found");
47+
return null;
48+
}
49+
50+
/**
51+
* Runs the install script from environment.json if present
52+
* Now runs asynchronously to avoid blocking server startup
53+
*/
54+
export async function runEnvironmentInstall(): Promise<void> {
55+
const environmentConfig = findEnvironmentFile();
56+
57+
if (!environmentConfig || !environmentConfig.install) {
58+
logger.debug("No install script found in environment.json, skipping...");
59+
return;
60+
}
61+
62+
const installScript = environmentConfig.install;
63+
logger.debug(
64+
chalk.blue(
65+
`\nRunning environment install script: ${chalk.dim(installScript)}`,
66+
),
67+
);
68+
69+
try {
70+
await execAsync(installScript, {
71+
cwd: process.cwd(),
72+
encoding: "utf-8",
73+
});
74+
75+
logger.debug(
76+
chalk.green("✓ Environment install script completed successfully"),
77+
);
78+
} catch (error) {
79+
logger.error(`Environment install script failed: ${formatError(error)}`);
80+
throw new Error(
81+
`Failed to run environment install script: ${formatError(error)}`,
82+
);
83+
}
84+
}
85+
86+
/**
87+
* Runs the install script from environment.json if present, with error handling
88+
* This version doesn't throw errors to avoid blocking server startup
89+
*/
90+
export async function runEnvironmentInstallSafe(): Promise<void> {
91+
const environmentConfig = findEnvironmentFile();
92+
93+
if (!environmentConfig || !environmentConfig.install) {
94+
logger.debug("No environment install script to run");
95+
return;
96+
}
97+
98+
logger.debug(
99+
chalk.blue("Running environment install script in background..."),
100+
);
101+
102+
try {
103+
await runEnvironmentInstall();
104+
logger.debug(
105+
chalk.green("✓ Environment install script completed successfully"),
106+
);
107+
} catch (error) {
108+
logger.error(
109+
chalk.yellow("Warning: Environment install script failed:"),
110+
formatError(error),
111+
);
112+
logger.error(
113+
chalk.dim("Server will continue to run without the install script."),
114+
);
115+
}
116+
}
117+
118+
/**
119+
* Gets the environment configuration if available
120+
*/
121+
export function getEnvironmentConfig(): EnvironmentConfig | null {
122+
return findEnvironmentFile();
123+
}

0 commit comments

Comments
 (0)