@pareto4/pp-core 1.12.1 → 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +3 -3
- package/README.md +26 -9
- package/agents/pp-code-reviewer.md +3 -2
- package/agents/pp-debug-session-manager.md +9 -6
- package/agents/pp-executor.md +7 -21
- package/agents/pp-plan-checker.md +4 -4
- package/agents/pp-planner.md +23 -9
- package/agents/pp-vault-reviewer.md +274 -0
- package/agents/pp-verifier.md +7 -3
- package/bin/install.js +10 -3
- package/commands/pp-execute-phase.md +1 -3
- package/commands/pp-ns-review.md +2 -1
- package/commands/pp-plan-phase.md +1 -2
- package/commands/pp-vault-review.md +35 -0
- package/commands/pp-verify-work.md +1 -2
- package/gemini-extension.json +1 -1
- package/hooks/dist/pp-check-update.js +0 -0
- package/hooks/dist/pp-cursor-session-start.js +1 -1
- package/hooks/dist/pp-statusline.js +1 -1
- package/hooks/dist/pp-update-banner.js +0 -0
- package/hooks/pp-check-update.js +0 -0
- package/hooks/pp-cursor-session-start.js +1 -1
- package/hooks/pp-statusline.js +1 -1
- package/hooks/pp-update-banner.js +0 -0
- package/package.json +14 -19
- package/pareto-skills/_shared/create-project-board.sh +0 -0
- package/pareto-skills/pp-project-setup/SKILL.md +1 -1
- package/pp-core/bin/check-latest-version.cjs +0 -0
- package/pp-core/bin/detect-build-commands.sh +2 -2
- package/pp-core/bin/lib/capability-activation.cjs +83 -9
- package/pp-core/bin/lib/capability-registry.cjs +526 -22
- package/pp-core/bin/lib/capability-state.cjs +160 -4
- package/pp-core/bin/lib/capability-writer.cjs +19 -5
- package/pp-core/bin/lib/check-command-router.cjs +3867 -274
- package/pp-core/bin/lib/clusters.cjs +4 -0
- package/pp-core/bin/lib/command-aliases.cjs +0 -28
- package/pp-core/bin/lib/commands.cjs +9 -4
- package/pp-core/bin/lib/compose-bindings.cjs +253 -76
- package/pp-core/bin/lib/config-loader.cjs +7 -103
- package/pp-core/bin/lib/config-schema.cjs +1 -1
- package/pp-core/bin/lib/config.cjs +154 -62
- package/pp-core/bin/lib/decisions.cjs +104 -27
- package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
- package/pp-core/bin/lib/frontmatter.cjs +1 -1
- package/pp-core/bin/lib/git-base-branch.cjs +138 -10
- package/pp-core/bin/lib/git-provider.cjs +4 -4
- package/pp-core/bin/lib/init-command-router.cjs +5 -8
- package/pp-core/bin/lib/init-contract.cjs +653 -629
- package/pp-core/bin/lib/init-interactive.cjs +77 -21
- package/pp-core/bin/lib/init.cjs +24 -51
- package/pp-core/bin/lib/install-profiles.cjs +1 -1
- package/pp-core/bin/lib/io.cjs +8 -0
- package/pp-core/bin/lib/loop-resolver.cjs +169 -47
- package/pp-core/bin/lib/org-profile.cjs +544 -53
- package/pp-core/bin/lib/package-identity.cjs +3 -3
- package/pp-core/bin/lib/phase-command-router.cjs +1 -23
- package/pp-core/bin/lib/phase-scope.cjs +1 -1
- package/pp-core/bin/lib/phase.cjs +11 -203
- package/pp-core/bin/lib/platform-bindings.cjs +40 -19
- package/pp-core/bin/lib/practices-review-check.cjs +15 -9
- package/pp-core/bin/lib/profile-output.cjs +1 -1
- package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
- package/pp-core/bin/lib/state.cjs +11 -85
- package/pp-core/bin/lib/template.cjs +1 -1
- package/pp-core/bin/lib/vault-audit.cjs +2594 -0
- package/pp-core/bin/lib/vault-command-router.cjs +2756 -60
- package/pp-core/bin/lib/vault-coordinates.cjs +13 -4
- package/pp-core/bin/lib/vault-index.cjs +699 -0
- package/pp-core/bin/lib/vault-mode.cjs +235 -0
- package/pp-core/bin/lib/vault-practices.cjs +1194 -89
- package/pp-core/bin/lib/vault-review.cjs +2102 -0
- package/pp-core/bin/lib/vault-seal.cjs +1936 -0
- package/pp-core/bin/lib/vault-standards.cjs +1505 -0
- package/pp-core/bin/lib/vault-trace.cjs +3184 -0
- package/pp-core/bin/lib/vault-update.cjs +242 -0
- package/pp-core/bin/lib/vault-write-back.cjs +78 -31
- package/pp-core/bin/lib/vault.cjs +2713 -634
- package/pp-core/bin/lib/verify.cjs +0 -11
- package/pp-core/bin/portable-timeout.sh +1 -1
- package/pp-core/bin/pp-tools.cjs +184 -37
- package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
- package/pp-core/bin/shared/config-schema.manifest.json +0 -3
- package/pp-core/bin/shared/model-catalog.json +1 -0
- package/pp-core/bin/verify-reapply-patches.cjs +0 -0
- package/pp-core/org-profile.json +26 -0
- package/pp-core/references/autonomous-best-effort.md +8 -7
- package/pp-core/references/loop-hook-dispatch.md +0 -14
- package/pp-core/references/planner-gap-closure.md +0 -1
- package/pp-core/references/planner-tdd.md +0 -1
- package/pp-core/references/planner-vault-practices.md +31 -3
- package/pp-core/references/planner-vault-standards.md +320 -0
- package/pp-core/references/planning-config.md +0 -8
- package/pp-core/references/practice-arithmetic-contract.md +121 -0
- package/pp-core/references/tdd.md +0 -1
- package/pp-core/references/verifier-practice-verdicts.md +263 -0
- package/pp-core/templates/README.md +1 -0
- package/pp-core/templates/VAULT-REVIEW.md +202 -0
- package/pp-core/templates/phase-prompt.md +2 -6
- package/pp-core/templates/practices/README.md +137 -11
- package/pp-core/templates/project-charter.md +226 -0
- package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
- package/pp-core/workflows/add-tests.md +55 -0
- package/pp-core/workflows/audit-fix.md +63 -0
- package/pp-core/workflows/audit-milestone.md +1 -1
- package/pp-core/workflows/autonomous.md +85 -11
- package/pp-core/workflows/check-todos.md +13 -2
- package/pp-core/workflows/code-review-fix.md +59 -1
- package/pp-core/workflows/code-review.md +10 -1
- package/pp-core/workflows/complete-milestone.md +1 -1
- package/pp-core/workflows/debug.md +56 -2
- package/pp-core/workflows/discovery-sprint/prefill.md +21 -0
- package/pp-core/workflows/discovery-sprint/prototype.md +46 -48
- package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
- package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
- package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
- package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
- package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
- package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
- package/pp-core/workflows/discovery-sprint/vault-context.md +213 -0
- package/pp-core/workflows/discovery-sprint.md +7 -3
- package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
- package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
- package/pp-core/workflows/discovery-to-build.md +9 -1
- package/pp-core/workflows/discuss-phase.md +3 -10
- package/pp-core/workflows/execute-phase/steps/check-query-gate.md +329 -0
- package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
- package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
- package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +98 -0
- package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
- package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
- package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
- package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +322 -18
- package/pp-core/workflows/execute-phase/steps/verifier-practice-payload.md +165 -0
- package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +163 -0
- package/pp-core/workflows/execute-phase.md +154 -110
- package/pp-core/workflows/execute-plan.md +58 -4
- package/pp-core/workflows/fast.md +53 -0
- package/pp-core/workflows/help/modes/full.md +1 -0
- package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
- package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
- package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
- package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
- package/pp-core/workflows/init.md +232 -272
- package/pp-core/workflows/new-project.md +31 -23
- package/pp-core/workflows/plan-phase.md +99 -43
- package/pp-core/workflows/quick.md +120 -2
- package/pp-core/workflows/secure-phase.md +1 -1
- package/pp-core/workflows/ship.md +57 -24
- package/pp-core/workflows/update.md +3 -3
- package/pp-core/workflows/validate-phase.md +60 -1
- package/pp-core/workflows/vault-review.md +325 -0
- package/pp-core/workflows/verify-work.md +13 -12
- package/scripts/changeset/cli.cjs +6 -5
- package/scripts/changeset/lint.cjs +0 -0
- package/scripts/changeset/new.cjs +33 -50
- package/scripts/dev-env.cjs +25 -85
- package/scripts/gen-capability-registry.cjs +199 -0
- package/scripts/gen-practice-arithmetic-contract.cjs +412 -0
- package/scripts/lib/allowlist-ratchet.cjs +1 -103
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
- package/scripts/lint-docs-required.cjs +0 -0
- package/scripts/lint-pr-check-project-dir.cjs +1 -3
- package/scripts/lint-test-file-count.allowlist.json +13 -2
- package/scripts/practice-arithmetic-contract.allow.json +35 -0
- package/scripts/prompt-injection-scan.sh +22 -15
- package/scripts/record-vault-mode-golden.cjs +89 -0
- package/scripts/release-channel.cjs +0 -0
- package/scripts/sync-manifest-versions.cjs +5 -4
- package/scripts/sync-rulesets.sh +1 -1
- package/scripts/update-size-baseline.cjs +30 -274
- package/scripts/vault-calibrate.cjs +996 -0
- package/scripts/verify-opengsd-sweep.cjs +3 -5
- package/scripts/workflow-size.cjs +9 -61
- package/pp-core/bin/lib/dispatch-plan.cjs +0 -472
- package/pp-core/bin/lib/install-run.cjs +0 -536
- package/pp-core/bin/lib/phase-tier.cjs +0 -467
- package/pp-core/bin/lib/plan-graph.cjs +0 -368
- package/pp-core/references/planner-plan-graph.md +0 -66
- package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
- package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
- package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
- package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -72
- package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -34
- package/scripts/lib/size-budget.cjs +0 -311
- package/scripts/lint-neutrality-names.cjs +0 -694
- package/scripts/lint-org-coordinates.allowlist.json +0 -35
- package/scripts/lint-org-coordinates.cjs +0 -426
|
@@ -1,536 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Install run — the single owner of heavy-tier "measure the installed
|
|
4
|
-
* product" verification (pack 9, item 5).
|
|
5
|
-
*
|
|
6
|
-
* For a pp-core package (a package.json whose `bin` has both `pp-core` and
|
|
7
|
-
* `pp-tools`), `phase.install-run <phase>`:
|
|
8
|
-
*
|
|
9
|
-
* 1. builds (`npm run build`, unless `--no-build`) and packs the package
|
|
10
|
-
* (`npm pack`, whose `prepack` compiles the shipped `.cjs`) — or takes a
|
|
11
|
-
* tarball given with `--tarball`;
|
|
12
|
-
* 2. installs the tarball into a temp npm prefix and runs the installer the
|
|
13
|
-
* user runs (`pp-core --claude --local`) in a temp fixture project, under
|
|
14
|
-
* a temp HOME — reusing the release smoke harness
|
|
15
|
-
* (scripts/release-tarball-smoke.cjs: `runSmoke`, `driveInstaller`);
|
|
16
|
-
* 3. runs init non-interactively through the INSTALLED pp-tools
|
|
17
|
-
* (`query init-contract --session-next/--session-answer`, the documented
|
|
18
|
-
* non-interactive form of `pp-tools init`);
|
|
19
|
-
* 4. runs the phase's install-check commands against the INSTALLED
|
|
20
|
-
* `.claude/pp-core/bin/pp-tools.cjs`, never the repository's;
|
|
21
|
-
* 5. writes `<phase_dir>/<NN>-INSTALL-RUN.json`: tarball name and version,
|
|
22
|
-
* every command with its exit code and truncated stdout/stderr, and a
|
|
23
|
-
* verdict (`pass` / `fail` / `not_applicable`).
|
|
24
|
-
*
|
|
25
|
-
* The install-check commands have ONE owner: the phase's ROADMAP entry, as an
|
|
26
|
-
* `**Install check:**` line of backticked `pp-tools …` commands (the same
|
|
27
|
-
* owner as the `**Tier:**` line). Without the line, `DEFAULT_INSTALL_CHECKS`
|
|
28
|
-
* run.
|
|
29
|
-
*
|
|
30
|
-
* npm runs offline first (`npm_config_offline`, from the caller's npm cache);
|
|
31
|
-
* on a cache miss it retries with `prefer-offline`, which may fetch the
|
|
32
|
-
* package's dependencies — the same network the existing install tests use.
|
|
33
|
-
* The registry is whatever the caller's npm configuration says; nothing here
|
|
34
|
-
* names one.
|
|
35
|
-
*/
|
|
36
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
-
};
|
|
39
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
exports.OUTPUT_LIMIT = exports.INIT_ANSWERS = exports.DEFAULT_INSTALL_CHECKS = exports.INSTALL_RUN_SUFFIX = exports.INSTALL_RUN_SCHEMA = void 0;
|
|
41
|
-
exports.parseInstallCheckField = parseInstallCheckField;
|
|
42
|
-
exports.splitCommandLine = splitCommandLine;
|
|
43
|
-
exports.parseCheckCommand = parseCheckCommand;
|
|
44
|
-
exports.resolveInstallChecks = resolveInstallChecks;
|
|
45
|
-
exports.truncateOutput = truncateOutput;
|
|
46
|
-
exports.computeInstallVerdict = computeInstallVerdict;
|
|
47
|
-
exports.readTarballPackageJson = readTarballPackageJson;
|
|
48
|
-
exports.isPpCorePackage = isPpCorePackage;
|
|
49
|
-
exports.parseInstallRunArgs = parseInstallRunArgs;
|
|
50
|
-
exports.findSmokeHarness = findSmokeHarness;
|
|
51
|
-
exports.buildRunEnv = buildRunEnv;
|
|
52
|
-
exports.runInstallRun = runInstallRun;
|
|
53
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
54
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
55
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
56
|
-
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
57
|
-
const node_zlib_1 = __importDefault(require("node:zlib"));
|
|
58
|
-
const node_child_process_1 = require("node:child_process");
|
|
59
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports -- roadmap-parser.cjs is an export= CommonJS module
|
|
60
|
-
const roadmapParser = require("./roadmap-parser.cjs");
|
|
61
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-locator.cjs is an export= CommonJS module
|
|
62
|
-
const phaseLocator = require("./phase-locator.cjs");
|
|
63
|
-
const { getRoadmapPhaseInternal } = roadmapParser;
|
|
64
|
-
const { findPhaseInternal } = phaseLocator;
|
|
65
|
-
exports.INSTALL_RUN_SCHEMA = 'pp-install-run/1';
|
|
66
|
-
exports.INSTALL_RUN_SUFFIX = 'INSTALL-RUN.json';
|
|
67
|
-
/** Run when the phase's ROADMAP entry has no `**Install check:**` line: the smoke job's surface. */
|
|
68
|
-
exports.DEFAULT_INSTALL_CHECKS = Object.freeze([
|
|
69
|
-
'pp-tools --help',
|
|
70
|
-
'pp-tools query config-get project.slug',
|
|
71
|
-
'pp-tools init phase-op 1',
|
|
72
|
-
'pp-tools progress',
|
|
73
|
-
]);
|
|
74
|
-
/** Fixed answers for the non-interactive init session in the fixture project. */
|
|
75
|
-
exports.INIT_ANSWERS = Object.freeze({
|
|
76
|
-
project_name: 'Install Run Fixture',
|
|
77
|
-
project_slug: 'install-run-fixture',
|
|
78
|
-
client_name: 'internal',
|
|
79
|
-
client_slug: 'internal',
|
|
80
|
-
description: 'Fixture project for the heavy-tier install run',
|
|
81
|
-
org_profile: 'none',
|
|
82
|
-
provider: 'none',
|
|
83
|
-
visibility: 'private',
|
|
84
|
-
});
|
|
85
|
-
exports.OUTPUT_LIMIT = 2000;
|
|
86
|
-
const INIT_MAX_STEPS = 30;
|
|
87
|
-
const COMMAND_TIMEOUT_MS = 120_000;
|
|
88
|
-
const BUILD_TIMEOUT_MS = 600_000;
|
|
89
|
-
const TOOL_NAMES = new Set(['pp-tools', 'pp_run']);
|
|
90
|
-
// ─── Pure parts ──────────────────────────────────────────────────────────────
|
|
91
|
-
const INSTALL_CHECK_RE = /^\*\*Install check(?::\*\*|\*\*:)[^\S\n]*([^\n]*)$/im;
|
|
92
|
-
/** The `**Install check:**` line of a ROADMAP phase section: its backticked commands, or null when absent. */
|
|
93
|
-
function parseInstallCheckField(section) {
|
|
94
|
-
if (!section)
|
|
95
|
-
return null;
|
|
96
|
-
const m = INSTALL_CHECK_RE.exec(section);
|
|
97
|
-
if (!m)
|
|
98
|
-
return null;
|
|
99
|
-
const commands = [...m[1].matchAll(/`([^`]+)`/g)].map((c) => c[1].trim()).filter(Boolean);
|
|
100
|
-
return { line: m[0].trim(), commands };
|
|
101
|
-
}
|
|
102
|
-
/** Split one command line into argv (single and double quotes, backslash escapes); no shell is involved. */
|
|
103
|
-
function splitCommandLine(text) {
|
|
104
|
-
const argv = [];
|
|
105
|
-
let cur = '';
|
|
106
|
-
let inToken = false;
|
|
107
|
-
let quote = null;
|
|
108
|
-
for (let i = 0; i < text.length; i++) {
|
|
109
|
-
const ch = text[i];
|
|
110
|
-
if (quote) {
|
|
111
|
-
if (ch === quote)
|
|
112
|
-
quote = null;
|
|
113
|
-
else if (ch === '\\' && quote === '"' && i + 1 < text.length)
|
|
114
|
-
cur += text[++i];
|
|
115
|
-
else
|
|
116
|
-
cur += ch;
|
|
117
|
-
}
|
|
118
|
-
else if (ch === '"' || ch === "'") {
|
|
119
|
-
quote = ch;
|
|
120
|
-
inToken = true;
|
|
121
|
-
}
|
|
122
|
-
else if (ch === '\\' && i + 1 < text.length) {
|
|
123
|
-
cur += text[++i];
|
|
124
|
-
inToken = true;
|
|
125
|
-
}
|
|
126
|
-
else if (/\s/.test(ch)) {
|
|
127
|
-
if (inToken)
|
|
128
|
-
argv.push(cur);
|
|
129
|
-
cur = '';
|
|
130
|
-
inToken = false;
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
cur += ch;
|
|
134
|
-
inToken = true;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
if (quote)
|
|
138
|
-
return { error: `unterminated ${quote} quote` };
|
|
139
|
-
if (inToken)
|
|
140
|
-
argv.push(cur);
|
|
141
|
-
return argv;
|
|
142
|
-
}
|
|
143
|
-
/** A listed command must start with `pp-tools` (or `pp_run`); the rest is its argv. */
|
|
144
|
-
function parseCheckCommand(text) {
|
|
145
|
-
const split = splitCommandLine(text);
|
|
146
|
-
if (!Array.isArray(split))
|
|
147
|
-
return { text, error: split.error };
|
|
148
|
-
if (split.length === 0 || !TOOL_NAMES.has(split[0])) {
|
|
149
|
-
return { text, error: 'an install check must be a `pp-tools …` command (run against the installed copy)' };
|
|
150
|
-
}
|
|
151
|
-
return { text, argv: split.slice(1) };
|
|
152
|
-
}
|
|
153
|
-
/** The phase's install checks from its ROADMAP section, or the default smoke set. */
|
|
154
|
-
function resolveInstallChecks(section) {
|
|
155
|
-
const field = parseInstallCheckField(section);
|
|
156
|
-
const texts = field ? field.commands : [...exports.DEFAULT_INSTALL_CHECKS];
|
|
157
|
-
const commands = [];
|
|
158
|
-
const invalid = [];
|
|
159
|
-
for (const text of texts) {
|
|
160
|
-
const parsed = parseCheckCommand(text);
|
|
161
|
-
if ('error' in parsed)
|
|
162
|
-
invalid.push(parsed);
|
|
163
|
-
else
|
|
164
|
-
commands.push(parsed);
|
|
165
|
-
}
|
|
166
|
-
if (field && field.commands.length === 0) {
|
|
167
|
-
invalid.push({ text: field.line, error: 'the **Install check:** line lists no backticked commands' });
|
|
168
|
-
}
|
|
169
|
-
return { source: field ? 'roadmap' : 'default', line: field ? field.line : null, commands, invalid };
|
|
170
|
-
}
|
|
171
|
-
/** Keep the head and tail of long output. */
|
|
172
|
-
function truncateOutput(text, limit = exports.OUTPUT_LIMIT) {
|
|
173
|
-
const s = String(text ?? '');
|
|
174
|
-
if (s.length <= limit)
|
|
175
|
-
return s;
|
|
176
|
-
const half = Math.floor(limit / 2);
|
|
177
|
-
return `${s.slice(0, half)}\n… [${s.length - limit} chars truncated] …\n${s.slice(s.length - half)}`;
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* The verdict: `not_applicable` when nothing installable was found; `fail`
|
|
181
|
-
* when any recorded command exited non-zero (or did not run), a listed check
|
|
182
|
-
* was invalid, or init did not finish; `pass` otherwise.
|
|
183
|
-
*/
|
|
184
|
-
function computeInstallVerdict(input) {
|
|
185
|
-
if (!input.applicable) {
|
|
186
|
-
return { verdict: 'not_applicable', reason: input.notApplicableReason || 'nothing installable', failures: [] };
|
|
187
|
-
}
|
|
188
|
-
const failures = input.commands
|
|
189
|
-
.filter((c) => c.exit_code !== 0)
|
|
190
|
-
.map((c) => ({ stage: c.stage, command: c.command, exit_code: c.exit_code, ...(c.error ? { error: c.error } : {}) }));
|
|
191
|
-
for (const bad of input.invalid) {
|
|
192
|
-
failures.push({ stage: 'check', command: bad.text, exit_code: null, error: bad.error });
|
|
193
|
-
}
|
|
194
|
-
if (!input.initDone && !failures.some((f) => f.stage !== 'check')) {
|
|
195
|
-
failures.push({ stage: 'init', command: 'pp-tools init', exit_code: null, error: 'the init session did not finish' });
|
|
196
|
-
}
|
|
197
|
-
if (!input.checksRun && failures.length === 0) {
|
|
198
|
-
failures.push({ stage: 'check', command: '(install checks)', exit_code: null, error: 'the install checks did not run' });
|
|
199
|
-
}
|
|
200
|
-
if (failures.length === 0)
|
|
201
|
-
return { verdict: 'pass', reason: 'every command exited 0 against the installed copy', failures };
|
|
202
|
-
const f = failures[0];
|
|
203
|
-
const how = f.exit_code === null ? (f.error || 'did not run') : `exited ${f.exit_code}`;
|
|
204
|
-
return { verdict: 'fail', reason: `${f.stage}: \`${f.command}\` ${how}`, failures };
|
|
205
|
-
}
|
|
206
|
-
/** `package/package.json` from an npm tarball (gzip + ustar), without a `tar` binary. */
|
|
207
|
-
function readTarballPackageJson(tarballPath) {
|
|
208
|
-
let buf;
|
|
209
|
-
try {
|
|
210
|
-
buf = node_zlib_1.default.gunzipSync(node_fs_1.default.readFileSync(tarballPath));
|
|
211
|
-
}
|
|
212
|
-
catch {
|
|
213
|
-
return null;
|
|
214
|
-
}
|
|
215
|
-
let off = 0;
|
|
216
|
-
let longName = null;
|
|
217
|
-
while (off + 512 <= buf.length) {
|
|
218
|
-
const header = buf.subarray(off, off + 512);
|
|
219
|
-
if (header.every((b) => b === 0))
|
|
220
|
-
break;
|
|
221
|
-
const field = (start, len) => header.subarray(start, start + len).toString('utf8').replace(/\0.*$/s, '');
|
|
222
|
-
const size = parseInt(field(124, 12).trim() || '0', 8) || 0;
|
|
223
|
-
const type = field(156, 1);
|
|
224
|
-
const prefix = field(345, 155);
|
|
225
|
-
const name = longName ?? (prefix ? `${prefix}/${field(0, 100)}` : field(0, 100));
|
|
226
|
-
longName = null;
|
|
227
|
-
const body = buf.subarray(off + 512, off + 512 + size);
|
|
228
|
-
if (type === 'L')
|
|
229
|
-
longName = body.toString('utf8').replace(/\0.*$/s, '');
|
|
230
|
-
else if (type === 'x') {
|
|
231
|
-
const m = /\d+ path=([^\n]*)\n/.exec(body.toString('utf8'));
|
|
232
|
-
if (m)
|
|
233
|
-
longName = m[1];
|
|
234
|
-
}
|
|
235
|
-
else if ((type === '0' || type === '') && name.replace(/^[^/]+\//, '') === 'package.json' && name.split('/').length === 2) {
|
|
236
|
-
try {
|
|
237
|
-
return JSON.parse(body.toString('utf8'));
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
off += 512 + Math.ceil(size / 512) * 512;
|
|
244
|
-
}
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
/** A pp-core package: its package.json `bin` names both `pp-core` (installer) and `pp-tools`. */
|
|
248
|
-
function isPpCorePackage(pkg) {
|
|
249
|
-
const bin = pkg && typeof pkg['bin'] === 'object' && pkg['bin'] !== null ? pkg['bin'] : null;
|
|
250
|
-
return !!bin && typeof bin['pp-core'] === 'string' && typeof bin['pp-tools'] === 'string';
|
|
251
|
-
}
|
|
252
|
-
function parseInstallRunArgs(args) {
|
|
253
|
-
const usage = 'Usage: phase install-run <phase> [--tarball <path.tgz>] [--package-dir <dir>] [--no-build]';
|
|
254
|
-
let phase = null;
|
|
255
|
-
let tarball = null;
|
|
256
|
-
let packageDir = null;
|
|
257
|
-
let build = true;
|
|
258
|
-
for (let i = 0; i < args.length; i++) {
|
|
259
|
-
const a = args[i];
|
|
260
|
-
if (a === '--raw')
|
|
261
|
-
continue;
|
|
262
|
-
if (a === '--no-build')
|
|
263
|
-
build = false;
|
|
264
|
-
else if (a === '--tarball' || a === '--package-dir') {
|
|
265
|
-
const v = args[i + 1];
|
|
266
|
-
if (!v || v.startsWith('--'))
|
|
267
|
-
return { error: `${a} requires a value. ${usage}` };
|
|
268
|
-
if (a === '--tarball')
|
|
269
|
-
tarball = v;
|
|
270
|
-
else
|
|
271
|
-
packageDir = v;
|
|
272
|
-
i++;
|
|
273
|
-
}
|
|
274
|
-
else if (a.startsWith('--'))
|
|
275
|
-
return { error: `phase install-run does not support ${a}. ${usage}` };
|
|
276
|
-
else if (phase === null)
|
|
277
|
-
phase = a;
|
|
278
|
-
else
|
|
279
|
-
return { error: `phase install-run takes one phase. ${usage}` };
|
|
280
|
-
}
|
|
281
|
-
if (phase === null)
|
|
282
|
-
return { error: `phase required for phase install-run. ${usage}` };
|
|
283
|
-
if (tarball && packageDir)
|
|
284
|
-
return { error: `--tarball and --package-dir are exclusive. ${usage}` };
|
|
285
|
-
return { phase, tarball, packageDir, build };
|
|
286
|
-
}
|
|
287
|
-
const HARNESS_REL = node_path_1.default.join('scripts', 'release-tarball-smoke.cjs');
|
|
288
|
-
/** The release smoke harness: the package's own first, then the running copy's. */
|
|
289
|
-
function findSmokeHarness(packageDir) {
|
|
290
|
-
const own = node_path_1.default.resolve(__dirname, '..', '..', '..');
|
|
291
|
-
for (const root of [packageDir, own]) {
|
|
292
|
-
if (!root)
|
|
293
|
-
continue;
|
|
294
|
-
const p = node_path_1.default.join(root, HARNESS_REL);
|
|
295
|
-
if (node_fs_1.default.existsSync(p))
|
|
296
|
-
return p;
|
|
297
|
-
}
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
const npmCmd = () => (process.platform === 'win32' ? 'npm.cmd' : 'npm');
|
|
301
|
-
function npmConfigGet(key, env) {
|
|
302
|
-
const r = (0, node_child_process_1.spawnSync)(npmCmd(), ['config', 'get', key], { encoding: 'utf-8', env, shell: process.platform === 'win32', timeout: 30_000, windowsHide: true });
|
|
303
|
-
const v = r.status === 0 ? String(r.stdout || '').trim() : '';
|
|
304
|
-
return v && v !== 'undefined' && v !== 'null' ? v : null;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* The env every child of the run sees: a temp HOME (and XDG config home), so
|
|
308
|
-
* nothing reads or writes the caller's runtime config dirs; the caller's npm
|
|
309
|
-
* cache and npm user config kept, so npm can install offline and reach the
|
|
310
|
-
* caller's configured registry.
|
|
311
|
-
*/
|
|
312
|
-
function buildRunEnv(base, home) {
|
|
313
|
-
const env = { ...base };
|
|
314
|
-
for (const k of Object.keys(env)) {
|
|
315
|
-
if (k.startsWith('GIT_') || k === 'GSD_TEST_MODE' || k === 'CLAUDE_CONFIG_DIR' || k === 'GSD_WORKSTREAM')
|
|
316
|
-
delete env[k];
|
|
317
|
-
}
|
|
318
|
-
const cache = base.npm_config_cache || npmConfigGet('cache', base);
|
|
319
|
-
if (cache)
|
|
320
|
-
env.npm_config_cache = cache;
|
|
321
|
-
env.npm_config_userconfig = base.npm_config_userconfig || node_path_1.default.join(node_os_1.default.homedir(), '.npmrc');
|
|
322
|
-
env.HOME = home;
|
|
323
|
-
env.USERPROFILE = home;
|
|
324
|
-
env.XDG_CONFIG_HOME = node_path_1.default.join(home, '.config');
|
|
325
|
-
env.npm_config_update_notifier = 'false';
|
|
326
|
-
env.npm_config_audit = 'false';
|
|
327
|
-
env.npm_config_fund = 'false';
|
|
328
|
-
env.npm_config_loglevel = 'error';
|
|
329
|
-
env.NO_UPDATE_NOTIFIER = '1';
|
|
330
|
-
return env;
|
|
331
|
-
}
|
|
332
|
-
const ANSI_RE = new RegExp('\\u001b\\[[0-9;]*[A-Za-z]', 'g');
|
|
333
|
-
/** Drop ANSI colour codes and replace the temp root with `<install-run>`. */
|
|
334
|
-
function scrub(text, root) {
|
|
335
|
-
const s = String(text ?? '').replace(ANSI_RE, '');
|
|
336
|
-
return root ? s.split(root).join('<install-run>') : s;
|
|
337
|
-
}
|
|
338
|
-
function record(out, root, stage, command, res, started) {
|
|
339
|
-
const entry = {
|
|
340
|
-
stage,
|
|
341
|
-
command,
|
|
342
|
-
exit_code: res.status,
|
|
343
|
-
stdout: truncateOutput(scrub(res.stdout ?? '', root)),
|
|
344
|
-
stderr: truncateOutput(scrub(res.stderr ?? '', root)),
|
|
345
|
-
duration_ms: Date.now() - started,
|
|
346
|
-
...(res.error ? { error: scrub(res.error, root) } : {}),
|
|
347
|
-
};
|
|
348
|
-
out.push(entry);
|
|
349
|
-
return entry;
|
|
350
|
-
}
|
|
351
|
-
function spawnRecorded(out, root, stage, command, file, args, opts) {
|
|
352
|
-
const started = Date.now();
|
|
353
|
-
const r = (0, node_child_process_1.spawnSync)(file, args, {
|
|
354
|
-
cwd: opts.cwd, env: opts.env, encoding: 'utf-8', timeout: opts.timeout ?? COMMAND_TIMEOUT_MS,
|
|
355
|
-
stdio: ['pipe', 'pipe', 'pipe'], shell: opts.shell ?? false, windowsHide: true,
|
|
356
|
-
});
|
|
357
|
-
const error = r.error ? String(r.error.message || r.error) : (r.signal ? `terminated by ${r.signal}` : undefined);
|
|
358
|
-
return record(out, root, stage, command, { status: r.status, stdout: r.stdout, stderr: r.stderr, error }, started);
|
|
359
|
-
}
|
|
360
|
-
/** Run the install run for `phase` and write its results file. Throws only on a missing phase. */
|
|
361
|
-
function runInstallRun(opts) {
|
|
362
|
-
const found = findPhaseInternal(opts.cwd, opts.phase);
|
|
363
|
-
if (!found)
|
|
364
|
-
throw new Error(`Phase ${opts.phase} not found`);
|
|
365
|
-
const phaseDirAbs = node_path_1.default.resolve(opts.cwd, found.directory);
|
|
366
|
-
const rp = getRoadmapPhaseInternal(opts.cwd, opts.phase);
|
|
367
|
-
const checks = resolveInstallChecks(rp?.section ?? null);
|
|
368
|
-
const commands = [];
|
|
369
|
-
const result = {
|
|
370
|
-
schema: exports.INSTALL_RUN_SCHEMA,
|
|
371
|
-
phase: found.phase_number,
|
|
372
|
-
phase_dir: found.directory.split(node_path_1.default.sep).join('/'),
|
|
373
|
-
generated_at: new Date().toISOString(),
|
|
374
|
-
verdict: 'fail',
|
|
375
|
-
reason: '',
|
|
376
|
-
package: { name: null, version: null, tarball: null, source: null },
|
|
377
|
-
install: { runtime: 'claude', scope: 'local', npm_mode: null, tools: null },
|
|
378
|
-
checks: { source: checks.source, line: checks.line, invalid: checks.invalid },
|
|
379
|
-
commands,
|
|
380
|
-
failures: [],
|
|
381
|
-
};
|
|
382
|
-
const root = node_path_1.default.join(node_os_1.default.tmpdir(), `pp-install-run-${node_crypto_1.default.randomUUID()}`);
|
|
383
|
-
let applicable = true;
|
|
384
|
-
let notApplicableReason = '';
|
|
385
|
-
let initDone = false;
|
|
386
|
-
let checksRun = false;
|
|
387
|
-
try {
|
|
388
|
-
node_fs_1.default.mkdirSync(root, { recursive: true });
|
|
389
|
-
const home = node_path_1.default.join(root, 'home');
|
|
390
|
-
const prefix = node_path_1.default.join(root, 'prefix');
|
|
391
|
-
const fixture = node_path_1.default.join(root, 'fixture');
|
|
392
|
-
for (const d of [home, prefix, fixture, node_path_1.default.join(root, 'pack')])
|
|
393
|
-
node_fs_1.default.mkdirSync(d, { recursive: true });
|
|
394
|
-
const env = buildRunEnv(opts.env ?? process.env, home);
|
|
395
|
-
const winShell = process.platform === 'win32';
|
|
396
|
-
// 1. The tarball: given, or built and packed from the package dir.
|
|
397
|
-
let tarballPath = null;
|
|
398
|
-
const packageDir = opts.tarball ? null : node_path_1.default.resolve(opts.cwd, opts.packageDir || '.');
|
|
399
|
-
if (opts.tarball) {
|
|
400
|
-
tarballPath = node_path_1.default.resolve(opts.cwd, opts.tarball);
|
|
401
|
-
result.package.source = 'tarball';
|
|
402
|
-
if (!node_fs_1.default.existsSync(tarballPath)) {
|
|
403
|
-
record(commands, root, 'pack', `(tarball) ${opts.tarball}`, { status: null, error: 'tarball not found' }, Date.now());
|
|
404
|
-
tarballPath = null;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
else if (packageDir) {
|
|
408
|
-
let pkg = null;
|
|
409
|
-
try {
|
|
410
|
-
pkg = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(packageDir, 'package.json'), 'utf-8'));
|
|
411
|
-
}
|
|
412
|
-
catch { /* no package.json */ }
|
|
413
|
-
if (!isPpCorePackage(pkg)) {
|
|
414
|
-
applicable = false;
|
|
415
|
-
notApplicableReason = 'the package dir is not a pp-core package (package.json bin lacks pp-core and pp-tools); nothing to install';
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
result.package.source = 'pack';
|
|
419
|
-
const built = opts.build === false ? null
|
|
420
|
-
: spawnRecorded(commands, root, 'build', 'npm run build', npmCmd(), ['run', 'build'], { cwd: packageDir, env, timeout: BUILD_TIMEOUT_MS, shell: winShell });
|
|
421
|
-
if (!built || built.exit_code === 0) {
|
|
422
|
-
const packed = spawnRecorded(commands, root, 'pack', 'npm pack', npmCmd(), ['pack', '--pack-destination', node_path_1.default.join(root, 'pack')], { cwd: packageDir, env, timeout: BUILD_TIMEOUT_MS, shell: winShell });
|
|
423
|
-
const tgz = node_fs_1.default.readdirSync(node_path_1.default.join(root, 'pack')).find((f) => f.endsWith('.tgz'));
|
|
424
|
-
if (packed.exit_code === 0 && tgz)
|
|
425
|
-
tarballPath = node_path_1.default.join(root, 'pack', tgz);
|
|
426
|
-
else if (packed.exit_code === 0) {
|
|
427
|
-
packed.exit_code = 1;
|
|
428
|
-
packed.error = 'npm pack produced no .tgz';
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
const harnessPath = applicable ? findSmokeHarness(packageDir) : null;
|
|
434
|
-
if (applicable && !harnessPath) {
|
|
435
|
-
applicable = false;
|
|
436
|
-
notApplicableReason = `no install harness (${HARNESS_REL.split(node_path_1.default.sep).join('/')}) in the package or the running pp-core`;
|
|
437
|
-
}
|
|
438
|
-
if (applicable && tarballPath) {
|
|
439
|
-
const meta = readTarballPackageJson(tarballPath);
|
|
440
|
-
result.package.tarball = node_path_1.default.basename(tarballPath);
|
|
441
|
-
result.package.name = meta && typeof meta['name'] === 'string' ? meta['name'] : null;
|
|
442
|
-
result.package.version = meta && typeof meta['version'] === 'string' ? meta['version'] : null;
|
|
443
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports -- the harness path is resolved at run time
|
|
444
|
-
const harness = require(harnessPath);
|
|
445
|
-
// 2. npm install into a temp prefix: offline first, then prefer-offline on a cache miss.
|
|
446
|
-
const installStarted = Date.now();
|
|
447
|
-
const smoke = (mode) => harness.runSmoke({
|
|
448
|
-
tarballPath, installPrefix: prefix, expectedVersion: result.package.version ?? '', lifecycleCommands: [],
|
|
449
|
-
npmEnv: { ...env, ...(mode === 'offline' ? { npm_config_offline: 'true' } : { npm_config_prefer_offline: 'true' }) },
|
|
450
|
-
});
|
|
451
|
-
let mode = 'offline';
|
|
452
|
-
let s = smoke(mode);
|
|
453
|
-
const detail = (key) => { const v = s.details[key]; return typeof v === 'string' ? v : ''; };
|
|
454
|
-
if (s.code === harness.SMOKE.INSTALL_FAILED && /ENOTCACHED/.test(detail('stderr'))) {
|
|
455
|
-
mode = 'prefer-offline';
|
|
456
|
-
s = smoke(mode);
|
|
457
|
-
}
|
|
458
|
-
result.install.npm_mode = mode;
|
|
459
|
-
const installCmd = `npm install -g --prefix <install-run>/prefix ${result.package.tarball} --${mode}`;
|
|
460
|
-
const installed = record(commands, root, 'install', installCmd, {
|
|
461
|
-
status: s.code === harness.SMOKE.OK ? 0 : 1,
|
|
462
|
-
stdout: detail('stdout'),
|
|
463
|
-
stderr: detail('stderr'),
|
|
464
|
-
error: s.code === harness.SMOKE.OK ? undefined : `harness code ${s.code}`,
|
|
465
|
-
}, installStarted);
|
|
466
|
-
// 3. The installer the user runs, in a fresh git project. The global npm
|
|
467
|
-
// prefix is the temp prefix: the installed product sees only itself
|
|
468
|
-
// installed globally, as on a fresh machine.
|
|
469
|
-
const toolEnv = { ...env, npm_config_prefix: prefix };
|
|
470
|
-
delete toolEnv.NPM_CONFIG_PREFIX;
|
|
471
|
-
if (installed.exit_code === 0) {
|
|
472
|
-
(0, node_child_process_1.spawnSync)('git', ['init', '-q'], { cwd: fixture, env, encoding: 'utf-8', timeout: COMMAND_TIMEOUT_MS, windowsHide: true });
|
|
473
|
-
const instStarted = Date.now();
|
|
474
|
-
const inst = harness.driveInstaller({
|
|
475
|
-
installPrefix: prefix, flags: ['--claude', '--local'], cwd: fixture, configRoot: node_path_1.default.join(fixture, '.claude'), env: toolEnv,
|
|
476
|
-
});
|
|
477
|
-
const tools = node_path_1.default.join(fixture, '.claude', 'pp-core', 'bin', 'pp-tools.cjs');
|
|
478
|
-
const toolsMissing = inst.ok && !node_fs_1.default.existsSync(tools);
|
|
479
|
-
record(commands, root, 'install', 'pp-core --claude --local', {
|
|
480
|
-
status: toolsMissing ? 1 : inst.status, stdout: inst.stdout, stderr: inst.stderr,
|
|
481
|
-
error: inst.reason || (toolsMissing ? 'the installer exited 0 but .claude/pp-core/bin/pp-tools.cjs is missing' : undefined),
|
|
482
|
-
}, instStarted);
|
|
483
|
-
if (inst.ok && !toolsMissing) {
|
|
484
|
-
result.install.tools = '.claude/pp-core/bin/pp-tools.cjs';
|
|
485
|
-
const runTool = (stage, label, argv) => spawnRecorded(commands, root, stage, label, process.execPath, [tools, ...argv], { cwd: fixture, env: toolEnv });
|
|
486
|
-
// 4. init, non-interactively, through the installed pp-tools.
|
|
487
|
-
for (let i = 0; i < INIT_MAX_STEPS && !initDone; i++) {
|
|
488
|
-
const next = runTool('init', 'pp-tools query init-contract --session-next --offline', ['query', 'init-contract', '--session-next', '--offline']);
|
|
489
|
-
if (next.exit_code !== 0)
|
|
490
|
-
break;
|
|
491
|
-
let state;
|
|
492
|
-
try {
|
|
493
|
-
state = JSON.parse(next.stdout);
|
|
494
|
-
}
|
|
495
|
-
catch {
|
|
496
|
-
next.exit_code = 1;
|
|
497
|
-
next.error = 'unparseable init session state';
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
if (state.done) {
|
|
501
|
-
initDone = true;
|
|
502
|
-
break;
|
|
503
|
-
}
|
|
504
|
-
const step = String(state.step ?? '');
|
|
505
|
-
const answer = exports.INIT_ANSWERS[step] ?? state.preselected ?? (state.optionalAnswer ? '' : undefined);
|
|
506
|
-
if (answer === undefined) {
|
|
507
|
-
next.exit_code = 1;
|
|
508
|
-
next.error = `no fixture answer for init step "${step}"`;
|
|
509
|
-
break;
|
|
510
|
-
}
|
|
511
|
-
const ans = runTool('init', `pp-tools query init-contract --session-answer ${step}=… --offline`, ['query', 'init-contract', '--session-answer', `${step}=${answer}`, '--offline']);
|
|
512
|
-
if (ans.exit_code !== 0)
|
|
513
|
-
break;
|
|
514
|
-
}
|
|
515
|
-
// 5. The phase's install checks against the installed copy.
|
|
516
|
-
for (const check of checks.commands)
|
|
517
|
-
runTool('check', check.text, check.argv);
|
|
518
|
-
checksRun = true;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
finally {
|
|
524
|
-
try {
|
|
525
|
-
node_fs_1.default.rmSync(root, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
|
|
526
|
-
}
|
|
527
|
-
catch { /* best-effort */ }
|
|
528
|
-
}
|
|
529
|
-
const v = computeInstallVerdict({ applicable, notApplicableReason, commands, invalid: checks.invalid, initDone, checksRun });
|
|
530
|
-
result.verdict = v.verdict;
|
|
531
|
-
result.reason = v.reason;
|
|
532
|
-
result.failures = v.failures;
|
|
533
|
-
const resultsFile = node_path_1.default.join(phaseDirAbs, `${found.phase_number}-${exports.INSTALL_RUN_SUFFIX}`);
|
|
534
|
-
node_fs_1.default.writeFileSync(resultsFile, JSON.stringify(result, null, 2) + '\n');
|
|
535
|
-
return { ...result, results_file: node_path_1.default.relative(opts.cwd, resultsFile).split(node_path_1.default.sep).join('/') };
|
|
536
|
-
}
|