fix: bound AgentRun AipodSpec describe output
This commit is contained in:
@@ -374,6 +374,187 @@ describe("AgentRun default transport contract", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test("aipodspec describe is bounded and homologous while full and raw stay complete", async () => {
|
||||
const aipodName = "Artificer";
|
||||
const hiddenCredential = "HIDDEN_AIPOD_CREDENTIAL_VALUE_MUST_NOT_BE_PRINTED";
|
||||
const providerCredential = {
|
||||
profile: "sub2api",
|
||||
name: "agentrun-provider",
|
||||
namespace: null,
|
||||
keys: ["auth.json", "config.toml"],
|
||||
value: hiddenCredential,
|
||||
valuesPrinted: false,
|
||||
};
|
||||
const toolCredentials = [
|
||||
{
|
||||
tool: "github",
|
||||
purpose: "github-pr",
|
||||
name: "agentrun-github",
|
||||
namespace: null,
|
||||
keys: ["GH_TOKEN"],
|
||||
projection: { kind: "env", envName: "GH_TOKEN", secretKey: "GH_TOKEN", value: hiddenCredential },
|
||||
token: hiddenCredential,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
{
|
||||
tool: "ssh",
|
||||
purpose: "remote-workspace",
|
||||
name: "agentrun-ssh",
|
||||
namespace: null,
|
||||
keys: ["config", "key"],
|
||||
projection: { kind: "mount", mountPath: "/run/secrets/ssh", value: hiddenCredential },
|
||||
valuesPrinted: false,
|
||||
},
|
||||
{
|
||||
tool: "provider",
|
||||
purpose: "model-auth",
|
||||
name: "agentrun-provider",
|
||||
namespace: null,
|
||||
keys: ["auth.json"],
|
||||
projection: { kind: "mount", mountPath: "/run/secrets/provider", value: hiddenCredential },
|
||||
valuesPrinted: false,
|
||||
},
|
||||
];
|
||||
const data = {
|
||||
action: "show",
|
||||
item: {
|
||||
name: aipodName,
|
||||
displayName: "Artificer",
|
||||
description: "x".repeat(20_000),
|
||||
specHash: "sha256:aipod-fixture",
|
||||
source: "config/aipods/artificer.yaml",
|
||||
backendProfile: "sub2api",
|
||||
model: { model: "gpt-5.5", reasoningEffort: "high" },
|
||||
imageRef: {
|
||||
kind: "env-image-dockerfile",
|
||||
repoUrl: "https://github.com/pikasTech/agentrun.git",
|
||||
commitId: "a".repeat(40),
|
||||
dockerfilePath: "deploy/container/Containerfile",
|
||||
sourceIdentity: "agentrun@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
valuesPrinted: false,
|
||||
},
|
||||
queue: "commander",
|
||||
lane: "v0.1",
|
||||
providerId: "NC01",
|
||||
providerCredentials: { count: 1, profiles: ["sub2api"], items: [providerCredential], valuesPrinted: false },
|
||||
toolCredentials: { count: 3, tools: ["github", "ssh", "provider"], items: toolCredentials, valuesPrinted: false },
|
||||
resourceBundleRef: {
|
||||
kind: "gitbundle",
|
||||
repoUrl: `https://fixture:${hiddenCredential}@github.com/pikasTech/unidesk.git`,
|
||||
ref: "master",
|
||||
commitId: null,
|
||||
bundles: { count: 6, items: [{ name: "unidesk-skills", targetPath: ".agents/skills" }], valuesPrinted: false },
|
||||
requiredSkills: { count: 11, names: ["unidesk-gh"], valuesPrinted: false },
|
||||
promptRefs: { count: 0, names: [], valuesPrinted: false },
|
||||
valuesPrinted: false,
|
||||
},
|
||||
createdAt: "2026-07-12T00:00:00.000Z",
|
||||
updatedAt: "2026-07-12T01:00:00.000Z",
|
||||
valuesPrinted: false,
|
||||
},
|
||||
spec: {
|
||||
apiVersion: "agentrun.pikastech.local/v1alpha1",
|
||||
kind: "AipodSpec",
|
||||
metadata: { name: aipodName, displayName: "Artificer", description: "x".repeat(20_000) },
|
||||
spec: {
|
||||
queue: "commander",
|
||||
lane: "v0.1",
|
||||
providerId: "NC01",
|
||||
backendProfile: "sub2api",
|
||||
model: { model: "gpt-5.5", reasoningEffort: "high" },
|
||||
workspaceRef: { kind: "opaque", path: "." },
|
||||
executionPolicy: {
|
||||
secretScope: {
|
||||
allowCredentialEcho: false,
|
||||
providerCredentials: [{ profile: "sub2api", secretRef: { name: "agentrun-provider", keys: ["auth.json"], value: hiddenCredential } }],
|
||||
toolCredentials: [{ tool: "github", secretRef: { name: "agentrun-github", keys: ["GH_TOKEN"], token: hiddenCredential } }],
|
||||
},
|
||||
},
|
||||
resourceBundleRef: {
|
||||
kind: "gitbundle",
|
||||
repoUrl: `https://fixture:${hiddenCredential}@github.com/pikasTech/unidesk.git`,
|
||||
ref: "master",
|
||||
bundles: [{ name: "unidesk-skills", subpath: ".agents/skills", targetPath: ".agents/skills" }],
|
||||
requiredSkills: [{ name: "unidesk-gh" }],
|
||||
},
|
||||
metadata: { aipod: aipodName, source: "config/aipods/artificer.yaml" },
|
||||
},
|
||||
},
|
||||
valuesPrinted: false,
|
||||
};
|
||||
let requests = 0;
|
||||
const server = Bun.serve({
|
||||
port: 0,
|
||||
fetch(request) {
|
||||
const url = new URL(request.url);
|
||||
expect(request.headers.get("authorization")).toBe("Bearer secret-value");
|
||||
expect(url.pathname).toBe(`/api/v1/aipod-specs/${aipodName}`);
|
||||
requests += 1;
|
||||
return Response.json({ ok: true, data });
|
||||
},
|
||||
});
|
||||
const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG;
|
||||
const previousKey = process.env.HWLAB_API_KEY;
|
||||
process.env.HWLAB_API_KEY = "secret-value";
|
||||
const tempConfigPath = `/tmp/unidesk-agentrun-aipodspec-test-${process.pid}-${Date.now()}.yaml`;
|
||||
try {
|
||||
process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath;
|
||||
await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, "")));
|
||||
|
||||
const text = renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`]));
|
||||
expect(text).toContain(`Name: aipodspec/${aipodName}`);
|
||||
expect(text).toContain("Hash: sha256:aipod-fixture");
|
||||
expect(text).toContain("Kind: opaque path=. branch=-");
|
||||
expect(text).toContain("References: bundles=6 requiredSkills=11 promptRefs=0");
|
||||
expect(text).toContain("Credentials: provider=1 tool=3 total=4");
|
||||
expect(text).toContain("secret=agentrun-provider keys=auth.json,config.toml");
|
||||
expect(text).toContain(`agentrun describe aipodspec/${aipodName} --full -o json`);
|
||||
expect(Buffer.byteLength(text, "utf8")).toBeLessThan(10_240);
|
||||
expect(text).not.toContain(hiddenCredential);
|
||||
|
||||
const jsonText = renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "-o", "json"]));
|
||||
const json = JSON.parse(jsonText) as Record<string, any>;
|
||||
const yamlText = renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "-o", "yaml"]));
|
||||
const yaml = Bun.YAML.parse(yamlText) as Record<string, any>;
|
||||
expect(yaml).toEqual(json);
|
||||
expect(json.kind).toBe("AipodSpec");
|
||||
expect(json.identity.specHash).toBe("sha256:aipod-fixture");
|
||||
expect(json.runtime).toMatchObject({ lane: "v0.1", backendProfile: "sub2api", providerId: "NC01" });
|
||||
expect(json.workspaceRef).toMatchObject({ kind: "opaque", path: ".", valuesPrinted: false });
|
||||
expect(json.resourceBundleRef.sourceIdentity.repoUrl).toBe("https://github.com/pikasTech/unidesk.git");
|
||||
expect(json.resourceBundleRef).toMatchObject({ bundleCount: 6, requiredSkillCount: 11, promptRefCount: 0 });
|
||||
expect(json.credentialRefs).toMatchObject({ totalCount: 4, valuesPrinted: false });
|
||||
expect(json.credentialRefs.provider.items[0].secretRef).toEqual({
|
||||
namespace: null,
|
||||
name: "agentrun-provider",
|
||||
keys: ["auth.json", "config.toml"],
|
||||
valuesPrinted: false,
|
||||
});
|
||||
expect(json.redaction).toEqual({ credentialValues: "omitted", secretRefsOnly: true, valuesPrinted: false });
|
||||
expect(json.valuesPrinted).toBe(false);
|
||||
for (const bounded of [jsonText, yamlText]) {
|
||||
expect(Buffer.byteLength(bounded, "utf8")).toBeLessThan(10_240);
|
||||
expect(bounded).not.toContain(hiddenCredential);
|
||||
expect(bounded).not.toContain("x".repeat(200));
|
||||
}
|
||||
|
||||
const full = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "--full", "-o", "json"]))) as { resource?: typeof data };
|
||||
expect(full.resource?.item.description).toBe("x".repeat(20_000));
|
||||
expect(full.resource?.spec.kind).toBe("AipodSpec");
|
||||
const raw = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "--raw"]))) as { data?: typeof data };
|
||||
expect(raw.data?.item.description).toBe("x".repeat(20_000));
|
||||
expect(raw.data?.spec.kind).toBe("AipodSpec");
|
||||
expect(requests).toBe(5);
|
||||
} finally {
|
||||
server.stop(true);
|
||||
if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG;
|
||||
else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig;
|
||||
if (previousKey === undefined) delete process.env.HWLAB_API_KEY;
|
||||
else process.env.HWLAB_API_KEY = previousKey;
|
||||
rmSync(tempConfigPath, { force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("retry dry-run is server-validated and attempts use the formal resource API", async () => {
|
||||
const taskId = "qt_failed_1";
|
||||
const attempt = {
|
||||
|
||||
@@ -1387,6 +1387,252 @@ export function compactTaskDescriptionPayload(ref: AgentRunResourceRef, task: Re
|
||||
};
|
||||
}
|
||||
|
||||
export function compactAipodSpecDescriptionPayload(ref: AgentRunResourceRef, data: unknown): Record<string, unknown> {
|
||||
const root = record(data);
|
||||
const describedItem = record(root.item);
|
||||
const item = Object.keys(describedItem).length > 0 ? describedItem : root;
|
||||
const manifest = record(root.spec);
|
||||
const manifestMetadata = record(manifest.metadata);
|
||||
const manifestSpec = record(manifest.spec);
|
||||
const manifestAipodMetadata = record(manifestSpec.metadata);
|
||||
const model = firstNonEmptyRecord(item.model, manifestSpec.model);
|
||||
const workspaceRef = compactAipodSpecWorkspaceRef(firstNonEmptyRecord(item.workspaceRef, manifestSpec.workspaceRef));
|
||||
const resourceBundleRef = compactAipodSpecResourceBundleRef(item.resourceBundleRef, manifestSpec.resourceBundleRef);
|
||||
const secretScope = record(record(manifestSpec.executionPolicy).secretScope);
|
||||
const providerCredentialRefs = compactAipodSpecCredentialRefs(item.providerCredentials, secretScope.providerCredentials, "provider");
|
||||
const toolCredentialRefs = compactAipodSpecCredentialRefs(item.toolCredentials, secretScope.toolCredentials, "tool");
|
||||
const imageRef = firstNonEmptyRecord(item.imageRef, manifestSpec.imageRef);
|
||||
return {
|
||||
kind: "AipodSpec",
|
||||
name: ref.name,
|
||||
state: boundedAipodSpecText(item.state ?? item.status ?? "available", 80),
|
||||
identity: {
|
||||
declaredName: boundedAipodSpecText(item.name ?? manifestMetadata.name ?? ref.name, 160),
|
||||
displayName: boundedAipodSpecText(item.displayName ?? manifestMetadata.displayName, 200),
|
||||
specHash: boundedAipodSpecText(item.specHash, 160),
|
||||
valuesPrinted: false,
|
||||
},
|
||||
runtime: {
|
||||
queue: boundedAipodSpecText(item.queue ?? manifestSpec.queue, 120),
|
||||
lane: boundedAipodSpecText(item.lane ?? manifestSpec.lane, 120),
|
||||
backendProfile: boundedAipodSpecText(item.backendProfile ?? item.profile ?? manifestSpec.backendProfile, 160),
|
||||
providerId: boundedAipodSpecText(item.providerId ?? manifestSpec.providerId, 160),
|
||||
model: {
|
||||
name: boundedAipodSpecText(model.model, 200),
|
||||
reasoningEffort: boundedAipodSpecText(model.reasoningEffort, 80),
|
||||
valuesPrinted: false,
|
||||
},
|
||||
valuesPrinted: false,
|
||||
},
|
||||
workspaceRef,
|
||||
resourceBundleRef,
|
||||
credentialRefs: {
|
||||
totalCount: providerCredentialRefs.count + toolCredentialRefs.count,
|
||||
provider: providerCredentialRefs,
|
||||
tool: toolCredentialRefs,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
provenance: {
|
||||
source: boundedAipodSpecText(item.source ?? manifestAipodMetadata.source, 320),
|
||||
apiVersion: boundedAipodSpecText(manifest.apiVersion, 120),
|
||||
sourceKind: boundedAipodSpecText(manifest.kind, 120),
|
||||
imageSourceIdentity: boundedAipodSpecText(imageRef.sourceIdentity, 320),
|
||||
createdAt: boundedAipodSpecText(item.createdAt, 120),
|
||||
updatedAt: boundedAipodSpecText(item.updatedAt, 120),
|
||||
valuesPrinted: false,
|
||||
},
|
||||
redaction: {
|
||||
credentialValues: "omitted",
|
||||
secretRefsOnly: true,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
next: {
|
||||
full: `bun scripts/cli.ts agentrun describe aipodspec/${ref.name} --full -o json`,
|
||||
raw: `bun scripts/cli.ts agentrun describe aipodspec/${ref.name} --raw`,
|
||||
},
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
export function renderAipodSpecDescription(payload: Record<string, unknown>): string {
|
||||
const identity = record(payload.identity);
|
||||
const runtime = record(payload.runtime);
|
||||
const model = record(runtime.model);
|
||||
const workspaceRef = record(payload.workspaceRef);
|
||||
const resourceBundleRef = record(payload.resourceBundleRef);
|
||||
const sourceIdentity = record(resourceBundleRef.sourceIdentity);
|
||||
const credentialRefs = record(payload.credentialRefs);
|
||||
const providerCredentialRefs = record(credentialRefs.provider);
|
||||
const toolCredentialRefs = record(credentialRefs.tool);
|
||||
const provenance = record(payload.provenance);
|
||||
const next = record(payload.next);
|
||||
const lines = [
|
||||
`Name: aipodspec/${displayValue(payload.name)}`,
|
||||
`State: ${displayValue(payload.state)}`,
|
||||
"",
|
||||
"Identity:",
|
||||
` Declared: ${displayValue(identity.declaredName)}`,
|
||||
` Display: ${displayValue(identity.displayName)}`,
|
||||
` Hash: ${displayValue(identity.specHash)}`,
|
||||
"",
|
||||
"Runtime:",
|
||||
` Queue: ${displayValue(runtime.queue)}`,
|
||||
` Lane: ${displayValue(runtime.lane)}`,
|
||||
` Profile: ${displayValue(runtime.backendProfile)}`,
|
||||
` Provider: ${displayValue(runtime.providerId)}`,
|
||||
` Model: ${displayValue(model.name)} reasoning=${displayValue(model.reasoningEffort)}`,
|
||||
"",
|
||||
"Workspace:",
|
||||
` Kind: ${displayValue(workspaceRef.kind)} path=${displayValue(workspaceRef.path)} branch=${displayValue(workspaceRef.branch)}`,
|
||||
"",
|
||||
"Primary resource bundle:",
|
||||
` Source: kind=${displayValue(sourceIdentity.kind)} repo=${displayValue(sourceIdentity.repoUrl)} ref=${displayValue(sourceIdentity.ref)} commit=${displayValue(sourceIdentity.commitId)}`,
|
||||
` References: bundles=${displayValue(resourceBundleRef.bundleCount)} requiredSkills=${displayValue(resourceBundleRef.requiredSkillCount)} promptRefs=${displayValue(resourceBundleRef.promptRefCount)}`,
|
||||
` Credentials: provider=${displayValue(providerCredentialRefs.count)} tool=${displayValue(toolCredentialRefs.count)} total=${displayValue(credentialRefs.totalCount)}`,
|
||||
];
|
||||
const credentialLines = [
|
||||
...renderAipodSpecCredentialRefLines(arrayRecords(providerCredentialRefs.items), "provider"),
|
||||
...renderAipodSpecCredentialRefLines(arrayRecords(toolCredentialRefs.items), "tool"),
|
||||
];
|
||||
if (credentialLines.length > 0) lines.push("", "SecretRefs:", ...credentialLines.map((line) => ` ${line}`));
|
||||
lines.push(
|
||||
"",
|
||||
"Provenance:",
|
||||
` Source: ${displayValue(provenance.source)}`,
|
||||
` Manifest: ${displayValue(provenance.apiVersion)} ${displayValue(provenance.sourceKind)}`,
|
||||
` Image source: ${displayValue(provenance.imageSourceIdentity)}`,
|
||||
` Updated: ${displayValue(provenance.updatedAt)}`,
|
||||
" Values printed: false",
|
||||
"",
|
||||
"Next:",
|
||||
` ${displayValue(next.full)}`,
|
||||
` ${displayValue(next.raw)}`,
|
||||
);
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function compactAipodSpecWorkspaceRef(value: Record<string, unknown>): Record<string, unknown> | null {
|
||||
if (Object.keys(value).length === 0) return null;
|
||||
return {
|
||||
kind: boundedAipodSpecText(value.kind, 80),
|
||||
path: boundedAipodSpecText(value.path, 320),
|
||||
branch: boundedAipodSpecText(value.branch, 160),
|
||||
repo: boundedAipodSpecRepoUrl(value.repo ?? value.repoUrl),
|
||||
commitId: boundedAipodSpecText(value.commitId, 160),
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function compactAipodSpecResourceBundleRef(primaryValue: unknown, fallbackValue: unknown): Record<string, unknown> | null {
|
||||
const value = firstNonEmptyRecord(primaryValue, fallbackValue);
|
||||
if (Object.keys(value).length === 0) return null;
|
||||
return {
|
||||
sourceIdentity: {
|
||||
kind: boundedAipodSpecText(value.kind, 80),
|
||||
repoUrl: boundedAipodSpecRepoUrl(value.repoUrl),
|
||||
ref: boundedAipodSpecText(value.ref, 160),
|
||||
commitId: boundedAipodSpecText(value.commitId, 160),
|
||||
valuesPrinted: false,
|
||||
},
|
||||
bundleCount: aipodSpecReferenceCount(value.bundles),
|
||||
requiredSkillCount: aipodSpecReferenceCount(value.requiredSkills),
|
||||
promptRefCount: aipodSpecReferenceCount(value.promptRefs),
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function compactAipodSpecCredentialRefs(primaryValue: unknown, fallbackValue: unknown, kind: "provider" | "tool"): { count: number; items: Record<string, unknown>[]; omittedCount: number; valuesPrinted: false } {
|
||||
const primary = record(primaryValue);
|
||||
const primaryItems = arrayRecords(primary.items ?? primaryValue);
|
||||
const fallbackItems = arrayRecords(fallbackValue);
|
||||
const sourceItems = primaryItems.length > 0 ? primaryItems : fallbackItems;
|
||||
const count = Object.keys(primary).length > 0 ? aipodSpecReferenceCount(primaryValue) : sourceItems.length;
|
||||
const items = sourceItems.slice(0, 6).map((item) => {
|
||||
const nestedSecretRef = record(item.secretRef);
|
||||
const projection = record(item.projection);
|
||||
return {
|
||||
...(kind === "provider"
|
||||
? { profile: boundedAipodSpecText(item.profile, 160) }
|
||||
: {
|
||||
tool: boundedAipodSpecText(item.tool, 160),
|
||||
purpose: boundedAipodSpecText(item.purpose, 200),
|
||||
}),
|
||||
secretRef: {
|
||||
namespace: boundedAipodSpecText(item.namespace ?? nestedSecretRef.namespace, 160),
|
||||
name: boundedAipodSpecText(item.name ?? nestedSecretRef.name, 200),
|
||||
keys: boundedAipodSpecStrings(item.keys ?? nestedSecretRef.keys, 6, 80),
|
||||
valuesPrinted: false,
|
||||
},
|
||||
...(kind === "tool"
|
||||
? {
|
||||
projection: {
|
||||
kind: boundedAipodSpecText(projection.kind, 80),
|
||||
envName: boundedAipodSpecText(projection.envName, 160),
|
||||
secretKey: boundedAipodSpecText(projection.secretKey, 160),
|
||||
mountPath: boundedAipodSpecText(projection.mountPath, 320),
|
||||
valuesPrinted: false,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
valuesPrinted: false,
|
||||
};
|
||||
});
|
||||
return {
|
||||
count,
|
||||
items,
|
||||
omittedCount: Math.max(0, count - items.length),
|
||||
valuesPrinted: false,
|
||||
};
|
||||
}
|
||||
|
||||
function renderAipodSpecCredentialRefLines(items: Record<string, unknown>[], kind: "provider" | "tool"): string[] {
|
||||
return items.map((item) => {
|
||||
const secretRef = record(item.secretRef);
|
||||
const namespace = stringOrNull(secretRef.namespace);
|
||||
const name = displayValue(secretRef.name);
|
||||
const reference = namespace === null ? name : `${namespace}/${name}`;
|
||||
const keys = Array.isArray(secretRef.keys) ? secretRef.keys.map(String).join(",") : "-";
|
||||
const identity = kind === "provider"
|
||||
? `profile=${displayValue(item.profile)}`
|
||||
: `tool=${displayValue(item.tool)} purpose=${displayValue(item.purpose)}`;
|
||||
return `${kind} ${identity} secret=${reference} keys=${keys}`;
|
||||
});
|
||||
}
|
||||
|
||||
function firstNonEmptyRecord(...values: unknown[]): Record<string, unknown> {
|
||||
for (const value of values) {
|
||||
const candidate = record(value);
|
||||
if (Object.keys(candidate).length > 0) return candidate;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
function aipodSpecReferenceCount(value: unknown): number {
|
||||
if (Array.isArray(value)) return value.length;
|
||||
const summary = record(value);
|
||||
const count = summary.count;
|
||||
if (typeof count === "number" && Number.isFinite(count) && count >= 0) return Math.floor(count);
|
||||
return arrayRecords(summary.items).length;
|
||||
}
|
||||
|
||||
function boundedAipodSpecStrings(value: unknown, limit: number, maxChars: number): string[] {
|
||||
if (!Array.isArray(value)) return [];
|
||||
return value
|
||||
.slice(0, limit)
|
||||
.map((item) => boundedAipodSpecText(item, maxChars))
|
||||
.filter((item): item is string => item !== null);
|
||||
}
|
||||
|
||||
function boundedAipodSpecText(value: unknown, maxChars: number): string | null {
|
||||
const text = stringOrNull(value);
|
||||
return text === null ? null : truncateOneLine(text, maxChars);
|
||||
}
|
||||
|
||||
function boundedAipodSpecRepoUrl(value: unknown): string | null {
|
||||
const sanitized = taskInputRepoUrl(value);
|
||||
return typeof sanitized === "string" ? truncateOneLine(sanitized, 320) : null;
|
||||
}
|
||||
|
||||
export function taskInputDescriptionPayload(ref: AgentRunResourceRef, task: Record<string, unknown>): Record<string, unknown> {
|
||||
const metadata = taskInputMetadata(task.metadata);
|
||||
const aipodImageRef = taskInputImageRef(metadata.aipodImageRef);
|
||||
|
||||
@@ -37,7 +37,7 @@ import type { AgentRunResourceOptions, AgentRunResourceRef, AgentRunResourceVerb
|
||||
import { agentRunDryRunPlan } from "./config";
|
||||
import { isHelpArg, renderAgentRunHelp } from "./entry";
|
||||
import { agentRunExplain, arrayRecords, shortId } from "./options";
|
||||
import { agentRunCancelAuthorityDisclosure, agentRunCancelCascadeScope, agentRunCancelFencingDisclosure, agentRunCancelRunnerAbortDisclosure, compactTaskDescriptionPayload, innerData, normalizeAipodSpecItems, normalizeAttemptResources, normalizeEventItems, normalizeLogItems, normalizeQueueAttemptItems, normalizeRunnerJobItems, normalizeSessionItems, normalizeSingleCommand, normalizeTaskItems, parseResourceKind, parseResourceRef, renderDescribe, renderEventLike, renderGenericDescription, renderMachine, renderMutationSummary, renderQueueAttemptList, renderQueueRetrySummary, renderResourceResult, renderResultSummary, renderTaskDescription, renderedCliResult, requiredContext, rerunWithoutDryRun, resolveAgentRunCancelPolicyTarget, resourceApply, resourceCreate, resourceDispatch, resourceSessionPromptCommand, taskInputDescriptionPayload, taskListState, unwrapTaskDetail } from "./render";
|
||||
import { agentRunCancelAuthorityDisclosure, agentRunCancelCascadeScope, agentRunCancelFencingDisclosure, agentRunCancelRunnerAbortDisclosure, compactAipodSpecDescriptionPayload, compactTaskDescriptionPayload, innerData, normalizeAipodSpecItems, normalizeAttemptResources, normalizeEventItems, normalizeLogItems, normalizeQueueAttemptItems, normalizeRunnerJobItems, normalizeSessionItems, normalizeSingleCommand, normalizeTaskItems, parseResourceKind, parseResourceRef, renderAipodSpecDescription, renderDescribe, renderEventLike, renderGenericDescription, renderMachine, renderMutationSummary, renderQueueAttemptList, renderQueueRetrySummary, renderResourceResult, renderResultSummary, renderTaskDescription, renderedCliResult, requiredContext, rerunWithoutDryRun, resolveAgentRunCancelPolicyTarget, resourceApply, resourceCreate, resourceDispatch, resourceSessionPromptCommand, taskInputDescriptionPayload, taskListState, unwrapTaskDetail } from "./render";
|
||||
import { AgentRunRestError, renderAgentRunRestError, resolveAgentRunRestTarget, runAgentRunRestCommand, withAgentRunRestTarget } from "./rest-bridge";
|
||||
import { runnerJobObservationScript, type RunnerJobObservationIdentity } from "./runner-observation";
|
||||
import { capture, captureJsonPayload, compactCapture, nonNegativeIntegerOrNull, record, stringOrNull } from "./utils";
|
||||
@@ -361,7 +361,10 @@ export async function resourceDescribe(config: UniDeskConfig | null, command: st
|
||||
}
|
||||
if (ref.kind === "aipodspec") {
|
||||
const result = await runAgentRunRestCommand(config, "aipod-specs", ["show", ref.name, ...(options.full ? ["--full"] : [])]);
|
||||
return renderDescribe(command, result, options, ref, renderGenericDescription(ref, innerData(result)));
|
||||
if (options.raw || options.full) return renderDescribe(command, result, options, ref, renderGenericDescription(ref, innerData(result)));
|
||||
const payload = compactAipodSpecDescriptionPayload(ref, innerData(result));
|
||||
if (options.output === "json" || options.output === "yaml") return renderMachine(command, payload, options.output, result.ok !== false);
|
||||
return renderedCliResult(result.ok !== false, command, renderAipodSpecDescription(payload));
|
||||
}
|
||||
throw new Error(`unsupported describe kind: ${ref.kind}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user