Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

115 lines
3.1 KiB
JavaScript

import { spawn } from "node:child_process";
import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { isAbsolute, join, resolve } from "node:path";
const projectRootEnvironment = "TUTTI_AGENT_SESSION_REPLAY_PROJECT_ROOT";
const temporaryProjectPrefix = "tutti-agent-session-rec-";
export function resolveAgentSessionReplayProjectRoot() {
const fromEnvironment = process.env[projectRootEnvironment]?.trim();
if (fromEnvironment) {
if (!isAbsolute(fromEnvironment)) {
throw new Error(`${projectRootEnvironment} must be an absolute path`);
}
return resolve(fromEnvironment);
}
// Pure helpers may resolve portable paths before the CLI acquires its
// run-scoped project. Keep that fallback outside the product checkout.
return join(tmpdir(), "tutti-agent-session-rec", `unbound-${process.pid}`);
}
export async function acquireAgentSessionReplayProjectRoot({
keepRuntime = false
} = {}) {
const previous = process.env[projectRootEnvironment];
if (previous?.trim()) {
const root = resolveAgentSessionReplayProjectRoot();
await mkdir(root, { recursive: true });
return {
owned: false,
root,
async dispose() {}
};
}
const root = await mkdtemp(join(tmpdir(), temporaryProjectPrefix));
try {
await initializeTemporaryProject(root);
} catch (error) {
await rm(root, { force: true, recursive: true });
throw error;
}
process.env[projectRootEnvironment] = root;
let disposed = false;
return {
owned: true,
root,
async dispose() {
if (disposed) return;
disposed = true;
if (previous === undefined) {
delete process.env[projectRootEnvironment];
} else {
process.env[projectRootEnvironment] = previous;
}
if (!keepRuntime) {
await rm(root, { force: true, recursive: true });
}
}
};
}
async function initializeTemporaryProject(root) {
await runGit(root, ["init", "--quiet"]);
await writeFile(
join(root, "README.md"),
[
"# Tutti session-replay temporary project",
"",
"This run-scoped project is intentionally outside the product checkout.",
""
].join("\n")
);
await runGit(root, ["add", "README.md"]);
await runGit(root, [
"-c",
"user.name=Tutti Session Replay",
"-c",
"user.email=session-replay@tutti.invalid",
"commit",
"--quiet",
"-m",
"chore: initialize session-replay project"
]);
await access(join(root, ".git"));
}
function runGit(cwd, args) {
return new Promise((resolveRun, rejectRun) => {
const child = spawn("git", args, {
cwd,
env: process.env,
stdio: ["ignore", "ignore", "pipe"]
});
let stderr = "";
child.stderr.on("data", (chunk) => {
stderr += chunk.toString();
});
child.once("error", rejectRun);
child.once("exit", (code, signal) => {
if (code === 0) {
resolveRun();
return;
}
rejectRun(
new Error(
`git ${args.join(" ")} failed (${code ?? signal ?? "unknown"})${
stderr.trim() ? `: ${stderr.trim()}` : ""
}`
)
);
});
});
}