@fitlab-ai/agent-infra 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -5
- package/README.zh-CN.md +21 -5
- package/bin/cli.ts +12 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/internal-cli.js +20 -0
- package/dist/lib/agent-client.js +163 -0
- package/dist/lib/agent-clients/adapter.js +294 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +62 -0
- package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
- package/dist/lib/agent-clients/adapters/codex.js +54 -0
- package/dist/lib/agent-clients/adapters/gemini-cli.js +64 -0
- package/dist/lib/agent-clients/adapters/index.js +20 -0
- package/dist/lib/agent-clients/adapters/opencode.js +64 -0
- package/dist/lib/agent-clients/config.js +177 -0
- package/dist/lib/agent-clients/custom-tuis.js +99 -0
- package/dist/lib/agent-clients/invocation.js +9 -0
- package/dist/lib/agent-clients/next-steps.js +38 -0
- package/dist/lib/agent-clients/project-assets.js +45 -0
- package/dist/lib/agent-clients/reconcile.js +235 -0
- package/dist/lib/agent-clients/registry.js +72 -0
- package/dist/lib/agent-clients/schema.js +57 -0
- package/dist/lib/agent-clients/types.js +29 -0
- package/dist/lib/builtin-tuis.js +9 -14
- package/dist/lib/defaults.json +85 -73
- package/dist/lib/git/review-snapshot.js +25 -10
- package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
- package/dist/lib/init.js +47 -91
- package/dist/lib/internal/agent-client.js +117 -0
- package/dist/lib/internal/git-workflow.js +1 -1
- package/dist/lib/internal/platform-release-notes.js +53 -0
- package/dist/lib/internal/release-workflow.js +175 -17
- package/dist/lib/internal/task-orchestration.js +151 -0
- package/dist/lib/internal/task-review.js +65 -0
- package/dist/lib/merge.js +2 -1
- package/dist/lib/platform/adapters.js +38 -1
- package/dist/lib/platform/change-request-git-evidence.js +113 -0
- package/dist/lib/platform/github-release-notes.js +96 -0
- package/dist/lib/platform/issues.js +4 -2
- package/dist/lib/platform/merged-pr-equivalence.js +84 -0
- package/dist/lib/platform/pr-checks.js +43 -15
- package/dist/lib/platform/pull-requests.js +113 -7
- package/dist/lib/platform/release-notes.js +143 -0
- package/dist/lib/platform/releases.js +1 -1
- package/dist/lib/platform/verification-required.js +31 -9
- package/dist/lib/prompt.js +15 -3
- package/dist/lib/release/channels.js +4 -1
- package/dist/lib/release/workflow.js +4 -2
- package/dist/lib/remove-dir.js +25 -0
- package/dist/lib/run/tui.js +8 -2
- package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
- package/dist/lib/sandbox/build-proxy.js +63 -0
- package/dist/lib/sandbox/clipboard/linux.js +2 -1
- package/dist/lib/sandbox/commands/create.js +133 -189
- package/dist/lib/sandbox/commands/enter.js +17 -1
- package/dist/lib/sandbox/commands/prune.js +2 -2
- package/dist/lib/sandbox/commands/rebuild.js +24 -7
- package/dist/lib/sandbox/commands/rm.js +3 -2
- package/dist/lib/sandbox/config.js +21 -4
- package/dist/lib/sandbox/constants.js +3 -0
- package/dist/lib/sandbox/dockerfile.js +2 -1
- package/dist/lib/sandbox/image-build.js +2 -1
- package/dist/lib/sandbox/managed-fs.js +10 -5
- package/dist/lib/sandbox/recovery.js +52 -36
- package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
- package/dist/lib/sandbox/runtimes/base.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/java17.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/java21.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/node20.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/node22.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/python3.dockerfile +8 -1
- package/dist/lib/sandbox/shell.js +3 -2
- package/dist/lib/sandbox/tool-types.js +8 -0
- package/dist/lib/sandbox/tools.js +2 -126
- package/dist/lib/task/artifact-lifecycle.js +1 -49
- package/dist/lib/task/commands/decisions.js +50 -20
- package/dist/lib/task/commands/issue-body.js +10 -5
- package/dist/lib/task/delegation-receipts.js +107 -0
- package/dist/lib/task/events.js +101 -2
- package/dist/lib/task/issue-form.js +2 -0
- package/dist/lib/task/orchestration.js +420 -0
- package/dist/lib/task/review-artifacts.js +143 -59
- package/dist/lib/task/review-finalization.js +166 -0
- package/dist/lib/task/review-fingerprint.js +13 -0
- package/dist/lib/task/verification-checks.js +2 -1
- package/dist/lib/task/verification-engine.js +168 -23
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/verification.js +4 -2
- package/dist/lib/task/workspace-snapshot.js +34 -0
- package/dist/lib/update.js +42 -161
- package/lib/agent-client.ts +214 -0
- package/lib/agent-clients/adapter.ts +461 -0
- package/lib/agent-clients/adapters/claude-code.ts +70 -0
- package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
- package/lib/agent-clients/adapters/codex.ts +58 -0
- package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
- package/lib/agent-clients/adapters/index.ts +27 -0
- package/lib/agent-clients/adapters/opencode.ts +66 -0
- package/lib/agent-clients/config.ts +278 -0
- package/lib/agent-clients/custom-tuis.ts +149 -0
- package/lib/agent-clients/invocation.ts +19 -0
- package/lib/agent-clients/next-steps.ts +72 -0
- package/lib/agent-clients/project-assets.ts +96 -0
- package/lib/agent-clients/reconcile.ts +324 -0
- package/lib/agent-clients/registry.ts +144 -0
- package/lib/agent-clients/schema.ts +62 -0
- package/lib/agent-clients/types.ts +78 -0
- package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
- package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
- package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
- package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
- package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
- package/lib/builtin-tuis.ts +16 -15
- package/lib/defaults.json +24 -12
- package/lib/git/review-snapshot.ts +39 -9
- package/lib/git/reviewed-commit-equivalence.ts +135 -0
- package/lib/init.ts +53 -121
- package/lib/internal/agent-client.ts +131 -0
- package/lib/internal/git-workflow.ts +1 -1
- package/lib/internal/platform-release-notes.ts +55 -0
- package/lib/internal/release-workflow.ts +172 -18
- package/lib/internal/task-orchestration.ts +132 -0
- package/lib/internal/task-review.ts +65 -0
- package/lib/merge.ts +2 -1
- package/lib/platform/adapters.ts +142 -3
- package/lib/platform/change-request-git-evidence.ts +159 -0
- package/lib/platform/github-release-notes.ts +132 -0
- package/lib/platform/issues.ts +6 -4
- package/lib/platform/merged-pr-equivalence.ts +107 -0
- package/lib/platform/pr-checks.ts +57 -28
- package/lib/platform/pull-requests.ts +140 -25
- package/lib/platform/release-notes.ts +167 -0
- package/lib/platform/releases.ts +1 -1
- package/lib/platform/verification-required.ts +37 -9
- package/lib/prompt.ts +16 -3
- package/lib/release/channels.ts +4 -1
- package/lib/release/workflow.ts +4 -3
- package/lib/remove-dir.ts +28 -0
- package/lib/run/tui.ts +9 -1
- package/lib/sandbox/agent-client-reconciler.ts +378 -0
- package/lib/sandbox/build-proxy.ts +94 -0
- package/lib/sandbox/clipboard/linux.ts +2 -1
- package/lib/sandbox/commands/create.ts +188 -203
- package/lib/sandbox/commands/enter.ts +23 -1
- package/lib/sandbox/commands/prune.ts +2 -2
- package/lib/sandbox/commands/rebuild.ts +29 -7
- package/lib/sandbox/commands/rm.ts +3 -2
- package/lib/sandbox/config.ts +31 -4
- package/lib/sandbox/constants.ts +6 -0
- package/lib/sandbox/dockerfile.ts +2 -1
- package/lib/sandbox/image-build.ts +4 -1
- package/lib/sandbox/managed-fs.ts +18 -5
- package/lib/sandbox/recovery.ts +98 -67
- package/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
- package/lib/sandbox/runtimes/base.dockerfile +8 -1
- package/lib/sandbox/runtimes/java17.dockerfile +8 -1
- package/lib/sandbox/runtimes/java21.dockerfile +8 -1
- package/lib/sandbox/runtimes/node20.dockerfile +8 -1
- package/lib/sandbox/runtimes/node22.dockerfile +8 -1
- package/lib/sandbox/runtimes/python3.dockerfile +8 -1
- package/lib/sandbox/shell.ts +4 -2
- package/lib/sandbox/tool-types.ts +143 -0
- package/lib/sandbox/tools.ts +5 -157
- package/lib/task/artifact-lifecycle.ts +1 -38
- package/lib/task/commands/decisions.ts +53 -20
- package/lib/task/commands/issue-body.ts +10 -5
- package/lib/task/delegation-receipts.ts +170 -0
- package/lib/task/events.ts +111 -3
- package/lib/task/issue-form.ts +4 -0
- package/lib/task/orchestration.ts +543 -0
- package/lib/task/review-artifacts.ts +201 -69
- package/lib/task/review-finalization.ts +275 -0
- package/lib/task/review-fingerprint.ts +15 -1
- package/lib/task/verification-checks.ts +2 -1
- package/lib/task/verification-engine.ts +190 -25
- package/lib/task/verification-review.ts +2 -0
- package/lib/task/verification.ts +6 -3
- package/lib/task/workspace-snapshot.ts +36 -0
- package/lib/update.ts +48 -184
- package/package.json +2 -2
- package/templates/.agents/README.en.md +21 -20
- package/templates/.agents/README.zh-CN.md +21 -20
- package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/commit-and-pr.en.md +1 -0
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
- package/templates/.agents/rules/human-decision-context.en.md +14 -12
- package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
- package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
- package/templates/.agents/rules/next-step-output.en.md +16 -0
- package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
- package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
- package/templates/.agents/rules/release-commands.en.md +2 -2
- package/templates/.agents/rules/release-commands.github.en.md +15 -39
- package/templates/.agents/rules/release-commands.github.zh-CN.md +14 -38
- package/templates/.agents/rules/release-commands.zh-CN.md +2 -2
- package/templates/.agents/rules/review-handshake.en.md +4 -3
- package/templates/.agents/rules/review-handshake.zh-CN.md +4 -3
- package/templates/.agents/rules/review-method.en.md +113 -0
- package/templates/.agents/rules/review-method.zh-CN.md +98 -0
- package/templates/.agents/rules/testing-discipline.en.md +20 -2
- package/templates/.agents/rules/testing-discipline.zh-CN.md +20 -2
- package/templates/.agents/skills/analyze-task/SKILL.en.md +9 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +9 -6
- package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
- package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
- package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
- package/templates/.agents/skills/commit/SKILL.en.md +11 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
- package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -38
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +16 -37
- package/templates/.agents/skills/create-task/SKILL.en.md +15 -11
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +15 -11
- package/templates/.agents/skills/create-task/reference/context-capture.en.md +29 -0
- package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +29 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
- package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
- package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
- package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
- package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
- package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
- package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
- package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
- package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
- package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
- package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
- package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
- package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
- package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
- package/templates/.agents/skills/test/SKILL.en.md +4 -4
- package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
- package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
- package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
- package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
- package/templates/.agents/templates/task.en.md +18 -0
- package/templates/.agents/templates/task.zh-CN.md +18 -0
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
- package/templates/.claude/commands/run-task.en.md +8 -0
- package/templates/.claude/commands/run-task.zh-CN.md +8 -0
- package/templates/.claude/settings.json +24 -0
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
- package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
- package/templates/.opencode/commands/run-task.en.md +11 -0
- package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
|
@@ -10,7 +10,8 @@ import { pruneSandboxDanglingImages } from '../image-prune.js';
|
|
|
10
10
|
import { removeManagedDir, removeWorktreeDir } from '../managed-fs.js';
|
|
11
11
|
import { runOk, runSafe, runSafeEngine } from '../shell.js';
|
|
12
12
|
import { resolveTaskBranch } from '../task-resolver.js';
|
|
13
|
-
import {
|
|
13
|
+
import { toolConfigDirCandidates, toolProjectDirCandidates } from '../tools.js';
|
|
14
|
+
import { createSandboxCapabilityPlan } from '../agent-client-reconciler.js';
|
|
14
15
|
import { fetchSandboxRows } from './list-running.js';
|
|
15
16
|
import { lookupShortIdByBranch } from '../../task/short-id.js';
|
|
16
17
|
const USAGE = `Usage:
|
|
@@ -284,7 +285,7 @@ export async function rm(args) {
|
|
|
284
285
|
throw new Error(USAGE);
|
|
285
286
|
}
|
|
286
287
|
const config = loadConfig();
|
|
287
|
-
const tools =
|
|
288
|
+
const tools = [...createSandboxCapabilityPlan(config).cleanupInventory];
|
|
288
289
|
if (values.purge) {
|
|
289
290
|
await rmPurge(config, tools);
|
|
290
291
|
return;
|
|
@@ -3,6 +3,8 @@ import path from 'node:path';
|
|
|
3
3
|
import { homedir, platform } from 'node:os';
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
5
|
import pc from 'picocolors';
|
|
6
|
+
import { normalizeAgentClients } from '../agent-clients/config.js';
|
|
7
|
+
import { isAgentClientId } from '../agent-clients/types.js';
|
|
6
8
|
import { validateSandboxEngine } from './engine.js';
|
|
7
9
|
import { hostJoin } from './engines/wsl2-paths.js';
|
|
8
10
|
import { findRuntimeEngineMismatches } from './runtime-engines.js';
|
|
@@ -10,7 +12,7 @@ import { parseCustomTools } from './tools.js';
|
|
|
10
12
|
const DEFAULTS = Object.freeze({
|
|
11
13
|
engine: null,
|
|
12
14
|
runtimes: ['node22'],
|
|
13
|
-
tools: ['agent-infra'
|
|
15
|
+
tools: ['agent-infra'],
|
|
14
16
|
refreshIntervalDays: 7,
|
|
15
17
|
dockerfile: null,
|
|
16
18
|
vm: {
|
|
@@ -46,6 +48,18 @@ function cloneDefaults() {
|
|
|
46
48
|
vm: { ...DEFAULTS.vm }
|
|
47
49
|
};
|
|
48
50
|
}
|
|
51
|
+
function resolveSandboxToolIds(sandbox, agentClients, defaults) {
|
|
52
|
+
if (Array.isArray(sandbox.tools)) {
|
|
53
|
+
const tools = sandbox.tools.filter((tool) => typeof tool === 'string');
|
|
54
|
+
return agentClients.source === 'canonical'
|
|
55
|
+
? tools.filter((tool) => !isAgentClientId(tool))
|
|
56
|
+
: tools;
|
|
57
|
+
}
|
|
58
|
+
if (agentClients.remainingSandboxTools !== undefined) {
|
|
59
|
+
return [...agentClients.remainingSandboxTools];
|
|
60
|
+
}
|
|
61
|
+
return [...defaults];
|
|
62
|
+
}
|
|
49
63
|
export function loadConfig({ platformFn = platform, writeStderr = (chunk) => process.stderr.write(chunk) } = {}) {
|
|
50
64
|
const repoRoot = detectRepoRoot();
|
|
51
65
|
const home = homedir();
|
|
@@ -57,6 +71,8 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
57
71
|
throw new Error('No .agents/.airc.json found. Run "ai init" first.');
|
|
58
72
|
}
|
|
59
73
|
const airc = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
74
|
+
const sandboxInput = airc.sandbox;
|
|
75
|
+
const agentClients = normalizeAgentClients(airc);
|
|
60
76
|
const defaults = cloneDefaults();
|
|
61
77
|
const sandbox = airc.sandbox ?? {};
|
|
62
78
|
const engine = validateSandboxEngine(sandbox.engine ?? defaults.engine, { platformFn });
|
|
@@ -83,6 +99,7 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
83
99
|
}
|
|
84
100
|
}
|
|
85
101
|
const customTools = parseCustomTools(sandbox.customTools, { home });
|
|
102
|
+
const tools = resolveSandboxToolIds(sandbox, agentClients, defaults.tools);
|
|
86
103
|
return {
|
|
87
104
|
repoRoot,
|
|
88
105
|
configPath,
|
|
@@ -97,10 +114,10 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
97
114
|
dotfilesDir: hostJoin(home, '.agent-infra', 'dotfiles'),
|
|
98
115
|
engine,
|
|
99
116
|
runtimes,
|
|
100
|
-
tools
|
|
101
|
-
? [...sandbox.tools]
|
|
102
|
-
: defaults.tools,
|
|
117
|
+
tools,
|
|
103
118
|
customTools,
|
|
119
|
+
agentClientState: agentClients.state,
|
|
120
|
+
agentClientSource: agentClients.source,
|
|
104
121
|
refreshIntervalDays: asNonNegativeIntegerOrDefault(sandbox.refreshIntervalDays, defaults.refreshIntervalDays),
|
|
105
122
|
dockerfile,
|
|
106
123
|
vm: {
|
|
@@ -75,6 +75,9 @@ export function sandboxImageConfigLabel(config) {
|
|
|
75
75
|
export function sandboxImageRefreshLabel(config) {
|
|
76
76
|
return `${sandboxLabel(config)}.last-refresh`;
|
|
77
77
|
}
|
|
78
|
+
export function sandboxRuntimeCapabilityLabel(config) {
|
|
79
|
+
return `agent-infra.sandbox.runtime-capability.${config.project}`;
|
|
80
|
+
}
|
|
78
81
|
export function parsePositiveIntegerOption(value, optionName) {
|
|
79
82
|
if (value === undefined || value === null) {
|
|
80
83
|
return undefined;
|
|
@@ -3,6 +3,7 @@ import os from 'node:os';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { removeDirRecursive } from '../remove-dir.js';
|
|
6
7
|
const RUNTIMES_DIR = path.join(path.dirname(fileURLToPath(import.meta.url)), 'runtimes');
|
|
7
8
|
function listRuntimeFragments() {
|
|
8
9
|
return fs.readdirSync(RUNTIMES_DIR)
|
|
@@ -63,7 +64,7 @@ export function prepareDockerfile(config) {
|
|
|
63
64
|
path: tempPath,
|
|
64
65
|
signature: dockerfileSignature(config),
|
|
65
66
|
cleanup() {
|
|
66
|
-
|
|
67
|
+
removeDirRecursive(tempDir);
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
70
|
}
|
|
@@ -14,7 +14,7 @@ export function buildImageSignature(preparedDockerfile, tools) {
|
|
|
14
14
|
.digest('hex')
|
|
15
15
|
.slice(0, 12);
|
|
16
16
|
}
|
|
17
|
-
export function buildSandboxImageArgs(config, tools, dockerfilePath, imageSignature, { engine, runFn = runEngine, runSafeFn = runSafeEngine, env = process.env, refresh = false, lastRefresh } = {}) {
|
|
17
|
+
export function buildSandboxImageArgs(config, tools, dockerfilePath, imageSignature, { engine, runFn = runEngine, runSafeFn = runSafeEngine, env = process.env, refresh = false, lastRefresh, buildProxyArgs = [] } = {}) {
|
|
18
18
|
const selectedEngine = engine ?? detectEngine({ engine: config.engine });
|
|
19
19
|
const { uid: hostUid, gid: hostGid } = resolveBuildUid({
|
|
20
20
|
engine: selectedEngine,
|
|
@@ -39,6 +39,7 @@ export function buildSandboxImageArgs(config, tools, dockerfilePath, imageSignat
|
|
|
39
39
|
'--label',
|
|
40
40
|
`${sandboxImageConfigLabel(config)}=${imageSignature}`
|
|
41
41
|
];
|
|
42
|
+
args.push(...buildProxyArgs);
|
|
42
43
|
if (lastRefresh !== undefined) {
|
|
43
44
|
args.push('--label', `${sandboxImageRefreshLabel(config)}=${lastRefresh}`);
|
|
44
45
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
3
|
-
import { run } from './shell.js';
|
|
2
|
+
import { run, runSafe } from './shell.js';
|
|
3
|
+
import { removeDirRecursive } from '../remove-dir.js';
|
|
4
4
|
export function assertManagedPath(root, target) {
|
|
5
5
|
const resolvedRoot = path.resolve(root);
|
|
6
6
|
const resolvedTarget = path.resolve(target);
|
|
@@ -12,14 +12,19 @@ export function assertManagedPath(root, target) {
|
|
|
12
12
|
}
|
|
13
13
|
export function removeManagedDir(root, dir) {
|
|
14
14
|
assertManagedPath(root, dir);
|
|
15
|
-
|
|
15
|
+
removeDirRecursive(dir);
|
|
16
16
|
}
|
|
17
|
-
export function removeWorktreeDir(repoRoot, worktreeBase, dir) {
|
|
17
|
+
export function removeWorktreeDir(repoRoot, worktreeBase, dir, { runFn = run, runSafeFn = runSafe } = {}) {
|
|
18
18
|
try {
|
|
19
|
-
|
|
19
|
+
runFn('git', ['-C', repoRoot, 'worktree', 'remove', dir, '--force']);
|
|
20
20
|
}
|
|
21
21
|
catch {
|
|
22
|
+
// On WSL2 the worktree is registered under its `/mnt/<drive>/...` path, so
|
|
23
|
+
// `git worktree remove <windows-path>` cannot match it. Delete the managed
|
|
24
|
+
// directory directly, then prune the now-dangling worktree metadata so the
|
|
25
|
+
// branch is no longer reported as checked out.
|
|
22
26
|
removeManagedDir(worktreeBase, dir);
|
|
27
|
+
runSafeFn('git', ['-C', repoRoot, 'worktree', 'prune']);
|
|
23
28
|
}
|
|
24
29
|
}
|
|
25
30
|
//# sourceMappingURL=managed-fs.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { containerNameCandidates, sandboxBranchLabel, sandboxLabel } from './constants.js';
|
|
3
|
+
import { containerNameCandidates, sandboxBranchLabel, sandboxLabel, sandboxRuntimeCapabilityLabel } from './constants.js';
|
|
4
|
+
import { isAgentClientId } from '../agent-clients/types.js';
|
|
5
|
+
import { createSandboxCapabilityPlan } from './agent-client-reconciler.js';
|
|
4
6
|
import { toEnginePath } from './engines/wsl2-paths.js';
|
|
5
7
|
import { sandboxCoreBindMounts } from './mounts.js';
|
|
6
8
|
import { runEngine, runOkEngine, runVerboseEngine } from './shell.js';
|
|
@@ -17,6 +19,19 @@ export function classifySandboxRecovery(snapshot) {
|
|
|
17
19
|
message: 'Container identity does not match the requested sandbox branch.'
|
|
18
20
|
});
|
|
19
21
|
}
|
|
22
|
+
if (snapshot.runtimeCapabilityOk === false) {
|
|
23
|
+
findings.push({
|
|
24
|
+
repairKind: 'hard-failure',
|
|
25
|
+
message: 'Container runtime capability signature does not match the current sandbox plan.'
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
for (const mountPath of snapshot.unexpectedCapabilityMounts ?? []) {
|
|
29
|
+
findings.push({
|
|
30
|
+
repairKind: 'hard-failure',
|
|
31
|
+
message: `Disabled Agent Client capability remains mounted at ${mountPath}.`,
|
|
32
|
+
path: mountPath
|
|
33
|
+
});
|
|
34
|
+
}
|
|
20
35
|
for (const mount of snapshot.mounts) {
|
|
21
36
|
if (mount.actualType !== mount.expectedType
|
|
22
37
|
|| !mount.sourceMatches
|
|
@@ -74,25 +89,11 @@ export function classifySandboxRecovery(snapshot) {
|
|
|
74
89
|
path: '/home/devuser/.bash_aliases'
|
|
75
90
|
});
|
|
76
91
|
}
|
|
77
|
-
|
|
78
|
-
if (!
|
|
79
|
-
findings.push({
|
|
80
|
-
repairKind: 'hard-failure',
|
|
81
|
-
message: 'Codex is not available on PATH inside the sandbox.'
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
if (!snapshot.codex.stateWritable) {
|
|
92
|
+
for (const check of snapshot.agentClientChecks) {
|
|
93
|
+
if (check.applicable && !check.healthy) {
|
|
85
94
|
findings.push({
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
path: '/home/devuser/.codex'
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (snapshot.codex.promptsSourceExists && !snapshot.codex.promptsValid) {
|
|
92
|
-
findings.push({
|
|
93
|
-
repairKind: 'builtin-link',
|
|
94
|
-
message: 'Codex prompts link does not point to the workspace commands directory.',
|
|
95
|
-
path: '/home/devuser/.codex/prompts'
|
|
95
|
+
...check.finding,
|
|
96
|
+
...(check.repair === undefined ? {} : { repair: check.repair })
|
|
96
97
|
});
|
|
97
98
|
}
|
|
98
99
|
}
|
|
@@ -154,8 +155,7 @@ function hostSourceAccessible(hostPath, writable) {
|
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
157
|
function expectedMounts(params) {
|
|
157
|
-
const { config, branch, actualMounts } = params;
|
|
158
|
-
const tools = resolveTools(config);
|
|
158
|
+
const { config, branch, tools, actualMounts } = params;
|
|
159
159
|
const core = sandboxCoreBindMounts(config, branch).map((mount) => ({
|
|
160
160
|
path: mount.containerPath,
|
|
161
161
|
expectedType: 'bind',
|
|
@@ -174,7 +174,9 @@ function expectedMounts(params) {
|
|
|
174
174
|
}];
|
|
175
175
|
}));
|
|
176
176
|
const persistentTools = tools
|
|
177
|
-
.filter((tool) => !tool.tmpfs
|
|
177
|
+
.filter((tool) => !tool.tmpfs
|
|
178
|
+
&& (config.agentClientSource === 'canonical'
|
|
179
|
+
|| actualMounts.has(tool.containerMount)))
|
|
178
180
|
.map((tool) => ({
|
|
179
181
|
path: tool.containerMount,
|
|
180
182
|
expectedType: 'bind',
|
|
@@ -245,7 +247,8 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
245
247
|
});
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
|
-
const
|
|
250
|
+
const capabilityPlan = createSandboxCapabilityPlan(params.config);
|
|
251
|
+
const tools = [...capabilityPlan.tools];
|
|
249
252
|
const seeds = declaredTmpfsSeedEntries(tools).map((seed) => {
|
|
250
253
|
const mounted = mountsByDestination.get(seed.stagingPath)?.Type === 'bind';
|
|
251
254
|
return {
|
|
@@ -266,11 +269,18 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
266
269
|
}));
|
|
267
270
|
const labels = inspection.Config?.Labels ?? {};
|
|
268
271
|
const branchLabel = labels[sandboxBranchLabel(params.config)];
|
|
269
|
-
const
|
|
272
|
+
const selectedToolIds = new Set(tools.map((tool) => tool.id));
|
|
273
|
+
const enforceCanonicalPlan = params.config.agentClientSource === 'canonical';
|
|
274
|
+
const unexpectedCapabilityMounts = enforceCanonicalPlan
|
|
275
|
+
? capabilityPlan.cleanupInventory
|
|
276
|
+
.filter((tool) => isAgentClientId(tool.id) && !selectedToolIds.has(tool.id))
|
|
277
|
+
.map((tool) => tool.containerMount)
|
|
278
|
+
.filter((mountPath) => mountsByDestination.has(mountPath))
|
|
279
|
+
: [];
|
|
270
280
|
const mountSnapshots = expectedMounts({
|
|
271
281
|
config: params.config,
|
|
272
282
|
branch: params.branch,
|
|
273
|
-
|
|
283
|
+
tools,
|
|
274
284
|
actualMounts: mountsByDestination
|
|
275
285
|
}).map((expected) => {
|
|
276
286
|
const actual = mountsByDestination.get(expected.path);
|
|
@@ -304,18 +314,25 @@ export function collectSandboxRecoverySnapshot(params) {
|
|
|
304
314
|
identityOk: typeof inspection.Id === 'string'
|
|
305
315
|
&& inspection.Id.length > 0
|
|
306
316
|
&& branchLabel === params.branch,
|
|
317
|
+
runtimeCapabilityOk: enforceCanonicalPlan
|
|
318
|
+
? labels[sandboxRuntimeCapabilityLabel(params.config)] === capabilityPlan.runtimeSignature
|
|
319
|
+
: undefined,
|
|
320
|
+
unexpectedCapabilityMounts,
|
|
307
321
|
mounts: mountSnapshots,
|
|
308
322
|
tmpfs,
|
|
309
323
|
seeds,
|
|
310
324
|
aliasesReadable: probe(params.engine, params.container, 'test -r "$1"', ['/home/devuser/.bash_aliases'], runOkFn),
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
325
|
+
agentClientChecks: capabilityPlan.recoveryChecks.map(({ adapterId, check }) => {
|
|
326
|
+
const applicable = check.when === undefined || probe(params.engine, params.container, check.when.script, [...check.when.args], runOkFn, check.when.user);
|
|
327
|
+
return {
|
|
328
|
+
adapterId,
|
|
329
|
+
checkId: check.id,
|
|
330
|
+
applicable,
|
|
331
|
+
healthy: !applicable || probe(params.engine, params.container, check.probe.script, [...check.probe.args], runOkFn, check.probe.user),
|
|
332
|
+
finding: check.finding,
|
|
333
|
+
...(check.repair === undefined ? {} : { repair: check.repair })
|
|
334
|
+
};
|
|
335
|
+
})
|
|
319
336
|
};
|
|
320
337
|
}
|
|
321
338
|
export function prepareTmpfsMounts(params) {
|
|
@@ -394,10 +411,9 @@ function repairFindings(params) {
|
|
|
394
411
|
deps: params.deps
|
|
395
412
|
});
|
|
396
413
|
const runVerboseFn = params.deps?.runVerbose ?? runVerboseEngine;
|
|
397
|
-
|
|
414
|
+
for (const repair of params.findings.flatMap((finding) => finding.repair === undefined ? [] : [finding.repair])) {
|
|
398
415
|
runVerboseFn(params.engine, 'docker', [
|
|
399
|
-
'exec', '--user',
|
|
400
|
-
'/workspace/.codex/commands', '/home/devuser/.codex/prompts'
|
|
416
|
+
'exec', '--user', repair.user, params.container, repair.command, ...repair.args
|
|
401
417
|
]);
|
|
402
418
|
}
|
|
403
419
|
}
|
|
@@ -5,20 +5,41 @@ ENV NPM_CONFIG_PREFIX=/home/devuser/.npm-global
|
|
|
5
5
|
ENV PATH="/home/devuser/.npm-global/bin:${PATH}"
|
|
6
6
|
|
|
7
7
|
ARG AI_TOOL_PACKAGES=
|
|
8
|
-
RUN
|
|
8
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
9
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
10
|
+
--mount=type=secret,id=NO_PROXY \
|
|
11
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
12
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
13
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
14
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
15
|
+
set -e && \
|
|
9
16
|
for pkg in ${AI_TOOL_PACKAGES}; do \
|
|
10
17
|
npm install -g "$pkg"; \
|
|
11
18
|
done
|
|
12
19
|
|
|
13
20
|
ARG AI_TOOLS_SHELL_INSTALL_B64=
|
|
14
|
-
RUN
|
|
21
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
22
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
23
|
+
--mount=type=secret,id=NO_PROXY \
|
|
24
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
25
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
26
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
27
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
28
|
+
if [ -n "${AI_TOOLS_SHELL_INSTALL_B64}" ]; then \
|
|
15
29
|
set -e && \
|
|
16
30
|
echo "${AI_TOOLS_SHELL_INSTALL_B64}" | base64 -d > /tmp/ai-tools-install.sh && \
|
|
17
31
|
bash /tmp/ai-tools-install.sh && \
|
|
18
32
|
rm /tmp/ai-tools-install.sh; \
|
|
19
33
|
fi
|
|
20
34
|
|
|
21
|
-
RUN
|
|
35
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
36
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
37
|
+
--mount=type=secret,id=NO_PROXY \
|
|
38
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
39
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
40
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
41
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
42
|
+
npm install -g pyright
|
|
22
43
|
|
|
23
44
|
RUN mkdir -p /home/devuser/.local/share /home/devuser/.local/state
|
|
24
45
|
|
|
@@ -19,7 +19,14 @@ RUN if [ "${HOST_UID}" = "0" ]; then \
|
|
|
19
19
|
useradd -u ${HOST_UID} -g ${HOST_GID} -m -s /bin/bash devuser; \
|
|
20
20
|
fi
|
|
21
21
|
|
|
22
|
-
RUN
|
|
22
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
23
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
24
|
+
--mount=type=secret,id=NO_PROXY \
|
|
25
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
26
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
27
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
28
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
29
|
+
apt-get update && apt-get install -y \
|
|
23
30
|
curl wget git vim file jq \
|
|
24
31
|
build-essential ca-certificates gnupg lsb-release \
|
|
25
32
|
libevent-core-2.1-7 libncursesw6 libtinfo6 \
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
RUN
|
|
1
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
2
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
3
|
+
--mount=type=secret,id=NO_PROXY \
|
|
4
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
5
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
6
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
7
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
8
|
+
apt-get update && apt-get install -y \
|
|
2
9
|
openjdk-17-jdk maven \
|
|
3
10
|
&& rm -rf /var/lib/apt/lists/*
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
RUN
|
|
1
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
2
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
3
|
+
--mount=type=secret,id=NO_PROXY \
|
|
4
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
5
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
6
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
7
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
8
|
+
apt-get update && apt-get install -y \
|
|
2
9
|
openjdk-21-jdk maven \
|
|
3
10
|
&& rm -rf /var/lib/apt/lists/*
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
RUN
|
|
1
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
2
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
3
|
+
--mount=type=secret,id=NO_PROXY \
|
|
4
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
5
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
6
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
7
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
8
|
+
bash -o pipefail -c 'curl -fsSL --retry 5 --retry-delay 2 --retry-all-errors https://deb.nodesource.com/setup_20.x | bash -' && \
|
|
2
9
|
apt-get install -y nodejs && \
|
|
3
10
|
rm -rf /var/lib/apt/lists/*
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
RUN
|
|
1
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
2
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
3
|
+
--mount=type=secret,id=NO_PROXY \
|
|
4
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
5
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
6
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
7
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
8
|
+
bash -o pipefail -c 'curl -fsSL --retry 5 --retry-delay 2 --retry-all-errors https://deb.nodesource.com/setup_22.x | bash -' && \
|
|
2
9
|
apt-get install -y nodejs && \
|
|
3
10
|
rm -rf /var/lib/apt/lists/*
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
RUN
|
|
1
|
+
RUN --mount=type=secret,id=HTTP_PROXY \
|
|
2
|
+
--mount=type=secret,id=HTTPS_PROXY \
|
|
3
|
+
--mount=type=secret,id=NO_PROXY \
|
|
4
|
+
export HTTP_PROXY="$(cat /run/secrets/HTTP_PROXY 2>/dev/null || true)" && \
|
|
5
|
+
export HTTPS_PROXY="$(cat /run/secrets/HTTPS_PROXY 2>/dev/null || true)" && \
|
|
6
|
+
export NO_PROXY="$(cat /run/secrets/NO_PROXY 2>/dev/null || true)" && \
|
|
7
|
+
export http_proxy="${HTTP_PROXY}" https_proxy="${HTTPS_PROXY}" no_proxy="${NO_PROXY}" && \
|
|
8
|
+
apt-get update && apt-get install -y \
|
|
2
9
|
python3 python3-pip python3-venv \
|
|
3
10
|
&& rm -rf /var/lib/apt/lists/*
|
|
@@ -8,7 +8,8 @@ function normalizeOptions(opts = {}, stdio) {
|
|
|
8
8
|
cwd: opts.cwd,
|
|
9
9
|
encoding: opts.encoding,
|
|
10
10
|
stdio,
|
|
11
|
-
timeout: opts.timeout ?? DEFAULT_TIMEOUT_MS
|
|
11
|
+
timeout: opts.timeout ?? DEFAULT_TIMEOUT_MS,
|
|
12
|
+
env: opts.env
|
|
12
13
|
};
|
|
13
14
|
}
|
|
14
15
|
function resolveCommand(cmd) {
|
|
@@ -113,7 +114,7 @@ export function runSafe(cmd, args, opts = {}) {
|
|
|
113
114
|
export function commandForEngine(engine, cmd, args = []) {
|
|
114
115
|
if (engine === 'wsl2') {
|
|
115
116
|
const resolvedWrapper = resolveCommand('wsl.exe');
|
|
116
|
-
return { cmd: resolvedWrapper, args: ['--', cmd, ...args] };
|
|
117
|
+
return { cmd: resolvedWrapper, args: ['--exec', cmd, ...args] };
|
|
117
118
|
}
|
|
118
119
|
if (cmd === 'docker') {
|
|
119
120
|
const context = getAdapter(engine).dockerContext;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { createSandboxCapabilityPlan } from './agent-client-reconciler.js';
|
|
2
3
|
import { safeNameCandidates, sanitizeBranchName } from './constants.js';
|
|
3
4
|
import { hostJoin } from './engines/wsl2-paths.js';
|
|
4
5
|
export function tmpfsSeedStagingPath(toolId, index) {
|
|
@@ -20,108 +21,6 @@ export function declaredTmpfsSeedEntries(tools) {
|
|
|
20
21
|
})));
|
|
21
22
|
}
|
|
22
23
|
const TOOL_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
23
|
-
function createBuiltinTools(home, project) {
|
|
24
|
-
return {
|
|
25
|
-
'claude-code': {
|
|
26
|
-
id: 'claude-code',
|
|
27
|
-
name: 'Claude Code',
|
|
28
|
-
install: { type: 'npm', cmd: '@anthropic-ai/claude-code@latest' },
|
|
29
|
-
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'claude-code'),
|
|
30
|
-
containerMount: '/home/devuser/.claude',
|
|
31
|
-
versionCmd: 'claude --version',
|
|
32
|
-
setupHint: 'Authenticates via host credentials live-mounted at ~/.claude/.credentials.json',
|
|
33
|
-
// Claude Code stores user data (.claude.json — onboarding state, theme,
|
|
34
|
-
// workspace trust) at $HOME/.claude.json by default, which sits OUTSIDE
|
|
35
|
-
// the bind-mounted /home/devuser/.claude tree, so our preseeded
|
|
36
|
-
// .claude.json never gets read and the theme picker re-runs on every
|
|
37
|
-
// container start. Pinning CLAUDE_CONFIG_DIR to the tool mount relocates
|
|
38
|
-
// .claude.json into the same directory as .credentials.json/settings.json,
|
|
39
|
-
// letting ensureClaudeOnboarding actually take effect.
|
|
40
|
-
envVars: { CLAUDE_CONFIG_DIR: '/home/devuser/.claude' },
|
|
41
|
-
hostPreSeedDirs: [
|
|
42
|
-
{ hostDir: hostJoin(home, '.claude', 'plugins'), sandboxSubdir: 'plugins' }
|
|
43
|
-
],
|
|
44
|
-
pathRewriteFiles: [
|
|
45
|
-
'plugins/installed_plugins.json',
|
|
46
|
-
'plugins/known_marketplaces.json'
|
|
47
|
-
],
|
|
48
|
-
hostLiveMounts: [
|
|
49
|
-
{
|
|
50
|
-
hostPath: hostJoin(home, '.agent-infra', 'credentials', project, 'claude-code', '.credentials.json'),
|
|
51
|
-
containerSubpath: '.credentials.json'
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
|
-
codex: {
|
|
56
|
-
id: 'codex',
|
|
57
|
-
name: 'Codex',
|
|
58
|
-
install: { type: 'npm', cmd: '@openai/codex' },
|
|
59
|
-
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'codex'),
|
|
60
|
-
containerMount: '/home/devuser/.codex',
|
|
61
|
-
versionCmd: 'codex --version',
|
|
62
|
-
setupHint: 'Run codex once inside the container and choose Device Code login if needed.',
|
|
63
|
-
// codex churns ~/.codex/logs_2.sqlite heavily (upstream openai/codex#24275);
|
|
64
|
-
// a bind-mount would write-amplify onto the host SSD via virtiofs. Mount the
|
|
65
|
-
// codex home as tmpfs so those logs stay in RAM and die with the container.
|
|
66
|
-
// Seeded config (config.toml, model-catalogs) is copied into the tmpfs at
|
|
67
|
-
// startup; runtime files like logs_2.sqlite stay in RAM.
|
|
68
|
-
tmpfs: { size: '512m', seed: ['config.toml', 'model-catalogs'] },
|
|
69
|
-
hostLiveMounts: [
|
|
70
|
-
{ hostPath: hostJoin(home, '.codex', 'auth.json'), containerSubpath: 'auth.json' }
|
|
71
|
-
],
|
|
72
|
-
postSetupCmds: [
|
|
73
|
-
'test -d /workspace/.codex/commands && ln -sfn /workspace/.codex/commands /home/devuser/.codex/prompts || true'
|
|
74
|
-
]
|
|
75
|
-
},
|
|
76
|
-
opencode: {
|
|
77
|
-
id: 'opencode',
|
|
78
|
-
name: 'OpenCode',
|
|
79
|
-
install: { type: 'npm', cmd: 'opencode-ai' },
|
|
80
|
-
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'opencode'),
|
|
81
|
-
containerMount: '/home/devuser/.local/share/opencode',
|
|
82
|
-
versionCmd: 'opencode version',
|
|
83
|
-
setupHint: 'Configure OpenCode credentials inside the container before first use.',
|
|
84
|
-
// OpenCode reads opencode.json from $XDG_CONFIG_HOME/opencode by default,
|
|
85
|
-
// outside this tool mount. Pin the config file path so the inherited
|
|
86
|
-
// sandbox opencode.json is the one the TUI actually reads.
|
|
87
|
-
envVars: { OPENCODE_CONFIG: '/home/devuser/.local/share/opencode/opencode.json' },
|
|
88
|
-
hostLiveMounts: [
|
|
89
|
-
{
|
|
90
|
-
hostPath: hostJoin(home, '.local', 'share', 'opencode', 'auth.json'),
|
|
91
|
-
containerSubpath: 'auth.json'
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
},
|
|
95
|
-
'gemini-cli': {
|
|
96
|
-
id: 'gemini-cli',
|
|
97
|
-
name: 'Gemini CLI',
|
|
98
|
-
install: { type: 'npm', cmd: '@google/gemini-cli' },
|
|
99
|
-
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'gemini-cli'),
|
|
100
|
-
containerMount: '/home/devuser/.gemini',
|
|
101
|
-
versionCmd: 'gemini --version',
|
|
102
|
-
setupHint: 'Run gemini inside the container to finish authentication.',
|
|
103
|
-
hostLiveMounts: [
|
|
104
|
-
{ hostPath: hostJoin(home, '.gemini', 'oauth_creds.json'), containerSubpath: 'oauth_creds.json' }
|
|
105
|
-
],
|
|
106
|
-
hostPreSeedFiles: [
|
|
107
|
-
{ hostPath: hostJoin(home, '.gemini', 'settings.json'), sandboxName: 'settings.json' },
|
|
108
|
-
{ hostPath: hostJoin(home, '.gemini', 'google_accounts.json'), sandboxName: 'google_accounts.json' }
|
|
109
|
-
]
|
|
110
|
-
},
|
|
111
|
-
'agent-infra': {
|
|
112
|
-
id: 'agent-infra',
|
|
113
|
-
name: 'agent-infra CLI',
|
|
114
|
-
install: { type: 'npm', cmd: '@fitlab-ai/agent-infra@latest' },
|
|
115
|
-
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'agent-infra'),
|
|
116
|
-
containerMount: '/home/devuser/.agent-infra-cli',
|
|
117
|
-
versionCmd: 'ai version --raw',
|
|
118
|
-
setupHint: 'Provides the ai and agent-infra CLI commands inside the sandbox.'
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
export function builtinToolIds() {
|
|
123
|
-
return Object.keys(createBuiltinTools('', ''));
|
|
124
|
-
}
|
|
125
24
|
function validateTool(tool) {
|
|
126
25
|
if (!tool.id || !TOOL_ID_PATTERN.test(tool.id)) {
|
|
127
26
|
throw new Error(`Invalid sandbox tool id: ${String(tool.id)}`);
|
|
@@ -308,30 +207,7 @@ export function parseCustomTools(value, options) {
|
|
|
308
207
|
return value.map((entry, index) => parseCustomTool(entry, index, options));
|
|
309
208
|
}
|
|
310
209
|
export function resolveTools(config) {
|
|
311
|
-
|
|
312
|
-
const customs = config.customTools ?? [];
|
|
313
|
-
const seen = new Set();
|
|
314
|
-
for (const tool of customs) {
|
|
315
|
-
if (builtins[tool.id]) {
|
|
316
|
-
throw new Error(`Custom sandbox tool id "${tool.id}" collides with a built-in tool`);
|
|
317
|
-
}
|
|
318
|
-
if (seen.has(tool.id)) {
|
|
319
|
-
throw new Error(`Duplicate sandbox tool id "${tool.id}" in customTools`);
|
|
320
|
-
}
|
|
321
|
-
seen.add(tool.id);
|
|
322
|
-
}
|
|
323
|
-
const merged = { ...builtins };
|
|
324
|
-
for (const tool of customs) {
|
|
325
|
-
merged[tool.id] = tool;
|
|
326
|
-
}
|
|
327
|
-
return config.tools.map((id) => {
|
|
328
|
-
const tool = merged[id];
|
|
329
|
-
if (!tool) {
|
|
330
|
-
throw new Error(`Unknown sandbox tool: ${id}`);
|
|
331
|
-
}
|
|
332
|
-
validateTool(tool);
|
|
333
|
-
return tool;
|
|
334
|
-
});
|
|
210
|
+
return [...createSandboxCapabilityPlan(config).tools];
|
|
335
211
|
}
|
|
336
212
|
export function toolConfigDir(tool, project, branch) {
|
|
337
213
|
return hostJoin(tool.sandboxBase, project, sanitizeBranchName(branch));
|