Skip to content
Open
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
35 changes: 1 addition & 34 deletions src/commands/benchmark-job/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "../../services/benchmarkService.js";
import { getClient } from "../../utils/client.js";
import { output, outputError } from "../../utils/output.js";
import { parseEnvVars, parseSecrets } from "../../utils/parse.js";

// Secret name prefix for benchmark job secrets
const SECRET_PREFIX = "BMJ_";
Expand Down Expand Up @@ -100,40 +101,6 @@ function parseAgentStrings(agentStrings: string[] | undefined): ParsedAgent[] {
return agents;
}

// Parse environment variables from KEY=value format
function parseEnvVars(envVars: string[]): Record<string, string> {
const result: Record<string, string> = {};
for (const envVar of envVars) {
const eqIndex = envVar.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid environment variable format: ${envVar}. Expected KEY=value`,
);
}
const key = envVar.substring(0, eqIndex);
const value = envVar.substring(eqIndex + 1);
result[key] = value;
}
return result;
}

// Parse secrets from ENV_VAR=SECRET_NAME format
function parseSecrets(secrets: string[]): Record<string, string> {
const result: Record<string, string> = {};
for (const secret of secrets) {
const eqIndex = secret.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid secret format: ${secret}. Expected ENV_VAR=SECRET_NAME`,
);
}
const envVarName = secret.substring(0, eqIndex);
const secretName = secret.substring(eqIndex + 1);
result[envVarName] = secretName;
}
return result;
}

// Validate agent is supported
function validateAgent(agent: string): asserts agent is SupportedAgent {
if (!(agent in SUPPORTED_AGENTS)) {
Expand Down
64 changes: 14 additions & 50 deletions src/commands/blueprint/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,63 +9,27 @@ import type {
} from "@runloop/api-client/resources/blueprints";
import { getClient } from "../../utils/client.js";
import { output, outputError } from "../../utils/output.js";
import {
formatTimestamp,
getLogLevelInfo,
} from "../../utils/logFormatter.js";

interface BlueprintLogsOptions {
id: string;
output?: string;
}

function formatLogLevel(level: string): string {
const normalized = level.toUpperCase();
switch (normalized) {
case "ERROR":
case "ERR":
return chalk.red.bold("ERROR");
case "WARN":
case "WARNING":
return chalk.yellow.bold("WARN ");
case "INFO":
return chalk.blue("INFO ");
case "DEBUG":
return chalk.gray("DEBUG");
const { name, color } = getLogLevelInfo(level);
switch (color) {
case "red":
return chalk.red.bold(name);
case "yellow":
return chalk.yellow.bold(name);
case "blue":
return chalk.blue(name);
default:
return chalk.gray(normalized.padEnd(5));
}
}

function formatTimestamp(timestampMs: number): string {
const date = new Date(timestampMs);
const now = new Date();

const isToday = date.toDateString() === now.toDateString();
const isThisYear = date.getFullYear() === now.getFullYear();

const time = date.toLocaleTimeString("en-US", {
hour12: false,
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
const ms = date.getMilliseconds().toString().padStart(3, "0");

if (isToday) {
// Today: show time with milliseconds for fine granularity
return chalk.dim(`${time}.${ms}`);
} else if (isThisYear) {
// This year: show "Jan 5 15:44:03"
const monthDay = date.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
});
return chalk.dim(`${monthDay} ${time}`);
} else {
// Older: show "Jan 5, 2024 15:44:03"
const fullDate = date.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
return chalk.dim(`${fullDate} ${time}`);
return chalk.gray(name);
}
}

Expand Down Expand Up @@ -107,7 +71,7 @@ function formatLogEntry(log: BlueprintBuildLog): string {
const parts: string[] = [];

// Timestamp
parts.push(formatTimestamp(log.timestamp_ms));
parts.push(chalk.dim(formatTimestamp(log.timestamp_ms)));

// Level
parts.push(formatLogLevel(log.level));
Expand Down
35 changes: 1 addition & 34 deletions src/commands/devbox/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import { getClient } from "../../utils/client.js";
import { output, outputError } from "../../utils/output.js";
import { parseEnvVars, parseSecrets } from "../../utils/parse.js";

interface CreateOptions {
name?: string;
Expand All @@ -29,40 +30,6 @@ interface CreateOptions {
output?: string;
}

// Parse environment variables from KEY=value format
function parseEnvVars(envVars: string[]): Record<string, string> {
const result: Record<string, string> = {};
for (const envVar of envVars) {
const eqIndex = envVar.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid environment variable format: ${envVar}. Expected KEY=value`,
);
}
const key = envVar.substring(0, eqIndex);
const value = envVar.substring(eqIndex + 1);
result[key] = value;
}
return result;
}

// Parse secrets from ENV_VAR=SECRET_NAME format
function parseSecrets(secrets: string[]): Record<string, string> {
const result: Record<string, string> = {};
for (const secret of secrets) {
const eqIndex = secret.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid secret format: ${secret}. Expected ENV_VAR=SECRET_NAME`,
);
}
const envVarName = secret.substring(0, eqIndex);
const secretName = secret.substring(eqIndex + 1);
result[envVarName] = secretName;
}
return result;
}

// Parse code mounts from JSON format
function parseCodeMounts(codeMounts: string[]): unknown[] {
return codeMounts.map((mount) => {
Expand Down
37 changes: 37 additions & 0 deletions src/utils/parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Parse KEY=value format strings into a Record
*/
export function parseEnvVars(envVars: string[]): Record<string, string> {
const result: Record<string, string> = {};
for (const envVar of envVars) {
const eqIndex = envVar.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid environment variable format: ${envVar}. Expected KEY=value`,
);
}
const key = envVar.substring(0, eqIndex);
const value = envVar.substring(eqIndex + 1);
result[key] = value;
}
return result;
}

/**
* Parse ENV_VAR=SECRET_NAME format strings into a Record
*/
export function parseSecrets(secrets: string[]): Record<string, string> {
const result: Record<string, string> = {};
for (const secret of secrets) {
const eqIndex = secret.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid secret format: ${secret}. Expected ENV_VAR=SECRET_NAME`,
);
}
const envVarName = secret.substring(0, eqIndex);
const secretName = secret.substring(eqIndex + 1);
result[envVarName] = secretName;
}
return result;
}
Loading