@outcomeeng/spx 0.6.11 → 0.6.13
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/dist/cli.js +1433 -300
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -126,6 +126,7 @@ var AGENT_RESUME_LIMITS = {
|
|
|
126
126
|
RECENT_DAYS: 7,
|
|
127
127
|
PER_AGENT_DISPLAYED_CANDIDATES: 5,
|
|
128
128
|
METADATA_HEAD_BYTES: 131072,
|
|
129
|
+
ACTIVITY_TAIL_BYTES: 131072,
|
|
129
130
|
HOURS_PER_DAY: 24,
|
|
130
131
|
MINUTES_PER_HOUR: 60,
|
|
131
132
|
SECONDS_PER_MINUTE: 60,
|
|
@@ -196,6 +197,10 @@ var FIRST_PICKER_INDEX = 0;
|
|
|
196
197
|
var PICKER_MOVE_UP_DELTA = -1;
|
|
197
198
|
var PICKER_MOVE_DOWN_DELTA = 1;
|
|
198
199
|
var PICKER_QUIT_INPUT = "q";
|
|
200
|
+
var AGENT_RESUME_TIE_ORDER = {
|
|
201
|
+
[AGENT_SESSION_KIND.CODEX]: 0,
|
|
202
|
+
[AGENT_SESSION_KIND.CLAUDE_CODE]: 1
|
|
203
|
+
};
|
|
199
204
|
var AgentResumeModeError = class extends Error {
|
|
200
205
|
constructor(selectedModes) {
|
|
201
206
|
super(`${AGENT_RESUME_TEXT.MODE_CONFLICT}: ${selectedModes.join(", ")}`);
|
|
@@ -314,7 +319,7 @@ function renderAgentResumeList(candidates) {
|
|
|
314
319
|
return AGENT_RESUME_TEXT.NO_MATCHES;
|
|
315
320
|
}
|
|
316
321
|
return candidates.map((candidate) => {
|
|
317
|
-
const updatedAt = candidate.
|
|
322
|
+
const updatedAt = candidate.lastActivityAtMs === null ? "unknown" : new Date(candidate.lastActivityAtMs).toISOString();
|
|
318
323
|
return `${updatedAt} ${AGENT_SESSION_LABEL[candidate.agent]} ${candidate.sessionId} ${candidate.cwd}`;
|
|
319
324
|
}).join("\n");
|
|
320
325
|
}
|
|
@@ -340,32 +345,41 @@ async function claudeTranscriptFiles(root, fs8, dirAccepts) {
|
|
|
340
345
|
return perDir.flat();
|
|
341
346
|
}
|
|
342
347
|
async function collectAgentCandidates(agent, files, fs8, cap, match, parseHead) {
|
|
343
|
-
const
|
|
344
|
-
const candidates = [];
|
|
345
|
-
for (const file of files) {
|
|
346
|
-
if (candidates.length >= cap) {
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
348
|
+
const candidates = await mapWithConcurrency(files, AGENT_RESUME_LIMITS.READ_CONCURRENCY, async (file) => {
|
|
349
349
|
const head = await fs8.readHead(file.path, AGENT_RESUME_LIMITS.METADATA_HEAD_BYTES).catch(() => null);
|
|
350
350
|
if (head === null) {
|
|
351
|
-
|
|
351
|
+
return null;
|
|
352
352
|
}
|
|
353
353
|
const core = parseHead(head);
|
|
354
|
-
if (core === null || !core.interactive || !match(core)
|
|
355
|
-
|
|
354
|
+
if (core === null || !core.interactive || !match(core)) {
|
|
355
|
+
return null;
|
|
356
356
|
}
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
const tail = await fs8.readTail(file.path, AGENT_RESUME_LIMITS.ACTIVITY_TAIL_BYTES).catch(() => null);
|
|
358
|
+
if (tail === null) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
359
362
|
agent,
|
|
360
363
|
sessionId: core.sessionId,
|
|
361
364
|
cwd: core.cwd,
|
|
362
365
|
sourcePath: file.path,
|
|
363
366
|
modifiedAtMs: file.modifiedAtMs,
|
|
367
|
+
lastActivityAtMs: latestTranscriptTimestampMs(tail),
|
|
364
368
|
updatedAt: core.updatedAt,
|
|
365
369
|
branch: core.branch
|
|
366
|
-
}
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
const bySessionId = /* @__PURE__ */ new Map();
|
|
373
|
+
for (const candidate of candidates) {
|
|
374
|
+
if (candidate === null) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const existing = bySessionId.get(candidate.sessionId);
|
|
378
|
+
if (existing === void 0 || compareCandidates(candidate, existing) < 0) {
|
|
379
|
+
bySessionId.set(candidate.sessionId, candidate);
|
|
380
|
+
}
|
|
367
381
|
}
|
|
368
|
-
return
|
|
382
|
+
return [...bySessionId.values()].sort(compareCandidates).slice(0, cap);
|
|
369
383
|
}
|
|
370
384
|
async function collectJsonlFiles(root, fs8) {
|
|
371
385
|
const entries = await fs8.readDir(root).catch(() => []);
|
|
@@ -475,6 +489,27 @@ function parseJsonObject(line) {
|
|
|
475
489
|
return null;
|
|
476
490
|
}
|
|
477
491
|
}
|
|
492
|
+
function latestTranscriptTimestampMs(transcriptSlice) {
|
|
493
|
+
let latest = null;
|
|
494
|
+
for (const line of transcriptSlice.split("\n")) {
|
|
495
|
+
const row = parseJsonObject(line);
|
|
496
|
+
if (row === null) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
const timestampMs = parseTimestampMs(firstString(row, [[AGENT_SESSION_JSON_FIELDS.TIMESTAMP]]));
|
|
500
|
+
if (timestampMs !== null && (latest === null || timestampMs > latest)) {
|
|
501
|
+
latest = timestampMs;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return latest;
|
|
505
|
+
}
|
|
506
|
+
function parseTimestampMs(timestamp) {
|
|
507
|
+
if (timestamp === null) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
const timestampMs = Date.parse(timestamp);
|
|
511
|
+
return Number.isNaN(timestampMs) ? null : timestampMs;
|
|
512
|
+
}
|
|
478
513
|
function firstString(row, paths) {
|
|
479
514
|
for (const path7 of paths) {
|
|
480
515
|
const value = valueAtPath(row, path7);
|
|
@@ -498,11 +533,30 @@ function isRecord(value) {
|
|
|
498
533
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
499
534
|
}
|
|
500
535
|
function compareCandidates(left, right) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
536
|
+
if (left.lastActivityAtMs !== null && right.lastActivityAtMs !== null) {
|
|
537
|
+
const activityDiff = right.lastActivityAtMs - left.lastActivityAtMs;
|
|
538
|
+
if (activityDiff !== 0) {
|
|
539
|
+
return activityDiff;
|
|
540
|
+
}
|
|
541
|
+
} else if (left.lastActivityAtMs !== null) {
|
|
542
|
+
return -1;
|
|
543
|
+
} else if (right.lastActivityAtMs !== null) {
|
|
544
|
+
return 1;
|
|
504
545
|
}
|
|
505
|
-
|
|
546
|
+
const agentDiff = AGENT_RESUME_TIE_ORDER[left.agent] - AGENT_RESUME_TIE_ORDER[right.agent];
|
|
547
|
+
if (agentDiff !== 0) {
|
|
548
|
+
return agentDiff;
|
|
549
|
+
}
|
|
550
|
+
return compareCodeUnits(`${left.sessionId}:${left.sourcePath}`, `${right.sessionId}:${right.sourcePath}`);
|
|
551
|
+
}
|
|
552
|
+
function compareCodeUnits(left, right) {
|
|
553
|
+
if (left < right) {
|
|
554
|
+
return -1;
|
|
555
|
+
}
|
|
556
|
+
if (left > right) {
|
|
557
|
+
return 1;
|
|
558
|
+
}
|
|
559
|
+
return 0;
|
|
506
560
|
}
|
|
507
561
|
function isPathInsideOrEqual(parent, child) {
|
|
508
562
|
const rel = relative(resolve3(parent), resolve3(child));
|
|
@@ -1094,6 +1148,19 @@ var nodeAgentSessionFileSystem = {
|
|
|
1094
1148
|
await handle.close();
|
|
1095
1149
|
}
|
|
1096
1150
|
},
|
|
1151
|
+
async readTail(path7, maxBytes) {
|
|
1152
|
+
const fileStat = await stat(path7);
|
|
1153
|
+
const bytesToRead = Math.min(maxBytes, fileStat.size);
|
|
1154
|
+
const start = Math.max(0, fileStat.size - bytesToRead);
|
|
1155
|
+
const handle = await open(path7, "r");
|
|
1156
|
+
try {
|
|
1157
|
+
const buffer = Buffer.alloc(bytesToRead);
|
|
1158
|
+
const { bytesRead } = await handle.read(buffer, 0, bytesToRead, start);
|
|
1159
|
+
return buffer.toString(AGENT_SESSION_STORE.TEXT_ENCODING, 0, bytesRead);
|
|
1160
|
+
} finally {
|
|
1161
|
+
await handle.close();
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1097
1164
|
async stat(path7) {
|
|
1098
1165
|
const result = await stat(path7);
|
|
1099
1166
|
return { mtimeMs: result.mtimeMs };
|
|
@@ -1787,6 +1854,7 @@ import {
|
|
|
1787
1854
|
mkdir as nodeMkdir,
|
|
1788
1855
|
open as nodeOpen,
|
|
1789
1856
|
readdir as nodeReaddir,
|
|
1857
|
+
rename as nodeRename,
|
|
1790
1858
|
rm as nodeRm
|
|
1791
1859
|
} from "fs/promises";
|
|
1792
1860
|
import { dirname as dirname2, join as join2 } from "path";
|
|
@@ -1880,6 +1948,9 @@ var defaultFileSystem = {
|
|
|
1880
1948
|
},
|
|
1881
1949
|
readdir: nodeReaddir,
|
|
1882
1950
|
lstat: nodeLstat,
|
|
1951
|
+
rename: async (from, to) => {
|
|
1952
|
+
await nodeRename(from, to);
|
|
1953
|
+
},
|
|
1883
1954
|
rm: async (path7, options) => {
|
|
1884
1955
|
await nodeRm(path7, options);
|
|
1885
1956
|
}
|
|
@@ -1972,8 +2043,8 @@ function formatRunTimestamp(date) {
|
|
|
1972
2043
|
);
|
|
1973
2044
|
return `${year}-${month}-${day}${RUN_TIMESTAMP_SEPARATOR}${hours}-${minutes}-${seconds}-${milliseconds}`;
|
|
1974
2045
|
}
|
|
1975
|
-
function generateRunId(
|
|
1976
|
-
return
|
|
2046
|
+
function generateRunId(randomBytes3 = nodeRandomBytes) {
|
|
2047
|
+
return randomBytes3(STATE_STORE_RUN_TOKEN.ID_BYTES).toString(HEX_ENCODING);
|
|
1977
2048
|
}
|
|
1978
2049
|
function createStateStoreRunToken(options) {
|
|
1979
2050
|
const startedAt = formatRunTimestamp(options.date);
|
|
@@ -1995,7 +2066,7 @@ async function createJsonlRunFile(scopeDir, domainName, options = {}) {
|
|
|
1995
2066
|
if (!domainRunsDir.ok) return domainRunsDir;
|
|
1996
2067
|
const maxAttempts = options.maxAttempts ?? RUN_FILE_CREATE_ATTEMPTS;
|
|
1997
2068
|
const startedDate = (options.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
1998
|
-
const
|
|
2069
|
+
const randomBytes3 = options.randomBytes ?? nodeRandomBytes;
|
|
1999
2070
|
try {
|
|
2000
2071
|
await fs8.mkdir(domainRunsDir.value, { recursive: true });
|
|
2001
2072
|
} catch (error) {
|
|
@@ -2005,7 +2076,7 @@ async function createJsonlRunFile(scopeDir, domainName, options = {}) {
|
|
|
2005
2076
|
};
|
|
2006
2077
|
}
|
|
2007
2078
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
2008
|
-
const token = createStateStoreRunToken({ date: startedDate, randomBytes:
|
|
2079
|
+
const token = createStateStoreRunToken({ date: startedDate, randomBytes: randomBytes3 });
|
|
2009
2080
|
const name = runFileName(token.runToken);
|
|
2010
2081
|
const path7 = join2(domainRunsDir.value, name);
|
|
2011
2082
|
try {
|
|
@@ -2528,8 +2599,8 @@ import path2 from "path";
|
|
|
2528
2599
|
// src/lib/atomic-file-write.ts
|
|
2529
2600
|
var TEMP_TOKEN_BYTES = 8;
|
|
2530
2601
|
var TEMP_SUFFIX = ".tmp";
|
|
2531
|
-
function atomicWriteTempPath(targetPath,
|
|
2532
|
-
const token =
|
|
2602
|
+
function atomicWriteTempPath(targetPath, randomBytes3) {
|
|
2603
|
+
const token = randomBytes3(TEMP_TOKEN_BYTES).toString("hex");
|
|
2533
2604
|
return `${targetPath}.${token}${TEMP_SUFFIX}`;
|
|
2534
2605
|
}
|
|
2535
2606
|
async function writeFileAtomic(targetPath, content, options) {
|
|
@@ -3010,6 +3081,7 @@ var AGENT = {
|
|
|
3010
3081
|
CLAUDE_CODE: "claudeCode"
|
|
3011
3082
|
};
|
|
3012
3083
|
var HARNESS_ENVIRONMENT_CONFIG_FIELDS = {
|
|
3084
|
+
METHODOLOGY: "methodology",
|
|
3013
3085
|
INSTRUCTIONS: "instructions",
|
|
3014
3086
|
AGENTS: "agents",
|
|
3015
3087
|
PLUGIN_BOOTSTRAP: "pluginBootstrap",
|
|
@@ -3029,6 +3101,8 @@ var HARNESS_ENVIRONMENT_CONFIG_FIELDS = {
|
|
|
3029
3101
|
VERSION: "version",
|
|
3030
3102
|
MARKETPLACE: "marketplace"
|
|
3031
3103
|
};
|
|
3104
|
+
var DEFAULT_METHODOLOGY_SOURCE = "outcomeeng/spec-tree";
|
|
3105
|
+
var DEFAULT_METHODOLOGY_VERSION = "installed";
|
|
3032
3106
|
var AGENT_SET = new Set(Object.values(AGENT));
|
|
3033
3107
|
var DEFAULT_AGENT_INSTRUCTION_TARGET_AGENTS = [
|
|
3034
3108
|
AGENT.CODEX,
|
|
@@ -3036,6 +3110,10 @@ var DEFAULT_AGENT_INSTRUCTION_TARGET_AGENTS = [
|
|
|
3036
3110
|
];
|
|
3037
3111
|
var DEFAULT_AGENT_INSTRUCTION_FILE_PATH = "AGENTS.md";
|
|
3038
3112
|
var DEFAULT_HARNESS_ENVIRONMENT_CONFIG = {
|
|
3113
|
+
methodology: {
|
|
3114
|
+
source: DEFAULT_METHODOLOGY_SOURCE,
|
|
3115
|
+
version: DEFAULT_METHODOLOGY_VERSION
|
|
3116
|
+
},
|
|
3039
3117
|
instructions: {
|
|
3040
3118
|
files: [
|
|
3041
3119
|
{
|
|
@@ -3069,10 +3147,15 @@ var DEFAULT_HARNESS_ENVIRONMENT_CONFIG = {
|
|
|
3069
3147
|
}
|
|
3070
3148
|
};
|
|
3071
3149
|
var HARNESS_ENVIRONMENT_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
3150
|
+
HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY,
|
|
3072
3151
|
HARNESS_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS,
|
|
3073
3152
|
HARNESS_ENVIRONMENT_CONFIG_FIELDS.AGENTS,
|
|
3074
3153
|
HARNESS_ENVIRONMENT_CONFIG_FIELDS.PLUGIN_BOOTSTRAP
|
|
3075
3154
|
]);
|
|
3155
|
+
var HARNESS_ENVIRONMENT_METHODOLOGY_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
3156
|
+
HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE,
|
|
3157
|
+
HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION
|
|
3158
|
+
]);
|
|
3076
3159
|
var HARNESS_ENVIRONMENT_INSTRUCTIONS_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
3077
3160
|
HARNESS_ENVIRONMENT_CONFIG_FIELDS.FILES
|
|
3078
3161
|
]);
|
|
@@ -3137,6 +3220,21 @@ function validateBoolean(path7, value) {
|
|
|
3137
3220
|
}
|
|
3138
3221
|
return { ok: true, value };
|
|
3139
3222
|
}
|
|
3223
|
+
function validateMethodology(raw) {
|
|
3224
|
+
const sectionPath = `${HARNESS_ENVIRONMENT_SECTION}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY}`;
|
|
3225
|
+
if (!isRecord2(raw)) {
|
|
3226
|
+
return { ok: false, error: `${sectionPath} must be an object` };
|
|
3227
|
+
}
|
|
3228
|
+
const unknown = rejectUnknownFields(sectionPath, raw, HARNESS_ENVIRONMENT_METHODOLOGY_ALLOWED_FIELDS);
|
|
3229
|
+
if (!unknown.ok) return unknown;
|
|
3230
|
+
const sourceRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE];
|
|
3231
|
+
const source = sourceRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.methodology.source } : validateNonEmptyString(`${sectionPath}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.SOURCE}`, sourceRaw);
|
|
3232
|
+
if (!source.ok) return source;
|
|
3233
|
+
const versionRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION];
|
|
3234
|
+
const version2 = versionRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.methodology.version } : validateNonEmptyString(`${sectionPath}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.VERSION}`, versionRaw);
|
|
3235
|
+
if (!version2.ok) return version2;
|
|
3236
|
+
return { ok: true, value: { source: source.value, version: version2.value } };
|
|
3237
|
+
}
|
|
3140
3238
|
function validateAgent(path7, value) {
|
|
3141
3239
|
if (typeof value !== "string" || !isAgent(value)) {
|
|
3142
3240
|
return { ok: false, error: `${path7} must be a registered agent` };
|
|
@@ -3223,37 +3321,37 @@ function validateAgents(raw) {
|
|
|
3223
3321
|
}
|
|
3224
3322
|
return { ok: true, value: agents };
|
|
3225
3323
|
}
|
|
3226
|
-
function validateAgentConfig(path7, raw,
|
|
3324
|
+
function validateAgentConfig(path7, raw, defaults6) {
|
|
3227
3325
|
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
3228
3326
|
const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_AGENT_CONFIG_ALLOWED_FIELDS);
|
|
3229
3327
|
if (!unknown.ok) return unknown;
|
|
3230
3328
|
const enabledRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED];
|
|
3231
|
-
const enabled = enabledRaw === void 0 ? { ok: true, value:
|
|
3329
|
+
const enabled = enabledRaw === void 0 ? { ok: true, value: defaults6.enabled } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.ENABLED}`, enabledRaw);
|
|
3232
3330
|
if (!enabled.ok) return enabled;
|
|
3233
3331
|
const hooksRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS];
|
|
3234
|
-
const hooks = hooksRaw === void 0 ? { ok: true, value:
|
|
3332
|
+
const hooks = hooksRaw === void 0 ? { ok: true, value: defaults6.hooks } : validateAgentHooks(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.HOOKS}`, hooksRaw, defaults6.hooks);
|
|
3235
3333
|
if (!hooks.ok) return hooks;
|
|
3236
3334
|
return { ok: true, value: { enabled: enabled.value, hooks: hooks.value } };
|
|
3237
3335
|
}
|
|
3238
|
-
function validateAgentHooks(path7, raw,
|
|
3336
|
+
function validateAgentHooks(path7, raw, defaults6) {
|
|
3239
3337
|
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
3240
3338
|
const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_AGENT_HOOKS_ALLOWED_FIELDS);
|
|
3241
3339
|
if (!unknown.ok) return unknown;
|
|
3242
3340
|
const sessionStartRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.SESSION_START];
|
|
3243
|
-
const sessionStart = sessionStartRaw === void 0 ? { ok: true, value:
|
|
3341
|
+
const sessionStart = sessionStartRaw === void 0 ? { ok: true, value: defaults6.sessionStart } : validateSessionStartHooks(
|
|
3244
3342
|
`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.SESSION_START}`,
|
|
3245
3343
|
sessionStartRaw,
|
|
3246
|
-
|
|
3344
|
+
defaults6.sessionStart
|
|
3247
3345
|
);
|
|
3248
3346
|
if (!sessionStart.ok) return sessionStart;
|
|
3249
3347
|
return { ok: true, value: { sessionStart: sessionStart.value } };
|
|
3250
3348
|
}
|
|
3251
|
-
function validateSessionStartHooks(path7, raw,
|
|
3349
|
+
function validateSessionStartHooks(path7, raw, defaults6) {
|
|
3252
3350
|
if (!isRecord2(raw)) return { ok: false, error: `${path7} must be an object` };
|
|
3253
3351
|
const unknown = rejectUnknownFields(path7, raw, HARNESS_ENVIRONMENT_SESSION_START_HOOKS_ALLOWED_FIELDS);
|
|
3254
3352
|
if (!unknown.ok) return unknown;
|
|
3255
3353
|
const compactStdoutRaw = raw[HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT];
|
|
3256
|
-
const compactStdout = compactStdoutRaw === void 0 ? { ok: true, value:
|
|
3354
|
+
const compactStdout = compactStdoutRaw === void 0 ? { ok: true, value: defaults6.compactStdout } : validateBoolean(`${path7}.${HARNESS_ENVIRONMENT_CONFIG_FIELDS.COMPACT_STDOUT}`, compactStdoutRaw);
|
|
3257
3355
|
if (!compactStdout.ok) return compactStdout;
|
|
3258
3356
|
return { ok: true, value: { compactStdout: compactStdout.value } };
|
|
3259
3357
|
}
|
|
@@ -3326,8 +3424,8 @@ function validatePluginBootstrap(raw) {
|
|
|
3326
3424
|
}
|
|
3327
3425
|
};
|
|
3328
3426
|
}
|
|
3329
|
-
function validateEntryArray(path7, raw, validateEntry,
|
|
3330
|
-
if (raw === void 0) return { ok: true, value:
|
|
3427
|
+
function validateEntryArray(path7, raw, validateEntry, defaults6) {
|
|
3428
|
+
if (raw === void 0) return { ok: true, value: defaults6 };
|
|
3331
3429
|
if (!Array.isArray(raw)) return { ok: false, error: `${path7} must be an array` };
|
|
3332
3430
|
const entries = [];
|
|
3333
3431
|
for (const [index, entry] of raw.entries()) {
|
|
@@ -3518,6 +3616,9 @@ function validate(value) {
|
|
|
3518
3616
|
HARNESS_ENVIRONMENT_ALLOWED_FIELDS
|
|
3519
3617
|
);
|
|
3520
3618
|
if (!unknown.ok) return unknown;
|
|
3619
|
+
const methodologyRaw = value[HARNESS_ENVIRONMENT_CONFIG_FIELDS.METHODOLOGY];
|
|
3620
|
+
const methodology = methodologyRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.methodology } : validateMethodology(methodologyRaw);
|
|
3621
|
+
if (!methodology.ok) return methodology;
|
|
3521
3622
|
const instructionsRaw = value[HARNESS_ENVIRONMENT_CONFIG_FIELDS.INSTRUCTIONS];
|
|
3522
3623
|
const instructions = instructionsRaw === void 0 ? { ok: true, value: DEFAULT_HARNESS_ENVIRONMENT_CONFIG.instructions } : validateInstructions(instructionsRaw);
|
|
3523
3624
|
if (!instructions.ok) return instructions;
|
|
@@ -3530,6 +3631,7 @@ function validate(value) {
|
|
|
3530
3631
|
return {
|
|
3531
3632
|
ok: true,
|
|
3532
3633
|
value: {
|
|
3634
|
+
methodology: methodology.value,
|
|
3533
3635
|
instructions: instructions.value,
|
|
3534
3636
|
agents: agents.value,
|
|
3535
3637
|
pluginBootstrap: pluginBootstrap.value
|
|
@@ -3618,6 +3720,36 @@ var diagnoseConfigDescriptor = {
|
|
|
3618
3720
|
validate: validate2
|
|
3619
3721
|
};
|
|
3620
3722
|
|
|
3723
|
+
// src/lib/agent-run-journal/config.ts
|
|
3724
|
+
var RUNTIME_SECTION = "runtime";
|
|
3725
|
+
var RUNTIME_CONFIG_FIELDS = {
|
|
3726
|
+
EVENT_NAMESPACE: "eventNamespace"
|
|
3727
|
+
};
|
|
3728
|
+
var RUNTIME_EVENT_NAMESPACE_DEFAULT = "sh.spx";
|
|
3729
|
+
var defaults2 = { eventNamespace: RUNTIME_EVENT_NAMESPACE_DEFAULT };
|
|
3730
|
+
function validate3(value) {
|
|
3731
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3732
|
+
return { ok: false, error: `${RUNTIME_SECTION} section must be an object` };
|
|
3733
|
+
}
|
|
3734
|
+
const candidate = value;
|
|
3735
|
+
const raw = candidate[RUNTIME_CONFIG_FIELDS.EVENT_NAMESPACE];
|
|
3736
|
+
if (raw === void 0) {
|
|
3737
|
+
return { ok: true, value: { eventNamespace: RUNTIME_EVENT_NAMESPACE_DEFAULT } };
|
|
3738
|
+
}
|
|
3739
|
+
if (typeof raw !== "string" || raw.trim().length === 0) {
|
|
3740
|
+
return {
|
|
3741
|
+
ok: false,
|
|
3742
|
+
error: `${RUNTIME_SECTION}.${RUNTIME_CONFIG_FIELDS.EVENT_NAMESPACE} must be a non-empty string`
|
|
3743
|
+
};
|
|
3744
|
+
}
|
|
3745
|
+
return { ok: true, value: { eventNamespace: raw } };
|
|
3746
|
+
}
|
|
3747
|
+
var runtimeConfigDescriptor = {
|
|
3748
|
+
section: RUNTIME_SECTION,
|
|
3749
|
+
defaults: defaults2,
|
|
3750
|
+
validate: validate3
|
|
3751
|
+
};
|
|
3752
|
+
|
|
3621
3753
|
// src/lib/file-inclusion/adapters/eslint.ts
|
|
3622
3754
|
function eslintAdapter(scope2, config) {
|
|
3623
3755
|
return scope2.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);
|
|
@@ -3678,7 +3810,7 @@ var DEFAULT_SCOPE_CONFIG = {};
|
|
|
3678
3810
|
var DEFAULT_TOOLS_CONFIG = Object.fromEntries(
|
|
3679
3811
|
Object.entries(TOOL_DEFAULT_FLAGS).map(([name, flag]) => [name, { ignoreFlag: flag }])
|
|
3680
3812
|
);
|
|
3681
|
-
var
|
|
3813
|
+
var defaults3 = {
|
|
3682
3814
|
scope: DEFAULT_SCOPE_CONFIG,
|
|
3683
3815
|
tools: DEFAULT_TOOLS_CONFIG
|
|
3684
3816
|
};
|
|
@@ -3750,7 +3882,7 @@ function validateTools(raw) {
|
|
|
3750
3882
|
}
|
|
3751
3883
|
return { ok: true, value: tools };
|
|
3752
3884
|
}
|
|
3753
|
-
function
|
|
3885
|
+
function validate4(value) {
|
|
3754
3886
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3755
3887
|
return { ok: false, error: `${FILE_INCLUSION_SECTION} section must be an object` };
|
|
3756
3888
|
}
|
|
@@ -3777,60 +3909,7 @@ function validate3(value) {
|
|
|
3777
3909
|
}
|
|
3778
3910
|
var fileInclusionConfigDescriptor = {
|
|
3779
3911
|
section: FILE_INCLUSION_SECTION,
|
|
3780
|
-
defaults:
|
|
3781
|
-
validate: validate3
|
|
3782
|
-
};
|
|
3783
|
-
|
|
3784
|
-
// src/config/source-roots.ts
|
|
3785
|
-
var TEST_RELEVANT_SOURCE_ROOT_PREFIX = {
|
|
3786
|
-
SOURCE: "src/",
|
|
3787
|
-
TESTING: "testing/",
|
|
3788
|
-
SCRIPTS: "scripts/",
|
|
3789
|
-
ESLINT_RULES: "eslint-rules/"
|
|
3790
|
-
};
|
|
3791
|
-
var TEST_RELEVANT_SOURCE_ROOT_PREFIXES = [
|
|
3792
|
-
TEST_RELEVANT_SOURCE_ROOT_PREFIX.SOURCE,
|
|
3793
|
-
TEST_RELEVANT_SOURCE_ROOT_PREFIX.TESTING,
|
|
3794
|
-
TEST_RELEVANT_SOURCE_ROOT_PREFIX.SCRIPTS,
|
|
3795
|
-
TEST_RELEVANT_SOURCE_ROOT_PREFIX.ESLINT_RULES
|
|
3796
|
-
];
|
|
3797
|
-
|
|
3798
|
-
// src/lib/precommit/config.ts
|
|
3799
|
-
var PRECOMMIT_SECTION = "precommit";
|
|
3800
|
-
var PRECOMMIT_DEFAULTS = {
|
|
3801
|
-
sourceDirs: TEST_RELEVANT_SOURCE_ROOT_PREFIXES,
|
|
3802
|
-
testPattern: ".test.ts"
|
|
3803
|
-
};
|
|
3804
|
-
function validate4(value) {
|
|
3805
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3806
|
-
return { ok: false, error: `${PRECOMMIT_SECTION} section must be an object` };
|
|
3807
|
-
}
|
|
3808
|
-
const candidate = value;
|
|
3809
|
-
const sourceDirs = candidate["sourceDirs"] ?? PRECOMMIT_DEFAULTS.sourceDirs;
|
|
3810
|
-
if (!Array.isArray(sourceDirs) || !sourceDirs.every((x) => typeof x === "string" && x.length > 0)) {
|
|
3811
|
-
return {
|
|
3812
|
-
ok: false,
|
|
3813
|
-
error: `${PRECOMMIT_SECTION}.sourceDirs must be a non-empty array of non-empty strings`
|
|
3814
|
-
};
|
|
3815
|
-
}
|
|
3816
|
-
const testPattern = candidate["testPattern"] ?? PRECOMMIT_DEFAULTS.testPattern;
|
|
3817
|
-
if (typeof testPattern !== "string" || testPattern.length === 0) {
|
|
3818
|
-
return {
|
|
3819
|
-
ok: false,
|
|
3820
|
-
error: `${PRECOMMIT_SECTION}.testPattern must be a non-empty string`
|
|
3821
|
-
};
|
|
3822
|
-
}
|
|
3823
|
-
return {
|
|
3824
|
-
ok: true,
|
|
3825
|
-
value: {
|
|
3826
|
-
sourceDirs,
|
|
3827
|
-
testPattern
|
|
3828
|
-
}
|
|
3829
|
-
};
|
|
3830
|
-
}
|
|
3831
|
-
var precommitConfigDescriptor = {
|
|
3832
|
-
section: PRECOMMIT_SECTION,
|
|
3833
|
-
defaults: PRECOMMIT_DEFAULTS,
|
|
3912
|
+
defaults: defaults3,
|
|
3834
3913
|
validate: validate4
|
|
3835
3914
|
};
|
|
3836
3915
|
|
|
@@ -4194,7 +4273,7 @@ var TESTING_CONFIG_FIELDS = {
|
|
|
4194
4273
|
PASSING_SCOPE: "passingScope"
|
|
4195
4274
|
};
|
|
4196
4275
|
var DEFAULT_PASSING_SCOPE = resolveDefaultPassingScope();
|
|
4197
|
-
var
|
|
4276
|
+
var defaults4 = {
|
|
4198
4277
|
passingScope: DEFAULT_PASSING_SCOPE
|
|
4199
4278
|
};
|
|
4200
4279
|
function resolveDefaultPassingScope() {
|
|
@@ -4214,7 +4293,7 @@ function validate6(value) {
|
|
|
4214
4293
|
const candidate = value;
|
|
4215
4294
|
const passingScopeRaw = candidate[TESTING_CONFIG_FIELDS.PASSING_SCOPE];
|
|
4216
4295
|
if (passingScopeRaw === void 0) {
|
|
4217
|
-
return { ok: true, value:
|
|
4296
|
+
return { ok: true, value: defaults4 };
|
|
4218
4297
|
}
|
|
4219
4298
|
const passingScopeResult = validatePathFilterConfig(
|
|
4220
4299
|
passingScopeRaw,
|
|
@@ -4230,7 +4309,7 @@ function validate6(value) {
|
|
|
4230
4309
|
}
|
|
4231
4310
|
var testingConfigDescriptor = {
|
|
4232
4311
|
section: TESTING_SECTION,
|
|
4233
|
-
defaults:
|
|
4312
|
+
defaults: defaults4,
|
|
4234
4313
|
validate: validate6
|
|
4235
4314
|
};
|
|
4236
4315
|
|
|
@@ -4378,7 +4457,7 @@ var VALIDATION_PATH_TOOL_SUBSECTIONS = {
|
|
|
4378
4457
|
LITERAL: "literal",
|
|
4379
4458
|
FORMATTING: "formatting"
|
|
4380
4459
|
};
|
|
4381
|
-
var
|
|
4460
|
+
var defaults5 = {
|
|
4382
4461
|
paths: {},
|
|
4383
4462
|
literal: {
|
|
4384
4463
|
enabled: true,
|
|
@@ -4418,7 +4497,7 @@ function validateLiteral(raw) {
|
|
|
4418
4497
|
};
|
|
4419
4498
|
}
|
|
4420
4499
|
const candidate = raw;
|
|
4421
|
-
const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ??
|
|
4500
|
+
const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults5.literal.enabled;
|
|
4422
4501
|
if (typeof enabledRaw !== "boolean") {
|
|
4423
4502
|
return {
|
|
4424
4503
|
ok: false,
|
|
@@ -4443,7 +4522,7 @@ function validateKnip(raw) {
|
|
|
4443
4522
|
};
|
|
4444
4523
|
}
|
|
4445
4524
|
const candidate = raw;
|
|
4446
|
-
const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ??
|
|
4525
|
+
const enabledRaw = candidate[VALIDATION_ENABLED_FIELD] ?? defaults5.knip.enabled;
|
|
4447
4526
|
if (typeof enabledRaw !== "boolean") {
|
|
4448
4527
|
return {
|
|
4449
4528
|
ok: false,
|
|
@@ -4470,7 +4549,7 @@ function validate8(value) {
|
|
|
4470
4549
|
}
|
|
4471
4550
|
var validationConfigDescriptor = {
|
|
4472
4551
|
section: VALIDATION_SECTION,
|
|
4473
|
-
defaults:
|
|
4552
|
+
defaults: defaults5,
|
|
4474
4553
|
validate: validate8
|
|
4475
4554
|
};
|
|
4476
4555
|
|
|
@@ -4480,17 +4559,17 @@ var productionRegistry = [
|
|
|
4480
4559
|
validationConfigDescriptor,
|
|
4481
4560
|
testingConfigDescriptor,
|
|
4482
4561
|
fileInclusionConfigDescriptor,
|
|
4483
|
-
precommitConfigDescriptor,
|
|
4484
4562
|
harnessEnvironmentConfigDescriptor,
|
|
4485
|
-
diagnoseConfigDescriptor
|
|
4563
|
+
diagnoseConfigDescriptor,
|
|
4564
|
+
runtimeConfigDescriptor
|
|
4486
4565
|
];
|
|
4487
4566
|
|
|
4488
4567
|
// src/config/descriptor-digest.ts
|
|
4489
4568
|
import { createHash as createHash3 } from "crypto";
|
|
4490
4569
|
var DEFAULT_DESCRIPTOR_PATH = "descriptor section";
|
|
4491
|
-
var
|
|
4570
|
+
var DESCRIPTOR_DIGEST_SHA256_ALGORITHM = "sha256";
|
|
4492
4571
|
var UTF8_ENCODING2 = "utf8";
|
|
4493
|
-
var
|
|
4572
|
+
var DESCRIPTOR_DIGEST_HEX_ENCODING = "hex";
|
|
4494
4573
|
function canonicalDescriptorJson(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
|
|
4495
4574
|
const normalized = normalizeDescriptorJsonValue(value, path7, /* @__PURE__ */ new WeakSet());
|
|
4496
4575
|
if (!normalized.ok) return normalized;
|
|
@@ -4499,7 +4578,7 @@ function canonicalDescriptorJson(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
|
|
|
4499
4578
|
function digestDescriptorSection(value, path7 = DEFAULT_DESCRIPTOR_PATH) {
|
|
4500
4579
|
const canonical = canonicalDescriptorJson(value, path7);
|
|
4501
4580
|
if (!canonical.ok) return canonical;
|
|
4502
|
-
const sha256 = createHash3(
|
|
4581
|
+
const sha256 = createHash3(DESCRIPTOR_DIGEST_SHA256_ALGORITHM).update(Buffer.from(canonical.value, UTF8_ENCODING2)).digest(DESCRIPTOR_DIGEST_HEX_ENCODING);
|
|
4503
4582
|
return {
|
|
4504
4583
|
ok: true,
|
|
4505
4584
|
value: {
|
|
@@ -6242,7 +6321,7 @@ import {
|
|
|
6242
6321
|
mkdir as nodeMkdir2,
|
|
6243
6322
|
readFile as nodeReadFile,
|
|
6244
6323
|
readlink as nodeReadlink,
|
|
6245
|
-
rename as
|
|
6324
|
+
rename as nodeRename2,
|
|
6246
6325
|
rm as nodeRm2,
|
|
6247
6326
|
symlink as nodeSymlink,
|
|
6248
6327
|
writeFile as nodeWriteFile
|
|
@@ -6254,7 +6333,7 @@ var defaultOccupancyFileSystem = {
|
|
|
6254
6333
|
writeFile: async (path7, data) => {
|
|
6255
6334
|
await nodeWriteFile(path7, data);
|
|
6256
6335
|
},
|
|
6257
|
-
rename:
|
|
6336
|
+
rename: nodeRename2,
|
|
6258
6337
|
symlink: nodeSymlink,
|
|
6259
6338
|
readlink: nodeReadlink,
|
|
6260
6339
|
readFile: nodeReadFile,
|
|
@@ -7145,9 +7224,9 @@ var JOURNAL_RUN_STATE_INCOMPLETE_REASON = {
|
|
|
7145
7224
|
};
|
|
7146
7225
|
var JOURNAL_RUN_EVENT = {
|
|
7147
7226
|
SOURCE: "/spx/journal",
|
|
7148
|
-
STARTED_TYPE:
|
|
7149
|
-
PROGRESS_TYPE:
|
|
7150
|
-
COMPLETED_TYPE:
|
|
7227
|
+
STARTED_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.started`,
|
|
7228
|
+
PROGRESS_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.progress`,
|
|
7229
|
+
COMPLETED_TYPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.journal.run.completed`
|
|
7151
7230
|
};
|
|
7152
7231
|
var JOURNAL_RUN_STATE_FIELDS = {
|
|
7153
7232
|
BRANCH_NAME: "branchName",
|
|
@@ -7166,13 +7245,18 @@ var JOURNAL_RUN_STATE_FIELDS = {
|
|
|
7166
7245
|
STATUS: "status"
|
|
7167
7246
|
};
|
|
7168
7247
|
function foldJournalRunState(events, sealed) {
|
|
7169
|
-
if (!sealed)
|
|
7248
|
+
if (!sealed) {
|
|
7249
|
+
return { ok: false, reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.UNSEALED };
|
|
7250
|
+
}
|
|
7170
7251
|
let completed;
|
|
7171
7252
|
for (const event of events) {
|
|
7172
7253
|
if (event.type === JOURNAL_RUN_EVENT.COMPLETED_TYPE) completed = event;
|
|
7173
7254
|
}
|
|
7174
7255
|
if (completed === void 0) {
|
|
7175
|
-
return {
|
|
7256
|
+
return {
|
|
7257
|
+
ok: false,
|
|
7258
|
+
reason: JOURNAL_RUN_STATE_INCOMPLETE_REASON.MISSING_STATE
|
|
7259
|
+
};
|
|
7176
7260
|
}
|
|
7177
7261
|
const validated = validateJournalRunState(completed.data);
|
|
7178
7262
|
if (!validated.ok) {
|
|
@@ -7185,13 +7269,17 @@ function foldJournalRunState(events, sealed) {
|
|
|
7185
7269
|
return validated;
|
|
7186
7270
|
}
|
|
7187
7271
|
function isJournalRunStateStatus(value) {
|
|
7188
|
-
return typeof value === "string" && Object.values(JOURNAL_RUN_STATE_STATUS).includes(
|
|
7272
|
+
return typeof value === "string" && Object.values(JOURNAL_RUN_STATE_STATUS).includes(
|
|
7273
|
+
value
|
|
7274
|
+
);
|
|
7189
7275
|
}
|
|
7190
7276
|
function isJournalTargetKind(value) {
|
|
7191
7277
|
return typeof value === "string" && Object.values(JOURNAL_TARGET_KIND).includes(value);
|
|
7192
7278
|
}
|
|
7193
7279
|
function validateJournalRunState(value) {
|
|
7194
|
-
if (!isRecord5(value))
|
|
7280
|
+
if (!isRecord5(value)) {
|
|
7281
|
+
return { ok: false, error: "journal run state must be an object" };
|
|
7282
|
+
}
|
|
7195
7283
|
const identity = readRunStateIdentity(value);
|
|
7196
7284
|
if (!identity.ok) return identity;
|
|
7197
7285
|
const body = readRunStateBody(value);
|
|
@@ -7203,9 +7291,15 @@ function readRunStateIdentity(value) {
|
|
|
7203
7291
|
if (!branchName.ok) return branchName;
|
|
7204
7292
|
const branchSlug = readString(value, JOURNAL_RUN_STATE_FIELDS.BRANCH_SLUG);
|
|
7205
7293
|
if (!branchSlug.ok) return branchSlug;
|
|
7206
|
-
const targetKind = readTargetKind(
|
|
7294
|
+
const targetKind = readTargetKind(
|
|
7295
|
+
value,
|
|
7296
|
+
JOURNAL_RUN_STATE_FIELDS.TARGET_KIND
|
|
7297
|
+
);
|
|
7207
7298
|
if (!targetKind.ok) return targetKind;
|
|
7208
|
-
const pullRequestNumber = readOptionalNonNegativeInteger(
|
|
7299
|
+
const pullRequestNumber = readOptionalNonNegativeInteger(
|
|
7300
|
+
value,
|
|
7301
|
+
JOURNAL_RUN_STATE_FIELDS.PULL_REQUEST_NUMBER
|
|
7302
|
+
);
|
|
7209
7303
|
if (!pullRequestNumber.ok) return pullRequestNumber;
|
|
7210
7304
|
const headSha = readString(value, JOURNAL_RUN_STATE_FIELDS.HEAD_SHA);
|
|
7211
7305
|
if (!headSha.ok) return headSha;
|
|
@@ -7227,9 +7321,15 @@ function readRunStateIdentity(value) {
|
|
|
7227
7321
|
};
|
|
7228
7322
|
}
|
|
7229
7323
|
function readRunStateBody(value) {
|
|
7230
|
-
const configDigest = readString(
|
|
7324
|
+
const configDigest = readString(
|
|
7325
|
+
value,
|
|
7326
|
+
JOURNAL_RUN_STATE_FIELDS.CONFIG_DIGEST
|
|
7327
|
+
);
|
|
7231
7328
|
if (!configDigest.ok) return configDigest;
|
|
7232
|
-
const participants = readStringArray(
|
|
7329
|
+
const participants = readStringArray(
|
|
7330
|
+
value,
|
|
7331
|
+
JOURNAL_RUN_STATE_FIELDS.PARTICIPANTS
|
|
7332
|
+
);
|
|
7233
7333
|
if (!participants.ok) return participants;
|
|
7234
7334
|
const scope2 = readPathFilter(value, JOURNAL_RUN_STATE_FIELDS.SCOPE);
|
|
7235
7335
|
if (!scope2.ok) return scope2;
|
|
@@ -7237,7 +7337,10 @@ function readRunStateBody(value) {
|
|
|
7237
7337
|
if (!startedAt.ok) return startedAt;
|
|
7238
7338
|
const completedAt = readString(value, JOURNAL_RUN_STATE_FIELDS.COMPLETED_AT);
|
|
7239
7339
|
if (!completedAt.ok) return completedAt;
|
|
7240
|
-
const outputPaths = readStringArray(
|
|
7340
|
+
const outputPaths = readStringArray(
|
|
7341
|
+
value,
|
|
7342
|
+
JOURNAL_RUN_STATE_FIELDS.OUTPUT_PATHS
|
|
7343
|
+
);
|
|
7241
7344
|
if (!outputPaths.ok) return outputPaths;
|
|
7242
7345
|
const status = readStatus(value, JOURNAL_RUN_STATE_FIELDS.STATUS);
|
|
7243
7346
|
if (!status.ok) return status;
|
|
@@ -7266,7 +7369,10 @@ function readOptionalString(value, field) {
|
|
|
7266
7369
|
function readOptionalNonNegativeInteger(value, field) {
|
|
7267
7370
|
const raw = value[field];
|
|
7268
7371
|
if (raw === void 0) return { ok: true, value: void 0 };
|
|
7269
|
-
return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? { ok: true, value: raw } : {
|
|
7372
|
+
return typeof raw === "number" && Number.isInteger(raw) && raw >= 0 ? { ok: true, value: raw } : {
|
|
7373
|
+
ok: false,
|
|
7374
|
+
error: `${field} must be a non-negative integer when present`
|
|
7375
|
+
};
|
|
7270
7376
|
}
|
|
7271
7377
|
function readStringArray(value, field) {
|
|
7272
7378
|
const raw = value[field];
|
|
@@ -7508,6 +7614,7 @@ function createJournal(backend, identity) {
|
|
|
7508
7614
|
|
|
7509
7615
|
// src/lib/appendable-journal-store/index.ts
|
|
7510
7616
|
var SEAL_MARKER_SUFFIX = ".sealed";
|
|
7617
|
+
var APPENDABLE_JOURNAL_SEAL_MARKER_CONTENT = "";
|
|
7511
7618
|
var LINE_SEPARATOR3 = "\n";
|
|
7512
7619
|
function appendableJournalSealMarkerPath(runFilePath) {
|
|
7513
7620
|
return `${runFilePath}${SEAL_MARKER_SUFFIX}`;
|
|
@@ -7547,7 +7654,7 @@ function createAppendableJournalStore(options) {
|
|
|
7547
7654
|
readAll,
|
|
7548
7655
|
async seal() {
|
|
7549
7656
|
await fs8.mkdir(dirname5(sealMarkerPath), { recursive: true });
|
|
7550
|
-
await fs8.writeFile(sealMarkerPath,
|
|
7657
|
+
await fs8.writeFile(sealMarkerPath, APPENDABLE_JOURNAL_SEAL_MARKER_CONTENT);
|
|
7551
7658
|
},
|
|
7552
7659
|
async isSealed() {
|
|
7553
7660
|
return await readFileOrUndefined(fs8, sealMarkerPath) !== void 0;
|
|
@@ -8004,6 +8111,20 @@ async function sealJournalRun(ref, options = {}) {
|
|
|
8004
8111
|
return { ok: false, error: `${JOURNAL_RUNTIME_ERROR.SEAL_FAILED}: ${toMessage(error)}` };
|
|
8005
8112
|
}
|
|
8006
8113
|
}
|
|
8114
|
+
async function isJournalRunSealed(ref, options = {}) {
|
|
8115
|
+
const runFilePath = bindRunFilePath(ref);
|
|
8116
|
+
if (!runFilePath.ok) return runFilePath;
|
|
8117
|
+
const fs8 = options.fs ?? defaultFileSystem;
|
|
8118
|
+
if (!await runFileExists(fs8, runFilePath.value)) {
|
|
8119
|
+
return { ok: false, error: JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND };
|
|
8120
|
+
}
|
|
8121
|
+
const store = createAppendableJournalStore({ runFilePath: runFilePath.value, fs: fs8 });
|
|
8122
|
+
try {
|
|
8123
|
+
return { ok: true, value: await store.isSealed() };
|
|
8124
|
+
} catch (error) {
|
|
8125
|
+
return { ok: false, error: `${JOURNAL_RUNTIME_ERROR.READ_FAILED}: ${toMessage(error)}` };
|
|
8126
|
+
}
|
|
8127
|
+
}
|
|
8007
8128
|
async function renderJournalRun(ref, projection, options = {}) {
|
|
8008
8129
|
const bound = await bindJournal(ref, options.fs);
|
|
8009
8130
|
if (!bound.ok) return bound;
|
|
@@ -11479,6 +11600,20 @@ function aggregateTestExitCode(invocations, unsupportedSelectionCount = 0) {
|
|
|
11479
11600
|
return SUCCESS_EXIT_CODE;
|
|
11480
11601
|
}
|
|
11481
11602
|
|
|
11603
|
+
// src/config/source-roots.ts
|
|
11604
|
+
var TEST_RELEVANT_SOURCE_ROOT_PREFIX = {
|
|
11605
|
+
SOURCE: "src/",
|
|
11606
|
+
TESTING: "testing/",
|
|
11607
|
+
SCRIPTS: "scripts/",
|
|
11608
|
+
ESLINT_RULES: "eslint-rules/"
|
|
11609
|
+
};
|
|
11610
|
+
var TEST_RELEVANT_SOURCE_ROOT_PREFIXES = [
|
|
11611
|
+
TEST_RELEVANT_SOURCE_ROOT_PREFIX.SOURCE,
|
|
11612
|
+
TEST_RELEVANT_SOURCE_ROOT_PREFIX.TESTING,
|
|
11613
|
+
TEST_RELEVANT_SOURCE_ROOT_PREFIX.SCRIPTS,
|
|
11614
|
+
TEST_RELEVANT_SOURCE_ROOT_PREFIX.ESLINT_RULES
|
|
11615
|
+
];
|
|
11616
|
+
|
|
11482
11617
|
// src/domains/test/changed-set-planning.ts
|
|
11483
11618
|
var PATH_SEPARATOR = "/";
|
|
11484
11619
|
var MARKDOWN_EXTENSION = ".md";
|
|
@@ -11683,8 +11818,8 @@ var PRODUCT_INPUT_DIGEST_FIELDS = {
|
|
|
11683
11818
|
DESCRIPTOR_ID: "descriptorId",
|
|
11684
11819
|
DIGEST: "digest"
|
|
11685
11820
|
};
|
|
11686
|
-
var
|
|
11687
|
-
var
|
|
11821
|
+
var SHA256_ALGORITHM2 = "sha256";
|
|
11822
|
+
var HEX_ENCODING2 = "hex";
|
|
11688
11823
|
var SEGMENT_SEPARATOR = "-";
|
|
11689
11824
|
var defaultFileSystem2 = defaultFileSystem;
|
|
11690
11825
|
function formatTestRunTimestamp(date) {
|
|
@@ -11960,7 +12095,7 @@ function isRecord6(value) {
|
|
|
11960
12095
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11961
12096
|
}
|
|
11962
12097
|
function sha256Hex2(value) {
|
|
11963
|
-
return createHash4(
|
|
12098
|
+
return createHash4(SHA256_ALGORITHM2).update(value).digest(HEX_ENCODING2);
|
|
11964
12099
|
}
|
|
11965
12100
|
var UNKNOWN_ERROR_MESSAGE = "unknown error";
|
|
11966
12101
|
function toErrorMessage3(error) {
|
|
@@ -19418,13 +19553,13 @@ async function persistVerificationContext(scope2, document, options = {}) {
|
|
|
19418
19553
|
const existing = await readExistingContext(fs8, contextPath.value);
|
|
19419
19554
|
if (!existing.ok) return existing;
|
|
19420
19555
|
if (existing.value === document.canonicalJson) {
|
|
19421
|
-
return { ok: true, value: { digest: document.digest, contextPath: contextPath.value } };
|
|
19556
|
+
return { ok: true, value: { digest: document.digest, contextPath: contextPath.value, created: false } };
|
|
19422
19557
|
}
|
|
19423
19558
|
return { ok: false, error: VERIFICATION_CONTEXT_RUNTIME_ERROR.CONTENT_MISMATCH };
|
|
19424
19559
|
}
|
|
19425
19560
|
return { ok: false, error: `${VERIFICATION_CONTEXT_RUNTIME_ERROR.WRITE_FAILED}: ${toMessage(error)}` };
|
|
19426
19561
|
}
|
|
19427
|
-
return { ok: true, value: { digest: document.digest, contextPath: contextPath.value } };
|
|
19562
|
+
return { ok: true, value: { digest: document.digest, contextPath: contextPath.value, created: true } };
|
|
19428
19563
|
}
|
|
19429
19564
|
async function readExistingContext(fs8, contextPath) {
|
|
19430
19565
|
try {
|
|
@@ -19570,6 +19705,7 @@ var verificationContextDomain = {
|
|
|
19570
19705
|
import { readFile as readFile13 } from "fs/promises";
|
|
19571
19706
|
|
|
19572
19707
|
// src/commands/verify/cli.ts
|
|
19708
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
19573
19709
|
import { dirname as dirname12 } from "path";
|
|
19574
19710
|
|
|
19575
19711
|
// src/domains/verify/verify.ts
|
|
@@ -19582,18 +19718,93 @@ var VERIFY_VERB = {
|
|
|
19582
19718
|
START: "start",
|
|
19583
19719
|
INPUT: "input",
|
|
19584
19720
|
APPEND_SCOPE: "append-scope",
|
|
19585
|
-
APPEND_FINDING: "append-finding"
|
|
19721
|
+
APPEND_FINDING: "append-finding",
|
|
19722
|
+
FINISH: "finish",
|
|
19723
|
+
STATUS: "status",
|
|
19724
|
+
RENDER: "render"
|
|
19586
19725
|
};
|
|
19726
|
+
var VERIFY_LIFECYCLE_ACTION = {
|
|
19727
|
+
SCOPE_ADD: "scope add",
|
|
19728
|
+
FINDING_ADD: "finding add",
|
|
19729
|
+
FINISH: VERIFY_VERB.FINISH
|
|
19730
|
+
};
|
|
19731
|
+
var UNSEALED_NEXT_ACTIONS = [
|
|
19732
|
+
VERIFY_LIFECYCLE_ACTION.SCOPE_ADD,
|
|
19733
|
+
VERIFY_LIFECYCLE_ACTION.FINDING_ADD,
|
|
19734
|
+
VERIFY_LIFECYCLE_ACTION.FINISH
|
|
19735
|
+
];
|
|
19587
19736
|
var VERIFY_VERIFICATION_TYPE = {
|
|
19737
|
+
AUDIT: "audit",
|
|
19588
19738
|
REVIEW: "review"
|
|
19589
19739
|
};
|
|
19740
|
+
var VERIFY_VERIFICATION_TYPES = new Set(Object.values(VERIFY_VERIFICATION_TYPE));
|
|
19741
|
+
function isVerifyVerificationType(value) {
|
|
19742
|
+
return VERIFY_VERIFICATION_TYPES.has(value);
|
|
19743
|
+
}
|
|
19590
19744
|
var REVIEW_FINDING_DISPOSITION = {
|
|
19591
19745
|
BLOCKING: "BLOCKING",
|
|
19592
19746
|
DEBT: "DEBT"
|
|
19593
19747
|
};
|
|
19748
|
+
var REVIEW_SCOPE_COVERAGE_STATE = {
|
|
19749
|
+
CLEAN: "clean",
|
|
19750
|
+
FINDING: "finding"
|
|
19751
|
+
};
|
|
19752
|
+
var REVIEW_ANCHOR_SIDE = {
|
|
19753
|
+
LEFT: "LEFT",
|
|
19754
|
+
RIGHT: "RIGHT"
|
|
19755
|
+
};
|
|
19756
|
+
var REVIEW_TERMINAL_STATE = {
|
|
19757
|
+
APPROVED: "approved",
|
|
19758
|
+
CHANGES_REQUESTED: "changes_requested",
|
|
19759
|
+
COMMENTED: "commented"
|
|
19760
|
+
};
|
|
19761
|
+
var AUDIT_CLASS = {
|
|
19762
|
+
IMPLEMENTATION: "implementation",
|
|
19763
|
+
INSTRUCTIONS: "instructions",
|
|
19764
|
+
SPEC: "spec"
|
|
19765
|
+
};
|
|
19766
|
+
var AUDIT_KIND = {
|
|
19767
|
+
ADR: "adr",
|
|
19768
|
+
ARCHITECTURE: "architecture",
|
|
19769
|
+
CODE: "code",
|
|
19770
|
+
COVERAGE_GAP: "coverage-gap",
|
|
19771
|
+
EVAL_EVIDENCE: "eval-evidence",
|
|
19772
|
+
GUIDE_TEMPLATE: "guide-template",
|
|
19773
|
+
PDR: "pdr",
|
|
19774
|
+
PROMPT: "prompt",
|
|
19775
|
+
SKILL: "skill",
|
|
19776
|
+
SPEC: "spec",
|
|
19777
|
+
SUBAGENT: "subagent",
|
|
19778
|
+
TESTS: "tests"
|
|
19779
|
+
};
|
|
19780
|
+
var AUDIT_COVERAGE_REQUIREMENT = {
|
|
19781
|
+
OPTIONAL: "optional",
|
|
19782
|
+
REQUIRED: "required"
|
|
19783
|
+
};
|
|
19784
|
+
var AUDIT_COVERAGE_STATUS = {
|
|
19785
|
+
AUDITED: "audited",
|
|
19786
|
+
INCOMPLETE: "incomplete",
|
|
19787
|
+
MISSING_SKILL: "missing-skill",
|
|
19788
|
+
NOT_APPLICABLE: "not-applicable",
|
|
19789
|
+
SKIPPED: "skipped",
|
|
19790
|
+
UNSUPPORTED: "unsupported"
|
|
19791
|
+
};
|
|
19792
|
+
var AUDIT_FINDING_SEVERITY = {
|
|
19793
|
+
BLOCKING: "blocking",
|
|
19794
|
+
DEBT: "debt"
|
|
19795
|
+
};
|
|
19796
|
+
var TERMINAL_METADATA_VALIDATION_ERROR = {
|
|
19797
|
+
METADATA_INVALID: "metadata-invalid",
|
|
19798
|
+
STATUS_CONFLICT: "status-conflict"
|
|
19799
|
+
};
|
|
19800
|
+
var VERIFY_EVIDENCE_KIND = {
|
|
19801
|
+
SCOPE: "scope",
|
|
19802
|
+
FINDING: "finding",
|
|
19803
|
+
TERMINAL_METADATA: "terminal-metadata"
|
|
19804
|
+
};
|
|
19594
19805
|
var VERIFY_APPEND_EVENT_TYPE = {
|
|
19595
|
-
SCOPE:
|
|
19596
|
-
FINDING:
|
|
19806
|
+
SCOPE: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.scope`,
|
|
19807
|
+
FINDING: `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.finding`
|
|
19597
19808
|
};
|
|
19598
19809
|
var VERIFY_EVENT_SOURCE = "/spx/verify";
|
|
19599
19810
|
var VERIFY_APPEND_EVENT_FIELD = {
|
|
@@ -19611,7 +19822,9 @@ var VERIFY_SCOPE_ERROR = {
|
|
|
19611
19822
|
var VERIFY_INPUT_DIGEST_PATH = "verify run input";
|
|
19612
19823
|
function parseChangesetScope(scope2) {
|
|
19613
19824
|
const separatorIndex = scope2.indexOf(VERIFY_SCOPE_SEPARATOR);
|
|
19614
|
-
if (separatorIndex < 0)
|
|
19825
|
+
if (separatorIndex < 0) {
|
|
19826
|
+
return { ok: false, error: VERIFY_SCOPE_ERROR.MALFORMED_CHANGESET };
|
|
19827
|
+
}
|
|
19615
19828
|
const base = scope2.slice(0, separatorIndex);
|
|
19616
19829
|
const head = scope2.slice(separatorIndex + VERIFY_SCOPE_SEPARATOR.length);
|
|
19617
19830
|
if (base.length === 0 || head.length === 0 || head.includes(VERIFY_SCOPE_SEPARATOR)) {
|
|
@@ -19631,7 +19844,10 @@ function buildRunLocator(parts) {
|
|
|
19631
19844
|
};
|
|
19632
19845
|
}
|
|
19633
19846
|
function digestRunInput(source, content) {
|
|
19634
|
-
const digest = digestDescriptorSection(
|
|
19847
|
+
const digest = digestDescriptorSection(
|
|
19848
|
+
{ source, content },
|
|
19849
|
+
VERIFY_INPUT_DIGEST_PATH
|
|
19850
|
+
);
|
|
19635
19851
|
if (!digest.ok) return digest;
|
|
19636
19852
|
return { ok: true, value: digest.value.sha256 };
|
|
19637
19853
|
}
|
|
@@ -19651,7 +19867,10 @@ function verifyInputRecordPath(scope2) {
|
|
|
19651
19867
|
if (!token.ok) return token;
|
|
19652
19868
|
return {
|
|
19653
19869
|
ok: true,
|
|
19654
|
-
value: join36(
|
|
19870
|
+
value: join36(
|
|
19871
|
+
runs.value,
|
|
19872
|
+
`${VERIFY_INPUT_RECORD.PREFIX}${token.value}${VERIFY_INPUT_RECORD.SUFFIX}`
|
|
19873
|
+
)
|
|
19655
19874
|
};
|
|
19656
19875
|
}
|
|
19657
19876
|
var VERIFY_APPEND_ATTEMPT = 1;
|
|
@@ -19665,67 +19884,546 @@ function parseAppendPayload(raw) {
|
|
|
19665
19884
|
function isJsonRecord(value) {
|
|
19666
19885
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19667
19886
|
}
|
|
19887
|
+
function readRequiredString(record6, field) {
|
|
19888
|
+
const value = record6[field];
|
|
19889
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
19890
|
+
}
|
|
19891
|
+
function readRequiredStringValue(record6, field) {
|
|
19892
|
+
const value = record6[field];
|
|
19893
|
+
return typeof value === "string" ? value : void 0;
|
|
19894
|
+
}
|
|
19895
|
+
var OPTIONAL_FIELD_STATE = {
|
|
19896
|
+
ABSENT: "absent",
|
|
19897
|
+
INVALID: "invalid",
|
|
19898
|
+
PRESENT: "present"
|
|
19899
|
+
};
|
|
19900
|
+
function readOptionalString2(record6, field) {
|
|
19901
|
+
if (!(field in record6)) return { state: OPTIONAL_FIELD_STATE.ABSENT };
|
|
19902
|
+
const value = record6[field];
|
|
19903
|
+
return typeof value === "string" && value.length > 0 ? { state: OPTIONAL_FIELD_STATE.PRESENT, value } : { state: OPTIONAL_FIELD_STATE.INVALID };
|
|
19904
|
+
}
|
|
19905
|
+
function readOptionalPositiveInteger(record6, field) {
|
|
19906
|
+
if (!(field in record6)) return { state: OPTIONAL_FIELD_STATE.ABSENT };
|
|
19907
|
+
const value = record6[field];
|
|
19908
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? { state: OPTIONAL_FIELD_STATE.PRESENT, value } : { state: OPTIONAL_FIELD_STATE.INVALID };
|
|
19909
|
+
}
|
|
19910
|
+
function optionalFieldValue(field) {
|
|
19911
|
+
return field.state === OPTIONAL_FIELD_STATE.PRESENT ? field.value : void 0;
|
|
19912
|
+
}
|
|
19913
|
+
function readRequiredRecord(record6, field) {
|
|
19914
|
+
const value = record6[field];
|
|
19915
|
+
return isJsonRecord(value) ? value : void 0;
|
|
19916
|
+
}
|
|
19917
|
+
function readOptionalRecord(record6, field) {
|
|
19918
|
+
if (!(field in record6)) return { state: OPTIONAL_FIELD_STATE.ABSENT };
|
|
19919
|
+
const value = record6[field];
|
|
19920
|
+
return isJsonRecord(value) ? { state: OPTIONAL_FIELD_STATE.PRESENT, value } : { state: OPTIONAL_FIELD_STATE.INVALID };
|
|
19921
|
+
}
|
|
19922
|
+
function hasInvalidOptionalField(...fields) {
|
|
19923
|
+
return fields.some((field) => field.state === OPTIONAL_FIELD_STATE.INVALID);
|
|
19924
|
+
}
|
|
19668
19925
|
function isReviewFindingDisposition(value) {
|
|
19669
19926
|
return Object.values(REVIEW_FINDING_DISPOSITION).includes(value);
|
|
19670
19927
|
}
|
|
19671
|
-
function
|
|
19928
|
+
function isReviewScopeCoverageState(value) {
|
|
19929
|
+
return typeof value === "string" && Object.values(REVIEW_SCOPE_COVERAGE_STATE).includes(value);
|
|
19930
|
+
}
|
|
19931
|
+
function isReviewAnchorSide(value) {
|
|
19932
|
+
return typeof value === "string" && Object.values(REVIEW_ANCHOR_SIDE).includes(value);
|
|
19933
|
+
}
|
|
19934
|
+
function isReviewTerminalState(value) {
|
|
19935
|
+
return typeof value === "string" && Object.values(REVIEW_TERMINAL_STATE).includes(value);
|
|
19936
|
+
}
|
|
19937
|
+
function isAuditClass(value) {
|
|
19938
|
+
return typeof value === "string" && Object.values(AUDIT_CLASS).includes(value);
|
|
19939
|
+
}
|
|
19940
|
+
function isAuditKind(value) {
|
|
19941
|
+
return typeof value === "string" && Object.values(AUDIT_KIND).includes(value);
|
|
19942
|
+
}
|
|
19943
|
+
function isAuditCoverageRequirement(value) {
|
|
19944
|
+
return typeof value === "string" && Object.values(AUDIT_COVERAGE_REQUIREMENT).includes(value);
|
|
19945
|
+
}
|
|
19946
|
+
function isAuditCoverageStatus(value) {
|
|
19947
|
+
return typeof value === "string" && Object.values(AUDIT_COVERAGE_STATUS).includes(value);
|
|
19948
|
+
}
|
|
19949
|
+
function isAuditFindingSeverity(value) {
|
|
19950
|
+
return typeof value === "string" && Object.values(AUDIT_FINDING_SEVERITY).includes(value);
|
|
19951
|
+
}
|
|
19952
|
+
function isCompatibleAuditKind(auditClass, auditKind) {
|
|
19953
|
+
if (auditKind === AUDIT_KIND.COVERAGE_GAP) return true;
|
|
19954
|
+
if (auditClass === AUDIT_CLASS.INSTRUCTIONS) {
|
|
19955
|
+
return auditKind === AUDIT_KIND.SKILL || auditKind === AUDIT_KIND.SUBAGENT || auditKind === AUDIT_KIND.PROMPT || auditKind === AUDIT_KIND.GUIDE_TEMPLATE;
|
|
19956
|
+
}
|
|
19957
|
+
if (auditClass === AUDIT_CLASS.SPEC) {
|
|
19958
|
+
return auditKind === AUDIT_KIND.SPEC || auditKind === AUDIT_KIND.ADR || auditKind === AUDIT_KIND.PDR;
|
|
19959
|
+
}
|
|
19960
|
+
return auditKind === AUDIT_KIND.CODE || auditKind === AUDIT_KIND.TESTS || auditKind === AUDIT_KIND.ARCHITECTURE || auditKind === AUDIT_KIND.EVAL_EVIDENCE;
|
|
19961
|
+
}
|
|
19962
|
+
function evidencePayloadValidator(validator) {
|
|
19963
|
+
return (input) => validator(input.payload);
|
|
19964
|
+
}
|
|
19965
|
+
function readReviewFindingMetadata(payload) {
|
|
19672
19966
|
if (!isJsonRecord(payload)) return void 0;
|
|
19673
19967
|
const { disposition, summary } = payload;
|
|
19674
19968
|
if (!isReviewFindingDisposition(disposition)) return void 0;
|
|
19675
19969
|
if (typeof summary !== "string" || summary.length === 0) return void 0;
|
|
19676
19970
|
return { disposition, summary };
|
|
19677
19971
|
}
|
|
19678
|
-
|
|
19679
|
-
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19972
|
+
function validateReviewFinding(payload) {
|
|
19973
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
19974
|
+
const path7 = readRequiredString(payload, "path");
|
|
19975
|
+
const originalCommit = readRequiredString(payload, "originalCommit");
|
|
19976
|
+
const diffHunk = readRequiredString(payload, "diffHunk");
|
|
19977
|
+
const body = readRequiredString(payload, "body");
|
|
19978
|
+
const { side } = payload;
|
|
19979
|
+
const finding = readReviewFindingMetadata(payload.finding);
|
|
19980
|
+
if (path7 === void 0 || originalCommit === void 0 || diffHunk === void 0 || body === void 0) {
|
|
19981
|
+
return void 0;
|
|
19982
|
+
}
|
|
19983
|
+
if (!isReviewAnchorSide(side)) return void 0;
|
|
19984
|
+
if (finding === void 0) return void 0;
|
|
19985
|
+
const line = readOptionalPositiveInteger(payload, "line");
|
|
19986
|
+
const position = readOptionalPositiveInteger(payload, "position");
|
|
19987
|
+
const providerIdentity = readOptionalString2(payload, "providerIdentity");
|
|
19988
|
+
const url = readOptionalString2(payload, "url");
|
|
19989
|
+
if (hasInvalidOptionalField(line, position, providerIdentity, url)) return void 0;
|
|
19990
|
+
const lineValue = optionalFieldValue(line);
|
|
19991
|
+
const positionValue = optionalFieldValue(position);
|
|
19992
|
+
if (lineValue === void 0 && positionValue === void 0) return void 0;
|
|
19993
|
+
const providerIdentityValue = optionalFieldValue(providerIdentity);
|
|
19994
|
+
const urlValue = optionalFieldValue(url);
|
|
19995
|
+
return {
|
|
19996
|
+
path: path7,
|
|
19997
|
+
side,
|
|
19998
|
+
originalCommit,
|
|
19999
|
+
diffHunk,
|
|
20000
|
+
body,
|
|
20001
|
+
finding,
|
|
20002
|
+
...providerIdentityValue === void 0 ? {} : { providerIdentity: providerIdentityValue },
|
|
20003
|
+
...lineValue === void 0 ? {} : { line: lineValue },
|
|
20004
|
+
...positionValue === void 0 ? {} : { position: positionValue },
|
|
20005
|
+
...urlValue === void 0 ? {} : { url: urlValue }
|
|
20006
|
+
};
|
|
19683
20007
|
}
|
|
19684
|
-
function
|
|
19685
|
-
|
|
19686
|
-
|
|
19687
|
-
);
|
|
19688
|
-
|
|
20008
|
+
function validateReviewScope(payload) {
|
|
20009
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20010
|
+
const path7 = readRequiredString(payload, "path");
|
|
20011
|
+
const commit = readRequiredString(payload, "commit");
|
|
20012
|
+
const { side, coverageState } = payload;
|
|
20013
|
+
if (path7 === void 0 || commit === void 0) return void 0;
|
|
20014
|
+
if (!isReviewAnchorSide(side)) return void 0;
|
|
20015
|
+
if (!isReviewScopeCoverageState(coverageState)) return void 0;
|
|
20016
|
+
const line = readOptionalPositiveInteger(payload, "line");
|
|
20017
|
+
const position = readOptionalPositiveInteger(payload, "position");
|
|
20018
|
+
const providerIdentity = readOptionalString2(payload, "providerIdentity");
|
|
20019
|
+
const url = readOptionalString2(payload, "url");
|
|
20020
|
+
if (hasInvalidOptionalField(line, position, providerIdentity, url)) return void 0;
|
|
20021
|
+
const lineValue = optionalFieldValue(line);
|
|
20022
|
+
const positionValue = optionalFieldValue(position);
|
|
20023
|
+
const providerIdentityValue = optionalFieldValue(providerIdentity);
|
|
20024
|
+
const urlValue = optionalFieldValue(url);
|
|
20025
|
+
return {
|
|
20026
|
+
path: path7,
|
|
20027
|
+
side,
|
|
20028
|
+
commit,
|
|
20029
|
+
coverageState,
|
|
20030
|
+
...providerIdentityValue === void 0 ? {} : { providerIdentity: providerIdentityValue },
|
|
20031
|
+
...lineValue === void 0 ? {} : { line: lineValue },
|
|
20032
|
+
...positionValue === void 0 ? {} : { position: positionValue },
|
|
20033
|
+
...urlValue === void 0 ? {} : { url: urlValue }
|
|
20034
|
+
};
|
|
19689
20035
|
}
|
|
19690
|
-
function
|
|
20036
|
+
function validateReviewTerminalMetadata(payload) {
|
|
20037
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20038
|
+
const actor = readRequiredString(payload, "actor");
|
|
20039
|
+
const body = readRequiredStringValue(payload, "body");
|
|
20040
|
+
const submittedAt = readRequiredString(payload, "submittedAt");
|
|
20041
|
+
const commit = readRequiredString(payload, "commit");
|
|
20042
|
+
const { state } = payload;
|
|
20043
|
+
if (actor === void 0 || body === void 0 || submittedAt === void 0 || commit === void 0) return void 0;
|
|
20044
|
+
if (!isReviewTerminalState(state)) return void 0;
|
|
20045
|
+
const providerIdentity = readOptionalString2(payload, "providerIdentity");
|
|
20046
|
+
const url = readOptionalString2(payload, "url");
|
|
20047
|
+
if (hasInvalidOptionalField(providerIdentity, url)) return void 0;
|
|
20048
|
+
const providerIdentityValue = optionalFieldValue(providerIdentity);
|
|
20049
|
+
const urlValue = optionalFieldValue(url);
|
|
19691
20050
|
return {
|
|
19692
|
-
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
|
|
19698
|
-
|
|
19699
|
-
|
|
20051
|
+
actor,
|
|
20052
|
+
state,
|
|
20053
|
+
body,
|
|
20054
|
+
submittedAt,
|
|
20055
|
+
commit,
|
|
20056
|
+
...providerIdentityValue === void 0 ? {} : { providerIdentity: providerIdentityValue },
|
|
20057
|
+
...urlValue === void 0 ? {} : { url: urlValue }
|
|
20058
|
+
};
|
|
20059
|
+
}
|
|
20060
|
+
function validateReviewTerminal(input) {
|
|
20061
|
+
const validated = input.metadata === void 0 ? void 0 : validateReviewTerminalMetadata(input.metadata);
|
|
20062
|
+
if (input.metadata !== void 0 && validated === void 0) {
|
|
20063
|
+
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.METADATA_INVALID };
|
|
20064
|
+
}
|
|
20065
|
+
const evidenceStatus = expectedReviewEvidenceTerminalStatus(input.events);
|
|
20066
|
+
const metadataStatus = expectedReviewMetadataTerminalStatus(validated);
|
|
20067
|
+
if (evidenceStatus !== void 0 && metadataStatus !== void 0 && evidenceStatus !== metadataStatus) {
|
|
20068
|
+
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
|
|
20069
|
+
}
|
|
20070
|
+
const expectedStatus = evidenceStatus ?? metadataStatus;
|
|
20071
|
+
if (expectedStatus !== void 0 && input.terminalStatus !== expectedStatus) {
|
|
20072
|
+
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
|
|
20073
|
+
}
|
|
20074
|
+
if (validated === void 0) return { ok: true, value: void 0 };
|
|
20075
|
+
return {
|
|
20076
|
+
ok: true,
|
|
20077
|
+
value: {
|
|
20078
|
+
actor: validated.actor,
|
|
20079
|
+
state: validated.state,
|
|
20080
|
+
body: validated.body,
|
|
20081
|
+
submittedAt: validated.submittedAt,
|
|
20082
|
+
commit: validated.commit,
|
|
20083
|
+
...validated.providerIdentity === void 0 ? {} : { providerIdentity: validated.providerIdentity },
|
|
20084
|
+
...validated.url === void 0 ? {} : { url: validated.url }
|
|
19700
20085
|
}
|
|
19701
20086
|
};
|
|
19702
20087
|
}
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
|
|
19708
|
-
|
|
19709
|
-
|
|
19710
|
-
|
|
19711
|
-
|
|
19712
|
-
|
|
19713
|
-
|
|
19714
|
-
|
|
19715
|
-
|
|
19716
|
-
|
|
19717
|
-
|
|
19718
|
-
|
|
19719
|
-
|
|
19720
|
-
|
|
19721
|
-
|
|
19722
|
-
|
|
19723
|
-
|
|
19724
|
-
|
|
19725
|
-
|
|
19726
|
-
|
|
19727
|
-
|
|
19728
|
-
|
|
20088
|
+
function validateAuditProducerIdentity(payload) {
|
|
20089
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20090
|
+
const producerKind = readRequiredString(payload, "producerKind");
|
|
20091
|
+
const agentName = readRequiredString(payload, "agentName");
|
|
20092
|
+
const agentOwningPluginName = readRequiredString(payload, "agentOwningPluginName");
|
|
20093
|
+
const skillName = readRequiredString(payload, "skillName");
|
|
20094
|
+
const skillOwningPluginName = readRequiredString(payload, "skillOwningPluginName");
|
|
20095
|
+
const invocationRole = readRequiredString(payload, "invocationRole");
|
|
20096
|
+
if (producerKind === void 0 || agentName === void 0 || agentOwningPluginName === void 0 || skillName === void 0 || skillOwningPluginName === void 0 || invocationRole === void 0) {
|
|
20097
|
+
return void 0;
|
|
20098
|
+
}
|
|
20099
|
+
return {
|
|
20100
|
+
producerKind,
|
|
20101
|
+
agentName,
|
|
20102
|
+
agentOwningPluginName,
|
|
20103
|
+
skillName,
|
|
20104
|
+
skillOwningPluginName,
|
|
20105
|
+
invocationRole
|
|
20106
|
+
};
|
|
20107
|
+
}
|
|
20108
|
+
function validateAuditProducerProvenance(payload) {
|
|
20109
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20110
|
+
const agentOwningPluginVersion = readRequiredString(payload, "agentOwningPluginVersion");
|
|
20111
|
+
const skillOwningPluginVersion = readRequiredString(payload, "skillOwningPluginVersion");
|
|
20112
|
+
if (agentOwningPluginVersion === void 0 || skillOwningPluginVersion === void 0) return void 0;
|
|
20113
|
+
const toolVersion = readOptionalString2(payload, "toolVersion");
|
|
20114
|
+
if (hasInvalidOptionalField(toolVersion)) return void 0;
|
|
20115
|
+
const toolVersionValue = optionalFieldValue(toolVersion);
|
|
20116
|
+
return {
|
|
20117
|
+
agentOwningPluginVersion,
|
|
20118
|
+
skillOwningPluginVersion,
|
|
20119
|
+
...toolVersionValue === void 0 ? {} : { toolVersion: toolVersionValue }
|
|
20120
|
+
};
|
|
20121
|
+
}
|
|
20122
|
+
function validateAuditPriorContextPartitions(payload) {
|
|
20123
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20124
|
+
const changedFilePartition = readRequiredString(payload, "changedFilePartition");
|
|
20125
|
+
const concernPartition = readRequiredString(payload, "concernPartition");
|
|
20126
|
+
if (changedFilePartition === void 0 || concernPartition === void 0) return void 0;
|
|
20127
|
+
const languagePartition = readOptionalString2(payload, "languagePartition");
|
|
20128
|
+
if (hasInvalidOptionalField(languagePartition)) return void 0;
|
|
20129
|
+
const languagePartitionValue = optionalFieldValue(languagePartition);
|
|
20130
|
+
return {
|
|
20131
|
+
changedFilePartition,
|
|
20132
|
+
concernPartition,
|
|
20133
|
+
...languagePartitionValue === void 0 ? {} : { languagePartition: languagePartitionValue }
|
|
20134
|
+
};
|
|
20135
|
+
}
|
|
20136
|
+
function validateOptionalAuditProducerProvenance(producerProvenance) {
|
|
20137
|
+
if (producerProvenance.state !== OPTIONAL_FIELD_STATE.PRESENT) return producerProvenance;
|
|
20138
|
+
const value = validateAuditProducerProvenance(producerProvenance.value);
|
|
20139
|
+
return value === void 0 ? { state: OPTIONAL_FIELD_STATE.INVALID } : { state: OPTIONAL_FIELD_STATE.PRESENT, value };
|
|
20140
|
+
}
|
|
20141
|
+
function auditKindAllowsProducerProvenance(auditKind, producerProvenance) {
|
|
20142
|
+
return auditKind !== AUDIT_KIND.COVERAGE_GAP || producerProvenance === void 0;
|
|
20143
|
+
}
|
|
20144
|
+
function auditKindAllowsCoverageStatus(auditKind, coverageStatus) {
|
|
20145
|
+
return auditKind !== AUDIT_KIND.COVERAGE_GAP || coverageStatus !== AUDIT_COVERAGE_STATUS.AUDITED && coverageStatus !== AUDIT_COVERAGE_STATUS.NOT_APPLICABLE;
|
|
20146
|
+
}
|
|
20147
|
+
function validateAuditScope(payload) {
|
|
20148
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20149
|
+
const unitId = readRequiredString(payload, "unitId");
|
|
20150
|
+
const subject = readRequiredString(payload, "subject");
|
|
20151
|
+
const { auditClass, auditKind, coverageRequirement, coverageStatus } = payload;
|
|
20152
|
+
if (unitId === void 0 || subject === void 0) return void 0;
|
|
20153
|
+
if (!isAuditClass(auditClass) || !isAuditKind(auditKind)) return void 0;
|
|
20154
|
+
if (!isCompatibleAuditKind(auditClass, auditKind)) return void 0;
|
|
20155
|
+
if (!isAuditCoverageRequirement(coverageRequirement)) return void 0;
|
|
20156
|
+
if (!isAuditCoverageStatus(coverageStatus)) return void 0;
|
|
20157
|
+
if (!auditKindAllowsCoverageStatus(auditKind, coverageStatus)) return void 0;
|
|
20158
|
+
const priorContext = validateAuditPriorContextPartitions(readRequiredRecord(payload, "priorContext"));
|
|
20159
|
+
const expectedProducer = validateAuditProducerIdentity(readRequiredRecord(payload, "expectedProducer"));
|
|
20160
|
+
const recordedByRunDriver = validateAuditProducerIdentity(readRequiredRecord(payload, "recordedByRunDriver"));
|
|
20161
|
+
if (priorContext === void 0 || expectedProducer === void 0 || recordedByRunDriver === void 0) {
|
|
20162
|
+
return void 0;
|
|
20163
|
+
}
|
|
20164
|
+
const parentUnitId = readOptionalString2(payload, "parentUnitId");
|
|
20165
|
+
const producerProvenance = validateOptionalAuditProducerProvenance(
|
|
20166
|
+
readOptionalRecord(payload, "producerProvenance")
|
|
20167
|
+
);
|
|
20168
|
+
if (hasInvalidOptionalField(parentUnitId, producerProvenance)) return void 0;
|
|
20169
|
+
const parentUnitIdValue = optionalFieldValue(parentUnitId);
|
|
20170
|
+
const producerProvenanceValue = optionalFieldValue(producerProvenance);
|
|
20171
|
+
if (parentUnitIdValue === unitId) return void 0;
|
|
20172
|
+
if (!auditKindAllowsProducerProvenance(auditKind, producerProvenanceValue)) return void 0;
|
|
20173
|
+
return {
|
|
20174
|
+
unitId,
|
|
20175
|
+
auditClass,
|
|
20176
|
+
auditKind,
|
|
20177
|
+
subject,
|
|
20178
|
+
coverageRequirement,
|
|
20179
|
+
coverageStatus,
|
|
20180
|
+
priorContext,
|
|
20181
|
+
expectedProducer,
|
|
20182
|
+
recordedByRunDriver,
|
|
20183
|
+
...parentUnitIdValue === void 0 ? {} : { parentUnitId: parentUnitIdValue },
|
|
20184
|
+
...producerProvenanceValue === void 0 ? {} : { producerProvenance: producerProvenanceValue }
|
|
20185
|
+
};
|
|
20186
|
+
}
|
|
20187
|
+
function validateAuditFindingEvidence(evidence) {
|
|
20188
|
+
if (evidence === void 0) return void 0;
|
|
20189
|
+
const observed = readRequiredString(evidence, "observed");
|
|
20190
|
+
const expected = readRequiredString(evidence, "expected");
|
|
20191
|
+
if (observed === void 0 || expected === void 0) return void 0;
|
|
20192
|
+
return { observed, expected };
|
|
20193
|
+
}
|
|
20194
|
+
function validateAuditFinding(payload) {
|
|
20195
|
+
if (!isJsonRecord(payload)) return void 0;
|
|
20196
|
+
const unitId = readRequiredString(payload, "unitId");
|
|
20197
|
+
const rule = readRequiredString(payload, "rule");
|
|
20198
|
+
const location = readRequiredString(payload, "location");
|
|
20199
|
+
const message = readRequiredString(payload, "message");
|
|
20200
|
+
const { severity } = payload;
|
|
20201
|
+
if (unitId === void 0 || rule === void 0 || location === void 0 || message === void 0) {
|
|
20202
|
+
return void 0;
|
|
20203
|
+
}
|
|
20204
|
+
if (!isAuditFindingSeverity(severity)) return void 0;
|
|
20205
|
+
const producerIdentity = validateAuditProducerIdentity(readRequiredRecord(payload, "producerIdentity"));
|
|
20206
|
+
const producerProvenance = validateAuditProducerProvenance(readRequiredRecord(payload, "producerProvenance"));
|
|
20207
|
+
const evidence = validateAuditFindingEvidence(readRequiredRecord(payload, "evidence"));
|
|
20208
|
+
if (producerIdentity === void 0 || producerProvenance === void 0 || evidence === void 0) {
|
|
20209
|
+
return void 0;
|
|
20210
|
+
}
|
|
20211
|
+
return {
|
|
20212
|
+
unitId,
|
|
20213
|
+
producerIdentity,
|
|
20214
|
+
producerProvenance,
|
|
20215
|
+
rule,
|
|
20216
|
+
severity,
|
|
20217
|
+
location,
|
|
20218
|
+
message,
|
|
20219
|
+
evidence
|
|
20220
|
+
};
|
|
20221
|
+
}
|
|
20222
|
+
function auditFindingReferencesRecordedScope(events, finding) {
|
|
20223
|
+
return events.some((event) => {
|
|
20224
|
+
if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
|
|
20225
|
+
const scope2 = validateAuditScope(event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD]);
|
|
20226
|
+
return scope2?.unitId === finding.unitId;
|
|
20227
|
+
});
|
|
20228
|
+
}
|
|
20229
|
+
function validateAuditFindingForRun(input) {
|
|
20230
|
+
const finding = validateAuditFinding(input.payload);
|
|
20231
|
+
if (finding === void 0) return void 0;
|
|
20232
|
+
return auditFindingReferencesRecordedScope(input.events, finding) ? finding : void 0;
|
|
20233
|
+
}
|
|
20234
|
+
var EVIDENCE_VALIDATORS = {
|
|
20235
|
+
[VERIFY_VERIFICATION_TYPE.AUDIT]: {
|
|
20236
|
+
[VERIFY_EVIDENCE_KIND.SCOPE]: evidencePayloadValidator(validateAuditScope),
|
|
20237
|
+
[VERIFY_EVIDENCE_KIND.FINDING]: validateAuditFindingForRun,
|
|
20238
|
+
[VERIFY_EVIDENCE_KIND.TERMINAL_METADATA]: validateAuditTerminal
|
|
20239
|
+
},
|
|
20240
|
+
[VERIFY_VERIFICATION_TYPE.REVIEW]: {
|
|
20241
|
+
[VERIFY_EVIDENCE_KIND.SCOPE]: evidencePayloadValidator(validateReviewScope),
|
|
20242
|
+
[VERIFY_EVIDENCE_KIND.FINDING]: evidencePayloadValidator(validateReviewFinding),
|
|
20243
|
+
[VERIFY_EVIDENCE_KIND.TERMINAL_METADATA]: validateReviewTerminal
|
|
20244
|
+
}
|
|
20245
|
+
};
|
|
20246
|
+
function evidenceValidatorFor(verificationType, evidenceKind) {
|
|
20247
|
+
return EVIDENCE_VALIDATORS[verificationType]?.[evidenceKind];
|
|
20248
|
+
}
|
|
20249
|
+
function terminalMetadataValidatorFor(verificationType) {
|
|
20250
|
+
return EVIDENCE_VALIDATORS[verificationType]?.[VERIFY_EVIDENCE_KIND.TERMINAL_METADATA];
|
|
20251
|
+
}
|
|
20252
|
+
function expectedReviewEvidenceTerminalStatus(events) {
|
|
20253
|
+
if (countVerifyFindings(events) > 0 || countReviewScopeFindingUnits(events) > 0) {
|
|
20254
|
+
return JOURNAL_RUN_STATE_STATUS.REJECTED;
|
|
20255
|
+
}
|
|
20256
|
+
return void 0;
|
|
20257
|
+
}
|
|
20258
|
+
function auditCoverageRejectsRun(scope2) {
|
|
20259
|
+
if (scope2.coverageRequirement !== AUDIT_COVERAGE_REQUIREMENT.REQUIRED) return false;
|
|
20260
|
+
return scope2.auditKind === AUDIT_KIND.COVERAGE_GAP || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.UNSUPPORTED || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.MISSING_SKILL || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.SKIPPED || scope2.coverageStatus === AUDIT_COVERAGE_STATUS.INCOMPLETE;
|
|
20261
|
+
}
|
|
20262
|
+
function expectedAuditTerminalStatus(events) {
|
|
20263
|
+
const hasFinding = countVerifyFindings(events) > 0;
|
|
20264
|
+
const auditScopeEvents = events.filter((event) => {
|
|
20265
|
+
if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
|
|
20266
|
+
return validateAuditScope(event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD]) !== void 0;
|
|
20267
|
+
});
|
|
20268
|
+
const hasUncoveredRequiredScope = events.some((event) => {
|
|
20269
|
+
if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
|
|
20270
|
+
const payload = event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD];
|
|
20271
|
+
const scope2 = validateAuditScope(payload);
|
|
20272
|
+
return scope2 === void 0 ? false : auditCoverageRejectsRun(scope2);
|
|
20273
|
+
});
|
|
20274
|
+
return hasFinding || auditScopeEvents.length === 0 || hasUncoveredRequiredScope ? JOURNAL_RUN_STATE_STATUS.REJECTED : JOURNAL_RUN_STATE_STATUS.APPROVED;
|
|
20275
|
+
}
|
|
20276
|
+
function validateAuditTerminal(input) {
|
|
20277
|
+
if (input.metadata !== void 0) {
|
|
20278
|
+
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.METADATA_INVALID };
|
|
20279
|
+
}
|
|
20280
|
+
if (input.terminalStatus !== expectedAuditTerminalStatus(input.events)) {
|
|
20281
|
+
return { ok: false, error: TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT };
|
|
20282
|
+
}
|
|
20283
|
+
return { ok: true, value: void 0 };
|
|
20284
|
+
}
|
|
20285
|
+
function expectedReviewMetadataTerminalStatus(metadata) {
|
|
20286
|
+
if (metadata?.state === REVIEW_TERMINAL_STATE.APPROVED) return JOURNAL_RUN_STATE_STATUS.APPROVED;
|
|
20287
|
+
if (metadata?.state === REVIEW_TERMINAL_STATE.CHANGES_REQUESTED) return JOURNAL_RUN_STATE_STATUS.REJECTED;
|
|
20288
|
+
return void 0;
|
|
20289
|
+
}
|
|
20290
|
+
function findAppendedSequence(events, idempotencyKey, eventType) {
|
|
20291
|
+
const match = events.find(
|
|
20292
|
+
(event) => event.type === eventType && isJsonRecord(event.data) && event.data[VERIFY_APPEND_EVENT_FIELD.IDEMPOTENCY_KEY] === idempotencyKey
|
|
20293
|
+
);
|
|
20294
|
+
return match?.seq;
|
|
20295
|
+
}
|
|
20296
|
+
function buildAppendEvent(args) {
|
|
20297
|
+
return {
|
|
20298
|
+
id: args.idempotencyKey,
|
|
20299
|
+
source: VERIFY_EVENT_SOURCE,
|
|
20300
|
+
type: args.eventType,
|
|
20301
|
+
time: args.at.toISOString(),
|
|
20302
|
+
attempt: VERIFY_APPEND_ATTEMPT,
|
|
20303
|
+
data: {
|
|
20304
|
+
[VERIFY_APPEND_EVENT_FIELD.IDEMPOTENCY_KEY]: args.idempotencyKey,
|
|
20305
|
+
[VERIFY_APPEND_EVENT_FIELD.PAYLOAD]: args.payload
|
|
20306
|
+
}
|
|
20307
|
+
};
|
|
20308
|
+
}
|
|
20309
|
+
var VERIFY_TERMINAL_EVENT_TYPE = `${RUNTIME_EVENT_NAMESPACE_DEFAULT}.verify.terminal`;
|
|
20310
|
+
var VERIFY_TERMINAL_EVENT_FIELD = {
|
|
20311
|
+
TERMINAL_METADATA: "terminalMetadata",
|
|
20312
|
+
TERMINAL_STATUS: "terminalStatus"
|
|
20313
|
+
};
|
|
20314
|
+
var VERIFY_TERMINAL_EVENT_ID_PREFIX = "verify-terminal-";
|
|
20315
|
+
function isVerifyTerminalStatus(value) {
|
|
20316
|
+
return isJournalRunStateStatus(value);
|
|
20317
|
+
}
|
|
20318
|
+
function buildTerminalEvent(args) {
|
|
20319
|
+
return {
|
|
20320
|
+
id: `${VERIFY_TERMINAL_EVENT_ID_PREFIX}${args.runToken}`,
|
|
20321
|
+
source: VERIFY_EVENT_SOURCE,
|
|
20322
|
+
type: VERIFY_TERMINAL_EVENT_TYPE,
|
|
20323
|
+
time: args.at.toISOString(),
|
|
20324
|
+
attempt: VERIFY_APPEND_ATTEMPT,
|
|
20325
|
+
data: {
|
|
20326
|
+
[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS]: args.terminalStatus,
|
|
20327
|
+
...args.terminalMetadata === void 0 ? {} : { [VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_METADATA]: args.terminalMetadata }
|
|
20328
|
+
}
|
|
20329
|
+
};
|
|
20330
|
+
}
|
|
20331
|
+
var VERIFY_NO_EVENTS_SEQUENCE = 0;
|
|
20332
|
+
function findTerminalEvent(events) {
|
|
20333
|
+
return events.find((event) => event.type === VERIFY_TERMINAL_EVENT_TYPE);
|
|
20334
|
+
}
|
|
20335
|
+
function terminalStatusOf(event) {
|
|
20336
|
+
if (event === void 0 || !isJsonRecord(event.data)) return void 0;
|
|
20337
|
+
const status = event.data[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_STATUS];
|
|
20338
|
+
return typeof status === "string" ? status : void 0;
|
|
20339
|
+
}
|
|
20340
|
+
function terminalMetadataOf(event) {
|
|
20341
|
+
if (event === void 0 || !isJsonRecord(event.data)) return void 0;
|
|
20342
|
+
return event.data[VERIFY_TERMINAL_EVENT_FIELD.TERMINAL_METADATA];
|
|
20343
|
+
}
|
|
20344
|
+
function countVerifyFindings(events) {
|
|
20345
|
+
return events.filter(
|
|
20346
|
+
(event) => event.type === VERIFY_APPEND_EVENT_TYPE.FINDING
|
|
20347
|
+
).length;
|
|
20348
|
+
}
|
|
20349
|
+
function countReviewScopeFindingUnits(events) {
|
|
20350
|
+
return events.filter((event) => {
|
|
20351
|
+
if (event.type !== VERIFY_APPEND_EVENT_TYPE.SCOPE || !isJsonRecord(event.data)) return false;
|
|
20352
|
+
const payload = event.data[VERIFY_APPEND_EVENT_FIELD.PAYLOAD];
|
|
20353
|
+
const scope2 = validateReviewScope(payload);
|
|
20354
|
+
return scope2?.coverageState === REVIEW_SCOPE_COVERAGE_STATE.FINDING;
|
|
20355
|
+
}).length;
|
|
20356
|
+
}
|
|
20357
|
+
function lastSequenceOf(events) {
|
|
20358
|
+
return events.reduce(
|
|
20359
|
+
(max, event) => event.seq > max ? event.seq : max,
|
|
20360
|
+
VERIFY_NO_EVENTS_SEQUENCE
|
|
20361
|
+
);
|
|
20362
|
+
}
|
|
20363
|
+
function projectVerifyRun(events) {
|
|
20364
|
+
const terminal = findTerminalEvent(events);
|
|
20365
|
+
const terminalStatus = terminalStatusOf(terminal);
|
|
20366
|
+
const terminalMetadata = terminalMetadataOf(terminal);
|
|
20367
|
+
const sealed = terminal !== void 0;
|
|
20368
|
+
return {
|
|
20369
|
+
sealed,
|
|
20370
|
+
...terminalStatus === void 0 ? {} : { terminalStatus },
|
|
20371
|
+
...terminalMetadata === void 0 ? {} : { terminalMetadata },
|
|
20372
|
+
findingCount: countVerifyFindings(events),
|
|
20373
|
+
lastSequence: lastSequenceOf(events),
|
|
20374
|
+
nextActions: sealed ? [] : UNSEALED_NEXT_ACTIONS
|
|
20375
|
+
};
|
|
20376
|
+
}
|
|
20377
|
+
|
|
20378
|
+
// src/commands/verify/cli.ts
|
|
20379
|
+
var VERIFY_CLI_EXIT_CODE = {
|
|
20380
|
+
OK: 0,
|
|
20381
|
+
ERROR: 1
|
|
20382
|
+
};
|
|
20383
|
+
var VERIFY_CLI_ENV = {
|
|
20384
|
+
BRANCH: SPX_VERIFY_ENV.BRANCH
|
|
20385
|
+
};
|
|
20386
|
+
var VERIFY_CLI_ERROR = {
|
|
20387
|
+
INPUT_REQUIRED: "spx verification run start requires --input <input-source>",
|
|
20388
|
+
RUN_REQUIRED: "spx verification run existing-run commands require an explicit --run <run-token>",
|
|
20389
|
+
RUN_NOT_FOUND: "spx verification run could not locate the requested run",
|
|
20390
|
+
RUN_SELECTOR_MISMATCH: "spx verification run selector does not match the recorded run",
|
|
20391
|
+
CHANGED_SCOPE_FAILED: "spx verification run could not derive the changeset changed-file scope",
|
|
20392
|
+
INPUT_PERSIST_FAILED: "spx verification run could not persist the recorded run input",
|
|
20393
|
+
INPUT_READ_FAILED: "spx verification run could not read the recorded run input",
|
|
20394
|
+
PAYLOAD_REQUIRED: "spx verification run evidence-add commands require --payload <payload-source>",
|
|
20395
|
+
IDEMPOTENCY_KEY_REQUIRED: "spx verification run evidence-add commands require --idempotency-key <key>",
|
|
20396
|
+
PAYLOAD_READ_FAILED: "spx verification run could not read the evidence payload",
|
|
20397
|
+
PAYLOAD_INVALID: "spx verification run evidence payload is not valid JSON",
|
|
20398
|
+
RUN_FINISHED: "spx verification run cannot add evidence to a finished run",
|
|
20399
|
+
SCOPE_INVALID: "spx verification run scope add payload failed verification-type validation",
|
|
20400
|
+
FINDING_INVALID: "spx verification run finding add payload failed verification-type validation",
|
|
20401
|
+
UNSUPPORTED_VERIFICATION_TYPE: "spx verification run verification type is not registered",
|
|
20402
|
+
APPEND_FAILED: "spx verification run could not append the evidence event",
|
|
20403
|
+
TERMINAL_STATUS_REQUIRED: "spx verification run finish requires --terminal-status <status>",
|
|
20404
|
+
TERMINAL_STATUS_INVALID: "spx verification run finish requires a terminal status in the journal terminal-status vocabulary",
|
|
20405
|
+
TERMINAL_METADATA_INVALID: "spx verification run terminal metadata failed verification-type validation",
|
|
20406
|
+
TERMINAL_STATUS_CONFLICT: "spx verification run terminal status conflicts with verification-type terminal metadata: status-conflict",
|
|
20407
|
+
FINISH_FAILED: "spx verification run could not record terminal completion",
|
|
20408
|
+
SEAL_FAILED: "spx verification run could not seal the run journal",
|
|
20409
|
+
STATUS_FAILED: "spx verification run could not read the run status",
|
|
20410
|
+
RENDER_FAILED: "spx verification run could not render the run projection"
|
|
20411
|
+
};
|
|
20412
|
+
var VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD = {
|
|
20413
|
+
RUN: "run=",
|
|
20414
|
+
VERIFICATION_TYPE: "verification-type=",
|
|
20415
|
+
SCOPE_TYPE: "scope-type=",
|
|
20416
|
+
SCOPE: "scope=",
|
|
20417
|
+
BACKEND: "backend=",
|
|
20418
|
+
NAMESPACE: "namespace=",
|
|
20419
|
+
TARGET: "target="
|
|
20420
|
+
};
|
|
20421
|
+
var VERIFY_START_ROLLBACK_ARTIFACT = {
|
|
20422
|
+
CONTEXT_FILE: "verification context file",
|
|
20423
|
+
RUN_FILE: "journal run file"
|
|
20424
|
+
};
|
|
20425
|
+
function okResult3(output) {
|
|
20426
|
+
return { exitCode: VERIFY_CLI_EXIT_CODE.OK, output };
|
|
19729
20427
|
}
|
|
19730
20428
|
function errorResult3(error) {
|
|
19731
20429
|
return { exitCode: VERIFY_CLI_EXIT_CODE.ERROR, output: error };
|
|
@@ -19781,73 +20479,131 @@ async function persistInputRecord(runScope2, record6, deps) {
|
|
|
19781
20479
|
const fs8 = deps.fs ?? defaultFileSystem;
|
|
19782
20480
|
try {
|
|
19783
20481
|
await fs8.mkdir(dirname12(path7.value), { recursive: true });
|
|
19784
|
-
await
|
|
20482
|
+
await writeFileAtomic(path7.value, JSON.stringify(record6), { fs: fs8, randomBytes: randomBytes2 });
|
|
19785
20483
|
return { ok: true, value: void 0 };
|
|
19786
20484
|
} catch (error) {
|
|
19787
20485
|
return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_PERSIST_FAILED}: ${toMessage2(error)}` };
|
|
19788
20486
|
}
|
|
19789
20487
|
}
|
|
20488
|
+
async function readStartInputContent(source, deps) {
|
|
20489
|
+
try {
|
|
20490
|
+
return { ok: true, value: await deps.readInputSource(source) };
|
|
20491
|
+
} catch (error) {
|
|
20492
|
+
return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
|
|
20493
|
+
}
|
|
20494
|
+
}
|
|
20495
|
+
async function removeStartedRunArtifact(path7, label, deps) {
|
|
20496
|
+
const fs8 = deps.fs ?? defaultFileSystem;
|
|
20497
|
+
try {
|
|
20498
|
+
await fs8.rm(path7, { force: true });
|
|
20499
|
+
return { ok: true, value: void 0 };
|
|
20500
|
+
} catch (error) {
|
|
20501
|
+
return {
|
|
20502
|
+
ok: false,
|
|
20503
|
+
error: `${VERIFY_CLI_ERROR.INPUT_PERSIST_FAILED}: rollback failed for ${label}: ${toMessage2(error)}`
|
|
20504
|
+
};
|
|
20505
|
+
}
|
|
20506
|
+
}
|
|
20507
|
+
async function removeStartedRunArtifacts(artifacts, deps) {
|
|
20508
|
+
const rollbackErrors = [];
|
|
20509
|
+
if (artifacts.contextPath !== void 0) {
|
|
20510
|
+
const contextRollback = await removeStartedRunArtifact(
|
|
20511
|
+
artifacts.contextPath,
|
|
20512
|
+
VERIFY_START_ROLLBACK_ARTIFACT.CONTEXT_FILE,
|
|
20513
|
+
deps
|
|
20514
|
+
);
|
|
20515
|
+
if (!contextRollback.ok) rollbackErrors.push(contextRollback.error);
|
|
20516
|
+
}
|
|
20517
|
+
if (artifacts.runFile !== void 0) {
|
|
20518
|
+
const runRollback = await removeStartedRunArtifact(
|
|
20519
|
+
artifacts.runFile,
|
|
20520
|
+
VERIFY_START_ROLLBACK_ARTIFACT.RUN_FILE,
|
|
20521
|
+
deps
|
|
20522
|
+
);
|
|
20523
|
+
if (!runRollback.ok) rollbackErrors.push(runRollback.error);
|
|
20524
|
+
}
|
|
20525
|
+
if (rollbackErrors.length > 0) return { ok: false, error: rollbackErrors.join("; ") };
|
|
20526
|
+
return { ok: true, value: void 0 };
|
|
20527
|
+
}
|
|
20528
|
+
function isStoredRecordedInput(value) {
|
|
20529
|
+
if (typeof value !== "object" || value === null) return false;
|
|
20530
|
+
const record6 = value;
|
|
20531
|
+
return typeof record6.scopeIdentity === "string" && typeof record6.scopeType === "string" && typeof record6.source === "string" && typeof record6.digest === "string" && typeof record6.content === "string";
|
|
20532
|
+
}
|
|
20533
|
+
function parseRecordedInput(content) {
|
|
20534
|
+
try {
|
|
20535
|
+
const parsed = JSON.parse(content);
|
|
20536
|
+
if (!isStoredRecordedInput(parsed)) {
|
|
20537
|
+
return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: recorded input is missing required fields` };
|
|
20538
|
+
}
|
|
20539
|
+
return { ok: true, value: parsed };
|
|
20540
|
+
} catch (error) {
|
|
20541
|
+
return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
|
|
20542
|
+
}
|
|
20543
|
+
}
|
|
19790
20544
|
async function readInputRecordAt(path7, deps) {
|
|
19791
20545
|
const fs8 = deps.fs ?? defaultFileSystem;
|
|
20546
|
+
let content;
|
|
19792
20547
|
try {
|
|
19793
|
-
|
|
19794
|
-
return { ok: true, value: JSON.parse(content) };
|
|
20548
|
+
content = await fs8.readFile(path7, STATE_STORE_TEXT_ENCODING);
|
|
19795
20549
|
} catch (error) {
|
|
19796
20550
|
if (hasErrorCode(error, ERROR_CODE_NOT_FOUND)) return { ok: true, value: void 0 };
|
|
19797
20551
|
return { ok: false, error: `${VERIFY_CLI_ERROR.INPUT_READ_FAILED}: ${toMessage2(error)}` };
|
|
19798
20552
|
}
|
|
20553
|
+
const parsed = parseRecordedInput(content);
|
|
20554
|
+
if (!parsed.ok) return parsed;
|
|
20555
|
+
return { ok: true, value: parsed.value };
|
|
19799
20556
|
}
|
|
19800
|
-
function
|
|
20557
|
+
function verifyRunLocatorDiagnostic(summary, context) {
|
|
19801
20558
|
return [
|
|
19802
|
-
|
|
19803
|
-
|
|
19804
|
-
|
|
19805
|
-
|
|
19806
|
-
|
|
19807
|
-
|
|
19808
|
-
|
|
19809
|
-
|
|
20559
|
+
summary,
|
|
20560
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.RUN}${context.runToken}`,
|
|
20561
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.VERIFICATION_TYPE}${context.verificationType}`,
|
|
20562
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.SCOPE_TYPE}${context.scopeType}`,
|
|
20563
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.SCOPE}${context.scopeIdentity}`,
|
|
20564
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.BACKEND}${context.backendIdentity}`,
|
|
20565
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.NAMESPACE}${context.storageNamespace}`,
|
|
20566
|
+
`${VERIFY_RUN_NOT_FOUND_DIAGNOSTIC_FIELD.TARGET}${context.searchedTarget}`
|
|
19810
20567
|
].join(" ");
|
|
19811
20568
|
}
|
|
19812
|
-
|
|
19813
|
-
|
|
19814
|
-
|
|
19815
|
-
|
|
19816
|
-
|
|
19817
|
-
const resolved = await resolveVerifyScope(deps);
|
|
19818
|
-
if (!resolved.ok) return errorResult3(resolved.error);
|
|
19819
|
-
const inputContent = await deps.readInputSource(options.input);
|
|
19820
|
-
const inputDigest = digestRunInput(options.input, inputContent);
|
|
19821
|
-
if (!inputDigest.ok) return errorResult3(inputDigest.error);
|
|
19822
|
-
const context = await verificationContextCreateCommand(
|
|
19823
|
-
{
|
|
19824
|
-
subject: VERIFICATION_CONTEXT_SUBJECT_KIND.CHANGESET,
|
|
19825
|
-
base: scope2.value.base,
|
|
19826
|
-
head: scope2.value.head,
|
|
19827
|
-
predicate: options.verificationType,
|
|
19828
|
-
workflow: options.verificationType
|
|
19829
|
-
},
|
|
19830
|
-
forwardDeps(deps)
|
|
19831
|
-
);
|
|
19832
|
-
if (context.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(context.output);
|
|
19833
|
-
const contextDigest = JSON.parse(context.output).digest;
|
|
20569
|
+
function verifyRunNotFoundDiagnostic(context) {
|
|
20570
|
+
return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_NOT_FOUND, context);
|
|
20571
|
+
}
|
|
20572
|
+
async function completeVerifyStartCommand(args) {
|
|
20573
|
+
const { options, deps } = args;
|
|
19834
20574
|
const opened = await journalOpenCommand(
|
|
19835
|
-
{ type: options.verificationType, branchSlug:
|
|
20575
|
+
{ type: options.verificationType, branchSlug: args.branchSlug },
|
|
19836
20576
|
forwardDeps(deps)
|
|
19837
20577
|
);
|
|
19838
|
-
if (opened.exitCode !== VERIFY_CLI_EXIT_CODE.OK)
|
|
20578
|
+
if (opened.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
|
|
20579
|
+
const rollback = await removeStartedRunArtifacts(
|
|
20580
|
+
{ ...args.contextCreated ? { contextPath: args.contextPath } : {} },
|
|
20581
|
+
deps
|
|
20582
|
+
);
|
|
20583
|
+
return errorResult3(rollback.ok ? opened.output : `${opened.output}; ${rollback.error}`);
|
|
20584
|
+
}
|
|
19839
20585
|
const { runToken, runFile } = JSON.parse(opened.output);
|
|
19840
20586
|
const runScope2 = {
|
|
19841
|
-
productDir:
|
|
19842
|
-
branchSlug:
|
|
20587
|
+
productDir: args.productDir,
|
|
20588
|
+
branchSlug: args.branchSlug,
|
|
19843
20589
|
type: options.verificationType,
|
|
19844
20590
|
runToken
|
|
19845
20591
|
};
|
|
19846
|
-
const recorded = {
|
|
20592
|
+
const recorded = {
|
|
20593
|
+
scopeIdentity: options.scope,
|
|
20594
|
+
scopeType: options.scopeType,
|
|
20595
|
+
source: options.input,
|
|
20596
|
+
digest: args.inputDigest,
|
|
20597
|
+
content: args.inputContent
|
|
20598
|
+
};
|
|
19847
20599
|
const persisted = await persistInputRecord(runScope2, recorded, deps);
|
|
19848
|
-
if (!persisted.ok)
|
|
19849
|
-
|
|
19850
|
-
|
|
20600
|
+
if (!persisted.ok) {
|
|
20601
|
+
const rollback = await removeStartedRunArtifacts(
|
|
20602
|
+
{ ...args.contextCreated ? { contextPath: args.contextPath } : {}, runFile },
|
|
20603
|
+
deps
|
|
20604
|
+
);
|
|
20605
|
+
return errorResult3(rollback.ok ? persisted.error : `${persisted.error}; ${rollback.error}`);
|
|
20606
|
+
}
|
|
19851
20607
|
const namespace = verifyRunsDir(runScope2);
|
|
19852
20608
|
if (!namespace.ok) return errorResult3(namespace.error);
|
|
19853
20609
|
const locator = buildRunLocator({
|
|
@@ -19855,52 +20611,69 @@ async function verifyStartCommand(options, deps) {
|
|
|
19855
20611
|
verificationType: options.verificationType,
|
|
19856
20612
|
scopeType: options.scopeType,
|
|
19857
20613
|
scopeIdentity: options.scope,
|
|
19858
|
-
backendIdentity:
|
|
20614
|
+
backendIdentity: args.backendIdentity,
|
|
19859
20615
|
storageNamespace: namespace.value,
|
|
19860
20616
|
runTarget: runFile
|
|
19861
20617
|
});
|
|
19862
20618
|
const report2 = {
|
|
19863
20619
|
runToken,
|
|
19864
|
-
contextDigest,
|
|
19865
|
-
changedScope: changedScope
|
|
19866
|
-
input: { source: options.input, digest: inputDigest
|
|
20620
|
+
contextDigest: args.contextDigest,
|
|
20621
|
+
changedScope: args.changedScope,
|
|
20622
|
+
input: { source: options.input, digest: args.inputDigest },
|
|
19867
20623
|
locator
|
|
19868
20624
|
};
|
|
19869
20625
|
return okResult3(JSON.stringify(report2));
|
|
19870
20626
|
}
|
|
19871
|
-
async function
|
|
19872
|
-
if (options.
|
|
20627
|
+
async function verifyStartCommand(options, deps) {
|
|
20628
|
+
if (!isVerifyVerificationType(options.verificationType)) {
|
|
20629
|
+
return errorResult3(VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE);
|
|
20630
|
+
}
|
|
20631
|
+
if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) return errorResult3(VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE);
|
|
20632
|
+
if (options.input.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.INPUT_REQUIRED);
|
|
20633
|
+
const scope2 = parseChangesetScope(options.scope);
|
|
20634
|
+
if (!scope2.ok) return errorResult3(scope2.error);
|
|
19873
20635
|
const resolved = await resolveVerifyScope(deps);
|
|
19874
20636
|
if (!resolved.ok) return errorResult3(resolved.error);
|
|
19875
|
-
const
|
|
20637
|
+
const inputContent = await readStartInputContent(options.input, deps);
|
|
20638
|
+
if (!inputContent.ok) return errorResult3(inputContent.error);
|
|
20639
|
+
const inputDigest = digestRunInput(options.input, inputContent.value);
|
|
20640
|
+
if (!inputDigest.ok) return errorResult3(inputDigest.error);
|
|
20641
|
+
const changedScope = await resolveChangedScope(scope2.value, deps);
|
|
20642
|
+
if (!changedScope.ok) return errorResult3(changedScope.error);
|
|
20643
|
+
const context = await verificationContextCreateCommand(
|
|
20644
|
+
{
|
|
20645
|
+
subject: VERIFICATION_CONTEXT_SUBJECT_KIND.CHANGESET,
|
|
20646
|
+
base: scope2.value.base,
|
|
20647
|
+
head: scope2.value.head,
|
|
20648
|
+
predicate: options.verificationType,
|
|
20649
|
+
workflow: options.verificationType
|
|
20650
|
+
},
|
|
20651
|
+
forwardDeps(deps)
|
|
20652
|
+
);
|
|
20653
|
+
if (context.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return errorResult3(context.output);
|
|
20654
|
+
const { digest: contextDigest, contextPath, created: contextCreated } = JSON.parse(context.output);
|
|
20655
|
+
return completeVerifyStartCommand({
|
|
20656
|
+
options,
|
|
20657
|
+
deps,
|
|
19876
20658
|
productDir: resolved.value.productDir,
|
|
19877
20659
|
branchSlug: resolved.value.branchSlug,
|
|
19878
|
-
|
|
19879
|
-
|
|
19880
|
-
|
|
19881
|
-
|
|
19882
|
-
|
|
19883
|
-
|
|
19884
|
-
|
|
19885
|
-
|
|
19886
|
-
|
|
19887
|
-
|
|
19888
|
-
|
|
19889
|
-
|
|
19890
|
-
|
|
19891
|
-
verificationType: options.verificationType,
|
|
19892
|
-
scopeType: options.scopeType,
|
|
19893
|
-
scopeIdentity: options.scope,
|
|
19894
|
-
backendIdentity: resolved.value.backendIdentity,
|
|
19895
|
-
storageNamespace: namespace.value,
|
|
19896
|
-
searchedTarget: path7.value
|
|
19897
|
-
})
|
|
19898
|
-
);
|
|
19899
|
-
}
|
|
20660
|
+
backendIdentity: resolved.value.backendIdentity,
|
|
20661
|
+
changedScope: changedScope.value,
|
|
20662
|
+
inputDigest: inputDigest.value,
|
|
20663
|
+
inputContent: inputContent.value,
|
|
20664
|
+
contextDigest,
|
|
20665
|
+
contextPath,
|
|
20666
|
+
contextCreated
|
|
20667
|
+
});
|
|
20668
|
+
}
|
|
20669
|
+
async function verifyInputCommand(options, deps) {
|
|
20670
|
+
const run = await resolveExistingRun(options, deps);
|
|
20671
|
+
if (!run.ok) return errorResult3(run.error);
|
|
20672
|
+
const record6 = run.value.recordedInput;
|
|
19900
20673
|
const report2 = {
|
|
19901
|
-
source: record6.
|
|
19902
|
-
digest: record6.
|
|
19903
|
-
content: record6.
|
|
20674
|
+
source: record6.source,
|
|
20675
|
+
digest: record6.digest,
|
|
20676
|
+
content: record6.content
|
|
19904
20677
|
};
|
|
19905
20678
|
return okResult3(JSON.stringify(report2));
|
|
19906
20679
|
}
|
|
@@ -19909,12 +20682,36 @@ async function readRunJournalEvents(scope2, deps) {
|
|
|
19909
20682
|
if (read.exitCode !== VERIFY_CLI_EXIT_CODE.OK) return { ok: false, error: read.output };
|
|
19910
20683
|
return { ok: true, value: JSON.parse(read.output) };
|
|
19911
20684
|
}
|
|
20685
|
+
async function readAppendExistingEvents(options, deps, journalScope, backendIdentity, namespace) {
|
|
20686
|
+
const existingEvents = await readRunJournalEvents(journalScope, deps);
|
|
20687
|
+
if (!existingEvents.ok) {
|
|
20688
|
+
if (existingEvents.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
|
|
20689
|
+
return {
|
|
20690
|
+
ok: false,
|
|
20691
|
+
error: appendRunNotFoundDiagnostic(options, backendIdentity, namespace)
|
|
20692
|
+
};
|
|
20693
|
+
}
|
|
20694
|
+
return { ok: false, error: `${VERIFY_CLI_ERROR.APPEND_FAILED}: ${existingEvents.error}` };
|
|
20695
|
+
}
|
|
20696
|
+
if (findTerminalEvent(existingEvents.value) !== void 0) {
|
|
20697
|
+
return { ok: false, error: VERIFY_CLI_ERROR.RUN_FINISHED };
|
|
20698
|
+
}
|
|
20699
|
+
return existingEvents;
|
|
20700
|
+
}
|
|
19912
20701
|
async function prepareAppend(options, deps) {
|
|
19913
20702
|
if (options.run.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.RUN_REQUIRED };
|
|
20703
|
+
if (!isVerifyVerificationType(options.verificationType)) {
|
|
20704
|
+
return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
|
|
20705
|
+
}
|
|
19914
20706
|
if (options.payload.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.PAYLOAD_REQUIRED };
|
|
19915
20707
|
if (options.idempotencyKey.trim().length === 0) {
|
|
19916
20708
|
return { ok: false, error: VERIFY_CLI_ERROR.IDEMPOTENCY_KEY_REQUIRED };
|
|
19917
20709
|
}
|
|
20710
|
+
if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) {
|
|
20711
|
+
return { ok: false, error: VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE };
|
|
20712
|
+
}
|
|
20713
|
+
const scope2 = parseChangesetScope(options.scope);
|
|
20714
|
+
if (!scope2.ok) return scope2;
|
|
19918
20715
|
const readPayload = deps.readPayloadSource;
|
|
19919
20716
|
const binding = deps.journalBinding;
|
|
19920
20717
|
if (readPayload === void 0 || binding === void 0) return { ok: false, error: VERIFY_CLI_ERROR.APPEND_FAILED };
|
|
@@ -19928,25 +20725,53 @@ async function prepareAppend(options, deps) {
|
|
|
19928
20725
|
};
|
|
19929
20726
|
const namespace = verifyRunsDir(runScope2);
|
|
19930
20727
|
if (!namespace.ok) return namespace;
|
|
20728
|
+
const journalScope = {
|
|
20729
|
+
type: options.verificationType,
|
|
20730
|
+
runToken: options.run,
|
|
20731
|
+
branchSlug: resolved.value.branchSlug
|
|
20732
|
+
};
|
|
20733
|
+
const existingEvents = await readAppendExistingEvents(
|
|
20734
|
+
options,
|
|
20735
|
+
deps,
|
|
20736
|
+
journalScope,
|
|
20737
|
+
resolved.value.backendIdentity,
|
|
20738
|
+
namespace.value
|
|
20739
|
+
);
|
|
20740
|
+
if (!existingEvents.ok) return existingEvents;
|
|
19931
20741
|
const inputPath = verifyInputRecordPath(runScope2);
|
|
19932
20742
|
if (!inputPath.ok) return inputPath;
|
|
19933
20743
|
const inputRecord = await readInputRecordAt(inputPath.value, deps);
|
|
19934
20744
|
if (!inputRecord.ok) return inputRecord;
|
|
19935
20745
|
if (inputRecord.value === void 0) {
|
|
19936
|
-
return {
|
|
20746
|
+
return {
|
|
20747
|
+
ok: false,
|
|
20748
|
+
error: appendRunNotFoundDiagnostic(options, resolved.value.backendIdentity, namespace.value, inputPath.value)
|
|
20749
|
+
};
|
|
20750
|
+
}
|
|
20751
|
+
if (!recordedSelectorMatches(inputRecord.value, options)) {
|
|
20752
|
+
return {
|
|
20753
|
+
ok: false,
|
|
20754
|
+
error: appendRunSelectorMismatchDiagnostic(
|
|
20755
|
+
options,
|
|
20756
|
+
resolved.value.backendIdentity,
|
|
20757
|
+
namespace.value,
|
|
20758
|
+
inputPath.value
|
|
20759
|
+
)
|
|
20760
|
+
};
|
|
19937
20761
|
}
|
|
19938
20762
|
return {
|
|
19939
20763
|
ok: true,
|
|
19940
20764
|
value: {
|
|
19941
20765
|
readPayload,
|
|
19942
20766
|
binding,
|
|
19943
|
-
journalScope
|
|
20767
|
+
journalScope,
|
|
19944
20768
|
namespace: namespace.value,
|
|
19945
|
-
backendIdentity: resolved.value.backendIdentity
|
|
20769
|
+
backendIdentity: resolved.value.backendIdentity,
|
|
20770
|
+
existingEvents: existingEvents.value
|
|
19946
20771
|
}
|
|
19947
20772
|
};
|
|
19948
20773
|
}
|
|
19949
|
-
function appendRunNotFoundDiagnostic(options, backendIdentity, namespace) {
|
|
20774
|
+
function appendRunNotFoundDiagnostic(options, backendIdentity, namespace, searchedTarget = namespace) {
|
|
19950
20775
|
return verifyRunNotFoundDiagnostic({
|
|
19951
20776
|
runToken: options.run,
|
|
19952
20777
|
verificationType: options.verificationType,
|
|
@@ -19954,15 +20779,32 @@ function appendRunNotFoundDiagnostic(options, backendIdentity, namespace) {
|
|
|
19954
20779
|
scopeIdentity: options.scope,
|
|
19955
20780
|
backendIdentity,
|
|
19956
20781
|
storageNamespace: namespace,
|
|
19957
|
-
searchedTarget
|
|
20782
|
+
searchedTarget
|
|
19958
20783
|
});
|
|
19959
20784
|
}
|
|
19960
|
-
function
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
20785
|
+
function appendRunSelectorMismatchDiagnostic(options, backendIdentity, namespace, searchedTarget) {
|
|
20786
|
+
return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_SELECTOR_MISMATCH, {
|
|
20787
|
+
runToken: options.run,
|
|
20788
|
+
verificationType: options.verificationType,
|
|
20789
|
+
scopeType: options.scopeType,
|
|
20790
|
+
scopeIdentity: options.scope,
|
|
20791
|
+
backendIdentity,
|
|
20792
|
+
storageNamespace: namespace,
|
|
20793
|
+
searchedTarget
|
|
20794
|
+
});
|
|
20795
|
+
}
|
|
20796
|
+
function validateAppendEvidence(verb, verificationType, payload, events) {
|
|
20797
|
+
const evidenceKind = verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_EVIDENCE_KIND.FINDING : VERIFY_EVIDENCE_KIND.SCOPE;
|
|
20798
|
+
const validator = evidenceValidatorFor(verificationType, evidenceKind);
|
|
20799
|
+
if (validator === void 0) return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
|
|
20800
|
+
const validated = validator({ payload, events });
|
|
20801
|
+
if (validated === void 0) {
|
|
20802
|
+
return {
|
|
20803
|
+
ok: false,
|
|
20804
|
+
error: verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_CLI_ERROR.FINDING_INVALID : VERIFY_CLI_ERROR.SCOPE_INVALID
|
|
20805
|
+
};
|
|
20806
|
+
}
|
|
20807
|
+
return { ok: true, value: JSON.parse(JSON.stringify(validated)) };
|
|
19966
20808
|
}
|
|
19967
20809
|
function appendEventType(verb) {
|
|
19968
20810
|
return verb === VERIFY_VERB.APPEND_FINDING ? VERIFY_APPEND_EVENT_TYPE.FINDING : VERIFY_APPEND_EVENT_TYPE.SCOPE;
|
|
@@ -19970,16 +20812,9 @@ function appendEventType(verb) {
|
|
|
19970
20812
|
async function verifyAppend(options, deps, verb) {
|
|
19971
20813
|
const prepared = await prepareAppend(options, deps);
|
|
19972
20814
|
if (!prepared.ok) return errorResult3(prepared.error);
|
|
19973
|
-
const { readPayload, binding, journalScope,
|
|
20815
|
+
const { readPayload, binding, journalScope, existingEvents } = prepared.value;
|
|
19974
20816
|
const eventType = appendEventType(verb);
|
|
19975
|
-
const
|
|
19976
|
-
if (!before.ok) {
|
|
19977
|
-
if (before.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
|
|
19978
|
-
return errorResult3(appendRunNotFoundDiagnostic(options, backendIdentity, namespace));
|
|
19979
|
-
}
|
|
19980
|
-
return errorResult3(`${VERIFY_CLI_ERROR.APPEND_FAILED}: ${before.error}`);
|
|
19981
|
-
}
|
|
19982
|
-
const existing = findAppendedSequence(before.value, options.idempotencyKey, eventType);
|
|
20817
|
+
const existing = findAppendedSequence(existingEvents, options.idempotencyKey, eventType);
|
|
19983
20818
|
if (existing !== void 0) {
|
|
19984
20819
|
const report3 = { sequence: existing, idempotent: true };
|
|
19985
20820
|
return okResult3(JSON.stringify(report3));
|
|
@@ -19992,12 +20827,12 @@ async function verifyAppend(options, deps, verb) {
|
|
|
19992
20827
|
}
|
|
19993
20828
|
const parsed = parseAppendPayload(rawPayload);
|
|
19994
20829
|
if (parsed === void 0) return errorResult3(VERIFY_CLI_ERROR.PAYLOAD_INVALID);
|
|
19995
|
-
const
|
|
19996
|
-
if (
|
|
20830
|
+
const evidence = validateAppendEvidence(verb, options.verificationType, parsed, existingEvents);
|
|
20831
|
+
if (!evidence.ok) return errorResult3(evidence.error);
|
|
19997
20832
|
const event = buildAppendEvent({
|
|
19998
20833
|
eventType,
|
|
19999
20834
|
idempotencyKey: options.idempotencyKey,
|
|
20000
|
-
payload:
|
|
20835
|
+
payload: evidence.value,
|
|
20001
20836
|
at: deps.now?.() ?? /* @__PURE__ */ new Date()
|
|
20002
20837
|
});
|
|
20003
20838
|
const appended = await journalAppendCommand(journalScope, event, binding, forwardDeps(deps));
|
|
@@ -20017,24 +20852,309 @@ async function verifyAppendScopeCommand(options, deps) {
|
|
|
20017
20852
|
async function verifyAppendFindingCommand(options, deps) {
|
|
20018
20853
|
return verifyAppend(options, deps, VERIFY_VERB.APPEND_FINDING);
|
|
20019
20854
|
}
|
|
20855
|
+
function existingRunNotFound(run, options) {
|
|
20856
|
+
return verifyRunNotFoundDiagnostic({
|
|
20857
|
+
runToken: run.runToken,
|
|
20858
|
+
verificationType: options.verificationType,
|
|
20859
|
+
scopeType: options.scopeType,
|
|
20860
|
+
scopeIdentity: options.scope,
|
|
20861
|
+
backendIdentity: run.backendIdentity,
|
|
20862
|
+
storageNamespace: run.namespace,
|
|
20863
|
+
searchedTarget: run.inputRecordPath
|
|
20864
|
+
});
|
|
20865
|
+
}
|
|
20866
|
+
function existingRunSelectorMismatch(run, options) {
|
|
20867
|
+
return verifyRunLocatorDiagnostic(VERIFY_CLI_ERROR.RUN_SELECTOR_MISMATCH, {
|
|
20868
|
+
runToken: run.runToken,
|
|
20869
|
+
verificationType: options.verificationType,
|
|
20870
|
+
scopeType: options.scopeType,
|
|
20871
|
+
scopeIdentity: options.scope,
|
|
20872
|
+
backendIdentity: run.backendIdentity,
|
|
20873
|
+
storageNamespace: run.namespace,
|
|
20874
|
+
searchedTarget: run.inputRecordPath
|
|
20875
|
+
});
|
|
20876
|
+
}
|
|
20877
|
+
function recordedSelectorMatches(record6, options) {
|
|
20878
|
+
return record6.scopeType === options.scopeType && record6.scopeIdentity === options.scope;
|
|
20879
|
+
}
|
|
20880
|
+
async function readExistingRecordedInput(run, deps) {
|
|
20881
|
+
return readInputRecordAt(run.inputRecordPath, deps);
|
|
20882
|
+
}
|
|
20883
|
+
async function resolveExistingRunAddress(options, deps) {
|
|
20884
|
+
if (!isVerifyVerificationType(options.verificationType)) {
|
|
20885
|
+
return { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
|
|
20886
|
+
}
|
|
20887
|
+
if (options.scopeType !== VERIFY_SCOPE_TYPE.CHANGESET) {
|
|
20888
|
+
return { ok: false, error: VERIFY_SCOPE_ERROR.UNSUPPORTED_SCOPE_TYPE };
|
|
20889
|
+
}
|
|
20890
|
+
const scope2 = parseChangesetScope(options.scope);
|
|
20891
|
+
if (!scope2.ok) return scope2;
|
|
20892
|
+
if (options.run.trim().length === 0) return { ok: false, error: VERIFY_CLI_ERROR.RUN_REQUIRED };
|
|
20893
|
+
const resolved = await resolveVerifyScope(deps);
|
|
20894
|
+
if (!resolved.ok) return resolved;
|
|
20895
|
+
const runScope2 = {
|
|
20896
|
+
productDir: resolved.value.productDir,
|
|
20897
|
+
branchSlug: resolved.value.branchSlug,
|
|
20898
|
+
type: options.verificationType,
|
|
20899
|
+
runToken: options.run
|
|
20900
|
+
};
|
|
20901
|
+
const namespace = verifyRunsDir(runScope2);
|
|
20902
|
+
if (!namespace.ok) return namespace;
|
|
20903
|
+
const inputPath = verifyInputRecordPath(runScope2);
|
|
20904
|
+
if (!inputPath.ok) return inputPath;
|
|
20905
|
+
return {
|
|
20906
|
+
ok: true,
|
|
20907
|
+
value: {
|
|
20908
|
+
productDir: resolved.value.productDir,
|
|
20909
|
+
runToken: options.run,
|
|
20910
|
+
journalScope: { type: options.verificationType, runToken: options.run, branchSlug: resolved.value.branchSlug },
|
|
20911
|
+
namespace: namespace.value,
|
|
20912
|
+
backendIdentity: resolved.value.backendIdentity,
|
|
20913
|
+
inputRecordPath: inputPath.value
|
|
20914
|
+
}
|
|
20915
|
+
};
|
|
20916
|
+
}
|
|
20917
|
+
async function resolveExistingRun(options, deps) {
|
|
20918
|
+
const address = await resolveExistingRunAddress(options, deps);
|
|
20919
|
+
if (!address.ok) return address;
|
|
20920
|
+
const inputRecord = await readExistingRecordedInput(address.value, deps);
|
|
20921
|
+
if (!inputRecord.ok) return inputRecord;
|
|
20922
|
+
if (inputRecord.value === void 0) {
|
|
20923
|
+
return { ok: false, error: existingRunNotFound(address.value, options) };
|
|
20924
|
+
}
|
|
20925
|
+
if (!recordedSelectorMatches(inputRecord.value, options)) {
|
|
20926
|
+
return { ok: false, error: existingRunSelectorMismatch(address.value, options) };
|
|
20927
|
+
}
|
|
20928
|
+
const run = { ...address.value, recordedInput: inputRecord.value };
|
|
20929
|
+
return { ok: true, value: run };
|
|
20930
|
+
}
|
|
20931
|
+
function isRecordedInputReadFailure(error) {
|
|
20932
|
+
return error.startsWith(VERIFY_CLI_ERROR.INPUT_READ_FAILED);
|
|
20933
|
+
}
|
|
20934
|
+
async function readRecordedInputForProjection(run, options, events, deps) {
|
|
20935
|
+
const terminal = findTerminalEvent(events);
|
|
20936
|
+
const inputRecord = await readExistingRecordedInput(run, deps);
|
|
20937
|
+
if (!inputRecord.ok) {
|
|
20938
|
+
if (terminal !== void 0 && isRecordedInputReadFailure(inputRecord.error)) {
|
|
20939
|
+
return { ok: true, value: void 0 };
|
|
20940
|
+
}
|
|
20941
|
+
return inputRecord;
|
|
20942
|
+
}
|
|
20943
|
+
if (inputRecord.value === void 0) return { ok: true, value: void 0 };
|
|
20944
|
+
if (!recordedSelectorMatches(inputRecord.value, options)) {
|
|
20945
|
+
return { ok: false, error: existingRunSelectorMismatch(run, options) };
|
|
20946
|
+
}
|
|
20947
|
+
return { ok: true, value: inputRecord.value };
|
|
20948
|
+
}
|
|
20949
|
+
function verifyFinishReport(runToken, projection) {
|
|
20950
|
+
return {
|
|
20951
|
+
runToken,
|
|
20952
|
+
...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
|
|
20953
|
+
...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
|
|
20954
|
+
sealed: projection.sealed,
|
|
20955
|
+
findingCount: projection.findingCount,
|
|
20956
|
+
lastSequence: projection.lastSequence
|
|
20957
|
+
};
|
|
20958
|
+
}
|
|
20959
|
+
async function isJournalPhysicallySealed(run, deps) {
|
|
20960
|
+
return isJournalRunSealed(
|
|
20961
|
+
{ ...run.journalScope, productDir: run.productDir },
|
|
20962
|
+
{ ...deps.fs === void 0 ? {} : { fs: deps.fs } }
|
|
20963
|
+
);
|
|
20964
|
+
}
|
|
20965
|
+
async function sealExistingRun(run, deps) {
|
|
20966
|
+
const sealed = await journalSealCommand(run.journalScope, forwardDeps(deps));
|
|
20967
|
+
if (sealed.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
|
|
20968
|
+
return errorResult3(`${VERIFY_CLI_ERROR.SEAL_FAILED}: ${sealed.output}`);
|
|
20969
|
+
}
|
|
20970
|
+
return void 0;
|
|
20971
|
+
}
|
|
20972
|
+
function finishReadFailure(run, options, error) {
|
|
20973
|
+
if (error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
|
|
20974
|
+
return errorResult3(existingRunNotFound(run, options));
|
|
20975
|
+
}
|
|
20976
|
+
return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${error}`);
|
|
20977
|
+
}
|
|
20978
|
+
async function readTerminalMetadata(options, deps) {
|
|
20979
|
+
if (options.terminalMetadata === void 0) return { ok: true, value: void 0 };
|
|
20980
|
+
const readPayload = deps.readPayloadSource;
|
|
20981
|
+
if (readPayload === void 0) return { ok: false, error: VERIFY_CLI_ERROR.TERMINAL_METADATA_INVALID };
|
|
20982
|
+
try {
|
|
20983
|
+
const rawMetadata = await readPayload(options.terminalMetadata);
|
|
20984
|
+
const parsed = parseAppendPayload(rawMetadata);
|
|
20985
|
+
if (parsed === void 0) return { ok: false, error: VERIFY_CLI_ERROR.PAYLOAD_INVALID };
|
|
20986
|
+
return { ok: true, value: parsed };
|
|
20987
|
+
} catch (error) {
|
|
20988
|
+
return { ok: false, error: `${VERIFY_CLI_ERROR.PAYLOAD_READ_FAILED}: ${toMessage2(error)}` };
|
|
20989
|
+
}
|
|
20990
|
+
}
|
|
20991
|
+
function validateTerminalMetadata(verificationType, terminalStatus, metadata, events) {
|
|
20992
|
+
const validator = terminalMetadataValidatorFor(verificationType);
|
|
20993
|
+
if (validator === void 0) {
|
|
20994
|
+
return metadata === void 0 ? { ok: true, value: void 0 } : { ok: false, error: VERIFY_CLI_ERROR.UNSUPPORTED_VERIFICATION_TYPE };
|
|
20995
|
+
}
|
|
20996
|
+
const validated = validator({ terminalStatus, metadata, events });
|
|
20997
|
+
if (validated.ok) return { ok: true, value: validated.value };
|
|
20998
|
+
return {
|
|
20999
|
+
ok: false,
|
|
21000
|
+
error: validated.error === TERMINAL_METADATA_VALIDATION_ERROR.STATUS_CONFLICT ? VERIFY_CLI_ERROR.TERMINAL_STATUS_CONFLICT : VERIFY_CLI_ERROR.TERMINAL_METADATA_INVALID
|
|
21001
|
+
};
|
|
21002
|
+
}
|
|
21003
|
+
async function finishProjectionResult(run, deps) {
|
|
21004
|
+
const events = await readRunJournalEvents(run.journalScope, deps);
|
|
21005
|
+
if (!events.ok) return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${events.error}`);
|
|
21006
|
+
return okResult3(JSON.stringify(verifyFinishReport(run.runToken, projectVerifyRun(events.value))));
|
|
21007
|
+
}
|
|
21008
|
+
async function retrySealForTerminalRun(run, deps) {
|
|
21009
|
+
const physicallySealed = await isJournalPhysicallySealed(run, deps);
|
|
21010
|
+
if (!physicallySealed.ok) return void 0;
|
|
21011
|
+
if (physicallySealed.value) return void 0;
|
|
21012
|
+
return sealExistingRun(run, deps);
|
|
21013
|
+
}
|
|
21014
|
+
async function verifyFinishCommand(options, deps) {
|
|
21015
|
+
if (options.terminalStatus.trim().length === 0) return errorResult3(VERIFY_CLI_ERROR.TERMINAL_STATUS_REQUIRED);
|
|
21016
|
+
if (!isVerifyTerminalStatus(options.terminalStatus)) return errorResult3(VERIFY_CLI_ERROR.TERMINAL_STATUS_INVALID);
|
|
21017
|
+
const run = await resolveExistingRunAddress(options, deps);
|
|
21018
|
+
if (!run.ok) return errorResult3(run.error);
|
|
21019
|
+
const before = await readRunJournalEvents(run.value.journalScope, deps);
|
|
21020
|
+
if (!before.ok) {
|
|
21021
|
+
return finishReadFailure(run.value, options, before.error);
|
|
21022
|
+
}
|
|
21023
|
+
const inputRecord = await readRecordedInputForProjection(run.value, options, before.value, deps);
|
|
21024
|
+
if (!inputRecord.ok) return errorResult3(inputRecord.error);
|
|
21025
|
+
if (findTerminalEvent(before.value) !== void 0) {
|
|
21026
|
+
const retrySeal = await retrySealForTerminalRun(run.value, deps);
|
|
21027
|
+
return retrySeal ?? finishProjectionResult(run.value, deps);
|
|
21028
|
+
}
|
|
21029
|
+
if (inputRecord.value === void 0) {
|
|
21030
|
+
return errorResult3(existingRunNotFound(run.value, options));
|
|
21031
|
+
}
|
|
21032
|
+
const rawTerminalMetadata = await readTerminalMetadata(options, deps);
|
|
21033
|
+
if (!rawTerminalMetadata.ok) return errorResult3(rawTerminalMetadata.error);
|
|
21034
|
+
const terminalMetadata = validateTerminalMetadata(
|
|
21035
|
+
options.verificationType,
|
|
21036
|
+
options.terminalStatus,
|
|
21037
|
+
rawTerminalMetadata.value,
|
|
21038
|
+
before.value
|
|
21039
|
+
);
|
|
21040
|
+
if (!terminalMetadata.ok) return errorResult3(terminalMetadata.error);
|
|
21041
|
+
const binding = deps.journalBinding;
|
|
21042
|
+
if (binding === void 0) return errorResult3(VERIFY_CLI_ERROR.FINISH_FAILED);
|
|
21043
|
+
const event = buildTerminalEvent({
|
|
21044
|
+
runToken: run.value.runToken,
|
|
21045
|
+
terminalStatus: options.terminalStatus,
|
|
21046
|
+
...terminalMetadata.value === void 0 ? {} : { terminalMetadata: terminalMetadata.value },
|
|
21047
|
+
at: deps.now?.() ?? /* @__PURE__ */ new Date()
|
|
21048
|
+
});
|
|
21049
|
+
const appended = await journalAppendCommand(run.value.journalScope, event, binding, forwardDeps(deps));
|
|
21050
|
+
if (appended.exitCode !== VERIFY_CLI_EXIT_CODE.OK) {
|
|
21051
|
+
return errorResult3(`${VERIFY_CLI_ERROR.FINISH_FAILED}: ${appended.output}`);
|
|
21052
|
+
}
|
|
21053
|
+
const sealResult = await sealExistingRun(run.value, deps);
|
|
21054
|
+
if (sealResult !== void 0) return sealResult;
|
|
21055
|
+
return finishProjectionResult(run.value, deps);
|
|
21056
|
+
}
|
|
21057
|
+
async function verifyStatusCommand(options, deps) {
|
|
21058
|
+
const run = await resolveExistingRunAddress(options, deps);
|
|
21059
|
+
if (!run.ok) return errorResult3(run.error);
|
|
21060
|
+
const events = await readRunJournalEvents(run.value.journalScope, deps);
|
|
21061
|
+
if (!events.ok) {
|
|
21062
|
+
if (events.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
|
|
21063
|
+
return errorResult3(existingRunNotFound(run.value, options));
|
|
21064
|
+
}
|
|
21065
|
+
return errorResult3(`${VERIFY_CLI_ERROR.STATUS_FAILED}: ${events.error}`);
|
|
21066
|
+
}
|
|
21067
|
+
const inputRecord = await readRecordedInputForProjection(run.value, options, events.value, deps);
|
|
21068
|
+
if (!inputRecord.ok) return errorResult3(inputRecord.error);
|
|
21069
|
+
if (inputRecord.value === void 0 && findTerminalEvent(events.value) === void 0) {
|
|
21070
|
+
return errorResult3(existingRunNotFound(run.value, options));
|
|
21071
|
+
}
|
|
21072
|
+
const projection = projectVerifyRun(events.value);
|
|
21073
|
+
const report2 = {
|
|
21074
|
+
runToken: run.value.runToken,
|
|
21075
|
+
verificationType: options.verificationType,
|
|
21076
|
+
scopeType: options.scopeType,
|
|
21077
|
+
sealed: projection.sealed,
|
|
21078
|
+
lastSequence: projection.lastSequence,
|
|
21079
|
+
...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
|
|
21080
|
+
...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
|
|
21081
|
+
findingCount: projection.findingCount,
|
|
21082
|
+
nextActions: projection.nextActions
|
|
21083
|
+
};
|
|
21084
|
+
return okResult3(JSON.stringify(report2));
|
|
21085
|
+
}
|
|
21086
|
+
async function verifyRenderCommand(options, deps) {
|
|
21087
|
+
const run = await resolveExistingRunAddress(options, deps);
|
|
21088
|
+
if (!run.ok) return errorResult3(run.error);
|
|
21089
|
+
const events = await readRunJournalEvents(run.value.journalScope, deps);
|
|
21090
|
+
if (!events.ok) {
|
|
21091
|
+
if (events.error === JOURNAL_RUNTIME_ERROR.RUN_NOT_FOUND) {
|
|
21092
|
+
return errorResult3(existingRunNotFound(run.value, options));
|
|
21093
|
+
}
|
|
21094
|
+
return errorResult3(`${VERIFY_CLI_ERROR.RENDER_FAILED}: ${events.error}`);
|
|
21095
|
+
}
|
|
21096
|
+
const inputRecord = await readRecordedInputForProjection(run.value, options, events.value, deps);
|
|
21097
|
+
if (!inputRecord.ok) return errorResult3(inputRecord.error);
|
|
21098
|
+
if (inputRecord.value === void 0 && findTerminalEvent(events.value) === void 0) {
|
|
21099
|
+
return errorResult3(existingRunNotFound(run.value, options));
|
|
21100
|
+
}
|
|
21101
|
+
const projection = projectVerifyRun(events.value);
|
|
21102
|
+
const report2 = {
|
|
21103
|
+
runToken: run.value.runToken,
|
|
21104
|
+
findingCount: projection.findingCount,
|
|
21105
|
+
sealed: projection.sealed,
|
|
21106
|
+
...projection.terminalStatus === void 0 ? {} : { terminalStatus: projection.terminalStatus },
|
|
21107
|
+
...projection.terminalMetadata === void 0 ? {} : { terminalMetadata: projection.terminalMetadata },
|
|
21108
|
+
events: events.value
|
|
21109
|
+
};
|
|
21110
|
+
return okResult3(JSON.stringify(report2));
|
|
21111
|
+
}
|
|
20020
21112
|
|
|
20021
21113
|
// src/interfaces/cli/verify.ts
|
|
21114
|
+
var VERIFICATION_RUN_CLI_SURFACE = {
|
|
21115
|
+
addCommandName: "add",
|
|
21116
|
+
findingResourceCommandName: "finding",
|
|
21117
|
+
forbiddenRootCommandName: "verify",
|
|
21118
|
+
forbiddenRunHelpTerms: ["Append", "append"],
|
|
21119
|
+
forbiddenRunCommandNames: ["journal", "event", "append-scope", "append-finding"],
|
|
21120
|
+
rootCommandName: "verification",
|
|
21121
|
+
runCommandName: "run",
|
|
21122
|
+
scopeResourceCommandName: "scope"
|
|
21123
|
+
};
|
|
20022
21124
|
var VERIFY_CLI = {
|
|
20023
|
-
|
|
21125
|
+
addCommandName: VERIFICATION_RUN_CLI_SURFACE.addCommandName,
|
|
21126
|
+
commandName: VERIFICATION_RUN_CLI_SURFACE.rootCommandName,
|
|
20024
21127
|
description: "Record and replay a typed verification run",
|
|
20025
21128
|
startCommandName: VERIFY_VERB.START,
|
|
20026
21129
|
inputCommandName: VERIFY_VERB.INPUT,
|
|
20027
|
-
|
|
20028
|
-
|
|
21130
|
+
findingCommandName: VERIFICATION_RUN_CLI_SURFACE.findingResourceCommandName,
|
|
21131
|
+
runCommandName: VERIFICATION_RUN_CLI_SURFACE.runCommandName,
|
|
21132
|
+
scopeCommandName: VERIFICATION_RUN_CLI_SURFACE.scopeResourceCommandName,
|
|
21133
|
+
finishCommandName: VERIFY_VERB.FINISH,
|
|
21134
|
+
statusCommandName: VERIFY_VERB.STATUS,
|
|
21135
|
+
renderCommandName: VERIFY_VERB.RENDER,
|
|
20029
21136
|
verificationTypeOption: "--verification-type <type>",
|
|
20030
21137
|
scopeTypeOption: "--scope-type <scope-type>",
|
|
20031
21138
|
scopeOption: "--scope <base>..<head>",
|
|
20032
21139
|
inputOption: "--input <input-source>",
|
|
20033
21140
|
runOption: "--run <token>",
|
|
20034
21141
|
payloadOption: "--payload <payload-source>",
|
|
20035
|
-
|
|
21142
|
+
payloadOptionDescription: "Evidence payload source; stdin or a file path",
|
|
21143
|
+
idempotencyKeyOption: "--idempotency-key <key>",
|
|
21144
|
+
idempotencyKeyOptionDescription: "Caller-supplied idempotency key for the evidence add",
|
|
21145
|
+
terminalMetadataOption: "--terminal-metadata <payload-source>",
|
|
21146
|
+
terminalStatusOption: "--terminal-status <status>"
|
|
20036
21147
|
};
|
|
20037
21148
|
var CLI_SOURCE_ENCODING = "utf8";
|
|
21149
|
+
var DEFAULT_VERIFY_CLI_HANDLERS = {
|
|
21150
|
+
appendFinding: verifyAppendFindingCommand,
|
|
21151
|
+
appendScope: verifyAppendScopeCommand,
|
|
21152
|
+
finish: verifyFinishCommand,
|
|
21153
|
+
input: verifyInputCommand,
|
|
21154
|
+
render: verifyRenderCommand,
|
|
21155
|
+
start: verifyStartCommand,
|
|
21156
|
+
status: verifyStatusCommand
|
|
21157
|
+
};
|
|
20038
21158
|
async function readStdinText() {
|
|
20039
21159
|
const chunks = [];
|
|
20040
21160
|
for await (const chunk of process.stdin) {
|
|
@@ -20049,30 +21169,43 @@ async function readCliSource(source) {
|
|
|
20049
21169
|
var verifyDomain = {
|
|
20050
21170
|
name: VERIFY_CLI.commandName,
|
|
20051
21171
|
description: VERIFY_CLI.description,
|
|
20052
|
-
register: (program, invocation) =>
|
|
20053
|
-
|
|
20054
|
-
|
|
20055
|
-
|
|
20056
|
-
|
|
20057
|
-
|
|
20058
|
-
|
|
20059
|
-
|
|
20060
|
-
|
|
20061
|
-
|
|
20062
|
-
|
|
20063
|
-
|
|
20064
|
-
|
|
20065
|
-
|
|
20066
|
-
|
|
20067
|
-
|
|
20068
|
-
|
|
20069
|
-
|
|
20070
|
-
|
|
20071
|
-
|
|
20072
|
-
|
|
20073
|
-
|
|
20074
|
-
}
|
|
20075
|
-
|
|
21172
|
+
register: (program, invocation) => registerVerifyCommands(program, invocation)
|
|
21173
|
+
};
|
|
21174
|
+
function registerVerifyCommands(program, invocation, handlers = DEFAULT_VERIFY_CLI_HANDLERS) {
|
|
21175
|
+
const deps = () => ({
|
|
21176
|
+
cwd: invocation.resolveEffectiveInvocationDir(),
|
|
21177
|
+
readInputSource: readCliSource,
|
|
21178
|
+
readPayloadSource: readCliSource,
|
|
21179
|
+
// The append verbs write a single structured JSON result to stdout, so the run's event
|
|
21180
|
+
// stream goes to stderr under the local backend rather than sharing the result channel.
|
|
21181
|
+
journalBinding: createJournalStreamBinding(invocation.io, stderrStreamSink(invocation.io))
|
|
21182
|
+
});
|
|
21183
|
+
const command = program.command(VERIFY_CLI.commandName).description(VERIFY_CLI.description);
|
|
21184
|
+
const runCommand = command.command(VERIFY_CLI.runCommandName).description("Manage a typed verification run lifecycle");
|
|
21185
|
+
runCommand.command(VERIFY_CLI.startCommandName).description("Start a changeset-scoped verification run and report its run locator").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.inputOption, "Verification input source; stdin or a file path").action(async (options) => {
|
|
21186
|
+
reportCliResult(await handlers.start(options, deps()), invocation.io);
|
|
21187
|
+
});
|
|
21188
|
+
runCommand.command(VERIFY_CLI.inputCommandName).description("Replay the verification input recorded at start").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
|
|
21189
|
+
reportCliResult(await handlers.input(options, deps()), invocation.io);
|
|
21190
|
+
});
|
|
21191
|
+
const scopeCommand = runCommand.command(VERIFY_CLI.scopeCommandName).description("Manage inspected scope evidence for a started verification run");
|
|
21192
|
+
scopeCommand.command(VERIFY_CLI.addCommandName).description("Record the inspected scope for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, VERIFY_CLI.payloadOptionDescription).requiredOption(VERIFY_CLI.idempotencyKeyOption, VERIFY_CLI.idempotencyKeyOptionDescription).action(async (options) => {
|
|
21193
|
+
reportCliResult(await handlers.appendScope(options, deps()), invocation.io);
|
|
21194
|
+
});
|
|
21195
|
+
const findingCommand = runCommand.command(VERIFY_CLI.findingCommandName).description("Manage finding evidence for a started verification run");
|
|
21196
|
+
findingCommand.command(VERIFY_CLI.addCommandName).description("Record a validated verification finding for a started run").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.payloadOption, VERIFY_CLI.payloadOptionDescription).requiredOption(VERIFY_CLI.idempotencyKeyOption, VERIFY_CLI.idempotencyKeyOptionDescription).action(async (options) => {
|
|
21197
|
+
reportCliResult(await handlers.appendFinding(options, deps()), invocation.io);
|
|
21198
|
+
});
|
|
21199
|
+
runCommand.command(VERIFY_CLI.finishCommandName).description("Record terminal completion, seal the run journal, and report its terminal projection").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").requiredOption(VERIFY_CLI.terminalStatusOption, "Terminal status recorded before sealing").option(VERIFY_CLI.terminalMetadataOption, "Verification-type terminal metadata source; stdin or a file path").action(async (options) => {
|
|
21200
|
+
reportCliResult(await handlers.finish(options, deps()), invocation.io);
|
|
21201
|
+
});
|
|
21202
|
+
runCommand.command(VERIFY_CLI.statusCommandName).description("Report the run's resumable status projected from its journal history").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
|
|
21203
|
+
reportCliResult(await handlers.status(options, deps()), invocation.io);
|
|
21204
|
+
});
|
|
21205
|
+
runCommand.command(VERIFY_CLI.renderCommandName).description("Render the run's journal projection with its authoritative finding count").requiredOption(VERIFY_CLI.verificationTypeOption, "Verification type recorded for the run").requiredOption(VERIFY_CLI.scopeTypeOption, "Scope type; changeset").requiredOption(VERIFY_CLI.scopeOption, "Changeset scope as <base>..<head>").requiredOption(VERIFY_CLI.runOption, "Run token reported by start").action(async (options) => {
|
|
21206
|
+
reportCliResult(await handlers.render(options, deps()), invocation.io);
|
|
21207
|
+
});
|
|
21208
|
+
}
|
|
20076
21209
|
|
|
20077
21210
|
// src/interfaces/cli/worktree.ts
|
|
20078
21211
|
import { randomBytes as nodeRandomBytes4 } from "crypto";
|