fix: project runner skills into dev containers
This commit is contained in:
@@ -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