pi-compass 0.2.0

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 (102) hide show
  1. package/README.md +74 -0
  2. package/dist/analyzers/build-script-detector.d.ts +3 -0
  3. package/dist/analyzers/build-script-detector.d.ts.map +1 -0
  4. package/dist/analyzers/build-script-detector.js +75 -0
  5. package/dist/analyzers/build-script-detector.js.map +1 -0
  6. package/dist/analyzers/convention-detector.d.ts +3 -0
  7. package/dist/analyzers/convention-detector.d.ts.map +1 -0
  8. package/dist/analyzers/convention-detector.js +47 -0
  9. package/dist/analyzers/convention-detector.js.map +1 -0
  10. package/dist/analyzers/directory-tree.d.ts +4 -0
  11. package/dist/analyzers/directory-tree.d.ts.map +1 -0
  12. package/dist/analyzers/directory-tree.js +60 -0
  13. package/dist/analyzers/directory-tree.js.map +1 -0
  14. package/dist/analyzers/entry-point-detector.d.ts +3 -0
  15. package/dist/analyzers/entry-point-detector.d.ts.map +1 -0
  16. package/dist/analyzers/entry-point-detector.js +87 -0
  17. package/dist/analyzers/entry-point-detector.js.map +1 -0
  18. package/dist/analyzers/framework-detector.d.ts +3 -0
  19. package/dist/analyzers/framework-detector.d.ts.map +1 -0
  20. package/dist/analyzers/framework-detector.js +63 -0
  21. package/dist/analyzers/framework-detector.js.map +1 -0
  22. package/dist/analyzers/index.d.ts +8 -0
  23. package/dist/analyzers/index.d.ts.map +1 -0
  24. package/dist/analyzers/index.js +8 -0
  25. package/dist/analyzers/index.js.map +1 -0
  26. package/dist/analyzers/key-file-detector.d.ts +3 -0
  27. package/dist/analyzers/key-file-detector.d.ts.map +1 -0
  28. package/dist/analyzers/key-file-detector.js +32 -0
  29. package/dist/analyzers/key-file-detector.js.map +1 -0
  30. package/dist/analyzers/package-detector.d.ts +3 -0
  31. package/dist/analyzers/package-detector.d.ts.map +1 -0
  32. package/dist/analyzers/package-detector.js +78 -0
  33. package/dist/analyzers/package-detector.js.map +1 -0
  34. package/dist/codemap-formatter.d.ts +4 -0
  35. package/dist/codemap-formatter.d.ts.map +1 -0
  36. package/dist/codemap-formatter.js +72 -0
  37. package/dist/codemap-formatter.js.map +1 -0
  38. package/dist/codemap-generator.d.ts +10 -0
  39. package/dist/codemap-generator.d.ts.map +1 -0
  40. package/dist/codemap-generator.js +80 -0
  41. package/dist/codemap-generator.js.map +1 -0
  42. package/dist/codemap-injector.d.ts +12 -0
  43. package/dist/codemap-injector.d.ts.map +1 -0
  44. package/dist/codemap-injector.js +20 -0
  45. package/dist/codemap-injector.js.map +1 -0
  46. package/dist/fs-utils.d.ts +3 -0
  47. package/dist/fs-utils.d.ts.map +1 -0
  48. package/dist/fs-utils.js +21 -0
  49. package/dist/fs-utils.js.map +1 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +69 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/onboard-command.d.ts +5 -0
  55. package/dist/onboard-command.d.ts.map +1 -0
  56. package/dist/onboard-command.js +33 -0
  57. package/dist/onboard-command.js.map +1 -0
  58. package/dist/onboard-tools.d.ts +4 -0
  59. package/dist/onboard-tools.d.ts.map +1 -0
  60. package/dist/onboard-tools.js +77 -0
  61. package/dist/onboard-tools.js.map +1 -0
  62. package/dist/project.d.ts +4 -0
  63. package/dist/project.d.ts.map +1 -0
  64. package/dist/project.js +20 -0
  65. package/dist/project.js.map +1 -0
  66. package/dist/storage.d.ts +12 -0
  67. package/dist/storage.d.ts.map +1 -0
  68. package/dist/storage.js +46 -0
  69. package/dist/storage.js.map +1 -0
  70. package/dist/tour-command.d.ts +5 -0
  71. package/dist/tour-command.d.ts.map +1 -0
  72. package/dist/tour-command.js +26 -0
  73. package/dist/tour-command.js.map +1 -0
  74. package/dist/tour-generator.d.ts +6 -0
  75. package/dist/tour-generator.d.ts.map +1 -0
  76. package/dist/tour-generator.js +204 -0
  77. package/dist/tour-generator.js.map +1 -0
  78. package/dist/types.d.ts +89 -0
  79. package/dist/types.d.ts.map +1 -0
  80. package/dist/types.js +2 -0
  81. package/dist/types.js.map +1 -0
  82. package/package.json +71 -0
  83. package/src/analyzers/build-script-detector.ts +85 -0
  84. package/src/analyzers/convention-detector.ts +52 -0
  85. package/src/analyzers/directory-tree.ts +65 -0
  86. package/src/analyzers/entry-point-detector.ts +98 -0
  87. package/src/analyzers/framework-detector.ts +76 -0
  88. package/src/analyzers/index.ts +7 -0
  89. package/src/analyzers/key-file-detector.ts +36 -0
  90. package/src/analyzers/package-detector.ts +87 -0
  91. package/src/codemap-formatter.ts +90 -0
  92. package/src/codemap-generator.ts +110 -0
  93. package/src/codemap-injector.ts +44 -0
  94. package/src/fs-utils.ts +19 -0
  95. package/src/index.ts +90 -0
  96. package/src/onboard-command.ts +60 -0
  97. package/src/onboard-tools.ts +116 -0
  98. package/src/project.ts +29 -0
  99. package/src/storage.ts +82 -0
  100. package/src/tour-command.ts +50 -0
  101. package/src/tour-generator.ts +237 -0
  102. package/src/types.ts +104 -0
