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
4 changes: 2 additions & 2 deletions jest.components.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ export default {
global: {
branches: 20,
functions: 20,
lines: 30,
statements: 30,
lines: 29,
statements: 29,
},
},

Expand Down
4 changes: 2 additions & 2 deletions src/commands/agent/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { output, outputError } from "../../utils/output.js";

interface CreateOptions {
name: string;
agentVersion: string;
agentVersion?: string;
source: string;
package?: string;
registryUrl?: string;
Expand Down Expand Up @@ -103,7 +103,7 @@ export async function createAgentCommand(

const agent = await createAgent({
name: options.name,
version: options.agentVersion,
...(options.agentVersion ? { version: options.agentVersion } : {}),
source: { type: sourceType, [sourceType]: sourceOptions },
});

Expand Down
17 changes: 12 additions & 5 deletions src/commands/agent/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,18 @@
{
header: "VERSION",
raw: (a) => {
if (a.source?.type === "object") return "-";
const v = a.version || a.source?.git?.ref || "";
if (!v) return "-";
const pkg = a.source?.npm?.package_name || a.source?.pip?.package_name;
return pkg ? `${pkg}@${a.version}` : a.version;
return pkg ? `${pkg}@${v}` : v;
},
styled(a) {
if (a.source?.type === "object") return "-";
const v = a.version || a.source?.git?.ref || "";
if (!v) return "-";
const pkg = a.source?.npm?.package_name || a.source?.pip?.package_name;
return pkg ? chalk.dim(pkg + "@") + a.version : a.version;
return pkg ? chalk.dim(pkg + "@") + v : v;
},
},
{
Expand Down Expand Up @@ -150,7 +156,7 @@
);
}

function printTable(agents: Agent[], isPublic: boolean): void {

Check warning on line 159 in src/commands/agent/list.tsx

View workflow job for this annotation

GitHub Actions / lint

'printTable' is defined but never used. Allowed unused vars must match /^_/u
if (isPublic) {
console.log(
chalk.dim("Showing PUBLIC agents. Use --private to see private agents"),
Expand Down Expand Up @@ -325,8 +331,9 @@
"version",
"Version",
(a: Agent) => {
if (a.source?.type === "object") return "";
const v = a.version || "";
if (a.source?.type === "object") return "-";
const v = a.version || a.source?.git?.ref || "";
if (!v) return "-";
if (v.length > 16) return `${v.slice(0, 8)}…${v.slice(-4)}`;
return v;
},
Expand Down Expand Up @@ -734,7 +741,7 @@
{showPopup && selectedAgentItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedAgentItem}
devbox={selectedAgentItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/axon/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

const CLI_PAGE_SIZE = 100;

function printTable(axons: Axon[]): void {

Check warning on line 37 in src/commands/axon/list.tsx

View workflow job for this annotation

GitHub Actions / lint

'printTable' is defined but never used. Allowed unused vars must match /^_/u
if (axons.length === 0) {
console.log(chalk.dim("No active axons found"));
return;
Expand Down Expand Up @@ -188,7 +188,7 @@
totalCount,
nextPage,
prevPage,
refresh,

Check warning on line 191 in src/commands/axon/list.tsx

View workflow job for this annotation

GitHub Actions / lint

'refresh' is assigned a value but never used. Allowed unused vars must match /^_/u
} = useCursorPagination({
fetchPage,
pageSize: PAGE_SIZE,
Expand Down Expand Up @@ -454,7 +454,7 @@
{showPopup && selectedAxonItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedAxonItem}
devbox={selectedAxonItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/blueprint/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ const ListBlueprintsUI = ({
{showPopup && selectedBlueprintItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedBlueprintItem}
devbox={selectedBlueprintItem}
operations={allOperations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
117 changes: 98 additions & 19 deletions src/commands/devbox/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import {
getAgent,
type Agent,
} from "../../services/agentService.js";
import { getObject } from "../../services/objectService.js";
import {
DEFAULT_MOUNT_PATH,
sanitizeMountSegment,
adjustFileExtension,
getDefaultAgentMountPath,
} from "../../utils/mount.js";

interface CreateOptions {
name?: string;
Expand All @@ -32,7 +39,7 @@ interface CreateOptions {
gateways?: string[];
mcp?: string[];
agent?: string[];
agentPath?: string;
object?: string[];
output?: string;
}

Expand Down Expand Up @@ -293,28 +300,100 @@ export async function createDevbox(options: CreateOptions = {}) {
createRequest.mcp = parseMcpSpecs(options.mcp);
}

// Handle agent mount
// Parse agent mounts (format: name_or_id or name_or_id:/mount/path)
const resolvedAgents: { agent: Agent; path?: string }[] = [];
if (options.agent && options.agent.length > 0) {
if (options.agent.length > 1) {
throw new Error(
"Mounting multiple agents via rli is not supported yet",
);
const parsedAgentSpecs: { idOrName: string; path?: string }[] = [];
for (const spec of options.agent) {
const colonIdx = spec.indexOf(":");
// Only treat colon as separator if what follows looks like an absolute path
if (colonIdx > 0 && spec[colonIdx + 1] === "/") {
parsedAgentSpecs.push({
idOrName: spec.substring(0, colonIdx),
path: spec.substring(colonIdx + 1),
});
} else {
parsedAgentSpecs.push({ idOrName: spec });
}
}
const agent = await resolveAgent(options.agent[0]);
const mount: Record<string, unknown> = {
type: "agent_mount",
agent_id: agent.id,
agent_name: null,
};
// agent_path only makes sense for git and object agents. Since
// we don't know at this stage what type of agent it is,
// however, we'll let the server error inform the user if they
// add this option in a case where it doesn't make sense.
if (options.agentPath) {
mount.agent_path = options.agentPath;
const resolved = await Promise.all(
parsedAgentSpecs.map(async ({ idOrName, path }) => ({
agent: await resolveAgent(idOrName),
path,
})),
);
resolvedAgents.push(...resolved);
}

// Parse object mounts (format: object_id or object_id:/mount/path)
const objectMounts: { object_id: string; object_path: string }[] = [];
if (options.object && options.object.length > 0) {
const parsedObjectSpecs: {
objectId: string;
explicitPath?: string;
}[] = [];
for (const spec of options.object) {
const colonIdx = spec.indexOf(":");
if (colonIdx > 0 && spec[colonIdx + 1] === "/") {
parsedObjectSpecs.push({
objectId: spec.substring(0, colonIdx),
explicitPath: spec.substring(colonIdx + 1),
});
} else {
parsedObjectSpecs.push({ objectId: spec });
}
}
const resolved = await Promise.all(
parsedObjectSpecs.map(async ({ objectId, explicitPath }) => {
if (explicitPath) {
return { object_id: objectId, object_path: explicitPath };
}
// No path specified — fetch object to generate default
const obj = await getObject(objectId);
const name = obj.name;
const contentType = obj.content_type;
if (name) {
const adjusted = adjustFileExtension(name, contentType);
const s = sanitizeMountSegment(adjusted);
const objectPath = s
? `${DEFAULT_MOUNT_PATH}/${s}`
: `${DEFAULT_MOUNT_PATH}/object_${objectId.slice(-8)}`;
return { object_id: objectId, object_path: objectPath };
}
return {
object_id: objectId,
object_path: `${DEFAULT_MOUNT_PATH}/object_${objectId.slice(-8)}`,
};
}),
);
objectMounts.push(...resolved);
}

// Add mounts (agents + objects)
if (resolvedAgents.length > 0 || objectMounts.length > 0) {
if (!createRequest.mounts) createRequest.mounts = [];
(createRequest.mounts as unknown[]).push(mount);
for (const { agent, path } of resolvedAgents) {
const mount: Record<string, unknown> = {
type: "agent_mount",
agent_id: agent.id,
agent_name: null,
};
const sourceType = agent.source?.type;
const needsPath = sourceType === "git" || sourceType === "object";
const effectivePath =
path || (needsPath ? getDefaultAgentMountPath(agent) : undefined);
if (effectivePath) {
mount.agent_path = effectivePath;
}
(createRequest.mounts as unknown[]).push(mount);
}
for (const om of objectMounts) {
(createRequest.mounts as unknown[]).push({
type: "object_mount",
object_id: om.object_id,
object_path: om.object_path,
});
}
}

if (Object.keys(launchParameters).length > 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/commands/devbox/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,7 @@ const ListDevboxesUI = ({
{showPopup && selectedDevbox && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedDevbox}
devbox={selectedDevbox}
operations={operations}
selectedOperation={selectedOperation}
onClose={() => setShowPopup(false)}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/gateway-config/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ const ListGatewayConfigsUI = ({
{showPopup && selectedConfigItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedConfigItem}
devbox={selectedConfigItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/mcp-config/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -664,7 +664,7 @@ const ListMcpConfigsUI = ({
{showPopup && selectedConfigItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedConfigItem}
devbox={selectedConfigItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/network-policy/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,7 @@ const ListNetworkPoliciesUI = ({
{showPopup && selectedPolicyItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedPolicyItem}
devbox={selectedPolicyItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/object/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ const ListObjectsUI = ({
{showPopup && selectedObjectItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedObjectItem}
devbox={selectedObjectItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/secret/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ const ListSecretsUI = ({
{showPopup && selectedSecretItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedSecretItem}
devbox={selectedSecretItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/snapshot/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ const ListSnapshotsUI = ({
{showPopup && selectedSnapshotItem && (
<Box marginTop={2} justifyContent="center">
<ActionsPopup
resource={selectedSnapshotItem}
devbox={selectedSnapshotItem}
operations={operations.map((op) => ({
key: op.key,
label: op.label,
Expand Down
4 changes: 2 additions & 2 deletions src/components/ActionsPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface ResourceWithId {
}

interface ActionsPopupProps {
resource: ResourceWithId;
devbox: ResourceWithId;
operations: Array<{
key: string;
label: string;
Expand All @@ -24,7 +24,7 @@ interface ActionsPopupProps {
}

export const ActionsPopup = ({
resource: _resource,
devbox: _devbox,
operations,
selectedOperation,
onClose: _onClose,
Expand Down
Loading
Loading