@patronage/software-factory 1.0.0-alpha.37 → 1.0.0-alpha.39
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/README.md +1 -1
- package/dist/index.d.ts +399 -64
- package/dist/index.js +3416 -1154
- package/dist/oxlint-jev/{bridge-B4Sx95ZO.js → bridge-PMzq2gZh.js} +98 -37
- package/dist/oxlint-jev/index.js +1 -1
- package/dist/oxlint-jev/worker.js +1 -1
- package/dist/schemas.d.ts +24 -2
- package/dist/schemas.js +26 -1
- package/package.json +2 -2
|
@@ -193,8 +193,19 @@ const openJevCache = ({ directory = defaultJevCacheDirectory(process.cwd()), end
|
|
|
193
193
|
};
|
|
194
194
|
//#endregion
|
|
195
195
|
//#region src/hq-access.ts
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
/**
|
|
197
|
+
* The environment variables that carry the HQ Cloudflare Access service token.
|
|
198
|
+
* Both names are shell identifiers, so `/bin/sh` passes them through on every
|
|
199
|
+
* platform, dash included (#1286, #1311). These are the only names read.
|
|
200
|
+
*/
|
|
201
|
+
const CF_ACCESS_CLIENT_ID_ENV = "CF_ACCESS_CLIENT_ID";
|
|
202
|
+
const CF_ACCESS_CLIENT_SECRET_ENV = "CF_ACCESS_CLIENT_SECRET";
|
|
203
|
+
/**
|
|
204
|
+
* The request headers Cloudflare Access reads the token from. They are the
|
|
205
|
+
* wire contract and do not follow the environment variable names.
|
|
206
|
+
*/
|
|
207
|
+
const CF_ACCESS_CLIENT_ID_HEADER = "CF-Access-Client-Id";
|
|
208
|
+
const CF_ACCESS_CLIENT_SECRET_HEADER = "CF-Access-Client-Secret";
|
|
198
209
|
/**
|
|
199
210
|
* True in a hosted runner, where secret-manager resolution must not be
|
|
200
211
|
* tried (#312). Lives here — a dependency-free leaf both
|
|
@@ -211,8 +222,8 @@ const buildCloudflareAccessRequestInit = (token, init) => ({
|
|
|
211
222
|
...init,
|
|
212
223
|
headers: {
|
|
213
224
|
...init.headers,
|
|
214
|
-
[
|
|
215
|
-
[
|
|
225
|
+
[CF_ACCESS_CLIENT_ID_HEADER]: token.clientId,
|
|
226
|
+
[CF_ACCESS_CLIENT_SECRET_HEADER]: token.clientSecret
|
|
216
227
|
},
|
|
217
228
|
redirect: "error"
|
|
218
229
|
});
|
|
@@ -221,9 +232,11 @@ const buildCloudflareAccessRequestInit = (token, init) => ({
|
|
|
221
232
|
/**
|
|
222
233
|
* Resolving the HQ Access credentials, and saying *why* when that fails.
|
|
223
234
|
*
|
|
224
|
-
* A deliberate command (`psf hq:flush`, and doctor's remote checks in #394)
|
|
225
|
-
*
|
|
226
|
-
*
|
|
235
|
+
* A deliberate command (`psf hq:flush`, and doctor's remote checks in #394)
|
|
236
|
+
* asks the secret manager for the HQ Access token, and since #1313 so does an
|
|
237
|
+
* HQ emission on an operator machine, once per process
|
|
238
|
+
* (`resolveHqCredentialsOncePerProcess`). This used to be a
|
|
239
|
+
* value-or-nothing answer, so a missing binary, a sandbox that
|
|
227
240
|
* cannot reach the keychain, and a mistyped reference all collapsed into one
|
|
228
241
|
* generic "credentials are unavailable" line. A sandboxed lane read that as
|
|
229
242
|
* environmental noise while every one of its proofs stayed spooled.
|
|
@@ -247,15 +260,16 @@ const spawnFailure = (error) => {
|
|
|
247
260
|
if (code === "EACCES" || code === "EPERM") return "resolver-blocked";
|
|
248
261
|
return "resolver-timeout";
|
|
249
262
|
};
|
|
250
|
-
const probe = (binary, reference, capture) => {
|
|
263
|
+
const probe = (binary, reference, capture, timeoutMs) => {
|
|
251
264
|
const result = spawnSync(binary, ["read", reference], {
|
|
252
265
|
encoding: "utf-8",
|
|
266
|
+
killSignal: "SIGKILL",
|
|
253
267
|
stdio: [
|
|
254
268
|
"ignore",
|
|
255
269
|
capture ? "pipe" : "ignore",
|
|
256
270
|
"ignore"
|
|
257
271
|
],
|
|
258
|
-
timeout:
|
|
272
|
+
timeout: timeoutMs
|
|
259
273
|
});
|
|
260
274
|
if (result.error) return { status: spawnFailure(result.error) };
|
|
261
275
|
if (result.signal) return { status: "resolver-timeout" };
|
|
@@ -276,20 +290,26 @@ const probe = (binary, reference, capture) => {
|
|
|
276
290
|
* *informative* one: a machine without `op-fast` that has `op` installed and
|
|
277
291
|
* denied must report the denial, not the missing binary.
|
|
278
292
|
*/
|
|
279
|
-
const resolveThrough = (reference, capture) => {
|
|
293
|
+
const resolveThrough = (reference, capture, timeoutMs = SECRET_PROBE_TIMEOUT_MS) => {
|
|
280
294
|
let failure = "resolver-missing";
|
|
281
295
|
for (const binary of SECRET_RESOLVER_BINARIES) {
|
|
282
|
-
const outcome = probe(binary, reference, capture);
|
|
296
|
+
const outcome = probe(binary, reference, capture, timeoutMs);
|
|
283
297
|
if (outcome.status === "resolved") return outcome;
|
|
284
298
|
if (failure === "resolver-missing") failure = outcome.status;
|
|
285
299
|
}
|
|
286
300
|
return { status: failure };
|
|
287
301
|
};
|
|
288
|
-
const defaultSecretReferenceResolver = (reference) => resolveThrough(reference, true);
|
|
289
302
|
/**
|
|
290
|
-
*
|
|
291
|
-
*
|
|
292
|
-
* probe
|
|
303
|
+
* The capturing resolver with its own probe ceiling. Production uses
|
|
304
|
+
* `defaultSecretReferenceResolver`; a test passes a short ceiling to prove the
|
|
305
|
+
* probe really ends there.
|
|
306
|
+
*/
|
|
307
|
+
const secretReferenceResolverWithin = (timeoutMs) => (reference) => resolveThrough(reference, true, timeoutMs);
|
|
308
|
+
const defaultSecretReferenceResolver = secretReferenceResolverWithin(SECRET_PROBE_TIMEOUT_MS);
|
|
309
|
+
/**
|
|
310
|
+
* Environment first, then the operator's configured references. The first
|
|
311
|
+
* reference that fails ends the resolution: a second probe would add nothing
|
|
312
|
+
* but another chance to hang.
|
|
293
313
|
*/
|
|
294
314
|
const resolveHqCredentials = ({ env, references, resolve = defaultSecretReferenceResolver }) => {
|
|
295
315
|
const clientId = env[CF_ACCESS_CLIENT_ID_ENV];
|
|
@@ -354,7 +374,7 @@ const hqIngestCredentialReferencesSchema = z.object({
|
|
|
354
374
|
const factoryUserConfigSchema = z.object({
|
|
355
375
|
githubApp: githubAppConfigSchema.optional(),
|
|
356
376
|
hqAllowedOrigins: z.array(hqAllowedOriginSchema).describe("Operator-controlled exact HTTPS origins authorized to receive HQ credential-bearing requests; an absent or empty list authorizes none.").optional(),
|
|
357
|
-
hqIngestCredentials: hqIngestCredentialReferencesSchema.describe("Operator-controlled secret-manager references for the HQ ingest Cloudflare Access service token. References only
|
|
377
|
+
hqIngestCredentials: hqIngestCredentialReferencesSchema.describe("Operator-controlled secret-manager references for the HQ ingest Cloudflare Access service token. References only: the factory resolves them in memory when it sends HQ evidence, and never prints, exports, or writes the values.").optional(),
|
|
358
378
|
schemaVersion: z.literal(FACTORY_USER_CONFIG_SCHEMA_VERSION)
|
|
359
379
|
});
|
|
360
380
|
function defaultUserConfigPath(env = process.env) {
|
|
@@ -368,14 +388,19 @@ function defaultUserConfigPath(env = process.env) {
|
|
|
368
388
|
*
|
|
369
389
|
* A request that carries the token goes only to an HTTPS origin with no
|
|
370
390
|
* embedded credentials that the operator listed, exactly, in
|
|
371
|
-
* `hqAllowedOrigins` in the operator user config
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
391
|
+
* `hqAllowedOrigins` in the operator user config or in
|
|
392
|
+
* `FACTORY_HQ_ALLOWED_ORIGINS` in the process environment. Those two lists
|
|
393
|
+
* are unioned. Committed repository data can name an origin; it cannot
|
|
394
|
+
* authorize one (ADR 0015). The environment variable is operator
|
|
395
|
+
* configuration, read only from the process environment passed in, never
|
|
396
|
+
* from the profile or any repository file. HQ ingest and the Jev client both
|
|
397
|
+
* call this module, so the two cannot drift apart: one protocol rule, one
|
|
398
|
+
* resolver.
|
|
375
399
|
*
|
|
376
|
-
* The reader is bounded. A config path that is a FIFO, a huge file, or a
|
|
377
|
-
* that hangs
|
|
378
|
-
* instead of holding a gate or a lint run open.
|
|
400
|
+
* The file reader is bounded. A config path that is a FIFO, a huge file, or a
|
|
401
|
+
* disk that hangs contributes no config origin within the caller's deadline
|
|
402
|
+
* instead of holding a gate or a lint run open. The environment list does not
|
|
403
|
+
* touch the filesystem, so it still applies when the file does not answer.
|
|
379
404
|
*/
|
|
380
405
|
/** Largest operator config or profile file the HQ readers will open. */
|
|
381
406
|
const MAX_HQ_CONFIG_BYTES = 1024 * 1024;
|
|
@@ -447,20 +472,59 @@ const hqAllowedOriginsFromConfigText = (text) => {
|
|
|
447
472
|
return [];
|
|
448
473
|
}
|
|
449
474
|
};
|
|
475
|
+
/** Operator allowlist supplied to a machine that has no user config file. */
|
|
476
|
+
const FACTORY_HQ_ALLOWED_ORIGINS_ENV = "FACTORY_HQ_ALLOWED_ORIGINS";
|
|
477
|
+
/**
|
|
478
|
+
* Exact HTTPS origins from `FACTORY_HQ_ALLOWED_ORIGINS` in `env`.
|
|
479
|
+
* Comma-separated. A segment that is not an exact origin is ignored.
|
|
480
|
+
* This reads that one property and nothing else: no file, no profile.
|
|
481
|
+
*/
|
|
482
|
+
const hqAllowedOriginsFromEnv = (env) => {
|
|
483
|
+
let raw;
|
|
484
|
+
try {
|
|
485
|
+
raw = env[FACTORY_HQ_ALLOWED_ORIGINS_ENV];
|
|
486
|
+
} catch {
|
|
487
|
+
return [];
|
|
488
|
+
}
|
|
489
|
+
if (typeof raw !== "string" || raw.trim() === "") return [];
|
|
490
|
+
const origins = [];
|
|
491
|
+
for (const segment of raw.split(",")) {
|
|
492
|
+
const candidate = segment.trim();
|
|
493
|
+
if (candidate === "") continue;
|
|
494
|
+
const endpoint = validatedHqOrigin(candidate);
|
|
495
|
+
if (endpoint !== void 0 && candidate === endpoint.origin) origins.push(endpoint.origin);
|
|
496
|
+
}
|
|
497
|
+
return origins;
|
|
498
|
+
};
|
|
499
|
+
/**
|
|
500
|
+
* Operator-authorized HQ origins. `configOrigins` (the user config's
|
|
501
|
+
* `hqAllowedOrigins`) is unioned with `FACTORY_HQ_ALLOWED_ORIGINS` from
|
|
502
|
+
* `env`. The environment value never replaces the config list, and neither
|
|
503
|
+
* list is read from the profile or any repository file.
|
|
504
|
+
*/
|
|
505
|
+
const resolveHqAllowedOrigins = (env, configOrigins) => {
|
|
506
|
+
const fromEnv = hqAllowedOriginsFromEnv(env);
|
|
507
|
+
if (fromEnv.length === 0) return [...configOrigins];
|
|
508
|
+
const allowed = [...configOrigins];
|
|
509
|
+
for (const origin of fromEnv) if (!allowed.includes(origin)) allowed.push(origin);
|
|
510
|
+
return allowed;
|
|
511
|
+
};
|
|
450
512
|
/**
|
|
451
513
|
* The operator's `hqAllowedOrigins`, read from the operator user config within
|
|
452
|
-
* `deadline` (a `performance.now()` time)
|
|
453
|
-
*
|
|
514
|
+
* `deadline` (a `performance.now()` time), unioned with
|
|
515
|
+
* `FACTORY_HQ_ALLOWED_ORIGINS`. A missing, unreadable, oversized or invalid
|
|
516
|
+
* file, or one that does not answer in time, contributes no config origin.
|
|
517
|
+
* The environment list still applies.
|
|
454
518
|
*/
|
|
455
519
|
const loadHqAllowedOrigins = async (env, deadline) => {
|
|
456
|
-
let
|
|
520
|
+
let configOrigins = [];
|
|
457
521
|
try {
|
|
458
|
-
|
|
522
|
+
const contents = await readBoundedTextFile(defaultUserConfigPath(env), deadline);
|
|
523
|
+
if (contents !== void 0) configOrigins = hqAllowedOriginsFromConfigText(contents);
|
|
459
524
|
} catch {
|
|
460
|
-
|
|
525
|
+
configOrigins = [];
|
|
461
526
|
}
|
|
462
|
-
|
|
463
|
-
return contents === void 0 ? [] : hqAllowedOriginsFromConfigText(contents);
|
|
527
|
+
return resolveHqAllowedOrigins(env, configOrigins);
|
|
464
528
|
};
|
|
465
529
|
/**
|
|
466
530
|
* The matching rule: the URL's origin must equal one listed origin exactly.
|
|
@@ -481,8 +545,8 @@ const isHqOriginAuthorized = (allowedOrigins, endpoint) => allowedOrigins.includ
|
|
|
481
545
|
* anything else happens, by the same code HQ ingest uses
|
|
482
546
|
* (`hq-origin-policy.ts`, ADR 0015): it must be an `https:` origin with no
|
|
483
547
|
* embedded credentials, listed exactly in the operator's `hqAllowedOrigins`.
|
|
484
|
-
* Only then are credentials read: `resolveHqCredentials` reads the
|
|
485
|
-
* `
|
|
548
|
+
* Only then are credentials read: `resolveHqCredentials` reads the
|
|
549
|
+
* `CF_ACCESS_CLIENT_ID` / `CF_ACCESS_CLIENT_SECRET` pair, and
|
|
486
550
|
* `buildCloudflareAccessRequestInit` attaches them to a request that refuses
|
|
487
551
|
* redirects so the credentials cannot leave the authorized origin.
|
|
488
552
|
*
|
|
@@ -647,11 +711,8 @@ const exchange = async (input) => {
|
|
|
647
711
|
throw new JevRequestError(0, "exchange_failed", "The HQ Jev exchange failed before a response could be read. No upstream text is reported: it can quote the request.");
|
|
648
712
|
}
|
|
649
713
|
};
|
|
650
|
-
/**
|
|
651
|
-
|
|
652
|
-
* hyphenated, so a plain `export` does not set them.
|
|
653
|
-
*/
|
|
654
|
-
const MISSING_CREDENTIALS_REASON = `no HQ credentials: ${CF_ACCESS_CLIENT_ID_ENV} and ${CF_ACCESS_CLIENT_SECRET_ENV} are not both in the environment. The names are literally hyphenated, so a plain \`export\` does not set them — prefix the command: \`env '${CF_ACCESS_CLIENT_ID_ENV}=…' '${CF_ACCESS_CLIENT_SECRET_ENV}=…' <the command> …\`.`;
|
|
714
|
+
/** The whole remedy, in one sentence. */
|
|
715
|
+
const MISSING_CREDENTIALS_REASON = `no HQ credentials: ${CF_ACCESS_CLIENT_ID_ENV} and ${CF_ACCESS_CLIENT_SECRET_ENV} are not both in the environment. Set both, or prefix the command: \`env '${CF_ACCESS_CLIENT_ID_ENV}=…' '${CF_ACCESS_CLIENT_SECRET_ENV}=…' <the command> …\`.`;
|
|
655
716
|
/** Where the operator config was looked for, for a message that names it. */
|
|
656
717
|
const operatorConfigLocation = (env) => {
|
|
657
718
|
try {
|
package/dist/oxlint-jev/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as buildJevRequests, l as noul, n as spawnJevBridge, o as defaultJevCacheDirectory } from "./bridge-
|
|
1
|
+
import { i as buildJevRequests, l as noul, n as spawnJevBridge, o as defaultJevCacheDirectory } from "./bridge-PMzq2gZh.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as resolveJevGateway, r as runJevFiles, s as openJevCache, t as allUnavailable } from "./bridge-
|
|
1
|
+
import { a as resolveJevGateway, r as runJevFiles, s as openJevCache, t as allUnavailable } from "./bridge-PMzq2gZh.js";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
//#region src/oxlint-jev/worker.ts
|
|
4
4
|
/**
|
package/dist/schemas.d.ts
CHANGED
|
@@ -1000,8 +1000,8 @@ declare const closeoutArtifactSchema: z.ZodObject<{
|
|
|
1000
1000
|
}, z.core.$strict>;
|
|
1001
1001
|
unit: z.ZodEnum<{
|
|
1002
1002
|
boolean: "boolean";
|
|
1003
|
-
count: "count";
|
|
1004
1003
|
text: "text";
|
|
1004
|
+
count: "count";
|
|
1005
1005
|
tokens: "tokens";
|
|
1006
1006
|
usd: "usd";
|
|
1007
1007
|
}>;
|
|
@@ -1012,6 +1012,28 @@ declare const closeoutArtifactSchema: z.ZodObject<{
|
|
|
1012
1012
|
}, z.core.$strict>;
|
|
1013
1013
|
type CloseoutArtifact = z.infer<typeof closeoutArtifactSchema>;
|
|
1014
1014
|
//#endregion
|
|
1015
|
+
//#region src/gate-timing-record.d.ts
|
|
1016
|
+
declare const gateTimingRecordSchema: z.ZodObject<{
|
|
1017
|
+
agentRunId: z.ZodString;
|
|
1018
|
+
cycle: z.ZodNumber;
|
|
1019
|
+
durationMs: z.ZodNumber;
|
|
1020
|
+
gate: z.ZodEnum<{
|
|
1021
|
+
"boundary:check": "boundary:check";
|
|
1022
|
+
"factory:closeout": "factory:closeout";
|
|
1023
|
+
"pr:ready": "pr:ready";
|
|
1024
|
+
"pr:review": "pr:review";
|
|
1025
|
+
"pr:verify": "pr:verify";
|
|
1026
|
+
}>;
|
|
1027
|
+
outcome: z.ZodEnum<{
|
|
1028
|
+
pass: "pass";
|
|
1029
|
+
fail: "fail";
|
|
1030
|
+
}>;
|
|
1031
|
+
schemaVersion: z.ZodLiteral<1>;
|
|
1032
|
+
startOffsetMs: z.ZodNumber;
|
|
1033
|
+
startedAt: z.ZodISODateTime;
|
|
1034
|
+
}, z.core.$strict>;
|
|
1035
|
+
type GateTimingRecord = z.infer<typeof gateTimingRecordSchema>;
|
|
1036
|
+
//#endregion
|
|
1015
1037
|
//#region src/schemas.d.ts
|
|
1016
1038
|
declare const EVIDENCE_ENVELOPE_SCHEMA_VERSION = 1;
|
|
1017
1039
|
declare const evidenceEnvelopeSchema: z.ZodObject<{
|
|
@@ -1408,4 +1430,4 @@ declare const prReadyProofSchema: z.ZodObject<{
|
|
|
1408
1430
|
waivedDemands: z.ZodOptional<z.ZodArray<z.ZodType<WaivedDemand, unknown, z.core.$ZodTypeInternals<WaivedDemand, unknown>>>>;
|
|
1409
1431
|
}, z.core.$strip>;
|
|
1410
1432
|
//#endregion
|
|
1411
|
-
export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, type BlockedReason, BoundaryCheckProofRecord, type BoundaryReviewProof, type CloseoutArtifact, EVIDENCE_ENVELOPE_SCHEMA_VERSION, type EvidenceEnvelope, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, type PrReadyProof, type PrReviewProof, type PrVerifyProof, type ReviewPromptSection, type ReviewPromptSectionProvenance, SUPPORTED_CLOSEOUT_SCHEMA_VERSIONS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, type WaivedDemand, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prReadyProofSchema, prReviewFindingSchema, prReviewProofSchema, prReviewResultSchema, prVerifyProofSchema, reviewPromptSectionSchema, reviewPromptSectionsSchema, waivedDemandSchema };
|
|
1433
|
+
export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, type BlockedReason, BoundaryCheckProofRecord, type BoundaryReviewProof, type CloseoutArtifact, EVIDENCE_ENVELOPE_SCHEMA_VERSION, type EvidenceEnvelope, type GateTimingRecord, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, type PrReadyProof, type PrReviewProof, type PrVerifyProof, type ReviewPromptSection, type ReviewPromptSectionProvenance, SUPPORTED_CLOSEOUT_SCHEMA_VERSIONS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, type WaivedDemand, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, gateTimingRecordSchema, prReadyProofSchema, prReviewFindingSchema, prReviewProofSchema, prReviewResultSchema, prVerifyProofSchema, reviewPromptSectionSchema, reviewPromptSectionsSchema, waivedDemandSchema };
|
package/dist/schemas.js
CHANGED
|
@@ -1284,6 +1284,31 @@ const closeoutArtifactSchema = z.object({
|
|
|
1284
1284
|
repo: RepoSchema,
|
|
1285
1285
|
schemaVersion: z.literal(5)
|
|
1286
1286
|
}).strict();
|
|
1287
|
+
/** The self-timed gate commands. */
|
|
1288
|
+
const FACTORY_GATE_NAMES = [
|
|
1289
|
+
"boundary:check",
|
|
1290
|
+
"factory:closeout",
|
|
1291
|
+
"pr:ready",
|
|
1292
|
+
"pr:review",
|
|
1293
|
+
"pr:verify"
|
|
1294
|
+
];
|
|
1295
|
+
const nonNegativeInteger = z.number().int().nonnegative();
|
|
1296
|
+
const gateTimingRecordSchema = z.object({
|
|
1297
|
+
/** The lane run identity the ledger is keyed by. */
|
|
1298
|
+
agentRunId: z.string().min(1),
|
|
1299
|
+
cycle: z.number().int().positive(),
|
|
1300
|
+
durationMs: nonNegativeInteger,
|
|
1301
|
+
gate: z.enum(FACTORY_GATE_NAMES),
|
|
1302
|
+
outcome: z.enum(["fail", "pass"]),
|
|
1303
|
+
schemaVersion: z.literal(1),
|
|
1304
|
+
/**
|
|
1305
|
+
* Milliseconds from the lane run's origin (the first record's start) to
|
|
1306
|
+
* this record's start. The first record is offset 0.
|
|
1307
|
+
*/
|
|
1308
|
+
startOffsetMs: nonNegativeInteger,
|
|
1309
|
+
/** Wall-clock start of this gate invocation (ISO 8601). */
|
|
1310
|
+
startedAt: z.iso.datetime()
|
|
1311
|
+
}).strict();
|
|
1287
1312
|
//#endregion
|
|
1288
1313
|
//#region src/schemas.ts
|
|
1289
1314
|
const evidenceCheckTypeSchema = z.enum(EVIDENCE_CHECK_TYPES);
|
|
@@ -1626,4 +1651,4 @@ const prReadyProofSchema = z.object({
|
|
|
1626
1651
|
for (const issue of blockedReasonIssues({ ...proof })) context.addIssue(issue);
|
|
1627
1652
|
});
|
|
1628
1653
|
//#endregion
|
|
1629
|
-
export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, EVIDENCE_ENVELOPE_SCHEMA_VERSION, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, SUPPORTED_CLOSEOUT_SCHEMA_VERSIONS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, prReadyProofSchema, prReviewFindingSchema, prReviewProofSchema, prReviewResultSchema, prVerifyProofSchema, reviewPromptSectionSchema, reviewPromptSectionsSchema, waivedDemandSchema };
|
|
1654
|
+
export { BLOCKED_REASONS_MAX, BLOCKED_REASON_DETAIL_MAX, BOUNDARY_CHECK_SCHEMA_VERSION, BOUNDARY_REVIEW_PROOF_KIND, EVIDENCE_ENVELOPE_SCHEMA_VERSION, PR_READY_SCHEMA_VERSION, PR_REVIEW_SCHEMA_VERSION, SUPPORTED_CLOSEOUT_SCHEMA_VERSIONS, SUPPORTED_PR_READY_SCHEMA_VERSIONS, SUPPORTED_PR_VERIFY_SCHEMA_VERSIONS, blockedReasonSchema, blockedReasonsSchema, boundaryCheckProofSchema, boundaryReviewProofSchema, closeoutArtifactSchema, evidenceEnvelopeSchema, gateTimingRecordSchema, prReadyProofSchema, prReviewFindingSchema, prReviewProofSchema, prReviewResultSchema, prVerifyProofSchema, reviewPromptSectionSchema, reviewPromptSectionsSchema, waivedDemandSchema };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patronage/software-factory",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.39",
|
|
4
4
|
"description": "Shared Patronage software factory CLI and project-profile validation tools",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"picomatch": "^4.0.5",
|
|
43
43
|
"yaml": "^2.9.0",
|
|
44
44
|
"zod": "4.4.3",
|
|
45
|
-
"@patronage/factory-ci": "1.0.0-alpha.
|
|
45
|
+
"@patronage/factory-ci": "1.0.0-alpha.39"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@oxlint/plugins": "1.76.0",
|