fix: project runner skills into dev containers
This commit is contained in:
@@ -238,13 +238,13 @@ bun scripts/code-queue-pr-preflight-example.ts --repo pikasTech/unidesk --base m
|
||||
|
||||
### Runner Skill 可用性
|
||||
|
||||
D601 Code Queue runner 的长期 skills source of truth 是宿主 `/home/ubuntu/.agents/skills`,生产和 dev Code Queue Pod 都必须只读挂载到容器内 `/root/.agents/skills`,并设置 `UNIDESK_SKILLS_PATH=/root/.agents/skills`。如果 target 暂缺但 approved source 存在且必需 skill 可读,runtime 必须把 `UNIDESK_SKILLS_PATH` 解析为可用 source 传给 runner,并在 health/preflight 中标记 `runnerUsable=true`、`contractOk=false`、`resolvedPathSource=source-fallback`、`degradedReason=skills-target-missing` 与 `resolution.hostRolloutRequired=true`;这表示任务执行能力可用,但 hostPath 投影仍需 host rollout 修复。不要使用或传播任何拼错的 skills 路径;如果配置的 source 或 target 命中拼写错误路径,health/preflight 必须直接返回 `blocker=forbidden-skills-path-configured`,并在 `pathSpelling.forbiddenPathConfigured=true` 与 `pathSpelling.forbiddenPathRoles` 中标明是 source、target 或两者,而不是降级成普通 missing path。
|
||||
D601 Code Queue runner 的长期 skills source of truth 是宿主 `/home/ubuntu/.agents/skills`,生产和 dev Code Queue Pod 都必须只读挂载到容器内 `/root/.agents/skills`,并设置 `UNIDESK_SKILLS_PATH=/root/.agents/skills`。provider dev container 由 scheduler 通过 Docker 启动时,也必须把同一宿主 source 只读 bind 到同一 target,并把 `UNIDESK_SKILLS_PATH` 显式传给 Codex/OpenCode 进程。target 缺失时即使 approved source 可读也不能 fallback 给 runner;health/preflight 必须标记 `runnerUsable=false`、`contractOk=false`、`resolvedPathSource=missing`、`degradedReason=skills-target-missing` 与 `resolution.hostRolloutRequired=true`。不要使用或传播任何拼错的 skills 路径;如果配置的 source 或 target 命中拼写错误路径,health/preflight 必须直接返回 `blocker=forbidden-skills-path-configured`,并在 `pathSpelling.forbiddenPathConfigured=true` 与 `pathSpelling.forbiddenPathRoles` 中标明是 source、target 或两者,而不是降级成普通 missing path。
|
||||
|
||||
执行面 `/health`、`/api/dev-ready` 和 `/api/runtime-preflight` 必须输出同一份只读 skill availability report。稳定字段包括 `source`、`target`、`resolvedPath`、`resolvedPathSource`、`resolution`、`requiredSkills`、`missingSkills`、`sourceSkillCount`、`targetSkillCount`、`degraded`、`degradedReason`、`blocker`、`pathSpelling` 和 `valuesPrinted=false`。`requiredSkills` 至少覆盖 `docs-spec`、`cli-spec`、`frontend-design` 与 `playwright-cli`;如果 source 与 target 都缺失、必需 skill 均不可用、拼写错误路径被配置或拼写错误路径已存在,报告必须显示 `ok=false` 和结构化 `blocker`,不能把 runner 能力缺口伪装成业务任务失败。target symlink 到 approved source 属于可接受的兼容修复,必须显示 `resolvedPathSource=target-symlink` 和有界 skill count。
|
||||
|
||||
执行面还必须提供 dry-run skills sync/preflight 合同:稳定入口是 `GET /api/skills-sync?dryRun=1`,CLI 入口是 `bun scripts/cli.ts codex skills-sync --dry-run [--full]`。该合同只描述受控 hostPath 生命周期,不复制文件、不从任意路径静默加载、不重启服务、不 rollout Pod、不读取 Secret。默认输出保持紧凑,必须报告 source、target、expected env/mount、required skill 列表、source/target skill counts、missing source/target skills、permission failure count、plannedActions 和修复指令;逐 skill 细节、完整 permission failure 和原始报告只能通过 `--full` 显式展开。非 dry-run 请求必须失败。
|
||||
|
||||
受控生命周期是更新宿主 `/home/ubuntu/.agents/skills` 这一 approved source,然后让生产和 dev Code Queue Pod 通过 manifest 中的 read-only hostPath 挂载读取 `/root/.agents/skills`。在线热更新只能作为临时恢复手段,长期验收必须以 manifest/source-of-truth、dry-run sync contract、结构化 health/preflight 和合同测试为准。需要验证时优先运行:
|
||||
受控生命周期是更新宿主 `/home/ubuntu/.agents/skills` 这一 approved source,然后让生产和 dev Code Queue Pod 通过 manifest 中的 read-only hostPath 挂载读取 `/root/.agents/skills`;provider dev container 还必须通过启动脚本把同一 source bind 到同一 target。在线热更新只能作为临时恢复手段,长期验收必须以 manifest/source-of-truth、runner container bind、dry-run sync contract、结构化 health/preflight 和合同测试为准。需要验证时优先运行:
|
||||
|
||||
```bash
|
||||
bun scripts/cli.ts codex skills-sync --dry-run
|
||||
|
||||
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { collectSkillAvailability, collectSkillSyncPreflight } from "../src/components/microservices/code-queue/src/skill-availability";
|
||||
import { buildDevContainerPlan, configureProviderRuntime, providerRuntimeForTest } from "../src/components/microservices/code-queue/src/provider-runtime";
|
||||
import { codexPrPreflightQueryForTest } from "./src/code-queue";
|
||||
import { summarizeMicroserviceObservation } from "./src/microservices";
|
||||
|
||||
@@ -71,6 +72,9 @@ assertCondition(!docsReference.includes(forbiddenPathLiteral), "reference docs m
|
||||
assertCondition(countOccurrences(productionManifest, "name: UNIDESK_SKILLS_PATH") === 3, "production read/write/scheduler must set UNIDESK_SKILLS_PATH", {
|
||||
count: countOccurrences(productionManifest, "name: UNIDESK_SKILLS_PATH"),
|
||||
});
|
||||
assertCondition(countOccurrences(productionManifest, "name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH") === 3, "production read/write/scheduler must expose the approved runner skills source path", {
|
||||
count: countOccurrences(productionManifest, "name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH"),
|
||||
});
|
||||
assertCondition(countOccurrences(productionManifest, "mountPath: /root/.agents/skills") === 3, "production read/write/scheduler must mount skills target", {
|
||||
count: countOccurrences(productionManifest, "mountPath: /root/.agents/skills"),
|
||||
});
|
||||
@@ -81,6 +85,9 @@ assertCondition(countOccurrences(productionManifest, "name: skills-dir") >= 6, "
|
||||
count: countOccurrences(productionManifest, "name: skills-dir"),
|
||||
});
|
||||
assertCondition(devManifest.includes("path: /home/ubuntu/.agents/skills"), "dev manifest should keep the same hostPath source of truth");
|
||||
assertCondition(countOccurrences(devManifest, "name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH") === 3, "dev read/write/scheduler must expose the approved runner skills source path", {
|
||||
count: countOccurrences(devManifest, "name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH"),
|
||||
});
|
||||
|
||||
const devCodeQueueDeploy = (deployJson.environments?.dev?.services ?? []).find((service) => service.id === "code-queue");
|
||||
assertCondition(devCodeQueueDeploy !== undefined, "deploy.json dev environment must include code-queue");
|
||||
@@ -107,6 +114,71 @@ assertCondition(pinnedRuntimePreflight.includes("skills.contractOk && ports.code
|
||||
assertCondition(pinnedIndexSource.includes("skills.contractOk === true"), "deploy.json dev code-queue commit dev-ready must require target projection contract");
|
||||
assertCondition(pinnedIndexSource.includes("return config.skillsPath"), "deploy.json dev code-queue commit must keep runner UNIDESK_SKILLS_PATH on the configured target");
|
||||
|
||||
configureProviderRuntime({
|
||||
config: {
|
||||
codexHome: "/var/lib/unidesk/code-queue/codex-home",
|
||||
defaultWorkdir: "/workspace",
|
||||
devContainerDefaultProviderId: "D601",
|
||||
devContainerImage: "unidesk-code-queue:d601",
|
||||
devContainerMasterHost: "74.48.78.17",
|
||||
devContainerWorkdir: "/home/ubuntu",
|
||||
executionProviderIds: ["D601"],
|
||||
mainProviderId: "D601-main",
|
||||
remoteCodexEnvKeys: [],
|
||||
remoteDefaultWorkdir: "/home/ubuntu",
|
||||
runnerSkillsSourcePath: "/home/ubuntu/.agents/skills",
|
||||
skillsPath: "/root/.agents/skills",
|
||||
sourceCodexConfig: "/root/.codex/config.toml",
|
||||
windowsNativeCodexBridgeDir: "/home/ubuntu/.unidesk/code-queue/windows-native-codex",
|
||||
windowsNativeCodexCommand: "codex app-server --listen stdio://",
|
||||
windowsNativeCodexConnectHost: "host.docker.internal",
|
||||
windowsNativeCodexDefaultWorkdir: "/mnt/f/Work/ConStart",
|
||||
windowsNativeCodexIdleTimeoutMs: 600_000,
|
||||
},
|
||||
safePreview: (value: string, max = 1000) => value.slice(0, max),
|
||||
});
|
||||
const devContainerPlan = buildDevContainerPlan("D601", { workdir: "/home/ubuntu" });
|
||||
const devContainerStartScript = providerRuntimeForTest.remoteContainerStartScript(devContainerPlan, false);
|
||||
assertCondition(devContainerStartScript.includes("SKILLS_SOURCE='/home/ubuntu/.agents/skills'"), "provider dev container start must use the D601 host skills source", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes("SKILLS_TARGET='/root/.agents/skills'"), "provider dev container start must use the runner target skills path", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes('-v "$SKILLS_SOURCE":"$SKILLS_TARGET":ro'), "provider dev container must bind source skills read-only to target", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes('-e UNIDESK_SKILLS_PATH="$SKILLS_TARGET"'), "provider dev container must export UNIDESK_SKILLS_PATH in docker run", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes('test -r "$UNIDESK_SKILLS_PATH/docs-spec/SKILL.md"'), "provider dev container readiness must verify required docs-spec skill at target", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes('test -r "$UNIDESK_SKILLS_PATH/cli-spec/SKILL.md"'), "provider dev container readiness must verify required cli-spec skill at target", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes('test -r "$UNIDESK_SKILLS_PATH/frontend-design/SKILL.md"'), "provider dev container readiness must verify required frontend-design skill at target", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes("playwright-cli/SKILL.md") && devContainerStartScript.includes("playwright/SKILL.md"), "provider dev container readiness must accept the playwright-cli alias", devContainerStartScript);
|
||||
assertCondition(devContainerStartScript.includes("reuse_ready") && devContainerStartScript.includes('test "$UNIDESK_SKILLS_PATH" = "/root/.agents/skills"'), "provider dev container reuse must revalidate target skills before keeping an old container", devContainerStartScript);
|
||||
const remoteCodexCommand = providerRuntimeForTest.remoteAppServerCommand({
|
||||
id: "task",
|
||||
queueId: "default",
|
||||
prompt: "",
|
||||
status: "running",
|
||||
cwd: "/home/ubuntu",
|
||||
providerId: "D601",
|
||||
model: "gpt-5.5",
|
||||
executionMode: "default",
|
||||
currentAttempt: 1,
|
||||
attempts: 1,
|
||||
maxAttempts: 1,
|
||||
codexThreadId: null,
|
||||
reasoningEffort: null,
|
||||
createdAt: "2026-05-24T00:00:00.000Z",
|
||||
updatedAt: "2026-05-24T00:00:00.000Z",
|
||||
startedAt: "2026-05-24T00:00:00.000Z",
|
||||
completedAt: null,
|
||||
lastActivityAt: "2026-05-24T00:00:00.000Z",
|
||||
branch: null,
|
||||
commitSha: null,
|
||||
title: null,
|
||||
error: null,
|
||||
judge: null,
|
||||
outputSeq: 0,
|
||||
outputs: [],
|
||||
events: [],
|
||||
metadata: {},
|
||||
} as never);
|
||||
assertCondition(remoteCodexCommand.includes("export UNIDESK_SKILLS_PATH=") && remoteCodexCommand.includes("/root/.agents/skills"), "remote codex app-server must receive the target skills env", remoteCodexCommand);
|
||||
|
||||
const available = collectSkillAvailability({
|
||||
source: "/home/ubuntu/.agents/skills",
|
||||
target: "/home/ubuntu/.agents/skills",
|
||||
@@ -446,6 +518,7 @@ process.stdout.write(`${JSON.stringify({
|
||||
ok: true,
|
||||
checks: [
|
||||
"production Code Queue mounts /home/ubuntu/.agents/skills read-only at /root/.agents/skills",
|
||||
"provider dev containers bind /home/ubuntu/.agents/skills read-only at /root/.agents/skills and pass UNIDESK_SKILLS_PATH to Codex/OpenCode",
|
||||
"deploy.json dev Code Queue pins a commit whose manifest and runtime require the target skills projection",
|
||||
"skill availability report exposes source, target, requiredSkills, missingSkills, version fingerprint/mtime, degraded/blocker and valuesPrinted=false",
|
||||
"skills sync dry-run reports source, target, counts, version fingerprint/mtime, missing skills, permission failures, instructions and no-copy actions",
|
||||
|
||||
@@ -24,6 +24,7 @@ services:
|
||||
CODE_QUEUE_STARTUP_OA_BACKFILL_ENABLED: "${CODE_QUEUE_STARTUP_OA_BACKFILL_ENABLED:-false}"
|
||||
CODE_QUEUE_WORKDIR: "${CODE_QUEUE_WORKDIR:-/workspace}"
|
||||
UNIDESK_SKILLS_PATH: "${UNIDESK_SKILLS_PATH:-/root/.agents/skills}"
|
||||
CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH: "${CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH:-/home/ubuntu/.agents/skills}"
|
||||
CODE_QUEUE_CODEX_HOME: "/var/lib/unidesk/code-queue/codex-home"
|
||||
CODE_QUEUE_OPENCODE_XDG_DIR: "/var/lib/unidesk/code-queue/opencode-xdg"
|
||||
CODE_QUEUE_SOURCE_CODEX_CONFIG: "/root/.codex/config.toml"
|
||||
|
||||
@@ -166,6 +166,7 @@ function remoteOpenCodeRunCommand(task: QueueTask, prompt: string): string {
|
||||
`export MINIMAX_API_BASE=${ctx().shellQuote(ctx().config.minimaxApiBase)}`,
|
||||
`export MINIMAX_MODEL=${ctx().shellQuote(ctx().config.minimaxModel)}`,
|
||||
`export OPENCODE_CONFIG_CONTENT=${ctx().shellQuote(openCodeConfigContent())}`,
|
||||
`export UNIDESK_SKILLS_PATH=${ctx().shellQuote(ctx().config.resolvedRunnerSkillsPath())}`,
|
||||
...gitConfigEntries.map(([key, value], index) => `export GIT_CONFIG_KEY_$((\${GIT_CONFIG_COUNT:-0}+${index}))=${ctx().shellQuote(key)} GIT_CONFIG_VALUE_$((\${GIT_CONFIG_COUNT:-0}+${index}))=${ctx().shellQuote(value)}`),
|
||||
`export GIT_CONFIG_COUNT=$((\${GIT_CONFIG_COUNT:-0}+${gitConfigEntries.length}))`,
|
||||
].join("; ");
|
||||
|
||||
@@ -402,6 +402,7 @@ function readConfig(): RuntimeConfig {
|
||||
executionProviderIds,
|
||||
remoteCodexEnvKeys: envList("CODE_QUEUE_REMOTE_CODEX_ENV_KEYS", ["OPENAI_API_KEY", "CRS_OAI_KEY", "OPENAI_BASE_URL", "OPENAI_API_BASE", "DEEPSEEK_API_KEY", "DEEPSEEK_API_BASE", "DEEPSEEK_MODEL", "MINIMAX_API_KEY", "MINIMAX_API_BASE", "MINIMAX_MODEL", "GH_TOKEN", "GITHUB_TOKEN", "GH_HOST", "GITHUB_API_URL", "GH_REPO"]),
|
||||
skillsPath: envString("UNIDESK_SKILLS_PATH", "/root/.agents/skills"),
|
||||
runnerSkillsSourcePath: envString("CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH", "/home/ubuntu/.agents/skills"),
|
||||
resolvedRunnerSkillsPath,
|
||||
codexHome: envString("CODE_QUEUE_CODEX_HOME", "/var/lib/unidesk/code-queue/codex-home"),
|
||||
opencodeXdgDir: envString("CODE_QUEUE_OPENCODE_XDG_DIR", resolve(dataDir, "opencode-xdg")),
|
||||
|
||||
@@ -8,7 +8,7 @@ export const codeQueueEnvironmentHintTitle = "# Code Queue 运行环境提示";
|
||||
export const codeQueueEnvironmentHint = [
|
||||
codeQueueEnvironmentHintTitle,
|
||||
"如果当前 Code Queue Docker 容器缺少完成任务所需的环境、系统包或语言依赖,可以先在容器内临时安装以推进当前任务;同时必须把该依赖补到 `src/components/microservices/code-queue/Dockerfile`,让后续任务重建镜像后可直接使用。",
|
||||
"任务可通过 `UNIDESK_SKILLS_PATH` 读取注入的宿主 skills;默认目标是 `/root/.agents/skills`,如果该挂载暂缺但 approved source `/home/ubuntu/.agents/skills` 可读,runner 会把 `UNIDESK_SKILLS_PATH` 解析到可用 source 并在 `/api/dev-ready` 的 `devReady.skills.resolution` 中报告需要 host rollout 的合同退化,不要读取或输出宿主 token/auth 配置。",
|
||||
"任务可通过 `UNIDESK_SKILLS_PATH` 读取注入的宿主 skills;默认目标是 `/root/.agents/skills`。如果该路径不可读或缺少必需 skills,runner/preflight 会以 infra blocker 暴露 target projection 缺口;不要读取或输出宿主 token/auth 配置。",
|
||||
].join("\n");
|
||||
|
||||
export function stripAutoReferenceHint(prompt: string): string {
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { DevContainerCommandLog, DevContainerPlan, JsonValue, QueueTask, Ru
|
||||
|
||||
export interface ProviderRuntimeContext {
|
||||
config: Pick<RuntimeConfig,
|
||||
"codexHome" | "defaultWorkdir" | "devContainerDefaultProviderId" | "devContainerImage" | "devContainerMasterHost" | "devContainerWorkdir" | "executionProviderIds" | "mainProviderId" | "remoteCodexEnvKeys" | "remoteDefaultWorkdir" | "sourceCodexConfig" | "windowsNativeCodexBridgeDir" | "windowsNativeCodexCommand" | "windowsNativeCodexConnectHost" | "windowsNativeCodexDefaultWorkdir" | "windowsNativeCodexIdleTimeoutMs"
|
||||
"codexHome" | "defaultWorkdir" | "devContainerDefaultProviderId" | "devContainerImage" | "devContainerMasterHost" | "devContainerWorkdir" | "executionProviderIds" | "mainProviderId" | "remoteCodexEnvKeys" | "remoteDefaultWorkdir" | "runnerSkillsSourcePath" | "skillsPath" | "sourceCodexConfig" | "windowsNativeCodexBridgeDir" | "windowsNativeCodexCommand" | "windowsNativeCodexConnectHost" | "windowsNativeCodexDefaultWorkdir" | "windowsNativeCodexIdleTimeoutMs"
|
||||
>;
|
||||
safePreview: (value: string, max?: number) => string;
|
||||
}
|
||||
@@ -432,12 +432,20 @@ REQUESTED_IMAGE=${shellQuote(plan.image)}
|
||||
KEY_DIR=${shellQuote(plan.keyDir)}
|
||||
WORKDIR=${shellQuote(plan.workdir)}
|
||||
CONTAINER_WORKDIR=${shellQuote(plan.containerWorkdir)}
|
||||
SKILLS_SOURCE=${shellQuote(ctx().config.runnerSkillsSourcePath)}
|
||||
SKILLS_TARGET=${shellQuote(ctx().config.skillsPath)}
|
||||
IMAGE="$REQUESTED_IMAGE"
|
||||
SSH_DIR="\${UNIDESK_HOST_ROOT_SSH_DIR:-$HOME/.ssh}"
|
||||
SSH_MOUNT_ARGS=()
|
||||
if [ -d "$SSH_DIR" ]; then SSH_MOUNT_ARGS=(-v "$SSH_DIR":/root/.ssh:ro); fi
|
||||
HOST_PATH_MOUNT_ARGS=()
|
||||
if [ -d /mnt ]; then HOST_PATH_MOUNT_ARGS+=(-v /mnt:/mnt); fi
|
||||
SKILLS_MOUNT_ARGS=()
|
||||
if [ ! -d "$SKILLS_SOURCE" ]; then
|
||||
echo "missing runner skills source $SKILLS_SOURCE; expected read-only projection to $SKILLS_TARGET" >&2
|
||||
exit 1
|
||||
fi
|
||||
SKILLS_MOUNT_ARGS=(-v "$SKILLS_SOURCE":"$SKILLS_TARGET":ro)
|
||||
if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then
|
||||
echo "missing dev container image $REQUESTED_IMAGE" >&2
|
||||
exit 1
|
||||
@@ -451,7 +459,7 @@ if [ ${forceRecreate ? "1" : "0"} -eq 0 ] && docker inspect "$CONTAINER" >/dev/n
|
||||
STATE=$(docker inspect "$CONTAINER" --format '{{.State.Status}}' 2>/dev/null || true)
|
||||
LABEL_WORKDIR=$(docker inspect "$CONTAINER" --format '{{ index .Config.Labels "unidesk.workdir" }}' 2>/dev/null || true)
|
||||
if [ "$STATE" = "running" ] && [ "$LABEL_WORKDIR" = "$WORKDIR" ]; then
|
||||
docker exec "$CONTAINER" bash -lc 'echo reuse_ready; command -v bash; test -d /run/unidesk-dev-proxy; test -d /var/lib/unidesk/code-queue/codex-home; test -d /var/lib/unidesk/code-queue/opencode-xdg' >/dev/null
|
||||
docker exec "$CONTAINER" bash -lc 'echo reuse_ready; command -v bash; test "$UNIDESK_SKILLS_PATH" = "/root/.agents/skills"; test -r "$UNIDESK_SKILLS_PATH/docs-spec/SKILL.md"; test -r "$UNIDESK_SKILLS_PATH/cli-spec/SKILL.md"; test -r "$UNIDESK_SKILLS_PATH/frontend-design/SKILL.md"; if [ -r "$UNIDESK_SKILLS_PATH/playwright-cli/SKILL.md" ]; then :; else test -r "$UNIDESK_SKILLS_PATH/playwright/SKILL.md"; fi; test -d /run/unidesk-dev-proxy; test -d /var/lib/unidesk/code-queue/codex-home; test -d /var/lib/unidesk/code-queue/opencode-xdg' >/dev/null
|
||||
echo "remote_container_reused container=$CONTAINER image=$(docker inspect "$CONTAINER" --format '{{.Config.Image}}') workdir=$WORKDIR"
|
||||
exit 0
|
||||
fi
|
||||
@@ -473,6 +481,7 @@ cid=$(docker run -d \\
|
||||
--env-file "$KEY_DIR/codex-env" \\
|
||||
-e CODEX_HOME=${shellQuote(plan.remoteCodexHome)} \\
|
||||
-e CODEX_INTERNAL_ORIGINATOR_OVERRIDE=unidesk_code_queue \\
|
||||
-e UNIDESK_SKILLS_PATH="$SKILLS_TARGET" \\
|
||||
-e XDG_DATA_HOME=${shellQuote(resolve(plan.remoteOpencodeXdgDir, "data"))} \\
|
||||
-e XDG_CONFIG_HOME=${shellQuote(resolve(plan.remoteOpencodeXdgDir, "config"))} \\
|
||||
-e XDG_CACHE_HOME=${shellQuote(resolve(plan.remoteOpencodeXdgDir, "cache"))} \\
|
||||
@@ -484,14 +493,15 @@ cid=$(docker run -d \\
|
||||
-v "$KEY_DIR/opencode-xdg":${shellQuote(plan.remoteOpencodeXdgDir)} \\
|
||||
"\${SSH_MOUNT_ARGS[@]}" \\
|
||||
"\${HOST_PATH_MOUNT_ARGS[@]}" \\
|
||||
"\${SKILLS_MOUNT_ARGS[@]}" \\
|
||||
-v "$WORKDIR":"$CONTAINER_WORKDIR" \\
|
||||
-v "$WORKDIR":/root/unidesk \\
|
||||
-w "$CONTAINER_WORKDIR" \\
|
||||
"$IMAGE" \\
|
||||
bash -lc 'mkdir -p /tmp/unidesk-tools; ln -sf /usr/local/bin/busybox /tmp/unidesk-tools/ip; ln -sf /usr/local/bin/busybox /tmp/unidesk-tools/ping; export PATH=/tmp/unidesk-tools:$PATH; echo ready; sleep infinity')
|
||||
docker exec "$CONTAINER" bash -lc 'mkdir -p /tmp/unidesk-tools; ln -sf /usr/local/bin/busybox /tmp/unidesk-tools/ip; ln -sf /usr/local/bin/busybox /tmp/unidesk-tools/ping; export PATH=/tmp/unidesk-tools:$PATH; echo container=$(hostname); pwd; ip route show default; ls -ld /dev/net/tun /run/unidesk-dev-proxy/id_ed25519 /var/lib/unidesk/code-queue/codex-home /var/lib/unidesk/code-queue/opencode-xdg; command -v ssh; command -v ip; command -v ping'
|
||||
docker exec "$CONTAINER" bash -lc 'mkdir -p /tmp/unidesk-tools; ln -sf /usr/local/bin/busybox /tmp/unidesk-tools/ip; ln -sf /usr/local/bin/busybox /tmp/unidesk-tools/ping; export PATH=/tmp/unidesk-tools:$PATH; echo container=$(hostname); pwd; ip route show default; test "$UNIDESK_SKILLS_PATH" = "/root/.agents/skills"; test -d "$UNIDESK_SKILLS_PATH"; test -r "$UNIDESK_SKILLS_PATH/docs-spec/SKILL.md"; test -r "$UNIDESK_SKILLS_PATH/cli-spec/SKILL.md"; test -r "$UNIDESK_SKILLS_PATH/frontend-design/SKILL.md"; if [ -r "$UNIDESK_SKILLS_PATH/playwright-cli/SKILL.md" ]; then :; else test -r "$UNIDESK_SKILLS_PATH/playwright/SKILL.md"; fi; ls -ld /dev/net/tun /run/unidesk-dev-proxy/id_ed25519 /var/lib/unidesk/code-queue/codex-home /var/lib/unidesk/code-queue/opencode-xdg "$UNIDESK_SKILLS_PATH"; command -v ssh; command -v ip; command -v ping'
|
||||
docker exec "$CONTAINER" bash -lc 'command -v iptables; iptables --version'
|
||||
echo "remote_container_ready container=$CONTAINER cid=$cid image=$IMAGE workdir=$WORKDIR"`;
|
||||
echo "remote_container_ready container=$CONTAINER cid=$cid image=$IMAGE workdir=$WORKDIR skillsTarget=$SKILLS_TARGET"`;
|
||||
}
|
||||
|
||||
function masterProxyPrepareScript(plan: DevContainerPlan): string {
|
||||
@@ -1016,6 +1026,7 @@ function remoteAppServerCommand(task: QueueTask): string {
|
||||
`cd ${shellQuote(task.cwd)}`,
|
||||
`export CODEX_HOME=${shellQuote(plan.remoteCodexHome)}`,
|
||||
"export CODEX_INTERNAL_ORIGINATOR_OVERRIDE=unidesk_code_queue",
|
||||
`export UNIDESK_SKILLS_PATH=${shellQuote(ctx().config.skillsPath)}`,
|
||||
gitConfigExports,
|
||||
"exec codex app-server --listen stdio://",
|
||||
].join("; ");
|
||||
@@ -1093,3 +1104,8 @@ export {
|
||||
throwIfCommandFailed,
|
||||
windowsNativeAppServerCommand,
|
||||
};
|
||||
|
||||
export const providerRuntimeForTest = {
|
||||
remoteContainerStartScript,
|
||||
remoteAppServerCommand,
|
||||
};
|
||||
|
||||
@@ -124,6 +124,7 @@ export interface RuntimeConfig {
|
||||
executionProviderIds: string[];
|
||||
remoteCodexEnvKeys: string[];
|
||||
skillsPath: string;
|
||||
runnerSkillsSourcePath: string;
|
||||
resolvedRunnerSkillsPath: () => string;
|
||||
codexHome: string;
|
||||
opencodeXdgDir: string;
|
||||
|
||||
@@ -82,6 +82,8 @@ spec:
|
||||
value: "/root/.codex/config.toml"
|
||||
- name: UNIDESK_SKILLS_PATH
|
||||
value: "/root/.agents/skills"
|
||||
- name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
|
||||
value: "/home/ubuntu/.agents/skills"
|
||||
- name: CODE_QUEUE_DEFAULT_MODEL
|
||||
value: "gpt-5.5"
|
||||
- name: CODE_QUEUE_MODELS
|
||||
@@ -328,6 +330,8 @@ spec:
|
||||
value: "/root/.codex/config.toml"
|
||||
- name: UNIDESK_SKILLS_PATH
|
||||
value: "/root/.agents/skills"
|
||||
- name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
|
||||
value: "/home/ubuntu/.agents/skills"
|
||||
- name: CODE_QUEUE_DEFAULT_MODEL
|
||||
value: "gpt-5.5"
|
||||
- name: CODE_QUEUE_MODELS
|
||||
@@ -1033,6 +1037,8 @@ spec:
|
||||
value: "/root/.codex/config.toml"
|
||||
- name: UNIDESK_SKILLS_PATH
|
||||
value: "/root/.agents/skills"
|
||||
- name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
|
||||
value: "/home/ubuntu/.agents/skills"
|
||||
- name: CODE_QUEUE_DEFAULT_MODEL
|
||||
value: "gpt-5.5"
|
||||
- name: CODE_QUEUE_MODELS
|
||||
|
||||
@@ -331,6 +331,8 @@ spec:
|
||||
value: never
|
||||
- name: UNIDESK_SKILLS_PATH
|
||||
value: /root/.agents/skills
|
||||
- name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
|
||||
value: /home/ubuntu/.agents/skills
|
||||
- name: CODE_QUEUE_EGRESS_PROXY_ENABLED
|
||||
value: "true"
|
||||
- name: CODE_QUEUE_EGRESS_PROXY_URL
|
||||
@@ -542,6 +544,8 @@ spec:
|
||||
value: "false"
|
||||
- name: UNIDESK_SKILLS_PATH
|
||||
value: /root/.agents/skills
|
||||
- name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
|
||||
value: /home/ubuntu/.agents/skills
|
||||
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
|
||||
value: "false"
|
||||
- name: CODE_QUEUE_CODEX_SQLITE_LOG_EXPORT_ENABLED
|
||||
@@ -694,6 +698,8 @@ spec:
|
||||
value: "false"
|
||||
- name: UNIDESK_SKILLS_PATH
|
||||
value: /root/.agents/skills
|
||||
- name: CODE_QUEUE_RUNNER_SKILLS_SOURCE_PATH
|
||||
value: /home/ubuntu/.agents/skills
|
||||
- name: CODE_QUEUE_NOTIFY_CLAUDEQQ_ENABLED
|
||||
value: "false"
|
||||
- name: CODE_QUEUE_CODEX_SQLITE_LOG_EXPORT_ENABLED
|
||||
|
||||
Reference in New Issue
Block a user