pi-para 0.5.2

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 (198) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/README.md +305 -0
  3. package/SETUP.md +171 -0
  4. package/dist/capture.d.ts +34 -0
  5. package/dist/capture.d.ts.map +1 -0
  6. package/dist/capture.js +461 -0
  7. package/dist/capture.js.map +1 -0
  8. package/dist/cli.d.ts +15 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +405 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands.d.ts +15 -0
  13. package/dist/commands.d.ts.map +1 -0
  14. package/dist/commands.js +786 -0
  15. package/dist/commands.js.map +1 -0
  16. package/dist/context.d.ts +61 -0
  17. package/dist/context.d.ts.map +1 -0
  18. package/dist/context.js +289 -0
  19. package/dist/context.js.map +1 -0
  20. package/dist/daemon.d.ts +49 -0
  21. package/dist/daemon.d.ts.map +1 -0
  22. package/dist/daemon.js +226 -0
  23. package/dist/daemon.js.map +1 -0
  24. package/dist/frontmatter.d.ts +59 -0
  25. package/dist/frontmatter.d.ts.map +1 -0
  26. package/dist/frontmatter.js +170 -0
  27. package/dist/frontmatter.js.map +1 -0
  28. package/dist/gepa/dataset.d.ts +36 -0
  29. package/dist/gepa/dataset.d.ts.map +1 -0
  30. package/dist/gepa/dataset.js +148 -0
  31. package/dist/gepa/dataset.js.map +1 -0
  32. package/dist/gepa/evaluator.d.ts +51 -0
  33. package/dist/gepa/evaluator.d.ts.map +1 -0
  34. package/dist/gepa/evaluator.js +317 -0
  35. package/dist/gepa/evaluator.js.map +1 -0
  36. package/dist/gepa/index.d.ts +66 -0
  37. package/dist/gepa/index.d.ts.map +1 -0
  38. package/dist/gepa/index.js +240 -0
  39. package/dist/gepa/index.js.map +1 -0
  40. package/dist/gepa/llm.d.ts +35 -0
  41. package/dist/gepa/llm.d.ts.map +1 -0
  42. package/dist/gepa/llm.js +268 -0
  43. package/dist/gepa/llm.js.map +1 -0
  44. package/dist/gepa/optimized/capture-prompt.txt +65 -0
  45. package/dist/gepa/optimizer.d.ts +29 -0
  46. package/dist/gepa/optimizer.d.ts.map +1 -0
  47. package/dist/gepa/optimizer.js +249 -0
  48. package/dist/gepa/optimizer.js.map +1 -0
  49. package/dist/gepa/targets.d.ts +39 -0
  50. package/dist/gepa/targets.d.ts.map +1 -0
  51. package/dist/gepa/targets.js +326 -0
  52. package/dist/gepa/targets.js.map +1 -0
  53. package/dist/gepa/types.d.ts +168 -0
  54. package/dist/gepa/types.d.ts.map +1 -0
  55. package/dist/gepa/types.js +124 -0
  56. package/dist/gepa/types.js.map +1 -0
  57. package/dist/index.d.ts +21 -0
  58. package/dist/index.d.ts.map +1 -0
  59. package/dist/index.js +294 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/ingest.d.ts +88 -0
  62. package/dist/ingest.d.ts.map +1 -0
  63. package/dist/ingest.js +105 -0
  64. package/dist/ingest.js.map +1 -0
  65. package/dist/link-discovery.d.ts +40 -0
  66. package/dist/link-discovery.d.ts.map +1 -0
  67. package/dist/link-discovery.js +122 -0
  68. package/dist/link-discovery.js.map +1 -0
  69. package/dist/link-utils.d.ts +30 -0
  70. package/dist/link-utils.d.ts.map +1 -0
  71. package/dist/link-utils.js +145 -0
  72. package/dist/link-utils.js.map +1 -0
  73. package/dist/lint.d.ts +39 -0
  74. package/dist/lint.d.ts.map +1 -0
  75. package/dist/lint.js +827 -0
  76. package/dist/lint.js.map +1 -0
  77. package/dist/maintainer.d.ts +24 -0
  78. package/dist/maintainer.d.ts.map +1 -0
  79. package/dist/maintainer.js +358 -0
  80. package/dist/maintainer.js.map +1 -0
  81. package/dist/processor.d.ts +14 -0
  82. package/dist/processor.d.ts.map +1 -0
  83. package/dist/processor.js +361 -0
  84. package/dist/processor.js.map +1 -0
  85. package/dist/query.d.ts +69 -0
  86. package/dist/query.d.ts.map +1 -0
  87. package/dist/query.js +107 -0
  88. package/dist/query.js.map +1 -0
  89. package/dist/raw.d.ts +57 -0
  90. package/dist/raw.d.ts.map +1 -0
  91. package/dist/raw.js +219 -0
  92. package/dist/raw.js.map +1 -0
  93. package/dist/redact.d.ts +21 -0
  94. package/dist/redact.d.ts.map +1 -0
  95. package/dist/redact.js +143 -0
  96. package/dist/redact.js.map +1 -0
  97. package/dist/scope.d.ts +54 -0
  98. package/dist/scope.d.ts.map +1 -0
  99. package/dist/scope.js +161 -0
  100. package/dist/scope.js.map +1 -0
  101. package/dist/scripts/bulk-link-fix.d.ts +9 -0
  102. package/dist/scripts/bulk-link-fix.d.ts.map +1 -0
  103. package/dist/scripts/bulk-link-fix.js +106 -0
  104. package/dist/scripts/bulk-link-fix.js.map +1 -0
  105. package/dist/session-tools.d.ts +33 -0
  106. package/dist/session-tools.d.ts.map +1 -0
  107. package/dist/session-tools.js +211 -0
  108. package/dist/session-tools.js.map +1 -0
  109. package/dist/state.d.ts +54 -0
  110. package/dist/state.d.ts.map +1 -0
  111. package/dist/state.js +176 -0
  112. package/dist/state.js.map +1 -0
  113. package/dist/store.d.ts +56 -0
  114. package/dist/store.d.ts.map +1 -0
  115. package/dist/store.js +227 -0
  116. package/dist/store.js.map +1 -0
  117. package/dist/summarize.d.ts +56 -0
  118. package/dist/summarize.d.ts.map +1 -0
  119. package/dist/summarize.js +231 -0
  120. package/dist/summarize.js.map +1 -0
  121. package/dist/tag-registry.d.ts +56 -0
  122. package/dist/tag-registry.d.ts.map +1 -0
  123. package/dist/tag-registry.js +146 -0
  124. package/dist/tag-registry.js.map +1 -0
  125. package/dist/templates/prompts.d.ts +63 -0
  126. package/dist/templates/prompts.d.ts.map +1 -0
  127. package/dist/templates/prompts.js +260 -0
  128. package/dist/templates/prompts.js.map +1 -0
  129. package/dist/tools.d.ts +26 -0
  130. package/dist/tools.d.ts.map +1 -0
  131. package/dist/tools.js +1033 -0
  132. package/dist/tools.js.map +1 -0
  133. package/dist/watcher.d.ts +25 -0
  134. package/dist/watcher.d.ts.map +1 -0
  135. package/dist/watcher.js +84 -0
  136. package/dist/watcher.js.map +1 -0
  137. package/dist/webui/client/dist/index.html +1885 -0
  138. package/dist/webui/server.d.ts +31 -0
  139. package/dist/webui/server.d.ts.map +1 -0
  140. package/dist/webui/server.js +566 -0
  141. package/dist/webui/server.js.map +1 -0
  142. package/dist/wiki.d.ts +103 -0
  143. package/dist/wiki.d.ts.map +1 -0
  144. package/dist/wiki.js +428 -0
  145. package/dist/wiki.js.map +1 -0
  146. package/package.json +142 -0
  147. package/scripts/gepa/__pycache__/dataset.cpython-313.pyc +0 -0
  148. package/scripts/gepa/__pycache__/lm_providers.cpython-313.pyc +0 -0
  149. package/scripts/gepa/__pycache__/metric.cpython-313.pyc +0 -0
  150. package/scripts/gepa/__pycache__/program.cpython-313.pyc +0 -0
  151. package/scripts/gepa/__pycache__/wiki_reader.cpython-313.pyc +0 -0
  152. package/scripts/gepa/dataset.py +192 -0
  153. package/scripts/gepa/lm_providers.py +472 -0
  154. package/scripts/gepa/metric.py +279 -0
  155. package/scripts/gepa/optimize.py +367 -0
  156. package/scripts/gepa/program.py +99 -0
  157. package/scripts/gepa/pyproject.toml +19 -0
  158. package/scripts/gepa/run-all.sh +53 -0
  159. package/scripts/gepa/uv.lock +2241 -0
  160. package/scripts/gepa/wiki_reader.py +113 -0
  161. package/skills/para/SKILL.md +77 -0
  162. package/skills/setup/SKILL.md +20 -0
  163. package/src/capture.ts +563 -0
  164. package/src/cli.ts +416 -0
  165. package/src/commands.ts +878 -0
  166. package/src/context.ts +390 -0
  167. package/src/daemon.ts +288 -0
  168. package/src/frontmatter.ts +219 -0
  169. package/src/gepa/index.ts +287 -0
  170. package/src/gepa/optimized/capture-prompt.txt +65 -0
  171. package/src/index.ts +384 -0
  172. package/src/ingest.ts +177 -0
  173. package/src/link-discovery.ts +170 -0
  174. package/src/link-utils.ts +169 -0
  175. package/src/lint.ts +1018 -0
  176. package/src/maintainer.ts +404 -0
  177. package/src/processor.ts +415 -0
  178. package/src/python/__pycache__/minimax_lm.cpython-312.pyc +0 -0
  179. package/src/python/minimax_lm.py +198 -0
  180. package/src/python/rlm_capture.py +215 -0
  181. package/src/query.ts +148 -0
  182. package/src/raw.ts +276 -0
  183. package/src/redact.ts +159 -0
  184. package/src/scope.ts +214 -0
  185. package/src/scripts/bulk-link-fix.ts +126 -0
  186. package/src/session-tools.ts +260 -0
  187. package/src/state.ts +271 -0
  188. package/src/store.ts +288 -0
  189. package/src/summarize.ts +273 -0
  190. package/src/tag-registry.ts +157 -0
  191. package/src/templates/index.md +17 -0
  192. package/src/templates/prompts.ts +274 -0
  193. package/src/templates/schema.md +116 -0
  194. package/src/tools.ts +1293 -0
  195. package/src/watcher.ts +101 -0
  196. package/src/webui/client/dist/index.html +1885 -0
  197. package/src/webui/server.ts +765 -0
  198. package/src/wiki.ts +550 -0
