repowise 0.1.88 → 0.1.90

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 +106 -13
  2. package/package.json +1 -1
@@ -321,6 +321,51 @@ async function scanLocalContextFiles(repoRoot, contextFolder) {
321
321
  }
322
322
  }
323
323
 
324
+ // ../../packages/shared/dist/lib/project-overview-injection.js
325
+ var START_MARKER = "<!-- repowise:agent-instructions:start -->";
326
+ var END_MARKER = "<!-- repowise:agent-instructions:end -->";
327
+ var AI_AGENT_USAGE_INSTRUCTIONS = `${START_MARKER}
328
+ ## How AI Agents Should Use This Context
329
+
330
+ This document is the **entry point** for RepoWise's pre-analyzed codebase context. The \`repowise-context/\` folder contains architecture, API contracts, data models, coding patterns, user flows, and domain knowledge \u2014 pre-extracted so AI agents can answer most questions without searching the codebase.
331
+
332
+ **Rules for using this context:**
333
+
334
+ 1. **Route first.** Use the *Context File Routing Map* below to identify which file(s) cover the domain of the current task. Files are organized by scope (root = cross-cutting, \`apps/<name>/\` = app-specific) and by concern (architecture, data models, API contracts, coding patterns, etc.).
335
+
336
+ 2. **Read before searching.** Consult the matching context file(s) before running grep/glob or reading source files. These files are the authoritative source for architecture, patterns, and conventions in this project.
337
+
338
+ 3. **Fall back when needed.** If the context files don't cover the question \u2014 or if the question is about ephemeral state (recent commits, branch status, in-flight work) \u2014 then use code search.
339
+
340
+ 4. **Propagate to subagents.** When delegating work to a sub-task or spawning another agent, explicitly instruct it to read \`repowise-context/project-overview.md\` first. Subagents do not inherit the parent agent's instructions automatically.
341
+
342
+ 5. **Don't edit these files manually.** The \`repowise-context/\` folder is regenerated by RepoWise on every sync. Manual edits will be overwritten. Update the source code and let the next sync regenerate the context.
343
+ ${END_MARKER}`;
344
+ function injectAgentInstructions(content) {
345
+ const lineEnding = content.includes("\r\n") ? "\r\n" : "\n";
346
+ const canonicalBlock = AI_AGENT_USAGE_INSTRUCTIONS.replace(/\n/g, lineEnding);
347
+ const startIdx = content.indexOf(START_MARKER);
348
+ const endIdx = content.indexOf(END_MARKER);
349
+ if (startIdx >= 0 && endIdx > startIdx) {
350
+ const currentBlock = content.slice(startIdx, endIdx + END_MARKER.length);
351
+ if (currentBlock === canonicalBlock) {
352
+ return content;
353
+ }
354
+ return content.slice(0, startIdx) + canonicalBlock + content.slice(endIdx + END_MARKER.length);
355
+ }
356
+ const h1Match = content.match(/^# Project Overview\s*$/m);
357
+ if (h1Match && h1Match.index !== void 0) {
358
+ const insertAt = h1Match.index + h1Match[0].length;
359
+ return content.slice(0, insertAt) + lineEnding + lineEnding + canonicalBlock + content.slice(insertAt);
360
+ }
361
+ const h2Match = content.match(/^## Summary\s*$/m);
362
+ if (h2Match && h2Match.index !== void 0) {
363
+ const insertAt = h2Match.index + h2Match[0].length;
364
+ return content.slice(0, insertAt) + lineEnding + lineEnding + canonicalBlock + content.slice(insertAt);
365
+ }
366
+ return canonicalBlock + lineEnding + lineEnding + content;
367
+ }
368
+
324
369
  // ../listener/dist/lib/config.js
325
370
  import { readFile as readFile2, writeFile as writeFile2, rename, unlink as unlink2, mkdir as mkdir2, chmod } from "fs/promises";
326
371
  import { join as join3 } from "path";
@@ -912,7 +957,8 @@ async function fetchContextFromServer(repoId, localPath, apiUrl) {
912
957
  const content = await contentRes.text();
913
958
  const filePath = join8(contextDir, file.fileName);
914
959
  await mkdir5(dirname3(filePath), { recursive: true });
915
- await writeFile5(filePath, content, "utf-8");
960
+ const finalContent = file.fileName === "project-overview.md" ? injectAgentInstructions(content) : content;
961
+ await writeFile5(filePath, finalContent, "utf-8");
916
962
  updatedFiles.push(file.fileName);
917
963
  }
918
964
  console.log(`Context fetch for ${repoId}: downloaded ${updatedFiles.length}/${files.length} file(s)`);
@@ -1674,6 +1720,31 @@ async function checkStaleContext(repos, state, groups) {
1674
1720
  }
1675
1721
  return dirty;
1676
1722
  }
1723
+ async function reconcileAgentInstructions(repos) {
1724
+ for (const repo of repos) {
1725
+ const path = join13(repo.localPath, "repowise-context", "project-overview.md");
1726
+ let content;
1727
+ try {
1728
+ content = await readFile6(path, "utf-8");
1729
+ } catch (err) {
1730
+ const code = err?.code;
1731
+ if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES" || code === "EPERM" || code === "EISDIR") {
1732
+ continue;
1733
+ }
1734
+ console.warn(`[reconcile] read failed for ${repo.repoId}:`, err instanceof Error ? err.message : String(err));
1735
+ continue;
1736
+ }
1737
+ const injected = injectAgentInstructions(content);
1738
+ if (injected === content)
1739
+ continue;
1740
+ try {
1741
+ await writeFile8(path, injected, "utf-8");
1742
+ console.log(`[reconcile] Reconciled agent instructions for ${repo.repoId}`);
1743
+ } catch (err) {
1744
+ console.warn(`[reconcile] write failed for ${repo.repoId}:`, err instanceof Error ? err.message : String(err));
1745
+ }
1746
+ }
1747
+ }
1677
1748
  async function startListener() {
1678
1749
  running = true;
1679
1750
  const configDir = getConfigDir();
@@ -1810,6 +1881,11 @@ async function startListener() {
1810
1881
  console.error = (...args) => origError(`[${ts()}]`, ...args);
1811
1882
  console.warn = (...args) => origWarn(`[${ts()}]`, ...args);
1812
1883
  console.log(`RepoWise Listener started \u2014 watching ${allRepoIds.length} repo(s)`);
1884
+ try {
1885
+ await reconcileAgentInstructions(config2.repos);
1886
+ } catch (err) {
1887
+ console.warn("[reconcile] Initial agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
1888
+ }
1813
1889
  const shutdown = async () => {
1814
1890
  console.log("Shutting down...");
1815
1891
  stop();
@@ -1946,6 +2022,11 @@ async function startListener() {
1946
2022
  } catch (err) {
1947
2023
  console.warn("[self-heal] Stale context check failed:", err instanceof Error ? err.message : String(err));
1948
2024
  }
2025
+ try {
2026
+ await reconcileAgentInstructions(config2.repos);
2027
+ } catch (err) {
2028
+ console.warn("[reconcile] Agent instructions reconciliation failed:", err instanceof Error ? err.message : String(err));
2029
+ }
1949
2030
  }
1950
2031
  if (latestCliVersion && currentVersion && !config2.noAutoUpdate && (state.crashCount ?? 0) < CRASH_LOOP_THRESHOLD) {
1951
2032
  if (latestCliVersion !== state.lastUpdateTargetVersion) {
@@ -3241,6 +3322,7 @@ async function create() {
3241
3322
  let repoRoot;
3242
3323
  let repoPlatform;
3243
3324
  let repoExternalId;
3325
+ let repoLookupError;
3244
3326
  spinner.start("Checking for pending repository...");
3245
3327
  try {
3246
3328
  const pending = await apiRequest("/v1/onboarding/pending");
@@ -3276,7 +3358,8 @@ async function create() {
3276
3358
  repoPlatform = match.platform;
3277
3359
  repoExternalId = match.externalId;
3278
3360
  }
3279
- } catch {
3361
+ } catch (err) {
3362
+ repoLookupError = err instanceof Error ? err.message : String(err);
3280
3363
  }
3281
3364
  } else {
3282
3365
  try {
@@ -3285,11 +3368,15 @@ async function create() {
3285
3368
  }
3286
3369
  }
3287
3370
  if (!repoId) {
3288
- spinner.fail(
3289
- chalk5.red(
3290
- "Could not find this repository in your RepoWise account. Connect it on the dashboard first."
3291
- )
3292
- );
3371
+ if (repoLookupError) {
3372
+ spinner.fail(chalk5.red(`Failed to look up repositories: ${repoLookupError}`));
3373
+ } else {
3374
+ spinner.fail(
3375
+ chalk5.red(
3376
+ "Could not find this repository in your RepoWise account. Connect it on the dashboard first."
3377
+ )
3378
+ );
3379
+ }
3293
3380
  process.exitCode = 1;
3294
3381
  return;
3295
3382
  }
@@ -4044,6 +4131,7 @@ async function sync() {
4044
4131
  let repoId;
4045
4132
  let repoPlatform;
4046
4133
  let repoExternalId;
4134
+ let repoLookupError;
4047
4135
  spinner.start("Resolving repository...");
4048
4136
  try {
4049
4137
  const repos = await apiRequest("/v1/repos");
@@ -4053,14 +4141,19 @@ async function sync() {
4053
4141
  repoPlatform = match.platform;
4054
4142
  repoExternalId = match.externalId;
4055
4143
  }
4056
- } catch {
4144
+ } catch (err) {
4145
+ repoLookupError = err instanceof Error ? err.message : String(err);
4057
4146
  }
4058
4147
  if (!repoId) {
4059
- spinner.fail(
4060
- chalk9.red(
4061
- "Could not find this repository in your RepoWise account. Run `repowise create` first."
4062
- )
4063
- );
4148
+ if (repoLookupError) {
4149
+ spinner.fail(chalk9.red(`Failed to look up repositories: ${repoLookupError}`));
4150
+ } else {
4151
+ spinner.fail(
4152
+ chalk9.red(
4153
+ "Could not find this repository in your RepoWise account. Run `repowise create` first."
4154
+ )
4155
+ );
4156
+ }
4064
4157
  process.exitCode = 1;
4065
4158
  return;
4066
4159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repowise",
3
- "version": "0.1.88",
3
+ "version": "0.1.90",
4
4
  "type": "module",
5
5
  "description": "AI-optimized codebase context generator",
6
6
  "bin": {