@pareto4/pp-core 1.13.0 → 1.18.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/.claude-plugin/plugin.json +3 -3
- package/README.md +31 -12
- package/agents/pp-code-fixer.md +0 -11
- package/agents/pp-code-reviewer.md +1 -77
- package/agents/pp-debug-session-manager.md +9 -6
- package/agents/pp-executor.md +12 -29
- package/agents/pp-plan-checker.md +4 -4
- package/agents/pp-planner.md +34 -20
- package/agents/pp-vault-reviewer.md +100 -23
- package/agents/pp-verifier.md +1 -3
- package/bin/install.js +10 -3
- package/commands/pp-execute-phase.md +1 -3
- package/commands/pp-ns-manage.md +1 -1
- package/commands/pp-ns-review.md +1 -1
- package/commands/pp-plan-phase.md +1 -2
- package/commands/pp-vault-promote.md +7 -8
- package/commands/pp-vault-review.md +6 -5
- 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 +10 -18
- 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 +201 -229
- package/pp-core/bin/lib/capability-state.cjs +93 -1
- package/pp-core/bin/lib/capability-writer.cjs +3 -3
- package/pp-core/bin/lib/check-command-router.cjs +1906 -1514
- package/pp-core/bin/lib/clusters.cjs +3 -0
- package/pp-core/bin/lib/command-aliases.cjs +0 -35
- package/pp-core/bin/lib/commands.cjs +9 -4
- package/pp-core/bin/lib/compose-bindings.cjs +251 -88
- 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 +151 -62
- package/pp-core/bin/lib/decisions.cjs +4 -4
- package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
- package/pp-core/bin/lib/frontmatter.cjs +1 -38
- package/pp-core/bin/lib/git-base-branch.cjs +11 -12
- package/pp-core/bin/lib/git-provider.cjs +9 -10
- package/pp-core/bin/lib/init-command-router.cjs +5 -8
- package/pp-core/bin/lib/init-contract.cjs +620 -738
- package/pp-core/bin/lib/init-interactive.cjs +62 -4
- 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 +4 -2
- package/pp-core/bin/lib/loop-resolver.cjs +165 -129
- package/pp-core/bin/lib/org-profile.cjs +402 -161
- package/pp-core/bin/lib/package-identity.cjs +3 -3
- package/pp-core/bin/lib/phase-command-router.cjs +1 -29
- package/pp-core/bin/lib/phase-scope.cjs +1 -1
- package/pp-core/bin/lib/phase.cjs +11 -253
- package/pp-core/bin/lib/platform-bindings.cjs +40 -19
- 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-command-router.cjs +1682 -477
- package/pp-core/bin/lib/vault-coordinates.cjs +16 -7
- package/pp-core/bin/lib/vault-index.cjs +656 -0
- package/pp-core/bin/lib/vault-seal.cjs +1851 -0
- package/pp-core/bin/lib/vault-standards-promote.cjs +577 -0
- package/pp-core/bin/lib/vault-standards-review.cjs +293 -0
- package/pp-core/bin/lib/vault-standards.cjs +1504 -0
- package/pp-core/bin/lib/vault-trace.cjs +155 -2778
- package/pp-core/bin/lib/vault-update.cjs +10 -59
- package/pp-core/bin/lib/vault.cjs +2570 -950
- 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 +157 -54
- 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 +2 -2
- 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 -25
- 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-standards.md +311 -0
- package/pp-core/references/planning-config.md +0 -8
- package/pp-core/references/tdd.md +0 -1
- package/pp-core/templates/README.md +1 -0
- package/pp-core/templates/VAULT-REVIEW.md +56 -0
- package/pp-core/templates/phase-prompt.md +2 -6
- package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
- package/pp-core/workflows/add-tests.md +55 -4
- package/pp-core/workflows/audit-fix.md +63 -2
- 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 -3
- package/pp-core/workflows/code-review.md +10 -57
- package/pp-core/workflows/complete-milestone.md +1 -1
- package/pp-core/workflows/debug.md +54 -4
- package/pp-core/workflows/discovery-sprint/prefill.md +19 -7
- package/pp-core/workflows/discovery-sprint/prototype.md +46 -49
- 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 +207 -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 +10 -2
- package/pp-core/workflows/discuss-phase.md +3 -10
- package/pp-core/workflows/execute-phase/steps/check-query-gate.md +327 -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 +78 -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 +219 -20
- package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +147 -0
- package/pp-core/workflows/execute-phase.md +152 -128
- package/pp-core/workflows/execute-plan.md +54 -6
- package/pp-core/workflows/fast.md +53 -4
- package/pp-core/workflows/help/modes/full.md +3 -3
- 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 +98 -45
- package/pp-core/workflows/quick.md +117 -3
- package/pp-core/workflows/secure-phase.md +1 -1
- package/pp-core/workflows/ship.md +57 -28
- package/pp-core/workflows/undo.md +1 -1
- package/pp-core/workflows/update.md +3 -3
- package/pp-core/workflows/validate-phase.md +58 -3
- package/pp-core/workflows/vault-review.md +161 -23
- package/pp-core/workflows/vault-write-back.md +73 -110
- package/pp-core/workflows/verify-work.md +12 -14
- 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 +120 -13
- 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 +3 -19
- package/scripts/lint-test-file-count.cjs +5 -6
- package/scripts/prompt-injection-scan.sh +19 -17
- 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/verify-opengsd-sweep.cjs +3 -5
- package/scripts/workflow-size.cjs +9 -61
- package/pp-core/bin/lib/dispatch-plan.cjs +0 -483
- package/pp-core/bin/lib/install-run.cjs +0 -536
- package/pp-core/bin/lib/loop-gates.cjs +0 -213
- package/pp-core/bin/lib/phase-manifest.cjs +0 -527
- package/pp-core/bin/lib/phase-tier.cjs +0 -480
- package/pp-core/bin/lib/plan-graph.cjs +0 -368
- package/pp-core/bin/lib/practices-review-check.cjs +0 -938
- package/pp-core/bin/lib/vault-audit.cjs +0 -2070
- package/pp-core/bin/lib/vault-practices.cjs +0 -1990
- package/pp-core/bin/lib/vault-review.cjs +0 -2359
- package/pp-core/bin/lib/vault-write-back.cjs +0 -877
- package/pp-core/references/executor-vault-trace.md +0 -47
- package/pp-core/references/planner-plan-graph.md +0 -66
- package/pp-core/references/planner-vault-practices.md +0 -112
- package/pp-core/templates/practices/README.md +0 -251
- package/pp-core/templates/practices/error-handling.md +0 -18
- package/pp-core/templates/practices/minimal-comments.md +0 -14
- package/pp-core/templates/practices/naming-convention.md +0 -18
- package/pp-core/templates/practices/practice-template.md +0 -23
- package/pp-core/workflows/discovery-sprint/vault-fetch.md +0 -37
- 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 -73
- package/pp-core/workflows/execute-phase/steps/vault-door-gate.md +0 -19
- package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -43
- 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
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
const packageName = "@pareto4/pp-core";
|
|
7
7
|
const binName = "pp-core";
|
|
8
|
-
const repoSlug = "
|
|
9
|
-
const repoUrl = "https://
|
|
10
|
-
const changelogRawUrl = "https://
|
|
8
|
+
const repoSlug = "pareto000/pp-core";
|
|
9
|
+
const repoUrl = "https://github.com/pareto000/pp-core";
|
|
10
|
+
const changelogRawUrl = "https://raw.githubusercontent.com/pareto000/pp-core/main/CHANGELOG.md";
|
|
11
11
|
const cacheSlug = "pareto4-pp-core";
|
|
12
12
|
const updateCacheFileName = "pp-update-check-pareto4-pp-core.json";
|
|
13
13
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Unsupported in this router:
|
|
7
7
|
* - scaffold: routed through top-level scaffold command.
|
|
8
8
|
*
|
|
9
|
-
* CJS-only subcommands: mvp-mode
|
|
9
|
+
* CJS-only subcommands: mvp-mode (dispatched directly, before hub).
|
|
10
10
|
*
|
|
11
11
|
* #3788: dispatch is mediated by CommandRoutingHub. The public entry point
|
|
12
12
|
* and observable CLI behaviour are unchanged.
|
|
@@ -51,34 +51,6 @@ function routePhaseCommand({ phase, args, cwd, raw, error }) {
|
|
|
51
51
|
phase.cmdPhaseMvpMode(cwd, args.slice(2), raw);
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
// `dispatch-plan` (pack 9): read-only; the executor spawns, suite runs and
|
|
55
|
-
// tracking commits execute-phase obeys (src/dispatch-plan.cts).
|
|
56
|
-
if (subcommand === 'dispatch-plan') {
|
|
57
|
-
phase.cmdPhaseDispatchPlan(cwd, args.slice(2), raw);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
// `install-run` (pack 9): heavy-tier verification of the installed product —
|
|
61
|
-
// pack, install, init, run the phase's install checks (src/install-run.cts).
|
|
62
|
-
if (subcommand === 'install-run') {
|
|
63
|
-
phase.cmdPhaseInstallRun(cwd, args.slice(2), raw);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
// `tier` / `tier-propose` (pack 9): the phase's ceremony tier and its
|
|
67
|
-
// proposal (src/phase-tier.cts); `tier-propose --record` writes ROADMAP.
|
|
68
|
-
if (subcommand === 'tier') {
|
|
69
|
-
phase.cmdPhaseTier(cwd, args.slice(2), raw);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (subcommand === 'tier-propose') {
|
|
73
|
-
phase.cmdPhaseTierPropose(cwd, args.slice(2), raw);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
// `manifest start|record` (pack 10): write `.phase-manifest.json`, which
|
|
77
|
-
// `/pp-undo --phase` reads (src/phase-manifest.cts).
|
|
78
|
-
if (subcommand === 'manifest') {
|
|
79
|
-
phase.cmdPhaseManifest(cwd, args.slice(2), raw);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
54
|
// ── Build the CJS registry ──────────────────────────────────────────────────
|
|
83
55
|
// Each handler receives a ctx object from the hub and must return a HubResult.
|
|
84
56
|
const cjsRegistry = {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* this caller use it?
|
|
5
5
|
*
|
|
6
6
|
* THE owner of that decision for every consumer of the raw phase locator
|
|
7
|
-
|
|
7
|
+
* (PBI 75323, quick 261009-gvf). The raw locator in phase-locator.cts answers a
|
|
8
8
|
* phase token from the live `phases/` tree first and then falls through to the
|
|
9
9
|
* closed milestones' `milestones/<v>-phases/` archives, marking such a match
|
|
10
10
|
* with the archive's version. It applies no milestone compare, and it must not:
|
|
@@ -56,14 +56,6 @@ const clock_cjs_1 = require("./clock.cjs");
|
|
|
56
56
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- uat-predicate.cjs is an export= CommonJS module
|
|
57
57
|
const uatPredicate = require("./uat-predicate.cjs");
|
|
58
58
|
const { evaluateUatPassed } = uatPredicate;
|
|
59
|
-
const plan_graph_cjs_1 = require("./plan-graph.cjs");
|
|
60
|
-
const dispatch_plan_cjs_1 = require("./dispatch-plan.cjs");
|
|
61
|
-
const phase_tier_cjs_1 = require("./phase-tier.cjs");
|
|
62
|
-
const install_run_cjs_1 = require("./install-run.cjs");
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports -- loop-resolver.cjs is an export= CommonJS module
|
|
64
|
-
const loopResolver = require("./loop-resolver.cjs");
|
|
65
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-manifest.cjs is an export= CommonJS module
|
|
66
|
-
const phaseManifest = require("./phase-manifest.cjs");
|
|
67
59
|
const { planningDir, withPlanningLock, milestonePathsFor } = planningWorkspace;
|
|
68
60
|
const { extractFrontmatter } = frontmatterMod;
|
|
69
61
|
const { readModifyWriteStateMd, stateExtractField, stateReplaceField, stateReplaceFieldWithFallback, syncStateFrontmatter, withStateLock, updatePerformanceMetricsSection, } = stateMod;
|
|
@@ -412,185 +404,6 @@ function cmdPhasePlanIndex(cwd, phase, raw) {
|
|
|
412
404
|
if (!phase) {
|
|
413
405
|
error('phase required for phase-plan-index');
|
|
414
406
|
}
|
|
415
|
-
const built = buildPhasePlanIndex(cwd, phase);
|
|
416
|
-
if (built.fatal !== undefined) {
|
|
417
|
-
error(built.fatal);
|
|
418
|
-
return;
|
|
419
|
-
}
|
|
420
|
-
output(built.result, raw);
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* `phase.dispatch-plan <phase> [--wave N] [--gaps-only] [--use-worktrees true|false]`:
|
|
424
|
-
* the executor spawns, builds, suite runs and tracking commits for the phase's
|
|
425
|
-
* incomplete plans (computed by src/dispatch-plan.cts from the plan inventory).
|
|
426
|
-
*/
|
|
427
|
-
function cmdPhaseDispatchPlan(cwd, args, raw) {
|
|
428
|
-
const parsed = (0, dispatch_plan_cjs_1.parseDispatchPlanArgs)(args);
|
|
429
|
-
if ('error' in parsed) {
|
|
430
|
-
error(parsed.error);
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
const built = buildPhasePlanIndex(cwd, parsed.phase);
|
|
434
|
-
if (built.fatal !== undefined) {
|
|
435
|
-
error(built.fatal);
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
if (built.phaseDir === null) {
|
|
439
|
-
output({ phase: built.result['phase'], error: 'Phase not found' }, raw);
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
const policy = (0, dispatch_plan_cjs_1.resolveDispatchPolicy)(cwd, parsed);
|
|
443
|
-
const plans = built.result['plans'].map((p) => {
|
|
444
|
-
const extra = built.extras.get(p['id']);
|
|
445
|
-
return {
|
|
446
|
-
id: p['id'],
|
|
447
|
-
title: p['title'] ?? null,
|
|
448
|
-
wave: p['wave'],
|
|
449
|
-
serial_group: p['serial_group'] ?? null,
|
|
450
|
-
files_modified: p['files_modified'],
|
|
451
|
-
autonomous: p['autonomous'],
|
|
452
|
-
has_summary: p['has_summary'],
|
|
453
|
-
requirements: extra?.requirements ?? [],
|
|
454
|
-
gap_closure: extra?.gapClosure ?? false,
|
|
455
|
-
};
|
|
456
|
-
});
|
|
457
|
-
const phaseDirRel = node_path_1.default.relative(cwd, built.phaseDir).split(node_path_1.default.sep).join('/');
|
|
458
|
-
const tier = (0, phase_tier_cjs_1.resolvePhaseTierForProject)(cwd, parsed.phase, parsed.tier);
|
|
459
|
-
// The executor brief: active execute:pre `into: executor` contributions,
|
|
460
|
-
// resolved by the loop resolver under this phase's tier. An unreadable config
|
|
461
|
-
// refuses here exactly as `loop render-hooks` does — a brief computed from
|
|
462
|
-
// swallowed defaults would silently drop a capability's executor contract.
|
|
463
|
-
const hooks = loopResolver.resolveProjectLoopHooks(cwd, 'execute:pre', { phaseTier: tier, what: 'phase.dispatch-plan' });
|
|
464
|
-
if (!hooks.ok) {
|
|
465
|
-
error(hooks.message, hooks.reason === 'config_unreadable' ? ERROR_REASON.CONFIG_PARSE_FAILED : undefined);
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
const executorContributions = loopResolver.contributionsInto(hooks.resolved, 'executor');
|
|
469
|
-
// The agent practice review's one applicability predicate (src/vault.cts),
|
|
470
|
-
// required lazily: only this command needs the vault module here.
|
|
471
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
472
|
-
const vaultMod = require('./vault.cjs');
|
|
473
|
-
const vaultReview = vaultMod.vaultReviewApplies(cwd);
|
|
474
|
-
output((0, dispatch_plan_cjs_1.computeDispatchPlan)(built.result['phase'], phaseDirRel, plans, policy, tier, { planBounceScript: tier.plan_bounce_script, vaultReview, executorContributions }), raw);
|
|
475
|
-
}
|
|
476
|
-
/**
|
|
477
|
-
* `phase.install-run <phase> [--tarball <tgz>] [--package-dir <dir>] [--no-build]`:
|
|
478
|
-
* pack, install into a temp project, init and run the phase's install checks
|
|
479
|
-
* against the installed copy; writes `<NN>-INSTALL-RUN.json` (src/install-run.cts).
|
|
480
|
-
*/
|
|
481
|
-
function cmdPhaseInstallRun(cwd, args, raw) {
|
|
482
|
-
const parsed = (0, install_run_cjs_1.parseInstallRunArgs)(args);
|
|
483
|
-
if ('error' in parsed) {
|
|
484
|
-
error(parsed.error, ERROR_REASON.USAGE);
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
let out;
|
|
488
|
-
try {
|
|
489
|
-
out = (0, install_run_cjs_1.runInstallRun)({ cwd, phase: parsed.phase, tarball: parsed.tarball, packageDir: parsed.packageDir, build: parsed.build });
|
|
490
|
-
}
|
|
491
|
-
catch (e) {
|
|
492
|
-
error(e.message);
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
output(out, raw);
|
|
496
|
-
}
|
|
497
|
-
/**
|
|
498
|
-
* `phase.tier <phase> [--tier light|standard|heavy]`: the phase's resolved
|
|
499
|
-
* ceremony tier — tier, source, gate set, suppressed gates (src/phase-tier.cts).
|
|
500
|
-
*/
|
|
501
|
-
/**
|
|
502
|
-
* `phase.manifest start|record <phase>`: write `.phase-manifest.json`, the
|
|
503
|
-
* file `/pp-undo --phase` reads (src/phase-manifest.cts). `start` anchors the
|
|
504
|
-
* phase at HEAD (write-once); `record` lists `<startCommit>..HEAD`. Always
|
|
505
|
-
* exits 0: a refusal is reported (`ok: false`, `reason`) and the caller
|
|
506
|
-
* continues — `/pp-undo` then falls back to its git-log search.
|
|
507
|
-
*/
|
|
508
|
-
function cmdPhaseManifest(cwd, args, raw) {
|
|
509
|
-
const usage = 'Usage: phase manifest start|record <phase>';
|
|
510
|
-
const positional = args.filter((a) => a !== '--raw');
|
|
511
|
-
const action = positional[0];
|
|
512
|
-
const phaseArg = positional[1];
|
|
513
|
-
if ((action !== 'start' && action !== 'record') || !phaseArg || positional.length > 2) {
|
|
514
|
-
error(usage, ERROR_REASON.USAGE);
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
const built = buildPhasePlanIndex(cwd, phaseArg);
|
|
518
|
-
if (built.fatal !== undefined) {
|
|
519
|
-
error(built.fatal);
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
if (built.phaseDir === null) {
|
|
523
|
-
const result = { ok: false, action, reason: phaseManifest.PHASE_MANIFEST_WRITE_REASON.PHASE_DIR_UNRESOLVABLE };
|
|
524
|
-
output(result, raw, phaseManifest.renderManifestResult(result));
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
const opts = { root: cwd, phaseDir: built.phaseDir, cwd };
|
|
528
|
-
const result = action === 'start' ? phaseManifest.recordPhaseStart(opts) : phaseManifest.recordPhaseCommits(opts);
|
|
529
|
-
output(result, raw, phaseManifest.renderManifestResult(result));
|
|
530
|
-
}
|
|
531
|
-
function cmdPhaseTier(cwd, args, raw) {
|
|
532
|
-
const usage = 'Usage: phase tier <phase> [--tier light|standard|heavy]';
|
|
533
|
-
const parsed = (0, phase_tier_cjs_1.parseTierFlag)(args.filter((a) => a !== '--raw'));
|
|
534
|
-
if ('error' in parsed) {
|
|
535
|
-
error(`${parsed.error}. ${usage}`, ERROR_REASON.USAGE);
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
if (parsed.rest.length !== 1 || parsed.rest[0].startsWith('--')) {
|
|
539
|
-
error(parsed.rest.length === 0 ? `phase required for phase tier. ${usage}` : `phase tier takes one phase and --tier. ${usage}`, ERROR_REASON.USAGE);
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
const phaseArg = parsed.rest[0];
|
|
543
|
-
output({ phase: phaseArg, ...(0, phase_tier_cjs_1.resolvePhaseTierForProject)(cwd, phaseArg, parsed.tier) }, raw);
|
|
544
|
-
}
|
|
545
|
-
/**
|
|
546
|
-
* `phase.tier-propose <phase> [--record] [--tier X]`: propose a tier from the
|
|
547
|
-
* phase's plans (`files_modified`) or, before planning, its requirement tags
|
|
548
|
-
* and ROADMAP text. `--record` writes it to the phase's ROADMAP `**Tier:**`
|
|
549
|
-
* field, marked `(proposed: …)`, unless the operator already chose one;
|
|
550
|
-
* `--record --tier X` records X as the operator's choice.
|
|
551
|
-
*/
|
|
552
|
-
function cmdPhaseTierPropose(cwd, args, raw) {
|
|
553
|
-
const usage = 'Usage: phase tier-propose <phase> [--record] [--tier light|standard|heavy]';
|
|
554
|
-
const parsed = (0, phase_tier_cjs_1.parseTierFlag)(args.filter((a) => a !== '--raw'));
|
|
555
|
-
if ('error' in parsed) {
|
|
556
|
-
error(`${parsed.error}. ${usage}`, ERROR_REASON.USAGE);
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
const doRecord = parsed.rest.includes('--record');
|
|
560
|
-
const positional = parsed.rest.filter((a) => a !== '--record');
|
|
561
|
-
if (positional.length !== 1 || positional[0].startsWith('--')) {
|
|
562
|
-
error(positional.length === 0 ? `phase required for phase tier-propose. ${usage}` : `phase tier-propose does not support ${positional.find((a) => a.startsWith('--')) ?? positional.join(' ')}. ${usage}`, ERROR_REASON.USAGE);
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
const phaseArg = positional[0];
|
|
566
|
-
const record = (0, phase_tier_cjs_1.readPhaseRecord)(cwd, phaseArg);
|
|
567
|
-
if (record.section === null) {
|
|
568
|
-
output({ phase: phaseArg, error: 'Phase not found in ROADMAP.md' }, raw);
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
const built = buildPhasePlanIndex(cwd, phaseArg);
|
|
572
|
-
const planRows = built.fatal === undefined && built.phaseDir !== null
|
|
573
|
-
? built.result['plans'].map((p) => ({ id: p['id'], files_modified: p['files_modified'] ?? [] }))
|
|
574
|
-
: [];
|
|
575
|
-
const reqMatch = record.section.match(/^\*\*Requirements:?\*\*[^\S\n]*:?[^\S\n]*([^\n]*)$/m);
|
|
576
|
-
const requirements = reqMatch ? reqMatch[1].replace(/[[\]]/g, '').split(',').map((s) => s.trim()).filter((s) => s !== '' && s !== 'TBD') : [];
|
|
577
|
-
const proposal = (0, phase_tier_cjs_1.proposePhaseTier)({ plans: planRows, requirements, roadmapText: record.section });
|
|
578
|
-
let recorded = null;
|
|
579
|
-
if (doRecord) {
|
|
580
|
-
recorded = parsed.tier !== null
|
|
581
|
-
? (0, phase_tier_cjs_1.recordPhaseTier)(cwd, phaseArg, parsed.tier, { proposed: false })
|
|
582
|
-
: (0, phase_tier_cjs_1.recordPhaseTier)(cwd, phaseArg, proposal.tier, { proposed: true, reason: proposal.reason });
|
|
583
|
-
}
|
|
584
|
-
const after = (0, phase_tier_cjs_1.resolvePhaseTierForProject)(cwd, phaseArg, parsed.tier);
|
|
585
|
-
output({
|
|
586
|
-
phase: phaseArg,
|
|
587
|
-
proposal,
|
|
588
|
-
phase_record: record.tier !== null ? { tier: record.tier, proposed: record.proposed } : null,
|
|
589
|
-
recorded,
|
|
590
|
-
effective: { tier: after.tier, source: after.source, suppressed: after.suppressed },
|
|
591
|
-
}, raw);
|
|
592
|
-
}
|
|
593
|
-
function buildPhasePlanIndex(cwd, phase) {
|
|
594
407
|
const phasesDir = node_path_1.default.join(planningDir(cwd), 'phases');
|
|
595
408
|
const normalized = normalizePhaseName(phase);
|
|
596
409
|
let phaseDir = null;
|
|
@@ -611,11 +424,8 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
611
424
|
// phases dir doesn't exist
|
|
612
425
|
}
|
|
613
426
|
if (!phaseDir) {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
phaseDir: null,
|
|
617
|
-
extras: new Map(),
|
|
618
|
-
};
|
|
427
|
+
output({ phase: normalized, error: 'Phase not found', plans: [], waves: {}, incomplete: [], has_checkpoints: false }, raw);
|
|
428
|
+
return;
|
|
619
429
|
}
|
|
620
430
|
void phaseDirName; // used only to set phaseDir above
|
|
621
431
|
const phaseFiles = node_fs_1.default.readdirSync(phaseDir);
|
|
@@ -637,13 +447,6 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
637
447
|
const xmlTasks = content.match(/<task[\s>]/gi) || [];
|
|
638
448
|
const mdTasks = content.match(/##\s*Task\s*\d+/gi) || [];
|
|
639
449
|
const taskCount = xmlTasks.length || mdTasks.length;
|
|
640
|
-
const taskTypes = xmlTasks.length > 0
|
|
641
|
-
? [...content.matchAll(/<task(\s[^>]*)?>/gi)].map((m) => /type=["']?([\w:-]+)/i.exec(m[1] ?? '')?.[1] ?? 'auto')
|
|
642
|
-
: mdTasks.map(() => 'auto');
|
|
643
|
-
const fmString = (key) => {
|
|
644
|
-
const value = fm[key];
|
|
645
|
-
return typeof value === 'string' && value.trim() !== '' ? value.trim() : null;
|
|
646
|
-
};
|
|
647
450
|
const parsedWave = parseInt(fm['wave'], 10);
|
|
648
451
|
const declaredWave = Number.isNaN(parsedWave) ? null : parsedWave;
|
|
649
452
|
let dependsOn = [];
|
|
@@ -666,10 +469,6 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
666
469
|
filesModified = Array.isArray(fmFiles) ? fmFiles.map(String) : [String(fmFiles)];
|
|
667
470
|
}
|
|
668
471
|
const hasSummary = completedPlanIds.has(planId) || completedPlanIds.has(extractCanonicalPlanId(planFile));
|
|
669
|
-
const fmReqs = fm['requirements'];
|
|
670
|
-
const requirements = (Array.isArray(fmReqs) ? fmReqs.map(String) : typeof fmReqs === 'string' && fmReqs.trim() !== '' ? fmReqs.split(/[\s,]+/) : [])
|
|
671
|
-
.map((r) => r.trim())
|
|
672
|
-
.filter((r) => r !== '' && r !== '[]');
|
|
673
472
|
rawPlans.push({
|
|
674
473
|
id: planId,
|
|
675
474
|
declaredWave,
|
|
@@ -679,13 +478,6 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
679
478
|
filesModified,
|
|
680
479
|
taskCount,
|
|
681
480
|
hasSummary,
|
|
682
|
-
title: (0, plan_graph_cjs_1.readPlanTitle)(fm['title']),
|
|
683
|
-
serialGroup: fmString('serial_group'),
|
|
684
|
-
chainReason: fmString('chain_reason'),
|
|
685
|
-
taskTypes,
|
|
686
|
-
requirements,
|
|
687
|
-
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- FrontmatterValue scalar-to-string
|
|
688
|
-
gapClosure: String(fm['gap_closure'] ?? '').trim() === 'true',
|
|
689
481
|
});
|
|
690
482
|
}
|
|
691
483
|
// ── Pass 2: topological level assignment via depends_on DAG ──────────────
|
|
@@ -694,31 +486,18 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
694
486
|
const lower = p.id.toLowerCase();
|
|
695
487
|
const existing = seenLower.get(lower);
|
|
696
488
|
if (existing !== undefined) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
};
|
|
489
|
+
error(`depends_on index collision in phase ${normalized}: plan IDs '${existing}' and '${p.id}' are identical when case-folded. Rename one file to avoid ambiguous dependency resolution.`);
|
|
490
|
+
return;
|
|
700
491
|
}
|
|
701
492
|
seenLower.set(lower, p.id);
|
|
702
493
|
}
|
|
703
494
|
const planMap = new Map(rawPlans.map((p) => [p.id.toLowerCase(), p]));
|
|
704
495
|
const canonicalToId = new Map(rawPlans.map((p) => [extractCanonicalPlanId(p.id).toLowerCase(), p.id]));
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const graph = (0, plan_graph_cjs_1.computePlanGraph)(rawPlans.map((p) => ({
|
|
711
|
-
id: p.id,
|
|
712
|
-
title: p.title,
|
|
713
|
-
dependsOn: p.dependsOn.map(resolveDep).filter((d) => d !== undefined),
|
|
714
|
-
filesModified: p.filesModified,
|
|
715
|
-
serialGroup: p.serialGroup,
|
|
716
|
-
chainReason: p.chainReason,
|
|
717
|
-
taskTypes: p.taskTypes,
|
|
718
|
-
})));
|
|
719
|
-
if (graph.cycle) {
|
|
720
|
-
const cycleNodes = graph.cycle;
|
|
721
|
-
return { fatal: `depends_on cycle detected in phase ${normalized} — cycle involves: ${cycleNodes.join(', ')}` };
|
|
496
|
+
const { level, visited } = computeDependencyLevels(rawPlans, planMap, canonicalToId);
|
|
497
|
+
if (visited < rawPlans.length) {
|
|
498
|
+
const cycleNodes = rawPlans.filter((p) => !level.has(p.id)).map((p) => p.id);
|
|
499
|
+
error(`depends_on cycle detected in phase ${normalized} — cycle involves: ${cycleNodes.join(', ')}`);
|
|
500
|
+
return;
|
|
722
501
|
}
|
|
723
502
|
// ── Pass 3: determine lowest bucket key and build output ─────────────────
|
|
724
503
|
const anyWaveZero = rawPlans.some((p) => p.declaredWave === 0);
|
|
@@ -735,16 +514,14 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
735
514
|
if (!rawPlan.hasSummary) {
|
|
736
515
|
incomplete.push(rawPlan.id);
|
|
737
516
|
}
|
|
738
|
-
const computedWave = (
|
|
517
|
+
const computedWave = (level.get(rawPlan.id) ?? 0) + levelOffset;
|
|
739
518
|
const effectiveWave = computedWave;
|
|
740
519
|
if (rawPlan.declaredWave !== null && rawPlan.declaredWave !== computedWave) {
|
|
741
520
|
warnings.push(`Plan ${rawPlan.id}: declared wave: ${rawPlan.declaredWave} but depends_on DAG places it in wave ${computedWave}`);
|
|
742
521
|
}
|
|
743
522
|
const plan = {
|
|
744
523
|
id: rawPlan.id,
|
|
745
|
-
title: rawPlan.title,
|
|
746
524
|
wave: effectiveWave,
|
|
747
|
-
serial_group: graph.serialGroupOf[rawPlan.id] ?? null,
|
|
748
525
|
depends_on: rawPlan.dependsOn.map((dep) => {
|
|
749
526
|
const lower = String(dep).toLowerCase();
|
|
750
527
|
return planMap.has(lower) ? planMap.get(lower).id : dep;
|
|
@@ -766,28 +543,14 @@ function buildPhasePlanIndex(cwd, phase) {
|
|
|
766
543
|
phase: normalized,
|
|
767
544
|
plans,
|
|
768
545
|
waves,
|
|
769
|
-
serial_groups: Object.fromEntries(graph.serialGroups.map((g) => [g.name, { wave: g.level + levelOffset, plans: g.plans, shared_files: g.shared_files }])),
|
|
770
|
-
graph: {
|
|
771
|
-
plan_count: graph.plan_count,
|
|
772
|
-
wave_count: graph.wave_count,
|
|
773
|
-
longest_chain: graph.longest_chain,
|
|
774
|
-
chain_check: graph.chain_check,
|
|
775
|
-
implicit_edges: graph.implicitEdges,
|
|
776
|
-
merge_candidates: graph.merge_candidates,
|
|
777
|
-
},
|
|
778
546
|
incomplete,
|
|
779
547
|
has_checkpoints: hasCheckpoints,
|
|
780
548
|
};
|
|
781
|
-
warnings.push(...graph.warnings);
|
|
782
549
|
if (planNamingWarning)
|
|
783
550
|
result['warning'] = planNamingWarning;
|
|
784
551
|
if (warnings.length > 0)
|
|
785
552
|
result['warnings'] = warnings;
|
|
786
|
-
|
|
787
|
-
result,
|
|
788
|
-
phaseDir,
|
|
789
|
-
extras: new Map(rawPlans.map((p) => [p.id, { requirements: p.requirements, gapClosure: p.gapClosure }])),
|
|
790
|
-
};
|
|
553
|
+
output(result, raw);
|
|
791
554
|
}
|
|
792
555
|
function cmdPhaseAdd(cwd, description, raw, customId) {
|
|
793
556
|
if (!description) {
|
|
@@ -1706,11 +1469,6 @@ module.exports = {
|
|
|
1706
1469
|
cmdPhaseNextDecimal,
|
|
1707
1470
|
cmdFindPhase,
|
|
1708
1471
|
cmdPhasePlanIndex,
|
|
1709
|
-
cmdPhaseDispatchPlan,
|
|
1710
|
-
cmdPhaseInstallRun,
|
|
1711
|
-
cmdPhaseTier,
|
|
1712
|
-
cmdPhaseTierPropose,
|
|
1713
|
-
cmdPhaseManifest,
|
|
1714
1472
|
cmdPhaseAdd,
|
|
1715
1473
|
cmdPhaseAddBatch,
|
|
1716
1474
|
cmdPhaseMvpMode,
|
|
@@ -34,8 +34,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
34
34
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
35
35
|
};
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.BINDINGS_COORDINATE_FIELDS = exports.MACHINE_SPECIFIC_CLONE_TARGET_PATTERNS = exports.VAULT_REPO_PATTERN_SOURCE = exports.PLATFORM_REPO_PATTERN_SOURCE = exports.CONTRACT_SCHEMA_VERSION = void 0;
|
|
37
|
+
exports.BINDINGS_COORDINATE_FIELDS = exports.MACHINE_SPECIFIC_CLONE_TARGET_PATTERNS = exports.VAULT_REPO_PATTERN_SOURCE = exports.PLATFORM_REPO_PATTERN_SOURCE = exports.SLUG_RE = exports.CONTRACT_SCHEMA_VERSION = void 0;
|
|
38
38
|
exports.validateBindings = validateBindings;
|
|
39
|
+
exports.redactCoordinateForEmission = redactCoordinateForEmission;
|
|
40
|
+
exports.redactBindingsField = redactBindingsField;
|
|
39
41
|
exports.redactBindingsForEmission = redactBindingsForEmission;
|
|
40
42
|
exports.cmdPlatformBindings = cmdPlatformBindings;
|
|
41
43
|
exports.cmdValidateBindings = cmdValidateBindings;
|
|
@@ -65,7 +67,7 @@ const SCHEMA_VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
|
65
67
|
exports.CONTRACT_SCHEMA_VERSION = '1.1.0';
|
|
66
68
|
const PLATFORM_TAG_RE = /^v\d+\.\d+\.\d+/;
|
|
67
69
|
// Provisional namespace pattern (lenient): only enforced if client.slug is present.
|
|
68
|
-
|
|
70
|
+
exports.SLUG_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
69
71
|
// A host-relative path of two or more slash-separated segments built from
|
|
70
72
|
// word/dot/hyphen characters — e.g. `pareto4/pareto-platform-gcp` or Azure's
|
|
71
73
|
// four-segment `org/project/_git/repo`. This is the pre-v1.1.0 vault-repo
|
|
@@ -77,8 +79,8 @@ const HOST_RELATIVE_SLUG_SOURCE = '^[\\w.-]+(?:\\/[\\w.-]+)+$';
|
|
|
77
79
|
* A host-relative path of two or more segments. Compiled into
|
|
78
80
|
* `platform.repo.pattern` by `scripts/gen-platform-bindings-schema.cjs` so
|
|
79
81
|
* the runtime regex and the schema pattern cannot drift (D-06). Deliberately
|
|
80
|
-
* accepts no URL and no SSH form: `
|
|
81
|
-
* host from `platform.host` itself (Phase 31 D-09), so a full URL here would
|
|
82
|
+
* accepts no URL and no SSH form: `resolveLatestPlatformTag` (compose-bindings)
|
|
83
|
+
* composes the host from `platform.host` itself (Phase 31 D-09), so a full URL here would
|
|
82
84
|
* give the host two competing encodings — `platform.host` is authoritative.
|
|
83
85
|
*/
|
|
84
86
|
exports.PLATFORM_REPO_PATTERN_SOURCE = HOST_RELATIVE_SLUG_SOURCE;
|
|
@@ -183,7 +185,7 @@ function validateBindings(o) {
|
|
|
183
185
|
// Provisional namespaces — lenient. A missing/unknown namespace is fine; only
|
|
184
186
|
// a PRESENT slug field that is malformed is flagged (it never gates on absence).
|
|
185
187
|
if (isObject(o.client) && o.client.slug !== undefined) {
|
|
186
|
-
if (typeof o.client.slug !== 'string' || !SLUG_RE.test(o.client.slug)) {
|
|
188
|
+
if (typeof o.client.slug !== 'string' || !exports.SLUG_RE.test(o.client.slug)) {
|
|
187
189
|
errors.push('client.slug: present but not a url-safe lowercase slug');
|
|
188
190
|
}
|
|
189
191
|
}
|
|
@@ -203,35 +205,53 @@ function validateBindings(o) {
|
|
|
203
205
|
// IN-03: project.slug — symmetric lenient check matching client.slug behaviour.
|
|
204
206
|
// The schema defines the same ^[a-z0-9][a-z0-9-]*$ pattern for both fields.
|
|
205
207
|
if (isObject(o.project) && o.project.slug !== undefined) {
|
|
206
|
-
if (typeof o.project.slug !== 'string' || !SLUG_RE.test(o.project.slug)) {
|
|
208
|
+
if (typeof o.project.slug !== 'string' || !exports.SLUG_RE.test(o.project.slug)) {
|
|
207
209
|
errors.push('project.slug: present but not a url-safe lowercase slug');
|
|
208
210
|
}
|
|
209
211
|
}
|
|
210
212
|
return { valid: errors.length === 0, errors, warnings };
|
|
211
213
|
}
|
|
212
214
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
215
|
+
* VAULT-EGRESS-1 (quick 261005-8py gap closure): the `.platform-bindings.json`
|
|
216
|
+
* fields that carry a remote repo coordinate, and therefore the fields a
|
|
217
|
+
* credential (`https://user:TOKEN@host/…`, `user:TOKEN@host:path`) can ride in.
|
|
218
|
+
* Hosts are deliberately NOT listed: `platform.host` is read for real use by
|
|
219
|
+
* /pp-init's provisioning step (`--pick platform.host`), and a host is a bare
|
|
220
|
+
* host by contract.
|
|
216
221
|
*/
|
|
217
222
|
exports.BINDINGS_COORDINATE_FIELDS = Object.freeze(['platform.repo', 'client.vaultRepo']);
|
|
218
223
|
/**
|
|
219
|
-
* Emission-only:
|
|
220
|
-
*
|
|
221
|
-
* required
|
|
222
|
-
*
|
|
224
|
+
* Emission-only: the display-safe form of one coordinate, through the ONE
|
|
225
|
+
* owner (`redactCloneTarget` in `src/vault.cts`) — never a second redactor.
|
|
226
|
+
* Lazily required, the idiom `src/vault-command-router.cts` uses, so this
|
|
227
|
+
* module's load graph is unchanged. Never call this on a value that is written
|
|
228
|
+
* to disk or handed to git: those keep the RAW coordinate.
|
|
229
|
+
*/
|
|
230
|
+
function redactCoordinateForEmission(value) {
|
|
231
|
+
if (typeof value !== 'string' || value === '')
|
|
232
|
+
return value;
|
|
233
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
234
|
+
const { redactCloneTarget } = require('./vault.cjs');
|
|
235
|
+
return redactCloneTarget(value) ?? value;
|
|
236
|
+
}
|
|
237
|
+
/** Emission-only: `value` redacted when `field` (dotted) is a coordinate field. */
|
|
238
|
+
function redactBindingsField(field, value) {
|
|
239
|
+
return exports.BINDINGS_COORDINATE_FIELDS.includes(field) ? redactCoordinateForEmission(value) : value;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Emission-only: a copy of a bindings-shaped object with every coordinate
|
|
243
|
+
* field routed through the owner. The input is never mutated — callers that
|
|
244
|
+
* compare (drift, `action`) or write keep the raw object.
|
|
223
245
|
*/
|
|
224
246
|
function redactBindingsForEmission(obj) {
|
|
225
247
|
if (!isObject(obj))
|
|
226
248
|
return obj;
|
|
227
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
228
|
-
const { redactCloneTarget } = require('./vault.cjs');
|
|
229
249
|
const copy = JSON.parse(JSON.stringify(obj));
|
|
230
250
|
for (const field of exports.BINDINGS_COORDINATE_FIELDS) {
|
|
231
251
|
const [ns, key] = field.split('.');
|
|
232
252
|
const parent = copy[ns];
|
|
233
253
|
if (isObject(parent) && typeof parent[key] === 'string') {
|
|
234
|
-
parent[key] =
|
|
254
|
+
parent[key] = redactCoordinateForEmission(parent[key]);
|
|
235
255
|
}
|
|
236
256
|
}
|
|
237
257
|
return copy;
|
|
@@ -281,9 +301,10 @@ function cmdPlatformBindings(cwd, args, raw) {
|
|
|
281
301
|
output(validateBindings(parsed), raw);
|
|
282
302
|
return;
|
|
283
303
|
}
|
|
284
|
-
// present + valid → echo the bindings under a present flag.
|
|
285
|
-
//
|
|
286
|
-
//
|
|
304
|
+
// present + valid → echo the bindings under a present flag. The coordinate
|
|
305
|
+
// fields are display-safe (VAULT-EGRESS-1); every other field is verbatim,
|
|
306
|
+
// and the one consumer of the whole dump (vault-load-gate.md) reads only
|
|
307
|
+
// `client.vaultRepo`'s presence and the raw `client.vaultRef`.
|
|
287
308
|
output(Object.assign({ present: true }, redactBindingsForEmission(parsed)), raw);
|
|
288
309
|
}
|
|
289
310
|
// Anchored regex for `?ref=` values in module source lines (T-07-04: untrusted text,
|
|
@@ -28,7 +28,7 @@ const { loadConfig } = configLoader;
|
|
|
28
28
|
const shell_command_projection_cjs_1 = require("./shell-command-projection.cjs");
|
|
29
29
|
const runtime_homes_cjs_1 = require("./runtime-homes.cjs");
|
|
30
30
|
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
31
|
-
//
|
|
31
|
+
// PBI 75232: the start-command fallback uses the pp-named alias (same function).
|
|
32
32
|
const runtime_slash_cjs_2 = require("./runtime-slash.cjs");
|
|
33
33
|
const runtime_name_policy_cjs_1 = require("./runtime-name-policy.cjs");
|
|
34
34
|
// eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-workspace.cjs is an export= CommonJS module
|