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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +140 -2
  3. package/dist/adapters/claude.d.ts +2 -0
  4. package/dist/adapters/claude.js +309 -0
  5. package/dist/adapters/claude.js.map +1 -0
  6. package/dist/bash-edits.d.ts +41 -0
  7. package/dist/bash-edits.js +440 -0
  8. package/dist/bash-edits.js.map +1 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +216 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/decision.d.ts +7 -0
  13. package/dist/decision.js +224 -0
  14. package/dist/decision.js.map +1 -0
  15. package/dist/discover.d.ts +32 -0
  16. package/dist/discover.js +179 -0
  17. package/dist/discover.js.map +1 -0
  18. package/dist/display.d.ts +28 -0
  19. package/dist/display.js +311 -0
  20. package/dist/display.js.map +1 -0
  21. package/dist/env.d.ts +5 -0
  22. package/dist/env.js +11 -0
  23. package/dist/env.js.map +1 -0
  24. package/dist/gh.d.ts +46 -0
  25. package/dist/gh.js +190 -0
  26. package/dist/gh.js.map +1 -0
  27. package/dist/glance.d.ts +15 -0
  28. package/dist/glance.js +75 -0
  29. package/dist/glance.js.map +1 -0
  30. package/dist/index.d.ts +12 -0
  31. package/dist/index.js +12 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/orphan.d.ts +44 -0
  34. package/dist/orphan.js +152 -0
  35. package/dist/orphan.js.map +1 -0
  36. package/dist/png.d.ts +2 -0
  37. package/dist/png.js +13 -0
  38. package/dist/png.js.map +1 -0
  39. package/dist/privacy.d.ts +7 -0
  40. package/dist/privacy.js +39 -0
  41. package/dist/privacy.js.map +1 -0
  42. package/dist/redact.d.ts +17 -0
  43. package/dist/redact.js +101 -0
  44. package/dist/redact.js.map +1 -0
  45. package/dist/run.d.ts +48 -0
  46. package/dist/run.js +218 -0
  47. package/dist/run.js.map +1 -0
  48. package/dist/summary.d.ts +7 -0
  49. package/dist/summary.js +134 -0
  50. package/dist/summary.js.map +1 -0
  51. package/dist/tests-detect.d.ts +19 -0
  52. package/dist/tests-detect.js +97 -0
  53. package/dist/tests-detect.js.map +1 -0
  54. package/dist/text.d.ts +8 -0
  55. package/dist/text.js +31 -0
  56. package/dist/text.js.map +1 -0
  57. package/dist/timeline/format.d.ts +28 -0
  58. package/dist/timeline/format.js +127 -0
  59. package/dist/timeline/format.js.map +1 -0
  60. package/dist/timeline/md.d.ts +17 -0
  61. package/dist/timeline/md.js +129 -0
  62. package/dist/timeline/md.js.map +1 -0
  63. package/dist/timeline/svg.d.ts +7 -0
  64. package/dist/timeline/svg.js +260 -0
  65. package/dist/timeline/svg.js.map +1 -0
  66. package/dist/timeline/wrap.d.ts +7 -0
  67. package/dist/timeline/wrap.js +77 -0
  68. package/dist/timeline/wrap.js.map +1 -0
  69. package/dist/types.d.ts +96 -0
  70. package/dist/types.js +5 -0
  71. package/dist/types.js.map +1 -0
  72. package/dist/version.d.ts +1 -0
  73. package/dist/version.js +2 -0
  74. package/dist/version.js.map +1 -0
  75. package/package.json +57 -4
