@fitlab-ai/agent-infra 0.6.4 → 0.7.0
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 +63 -27
- package/README.zh-CN.md +61 -25
- package/bin/cli.ts +18 -6
- package/dist/bin/cli.js +20 -6
- package/dist/lib/cp.js +127 -0
- package/dist/lib/defaults.json +1 -0
- package/dist/lib/init.js +3 -0
- package/dist/lib/sandbox/clipboard/bridge.js +23 -4
- package/dist/lib/sandbox/clipboard/index.js +12 -3
- package/dist/lib/sandbox/commands/create.js +11 -2
- package/dist/lib/sandbox/commands/enter.js +29 -6
- package/dist/lib/sandbox/commands/list-running.js +108 -0
- package/dist/lib/sandbox/commands/ls.js +24 -45
- package/dist/lib/sandbox/commands/rebuild.js +15 -7
- package/dist/lib/sandbox/config.js +3 -0
- package/dist/lib/sandbox/index.js +6 -4
- package/dist/lib/sandbox/readme-scaffold.js +148 -0
- package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +12 -6
- package/dist/lib/sandbox/runtimes/base.dockerfile +3 -3
- package/dist/lib/sandbox/tools.js +213 -8
- package/dist/lib/update.js +12 -1
- package/lib/cp.ts +177 -0
- package/lib/defaults.json +1 -0
- package/lib/init.ts +10 -0
- package/lib/sandbox/clipboard/bridge.ts +23 -4
- package/lib/sandbox/clipboard/index.ts +12 -3
- package/lib/sandbox/commands/create.ts +18 -2
- package/lib/sandbox/commands/enter.ts +48 -6
- package/lib/sandbox/commands/list-running.ts +135 -0
- package/lib/sandbox/commands/ls.ts +28 -49
- package/lib/sandbox/commands/rebuild.ts +24 -7
- package/lib/sandbox/config.ts +7 -0
- package/lib/sandbox/index.ts +6 -4
- package/lib/sandbox/readme-scaffold.ts +177 -0
- package/lib/sandbox/runtimes/ai-tools.dockerfile +12 -6
- package/lib/sandbox/runtimes/base.dockerfile +3 -3
- package/lib/sandbox/tools.ts +248 -9
- package/lib/update.ts +15 -1
- package/package.json +1 -1
- package/templates/.agents/QUICKSTART.en.md +1 -1
- package/templates/.agents/QUICKSTART.zh-CN.md +1 -1
- package/templates/.agents/README.en.md +79 -2
- package/templates/.agents/README.zh-CN.md +79 -2
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.zh-CN.md +1 -1
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.github.en.md +6 -5
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +6 -5
- package/templates/.agents/rules/milestone-inference.github.en.md +2 -2
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +2 -2
- package/templates/.agents/rules/no-mid-flow-questions.en.md +57 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +57 -0
- package/templates/.agents/rules/pr-sync.github.en.md +4 -5
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +4 -5
- package/templates/.agents/rules/task-management.en.md +9 -6
- package/templates/.agents/rules/task-management.zh-CN.md +9 -6
- package/templates/.agents/rules/testing-discipline.en.md +2 -2
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -2
- package/templates/.agents/scripts/validate-artifact.js +1 -1
- package/templates/.agents/skills/analyze-task/SKILL.en.md +16 -4
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +16 -4
- package/templates/.agents/skills/check-task/SKILL.en.md +43 -32
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +42 -31
- package/templates/.agents/skills/code-task/SKILL.en.md +117 -0
- package/templates/.agents/skills/{implement-task → code-task}/SKILL.zh-CN.md +51 -24
- package/templates/.agents/skills/{implement-task → code-task}/config/verify.en.json +4 -4
- package/templates/.agents/skills/{implement-task → code-task}/config/verify.zh-CN.json +4 -4
- package/templates/.agents/skills/{implement-task → code-task}/reference/branch-management.zh-CN.md +2 -2
- package/templates/.agents/skills/{implement-task/reference/implementation-rules.en.md → code-task/reference/code-rules.en.md} +6 -6
- package/templates/.agents/skills/{implement-task/reference/implementation-rules.zh-CN.md → code-task/reference/code-rules.zh-CN.md} +3 -3
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +69 -0
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +69 -0
- package/templates/.agents/skills/{refine-task/reference/fix-workflow.en.md → code-task/reference/fix-mode.en.md} +12 -12
- package/templates/.agents/skills/{refine-task/reference/fix-workflow.zh-CN.md → code-task/reference/fix-mode.zh-CN.md} +8 -8
- package/templates/.agents/skills/code-task/reference/output-template.en.md +20 -0
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +20 -0
- package/templates/.agents/skills/{implement-task → code-task}/reference/report-template.en.md +4 -4
- package/templates/.agents/skills/{implement-task → code-task}/reference/report-template.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/scripts/detect-mode.js +370 -0
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +10 -6
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +10 -6
- package/templates/.agents/skills/complete-task/SKILL.en.md +5 -3
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/create-pr/SKILL.en.md +17 -1
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +17 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-issue/SKILL.en.md +3 -3
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/plan-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/restore-task/SKILL.en.md +4 -3
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +76 -0
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +102 -0
- package/templates/.agents/skills/review-analysis/config/verify.en.json +51 -0
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +51 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +87 -0
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +87 -0
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +90 -0
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +91 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +47 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +47 -0
- package/templates/.agents/skills/{review-task → review-code}/SKILL.en.md +11 -9
- package/templates/.agents/skills/{review-task → review-code}/SKILL.zh-CN.md +15 -9
- package/templates/.agents/skills/{review-task → review-code}/config/verify.en.json +7 -5
- package/templates/.agents/skills/{review-task → review-code}/config/verify.zh-CN.json +6 -4
- package/templates/.agents/skills/{review-task → review-code}/reference/output-templates.en.md +21 -17
- package/templates/.agents/skills/{review-task → review-code}/reference/output-templates.zh-CN.md +19 -15
- package/templates/.agents/skills/{review-task → review-code}/reference/report-template.en.md +5 -6
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +91 -0
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +48 -0
- package/templates/.agents/skills/{review-task → review-code}/reference/review-criteria.zh-CN.md +10 -4
- package/templates/.agents/skills/review-plan/SKILL.en.md +76 -0
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +102 -0
- package/templates/.agents/skills/{refine-task → review-plan}/config/verify.en.json +14 -10
- package/templates/.agents/skills/{refine-task → review-plan}/config/verify.zh-CN.json +14 -10
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +87 -0
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +87 -0
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +90 -0
- package/templates/.agents/skills/{review-task → review-plan}/reference/report-template.zh-CN.md +3 -3
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +47 -0
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +47 -0
- package/templates/.agents/skills/test/SKILL.en.md +2 -2
- package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -31
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +1 -0
- package/templates/.agents/templates/task.en.md +3 -3
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +126 -80
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +90 -44
- package/templates/.agents/workflows/feature-development.en.yaml +115 -70
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +92 -47
- package/templates/.agents/workflows/refactoring.en.yaml +123 -78
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +89 -44
- package/templates/.claude/commands/code-task.en.md +8 -0
- package/templates/.claude/commands/code-task.zh-CN.md +8 -0
- package/templates/.claude/commands/review-analysis.en.md +8 -0
- package/templates/.claude/commands/review-analysis.zh-CN.md +8 -0
- package/templates/.claude/commands/review-code.en.md +8 -0
- package/templates/.claude/commands/review-code.zh-CN.md +8 -0
- package/templates/.claude/commands/review-plan.en.md +8 -0
- package/templates/.claude/commands/review-plan.zh-CN.md +8 -0
- package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +1 -1
- package/templates/.gemini/commands/_project_/code-task.en.toml +8 -0
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +8 -0
- package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +1 -1
- package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +1 -1
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +8 -0
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +8 -0
- package/templates/.gemini/commands/_project_/review-code.en.toml +8 -0
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +8 -0
- package/templates/.gemini/commands/_project_/review-plan.en.toml +8 -0
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +8 -0
- package/templates/.opencode/commands/code-task.en.md +11 -0
- package/templates/.opencode/commands/code-task.zh-CN.md +11 -0
- package/templates/.opencode/commands/review-analysis.en.md +11 -0
- package/templates/.opencode/commands/review-analysis.zh-CN.md +11 -0
- package/templates/.opencode/commands/review-code.en.md +11 -0
- package/templates/.opencode/commands/review-code.zh-CN.md +11 -0
- package/templates/.opencode/commands/review-plan.en.md +11 -0
- package/templates/.opencode/commands/review-plan.zh-CN.md +11 -0
- package/templates/.agents/skills/implement-task/SKILL.en.md +0 -173
- package/templates/.agents/skills/implement-task/reference/output-template.en.md +0 -20
- package/templates/.agents/skills/implement-task/reference/output-template.zh-CN.md +0 -20
- package/templates/.agents/skills/refine-task/SKILL.en.md +0 -153
- package/templates/.agents/skills/refine-task/SKILL.zh-CN.md +0 -153
- package/templates/.agents/skills/refine-task/reference/report-template.en.md +0 -64
- package/templates/.agents/skills/refine-task/reference/report-template.zh-CN.md +0 -64
- package/templates/.agents/skills/review-task/reference/review-criteria.en.md +0 -42
- package/templates/.claude/commands/implement-task.en.md +0 -8
- package/templates/.claude/commands/implement-task.zh-CN.md +0 -8
- package/templates/.claude/commands/refine-task.en.md +0 -8
- package/templates/.claude/commands/refine-task.zh-CN.md +0 -8
- package/templates/.claude/commands/review-task.en.md +0 -8
- package/templates/.claude/commands/review-task.zh-CN.md +0 -8
- package/templates/.gemini/commands/_project_/implement-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/implement-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/refine-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/refine-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/review-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/review-task.zh-CN.toml +0 -8
- package/templates/.opencode/commands/implement-task.en.md +0 -11
- package/templates/.opencode/commands/implement-task.zh-CN.md +0 -11
- package/templates/.opencode/commands/refine-task.en.md +0 -11
- package/templates/.opencode/commands/refine-task.zh-CN.md +0 -11
- package/templates/.opencode/commands/review-task.en.md +0 -11
- package/templates/.opencode/commands/review-task.zh-CN.md +0 -11
- /package/templates/.agents/skills/{implement-task → code-task}/reference/branch-management.en.md +0 -0
|
@@ -8,12 +8,17 @@ import { prepareDockerfile } from '../dockerfile.ts';
|
|
|
8
8
|
import { sandboxImageConfigLabel, sandboxLabel } from '../constants.ts';
|
|
9
9
|
import { detectEngine, ensureDocker } from '../engine.ts';
|
|
10
10
|
import { runEngine, runOkEngine, runSafeEngine, runVerboseEngine } from '../shell.ts';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
imageSignatureFields,
|
|
13
|
+
resolveTools,
|
|
14
|
+
toolNpmPackagesArg,
|
|
15
|
+
toolShellInstallScriptBase64
|
|
16
|
+
} from '../tools.ts';
|
|
12
17
|
import type { SandboxTool } from '../tools.ts';
|
|
13
18
|
import { toEnginePath } from '../engines/wsl2-paths.ts';
|
|
14
19
|
import { resolveBuildUid } from '../engines/native.ts';
|
|
15
20
|
|
|
16
|
-
const USAGE = `Usage: ai sandbox rebuild [--quiet]`;
|
|
21
|
+
const USAGE = `Usage: ai sandbox rebuild [--quiet] [--refresh]`;
|
|
17
22
|
|
|
18
23
|
type PreparedDockerfile = ReturnType<typeof prepareDockerfile>;
|
|
19
24
|
type EngineRunFn = (engine: string, cmd: string, args: string[], opts?: { cwd?: string }) => string;
|
|
@@ -23,7 +28,7 @@ function buildSignature(preparedDockerfile: PreparedDockerfile, tools: SandboxTo
|
|
|
23
28
|
return createHash('sha256')
|
|
24
29
|
.update(JSON.stringify({
|
|
25
30
|
dockerfile: preparedDockerfile.signature,
|
|
26
|
-
tools: tools
|
|
31
|
+
tools: imageSignatureFields(tools)
|
|
27
32
|
}))
|
|
28
33
|
.digest('hex')
|
|
29
34
|
.slice(0, 12);
|
|
@@ -38,12 +43,14 @@ export function buildArgs(
|
|
|
38
43
|
engine,
|
|
39
44
|
runFn = runEngine,
|
|
40
45
|
runSafeFn = runSafeEngine,
|
|
41
|
-
env = process.env
|
|
46
|
+
env = process.env,
|
|
47
|
+
refresh = false
|
|
42
48
|
}: {
|
|
43
49
|
engine?: string;
|
|
44
50
|
runFn?: EngineRunFn;
|
|
45
51
|
runSafeFn?: EngineRunSafeFn;
|
|
46
52
|
env?: NodeJS.ProcessEnv;
|
|
53
|
+
refresh?: boolean;
|
|
47
54
|
} = {}
|
|
48
55
|
): string[] {
|
|
49
56
|
const selectedEngine = engine ?? detectEngine(config);
|
|
@@ -54,7 +61,7 @@ export function buildArgs(
|
|
|
54
61
|
env
|
|
55
62
|
});
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
const args = [
|
|
58
65
|
'build',
|
|
59
66
|
'-t',
|
|
60
67
|
config.imageName,
|
|
@@ -64,6 +71,8 @@ export function buildArgs(
|
|
|
64
71
|
`HOST_GID=${hostGid}`,
|
|
65
72
|
'--build-arg',
|
|
66
73
|
`AI_TOOL_PACKAGES=${toolNpmPackagesArg(tools)}`,
|
|
74
|
+
'--build-arg',
|
|
75
|
+
`AI_TOOLS_SHELL_INSTALL_B64=${toolShellInstallScriptBase64(tools)}`,
|
|
67
76
|
'--label',
|
|
68
77
|
sandboxLabel(config),
|
|
69
78
|
'--label',
|
|
@@ -72,6 +81,12 @@ export function buildArgs(
|
|
|
72
81
|
toEnginePath(selectedEngine, dockerfilePath),
|
|
73
82
|
toEnginePath(selectedEngine, config.repoRoot)
|
|
74
83
|
];
|
|
84
|
+
|
|
85
|
+
if (refresh) {
|
|
86
|
+
args.splice(1, 0, '--no-cache', '--pull');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return args;
|
|
75
90
|
}
|
|
76
91
|
|
|
77
92
|
function removeImageIfPresent(imageName: string, engine: string): void {
|
|
@@ -86,6 +101,7 @@ export async function rebuild(args: string[]): Promise<void> {
|
|
|
86
101
|
allowPositionals: true,
|
|
87
102
|
strict: true,
|
|
88
103
|
options: {
|
|
104
|
+
refresh: { type: 'boolean' },
|
|
89
105
|
quiet: { type: 'boolean', short: 'q' },
|
|
90
106
|
help: { type: 'boolean', short: 'h' }
|
|
91
107
|
}
|
|
@@ -101,6 +117,7 @@ export async function rebuild(args: string[]): Promise<void> {
|
|
|
101
117
|
const preparedDockerfile = prepareDockerfile(config);
|
|
102
118
|
const imageSignature = buildSignature(preparedDockerfile, tools);
|
|
103
119
|
const quiet = values.quiet ?? false;
|
|
120
|
+
const refresh = values.refresh ?? false;
|
|
104
121
|
const engine = detectEngine(config);
|
|
105
122
|
|
|
106
123
|
await ensureDocker(config, undefined);
|
|
@@ -113,7 +130,7 @@ export async function rebuild(args: string[]): Promise<void> {
|
|
|
113
130
|
removeImageIfPresent(config.imageName, engine);
|
|
114
131
|
spinner.stop('Old image removed');
|
|
115
132
|
spinner.start('Building image...');
|
|
116
|
-
runEngine(engine, 'docker', buildArgs(config, tools, preparedDockerfile.path, imageSignature, { engine }), {
|
|
133
|
+
runEngine(engine, 'docker', buildArgs(config, tools, preparedDockerfile.path, imageSignature, { engine, refresh }), {
|
|
117
134
|
cwd: config.repoRoot
|
|
118
135
|
});
|
|
119
136
|
spinner.stop(pc.green('Sandbox image rebuilt'));
|
|
@@ -124,7 +141,7 @@ export async function rebuild(args: string[]): Promise<void> {
|
|
|
124
141
|
runVerboseEngine(
|
|
125
142
|
engine,
|
|
126
143
|
'docker',
|
|
127
|
-
buildArgs(config, tools, preparedDockerfile.path, imageSignature, { engine }),
|
|
144
|
+
buildArgs(config, tools, preparedDockerfile.path, imageSignature, { engine, refresh }),
|
|
128
145
|
{ cwd: config.repoRoot }
|
|
129
146
|
);
|
|
130
147
|
p.log.success(pc.green('Sandbox image rebuilt'));
|
package/lib/sandbox/config.ts
CHANGED
|
@@ -6,6 +6,8 @@ import pc from 'picocolors';
|
|
|
6
6
|
import { validateSandboxEngine } from './engine.ts';
|
|
7
7
|
import { hostJoin } from './engines/wsl2-paths.ts';
|
|
8
8
|
import { findRuntimeEngineMismatches } from './runtime-engines.ts';
|
|
9
|
+
import { parseCustomTools } from './tools.ts';
|
|
10
|
+
import type { SandboxTool } from './tools.ts';
|
|
9
11
|
|
|
10
12
|
const DEFAULTS = Object.freeze({
|
|
11
13
|
engine: null,
|
|
@@ -26,6 +28,7 @@ type SandboxConfigInput = {
|
|
|
26
28
|
engine?: string | null;
|
|
27
29
|
runtimes?: string[];
|
|
28
30
|
tools?: string[];
|
|
31
|
+
customTools?: unknown;
|
|
29
32
|
dockerfile?: string | null;
|
|
30
33
|
vm?: Record<string, unknown>;
|
|
31
34
|
};
|
|
@@ -51,6 +54,7 @@ export type SandboxConfig = {
|
|
|
51
54
|
engine: string | null;
|
|
52
55
|
runtimes: string[];
|
|
53
56
|
tools: string[];
|
|
57
|
+
customTools: SandboxTool[];
|
|
54
58
|
dockerfile: string | null;
|
|
55
59
|
vm: SandboxVmConfig;
|
|
56
60
|
};
|
|
@@ -136,6 +140,8 @@ export function loadConfig({
|
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
|
|
143
|
+
const customTools = parseCustomTools(sandbox.customTools, { home });
|
|
144
|
+
|
|
139
145
|
return {
|
|
140
146
|
repoRoot,
|
|
141
147
|
configPath,
|
|
@@ -153,6 +159,7 @@ export function loadConfig({
|
|
|
153
159
|
tools: Array.isArray(sandbox.tools) && sandbox.tools.length > 0
|
|
154
160
|
? [...sandbox.tools]
|
|
155
161
|
: defaults.tools,
|
|
162
|
+
customTools,
|
|
156
163
|
dockerfile,
|
|
157
164
|
vm: {
|
|
158
165
|
cpu: asPositiveNumberOrNull(sandbox.vm?.cpu) ?? defaults.vm.cpu,
|
package/lib/sandbox/index.ts
CHANGED
|
@@ -2,13 +2,15 @@ const USAGE = `Usage: ai sandbox <command> [options]
|
|
|
2
2
|
|
|
3
3
|
Commands:
|
|
4
4
|
create <branch> [base] Create a sandbox (VM + image + worktree + container)
|
|
5
|
-
exec <branch> [cmd...]
|
|
6
|
-
|
|
5
|
+
exec <branch | '#N'> [cmd...]
|
|
6
|
+
Enter sandbox or run a command (use leftmost '#' column from 'ls')
|
|
7
7
|
ls List sandboxes for the current project
|
|
8
|
-
rm <branch> [--all] Remove a sandbox or all sandboxes
|
|
9
8
|
prune [--dry-run] Remove orphaned per-branch state dirs
|
|
9
|
+
rebuild [--quiet] [--refresh]
|
|
10
|
+
Rebuild the sandbox image (--refresh pulls base + tools)
|
|
11
|
+
refresh Sync host Claude Code credentials to all sandbox copies
|
|
12
|
+
rm <branch> [--all] Remove a sandbox or all sandboxes
|
|
10
13
|
vm status|start|stop Manage the sandbox VM (macOS) or check the backend (Windows)
|
|
11
|
-
rebuild [--quiet] Rebuild the sandbox image
|
|
12
14
|
|
|
13
15
|
Run 'ai sandbox <command> --help' for details.`;
|
|
14
16
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { shareBranchDir, shareCommonDir } from './constants.ts';
|
|
4
|
+
|
|
5
|
+
type ScaffoldResult = { created: boolean; path: string };
|
|
6
|
+
type WriteStderr = (chunk: string) => void;
|
|
7
|
+
type ScaffoldFs = Pick<typeof fs, 'mkdirSync' | 'writeFileSync'>;
|
|
8
|
+
type ScaffoldOptions = {
|
|
9
|
+
writeStderr?: WriteStderr;
|
|
10
|
+
fsModule?: ScaffoldFs;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const DOTFILES_README = `# User-level dotfiles channel
|
|
14
|
+
|
|
15
|
+
This directory is mounted **read-only** into every sandbox container at
|
|
16
|
+
\`/dotfiles\`. On entry, \`sandbox-dotfiles-link\` mirrors every file here as a
|
|
17
|
+
symlink under \`$HOME\` (e.g. \`.tmux.conf\` -> \`/home/devuser/.tmux.conf\`),
|
|
18
|
+
overriding image defaults so your editor, shell, and tool preferences follow
|
|
19
|
+
you across \`ai sandbox destroy + create\`.
|
|
20
|
+
|
|
21
|
+
See: https://github.com/fitlab-ai/agent-infra/blob/main/README.md#user-level-dotfiles-channel
|
|
22
|
+
|
|
23
|
+
Common usage - drop files or symlinks here:
|
|
24
|
+
|
|
25
|
+
\`\`\`sh
|
|
26
|
+
# Real files
|
|
27
|
+
echo "set -g mouse on" > ~/.agent-infra/dotfiles/.tmux.conf
|
|
28
|
+
|
|
29
|
+
# Symlinks to live host paths
|
|
30
|
+
ln -s ~/.tmux.conf ~/.agent-infra/dotfiles/.tmux.conf
|
|
31
|
+
ln -s ~/.config/lazygit ~/.agent-infra/dotfiles/.config/lazygit
|
|
32
|
+
\`\`\`
|
|
33
|
+
|
|
34
|
+
> Do **not** put secrets here. Use the dedicated SSH / credential mounts.
|
|
35
|
+
|
|
36
|
+
If you delete this file, the next \`ai sandbox create\` will re-create it
|
|
37
|
+
verbatim. To stop seeing it, edit or empty the file in place - the scaffold
|
|
38
|
+
only writes \`README.md\` when it is missing, never when it already exists.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
# 用户级 dotfiles 通道
|
|
43
|
+
|
|
44
|
+
该目录被以**只读**方式挂载到每个 sandbox 容器的 \`/dotfiles\`。容器启动时,
|
|
45
|
+
\`sandbox-dotfiles-link\` 会把这里的每个文件 \`ln -sfn\` 到 \`$HOME\` 对应路径
|
|
46
|
+
(例如 \`.tmux.conf -> /home/devuser/.tmux.conf\`),覆盖镜像默认值,让你的编辑器、
|
|
47
|
+
shell、工具偏好跨 \`ai sandbox destroy + create\` 持久存在。
|
|
48
|
+
|
|
49
|
+
参考:https://github.com/fitlab-ai/agent-infra/blob/main/README.zh-CN.md#用户级-dotfiles-通道
|
|
50
|
+
|
|
51
|
+
常见用法:把文件或符号链接放进来:
|
|
52
|
+
|
|
53
|
+
\`\`\`sh
|
|
54
|
+
# 直接放文件
|
|
55
|
+
echo "set -g mouse on" > ~/.agent-infra/dotfiles/.tmux.conf
|
|
56
|
+
|
|
57
|
+
# 用符号链接指向 host 实际文件
|
|
58
|
+
ln -s ~/.tmux.conf ~/.agent-infra/dotfiles/.tmux.conf
|
|
59
|
+
ln -s ~/.config/lazygit ~/.agent-infra/dotfiles/.config/lazygit
|
|
60
|
+
\`\`\`
|
|
61
|
+
|
|
62
|
+
> **不要**在此放任何凭证。SSH / 凭证请使用专用挂载通道。
|
|
63
|
+
|
|
64
|
+
如果你删除该文件,下一次 \`ai sandbox create\` 会原样重新生成。如果你不想再
|
|
65
|
+
看到它,**就地编辑或清空内容**即可:scaffold 仅在 \`README.md\` **缺失**时
|
|
66
|
+
写入,文件存在(哪怕被清空)就不会被重写。
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const SHARE_COMMON_README = `# /share/common - host <-> sandbox shared scratch (cross-branch)
|
|
70
|
+
|
|
71
|
+
This directory is mounted **read-write** into every sandbox container of this
|
|
72
|
+
project at \`/share/common\`, regardless of branch. Drop files here to share
|
|
73
|
+
between host and any sandbox without polluting the git worktree.
|
|
74
|
+
|
|
75
|
+
See: https://github.com/fitlab-ai/agent-infra/blob/main/README.md#host-sandbox-file-exchange
|
|
76
|
+
|
|
77
|
+
This file is safe to delete; the next \`ai sandbox create\` will re-create it.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
# /share/common - 宿主 <-> sandbox 共享暂存(跨分支)
|
|
82
|
+
|
|
83
|
+
该目录被以**读写**方式挂载到本项目所有 sandbox 容器的 \`/share/common\`,
|
|
84
|
+
跨分支可见。可用来在宿主和任意 sandbox 之间传文件,无需弄脏 git worktree。
|
|
85
|
+
|
|
86
|
+
参考:https://github.com/fitlab-ai/agent-infra/blob/main/README.zh-CN.md#宿主-沙箱文件交换
|
|
87
|
+
|
|
88
|
+
该文件可以安全删除;下一次 \`ai sandbox create\` 会重新生成。
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const SHARE_BRANCH_README = `# /share/branch - host <-> sandbox shared scratch (branch-exclusive)
|
|
92
|
+
|
|
93
|
+
This directory is mounted **read-write** into the sandbox container of this
|
|
94
|
+
project's current branch at \`/share/branch\`. Files here are exclusive to this
|
|
95
|
+
branch's sandbox and do not leak across branches.
|
|
96
|
+
|
|
97
|
+
See: https://github.com/fitlab-ai/agent-infra/blob/main/README.md#host-sandbox-file-exchange
|
|
98
|
+
|
|
99
|
+
This file is safe to delete; the next \`ai sandbox create\` will re-create it.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
# /share/branch - 宿主 <-> sandbox 共享暂存(分支独占)
|
|
104
|
+
|
|
105
|
+
该目录被以**读写**方式挂载到本项目当前分支 sandbox 容器的 \`/share/branch\`,
|
|
106
|
+
仅当前分支可见,不会跨分支泄漏。
|
|
107
|
+
|
|
108
|
+
参考:https://github.com/fitlab-ai/agent-infra/blob/main/README.zh-CN.md#宿主-沙箱文件交换
|
|
109
|
+
|
|
110
|
+
该文件可以安全删除;下一次 \`ai sandbox create\` 会重新生成。
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
function errorDetail(error: unknown): string {
|
|
114
|
+
return error instanceof Error ? error.message : 'unknown error';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function errorCode(error: unknown): string {
|
|
118
|
+
return typeof error === 'object' && error !== null && 'code' in error
|
|
119
|
+
? String(error.code)
|
|
120
|
+
: '';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function ensureFile(target: string, content: string, options: ScaffoldOptions): ScaffoldResult {
|
|
124
|
+
const writeStderr = options.writeStderr ?? ((chunk) => process.stderr.write(chunk));
|
|
125
|
+
const fsModule = options.fsModule ?? fs;
|
|
126
|
+
const result: ScaffoldResult = { created: false, path: target };
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
fsModule.mkdirSync(path.dirname(target), { recursive: true });
|
|
130
|
+
} catch (error) {
|
|
131
|
+
writeStderr(`sandbox-readme-scaffold: skipping ${target} (${errorDetail(error)})\n`);
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
fsModule.writeFileSync(target, content, { encoding: 'utf8', flag: 'wx' });
|
|
137
|
+
result.created = true;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
if (errorCode(error) === 'EEXIST') {
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
writeStderr(`sandbox-readme-scaffold: skipping ${target} (${errorDetail(error)})\n`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function ensureDotfilesReadme(dotfilesDir: string, options: ScaffoldOptions = {}): ScaffoldResult {
|
|
149
|
+
return ensureFile(path.join(dotfilesDir, 'README.md'), DOTFILES_README, options);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function ensureShareCommonReadme(
|
|
153
|
+
config: { shareBase: string },
|
|
154
|
+
options: ScaffoldOptions = {}
|
|
155
|
+
): ScaffoldResult {
|
|
156
|
+
return ensureFile(path.join(shareCommonDir(config), 'README.md'), SHARE_COMMON_README, options);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function ensureShareBranchReadme(
|
|
160
|
+
config: { shareBase: string },
|
|
161
|
+
branch: string,
|
|
162
|
+
options: ScaffoldOptions = {}
|
|
163
|
+
): ScaffoldResult {
|
|
164
|
+
return ensureFile(path.join(shareBranchDir(config, branch), 'README.md'), SHARE_BRANCH_README, options);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function ensureSandboxDiscoveryReadmes(
|
|
168
|
+
config: { shareBase: string; dotfilesDir: string },
|
|
169
|
+
branch: string,
|
|
170
|
+
options: ScaffoldOptions = {}
|
|
171
|
+
): ScaffoldResult[] {
|
|
172
|
+
return [
|
|
173
|
+
ensureDotfilesReadme(config.dotfilesDir, options),
|
|
174
|
+
ensureShareCommonReadme(config, options),
|
|
175
|
+
ensureShareBranchReadme(config, branch, options)
|
|
176
|
+
];
|
|
177
|
+
}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
USER devuser
|
|
2
|
+
ENV DISABLE_UPDATES=1
|
|
3
|
+
ENV OPENCODE_DISABLE_AUTOUPDATE=1
|
|
2
4
|
ENV NPM_CONFIG_PREFIX=/home/devuser/.npm-global
|
|
3
5
|
ENV PATH="/home/devuser/.npm-global/bin:${PATH}"
|
|
4
6
|
|
|
5
|
-
ARG AI_TOOL_PACKAGES
|
|
6
|
-
RUN
|
|
7
|
-
echo "AI_TOOL_PACKAGES build arg is required"; \
|
|
8
|
-
exit 1; \
|
|
9
|
-
fi && \
|
|
10
|
-
set -e && \
|
|
7
|
+
ARG AI_TOOL_PACKAGES=
|
|
8
|
+
RUN set -e && \
|
|
11
9
|
for pkg in ${AI_TOOL_PACKAGES}; do \
|
|
12
10
|
npm install -g "$pkg"; \
|
|
13
11
|
done
|
|
14
12
|
|
|
13
|
+
ARG AI_TOOLS_SHELL_INSTALL_B64=
|
|
14
|
+
RUN if [ -n "${AI_TOOLS_SHELL_INSTALL_B64}" ]; then \
|
|
15
|
+
set -e && \
|
|
16
|
+
echo "${AI_TOOLS_SHELL_INSTALL_B64}" | base64 -d > /tmp/ai-tools-install.sh && \
|
|
17
|
+
bash /tmp/ai-tools-install.sh && \
|
|
18
|
+
rm /tmp/ai-tools-install.sh; \
|
|
19
|
+
fi
|
|
20
|
+
|
|
15
21
|
RUN npm install -g pyright
|
|
16
22
|
|
|
17
23
|
RUN mkdir -p /home/devuser/.local/share /home/devuser/.local/state
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
FROM ubuntu:
|
|
1
|
+
FROM ubuntu:24.04
|
|
2
2
|
|
|
3
3
|
LABEL description="AI coding sandbox"
|
|
4
4
|
|
|
@@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y \
|
|
|
28
28
|
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
|
29
29
|
> /etc/apt/sources.list.d/github-cli.list \
|
|
30
30
|
&& apt-get update && apt-get install -y gh \
|
|
31
|
-
&& TMUX_VERSION=3.
|
|
31
|
+
&& TMUX_VERSION=3.6b \
|
|
32
32
|
&& wget -qO /tmp/tmux.tar.gz \
|
|
33
33
|
"https://github.com/tmux/tmux/releases/download/${TMUX_VERSION}/tmux-${TMUX_VERSION}.tar.gz" \
|
|
34
34
|
&& tar xzf /tmp/tmux.tar.gz -C /tmp \
|
|
@@ -126,7 +126,7 @@ find . -type f -print | while IFS= read -r rel; do
|
|
|
126
126
|
.config/opencode|.config/opencode/*|\
|
|
127
127
|
.local/share/opencode|.local/share/opencode/*|\
|
|
128
128
|
.host-shell-config|.host-shell-config/*|\
|
|
129
|
-
.gitconfig|.gitignore_global|.stCommitMsg|.bash_aliases)
|
|
129
|
+
.gitconfig|.gitignore_global|.stCommitMsg|.bash_aliases|README.md)
|
|
130
130
|
continue ;;
|
|
131
131
|
esac
|
|
132
132
|
|