@@ -0,0 +1,12 @@
1
+ import type { CodeMap, CodeTour, CacheEntry } from "./types.js";
2
+ export declare function getBaseDir(): string;
3
+ export declare function getProjectDir(projectId: string, baseDir?: string): string;
4
+ export declare function getCodemapPath(projectId: string, baseDir?: string): string;
5
+ export declare function getToursDir(projectId: string, baseDir?: string): string;
6
+ export declare function getTourPath(projectId: string, topic: string, baseDir?: string): string;
7
+ export declare function ensureStorageLayout(projectId: string, baseDir?: string): void;
8
+ export declare function loadCachedCodemap(projectId: string, baseDir?: string): CacheEntry<CodeMap> | null;
9
+ export declare function saveCachedCodemap(projectId: string, entry: CacheEntry<CodeMap>, baseDir?: string): void;
10
+ export declare function loadCachedTour(projectId: string, topic: string, baseDir?: string): CacheEntry<CodeTour> | null;
11
+ export declare function saveCachedTour(projectId: string, topic: string, entry: CacheEntry<CodeTour>, baseDir?: string): void;
12
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEhE,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,SAAe,GAAG,MAAM,CAE/E;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,SAAe,GAAG,MAAM,CAEhF;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,SAAe,GAAG,MAAM,CAE7E;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,SAAe,GAAG,MAAM,CAE5F;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,SAAe,GAAG,IAAI,CAEnF;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,SAAe,GACrB,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAO5B;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,EAC1B,OAAO,SAAe,GACrB,IAAI,CAMN;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,SAAe,GACrB,UAAU,CAAC,QAAQ,CAAC,GAAG,IAAI,CAO7B;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,EAC3B,OAAO,SAAe,GACrB,IAAI,CAMN"}
@@ -0,0 +1,46 @@
1
+ import { mkdirSync, readFileSync, writeFileSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ export function getBaseDir() {
5
+ return join(homedir(), ".pi", "compass");
6
+ }
7
+ export function getProjectDir(projectId, baseDir = getBaseDir()) {
8
+ return join(baseDir, "projects", projectId);
9
+ }
10
+ export function getCodemapPath(projectId, baseDir = getBaseDir()) {
11
+ return join(getProjectDir(projectId, baseDir), "codemap.json");
12
+ }
13
+ export function getToursDir(projectId, baseDir = getBaseDir()) {
14
+ return join(getProjectDir(projectId, baseDir), "tours");
15
+ }
16
+ export function getTourPath(projectId, topic, baseDir = getBaseDir()) {
17
+ return join(getToursDir(projectId, baseDir), `${topic}.json`);
18
+ }
19
+ export function ensureStorageLayout(projectId, baseDir = getBaseDir()) {
20
+ mkdirSync(getToursDir(projectId, baseDir), { recursive: true });
21
+ }
22
+ export function loadCachedCodemap(projectId, baseDir = getBaseDir()) {
23
+ try {
24
+ const raw = readFileSync(getCodemapPath(projectId, baseDir), "utf-8");
25
+ return JSON.parse(raw);
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ export function saveCachedCodemap(projectId, entry, baseDir = getBaseDir()) {
32
+ writeFileSync(getCodemapPath(projectId, baseDir), JSON.stringify(entry, null, 2), "utf-8");
33
+ }
34
+ export function loadCachedTour(projectId, topic, baseDir = getBaseDir()) {
35
+ try {
36
+ const raw = readFileSync(getTourPath(projectId, topic, baseDir), "utf-8");
37
+ return JSON.parse(raw);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ export function saveCachedTour(projectId, topic, entry, baseDir = getBaseDir()) {
44
+ writeFileSync(getTourPath(projectId, topic, baseDir), JSON.stringify(entry, null, 2), "utf-8");
45
+ }
46
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,SAAiB,EAAE,OAAO,GAAG,UAAU,EAAE;IACrE,OAAO,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,OAAO,GAAG,UAAU,EAAE;IACtE,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,OAAO,GAAG,UAAU,EAAE;IACnE,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,KAAa,EAAE,OAAO,GAAG,UAAU,EAAE;IAClF,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,SAAiB,EAAE,OAAO,GAAG,UAAU,EAAE;IAC3E,SAAS,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,OAAO,GAAG,UAAU,EAAE;IAEtB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,KAA0B,EAC1B,OAAO,GAAG,UAAU,EAAE;IAEtB,aAAa,CACX,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAC9B,OAAO,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,SAAiB,EACjB,KAAa,EACb,OAAO,GAAG,UAAU,EAAE;IAEtB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,SAAiB,EACjB,KAAa,EACb,KAA2B,EAC3B,OAAO,GAAG,UAAU,EAAE;IAEtB,aAAa,CACX,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,EACtC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAC9B,OAAO,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ExtensionAPI, ExtensionCommandContext } from "@mariozechner/pi-coding-agent";
2
+ import type { StateRef } from "./types.js";
3
+ export declare const COMMAND_NAME = "tour";
4
+ export declare function handleTourCommand(args: string, ctx: ExtensionCommandContext, pi: ExtensionAPI, stateRef: StateRef): Promise<void>;
5
+ //# sourceMappingURL=tour-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour-command.d.ts","sourceRoot":"","sources":["../src/tour-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,uBAAuB,EACxB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,uBAAuB,EAC5B,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAkCf"}
@@ -0,0 +1,26 @@
1
+ import { detectAvailableTopics, getOrGenerateTour, formatTourMarkdown } from "./tour-generator.js";
2
+ import { getOrGenerateCodemap } from "./codemap-generator.js";
3
+ export const COMMAND_NAME = "tour";
4
+ export async function handleTourCommand(args, ctx, pi, stateRef) {
5
+ const state = stateRef.get();
6
+ if (!state.project) {
7
+ ctx.ui.notify("No project detected. Run from within a git repository.", "error");
8
+ return;
9
+ }
10
+ const codemap = state.cachedCodemap?.data
11
+ ?? getOrGenerateCodemap(state.project.root, state.project.id, state.project.name).codemap;
12
+ const topic = args.trim();
13
+ if (!topic) {
14
+ const topics = detectAvailableTopics(state.project.root, codemap);
15
+ if (topics.length === 0) {
16
+ ctx.ui.notify("No tour topics detected in this project.", "info");
17
+ return;
18
+ }
19
+ ctx.ui.notify(`Available tour topics:\n${topics.map((t) => ` - ${t}`).join("\n")}\n\nUsage: /tour <topic>`, "info");
20
+ return;
21
+ }
22
+ const tour = getOrGenerateTour(state.project.root, topic, codemap, state.project.id);
23
+ const markdown = formatTourMarkdown(tour);
24
+ pi.sendUserMessage(`${markdown}\n\nAsk me about any of these files for more detail.`, { deliverAs: "followUp" });
25
+ }
26
+ //# sourceMappingURL=tour-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour-command.js","sourceRoot":"","sources":["../src/tour-command.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEnG,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AAEnC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAY,EACZ,GAA4B,EAC5B,EAAgB,EAChB,QAAkB;IAElB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACnB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,wDAAwD,EAAE,OAAO,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,EAAE,IAAI;WACpC,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IAE5F,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE1B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,0CAA0C,EAAE,MAAM,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QACD,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;QACrH,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,iBAAiB,CAC5B,KAAK,CAAC,OAAO,CAAC,IAAI,EAClB,KAAK,EACL,OAAO,EACP,KAAK,CAAC,OAAO,CAAC,EAAE,CACjB,CAAC;IAEF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC1C,EAAE,CAAC,eAAe,CAChB,GAAG,QAAQ,sDAAsD,EACjE,EAAE,SAAS,EAAE,UAAU,EAAE,CAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { CodeMap, CodeTour } from "./types.js";
2
+ export declare function detectAvailableTopics(_cwd: string, codemap: CodeMap): readonly string[];
3
+ export declare function generateTour(cwd: string, topic: string, codemap: CodeMap): CodeTour;
4
+ export declare function formatTourMarkdown(tour: CodeTour): string;
5
+ export declare function getOrGenerateTour(cwd: string, topic: string, codemap: CodeMap, projectId: string, baseDir?: string): CodeTour;
6
+ //# sourceMappingURL=tour-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour-generator.d.ts","sourceRoot":"","sources":["../src/tour-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAwB,MAAM,YAAY,CAAC;AAO1E,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,SAAS,MAAM,EAAE,CAuBnB;AAED,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GACf,QAAQ,CASV;AAyJD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAazD;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,QAAQ,CAYV"}
@@ -0,0 +1,204 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { join, extname } from "node:path";
3
+ import { loadCachedTour, saveCachedTour } from "./storage.js";
4
+ const TEST_INDICATORS = ["test", "tests", "spec", "__tests__", "e2e"];
5
+ const CI_INDICATORS = [".github", ".gitlab-ci.yml", "Jenkinsfile"];
6
+ const DB_INDICATORS = ["migrations", "prisma", "drizzle", "alembic", "db", "database"];
7
+ export function detectAvailableTopics(_cwd, codemap) {
8
+ const topics = [];
9
+ for (const entry of codemap.directoryTree) {
10
+ if (entry.type === "dir" && entry.name !== "node_modules" && entry.name !== "dist") {
11
+ topics.push(entry.name);
12
+ }
13
+ }
14
+ const allNames = codemap.directoryTree.map((e) => e.name.toLowerCase());
15
+ const keyFilePaths = codemap.keyFiles.map((k) => k.path.toLowerCase());
16
+ if (TEST_INDICATORS.some((t) => allNames.includes(t))) {
17
+ topics.push("testing");
18
+ }
19
+ if (CI_INDICATORS.some((c) => allNames.includes(c) || keyFilePaths.some((k) => k.includes(c)))) {
20
+ topics.push("ci");
21
+ }
22
+ if (DB_INDICATORS.some((d) => allNames.includes(d))) {
23
+ topics.push("database");
24
+ }
25
+ return [...new Set(topics)];
26
+ }
27
+ export function generateTour(cwd, topic, codemap) {
28
+ const steps = buildTourSteps(cwd, topic);
29
+ return {
30
+ projectId: codemap.projectId,
31
+ topic,
32
+ generatedAt: new Date().toISOString(),
33
+ steps,
34
+ };
35
+ }
36
+ function buildTourSteps(cwd, topic) {
37
+ const steps = [];
38
+ const topicDir = join(cwd, topic);
39
+ const srcTopicDir = join(cwd, "src", topic);
40
+ const dir = safeIsDir(topicDir) ? topicDir : safeIsDir(srcTopicDir) ? srcTopicDir : null;
41
+ if (dir) {
42
+ const files = collectFiles(dir, cwd, 3);
43
+ for (const file of files.slice(0, 15)) {
44
+ steps.push({
45
+ file,
46
+ description: describeFile(file),
47
+ });
48
+ }
49
+ }
50
+ if (topic === "testing") {
51
+ steps.push(...findTestFiles(cwd));
52
+ }
53
+ else if (topic === "ci") {
54
+ steps.push(...findCiFiles(cwd));
55
+ }
56
+ return steps;
57
+ }
58
+ function collectFiles(dir, root, depth) {
59
+ if (depth <= 0)
60
+ return [];
61
+ const results = [];
62
+ let entries;
63
+ try {
64
+ entries = readdirSync(dir);
65
+ }
66
+ catch {
67
+ return [];
68
+ }
69
+ for (const name of entries.sort()) {
70
+ if (name.startsWith("."))
71
+ continue;
72
+ const full = join(dir, name);
73
+ const rel = full.slice(root.length + 1);
74
+ try {
75
+ const stat = statSync(full);
76
+ if (stat.isFile() && isSourceFile(name)) {
77
+ results.push(rel);
78
+ }
79
+ else if (stat.isDirectory()) {
80
+ results.push(...collectFiles(full, root, depth - 1));
81
+ }
82
+ }
83
+ catch {
84
+ continue;
85
+ }
86
+ }
87
+ return results;
88
+ }
89
+ function findTestFiles(cwd) {
90
+ const steps = [];
91
+ for (const dir of TEST_INDICATORS) {
92
+ const full = join(cwd, dir);
93
+ if (safeIsDir(full)) {
94
+ const files = collectFiles(full, cwd, 2);
95
+ for (const file of files.slice(0, 5)) {
96
+ steps.push({ file, description: describeFile(file) });
97
+ }
98
+ }
99
+ }
100
+ return steps;
101
+ }
102
+ function findCiFiles(cwd) {
103
+ const steps = [];
104
+ const workflowDir = join(cwd, ".github", "workflows");
105
+ if (safeIsDir(workflowDir)) {
106
+ try {
107
+ for (const name of readdirSync(workflowDir)) {
108
+ steps.push({
109
+ file: `.github/workflows/${name}`,
110
+ description: `CI workflow: ${name}`,
111
+ });
112
+ }
113
+ }
114
+ catch {
115
+ // ignore
116
+ }
117
+ }
118
+ for (const file of [".gitlab-ci.yml", "Jenkinsfile"]) {
119
+ if (safeExists(join(cwd, file))) {
120
+ steps.push({ file, description: `CI configuration: ${file}` });
121
+ }
122
+ }
123
+ return steps;
124
+ }
125
+ function describeFile(filePath) {
126
+ const parts = filePath.split("/");
127
+ const fileName = parts[parts.length - 1] ?? filePath;
128
+ const ext = extname(fileName);
129
+ const baseName = fileName.replace(ext, "");
130
+ if (fileName.includes("test") || fileName.includes("spec")) {
131
+ return `Test file for ${baseName.replace(/[._-]?(test|spec)/, "")}`;
132
+ }
133
+ if (fileName === "index.ts" || fileName === "index.js") {
134
+ const parent = parts[parts.length - 2];
135
+ return parent ? `Entry point for ${parent} module` : "Package entry point";
136
+ }
137
+ if (fileName.includes("config"))
138
+ return `Configuration: ${baseName}`;
139
+ if (fileName.includes("route") || fileName.includes("router"))
140
+ return `Routing: ${baseName}`;
141
+ if (fileName.includes("middleware"))
142
+ return `Middleware: ${baseName}`;
143
+ if (fileName.includes("model") || fileName.includes("schema"))
144
+ return `Data model: ${baseName}`;
145
+ if (fileName.includes("service"))
146
+ return `Service: ${baseName}`;
147
+ if (fileName.includes("controller") || fileName.includes("handler"))
148
+ return `Handler: ${baseName}`;
149
+ if (fileName.includes("util") || fileName.includes("helper"))
150
+ return `Utility: ${baseName}`;
151
+ return `${baseName} module`;
152
+ }
153
+ const SOURCE_EXTENSIONS = new Set([
154
+ ".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java",
155
+ ".rb", ".php", ".ex", ".exs", ".kt", ".swift", ".c", ".cpp",
156
+ ".h", ".yml", ".yaml", ".toml", ".json",
157
+ ]);
158
+ function isSourceFile(name) {
159
+ return SOURCE_EXTENSIONS.has(extname(name));
160
+ }
161
+ function safeIsDir(path) {
162
+ try {
163
+ return statSync(path).isDirectory();
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ }
169
+ function safeExists(path) {
170
+ try {
171
+ statSync(path);
172
+ return true;
173
+ }
174
+ catch {
175
+ return false;
176
+ }
177
+ }
178
+ export function formatTourMarkdown(tour) {
179
+ if (tour.steps.length === 0) {
180
+ return `No files found for topic "${tour.topic}".`;
181
+ }
182
+ const lines = [`## Code Tour: ${tour.topic}`, ""];
183
+ for (let i = 0; i < tour.steps.length; i++) {
184
+ const step = tour.steps[i];
185
+ lines.push(`**${i + 1}.** \`${step.file}\``);
186
+ lines.push(` ${step.description}`);
187
+ lines.push("");
188
+ }
189
+ return lines.join("\n");
190
+ }
191
+ export function getOrGenerateTour(cwd, topic, codemap, projectId, baseDir) {
192
+ const cached = loadCachedTour(projectId, topic, baseDir);
193
+ if (cached)
194
+ return cached.data;
195
+ const tour = generateTour(cwd, topic, codemap);
196
+ const entry = {
197
+ data: tour,
198
+ contentHash: codemap.contentHash,
199
+ createdAt: tour.generatedAt,
200
+ };
201
+ saveCachedTour(projectId, topic, entry, baseDir);
202
+ return tour;
203
+ }
204
+ //# sourceMappingURL=tour-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tour-generator.js","sourceRoot":"","sources":["../src/tour-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ export interface ProjectInfo {
2
+ readonly id: string;
3
+ readonly name: string;
4
+ readonly root: string;
5
+ readonly remote: string;
6
+ }
7
+ export interface DirectoryEntry {
8
+ readonly name: string;
9
+ readonly type: "file" | "dir";
10
+ readonly children?: readonly DirectoryEntry[];
11
+ }
12
+ export type PackageManager = "npm" | "cargo" | "go" | "pip" | "poetry" | "gradle" | "maven" | "composer" | "bundler" | "mix";
13
+ export interface PackageInfo {
14
+ readonly manager: PackageManager;
15
+ readonly name: string;
16
+ readonly version?: string;
17
+ readonly dependencies: readonly string[];
18
+ }
19
+ export interface FrameworkDetection {
20
+ readonly name: string;
21
+ readonly version?: string;
22
+ readonly confidence: "definite" | "likely";
23
+ readonly source: string;
24
+ }
25
+ export type EntryPointKind = "main" | "index" | "route" | "handler" | "config";
26
+ export interface EntryPoint {
27
+ readonly path: string;
28
+ readonly kind: EntryPointKind;
29
+ }
30
+ export interface BuildScript {
31
+ readonly name: string;
32
+ readonly command: string;
33
+ readonly source: string;
34
+ }
35
+ export interface Convention {
36
+ readonly source: string;
37
+ readonly content: string;
38
+ }
39
+ export interface KeyFile {
40
+ readonly path: string;
41
+ readonly description: string;
42
+ }
43
+ export interface CodeMap {
44
+ readonly projectId: string;
45
+ readonly projectName: string;
46
+ readonly generatedAt: string;
47
+ readonly contentHash: string;
48
+ readonly directoryTree: readonly DirectoryEntry[];
49
+ readonly packages: readonly PackageInfo[];
50
+ readonly frameworks: readonly FrameworkDetection[];
51
+ readonly entryPoints: readonly EntryPoint[];
52
+ readonly buildScripts: readonly BuildScript[];
53
+ readonly conventions: readonly Convention[];
54
+ readonly keyFiles: readonly KeyFile[];
55
+ }
56
+ export interface TourStep {
57
+ readonly file: string;
58
+ readonly startLine?: number;
59
+ readonly endLine?: number;
60
+ readonly description: string;
61
+ }
62
+ export interface CodeTour {
63
+ readonly projectId: string;
64
+ readonly topic: string;
65
+ readonly generatedAt: string;
66
+ readonly steps: readonly TourStep[];
67
+ }
68
+ export interface CacheEntry<T> {
69
+ readonly data: T;
70
+ readonly contentHash: string;
71
+ readonly createdAt: string;
72
+ }
73
+ export interface CompassConfig {
74
+ readonly max_injection_chars: number;
75
+ readonly inject_on_first_turn: boolean;
76
+ readonly cache_enabled: boolean;
77
+ }
78
+ export interface StateRef {
79
+ get: () => CompassState;
80
+ set: (s: CompassState) => void;
81
+ }
82
+ export interface CompassState {
83
+ readonly project: ProjectInfo | null;
84
+ readonly turnCount: number;
85
+ readonly codemapInjected: boolean;
86
+ readonly cachedCodemap: CacheEntry<CodeMap> | null;
87
+ readonly stale: boolean;
88
+ }
89
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "pi-compass",
3
+ "version": "0.2.0",
4
+ "description": "A Pi extension that generates structured codebase maps and interactive code tours for agent onboarding.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Matt Devy",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/MattDevy/pi-extensions.git",
11
+ "directory": "packages/pi-compass"
12
+ },
13
+ "homepage": "https://github.com/MattDevy/pi-extensions/tree/main/packages/pi-compass#readme",
14
+ "bugs": {
15
+ "url": "https://github.com/MattDevy/pi-extensions/issues"
16
+ },
17
+ "keywords": [
18
+ "pi-package",
19
+ "pi-extension",
20
+ "pi-coding-agent",
21
+ "codebase-onboarding",
22
+ "codemap",
23
+ "code-tour",
24
+ "ai",
25
+ "llm",
26
+ "ai-agent",
27
+ "coding-assistant",
28
+ "developer-tools"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "src",
36
+ "!src/**/*.test.ts",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "main": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "pi": {
43
+ "extensions": [
44
+ "dist/index.js"
45
+ ]
46
+ },
47
+ "scripts": {
48
+ "clean": "rm -rf dist tsconfig.build.tsbuildinfo",
49
+ "build": "npm run clean && tsc -p tsconfig.build.json",
50
+ "typecheck": "tsc --noEmit",
51
+ "test": "vitest run",
52
+ "lint": "eslint src/",
53
+ "check": "vitest run && eslint src/ && tsc --noEmit",
54
+ "prepublishOnly": "npm run build && npm run check",
55
+ "prepack": "test -d dist || { echo 'Error: dist/ missing. Run npm run build first.' && exit 1; }"
56
+ },
57
+ "peerDependencies": {
58
+ "@mariozechner/pi-coding-agent": "^0.62.0",
59
+ "@mariozechner/pi-ai": "^0.62.0",
60
+ "@mariozechner/pi-tui": "^0.62.0",
61
+ "@sinclair/typebox": "^0.34.0"
62
+ },
63
+ "devDependencies": {
64
+ "@types/node": "^24.0.0",
65
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
66
+ "@typescript-eslint/parser": "^8.0.0",
67
+ "eslint": "^9.0.0",
68
+ "typescript": "^5.7.0",
69
+ "vitest": "^3.0.0"
70
+ }
71
+ }
@@ -0,0 +1,85 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import type { BuildScript } from "../types.js";
4
+
5
+ const INTERESTING_SCRIPTS = new Set([
6
+ "build", "dev", "start", "test", "lint", "check",
7
+ "typecheck", "format", "deploy", "clean", "serve",
8
+ "preview", "generate", "migrate", "seed",
9
+ ]);
10
+
11
+ export function detectBuildScripts(cwd: string): readonly BuildScript[] {
12
+ const results: BuildScript[] = [];
13
+
14
+ results.push(...extractNpmScripts(cwd));
15
+ results.push(...extractMakefileTargets(cwd));
16
+ results.push(...detectCiFiles(cwd));
17
+ results.push(...detectContainerFiles(cwd));
18
+
19
+ return results;
20
+ }
21
+
22
+ function extractNpmScripts(cwd: string): BuildScript[] {
23
+ try {
24
+ const raw = readFileSync(join(cwd, "package.json"), "utf-8");
25
+ const pkg = JSON.parse(raw) as Record<string, unknown>;
26
+ const scripts = pkg["scripts"];
27
+ if (!scripts || typeof scripts !== "object") return [];
28
+
29
+ return Object.entries(scripts as Record<string, unknown>)
30
+ .filter(([name]) => INTERESTING_SCRIPTS.has(name))
31
+ .map(([name, cmd]) => ({
32
+ name,
33
+ command: typeof cmd === "string" ? cmd : String(cmd),
34
+ source: "package.json",
35
+ }));
36
+ } catch {
37
+ return [];
38
+ }
39
+ }
40
+
41
+ function extractMakefileTargets(cwd: string): BuildScript[] {
42
+ const makefilePath = join(cwd, "Makefile");
43
+ try {
44
+ const content = readFileSync(makefilePath, "utf-8");
45
+ const targets = [...content.matchAll(/^([a-zA-Z_][\w-]*)\s*:/gm)];
46
+ return targets
47
+ .filter(([, name]) => name && !name.startsWith("."))
48
+ .map(([, name]) => ({
49
+ name: name!,
50
+ command: `make ${name}`,
51
+ source: "Makefile",
52
+ }));
53
+ } catch {
54
+ return [];
55
+ }
56
+ }
57
+
58
+ function detectCiFiles(cwd: string): BuildScript[] {
59
+ const results: BuildScript[] = [];
60
+
61
+ if (existsSync(join(cwd, ".github", "workflows"))) {
62
+ results.push({ name: "ci", command: "GitHub Actions", source: ".github/workflows/" });
63
+ }
64
+ if (existsSync(join(cwd, ".gitlab-ci.yml"))) {
65
+ results.push({ name: "ci", command: "GitLab CI", source: ".gitlab-ci.yml" });
66
+ }
67
+ if (existsSync(join(cwd, "Jenkinsfile"))) {
68
+ results.push({ name: "ci", command: "Jenkins", source: "Jenkinsfile" });
69
+ }
70
+
71
+ return results;
72
+ }
73
+
74
+ function detectContainerFiles(cwd: string): BuildScript[] {
75
+ const results: BuildScript[] = [];
76
+
77
+ if (existsSync(join(cwd, "Dockerfile"))) {
78
+ results.push({ name: "docker", command: "docker build", source: "Dockerfile" });
79
+ }
80
+ if (existsSync(join(cwd, "docker-compose.yml")) || existsSync(join(cwd, "docker-compose.yaml"))) {
81
+ results.push({ name: "docker-compose", command: "docker compose up", source: "docker-compose.yml" });
82
+ }
83
+
84
+ return results;
85
+ }
@@ -0,0 +1,52 @@
1
+ import { join } from "node:path";
2
+ import type { Convention } from "../types.js";
3
+ import { readTextFile } from "../fs-utils.js";
4
+
5
+ const MAX_CONTENT_LENGTH = 2000;
6
+
7
+ const CONVENTION_FILES: readonly string[] = [
8
+ "AGENTS.md",
9
+ "CLAUDE.md",
10
+ "GEMINI.md",
11
+ ".editorconfig",
12
+ "eslint.config.js",
13
+ "eslint.config.ts",
14
+ "eslint.config.mjs",
15
+ ".eslintrc.json",
16
+ ".eslintrc.js",
17
+ ".eslintrc.yml",
18
+ "prettier.config.js",
19
+ "prettier.config.ts",
20
+ ".prettierrc",
21
+ ".prettierrc.json",
22
+ "biome.json",
23
+ "biome.jsonc",
24
+ "rustfmt.toml",
25
+ ".golangci.yml",
26
+ ".golangci.yaml",
27
+ "CONTRIBUTING.md",
28
+ ".stylelintrc.json",
29
+ "deno.json",
30
+ "deno.jsonc",
31
+ ];
32
+
33
+ export function detectConventions(cwd: string): readonly Convention[] {
34
+ const results: Convention[] = [];
35
+
36
+ for (const file of CONVENTION_FILES) {
37
+ const content = readTextFile(join(cwd, file));
38
+ if (content !== null) {
39
+ results.push({
40
+ source: file,
41
+ content: truncate(content, MAX_CONTENT_LENGTH),
42
+ });
43
+ }
44
+ }
45
+
46
+ return results;
47
+ }
48
+
49
+ function truncate(text: string, maxLength: number): string {
50
+ if (text.length <= maxLength) return text;
51
+ return text.slice(0, maxLength) + "\n... (truncated)";
52
+ }