@@ -0,0 +1,179 @@
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 { parseClaude } from "./adapters/claude.js";
6
+ export class NoSessionError extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = "NoSessionError";
10
+ }
11
+ }
12
+ /** Claude config dir. `CLAUDE_CONFIG_DIR` is honored when set; otherwise `~/.claude`. */
13
+ export function defaultClaudeHome(env = process.env, home = os.homedir()) {
14
+ return env.CLAUDE_CONFIG_DIR || path.join(home, ".claude");
15
+ }
16
+ /**
17
+ * Directory slug Claude Code uses under `projects/`.
18
+ * Replaces ":", "\", and "/" with "-". The encoding is lossy when the path
19
+ * itself contains dashes, so selection still reads the `cwd` field.
20
+ */
21
+ export function claudeProjectSlug(cwd) {
22
+ return path.resolve(cwd).replace(/[:\\/]/g, "-");
23
+ }
24
+ export function pathsRelated(leftPath, rightPath) {
25
+ const left = path.resolve(leftPath);
26
+ const right = path.resolve(rightPath);
27
+ return left === right || right.startsWith(`${left}${path.sep}`) || left.startsWith(`${right}${path.sep}`);
28
+ }
29
+ export function listClaudeSessions(claudeHome) {
30
+ const projects = path.join(claudeHome, "projects");
31
+ if (!fs.existsSync(projects))
32
+ return [];
33
+ const sessions = [];
34
+ let slugs;
35
+ try {
36
+ slugs = fs.readdirSync(projects, { withFileTypes: true });
37
+ }
38
+ catch {
39
+ return [];
40
+ }
41
+ for (const slug of slugs) {
42
+ if (!slug.isDirectory())
43
+ continue;
44
+ const dir = path.join(projects, slug.name);
45
+ let entries;
46
+ try {
47
+ entries = fs.readdirSync(dir, { withFileTypes: true });
48
+ }
49
+ catch {
50
+ continue;
51
+ }
52
+ for (const entry of entries) {
53
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
54
+ continue;
55
+ sessions.push(path.join(dir, entry.name));
56
+ }
57
+ }
58
+ return sessions;
59
+ }
60
+ export function selectClaudeSession(files, targetCwd, recentFiles = []) {
61
+ const related = [];
62
+ const others = [];
63
+ for (const file of files) {
64
+ let mtime = 0;
65
+ try {
66
+ mtime = fs.statSync(file).mtimeMs;
67
+ }
68
+ catch {
69
+ continue;
70
+ }
71
+ const cwd = sniffCwd(file);
72
+ if (cwd && pathsRelated(cwd, targetCwd))
73
+ related.push({ file, mtime });
74
+ else
75
+ others.push({ file, mtime });
76
+ }
77
+ if (related.length > 0) {
78
+ related.sort((a, b) => b.mtime - a.mtime);
79
+ return related[0]?.file ?? null;
80
+ }
81
+ others.sort((a, b) => b.mtime - a.mtime);
82
+ let best = null;
83
+ for (const candidate of others.slice(0, 8)) {
84
+ let summary;
85
+ try {
86
+ summary = parseClaude(fs.readFileSync(candidate.file, "utf8"), path.basename(candidate.file));
87
+ }
88
+ catch {
89
+ continue;
90
+ }
91
+ const score = overlapScore(summary.files.map((file) => file.path), targetCwd, recentFiles);
92
+ if (score <= 0)
93
+ continue;
94
+ if (!best || score > best.score || (score === best.score && candidate.mtime > best.mtime)) {
95
+ best = { file: candidate.file, score, mtime: candidate.mtime };
96
+ }
97
+ }
98
+ return best?.file ?? null;
99
+ }
100
+ export function findSession(options) {
101
+ const recent = options.recentFiles ?? gitChangedFiles(options.cwd);
102
+ const claude = selectClaudeSession(listClaudeSessions(options.claudeHome), options.cwd, recent);
103
+ if (!claude)
104
+ throw new NoSessionError(missingClaude(options.cwd));
105
+ return { source: "claude-code", path: claude };
106
+ }
107
+ export function gitChangedFiles(cwd) {
108
+ const names = new Set();
109
+ for (const args of [
110
+ ["diff", "--name-only", "HEAD"],
111
+ ["diff", "--name-only", "--cached"],
112
+ ["ls-files", "--others", "--exclude-standard"],
113
+ ]) {
114
+ for (const line of gitLines(cwd, args))
115
+ names.add(line);
116
+ }
117
+ return [...names];
118
+ }
119
+ function gitLines(cwd, args) {
120
+ const result = spawnSync("git", args, { cwd, encoding: "utf8" });
121
+ if (result.status !== 0 || !result.stdout)
122
+ return [];
123
+ return result.stdout
124
+ .split("\n")
125
+ .map((line) => line.trim())
126
+ .filter(Boolean);
127
+ }
128
+ function overlapScore(paths, targetCwd, recentFiles) {
129
+ if (recentFiles.length === 0)
130
+ return 0;
131
+ const root = path.resolve(targetCwd);
132
+ let score = 0;
133
+ for (const filePath of paths) {
134
+ for (const changed of recentFiles) {
135
+ const changedAbs = path.resolve(root, changed);
136
+ const fileAbs = path.isAbsolute(filePath) ? path.resolve(filePath) : path.resolve(root, filePath);
137
+ if (filePath === changed || fileAbs === changedAbs || filePath.endsWith(`/${changed}`))
138
+ score += 1;
139
+ }
140
+ }
141
+ return score;
142
+ }
143
+ /** Read `cwd` from the head of a session file. The first record normally carries it. */
144
+ export function sniffCwd(file) {
145
+ let fd;
146
+ try {
147
+ fd = fs.openSync(file, "r");
148
+ const buf = Buffer.alloc(256 * 1024);
149
+ const count = fs.readSync(fd, buf, 0, buf.length, 0);
150
+ const text = buf.subarray(0, count).toString("utf8");
151
+ const lines = text.split(/\r?\n/);
152
+ if (count === buf.length)
153
+ lines.pop();
154
+ for (const line of lines) {
155
+ if (!line.trim())
156
+ continue;
157
+ try {
158
+ const record = JSON.parse(line);
159
+ if (typeof record.cwd === "string" && record.cwd.trim())
160
+ return record.cwd;
161
+ }
162
+ catch {
163
+ // Keep scanning. Discovery must tolerate a bad line.
164
+ }
165
+ }
166
+ }
167
+ catch {
168
+ return undefined;
169
+ }
170
+ finally {
171
+ if (fd !== undefined)
172
+ fs.closeSync(fd);
173
+ }
174
+ return undefined;
175
+ }
176
+ function missingClaude(cwd) {
177
+ return `No Claude Code session for ${cwd}. Looked under the Claude projects directory for a session whose cwd matches this directory, or that edited the files git currently shows as changed. Pass --session <file.jsonl> to choose one.`;
178
+ }
179
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { RedactOptions } from "./redact.js";
2
+ import type { SessionSummary } from "./types.js";
3
+ /** Locked KEY DECISION copy. The short form drops the second clause. */
4
+ export declare const LOCKED_DECISION = "Ship the redacted timeline; secrets stay off the PR.";
5
+ export interface Presented {
6
+ summary: SessionSummary;
7
+ /** True when a secret was removed from a string a reviewer might read. */
8
+ secretsStripped: boolean;
9
+ /** How many secret spans were removed. Drives the `redacted ×N` badge only. */
10
+ maskedCount: number;
11
+ }
12
+ /**
13
+ * Reviewer-facing copy. Sentences and shell assignments that contain a secret
14
+ * are deleted. Nothing is replaced with a `[REDACTED_*]` token.
15
+ */
16
+ export declare function presentSummary(input: SessionSummary, options?: RedactOptions): Presented;
17
+ export declare function scrubTitle(text: string, options?: RedactOptions): string;
18
+ /** Drop Claude Code wrappers such as `<pasted_content id="...">...</pasted_content>`. */
19
+ export declare function stripPastedWrappers(text: string): string;
20
+ export declare function scrubProse(text: string, options?: RedactOptions): string;
21
+ /**
22
+ * A sentence whose job is to point at a private path. Drop the whole sentence
23
+ * so deletion does not leave "完整輸出存在 。" or "The full output is saved at ."
24
+ */
25
+ export declare function isPathReferenceSentence(sentence: string): boolean;
26
+ /** Drop markdown markers and empty code spans left behind when a path was deleted. */
27
+ export declare function cleanDisplayMarkdown(text: string): string;
28
+ export declare function scrubCommand(command: string, options?: RedactOptions): string;
@@ -0,0 +1,311 @@
1
+ import { decisionFromEvents } from "./decision.js";
2
+ import { redact } from "./redact.js";
3
+ import { hasPrivatePath, stripPrivatePaths } from "./privacy.js";
4
+ import { rollupTests, withSteps } from "./summary.js";
5
+ import { displayTestCommand } from "./tests-detect.js";
6
+ import { oneLine } from "./text.js";
7
+ const MARKER = /\[REDACTED_[A-Z0-9_]+\]/;
8
+ /** Locked KEY DECISION copy. The short form drops the second clause. */
9
+ export const LOCKED_DECISION = "Ship the redacted timeline; secrets stay off the PR.";
10
+ /**
11
+ * Reviewer-facing copy. Sentences and shell assignments that contain a secret
12
+ * are deleted. Nothing is replaced with a `[REDACTED_*]` token.
13
+ */
14
+ export function presentSummary(input, options = {}) {
15
+ const probed = [input.title, input.decision, ...input.files.map((file) => file.path), ...input.tests.map((test) => test.command)].join("\n");
16
+ const maskedCount = redact(probed, options).match(/\[REDACTED_[A-Z0-9_]+\]/g)?.length ?? 0;
17
+ const secretsStripped = maskedCount > 0;
18
+ const decision = scrubDecision(input.decision, input, options);
19
+ const title = scrubTitle(input.title, options);
20
+ const events = input.events.map((event) => scrubEvent(event, options)).filter((event) => event !== undefined);
21
+ return {
22
+ secretsStripped,
23
+ maskedCount,
24
+ summary: withSteps({
25
+ ...input,
26
+ title: title || "Coding-agent session",
27
+ decision,
28
+ cwd: publicCwd(input.cwd),
29
+ branch: input.branch ? stripPrivatePaths(input.branch) || undefined : undefined,
30
+ events,
31
+ }),
32
+ };
33
+ }
34
+ const FENCE_LANG = /^(?:text|bash|sh|shell|md|markdown|json|javascript|js|ts|typescript|python|py|diff|plaintext)\s+/i;
35
+ export function scrubTitle(text, options = {}) {
36
+ // Emails never lead the title. A sentence that is only an address is dropped.
37
+ const clean = scrubProse(stripFenceLang(stripPastedWrappers(text)), { ...options, emails: true });
38
+ const sentences = splitSentences(clean)
39
+ .map((sentence) => stripFenceLang(sentence))
40
+ .filter((sentence) => sentence && !isOnlyEmail(sentence));
41
+ const task = sentences.find((sentence) => isTaskSentence(sentence)) ??
42
+ sentences.find((sentence) => !isMetaInstruction(sentence) && !isConstraintSentence(sentence)) ??
43
+ sentences[0] ??
44
+ "";
45
+ return task;
46
+ }
47
+ const TASK_VERBS = /^(?:fix|make|add|find|implement|update|run|change|correct|strip|remove|keep|請|修正|修|新增|實作|更新|執行|找出|改)/i;
48
+ function stripFenceLang(text) {
49
+ return text.replace(FENCE_LANG, "").trim();
50
+ }
51
+ function isConstraintSentence(sentence) {
52
+ if (isTaskSentence(sentence))
53
+ return false;
54
+ return /不要|別[刪跳]|don't\b|do not\b|must not\b|\bnever\b/i.test(sentence);
55
+ }
56
+ function isTaskSentence(sentence) {
57
+ return TASK_VERBS.test(sentence.trim());
58
+ }
59
+ /** Language, format, and disclaimer lines Claude Code puts ahead of the task. */
60
+ function isMetaInstruction(sentence) {
61
+ const text = sentence.trim().replace(/[.!?。]+$/g, "");
62
+ return (/^(?:respond|answer|reply)\b(?:\s+\w+){0,6}\s+in\b/i.test(text) ||
63
+ /^be concise\b/i.test(text) ||
64
+ /^keep (?:it|this|your (?:answer|response)) (?:brief|short|concise)\b/i.test(text) ||
65
+ /^this is an intentional\b/i.test(text) ||
66
+ /\bnot a real\b.+\b(?:incident|customer|bug|session)\b/i.test(text) ||
67
+ /^(?:note|context)\s*:/i.test(text));
68
+ }
69
+ /** Drop Claude Code wrappers such as `<pasted_content id="...">...</pasted_content>`. */
70
+ export function stripPastedWrappers(text) {
71
+ let current = text;
72
+ for (let pass = 0; pass < 4; pass += 1) {
73
+ const next = current.replace(/<([A-Za-z][\w:-]*)\b[^>]*>[\s\S]*?<\/\1>/g, (full) => full.replace(/^<[^>]*>/, "").replace(/<\/[^>]*>$/, ""));
74
+ if (next === current)
75
+ break;
76
+ current = next;
77
+ }
78
+ return current
79
+ .replace(/<\/?[A-Za-z][\w:-]*\b[^>]*>/g, " ")
80
+ .replace(/[ \t]{2,}/g, " ")
81
+ .trim();
82
+ }
83
+ export function scrubProse(text, options = {}) {
84
+ const withoutFences = text.replace(/```[\s\S]*?```/g, "\n").replace(/~~~[\s\S]*?~~~/g, "\n");
85
+ const kept = splitSentences(withoutFences)
86
+ .filter((sentence) => !isPathReferenceSentence(sentence))
87
+ .map((sentence) => cleanDisplayMarkdown(stripPrivatePaths(sentence)).trim())
88
+ .filter((sentence) => sentence && !isPathReferenceSentence(sentence) && !sentenceHasSecret(sentence, options));
89
+ return oneLine(kept.join(" "));
90
+ }
91
+ function splitSentences(text) {
92
+ const sentences = [];
93
+ for (const line of text.split(/\n+/)) {
94
+ let current = "";
95
+ const chars = [...line];
96
+ for (let index = 0; index < chars.length; index += 1) {
97
+ const ch = chars[index] ?? "";
98
+ current += ch;
99
+ const next = chars[index + 1];
100
+ const cjkEnd = ch === "。" || ch === "!" || ch === "?";
101
+ const enEnd = (ch === "." || ch === "!" || ch === "?") && (next === undefined || /\s/.test(next));
102
+ if (!cjkEnd && !enEnd)
103
+ continue;
104
+ const trimmed = current.trim();
105
+ if (trimmed)
106
+ sentences.push(trimmed);
107
+ current = "";
108
+ if (next && /\s/.test(next))
109
+ index += 1;
110
+ }
111
+ const rest = current.trim();
112
+ if (rest)
113
+ sentences.push(rest);
114
+ }
115
+ return sentences;
116
+ }
117
+ /**
118
+ * A sentence whose job is to point at a private path. Drop the whole sentence
119
+ * so deletion does not leave "完整輸出存在 。" or "The full output is saved at ."
120
+ */
121
+ export function isPathReferenceSentence(sentence) {
122
+ const hadPath = hasPrivatePath(sentence) || /`{2,}|`\s*`/.test(sentence);
123
+ const core = locatorCore(sentence);
124
+ if (!core)
125
+ return hadPath;
126
+ if (!isLocatorCore(core))
127
+ return false;
128
+ return hadPath || isLocatorCore(core);
129
+ }
130
+ function locatorCore(sentence) {
131
+ return cleanDisplayMarkdown(stripPrivatePaths(sentence))
132
+ .replace(/`+/g, "")
133
+ .replace(/[。!?.!?]+/g, "")
134
+ .replace(/\s+/g, " ")
135
+ .trim();
136
+ }
137
+ const LOCATOR_WORDS = new Set([
138
+ "the",
139
+ "a",
140
+ "an",
141
+ "full",
142
+ "output",
143
+ "outputs",
144
+ "log",
145
+ "logs",
146
+ "file",
147
+ "files",
148
+ "checkout",
149
+ "note",
150
+ "notes",
151
+ "is",
152
+ "are",
153
+ "was",
154
+ "were",
155
+ "saved",
156
+ "written",
157
+ "stored",
158
+ "located",
159
+ "kept",
160
+ "live",
161
+ "lives",
162
+ "at",
163
+ "in",
164
+ "under",
165
+ "to",
166
+ "on",
167
+ "and",
168
+ "of",
169
+ ]);
170
+ function isLocatorCore(core) {
171
+ if (/^(?:完整|修正前的|修正後的)?輸出存在$/.test(core))
172
+ return true;
173
+ if (/^(?:日誌|日志|記錄|檔案)(?:在|位於|存在)$/.test(core))
174
+ return true;
175
+ const words = core
176
+ .replace(/\/[^\s]+/g, " ")
177
+ .split(/\s+/)
178
+ .map((word) => word.trim())
179
+ .filter(Boolean);
180
+ if (words.length === 0 || words.length > 12)
181
+ return false;
182
+ if (words.some((word) => /[\u3400-\u9fff]/.test(word)))
183
+ return false;
184
+ return words.every((word) => LOCATOR_WORDS.has(word.toLowerCase().replace(/^[("']+|[)"',]+$/g, "")));
185
+ }
186
+ /** Drop markdown markers and empty code spans left behind when a path was deleted. */
187
+ export function cleanDisplayMarkdown(text) {
188
+ return text
189
+ .replace(/```[\s\S]*?```/g, " ")
190
+ .replace(/~~~[\s\S]*?~~~/g, " ")
191
+ .replace(/`{1,3}\s*`{1,3}/g, "")
192
+ .replace(/\*\*([^*]+)\*\*/g, "$1")
193
+ .replace(/__([^_]+)__/g, "$1")
194
+ .replace(/(^|[^\w*])\*([^*\n]+)\*(?!\*)/g, "$1$2")
195
+ .replace(/`([^`]+)`/g, "$1")
196
+ .replace(/`+/g, "")
197
+ .replace(/^\s{0,3}#{1,6}\s+/gm, "")
198
+ .replace(/[ \t]{2,}/g, " ")
199
+ .trim();
200
+ }
201
+ export function scrubCommand(command, options = {}) {
202
+ const displayed = displayTestCommand(command);
203
+ const source = displayed || command;
204
+ const pieces = source.split(/\s*(?:&&|\|\||;)\s*/);
205
+ const kept = pieces.map((piece) => scrubCommandPiece(piece, options)).filter((piece) => piece.length > 0);
206
+ return oneLine(stripPrivatePaths(kept.join(" && ")));
207
+ }
208
+ function scrubDecision(text, summary, options) {
209
+ const prose = scrubProse(text, options);
210
+ const explicit = explicitSentence(prose);
211
+ if (explicit && explicit.replace(/[。..]$/u, "") === "Ship the redacted timeline")
212
+ return LOCKED_DECISION;
213
+ if (explicit && !isStatusBoilerplate(explicit))
214
+ return finishSentence(explicit);
215
+ const derived = decisionFromEvents(summary);
216
+ if (derived)
217
+ return derived;
218
+ return fallbackDecision(summary);
219
+ }
220
+ /** One short statement. A multi-sentence status report is not a decision. */
221
+ function explicitSentence(prose) {
222
+ const sentences = splitSentences(prose).filter((sentence) => sentence.length >= 12 && sentence.length <= 180);
223
+ if (sentences.length !== 1)
224
+ return undefined;
225
+ return sentences[0];
226
+ }
227
+ function isStatusBoilerplate(sentence) {
228
+ return (/^(?:修好了|完成了|done\b)/i.test(sentence) ||
229
+ /全部通過|測試通過/.test(sentence) ||
230
+ /\b(?:tests?|suite) (?:passed|passes|pass)\b/i.test(sentence) ||
231
+ /^fixed the .+ so the (?:suite|tests)/i.test(sentence) ||
232
+ /^the tests passed\b/i.test(sentence) ||
233
+ /^原因與修正[::]?$/.test(sentence) ||
234
+ /^修正前的失敗結果/.test(sentence));
235
+ }
236
+ function finishSentence(sentence) {
237
+ const trimmed = sentence.trim();
238
+ if (/[。!?.!?]$/.test(trimmed))
239
+ return trimmed;
240
+ return `${trimmed}.`;
241
+ }
242
+ function fallbackDecision(summary) {
243
+ const count = summary.files.length;
244
+ const files = count === 0 ? "" : `Edited ${count} file${count === 1 ? "" : "s"}`;
245
+ const outcome = rollupTests(summary.tests);
246
+ if (files && outcome === "pass")
247
+ return `${files} and the tests passed.`;
248
+ if (files && outcome === "fail")
249
+ return `${files}, and the tests failed.`;
250
+ if (files)
251
+ return `${files}.`;
252
+ if (outcome === "pass")
253
+ return "The tests passed.";
254
+ if (outcome === "fail")
255
+ return "The tests failed.";
256
+ return "The session is ready for review.";
257
+ }
258
+ function scrubCommandPiece(piece, options) {
259
+ let rest = piece.trim();
260
+ const kept = [];
261
+ const env = /^([A-Za-z_][A-Za-z0-9_]*)=(?:"([^"]*)"|'([^']*)'|(\S+))\s*/;
262
+ let match = env.exec(rest);
263
+ while (match) {
264
+ const key = match[1] ?? "";
265
+ const value = match[2] ?? match[3] ?? match[4] ?? "";
266
+ if (!sentenceHasSecret(`${key}=${value}`, options))
267
+ kept.push(`${key}=${value}`);
268
+ rest = rest.slice(match[0].length);
269
+ match = env.exec(rest);
270
+ }
271
+ const words = rest.split(/\s+/).filter((word) => word && !sentenceHasSecret(word, options));
272
+ return [...kept, ...words].join(" ").trim();
273
+ }
274
+ function scrubPiece(text, options) {
275
+ const stripped = stripPrivatePaths(text).replace(/^\/+/, "");
276
+ if (!stripped || sentenceHasSecret(stripped, options))
277
+ return "";
278
+ return oneLine(stripped);
279
+ }
280
+ function scrubEvent(event, options) {
281
+ if (event.kind === "read") {
282
+ const path = event.path ? scrubPiece(event.path, options) : "";
283
+ return { kind: "read", path: path || undefined };
284
+ }
285
+ if (event.kind === "edit") {
286
+ const path = scrubPiece(event.path, options);
287
+ if (!path)
288
+ return undefined;
289
+ return { kind: "edit", path, action: event.action };
290
+ }
291
+ if (event.kind === "test") {
292
+ const command = scrubCommand(event.command, options);
293
+ if (!command)
294
+ return undefined;
295
+ return { ...event, command };
296
+ }
297
+ return event;
298
+ }
299
+ function publicCwd(cwd) {
300
+ if (!cwd)
301
+ return undefined;
302
+ const stripped = stripPrivatePaths(cwd).trim();
303
+ return stripped || undefined;
304
+ }
305
+ function sentenceHasSecret(text, options) {
306
+ return MARKER.test(redact(text, options));
307
+ }
308
+ function isOnlyEmail(text) {
309
+ return /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\.?$/.test(text.trim());
310
+ }
311
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../src/display.ts"],"names":[],"mappings":"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"}
package/dist/env.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Current names are PRTAPE_*. AGENTTAPE_* still works.
3
+ * When the new name is set, even to an empty string, it wins.
4
+ */
5
+ export declare function envValue(suffix: string, env?: NodeJS.ProcessEnv): string | undefined;
package/dist/env.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Current names are PRTAPE_*. AGENTTAPE_* still works.
3
+ * When the new name is set, even to an empty string, it wins.
4
+ */
5
+ export function envValue(suffix, env = process.env) {
6
+ const current = `PRTAPE_${suffix}`;
7
+ if (env[current] !== undefined)
8
+ return env[current];
9
+ return env[`AGENTTAPE_${suffix}`];
10
+ }
11
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc,EAAE,MAAyB,OAAO,CAAC,GAAG;IAC3E,MAAM,OAAO,GAAG,UAAU,MAAM,EAAE,CAAC;IACnC,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC;IACpD,OAAO,GAAG,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC;AACpC,CAAC"}
package/dist/gh.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ export interface CommandResult {
2
+ code: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ }
6
+ export interface CommandRunner {
7
+ (command: string, args: string[], options: {
8
+ cwd: string;
9
+ input?: string;
10
+ }): Promise<CommandResult>;
11
+ }
12
+ export interface PrRef {
13
+ number: number;
14
+ url: string;
15
+ commentId: number;
16
+ /** True when an existing PRtape or AgentTape comment was edited instead of created. */
17
+ updated: boolean;
18
+ }
19
+ export declare class GhError extends Error {
20
+ constructor(message: string);
21
+ }
22
+ /**
23
+ * The only network path in PRtape. `gh` talks to GitHub when the user
24
+ * runs `prtape pr` without `--dry-run`. There is no telemetry.
25
+ */
26
+ export declare function defaultRunner(command: string, args: string[], options: {
27
+ cwd: string;
28
+ input?: string;
29
+ }): Promise<CommandResult>;
30
+ export declare function explainGhFailure(result: CommandResult): string;
31
+ /**
32
+ * PNG comments and the mermaid fallback both match. Other review chatter does not.
33
+ * `<!-- prtape -->` is the marker id. Visible headings say PRtape.
34
+ * Older AgentTape comments still match so a rerun updates them.
35
+ */
36
+ export declare function isPrtapeComment(body: string): boolean;
37
+ /** @deprecated Use isPrtapeComment. Kept so older imports still find both markers. */
38
+ export declare function isAgentTapeComment(body: string): boolean;
39
+ /**
40
+ * Create or update one PRtape comment on the pull request.
41
+ * A second run PATCHes the latest matching comment from the current `gh` user
42
+ * instead of calling `gh pr comment` again.
43
+ */
44
+ /** Head branch of the pull request that will receive the comment. Undefined when gh cannot answer. */
45
+ export declare function pullRequestHead(cwd: string, runner?: CommandRunner, prNumber?: number): Promise<string | undefined>;
46
+ export declare function postComment(cwd: string, body: string, runner?: CommandRunner, prNumber?: number): Promise<PrRef>;