diff --git a/packages/cli/src/commands/config-file.impl.ts b/packages/cli/src/commands/config-file.impl.ts index 66f81eec5..3d76b0574 100644 --- a/packages/cli/src/commands/config-file.impl.ts +++ b/packages/cli/src/commands/config-file.impl.ts @@ -135,7 +135,7 @@ function buildConfigPushSource(configFilePath: string, flags: SourceFlagOptions) repo: repository.repo, branch, commit_hash: sha, - config_file_path: configFilePath, + config_file_path: normalizeRepoRelativePath(configFilePath, "--config-file"), }; } diff --git a/packages/cli/src/commands/fix.impl.ts b/packages/cli/src/commands/fix.impl.ts index 9d5e7c208..1075e1fef 100644 --- a/packages/cli/src/commands/fix.impl.ts +++ b/packages/cli/src/commands/fix.impl.ts @@ -4,11 +4,7 @@ import { randomBytes } from "node:crypto"; import { runClaudeAgent } from "../lib/claude-agent.js"; import { CliError } from "../lib/errors.js"; import { isNonInteractiveEnv } from "../lib/interactive.js"; - -type FixOptions = { - error?: string, - yes?: boolean, -}; +import type { FixOptions } from "./fix.js"; const MAX_ERROR_LENGTH = 8000; const MAX_STDIN_BYTES = MAX_ERROR_LENGTH * 4; diff --git a/packages/cli/src/commands/fix.ts b/packages/cli/src/commands/fix.ts index 0189528f5..2aa96cc91 100644 --- a/packages/cli/src/commands/fix.ts +++ b/packages/cli/src/commands/fix.ts @@ -1,6 +1,6 @@ import { Command } from "commander"; -type FixOptions = { error?: string, yes?: boolean }; +export type FixOptions = { error?: string, yes?: boolean }; export function registerFixCommand(program: Command) { program.command("fix").description("Use an AI agent to fix a Hexclave error in your project").option("--error ", "The error message to fix (also accepts stdin)").option("-y, --yes", "Skip the confirmation prompt").action(async (opts: FixOptions) => { diff --git a/packages/cli/src/commands/init.impl.ts b/packages/cli/src/commands/init.impl.ts index b8e078fc1..66df0af28 100644 --- a/packages/cli/src/commands/init.impl.ts +++ b/packages/cli/src/commands/init.impl.ts @@ -20,7 +20,7 @@ import { isNonInteractiveEnv } from "../lib/interactive.js"; const VALID_INIT_MODES = ["create", "create-cloud", "link-config", "link-cloud"] as const; type InitMode = typeof VALID_INIT_MODES[number]; -type InitOptions = { +export type InitOptions = { mode?: InitMode, apps?: string, configFile?: string, selectProjectId?: string, outputDir?: string, agent?: boolean, displayName?: string, }; diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 61bdbca67..2450534c6 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -1,6 +1,5 @@ import { Command } from "commander"; - -type InitOptions = { mode?: "create" | "create-cloud" | "link-config" | "link-cloud", apps?: string, configFile?: string, selectProjectId?: string, outputDir?: string, agent?: boolean, displayName?: string }; +import type { InitOptions } from "./init.impl.js"; export function registerInitCommand(program: Command) { program.command("init").description("Initialize Hexclave in your project").option("--mode ", "Mode: create, create-cloud, link-config, or link-cloud (skips interactive prompts)").option("--apps ", "Comma-separated app IDs to enable (for create mode)").option("--config-file ", "Path to existing config file (for link-config mode)").option("--select-project-id ", "Project ID to link (for link-cloud mode)").option("--output-dir ", "Directory to write output files (defaults to cwd)").option("--no-agent", "Skip Claude agent and print setup instructions instead").option("--display-name ", "Project display name (used by create-cloud mode)").action(async (opts: InitOptions) => { diff --git a/packages/cli/src/commands/project.impl.ts b/packages/cli/src/commands/project.impl.ts index cadf56269..36dc7a834 100644 --- a/packages/cli/src/commands/project.impl.ts +++ b/packages/cli/src/commands/project.impl.ts @@ -21,7 +21,6 @@ export async function runList(program: Command, opts: ProjectListFlags) { export async function runCreate(program: Command, opts: { cloud?: boolean, displayName?: string }) { if (!opts.cloud) throw new CliError("hexclave project create currently only creates cloud projects. Pass --cloud to confirm."); - const [{ getInternalUser }, { resolveLoginConfig, resolveSessionAuth }, { createProjectInteractively }] = await Promise.all([import("../lib/app.js"), import("../lib/auth.js"), import("../lib/create-project.js")]); const auth = resolveSessionAuth(); const user = await getInternalUser(auth); const { dashboardUrl } = resolveLoginConfig(); diff --git a/packages/cli/src/lib/sentry.ts b/packages/cli/src/lib/sentry.ts index 1b9039d8b..8602189c4 100644 --- a/packages/cli/src/lib/sentry.ts +++ b/packages/cli/src/lib/sentry.ts @@ -64,14 +64,20 @@ async function initializeSentry(): Promise { } export function initSentry(): void { - registrationPromise ??= import("@hexclave/shared/dist/utils/errors").then(({ registerErrorSink }) => registerErrorSink((location, error, level) => { - capturePromise = (async () => { - await initializeSentry(); - const Sentry = await loadSentry(); - Sentry.captureException(error, { extra: { location }, level }); - await Sentry.flush(2000); - })(); - })); + registrationPromise ??= import("@hexclave/shared/dist/utils/errors") + .then(({ registerErrorSink }) => registerErrorSink((location, error, level) => { + capturePromise = (async () => { + await initializeSentry(); + const Sentry = await loadSentry(); + Sentry.captureException(error, { extra: { location }, level }); + await Sentry.flush(2000); + })().catch(() => { + // Optional telemetry failures must not create unhandled rejections or affect CLI errors. + }); + })) + .catch(() => { + // Optional telemetry registration failures must not create unhandled rejections or affect CLI errors. + }); } export async function captureFatalError(location: string, error: unknown, timeoutMs = 2000): Promise {