@agentteams/runner 0.0.101 → 0.0.102

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.
@@ -0,0 +1,66 @@
1
+ import type { DiscoveredWorktreeSyncItem, DiscoveredWorktreeSyncRepository, DiscoveryRepository } from '../types.js';
2
+ /**
3
+ * AgentRunner의 Git worktree 자동 발견·정합성 복구.
4
+ *
5
+ * `git worktree list --porcelain -z`를 파싱해 linked worktree만 골라 서버에 full snapshot으로 보고한다.
6
+ * 핵심 계약:
7
+ * - 머신 전체를 검색하지 않는다. 연결된(discovery 대상) repository로만 범위를 제한한다.
8
+ * - `git worktree prune/remove`를 호출하지 않는다. 오직 읽기(list)만 한다.
9
+ * - Git 명령 실패/malformed 출력은 해당 repository를 ok=false로 보고해 서버가 기존 상태를 보존하게 한다.
10
+ * 빈 성공 snapshot으로 오인 보고하지 않는다.
11
+ * - localKey는 canonical 경로의 해시로, 절대 경로를 서버 payload에 노출하지 않으면서 재시작 후에도 안정적으로 매칭된다.
12
+ */
13
+ export type WorktreeRecord = {
14
+ path: string;
15
+ head: string | null;
16
+ branch: string | null;
17
+ detached: boolean;
18
+ bare: boolean;
19
+ locked: boolean;
20
+ prunable: boolean;
21
+ };
22
+ /**
23
+ * `git worktree list --porcelain -z` 출력을 파싱한다.
24
+ *
25
+ * `-z`에서 각 attribute는 NUL로 종료되고, record는 빈 attribute(연속 NUL)로 구분된다.
26
+ * 첫 record는 항상 main worktree다(git이 보장). 호출자가 필요 시 제외한다.
27
+ */
28
+ export declare const parseWorktreePorcelain: (output: string) => WorktreeRecord[];
29
+ /** canonical 경로를 서버에 노출하지 않는 daemon-scoped opaque 안정 키로 변환한다. */
30
+ export declare const computeLocalKey: (canonicalPath: string) => string;
31
+ export type RepositoryDiscovery = {
32
+ ok: boolean;
33
+ items: DiscoveredWorktreeSyncItem[];
34
+ mappings: Record<string, string>;
35
+ };
36
+ /**
37
+ * 한 로컬 저장소의 linked worktree를 발견한다.
38
+ *
39
+ * main worktree(첫 record), bare, prunable은 제외한다. prunable/부재는 서버에서 보고 누락으로 MISSING 처리된다.
40
+ * Git 명령이 실패하면 ok=false로 반환해 서버가 기존 상태를 보존하게 한다.
41
+ *
42
+ * @param runGit 테스트 주입용 git 실행기. 기본은 실제 `git` 호출.
43
+ */
44
+ export declare const discoverRepositoryWorktrees: (repoPath: string, runGit?: (args: string[], cwd: string) => string) => RepositoryDiscovery;
45
+ /** 로컬 저장소의 origin remote를 정규화 신원으로 변환한다. 매칭 실패 시 null. */
46
+ export declare const resolveRepositoryOrigin: (repoPath: string, runGit?: (args: string[], cwd: string) => string) => string | null;
47
+ export type ReconcileDiscoveryDeps = {
48
+ fetchDiscoveryRepositories: () => Promise<DiscoveryRepository[]>;
49
+ syncDiscoveredWorktrees: (repositories: DiscoveredWorktreeSyncRepository[]) => Promise<void>;
50
+ authPaths: string[];
51
+ isGitRepo?: (dirPath: string) => boolean;
52
+ findMemberRepoCandidates?: (root: string) => string[];
53
+ resolveRepositoryOrigin?: (repoPath: string) => string | null;
54
+ discoverRepositoryWorktrees?: (repoPath: string) => RepositoryDiscovery;
55
+ loadMappings?: () => Record<string, string>;
56
+ saveMappings?: (mappings: Record<string, string>) => void;
57
+ };
58
+ /**
59
+ * 연결 저장소 범위에서 발견 worktree를 정합화하고 서버에 full snapshot을 보고한다.
60
+ *
61
+ * - discovery 대상 repository(remoteUrl)만 로컬 저장소 origin과 매칭한다. scope 밖은 Git 명령·payload 모두에서 제외한다.
62
+ * - 로컬에서 매칭되지 않은 repository는 보고 목록에서 아예 제외한다(빈 성공 snapshot으로 MISSING 오탐 방지).
63
+ * - 매칭됐지만 Git 조회 실패면 ok=false로 보고해 서버가 기존 상태를 보존하게 한다.
64
+ * - localKey↔경로 매핑을 원자적으로 저장한다(민감 경로는 서버로 전송하지 않는다).
65
+ */
66
+ export declare const reconcileDiscoveredWorktrees: (deps: ReconcileDiscoveryDeps) => Promise<void>;
@@ -0,0 +1,227 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { createHash } from 'node:crypto';
3
+ import { realpathSync } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { findMemberRepoCandidates, normalizeRemoteUrl } from './resolve-member-repo.js';
6
+ import { isGitRepo } from './git-worktree.js';
7
+ import { loadDiscoveredWorktreeMappings, saveDiscoveredWorktreeMappings } from './discovered-worktree-store.js';
8
+ /**
9
+ * `git worktree list --porcelain -z` 출력을 파싱한다.
10
+ *
11
+ * `-z`에서 각 attribute는 NUL로 종료되고, record는 빈 attribute(연속 NUL)로 구분된다.
12
+ * 첫 record는 항상 main worktree다(git이 보장). 호출자가 필요 시 제외한다.
13
+ */
14
+ export const parseWorktreePorcelain = (output) => {
15
+ if (!output || !output.endsWith('\0\0')) {
16
+ throw new Error('Malformed git worktree porcelain output: missing complete record terminator');
17
+ }
18
+ const records = [];
19
+ // NUL 구분 토큰. 마지막 빈 토큰(trailing NUL)은 무시된다.
20
+ const tokens = output.split('\0');
21
+ let current = null;
22
+ const flush = () => {
23
+ if (current) {
24
+ records.push(current);
25
+ current = null;
26
+ }
27
+ };
28
+ for (const token of tokens) {
29
+ if (token === '') {
30
+ // record 경계.
31
+ flush();
32
+ continue;
33
+ }
34
+ const spaceIndex = token.indexOf(' ');
35
+ const key = spaceIndex === -1 ? token : token.slice(0, spaceIndex);
36
+ const value = spaceIndex === -1 ? '' : token.slice(spaceIndex + 1);
37
+ if (key === 'worktree') {
38
+ flush();
39
+ current = { path: value, head: null, branch: null, detached: false, bare: false, locked: false, prunable: false };
40
+ continue;
41
+ }
42
+ if (!current) {
43
+ throw new Error(`Malformed git worktree porcelain output: attribute before worktree (${key})`);
44
+ }
45
+ switch (key) {
46
+ case 'HEAD':
47
+ current.head = value || null;
48
+ break;
49
+ case 'branch':
50
+ // refs/heads/<name> → <name>
51
+ current.branch = value.replace(/^refs\/heads\//, '') || null;
52
+ break;
53
+ case 'detached':
54
+ current.detached = true;
55
+ break;
56
+ case 'bare':
57
+ current.bare = true;
58
+ break;
59
+ case 'locked':
60
+ current.locked = true;
61
+ break;
62
+ case 'prunable':
63
+ current.prunable = true;
64
+ break;
65
+ default:
66
+ break;
67
+ }
68
+ }
69
+ flush();
70
+ if (records.length === 0 ||
71
+ records.some((record) => record.path.trim().length === 0 ||
72
+ (!record.bare && !record.prunable && record.head === null) ||
73
+ (!record.bare && !record.prunable && !record.detached && record.branch === null))) {
74
+ throw new Error('Malformed git worktree porcelain output: incomplete worktree record');
75
+ }
76
+ return records;
77
+ };
78
+ /** canonical 경로를 서버에 노출하지 않는 daemon-scoped opaque 안정 키로 변환한다. */
79
+ export const computeLocalKey = (canonicalPath) => createHash('sha256').update(canonicalPath).digest('hex');
80
+ const runGitCapture = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], windowsHide: true });
81
+ const canonicalize = (p) => {
82
+ try {
83
+ return realpathSync(p);
84
+ }
85
+ catch {
86
+ return path.resolve(p);
87
+ }
88
+ };
89
+ /**
90
+ * 한 로컬 저장소의 linked worktree를 발견한다.
91
+ *
92
+ * main worktree(첫 record), bare, prunable은 제외한다. prunable/부재는 서버에서 보고 누락으로 MISSING 처리된다.
93
+ * Git 명령이 실패하면 ok=false로 반환해 서버가 기존 상태를 보존하게 한다.
94
+ *
95
+ * @param runGit 테스트 주입용 git 실행기. 기본은 실제 `git` 호출.
96
+ */
97
+ export const discoverRepositoryWorktrees = (repoPath, runGit = runGitCapture) => {
98
+ let output;
99
+ try {
100
+ output = runGit(['worktree', 'list', '--porcelain', '-z'], repoPath);
101
+ }
102
+ catch {
103
+ // Git 명령 실패: 기존 상태 보존을 위해 ok=false.
104
+ return { ok: false, items: [], mappings: {} };
105
+ }
106
+ let records;
107
+ try {
108
+ records = parseWorktreePorcelain(output);
109
+ }
110
+ catch {
111
+ return { ok: false, items: [], mappings: {} };
112
+ }
113
+ const items = [];
114
+ const mappings = {};
115
+ // 첫 record는 main worktree → 제외(기존 AgentConfig 실행 경로와 중복).
116
+ for (const record of records.slice(1)) {
117
+ if (record.bare || record.prunable) {
118
+ continue;
119
+ }
120
+ const canonical = canonicalize(record.path);
121
+ const localKey = computeLocalKey(canonical);
122
+ items.push({
123
+ localKey,
124
+ branch: record.branch,
125
+ headSha: record.head,
126
+ displayName: record.branch ?? path.basename(canonical),
127
+ });
128
+ mappings[localKey] = canonical;
129
+ }
130
+ return { ok: true, items, mappings };
131
+ };
132
+ /** 로컬 저장소의 origin remote를 정규화 신원으로 변환한다. 매칭 실패 시 null. */
133
+ export const resolveRepositoryOrigin = (repoPath, runGit = runGitCapture) => {
134
+ try {
135
+ const origin = runGit(['remote', 'get-url', 'origin'], repoPath).trim();
136
+ return origin ? normalizeRemoteUrl(origin) : null;
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ };
142
+ /**
143
+ * 연결 저장소 범위에서 발견 worktree를 정합화하고 서버에 full snapshot을 보고한다.
144
+ *
145
+ * - discovery 대상 repository(remoteUrl)만 로컬 저장소 origin과 매칭한다. scope 밖은 Git 명령·payload 모두에서 제외한다.
146
+ * - 로컬에서 매칭되지 않은 repository는 보고 목록에서 아예 제외한다(빈 성공 snapshot으로 MISSING 오탐 방지).
147
+ * - 매칭됐지만 Git 조회 실패면 ok=false로 보고해 서버가 기존 상태를 보존하게 한다.
148
+ * - localKey↔경로 매핑을 원자적으로 저장한다(민감 경로는 서버로 전송하지 않는다).
149
+ */
150
+ export const reconcileDiscoveredWorktrees = async (deps) => {
151
+ const detectGitRepo = deps.isGitRepo ?? isGitRepo;
152
+ const findCandidates = deps.findMemberRepoCandidates ?? findMemberRepoCandidates;
153
+ const resolveOrigin = deps.resolveRepositoryOrigin ?? ((repoPath) => resolveRepositoryOrigin(repoPath));
154
+ const discover = deps.discoverRepositoryWorktrees ?? ((repoPath) => discoverRepositoryWorktrees(repoPath));
155
+ const loadMappings = deps.loadMappings ?? (() => loadDiscoveredWorktreeMappings());
156
+ const saveMappings = deps.saveMappings ?? ((m) => void saveDiscoveredWorktreeMappings(m));
157
+ const repositories = await deps.fetchDiscoveryRepositories();
158
+ // 정규화된 remote 신원 → repositoryId (연결 범위).
159
+ const remoteToRepoIds = new Map();
160
+ for (const repo of repositories) {
161
+ if (!repo.remoteUrl) {
162
+ continue;
163
+ }
164
+ const normalized = normalizeRemoteUrl(repo.remoteUrl);
165
+ if (normalized) {
166
+ const ids = remoteToRepoIds.get(normalized) ?? [];
167
+ ids.push(repo.id);
168
+ remoteToRepoIds.set(normalized, ids);
169
+ }
170
+ }
171
+ const perRepo = new Map();
172
+ for (const authPath of deps.authPaths) {
173
+ let candidates;
174
+ try {
175
+ candidates = detectGitRepo(authPath) ? [authPath] : findCandidates(authPath);
176
+ }
177
+ catch {
178
+ continue;
179
+ }
180
+ for (const candidate of candidates) {
181
+ const normalized = resolveOrigin(candidate);
182
+ if (!normalized) {
183
+ continue;
184
+ }
185
+ const repositoryIds = remoteToRepoIds.get(normalized);
186
+ if (!repositoryIds || repositoryIds.length === 0) {
187
+ // discovery scope 밖 → 명령/보고 대상에서 제외.
188
+ continue;
189
+ }
190
+ const discovery = discover(candidate);
191
+ for (const repositoryId of repositoryIds) {
192
+ const acc = perRepo.get(repositoryId) ?? { ok: false, items: new Map(), mappings: {} };
193
+ // 여러 checkout이 같은 repository를 가리키면 ok는 AND(하나라도 실패면 보존), item/mapping은 localKey로 dedupe.
194
+ acc.ok = perRepo.has(repositoryId) ? acc.ok && discovery.ok : discovery.ok;
195
+ if (discovery.ok) {
196
+ for (const item of discovery.items) {
197
+ acc.items.set(item.localKey, item);
198
+ }
199
+ Object.assign(acc.mappings, discovery.mappings);
200
+ }
201
+ perRepo.set(repositoryId, acc);
202
+ }
203
+ }
204
+ }
205
+ if (perRepo.size === 0) {
206
+ return;
207
+ }
208
+ const syncRepositories = [];
209
+ const freshMappings = {};
210
+ for (const [repositoryId, acc] of perRepo) {
211
+ Object.assign(freshMappings, acc.mappings);
212
+ syncRepositories.push({
213
+ repositoryId,
214
+ ok: acc.ok,
215
+ worktrees: acc.ok ? Array.from(acc.items.values()) : [],
216
+ });
217
+ }
218
+ // 스캔되지 않은 repository의 매핑은 실행을 위해 보존하고, 이번 cycle의 매핑을 합친다.
219
+ try {
220
+ saveMappings({ ...loadMappings(), ...freshMappings });
221
+ }
222
+ catch {
223
+ // 매핑 저장 실패는 보고를 막지 않는다.
224
+ }
225
+ await deps.syncDiscoveredWorktrees(syncRepositories);
226
+ };
227
+ //# sourceMappingURL=worktree-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-discovery.js","sourceRoot":"","sources":["../../src/utils/worktree-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,193 @@
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { mkdtempSync, rmSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { tmpdir } from 'node:os';
6
+ import test from 'node:test';
7
+ import { computeLocalKey, discoverRepositoryWorktrees, parseWorktreePorcelain, reconcileDiscoveredWorktrees, } from './worktree-discovery.js';
8
+ // `git worktree list --porcelain -z`는 attribute를 NUL로 종료하고 record를 빈 attribute(연속 NUL)로 구분한다.
9
+ const rec = (lines) => lines.map((l) => `${l}\0`).join('') + '\0';
10
+ test('parseWorktreePorcelain: main + linked + detached + locked', () => {
11
+ const output = rec(['worktree /repo/main', 'HEAD aaa111', 'branch refs/heads/main']) +
12
+ rec(['worktree /repo/.wt/feature', 'HEAD bbb222', 'branch refs/heads/feature/x']) +
13
+ rec(['worktree /repo/.wt/detached', 'HEAD ccc333', 'detached']) +
14
+ rec(['worktree /repo/.wt/locked', 'HEAD ddd444', 'branch refs/heads/locked-wt', 'locked']);
15
+ const records = parseWorktreePorcelain(output);
16
+ assert.equal(records.length, 4);
17
+ assert.deepEqual(records.map((r) => r.path), ['/repo/main', '/repo/.wt/feature', '/repo/.wt/detached', '/repo/.wt/locked']);
18
+ assert.equal(records[1].branch, 'feature/x');
19
+ assert.equal(records[2].detached, true);
20
+ assert.equal(records[2].branch, null);
21
+ assert.equal(records[3].locked, true);
22
+ assert.equal(records[3].branch, 'locked-wt');
23
+ });
24
+ test('parseWorktreePorcelain: prunable and bare flags', () => {
25
+ const output = rec(['worktree /repo/main', 'HEAD aaa', 'bare']) +
26
+ rec([
27
+ 'worktree /repo/.wt/gone',
28
+ 'HEAD bbb',
29
+ 'branch refs/heads/gone',
30
+ 'prunable gitdir file points to non-existent location',
31
+ ]);
32
+ const records = parseWorktreePorcelain(output);
33
+ assert.equal(records[0].bare, true);
34
+ assert.equal(records[1].prunable, true);
35
+ });
36
+ test('parseWorktreePorcelain: whitespace, non-ASCII, and Windows paths', () => {
37
+ const output = rec(['worktree /repo/main', 'HEAD a', 'branch refs/heads/main']) +
38
+ rec(['worktree /repo/.wt/with space', 'HEAD b', 'branch refs/heads/spaced']) +
39
+ rec(['worktree /repo/.wt/한글-브랜치', 'HEAD c', 'branch refs/heads/한글']) +
40
+ rec(['worktree C:\\Users\\dev\\repo\\.wt\\win', 'HEAD d', 'branch refs/heads/win']);
41
+ const records = parseWorktreePorcelain(output);
42
+ assert.equal(records[1].path, '/repo/.wt/with space');
43
+ assert.equal(records[2].path, '/repo/.wt/한글-브랜치');
44
+ assert.equal(records[2].branch, '한글');
45
+ assert.equal(records[3].path, 'C:\\Users\\dev\\repo\\.wt\\win');
46
+ });
47
+ test('discoverRepositoryWorktrees: excludes main/bare/prunable and maps linked worktrees', () => {
48
+ const output = rec(['worktree /repo/main', 'HEAD aaa', 'branch refs/heads/main']) +
49
+ rec(['worktree /repo/.wt/feature', 'HEAD bbb', 'branch refs/heads/feature/x']) +
50
+ rec(['worktree /repo/.wt/gone', 'HEAD ccc', 'branch refs/heads/gone', 'prunable reason']);
51
+ const result = discoverRepositoryWorktrees('/repo/main', () => output);
52
+ assert.equal(result.ok, true);
53
+ assert.equal(result.items.length, 1);
54
+ const item = result.items[0];
55
+ assert.equal(item.branch, 'feature/x');
56
+ assert.equal(item.headSha, 'bbb');
57
+ // localKey는 canonical 경로 해시. mapping은 절대 경로를 보관한다(서버로는 전송하지 않음).
58
+ assert.ok(result.mappings[item.localKey]);
59
+ assert.equal(item.localKey.length, 64);
60
+ });
61
+ test('discoverRepositoryWorktrees: git failure returns ok=false to preserve server state', () => {
62
+ const result = discoverRepositoryWorktrees('/repo/main', () => {
63
+ throw new Error('git not a repository');
64
+ });
65
+ assert.equal(result.ok, false);
66
+ assert.deepEqual(result.items, []);
67
+ });
68
+ test('discoverRepositoryWorktrees: malformed successful output returns ok=false to preserve server state', () => {
69
+ for (const output of ['', 'garbage\0\0', 'worktree /repo/main\0HEAD abc\0']) {
70
+ const result = discoverRepositoryWorktrees('/repo/main', () => output);
71
+ assert.equal(result.ok, false);
72
+ assert.deepEqual(result.items, []);
73
+ }
74
+ });
75
+ test('reconcileDiscoveredWorktrees: only in-scope repositories are reported; git failure reported as ok=false', async () => {
76
+ const repositories = [
77
+ { id: 'repo-a', projectId: 'p1', remoteUrl: 'https://example.com/acme/a.git' },
78
+ { id: 'repo-b', projectId: 'p1', remoteUrl: 'https://example.com/acme/b.git' },
79
+ // remoteUrl 없음 → 매칭 불가
80
+ { id: 'repo-c', projectId: 'p1', remoteUrl: null },
81
+ ];
82
+ let synced = null;
83
+ const savedMappings = [];
84
+ await reconcileDiscoveredWorktrees({
85
+ fetchDiscoveryRepositories: async () => repositories,
86
+ syncDiscoveredWorktrees: async (repos) => {
87
+ synced = repos;
88
+ },
89
+ authPaths: ['/auth/a', '/auth/b', '/auth/out-of-scope'],
90
+ isGitRepo: () => true,
91
+ // 각 authPath가 자체 git repo. origin으로 repo 신원 매칭.
92
+ resolveRepositoryOrigin: (repoPath) => {
93
+ if (repoPath === '/auth/a')
94
+ return 'example.com/acme/a';
95
+ if (repoPath === '/auth/b')
96
+ return 'example.com/acme/b';
97
+ return 'example.com/acme/unknown'; // scope 밖
98
+ },
99
+ discoverRepositoryWorktrees: (repoPath) => {
100
+ if (repoPath === '/auth/a') {
101
+ return {
102
+ ok: true,
103
+ items: [{ localKey: 'k-a', branch: 'feat/a', headSha: 'a1', displayName: 'feat/a' }],
104
+ mappings: { 'k-a': '/auth/a/.wt/x' },
105
+ };
106
+ }
107
+ // repo-b: git 조회 실패
108
+ return { ok: false, items: [], mappings: {} };
109
+ },
110
+ loadMappings: () => ({}),
111
+ saveMappings: (m) => savedMappings.push(m),
112
+ });
113
+ assert.ok(synced);
114
+ const reported = synced;
115
+ // out-of-scope repo는 보고되지 않는다.
116
+ const ids = reported.map((r) => r.repositoryId).sort();
117
+ assert.deepEqual(ids, ['repo-a', 'repo-b']);
118
+ const a = reported.find((r) => r.repositoryId === 'repo-a');
119
+ assert.equal(a.ok, true);
120
+ assert.equal(a.worktrees.length, 1);
121
+ const b = reported.find((r) => r.repositoryId === 'repo-b');
122
+ assert.equal(b.ok, false);
123
+ assert.deepEqual(b.worktrees, []);
124
+ // 매핑이 원자적으로 저장된다.
125
+ assert.deepEqual(savedMappings.at(-1), { 'k-a': '/auth/a/.wt/x' });
126
+ });
127
+ test('reconcileDiscoveredWorktrees: no local match reports nothing (avoids false MISSING)', async () => {
128
+ let synced = null;
129
+ await reconcileDiscoveredWorktrees({
130
+ fetchDiscoveryRepositories: async () => [{ id: 'repo-x', projectId: 'p', remoteUrl: 'https://example.com/x.git' }],
131
+ syncDiscoveredWorktrees: async (repos) => {
132
+ synced = repos;
133
+ },
134
+ authPaths: ['/auth/unrelated'],
135
+ isGitRepo: () => true,
136
+ resolveRepositoryOrigin: () => 'example.com/unrelated', // no match
137
+ discoverRepositoryWorktrees: () => ({ ok: true, items: [], mappings: {} }),
138
+ loadMappings: () => ({}),
139
+ saveMappings: () => { },
140
+ });
141
+ // 매칭 repository가 없으면 sync 자체를 호출하지 않는다.
142
+ assert.equal(synced, null);
143
+ });
144
+ test('reconcileDiscoveredWorktrees fans one remote snapshot out to every matching project repository', async () => {
145
+ let synced = [];
146
+ await reconcileDiscoveredWorktrees({
147
+ fetchDiscoveryRepositories: async () => [
148
+ { id: 'repo-project-a', projectId: 'a', remoteUrl: 'https://example.com/shared.git' },
149
+ { id: 'repo-project-b', projectId: 'b', remoteUrl: 'git@example.com:shared.git' },
150
+ ],
151
+ syncDiscoveredWorktrees: async (repositories) => {
152
+ synced = repositories;
153
+ },
154
+ authPaths: ['/auth/shared'],
155
+ isGitRepo: () => true,
156
+ resolveRepositoryOrigin: () => 'example.com/shared',
157
+ discoverRepositoryWorktrees: () => ({
158
+ ok: true,
159
+ items: [{ localKey: 'shared-key', branch: 'feature/shared', headSha: 'abc', displayName: 'shared' }],
160
+ mappings: { 'shared-key': '/auth/shared-wt' },
161
+ }),
162
+ loadMappings: () => ({}),
163
+ saveMappings: () => { },
164
+ });
165
+ assert.deepEqual(synced.map((repository) => repository.repositoryId).sort(), ['repo-project-a', 'repo-project-b']);
166
+ assert.ok(synced.every((repository) => repository.worktrees[0]?.localKey === 'shared-key'));
167
+ });
168
+ test('end-to-end: linked worktree added by another tool is discovered without Orca', () => {
169
+ const root = mkdtempSync(join(tmpdir(), 'wt-discovery-'));
170
+ try {
171
+ const repo = join(root, 'repo');
172
+ execFileSync('git', ['init', repo], { stdio: 'pipe' });
173
+ execFileSync('git', ['-C', repo, 'config', 'user.email', 't@t.com'], { stdio: 'pipe' });
174
+ execFileSync('git', ['-C', repo, 'config', 'user.name', 'T'], { stdio: 'pipe' });
175
+ execFileSync('git', ['-C', repo, 'commit', '--allow-empty', '-m', 'init'], { stdio: 'pipe' });
176
+ // 외부 도구 방식: 직접 git worktree add
177
+ const wtPath = join(root, 'external-wt');
178
+ execFileSync('git', ['-C', repo, 'worktree', 'add', '-b', 'external/feature', wtPath], { stdio: 'pipe' });
179
+ const result = discoverRepositoryWorktrees(repo);
180
+ assert.equal(result.ok, true);
181
+ // main은 제외, 외부 linked worktree만 발견
182
+ assert.equal(result.items.length, 1);
183
+ assert.equal(result.items[0].branch, 'external/feature');
184
+ const mappedPath = result.mappings[result.items[0].localKey];
185
+ assert.ok(mappedPath);
186
+ // localKey는 canonical 경로 해시와 일치
187
+ assert.equal(computeLocalKey(mappedPath), result.items[0].localKey);
188
+ }
189
+ finally {
190
+ rmSync(root, { recursive: true, force: true });
191
+ }
192
+ });
193
+ //# sourceMappingURL=worktree-discovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-discovery.test.js","sourceRoot":"","sources":["../../src/utils/worktree-discovery.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,sBAAsB,EACtB,4BAA4B,GAE7B,MAAM,yBAAyB,CAAC;AAGjC,8FAA8F;AAC9F,MAAM,GAAG,GAAG,CAAC,KAAe,EAAU,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;AAEpF,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,MAAM,MAAM,GACV,GAAG,CAAC,CAAC,qBAAqB,EAAE,aAAa,EAAE,wBAAwB,CAAC,CAAC;QACrE,GAAG,CAAC,CAAC,4BAA4B,EAAE,aAAa,EAAE,6BAA6B,CAAC,CAAC;QACjF,GAAG,CAAC,CAAC,6BAA6B,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;QAC/D,GAAG,CAAC,CAAC,2BAA2B,EAAE,aAAa,EAAE,6BAA6B,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE7F,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAChC,MAAM,CAAC,SAAS,CACd,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAC1B,CAAC,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,kBAAkB,CAAC,CAC9E,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACxC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,iDAAiD,EAAE,GAAG,EAAE;IAC3D,MAAM,MAAM,GACV,GAAG,CAAC,CAAC,qBAAqB,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAChD,GAAG,CAAC;YACF,yBAAyB;YACzB,UAAU;YACV,wBAAwB;YACxB,sDAAsD;SACvD,CAAC,CAAC;IACL,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kEAAkE,EAAE,GAAG,EAAE;IAC5E,MAAM,MAAM,GACV,GAAG,CAAC,CAAC,qBAAqB,EAAE,QAAQ,EAAE,wBAAwB,CAAC,CAAC;QAChE,GAAG,CAAC,CAAC,+BAA+B,EAAE,QAAQ,EAAE,0BAA0B,CAAC,CAAC;QAC5E,GAAG,CAAC,CAAC,2BAA2B,EAAE,QAAQ,EAAE,sBAAsB,CAAC,CAAC;QACpE,GAAG,CAAC,CAAC,yCAAyC,EAAE,QAAQ,EAAE,uBAAuB,CAAC,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,gCAAgC,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oFAAoF,EAAE,GAAG,EAAE;IAC9F,MAAM,MAAM,GACV,GAAG,CAAC,CAAC,qBAAqB,EAAE,UAAU,EAAE,wBAAwB,CAAC,CAAC;QAClE,GAAG,CAAC,CAAC,4BAA4B,EAAE,UAAU,EAAE,6BAA6B,CAAC,CAAC;QAC9E,GAAG,CAAC,CAAC,yBAAyB,EAAE,UAAU,EAAE,wBAAwB,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAE5F,MAAM,MAAM,GAAG,2BAA2B,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACvC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAClC,iEAAiE;IACjE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oFAAoF,EAAE,GAAG,EAAE;IAC9F,MAAM,MAAM,GAAG,2BAA2B,CAAC,YAAY,EAAE,GAAG,EAAE;QAC5D,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC/B,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,oGAAoG,EAAE,GAAG,EAAE;IAC9G,KAAK,MAAM,MAAM,IAAI,CAAC,EAAE,EAAE,aAAa,EAAE,iCAAiC,CAAC,EAAE,CAAC;QAC5E,MAAM,MAAM,GAAG,2BAA2B,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC/B,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yGAAyG,EAAE,KAAK,IAAI,EAAE;IACzH,MAAM,YAAY,GAA0B;QAC1C,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,gCAAgC,EAAE;QAC9E,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,gCAAgC,EAAE;QAC9E,uBAAuB;QACvB,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE;KACnD,CAAC;IAEF,IAAI,MAAM,GAA8C,IAAI,CAAC;IAC7D,MAAM,aAAa,GAA6B,EAAE,CAAC;IAEnD,MAAM,4BAA4B,CAAC;QACjC,0BAA0B,EAAE,KAAK,IAAI,EAAE,CAAC,YAAY;QACpD,uBAAuB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACvC,MAAM,GAAG,KAAK,CAAC;QACjB,CAAC;QACD,SAAS,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,oBAAoB,CAAC;QACvD,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;QACrB,gDAAgD;QAChD,uBAAuB,EAAE,CAAC,QAAQ,EAAE,EAAE;YACpC,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,oBAAoB,CAAC;YACxD,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,oBAAoB,CAAC;YACxD,OAAO,0BAA0B,CAAC,CAAC,UAAU;QAC/C,CAAC;QACD,2BAA2B,EAAE,CAAC,QAAQ,EAAuB,EAAE;YAC7D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO;oBACL,EAAE,EAAE,IAAI;oBACR,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;oBACpF,QAAQ,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;iBACrC,CAAC;YACJ,CAAC;YACD,oBAAoB;YACpB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAChD,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACxB,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;KAC3C,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IAClB,MAAM,QAAQ,GAAG,MAAuD,CAAC;IACzE,+BAA+B;IAC/B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC;IACvD,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAE,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACzB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAE,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC1B,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAClC,kBAAkB;IAClB,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;IACrG,IAAI,MAAM,GAA8C,IAAI,CAAC;IAC7D,MAAM,4BAA4B,CAAC;QACjC,0BAA0B,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC;QAClH,uBAAuB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACvC,MAAM,GAAG,KAAK,CAAC;QACjB,CAAC;QACD,SAAS,EAAE,CAAC,iBAAiB,CAAC;QAC9B,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;QACrB,uBAAuB,EAAE,GAAG,EAAE,CAAC,uBAAuB,EAAE,WAAW;QACnE,2BAA2B,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC1E,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACxB,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;KACvB,CAAC,CAAC;IACH,wCAAwC;IACxC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gGAAgG,EAAE,KAAK,IAAI,EAAE;IAChH,IAAI,MAAM,GAAuC,EAAE,CAAC;IACpD,MAAM,4BAA4B,CAAC;QACjC,0BAA0B,EAAE,KAAK,IAAI,EAAE,CAAC;YACtC,EAAE,EAAE,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,gCAAgC,EAAE;YACrF,EAAE,EAAE,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,4BAA4B,EAAE;SAClF;QACD,uBAAuB,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE;YAC9C,MAAM,GAAG,YAAY,CAAC;QACxB,CAAC;QACD,SAAS,EAAE,CAAC,cAAc,CAAC;QAC3B,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;QACrB,uBAAuB,EAAE,GAAG,EAAE,CAAC,oBAAoB;QACnD,2BAA2B,EAAE,GAAG,EAAE,CAAC,CAAC;YAClC,EAAE,EAAE,IAAI;YACR,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;YACpG,QAAQ,EAAE,EAAE,YAAY,EAAE,iBAAiB,EAAE;SAC9C,CAAC;QACF,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACxB,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;KACvB,CAAC,CAAC;IAEH,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACnH,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC;AAC9F,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,8EAA8E,EAAE,GAAG,EAAE;IACxF,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChC,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACvD,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxF,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACjF,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAE9F,gCAAgC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACzC,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAE1G,MAAM,MAAM,GAAG,2BAA2B,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC9B,mCAAmC;QACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC7D,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC;QACtB,gCAAgC;QAChC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACtE,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;AACH,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentteams/runner",
3
- "version": "0.0.101",
3
+ "version": "0.0.102",
4
4
  "description": "AgentRunner - Background runner that polls and executes AI agent tasks",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",