@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
package/README.md
CHANGED
|
@@ -76,6 +76,6 @@ npx skills add https://github.com/patronage/software-factory -g --all
|
|
|
76
76
|
|
|
77
77
|
They provide procedure and link back to the documentation site; they are not a second command reference.
|
|
78
78
|
|
|
79
|
-
The package also exports an Oxlint plugin at `@patronage/software-factory/oxlint-jev`. It asks Jev questions that a project writes about its own code, through HQ, from a dedicated Oxlint config. It records by default and sends only with `PATRONAGE_JEV_MODE=live`. `psf jev:calibrate` scores those questions against the project's labeled cases. Both are session diagnostics, never gates. See [Ask Jev about code](https://factory.patronage.com/
|
|
79
|
+
The package also exports an Oxlint plugin at `@patronage/software-factory/oxlint-jev`. It asks Jev questions that a project writes about its own code, through HQ, from a dedicated Oxlint config. It records by default and sends only with `PATRONAGE_JEV_MODE=live`. `psf jev:calibrate` scores those questions against the project's labeled cases. Both are session diagnostics, never gates. See [Ask Jev about your code](https://factory.patronage.com/tutorials/ask-jev-about-code).
|
|
80
80
|
|
|
81
81
|
`assembleReviewPrompt` puts a repository-root `CODING_STANDARDS.md` into the correctness prompt when the file exists and is not blank. It reads the file at the candidate head, not from the working tree, and emits one `coding-standards` section that names the head SHA. A repository without the file gets an unchanged prompt. `pr:review --assemble` writes that factory-owned prompt under `.factory-memory/pr-review-prompt.json`. `pr:review --findings` copies the recorded sections onto the proof when the artifact's patch-id matches.
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,114 @@ import { z } from "zod";
|
|
|
4
4
|
import { PreviewProofRegistration } from "@patronage/factory-ci";
|
|
5
5
|
import { JsonValue, Questions, SystemOneRequest, choice, noul, score } from "@typesafe-ai/sdk";
|
|
6
6
|
|
|
7
|
+
//#region src/factory-app-broker-client.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* The opt-in broker permission set (#1360): `pull_requests: write`,
|
|
10
|
+
* `issues: read`, and `contents: read` on the requesting repository. The
|
|
11
|
+
* read-only contents grant is there because GitHub's pull request create
|
|
12
|
+
* reads the head and base refs (#1327, #1375). The CLI asks for the scope by
|
|
13
|
+
* name and the broker decides its permissions. A request without a scope is
|
|
14
|
+
* the `checks: write` mint, unchanged.
|
|
15
|
+
*/
|
|
16
|
+
declare const FACTORY_APP_BROKER_ADMISSION_SCOPE = "admission";
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/user-config.d.ts
|
|
19
|
+
declare const githubAppConfigSchema: z.ZodObject<{
|
|
20
|
+
appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
21
|
+
installationId: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
privateKeyPath: z.ZodString;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
type GithubAppConfig = z.infer<typeof githubAppConfigSchema>;
|
|
25
|
+
declare const hqIngestCredentialReferencesSchema: z.ZodObject<{
|
|
26
|
+
clientIdRef: z.ZodString;
|
|
27
|
+
clientSecretRef: z.ZodString;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
type HqIngestCredentialReferences = z.infer<typeof hqIngestCredentialReferencesSchema>;
|
|
30
|
+
declare const factoryUserConfigSchema: z.ZodObject<{
|
|
31
|
+
githubApp: z.ZodOptional<z.ZodObject<{
|
|
32
|
+
appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
33
|
+
installationId: z.ZodOptional<z.ZodNumber>;
|
|
34
|
+
privateKeyPath: z.ZodString;
|
|
35
|
+
}, z.core.$strip>>;
|
|
36
|
+
hqAllowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
37
|
+
hqIngestCredentials: z.ZodOptional<z.ZodObject<{
|
|
38
|
+
clientIdRef: z.ZodString;
|
|
39
|
+
clientSecretRef: z.ZodString;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
schemaVersion: z.ZodLiteral<2>;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
type FactoryUserConfig = z.infer<typeof factoryUserConfigSchema>;
|
|
44
|
+
interface LoadUserConfigResult {
|
|
45
|
+
path: string;
|
|
46
|
+
config: FactoryUserConfig;
|
|
47
|
+
ignoredKeys?: string[];
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/github-app-access.d.ts
|
|
51
|
+
interface FactoryAppAccessDependencies {
|
|
52
|
+
env?: NodeJS.ProcessEnv;
|
|
53
|
+
existsSync?: (path: string) => boolean;
|
|
54
|
+
exchangeBroker?: (input: {
|
|
55
|
+
fetch?: typeof fetch;
|
|
56
|
+
oidc: string;
|
|
57
|
+
owner: string;
|
|
58
|
+
repo: string;
|
|
59
|
+
scope?: typeof FACTORY_APP_BROKER_ADMISSION_SCOPE;
|
|
60
|
+
timeoutMs?: number;
|
|
61
|
+
url?: string;
|
|
62
|
+
}) => Promise<string>;
|
|
63
|
+
fetch?: typeof fetch;
|
|
64
|
+
githubApp?: GithubAppConfig;
|
|
65
|
+
mintCursorOidc?: (input: {
|
|
66
|
+
audience?: string;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
socketPath?: string;
|
|
69
|
+
timeoutMs?: number;
|
|
70
|
+
}) => Promise<string>;
|
|
71
|
+
now?: () => number;
|
|
72
|
+
/**
|
|
73
|
+
* Cancels the Cursor OIDC mint (#1322). Fetch-based calls are cancelled
|
|
74
|
+
* through the `fetch` the caller passes, which joins its own signal.
|
|
75
|
+
*/
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
timeoutMs?: number;
|
|
78
|
+
token?: string;
|
|
79
|
+
transportAttempts?: number;
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/admission-credential.d.ts
|
|
83
|
+
/**
|
|
84
|
+
* The GitHub calls a Cursor VM's own `gh` credential cannot make (#1327).
|
|
85
|
+
* Cursor mints the VM token without `pull_requests: write` or `issues`, so on
|
|
86
|
+
* a Cursor managed runtime these, and only these, run on the broker's
|
|
87
|
+
* `admission` token (#1360): `pull_requests: write`, `issues: read`, and
|
|
88
|
+
* `contents: read`, which creating a pull request needs because GitHub reads
|
|
89
|
+
* the head and base refs (#1375). Push,
|
|
90
|
+
* marking ready, arming auto-merge, check runs, and every other call keep
|
|
91
|
+
* their own credential.
|
|
92
|
+
*/
|
|
93
|
+
type AdmissionOperation = "create-pull-request" | "edit-pull-request-body" | "read-issue" | "read-pull-request-for-status-hud";
|
|
94
|
+
/** The one repository the admission token is minted for. */
|
|
95
|
+
interface AdmissionRepository {
|
|
96
|
+
owner: string;
|
|
97
|
+
repo: string;
|
|
98
|
+
}
|
|
99
|
+
interface AdmissionCredential {
|
|
100
|
+
/**
|
|
101
|
+
* The environment overlay for ONE `gh` subprocess that performs
|
|
102
|
+
* `operation`. `undefined` off a Cursor managed runtime: nothing is minted
|
|
103
|
+
* and the subprocess environment is untouched. On one, `{ GH_TOKEN }` with
|
|
104
|
+
* the admission token. Throws {@link AdmissionCredentialError} when the mint
|
|
105
|
+
* fails.
|
|
106
|
+
*/
|
|
107
|
+
ghEnv: (operation: AdmissionOperation, repository: AdmissionRepository) => Promise<Readonly<Record<string, string>> | undefined>;
|
|
108
|
+
/**
|
|
109
|
+
* The same token for one direct REST request, or `undefined` off a Cursor
|
|
110
|
+
* managed runtime.
|
|
111
|
+
*/
|
|
112
|
+
token: (operation: AdmissionOperation, repository: AdmissionRepository) => Promise<string | undefined>;
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
7
115
|
//#region src/review-rungs.d.ts
|
|
8
116
|
declare const EVIDENCE_REVIEW_RUNGS: readonly ["independent-model", "oracle", "human"];
|
|
9
117
|
type EvidenceReviewRung = (typeof EVIDENCE_REVIEW_RUNGS)[number];
|
|
@@ -332,6 +440,32 @@ declare const authorizeDemandWaiver: ({
|
|
|
332
440
|
session: string | undefined;
|
|
333
441
|
}) => AuthorizeDemandWaiverResult;
|
|
334
442
|
//#endregion
|
|
443
|
+
//#region src/hq-credentials.d.ts
|
|
444
|
+
/**
|
|
445
|
+
* Why a reference did not resolve. Each value names a different remedy, and
|
|
446
|
+
* none of them can be inferred from a value-or-nothing result:
|
|
447
|
+
*
|
|
448
|
+
* - `resolver-missing` — no secret-manager binary on PATH.
|
|
449
|
+
* - `resolver-blocked` — a binary exists but this session may not execute it
|
|
450
|
+
* (a sandbox denying exec). The command belongs outside the sandbox.
|
|
451
|
+
* - `resolver-timeout` — the probe expired: a desktop agent waiting on an
|
|
452
|
+
* approval nobody can give here.
|
|
453
|
+
* - `resolver-refused` — the binary ran and produced no value. Its store is
|
|
454
|
+
* unreachable from this session (a sandbox with no keychain access) or the
|
|
455
|
+
* reference is not readable. These two stay one status on purpose: telling
|
|
456
|
+
* them apart would mean reading resolver output.
|
|
457
|
+
*/
|
|
458
|
+
type SecretResolutionFailure = "resolver-blocked" | "resolver-missing" | "resolver-refused" | "resolver-timeout";
|
|
459
|
+
/** A structured resolution outcome. The value travels only when resolved. */
|
|
460
|
+
type SecretResolution = {
|
|
461
|
+
status: "resolved";
|
|
462
|
+
value: string;
|
|
463
|
+
} | {
|
|
464
|
+
status: SecretResolutionFailure;
|
|
465
|
+
};
|
|
466
|
+
/** Resolves a secret reference. Injected so tests stay offline. */
|
|
467
|
+
type SecretReferenceResolver = (reference: string) => SecretResolution;
|
|
468
|
+
//#endregion
|
|
335
469
|
//#region src/hq-ingest-sink.d.ts
|
|
336
470
|
interface HqIngestDependencies {
|
|
337
471
|
/**
|
|
@@ -344,6 +478,12 @@ interface HqIngestDependencies {
|
|
|
344
478
|
fetch?: typeof fetch;
|
|
345
479
|
now?: () => Date;
|
|
346
480
|
randomUUID?: () => string;
|
|
481
|
+
/**
|
|
482
|
+
* Resolves one `hqIngestCredentials` reference on an operator machine
|
|
483
|
+
* (#1313). Injected so tests stay offline; production asks `op-fast`, then
|
|
484
|
+
* `op`.
|
|
485
|
+
*/
|
|
486
|
+
resolveSecret?: SecretReferenceResolver;
|
|
347
487
|
/**
|
|
348
488
|
* Ceiling for persisting a failure after the transport leg (default
|
|
349
489
|
* `HQ_JOURNAL_FLUSH_BUDGET_MS`). Injectable for the same reason as
|
|
@@ -458,6 +598,12 @@ interface HqSpoolWorkCount {
|
|
|
458
598
|
oldestQueuedAt?: string;
|
|
459
599
|
/** Spooled events waiting in the locations below. */
|
|
460
600
|
pending: number;
|
|
601
|
+
/**
|
|
602
|
+
* How many pending events carry each recorded spool reason (#1317). Present
|
|
603
|
+
* only when the caller asked for `reasons`. An event whose file could not be
|
|
604
|
+
* read or parsed within budget is counted in `pending` and absent here.
|
|
605
|
+
*/
|
|
606
|
+
reasons?: Record<string, number>;
|
|
461
607
|
/** Locations that exist and hold spooled work. */
|
|
462
608
|
spools: string[];
|
|
463
609
|
/**
|
|
@@ -477,7 +623,9 @@ interface HqSpoolWorkCount {
|
|
|
477
623
|
* same locations `flushHqSpool` drains are inspected here, read-only: no
|
|
478
624
|
* directory is created, nothing is secured, and nothing is delivered.
|
|
479
625
|
*/
|
|
480
|
-
declare function countHqSpoolWork(input: Pick<HqSpoolFlushInput, "explicitDirectories" | "repository"
|
|
626
|
+
declare function countHqSpoolWork(input: Pick<HqSpoolFlushInput, "explicitDirectories" | "repository"> & {
|
|
627
|
+
/** Also read each pending event's recorded reason (#1317). */reasons?: boolean;
|
|
628
|
+
}, dependencies?: {
|
|
481
629
|
budgetMs?: number;
|
|
482
630
|
env?: NodeJS.ProcessEnv;
|
|
483
631
|
}): Promise<HqSpoolWorkCount>;
|
|
@@ -1250,58 +1398,6 @@ declare const followUpFromArgv: (argv: string[]) => FollowUpAction;
|
|
|
1250
1398
|
/** Canonical zod schema for the optional follow-up field on JSON outputs. */
|
|
1251
1399
|
declare const FollowUpActionSchema: z.ZodType<FollowUpAction>;
|
|
1252
1400
|
//#endregion
|
|
1253
|
-
//#region src/user-config.d.ts
|
|
1254
|
-
declare const githubAppConfigSchema: z.ZodObject<{
|
|
1255
|
-
appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
1256
|
-
installationId: z.ZodOptional<z.ZodNumber>;
|
|
1257
|
-
privateKeyPath: z.ZodString;
|
|
1258
|
-
}, z.core.$strip>;
|
|
1259
|
-
type GithubAppConfig = z.infer<typeof githubAppConfigSchema>;
|
|
1260
|
-
declare const factoryUserConfigSchema: z.ZodObject<{
|
|
1261
|
-
githubApp: z.ZodOptional<z.ZodObject<{
|
|
1262
|
-
appId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
1263
|
-
installationId: z.ZodOptional<z.ZodNumber>;
|
|
1264
|
-
privateKeyPath: z.ZodString;
|
|
1265
|
-
}, z.core.$strip>>;
|
|
1266
|
-
hqAllowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
1267
|
-
hqIngestCredentials: z.ZodOptional<z.ZodObject<{
|
|
1268
|
-
clientIdRef: z.ZodString;
|
|
1269
|
-
clientSecretRef: z.ZodString;
|
|
1270
|
-
}, z.core.$strip>>;
|
|
1271
|
-
schemaVersion: z.ZodLiteral<2>;
|
|
1272
|
-
}, z.core.$strip>;
|
|
1273
|
-
type FactoryUserConfig = z.infer<typeof factoryUserConfigSchema>;
|
|
1274
|
-
interface LoadUserConfigResult {
|
|
1275
|
-
path: string;
|
|
1276
|
-
config: FactoryUserConfig;
|
|
1277
|
-
ignoredKeys?: string[];
|
|
1278
|
-
}
|
|
1279
|
-
//#endregion
|
|
1280
|
-
//#region src/github-app-access.d.ts
|
|
1281
|
-
interface FactoryAppAccessDependencies {
|
|
1282
|
-
env?: NodeJS.ProcessEnv;
|
|
1283
|
-
existsSync?: (path: string) => boolean;
|
|
1284
|
-
exchangeBroker?: (input: {
|
|
1285
|
-
fetch?: typeof fetch;
|
|
1286
|
-
oidc: string;
|
|
1287
|
-
owner: string;
|
|
1288
|
-
repo: string;
|
|
1289
|
-
timeoutMs?: number;
|
|
1290
|
-
url?: string;
|
|
1291
|
-
}) => Promise<string>;
|
|
1292
|
-
fetch?: typeof fetch;
|
|
1293
|
-
githubApp?: GithubAppConfig;
|
|
1294
|
-
mintCursorOidc?: (input: {
|
|
1295
|
-
audience?: string;
|
|
1296
|
-
socketPath?: string;
|
|
1297
|
-
timeoutMs?: number;
|
|
1298
|
-
}) => Promise<string>;
|
|
1299
|
-
now?: () => number;
|
|
1300
|
-
timeoutMs?: number;
|
|
1301
|
-
token?: string;
|
|
1302
|
-
transportAttempts?: number;
|
|
1303
|
-
}
|
|
1304
|
-
//#endregion
|
|
1305
1401
|
//#region src/pr-verify-mode.d.ts
|
|
1306
1402
|
/**
|
|
1307
1403
|
* The verification mode `pr:verify` resolved for a run.
|
|
@@ -1547,6 +1643,7 @@ type PostCommitStatus = (input: PostCommitStatusInput) => void;
|
|
|
1547
1643
|
//#region src/github-check-runs.d.ts
|
|
1548
1644
|
declare const FACTORY_CHECK_NAMES: {
|
|
1549
1645
|
readonly "pr-ready": "patronage-factory/pr-ready";
|
|
1646
|
+
readonly "pr-review": "patronage-factory/pr-review";
|
|
1550
1647
|
readonly "pr-verify": "patronage-factory/pr-verify";
|
|
1551
1648
|
};
|
|
1552
1649
|
type FactoryCheckGate = keyof typeof FACTORY_CHECK_NAMES;
|
|
@@ -1570,11 +1667,12 @@ interface PublishFactoryCheckInput {
|
|
|
1570
1667
|
}
|
|
1571
1668
|
interface CheckRunDependencies extends FactoryAppAccessDependencies {
|
|
1572
1669
|
postCommitStatus?: PostCommitStatus;
|
|
1573
|
-
resolveDetailsUrl?: (input: PublishFactoryCheckInput) => Promise<string> | string;
|
|
1670
|
+
resolveDetailsUrl?: (input: PublishFactoryCheckInput, signal?: AbortSignal) => Promise<string> | string;
|
|
1574
1671
|
/**
|
|
1575
1672
|
* Bounded retry for the check-run POST. GitHub answers 422 for a head SHA it
|
|
1576
1673
|
* has not seen yet, which is the normal state when `pr:verify` runs before
|
|
1577
|
-
* the branch is pushed, and is also briefly true right after a push.
|
|
1674
|
+
* the branch is pushed, and is also briefly true right after a push. Only
|
|
1675
|
+
* that answer is retried (`isRetryableCheckRunFailure`).
|
|
1578
1676
|
*/
|
|
1579
1677
|
retry?: {
|
|
1580
1678
|
attempts: number;
|
|
@@ -1659,6 +1757,15 @@ declare function fetchPrVerifyProofBinding({
|
|
|
1659
1757
|
sha: string;
|
|
1660
1758
|
runJson?: GhJsonRunner;
|
|
1661
1759
|
}): PrVerifyProofBinding | undefined;
|
|
1760
|
+
/**
|
|
1761
|
+
* Where rules 2 and 4 read from: the App id to trust and the `gh api` runner.
|
|
1762
|
+
* Both default to production (the user config's App id else the pinned one,
|
|
1763
|
+
* and `runGhJson`); tests state them.
|
|
1764
|
+
*/
|
|
1765
|
+
interface ExactHeadRunSource {
|
|
1766
|
+
appId?: () => string;
|
|
1767
|
+
runJson?: GhJsonRunner;
|
|
1768
|
+
}
|
|
1662
1769
|
//#endregion
|
|
1663
1770
|
//#region src/merge-freeze.d.ts
|
|
1664
1771
|
declare const MERGE_FREEZE_CHECK_NAME = "patronage-factory/merge-freeze";
|
|
@@ -2124,6 +2231,8 @@ declare const isSupersededHostedVerifyCheck: (check: StatusCheckRollup, cutoffIs
|
|
|
2124
2231
|
* `gh` is injectable so a test can hand the real read a fake GitHub.
|
|
2125
2232
|
*/
|
|
2126
2233
|
declare const fetchGitHubBranchTipSha: (repository: CheckoutRepository, branch: string, cwd: string, gh?: <T>(args: string[], cwd: string) => T) => string;
|
|
2234
|
+
/** An asynchronous `gh` JSON read. Injected so a test can hand the reads a fake GitHub. */
|
|
2235
|
+
type GhBoundedJsonReader = (args: string[], cwd: string) => Promise<unknown>;
|
|
2127
2236
|
//#endregion
|
|
2128
2237
|
//#region src/github-app-client.d.ts
|
|
2129
2238
|
interface FactoryAppRequest {
|
|
@@ -2499,6 +2608,12 @@ interface ReadFactoryPrStatusSourcesInput {
|
|
|
2499
2608
|
* a completed unsuccessful check run when inventory has no registration.
|
|
2500
2609
|
*/
|
|
2501
2610
|
readonly previewTargets?: readonly string[];
|
|
2611
|
+
/**
|
|
2612
|
+
* Token for the `/pulls/:n` identity read only. Defaults to `token`. On a
|
|
2613
|
+
* Cursor VM `token` is the broker's checks token, which cannot read pulls,
|
|
2614
|
+
* so this is the broker's admission token (#1327).
|
|
2615
|
+
*/
|
|
2616
|
+
readonly pullToken?: string;
|
|
2502
2617
|
readonly repo: string;
|
|
2503
2618
|
/** Factory App installation token, normally minted by the presentation job. */
|
|
2504
2619
|
readonly token: string;
|
|
@@ -2555,8 +2670,19 @@ interface RefreshFactoryPrStatusHudInput {
|
|
|
2555
2670
|
readonly repo: string;
|
|
2556
2671
|
readonly token?: string;
|
|
2557
2672
|
}
|
|
2673
|
+
/**
|
|
2674
|
+
* Where a local HUD refresh gets its credentials. Defaults to the process
|
|
2675
|
+
* environment, the user config, the real broker, and `fetch`.
|
|
2676
|
+
*/
|
|
2677
|
+
interface RefreshFactoryPrStatusHudDependencies {
|
|
2678
|
+
/** The broker's admission token on a Cursor VM, for the pull read (#1327). */
|
|
2679
|
+
readonly admission?: AdmissionCredential;
|
|
2680
|
+
/** The checks-scope broker mint on a Cursor VM, unchanged (#949). */
|
|
2681
|
+
readonly factoryApp?: FactoryAppAccessDependencies;
|
|
2682
|
+
readonly fetch?: typeof fetch;
|
|
2683
|
+
}
|
|
2558
2684
|
/** Plan from the checkout and present the App-owned HUD. */
|
|
2559
|
-
declare function refreshFactoryPrStatusHud(input: RefreshFactoryPrStatusHudInput): Promise<UpsertFactoryPrStatusCommentResult>;
|
|
2685
|
+
declare function refreshFactoryPrStatusHud(input: RefreshFactoryPrStatusHudInput, dependencies?: RefreshFactoryPrStatusHudDependencies): Promise<UpsertFactoryPrStatusCommentResult>;
|
|
2560
2686
|
/**
|
|
2561
2687
|
* Presentation must not fail an admission gate. Used after pr:ready publishes
|
|
2562
2688
|
* its check so the table is not stuck at first-write.
|
|
@@ -2728,19 +2854,34 @@ interface PullRequestArmingFacts {
|
|
|
2728
2854
|
* arm, and its notice says which read failed.
|
|
2729
2855
|
*/
|
|
2730
2856
|
interface ArmingPolicyReads {
|
|
2731
|
-
/**
|
|
2857
|
+
/**
|
|
2858
|
+
* One issue's sub-issue parent, or `null` when it has none. An issue read,
|
|
2859
|
+
* so on a Cursor VM the real one runs on the admission token (#1327).
|
|
2860
|
+
*/
|
|
2732
2861
|
readIssueParent: (input: {
|
|
2733
2862
|
issue: number;
|
|
2734
2863
|
owner: string;
|
|
2735
2864
|
repo: string;
|
|
2736
|
-
}) => IssueParent | null
|
|
2865
|
+
}) => IssueParent | null | Promise<IssueParent | null>;
|
|
2866
|
+
/**
|
|
2867
|
+
* The repository's auto-merge setting and this pull request's labels and
|
|
2868
|
+
* closing issues. The closing issues are issue data, which the VM's own
|
|
2869
|
+
* `gh` credential reads back as none rather than refusing, so on a Cursor
|
|
2870
|
+
* VM the real one also runs on the admission token (#1327).
|
|
2871
|
+
*/
|
|
2737
2872
|
readPullRequest: (input: {
|
|
2738
2873
|
owner: string;
|
|
2739
2874
|
pr: number;
|
|
2740
2875
|
repo: string;
|
|
2741
|
-
}) => PullRequestArmingFacts
|
|
2876
|
+
}) => PullRequestArmingFacts | Promise<PullRequestArmingFacts>;
|
|
2742
2877
|
}
|
|
2743
2878
|
interface PrReadyDependencies {
|
|
2879
|
+
/**
|
|
2880
|
+
* The broker's admission token on a Cursor VM (#1327), for issue reads the
|
|
2881
|
+
* VM's own `gh` credential cannot make. Defaults to the process-wide
|
|
2882
|
+
* credential, which mints nothing off a Cursor managed runtime.
|
|
2883
|
+
*/
|
|
2884
|
+
admission?: AdmissionCredential;
|
|
2744
2885
|
/**
|
|
2745
2886
|
* Arms GitHub native auto-merge for an admitted candidate (#477, #1299).
|
|
2746
2887
|
* Defaults to the real `gh pr merge --auto` call plus the read-back that
|
|
@@ -2759,6 +2900,16 @@ interface PrReadyDependencies {
|
|
|
2759
2900
|
* policy — unreadable authority is never absent authority.
|
|
2760
2901
|
*/
|
|
2761
2902
|
basePolicy?: BaseReviewPolicyAuthority;
|
|
2903
|
+
/**
|
|
2904
|
+
* #1323: where the exact-head rules read GitHub's App runs for `pr-verify`
|
|
2905
|
+
* and `pr-review` at one head. `pr:ready` refuses when any App run of
|
|
2906
|
+
* either gate at the PR head is not a completed pass (rule 4); `pr:publish`,
|
|
2907
|
+
* which inherits this, posts a gate's proof only when its head has no run
|
|
2908
|
+
* for that gate (rule 2). Defaults to the user config's App id, else the
|
|
2909
|
+
* pinned factory App id, and the real `gh api` read, since readiness is a
|
|
2910
|
+
* control and an absent dependency must not mean an unread veto.
|
|
2911
|
+
*/
|
|
2912
|
+
exactHeadRuns?: ExactHeadRunSource;
|
|
2762
2913
|
github?: {
|
|
2763
2914
|
fetchClosingPullRequests?: (input: {
|
|
2764
2915
|
issue: number;
|
|
@@ -3188,6 +3339,11 @@ interface BoundaryCheckArgs {
|
|
|
3188
3339
|
repo?: string;
|
|
3189
3340
|
}
|
|
3190
3341
|
interface BoundaryCheckDependencies {
|
|
3342
|
+
/**
|
|
3343
|
+
* The broker's admission token on a Cursor VM (#1327), for the issue reads.
|
|
3344
|
+
* Read by {@link runBoundaryCheckWithAdmission} only.
|
|
3345
|
+
*/
|
|
3346
|
+
admission?: AdmissionCredential;
|
|
3191
3347
|
github?: BoundaryCheckGithub;
|
|
3192
3348
|
hq?: HqIngestDependencies;
|
|
3193
3349
|
readWaivers?: (cwd: string) => DemandWaiver[];
|
|
@@ -3355,6 +3511,12 @@ interface PrReviewIssueBodyInput {
|
|
|
3355
3511
|
repo: string;
|
|
3356
3512
|
}
|
|
3357
3513
|
interface PrReviewDependencies {
|
|
3514
|
+
/**
|
|
3515
|
+
* The broker's admission token on a Cursor VM (#1327), for the issue reads
|
|
3516
|
+
* `--assemble` makes. Defaults to the process-wide credential, which mints
|
|
3517
|
+
* nothing off a Cursor managed runtime.
|
|
3518
|
+
*/
|
|
3519
|
+
admission?: AdmissionCredential;
|
|
3358
3520
|
/**
|
|
3359
3521
|
* Test-only seam (#1131): runs after the recording has read the proof
|
|
3360
3522
|
* state it is applied to and immediately before the compare-and-swap write,
|
|
@@ -3403,6 +3565,11 @@ interface PrReviewDependencies {
|
|
|
3403
3565
|
* measured against (#1131). Defaults to the GitHub lookup.
|
|
3404
3566
|
*/
|
|
3405
3567
|
lookupPullRequestBase?: (cwd: string) => LivePullRequestBaseLookup;
|
|
3568
|
+
/**
|
|
3569
|
+
* #1323: the detached `patronage-factory/pr-review` publisher, the same one
|
|
3570
|
+
* `pr:verify` uses. Injected by the CLI; absent, no check run is posted.
|
|
3571
|
+
*/
|
|
3572
|
+
publishCheckRun?: (input: PublishFactoryCheckInput) => void;
|
|
3406
3573
|
}
|
|
3407
3574
|
declare function runPrReview(args: PrReviewArgs, dependencies?: PrReviewDependencies): Promise<PrReviewProof>;
|
|
3408
3575
|
//#endregion
|
|
@@ -3554,6 +3721,12 @@ interface PrPublishResult {
|
|
|
3554
3721
|
* it stays an additive change to the published result contract.
|
|
3555
3722
|
*/
|
|
3556
3723
|
verificationReuse?: VerificationReuse;
|
|
3724
|
+
/**
|
|
3725
|
+
* Whether the conclusion-only pr:review check run landed for this head
|
|
3726
|
+
* (#1323). Optional so adding it stays an additive change to the published
|
|
3727
|
+
* result contract.
|
|
3728
|
+
*/
|
|
3729
|
+
reviewProofBinding?: ReviewProofBindingOutcome;
|
|
3557
3730
|
/**
|
|
3558
3731
|
* Whether the durable pr:verify check-run binding landed for this head (#247).
|
|
3559
3732
|
* Always populated from this version on; optional so adding it stays an
|
|
@@ -3568,8 +3741,17 @@ declare class PrPublishFollowUpError extends Error {
|
|
|
3568
3741
|
interface PrPublishDependencies extends PrReadyDependencies {
|
|
3569
3742
|
currentBranch?: (cwd: string) => string | undefined;
|
|
3570
3743
|
/**
|
|
3571
|
-
* Awaited
|
|
3572
|
-
*
|
|
3744
|
+
* Awaited publication of the conclusion-only `pr:review` check run for the
|
|
3745
|
+
* publish head (#1323). Returns whether the App-owned check run landed.
|
|
3746
|
+
* Injected by the CLI like the verify sink. A review cycle publish records
|
|
3747
|
+
* from `--findings` posts through it too, accepted or blocked.
|
|
3748
|
+
*/
|
|
3749
|
+
ensureReviewCheckRun?: typeof ensureFactoryCheckRunPublished;
|
|
3750
|
+
/**
|
|
3751
|
+
* Awaited post of the `pr:verify` check run once the head SHA is on GitHub
|
|
3752
|
+
* (#247), when the head has no run for it yet (#1323). Returns whether the
|
|
3753
|
+
* App-owned check run landed. A `pr:verify` publish runs fresh posts through
|
|
3754
|
+
* it too, pass or failure (#1323).
|
|
3573
3755
|
*/
|
|
3574
3756
|
ensureVerifyCheckRun?: typeof ensureFactoryCheckRunPublished;
|
|
3575
3757
|
factoryCliInvocation?: FactoryCliInvocation;
|
|
@@ -3584,7 +3766,11 @@ interface PrPublishDependencies extends PrReadyDependencies {
|
|
|
3584
3766
|
};
|
|
3585
3767
|
runFollowUp?: FollowUpRunner;
|
|
3586
3768
|
runPrReady?: typeof runPrReady;
|
|
3587
|
-
|
|
3769
|
+
/**
|
|
3770
|
+
* The review producer publish runs for `--findings`. Its second argument
|
|
3771
|
+
* carries the publisher for the verdict it records (#1323).
|
|
3772
|
+
*/
|
|
3773
|
+
runPrReview?: (args: PrReviewArgs, dependencies?: ProducerPublisher) => Promise<PrReviewProof>;
|
|
3588
3774
|
/** Settles asynchronously scheduled sink work before the handoff drain. */
|
|
3589
3775
|
awaitPendingIngest?: () => Promise<void>;
|
|
3590
3776
|
/**
|
|
@@ -3594,7 +3780,11 @@ interface PrPublishDependencies extends PrReadyDependencies {
|
|
|
3594
3780
|
flushHqSpool?: (args: {
|
|
3595
3781
|
cwd: string;
|
|
3596
3782
|
}) => Promise<HqFlushResult>;
|
|
3597
|
-
|
|
3783
|
+
/**
|
|
3784
|
+
* The verify producer publish runs when no proof applies. Its second
|
|
3785
|
+
* argument carries the publisher for the verdict it produces (#1323).
|
|
3786
|
+
*/
|
|
3787
|
+
runPrVerify?: (args: PrVerifyArgs, dependencies?: ProducerPublisher) => Promise<PrVerifyProof>;
|
|
3598
3788
|
/**
|
|
3599
3789
|
* Injectable clock for the promotion instant the hosted-run await measures
|
|
3600
3790
|
* `verify` staleness against (#1045; tests only — production reads the real
|
|
@@ -3612,13 +3802,19 @@ interface PrPublishDependencies extends PrReadyDependencies {
|
|
|
3612
3802
|
* the publish summary: a binding that silently failed to land is
|
|
3613
3803
|
* indistinguishable from verification that never happened, and the operator is
|
|
3614
3804
|
* the only one who can fix the cause (usually an unpushed head).
|
|
3805
|
+
*
|
|
3806
|
+
* #1323 (rule 2): `skipped-existing-run` means the head already has an App run
|
|
3807
|
+
* for the gate, so publish posted nothing; `skipped-unreadable` means GitHub's
|
|
3808
|
+
* runs at the head could not be read whole, so publish posted nothing either.
|
|
3615
3809
|
*/
|
|
3616
3810
|
type VerifyProofBindingOutcome = {
|
|
3617
3811
|
status: "not-attempted";
|
|
3618
3812
|
} | {
|
|
3619
3813
|
headSha: string;
|
|
3620
|
-
status:
|
|
3814
|
+
status: ExactHeadBindingStatus | "skipped-relabelled-head";
|
|
3621
3815
|
};
|
|
3816
|
+
/** What a gate's post at the publish head came to, once rule 2 has read. */
|
|
3817
|
+
type ExactHeadBindingStatus = "failed" | "published" | "skipped-existing-run" | "skipped-unreadable";
|
|
3622
3818
|
/**
|
|
3623
3819
|
* Whether publish reused the on-disk `pr:verify` proof, and the one-line reason
|
|
3624
3820
|
* (#291). Publish decides reuse silently today, which is what made the
|
|
@@ -3629,6 +3825,21 @@ interface VerificationReuse {
|
|
|
3629
3825
|
reason: string;
|
|
3630
3826
|
reused: boolean;
|
|
3631
3827
|
}
|
|
3828
|
+
/** The publisher a producer takes: `pr:verify`'s and `pr:review`'s own seam. */
|
|
3829
|
+
interface ProducerPublisher {
|
|
3830
|
+
publishCheckRun?: (input: PublishFactoryCheckInput) => void;
|
|
3831
|
+
}
|
|
3832
|
+
/**
|
|
3833
|
+
* What became of the conclusion-only `pr:review` check run for this publish
|
|
3834
|
+
* (#1323). A proof that records no review (`not-required`) has no verdict to
|
|
3835
|
+
* post.
|
|
3836
|
+
*/
|
|
3837
|
+
type ReviewProofBindingOutcome = {
|
|
3838
|
+
status: "not-attempted";
|
|
3839
|
+
} | {
|
|
3840
|
+
headSha: string;
|
|
3841
|
+
status: ExactHeadBindingStatus | "skipped-no-review" | "skipped-relabelled-head";
|
|
3842
|
+
};
|
|
3632
3843
|
/**
|
|
3633
3844
|
* Whether publish runs the follow-up `pr:ready` recommended, plus the one-line
|
|
3634
3845
|
* reason either way (#291).
|
|
@@ -4728,6 +4939,112 @@ interface HqSpoolCheckDependencies {
|
|
|
4728
4939
|
countSpool?: typeof countHqSpoolWork;
|
|
4729
4940
|
sweepOrphans?: typeof sweepHqSpoolOrphans;
|
|
4730
4941
|
}
|
|
4942
|
+
/** Test seams. Production never sets these. */
|
|
4943
|
+
interface HqReadinessCheckDependencies {
|
|
4944
|
+
fetch?: typeof fetch;
|
|
4945
|
+
resolveSecret?: SecretReferenceResolver;
|
|
4946
|
+
timeoutMs?: number;
|
|
4947
|
+
}
|
|
4948
|
+
//#endregion
|
|
4949
|
+
//#region src/hq-last-stored.d.ts
|
|
4950
|
+
declare const lastStoredSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4951
|
+
found: z.ZodLiteral<true>;
|
|
4952
|
+
lastFromCaller: z.ZodNullable<z.ZodObject<{
|
|
4953
|
+
anyRepository: z.ZodNullable<z.ZodObject<{
|
|
4954
|
+
receivedAt: z.ZodString;
|
|
4955
|
+
}, z.core.$strip>>;
|
|
4956
|
+
inRepository: z.ZodNullable<z.ZodObject<{
|
|
4957
|
+
receivedAt: z.ZodString;
|
|
4958
|
+
}, z.core.$strip>>;
|
|
4959
|
+
machine: z.ZodString;
|
|
4960
|
+
}, z.core.$strip>>;
|
|
4961
|
+
lastProofEvent: z.ZodNullable<z.ZodObject<{
|
|
4962
|
+
receivedAt: z.ZodString;
|
|
4963
|
+
kind: z.ZodString;
|
|
4964
|
+
observedAt: z.ZodString;
|
|
4965
|
+
}, z.core.$strip>>;
|
|
4966
|
+
lastWebhookEvent: z.ZodNullable<z.ZodObject<{
|
|
4967
|
+
receivedAt: z.ZodString;
|
|
4968
|
+
event: z.ZodString;
|
|
4969
|
+
}, z.core.$strip>>;
|
|
4970
|
+
repository: z.ZodString;
|
|
4971
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
4972
|
+
found: z.ZodLiteral<false>;
|
|
4973
|
+
lastFromCaller: z.ZodNullable<z.ZodObject<{
|
|
4974
|
+
anyRepository: z.ZodNullable<z.ZodObject<{
|
|
4975
|
+
receivedAt: z.ZodString;
|
|
4976
|
+
}, z.core.$strip>>;
|
|
4977
|
+
inRepository: z.ZodNullable<z.ZodObject<{
|
|
4978
|
+
receivedAt: z.ZodString;
|
|
4979
|
+
}, z.core.$strip>>;
|
|
4980
|
+
machine: z.ZodString;
|
|
4981
|
+
}, z.core.$strip>>;
|
|
4982
|
+
repository: z.ZodString;
|
|
4983
|
+
}, z.core.$strip>], "found">;
|
|
4984
|
+
type HqLastStoredAnswer = z.infer<typeof lastStoredSchema>;
|
|
4985
|
+
/**
|
|
4986
|
+
* Why HQ gave no answer. `detail` is the operator-facing sentence; it can name
|
|
4987
|
+
* a reference or a status, never a credential value.
|
|
4988
|
+
*/
|
|
4989
|
+
type HqLastStoredUnknownReason = "no-credentials" | "no-endpoint" | "origin-not-authorized" | "unexpected-response" | "unreachable";
|
|
4990
|
+
type HqLastStored = {
|
|
4991
|
+
answer: HqLastStoredAnswer;
|
|
4992
|
+
status: "answered";
|
|
4993
|
+
} | {
|
|
4994
|
+
detail: string;
|
|
4995
|
+
reason: HqLastStoredUnknownReason;
|
|
4996
|
+
status: "unknown";
|
|
4997
|
+
};
|
|
4998
|
+
interface HqLastStoredInput {
|
|
4999
|
+
/** The profile's `hq.endpoint`, HQ's origin. */
|
|
5000
|
+
endpoint: string;
|
|
5001
|
+
env: NodeJS.ProcessEnv;
|
|
5002
|
+
/** The operator's `hqAllowedOrigins`. */
|
|
5003
|
+
hqAllowedOrigins?: readonly string[];
|
|
5004
|
+
hqIngestCredentials?: HqIngestCredentialReferences;
|
|
5005
|
+
repository: {
|
|
5006
|
+
owner: string;
|
|
5007
|
+
repo: string;
|
|
5008
|
+
};
|
|
5009
|
+
}
|
|
5010
|
+
/** Test seams. Production never sets these. */
|
|
5011
|
+
interface HqLastStoredDependencies {
|
|
5012
|
+
fetch?: typeof fetch;
|
|
5013
|
+
resolveSecret?: SecretReferenceResolver;
|
|
5014
|
+
timeoutMs?: number;
|
|
5015
|
+
}
|
|
5016
|
+
/** Asks HQ when it last stored an event for `repository`. Never throws. */
|
|
5017
|
+
declare function fetchHqLastStored(input: HqLastStoredInput, dependencies?: HqLastStoredDependencies): Promise<HqLastStored>;
|
|
5018
|
+
//#endregion
|
|
5019
|
+
//#region src/doctor-hq-last-stored.d.ts
|
|
5020
|
+
/** Test seams. Production never sets these. */
|
|
5021
|
+
interface HqLastStoredCheckDependencies {
|
|
5022
|
+
countSpool?: typeof countHqSpoolWork;
|
|
5023
|
+
lastStored?: typeof fetchHqLastStored;
|
|
5024
|
+
now?: () => Date;
|
|
5025
|
+
}
|
|
5026
|
+
//#endregion
|
|
5027
|
+
//#region src/doctor-hq-webhook.d.ts
|
|
5028
|
+
/** Test seams. Production never sets these. */
|
|
5029
|
+
interface HqWebhookCheckDependencies {
|
|
5030
|
+
gh?: GhBoundedJsonReader;
|
|
5031
|
+
lastStored?: typeof fetchHqLastStored;
|
|
5032
|
+
now?: () => Date;
|
|
5033
|
+
}
|
|
5034
|
+
//#endregion
|
|
5035
|
+
//#region src/doctor-machine-checks.d.ts
|
|
5036
|
+
/** Test seams. Production never sets these. */
|
|
5037
|
+
interface MachineCheckDependencies {
|
|
5038
|
+
cpuCount?: () => number;
|
|
5039
|
+
/** Whether an executable file with this name is on the PATH in `env`. */
|
|
5040
|
+
isOnPath?: (name: string, env: NodeJS.ProcessEnv) => boolean;
|
|
5041
|
+
nodeVersion?: string;
|
|
5042
|
+
platform?: NodeJS.Platform;
|
|
5043
|
+
/** A small text file's contents, or undefined when it cannot be read. */
|
|
5044
|
+
readText?: (filePath: string) => string | undefined;
|
|
5045
|
+
/** What `/bin/sh` resolves to, or undefined when it cannot be resolved. */
|
|
5046
|
+
resolveShell?: () => string | undefined;
|
|
5047
|
+
}
|
|
4731
5048
|
//#endregion
|
|
4732
5049
|
//#region src/doctor.d.ts
|
|
4733
5050
|
interface DoctorReport {
|
|
@@ -4745,8 +5062,16 @@ interface DoctorProjectProfileInput extends LoadProjectProfileInput {
|
|
|
4745
5062
|
/** Diff base for the admission preflight; ignored unless `preflight`. */
|
|
4746
5063
|
base?: string;
|
|
4747
5064
|
env?: NodeJS.ProcessEnv;
|
|
5065
|
+
/** Test seam for the hq-last-stored row (#1342); production never sets this. */
|
|
5066
|
+
hqLastStoredDependencies?: HqLastStoredCheckDependencies;
|
|
5067
|
+
/** Test seam for the HQ readiness rows (#1315); production never sets this. */
|
|
5068
|
+
hqReadinessDependencies?: HqReadinessCheckDependencies;
|
|
4748
5069
|
/** Test seam for the local HQ spool check (#394); production never sets this. */
|
|
4749
5070
|
hqSpoolDependencies?: HqSpoolCheckDependencies;
|
|
5071
|
+
/** Test seam for the hq-webhook row (#1341); production never sets this. */
|
|
5072
|
+
hqWebhookDependencies?: HqWebhookCheckDependencies;
|
|
5073
|
+
/** Test seam for the machine readiness rows (#1315); production never sets this. */
|
|
5074
|
+
machineDependencies?: MachineCheckDependencies;
|
|
4750
5075
|
/**
|
|
4751
5076
|
* Append the read-only admission checklist (#292): every requirement this
|
|
4752
5077
|
* candidate must satisfy before merge, named in one pass. Preflight checks
|
|
@@ -4880,6 +5205,10 @@ interface EvaluationInput {
|
|
|
4880
5205
|
blockingReasons: string[];
|
|
4881
5206
|
notices: string[];
|
|
4882
5207
|
};
|
|
5208
|
+
exactHeadRunRefusals?: {
|
|
5209
|
+
prReview: string[];
|
|
5210
|
+
prVerify: string[];
|
|
5211
|
+
};
|
|
4883
5212
|
waivers?: DemandWaiver[];
|
|
4884
5213
|
}
|
|
4885
5214
|
declare const evaluateReadiness: (input: EvaluationInput) => {
|
|
@@ -5802,6 +6131,12 @@ declare function createProgram(options?: CreateProgramOptions): Command;
|
|
|
5802
6131
|
* runnable bin module, which follow-up commands spawn; the bin entry passes its
|
|
5803
6132
|
* own path. This function never runs itself — `./cli.js` is the only caller
|
|
5804
6133
|
* that does (#386).
|
|
6134
|
+
*
|
|
6135
|
+
* On the way out it waits for the command's own check-run publications
|
|
6136
|
+
* (bounded, #1322) and HQ emissions, then drains
|
|
6137
|
+
* the checkout's HQ spool once (#1313). This is the one place that drains on
|
|
6138
|
+
* exit. `pr:ready` then prints one line if events are still spooled (#1317).
|
|
6139
|
+
* None of these steps can throw or change the command's exit code.
|
|
5805
6140
|
*/
|
|
5806
6141
|
declare function run(argv?: string[], cliEntry?: string): Promise<void>;
|
|
5807
6142
|
//#endregion
|