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.
- package/CHANGELOG.md +214 -0
- package/README.md +305 -0
- package/SETUP.md +171 -0
- package/dist/capture.d.ts +34 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +461 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +405 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +15 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +786 -0
- package/dist/commands.js.map +1 -0
- package/dist/context.d.ts +61 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +289 -0
- package/dist/context.js.map +1 -0
- package/dist/daemon.d.ts +49 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +226 -0
- package/dist/daemon.js.map +1 -0
- package/dist/frontmatter.d.ts +59 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +170 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/gepa/dataset.d.ts +36 -0
- package/dist/gepa/dataset.d.ts.map +1 -0
- package/dist/gepa/dataset.js +148 -0
- package/dist/gepa/dataset.js.map +1 -0
- package/dist/gepa/evaluator.d.ts +51 -0
- package/dist/gepa/evaluator.d.ts.map +1 -0
- package/dist/gepa/evaluator.js +317 -0
- package/dist/gepa/evaluator.js.map +1 -0
- package/dist/gepa/index.d.ts +66 -0
- package/dist/gepa/index.d.ts.map +1 -0
- package/dist/gepa/index.js +240 -0
- package/dist/gepa/index.js.map +1 -0
- package/dist/gepa/llm.d.ts +35 -0
- package/dist/gepa/llm.d.ts.map +1 -0
- package/dist/gepa/llm.js +268 -0
- package/dist/gepa/llm.js.map +1 -0
- package/dist/gepa/optimized/capture-prompt.txt +65 -0
- package/dist/gepa/optimizer.d.ts +29 -0
- package/dist/gepa/optimizer.d.ts.map +1 -0
- package/dist/gepa/optimizer.js +249 -0
- package/dist/gepa/optimizer.js.map +1 -0
- package/dist/gepa/targets.d.ts +39 -0
- package/dist/gepa/targets.d.ts.map +1 -0
- package/dist/gepa/targets.js +326 -0
- package/dist/gepa/targets.js.map +1 -0
- package/dist/gepa/types.d.ts +168 -0
- package/dist/gepa/types.d.ts.map +1 -0
- package/dist/gepa/types.js +124 -0
- package/dist/gepa/types.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +294 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +88 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +105 -0
- package/dist/ingest.js.map +1 -0
- package/dist/link-discovery.d.ts +40 -0
- package/dist/link-discovery.d.ts.map +1 -0
- package/dist/link-discovery.js +122 -0
- package/dist/link-discovery.js.map +1 -0
- package/dist/link-utils.d.ts +30 -0
- package/dist/link-utils.d.ts.map +1 -0
- package/dist/link-utils.js +145 -0
- package/dist/link-utils.js.map +1 -0
- package/dist/lint.d.ts +39 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +827 -0
- package/dist/lint.js.map +1 -0
- package/dist/maintainer.d.ts +24 -0
- package/dist/maintainer.d.ts.map +1 -0
- package/dist/maintainer.js +358 -0
- package/dist/maintainer.js.map +1 -0
- package/dist/processor.d.ts +14 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +361 -0
- package/dist/processor.js.map +1 -0
- package/dist/query.d.ts +69 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +107 -0
- package/dist/query.js.map +1 -0
- package/dist/raw.d.ts +57 -0
- package/dist/raw.d.ts.map +1 -0
- package/dist/raw.js +219 -0
- package/dist/raw.js.map +1 -0
- package/dist/redact.d.ts +21 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +143 -0
- package/dist/redact.js.map +1 -0
- package/dist/scope.d.ts +54 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +161 -0
- package/dist/scope.js.map +1 -0
- package/dist/scripts/bulk-link-fix.d.ts +9 -0
- package/dist/scripts/bulk-link-fix.d.ts.map +1 -0
- package/dist/scripts/bulk-link-fix.js +106 -0
- package/dist/scripts/bulk-link-fix.js.map +1 -0
- package/dist/session-tools.d.ts +33 -0
- package/dist/session-tools.d.ts.map +1 -0
- package/dist/session-tools.js +211 -0
- package/dist/session-tools.js.map +1 -0
- package/dist/state.d.ts +54 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +176 -0
- package/dist/state.js.map +1 -0
- package/dist/store.d.ts +56 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +227 -0
- package/dist/store.js.map +1 -0
- package/dist/summarize.d.ts +56 -0
- package/dist/summarize.d.ts.map +1 -0
- package/dist/summarize.js +231 -0
- package/dist/summarize.js.map +1 -0
- package/dist/tag-registry.d.ts +56 -0
- package/dist/tag-registry.d.ts.map +1 -0
- package/dist/tag-registry.js +146 -0
- package/dist/tag-registry.js.map +1 -0
- package/dist/templates/prompts.d.ts +63 -0
- package/dist/templates/prompts.d.ts.map +1 -0
- package/dist/templates/prompts.js +260 -0
- package/dist/templates/prompts.js.map +1 -0
- package/dist/tools.d.ts +26 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +1033 -0
- package/dist/tools.js.map +1 -0
- package/dist/watcher.d.ts +25 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +84 -0
- package/dist/watcher.js.map +1 -0
- package/dist/webui/client/dist/index.html +1885 -0
- package/dist/webui/server.d.ts +31 -0
- package/dist/webui/server.d.ts.map +1 -0
- package/dist/webui/server.js +566 -0
- package/dist/webui/server.js.map +1 -0
- package/dist/wiki.d.ts +103 -0
- package/dist/wiki.d.ts.map +1 -0
- package/dist/wiki.js +428 -0
- package/dist/wiki.js.map +1 -0
- package/package.json +142 -0
- package/scripts/gepa/__pycache__/dataset.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/lm_providers.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/metric.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/program.cpython-313.pyc +0 -0
- package/scripts/gepa/__pycache__/wiki_reader.cpython-313.pyc +0 -0
- package/scripts/gepa/dataset.py +192 -0
- package/scripts/gepa/lm_providers.py +472 -0
- package/scripts/gepa/metric.py +279 -0
- package/scripts/gepa/optimize.py +367 -0
- package/scripts/gepa/program.py +99 -0
- package/scripts/gepa/pyproject.toml +19 -0
- package/scripts/gepa/run-all.sh +53 -0
- package/scripts/gepa/uv.lock +2241 -0
- package/scripts/gepa/wiki_reader.py +113 -0
- package/skills/para/SKILL.md +77 -0
- package/skills/setup/SKILL.md +20 -0
- package/src/capture.ts +563 -0
- package/src/cli.ts +416 -0
- package/src/commands.ts +878 -0
- package/src/context.ts +390 -0
- package/src/daemon.ts +288 -0
- package/src/frontmatter.ts +219 -0
- package/src/gepa/index.ts +287 -0
- package/src/gepa/optimized/capture-prompt.txt +65 -0
- package/src/index.ts +384 -0
- package/src/ingest.ts +177 -0
- package/src/link-discovery.ts +170 -0
- package/src/link-utils.ts +169 -0
- package/src/lint.ts +1018 -0
- package/src/maintainer.ts +404 -0
- package/src/processor.ts +415 -0
- package/src/python/__pycache__/minimax_lm.cpython-312.pyc +0 -0
- package/src/python/minimax_lm.py +198 -0
- package/src/python/rlm_capture.py +215 -0
- package/src/query.ts +148 -0
- package/src/raw.ts +276 -0
- package/src/redact.ts +159 -0
- package/src/scope.ts +214 -0
- package/src/scripts/bulk-link-fix.ts +126 -0
- package/src/session-tools.ts +260 -0
- package/src/state.ts +271 -0
- package/src/store.ts +288 -0
- package/src/summarize.ts +273 -0
- package/src/tag-registry.ts +157 -0
- package/src/templates/index.md +17 -0
- package/src/templates/prompts.ts +274 -0
- package/src/templates/schema.md +116 -0
- package/src/tools.ts +1293 -0
- package/src/watcher.ts +101 -0
- package/src/webui/client/dist/index.html +1885 -0
- package/src/webui/server.ts +765 -0
- 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
|
package/dist/raw.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw.js","sourceRoot":"","sources":["../src/raw.ts"],"names":[],"mappings":"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"}
|
package/dist/redact.d.ts
ADDED
|
@@ -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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"}
|
package/dist/scope.d.ts
ADDED
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"bulk-link-fix.d.ts","sourceRoot":"","sources":["../../src/scripts/bulk-link-fix.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|