vouchington-tooling 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -5
- package/dist/cli/commands/link-skill.d.mts +5 -0
- package/dist/cli/commands/link-skill.mjs +6 -0
- package/dist/cli/index.mjs +3 -0
- package/dist/cli/parse.d.mts +5 -0
- package/dist/cli/parse.mjs +25 -0
- package/dist/cli/usage.d.mts +1 -1
- package/dist/cli/usage.mjs +2 -0
- package/dist/gha-post-review/github.d.mts +2 -0
- package/dist/gha-post-review/github.mjs +47 -5
- package/dist/gha-post-review/post.mjs +6 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -0
- package/dist/pnpm-install/index.d.mts +2 -1
- package/dist/pnpm-install/index.mjs +2 -1
- package/dist/pnpm-install/install-operations.d.mts +4 -0
- package/dist/pnpm-install/install-operations.mjs +38 -0
- package/dist/pnpm-install/metadata-legacy.d.mts +4 -0
- package/dist/pnpm-install/metadata-legacy.mjs +81 -0
- package/dist/pnpm-install/metadata.d.mts +16 -3
- package/dist/pnpm-install/metadata.mjs +103 -36
- package/dist/pnpm-install/pending-builds.d.mts +17 -0
- package/dist/pnpm-install/pending-builds.mjs +87 -0
- package/dist/pnpm-install/pnpm-install-fake-pnpm.test-helpers.d.mts +1 -0
- package/dist/pnpm-install/pnpm-install-fake-pnpm.test-helpers.mjs +52 -0
- package/dist/pnpm-install/pnpm-install-fixture.test-helpers.mjs +6 -40
- package/dist/pnpm-install/runner.mjs +72 -56
- package/dist/pnpm-install/transition.d.mts +23 -0
- package/dist/pnpm-install/transition.mjs +36 -0
- package/dist/skill-discovery/index.d.mts +12 -0
- package/dist/skill-discovery/index.mjs +64 -0
- package/dist/skill-discovery/manifest.d.mts +15 -0
- package/dist/skill-discovery/manifest.mjs +85 -0
- package/dist/skill-discovery/target-directory.d.mts +10 -0
- package/dist/skill-discovery/target-directory.mjs +126 -0
- package/package.json +6 -1
- package/scripts/build.mjs +16 -4
- package/skills/agent-workflow/SKILL.md +5 -0
- package/skills/agent-workflow/references/evidence-sweep.md +8 -0
- package/skills/agent-workflow/references/implementation-and-review.md +9 -0
- package/skills/agent-workflow/references/implementation.md +8 -0
- package/skills/agent-workflow/references/review.md +7 -0
- package/skills/backend-vitest-test-authoring/SKILL.md +15 -0
- package/skills/backend-vitest-test-authoring/references/integration-boundaries.md +10 -0
- package/skills/dotnet-test-authoring/SKILL.md +16 -0
- package/skills/manifest.json +158 -0
- package/skills/nextjs-vitest-test-authoring/SKILL.md +15 -0
- package/skills/nextjs-vitest-test-authoring/references/framework-boundaries.md +9 -0
- package/skills/planning/SKILL.md +3 -0
- package/skills/planning/references/impact-discovery.md +9 -0
- package/skills/playwright-authoring/SKILL.md +15 -0
- package/skills/playwright-authoring/references/browser-reliability.md +9 -0
- package/skills/postgres-node-performance-tuning/SKILL.md +15 -0
- package/skills/postgres-node-performance-tuning/references/performance-patterns.md +14 -0
- package/skills/postgres-partitioning-uuid-v7/SKILL.md +16 -0
- package/skills/postgres-partitioning-uuid-v7/references/partition-lifecycle.md +14 -0
- package/skills/storybook-authoring/SKILL.md +15 -0
- package/skills/storybook-authoring/references/component-coverage.md +9 -0
- package/skills/swift-test-authoring/SKILL.md +15 -0
- package/skills/swift-test-authoring/references/network-test-doubles.md +9 -0
- package/skills/test-authoring/SKILL.md +17 -0
- package/skills/test-authoring/references/core-practice.md +10 -0
- package/skills/vitest-test-authoring/SKILL.md +15 -0
- package/skills/vitest-test-authoring/references/mock-boundaries.md +9 -0
package/README.md
CHANGED
|
@@ -47,6 +47,15 @@ vouchington post-review
|
|
|
47
47
|
vouchington stage-review-payload optional|required <source> <destination>
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
For persistent `pnpm-install`, v4 metadata tracks structural inputs separately from the
|
|
51
|
+
`--install-scripts` policy. A warm scripts-enabled tree can therefore toggle
|
|
52
|
+
`true → false → true` without forced reconciliation; a tree first installed with scripts disabled
|
|
53
|
+
uses one script-suppressed verification install followed by `pnpm rebuild --pending --recursive`.
|
|
54
|
+
When only newly pending dependency package IDs remain, it instead rebuilds those exact IDs without
|
|
55
|
+
rerunning first-party workspace hooks.
|
|
56
|
+
The command emits a structured non-secret provenance diagnostic identifying changed structural
|
|
57
|
+
categories, the last script policy, script capability, and native-binary health.
|
|
58
|
+
|
|
50
59
|
`download-optional-run-artifacts` uses the current Actions run and host. Pattern mode discovers
|
|
51
60
|
non-expired artifacts across the run, keeps the first result for each name (matching `gh run
|
|
52
61
|
download`), and extracts each selected name into its own directory. Ordinary absence is reported as
|
|
@@ -190,8 +199,16 @@ process-group probe and bounded-drain semantics outside a browser session.
|
|
|
190
199
|
|
|
191
200
|
## Workflow skills outside plugins
|
|
192
201
|
|
|
193
|
-
The package ships
|
|
194
|
-
`skills/<skill>/SKILL.md`. This stable installed path supports agents that do not
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
The package ships a flat union of canonical workflow, testing, and database skills at
|
|
203
|
+
`skills/<skill>/SKILL.md`. This stable installed path supports agents that do not load Claude or
|
|
204
|
+
Codex plugins. The package build materializes plugin source trees without hand-copying skill content
|
|
205
|
+
and writes sorted schema-v1 provenance to `skills/manifest.json`.
|
|
206
|
+
Each manifest entry may declare its ordered `prerequisites`; ordinary Markdown links remain
|
|
207
|
+
cross-references and never cause additional skills to be linked.
|
|
208
|
+
|
|
209
|
+
Use `readSkillManifest(skillsRoot)` to discover installed skills or
|
|
210
|
+
`linkSkill({ name, sourceRoot, targetRoot })` to link one into an explicit consumer directory. The
|
|
211
|
+
CLI equivalent is `vouchington link-skill <name> --source-root <skills-dir> --target-root <dir>`.
|
|
212
|
+
It rejects unknown names, paths outside either root, and existing non-matching destinations.
|
|
213
|
+
`targetRoot` must already exist as a physical directory path: symlinked target roots or ancestors are
|
|
214
|
+
rejected.
|
package/dist/cli/index.mjs
CHANGED
|
@@ -15,6 +15,7 @@ import { runStageReviewPayloadCommand } from './commands/stage-review-payload.mj
|
|
|
15
15
|
import { runSwiftSemanticEqualCommand } from './commands/swift-semantic-equal.mjs';
|
|
16
16
|
import { runVitestBlobManifestCommand } from './commands/vitest-blob-manifest.mjs';
|
|
17
17
|
import { runRetrospectiveTranscriptCommand } from './commands/retrospective-transcript.mjs';
|
|
18
|
+
import { runLinkSkill } from './commands/link-skill.mjs';
|
|
18
19
|
import { runWithHostLock } from './commands/with-host-lock.mjs';
|
|
19
20
|
import { parseCli } from './parse.mjs';
|
|
20
21
|
import { packageScriptPath } from './script-path.mjs';
|
|
@@ -99,6 +100,8 @@ export function runCli(argv = process.argv) {
|
|
|
99
100
|
return runGhaArtifactsCleanup(parsed);
|
|
100
101
|
case 'retrospective-transcript':
|
|
101
102
|
return runRetrospectiveTranscriptCommand(parsed.args);
|
|
103
|
+
case 'link-skill':
|
|
104
|
+
return runLinkSkill(parsed);
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
function readInstalledVersion() {
|
package/dist/cli/parse.d.mts
CHANGED
|
@@ -43,6 +43,11 @@ export type ParsedCli = {
|
|
|
43
43
|
} | {
|
|
44
44
|
kind: 'retrospective-transcript';
|
|
45
45
|
args: string[];
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'link-skill';
|
|
48
|
+
name: string;
|
|
49
|
+
sourceRoot: string;
|
|
50
|
+
targetRoot: string;
|
|
46
51
|
} | ParsedGhaRuntimeAudit | ParsedGhaArtifactsCleanup;
|
|
47
52
|
export type ScriptCommand = 'gha-output' | 'gha-needs-results' | 'download-with-diagnostics' | 'download-optional-run-artifacts' | 'host-pressure-diagnostics' | 'allocate-browser-safe-ports' | 'diagnose-port-collision' | 'prepare-trivy-db' | 'check-cache-size' | 'make-shard-matrix' | 'load-runner-env' | 'clean-workspace' | 'install-github-release' | 'run-with-timeout' | 'lint-links' | 'materialize-pr-context' | 'wait-for-apt-locks' | 'install-playwright-chromium-arm64' | 'ghcr-package-retention';
|
|
48
53
|
export declare function parseCli(argv: readonly string[]): ParsedCli;
|
package/dist/cli/parse.mjs
CHANGED
|
@@ -50,6 +50,8 @@ export function parseCli(argv) {
|
|
|
50
50
|
return parseHttpOrigin(rest);
|
|
51
51
|
if (command === 'retrospective-transcript')
|
|
52
52
|
return { kind: 'retrospective-transcript', args: rest };
|
|
53
|
+
if (command === 'link-skill')
|
|
54
|
+
return parseLinkSkill(rest);
|
|
53
55
|
if (command === 'gha-artifacts-cleanup')
|
|
54
56
|
return parseGhaArtifactsCleanup(rest);
|
|
55
57
|
if (command !== undefined && SCRIPT_COMMANDS.has(command)) {
|
|
@@ -57,6 +59,29 @@ export function parseCli(argv) {
|
|
|
57
59
|
}
|
|
58
60
|
return { kind: 'error', message: `unknown command: ${command}` };
|
|
59
61
|
}
|
|
62
|
+
function parseLinkSkill(args) {
|
|
63
|
+
const [name, ...flags] = args;
|
|
64
|
+
if (name === undefined || name.startsWith('-'))
|
|
65
|
+
return { kind: 'error', message: 'link-skill requires a skill name' };
|
|
66
|
+
let sourceRoot;
|
|
67
|
+
let targetRoot;
|
|
68
|
+
for (let index = 0; index < flags.length; index += 1) {
|
|
69
|
+
const flag = flags[index];
|
|
70
|
+
const value = flags[index + 1];
|
|
71
|
+
if (flag !== '--source-root' && flag !== '--target-root')
|
|
72
|
+
return { kind: 'error', message: `unknown link-skill option: ${flag}` };
|
|
73
|
+
if (value === undefined)
|
|
74
|
+
return { kind: 'error', message: `${flag} requires a path` };
|
|
75
|
+
if (flag === '--source-root')
|
|
76
|
+
sourceRoot = value;
|
|
77
|
+
else
|
|
78
|
+
targetRoot = value;
|
|
79
|
+
index += 1;
|
|
80
|
+
}
|
|
81
|
+
if (sourceRoot === undefined || targetRoot === undefined)
|
|
82
|
+
return { kind: 'error', message: 'link-skill requires --source-root and --target-root' };
|
|
83
|
+
return { kind: 'link-skill', name, sourceRoot, targetRoot };
|
|
84
|
+
}
|
|
60
85
|
function parseRunnerPortPolicy(args) {
|
|
61
86
|
let file;
|
|
62
87
|
let reserved;
|
package/dist/cli/usage.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n download-optional-run-artifacts Download optional artifacts from the current run\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\ndownload-optional-run-artifacts (--name <name> | --pattern <pattern>) --dir <directory>\nhost-pressure-diagnostics\nallocate-browser-safe-ports [count] [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--expected-sha256 SHA256] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\nretrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]\n";
|
|
1
|
+
export declare const USAGE = "Usage: vouchington <command> [options]\n\nCommands:\n runner-port-policy Print or validate a runner port policy\n with-host-lock Run a command under a host-wide lock\n gha-runtime-audit Audit successful GitHub Actions job runtimes\n gha-output Write a collision-safe multiline GITHUB_OUTPUT record\n gha-needs-results Fail if required GitHub Actions job results failed\n download-with-diagnostics Download a URL and report HTTP status on failure\n download-optional-run-artifacts Download optional artifacts from the current run\n host-pressure-diagnostics Print a bounded host memory/OOM/PSI snapshot\n allocate-browser-safe-ports Allocate Fetch-safe localhost ports\n diagnose-port-collision Capture bounded localhost port diagnostics\n prepare-trivy-db Download the Trivy vulnerability database\n gha-artifacts-cleanup Delete classified GitHub Actions artifacts\n http-origin Validate an optional HTTP(S) origin\n vitest-blob-manifest Stamp a vitest-blob-manifest:v1 identity file\n pnpm-install Install a pnpm workspace with retry and release-age fail-fast\n check-cache-size Measure a path and decide whether to save a GHA cache\n make-shard-matrix Emit a [1..N] GitHub Actions shard matrix\n load-runner-env Overlay a runner env file onto GITHUB_ENV with injection guards\n clean-workspace Reset a persistent-runner workspace with a fork-PR trust gate\n install-github-release Download a checksum-verified GitHub Release binary\n run-with-timeout Run a command with GNU timeout or a Perl fallback\n lint-links Two-pass lychee: internal links fail, external warn\n materialize-pr-context Dump PR title/body/files/diff/comments and #N crawl\n wait-for-apt-locks Wait until apt/dpkg lock files are free\n install-playwright-chromium-arm64 Install Playwright Chromium from browsers.json\n ghcr-package-retention Delete old GHCR package versions past KEEP_MIN\n nuget-central-version Validate a Directory.Packages.props PackageVersion delta\n swift-semantic-equal Compare Swift sources ignoring comments and whitespace\n post-review Post one COMMENT review from a staged payload file\n stage-review-payload Validate a review payload file into a staging directory\n retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts\n link-skill Link one packaged skill into an explicit consumer directory\n\nOptions:\n -h, --help Show this help\n -v, --version Print the package version\n\nrunner-port-policy\n (no args) Print the shipped policy as JSON\n --file <path> Validate and print a policy file\n --reserved <port> Print true if the port is reserved\n\nwith-host-lock\n --name <family>\n [--slots <n>]\n --timeout-seconds <n>\n [--command-timeout-seconds <n>]\n [--failure-diagnostics <absolute-script>]\n [--on-acquire-timeout fail|run-unlocked]\n -- <command> [args...]\n\ngha-runtime-audit\n [--repository owner/name] Default GITHUB_REPOSITORY\n [--branch main]\n --pr-workflow <name|/regex/> Repeatable\n --push-workflow <name|/regex/> Repeatable\n\ngha-output <name>\ngha-needs-results [label]\ndownload-with-diagnostics <url> <destination> [-- curl-args...]\ndownload-optional-run-artifacts (--name <name> | --pattern <pattern>) --dir <directory>\nhost-pressure-diagnostics\nallocate-browser-safe-ports [count] [--policy path] [--forbidden-ports path]\ndiagnose-port-collision [--ports \"2200 2216\"] [--output-dir PATH]\nprepare-trivy-db\ngha-artifacts-cleanup run --run-id <id> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\ngha-artifacts-cleanup sweep --older-than-hours <n> [--keep-pattern glob] [--delete-pattern glob] [--patterns-file json]\nhttp-origin [--field NAME] [value]\nvitest-blob-manifest <suite> [reports-directory]\npnpm-install --runner-lifecycle persistent|ephemeral|ephemeral-full --install-scripts true|false\ncheck-cache-size <path> <max-bytes> <label>\nmake-shard-matrix <total>\nload-runner-env\nclean-workspace\ninstall-github-release --repo owner/name --version X --asset 'name-{platform}.tar.gz' --bin name [--tag-prefix PREFIX] [--expected-sha256 SHA256] [--no-checksum] [--checksums-asset NAME] [--version-flag FLAG] [--bin-dir DIR]\nrun-with-timeout <timeout-seconds> <kill-after-seconds> <command...>\nlint-links [--offline] [--config PATH] [--glob PATTERN] [files...]\nmaterialize-pr-context\nwait-for-apt-locks\ninstall-playwright-chromium-arm64 [name:archive...]\nghcr-package-retention <url-encoded-package>...\nnuget-central-version <trusted-props> <candidate-props> <metadata-json> <output-props>\nswift-semantic-equal <base> <head> <file.swift>\npost-review\nstage-review-payload optional|required <source> <destination>\nretrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]\nlink-skill <name> --source-root <skills-dir> --target-root <consumer-skills-dir>\n";
|
|
2
2
|
export declare function printUsage(stream?: NodeJS.WritableStream): void;
|
package/dist/cli/usage.mjs
CHANGED
|
@@ -32,6 +32,7 @@ Commands:
|
|
|
32
32
|
post-review Post one COMMENT review from a staged payload file
|
|
33
33
|
stage-review-payload Validate a review payload file into a staging directory
|
|
34
34
|
retrospective-transcript Format facts from Claude-compatible, Codex, or Grok transcripts
|
|
35
|
+
link-skill Link one packaged skill into an explicit consumer directory
|
|
35
36
|
|
|
36
37
|
Options:
|
|
37
38
|
-h, --help Show this help
|
|
@@ -86,6 +87,7 @@ swift-semantic-equal <base> <head> <file.swift>
|
|
|
86
87
|
post-review
|
|
87
88
|
stage-review-payload optional|required <source> <destination>
|
|
88
89
|
retrospective-transcript [--session-id ID] [--jsonl PATH] [--projects-dir PATH] [--codex-sessions-dir PATH] [--grok-sessions-dir PATH]
|
|
90
|
+
link-skill <name> --source-root <skills-dir> --target-root <consumer-skills-dir>
|
|
89
91
|
`;
|
|
90
92
|
export function printUsage(stream = process.stdout) {
|
|
91
93
|
stream.write(USAGE);
|
|
@@ -14,6 +14,8 @@ export declare function createGhPostReviewIo(options: {
|
|
|
14
14
|
payloadBytes: Buffer;
|
|
15
15
|
token: string;
|
|
16
16
|
exec: GhExec;
|
|
17
|
+
expectedHeadSha?: string;
|
|
18
|
+
expectedBaseSha?: string;
|
|
17
19
|
}): PostReviewIo;
|
|
18
20
|
export declare function postReviewFromEnv(env?: NodeJS.ProcessEnv, exec?: GhExec, claudeIo?: import("./claude-token.mts").ClaudeTokenIo): Promise<{
|
|
19
21
|
posted: boolean;
|
|
@@ -33,8 +33,25 @@ export function writePostedOutput(posted, outputPath = process.env.GITHUB_OUTPUT
|
|
|
33
33
|
return;
|
|
34
34
|
appendFileSync(outputPath, `posted=${posted ? 'true' : 'false'}\n`);
|
|
35
35
|
}
|
|
36
|
+
function readPullRefs(repository, prNumber, exec) {
|
|
37
|
+
let lastError;
|
|
38
|
+
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
39
|
+
try {
|
|
40
|
+
return exec([
|
|
41
|
+
'api',
|
|
42
|
+
`repos/${repository}/pulls/${prNumber}`,
|
|
43
|
+
'--jq',
|
|
44
|
+
'[.head.sha, .base.sha] | @tsv',
|
|
45
|
+
]).split('\t');
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
lastError = error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
throw lastError;
|
|
52
|
+
}
|
|
36
53
|
export function createGhPostReviewIo(options) {
|
|
37
|
-
const { repository, prNumber, payloadBytes, token, exec } = options;
|
|
54
|
+
const { repository, prNumber, payloadBytes, token, exec, expectedHeadSha, expectedBaseSha } = options;
|
|
38
55
|
return {
|
|
39
56
|
readFile() {
|
|
40
57
|
return payloadBytes;
|
|
@@ -43,11 +60,34 @@ export function createGhPostReviewIo(options) {
|
|
|
43
60
|
rmSync(path, { force: true });
|
|
44
61
|
},
|
|
45
62
|
getHeadSha() {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
if (!/^[1-9][0-9]*$/u.test(prNumber)) {
|
|
64
|
+
throw new ReviewPayloadError('PR_NUMBER must be a positive integer.');
|
|
65
|
+
}
|
|
66
|
+
if (Boolean(expectedHeadSha) !== Boolean(expectedBaseSha)) {
|
|
67
|
+
throw new ReviewPayloadError('EXPECTED_HEAD_SHA and EXPECTED_BASE_SHA must be provided together.');
|
|
68
|
+
}
|
|
69
|
+
if (expectedHeadSha && !/^[0-9a-f]{40}$/u.test(expectedHeadSha)) {
|
|
70
|
+
throw new ReviewPayloadError('EXPECTED_HEAD_SHA must be a full lowercase commit SHA.');
|
|
71
|
+
}
|
|
72
|
+
if (expectedBaseSha && !/^[0-9a-f]{40}$/u.test(expectedBaseSha)) {
|
|
73
|
+
throw new ReviewPayloadError('EXPECTED_BASE_SHA must be a full lowercase commit SHA.');
|
|
74
|
+
}
|
|
75
|
+
const refs = readPullRefs(repository, prNumber, exec);
|
|
76
|
+
const [headSha = '', baseSha = ''] = refs;
|
|
77
|
+
if (!/^[0-9a-f]{40}$/u.test(headSha)) {
|
|
78
|
+
throw new ReviewPayloadError(`Could not resolve PR head SHA (got "${headSha}").`);
|
|
79
|
+
}
|
|
80
|
+
if (!/^[0-9a-f]{40}$/u.test(baseSha)) {
|
|
81
|
+
throw new ReviewPayloadError(`Could not resolve PR base SHA (got "${baseSha}").`);
|
|
82
|
+
}
|
|
83
|
+
if (expectedHeadSha && headSha !== expectedHeadSha) {
|
|
84
|
+
throw new ReviewPayloadError('PR head changed before posting the selected review.');
|
|
85
|
+
}
|
|
86
|
+
if (expectedBaseSha && baseSha !== expectedBaseSha) {
|
|
87
|
+
throw new ReviewPayloadError('PR base changed before posting the selected review.');
|
|
49
88
|
}
|
|
50
|
-
|
|
89
|
+
// Preserve the orchestrator-selected revision as the review commit_id after equality checks.
|
|
90
|
+
return expectedHeadSha || headSha;
|
|
51
91
|
},
|
|
52
92
|
listPullFiles() {
|
|
53
93
|
return parseReviewFilesJson(exec(['api', '--paginate', `repos/${repository}/pulls/${prNumber}/files?per_page=100`]));
|
|
@@ -69,6 +109,8 @@ export async function postReviewFromEnv(env = process.env, exec = createGhExec()
|
|
|
69
109
|
payloadBytes,
|
|
70
110
|
token,
|
|
71
111
|
exec,
|
|
112
|
+
expectedHeadSha: env.EXPECTED_HEAD_SHA ?? '',
|
|
113
|
+
expectedBaseSha: env.EXPECTED_BASE_SHA ?? '',
|
|
72
114
|
}));
|
|
73
115
|
const token = resolveReviewPostToken(env);
|
|
74
116
|
if (token.source === 'github-token')
|
|
@@ -2,13 +2,18 @@ import { ReviewPayloadError, indexReviewFiles, parseReviewPayload, remapReviewCo
|
|
|
2
2
|
export { MAX_REVIEW_COMMENTS as MAX_COMMENTS, MAX_REVIEW_PAYLOAD_BYTES as MAX_PAYLOAD_BYTES, ReviewPayloadError as PostReviewError, } from '../gha-review-payload/index.mjs';
|
|
3
3
|
export function runPostReview(payloadPath, io) {
|
|
4
4
|
try {
|
|
5
|
-
|
|
5
|
+
const selectedHeadSha = io.getHeadSha();
|
|
6
|
+
let review = parseReviewPayload(io.readFile(payloadPath), selectedHeadSha);
|
|
6
7
|
try {
|
|
7
8
|
review = remapReviewComments(review, indexReviewFiles(io.listPullFiles()));
|
|
8
9
|
}
|
|
9
10
|
catch {
|
|
10
11
|
// Keep the parsed review when the PR file list is unavailable.
|
|
11
12
|
}
|
|
13
|
+
// The adapter also revalidates a pinned base; equality catches legacy live-head drift.
|
|
14
|
+
if (io.getHeadSha() !== selectedHeadSha) {
|
|
15
|
+
throw new ReviewPayloadError('PR head changed while preparing the selected review.');
|
|
16
|
+
}
|
|
12
17
|
const first = io.postReview(review);
|
|
13
18
|
if (first.ok)
|
|
14
19
|
return { posted: true };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { linkSkill, readSkillManifest } from './skill-discovery/index.mts';
|
|
2
|
+
export type { LinkSkillOptions, LinkSkillResult, SkillManifest, SkillManifestEntry, } from './skill-discovery/index.mts';
|
|
1
3
|
export { codexChildren, codexIdentity, computeTranscriptFacts, formatTranscriptFacts, formatUnavailable, resolveTranscriptFile, runRetrospectiveTranscript, } from './retrospective-transcript/index.mts';
|
|
2
4
|
export type { ResolveOptions, TokenTotals, TranscriptFacts, } from './retrospective-transcript/index.mts';
|
|
3
5
|
export { buildSessionFrictionReport, classifyFrictionObservation, FRICTION_LOG_MAX_EVENTS, isConformingCiFailureBlock, normalizeCommandPrefix, readFrictionLog, recordFriction, } from './session-friction/index.mts';
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable max-lines -- package entry point enumerates the supported public API. */
|
|
2
|
+
export { linkSkill, readSkillManifest } from './skill-discovery/index.mjs';
|
|
2
3
|
export { codexChildren, codexIdentity, computeTranscriptFacts, formatTranscriptFacts, formatUnavailable, resolveTranscriptFile, runRetrospectiveTranscript, } from './retrospective-transcript/index.mjs';
|
|
3
4
|
export { buildSessionFrictionReport, classifyFrictionObservation, FRICTION_LOG_MAX_EVENTS, isConformingCiFailureBlock, normalizeCommandPrefix, readFrictionLog, recordFriction, } from './session-friction/index.mjs';
|
|
4
5
|
export { EphemeralListenerAttemptsExhaustedError, isRunnerReservedPort, listenOnRunnerUnreservedEphemeralPort, loadRunnerPortPolicy, runnerPortPolicy, validateRunnerPortPolicy, } from './runner-port-policy/index.mjs';
|
|
@@ -6,4 +6,5 @@ export { formatReleaseAgeFailure, isReleaseAgeViolation, parseReleaseAgeViolatio
|
|
|
6
6
|
export { flattenReleaseAgeSelectors, packageNameFromPnpmLockKey, pnpmLockPackageKeyMatchesSelector, validateReleaseAgeExemptionGroups, validateReleaseAgePolicy, } from './release-age-policy.mts';
|
|
7
7
|
export type { ReleaseAgeExemptionGroup, ReleaseAgePermanentExemption, ReleaseAgePolicyConfig, ReleaseAgePolicySnapshot, } from './release-age-policy.mts';
|
|
8
8
|
export { INSTALL_TERMINATION_FAILED, installExitCode, safeProcessGroup, startInstallHeartbeat, terminateProcessGroup, terminateSafeProcessGroup, } from './process.mts';
|
|
9
|
-
export { persistentDependencyTreeIsCold
|
|
9
|
+
export { persistentDependencyTreeIsCold } from './metadata.mts';
|
|
10
|
+
export { persistentMetadataFingerprint, persistentMetadataMatches, writePersistentMetadataStamp, } from './metadata-legacy.mts';
|
|
@@ -4,4 +4,5 @@ export { baseInstallArgs, findWorkspaceLinkMismatches, listWorkspaces, logWorksp
|
|
|
4
4
|
export { formatReleaseAgeFailure, isReleaseAgeViolation, parseReleaseAgeViolations, } from './release-age.mjs';
|
|
5
5
|
export { flattenReleaseAgeSelectors, packageNameFromPnpmLockKey, pnpmLockPackageKeyMatchesSelector, validateReleaseAgeExemptionGroups, validateReleaseAgePolicy, } from './release-age-policy.mjs';
|
|
6
6
|
export { INSTALL_TERMINATION_FAILED, installExitCode, safeProcessGroup, startInstallHeartbeat, terminateProcessGroup, terminateSafeProcessGroup, } from './process.mjs';
|
|
7
|
-
export { persistentDependencyTreeIsCold
|
|
7
|
+
export { persistentDependencyTreeIsCold } from './metadata.mjs';
|
|
8
|
+
export { persistentMetadataFingerprint, persistentMetadataMatches, writePersistentMetadataStamp, } from './metadata-legacy.mjs';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CommandResult, type InstallOptions } from './support.mts';
|
|
2
|
+
export declare function withScriptPolicy(args: string[], installScripts: boolean): string[];
|
|
3
|
+
export declare function install(args: string[], options: InstallOptions, label: string): Promise<void>;
|
|
4
|
+
export declare function reconcileOrFail(options: InstallOptions, runCapture: (args: string[]) => Promise<CommandResult>): Promise<void>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { scheduler } from 'node:timers/promises';
|
|
2
|
+
import { runPnpm } from './exec.mjs';
|
|
3
|
+
import { INSTALL_TERMINATION_FAILED } from './process.mjs';
|
|
4
|
+
import { formatReleaseAgeFailure, isReleaseAgeViolation } from './release-age.mjs';
|
|
5
|
+
import { baseInstallArgs, findWorkspaceLinkMismatches, logWorkspaceLinkMismatches, } from './support.mjs';
|
|
6
|
+
function fail(message) {
|
|
7
|
+
throw new Error(message);
|
|
8
|
+
}
|
|
9
|
+
export function withScriptPolicy(args, installScripts) {
|
|
10
|
+
return installScripts ? args : [...args, '--ignore-scripts'];
|
|
11
|
+
}
|
|
12
|
+
export async function install(args, options, label) {
|
|
13
|
+
for (let attempt = 1; attempt <= options.maxAttempts; attempt += 1) {
|
|
14
|
+
const result = await runPnpm(args, options);
|
|
15
|
+
if (result.code === 0)
|
|
16
|
+
return;
|
|
17
|
+
if (result.code === INSTALL_TERMINATION_FAILED)
|
|
18
|
+
fail(`${label} could not terminate safely`);
|
|
19
|
+
const output = `${result.output}\n${result.errorOutput ?? ''}`;
|
|
20
|
+
if (isReleaseAgeViolation(output))
|
|
21
|
+
fail(formatReleaseAgeFailure(label, output));
|
|
22
|
+
if (attempt < options.maxAttempts) {
|
|
23
|
+
console.warn(`${label} failed (attempt ${attempt}/${options.maxAttempts}); retrying`);
|
|
24
|
+
await scheduler.wait(5000);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
fail(`${label} failed after ${options.maxAttempts} attempt${options.maxAttempts === 1 ? '' : 's'}`);
|
|
28
|
+
}
|
|
29
|
+
export async function reconcileOrFail(options, runCapture) {
|
|
30
|
+
const forced = ['install', '--frozen-lockfile', '--force', ...baseInstallArgs.slice(2)];
|
|
31
|
+
await install([...forced, '--ignore-scripts', '--ignore-pnpmfile'], options, 'script-free reconciliation');
|
|
32
|
+
await install(withScriptPolicy(forced, options.installScripts), options, 'strict persistent reconciliation');
|
|
33
|
+
const remaining = await findWorkspaceLinkMismatches(runCapture);
|
|
34
|
+
if (remaining.length > 0) {
|
|
35
|
+
logWorkspaceLinkMismatches(remaining);
|
|
36
|
+
fail('persistent reconciliation completed with invalid workspace links');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type CaptureCommand } from './support.mts';
|
|
2
|
+
export declare function persistentMetadataFingerprint(runCapture: CaptureCommand, installScripts: boolean): Promise<string>;
|
|
3
|
+
export declare function persistentMetadataMatches(fingerprint: string): Promise<boolean>;
|
|
4
|
+
export declare function writePersistentMetadataStamp(fingerprint: string): Promise<void>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { listWorkspaces, reportGlibcVersionRuntime } from './support.mjs';
|
|
5
|
+
function persistentMetadataStampPath() {
|
|
6
|
+
return path.join(process.cwd(), 'node_modules', '.pnpm-install-metadata-health.v3.json');
|
|
7
|
+
}
|
|
8
|
+
function legacySharedStampPath() {
|
|
9
|
+
return path.join(process.cwd(), 'node_modules', '.pnpm-install-metadata-health.json');
|
|
10
|
+
}
|
|
11
|
+
function addFingerprintInput(hash, label, value) {
|
|
12
|
+
hash.update(`${label.length}:${label}${value.length}:${value}`);
|
|
13
|
+
}
|
|
14
|
+
async function optionalFile(pathname) {
|
|
15
|
+
try {
|
|
16
|
+
return await readFile(pathname, 'utf8');
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error.code === 'ENOENT')
|
|
20
|
+
return '';
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function runtimePlatformIdentity() {
|
|
25
|
+
const report = process.report?.getReport();
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
arch: process.arch,
|
|
28
|
+
glibc: reportGlibcVersionRuntime(report),
|
|
29
|
+
modules: process.versions.modules,
|
|
30
|
+
node: process.version,
|
|
31
|
+
npmConfigArch: process.env.npm_config_arch ?? '',
|
|
32
|
+
npmConfigLibc: process.env.npm_config_libc ?? '',
|
|
33
|
+
npmConfigPlatform: process.env.npm_config_platform ?? '',
|
|
34
|
+
platform: process.platform,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export async function persistentMetadataFingerprint(runCapture, installScripts) {
|
|
38
|
+
const workspaces = (await listWorkspaces(runCapture)).toSorted((left, right) => left.path.localeCompare(right.path));
|
|
39
|
+
const pnpmVersion = await runCapture(['--version']);
|
|
40
|
+
if (pnpmVersion.code !== 0)
|
|
41
|
+
throw new Error(`pnpm --version failed: ${pnpmVersion.errorOutput?.trim() || pnpmVersion.output.trim() || 'unknown error'}`);
|
|
42
|
+
const hash = createHash('sha256');
|
|
43
|
+
addFingerprintInput(hash, 'runtime', runtimePlatformIdentity());
|
|
44
|
+
addFingerprintInput(hash, 'pnpm', pnpmVersion.output.trim());
|
|
45
|
+
addFingerprintInput(hash, 'installScripts', String(installScripts));
|
|
46
|
+
for (const filename of [
|
|
47
|
+
'pnpm-lock.yaml',
|
|
48
|
+
'pnpm-workspace.yaml',
|
|
49
|
+
'.npmrc',
|
|
50
|
+
'.pnpmfile.cjs',
|
|
51
|
+
'.pnpmfile.mjs',
|
|
52
|
+
])
|
|
53
|
+
addFingerprintInput(hash, filename, await optionalFile(path.join(process.cwd(), filename)));
|
|
54
|
+
for (const workspace of workspaces)
|
|
55
|
+
addFingerprintInput(hash, path.relative(process.cwd(), path.join(workspace.path, 'package.json')), await readFile(path.join(workspace.path, 'package.json'), 'utf8'));
|
|
56
|
+
return hash.digest('hex');
|
|
57
|
+
}
|
|
58
|
+
export async function persistentMetadataMatches(fingerprint) {
|
|
59
|
+
for (const filename of [persistentMetadataStampPath(), legacySharedStampPath()]) {
|
|
60
|
+
try {
|
|
61
|
+
const stamp = JSON.parse(await readFile(filename, 'utf8'));
|
|
62
|
+
if (stamp.version === 3 && stamp.fingerprint === fingerprint)
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch { }
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
export async function writePersistentMetadataStamp(fingerprint) {
|
|
70
|
+
const stampPath = persistentMetadataStampPath();
|
|
71
|
+
const directory = path.dirname(stampPath);
|
|
72
|
+
const temporary = `${stampPath}.${process.pid}.tmp`;
|
|
73
|
+
await mkdir(directory, { recursive: true });
|
|
74
|
+
try {
|
|
75
|
+
await writeFile(temporary, `${JSON.stringify({ fingerprint, version: 3 })}\n`);
|
|
76
|
+
await rename(temporary, stampPath);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await rm(temporary, { force: true });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
import { type CaptureCommand } from './support.mts';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import { type ProvenanceStatus } from './transition.mts';
|
|
3
|
+
declare const componentNames: readonly ['lockfile', 'npm-config', 'pnpm', 'pnpmfiles', 'runtime', 'workspace-config', 'workspace-manifests'];
|
|
4
|
+
type ComponentName = (typeof componentNames)[number];
|
|
5
|
+
type StructuralProvenance = Record<ComponentName, string>;
|
|
6
|
+
export declare function persistentMetadataFingerprintV4(runCapture: CaptureCommand): Promise<{
|
|
7
|
+
lockfile: string;
|
|
8
|
+
'npm-config': string;
|
|
9
|
+
pnpm: string;
|
|
10
|
+
pnpmfiles: string;
|
|
11
|
+
runtime: string;
|
|
12
|
+
'workspace-config': string;
|
|
13
|
+
'workspace-manifests': string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function persistentMetadataStatusV4(provenance: StructuralProvenance): Promise<ProvenanceStatus>;
|
|
16
|
+
export declare function writePersistentMetadataStampV4(provenance: StructuralProvenance, installScripts: boolean, resetScriptsEnabledCapability: boolean, pendingDependencyBuilds?: string[]): Promise<void>;
|
|
4
17
|
export declare function persistentDependencyTreeIsCold(): Promise<boolean>;
|
|
5
|
-
export
|
|
18
|
+
export {};
|