repowise 0.1.87 → 0.1.88

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.
Files changed (2) hide show
  1. package/dist/bin/repowise.js +606 -305
  2. package/package.json +1 -1
@@ -3,12 +3,12 @@
3
3
  // bin/repowise.ts
4
4
  import { readFileSync as readFileSync2 } from "fs";
5
5
  import { fileURLToPath as fileURLToPath3 } from "url";
6
- import { dirname as dirname9, join as join22 } from "path";
6
+ import { dirname as dirname9, join as join23 } from "path";
7
7
  import { Command } from "commander";
8
8
 
9
9
  // ../listener/dist/main.js
10
- import { readFile as readFile5, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
11
- import { join as join12, dirname as dirname4 } from "path";
10
+ import { readFile as readFile6, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
11
+ import { join as join13, dirname as dirname5 } from "path";
12
12
  import { fileURLToPath as fileURLToPath2 } from "url";
13
13
  import lockfile2 from "proper-lockfile";
14
14
 
@@ -20,17 +20,318 @@ function getConfigDir() {
20
20
  return join(homedir(), isStaging ? ".repowise-staging" : ".repowise");
21
21
  }
22
22
 
23
+ // ../../packages/shared/dist/lib/ai-tools.js
24
+ import { readFile, writeFile, mkdir, readdir, stat, unlink } from "fs/promises";
25
+ import { join as join2, dirname } from "path";
26
+ var AI_TOOL_CONFIG = {
27
+ cursor: {
28
+ label: "Cursor",
29
+ fileName: "repowise.mdc",
30
+ filePath: ".cursor/rules/repowise.mdc",
31
+ legacyFilePath: ".cursorrules",
32
+ markerStart: "<!-- repowise-start -->",
33
+ markerEnd: "<!-- repowise-end -->",
34
+ format: "markdown",
35
+ frontmatter: "---\ndescription: RepoWise project context\nglobs: \nalwaysApply: true\n---",
36
+ owned: true
37
+ },
38
+ "claude-code": {
39
+ label: "Claude Code",
40
+ fileName: "CLAUDE.md",
41
+ filePath: "CLAUDE.md",
42
+ markerStart: "<!-- repowise-start -->",
43
+ markerEnd: "<!-- repowise-end -->",
44
+ format: "markdown",
45
+ owned: false
46
+ },
47
+ copilot: {
48
+ label: "GitHub Copilot",
49
+ fileName: "copilot-instructions.md",
50
+ filePath: ".github/copilot-instructions.md",
51
+ markerStart: "<!-- repowise-start -->",
52
+ markerEnd: "<!-- repowise-end -->",
53
+ format: "markdown",
54
+ owned: false
55
+ },
56
+ windsurf: {
57
+ label: "Windsurf",
58
+ fileName: "repowise.md",
59
+ filePath: ".windsurf/rules/repowise.md",
60
+ legacyFilePath: ".windsurfrules",
61
+ markerStart: "<!-- repowise-start -->",
62
+ markerEnd: "<!-- repowise-end -->",
63
+ format: "markdown",
64
+ frontmatter: "---\ntrigger: always_on\ndescription: RepoWise project context\n---",
65
+ owned: true
66
+ },
67
+ cline: {
68
+ label: "Cline",
69
+ fileName: "repowise.md",
70
+ filePath: ".clinerules/repowise.md",
71
+ legacyFilePath: ".clinerules",
72
+ markerStart: "<!-- repowise-start -->",
73
+ markerEnd: "<!-- repowise-end -->",
74
+ format: "markdown",
75
+ owned: true
76
+ },
77
+ codex: {
78
+ label: "Codex",
79
+ fileName: "AGENTS.md",
80
+ filePath: "AGENTS.md",
81
+ markerStart: "<!-- repowise-start -->",
82
+ markerEnd: "<!-- repowise-end -->",
83
+ format: "markdown",
84
+ owned: false
85
+ },
86
+ "roo-code": {
87
+ label: "Roo Code",
88
+ fileName: "repowise.md",
89
+ filePath: ".roo/rules/repowise.md",
90
+ legacyFilePath: ".roo/rules.md",
91
+ markerStart: "<!-- repowise-start -->",
92
+ markerEnd: "<!-- repowise-end -->",
93
+ format: "markdown",
94
+ owned: true
95
+ },
96
+ gemini: {
97
+ label: "Gemini CLI",
98
+ fileName: "GEMINI.md",
99
+ filePath: "GEMINI.md",
100
+ markerStart: "<!-- repowise-start -->",
101
+ markerEnd: "<!-- repowise-end -->",
102
+ format: "markdown",
103
+ owned: false
104
+ },
105
+ junie: {
106
+ label: "JetBrains Junie",
107
+ fileName: "AGENTS.md",
108
+ filePath: ".junie/AGENTS.md",
109
+ markerStart: "<!-- repowise-start -->",
110
+ markerEnd: "<!-- repowise-end -->",
111
+ format: "markdown",
112
+ owned: true
113
+ },
114
+ warp: {
115
+ label: "Warp",
116
+ fileName: "AGENTS.md",
117
+ filePath: "AGENTS.md",
118
+ markerStart: "<!-- repowise-start -->",
119
+ markerEnd: "<!-- repowise-end -->",
120
+ format: "markdown",
121
+ owned: false
122
+ },
123
+ jules: {
124
+ label: "Google Jules",
125
+ fileName: "AGENTS.md",
126
+ filePath: "AGENTS.md",
127
+ markerStart: "<!-- repowise-start -->",
128
+ markerEnd: "<!-- repowise-end -->",
129
+ format: "markdown",
130
+ owned: false
131
+ },
132
+ amp: {
133
+ label: "Amp",
134
+ fileName: "AGENTS.md",
135
+ filePath: "AGENTS.md",
136
+ markerStart: "<!-- repowise-start -->",
137
+ markerEnd: "<!-- repowise-end -->",
138
+ format: "markdown",
139
+ owned: false
140
+ },
141
+ devin: {
142
+ label: "Devin",
143
+ fileName: "AGENTS.md",
144
+ filePath: "AGENTS.md",
145
+ markerStart: "<!-- repowise-start -->",
146
+ markerEnd: "<!-- repowise-end -->",
147
+ format: "markdown",
148
+ owned: false
149
+ }
150
+ };
151
+ var SUPPORTED_TOOLS = Object.keys(AI_TOOL_CONFIG);
152
+ function sanitizeRepoName(name) {
153
+ return name.replace(/[<>[\]`()|\\]/g, "");
154
+ }
155
+ function fileDescriptionFromName(fileName) {
156
+ return fileName.replace(/\.md$/, "").split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
157
+ }
158
+ function generateReference(tool, repoName, contextFolder, contextFiles) {
159
+ const config2 = AI_TOOL_CONFIG[tool];
160
+ const safeName = sanitizeRepoName(repoName);
161
+ const fileLines = contextFiles.map((f) => {
162
+ const baseName = f.fileName.split("/").pop() ?? f.fileName;
163
+ const desc = fileDescriptionFromName(baseName);
164
+ const isOverview = baseName === "project-overview.md";
165
+ return { path: f.relativePath, desc: isOverview ? `${desc} (full index of all files)` : desc };
166
+ });
167
+ const hasFiles = fileLines.length > 0;
168
+ const contentLines = [
169
+ `## Project Context \u2014 ${safeName}`,
170
+ "",
171
+ `This repository has AI-optimized context files generated by RepoWise.`,
172
+ `**IMPORTANT: Before answering questions about the codebase or making any changes, ALWAYS check the \`${contextFolder}/\` folder first.** These files contain pre-analyzed architecture, patterns, API contracts, and domain knowledge that will answer most questions without needing to search the codebase.`,
173
+ "",
174
+ `**Start here:** \`${contextFolder}/project-overview.md\` \u2014 the routing document that maps every context file to its domain. Read it first to find which context file has the answer you need.`,
175
+ ""
176
+ ];
177
+ if (hasFiles) {
178
+ contentLines.push(`**Core context files:**`, "", ...fileLines.map((f) => `- \`${f.path}\` \u2014 ${f.desc}`), "", `> Additional context files may exist beyond this list. Check \`project-overview.md\` for the complete index.`, "");
179
+ }
180
+ contentLines.push(`**Subagents:** When delegating tasks to sub-agents, always include this instruction: "Read \`${contextFolder}/project-overview.md\` before performing any work."`);
181
+ if (config2.owned) {
182
+ const parts = [];
183
+ if (config2.frontmatter) {
184
+ parts.push(config2.frontmatter);
185
+ }
186
+ parts.push("", ...contentLines, "");
187
+ return parts.join("\n");
188
+ }
189
+ return [config2.markerStart, "", ...contentLines, "", config2.markerEnd].join("\n");
190
+ }
191
+ async function updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles) {
192
+ const config2 = AI_TOOL_CONFIG[tool];
193
+ const fullPath = join2(repoRoot, config2.filePath);
194
+ const dir = dirname(fullPath);
195
+ if (dir !== repoRoot) {
196
+ await mkdir(dir, { recursive: true });
197
+ }
198
+ const referenceBlock = generateReference(tool, repoName, contextFolder, contextFiles);
199
+ if (config2.owned) {
200
+ let created2 = true;
201
+ try {
202
+ await stat(fullPath);
203
+ created2 = false;
204
+ } catch {
205
+ }
206
+ await writeFile(fullPath, referenceBlock, "utf-8");
207
+ return { created: created2 };
208
+ }
209
+ let existing = "";
210
+ let created = true;
211
+ try {
212
+ existing = await readFile(fullPath, "utf-8");
213
+ created = false;
214
+ } catch (err) {
215
+ if (err.code !== "ENOENT")
216
+ throw err;
217
+ }
218
+ const startIdx = existing.indexOf(config2.markerStart);
219
+ const endIdx = existing.indexOf(config2.markerEnd);
220
+ let content;
221
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
222
+ const before = existing.slice(0, startIdx);
223
+ const after = existing.slice(endIdx + config2.markerEnd.length);
224
+ content = before + referenceBlock + after;
225
+ } else {
226
+ const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n\n" : existing.length > 0 ? "\n" : "";
227
+ content = existing + separator + referenceBlock + "\n";
228
+ }
229
+ await writeFile(fullPath, content, "utf-8");
230
+ return { created };
231
+ }
232
+ async function migrateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles) {
233
+ const config2 = AI_TOOL_CONFIG[tool];
234
+ if (!config2.legacyFilePath)
235
+ return { migrated: false, legacyRemoved: false };
236
+ const legacyPath = join2(repoRoot, config2.legacyFilePath);
237
+ let legacyIsFile = false;
238
+ try {
239
+ const s = await stat(legacyPath);
240
+ legacyIsFile = s.isFile();
241
+ } catch {
242
+ await updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
243
+ return { migrated: false, legacyRemoved: false };
244
+ }
245
+ if (!legacyIsFile) {
246
+ await updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
247
+ return { migrated: false, legacyRemoved: false };
248
+ }
249
+ const legacyContent = await readFile(legacyPath, "utf-8");
250
+ let cleaned = legacyContent;
251
+ const oldMarkers = [
252
+ { start: "# --- repowise-start ---", end: "# --- repowise-end ---" },
253
+ { start: "<!-- repowise-start -->", end: "<!-- repowise-end -->" }
254
+ ];
255
+ for (const m of oldMarkers) {
256
+ const si = cleaned.indexOf(m.start);
257
+ const ei = cleaned.indexOf(m.end);
258
+ if (si !== -1 && ei !== -1 && ei > si) {
259
+ cleaned = cleaned.slice(0, si) + cleaned.slice(ei + m.end.length);
260
+ }
261
+ }
262
+ cleaned = cleaned.replace(/\n{3,}/g, "\n\n").trim();
263
+ if (tool === "cline") {
264
+ if (cleaned.length > 0) {
265
+ await unlink(legacyPath);
266
+ await mkdir(join2(repoRoot, ".clinerules"), { recursive: true });
267
+ await writeFile(join2(repoRoot, ".clinerules/user-rules.md"), cleaned + "\n", "utf-8");
268
+ } else {
269
+ await unlink(legacyPath);
270
+ }
271
+ } else if (cleaned.length > 0) {
272
+ await writeFile(legacyPath, cleaned + "\n", "utf-8");
273
+ } else {
274
+ await unlink(legacyPath);
275
+ }
276
+ await updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
277
+ return { migrated: true, legacyRemoved: cleaned.length === 0 };
278
+ }
279
+ async function fileExists(path) {
280
+ try {
281
+ await stat(path);
282
+ return true;
283
+ } catch {
284
+ return false;
285
+ }
286
+ }
287
+ async function detectInstalledTools(repoRoot) {
288
+ const detected = [];
289
+ for (const [tool, config2] of Object.entries(AI_TOOL_CONFIG)) {
290
+ if (tool !== "codex" && config2.filePath === "AGENTS.md")
291
+ continue;
292
+ if (await fileExists(join2(repoRoot, config2.filePath))) {
293
+ detected.push(tool);
294
+ } else if (config2.legacyFilePath && await fileExists(join2(repoRoot, config2.legacyFilePath))) {
295
+ detected.push(tool);
296
+ }
297
+ }
298
+ return detected;
299
+ }
300
+ async function scanLocalContextFiles(repoRoot, contextFolder) {
301
+ const folderPath = join2(repoRoot, contextFolder);
302
+ try {
303
+ const entries = await readdir(folderPath, { withFileTypes: true, recursive: true });
304
+ const results = [];
305
+ for (const entry of entries) {
306
+ if (!entry.isFile() || !entry.name.endsWith(".md"))
307
+ continue;
308
+ const parentDir = entry.parentPath ?? folderPath;
309
+ const fullPath = join2(parentDir, entry.name);
310
+ const relFromContext = fullPath.slice(folderPath.length + 1);
311
+ results.push({
312
+ fileName: relFromContext,
313
+ relativePath: `${contextFolder}/${relFromContext}`
314
+ });
315
+ }
316
+ return results.sort((a, b) => a.fileName.localeCompare(b.fileName));
317
+ } catch (err) {
318
+ if (err.code === "ENOENT")
319
+ return [];
320
+ throw err;
321
+ }
322
+ }
323
+
23
324
  // ../listener/dist/lib/config.js
