@agentteams/runner 0.0.46
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/dist/api-client.d.ts +22 -0
- package/dist/api-client.js +201 -0
- package/dist/api-client.js.map +1 -0
- package/dist/api-client.test.d.ts +1 -0
- package/dist/api-client.test.js +118 -0
- package/dist/api-client.test.js.map +1 -0
- package/dist/autostart.d.ts +19 -0
- package/dist/autostart.js +359 -0
- package/dist/autostart.js.map +1 -0
- package/dist/autostart.test.d.ts +1 -0
- package/dist/autostart.test.js +42 -0
- package/dist/autostart.test.js.map +1 -0
- package/dist/commands/cleanup.d.ts +1 -0
- package/dist/commands/cleanup.js +12 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +57 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/restart.d.ts +1 -0
- package/dist/commands/restart.js +7 -0
- package/dist/commands/restart.js.map +1 -0
- package/dist/commands/start.d.ts +1 -0
- package/dist/commands/start.js +34 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +20 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +1 -0
- package/dist/commands/stop.js +21 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/uninstall.d.ts +1 -0
- package/dist/commands/uninstall.js +21 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.js +58 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/update.test.d.ts +1 -0
- package/dist/commands/update.test.js +104 -0
- package/dist/commands/update.test.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +69 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +1 -0
- package/dist/config.test.js +133 -0
- package/dist/config.test.js.map +1 -0
- package/dist/daemon-control.d.ts +21 -0
- package/dist/daemon-control.js +58 -0
- package/dist/daemon-control.js.map +1 -0
- package/dist/daemon-control.test.d.ts +1 -0
- package/dist/daemon-control.test.js +48 -0
- package/dist/daemon-control.test.js.map +1 -0
- package/dist/executable.d.ts +25 -0
- package/dist/executable.js +141 -0
- package/dist/executable.js.map +1 -0
- package/dist/executable.test.d.ts +1 -0
- package/dist/executable.test.js +57 -0
- package/dist/executable.test.js.map +1 -0
- package/dist/handlers/trigger-handler.d.ts +25 -0
- package/dist/handlers/trigger-handler.js +308 -0
- package/dist/handlers/trigger-handler.js.map +1 -0
- package/dist/handlers/trigger-handler.test.d.ts +1 -0
- package/dist/handlers/trigger-handler.test.js +496 -0
- package/dist/handlers/trigger-handler.test.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +5 -0
- package/dist/logger.js +25 -0
- package/dist/logger.js.map +1 -0
- package/dist/pid.d.ts +8 -0
- package/dist/pid.js +49 -0
- package/dist/pid.js.map +1 -0
- package/dist/poller.d.ts +20 -0
- package/dist/poller.js +214 -0
- package/dist/poller.js.map +1 -0
- package/dist/poller.test.d.ts +1 -0
- package/dist/poller.test.js +382 -0
- package/dist/poller.test.js.map +1 -0
- package/dist/runners/amp.d.ts +5 -0
- package/dist/runners/amp.js +316 -0
- package/dist/runners/amp.js.map +1 -0
- package/dist/runners/claude-code.d.ts +6 -0
- package/dist/runners/claude-code.js +340 -0
- package/dist/runners/claude-code.js.map +1 -0
- package/dist/runners/claude-code.test.d.ts +1 -0
- package/dist/runners/claude-code.test.js +39 -0
- package/dist/runners/claude-code.test.js.map +1 -0
- package/dist/runners/codex.d.ts +6 -0
- package/dist/runners/codex.js +324 -0
- package/dist/runners/codex.js.map +1 -0
- package/dist/runners/codex.test.d.ts +1 -0
- package/dist/runners/codex.test.js +66 -0
- package/dist/runners/codex.test.js.map +1 -0
- package/dist/runners/gemini.d.ts +5 -0
- package/dist/runners/gemini.js +304 -0
- package/dist/runners/gemini.js.map +1 -0
- package/dist/runners/gemini.test.d.ts +1 -0
- package/dist/runners/gemini.test.js +16 -0
- package/dist/runners/gemini.test.js.map +1 -0
- package/dist/runners/index.d.ts +2 -0
- package/dist/runners/index.js +27 -0
- package/dist/runners/index.js.map +1 -0
- package/dist/runners/index.test.d.ts +1 -0
- package/dist/runners/index.test.js +19 -0
- package/dist/runners/index.test.js.map +1 -0
- package/dist/runners/log-reporter.d.ts +18 -0
- package/dist/runners/log-reporter.js +127 -0
- package/dist/runners/log-reporter.js.map +1 -0
- package/dist/runners/log-reporter.test.d.ts +1 -0
- package/dist/runners/log-reporter.test.js +152 -0
- package/dist/runners/log-reporter.test.js.map +1 -0
- package/dist/runners/opencode.d.ts +6 -0
- package/dist/runners/opencode.js +304 -0
- package/dist/runners/opencode.js.map +1 -0
- package/dist/runners/stream-json-parser.d.ts +17 -0
- package/dist/runners/stream-json-parser.js +116 -0
- package/dist/runners/stream-json-parser.js.map +1 -0
- package/dist/runners/types.d.ts +26 -0
- package/dist/runners/types.js +2 -0
- package/dist/runners/types.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/auth-path-store.d.ts +3 -0
- package/dist/utils/auth-path-store.js +37 -0
- package/dist/utils/auth-path-store.js.map +1 -0
- package/dist/utils/auth-path-store.test.d.ts +1 -0
- package/dist/utils/auth-path-store.test.js +70 -0
- package/dist/utils/auth-path-store.test.js.map +1 -0
- package/dist/utils/convention-sync.d.ts +8 -0
- package/dist/utils/convention-sync.js +41 -0
- package/dist/utils/convention-sync.js.map +1 -0
- package/dist/utils/convention-sync.test.d.ts +1 -0
- package/dist/utils/convention-sync.test.js +75 -0
- package/dist/utils/convention-sync.test.js.map +1 -0
- package/dist/utils/git-worktree.d.ts +9 -0
- package/dist/utils/git-worktree.js +150 -0
- package/dist/utils/git-worktree.js.map +1 -0
- package/dist/utils/git-worktree.test.d.ts +1 -0
- package/dist/utils/git-worktree.test.js +294 -0
- package/dist/utils/git-worktree.test.js.map +1 -0
- package/dist/utils/origin-issue-safeguard.d.ts +16 -0
- package/dist/utils/origin-issue-safeguard.js +198 -0
- package/dist/utils/origin-issue-safeguard.js.map +1 -0
- package/dist/utils/runner-cleanup.d.ts +10 -0
- package/dist/utils/runner-cleanup.js +59 -0
- package/dist/utils/runner-cleanup.js.map +1 -0
- package/dist/utils/runner-cleanup.test.d.ts +1 -0
- package/dist/utils/runner-cleanup.test.js +93 -0
- package/dist/utils/runner-cleanup.test.js.map +1 -0
- package/dist/utils/runner-history.d.ts +6 -0
- package/dist/utils/runner-history.js +13 -0
- package/dist/utils/runner-history.js.map +1 -0
- package/dist/utils/runner-history.test.d.ts +1 -0
- package/dist/utils/runner-history.test.js +25 -0
- package/dist/utils/runner-history.test.js.map +1 -0
- package/package.json +50 -0
- package/readme.md +188 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { basename, dirname, join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import { isGitRepo, createWorktree, removeWorktree, resolveWorktreePath, normalizeClaudeSandboxPath } from "./git-worktree.js";
|
|
8
|
+
const makeTempGitRepo = () => {
|
|
9
|
+
const dir = mkdtempSync(join(tmpdir(), "git-worktree-test-"));
|
|
10
|
+
execFileSync("git", ["init", dir], { stdio: "pipe" });
|
|
11
|
+
execFileSync("git", ["-C", dir, "config", "user.email", "test@test.com"], { stdio: "pipe" });
|
|
12
|
+
execFileSync("git", ["-C", dir, "config", "user.name", "Test"], { stdio: "pipe" });
|
|
13
|
+
// Create an initial commit so HEAD exists
|
|
14
|
+
execFileSync("git", ["-C", dir, "commit", "--allow-empty", "-m", "initial"], { stdio: "pipe" });
|
|
15
|
+
return dir;
|
|
16
|
+
};
|
|
17
|
+
const cleanupDir = (dir) => {
|
|
18
|
+
rmSync(dir, { recursive: true, force: true });
|
|
19
|
+
};
|
|
20
|
+
test("isGitRepo returns true for a git directory", () => {
|
|
21
|
+
const repo = makeTempGitRepo();
|
|
22
|
+
try {
|
|
23
|
+
assert.equal(isGitRepo(repo), true);
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
cleanupDir(repo);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
test("isGitRepo returns false for a non-git directory", () => {
|
|
30
|
+
const dir = mkdtempSync(join(tmpdir(), "git-worktree-test-nongit-"));
|
|
31
|
+
try {
|
|
32
|
+
assert.equal(isGitRepo(dir), false);
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
cleanupDir(dir);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
test("isGitRepo returns false for a non-existent directory", () => {
|
|
39
|
+
assert.equal(isGitRepo(join(tmpdir(), "nonexistent-dir-" + Date.now())), false);
|
|
40
|
+
});
|
|
41
|
+
test("resolveWorktreePath returns sibling directory path", () => {
|
|
42
|
+
const authPath = join("home", "user", "projects", "my-repo");
|
|
43
|
+
const worktreeId = "abc123";
|
|
44
|
+
const expected = join("home", "user", "projects", ".my-repo-worktrees", "wt-abc123");
|
|
45
|
+
assert.equal(resolveWorktreePath(authPath, worktreeId), expected);
|
|
46
|
+
});
|
|
47
|
+
test("createWorktree creates worktree at expected path", () => {
|
|
48
|
+
const repo = makeTempGitRepo();
|
|
49
|
+
const worktreeId = "test-wt-001";
|
|
50
|
+
try {
|
|
51
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
52
|
+
const repoName = basename(repo);
|
|
53
|
+
const expectedPath = join(dirname(repo), `.${repoName}-worktrees`, `wt-${worktreeId}`);
|
|
54
|
+
assert.equal(worktreePath, expectedPath);
|
|
55
|
+
assert.equal(existsSync(worktreePath), true);
|
|
56
|
+
assert.equal(isGitRepo(worktreePath), true);
|
|
57
|
+
// Verify branch was created
|
|
58
|
+
const branches = execFileSync("git", ["-C", repo, "branch", "--list", `worktree/${worktreeId}`], {
|
|
59
|
+
stdio: "pipe",
|
|
60
|
+
encoding: "utf8"
|
|
61
|
+
}).trim();
|
|
62
|
+
assert.ok(branches.includes(`worktree/${worktreeId}`));
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
cleanupDir(repo);
|
|
66
|
+
// Clean up sibling worktree directory
|
|
67
|
+
const repoName = basename(repo);
|
|
68
|
+
const worktreeDir = join(dirname(repo), `.${repoName}-worktrees`);
|
|
69
|
+
cleanupDir(worktreeDir);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
test("createWorktree creates worktree from specified baseBranch", () => {
|
|
73
|
+
const repo = makeTempGitRepo();
|
|
74
|
+
const worktreeId = "test-wt-branch";
|
|
75
|
+
try {
|
|
76
|
+
const initialBranch = execFileSync("git", ["-C", repo, "branch", "--show-current"], {
|
|
77
|
+
stdio: "pipe",
|
|
78
|
+
encoding: "utf8"
|
|
79
|
+
}).trim();
|
|
80
|
+
// Create a branch to use as base
|
|
81
|
+
execFileSync("git", ["-C", repo, "checkout", "-b", "feature-branch"], { stdio: "pipe" });
|
|
82
|
+
execFileSync("git", ["-C", repo, "commit", "--allow-empty", "-m", "feature commit"], { stdio: "pipe" });
|
|
83
|
+
execFileSync("git", ["-C", repo, "checkout", initialBranch], { stdio: "pipe" });
|
|
84
|
+
const worktreePath = createWorktree(repo, {
|
|
85
|
+
worktreeId,
|
|
86
|
+
baseBranch: "feature-branch"
|
|
87
|
+
});
|
|
88
|
+
assert.equal(existsSync(worktreePath), true);
|
|
89
|
+
assert.equal(isGitRepo(worktreePath), true);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
cleanupDir(repo);
|
|
93
|
+
const repoName = basename(repo);
|
|
94
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
test("createWorktree reuses existing worktree", () => {
|
|
98
|
+
const repo = makeTempGitRepo();
|
|
99
|
+
const worktreeId = "test-wt-reuse";
|
|
100
|
+
try {
|
|
101
|
+
const firstPath = createWorktree(repo, { worktreeId });
|
|
102
|
+
assert.equal(existsSync(firstPath), true);
|
|
103
|
+
// Second call should reuse existing worktree
|
|
104
|
+
const secondPath = createWorktree(repo, { worktreeId });
|
|
105
|
+
assert.equal(secondPath, firstPath);
|
|
106
|
+
assert.equal(existsSync(secondPath), true);
|
|
107
|
+
assert.equal(isGitRepo(secondPath), true);
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
cleanupDir(repo);
|
|
111
|
+
const repoName = basename(repo);
|
|
112
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
test("removeWorktree cleans up worktree and branch", () => {
|
|
116
|
+
const repo = makeTempGitRepo();
|
|
117
|
+
const worktreeId = "test-wt-remove";
|
|
118
|
+
try {
|
|
119
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
120
|
+
assert.equal(existsSync(worktreePath), true);
|
|
121
|
+
removeWorktree(repo, worktreePath, worktreeId);
|
|
122
|
+
assert.equal(existsSync(worktreePath), false);
|
|
123
|
+
// Verify branch was deleted
|
|
124
|
+
const branches = execFileSync("git", ["-C", repo, "branch", "--list", `worktree/${worktreeId}`], {
|
|
125
|
+
stdio: "pipe",
|
|
126
|
+
encoding: "utf8"
|
|
127
|
+
}).trim();
|
|
128
|
+
assert.equal(branches, "");
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
cleanupDir(repo);
|
|
132
|
+
const repoName = basename(repo);
|
|
133
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
test("createWorktree symlinks .agentteams from original repo", () => {
|
|
137
|
+
const repo = makeTempGitRepo();
|
|
138
|
+
const worktreeId = "test-wt-symlink";
|
|
139
|
+
try {
|
|
140
|
+
// Create .agentteams/ in the original repo
|
|
141
|
+
const agentteamsDir = join(repo, ".agentteams");
|
|
142
|
+
mkdirSync(agentteamsDir, { recursive: true });
|
|
143
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
144
|
+
const targetLink = join(worktreePath, ".agentteams");
|
|
145
|
+
assert.equal(existsSync(targetLink), true);
|
|
146
|
+
assert.equal(lstatSync(targetLink).isSymbolicLink(), true);
|
|
147
|
+
assert.equal(readlinkSync(targetLink), agentteamsDir);
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
cleanupDir(repo);
|
|
151
|
+
const repoName = basename(repo);
|
|
152
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
test("createWorktree throws for invalid (non-git) path", () => {
|
|
156
|
+
const dir = mkdtempSync(join(tmpdir(), "git-worktree-test-invalid-"));
|
|
157
|
+
try {
|
|
158
|
+
assert.throws(() => createWorktree(dir, { worktreeId: "invalid-test" }), (err) => {
|
|
159
|
+
assert.ok(err.message.includes("Not a git repository"));
|
|
160
|
+
return true;
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
cleanupDir(dir);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
test("createWorktree copies root .env files", () => {
|
|
168
|
+
const repo = makeTempGitRepo();
|
|
169
|
+
const worktreeId = "test-wt-env-root";
|
|
170
|
+
try {
|
|
171
|
+
// Create .env and .env.local in the repo root
|
|
172
|
+
writeFileSync(join(repo, ".env"), "ROOT_KEY=value");
|
|
173
|
+
writeFileSync(join(repo, ".env.local"), "LOCAL_KEY=value");
|
|
174
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
175
|
+
const envFile = join(worktreePath, ".env");
|
|
176
|
+
const envLocalFile = join(worktreePath, ".env.local");
|
|
177
|
+
assert.equal(existsSync(envFile), true);
|
|
178
|
+
assert.equal(lstatSync(envFile).isSymbolicLink(), false, ".env should be a copy, not a symlink");
|
|
179
|
+
assert.equal(readFileSync(envFile, "utf8"), "ROOT_KEY=value");
|
|
180
|
+
assert.equal(existsSync(envLocalFile), true);
|
|
181
|
+
assert.equal(lstatSync(envLocalFile).isSymbolicLink(), false, ".env.local should be a copy, not a symlink");
|
|
182
|
+
assert.equal(readFileSync(envLocalFile, "utf8"), "LOCAL_KEY=value");
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
cleanupDir(repo);
|
|
186
|
+
const repoName = basename(repo);
|
|
187
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
test("createWorktree copies workspace-level .env files", () => {
|
|
191
|
+
const repo = makeTempGitRepo();
|
|
192
|
+
const worktreeId = "test-wt-env-ws";
|
|
193
|
+
try {
|
|
194
|
+
// Add .gitignore to ignore .env files (like a real project)
|
|
195
|
+
writeFileSync(join(repo, ".gitignore"), ".env\n.env.*\n");
|
|
196
|
+
// Create workspace dirs with a tracked file so dirs exist in worktree
|
|
197
|
+
mkdirSync(join(repo, "api"));
|
|
198
|
+
mkdirSync(join(repo, "web"));
|
|
199
|
+
writeFileSync(join(repo, "api", "index.ts"), "// api");
|
|
200
|
+
writeFileSync(join(repo, "web", "index.ts"), "// web");
|
|
201
|
+
execFileSync("git", ["-C", repo, "add", "-A"], { stdio: "pipe" });
|
|
202
|
+
execFileSync("git", ["-C", repo, "commit", "-m", "add workspace dirs"], { stdio: "pipe" });
|
|
203
|
+
// Create .env files AFTER commit (gitignored, won't be in worktree)
|
|
204
|
+
writeFileSync(join(repo, "api", ".env"), "DB_URL=postgres://...");
|
|
205
|
+
writeFileSync(join(repo, "web", ".env"), "NEXT_PUBLIC_API=http://...");
|
|
206
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
207
|
+
const apiEnvFile = join(worktreePath, "api", ".env");
|
|
208
|
+
const webEnvFile = join(worktreePath, "web", ".env");
|
|
209
|
+
assert.equal(existsSync(apiEnvFile), true);
|
|
210
|
+
assert.equal(lstatSync(apiEnvFile).isSymbolicLink(), false, "api/.env should be a copy, not a symlink");
|
|
211
|
+
assert.equal(readFileSync(apiEnvFile, "utf8"), "DB_URL=postgres://...");
|
|
212
|
+
assert.equal(existsSync(webEnvFile), true);
|
|
213
|
+
assert.equal(lstatSync(webEnvFile).isSymbolicLink(), false, "web/.env should be a copy, not a symlink");
|
|
214
|
+
assert.equal(readFileSync(webEnvFile, "utf8"), "NEXT_PUBLIC_API=http://...");
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
cleanupDir(repo);
|
|
218
|
+
const repoName = basename(repo);
|
|
219
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
test("createWorktree skips .env files that already exist in worktree (git-tracked)", () => {
|
|
223
|
+
const repo = makeTempGitRepo();
|
|
224
|
+
const worktreeId = "test-wt-env-skip";
|
|
225
|
+
try {
|
|
226
|
+
// Create and commit .env.example (git-tracked — will exist in worktree)
|
|
227
|
+
writeFileSync(join(repo, ".env.example"), "EXAMPLE=true");
|
|
228
|
+
execFileSync("git", ["-C", repo, "add", ".env.example"], { stdio: "pipe" });
|
|
229
|
+
execFileSync("git", ["-C", repo, "commit", "-m", "add env example"], { stdio: "pipe" });
|
|
230
|
+
// Also create .env (gitignored — should be copied)
|
|
231
|
+
writeFileSync(join(repo, ".env"), "SECRET=value");
|
|
232
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
233
|
+
// .env.example should NOT be overwritten (it's a regular file from git)
|
|
234
|
+
const exampleFile = join(worktreePath, ".env.example");
|
|
235
|
+
assert.equal(existsSync(exampleFile), true);
|
|
236
|
+
assert.equal(lstatSync(exampleFile).isSymbolicLink(), false);
|
|
237
|
+
// .env should be a copied file, not a symlink
|
|
238
|
+
const envFile = join(worktreePath, ".env");
|
|
239
|
+
assert.equal(existsSync(envFile), true);
|
|
240
|
+
assert.equal(lstatSync(envFile).isSymbolicLink(), false, ".env should be a copy, not a symlink");
|
|
241
|
+
assert.equal(readFileSync(envFile, "utf8"), "SECRET=value");
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
cleanupDir(repo);
|
|
245
|
+
const repoName = basename(repo);
|
|
246
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
test("removeWorktree throws for non-existent worktree path", () => {
|
|
250
|
+
const repo = makeTempGitRepo();
|
|
251
|
+
const worktreeId = "test-wt-already-gone";
|
|
252
|
+
try {
|
|
253
|
+
const worktreePath = resolveWorktreePath(repo, worktreeId);
|
|
254
|
+
assert.throws(() => removeWorktree(repo, worktreePath, worktreeId), (err) => {
|
|
255
|
+
assert.ok(err.message.includes("does not exist"));
|
|
256
|
+
return true;
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
cleanupDir(repo);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
test("normalizeClaudeSandboxPath returns absolute path as-is", () => {
|
|
264
|
+
assert.equal(normalizeClaudeSandboxPath("/Users/justin/Project"), "/Users/justin/Project");
|
|
265
|
+
assert.equal(normalizeClaudeSandboxPath("/home/user/repo"), "/home/user/repo");
|
|
266
|
+
});
|
|
267
|
+
// Claude Code runner uses --dangerously-skip-permissions, so no sandbox
|
|
268
|
+
// or permission settings are written to settings.local.json.
|
|
269
|
+
test("healWorktreeConfig restores missing .agentteams symlink on reuse", () => {
|
|
270
|
+
const repo = makeTempGitRepo();
|
|
271
|
+
const worktreeId = "test-wt-heal-symlink";
|
|
272
|
+
try {
|
|
273
|
+
// Create .agentteams/ in the original repo
|
|
274
|
+
mkdirSync(join(repo, ".agentteams"), { recursive: true });
|
|
275
|
+
const worktreePath = createWorktree(repo, { worktreeId });
|
|
276
|
+
const targetLink = join(worktreePath, ".agentteams");
|
|
277
|
+
// Verify symlink was created on first run
|
|
278
|
+
assert.equal(lstatSync(targetLink).isSymbolicLink(), true);
|
|
279
|
+
// Simulate broken state: remove the symlink
|
|
280
|
+
unlinkSync(targetLink);
|
|
281
|
+
assert.equal(existsSync(targetLink), false);
|
|
282
|
+
// Reuse triggers healWorktreeConfig which should restore the symlink
|
|
283
|
+
const reusedPath = createWorktree(repo, { worktreeId });
|
|
284
|
+
assert.equal(reusedPath, worktreePath);
|
|
285
|
+
assert.equal(existsSync(targetLink), true);
|
|
286
|
+
assert.equal(lstatSync(targetLink).isSymbolicLink(), true);
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
cleanupDir(repo);
|
|
290
|
+
const repoName = basename(repo);
|
|
291
|
+
cleanupDir(join(dirname(repo), `.${repoName}-worktrees`));
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
//# sourceMappingURL=git-worktree.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-worktree.test.js","sourceRoot":"","sources":["../../src/utils/git-worktree.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type IssueRef = {
|
|
2
|
+
provider: string;
|
|
3
|
+
externalId: string;
|
|
4
|
+
externalUrl: string;
|
|
5
|
+
externalTitle?: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* 프롬프트에서 이슈 참조를 추출합니다 (문자열 / Tiptap JSON 모두 지원).
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractIssueRefsFromPrompt(prompt: string | Record<string, unknown>): IssueRef[];
|
|
11
|
+
/**
|
|
12
|
+
* 트리거 완료 후 origin issue 자동 연결 안전장치를 실행합니다.
|
|
13
|
+
* fire-and-forget: 실패해도 트리거 완료에 영향 없음.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runOriginIssueSafeguard(prompt: string | Record<string, unknown>, historyPath: string | null, authPath: string | null): Promise<void>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3차 방어: 러너 완료 후 origin issue 자동 연결 안전장치
|
|
3
|
+
*
|
|
4
|
+
* 사용자 프롬프트에 이슈 entityReference가 있고,
|
|
5
|
+
* 러너 히스토리에서 플랜 생성이 감지되면,
|
|
6
|
+
* `agentteams plan issue` CLI를 실행하여 이슈를 연결합니다.
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from "node:child_process";
|
|
9
|
+
import { readFile } from "node:fs/promises";
|
|
10
|
+
import { logger } from "../logger.js";
|
|
11
|
+
const ENTITY_TYPE_TO_PROVIDER = {
|
|
12
|
+
GITHUB_ISSUE: "GITHUB",
|
|
13
|
+
GITLAB_ISSUE: "GITLAB",
|
|
14
|
+
LINEAR_ISSUE: "LINEAR",
|
|
15
|
+
};
|
|
16
|
+
const ISSUE_ENTITY_TYPES = new Set(Object.keys(ENTITY_TYPE_TO_PROVIDER));
|
|
17
|
+
/**
|
|
18
|
+
* 프롬프트(문자열)에서 이슈 entityReference를 추출합니다.
|
|
19
|
+
* 형식: [label](TYPE:id) — TYPE이 GITHUB_ISSUE, GITLAB_ISSUE, LINEAR_ISSUE인 경우
|
|
20
|
+
*/
|
|
21
|
+
function extractIssueRefsFromText(text) {
|
|
22
|
+
const results = [];
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
// Pattern: [label](TYPE:id) or [label](TYPE:id:path)
|
|
25
|
+
const refPattern = /\[([^\]]*)\]\((\w+):([^)]+)\)/g;
|
|
26
|
+
let match;
|
|
27
|
+
while ((match = refPattern.exec(text)) !== null) {
|
|
28
|
+
const [, label, entityType, rest] = match;
|
|
29
|
+
if (!ISSUE_ENTITY_TYPES.has(entityType))
|
|
30
|
+
continue;
|
|
31
|
+
const provider = ENTITY_TYPE_TO_PROVIDER[entityType];
|
|
32
|
+
// rest may be "id" or "id:url" — for LINEAR_ISSUE it's typically a UUID
|
|
33
|
+
const entityId = rest.split(":")[0];
|
|
34
|
+
if (!entityId)
|
|
35
|
+
continue;
|
|
36
|
+
const key = `${provider}:${entityId}`;
|
|
37
|
+
if (seen.has(key))
|
|
38
|
+
continue;
|
|
39
|
+
seen.add(key);
|
|
40
|
+
results.push({
|
|
41
|
+
provider,
|
|
42
|
+
externalId: entityId,
|
|
43
|
+
externalUrl: "", // URL not available from text format
|
|
44
|
+
externalTitle: label || undefined,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return results;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 프롬프트(Tiptap JSON)에서 이슈 entityReference 노드를 추출합니다.
|
|
51
|
+
*/
|
|
52
|
+
function extractIssueRefsFromTiptap(content) {
|
|
53
|
+
const results = [];
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
function walk(node) {
|
|
56
|
+
if (node.type === "entityReference" && node.attrs) {
|
|
57
|
+
const attrs = node.attrs;
|
|
58
|
+
const entityType = attrs.entityType;
|
|
59
|
+
const provider = ENTITY_TYPE_TO_PROVIDER[entityType];
|
|
60
|
+
if (provider) {
|
|
61
|
+
const entityId = attrs.entityId ?? "";
|
|
62
|
+
const htmlUrl = attrs.htmlUrl ?? "";
|
|
63
|
+
const label = attrs.label ?? "";
|
|
64
|
+
if (entityId) {
|
|
65
|
+
const key = `${provider}:${entityId}`;
|
|
66
|
+
if (!seen.has(key)) {
|
|
67
|
+
seen.add(key);
|
|
68
|
+
results.push({
|
|
69
|
+
provider,
|
|
70
|
+
externalId: entityId,
|
|
71
|
+
externalUrl: htmlUrl,
|
|
72
|
+
externalTitle: label || undefined,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (Array.isArray(node.content)) {
|
|
79
|
+
for (const child of node.content) {
|
|
80
|
+
walk(child);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
walk(content);
|
|
85
|
+
return results;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 프롬프트에서 이슈 참조를 추출합니다 (문자열 / Tiptap JSON 모두 지원).
|
|
89
|
+
*/
|
|
90
|
+
export function extractIssueRefsFromPrompt(prompt) {
|
|
91
|
+
if (typeof prompt === "string") {
|
|
92
|
+
return extractIssueRefsFromText(prompt);
|
|
93
|
+
}
|
|
94
|
+
return extractIssueRefsFromTiptap(prompt);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 히스토리 마크다운에서 생성된 플랜 ID를 추출합니다.
|
|
98
|
+
* `plan create` 출력이나 planId 패턴을 감지합니다.
|
|
99
|
+
*/
|
|
100
|
+
function extractCreatedPlanIds(historyMarkdown) {
|
|
101
|
+
const planIds = [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
// Pattern 1: CLI output JSON containing "id" field — e.g., { "id": "uuid", ... }
|
|
104
|
+
// Pattern 2: plan ID in format like planId: uuid or --id uuid
|
|
105
|
+
// Pattern 3: UUID-like strings after "plan create" or "Plan created" context
|
|
106
|
+
const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;
|
|
107
|
+
// Look for lines that suggest plan creation
|
|
108
|
+
const lines = historyMarkdown.split("\n");
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
const lower = line.toLowerCase();
|
|
111
|
+
if (lower.includes("plan create") ||
|
|
112
|
+
lower.includes("plan created") ||
|
|
113
|
+
lower.includes("creating plan") ||
|
|
114
|
+
lower.includes("plan-id") ||
|
|
115
|
+
lower.includes("planid")) {
|
|
116
|
+
const matches = line.match(uuidPattern);
|
|
117
|
+
if (matches) {
|
|
118
|
+
for (const id of matches) {
|
|
119
|
+
if (!seen.has(id)) {
|
|
120
|
+
seen.add(id);
|
|
121
|
+
planIds.push(id);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return planIds;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* `agentteams plan issue` CLI를 실행합니다 (fire-and-forget).
|
|
131
|
+
*/
|
|
132
|
+
function execPlanIssue(cwd, planId, issue) {
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
const args = [
|
|
135
|
+
"plan", "issue",
|
|
136
|
+
"--id", planId,
|
|
137
|
+
"--provider", issue.provider,
|
|
138
|
+
"--external-id", issue.externalId,
|
|
139
|
+
"--external-url", issue.externalUrl || "unknown",
|
|
140
|
+
];
|
|
141
|
+
if (issue.externalTitle) {
|
|
142
|
+
args.push("--title", issue.externalTitle);
|
|
143
|
+
}
|
|
144
|
+
execFile("agentteams", args, { cwd, timeout: 15000 }, (error) => {
|
|
145
|
+
if (error) {
|
|
146
|
+
// 409 or other failure — skip silently
|
|
147
|
+
logger.warn("Origin issue safeguard: plan issue command failed", {
|
|
148
|
+
planId,
|
|
149
|
+
provider: issue.provider,
|
|
150
|
+
externalId: issue.externalId,
|
|
151
|
+
error: error.message,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
resolve();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 트리거 완료 후 origin issue 자동 연결 안전장치를 실행합니다.
|
|
160
|
+
* fire-and-forget: 실패해도 트리거 완료에 영향 없음.
|
|
161
|
+
*/
|
|
162
|
+
export async function runOriginIssueSafeguard(prompt, historyPath, authPath) {
|
|
163
|
+
if (!historyPath || !authPath)
|
|
164
|
+
return;
|
|
165
|
+
try {
|
|
166
|
+
// 1. 프롬프트에서 이슈 참조 추출
|
|
167
|
+
const issueRefs = extractIssueRefsFromPrompt(prompt);
|
|
168
|
+
if (issueRefs.length === 0)
|
|
169
|
+
return;
|
|
170
|
+
// 2. 히스토리에서 플랜 생성 감지
|
|
171
|
+
let historyContent;
|
|
172
|
+
try {
|
|
173
|
+
historyContent = await readFile(historyPath, "utf8");
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return; // 히스토리 파일 없으면 중단
|
|
177
|
+
}
|
|
178
|
+
const planIds = extractCreatedPlanIds(historyContent);
|
|
179
|
+
if (planIds.length === 0)
|
|
180
|
+
return;
|
|
181
|
+
// 3. 각 플랜 × 이슈 조합에 대해 CLI 실행
|
|
182
|
+
logger.info("Origin issue safeguard: linking issues to plans", {
|
|
183
|
+
planIds,
|
|
184
|
+
issueCount: issueRefs.length,
|
|
185
|
+
});
|
|
186
|
+
for (const planId of planIds) {
|
|
187
|
+
for (const issue of issueRefs) {
|
|
188
|
+
await execPlanIssue(authPath, planId, issue);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
logger.warn("Origin issue safeguard failed (non-blocking)", {
|
|
194
|
+
error: error instanceof Error ? error.message : String(error),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=origin-issue-safeguard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origin-issue-safeguard.js","sourceRoot":"","sources":["../../src/utils/origin-issue-safeguard.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAStC,MAAM,uBAAuB,GAA2B;IACtD,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;IACtB,YAAY,EAAE,QAAQ;CACvB,CAAC;AAEF,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC;AAEzE;;;GAGG;AACH,SAAS,wBAAwB,CAAC,IAAY;IAC5C,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,qDAAqD;IACrD,MAAM,UAAU,GAAG,gCAAgC,CAAC;IACpD,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAChD,MAAM,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;QAC1C,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAS;QAElD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;QACrD,wEAAwE;QACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACpC,IAAI,CAAC,QAAQ;YAAE,SAAS;QAExB,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;QACtC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEd,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ;YACR,UAAU,EAAE,QAAQ;YACpB,WAAW,EAAE,EAAE,EAAE,qCAAqC;YACtD,aAAa,EAAE,KAAK,IAAI,SAAS;SAClC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,0BAA0B,CAAC,OAAgC;IAClE,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,SAAS,IAAI,CAAC,IAA6B;QACzC,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAgC,CAAC;YACpD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAoB,CAAC;YAC9C,MAAM,QAAQ,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;YACrD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,GAAI,KAAK,CAAC,QAAmB,IAAI,EAAE,CAAC;gBAClD,MAAM,OAAO,GAAI,KAAK,CAAC,OAAkB,IAAI,EAAE,CAAC;gBAChD,MAAM,KAAK,GAAI,KAAK,CAAC,KAAgB,IAAI,EAAE,CAAC;gBAE5C,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,GAAG,GAAG,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC;oBACtC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;wBACnB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACd,OAAO,CAAC,IAAI,CAAC;4BACX,QAAQ;4BACR,UAAU,EAAE,QAAQ;4BACpB,WAAW,EAAE,OAAO;4BACpB,aAAa,EAAE,KAAK,IAAI,SAAS;yBAClC,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAoC,EAAE,CAAC;gBAC9D,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,CAAC;IACd,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAAwC;IACjF,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,0BAA0B,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,SAAS,qBAAqB,CAAC,eAAuB;IACpD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,iFAAiF;IACjF,8DAA8D;IAC9D,6EAA6E;IAC7E,MAAM,WAAW,GAAG,gEAAgE,CAAC;IAErF,4CAA4C;IAC5C,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACjC,IACE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC7B,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;YAC9B,KAAK,CAAC,QAAQ,CAAC,eAAe,CAAC;YAC/B,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC;YACzB,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EACxB,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACxC,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;wBAClB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACb,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACnB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CACpB,GAAW,EACX,MAAc,EACd,KAAe;IAEf,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG;YACX,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,KAAK,CAAC,QAAQ;YAC5B,eAAe,EAAE,KAAK,CAAC,UAAU;YACjC,gBAAgB,EAAE,KAAK,CAAC,WAAW,IAAI,SAAS;SACjD,CAAC;QACF,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QAC5C,CAAC;QAED,QAAQ,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAmB,EAAE,EAAE;YAC5E,IAAI,KAAK,EAAE,CAAC;gBACV,uCAAuC;gBACvC,MAAM,CAAC,IAAI,CAAC,mDAAmD,EAAE;oBAC/D,MAAM;oBACN,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,UAAU,EAAE,KAAK,CAAC,UAAU;oBAC5B,KAAK,EAAE,KAAK,CAAC,OAAO;iBACrB,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAAwC,EACxC,WAA0B,EAC1B,QAAuB;IAEvB,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEtC,IAAI,CAAC;QACH,qBAAqB;QACrB,MAAM,SAAS,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;QACrD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEnC,qBAAqB;QACrB,IAAI,cAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,cAAc,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,iBAAiB;QAC3B,CAAC;QAED,MAAM,OAAO,GAAG,qBAAqB,CAAC,cAAc,CAAC,CAAC;QACtD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEjC,6BAA6B;QAC7B,MAAM,CAAC,IAAI,CAAC,iDAAiD,EAAE;YAC7D,OAAO;YACP,UAAU,EAAE,SAAS,CAAC,MAAM;SAC7B,CAAC,CAAC;QAEH,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;gBAC9B,MAAM,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YAC/C,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,8CAA8C,EAAE;YAC1D,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { readdir, stat, unlink } from "node:fs/promises";
|
|
2
|
+
import { logger } from "../logger.js";
|
|
3
|
+
type CleanupDeps = {
|
|
4
|
+
readdir?: typeof readdir;
|
|
5
|
+
stat?: typeof stat;
|
|
6
|
+
unlink?: typeof unlink;
|
|
7
|
+
logger?: Pick<typeof logger, "info" | "warn">;
|
|
8
|
+
};
|
|
9
|
+
export declare const runCleanup: (authPath: string, deps?: CleanupDeps) => Promise<void>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readdir, stat, unlink } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
const LOG_TTL_MS = 1 * 24 * 60 * 60 * 1000;
|
|
5
|
+
const HISTORY_TTL_MS = 3 * 24 * 60 * 60 * 1000;
|
|
6
|
+
const purgeExpiredFiles = async (directory, ttlMs, deps) => {
|
|
7
|
+
let deleted = 0;
|
|
8
|
+
let entries;
|
|
9
|
+
try {
|
|
10
|
+
entries = await deps.readdir(directory);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code === "ENOENT") {
|
|
14
|
+
return 0;
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
const filePath = join(directory, entry);
|
|
21
|
+
try {
|
|
22
|
+
const fileStat = await deps.stat(filePath);
|
|
23
|
+
if (now - fileStat.mtimeMs > ttlMs) {
|
|
24
|
+
await deps.unlink(filePath);
|
|
25
|
+
deleted++;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error.code === "ENOENT") {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
deps.logger.warn("Failed to delete expired file", {
|
|
33
|
+
filePath,
|
|
34
|
+
error: error instanceof Error ? error.message : String(error)
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return deleted;
|
|
39
|
+
};
|
|
40
|
+
export const runCleanup = async (authPath, deps = {}) => {
|
|
41
|
+
const resolvedDeps = {
|
|
42
|
+
readdir: deps.readdir ?? readdir,
|
|
43
|
+
stat: deps.stat ?? stat,
|
|
44
|
+
unlink: deps.unlink ?? unlink,
|
|
45
|
+
logger: deps.logger ?? logger
|
|
46
|
+
};
|
|
47
|
+
const logDir = join(authPath, ".agentteams", "runner", "log");
|
|
48
|
+
const historyDir = join(authPath, ".agentteams", "runner", "history");
|
|
49
|
+
const [logDeleted, historyDeleted] = await Promise.all([
|
|
50
|
+
purgeExpiredFiles(logDir, LOG_TTL_MS, resolvedDeps),
|
|
51
|
+
purgeExpiredFiles(historyDir, HISTORY_TTL_MS, resolvedDeps)
|
|
52
|
+
]);
|
|
53
|
+
resolvedDeps.logger.info("Runner cleanup completed", {
|
|
54
|
+
authPath,
|
|
55
|
+
logDeleted,
|
|
56
|
+
historyDeleted
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=runner-cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-cleanup.js","sourceRoot":"","sources":["../../src/utils/runner-cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|