prtape-cli 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +138 -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 +214 -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/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":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,YAAY,EACZ,mBAAmB,EACnB,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,MAAM,CAAC,MAAM,WAAW,GAAG,cAAc,CAAC;AAyB1C,MAAM,UAAU,UAAU,CAAC,IAAc,EAAE,GAAW,EAAE,KAAc;IACpE,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QACpC,GAAG;QACH,QAAQ,EAAE,MAAM;QAChB,KAAK;QACL,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE;KAClD,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;KAC5B,CAAC;AACJ,CAAC;AAUD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAgB;IACpD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC;IAC7C,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,UAAU,CAAC;IACpC,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,UAAU;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAEzD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,6BAA6B,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/G,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9C,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;QAC7G,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;IACjF,CAAC;IAED,IAAI,MAAwD,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAqD,CAAC;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,CAAC,mCAAmC,CAAC,EAAE,CAAC;IAC1F,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACpF,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,CAAC,4CAA4C,CAAC,EAAE,CAAC;IACnG,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,CAAC;IAEpF,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,aAAa,CAAC;QAC3B,MAAM,EAAE,SAAS;QACjB,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;QACzD,GAAG;QACH,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,eAAe,EAAE,qCAAqC,CAAC,IAAI,CAAC,SAAS,CAAC;KACvE,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAE9B,OAAO;QACL,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,SAAS,EAAE,MAAM,CAAC,SAAS,KAAK,IAAI;QACpC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,CAAC;KACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,aAAqB,EAAE,GAAW;IAC1D,OAAO,sBAAsB,aAAa,QAAQ,GAAG,IAAI,WAAW,EAAE,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAO7B;IACC,IAAI,QAAQ,CAAC,WAAW,CAAC,KAAK,GAAG,EAAE,CAAC;QAClC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,CAAC;IACnD,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,UAAU,CAAC;IACpC,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAElC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACtC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;IAC/F,GAAG,CAAC,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACjD,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IAEnD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC5C,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACrC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,2CAA2C,CAAC,EAAE,CAAC;IAC7F,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC/F,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,OAAO,KAAK,WAAW,IAAI,CAAC;IAC5D,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,oBAAoB,CAAC,EAAE,CAAC;IACpG,CAAC;IAED,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3E,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,yBAAyB,CAAC,EAAE,CAAC;IAC7G,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;IAElG,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe;QAClC,CAAC,CAAC,CAAC,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,2CAA2C,CAAC;QACjF,CAAC,CAAC,EAAE,CAAC;IACP,kFAAkF;IAClF,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;IAC7E,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QAC9C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;IACvG,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,SAAS;QACd,GAAG;QACH,GAAG,EAAE,EAAE;QACP,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAAqB;IAC1C,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,GAAG,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,eAAe,EAAE,CAAC;IACpF,OAAO,YAAY,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,WAAW,CAAC,GAAc;IACjC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACjF,MAAM,KAAK,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACnF,OAAO;QACL,IAAI,EAAE,IAAI,IAAI,QAAQ;QACtB,KAAK,EAAE,KAAK,IAAI,wBAAwB;KACzC,CAAC;AACJ,CAAC"}
|
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;
|
package/dist/redact.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { withSteps } from "./summary.js";
|
|
2
|
+
/**
|
|
3
|
+
* Replacement tokens. They are stable on purpose so a second pass is a no-op
|
|
4
|
+
* and tests can assert on them.
|
|
5
|
+
*/
|
|
6
|
+
export const REDACTED_API_KEY = "[REDACTED_API_KEY]";
|
|
7
|
+
export const REDACTED_GITHUB_TOKEN = "[REDACTED_GITHUB_TOKEN]";
|
|
8
|
+
export const REDACTED_AWS_KEY = "[REDACTED_AWS_KEY]";
|
|
9
|
+
export const REDACTED_IP = "[REDACTED_IP]";
|
|
10
|
+
export const REDACTED_HOST = "[REDACTED_HOST]";
|
|
11
|
+
export const REDACTED_EMAIL = "[REDACTED_EMAIL]";
|
|
12
|
+
/**
|
|
13
|
+
* Default redaction. Order matters: `sk-ant-` before generic `sk-`.
|
|
14
|
+
*
|
|
15
|
+
* Patterns are intentionally prefix-based, not entropy-based. A novel secret
|
|
16
|
+
* that does not match these shapes is not caught. Emails are off unless
|
|
17
|
+
* `options.emails` is set.
|
|
18
|
+
*/
|
|
19
|
+
const SECRET_RULES = [
|
|
20
|
+
{
|
|
21
|
+
pattern: /sk-ant-[A-Za-z0-9_-]{8,}/g,
|
|
22
|
+
replace: REDACTED_API_KEY,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
pattern: /(?<![A-Za-z0-9_-])sk-[A-Za-z0-9_-]{8,}/g,
|
|
26
|
+
replace: REDACTED_API_KEY,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
pattern: /gh[pousr]_[A-Za-z0-9]{20,}/g,
|
|
30
|
+
replace: REDACTED_GITHUB_TOKEN,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pattern: /(?<![A-Z0-9])(?:AKIA|ASIA|AIDA|AROA)[A-Z0-9]{16}(?![A-Z0-9])/g,
|
|
34
|
+
replace: REDACTED_AWS_KEY,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
pattern: /(aws_secret_access_key|AWS_SECRET_ACCESS_KEY)(\s*[=:]\s*)(["']?)[^\s"'\\]+/gi,
|
|
38
|
+
replace: `$1$2$3${REDACTED_AWS_KEY}`,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
// RFC1918 plus link-local. Loopback is left alone.
|
|
42
|
+
pattern: /\b(?:10(?:\.\d{1,3}){3}|192\.168(?:\.\d{1,3}){2}|172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2}|169\.254(?:\.\d{1,3}){2})\b/g,
|
|
43
|
+
replace: REDACTED_IP,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
// Hostnames that end in .internal or .local. `localhost` has no dot, so it stays.
|
|
47
|
+
pattern: /\b(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+(?:internal|local)(?![A-Za-z0-9.-])/g,
|
|
48
|
+
replace: REDACTED_HOST,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
const EMAIL_RULE = {
|
|
52
|
+
pattern: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,
|
|
53
|
+
replace: REDACTED_EMAIL,
|
|
54
|
+
};
|
|
55
|
+
export function redact(value, options = {}) {
|
|
56
|
+
let out = value;
|
|
57
|
+
for (const rule of SECRET_RULES) {
|
|
58
|
+
out = out.replace(rule.pattern, rule.replace);
|
|
59
|
+
}
|
|
60
|
+
if (options.emails) {
|
|
61
|
+
out = out.replace(EMAIL_RULE.pattern, EMAIL_RULE.replace);
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
function redactEvent(event, options) {
|
|
66
|
+
if (event.kind === "read")
|
|
67
|
+
return { kind: "read", path: event.path ? redact(event.path, options) : undefined };
|
|
68
|
+
if (event.kind === "edit")
|
|
69
|
+
return { kind: "edit", path: redact(event.path, options), action: event.action };
|
|
70
|
+
if (event.kind === "test")
|
|
71
|
+
return { ...event, command: redact(event.command, options) };
|
|
72
|
+
return event;
|
|
73
|
+
}
|
|
74
|
+
function redactOptional(value, options) {
|
|
75
|
+
if (value === undefined)
|
|
76
|
+
return undefined;
|
|
77
|
+
return redact(value, options);
|
|
78
|
+
}
|
|
79
|
+
export function redactSession(summary, options = {}) {
|
|
80
|
+
const draft = {
|
|
81
|
+
source: summary.source,
|
|
82
|
+
sessionId: redact(summary.sessionId, options),
|
|
83
|
+
startedAt: redactOptional(summary.startedAt, options),
|
|
84
|
+
model: redactOptional(summary.model, options),
|
|
85
|
+
branch: redactOptional(summary.branch, options),
|
|
86
|
+
cwd: redactOptional(summary.cwd, options),
|
|
87
|
+
title: redact(summary.title, options),
|
|
88
|
+
decision: redact(summary.decision, options),
|
|
89
|
+
files: summary.files.map((file) => ({
|
|
90
|
+
path: redact(file.path, options),
|
|
91
|
+
action: file.action,
|
|
92
|
+
})),
|
|
93
|
+
tests: summary.tests.map((test) => ({
|
|
94
|
+
command: redact(test.command, options),
|
|
95
|
+
outcome: test.outcome,
|
|
96
|
+
})),
|
|
97
|
+
events: summary.events?.map((event) => redactEvent(event, options)),
|
|
98
|
+
};
|
|
99
|
+
return withSteps(draft);
|
|
100
|
+
}
|
|
101
|
+
//# 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/run.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type SourceChoice } from "./discover.js";
|
|
2
|
+
import { type CommandRunner } from "./gh.js";
|
|
3
|
+
import { type HostResult } from "./orphan.js";
|
|
4
|
+
import type { SessionSummary } from "./types.js";
|
|
5
|
+
export type ImageHost = (input: {
|
|
6
|
+
cwd: string;
|
|
7
|
+
png: Buffer;
|
|
8
|
+
}) => Promise<HostResult>;
|
|
9
|
+
export interface RunOptions {
|
|
10
|
+
cwd: string;
|
|
11
|
+
sessionPath?: string;
|
|
12
|
+
source: SourceChoice;
|
|
13
|
+
claudeHome?: string;
|
|
14
|
+
dryRun: boolean;
|
|
15
|
+
redactEmails: boolean;
|
|
16
|
+
/** Comment on this pull request instead of the one for the current branch. */
|
|
17
|
+
prNumber?: number;
|
|
18
|
+
/** Show the Demo project tag. Off unless `--demo` or `--label demo` is set. */
|
|
19
|
+
demo?: boolean;
|
|
20
|
+
tmpDir?: string;
|
|
21
|
+
runner?: CommandRunner;
|
|
22
|
+
recentFiles?: string[];
|
|
23
|
+
/** Test hook. Production uses `hostTimelinePng`. */
|
|
24
|
+
hostImage?: ImageHost;
|
|
25
|
+
}
|
|
26
|
+
export interface RunResult {
|
|
27
|
+
summary: SessionSummary;
|
|
28
|
+
comment: string;
|
|
29
|
+
svg: string;
|
|
30
|
+
svgPath: string;
|
|
31
|
+
pngPath?: string;
|
|
32
|
+
posted: boolean;
|
|
33
|
+
imageHosted: boolean;
|
|
34
|
+
imageUrl?: string;
|
|
35
|
+
note: string;
|
|
36
|
+
sessionNote?: string;
|
|
37
|
+
prNumber?: number;
|
|
38
|
+
prUrl?: string;
|
|
39
|
+
origin: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function toPublicJson(summary: SessionSummary, image?: {
|
|
42
|
+
imageHosted: boolean;
|
|
43
|
+
imageUrl?: string;
|
|
44
|
+
}): unknown;
|
|
45
|
+
export declare function runPr(options: RunOptions): Promise<RunResult>;
|
|
46
|
+
export declare function formatPosted(result: RunResult): string;
|
|
47
|
+
export declare function writeTimelineFile(contents: string | Buffer, cwd: string, sessionId: string, tmpDir: string, extension: "svg" | "png"): string;
|
|
48
|
+
export declare function assertNotInsideProject(target: string, cwd: string): void;
|