24
- import { readFile, writeFile, rename, unlink, mkdir, chmod } from "fs/promises";
25
- import { join as join2 } from "path";
325
+ import { readFile as readFile2, writeFile as writeFile2, rename, unlink as unlink2, mkdir as mkdir2, chmod } from "fs/promises";
326
+ import { join as join3 } from "path";
26
327
  import lockfile from "proper-lockfile";
27
328
  var DEFAULT_API_URL = false ? "https://staging-api.repowise.ai" : "https://api.repowise.ai";
28
329
  async function getListenerConfig() {
29
330
  const configDir = getConfigDir();
30
- const configPath = join2(configDir, "config.json");
331
+ const configPath = join3(configDir, "config.json");
31
332
  const apiUrl = process.env["REPOWISE_API_URL"] ?? DEFAULT_API_URL;
32
333
  try {
33
- const data = await readFile(configPath, "utf-8");
334
+ const data = await readFile2(configPath, "utf-8");
34
335
  const raw = JSON.parse(data);
35
336
  const validRepos = (raw.repos ?? []).filter((r) => typeof r === "object" && r !== null && typeof r.repoId === "string" && typeof r.localPath === "string");
36
337
  return {
@@ -45,10 +346,10 @@ async function getListenerConfig() {
45
346
  }
46
347
  async function saveListenerConfig(config2) {
47
348
  const configDir = getConfigDir();
48
- const configPath = join2(configDir, "config.json");
49
- await mkdir(configDir, { recursive: true, mode: 448 });
349
+ const configPath = join3(configDir, "config.json");
350
+ await mkdir2(configDir, { recursive: true, mode: 448 });
50
351
  try {
51
- await writeFile(configPath, "", { flag: "a" });
352
+ await writeFile2(configPath, "", { flag: "a" });
52
353
  } catch {
53
354
  }
54
355
  let release = null;
@@ -56,7 +357,7 @@ async function saveListenerConfig(config2) {
56
357
  release = await lockfile.lock(configPath, { stale: 1e4, retries: 3, realpath: false });
57
358
  let raw = {};
58
359
  try {
59
- const data = await readFile(configPath, "utf-8");
360
+ const data = await readFile2(configPath, "utf-8");
60
361
  raw = JSON.parse(data);
61
362
  } catch {
62
363
  }
@@ -67,12 +368,12 @@ async function saveListenerConfig(config2) {
67
368
  };
68
369
  const tmpPath = configPath + ".tmp";
69
370
  try {
70
- await writeFile(tmpPath, JSON.stringify(output, null, 2));
371
+ await writeFile2(tmpPath, JSON.stringify(output, null, 2));
71
372
  await chmod(tmpPath, 384);
72
373
  await rename(tmpPath, configPath);
73
374
  } catch (err) {
74
375
  try {
75
- await unlink(tmpPath);
376
+ await unlink2(tmpPath);
76
377
  } catch {
77
378
  }
78
379
  throw err;
@@ -88,15 +389,15 @@ async function saveListenerConfig(config2) {
88
389
  }
89
390
 
90
391
  // ../listener/dist/lib/state.js
91
- import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2, rename as rename2, unlink as unlink2 } from "fs/promises";
92
- import { join as join3 } from "path";
392
+ import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, chmod as chmod2, rename as rename2, unlink as unlink3 } from "fs/promises";
393
+ import { join as join4 } from "path";
93
394
  function emptyState() {
94
395
  return { repos: {} };
95
396
  }
96
397
  async function loadState() {
97
- const statePath = join3(getConfigDir(), "listener-state.json");
398
+ const statePath = join4(getConfigDir(), "listener-state.json");
98
399
  try {
99
- const data = await readFile2(statePath, "utf-8");
400
+ const data = await readFile3(statePath, "utf-8");
100
401
  return JSON.parse(data);
101
402
  } catch (err) {
102
403
  if (err.code === "ENOENT" || err instanceof SyntaxError) {
@@ -107,16 +408,16 @@ async function loadState() {
107
408
  }
108
409
  async function saveState(state) {
109
410
  const configDir = getConfigDir();
110
- const statePath = join3(configDir, "listener-state.json");
111
- await mkdir2(configDir, { recursive: true, mode: 448 });
411
+ const statePath = join4(configDir, "listener-state.json");
412
+ await mkdir3(configDir, { recursive: true, mode: 448 });
112
413
  const tmpPath = statePath + ".tmp";
113
414
  try {
114
- await writeFile2(tmpPath, JSON.stringify(state, null, 2));
415
+ await writeFile3(tmpPath, JSON.stringify(state, null, 2));
115
416
  await chmod2(tmpPath, 384);
116
417
  await rename2(tmpPath, statePath);
117
418
  } catch (err) {
118
419
  try {
119
- await unlink2(tmpPath);
420
+ await unlink3(tmpPath);
120
421
  } catch {
121
422
  }
122
423
  throw err;
@@ -125,7 +426,7 @@ async function saveState(state) {
125
426
 
126
427
  // ../listener/dist/lib/reconcile.js
127
428
  import { statSync, readdirSync } from "fs";
128
- import { basename, dirname, join as join4 } from "path";
429
+ import { basename, dirname as dirname2, join as join5 } from "path";
129
430
  function reconcileRepos(configRepos, activeRepos, state, apiUrl, options) {
130
431
  if (activeRepos.length === 0) {
131
432
  return { updated: false, repos: configRepos, changes: [], addedRepos: [] };
@@ -169,7 +470,7 @@ function reconcileRepos(configRepos, activeRepos, state, apiUrl, options) {
169
470
  }
170
471
  }
171
472
  const dirName = basename(repo.localPath);
172
- const parentDir = basename(dirname(repo.localPath));
473
+ const parentDir = basename(dirname2(repo.localPath));
173
474
  const fullPathName = `${parentDir}/${dirName}`;
174
475
  let matches = activeRepos.filter((ar) => ar.fullName === fullPathName);
175
476
  if (matches.length === 0) {
@@ -209,7 +510,7 @@ function reconcileRepos(configRepos, activeRepos, state, apiUrl, options) {
209
510
  if (unmatchedActiveRepos.length > 0) {
210
511
  const parentDirs = /* @__PURE__ */ new Set();
211
512
  for (const repo of updatedRepos) {
212
- parentDirs.add(dirname(repo.localPath));
513
+ parentDirs.add(dirname2(repo.localPath));
213
514
  }
214
515
  for (const activeRepo of unmatchedActiveRepos) {
215
516
  const found = findLocalRepo(activeRepo, parentDirs, usedPaths);
@@ -243,7 +544,7 @@ function findLocalRepo(activeRepo, parentDirs, usedPaths) {
243
544
  const nameParts = activeRepo.fullName.split("/");
244
545
  const repoName = nameParts[nameParts.length - 1];
245
546
  for (const parentDir of parentDirs) {
246
- const candidate = join4(parentDir, repoName);
547
+ const candidate = join5(parentDir, repoName);
247
548
  if (!usedPaths.has(candidate) && hasContextFolder(candidate)) {
248
549
  return candidate;
249
550
  }
@@ -252,7 +553,7 @@ function findLocalRepo(activeRepo, parentDirs, usedPaths) {
252
553
  }
253
554
  function hasContextFolder(dirPath) {
254
555
  try {
255
- const contextPath = join4(dirPath, "repowise-context");
556
+ const contextPath = join5(dirPath, "repowise-context");
256
557
  const s = statSync(contextPath);
257
558
  if (!s.isDirectory())
258
559
  return false;
@@ -282,8 +583,8 @@ function migrateState(state, oldId, newId) {
282
583
  }
283
584
 
284
585
  // ../listener/dist/lib/auth.js
285
- import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, chmod as chmod3 } from "fs/promises";
286
- import { join as join5 } from "path";
586
+ import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, chmod as chmod3 } from "fs/promises";
587
+ import { join as join6 } from "path";
287
588
  function getTokenUrl(creds) {
288
589
  const cognito = creds?.cognito;
289
590
  const domain = process.env["REPOWISE_COGNITO_DOMAIN"] ?? cognito?.domain ?? "auth-repowise-dev";
@@ -322,8 +623,8 @@ async function refreshTokens(refreshToken, creds) {
322
623
  }
323
624
  async function getStoredCredentials() {
324
625
  try {
325
- const credPath = join5(getConfigDir(), "credentials.json");
326
- const data = await readFile3(credPath, "utf-8");
626
+ const credPath = join6(getConfigDir(), "credentials.json");
627
+ const data = await readFile4(credPath, "utf-8");
327
628
  return JSON.parse(data);
328
629
  } catch (err) {
329
630
  if (err.code === "ENOENT" || err instanceof SyntaxError) {
@@ -334,9 +635,9 @@ async function getStoredCredentials() {
334
635
  }
335
636
  async function storeCredentials(credentials) {
336
637
  const dir = getConfigDir();
337
- const credPath = join5(dir, "credentials.json");
338
- await mkdir3(dir, { recursive: true, mode: 448 });
339
- await writeFile3(credPath, JSON.stringify(credentials, null, 2));
638
+ const credPath = join6(dir, "credentials.json");
639
+ await mkdir4(dir, { recursive: true, mode: 448 });
640
+ await writeFile4(credPath, JSON.stringify(credentials, null, 2));
340
641
  await chmod3(credPath, 384);
341
642
  }
342
643
  async function getValidCredentials(options) {
@@ -487,16 +788,16 @@ function notifyContextUpdated(repoId, fileCount) {
487
788
 
488
789
  // ../listener/dist/context-fetcher.js
489
790
  import { execFile } from "child_process";
490
- import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
491
- import { dirname as dirname2, join as join7 } from "path";
791
+ import { mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
792
+ import { dirname as dirname3, join as join8 } from "path";
492
793
  import { promisify } from "util";
493
794
 
494
795
  // ../listener/dist/file-writer.js
495
796
  import { access } from "fs/promises";
496
- import { join as join6 } from "path";
797
+ import { join as join7 } from "path";
497
798
  async function verifyContextFolder(localPath) {
498
799
  try {
499
- await access(join6(localPath, "repowise-context"));
800
+ await access(join7(localPath, "repowise-context"));
500
801
  return true;
501
802
  } catch {
502
803
  return false;
@@ -584,8 +885,8 @@ async function fetchContextFromServer(repoId, localPath, apiUrl) {
584
885
  if (files.length === 0) {
585
886
  return { success: true, updatedFiles: [] };
586
887
  }
587
- const contextDir = join7(localPath, "repowise-context");
588
- await mkdir4(contextDir, { recursive: true });
888
+ const contextDir = join8(localPath, "repowise-context");
889
+ await mkdir5(contextDir, { recursive: true });
589
890
  const updatedFiles = [];
590
891
  for (const file of files) {
591
892
  if (file.fileName.includes(".."))
@@ -609,9 +910,9 @@ async function fetchContextFromServer(repoId, localPath, apiUrl) {
609
910
  continue;
610
911
  }
611
912
  const content = await contentRes.text();
612
- const filePath = join7(contextDir, file.fileName);
613
- await mkdir4(dirname2(filePath), { recursive: true });
614
- await writeFile4(filePath, content, "utf-8");
913
+ const filePath = join8(contextDir, file.fileName);
914
+ await mkdir5(dirname3(filePath), { recursive: true });
915
+ await writeFile5(filePath, content, "utf-8");
615
916
  updatedFiles.push(file.fileName);
616
917
  }
617
918
  console.log(`Context fetch for ${repoId}: downloaded ${updatedFiles.length}/${files.length} file(s)`);
@@ -626,19 +927,19 @@ async function fetchContextFromServer(repoId, localPath, apiUrl) {
626
927
  // ../listener/dist/process-manager.js
627
928
  import { spawn } from "child_process";
628
929
  import { openSync, closeSync } from "fs";
629
- import { readFile as readFile4, writeFile as writeFile5, mkdir as mkdir5, unlink as unlink3 } from "fs/promises";
930
+ import { readFile as readFile5, writeFile as writeFile6, mkdir as mkdir6, unlink as unlink4 } from "fs/promises";
630
931
  import { homedir as homedir2 } from "os";
631
- import { join as join8 } from "path";
932
+ import { join as join9 } from "path";
632
933
  import { createRequire } from "module";
633
934
  import { fileURLToPath } from "url";
634
935
  function repowiseDir() {
635
936
  return getConfigDir();
636
937
  }
637
938
  function pidPath() {
638
- return join8(repowiseDir(), "listener.pid");
939
+ return join9(repowiseDir(), "listener.pid");
639
940
  }
640
941
  function logDirPath() {
641
- return join8(repowiseDir(), "logs");
942
+ return join9(repowiseDir(), "logs");
642
943
  }
643
944
  function resolveListenerCommand() {
644
945
  try {
@@ -652,7 +953,7 @@ function resolveListenerCommand() {
652
953
  }
653
954
  async function readPid() {
654
955
  try {
655
- const content = await readFile4(pidPath(), "utf-8");
956
+ const content = await readFile5(pidPath(), "utf-8");
656
957
  const pid = parseInt(content.trim(), 10);
657
958
  return Number.isNaN(pid) ? null : pid;
658
959
  } catch (err) {
@@ -676,10 +977,10 @@ async function startBackground() {
676
977
  return pid2;
677
978
  }
678
979
  const logDir2 = logDirPath();
679
- await mkdir5(logDir2, { recursive: true });
980
+ await mkdir6(logDir2, { recursive: true });
680
981
  const cmd = resolveListenerCommand();
681
- const stdoutFd = openSync(join8(logDir2, "listener-stdout.log"), "a");
682
- const stderrFd = openSync(join8(logDir2, "listener-stderr.log"), "a");
982
+ const stdoutFd = openSync(join9(logDir2, "listener-stdout.log"), "a");
983
+ const stderrFd = openSync(join9(logDir2, "listener-stderr.log"), "a");
683
984
  const child = spawn(process.execPath, [cmd.script, ...cmd.args], {
684
985
  detached: true,
685
986
  stdio: ["ignore", stdoutFd, stderrFd],
@@ -692,7 +993,7 @@ async function startBackground() {
692
993
  const pid = child.pid;
693
994
  if (!pid)
694
995
  throw new Error("Failed to spawn listener process");
695
- await writeFile5(pidPath(), String(pid));
996
+ await writeFile6(pidPath(), String(pid));
696
997
  return pid;
697
998
  }
698
999
  async function stopProcess() {
@@ -727,7 +1028,7 @@ async function isRunning() {
727
1028
  }
728
1029
  async function removePidFile() {
729
1030
  try {
730
- await unlink3(pidPath());
1031
+ await unlink4(pidPath());
731
1032
  } catch {
732
1033
  }
733
1034
  }
@@ -735,7 +1036,7 @@ async function removePidFile() {
735
1036
  // ../listener/dist/lib/auto-updater.js
736
1037
  import { execFile as execFile2 } from "child_process";
737
1038
  import { access as access2, constants, realpath } from "fs/promises";
738
- import { dirname as dirname3, join as join9 } from "path";
1039
+ import { dirname as dirname4, join as join10 } from "path";
739
1040
  import { promisify as promisify2 } from "util";
740
1041
  var execFileAsync2 = promisify2(execFile2);
741
1042
  async function installUpdate(currentVersion, packageName, targetVersion) {
@@ -747,12 +1048,12 @@ async function installUpdate(currentVersion, packageName, targetVersion) {
747
1048
  console.log(`[auto-update] ${targetVersion} is not newer than ${currentVersion} \u2014 skipping`);
748
1049
  return { updated: false };
749
1050
  }
750
- const npmWrapper = join9(dirname3(process.execPath), "npm");
1051
+ const npmWrapper = join10(dirname4(process.execPath), "npm");
751
1052
  const npmScript = await realpath(npmWrapper);
752
1053
  const runNpm = (args) => execFileAsync2(process.execPath, [npmScript, ...args], { timeout: 6e4 });
753
1054
  try {
754
1055
  const { stdout: prefix } = await runNpm(["prefix", "-g"]);
755
- const npmDir = join9(prefix.trim(), "lib", "node_modules");
1056
+ const npmDir = join10(prefix.trim(), "lib", "node_modules");
756
1057
  const checkDir = process.platform === "win32" ? prefix.trim() : npmDir;
757
1058
  await access2(checkDir, constants.W_OK);
758
1059
  } catch (err) {
@@ -821,14 +1122,14 @@ function comparePrerelease(a, b) {
821
1122
  }
822
1123
 
823
1124
  // ../listener/dist/lifecycle.js
824
- import { unlink as unlink5 } from "fs/promises";
825
- import { join as join11 } from "path";
1125
+ import { unlink as unlink6 } from "fs/promises";
1126
+ import { join as join12 } from "path";
826
1127
 
827
1128
  // ../listener/dist/service-installer.js
828
1129
  import { execFile as execFile3 } from "child_process";
829
- import { writeFile as writeFile6, mkdir as mkdir6, unlink as unlink4 } from "fs/promises";
1130
+ import { writeFile as writeFile7, mkdir as mkdir7, unlink as unlink5 } from "fs/promises";
830
1131
  import { homedir as homedir3 } from "os";
831
- import { join as join10 } from "path";
1132
+ import { join as join11 } from "path";
832
1133
  var IS_STAGING = true ? false : false;
833
1134
  function exec(cmd, args) {
834
1135
  return new Promise((resolve, reject) => {
@@ -843,10 +1144,10 @@ function exec(cmd, args) {
843
1144
  }
844
1145
  var PLIST_LABEL = IS_STAGING ? "com.repowise-staging.listener" : "com.repowise.listener";
845
1146
  function plistPath() {
846
- return join10(homedir3(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
1147
+ return join11(homedir3(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
847
1148
  }
848
1149
  function logDir() {
849
- return join10(getConfigDir(), "logs");
1150
+ return join11(getConfigDir(), "logs");
850
1151
  }
851
1152
  function buildPlist() {
852
1153
  const cmd = resolveListenerCommand();
@@ -868,22 +1169,22 @@ ${programArgs}
868
1169
  <key>KeepAlive</key>
869
1170
  <true/>
870
1171
  <key>StandardOutPath</key>
871
- <string>${join10(logs, "listener-stdout.log")}</string>
1172
+ <string>${join11(logs, "listener-stdout.log")}</string>
872
1173
  <key>StandardErrorPath</key>
873
- <string>${join10(logs, "listener-stderr.log")}</string>
1174
+ <string>${join11(logs, "listener-stderr.log")}</string>
874
1175
  <key>ProcessType</key>
875
1176
  <string>Background</string>
876
1177
  </dict>
877
1178
  </plist>`;
878
1179
  }
879
1180
  async function darwinInstall() {
880
- await mkdir6(logDir(), { recursive: true });
881
- await mkdir6(join10(homedir3(), "Library", "LaunchAgents"), { recursive: true });
1181
+ await mkdir7(logDir(), { recursive: true });
1182
+ await mkdir7(join11(homedir3(), "Library", "LaunchAgents"), { recursive: true });
882
1183
  try {
883
1184
  await exec("launchctl", ["unload", plistPath()]);
884
1185
  } catch {
885
1186
  }
886
- await writeFile6(plistPath(), buildPlist());
1187
+ await writeFile7(plistPath(), buildPlist());
887
1188
  await exec("launchctl", ["load", plistPath()]);
888
1189
  }
889
1190
  async function darwinUninstall() {
@@ -892,7 +1193,7 @@ async function darwinUninstall() {
892
1193
  } catch {
893
1194
  }
894
1195
  try {
895
- await unlink4(plistPath());
1196
+ await unlink5(plistPath());
896
1197
  } catch {
897
1198
  }
898
1199
  }
@@ -906,7 +1207,7 @@ async function darwinIsInstalled() {
906
1207
  }
907
1208
  var SYSTEMD_SERVICE = IS_STAGING ? "repowise-staging-listener" : "repowise-listener";
908
1209
  function unitPath() {
909
- return join10(homedir3(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
1210
+ return join11(homedir3(), ".config", "systemd", "user", `${SYSTEMD_SERVICE}.service`);
910
1211
  }
911
1212
  function buildUnit() {
912
1213
  const cmd = resolveListenerCommand();
@@ -922,16 +1223,16 @@ Type=simple
922
1223
  ExecStart=${execStart}
923
1224
  Restart=always
924
1225
  RestartSec=10
925
- StandardOutput=append:${join10(logs, "listener-stdout.log")}
926
- StandardError=append:${join10(logs, "listener-stderr.log")}
1226
+ StandardOutput=append:${join11(logs, "listener-stdout.log")}
1227
+ StandardError=append:${join11(logs, "listener-stderr.log")}
927
1228
 
928
1229
  [Install]
929
1230
  WantedBy=default.target`;
930
1231
  }
931
1232
  async function linuxInstall() {
932
- await mkdir6(logDir(), { recursive: true });
933
- await mkdir6(join10(homedir3(), ".config", "systemd", "user"), { recursive: true });
934
- await writeFile6(unitPath(), buildUnit());
1233
+ await mkdir7(logDir(), { recursive: true });
1234
+ await mkdir7(join11(homedir3(), ".config", "systemd", "user"), { recursive: true });
1235
+ await writeFile7(unitPath(), buildUnit());
935
1236
  await exec("systemctl", ["--user", "daemon-reload"]);
936
1237
  await exec("systemctl", ["--user", "enable", SYSTEMD_SERVICE]);
937
1238
  await exec("systemctl", ["--user", "start", SYSTEMD_SERVICE]);
@@ -946,7 +1247,7 @@ async function linuxUninstall() {
946
1247
  } catch {
947
1248
  }
948
1249
  try {
949
- await unlink4(unitPath());
1250
+ await unlink5(unitPath());
950
1251
  } catch {
951
1252
  }
952
1253
  try {
@@ -964,7 +1265,7 @@ async function linuxIsInstalled() {
964
1265
  }
965
1266
  var TASK_NAME = IS_STAGING ? "RepoWise Staging Listener" : "RepoWise Listener";
966
1267
  async function win32Install() {
967
- await mkdir6(logDir(), { recursive: true });
1268
+ await mkdir7(logDir(), { recursive: true });
968
1269
  const cmd = resolveListenerCommand();
969
1270
  const taskCmd = [process.execPath, cmd.script, ...cmd.args].map((a) => `"${a}"`).join(" ");
970
1271
  await exec("schtasks", [
@@ -1115,7 +1416,7 @@ async function getListenerStatus() {
1115
1416
  return { running: true, method: "pid", pid, serviceInstalled: serviceInstalled2 };
1116
1417
  }
1117
1418
  try {
1118
- await unlink5(join11(getConfigDir(), "listener.pid"));
1419
+ await unlink6(join12(getConfigDir(), "listener.pid"));
1119
1420
  } catch {
1120
1421
  }
1121
1422
  }
@@ -1163,6 +1464,57 @@ var TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1e3;
1163
1464
  var STALE_CHECK_COOLDOWN_MS = 60 * 60 * 1e3;
1164
1465
  var CRASH_LOOP_WINDOW_MS = 3e4;
1165
1466
  var CRASH_LOOP_THRESHOLD = 3;
1467
+ async function readRawToolConfig() {
1468
+ try {
1469
+ const configPath = join13(getConfigDir(), "config.json");
1470
+ const data = await readFile6(configPath, "utf-8");
1471
+ const raw = JSON.parse(data);
1472
+ return {
1473
+ aiTools: Array.isArray(raw["aiTools"]) ? raw["aiTools"] : void 0,
1474
+ contextFolder: typeof raw["contextFolder"] === "string" ? raw["contextFolder"] : void 0
1475
+ };
1476
+ } catch {
1477
+ return {};
1478
+ }
1479
+ }
1480
+ async function updateToolConfigsForRepo(localPath, config2, state, repoId) {
1481
+ const contextFolder = config2.contextFolder ?? "repowise-context";
1482
+ const repoName = localPath.split("/").pop() ?? "unknown";
1483
+ let tools = config2.aiTools ?? [];
1484
+ if (tools.length === 0) {
1485
+ tools = await detectInstalledTools(localPath);
1486
+ }
1487
+ if (tools.length === 0)
1488
+ return;
1489
+ const contextFiles = await scanLocalContextFiles(localPath, contextFolder);
1490
+ if (contextFiles.length === 0)
1491
+ return;
1492
+ const hash = JSON.stringify({ tools, files: contextFiles.map((f) => f.fileName) });
1493
+ if (state.repos[repoId]?.lastToolConfigHash === hash)
1494
+ return;
1495
+ const written = /* @__PURE__ */ new Set();
1496
+ for (const tool of tools) {
1497
+ const toolConfig = AI_TOOL_CONFIG[tool];
1498
+ if (!toolConfig)
1499
+ continue;
1500
+ if (written.has(toolConfig.filePath))
1501
+ continue;
1502
+ written.add(toolConfig.filePath);
1503
+ if (toolConfig.legacyFilePath) {
1504
+ await migrateToolConfig(localPath, tool, repoName, contextFolder, contextFiles);
1505
+ } else {
1506
+ await updateToolConfig(localPath, tool, repoName, contextFolder, contextFiles);
1507
+ }
1508
+ }
1509
+ if (!written.has("AGENTS.md")) {
1510
+ await updateToolConfig(localPath, "codex", repoName, contextFolder, contextFiles);
1511
+ }
1512
+ if (!state.repos[repoId]) {
1513
+ state.repos[repoId] = { lastSyncTimestamp: "", lastSyncCommitSha: null };
1514
+ }
1515
+ state.repos[repoId].lastToolConfigHash = hash;
1516
+ console.log(`[ai-tools] Updated tool configs for ${repoId}`);
1517
+ }
1166
1518
  var running = false;
1167
1519
  var sleepResolve = null;
1168
1520
  var releaseLock = null;
@@ -1212,6 +1564,12 @@ async function processNotifications(notifications, state, repoLocalPaths, apiUrl
1212
1564
  if (result.success) {
1213
1565
  updateCount++;
1214
1566
  notifyContextUpdated(notif.repoId, result.updatedFiles.length);
1567
+ try {
1568
+ const toolConfig = await readRawToolConfig();
1569
+ await updateToolConfigsForRepo(localPath, toolConfig, state, notif.repoId);
1570
+ } catch (toolErr) {
1571
+ console.warn(`[ai-tools] Tool config update failed for ${notif.repoId}:`, toolErr instanceof Error ? toolErr.message : toolErr);
1572
+ }
1215
1573
  state.repos[notif.repoId] = {
1216
1574
  ...state.repos[notif.repoId],
1217
1575
  lastSyncTimestamp: notif.createdAt,
@@ -1287,7 +1645,7 @@ async function checkStaleContext(repos, state, groups) {
1287
1645
  if (group?.offline.isOffline)
1288
1646
  continue;
1289
1647
  const { statSync: statSync2, readdirSync: readdirSync2 } = await import("fs");
1290
- const contextPath = join12(repo.localPath, "repowise-context");
1648
+ const contextPath = join13(repo.localPath, "repowise-context");
1291
1649
  let isMissingOrEmpty = false;
1292
1650
  try {
1293
1651
  const s = statSync2(contextPath);
@@ -1319,9 +1677,9 @@ async function checkStaleContext(repos, state, groups) {
1319
1677
  async function startListener() {
1320
1678
  running = true;
1321
1679
  const configDir = getConfigDir();
1322
- await mkdir7(configDir, { recursive: true });
1323
- const lockPath = join12(configDir, "listener.lock");
1324
- await writeFile7(lockPath, "", { flag: "a" });
1680
+ await mkdir8(configDir, { recursive: true });
1681
+ const lockPath = join13(configDir, "listener.lock");
1682
+ await writeFile8(lockPath, "", { flag: "a" });
1325
1683
  let lockIsHeld = false;
1326
1684
  try {
1327
1685
  lockIsHeld = await lockfile2.check(lockPath, { stale: 3e4, realpath: false });
@@ -1363,7 +1721,7 @@ async function startListener() {
1363
1721
  return;
1364
1722
  }
1365
1723
  if (config2.repos.length === 0 && !config2.autoDiscoverRepos) {
1366
- console.error(`No repos configured. Add repos to ${join12(configDir, "config.json")}`);
1724
+ console.error(`No repos configured. Add repos to ${join13(configDir, "config.json")}`);
1367
1725
  await releaseLockAndExit();
1368
1726
  process.exitCode = 1;
1369
1727
  return;
@@ -1430,9 +1788,9 @@ async function startListener() {
1430
1788
  const packageName = true ? "repowise" : "repowise";
1431
1789
  let currentVersion = "";
1432
1790
  try {
1433
- const selfDir = dirname4(fileURLToPath2(import.meta.url));
1434
- const pkgJsonPath = join12(selfDir, "..", "..", "package.json");
1435
- const pkgJson = JSON.parse(await readFile5(pkgJsonPath, "utf-8"));
1791
+ const selfDir = dirname5(fileURLToPath2(import.meta.url));
1792
+ const pkgJsonPath = join13(selfDir, "..", "..", "package.json");
1793
+ const pkgJson = JSON.parse(await readFile6(pkgJsonPath, "utf-8"));
1436
1794
  currentVersion = pkgJson.version;
1437
1795
  } catch (err) {
1438
1796
  console.log(`[auto-update] Version detection failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -1651,7 +2009,7 @@ async function startListener() {
1651
2009
  } catch {
1652
2010
  }
1653
2011
  }
1654
- const credentialsPath = join12(getConfigDir(), "credentials.json");
2012
+ const credentialsPath = join13(getConfigDir(), "credentials.json");
1655
2013
  let credentialsChanged = false;
1656
2014
  let watcher = null;
1657
2015
  try {
@@ -1697,7 +2055,7 @@ if (isDirectRun) {
1697
2055
 
1698
2056
  // src/lib/env.ts
1699
2057
  import { homedir as homedir4 } from "os";
1700
- import { join as join13 } from "path";
2058
+ import { join as join14 } from "path";
1701
2059
  var IS_STAGING2 = true ? false : false;
1702
2060
  var PRODUCTION = {
1703
2061
  apiUrl: "https://api.repowise.ai",
@@ -1717,7 +2075,7 @@ function getEnvConfig() {
1717
2075
  return IS_STAGING2 ? STAGING : PRODUCTION;
1718
2076
  }
1719
2077
  function getConfigDir2() {
1720
- return join13(homedir4(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
2078
+ return join14(homedir4(), IS_STAGING2 ? ".repowise-staging" : ".repowise");
1721
2079
  }
1722
2080
  function getPackageName() {
1723
2081
  return true ? "repowise" : "repowise";
@@ -1727,12 +2085,12 @@ function getPackageName() {
1727
2085
  import chalk from "chalk";
1728
2086
 
1729
2087
  // src/lib/config.ts
1730
- import { readFile as readFile6, writeFile as writeFile8, mkdir as mkdir8, rename as rename3, unlink as unlink6 } from "fs/promises";
1731
- import { join as join14 } from "path";
2088
+ import { readFile as readFile7, writeFile as writeFile9, mkdir as mkdir9, rename as rename3, unlink as unlink7 } from "fs/promises";
2089
+ import { join as join15 } from "path";
1732
2090
  import lockfile3 from "proper-lockfile";
1733
2091
  async function getConfig() {
1734
2092
  try {
1735
- const data = await readFile6(join14(getConfigDir2(), "config.json"), "utf-8");
2093
+ const data = await readFile7(join15(getConfigDir2(), "config.json"), "utf-8");
1736
2094
  return JSON.parse(data);
1737
2095
  } catch {
1738
2096
  return {};
@@ -1740,15 +2098,15 @@ async function getConfig() {
1740
2098
  }
1741
2099
  async function saveConfig(config2) {
1742
2100
  const dir = getConfigDir2();
1743
- const path = join14(dir, "config.json");
1744
- await mkdir8(dir, { recursive: true });
2101
+ const path = join15(dir, "config.json");
2102
+ await mkdir9(dir, { recursive: true });
1745
2103
  const tmpPath = path + ".tmp";
1746
2104
  try {
1747
- await writeFile8(tmpPath, JSON.stringify(config2, null, 2));
2105
+ await writeFile9(tmpPath, JSON.stringify(config2, null, 2));
1748
2106
  await rename3(tmpPath, path);
1749
2107
  } catch (err) {
1750
2108
  try {
1751
- await unlink6(tmpPath);
2109
+ await unlink7(tmpPath);
1752
2110
  } catch {
1753
2111
  }
1754
2112
  throw err;
@@ -1756,10 +2114,10 @@ async function saveConfig(config2) {
1756
2114
  }
1757
2115
  async function mergeAndSaveConfig(updates) {
1758
2116
  const dir = getConfigDir2();
1759
- const path = join14(dir, "config.json");
1760
- await mkdir8(dir, { recursive: true });
2117
+ const path = join15(dir, "config.json");
2118
+ await mkdir9(dir, { recursive: true });
1761
2119
  try {
1762
- await writeFile8(path, "", { flag: "a" });
2120
+ await writeFile9(path, "", { flag: "a" });
1763
2121
  } catch {
1764
2122
  }
1765
2123
  let release = null;
@@ -1767,7 +2125,7 @@ async function mergeAndSaveConfig(updates) {
1767
2125
  release = await lockfile3.lock(path, { stale: 1e4, retries: 3, realpath: false });
1768
2126
  let raw = {};
1769
2127
  try {
1770
- raw = JSON.parse(await readFile6(path, "utf-8"));
2128
+ raw = JSON.parse(await readFile7(path, "utf-8"));
1771
2129
  } catch {
1772
2130
  }
1773
2131
  const merged = { ...raw, ...updates };
@@ -1827,7 +2185,7 @@ async function showWelcome(currentVersion) {
1827
2185
 
1828
2186
  // src/commands/create.ts
1829
2187
  import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
1830
- import { dirname as dirname6, join as join18 } from "path";
2188
+ import { dirname as dirname6, join as join19 } from "path";
1831
2189
  import chalk5 from "chalk";
1832
2190
  import ora from "ora";
1833
2191
 
@@ -1928,9 +2286,9 @@ function resolveRole(groups) {
1928
2286
 
1929
2287
  // src/lib/auth.ts
1930
2288
  import { createHash, randomBytes } from "crypto";
1931
- import { readFile as readFile7, writeFile as writeFile9, mkdir as mkdir9, chmod as chmod4, unlink as unlink7 } from "fs/promises";
2289
+ import { readFile as readFile8, writeFile as writeFile10, mkdir as mkdir10, chmod as chmod4, unlink as unlink8 } from "fs/promises";
1932
2290
  import http from "http";
1933
- import { join as join15 } from "path";
2291
+ import { join as join16 } from "path";
1934
2292
  var CLI_CALLBACK_PORT = 19876;
1935
2293
  var CALLBACK_TIMEOUT_MS = 12e4;
1936
2294
  function getCognitoConfigForStorage() {
@@ -2096,8 +2454,8 @@ async function refreshTokens2(refreshToken) {
2096
2454
  }
2097
2455
  async function getStoredCredentials2() {
2098
2456
  try {
2099
- const credPath = join15(getConfigDir2(), "credentials.json");
2100
- const data = await readFile7(credPath, "utf-8");
2457
+ const credPath = join16(getConfigDir2(), "credentials.json");
2458
+ const data = await readFile8(credPath, "utf-8");
2101
2459
  return JSON.parse(data);
2102
2460
  } catch (err) {
2103
2461
  if (err.code === "ENOENT" || err instanceof SyntaxError) {
@@ -2108,14 +2466,14 @@ async function getStoredCredentials2() {
2108
2466
  }
2109
2467
  async function storeCredentials2(credentials) {
2110
2468
  const dir = getConfigDir2();
2111
- const credPath = join15(dir, "credentials.json");
2112
- await mkdir9(dir, { recursive: true, mode: 448 });
2113
- await writeFile9(credPath, JSON.stringify(credentials, null, 2));
2469
+ const credPath = join16(dir, "credentials.json");
2470
+ await mkdir10(dir, { recursive: true, mode: 448 });
2471
+ await writeFile10(credPath, JSON.stringify(credentials, null, 2));
2114
2472
  await chmod4(credPath, 384);
2115
2473
  }
2116
2474
  async function clearCredentials() {
2117
2475
  try {
2118
- await unlink7(join15(getConfigDir2(), "credentials.json"));
2476
+ await unlink8(join16(getConfigDir2(), "credentials.json"));
2119
2477
  } catch (err) {
2120
2478
  if (err.code !== "ENOENT") throw err;
2121
2479
  }
@@ -2278,23 +2636,34 @@ async function apiRequest(path, options) {
2278
2636
  }
2279
2637
 
2280
2638
  // src/lib/prompts.ts
2281
- import { checkbox, confirm } from "@inquirer/prompts";
2639
+ import { checkbox, confirm, Separator } from "@inquirer/prompts";
2282
2640
  import chalk2 from "chalk";
2283
2641
  async function selectAiTools() {
2284
2642
  const choices = [
2643
+ new Separator(chalk2.dim("\u2500\u2500 Popular \u2500\u2500")),
2285
2644
  { name: "Cursor", value: "cursor" },
2286
2645
  { name: "Claude Code", value: "claude-code" },
2287
2646
  { name: "GitHub Copilot", value: "copilot" },
2288
2647
  { name: "Windsurf", value: "windsurf" },
2648
+ new Separator(chalk2.dim("\u2500\u2500 More Tools \u2500\u2500")),
2289
2649
  { name: "Cline", value: "cline" },
2290
2650
  { name: "Codex", value: "codex" },
2291
2651
  { name: "Roo Code", value: "roo-code" },
2652
+ { name: "Gemini CLI", value: "gemini" },
2653
+ new Separator(chalk2.dim("\u2500\u2500 Cloud Agents \u2500\u2500")),
2654
+ { name: "Warp", value: "warp" },
2655
+ { name: "JetBrains Junie", value: "junie" },
2656
+ { name: "Google Jules", value: "jules" },
2657
+ { name: "Amp", value: "amp" },
2658
+ { name: "Devin", value: "devin" },
2659
+ new Separator(chalk2.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")),
2292
2660
  { name: "Other (manual setup)", value: "other" }
2293
2661
  ];
2294
2662
  while (true) {
2295
2663
  const selected = await checkbox({
2296
2664
  message: chalk2.bold("Which AI tools do you use?") + chalk2.dim(" (Space to select, Enter to continue)"),
2297
- choices
2665
+ choices,
2666
+ pageSize: 22
2298
2667
  });
2299
2668
  if (selected.length === 0) {
2300
2669
  const goBack = await confirm({
@@ -2310,191 +2679,54 @@ async function selectAiTools() {
2310
2679
  }
2311
2680
 
2312
2681
  // src/lib/ai-tools.ts
2313
- import { readFile as readFile8, writeFile as writeFile10, mkdir as mkdir10, readdir } from "fs/promises";
2314
- import { join as join16, dirname as dirname5 } from "path";
2315
- var AI_TOOL_CONFIG = {
2316
- cursor: {
2317
- label: "Cursor",
2318
- fileName: ".cursorrules",
2319
- filePath: ".cursorrules",
2320
- markerStart: "# --- repowise-start ---",
2321
- markerEnd: "# --- repowise-end ---",
2322
- format: "plain-text"
2323
- },
2324
- "claude-code": {
2325
- label: "Claude Code",
2326
- fileName: "CLAUDE.md",
2327
- filePath: "CLAUDE.md",
2328
- markerStart: "<!-- repowise-start -->",
2329
- markerEnd: "<!-- repowise-end -->",
2330
- format: "markdown"
2331
- },
2332
- copilot: {
2333
- label: "GitHub Copilot",
2334
- fileName: "copilot-instructions.md",
2335
- filePath: ".github/copilot-instructions.md",
2336
- markerStart: "<!-- repowise-start -->",
2337
- markerEnd: "<!-- repowise-end -->",
2338
- format: "markdown"
2339
- },
2340
- windsurf: {
2341
- label: "Windsurf",
2342
- fileName: ".windsurfrules",
2343
- filePath: ".windsurfrules",
2344
- markerStart: "# --- repowise-start ---",
2345
- markerEnd: "# --- repowise-end ---",
2346
- format: "plain-text"
2347
- },
2348
- cline: {
2349
- label: "Cline",
2350
- fileName: ".clinerules",
2351
- filePath: ".clinerules",
2352
- markerStart: "# --- repowise-start ---",
2353
- markerEnd: "# --- repowise-end ---",
2354
- format: "plain-text"
2355
- },
2356
- codex: {
2357
- label: "Codex",
2358
- fileName: "AGENTS.md",
2359
- filePath: "AGENTS.md",
2360
- markerStart: "<!-- repowise-start -->",
2361
- markerEnd: "<!-- repowise-end -->",
2362
- format: "markdown"
2363
- },
2364
- "roo-code": {
2365
- label: "Roo Code",
2366
- fileName: "rules.md",
2367
- filePath: ".roo/rules.md",
2368
- markerStart: "<!-- repowise-start -->",
2369
- markerEnd: "<!-- repowise-end -->",
2370
- format: "markdown"
2371
- }
2372
- };
2373
- var SUPPORTED_TOOLS = Object.keys(AI_TOOL_CONFIG);
2374
- function sanitizeRepoName(name) {
2375
- return name.replace(/[<>[\]`()|\\]/g, "");
2376
- }
2377
- function fileDescriptionFromName(fileName) {
2378
- return fileName.replace(/\.md$/, "").split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
2379
- }
2380
- function generateReference(tool, repoName, contextFolder, contextFiles) {
2381
- const config2 = AI_TOOL_CONFIG[tool];
2382
- const safeName = sanitizeRepoName(repoName);
2383
- const fileLines = contextFiles.map((f) => {
2384
- const baseName = f.fileName.split("/").pop() ?? f.fileName;
2385
- const desc = fileDescriptionFromName(baseName);
2386
- const isOverview = baseName === "project-overview.md";
2387
- return { path: f.relativePath, desc: isOverview ? `${desc} (full index of all files)` : desc };
2388
- });
2389
- const hasFiles = fileLines.length > 0;
2390
- if (config2.format === "markdown") {
2391
- const lines2 = [
2392
- config2.markerStart,
2393
- "",
2394
- `## Project Context \u2014 ${safeName}`,
2395
- "",
2396
- `This repository has AI-optimized context files generated by RepoWise.`,
2397
- `**IMPORTANT: Before answering questions about the codebase or making any changes, ALWAYS check the \`${contextFolder}/\` folder first.** These files contain pre-analyzed architecture, patterns, API contracts, and domain knowledge that will answer most questions without needing to search the codebase.`,
2398
- "",
2399
- `**Start here:** \`${contextFolder}/project-overview.md\` \u2014 the routing document that maps every context file to its domain. Read it first to find which context file has the answer you need.`,
2400
- ""
2401
- ];
2402
- if (hasFiles) {
2403
- lines2.push(
2404
- `**Core context files:**`,
2405
- "",
2406
- ...fileLines.map((f) => `- \`${f.path}\` \u2014 ${f.desc}`),
2407
- "",
2408
- `> Additional context files may exist beyond this list. Check \`project-overview.md\` for the complete index.`
2409
- );
2410
- }
2411
- lines2.push("", config2.markerEnd);
2412
- return lines2.join("\n");
2413
- }
2414
- const lines = [
2415
- config2.markerStart,
2416
- `# Project Context \u2014 ${safeName}`,
2417
- "#",
2418
- `# This repository has AI-optimized context files generated by RepoWise.`,
2419
- `# IMPORTANT: Before answering questions about the codebase or making any changes,`,
2420
- `# ALWAYS check the ${contextFolder}/ folder first. These files contain pre-analyzed`,
2421
- `# architecture, patterns, API contracts, and domain knowledge that will answer`,
2422
- `# most questions without needing to search the codebase.`,
2423
- "#",
2424
- `# Start here: ${contextFolder}/project-overview.md`,
2425
- `# The routing document that maps every context file to its domain.`,
2426
- `# Read it first to find which context file has the answer you need.`
2427
- ];
2428
- if (hasFiles) {
2429
- lines.push(
2430
- "#",
2431
- `# Core context files:`,
2432
- ...fileLines.map((f) => `# ${f.path} \u2014 ${f.desc}`),
2433
- "#",
2434
- "# Additional context files may exist beyond this list.",
2435
- "# Check project-overview.md for the complete index."
2436
- );
2437
- }
2438
- lines.push(config2.markerEnd);
2439
- return lines.join("\n");
2440
- }
2441
- async function updateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles) {
2442
- const config2 = AI_TOOL_CONFIG[tool];
2443
- const fullPath = join16(repoRoot, config2.filePath);
2444
- const dir = dirname5(fullPath);
2445
- if (dir !== repoRoot) {
2446
- await mkdir10(dir, { recursive: true });
2447
- }
2448
- const referenceBlock = generateReference(tool, repoName, contextFolder, contextFiles);
2449
- let existing = "";
2450
- let created = true;
2682
+ import { readFile as readFile9, writeFile as writeFile11, mkdir as mkdir11 } from "fs/promises";
2683
+ import { join as join17 } from "path";
2684
+ var REPOWISE_HOOK_MARKER = "repowise-context";
2685
+ async function writeClaudeSubagentHook(repoRoot, contextFolder) {
2686
+ const settingsPath = join17(repoRoot, ".claude", "settings.json");
2687
+ let settings = {};
2451
2688
  try {
2452
- existing = await readFile8(fullPath, "utf-8");
2453
- created = false;
2454
- } catch (err) {
2455
- if (err.code !== "ENOENT") throw err;
2689
+ const raw = await readFile9(settingsPath, "utf-8");
2690
+ settings = JSON.parse(raw);
2691
+ } catch {
2456
2692
  }
2457
- const startIdx = existing.indexOf(config2.markerStart);
2458
- const endIdx = existing.indexOf(config2.markerEnd);
2459
- let content;
2460
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
2461
- const before = existing.slice(0, startIdx);
2462
- const after = existing.slice(endIdx + config2.markerEnd.length);
2463
- content = before + referenceBlock + after;
2464
- } else {
2465
- const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n\n" : existing.length > 0 ? "\n" : "";
2466
- content = existing + separator + referenceBlock + "\n";
2693
+ if (!settings["hooks"] || typeof settings["hooks"] !== "object") {
2694
+ settings["hooks"] = {};
2467
2695
  }
2468
- await writeFile10(fullPath, content, "utf-8");
2469
- return { created };
2470
- }
2471
- async function scanLocalContextFiles(repoRoot, contextFolder) {
2472
- const folderPath = join16(repoRoot, contextFolder);
2473
- try {
2474
- const entries = await readdir(folderPath, { withFileTypes: true, recursive: true });
2475
- const results = [];
2476
- for (const entry of entries) {
2477
- if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
2478
- const parentDir = entry.parentPath ?? folderPath;
2479
- const fullPath = join16(parentDir, entry.name);
2480
- const relFromContext = fullPath.slice(folderPath.length + 1);
2481
- results.push({
2482
- fileName: relFromContext,
2483
- relativePath: `${contextFolder}/${relFromContext}`
2484
- });
2485
- }
2486
- return results.sort((a, b) => a.fileName.localeCompare(b.fileName));
2487
- } catch (err) {
2488
- if (err.code === "ENOENT") return [];
2489
- throw err;
2696
+ const hooks = settings["hooks"];
2697
+ const repoWiseHook = {
2698
+ matcher: "",
2699
+ hooks: [
2700
+ {
2701
+ type: "command",
2702
+ command: `echo '{"additionalContext":"IMPORTANT: Read ${contextFolder}/project-overview.md before performing any work. This file maps every context file to its domain."}'`
2703
+ }
2704
+ ]
2705
+ };
2706
+ const subagentStart = Array.isArray(hooks["SubagentStart"]) ? hooks["SubagentStart"] : [];
2707
+ const existingIdx = subagentStart.findIndex((entry) => {
2708
+ const entryHooks = entry["hooks"];
2709
+ return entryHooks?.some((h) => {
2710
+ const cmd = h["command"];
2711
+ return typeof cmd === "string" && cmd.includes(REPOWISE_HOOK_MARKER);
2712
+ });
2713
+ });
2714
+ if (existingIdx >= 0) {
2715
+ subagentStart[existingIdx] = repoWiseHook;
2716
+ } else {
2717
+ subagentStart.push(repoWiseHook);
2490
2718
  }
2719
+ hooks["SubagentStart"] = subagentStart;
2720
+ settings["hooks"] = hooks;
2721
+ await mkdir11(join17(repoRoot, ".claude"), { recursive: true });
2722
+ await writeFile11(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
2491
2723
  }
2492
2724
 
2493
2725
  // src/lib/gitignore.ts
2494
2726
  import { readFileSync, writeFileSync, existsSync } from "fs";
2495
- import { join as join17 } from "path";
2727
+ import { join as join18 } from "path";
2496
2728
  function ensureGitignore(repoRoot, entry) {
2497
- const gitignorePath = join17(repoRoot, ".gitignore");
2729
+ const gitignorePath = join18(repoRoot, ".gitignore");
2498
2730
  if (existsSync(gitignorePath)) {
2499
2731
  const content = readFileSync(gitignorePath, "utf-8");
2500
2732
  const lines = content.split("\n").map((l) => l.trim());
@@ -3120,7 +3352,7 @@ async function create() {
3120
3352
  if (hasOther) {
3121
3353
  console.log(
3122
3354
  chalk5.cyan(
3123
- "\nFor AI tools not listed, context files still work with any tool that reads the filesystem.\nRequest support for your tool at: https://dashboard.repowise.ai/support/ai-tools"
3355
+ "\nFor AI tools not listed, context files still work with any tool that reads the filesystem.\nTo request full support for a new AI tool, email support@repowise.ai"
3124
3356
  )
3125
3357
  );
3126
3358
  }
@@ -3237,7 +3469,7 @@ async function create() {
3237
3469
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
3238
3470
  const files = listResult.data?.files ?? listResult.files ?? [];
3239
3471
  if (files.length > 0) {
3240
- const contextDir = join18(repoRoot, DEFAULT_CONTEXT_FOLDER);
3472
+ const contextDir = join19(repoRoot, DEFAULT_CONTEXT_FOLDER);
3241
3473
  mkdirSync(contextDir, { recursive: true });
3242
3474
  let downloadedCount = 0;
3243
3475
  let failedCount = 0;
@@ -3251,7 +3483,7 @@ async function create() {
3251
3483
  const response = await fetch(presignedUrl);
3252
3484
  if (response.ok) {
3253
3485
  const content = await response.text();
3254
- const filePath = join18(contextDir, file.fileName);
3486
+ const filePath = join19(contextDir, file.fileName);
3255
3487
  mkdirSync(dirname6(filePath), { recursive: true });
3256
3488
  writeFileSync2(filePath, content, "utf-8");
3257
3489
  downloadedCount++;
@@ -3295,10 +3527,17 @@ Files are stored on our servers (not in git). Retry when online.`
3295
3527
  )
3296
3528
  );
3297
3529
  }
3298
- if (tools.length > 0 && repoRoot) {
3530
+ if (repoRoot) {
3299
3531
  spinner.start("Configuring AI tools...");
3300
3532
  const results = [];
3533
+ const written = /* @__PURE__ */ new Set();
3301
3534
  for (const tool of tools) {
3535
+ const config2 = AI_TOOL_CONFIG[tool];
3536
+ if (written.has(config2.filePath)) continue;
3537
+ written.add(config2.filePath);
3538
+ if (config2.legacyFilePath) {
3539
+ await migrateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
3540
+ }
3302
3541
  const { created: wasCreated } = await updateToolConfig(
3303
3542
  repoRoot,
3304
3543
  tool,
@@ -3306,10 +3545,23 @@ Files are stored on our servers (not in git). Retry when online.`
3306
3545
  contextFolder,
3307
3546
  contextFiles
3308
3547
  );
3309
- const config2 = AI_TOOL_CONFIG[tool];
3310
3548
  const action = wasCreated ? "Created" : "Updated";
3311
3549
  results.push(` ${action} ${config2.filePath}`);
3312
3550
  }
3551
+ if (!written.has("AGENTS.md")) {
3552
+ const { created: wasCreated } = await updateToolConfig(
3553
+ repoRoot,
3554
+ "codex",
3555
+ repoName,
3556
+ contextFolder,
3557
+ contextFiles
3558
+ );
3559
+ results.push(` ${wasCreated ? "Created" : "Updated"} AGENTS.md`);
3560
+ }
3561
+ if (tools.includes("claude-code")) {
3562
+ await writeClaudeSubagentHook(repoRoot, contextFolder);
3563
+ results.push(" Configured .claude/settings.json (SubagentStart hook)");
3564
+ }
3313
3565
  spinner.succeed("AI tools configured");
3314
3566
  console.log(chalk5.dim(results.join("\n")));
3315
3567
  }
@@ -3372,7 +3624,7 @@ Files are stored on our servers (not in git). Retry when online.`
3372
3624
 
3373
3625
  // src/commands/member.ts
3374
3626
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
3375
- import { dirname as dirname7, join as join19 } from "path";
3627
+ import { dirname as dirname7, join as join20 } from "path";
3376
3628
  import chalk6 from "chalk";
3377
3629
  import ora2 from "ora";
3378
3630
  var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
@@ -3496,7 +3748,7 @@ async function member() {
3496
3748
  spinner.succeed(`Found ${chalk6.bold(files.length)} context files on server`);
3497
3749
  const { tools } = await selectAiTools();
3498
3750
  spinner.start("Downloading context files...");
3499
- const contextDir = join19(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3751
+ const contextDir = join20(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3500
3752
  mkdirSync2(contextDir, { recursive: true });
3501
3753
  let downloadedCount = 0;
3502
3754
  let failedCount = 0;
@@ -3511,7 +3763,7 @@ async function member() {
3511
3763
  const response = await fetch(presignedUrl);
3512
3764
  if (response.ok) {
3513
3765
  const content = await response.text();
3514
- const filePath = join19(contextDir, file.fileName);
3766
+ const filePath = join20(contextDir, file.fileName);
3515
3767
  mkdirSync2(dirname7(filePath), { recursive: true });
3516
3768
  writeFileSync3(filePath, content, "utf-8");
3517
3769
  downloadedCount++;
@@ -3533,11 +3785,15 @@ async function member() {
3533
3785
  ensureGitignore(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3534
3786
  } catch {
3535
3787
  }
3536
- if (tools.length > 0) {
3788
+ {
3537
3789
  spinner.start("Configuring AI tools...");
3538
3790
  const contextFiles = await scanLocalContextFiles(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3539
3791
  const configured = [];
3792
+ const written = /* @__PURE__ */ new Set();
3540
3793
  for (const tool of tools) {
3794
+ const config2 = AI_TOOL_CONFIG[tool];
3795
+ if (written.has(config2.filePath)) continue;
3796
+ written.add(config2.filePath);
3541
3797
  const { created } = await updateToolConfig(
3542
3798
  repoRoot,
3543
3799
  tool,
@@ -3545,9 +3801,22 @@ async function member() {
3545
3801
  DEFAULT_CONTEXT_FOLDER2,
3546
3802
  contextFiles
3547
3803
  );
3548
- const config2 = AI_TOOL_CONFIG[tool];
3549
3804
  configured.push(`${created ? "Created" : "Updated"} ${config2.filePath}`);
3550
3805
  }
3806
+ if (!written.has("AGENTS.md")) {
3807
+ const { created } = await updateToolConfig(
3808
+ repoRoot,
3809
+ "codex",
3810
+ repoName,
3811
+ DEFAULT_CONTEXT_FOLDER2,
3812
+ contextFiles
3813
+ );
3814
+ configured.push(`${created ? "Created" : "Updated"} AGENTS.md`);
3815
+ }
3816
+ if (tools.includes("claude-code")) {
3817
+ await writeClaudeSubagentHook(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3818
+ configured.push("Configured .claude/settings.json (SubagentStart hook)");
3819
+ }
3551
3820
  spinner.succeed("AI tools configured");
3552
3821
  for (const msg of configured) {
3553
3822
  console.log(chalk6.dim(` ${msg}`));
@@ -3679,15 +3948,15 @@ async function logout() {
3679
3948
  }
3680
3949
 
3681
3950
  // src/commands/status.ts
3682
- import { readFile as readFile9 } from "fs/promises";
3683
- import { basename as basename2, join as join20 } from "path";
3951
+ import { readFile as readFile10 } from "fs/promises";
3952
+ import { basename as basename2, join as join21 } from "path";
3684
3953
  async function status() {
3685
3954
  const configDir = getConfigDir2();
3686
- const STATE_PATH = join20(configDir, "listener-state.json");
3687
- const CONFIG_PATH = join20(configDir, "config.json");
3955
+ const STATE_PATH = join21(configDir, "listener-state.json");
3956
+ const CONFIG_PATH = join21(configDir, "config.json");
3688
3957
  let state = null;
3689
3958
  try {
3690
- const data = await readFile9(STATE_PATH, "utf-8");
3959
+ const data = await readFile10(STATE_PATH, "utf-8");
3691
3960
  state = JSON.parse(data);
3692
3961
  } catch {
3693
3962
  }
@@ -3713,7 +3982,7 @@ async function status() {
3713
3982
  }
3714
3983
  const repoNames = /* @__PURE__ */ new Map();
3715
3984
  try {
3716
- const configData = await readFile9(CONFIG_PATH, "utf-8");
3985
+ const configData = await readFile10(CONFIG_PATH, "utf-8");
3717
3986
  const config2 = JSON.parse(configData);
3718
3987
  for (const repo of config2.repos ?? []) {
3719
3988
  repoNames.set(repo.repoId, basename2(repo.localPath));
@@ -3732,7 +4001,7 @@ async function status() {
3732
4001
 
3733
4002
  // src/commands/sync.ts
3734
4003
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
3735
- import { dirname as dirname8, join as join21 } from "path";
4004
+ import { dirname as dirname8, join as join22 } from "path";
3736
4005
  import chalk9 from "chalk";
3737
4006
  import ora4 from "ora";
3738
4007
  var POLL_INTERVAL_MS2 = 3e3;
@@ -3875,7 +4144,7 @@ async function sync() {
3875
4144
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
3876
4145
  const files = listResult.data?.files ?? listResult.files ?? [];
3877
4146
  if (files.length > 0) {
3878
- const contextDir = join21(repoRoot, DEFAULT_CONTEXT_FOLDER3);
4147
+ const contextDir = join22(repoRoot, DEFAULT_CONTEXT_FOLDER3);
3879
4148
  mkdirSync3(contextDir, { recursive: true });
3880
4149
  let downloadedCount = 0;
3881
4150
  let failedCount = 0;
@@ -3889,7 +4158,7 @@ async function sync() {
3889
4158
  const response = await fetch(presignedUrl);
3890
4159
  if (response.ok) {
3891
4160
  const content = await response.text();
3892
- const filePath = join21(contextDir, file.fileName);
4161
+ const filePath = join22(contextDir, file.fileName);
3893
4162
  mkdirSync3(dirname8(filePath), { recursive: true });
3894
4163
  writeFileSync4(filePath, content, "utf-8");
3895
4164
  downloadedCount++;
@@ -3908,6 +4177,38 @@ async function sync() {
3908
4177
  ensureGitignore(repoRoot, DEFAULT_CONTEXT_FOLDER3);
3909
4178
  } catch {
3910
4179
  }
4180
+ try {
4181
+ const existingConfig = await getConfig();
4182
+ const aiTools = existingConfig.aiTools ?? [];
4183
+ if (aiTools.length > 0) {
4184
+ const contextFiles = await scanLocalContextFiles(repoRoot, DEFAULT_CONTEXT_FOLDER3);
4185
+ if (contextFiles.length > 0) {
4186
+ const written = /* @__PURE__ */ new Set();
4187
+ for (const tool of aiTools) {
4188
+ const config2 = AI_TOOL_CONFIG[tool];
4189
+ if (!config2 || written.has(config2.filePath)) continue;
4190
+ written.add(config2.filePath);
4191
+ await updateToolConfig(
4192
+ repoRoot,
4193
+ tool,
4194
+ repoName,
4195
+ DEFAULT_CONTEXT_FOLDER3,
4196
+ contextFiles
4197
+ );
4198
+ }
4199
+ if (!written.has("AGENTS.md")) {
4200
+ await updateToolConfig(
4201
+ repoRoot,
4202
+ "codex",
4203
+ repoName,
4204
+ DEFAULT_CONTEXT_FOLDER3,
4205
+ contextFiles
4206
+ );
4207
+ }
4208
+ }
4209
+ }
4210
+ } catch {
4211
+ }
3911
4212
  } else {
3912
4213
  spinner.info("No context files found on server");
3913
4214
  }
@@ -4109,7 +4410,7 @@ async function config() {
4109
4410
  // bin/repowise.ts
4110
4411
  var __filename = fileURLToPath3(import.meta.url);
4111
4412
  var __dirname = dirname9(__filename);
4112
- var pkg = JSON.parse(readFileSync2(join22(__dirname, "..", "..", "package.json"), "utf-8"));
4413
+ var pkg = JSON.parse(readFileSync2(join23(__dirname, "..", "..", "package.json"), "utf-8"));
4113
4414
  var program = new Command();
4114
4415
  program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
4115
4416
  await showWelcome(pkg.version);