package/dist/raw.js ADDED
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Raw source vault and session digests.
3
+ *
4
+ * Manages immutable source material in ~/.pi/wiki/raw/ and
5
+ * session digest entries in sessions.md.
6
+ */
7
+ import { readFile, writeFile, mkdir, access } from "node:fs/promises";
8
+ import { join, basename, extname } from "node:path";
9
+ // -- Helpers -----------------------------------------------------------------
10
+ const RAW_SUBDIRS = {
11
+ url: "articles",
12
+ file: "docs",
13
+ text: "notes",
14
+ };
15
+ /**
16
+ * Slugify a string for use as a filename. Lowercase, hyphens, no special
17
+ * characters. Collapses multiple hyphens. Trims leading/trailing hyphens.
18
+ */
19
+ function slugify(input) {
20
+ return input
21
+ .toLowerCase()
22
+ .replace(/[^a-z0-9]+/g, "-")
23
+ .replace(/-+/g, "-")
24
+ .replace(/^-|-$/g, "");
25
+ }
26
+ /**
27
+ * Derive a filename slug from the original path based on source type.
28
+ *
29
+ * - URL: extract domain + path components
30
+ * - file: use the filename without extension
31
+ * - text: use a timestamp-based name
32
+ */
33
+ function deriveSlug(type, originalPath) {
34
+ if (type === "url") {
35
+ try {
36
+ const url = new URL(originalPath);
37
+ const host = url.hostname.replace(/^www\./, "");
38
+ const pathParts = url.pathname
39
+ .split("/")
40
+ .filter((p) => p.length > 0)
41
+ .slice(0, 3);
42
+ const raw = [host, ...pathParts].join("-");
43
+ return slugify(raw) || "untitled";
44
+ }
45
+ catch {
46
+ return slugify(originalPath) || "untitled";
47
+ }
48
+ }
49
+ if (type === "file") {
50
+ const name = basename(originalPath, extname(originalPath));
51
+ return slugify(name) || "untitled";
52
+ }
53
+ // text: timestamp-based
54
+ const ts = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
55
+ return `note-${ts}`;
56
+ }
57
+ async function fileExists(path) {
58
+ try {
59
+ await access(path);
60
+ return true;
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ /**
67
+ * Ensure a unique filename by appending -2, -3, etc. if the slug already exists.
68
+ */
69
+ async function uniquePath(dir, slug, ext) {
70
+ let candidate = join(dir, `${slug}${ext}`);
71
+ if (!(await fileExists(candidate)))
72
+ return candidate;
73
+ let i = 2;
74
+ while (await fileExists(join(dir, `${slug}-${i}${ext}`))) {
75
+ i++;
76
+ }
77
+ return join(dir, `${slug}-${i}${ext}`);
78
+ }
79
+ // -- Functions ---------------------------------------------------------------
80
+ /**
81
+ * Save a raw source to the vault. URL sources go to raw/articles/,
82
+ * file sources to raw/docs/, text sources to raw/notes/.
83
+ *
84
+ * The file is saved as markdown with a metadata header.
85
+ * Returns the path relative to wikiDir (e.g. "raw/articles/example-com-page.md").
86
+ */
87
+ export async function saveRawSource(wikiDir, source) {
88
+ const subdir = RAW_SUBDIRS[source.type];
89
+ const dir = join(wikiDir, "raw", subdir);
90
+ await mkdir(dir, { recursive: true });
91
+ const slug = deriveSlug(source.type, source.originalPath);
92
+ const filePath = await uniquePath(dir, slug, ".md");
93
+ const fileName = basename(filePath);
94
+ const header = [
95
+ "---",
96
+ `source_type: ${source.type}`,
97
+ `original_path: "${source.originalPath}"`,
98
+ `ingested_at: "${new Date().toISOString()}"`,
99
+ "---",
100
+ "",
101
+ ].join("\n");
102
+ await writeFile(filePath, header + source.content, "utf-8");
103
+ return `raw/${subdir}/${fileName}`;
104
+ }
105
+ /**
106
+ * Append a session digest entry to sessions.md in the documented format:
107
+ *
108
+ * ```
109
+ * ## [2026-04-27] pi-mono | SSL certificate debugging
110
+ * - **Session**: `~/.pi/agent/sessions/.../file.jsonl`
111
+ * - **Scope**: pi-mono
112
+ * - **Captured**: [[ssl-cert-gotchas]]
113
+ * - **Summary**: One-paragraph summary...
114
+ * ```
115
+ *
116
+ * Creates sessions.md if it does not exist.
117
+ */
118
+ export async function appendSessionDigest(wikiDir, digest) {
119
+ const sessionsPath = join(wikiDir, "sessions.md");
120
+ let existing;
121
+ try {
122
+ existing = await readFile(sessionsPath, "utf-8");
123
+ }
124
+ catch (err) {
125
+ if (err.code === "ENOENT") {
126
+ existing = "# Session Digests\n";
127
+ }
128
+ else {
129
+ throw err;
130
+ }
131
+ }
132
+ const captured = digest.capturedPages.map((p) => `[[${p}]]`).join(", ");
133
+ const heading = digest.summary.split(/[.!?\n]/)[0].trim() || "Session capture";
134
+ const entry = [
135
+ "",
136
+ `## [${digest.date}] ${digest.project} | ${heading}`,
137
+ `- **Session**: \`${digest.sessionFile}\``,
138
+ `- **Scope**: ${digest.scope}`,
139
+ `- **Captured**: ${captured || "none"}`,
140
+ `- **Summary**: ${digest.summary}`,
141
+ "",
142
+ ].join("\n");
143
+ await writeFile(sessionsPath, existing + entry, "utf-8");
144
+ }
145
+ /**
146
+ * Parse sessions.md and return session digest entries.
147
+ * Optionally filter by scope and/or limit the number of results.
148
+ * Results are returned in file order (oldest first).
149
+ */
150
+ export async function readSessionDigests(wikiDir, options) {
151
+ const sessionsPath = join(wikiDir, "sessions.md");
152
+ let content;
153
+ try {
154
+ content = await readFile(sessionsPath, "utf-8");
155
+ }
156
+ catch (err) {
157
+ if (err.code === "ENOENT") {
158
+ return [];
159
+ }
160
+ throw err;
161
+ }
162
+ const digests = [];
163
+ // Split on ## headings (session entries)
164
+ const entryPattern = /^## \[([^\]]+)\] ([^|]+)\| (.+)$/gm;
165
+ let match;
166
+ while ((match = entryPattern.exec(content)) !== null) {
167
+ const date = match[1].trim();
168
+ const project = match[2].trim();
169
+ // Extract the block after this heading until the next heading or end
170
+ const startIdx = match.index + match[0].length;
171
+ const nextHeading = content.indexOf("\n## ", startIdx);
172
+ const block = nextHeading === -1
173
+ ? content.slice(startIdx)
174
+ : content.slice(startIdx, nextHeading);
175
+ const sessionFile = extractField(block, "Session");
176
+ const scope = extractField(block, "Scope");
177
+ const capturedRaw = extractField(block, "Captured");
178
+ const summary = extractField(block, "Summary");
179
+ // Parse captured wikilinks: [[slug1]], [[slug2]]
180
+ const capturedPages = [];
181
+ const linkPattern = /\[\[([^\]]+)\]\]/g;
182
+ let linkMatch;
183
+ while ((linkMatch = linkPattern.exec(capturedRaw)) !== null) {
184
+ capturedPages.push(linkMatch[1]);
185
+ }
186
+ digests.push({
187
+ date,
188
+ project,
189
+ sessionFile,
190
+ scope,
191
+ capturedPages,
192
+ summary,
193
+ });
194
+ }
195
+ // Apply scope filter
196
+ let filtered = digests;
197
+ if (options?.scope) {
198
+ const scopeFilter = options.scope;
199
+ filtered = filtered.filter((d) => d.scope === scopeFilter);
200
+ }
201
+ // Apply limit (return the last N entries — most recent)
202
+ if (options?.limit !== undefined && options.limit < filtered.length) {
203
+ filtered = filtered.slice(filtered.length - options.limit);
204
+ }
205
+ return filtered;
206
+ }
207
+ /**
208
+ * Extract a field value from a session digest block.
209
+ * Matches lines like: `- **Field**: value` or `- **Field**: \`value\``
210
+ */
211
+ function extractField(block, field) {
212
+ const pattern = new RegExp(`^- \\*\\*${field}\\*\\*:\\s*(.+)$`, "m");
213
+ const match = pattern.exec(block);
214
+ if (!match)
215
+ return "";
216
+ // Strip backticks wrapping the value
217
+ return match[1].trim().replace(/^`|`$/g, "");
218
+ }
219
+ //# sourceMappingURL=raw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"raw.js","sourceRoot":"","sources":["../src/raw.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpD,+EAA+E;AAE/E,MAAM,WAAW,GAA4C;IAC3D,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,OAAO;CACd,CAAC;AAEF;;;GAGG;AACH,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,IAA6B,EAAE,YAAoB;IACrE,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;YAClC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ;iBAC3B,KAAK,CAAC,GAAG,CAAC;iBACV,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;iBAC3B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACf,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,OAAO,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;QAC3D,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC;IACrC,CAAC;IAED,wBAAwB;IACxB,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,QAAQ,EAAE,EAAE,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,IAAY,EAAE,GAAW;IAC9D,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAErD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;QACzD,CAAC,EAAE,CAAC;IACN,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;AACzC,CAAC;AAED,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,MAIC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,MAAM,GAAG;QACb,KAAK;QACL,gBAAgB,MAAM,CAAC,IAAI,EAAE;QAC7B,mBAAmB,MAAM,CAAC,YAAY,GAAG;QACzC,iBAAiB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,GAAG;QAC5C,KAAK;QACL,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAE5D,OAAO,OAAO,MAAM,IAAI,QAAQ,EAAE,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAAe,EACf,MAAqB;IAErB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAElD,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,QAAQ,GAAG,qBAAqB,CAAC;QACnC,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,iBAAiB,CAAC;IAE/E,MAAM,KAAK,GAAG;QACZ,EAAE;QACF,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,MAAM,OAAO,EAAE;QACpD,oBAAoB,MAAM,CAAC,WAAW,IAAI;QAC1C,gBAAgB,MAAM,CAAC,KAAK,EAAE;QAC9B,mBAAmB,QAAQ,IAAI,MAAM,EAAE;QACvC,kBAAkB,MAAM,CAAC,OAAO,EAAE;QAClC,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,SAAS,CAAC,YAAY,EAAE,QAAQ,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,OAA4C;IAE5C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAElD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,yCAAyC;IACzC,MAAM,YAAY,GAAG,oCAAoC,CAAC;IAC1D,IAAI,KAA6B,CAAC;IAElC,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,qEAAqE;QACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,WAAW,KAAK,CAAC,CAAC;YAC9B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC;YACzB,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAEzC,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QAE/C,iDAAiD;QACjD,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,mBAAmB,CAAC;QACxC,IAAI,SAAiC,CAAC;QACtC,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5D,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,OAAO;YACP,WAAW;YACX,KAAK;YACL,aAAa;YACb,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,qBAAqB;IACrB,IAAI,QAAQ,GAAG,OAAO,CAAC;IACvB,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;QACnB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC;QAClC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC;IAC7D,CAAC;IAED,wDAAwD;IACxD,IAAI,OAAO,EAAE,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpE,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,KAAa,EAAE,KAAa;IAChD,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,YAAY,KAAK,kBAAkB,EAAE,GAAG,CAAC,CAAC;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,qCAAqC;IACrC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Secret redaction — strips API keys, tokens, passwords, and other
3
+ * sensitive values from wiki page content before writing.
4
+ *
5
+ * Runs automatically on every wiki_write to prevent secrets from
6
+ * being persisted in the knowledge base.
7
+ */
8
+ /**
9
+ * Redact secrets from text content.
10
+ * Returns the redacted text and count of redactions made.
11
+ */
12
+ export declare function redactSecrets(text: string): {
13
+ text: string;
14
+ redactions: number;
15
+ };
16
+ /**
17
+ * Check if text contains any detectable secrets.
18
+ * Faster than redactSecrets() — stops at first match.
19
+ */
20
+ export declare function containsSecrets(text: string): boolean;
21
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuHH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAiBhF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMrD"}
package/dist/redact.js ADDED
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Secret redaction — strips API keys, tokens, passwords, and other
3
+ * sensitive values from wiki page content before writing.
4
+ *
5
+ * Runs automatically on every wiki_write to prevent secrets from
6
+ * being persisted in the knowledge base.
7
+ */
8
+ /**
9
+ * Secret detection patterns — ordered from most specific to most general.
10
+ *
11
+ * Each pattern matches a specific type of secret. The replacement preserves
12
+ * the key type for documentation purposes while removing the actual value.
13
+ */
14
+ const SECRET_PATTERNS = [
15
+ // --- Provider-specific API key formats ---
16
+ {
17
+ name: "OpenRouter API key",
18
+ pattern: /sk-or-v1-[a-f0-9]{64}/g,
19
+ replacement: "<REDACTED:openrouter-key>",
20
+ },
21
+ {
22
+ name: "OpenAI API key",
23
+ pattern: /sk-[a-zA-Z0-9]{48,}/g,
24
+ replacement: "<REDACTED:openai-key>",
25
+ },
26
+ {
27
+ name: "Anthropic API key",
28
+ pattern: /sk-ant-[a-zA-Z0-9_-]{40,}/g,
29
+ replacement: "<REDACTED:anthropic-key>",
30
+ },
31
+ {
32
+ name: "MiniMax API key",
33
+ pattern: /sk-cp-[a-zA-Z0-9_-]{40,}/g,
34
+ replacement: "<REDACTED:minimax-key>",
35
+ },
36
+ {
37
+ name: "GitHub PAT (fine-grained)",
38
+ pattern: /github_pat_[a-zA-Z0-9_]{60,}/g,
39
+ replacement: "<REDACTED:github-pat>",
40
+ },
41
+ {
42
+ name: "GitHub PAT (classic)",
43
+ pattern: /ghp_[a-zA-Z0-9]{36,}/g,
44
+ replacement: "<REDACTED:github-pat>",
45
+ },
46
+ {
47
+ name: "GitHub OAuth token",
48
+ pattern: /gho_[a-zA-Z0-9]{36,}/g,
49
+ replacement: "<REDACTED:github-oauth>",
50
+ },
51
+ {
52
+ name: "AWS Access Key ID",
53
+ pattern: /AKIA[0-9A-Z]{16}/g,
54
+ replacement: "<REDACTED:aws-key-id>",
55
+ },
56
+ {
57
+ name: "AWS Secret Access Key",
58
+ pattern: /(?<=aws_secret_access_key\s*[=:]\s*)[A-Za-z0-9/+=]{40}/g,
59
+ replacement: "<REDACTED:aws-secret>",
60
+ },
61
+ {
62
+ name: "Jina API key",
63
+ pattern: /jina_[a-zA-Z0-9_-]{30,}/g,
64
+ replacement: "<REDACTED:jina-key>",
65
+ },
66
+ {
67
+ name: "Bearer token",
68
+ pattern: /Bearer [a-zA-Z0-9._-]{30,}/g,
69
+ replacement: "Bearer <REDACTED>",
70
+ },
71
+ // --- Generic key/value patterns in YAML/config context ---
72
+ // Match: key: <long-alphanumeric-value> (in YAML blocks)
73
+ {
74
+ name: "YAML key value",
75
+ pattern: /(?<=^\s*key:\s*)[a-zA-Z0-9_-]{32,}/gm,
76
+ replacement: "<REDACTED>",
77
+ },
78
+ // Match: token: <long-alphanumeric-value>
79
+ {
80
+ name: "YAML token value",
81
+ pattern: /(?<=^\s*token:\s*)[a-zA-Z0-9_-]{32,}/gm,
82
+ replacement: "<REDACTED>",
83
+ },
84
+ // Match: secret: <long-alphanumeric-value>
85
+ {
86
+ name: "YAML secret value",
87
+ pattern: /(?<=^\s*secret:\s*)[a-zA-Z0-9_-]{32,}/gm,
88
+ replacement: "<REDACTED>",
89
+ },
90
+ // Match: password: <value> (any length, in YAML)
91
+ {
92
+ name: "YAML password value",
93
+ pattern: /(?<=^\s*password:\s*)\S+/gm,
94
+ replacement: "<REDACTED>",
95
+ },
96
+ // Match: api_key: / apiKey: <long-alphanumeric-value>
97
+ {
98
+ name: "YAML api_key value",
99
+ pattern: /(?<=^\s*(?:api_key|apiKey|api-key):\s*)[a-zA-Z0-9_-]{20,}/gm,
100
+ replacement: "<REDACTED>",
101
+ },
102
+ // --- Environment variable patterns ---
103
+ // Match: export SECRET_NAME=value or SECRET_NAME="value"
104
+ {
105
+ name: "Env var secret",
106
+ pattern: /(?<=(?:export\s+)?(?:API_KEY|SECRET|TOKEN|PASSWORD|PRIVATE_KEY|ACCESS_KEY)[A-Z_]*\s*=\s*["']?)[^\s"']{16,}/g,
107
+ replacement: "<REDACTED>",
108
+ },
109
+ ];
110
+ // -- Public API --------------------------------------------------------------
111
+ /**
112
+ * Redact secrets from text content.
113
+ * Returns the redacted text and count of redactions made.
114
+ */
115
+ export function redactSecrets(text) {
116
+ let result = text;
117
+ let redactions = 0;
118
+ for (const { pattern, replacement } of SECRET_PATTERNS) {
119
+ // Reset regex state for global patterns
120
+ const re = new RegExp(pattern.source, pattern.flags);
121
+ const before = result;
122
+ result = result.replace(re, replacement);
123
+ if (result !== before) {
124
+ // Count how many replacements were made
125
+ const matches = before.match(new RegExp(pattern.source, pattern.flags));
126
+ redactions += matches?.length ?? 1;
127
+ }
128
+ }
129
+ return { text: result, redactions };
130
+ }
131
+ /**
132
+ * Check if text contains any detectable secrets.
133
+ * Faster than redactSecrets() — stops at first match.
134
+ */
135
+ export function containsSecrets(text) {
136
+ for (const { pattern } of SECRET_PATTERNS) {
137
+ const re = new RegExp(pattern.source, pattern.flags);
138
+ if (re.test(text))
139
+ return true;
140
+ }
141
+ return false;
142
+ }
143
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Project scope detection and filtering.
3
+ *
4
+ * Determines which wiki pages are relevant to the current working context
5
+ * by auto-detecting project name from cwd (git remote, git root, dirname)
6
+ * or reading explicit config from .pi/wiki-scope.json.
7
+ */
8
+ export interface ProjectScope {
9
+ name: string;
10
+ include: string[];
11
+ exclude: string[];
12
+ source: "config" | "git-remote" | "git-root" | "dirname";
13
+ }
14
+ /** .pi/wiki-scope.json schema */
15
+ export interface ScopeConfig {
16
+ name: string;
17
+ include?: string[];
18
+ exclude?: string[];
19
+ }
20
+ /**
21
+ * Extract a repo name from a git remote URL.
22
+ *
23
+ * Handles:
24
+ * git@github.com:user/repo.git -> repo
25
+ * https://github.com/user/repo.git -> repo
26
+ * https://github.com/user/repo -> repo
27
+ * ssh://git@host/user/repo.git -> repo
28
+ */
29
+ export declare function extractRepoName(remoteUrl: string): string | null;
30
+ /**
31
+ * Load .pi/wiki-scope.json from the given directory.
32
+ * Returns null if the file doesn't exist or is invalid JSON.
33
+ */
34
+ export declare function loadScopeConfig(cwd: string): Promise<ScopeConfig | null>;
35
+ /**
36
+ * Auto-detect project scope from the working directory.
37
+ *
38
+ * Detection priority:
39
+ * 1. .pi/wiki-scope.json (explicit config)
40
+ * 2. Git remote origin URL -> repo name
41
+ * 3. Git repository root directory name
42
+ * 4. cwd basename (fallback)
43
+ */
44
+ export declare function detectScope(cwd: string): Promise<ProjectScope>;
45
+ /**
46
+ * Check whether a page's scope tags match the project scope.
47
+ *
48
+ * Rules:
49
+ * - A page matches if its scope contains "global" OR any tag in projectScope.include
50
+ * - A page is excluded if its scope contains any tag in projectScope.exclude
51
+ * - Exclude takes priority over include
52
+ */
53
+ export declare function matchesScope(pageScope: string[], projectScope: ProjectScope): boolean;
54
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;CAC1D;AAED,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYhE;AAID;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAwC7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAuDpE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EAAE,EACnB,YAAY,EAAE,YAAY,GACzB,OAAO,CAeT"}
package/dist/scope.js ADDED
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Project scope detection and filtering.
3
+ *
4
+ * Determines which wiki pages are relevant to the current working context
5
+ * by auto-detecting project name from cwd (git remote, git root, dirname)
6
+ * or reading explicit config from .pi/wiki-scope.json.
7
+ */
8
+ import { execFile } from "node:child_process";
9
+ import { readFile } from "node:fs/promises";
10
+ import { basename, join } from "node:path";
11
+ // -- Helpers ----------------------------------------------------------------
12
+ /** Run a command and return trimmed stdout, or null on failure. */
13
+ function exec(cmd, args, cwd) {
14
+ return new Promise((resolve) => {
15
+ execFile(cmd, args, { cwd }, (err, stdout) => {
16
+ if (err) {
17
+ resolve(null);
18
+ return;
19
+ }
20
+ const trimmed = (stdout ?? "").trim();
21
+ resolve(trimmed || null);
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Extract a repo name from a git remote URL.
27
+ *
28
+ * Handles:
29
+ * git@github.com:user/repo.git -> repo
30
+ * https://github.com/user/repo.git -> repo
31
+ * https://github.com/user/repo -> repo
32
+ * ssh://git@host/user/repo.git -> repo
33
+ */
34
+ export function extractRepoName(remoteUrl) {
35
+ // Strip trailing slashes
36
+ let url = remoteUrl.trim().replace(/\/+$/, "");
37
+ // Strip .git suffix
38
+ url = url.replace(/\.git$/, "");
39
+ // Get the last path segment
40
+ const lastSlash = url.lastIndexOf("/");
41
+ const lastColon = url.lastIndexOf(":");
42
+ const sep = Math.max(lastSlash, lastColon);
43
+ if (sep < 0 || sep === url.length - 1)
44
+ return null;
45
+ const name = url.slice(sep + 1);
46
+ return name || null;
47
+ }
48
+ // -- Public API -------------------------------------------------------------
49
+ /**
50
+ * Load .pi/wiki-scope.json from the given directory.
51
+ * Returns null if the file doesn't exist or is invalid JSON.
52
+ */
53
+ export async function loadScopeConfig(cwd) {
54
+ const configPath = join(cwd, ".pi", "wiki-scope.json");
55
+ let raw;
56
+ try {
57
+ raw = await readFile(configPath, "utf-8");
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ let parsed;
63
+ try {
64
+ parsed = JSON.parse(raw);
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ if (typeof parsed !== "object" ||
70
+ parsed === null ||
71
+ typeof parsed.name !== "string" ||
72
+ !parsed.name) {
73
+ return null;
74
+ }
75
+ const obj = parsed;
76
+ const config = { name: obj.name };
77
+ if (Array.isArray(obj.include)) {
78
+ config.include = obj.include.filter((v) => typeof v === "string");
79
+ }
80
+ if (Array.isArray(obj.exclude)) {
81
+ config.exclude = obj.exclude.filter((v) => typeof v === "string");
82
+ }
83
+ return config;
84
+ }
85
+ /**
86
+ * Auto-detect project scope from the working directory.
87
+ *
88
+ * Detection priority:
89
+ * 1. .pi/wiki-scope.json (explicit config)
90
+ * 2. Git remote origin URL -> repo name
91
+ * 3. Git repository root directory name
92
+ * 4. cwd basename (fallback)
93
+ */
94
+ export async function detectScope(cwd) {
95
+ // 1. Explicit config
96
+ const config = await loadScopeConfig(cwd);
97
+ if (config) {
98
+ const include = Array.from(new Set([config.name, ...(config.include ?? [])]));
99
+ return {
100
+ name: config.name,
101
+ include,
102
+ exclude: config.exclude ?? [],
103
+ source: "config",
104
+ };
105
+ }
106
+ // 2. Git remote origin
107
+ const remoteUrl = await exec("git", ["remote", "get-url", "origin"], cwd);
108
+ if (remoteUrl) {
109
+ const repoName = extractRepoName(remoteUrl);
110
+ if (repoName) {
111
+ return {
112
+ name: repoName,
113
+ include: [repoName],
114
+ exclude: [],
115
+ source: "git-remote",
116
+ };
117
+ }
118
+ }
119
+ // 3. Git root directory name
120
+ const gitRoot = await exec("git", ["rev-parse", "--show-toplevel"], cwd);
121
+ if (gitRoot) {
122
+ const name = basename(gitRoot);
123
+ if (name) {
124
+ return {
125
+ name,
126
+ include: [name],
127
+ exclude: [],
128
+ source: "git-root",
129
+ };
130
+ }
131
+ }
132
+ // 4. Fallback to cwd basename
133
+ const name = basename(cwd);
134
+ return {
135
+ name,
136
+ include: [name],
137
+ exclude: [],
138
+ source: "dirname",
139
+ };
140
+ }
141
+ /**
142
+ * Check whether a page's scope tags match the project scope.
143
+ *
144
+ * Rules:
145
+ * - A page matches if its scope contains "global" OR any tag in projectScope.include
146
+ * - A page is excluded if its scope contains any tag in projectScope.exclude
147
+ * - Exclude takes priority over include
148
+ */
149
+ export function matchesScope(pageScope, projectScope) {
150
+ // Exclude takes priority
151
+ if (projectScope.exclude.length > 0 &&
152
+ pageScope.some((tag) => projectScope.exclude.includes(tag))) {
153
+ return false;
154
+ }
155
+ // Match: "global" or any include tag
156
+ if (pageScope.includes("global")) {
157
+ return true;
158
+ }
159
+ return pageScope.some((tag) => projectScope.include.includes(tag));
160
+ }
161
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * One-time bulk fix: auto-link slugs, normalize tags, sync frontmatter.links
4
+ * across all wiki pages.
5
+ *
6
+ * Usage: npx tsx src/scripts/bulk-link-fix.ts [--dry-run]
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=bulk-link-fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bulk-link-fix.d.ts","sourceRoot":"","sources":["../../src/scripts/bulk-link-fix.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}