@outerlayer/cli 0.11.0 → 0.13.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/CHANGELOG.md +23 -0
- package/README.md +16 -7
- package/dist/{agent-setup-YEFN74Y4.js → agent-setup-QE6PSCEZ.js} +8 -8
- package/dist/build-info.json +1 -1
- package/dist/{builder-PP436VGZ.js → builder-UUS4ORDH.js} +3 -3
- package/dist/{check-YDXOLVJ5.js → check-63IDCEEV.js} +31 -30
- package/dist/{chunk-XR3BJN33.js → chunk-22RMZBGW.js} +20 -1
- package/dist/{chunk-TB7EP24C.js → chunk-2M63GG56.js} +1 -1
- package/dist/{chunk-Y6P5XX2B.js → chunk-3D4OYFCD.js} +4 -4
- package/dist/{chunk-2GBCTEN4.js → chunk-3KTA5UU2.js} +1 -1
- package/dist/{chunk-USO2DKBD.js → chunk-4KSQKQXE.js} +8 -2
- package/dist/{chunk-UES67HLJ.js → chunk-4QVZCVWT.js} +5 -5
- package/dist/{chunk-I263FZ3A.js → chunk-6S3H3J6H.js} +3 -3
- package/dist/{chunk-BHOBM3IZ.js → chunk-C6IV5BV7.js} +10 -10
- package/dist/{chunk-VDI5POCC.js → chunk-CNFVHDHG.js} +1 -1
- package/dist/{chunk-EOWWTFUU.js → chunk-DPKX26LT.js} +92 -16
- package/dist/{chunk-SUMWRA7K.js → chunk-DXQ5MHCO.js} +1 -1
- package/dist/{chunk-ZQ5JGHUO.js → chunk-EFZLAYPE.js} +2 -2
- package/dist/{chunk-RWQWPZB4.js → chunk-GI4XXD4I.js} +3 -3
- package/dist/{chunk-YU5GL7QS.js → chunk-HDTVTA6I.js} +2 -2
- package/dist/{chunk-BFESLKPP.js → chunk-IP7BIBXJ.js} +19 -1
- package/dist/{chunk-YT35WGIP.js → chunk-J5M7BSJQ.js} +99 -7
- package/dist/{chunk-IU4NZROR.js → chunk-JXYVA45C.js} +1 -1
- package/dist/{chunk-BMX3L7CR.js → chunk-LCEXHCHD.js} +1 -1
- package/dist/{chunk-7C4T5BGN.js → chunk-MJXXRX4M.js} +54 -12
- package/dist/{chunk-E5DC4VZL.js → chunk-MZN7AQOB.js} +8 -8
- package/dist/{chunk-CJGQQZWB.js → chunk-NX57IBNK.js} +1 -1
- package/dist/{chunk-DTDZXDQ3.js → chunk-P4MM66C6.js} +31 -18
- package/dist/{chunk-BEZSECPA.js → chunk-P6FX4D43.js} +1 -1
- package/dist/{chunk-A56PYPDF.js → chunk-R7OQTKWT.js} +2 -1
- package/dist/{chunk-TFIOXPZT.js → chunk-RLYZLUQ7.js} +67 -5
- package/dist/chunk-RMWLBUCJ.js +50 -0
- package/dist/{chunk-4HMXH2OA.js → chunk-SFFHGX3G.js} +1 -1
- package/dist/{chunk-3YFCWYBU.js → chunk-SVEP7PVH.js} +14 -14
- package/dist/chunk-T5VPP6H7.js +65 -0
- package/dist/{chunk-BGWTYRSS.js → chunk-TCIW27FM.js} +1 -1
- package/dist/{chunk-R7BJYFD2.js → chunk-TOPDNXHZ.js} +5 -5
- package/dist/{chunk-HKUH5AR2.js → chunk-XJKL4BNU.js} +3 -3
- package/dist/{cli-RQZXTOEI.js → cli-WSBIAVZU.js} +176 -88
- package/dist/{command-U6UGIBVT.js → command-N7BAB4XJ.js} +21 -22
- package/dist/{config-MKBX2ZQD.js → config-N3C6DFQA.js} +1 -1
- package/dist/{connect-cmd-5MIUNYAY.js → connect-cmd-FGYRLLXL.js} +5 -5
- package/dist/{context-adopt-A77G67CP.js → context-adopt-B3PWGFHL.js} +5 -5
- package/dist/{context-materialize-KQZYATQZ.js → context-materialize-7S6NLLRO.js} +5 -5
- package/dist/{dist-3M3ZMEZF.js → dist-LKDWQWZ7.js} +2 -2
- package/dist/{docker-WVRRMK6R.js → docker-BZ55BMBJ.js} +4 -4
- package/dist/{doctor-ZF4PYWVN.js → doctor-3H25Q7WT.js} +23 -20
- package/dist/{emit-artifact-cmd-VKPW577P.js → emit-artifact-cmd-IQCRXOH7.js} +9 -9
- package/dist/{emit-cmd-SU62J2PB.js → emit-cmd-KDSM5VAO.js} +4 -4
- package/dist/{emit-criteria-cmd-U2TL6FYY.js → emit-criteria-cmd-EYUXME26.js} +7 -7
- package/dist/emit-finding-cmd-P4RKBPBB.js +465 -0
- package/dist/{emit-result-cmd-GKBVPMU4.js → emit-result-cmd-6XYENU6H.js} +9 -9
- package/dist/{hook-fast-AQCAQIA6.js → hook-fast-PXWKQPN6.js} +1 -1
- package/dist/{import-capture-cmd-5NJVL2HN.js → import-capture-cmd-2BKM5I2N.js} +3 -3
- package/dist/{import-ruler-cmd-TUK3MRPC.js → import-ruler-cmd-IXR7YK47.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/{init-PUY2BUHH.js → init-2LWVS4AH.js} +21 -17
- package/dist/{init-M5IBAGVE.js → init-ZL7ORPTF.js} +53 -32
- package/dist/{init-cmd-NPNR23UL.js → init-cmd-JXOBCOIB.js} +16 -14
- package/dist/{install-HKOVISUP.js → install-HDBIPHTX.js} +2 -4
- package/dist/{login-browser-7XGSV7MA.js → login-browser-QZCS3WW6.js} +2 -1
- package/dist/{loop-3FNROLW7.js → loop-XOAE6ZIY.js} +32 -30
- package/dist/{machine-RWDDJRWB.js → machine-G6PY2J2J.js} +16 -16
- package/dist/{mcp-install-cmd-XZARXNYT.js → mcp-install-cmd-VXVIH7PH.js} +1 -1
- package/dist/runner-env-XTC53CHN.js +15 -0
- package/dist/runner-key-TDTLNAKJ.js +154 -0
- package/dist/{session-sender-E3UHGSNV.js → session-sender-XVGZFWRK.js} +7 -7
- package/dist/{starter-pack-I35VNYAR.js → starter-pack-B7JPGEDO.js} +4 -4
- package/dist/{status-2OW5AKWL.js → status-MRTPG34B.js} +22 -22
- package/dist/{sync-cmd-ULKXCHO2.js → sync-cmd-UBUZMMDN.js} +6 -6
- package/dist/{watch-IU6NHB4K.js → watch-STNPEWD6.js} +6 -6
- package/dist/{work-claim-cmd-LXXSNEGF.js → work-claim-cmd-CWGYEIJE.js} +11 -11
- package/dist/{work-cmd-ZJY3NA2G.js → work-cmd-X7NMJDFL.js} +8 -8
- package/dist/{work-comment-cmd-34FTLPUO.js → work-comment-cmd-FI2TMAYQ.js} +8 -8
- package/dist/{work-open-pr-cmd-YZAENDP6.js → work-open-pr-cmd-OVHJ5I5H.js} +9 -9
- package/dist/{work-pr-cmd-EXTOGBJC.js → work-pr-cmd-Y5TDMQ4O.js} +8 -8
- package/package.json +1 -1
- package/skill-pack/maintained/reporting-findings/SKILL.md +84 -5
- package/skill-pack/template/build/SKILL.md +60 -33
- package/skill-pack/template/build/references/agent-briefs.md +4 -2
- package/skill-pack/template/build/references/release.md +1 -1
- package/skill-pack/template/build/references/review-loop.md +6 -2
- package/skill-pack/template/build/scripts/record-criteria.mjs +109 -143
- package/skill-pack/validators/code-review.yaml +4 -2
- package/dist/chunk-FBTE2A2X.js +0 -38
- package/dist/chunk-JKIWMRFH.js +0 -27
- package/dist/chunk-T6OIJQRT.js +0 -31
- package/dist/emit-finding-cmd-TMOOKHPD.js +0 -251
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { launchRefusalForSession } from './chunk-HHJDN6AU.js';
|
|
4
|
+
import { autoConnect } from './chunk-EFZLAYPE.js';
|
|
5
|
+
import { detectActiveSession, transcriptPathForSession } from './chunk-IP7BIBXJ.js';
|
|
6
|
+
import './chunk-4QVZCVWT.js';
|
|
7
|
+
import './chunk-CNFVHDHG.js';
|
|
8
|
+
import { resolveRepoIdentity, defaultProjectsDir, findTranscripts, sessionIdFromPath, scrubText } from './chunk-JXYVA45C.js';
|
|
9
|
+
import './chunk-4KSQKQXE.js';
|
|
10
|
+
import './chunk-N6LURUEF.js';
|
|
11
|
+
import './chunk-YRYMNBGQ.js';
|
|
12
|
+
import { launchedItemForSession } from './chunk-GQD22KKN.js';
|
|
13
|
+
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
14
|
+
import { readLatestProvenanceForSession } from './chunk-ZJSNLVCE.js';
|
|
15
|
+
import { defaultFetch } from './chunk-YO4PSLVB.js';
|
|
16
|
+
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-PLMTLGYH.js';
|
|
17
|
+
import { FindingBatchSchema, FindingsResponseSchema, SAME_PROBLEM_RULES } from './chunk-J5M7BSJQ.js';
|
|
18
|
+
import './chunk-EABW6AJQ.js';
|
|
19
|
+
import './chunk-V7NIVOFD.js';
|
|
20
|
+
import './chunk-ZM2IMMYN.js';
|
|
21
|
+
import './chunk-BJ3KTMDH.js';
|
|
22
|
+
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
23
|
+
import './chunk-Z5GEFMRW.js';
|
|
24
|
+
import { readFileSync, existsSync } from 'fs';
|
|
25
|
+
import { join } from 'path';
|
|
26
|
+
|
|
27
|
+
createRequire(import.meta.url);
|
|
28
|
+
var RECENT_EVENT_COUNT = 30;
|
|
29
|
+
var SUMMARY_MAX = 110;
|
|
30
|
+
function locateTranscript(sessionId, home) {
|
|
31
|
+
const fromSpool = transcriptPathForSession(sessionId, home);
|
|
32
|
+
if (fromSpool !== void 0 && existsSync(fromSpool)) return fromSpool;
|
|
33
|
+
const root = home === "" ? defaultProjectsDir() : join(home, ".claude", "projects");
|
|
34
|
+
return findTranscripts(root).find((entry) => !entry.isSubagent && sessionIdFromPath(entry.file) === sessionId)?.file;
|
|
35
|
+
}
|
|
36
|
+
function blockText(block) {
|
|
37
|
+
if (typeof block === "string") return block;
|
|
38
|
+
if (typeof block !== "object" || block === null) return "";
|
|
39
|
+
const b = block;
|
|
40
|
+
if (b.type === "text" && typeof b.text === "string") return b.text;
|
|
41
|
+
if (b.type === "tool_use") {
|
|
42
|
+
const input = b.input ?? {};
|
|
43
|
+
const detail = [input.command, input.file_path, input.pattern, input.description, input.prompt, input.url].find((v) => typeof v === "string");
|
|
44
|
+
return `${String(b.name ?? "tool")}: ${detail ?? ""}`;
|
|
45
|
+
}
|
|
46
|
+
if (b.type === "tool_result") {
|
|
47
|
+
const content = b.content;
|
|
48
|
+
const inner = typeof content === "string" ? content : Array.isArray(content) ? content.map(blockText).join(" ") : "";
|
|
49
|
+
return `result: ${inner}`;
|
|
50
|
+
}
|
|
51
|
+
return "";
|
|
52
|
+
}
|
|
53
|
+
function summarize(type, message) {
|
|
54
|
+
const content = typeof message === "object" && message !== null ? message.content : void 0;
|
|
55
|
+
const text = Array.isArray(content) ? content.map(blockText).join(" ") : blockText(content);
|
|
56
|
+
const flat = scrubText(text.replace(/\s+/g, " ").trim());
|
|
57
|
+
const clipped = flat.length > SUMMARY_MAX ? `${flat.slice(0, SUMMARY_MAX - 1)}\u2026` : flat;
|
|
58
|
+
return `${type === "user" ? "user" : "agent"}: ${clipped}`;
|
|
59
|
+
}
|
|
60
|
+
function readSessionEvents(transcriptPath) {
|
|
61
|
+
let text;
|
|
62
|
+
try {
|
|
63
|
+
text = readFileSync(transcriptPath, "utf8");
|
|
64
|
+
} catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const events = [];
|
|
68
|
+
text.split("\n").forEach((line, index) => {
|
|
69
|
+
if (line.trim() === "") return;
|
|
70
|
+
let record;
|
|
71
|
+
try {
|
|
72
|
+
record = JSON.parse(line);
|
|
73
|
+
} catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (record.type !== "user" && record.type !== "assistant" || typeof record.timestamp !== "string") return;
|
|
77
|
+
if (!Number.isFinite(Date.parse(record.timestamp))) return;
|
|
78
|
+
events.push({ id: `e${index + 1}`, at: record.timestamp, summary: summarize(record.type, record.message) });
|
|
79
|
+
});
|
|
80
|
+
return events;
|
|
81
|
+
}
|
|
82
|
+
function recentSessionEvents(sessionId, home, count = RECENT_EVENT_COUNT) {
|
|
83
|
+
const path = locateTranscript(sessionId, home);
|
|
84
|
+
if (path === void 0) return void 0;
|
|
85
|
+
return readSessionEvents(path).slice(-count);
|
|
86
|
+
}
|
|
87
|
+
var SessionEventNotFoundError = class extends Error {
|
|
88
|
+
};
|
|
89
|
+
function loadSessionEvents(sessionId, home) {
|
|
90
|
+
const path = locateTranscript(sessionId, home);
|
|
91
|
+
return path === void 0 ? void 0 : readSessionEvents(path);
|
|
92
|
+
}
|
|
93
|
+
function pickSessionEvent(events, id) {
|
|
94
|
+
if (events === void 0) {
|
|
95
|
+
throw new SessionEventNotFoundError(`event ${id}: this session's transcript was not found on this machine`);
|
|
96
|
+
}
|
|
97
|
+
const found = events.find((event) => event.id === id);
|
|
98
|
+
if (found === void 0) {
|
|
99
|
+
throw new SessionEventNotFoundError(`event ${id} is not in this session's transcript \u2014 pick an id from the list \`outerlayer emit finding\` prints`);
|
|
100
|
+
}
|
|
101
|
+
return { id: found.id, at: found.at };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/emit-finding-output.ts
|
|
105
|
+
var NEEDS_CHOICE_EXIT_CODE = 3;
|
|
106
|
+
function clock(iso) {
|
|
107
|
+
const date = new Date(iso);
|
|
108
|
+
return [date.getHours(), date.getMinutes(), date.getSeconds()].map((n) => String(n).padStart(2, "0")).join(":");
|
|
109
|
+
}
|
|
110
|
+
function formatRecentEvents(events) {
|
|
111
|
+
if (events.length === 0) return "";
|
|
112
|
+
const lines = events.map((event) => ` ${event.id.padEnd(7)} ${clock(event.at)} ${event.summary}`);
|
|
113
|
+
return [
|
|
114
|
+
"Recent events in this session (id, local time, what happened):",
|
|
115
|
+
...lines,
|
|
116
|
+
"To record time lost, run again with --started-at <id of the event where you first hit the problem>",
|
|
117
|
+
"and --ended-at <id of the event where you got past it>. The time is read from those events."
|
|
118
|
+
].join("\n");
|
|
119
|
+
}
|
|
120
|
+
function plain(text) {
|
|
121
|
+
return text.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]+/g, " ").trim();
|
|
122
|
+
}
|
|
123
|
+
function quoted(title) {
|
|
124
|
+
return `"${plain(title)}"`;
|
|
125
|
+
}
|
|
126
|
+
function storedLine(result) {
|
|
127
|
+
const problems = result.problems ?? [];
|
|
128
|
+
const where = problems.length === 0 ? "" : ` \u2192 ${problems.map((p) => `problem ${plain(p.id)} ${quoted(p.title)}`).join(", ")}`;
|
|
129
|
+
const how = result.method === "kept" ? " (kept the problems it already had)" : result.method ? ` (${result.method})` : "";
|
|
130
|
+
const lines = [` ${result.id}${where}${how}`];
|
|
131
|
+
for (const replaced of result.overridden ?? []) {
|
|
132
|
+
lines.push(` ${quoted(replaced.title)} (${plain(replaced.id)}) was not linked: a key of this finding is owned by the problem above`);
|
|
133
|
+
}
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
function formatStored(results) {
|
|
137
|
+
const stored = results.filter((r) => r.outcome === "stored");
|
|
138
|
+
if (stored.length === 0) return "";
|
|
139
|
+
return ["Joined problems:", ...stored.map(storedLine)].join("\n");
|
|
140
|
+
}
|
|
141
|
+
function formatCandidates(results, rerun) {
|
|
142
|
+
const pending = results.filter((r) => r.outcome === "needs_choice");
|
|
143
|
+
if (pending.length === 0) return "";
|
|
144
|
+
const blocks = [];
|
|
145
|
+
for (const result of pending) {
|
|
146
|
+
const lines = [`Finding ${result.id} was not stored. These problems may be the same one:`];
|
|
147
|
+
for (const candidate of result.candidates ?? []) {
|
|
148
|
+
lines.push(
|
|
149
|
+
"",
|
|
150
|
+
` ${plain(candidate.id)} ${quoted(candidate.title)} (${candidate.reportCount} ${candidate.reportCount === 1 ? "report" : "reports"})`
|
|
151
|
+
);
|
|
152
|
+
for (const report of candidate.reports) {
|
|
153
|
+
const cause = report.cause ? `cause: ${plain(report.cause)}` : "cause: not recorded";
|
|
154
|
+
lines.push(` - ${quoted(report.title)} ${cause}${report.file ? ` (${plain(report.file)})` : ""}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
blocks.push(lines.join("\n"));
|
|
158
|
+
}
|
|
159
|
+
return [blocks.join("\n\n"), "", "What counts as the same problem:", SAME_PROBLEM_RULES, "", rerun].join("\n");
|
|
160
|
+
}
|
|
161
|
+
var RERUN_SINGLE = 'Run the same command again with --problem <id> --link-reason "<why>" (one --problem for each problem this finding reports), or with --new if none of these is the same problem.';
|
|
162
|
+
function rerunBatch(file) {
|
|
163
|
+
const target = file === "-" ? "the batch" : file;
|
|
164
|
+
return `In ${target}, give each finding listed above "problems": [<id>, ...] with "linkReason": "<why>", or "new": true if none of these is the same problem. Then run emit findings again: the findings already stored are updated in place.`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// src/emit-finding-cmd.ts
|
|
168
|
+
var GREEN = "\x1B[32m";
|
|
169
|
+
var DIM = "\x1B[2m";
|
|
170
|
+
var RESET = "\x1B[0m";
|
|
171
|
+
var EmitFindingError = class extends Error {
|
|
172
|
+
};
|
|
173
|
+
var REMOVED_FINDING_FLAGS = ["subject", "kind", "severity", "verdict", "fixed", "source"];
|
|
174
|
+
function refuseRemovedFindingFlags(opts) {
|
|
175
|
+
const used = REMOVED_FINDING_FLAGS.find((flag) => opts[flag] !== void 0);
|
|
176
|
+
if (used === void 0) return;
|
|
177
|
+
throw new EmitFindingError(
|
|
178
|
+
`--${used} is no longer accepted: findings record problems in the factory, not review verdicts. Pass --category <context|flaky-test|tooling|environment|defect|other> instead.`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
function parseItemFlag(raw) {
|
|
182
|
+
if (raw === void 0) return void 0;
|
|
183
|
+
const number = parseTrackerNumber(raw);
|
|
184
|
+
if (number === void 0) {
|
|
185
|
+
throw new EmitFindingError(trackerNumberError("--item", raw));
|
|
186
|
+
}
|
|
187
|
+
return { number };
|
|
188
|
+
}
|
|
189
|
+
function parseIntFlag(raw, flag, opts) {
|
|
190
|
+
if (raw === void 0) return void 0;
|
|
191
|
+
if (!/^-?\d+$/.test(raw)) {
|
|
192
|
+
throw new EmitFindingError(`invalid ${flag} "${raw}" \u2014 expected a whole number`);
|
|
193
|
+
}
|
|
194
|
+
const n = Number(raw);
|
|
195
|
+
if (!Number.isSafeInteger(n) || n < opts.min) {
|
|
196
|
+
throw new EmitFindingError(`invalid ${flag} "${raw}" \u2014 expected a whole number >= ${opts.min}`);
|
|
197
|
+
}
|
|
198
|
+
return n;
|
|
199
|
+
}
|
|
200
|
+
async function readAllStdin() {
|
|
201
|
+
const chunks = [];
|
|
202
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
203
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
204
|
+
}
|
|
205
|
+
function recordFromFlags(opts) {
|
|
206
|
+
const line = parseIntFlag(opts.line, "--line", { min: 1 });
|
|
207
|
+
const ruleLine = parseIntFlag(opts.ruleLine, "--rule-line", { min: 1 });
|
|
208
|
+
const turnIndex = parseIntFlag(opts.turn, "--turn", { min: 0 });
|
|
209
|
+
const round = parseIntFlag(opts.round, "--round", { min: 0 });
|
|
210
|
+
const hasRule = opts.rulePath !== void 0 || opts.ruleQuote !== void 0 || opts.ruleRelation !== void 0 || ruleLine !== void 0;
|
|
211
|
+
return {
|
|
212
|
+
id: opts.id,
|
|
213
|
+
category: opts.category,
|
|
214
|
+
title: opts.title,
|
|
215
|
+
file: opts.file,
|
|
216
|
+
line: line ?? null,
|
|
217
|
+
rule: hasRule ? {
|
|
218
|
+
path: opts.rulePath,
|
|
219
|
+
line: ruleLine ?? null,
|
|
220
|
+
...opts.ruleQuote !== void 0 ? { quote: opts.ruleQuote } : {},
|
|
221
|
+
relation: opts.ruleRelation
|
|
222
|
+
} : null,
|
|
223
|
+
where: {
|
|
224
|
+
label: opts.where,
|
|
225
|
+
...opts.traceId !== void 0 ? { traceId: opts.traceId } : {},
|
|
226
|
+
...turnIndex !== void 0 ? { turnIndex } : {},
|
|
227
|
+
...round !== void 0 ? { round } : {}
|
|
228
|
+
},
|
|
229
|
+
detail: opts.detail,
|
|
230
|
+
cause: opts.cause,
|
|
231
|
+
suggestion: opts.suggestion,
|
|
232
|
+
command: opts.command,
|
|
233
|
+
error: opts.error,
|
|
234
|
+
test: opts.test,
|
|
235
|
+
symbol: opts.symbol,
|
|
236
|
+
...opts.problem !== void 0 && opts.problem.length > 0 ? { problems: opts.problem } : {},
|
|
237
|
+
linkReason: opts.linkReason,
|
|
238
|
+
...opts.new === true ? { new: true } : {},
|
|
239
|
+
// Event ids, resolved to { id, at } against the session transcript
|
|
240
|
+
// before the batch is validated.
|
|
241
|
+
startedAt: opts.startedAt,
|
|
242
|
+
endedAt: opts.endedAt
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function resolveEvents(finding, sessionId, loadEvents) {
|
|
246
|
+
const out = { ...finding };
|
|
247
|
+
for (const key of ["startedAt", "endedAt"]) {
|
|
248
|
+
const value = out[key];
|
|
249
|
+
if (typeof value !== "string") continue;
|
|
250
|
+
if (sessionId === void 0) {
|
|
251
|
+
throw new EmitFindingError(
|
|
252
|
+
`${key === "startedAt" ? "--started-at" : "--ended-at"} names an event of the recording session, but no recorded session was found here`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
out[key] = pickSessionEvent(loadEvents(sessionId), value);
|
|
257
|
+
} catch (err) {
|
|
258
|
+
throw new EmitFindingError(err.message);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
263
|
+
function eventLoader(home) {
|
|
264
|
+
let loaded = false;
|
|
265
|
+
let events;
|
|
266
|
+
return (sessionId) => {
|
|
267
|
+
if (!loaded) {
|
|
268
|
+
events = loadSessionEvents(sessionId, home);
|
|
269
|
+
loaded = true;
|
|
270
|
+
}
|
|
271
|
+
return events;
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function firstIssueMessage(result) {
|
|
275
|
+
const issue = result.error.issues[0];
|
|
276
|
+
return issue ? `${issue.path.join(".")}: ${issue.message}` : "malformed";
|
|
277
|
+
}
|
|
278
|
+
function detectUploadSessionId(opts) {
|
|
279
|
+
const identity = resolveRepoIdentity(opts.cwd);
|
|
280
|
+
return detectActiveSession({
|
|
281
|
+
env: opts.env,
|
|
282
|
+
home: opts.home,
|
|
283
|
+
cwds: identity.repoRoot !== void 0 ? [identity.repoRoot, opts.cwd] : [opts.cwd],
|
|
284
|
+
nowMs: opts.now().getTime()
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
function resolveUploadTarget(opts) {
|
|
288
|
+
const item = parseItemFlag(opts.item);
|
|
289
|
+
const sessionId = opts.sessionId;
|
|
290
|
+
if (sessionId !== void 0) {
|
|
291
|
+
const refusal = launchRefusalForSession(sessionId, opts.home);
|
|
292
|
+
if (refusal !== void 0) throw new EmitFindingError(refusal);
|
|
293
|
+
}
|
|
294
|
+
if (item !== void 0) {
|
|
295
|
+
return sessionId !== void 0 ? { item, sessionId } : { item };
|
|
296
|
+
}
|
|
297
|
+
if (sessionId === void 0) {
|
|
298
|
+
throw new EmitFindingError(
|
|
299
|
+
"nothing to attach this to \u2014 no work item. Pass --item <number>, or run inside a recorded session launched with OUTERLAYER_WORK \u2014 its own launch record names the item automatically."
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
const launchedNumber = launchedItemForSession(sessionId, opts.home);
|
|
303
|
+
if (launchedNumber === void 0) {
|
|
304
|
+
throw new EmitFindingError(
|
|
305
|
+
"nothing to attach this to \u2014 no work item. Pass --item <number>; this recorded session's own launch record names no item either."
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
return { item: { number: launchedNumber }, sessionId };
|
|
309
|
+
}
|
|
310
|
+
async function upload(batch, target, opts) {
|
|
311
|
+
const refusal = await autoConnect(opts);
|
|
312
|
+
if (refusal !== void 0) throw new EmitFindingError(refusal);
|
|
313
|
+
const resolved = resolveGatewayCredentials(opts);
|
|
314
|
+
if (!resolved.ok) throw new EmitFindingError(resolved.message);
|
|
315
|
+
const { url, credential: apiKey, appId } = resolved;
|
|
316
|
+
const request = {
|
|
317
|
+
...batch,
|
|
318
|
+
item: target.item,
|
|
319
|
+
...target.sessionId !== void 0 ? { sessionId: target.sessionId } : {}
|
|
320
|
+
};
|
|
321
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
322
|
+
const endpoint = new URL("/v1/findings", url).toString();
|
|
323
|
+
let response;
|
|
324
|
+
try {
|
|
325
|
+
response = await fetchImpl(endpoint, {
|
|
326
|
+
method: "POST",
|
|
327
|
+
headers: {
|
|
328
|
+
"content-type": "application/json",
|
|
329
|
+
authorization: `Bearer ${apiKey}`,
|
|
330
|
+
"x-outerlayer-app-id": appId
|
|
331
|
+
},
|
|
332
|
+
body: JSON.stringify(request)
|
|
333
|
+
});
|
|
334
|
+
} catch (err) {
|
|
335
|
+
throw new EmitFindingError(`network error reaching ${endpoint}: ${String(err)}`);
|
|
336
|
+
}
|
|
337
|
+
if (response.status === 401) {
|
|
338
|
+
throw new EmitFindingError(
|
|
339
|
+
unauthorizedMessage(apiKey)
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
let detail = "";
|
|
344
|
+
try {
|
|
345
|
+
detail = (await response.text()).replace(/\s+/g, " ").trim().slice(0, 160);
|
|
346
|
+
} catch {
|
|
347
|
+
}
|
|
348
|
+
throw new EmitFindingError(`emit failed (${response.status})${detail ? `: ${detail}` : ""}`);
|
|
349
|
+
}
|
|
350
|
+
let data = {};
|
|
351
|
+
try {
|
|
352
|
+
data = (await response.json()).data ?? {};
|
|
353
|
+
} catch {
|
|
354
|
+
}
|
|
355
|
+
const count = typeof data.count === "number" ? data.count : batch.findings.length;
|
|
356
|
+
const parsedResponse = FindingsResponseSchema.safeParse(data);
|
|
357
|
+
const results = parsedResponse.success ? parsedResponse.data.results : [];
|
|
358
|
+
const needsChoice = results.some((r) => r.outcome === "needs_choice");
|
|
359
|
+
const exitCode = needsChoice ? NEEDS_CHOICE_EXIT_CODE : 0;
|
|
360
|
+
let output;
|
|
361
|
+
if (opts.json) {
|
|
362
|
+
output = JSON.stringify(data);
|
|
363
|
+
} else {
|
|
364
|
+
const summary = `${GREEN}\u2713${RESET} recorded ${count} ${count === 1 ? "finding" : "findings"} ${DIM}\xB7${RESET} item #${target.item.number}`;
|
|
365
|
+
output = [
|
|
366
|
+
opts.eventsBlock ?? "",
|
|
367
|
+
count > 0 || !needsChoice ? summary : "",
|
|
368
|
+
formatStored(results),
|
|
369
|
+
formatCandidates(results, opts.rerun)
|
|
370
|
+
].filter((part) => part !== "").join("\n\n");
|
|
371
|
+
}
|
|
372
|
+
if (!opts.quiet) process.stdout.write(output + "\n");
|
|
373
|
+
return { data, output, exitCode };
|
|
374
|
+
}
|
|
375
|
+
async function runEmitFinding(opts) {
|
|
376
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
377
|
+
const home = opts.home ?? homeFromEnv();
|
|
378
|
+
const env = opts.env ?? process.env;
|
|
379
|
+
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
380
|
+
const sessionId = detectUploadSessionId({ cwd, home, env, now });
|
|
381
|
+
const contextSourceSha = opts.contextSourceSha ?? (sessionId !== void 0 ? readLatestProvenanceForSession(sessionId, home)?.sha ?? void 0 : void 0);
|
|
382
|
+
const rawBatch = {
|
|
383
|
+
schemaVersion: 3,
|
|
384
|
+
...opts.headSha !== void 0 ? { headSha: opts.headSha } : {},
|
|
385
|
+
...contextSourceSha !== void 0 ? { contextSourceSha } : {},
|
|
386
|
+
findings: [resolveEvents(recordFromFlags(opts), sessionId, eventLoader(home))]
|
|
387
|
+
};
|
|
388
|
+
const parsed = FindingBatchSchema.safeParse(rawBatch);
|
|
389
|
+
if (!parsed.success) {
|
|
390
|
+
throw new EmitFindingError(`invalid finding \u2014 ${firstIssueMessage(parsed)}`);
|
|
391
|
+
}
|
|
392
|
+
const target = resolveUploadTarget({ item: opts.item, sessionId, home });
|
|
393
|
+
const events = opts.startedAt === void 0 && sessionId !== void 0 ? recentSessionEvents(sessionId, home) : void 0;
|
|
394
|
+
return upload(parsed.data, target, {
|
|
395
|
+
json: opts.json,
|
|
396
|
+
url: opts.url,
|
|
397
|
+
apiKey: opts.apiKey,
|
|
398
|
+
appId: opts.appId,
|
|
399
|
+
cwd,
|
|
400
|
+
quiet: opts.quiet,
|
|
401
|
+
home,
|
|
402
|
+
env,
|
|
403
|
+
fetchImpl: opts.fetchImpl,
|
|
404
|
+
eventsBlock: events !== void 0 && !opts.json ? formatRecentEvents(events) : void 0,
|
|
405
|
+
rerun: RERUN_SINGLE
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
async function runEmitFindings(opts) {
|
|
409
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
410
|
+
const home = opts.home ?? homeFromEnv();
|
|
411
|
+
const env = opts.env ?? process.env;
|
|
412
|
+
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
413
|
+
let text;
|
|
414
|
+
if (opts.file === "-") {
|
|
415
|
+
text = await (opts.readStdin ?? readAllStdin)();
|
|
416
|
+
} else {
|
|
417
|
+
try {
|
|
418
|
+
text = readFileSync(opts.file, "utf8");
|
|
419
|
+
} catch (err) {
|
|
420
|
+
throw new EmitFindingError(`cannot read "${opts.file}": ${String(err)}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
let raw;
|
|
424
|
+
try {
|
|
425
|
+
raw = JSON.parse(text);
|
|
426
|
+
} catch (err) {
|
|
427
|
+
throw new EmitFindingError(`"${opts.file}" is not valid JSON: ${String(err)}`);
|
|
428
|
+
}
|
|
429
|
+
const version = raw?.schemaVersion;
|
|
430
|
+
if (version === 1 || version === 2) {
|
|
431
|
+
throw new EmitFindingError(
|
|
432
|
+
`"${opts.file}" uses schemaVersion ${version}, which is no longer accepted. Use schemaVersion 3: each finding takes a category (context, flaky-test, tooling, environment, defect or other), and may carry detail, cause, suggestion, command, error, test, symbol, problems with linkReason, or new.`
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
const sessionId = detectUploadSessionId({ cwd, home, env, now });
|
|
436
|
+
if (Array.isArray(raw?.findings)) {
|
|
437
|
+
const batch = raw;
|
|
438
|
+
const loadEvents = eventLoader(home);
|
|
439
|
+
raw = {
|
|
440
|
+
...batch,
|
|
441
|
+
findings: batch.findings.map(
|
|
442
|
+
(entry) => typeof entry === "object" && entry !== null ? resolveEvents(entry, sessionId, loadEvents) : entry
|
|
443
|
+
)
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
const parsed = FindingBatchSchema.safeParse(raw);
|
|
447
|
+
if (!parsed.success) {
|
|
448
|
+
throw new EmitFindingError(`invalid finding batch \u2014 ${firstIssueMessage(parsed)}`);
|
|
449
|
+
}
|
|
450
|
+
const target = resolveUploadTarget({ item: opts.item, sessionId, home });
|
|
451
|
+
return upload(parsed.data, target, {
|
|
452
|
+
json: opts.json,
|
|
453
|
+
url: opts.url,
|
|
454
|
+
apiKey: opts.apiKey,
|
|
455
|
+
appId: opts.appId,
|
|
456
|
+
cwd,
|
|
457
|
+
quiet: opts.quiet,
|
|
458
|
+
home,
|
|
459
|
+
env,
|
|
460
|
+
fetchImpl: opts.fetchImpl,
|
|
461
|
+
rerun: rerunBatch(opts.file)
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export { EmitFindingError, refuseRemovedFindingFlags, runEmitFinding, runEmitFindings };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { detectCi } from './chunk-
|
|
3
|
+
import { detectCi } from './chunk-3D4OYFCD.js';
|
|
4
4
|
import { launchRefusalForSession } from './chunk-HHJDN6AU.js';
|
|
5
5
|
import './chunk-TBT347UY.js';
|
|
6
6
|
import './chunk-F7CU5ABH.js';
|
|
7
7
|
import './chunk-BKO6JEZI.js';
|
|
8
|
-
import { autoConnect } from './chunk-
|
|
9
|
-
import { detectActiveSession } from './chunk-
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import { resolveRepoIdentity } from './chunk-
|
|
13
|
-
import './chunk-
|
|
8
|
+
import { autoConnect } from './chunk-EFZLAYPE.js';
|
|
9
|
+
import { detectActiveSession } from './chunk-IP7BIBXJ.js';
|
|
10
|
+
import './chunk-4QVZCVWT.js';
|
|
11
|
+
import './chunk-CNFVHDHG.js';
|
|
12
|
+
import { resolveRepoIdentity } from './chunk-JXYVA45C.js';
|
|
13
|
+
import './chunk-4KSQKQXE.js';
|
|
14
14
|
import './chunk-N6LURUEF.js';
|
|
15
15
|
import './chunk-YRYMNBGQ.js';
|
|
16
16
|
import './chunk-GQD22KKN.js';
|
|
@@ -19,11 +19,11 @@ import './chunk-5QRP3MVS.js';
|
|
|
19
19
|
import './chunk-ZJSNLVCE.js';
|
|
20
20
|
import { defaultFetch } from './chunk-YO4PSLVB.js';
|
|
21
21
|
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-PLMTLGYH.js';
|
|
22
|
-
import { EmittedNameSchema, EMITTED_RESULT_MAX_LINK_LENGTH, EMITTED_RESULTS, EMITTED_RESULT_MAX_BODY_LENGTH } from './chunk-
|
|
22
|
+
import { EmittedNameSchema, EMITTED_RESULT_MAX_LINK_LENGTH, EMITTED_RESULTS, EMITTED_RESULT_MAX_BODY_LENGTH } from './chunk-J5M7BSJQ.js';
|
|
23
23
|
import './chunk-EABW6AJQ.js';
|
|
24
24
|
import './chunk-V7NIVOFD.js';
|
|
25
25
|
import './chunk-ZM2IMMYN.js';
|
|
26
|
-
import './chunk-
|
|
26
|
+
import './chunk-SFFHGX3G.js';
|
|
27
27
|
import './chunk-XCCLFVXM.js';
|
|
28
28
|
import './chunk-BJ3KTMDH.js';
|
|
29
29
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
export { AUTO_SYNC_DEBOUNCE_MS, WORK_LEASE_RENEW_DEBOUNCE_MS, WORK_LINK_RETRIES, contextPossiblyGoverned, handleWorkLaunch, handleWorkSessionEnd, hookFiredMarkerPath, logHookError, markWorkLeaseRenewed, maybeAutoSync, maybeRenewWorkLease, recordLinkExitFailure, runHookFast, spoolDir } from './chunk-
|
|
3
|
+
export { AUTO_SYNC_DEBOUNCE_MS, WORK_LEASE_RENEW_DEBOUNCE_MS, WORK_LINK_RETRIES, contextPossiblyGoverned, handleWorkLaunch, handleWorkSessionEnd, hookFiredMarkerPath, logHookError, markWorkLeaseRenewed, maybeAutoSync, maybeRenewWorkLease, recordLinkExitFailure, runHookFast, spoolDir } from './chunk-SFFHGX3G.js';
|
|
4
4
|
import './chunk-XCCLFVXM.js';
|
|
5
5
|
import './chunk-BJ3KTMDH.js';
|
|
6
6
|
import './chunk-VNVZDWO3.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
3
|
+
import { loadMaintainedFiles, writeMaintainedFiles } from './chunk-TCIW27FM.js';
|
|
4
|
+
import './chunk-2M63GG56.js';
|
|
5
|
+
import './chunk-J5M7BSJQ.js';
|
|
6
6
|
import './chunk-RA3O54FC.js';
|
|
7
7
|
import './chunk-Z5GEFMRW.js';
|
|
8
8
|
import { statSync, existsSync, readFileSync, writeFileSync } from 'fs';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { normalizePath } from './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import { normalizePath } from './chunk-2M63GG56.js';
|
|
4
|
+
import './chunk-J5M7BSJQ.js';
|
|
5
5
|
import './chunk-Z5GEFMRW.js';
|
|
6
6
|
import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
|
|
7
7
|
import { join, dirname } from 'path';
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ createRequire(import.meta.url);
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
var argv = process.argv.slice(2);
|
|
8
8
|
if (argv[0] === "hook") {
|
|
9
|
-
const { runHookFast } = await import('./hook-fast-
|
|
9
|
+
const { runHookFast } = await import('./hook-fast-PXWKQPN6.js');
|
|
10
10
|
await runHookFast(argv[1]);
|
|
11
11
|
process.exit(0);
|
|
12
12
|
}
|
|
@@ -21,6 +21,6 @@ if (argv[0] === "statusline") {
|
|
|
21
21
|
await runStatuslineFast(argv.slice(1));
|
|
22
22
|
process.exit(0);
|
|
23
23
|
}
|
|
24
|
-
(await import('./hook-fast-
|
|
25
|
-
var { runCli } = await import('./cli-
|
|
24
|
+
(await import('./hook-fast-PXWKQPN6.js')).recordLinkExitFailure(argv);
|
|
25
|
+
var { runCli } = await import('./cli-WSBIAVZU.js');
|
|
26
26
|
await runCli(process.argv);
|
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
export { PLACEHOLDER_MARKER, RunnerInitError, isPlaceholderCommand, readConfigObject, runRunnerInit } from './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
3
|
+
export { PLACEHOLDER_MARKER, RunnerInitError, isPlaceholderCommand, prepareRunnerInit, readConfigObject, runRunnerInit, writeRunnerInit } from './chunk-MJXXRX4M.js';
|
|
4
|
+
import './chunk-P6FX4D43.js';
|
|
5
|
+
import './chunk-MZN7AQOB.js';
|
|
6
|
+
import './chunk-T5VPP6H7.js';
|
|
7
|
+
import './chunk-RLYZLUQ7.js';
|
|
8
|
+
import './chunk-6MZSX4M7.js';
|
|
6
9
|
import './chunk-3FMPZPJQ.js';
|
|
7
10
|
import './chunk-N5FOE5PS.js';
|
|
8
11
|
import './chunk-OGFGZQA3.js';
|
|
9
|
-
import './chunk-
|
|
12
|
+
import './chunk-3KTA5UU2.js';
|
|
10
13
|
import './chunk-QOZKPLVJ.js';
|
|
11
|
-
import './chunk-
|
|
14
|
+
import './chunk-NX57IBNK.js';
|
|
12
15
|
import './chunk-CX22S5BA.js';
|
|
13
16
|
import './chunk-QKFB4K7X.js';
|
|
14
17
|
import './chunk-RSNSZ2LJ.js';
|
|
15
|
-
import './chunk-
|
|
16
|
-
import './chunk-
|
|
17
|
-
import './chunk-
|
|
18
|
-
import './chunk-
|
|
19
|
-
import './chunk-
|
|
20
|
-
import './chunk-
|
|
21
|
-
import './chunk-
|
|
18
|
+
import './chunk-P4MM66C6.js';
|
|
19
|
+
import './chunk-EFZLAYPE.js';
|
|
20
|
+
import './chunk-IP7BIBXJ.js';
|
|
21
|
+
import './chunk-4QVZCVWT.js';
|
|
22
|
+
import './chunk-CNFVHDHG.js';
|
|
23
|
+
import './chunk-JXYVA45C.js';
|
|
24
|
+
import './chunk-4KSQKQXE.js';
|
|
22
25
|
import './chunk-N6LURUEF.js';
|
|
23
26
|
import './chunk-YRYMNBGQ.js';
|
|
27
|
+
import './chunk-22RMZBGW.js';
|
|
24
28
|
import './chunk-UXYLWVTQ.js';
|
|
25
29
|
import './chunk-7RQ73DLO.js';
|
|
26
30
|
import './chunk-4Q7OMKAT.js';
|
|
27
31
|
import './chunk-WZBHBH3J.js';
|
|
28
|
-
import './chunk-
|
|
32
|
+
import './chunk-GI4XXD4I.js';
|
|
29
33
|
import './chunk-ZJSNLVCE.js';
|
|
30
|
-
import './chunk-
|
|
31
|
-
import './chunk-
|
|
32
|
-
import './chunk-
|
|
34
|
+
import './chunk-TCIW27FM.js';
|
|
35
|
+
import './chunk-LCEXHCHD.js';
|
|
36
|
+
import './chunk-2M63GG56.js';
|
|
33
37
|
import './chunk-YO4PSLVB.js';
|
|
34
38
|
import './chunk-PLMTLGYH.js';
|
|
35
|
-
import './chunk-
|
|
39
|
+
import './chunk-J5M7BSJQ.js';
|
|
36
40
|
import './chunk-EABW6AJQ.js';
|
|
37
41
|
import './chunk-BYT5O5RV.js';
|
|
38
42
|
import './chunk-RA3O54FC.js';
|