prtape-cli 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +140 -2
- package/dist/adapters/claude.d.ts +2 -0
- package/dist/adapters/claude.js +309 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/bash-edits.d.ts +41 -0
- package/dist/bash-edits.js +440 -0
- package/dist/bash-edits.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +216 -0
- package/dist/cli.js.map +1 -0
- package/dist/decision.d.ts +7 -0
- package/dist/decision.js +224 -0
- package/dist/decision.js.map +1 -0
- package/dist/discover.d.ts +32 -0
- package/dist/discover.js +179 -0
- package/dist/discover.js.map +1 -0
- package/dist/display.d.ts +28 -0
- package/dist/display.js +311 -0
- package/dist/display.js.map +1 -0
- package/dist/env.d.ts +5 -0
- package/dist/env.js +11 -0
- package/dist/env.js.map +1 -0
- package/dist/gh.d.ts +46 -0
- package/dist/gh.js +190 -0
- package/dist/gh.js.map +1 -0
- package/dist/glance.d.ts +15 -0
- package/dist/glance.js +75 -0
- package/dist/glance.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/orphan.d.ts +44 -0
- package/dist/orphan.js +152 -0
- package/dist/orphan.js.map +1 -0
- package/dist/png.d.ts +2 -0
- package/dist/png.js +13 -0
- package/dist/png.js.map +1 -0
- package/dist/privacy.d.ts +7 -0
- package/dist/privacy.js +39 -0
- package/dist/privacy.js.map +1 -0
- package/dist/redact.d.ts +17 -0
- package/dist/redact.js +101 -0
- package/dist/redact.js.map +1 -0
- package/dist/run.d.ts +48 -0
- package/dist/run.js +218 -0
- package/dist/run.js.map +1 -0
- package/dist/summary.d.ts +7 -0
- package/dist/summary.js +134 -0
- package/dist/summary.js.map +1 -0
- package/dist/tests-detect.d.ts +19 -0
- package/dist/tests-detect.js +97 -0
- package/dist/tests-detect.js.map +1 -0
- package/dist/text.d.ts +8 -0
- package/dist/text.js +31 -0
- package/dist/text.js.map +1 -0
- package/dist/timeline/format.d.ts +28 -0
- package/dist/timeline/format.js +127 -0
- package/dist/timeline/format.js.map +1 -0
- package/dist/timeline/md.d.ts +17 -0
- package/dist/timeline/md.js +129 -0
- package/dist/timeline/md.js.map +1 -0
- package/dist/timeline/svg.d.ts +7 -0
- package/dist/timeline/svg.js +260 -0
- package/dist/timeline/svg.js.map +1 -0
- package/dist/timeline/wrap.d.ts +7 -0
- package/dist/timeline/wrap.js +77 -0
- package/dist/timeline/wrap.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/dist/version.js.map +1 -0
- package/package.json +57 -4
package/dist/gh.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
export class GhError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "GhError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The only network path in PRtape. `gh` talks to GitHub when the user
|
|
10
|
+
* runs `prtape pr` without `--dry-run`. There is no telemetry.
|
|
11
|
+
*/
|
|
12
|
+
export function defaultRunner(command, args, options) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const child = spawn(command, args, { cwd: options.cwd, stdio: ["pipe", "pipe", "pipe"] });
|
|
15
|
+
const stdout = [];
|
|
16
|
+
const stderr = [];
|
|
17
|
+
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
18
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
19
|
+
child.on("error", (error) => {
|
|
20
|
+
if (error.code === "ENOENT") {
|
|
21
|
+
resolve({ code: 127, stdout: "", stderr: `${command} not found` });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
reject(error);
|
|
25
|
+
});
|
|
26
|
+
child.on("close", (code) => {
|
|
27
|
+
resolve({
|
|
28
|
+
code: code ?? 1,
|
|
29
|
+
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
30
|
+
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
if (options.input !== undefined)
|
|
34
|
+
child.stdin.end(options.input);
|
|
35
|
+
else
|
|
36
|
+
child.stdin.end();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export function explainGhFailure(result) {
|
|
40
|
+
const text = `${result.stderr}\n${result.stdout}`;
|
|
41
|
+
if (result.code === 127 || /not found|ENOENT/i.test(text)) {
|
|
42
|
+
return "gh is not installed.";
|
|
43
|
+
}
|
|
44
|
+
if (/not logged into|gh auth login|GH_TOKEN|GITHUB_TOKEN|HTTP 401|HTTP 403|authentication required|set up authentication/i.test(text)) {
|
|
45
|
+
return "gh is not authenticated.";
|
|
46
|
+
}
|
|
47
|
+
if (/no pull requests? found|no prs? found/i.test(text)) {
|
|
48
|
+
return "No pull request for this branch.";
|
|
49
|
+
}
|
|
50
|
+
const detail = result.stderr.trim().split("\n").find((line) => line.trim()) ?? "gh failed.";
|
|
51
|
+
return detail;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* PNG comments and the mermaid fallback both match. Other review chatter does not.
|
|
55
|
+
* `<!-- prtape -->` is the marker id. Visible headings say PRtape.
|
|
56
|
+
* Older AgentTape comments still match so a rerun updates them.
|
|
57
|
+
*/
|
|
58
|
+
export function isPrtapeComment(body) {
|
|
59
|
+
return (body.includes("<!-- prtape -->") ||
|
|
60
|
+
body.includes(" ||
|
|
61
|
+
body.includes("### PRtape") ||
|
|
62
|
+
body.includes("Redacted locally by PRtape") ||
|
|
63
|
+
body.includes(" ||
|
|
64
|
+
body.includes("### AgentTape") ||
|
|
65
|
+
body.includes("Redacted locally by AgentTape"));
|
|
66
|
+
}
|
|
67
|
+
/** @deprecated Use isPrtapeComment. Kept so older imports still find both markers. */
|
|
68
|
+
export function isAgentTapeComment(body) {
|
|
69
|
+
return isPrtapeComment(body);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create or update one PRtape comment on the pull request.
|
|
73
|
+
* A second run PATCHes the latest matching comment from the current `gh` user
|
|
74
|
+
* instead of calling `gh pr comment` again.
|
|
75
|
+
*/
|
|
76
|
+
/** Head branch of the pull request that will receive the comment. Undefined when gh cannot answer. */
|
|
77
|
+
export async function pullRequestHead(cwd, runner = defaultRunner, prNumber) {
|
|
78
|
+
const selector = prNumber !== undefined ? [String(prNumber)] : [];
|
|
79
|
+
const view = await runner("gh", ["pr", "view", ...selector, "--json", "headRefName"], { cwd });
|
|
80
|
+
if (view.code !== 0)
|
|
81
|
+
return undefined;
|
|
82
|
+
try {
|
|
83
|
+
const parsed = JSON.parse(view.stdout);
|
|
84
|
+
return typeof parsed.headRefName === "string" && parsed.headRefName.trim() ? parsed.headRefName.trim() : undefined;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export async function postComment(cwd, body, runner = defaultRunner, prNumber) {
|
|
91
|
+
const selector = prNumber !== undefined ? [String(prNumber)] : [];
|
|
92
|
+
const view = await runner("gh", ["pr", "view", ...selector, "--json", "number,url,title"], { cwd });
|
|
93
|
+
if (view.code !== 0)
|
|
94
|
+
throw new GhError(explainGhFailure(view));
|
|
95
|
+
let parsed;
|
|
96
|
+
try {
|
|
97
|
+
parsed = JSON.parse(view.stdout);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
throw new GhError("gh pr view did not return JSON.");
|
|
101
|
+
}
|
|
102
|
+
if (typeof parsed.number !== "number") {
|
|
103
|
+
throw new GhError("No pull request for this branch.");
|
|
104
|
+
}
|
|
105
|
+
const url = typeof parsed.url === "string" ? parsed.url : "";
|
|
106
|
+
const repo = ownerRepo(url) ?? (await repoSlug(cwd, runner));
|
|
107
|
+
if (!repo)
|
|
108
|
+
throw new GhError("Could not resolve owner/repo for the pull request comment.");
|
|
109
|
+
const login = await currentLogin(cwd, runner);
|
|
110
|
+
const existing = login ? await latestAgentTapeComment(cwd, runner, repo, parsed.number, login) : undefined;
|
|
111
|
+
const payload = JSON.stringify({ body });
|
|
112
|
+
if (existing) {
|
|
113
|
+
const patched = await runner("gh", ["api", "--method", "PATCH", `repos/${repo}/issues/comments/${existing.id}`, "--input", "-"], { cwd, input: payload });
|
|
114
|
+
if (patched.code !== 0)
|
|
115
|
+
throw new GhError(explainGhFailure(patched));
|
|
116
|
+
return { number: parsed.number, url, commentId: existing.id, updated: true };
|
|
117
|
+
}
|
|
118
|
+
const created = await runner("gh", ["api", "--method", "POST", `repos/${repo}/issues/${parsed.number}/comments`, "--input", "-"], { cwd, input: payload });
|
|
119
|
+
if (created.code !== 0)
|
|
120
|
+
throw new GhError(explainGhFailure(created));
|
|
121
|
+
let commentId = 0;
|
|
122
|
+
try {
|
|
123
|
+
const createdBody = JSON.parse(created.stdout);
|
|
124
|
+
if (typeof createdBody.id === "number")
|
|
125
|
+
commentId = createdBody.id;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
commentId = 0;
|
|
129
|
+
}
|
|
130
|
+
return { number: parsed.number, url, commentId, updated: false };
|
|
131
|
+
}
|
|
132
|
+
function ownerRepo(url) {
|
|
133
|
+
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/pull\/\d+/.exec(url);
|
|
134
|
+
if (!match?.[1] || !match[2])
|
|
135
|
+
return undefined;
|
|
136
|
+
return `${match[1]}/${match[2]}`;
|
|
137
|
+
}
|
|
138
|
+
async function repoSlug(cwd, runner) {
|
|
139
|
+
const view = await runner("gh", ["repo", "view", "--json", "nameWithOwner"], { cwd });
|
|
140
|
+
if (view.code !== 0)
|
|
141
|
+
return undefined;
|
|
142
|
+
try {
|
|
143
|
+
const parsed = JSON.parse(view.stdout);
|
|
144
|
+
return typeof parsed.nameWithOwner === "string" ? parsed.nameWithOwner : undefined;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function currentLogin(cwd, runner) {
|
|
151
|
+
const user = await runner("gh", ["api", "user"], { cwd });
|
|
152
|
+
if (user.code !== 0)
|
|
153
|
+
return undefined;
|
|
154
|
+
try {
|
|
155
|
+
const parsed = JSON.parse(user.stdout);
|
|
156
|
+
return typeof parsed.login === "string" ? parsed.login : undefined;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async function latestAgentTapeComment(cwd, runner, repo, prNumber, login) {
|
|
163
|
+
const listed = await runner("gh", ["api", "--paginate", `repos/${repo}/issues/${prNumber}/comments`], { cwd });
|
|
164
|
+
if (listed.code !== 0)
|
|
165
|
+
throw new GhError(explainGhFailure(listed));
|
|
166
|
+
let comments = [];
|
|
167
|
+
try {
|
|
168
|
+
const parsed = JSON.parse(listed.stdout);
|
|
169
|
+
if (Array.isArray(parsed))
|
|
170
|
+
comments = parsed;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
throw new GhError("gh api did not return pull request comments as JSON.");
|
|
174
|
+
}
|
|
175
|
+
const mine = comments.filter((comment) => {
|
|
176
|
+
return (comment.user?.login === login &&
|
|
177
|
+
typeof comment.body === "string" &&
|
|
178
|
+
isPrtapeComment(comment.body) &&
|
|
179
|
+
typeof comment.id === "number");
|
|
180
|
+
});
|
|
181
|
+
mine.sort((a, b) => {
|
|
182
|
+
const byTime = String(b.created_at ?? "").localeCompare(String(a.created_at ?? ""));
|
|
183
|
+
if (byTime !== 0)
|
|
184
|
+
return byTime;
|
|
185
|
+
return Number(b.id) - Number(a.id);
|
|
186
|
+
});
|
|
187
|
+
const latest = mine[0];
|
|
188
|
+
return typeof latest?.id === "number" ? { id: latest.id } : undefined;
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=gh.js.map
|
package/dist/gh.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh.js","sourceRoot":"","sources":["../src/gh.ts"],"names":[],"mappings":"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"}
|
package/dist/glance.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-glance failures: what broke, how to fix it, and the text-timeline fallback.
|
|
3
|
+
* These strings are the product contract. Do not shorten them into a bare exit code.
|
|
4
|
+
*/
|
|
5
|
+
/** Custom ref namespace. Never a branch under refs/heads, so it cannot merge into main. */
|
|
6
|
+
export declare const ORPHAN_REF_PREFIX = "refs/prtape";
|
|
7
|
+
export declare function orphanRef(anchor: string): string;
|
|
8
|
+
export declare function glanceMissingGh(): string;
|
|
9
|
+
export declare function glanceUnauth(): string;
|
|
10
|
+
export declare function glancePushDenied(): string;
|
|
11
|
+
export declare function glancePushOther(detail: string): string;
|
|
12
|
+
export declare function glanceNoOrigin(): string;
|
|
13
|
+
export declare function glanceRaster(): string;
|
|
14
|
+
export declare function glanceRepoUnreadable(detail: string): string;
|
|
15
|
+
export declare function isPermissionFailure(text: string): boolean;
|
package/dist/glance.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-glance failures: what broke, how to fix it, and the text-timeline fallback.
|
|
3
|
+
* These strings are the product contract. Do not shorten them into a bare exit code.
|
|
4
|
+
*/
|
|
5
|
+
/** Custom ref namespace. Never a branch under refs/heads, so it cannot merge into main. */
|
|
6
|
+
export const ORPHAN_REF_PREFIX = "refs/prtape";
|
|
7
|
+
export function orphanRef(anchor) {
|
|
8
|
+
const safe = anchor.replace(/[^A-Za-z0-9._-]/g, "").slice(0, 64);
|
|
9
|
+
if (!safe) {
|
|
10
|
+
throw new Error("Refusing to build an orphan ref without an anchor.");
|
|
11
|
+
}
|
|
12
|
+
const ref = `${ORPHAN_REF_PREFIX}/${safe}`;
|
|
13
|
+
if (!ref.startsWith(`${ORPHAN_REF_PREFIX}/`)) {
|
|
14
|
+
throw new Error(`Refusing to push outside ${ORPHAN_REF_PREFIX}/.`);
|
|
15
|
+
}
|
|
16
|
+
return ref;
|
|
17
|
+
}
|
|
18
|
+
export function glanceMissingGh() {
|
|
19
|
+
return [
|
|
20
|
+
"Image not posted: gh is not installed.",
|
|
21
|
+
"Fix: install GitHub CLI from https://cli.github.com, then run `gh auth login`.",
|
|
22
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
23
|
+
].join("\n");
|
|
24
|
+
}
|
|
25
|
+
export function glanceUnauth() {
|
|
26
|
+
return [
|
|
27
|
+
"Image not posted: gh is not authenticated.",
|
|
28
|
+
"Fix: run `gh auth login`.",
|
|
29
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
30
|
+
].join("\n");
|
|
31
|
+
}
|
|
32
|
+
export function glancePushDenied() {
|
|
33
|
+
return [
|
|
34
|
+
`Image not posted: push to orphan ref ${ORPHAN_REF_PREFIX}/<sha> was denied.`,
|
|
35
|
+
"Fix: give this account write access to the repo, then rerun `prtape pr`.",
|
|
36
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
37
|
+
].join("\n");
|
|
38
|
+
}
|
|
39
|
+
export function glancePushOther(detail) {
|
|
40
|
+
const line = detail.trim().split("\n").find((item) => item.trim()) ?? "git push failed.";
|
|
41
|
+
return [
|
|
42
|
+
`Image not posted: could not push the PNG to orphan ref ${ORPHAN_REF_PREFIX}/<sha>.`,
|
|
43
|
+
line,
|
|
44
|
+
"Fix: run `gh auth status`, confirm you can push to origin, then rerun `prtape pr`.",
|
|
45
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
46
|
+
].join("\n");
|
|
47
|
+
}
|
|
48
|
+
export function glanceNoOrigin() {
|
|
49
|
+
return [
|
|
50
|
+
"Image not posted: this repo has no origin remote.",
|
|
51
|
+
"Fix: `git remote add origin <github-url>`, then rerun `prtape pr`.",
|
|
52
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
53
|
+
].join("\n");
|
|
54
|
+
}
|
|
55
|
+
export function glanceRaster() {
|
|
56
|
+
return [
|
|
57
|
+
"Image not posted: the timeline PNG could not be rendered.",
|
|
58
|
+
"Fix: reinstall prtape-cli so the SVG rasterizer is available, then rerun `prtape pr`.",
|
|
59
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
60
|
+
].join("\n");
|
|
61
|
+
}
|
|
62
|
+
export function glanceRepoUnreadable(detail) {
|
|
63
|
+
const line = detail.trim().split("\n").find((item) => item.trim()) ?? "gh repo view failed.";
|
|
64
|
+
return [
|
|
65
|
+
"Image not posted: gh could not read this repository.",
|
|
66
|
+
line,
|
|
67
|
+
"Fix: run `gh repo view` from the project, then rerun `prtape pr`.",
|
|
68
|
+
"Fell back to the text timeline (ASCII + mermaid).",
|
|
69
|
+
].join("\n");
|
|
70
|
+
}
|
|
71
|
+
const PERMISSION = /permission denied|HTTP 401|HTTP 403|403 Forbidden|authentication failed|could not read Username|denied to|not authorized|write access|GH006|GH013|protected branch/i;
|
|
72
|
+
export function isPermissionFailure(text) {
|
|
73
|
+
return PERMISSION.test(text);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=glance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glance.js","sourceRoot":"","sources":["../src/glance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,2FAA2F;AAC3F,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAE/C,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,iBAAiB,IAAI,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,iBAAiB,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,4BAA4B,iBAAiB,IAAI,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO;QACL,wCAAwC;QACxC,gFAAgF;QAChF,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,4CAA4C;QAC5C,2BAA2B;QAC3B,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,wCAAwC,iBAAiB,oBAAoB;QAC7E,0EAA0E;QAC1E,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,kBAAkB,CAAC;IACzF,OAAO;QACL,0DAA0D,iBAAiB,SAAS;QACpF,IAAI;QACJ,oFAAoF;QACpF,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,mDAAmD;QACnD,oEAAoE;QACpE,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO;QACL,2DAA2D;QAC3D,uFAAuF;QACvF,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,sBAAsB,CAAC;IAC7F,OAAO;QACL,sDAAsD;QACtD,IAAI;QACJ,mEAAmE;QACnE,mDAAmD;KACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,GACd,qKAAqK,CAAC;AAExK,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { parseClaude } from "./adapters/claude.js";
|
|
2
|
+
export { findSession, NoSessionError, type SourceChoice } from "./discover.js";
|
|
3
|
+
export { postComment, GhError } from "./gh.js";
|
|
4
|
+
export { redact, redactSession, type RedactOptions } from "./redact.js";
|
|
5
|
+
export { runPr, toPublicJson, type RunOptions, type RunResult } from "./run.js";
|
|
6
|
+
export { hostTimelinePng, ORPHAN_FILE, rawPngUrl } from "./orphan.js";
|
|
7
|
+
export { ORPHAN_REF_PREFIX, orphanRef } from "./glance.js";
|
|
8
|
+
export { renderPng } from "./png.js";
|
|
9
|
+
export { renderComment } from "./timeline/md.js";
|
|
10
|
+
export { renderSvg } from "./timeline/svg.js";
|
|
11
|
+
export type { SessionSummary, SourceKind } from "./types.js";
|
|
12
|
+
export { VERSION } from "./version.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { parseClaude } from "./adapters/claude.js";
|
|
2
|
+
export { findSession, NoSessionError } from "./discover.js";
|
|
3
|
+
export { postComment, GhError } from "./gh.js";
|
|
4
|
+
export { redact, redactSession } from "./redact.js";
|
|
5
|
+
export { runPr, toPublicJson } from "./run.js";
|
|
6
|
+
export { hostTimelinePng, ORPHAN_FILE, rawPngUrl } from "./orphan.js";
|
|
7
|
+
export { ORPHAN_REF_PREFIX, orphanRef } from "./glance.js";
|
|
8
|
+
export { renderPng } from "./png.js";
|
|
9
|
+
export { renderComment } from "./timeline/md.js";
|
|
10
|
+
export { renderSvg } from "./timeline/svg.js";
|
|
11
|
+
export { VERSION } from "./version.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAqB,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAsB,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAmC,MAAM,UAAU,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/orphan.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { CommandRunner } from "./gh.js";
|
|
2
|
+
export declare const ORPHAN_FILE = "timeline.png";
|
|
3
|
+
export interface HostedPng {
|
|
4
|
+
ok: true;
|
|
5
|
+
url: string;
|
|
6
|
+
sha: string;
|
|
7
|
+
ref: string;
|
|
8
|
+
isPrivate: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface HostFailure {
|
|
11
|
+
ok: false;
|
|
12
|
+
glance: string;
|
|
13
|
+
}
|
|
14
|
+
export type HostResult = HostedPng | HostFailure;
|
|
15
|
+
export interface GitResult {
|
|
16
|
+
code: number;
|
|
17
|
+
stdout: string;
|
|
18
|
+
stderr: string;
|
|
19
|
+
}
|
|
20
|
+
export type GitRunner = (args: string[], cwd: string, input?: string) => GitResult;
|
|
21
|
+
export declare function defaultGit(args: string[], cwd: string, input?: string): GitResult;
|
|
22
|
+
export interface HostInput {
|
|
23
|
+
cwd: string;
|
|
24
|
+
png: Buffer;
|
|
25
|
+
runner?: CommandRunner;
|
|
26
|
+
git?: GitRunner;
|
|
27
|
+
tmpRoot?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a parentless commit whose tree is exactly `timeline.png`, then push
|
|
31
|
+
* it to `refs/prtape/<head-sha>`. No other blobs. The user's index, HEAD,
|
|
32
|
+
* branch, and working tree are not modified. The comment URL is
|
|
33
|
+
* `https://github.com/{owner}/{repo}/raw/{commit}/timeline.png`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function hostTimelinePng(input: HostInput): Promise<HostResult>;
|
|
36
|
+
export declare function rawPngUrl(nameWithOwner: string, sha: string): string;
|
|
37
|
+
export declare function pushOrphanPng(input: {
|
|
38
|
+
remote: string;
|
|
39
|
+
png: Buffer;
|
|
40
|
+
anchor?: string;
|
|
41
|
+
git?: GitRunner;
|
|
42
|
+
tmpRoot?: string;
|
|
43
|
+
useGhCredential?: boolean;
|
|
44
|
+
}): (HostedPng) | HostFailure;
|
package/dist/orphan.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { envValue } from "./env.js";
|
|
6
|
+
import { defaultRunner } from "./gh.js";
|
|
7
|
+
import { glanceMissingGh, glanceNoOrigin, glancePushDenied, glancePushOther, glanceRepoUnreadable, glanceUnauth, isPermissionFailure, orphanRef, } from "./glance.js";
|
|
8
|
+
export const ORPHAN_FILE = "timeline.png";
|
|
9
|
+
export function defaultGit(args, cwd, input) {
|
|
10
|
+
const result = spawnSync("git", args, {
|
|
11
|
+
cwd,
|
|
12
|
+
encoding: "utf8",
|
|
13
|
+
input,
|
|
14
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
code: result.status ?? 1,
|
|
18
|
+
stdout: result.stdout ?? "",
|
|
19
|
+
stderr: result.stderr ?? "",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build a parentless commit whose tree is exactly `timeline.png`, then push
|
|
24
|
+
* it to `refs/prtape/<head-sha>`. No other blobs. The user's index, HEAD,
|
|
25
|
+
* branch, and working tree are not modified. The comment URL is
|
|
26
|
+
* `https://github.com/{owner}/{repo}/raw/{commit}/timeline.png`.
|
|
27
|
+
*/
|
|
28
|
+
export async function hostTimelinePng(input) {
|
|
29
|
+
const runner = input.runner ?? defaultRunner;
|
|
30
|
+
const git = input.git ?? defaultGit;
|
|
31
|
+
const auth = await runner("gh", ["auth", "status"], { cwd: input.cwd });
|
|
32
|
+
const authGlance = glanceForAuth(auth);
|
|
33
|
+
if (authGlance)
|
|
34
|
+
return { ok: false, glance: authGlance };
|
|
35
|
+
const repo = await runner("gh", ["repo", "view", "--json", "nameWithOwner,isPrivate,url"], { cwd: input.cwd });
|
|
36
|
+
if (repo.code !== 0) {
|
|
37
|
+
const text = `${repo.stderr}\n${repo.stdout}`;
|
|
38
|
+
if (isPermissionFailure(text) || /auth|not logged/i.test(text))
|
|
39
|
+
return { ok: false, glance: glanceUnauth() };
|
|
40
|
+
return { ok: false, glance: glanceRepoUnreadable(repo.stderr || repo.stdout) };
|
|
41
|
+
}
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(repo.stdout);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return { ok: false, glance: glanceRepoUnreadable("gh repo view did not return JSON.") };
|
|
48
|
+
}
|
|
49
|
+
if (typeof parsed.nameWithOwner !== "string" || !parsed.nameWithOwner.includes("/")) {
|
|
50
|
+
return { ok: false, glance: glanceRepoUnreadable("gh repo view did not return nameWithOwner.") };
|
|
51
|
+
}
|
|
52
|
+
const remote = git(["remote", "get-url", "origin"], input.cwd);
|
|
53
|
+
const remoteUrl = remote.stdout.trim();
|
|
54
|
+
if (remote.code !== 0 || !remoteUrl)
|
|
55
|
+
return { ok: false, glance: glanceNoOrigin() };
|
|
56
|
+
const head = git(["rev-parse", "HEAD"], input.cwd).stdout.trim();
|
|
57
|
+
const pushed = pushOrphanPng({
|
|
58
|
+
remote: remoteUrl,
|
|
59
|
+
png: input.png,
|
|
60
|
+
anchor: /^[0-9a-f]{7,64}$/i.test(head) ? head : undefined,
|
|
61
|
+
git,
|
|
62
|
+
tmpRoot: input.tmpRoot,
|
|
63
|
+
useGhCredential: /^https:\/\/([^/]+\.)?github\.com\//i.test(remoteUrl),
|
|
64
|
+
});
|
|
65
|
+
if (!pushed.ok)
|
|
66
|
+
return pushed;
|
|
67
|
+
return {
|
|
68
|
+
ok: true,
|
|
69
|
+
sha: pushed.sha,
|
|
70
|
+
ref: pushed.ref,
|
|
71
|
+
isPrivate: parsed.isPrivate === true,
|
|
72
|
+
url: rawPngUrl(parsed.nameWithOwner, pushed.sha),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function rawPngUrl(nameWithOwner, sha) {
|
|
76
|
+
return `https://github.com/${nameWithOwner}/raw/${sha}/${ORPHAN_FILE}`;
|
|
77
|
+
}
|
|
78
|
+
export function pushOrphanPng(input) {
|
|
79
|
+
if (envValue("DENY_PUSH") === "1") {
|
|
80
|
+
return { ok: false, glance: glancePushDenied() };
|
|
81
|
+
}
|
|
82
|
+
const git = input.git ?? defaultGit;
|
|
83
|
+
const tmp = fs.mkdtempSync(path.join(input.tmpRoot ?? os.tmpdir(), "prtape-orphan-"));
|
|
84
|
+
const identity = gitIdentity(git);
|
|
85
|
+
const init = git(["init", "-q"], tmp);
|
|
86
|
+
if (init.code !== 0)
|
|
87
|
+
return { ok: false, glance: glancePushOther(init.stderr || init.stdout) };
|
|
88
|
+
git(["config", "user.name", identity.name], tmp);
|
|
89
|
+
git(["config", "user.email", identity.email], tmp);
|
|
90
|
+
const pngPath = path.join(tmp, ORPHAN_FILE);
|
|
91
|
+
fs.writeFileSync(pngPath, input.png, { mode: 0o600 });
|
|
92
|
+
const pngBlob = git(["hash-object", "-w", pngPath], tmp).stdout.trim();
|
|
93
|
+
if (!/^[0-9a-f]{40}$/i.test(pngBlob)) {
|
|
94
|
+
return { ok: false, glance: glancePushOther("git hash-object did not return a blob id.") };
|
|
95
|
+
}
|
|
96
|
+
const anchor = input.anchor && /^[0-9a-f]{7,64}$/i.test(input.anchor) ? input.anchor : pngBlob;
|
|
97
|
+
let ref;
|
|
98
|
+
try {
|
|
99
|
+
ref = orphanRef(anchor);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
103
|
+
return { ok: false, glance: glancePushOther(message) };
|
|
104
|
+
}
|
|
105
|
+
const treeSpec = `100644 blob ${pngBlob}\t${ORPHAN_FILE}\n`;
|
|
106
|
+
const tree = git(["mktree"], tmp, treeSpec);
|
|
107
|
+
const treeSha = tree.stdout.trim();
|
|
108
|
+
if (tree.code !== 0 || !/^[0-9a-f]{40}$/i.test(treeSha)) {
|
|
109
|
+
return { ok: false, glance: glancePushOther(tree.stderr || tree.stdout || "git mktree failed.") };
|
|
110
|
+
}
|
|
111
|
+
const commit = git(["commit-tree", treeSha, "-m", "PRtape timeline"], tmp);
|
|
112
|
+
const commitSha = commit.stdout.trim();
|
|
113
|
+
if (commit.code !== 0 || !/^[0-9a-f]{40}$/i.test(commitSha)) {
|
|
114
|
+
return { ok: false, glance: glancePushOther(commit.stderr || commit.stdout || "git commit-tree failed.") };
|
|
115
|
+
}
|
|
116
|
+
const added = git(["remote", "add", "origin", input.remote], tmp);
|
|
117
|
+
if (added.code !== 0)
|
|
118
|
+
return { ok: false, glance: glancePushOther(added.stderr || added.stdout) };
|
|
119
|
+
const prefix = input.useGhCredential
|
|
120
|
+
? ["-c", "credential.helper=", "-c", "credential.helper=!gh auth git-credential"]
|
|
121
|
+
: [];
|
|
122
|
+
// `+` forces only this refspec. The destination is refs/prtape/*, never a branch.
|
|
123
|
+
const push = git([...prefix, "push", "origin", `+${commitSha}:${ref}`], tmp);
|
|
124
|
+
if (push.code !== 0) {
|
|
125
|
+
const text = `${push.stderr}\n${push.stdout}`;
|
|
126
|
+
return { ok: false, glance: isPermissionFailure(text) ? glancePushDenied() : glancePushOther(text) };
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
ok: true,
|
|
130
|
+
sha: commitSha,
|
|
131
|
+
ref,
|
|
132
|
+
url: "",
|
|
133
|
+
isPrivate: false,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function glanceForAuth(result) {
|
|
137
|
+
if (result.code === 0)
|
|
138
|
+
return null;
|
|
139
|
+
const text = `${result.stderr}\n${result.stdout}`;
|
|
140
|
+
if (result.code === 127 || /not found|ENOENT/i.test(text))
|
|
141
|
+
return glanceMissingGh();
|
|
142
|
+
return glanceUnauth();
|
|
143
|
+
}
|
|
144
|
+
function gitIdentity(git) {
|
|
145
|
+
const name = git(["config", "--global", "user.name"], os.tmpdir()).stdout.trim();
|
|
146
|
+
const email = git(["config", "--global", "user.email"], os.tmpdir()).stdout.trim();
|
|
147
|
+
return {
|
|
148
|
+
name: name || "PRtape",
|
|
149
|
+
email: email || "prtape@example.invalid",
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=orphan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orphan.js","sourceRoot":"","sources":["../src/orphan.ts"],"names":[],"mappings":"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"}
|
package/dist/png.d.ts
ADDED
package/dist/png.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Resvg } from "@resvg/resvg-js";
|
|
2
|
+
/** Rasterize the timeline SVG. System fonts supply Inter and JetBrains Mono when installed. */
|
|
3
|
+
export function renderPng(svg) {
|
|
4
|
+
const resvg = new Resvg(svg, {
|
|
5
|
+
fitTo: { mode: "width", value: 1920 },
|
|
6
|
+
font: {
|
|
7
|
+
loadSystemFonts: true,
|
|
8
|
+
defaultFontFamily: "Inter",
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
return Buffer.from(resvg.render().asPng());
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=png.js.map
|
package/dist/png.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"png.js","sourceRoot":"","sources":["../src/png.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAExC,+FAA+F;AAC/F,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,EAAE;QAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;QACrC,IAAI,EAAE;YACJ,eAAe,EAAE,IAAI;YACrB,iBAAiB,EAAE,OAAO;SAC3B;KACF,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delete macOS and Linux home prefixes and Claude scratch paths from text a
|
|
3
|
+
* reviewer might read. Spans are removed, not replaced with a token.
|
|
4
|
+
*/
|
|
5
|
+
export declare function hasPrivatePath(text: string): boolean;
|
|
6
|
+
export declare function stripPrivatePaths(text: string): string;
|
|
7
|
+
export declare function isScratchPath(filePath: string): boolean;
|
package/dist/privacy.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delete macOS and Linux home prefixes and Claude scratch paths from text a
|
|
3
|
+
* reviewer might read. Spans are removed, not replaced with a token.
|
|
4
|
+
*/
|
|
5
|
+
const SCRATCH_TOKEN = /(?:\/private)?\/tmp\/claude-[A-Za-z0-9._-]+(?:\/[^\s"'`|;&<>]*)?|\/var\/folders\/[^\s"'`|;&<>]+/g;
|
|
6
|
+
const HOME_PREFIX = /\/Users\/[^\s/"'`|;&<>]+|\/home\/[^\s/"'`|;&<>]+/g;
|
|
7
|
+
/** Claude's project slug encodes `/Users/<name>/` as `-Users-<name>-`. */
|
|
8
|
+
const ENCODED_HOME = /-(?:Users|home)-[A-Za-z0-9._]+-/g;
|
|
9
|
+
export function hasPrivatePath(text) {
|
|
10
|
+
return (/(?:\/private)?\/tmp\/claude-[A-Za-z0-9._-]+/.test(text) ||
|
|
11
|
+
/\/var\/folders\//.test(text) ||
|
|
12
|
+
/\/Users\/[^\s/"'`|;&<>]+/.test(text) ||
|
|
13
|
+
/\/home\/[^\s/"'`|;&<>]+/.test(text) ||
|
|
14
|
+
/-(?:Users|home)-[A-Za-z0-9._]+-/.test(text));
|
|
15
|
+
}
|
|
16
|
+
export function stripPrivatePaths(text) {
|
|
17
|
+
return text
|
|
18
|
+
.replace(SCRATCH_TOKEN, "")
|
|
19
|
+
.replace(ENCODED_HOME, "")
|
|
20
|
+
.replace(HOME_PREFIX, "")
|
|
21
|
+
.replace(/[ \t]{2,}/g, " ")
|
|
22
|
+
.replace(/[ \t]+$/g, "")
|
|
23
|
+
.replace(/^[ \t]+/g, "");
|
|
24
|
+
}
|
|
25
|
+
export function isScratchPath(filePath) {
|
|
26
|
+
const value = filePath.replace(/\\/g, "/").trim();
|
|
27
|
+
if (!value || value === "/dev/null" || value === "nul")
|
|
28
|
+
return true;
|
|
29
|
+
if (/^(?:\/private)?\/tmp\//.test(value))
|
|
30
|
+
return true;
|
|
31
|
+
if (value.startsWith("/var/folders/"))
|
|
32
|
+
return true;
|
|
33
|
+
if (/(?:^|\/)scratchpad(?:\/|$)/.test(value))
|
|
34
|
+
return true;
|
|
35
|
+
if (/(?:^|\/)\.claude(?:\/|$)/.test(value))
|
|
36
|
+
return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=privacy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privacy.js","sourceRoot":"","sources":["../src/privacy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,aAAa,GACjB,kGAAkG,CAAC;AAErG,MAAM,WAAW,GAAG,mDAAmD,CAAC;AAExE,0EAA0E;AAC1E,MAAM,YAAY,GAAG,kCAAkC,CAAC;AAExD,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,CACL,6CAA6C,CAAC,IAAI,CAAC,IAAI,CAAC;QACxD,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7B,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC;QACrC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;QACpC,iCAAiC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC7C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI;SACR,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;SAC1B,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;SACxB,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC;SAC1B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,WAAW,IAAI,KAAK,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACpE,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtD,IAAI,KAAK,CAAC,UAAU,CAAC,eAAe,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/redact.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SessionDraft, SessionSummary } from "./types.js";
|
|
2
|
+
export interface RedactOptions {
|
|
3
|
+
/** Emails stay visible unless this is set. */
|
|
4
|
+
emails?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Replacement tokens. They are stable on purpose so a second pass is a no-op
|
|
8
|
+
* and tests can assert on them.
|
|
9
|
+
*/
|
|
10
|
+
export declare const REDACTED_API_KEY = "[REDACTED_API_KEY]";
|
|
11
|
+
export declare const REDACTED_GITHUB_TOKEN = "[REDACTED_GITHUB_TOKEN]";
|
|
12
|
+
export declare const REDACTED_AWS_KEY = "[REDACTED_AWS_KEY]";
|
|
13
|
+
export declare const REDACTED_IP = "[REDACTED_IP]";
|
|
14
|
+
export declare const REDACTED_HOST = "[REDACTED_HOST]";
|
|
15
|
+
export declare const REDACTED_EMAIL = "[REDACTED_EMAIL]";
|
|
16
|
+
export declare function redact(value: string, options?: RedactOptions): string;
|
|
17
|
+
export declare function redactSession(summary: SessionSummary | SessionDraft, options?: RedactOptions): SessionSummary;
|