@outerlayer/cli 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/README.md +229 -60
- package/dist/agent-setup-IFH3FB5X.js +197 -0
- package/dist/build-TZUUTRGH.js +9 -0
- package/dist/build-info.json +1 -1
- package/dist/check-7MFH6HNC.js +94 -0
- package/dist/chunk-3TFPDVTI.js +94 -0
- package/dist/{chunk-4TNZMO7V.js → chunk-4C4THABW.js} +5566 -754
- package/dist/{chunk-R5KBGVII.js → chunk-5QRP3MVS.js} +30 -14
- package/dist/chunk-5Y3QQRUH.js +300 -0
- package/dist/chunk-774HEQL6.js +178 -0
- package/dist/{work-pr-cmd-AZQPWH4H.js → chunk-7WERLFVR.js} +9 -26
- package/dist/chunk-ABIWDUMS.js +104 -0
- package/dist/chunk-AUFG23AA.js +534 -0
- package/dist/chunk-B2G7JHHB.js +42 -0
- package/dist/chunk-BCJNHMZT.js +34 -0
- package/dist/chunk-BCLJSQCV.js +56 -0
- package/dist/chunk-BFESLKPP.js +61 -0
- package/dist/chunk-BJ3KTMDH.js +63 -0
- package/dist/chunk-BKO6JEZI.js +47 -0
- package/dist/chunk-BOLTI6LR.js +37 -0
- package/dist/chunk-CBPPJSAR.js +89 -0
- package/dist/chunk-DM3VFDS3.js +1461 -0
- package/dist/{chunk-65WXAANR.js → chunk-DVDEBNQJ.js} +17 -2
- package/dist/{chunk-TFUIDMOB.js → chunk-EABW6AJQ.js} +12 -1
- package/dist/{chunk-KFYJV2ZG.js → chunk-EMY4I27X.js} +1 -1
- package/dist/{chunk-NTTPJV35.js → chunk-F47JBIAW.js} +3 -1
- package/dist/chunk-F6GFZXZ3.js +60 -0
- package/dist/{chunk-YOOSBOKS.js → chunk-F7CU5ABH.js} +1 -1
- package/dist/{emit-cmd-TWSYYEZI.js → chunk-H5NCNVDA.js} +68 -17
- package/dist/chunk-HZRNMGLF.js +2233 -0
- package/dist/chunk-LF6MLJCY.js +38 -0
- package/dist/{chunk-U32VSRLO.js → chunk-LT5TZHYH.js} +95 -634
- package/dist/chunk-LYCDNMOH.js +83 -0
- package/dist/chunk-M5POMKKW.js +1051 -0
- package/dist/{mcp-install-cmd-FDQH6SEN.js → chunk-MQ3IPHIZ.js} +35 -18
- package/dist/{chunk-D77LS3UI.js → chunk-N5FOE5PS.js} +33 -4
- package/dist/chunk-N6LURUEF.js +64 -0
- package/dist/chunk-OGFGZQA3.js +23 -0
- package/dist/chunk-QDQEUVUF.js +9 -0
- package/dist/chunk-QOZKPLVJ.js +226 -0
- package/dist/chunk-QY22NZUW.js +1764 -0
- package/dist/chunk-RA3O54FC.js +30 -0
- package/dist/chunk-RFUPN6KX.js +71 -0
- package/dist/chunk-SY4GK4SP.js +55 -0
- package/dist/chunk-TBT347UY.js +41 -0
- package/dist/chunk-TWNWNS2Q.js +1084 -0
- package/dist/{chunk-NXLLURA4.js → chunk-UFFXNXLQ.js} +115 -71
- package/dist/chunk-USO2DKBD.js +421 -0
- package/dist/chunk-W4SQCOZU.js +206 -0
- package/dist/{chunk-Q6CL5THG.js → chunk-W5FVUZXV.js} +208 -61
- package/dist/chunk-WFJ65NUD.js +383 -0
- package/dist/{chunk-A3WLZX2F.js → chunk-WIOZAJ2W.js} +15 -2
- package/dist/chunk-WO2BXCTQ.js +83 -0
- package/dist/{chunk-I3ETLSNE.js → chunk-XCCLFVXM.js} +120 -11
- package/dist/{context-materialize-6WKT3RBQ.js → chunk-XDDW4FRS.js} +134 -26
- package/dist/chunk-Y7KJLXYN.js +232 -0
- package/dist/chunk-YFHIIH4B.js +102 -0
- package/dist/chunk-YYYXRJUW.js +101 -0
- package/dist/chunk-ZM2IMMYN.js +76 -0
- package/dist/chunk-ZMYPLFG3.js +71 -0
- package/dist/chunk-ZNA27WEV.js +470 -0
- package/dist/{cli-G7DILYJY.js → cli-W62AFRSW.js} +616 -878
- package/dist/{paths-D2VGWWFI.js → cli-build-K56DK4DS.js} +1 -1
- package/dist/config-XVJYZ4IQ.js +9 -0
- package/dist/connect-cmd-ZTJONP37.js +16 -0
- package/dist/context-adopt-UMA4O5NY.js +105 -0
- package/dist/context-materialize-G2FUFC72.js +19 -0
- package/dist/dist-44CQVWGT.js +6 -0
- package/dist/docker-NEGDLU6D.js +7 -0
- package/dist/doctor-53F2PYY7.js +43 -0
- package/dist/doctor-ZLGZYMDK.js +426 -0
- package/dist/{emit-artifact-cmd-UQVT3OKW.js → emit-artifact-cmd-AKZP7TMF.js} +87 -23
- package/dist/emit-cmd-DCERAU27.js +9 -0
- package/dist/emit-criteria-cmd-7MXQVCKD.js +166 -0
- package/dist/{emit-finding-cmd-FDOU2OPD.js → emit-finding-cmd-N2FTGCVC.js} +34 -31
- package/dist/{emit-result-cmd-H2T4C2K3.js → emit-result-cmd-4CPDBMN2.js} +34 -62
- package/dist/exec-client-4XGXV3XN.js +8 -0
- package/dist/guest-init-GENRHNP7.js +8 -0
- package/dist/hook-fast-EYENPK6F.js +9 -0
- package/dist/{hook-wrap-fast-KXYNX3AD.js → hook-wrap-fast-NPLHJXFK.js} +2 -2
- package/dist/host-key-KDYZ5ECC.js +7 -0
- package/dist/import-capture-cmd-AVZ4VIVJ.js +68 -0
- package/dist/{import-ruler-cmd-7LH2QOMG.js → import-ruler-cmd-GUHL6IY5.js} +1 -1
- package/dist/index.js +4 -4
- package/dist/init-55Y4LHWF.js +36 -0
- package/dist/init-XXEKWZQP.js +221 -0
- package/dist/init-cmd-WLST2F7G.js +135 -0
- package/dist/install-cmd-7WXOIFDO.js +55 -0
- package/dist/lima-XN65D7GN.js +55 -0
- package/dist/login-browser-7XGSV7MA.js +10 -0
- package/dist/{config-POF7DEQW.js → logout-cmd-QAUFDJ6J.js} +3 -1
- package/dist/{logs-TRNPQM42.js → logs-7RYUH5A6.js} +1 -1
- package/dist/loop-JFIBP4B7.js +43 -0
- package/dist/machine-ZBPT2J3R.js +35 -0
- package/dist/mcp-install-cmd-RLK4SO3N.js +9 -0
- package/dist/{mcp-serve-cmd-57EZZOTL.js → mcp-serve-cmd-N6UD2KBX.js} +20 -9
- package/dist/paths-OYKMVYJP.js +6 -0
- package/dist/{pidfile-PTW76F56.js → pidfile-UZRH774M.js} +2 -3
- package/dist/real-deps-SU24ZA2K.js +21 -0
- package/dist/relay-L76HDX72.js +46 -0
- package/dist/settings-J2652U5N.js +7 -0
- package/dist/starter-pack-LIZYMKYQ.js +10 -0
- package/dist/{status-I27IST4L.js → status-UJXWZRN5.js} +30 -13
- package/dist/{statusline-fast-3C5OXHDD.js → statusline-fast-SVTMBMD7.js} +3 -2
- package/dist/sync-cmd-4G4A7EVN.js +28 -0
- package/dist/version-BWM6VLDI.js +6 -0
- package/dist/{watch-3DTPJETH.js → watch-7SKJKGAA.js} +19 -8
- package/dist/{work-claim-cmd-5AUNCLS2.js → work-claim-cmd-5F7VZ42N.js} +34 -21
- package/dist/work-cmd-QAUZ7MTD.js +17 -0
- package/dist/work-comment-cmd-BNCSBTLH.js +106 -0
- package/dist/{work-launch-LT663PB3.js → work-launch-YI4CJDAP.js} +1 -1
- package/dist/work-open-pr-cmd-VFYZHIIW.js +156 -0
- package/dist/work-pr-cmd-PV32ZLSI.js +16 -0
- package/package.json +13 -3
- package/skill-pack/maintained/amend/SKILL.md +104 -0
- package/skill-pack/maintained/emitting-evidence/SKILL.md +108 -0
- package/skill-pack/maintained/emitting-evidence/references/agents-snippet.md +20 -0
- package/skill-pack/maintained/outerlayer/SKILL.md +55 -0
- package/skill-pack/maintained/reporting-findings/SKILL.md +148 -0
- package/skill-pack/template/build/SKILL.md +193 -0
- package/skill-pack/template/build/references/agent-briefs.md +243 -0
- package/skill-pack/template/build/references/criteria-judge.md +91 -0
- package/skill-pack/template/build/references/evidence.md +42 -0
- package/skill-pack/template/build/references/release.md +74 -0
- package/skill-pack/template/build/references/review-briefs.md +275 -0
- package/skill-pack/template/build/references/review-loop.md +158 -0
- package/skill-pack/template/build/scripts/record-criteria.mjs +235 -0
- package/skill-pack/template/spec/SKILL.md +84 -0
- package/skill-pack/template/writing-specs/SKILL.md +134 -0
- package/dist/chunk-DCNOXRMV.js +0 -589
- package/dist/chunk-JJP7YLMN.js +0 -25
- package/dist/chunk-OZ7C3XUE.js +0 -34
- package/dist/chunk-WQ6VGRGZ.js +0 -150
- package/dist/hook-fast-J5LCDHUJ.js +0 -8
- package/dist/import-capture-cmd-EUMBGIV3.js +0 -176
- package/dist/init-PTBITAUO.js +0 -103
- package/dist/login-cmd-IRX6LZT7.js +0 -62
- package/dist/loop-ASZRX3CZ.js +0 -648
- package/dist/sync-cmd-BBAUZ5JD.js +0 -17
- package/dist/work-cmd-2P4BVX47.js +0 -18
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import { staleBuildRefusal, staleBuildWarning
|
|
4
|
-
import {
|
|
3
|
+
import { staleBuildRefusal, staleBuildWarning } from './chunk-LT5TZHYH.js';
|
|
4
|
+
import { detectCi } from './chunk-LYCDNMOH.js';
|
|
5
|
+
import { launchRefusalForSession } from './chunk-BCJNHMZT.js';
|
|
6
|
+
import './chunk-TBT347UY.js';
|
|
7
|
+
import './chunk-F7CU5ABH.js';
|
|
8
|
+
import './chunk-BKO6JEZI.js';
|
|
9
|
+
import { detectActiveSession } from './chunk-BFESLKPP.js';
|
|
10
|
+
import { readEffectiveArtifactSpoolState, localArtifactIds, isArtifactTombstoned, artifactBlobsDir, appendArtifactRecord, artifactsSpoolPath, findPendingArtifactRecord, appendArtifactTombstone } from './chunk-WFJ65NUD.js';
|
|
11
|
+
import { ARTIFACT_MAX_CAPTION_LENGTH, ArtifactCriterionIdSchema, ARTIFACT_MAX_FILENAME_LENGTH, mediaTypeForArtifactPath, inferArtifactKind, resolveRepoIdentity, ARTIFACT_MAX_REPLACES_TARGETS, parseTestSelector, parseJunit, bindTests } from './chunk-4C4THABW.js';
|
|
5
12
|
import './chunk-YRYMNBGQ.js';
|
|
6
|
-
import './chunk-
|
|
13
|
+
import './chunk-DVDEBNQJ.js';
|
|
7
14
|
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
15
|
+
import './chunk-5QRP3MVS.js';
|
|
8
16
|
import './chunk-ZJSNLVCE.js';
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import './chunk-
|
|
13
|
-
import
|
|
17
|
+
import { defaultFetch } from './chunk-BCLJSQCV.js';
|
|
18
|
+
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
|
|
19
|
+
import './chunk-EABW6AJQ.js';
|
|
20
|
+
import './chunk-M5POMKKW.js';
|
|
21
|
+
import './chunk-ZM2IMMYN.js';
|
|
22
|
+
import './chunk-UFFXNXLQ.js';
|
|
23
|
+
import './chunk-XCCLFVXM.js';
|
|
24
|
+
import './chunk-BJ3KTMDH.js';
|
|
14
25
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
15
26
|
import './chunk-Z5GEFMRW.js';
|
|
16
27
|
import { createHash, randomUUID } from 'crypto';
|
|
@@ -77,6 +88,52 @@ function prNumberFromCiEnv(env) {
|
|
|
77
88
|
}
|
|
78
89
|
return void 0;
|
|
79
90
|
}
|
|
91
|
+
function prHeadShaFromCiEnv(env) {
|
|
92
|
+
if (!env.GITHUB_EVENT_PATH) return void 0;
|
|
93
|
+
try {
|
|
94
|
+
const event = JSON.parse(readFileSync(env.GITHUB_EVENT_PATH, "utf8"));
|
|
95
|
+
const sha = event.pull_request?.head?.sha;
|
|
96
|
+
return typeof sha === "string" && /^[0-9a-f]{40,64}$/i.test(sha) ? sha.toLowerCase() : void 0;
|
|
97
|
+
} catch {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function checkTestResults(params) {
|
|
102
|
+
const { file, bytes, mediaType, criterionId, rawTests, warn } = params;
|
|
103
|
+
const selection = [];
|
|
104
|
+
for (const raw of rawTests) {
|
|
105
|
+
const parsedSelector = parseTestSelector(raw);
|
|
106
|
+
if (!parsedSelector.ok) throw new EmitArtifactError(`invalid --test "${raw}" \u2014 ${parsedSelector.message}`);
|
|
107
|
+
if (selection.some((entry) => entry.name === parsedSelector.test.name)) {
|
|
108
|
+
throw new EmitArtifactError(`invalid --test \u2014 "${parsedSelector.test.name}" is named more than once`);
|
|
109
|
+
}
|
|
110
|
+
selection.push(parsedSelector.test);
|
|
111
|
+
}
|
|
112
|
+
if (selection.length > 0 && criterionId === void 0) {
|
|
113
|
+
throw new EmitArtifactError("--test names tests that prove a criterion \u2014 add --for <criterion-id>");
|
|
114
|
+
}
|
|
115
|
+
if (mediaType !== "application/xml") {
|
|
116
|
+
if (selection.length > 0) {
|
|
117
|
+
throw new EmitArtifactError(`--test needs a JUnit XML file, but ${file} is not an .xml file`);
|
|
118
|
+
}
|
|
119
|
+
return void 0;
|
|
120
|
+
}
|
|
121
|
+
if (criterionId === void 0) return void 0;
|
|
122
|
+
const parsed = parseJunit(bytes);
|
|
123
|
+
if (parsed.kind === "refused") throw new EmitArtifactError(`${file} cannot be read as test results \u2014 ${parsed.message}`);
|
|
124
|
+
if (parsed.kind === "other") {
|
|
125
|
+
if (selection.length > 0) {
|
|
126
|
+
throw new EmitArtifactError(`--test needs JUnit XML, but ${file} has no <testsuites> or <testsuite> root`);
|
|
127
|
+
}
|
|
128
|
+
return void 0;
|
|
129
|
+
}
|
|
130
|
+
const bound = bindTests(parsed, selection);
|
|
131
|
+
if (!bound.ok) throw new EmitArtifactError(`${file} has no test named "${bound.missing}"`);
|
|
132
|
+
for (const name of bound.duplicates) {
|
|
133
|
+
warn(`${file} has more than one test named "${name}"; all of them are bound, so each must pass`);
|
|
134
|
+
}
|
|
135
|
+
return selection.length > 0 ? selection : void 0;
|
|
136
|
+
}
|
|
80
137
|
async function runEmitArtifact(opts) {
|
|
81
138
|
const env = opts.env ?? process.env;
|
|
82
139
|
const refusal = staleBuildRefusal(env);
|
|
@@ -177,6 +234,17 @@ async function runEmitArtifact(opts) {
|
|
|
177
234
|
}
|
|
178
235
|
const mediaType = mediaTypeForArtifactPath(filePath);
|
|
179
236
|
const kind = inferArtifactKind(mediaType);
|
|
237
|
+
const tests = checkTestResults({
|
|
238
|
+
file: opts.file,
|
|
239
|
+
bytes,
|
|
240
|
+
mediaType,
|
|
241
|
+
criterionId,
|
|
242
|
+
rawTests: opts.tests ?? [],
|
|
243
|
+
warn: (message) => {
|
|
244
|
+
if (!opts.quiet) process.stderr.write(`${YELLOW}!${RESET} ${message}
|
|
245
|
+
`);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
180
248
|
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
181
249
|
const identity = resolveRepoIdentity(cwd);
|
|
182
250
|
const sessionId = detectActiveSession({
|
|
@@ -213,7 +281,8 @@ async function runEmitArtifact(opts) {
|
|
|
213
281
|
caption,
|
|
214
282
|
...criterionId !== void 0 ? { criterionId } : {},
|
|
215
283
|
...replacesTargets !== void 0 ? { replaces: replacesTargets[0] } : {},
|
|
216
|
-
...replacesTargets !== void 0 && replacesTargets.length > 1 ? { replacesTargets } : {}
|
|
284
|
+
...replacesTargets !== void 0 && replacesTargets.length > 1 ? { replacesTargets } : {},
|
|
285
|
+
...tests !== void 0 ? { tests } : {}
|
|
217
286
|
};
|
|
218
287
|
try {
|
|
219
288
|
appendArtifactRecord(record, home);
|
|
@@ -251,17 +320,11 @@ async function runEmitArtifact(opts) {
|
|
|
251
320
|
"nothing to attach this to \u2014 no recorded session, no PR, and no git repo. Run inside a recorded Claude Code session, from a git checkout, in CI with PR context, or pass --pr <number>."
|
|
252
321
|
);
|
|
253
322
|
}
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
const appId = opts.appId ?? env.OUTERLAYER_APP_ID ?? fileConfig.appId;
|
|
258
|
-
if (!url || !apiKey || !appId) {
|
|
259
|
-
const missing = [!url && "--url", !apiKey && "--api-key", !appId && "--app-id"].filter(Boolean).join(", ");
|
|
260
|
-
throw new EmitArtifactError(
|
|
261
|
-
`missing ${missing}. Run \`outerlayer login --url <your gateway>\` and paste the key at the prompt, or set OUTERLAYER_URL / OUTERLAYER_API_KEY / OUTERLAYER_APP_ID. Mint a key in the dashboard: Settings \u2192 API keys.`
|
|
262
|
-
);
|
|
263
|
-
}
|
|
323
|
+
const resolved = resolveGatewayCredentials({ ...opts, home, env });
|
|
324
|
+
if (!resolved.ok) throw new EmitArtifactError(resolved.message);
|
|
325
|
+
const { url, credential: apiKey, appId } = resolved;
|
|
264
326
|
const clientArtifactId = randomUUID();
|
|
327
|
+
const commitSha = prHeadShaFromCiEnv(env) ?? identity.commitSha;
|
|
265
328
|
const singleTarget = replacesTargets !== void 0 && replacesTargets.length === 1 ? replacesTargets[0] : void 0;
|
|
266
329
|
const targetPendingLocally = singleTarget !== void 0 && findPendingArtifactRecord(singleTarget, home) !== void 0;
|
|
267
330
|
const directTargets = targetPendingLocally ? void 0 : replacesTargets;
|
|
@@ -281,13 +344,14 @@ async function runEmitArtifact(opts) {
|
|
|
281
344
|
...repository !== void 0 ? { repository } : {},
|
|
282
345
|
...identity.gitRepo !== void 0 ? { gitRepo: identity.gitRepo } : {},
|
|
283
346
|
...identity.gitBranch !== void 0 ? { gitBranch: identity.gitBranch } : {},
|
|
284
|
-
...
|
|
347
|
+
...commitSha !== void 0 ? { commitSha } : {},
|
|
285
348
|
...directTargets !== void 0 && directTargets.length > 0 ? { replaces: directTargets[0] } : {},
|
|
286
|
-
...directTargets !== void 0 && directTargets.length > 1 ? { replacesTargets: directTargets } : {}
|
|
349
|
+
...directTargets !== void 0 && directTargets.length > 1 ? { replacesTargets: directTargets } : {},
|
|
350
|
+
...tests !== void 0 ? { tests } : {}
|
|
287
351
|
},
|
|
288
352
|
blob: { data: bytes.toString("base64") }
|
|
289
353
|
};
|
|
290
|
-
const fetchImpl = opts.fetchImpl ??
|
|
354
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
291
355
|
const endpoint = new URL("/v1/artifacts", url).toString();
|
|
292
356
|
let response;
|
|
293
357
|
try {
|
|
@@ -305,7 +369,7 @@ async function runEmitArtifact(opts) {
|
|
|
305
369
|
}
|
|
306
370
|
if (response.status === 401) {
|
|
307
371
|
throw new EmitArtifactError(
|
|
308
|
-
|
|
372
|
+
unauthorizedMessage(apiKey)
|
|
309
373
|
);
|
|
310
374
|
}
|
|
311
375
|
if (!response.ok) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
export { EmitError, runEmit } from './chunk-H5NCNVDA.js';
|
|
4
|
+
import './chunk-WO2BXCTQ.js';
|
|
5
|
+
import './chunk-EMY4I27X.js';
|
|
6
|
+
import './chunk-RA3O54FC.js';
|
|
7
|
+
import './chunk-Z5GEFMRW.js';
|
|
8
|
+
|
|
9
|
+
createRequire(import.meta.url);
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { launchRefusalForSession } from './chunk-BCJNHMZT.js';
|
|
4
|
+
import { detectActiveSession } from './chunk-BFESLKPP.js';
|
|
5
|
+
import { resolveRepoIdentity, CriteriaListSchema } from './chunk-4C4THABW.js';
|
|
6
|
+
import { launchedItemForSession } from './chunk-DVDEBNQJ.js';
|
|
7
|
+
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
8
|
+
import { defaultFetch } from './chunk-BCLJSQCV.js';
|
|
9
|
+
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
|
|
10
|
+
import './chunk-EABW6AJQ.js';
|
|
11
|
+
import './chunk-M5POMKKW.js';
|
|
12
|
+
import './chunk-ZM2IMMYN.js';
|
|
13
|
+
import './chunk-BJ3KTMDH.js';
|
|
14
|
+
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
15
|
+
import './chunk-Z5GEFMRW.js';
|
|
16
|
+
import { readFileSync } from 'fs';
|
|
17
|
+
|
|
18
|
+
createRequire(import.meta.url);
|
|
19
|
+
var GREEN = "\x1B[32m";
|
|
20
|
+
var DIM = "\x1B[2m";
|
|
21
|
+
var RESET = "\x1B[0m";
|
|
22
|
+
var EmitCriteriaError = class extends Error {
|
|
23
|
+
};
|
|
24
|
+
var REPLACE_REFUSED_MESSAGE = "this item already has a recorded list, and a person must replace it. Run the command yourself, outside the session, with your own login. A repository's .outerlayer/policy.yaml can let sessions replace it with `criteria: { replace: anyone }`.";
|
|
25
|
+
async function readAllStdin() {
|
|
26
|
+
const chunks = [];
|
|
27
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
28
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
29
|
+
}
|
|
30
|
+
function valueAt(raw, path) {
|
|
31
|
+
let current = raw;
|
|
32
|
+
for (const key of path) current = current?.[key];
|
|
33
|
+
return current;
|
|
34
|
+
}
|
|
35
|
+
function describeIssue(raw, issue) {
|
|
36
|
+
const where = issue.path.join(".");
|
|
37
|
+
if (issue.code === "custom") return `${where}: ${issue.message}`;
|
|
38
|
+
const value = valueAt(raw, issue.path);
|
|
39
|
+
const leaf = issue.path[issue.path.length - 1];
|
|
40
|
+
if ((leaf === "id" || leaf === "proof") && value !== void 0) {
|
|
41
|
+
return `${where}: ${JSON.stringify(value)} is not accepted (${issue.message})`;
|
|
42
|
+
}
|
|
43
|
+
return `${where}: ${issue.message}`;
|
|
44
|
+
}
|
|
45
|
+
function parseFile(raw) {
|
|
46
|
+
const parsed = CriteriaListSchema.safeParse(raw);
|
|
47
|
+
if (parsed.success) return parsed.data;
|
|
48
|
+
const issue = parsed.error.issues[0];
|
|
49
|
+
throw new EmitCriteriaError(
|
|
50
|
+
`invalid criteria list \u2014 ${issue ? describeIssue(raw, issue) : "malformed"}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
function resolveTarget(opts) {
|
|
54
|
+
let item;
|
|
55
|
+
if (opts.item !== void 0) {
|
|
56
|
+
const number = parseTrackerNumber(opts.item);
|
|
57
|
+
if (number === void 0) throw new EmitCriteriaError(trackerNumberError("--item", opts.item));
|
|
58
|
+
item = { number };
|
|
59
|
+
}
|
|
60
|
+
const { sessionId } = opts;
|
|
61
|
+
if (sessionId !== void 0) {
|
|
62
|
+
const refusal = launchRefusalForSession(sessionId, opts.home);
|
|
63
|
+
if (refusal !== void 0) throw new EmitCriteriaError(refusal);
|
|
64
|
+
}
|
|
65
|
+
if (item !== void 0) return sessionId !== void 0 ? { item, sessionId } : { item };
|
|
66
|
+
if (sessionId === void 0) {
|
|
67
|
+
throw new EmitCriteriaError(
|
|
68
|
+
"nothing to record this on \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."
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const launched = launchedItemForSession(sessionId, opts.home);
|
|
72
|
+
if (launched === void 0) {
|
|
73
|
+
throw new EmitCriteriaError(
|
|
74
|
+
"nothing to record this on \u2014 no work item. Pass --item <number>; this recorded session's own launch record names no item either."
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return { item: { number: launched }, sessionId };
|
|
78
|
+
}
|
|
79
|
+
async function errorCode(response) {
|
|
80
|
+
let text = "";
|
|
81
|
+
try {
|
|
82
|
+
text = await response.text();
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
let code = null;
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(text);
|
|
88
|
+
if (typeof parsed.error?.code === "string") code = parsed.error.code;
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
return { code, detail: text.replace(/\s+/g, " ").trim().slice(0, 160) };
|
|
92
|
+
}
|
|
93
|
+
async function runEmitCriteria(opts) {
|
|
94
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
95
|
+
const home = opts.home ?? homeFromEnv();
|
|
96
|
+
const env = opts.env ?? process.env;
|
|
97
|
+
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
98
|
+
let text;
|
|
99
|
+
if (opts.file === "-") {
|
|
100
|
+
text = await (opts.readStdin ?? readAllStdin)();
|
|
101
|
+
} else {
|
|
102
|
+
try {
|
|
103
|
+
text = readFileSync(opts.file, "utf8");
|
|
104
|
+
} catch (err) {
|
|
105
|
+
throw new EmitCriteriaError(`cannot read "${opts.file}": ${String(err)}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
let raw;
|
|
109
|
+
try {
|
|
110
|
+
raw = JSON.parse(text);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
throw new EmitCriteriaError(`"${opts.file}" is not valid JSON: ${String(err)}`);
|
|
113
|
+
}
|
|
114
|
+
const list = parseFile(raw);
|
|
115
|
+
const identity = resolveRepoIdentity(cwd);
|
|
116
|
+
const sessionId = detectActiveSession({
|
|
117
|
+
env,
|
|
118
|
+
home,
|
|
119
|
+
cwds: identity.repoRoot !== void 0 ? [identity.repoRoot, cwd] : [cwd],
|
|
120
|
+
nowMs: now().getTime()
|
|
121
|
+
});
|
|
122
|
+
const target = resolveTarget({ item: opts.item, sessionId, home });
|
|
123
|
+
const resolved = resolveGatewayCredentials({ url: opts.url, apiKey: opts.apiKey, appId: opts.appId, cwd, home, env });
|
|
124
|
+
if (!resolved.ok) throw new EmitCriteriaError(resolved.message);
|
|
125
|
+
const { url, credential: apiKey, appId } = resolved;
|
|
126
|
+
const request = {
|
|
127
|
+
...list,
|
|
128
|
+
item: target.item,
|
|
129
|
+
...target.sessionId !== void 0 ? { sessionId: target.sessionId } : {}
|
|
130
|
+
};
|
|
131
|
+
const endpoint = new URL("/v1/criteria", url).toString();
|
|
132
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
133
|
+
let response;
|
|
134
|
+
try {
|
|
135
|
+
response = await fetchImpl(endpoint, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: {
|
|
138
|
+
"content-type": "application/json",
|
|
139
|
+
authorization: `Bearer ${apiKey}`,
|
|
140
|
+
"x-outerlayer-app-id": appId
|
|
141
|
+
},
|
|
142
|
+
body: JSON.stringify(request)
|
|
143
|
+
});
|
|
144
|
+
} catch (err) {
|
|
145
|
+
throw new EmitCriteriaError(`network error reaching ${endpoint}: ${String(err)}`);
|
|
146
|
+
}
|
|
147
|
+
if (response.status === 401) throw new EmitCriteriaError(unauthorizedMessage(apiKey));
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
const { code, detail } = await errorCode(response);
|
|
150
|
+
if (response.status === 409 && code === "criteria_replace_refused") {
|
|
151
|
+
throw new EmitCriteriaError(`refused (409): ${REPLACE_REFUSED_MESSAGE}`);
|
|
152
|
+
}
|
|
153
|
+
throw new EmitCriteriaError(`emit failed (${response.status})${detail ? `: ${detail}` : ""}`);
|
|
154
|
+
}
|
|
155
|
+
let data = {};
|
|
156
|
+
try {
|
|
157
|
+
data = (await response.json()).data ?? {};
|
|
158
|
+
} catch {
|
|
159
|
+
}
|
|
160
|
+
const count = typeof data.count === "number" ? data.count : list.criteria.length;
|
|
161
|
+
const output = opts.json ? JSON.stringify(data) : `${GREEN}\u2713${RESET} recorded ${count} ${count === 1 ? "criterion" : "criteria"} ${DIM}\xB7${RESET} item #${target.item.number}`;
|
|
162
|
+
if (!opts.quiet) process.stdout.write(output + "\n");
|
|
163
|
+
return { data, output, exitCode: 0 };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export { EmitCriteriaError, runEmitCriteria };
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import './chunk-
|
|
6
|
-
import { launchedItemForSession } from './chunk-
|
|
3
|
+
import { launchRefusalForSession } from './chunk-BCJNHMZT.js';
|
|
4
|
+
import { detectActiveSession } from './chunk-BFESLKPP.js';
|
|
5
|
+
import { FindingBatchSchema, resolveRepoIdentity } from './chunk-4C4THABW.js';
|
|
6
|
+
import { launchedItemForSession } from './chunk-DVDEBNQJ.js';
|
|
7
7
|
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
8
8
|
import { readLatestProvenanceForSession } from './chunk-ZJSNLVCE.js';
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import './chunk-
|
|
13
|
-
import
|
|
9
|
+
import { defaultFetch } from './chunk-BCLJSQCV.js';
|
|
10
|
+
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
|
|
11
|
+
import './chunk-EABW6AJQ.js';
|
|
12
|
+
import './chunk-M5POMKKW.js';
|
|
13
|
+
import './chunk-ZM2IMMYN.js';
|
|
14
|
+
import './chunk-BJ3KTMDH.js';
|
|
14
15
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
15
16
|
import './chunk-Z5GEFMRW.js';
|
|
16
17
|
import { readFileSync } from 'fs';
|
|
@@ -21,6 +22,14 @@ var DIM = "\x1B[2m";
|
|
|
21
22
|
var RESET = "\x1B[0m";
|
|
22
23
|
var EmitFindingError = class extends Error {
|
|
23
24
|
};
|
|
25
|
+
var REMOVED_FINDING_FLAGS = ["subject", "kind", "severity", "verdict", "fixed", "source"];
|
|
26
|
+
function refuseRemovedFindingFlags(opts) {
|
|
27
|
+
const used = REMOVED_FINDING_FLAGS.find((flag) => opts[flag] !== void 0);
|
|
28
|
+
if (used === void 0) return;
|
|
29
|
+
throw new EmitFindingError(
|
|
30
|
+
`--${used} is no longer accepted: findings record problems in the factory, not review verdicts. Pass --category <context|flaky-test|tooling|environment|defect|other> instead.`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
24
33
|
function parseItemFlag(raw) {
|
|
25
34
|
if (raw === void 0) return void 0;
|
|
26
35
|
const number = parseTrackerNumber(raw);
|
|
@@ -50,23 +59,19 @@ function recordFromFlags(opts) {
|
|
|
50
59
|
const ruleLine = parseIntFlag(opts.ruleLine, "--rule-line", { min: 1 });
|
|
51
60
|
const turnIndex = parseIntFlag(opts.turn, "--turn", { min: 0 });
|
|
52
61
|
const round = parseIntFlag(opts.round, "--round", { min: 0 });
|
|
62
|
+
const hasRule = opts.rulePath !== void 0 || opts.ruleQuote !== void 0 || opts.ruleRelation !== void 0 || ruleLine !== void 0;
|
|
53
63
|
return {
|
|
54
64
|
id: opts.id,
|
|
55
|
-
|
|
65
|
+
category: opts.category,
|
|
56
66
|
title: opts.title,
|
|
57
67
|
file: opts.file,
|
|
58
68
|
line: line ?? null,
|
|
59
|
-
|
|
60
|
-
kind: opts.kind,
|
|
61
|
-
verdict: opts.verdict,
|
|
62
|
-
fixed: opts.fixed ?? false,
|
|
63
|
-
rule: opts.rulePath !== void 0 ? {
|
|
69
|
+
rule: hasRule ? {
|
|
64
70
|
path: opts.rulePath,
|
|
65
71
|
line: ruleLine ?? null,
|
|
66
|
-
quote: opts.ruleQuote
|
|
72
|
+
...opts.ruleQuote !== void 0 ? { quote: opts.ruleQuote } : {},
|
|
67
73
|
relation: opts.ruleRelation
|
|
68
74
|
} : null,
|
|
69
|
-
source: opts.source,
|
|
70
75
|
where: {
|
|
71
76
|
label: opts.where,
|
|
72
77
|
...opts.traceId !== void 0 ? { traceId: opts.traceId } : {},
|
|
@@ -112,22 +117,15 @@ function resolveUploadTarget(opts) {
|
|
|
112
117
|
return { item: { number: launchedNumber }, sessionId };
|
|
113
118
|
}
|
|
114
119
|
async function upload(batch, target, opts) {
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
const appId = opts.appId ?? opts.env.OUTERLAYER_APP_ID ?? fileConfig.appId;
|
|
119
|
-
if (!url || !apiKey || !appId) {
|
|
120
|
-
const missing = [!url && "--url", !apiKey && "--api-key", !appId && "--app-id"].filter(Boolean).join(", ");
|
|
121
|
-
throw new EmitFindingError(
|
|
122
|
-
`missing ${missing}. Run \`outerlayer login --url <your gateway>\` and paste the key at the prompt, or set OUTERLAYER_URL / OUTERLAYER_API_KEY / OUTERLAYER_APP_ID. Mint a key in the dashboard: Settings \u2192 API keys.`
|
|
123
|
-
);
|
|
124
|
-
}
|
|
120
|
+
const resolved = resolveGatewayCredentials(opts);
|
|
121
|
+
if (!resolved.ok) throw new EmitFindingError(resolved.message);
|
|
122
|
+
const { url, credential: apiKey, appId } = resolved;
|
|
125
123
|
const request = {
|
|
126
124
|
...batch,
|
|
127
125
|
item: target.item,
|
|
128
126
|
...target.sessionId !== void 0 ? { sessionId: target.sessionId } : {}
|
|
129
127
|
};
|
|
130
|
-
const fetchImpl = opts.fetchImpl ??
|
|
128
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
131
129
|
const endpoint = new URL("/v1/findings", url).toString();
|
|
132
130
|
let response;
|
|
133
131
|
try {
|
|
@@ -145,7 +143,7 @@ async function upload(batch, target, opts) {
|
|
|
145
143
|
}
|
|
146
144
|
if (response.status === 401) {
|
|
147
145
|
throw new EmitFindingError(
|
|
148
|
-
|
|
146
|
+
unauthorizedMessage(apiKey)
|
|
149
147
|
);
|
|
150
148
|
}
|
|
151
149
|
if (!response.ok) {
|
|
@@ -174,7 +172,7 @@ async function runEmitFinding(opts) {
|
|
|
174
172
|
const sessionId = detectUploadSessionId({ cwd, home, env, now });
|
|
175
173
|
const contextSourceSha = opts.contextSourceSha ?? (sessionId !== void 0 ? readLatestProvenanceForSession(sessionId, home)?.sha ?? void 0 : void 0);
|
|
176
174
|
const rawBatch = {
|
|
177
|
-
schemaVersion:
|
|
175
|
+
schemaVersion: 2,
|
|
178
176
|
...opts.headSha !== void 0 ? { headSha: opts.headSha } : {},
|
|
179
177
|
...contextSourceSha !== void 0 ? { contextSourceSha } : {},
|
|
180
178
|
findings: [recordFromFlags(opts)]
|
|
@@ -216,6 +214,11 @@ async function runEmitFindings(opts) {
|
|
|
216
214
|
} catch (err) {
|
|
217
215
|
throw new EmitFindingError(`"${opts.file}" is not valid JSON: ${String(err)}`);
|
|
218
216
|
}
|
|
217
|
+
if (typeof raw === "object" && raw !== null && raw.schemaVersion === 1) {
|
|
218
|
+
throw new EmitFindingError(
|
|
219
|
+
`"${opts.file}" uses schemaVersion 1, which is no longer accepted. Use schemaVersion 2: each finding takes a category (context, flaky-test, tooling, environment, defect or other) in place of subject, kind, severity, verdict, fixed and source.`
|
|
220
|
+
);
|
|
221
|
+
}
|
|
219
222
|
const parsed = FindingBatchSchema.safeParse(raw);
|
|
220
223
|
if (!parsed.success) {
|
|
221
224
|
throw new EmitFindingError(`invalid finding batch \u2014 ${firstIssueMessage(parsed)}`);
|
|
@@ -234,4 +237,4 @@ async function runEmitFindings(opts) {
|
|
|
234
237
|
});
|
|
235
238
|
}
|
|
236
239
|
|
|
237
|
-
export { EmitFindingError, runEmitFinding, runEmitFindings };
|
|
240
|
+
export { EmitFindingError, refuseRemovedFindingFlags, runEmitFinding, runEmitFindings };
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import './chunk-LT5TZHYH.js';
|
|
4
|
+
import { detectCi } from './chunk-LYCDNMOH.js';
|
|
5
|
+
import { launchRefusalForSession } from './chunk-BCJNHMZT.js';
|
|
6
|
+
import './chunk-TBT347UY.js';
|
|
7
|
+
import './chunk-F7CU5ABH.js';
|
|
8
|
+
import './chunk-BKO6JEZI.js';
|
|
9
|
+
import { detectActiveSession } from './chunk-BFESLKPP.js';
|
|
10
|
+
import './chunk-WFJ65NUD.js';
|
|
11
|
+
import { EmittedNameSchema, EMITTED_RESULT_MAX_LINK_LENGTH, EMITTED_RESULTS, EMITTED_RESULT_MAX_BODY_LENGTH, resolveRepoIdentity } from './chunk-4C4THABW.js';
|
|
5
12
|
import './chunk-YRYMNBGQ.js';
|
|
6
|
-
import './chunk-
|
|
13
|
+
import './chunk-DVDEBNQJ.js';
|
|
7
14
|
import { parseTrackerNumber, trackerNumberError } from './chunk-WZBHBH3J.js';
|
|
15
|
+
import './chunk-5QRP3MVS.js';
|
|
8
16
|
import './chunk-ZJSNLVCE.js';
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
11
|
-
import './chunk-
|
|
12
|
-
import './chunk-
|
|
13
|
-
import
|
|
17
|
+
import { defaultFetch } from './chunk-BCLJSQCV.js';
|
|
18
|
+
import { resolveGatewayCredentials, unauthorizedMessage } from './chunk-BOLTI6LR.js';
|
|
19
|
+
import './chunk-EABW6AJQ.js';
|
|
20
|
+
import './chunk-M5POMKKW.js';
|
|
21
|
+
import './chunk-ZM2IMMYN.js';
|
|
22
|
+
import './chunk-UFFXNXLQ.js';
|
|
23
|
+
import './chunk-XCCLFVXM.js';
|
|
24
|
+
import './chunk-BJ3KTMDH.js';
|
|
14
25
|
import { homeFromEnv } from './chunk-VNVZDWO3.js';
|
|
15
26
|
import './chunk-Z5GEFMRW.js';
|
|
16
27
|
import { randomUUID } from 'crypto';
|
|
@@ -53,23 +64,7 @@ async function runEmitResult(opts) {
|
|
|
53
64
|
`invalid name "${opts.name}" \u2014 an emit name is 1-64 characters: a lowercase letter followed by lowercase letters, digits, ".", "_" or "-" (e.g. smoke.pass)`
|
|
54
65
|
);
|
|
55
66
|
}
|
|
56
|
-
const isArtifactReview = opts.name === ARTIFACT_REVIEW_CHECK_NAME;
|
|
57
|
-
const artifactId = opts.artifact === "" ? void 0 : opts.artifact;
|
|
58
|
-
if (isArtifactReview) {
|
|
59
|
-
if (artifactId === void 0) {
|
|
60
|
-
throw new EmitResultError(
|
|
61
|
-
`--artifact <id> is required for ${ARTIFACT_REVIEW_CHECK_NAME} \u2014 it names which artifact this verdict is on`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
} else if (artifactId !== void 0) {
|
|
65
|
-
throw new EmitResultError(`--artifact is only accepted with ${ARTIFACT_REVIEW_CHECK_NAME}`);
|
|
66
|
-
}
|
|
67
67
|
const link = opts.link === "" ? void 0 : opts.link;
|
|
68
|
-
if (isArtifactReview && link !== void 0) {
|
|
69
|
-
throw new EmitResultError(
|
|
70
|
-
`--link is refused for ${ARTIFACT_REVIEW_CHECK_NAME} \u2014 an artifact verdict is a judgment on evidence already on file, never a run to point at; pass --body / --body-file instead`
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
68
|
if (link !== void 0) {
|
|
74
69
|
if (!link.startsWith("http://") && !link.startsWith("https://")) {
|
|
75
70
|
throw new EmitResultError(`invalid --link "${link}" \u2014 expected an http:// or https:// URL`);
|
|
@@ -100,8 +95,6 @@ async function runEmitResult(opts) {
|
|
|
100
95
|
body = opts.body;
|
|
101
96
|
} else if (opts.bodyFile !== void 0) {
|
|
102
97
|
body = await readBodyFile(opts.bodyFile, opts.readStdin);
|
|
103
|
-
} else if (isArtifactReview && result === "fail") {
|
|
104
|
-
body = await (opts.readStdin ?? readAllStdin)();
|
|
105
98
|
}
|
|
106
99
|
if (body !== void 0) {
|
|
107
100
|
body = body.trim();
|
|
@@ -116,13 +109,7 @@ async function runEmitResult(opts) {
|
|
|
116
109
|
);
|
|
117
110
|
}
|
|
118
111
|
}
|
|
119
|
-
if (
|
|
120
|
-
if (result === "fail" && body === void 0) {
|
|
121
|
-
throw new EmitResultError(
|
|
122
|
-
`a failing artifact verdict needs a sentence \u2014 pass --body or --body-file with one sentence saying what is wrong`
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
} else if (result === "fail" && link === void 0 && body === void 0) {
|
|
112
|
+
if (result === "fail" && link === void 0 && body === void 0) {
|
|
126
113
|
throw new EmitResultError(
|
|
127
114
|
`a failing check needs something to act on \u2014 pass --link with the run URL, or --body / --body-file with one sentence saying what is wrong`
|
|
128
115
|
);
|
|
@@ -135,37 +122,23 @@ async function runEmitResult(opts) {
|
|
|
135
122
|
cwds: identity.repoRoot !== void 0 ? [identity.repoRoot, cwd] : [cwd],
|
|
136
123
|
nowMs: now().getTime()
|
|
137
124
|
});
|
|
138
|
-
if (
|
|
125
|
+
if (item === void 0 && sessionId === void 0) {
|
|
139
126
|
throw new EmitResultError(
|
|
140
|
-
"
|
|
127
|
+
"nothing to attach this to \u2014 no work item. Pass --item <number>; a recorded session alone does not name one."
|
|
141
128
|
);
|
|
142
129
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
"nothing to attach this to \u2014 no work item. Pass --item <number>; a recorded session alone does not name one, and a session with no --item is always refused as self-judgment."
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
if (sessionId !== void 0) {
|
|
150
|
-
const refusal = launchRefusalForSession(sessionId, home);
|
|
151
|
-
if (refusal !== void 0) throw new EmitResultError(refusal);
|
|
152
|
-
}
|
|
153
|
-
if (item === void 0 && sessionId !== void 0) {
|
|
154
|
-
throw new EmitResultError(
|
|
155
|
-
"a session records a check only on a work item it was not launched for, named with --item \u2014 the item this session was launched for needs a machine key (an API key run outside the recorded session) or CI."
|
|
156
|
-
);
|
|
157
|
-
}
|
|
130
|
+
if (sessionId !== void 0) {
|
|
131
|
+
const refusal = launchRefusalForSession(sessionId, home);
|
|
132
|
+
if (refusal !== void 0) throw new EmitResultError(refusal);
|
|
158
133
|
}
|
|
159
|
-
|
|
160
|
-
const url = opts.url ?? env.OUTERLAYER_URL ?? fileConfig.url;
|
|
161
|
-
const apiKey = opts.apiKey ?? env.OUTERLAYER_API_KEY ?? fileConfig.apiKey;
|
|
162
|
-
const appId = opts.appId ?? env.OUTERLAYER_APP_ID ?? fileConfig.appId;
|
|
163
|
-
if (!url || !apiKey || !appId) {
|
|
164
|
-
const missing = [!url && "--url", !apiKey && "--api-key", !appId && "--app-id"].filter(Boolean).join(", ");
|
|
134
|
+
if (item === void 0) {
|
|
165
135
|
throw new EmitResultError(
|
|
166
|
-
|
|
136
|
+
"nothing to attach this to \u2014 no work item. Pass --item <number>; a recorded session alone does not name one."
|
|
167
137
|
);
|
|
168
138
|
}
|
|
139
|
+
const resolved = resolveGatewayCredentials({ ...opts, home, env });
|
|
140
|
+
if (!resolved.ok) throw new EmitResultError(resolved.message);
|
|
141
|
+
const { url, credential: apiKey, appId } = resolved;
|
|
169
142
|
const ci = detectCi(env);
|
|
170
143
|
const request = {
|
|
171
144
|
schemaVersion: 1,
|
|
@@ -178,11 +151,10 @@ async function runEmitResult(opts) {
|
|
|
178
151
|
emittedAt: now().toISOString(),
|
|
179
152
|
...ci ? { ci: true } : {},
|
|
180
153
|
...sessionId !== void 0 ? { sessionId } : {},
|
|
181
|
-
...item !== void 0 ? { item } : {}
|
|
182
|
-
...isArtifactReview ? { artifactId } : {}
|
|
154
|
+
...item !== void 0 ? { item } : {}
|
|
183
155
|
}
|
|
184
156
|
};
|
|
185
|
-
const fetchImpl = opts.fetchImpl ??
|
|
157
|
+
const fetchImpl = opts.fetchImpl ?? defaultFetch;
|
|
186
158
|
const endpoint = new URL("/v1/emitted-results", url).toString();
|
|
187
159
|
let response;
|
|
188
160
|
try {
|
|
@@ -200,7 +172,7 @@ async function runEmitResult(opts) {
|
|
|
200
172
|
}
|
|
201
173
|
if (response.status === 401) {
|
|
202
174
|
throw new EmitResultError(
|
|
203
|
-
|
|
175
|
+
unauthorizedMessage(apiKey)
|
|
204
176
|
);
|
|
205
177
|
}
|
|
206
178
|
if (!response.ok) {
|
|
@@ -216,7 +188,7 @@ async function runEmitResult(opts) {
|
|
|
216
188
|
data = (await response.json()).data ?? {};
|
|
217
189
|
} catch {
|
|
218
190
|
}
|
|
219
|
-
const anchorLabel =
|
|
191
|
+
const anchorLabel = `item #${item.number}`;
|
|
220
192
|
const recordedId = typeof data.id === "string" ? data.id : "";
|
|
221
193
|
const idSuffix = recordedId ? ` ${DIM}\xB7${RESET} ${recordedId}` : "";
|
|
222
194
|
const output = opts.json ? JSON.stringify(data) : `${GREEN}\u2713${RESET} emitted ${opts.name} (${result}) ${DIM}\xB7${RESET} ${anchorLabel}${idSuffix}`;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
export { CAPTURE_LIMIT_BYTES, ExecConnectionError, HANDSHAKE_TIMEOUT_MS, execCapture, runExec, runVmExec, vmExecArgs, waitForAgent } from './chunk-W4SQCOZU.js';
|
|
4
|
+
import './chunk-B2G7JHHB.js';
|
|
5
|
+
import './chunk-AUFG23AA.js';
|
|
6
|
+
import './chunk-Z5GEFMRW.js';
|
|
7
|
+
|
|
8
|
+
createRequire(import.meta.url);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
export { DOCKERD_LOG, HELPER_PATH, realGuestHost, relayPortsFrom, runGuestInit } from './chunk-CBPPJSAR.js';
|
|
4
|
+
import './chunk-B2G7JHHB.js';
|
|
5
|
+
import './chunk-AUFG23AA.js';
|
|
6
|
+
import './chunk-Z5GEFMRW.js';
|
|
7
|
+
|
|
8
|
+
createRequire(import.meta.url);
|