repowise 0.1.87 → 0.1.89

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 +630 -317
  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());
@@ -3009,6 +3241,7 @@ async function create() {
3009
3241
  let repoRoot;
3010
3242
  let repoPlatform;
3011
3243
  let repoExternalId;
3244
+ let repoLookupError;
3012
3245
  spinner.start("Checking for pending repository...");
3013
3246
  try {
3014
3247
  const pending = await apiRequest("/v1/onboarding/pending");
@@ -3044,7 +3277,8 @@ async function create() {
3044
3277
  repoPlatform = match.platform;
3045
3278
  repoExternalId = match.externalId;
3046
3279
  }
3047
- } catch {
3280
+ } catch (err) {
3281
+ repoLookupError = err instanceof Error ? err.message : String(err);
3048
3282
  }
3049
3283
  } else {
3050
3284
  try {
@@ -3053,11 +3287,15 @@ async function create() {
3053
3287
  }
3054
3288
  }
3055
3289
  if (!repoId) {
3056
- spinner.fail(
3057
- chalk5.red(
3058
- "Could not find this repository in your RepoWise account. Connect it on the dashboard first."
3059
- )
3060
- );
3290
+ if (repoLookupError) {
3291
+ spinner.fail(chalk5.red(`Failed to look up repositories: ${repoLookupError}`));
3292
+ } else {
3293
+ spinner.fail(
3294
+ chalk5.red(
3295
+ "Could not find this repository in your RepoWise account. Connect it on the dashboard first."
3296
+ )
3297
+ );
3298
+ }
3061
3299
  process.exitCode = 1;
3062
3300
  return;
3063
3301
  }
@@ -3120,7 +3358,7 @@ async function create() {
3120
3358
  if (hasOther) {
3121
3359
  console.log(
3122
3360
  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"
3361
+ "\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
3362
  )
3125
3363
  );
3126
3364
  }
@@ -3237,7 +3475,7 @@ async function create() {
3237
3475
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
3238
3476
  const files = listResult.data?.files ?? listResult.files ?? [];
3239
3477
  if (files.length > 0) {
3240
- const contextDir = join18(repoRoot, DEFAULT_CONTEXT_FOLDER);
3478
+ const contextDir = join19(repoRoot, DEFAULT_CONTEXT_FOLDER);
3241
3479
  mkdirSync(contextDir, { recursive: true });
3242
3480
  let downloadedCount = 0;
3243
3481
  let failedCount = 0;
@@ -3251,7 +3489,7 @@ async function create() {
3251
3489
  const response = await fetch(presignedUrl);
3252
3490
  if (response.ok) {
3253
3491
  const content = await response.text();
3254
- const filePath = join18(contextDir, file.fileName);
3492
+ const filePath = join19(contextDir, file.fileName);
3255
3493
  mkdirSync(dirname6(filePath), { recursive: true });
3256
3494
  writeFileSync2(filePath, content, "utf-8");
3257
3495
  downloadedCount++;
@@ -3295,10 +3533,17 @@ Files are stored on our servers (not in git). Retry when online.`
3295
3533
  )
3296
3534
  );
3297
3535
  }
3298
- if (tools.length > 0 && repoRoot) {
3536
+ if (repoRoot) {
3299
3537
  spinner.start("Configuring AI tools...");
3300
3538
  const results = [];
3539
+ const written = /* @__PURE__ */ new Set();
3301
3540
  for (const tool of tools) {
3541
+ const config2 = AI_TOOL_CONFIG[tool];
3542
+ if (written.has(config2.filePath)) continue;
3543
+ written.add(config2.filePath);
3544
+ if (config2.legacyFilePath) {
3545
+ await migrateToolConfig(repoRoot, tool, repoName, contextFolder, contextFiles);
3546
+ }
3302
3547
  const { created: wasCreated } = await updateToolConfig(
3303
3548
  repoRoot,
3304
3549
  tool,
@@ -3306,10 +3551,23 @@ Files are stored on our servers (not in git). Retry when online.`
3306
3551
  contextFolder,
3307
3552
  contextFiles
3308
3553
  );
3309
- const config2 = AI_TOOL_CONFIG[tool];
3310
3554
  const action = wasCreated ? "Created" : "Updated";
3311
3555
  results.push(` ${action} ${config2.filePath}`);
3312
3556
  }
3557
+ if (!written.has("AGENTS.md")) {
3558
+ const { created: wasCreated } = await updateToolConfig(
3559
+ repoRoot,
3560
+ "codex",
3561
+ repoName,
3562
+ contextFolder,
3563
+ contextFiles
3564
+ );
3565
+ results.push(` ${wasCreated ? "Created" : "Updated"} AGENTS.md`);
3566
+ }
3567
+ if (tools.includes("claude-code")) {
3568
+ await writeClaudeSubagentHook(repoRoot, contextFolder);
3569
+ results.push(" Configured .claude/settings.json (SubagentStart hook)");
3570
+ }
3313
3571
  spinner.succeed("AI tools configured");
3314
3572
  console.log(chalk5.dim(results.join("\n")));
3315
3573
  }
@@ -3372,7 +3630,7 @@ Files are stored on our servers (not in git). Retry when online.`
3372
3630
 
3373
3631
  // src/commands/member.ts
3374
3632
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
3375
- import { dirname as dirname7, join as join19 } from "path";
3633
+ import { dirname as dirname7, join as join20 } from "path";
3376
3634
  import chalk6 from "chalk";
3377
3635
  import ora2 from "ora";
3378
3636
  var DEFAULT_CONTEXT_FOLDER2 = "repowise-context";
@@ -3496,7 +3754,7 @@ async function member() {
3496
3754
  spinner.succeed(`Found ${chalk6.bold(files.length)} context files on server`);
3497
3755
  const { tools } = await selectAiTools();
3498
3756
  spinner.start("Downloading context files...");
3499
- const contextDir = join19(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3757
+ const contextDir = join20(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3500
3758
  mkdirSync2(contextDir, { recursive: true });
3501
3759
  let downloadedCount = 0;
3502
3760
  let failedCount = 0;
@@ -3511,7 +3769,7 @@ async function member() {
3511
3769
  const response = await fetch(presignedUrl);
3512
3770
  if (response.ok) {
3513
3771
  const content = await response.text();
3514
- const filePath = join19(contextDir, file.fileName);
3772
+ const filePath = join20(contextDir, file.fileName);
3515
3773
  mkdirSync2(dirname7(filePath), { recursive: true });
3516
3774
  writeFileSync3(filePath, content, "utf-8");
3517
3775
  downloadedCount++;
@@ -3533,11 +3791,15 @@ async function member() {
3533
3791
  ensureGitignore(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3534
3792
  } catch {
3535
3793
  }
3536
- if (tools.length > 0) {
3794
+ {
3537
3795
  spinner.start("Configuring AI tools...");
3538
3796
  const contextFiles = await scanLocalContextFiles(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3539
3797
  const configured = [];
3798
+ const written = /* @__PURE__ */ new Set();
3540
3799
  for (const tool of tools) {
3800
+ const config2 = AI_TOOL_CONFIG[tool];
3801
+ if (written.has(config2.filePath)) continue;
3802
+ written.add(config2.filePath);
3541
3803
  const { created } = await updateToolConfig(
3542
3804
  repoRoot,
3543
3805
  tool,
@@ -3545,9 +3807,22 @@ async function member() {
3545
3807
  DEFAULT_CONTEXT_FOLDER2,
3546
3808
  contextFiles
3547
3809
  );
3548
- const config2 = AI_TOOL_CONFIG[tool];
3549
3810
  configured.push(`${created ? "Created" : "Updated"} ${config2.filePath}`);
3550
3811
  }
3812
+ if (!written.has("AGENTS.md")) {
3813
+ const { created } = await updateToolConfig(
3814
+ repoRoot,
3815
+ "codex",
3816
+ repoName,
3817
+ DEFAULT_CONTEXT_FOLDER2,
3818
+ contextFiles
3819
+ );
3820
+ configured.push(`${created ? "Created" : "Updated"} AGENTS.md`);
3821
+ }
3822
+ if (tools.includes("claude-code")) {
3823
+ await writeClaudeSubagentHook(repoRoot, DEFAULT_CONTEXT_FOLDER2);
3824
+ configured.push("Configured .claude/settings.json (SubagentStart hook)");
3825
+ }
3551
3826
  spinner.succeed("AI tools configured");
3552
3827
  for (const msg of configured) {
3553
3828
  console.log(chalk6.dim(` ${msg}`));
@@ -3679,15 +3954,15 @@ async function logout() {
3679
3954
  }
3680
3955
 
3681
3956
  // src/commands/status.ts
3682
- import { readFile as readFile9 } from "fs/promises";
3683
- import { basename as basename2, join as join20 } from "path";
3957
+ import { readFile as readFile10 } from "fs/promises";
3958
+ import { basename as basename2, join as join21 } from "path";
3684
3959
  async function status() {
3685
3960
  const configDir = getConfigDir2();
3686
- const STATE_PATH = join20(configDir, "listener-state.json");
3687
- const CONFIG_PATH = join20(configDir, "config.json");
3961
+ const STATE_PATH = join21(configDir, "listener-state.json");
3962
+ const CONFIG_PATH = join21(configDir, "config.json");
3688
3963
  let state = null;
3689
3964
  try {
3690
- const data = await readFile9(STATE_PATH, "utf-8");
3965
+ const data = await readFile10(STATE_PATH, "utf-8");
3691
3966
  state = JSON.parse(data);
3692
3967
  } catch {
3693
3968
  }
@@ -3713,7 +3988,7 @@ async function status() {
3713
3988
  }
3714
3989
  const repoNames = /* @__PURE__ */ new Map();
3715
3990
  try {
3716
- const configData = await readFile9(CONFIG_PATH, "utf-8");
3991
+ const configData = await readFile10(CONFIG_PATH, "utf-8");
3717
3992
  const config2 = JSON.parse(configData);
3718
3993
  for (const repo of config2.repos ?? []) {
3719
3994
  repoNames.set(repo.repoId, basename2(repo.localPath));
@@ -3732,7 +4007,7 @@ async function status() {
3732
4007
 
3733
4008
  // src/commands/sync.ts
3734
4009
  import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
3735
- import { dirname as dirname8, join as join21 } from "path";
4010
+ import { dirname as dirname8, join as join22 } from "path";
3736
4011
  import chalk9 from "chalk";
3737
4012
  import ora4 from "ora";
3738
4013
  var POLL_INTERVAL_MS2 = 3e3;
@@ -3775,6 +4050,7 @@ async function sync() {
3775
4050
  let repoId;
3776
4051
  let repoPlatform;
3777
4052
  let repoExternalId;
4053
+ let repoLookupError;
3778
4054
  spinner.start("Resolving repository...");
3779
4055
  try {
3780
4056
  const repos = await apiRequest("/v1/repos");
@@ -3784,14 +4060,19 @@ async function sync() {
3784
4060
  repoPlatform = match.platform;
3785
4061
  repoExternalId = match.externalId;
3786
4062
  }
3787
- } catch {
4063
+ } catch (err) {
4064
+ repoLookupError = err instanceof Error ? err.message : String(err);
3788
4065
  }
3789
4066
  if (!repoId) {
3790
- spinner.fail(
3791
- chalk9.red(
3792
- "Could not find this repository in your RepoWise account. Run `repowise create` first."
3793
- )
3794
- );
4067
+ if (repoLookupError) {
4068
+ spinner.fail(chalk9.red(`Failed to look up repositories: ${repoLookupError}`));
4069
+ } else {
4070
+ spinner.fail(
4071
+ chalk9.red(
4072
+ "Could not find this repository in your RepoWise account. Run `repowise create` first."
4073
+ )
4074
+ );
4075
+ }
3795
4076
  process.exitCode = 1;
3796
4077
  return;
3797
4078
  }
@@ -3875,7 +4156,7 @@ async function sync() {
3875
4156
  const listResult = await apiRequest(`/v1/repos/${repoId}/context`);
3876
4157
  const files = listResult.data?.files ?? listResult.files ?? [];
3877
4158
  if (files.length > 0) {
3878
- const contextDir = join21(repoRoot, DEFAULT_CONTEXT_FOLDER3);
4159
+ const contextDir = join22(repoRoot, DEFAULT_CONTEXT_FOLDER3);
3879
4160
  mkdirSync3(contextDir, { recursive: true });
3880
4161
  let downloadedCount = 0;
3881
4162
  let failedCount = 0;
@@ -3889,7 +4170,7 @@ async function sync() {
3889
4170
  const response = await fetch(presignedUrl);
3890
4171
  if (response.ok) {
3891
4172
  const content = await response.text();
3892
- const filePath = join21(contextDir, file.fileName);
4173
+ const filePath = join22(contextDir, file.fileName);
3893
4174
  mkdirSync3(dirname8(filePath), { recursive: true });
3894
4175
  writeFileSync4(filePath, content, "utf-8");
3895
4176
  downloadedCount++;
@@ -3908,6 +4189,38 @@ async function sync() {
3908
4189
  ensureGitignore(repoRoot, DEFAULT_CONTEXT_FOLDER3);
3909
4190
  } catch {
3910
4191
  }
4192
+ try {
4193
+ const existingConfig = await getConfig();
4194
+ const aiTools = existingConfig.aiTools ?? [];
4195
+ if (aiTools.length > 0) {
4196
+ const contextFiles = await scanLocalContextFiles(repoRoot, DEFAULT_CONTEXT_FOLDER3);
4197
+ if (contextFiles.length > 0) {
4198
+ const written = /* @__PURE__ */ new Set();
4199
+ for (const tool of aiTools) {
4200
+ const config2 = AI_TOOL_CONFIG[tool];
4201
+ if (!config2 || written.has(config2.filePath)) continue;
4202
+ written.add(config2.filePath);
4203
+ await updateToolConfig(
4204
+ repoRoot,
4205
+ tool,
4206
+ repoName,
4207
+ DEFAULT_CONTEXT_FOLDER3,
4208
+ contextFiles
4209
+ );
4210
+ }
4211
+ if (!written.has("AGENTS.md")) {
4212
+ await updateToolConfig(
4213
+ repoRoot,
4214
+ "codex",
4215
+ repoName,
4216
+ DEFAULT_CONTEXT_FOLDER3,
4217
+ contextFiles
4218
+ );
4219
+ }
4220
+ }
4221
+ }
4222
+ } catch {
4223
+ }
3911
4224
  } else {
3912
4225
  spinner.info("No context files found on server");
3913
4226
  }
@@ -4109,7 +4422,7 @@ async function config() {
4109
4422
  // bin/repowise.ts
4110
4423
  var __filename = fileURLToPath3(import.meta.url);
4111
4424
  var __dirname = dirname9(__filename);
4112
- var pkg = JSON.parse(readFileSync2(join22(__dirname, "..", "..", "package.json"), "utf-8"));
4425
+ var pkg = JSON.parse(readFileSync2(join23(__dirname, "..", "..", "package.json"), "utf-8"));
4113
4426
  var program = new Command();
4114
4427
  program.name(getPackageName()).description("AI-optimized codebase context generator").version(pkg.version).hook("preAction", async () => {
4115
4428
  await showWelcome(pkg.version);